From 5544c1b492fb00740807fb6a277593e5578300e2 Mon Sep 17 00:00:00 2001 From: Cole Robinson Date: Oct 28 2012 18:05:07 +0000 Subject: Pull patches queued for qemu 1.2.1 --- diff --git a/0001-Revert-qemu-char-Re-connect-for-tcp_chr_write-unconn.patch b/0001-Revert-qemu-char-Re-connect-for-tcp_chr_write-unconn.patch deleted file mode 100644 index 42d1484..0000000 --- a/0001-Revert-qemu-char-Re-connect-for-tcp_chr_write-unconn.patch +++ /dev/null @@ -1,14 +0,0 @@ ---- qemu-kvm-1.2.0/qemu-char.c~ 2012-09-12 19:46:36.491936229 +0100 -+++ qemu-kvm-1.2.0/qemu-char.c 2012-09-12 19:47:33.349972760 +0100 -@@ -2268,9 +2268,8 @@ - } - return ret; - } else { -- /* (Re-)connect for unconnected writing */ -- tcp_chr_connect(chr); -- return 0; -+ /* XXX: indicate an error ? */ -+ return len; - } - } - diff --git a/0001-mips-Fix-link-error-with-piix4_pm_init.patch b/0001-mips-Fix-link-error-with-piix4_pm_init.patch deleted file mode 100644 index 723524c..0000000 --- a/0001-mips-Fix-link-error-with-piix4_pm_init.patch +++ /dev/null @@ -1,30 +0,0 @@ -From 4ba58730950a376dfb9f0424acb2b2cc3fbeda4f Mon Sep 17 00:00:00 2001 -From: Cole Robinson -Date: Mon, 6 Aug 2012 17:12:40 -0400 -Subject: [PATCH] mips: Fix link error with 'piix4_pm_init' - - LINK mips-softmmu/qemu-system-mips - LINK m68k-softmmu/qemu-system-m68k -hw/mips/../mips_malta.o: In function `mips_malta_init': -/home/crobinso/qemu-kvm/hw/mips/../mips_malta.c:961: undefined reference to `piix4_pm_init' - -Signed-off-by: Cole Robinson ---- - hw/mips/Makefile.objs | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/hw/mips/Makefile.objs b/hw/mips/Makefile.objs -index 29a5d0d..89af0e9 100644 ---- a/hw/mips/Makefile.objs -+++ b/hw/mips/Makefile.objs -@@ -1,6 +1,7 @@ - obj-y = mips_r4k.o mips_jazz.o mips_malta.o mips_mipssim.o - obj-y += mips_addr.o mips_timer.o mips_int.o - obj-y += gt64xxx.o mc146818rtc.o -+obj-y += acpi.o acpi_piix4.o - obj-$(CONFIG_FULONG) += bonito.o vt82c686.o mips_fulong2e.o - - obj-y := $(addprefix ../,$(obj-y)) --- -1.7.11.2 - diff --git a/0001-target-xtensa-convert-host-errno-values-to-guest.patch b/0001-target-xtensa-convert-host-errno-values-to-guest.patch new file mode 100644 index 0000000..7eb51fe --- /dev/null +++ b/0001-target-xtensa-convert-host-errno-values-to-guest.patch @@ -0,0 +1,183 @@ +From 707f294ca28977968fb85bf36f10c6b37b16f557 Mon Sep 17 00:00:00 2001 +From: Max Filippov +Date: Wed, 29 Aug 2012 23:54:25 +0400 +Subject: [PATCH] target-xtensa: convert host errno values to guest + +Guest errno values are taken from the newlib. Convert only those errno +values that can be returned from used system calls. + +Signed-off-by: Max Filippov +Signed-off-by: Blue Swirl +Signed-off-by: Michael Roth +--- + target-xtensa/xtensa-semi.c | 106 ++++++++++++++++++++++++++++++++++++++++---- + 1 file changed, 98 insertions(+), 8 deletions(-) + +diff --git a/target-xtensa/xtensa-semi.c b/target-xtensa/xtensa-semi.c +index 6d001c2..e745bef 100644 +--- a/target-xtensa/xtensa-semi.c ++++ b/target-xtensa/xtensa-semi.c +@@ -54,6 +54,96 @@ enum { + SELECT_ONE_EXCEPT = 3, + }; + ++enum { ++ TARGET_EPERM = 1, ++ TARGET_ENOENT = 2, ++ TARGET_ESRCH = 3, ++ TARGET_EINTR = 4, ++ TARGET_EIO = 5, ++ TARGET_ENXIO = 6, ++ TARGET_E2BIG = 7, ++ TARGET_ENOEXEC = 8, ++ TARGET_EBADF = 9, ++ TARGET_ECHILD = 10, ++ TARGET_EAGAIN = 11, ++ TARGET_ENOMEM = 12, ++ TARGET_EACCES = 13, ++ TARGET_EFAULT = 14, ++ TARGET_ENOTBLK = 15, ++ TARGET_EBUSY = 16, ++ TARGET_EEXIST = 17, ++ TARGET_EXDEV = 18, ++ TARGET_ENODEV = 19, ++ TARGET_ENOTDIR = 20, ++ TARGET_EISDIR = 21, ++ TARGET_EINVAL = 22, ++ TARGET_ENFILE = 23, ++ TARGET_EMFILE = 24, ++ TARGET_ENOTTY = 25, ++ TARGET_ETXTBSY = 26, ++ TARGET_EFBIG = 27, ++ TARGET_ENOSPC = 28, ++ TARGET_ESPIPE = 29, ++ TARGET_EROFS = 30, ++ TARGET_EMLINK = 31, ++ TARGET_EPIPE = 32, ++ TARGET_EDOM = 33, ++ TARGET_ERANGE = 34, ++ TARGET_ENOSYS = 88, ++ TARGET_ELOOP = 92, ++}; ++ ++static uint32_t errno_h2g(int host_errno) ++{ ++ static const uint32_t guest_errno[] = { ++ [EPERM] = TARGET_EPERM, ++ [ENOENT] = TARGET_ENOENT, ++ [ESRCH] = TARGET_ESRCH, ++ [EINTR] = TARGET_EINTR, ++ [EIO] = TARGET_EIO, ++ [ENXIO] = TARGET_ENXIO, ++ [E2BIG] = TARGET_E2BIG, ++ [ENOEXEC] = TARGET_ENOEXEC, ++ [EBADF] = TARGET_EBADF, ++ [ECHILD] = TARGET_ECHILD, ++ [EAGAIN] = TARGET_EAGAIN, ++ [ENOMEM] = TARGET_ENOMEM, ++ [EACCES] = TARGET_EACCES, ++ [EFAULT] = TARGET_EFAULT, ++ [ENOTBLK] = TARGET_ENOTBLK, ++ [EBUSY] = TARGET_EBUSY, ++ [EEXIST] = TARGET_EEXIST, ++ [EXDEV] = TARGET_EXDEV, ++ [ENODEV] = TARGET_ENODEV, ++ [ENOTDIR] = TARGET_ENOTDIR, ++ [EISDIR] = TARGET_EISDIR, ++ [EINVAL] = TARGET_EINVAL, ++ [ENFILE] = TARGET_ENFILE, ++ [EMFILE] = TARGET_EMFILE, ++ [ENOTTY] = TARGET_ENOTTY, ++ [ETXTBSY] = TARGET_ETXTBSY, ++ [EFBIG] = TARGET_EFBIG, ++ [ENOSPC] = TARGET_ENOSPC, ++ [ESPIPE] = TARGET_ESPIPE, ++ [EROFS] = TARGET_EROFS, ++ [EMLINK] = TARGET_EMLINK, ++ [EPIPE] = TARGET_EPIPE, ++ [EDOM] = TARGET_EDOM, ++ [ERANGE] = TARGET_ERANGE, ++ [ENOSYS] = TARGET_ENOSYS, ++ [ELOOP] = TARGET_ELOOP, ++ }; ++ ++ if (host_errno == 0) { ++ return 0; ++ } else if (host_errno > 0 && host_errno < ARRAY_SIZE(guest_errno) && ++ guest_errno[host_errno]) { ++ return guest_errno[host_errno]; ++ } else { ++ return TARGET_EINVAL; ++ } ++} ++ + void HELPER(simcall)(CPUXtensaState *env) + { + uint32_t *regs = env->regs; +@@ -87,14 +177,14 @@ void HELPER(simcall)(CPUXtensaState *env) + regs[2] = is_write ? + write(fd, buf, io_sz) : + read(fd, buf, io_sz); +- regs[3] = errno; ++ regs[3] = errno_h2g(errno); + cpu_physical_memory_unmap(buf, sz, is_write, sz); + if (regs[2] == -1) { + break; + } + } else { + regs[2] = -1; +- regs[3] = EINVAL; ++ regs[3] = TARGET_EINVAL; + break; + } + } +@@ -117,10 +207,10 @@ void HELPER(simcall)(CPUXtensaState *env) + + if (rc == 0 && i < ARRAY_SIZE(name)) { + regs[2] = open(name, regs[4], regs[5]); +- regs[3] = errno; ++ regs[3] = errno_h2g(errno); + } else { + regs[2] = -1; +- regs[3] = EINVAL; ++ regs[3] = TARGET_EINVAL; + } + } + break; +@@ -130,13 +220,13 @@ void HELPER(simcall)(CPUXtensaState *env) + regs[2] = regs[3] = 0; + } else { + regs[2] = close(regs[3]); +- regs[3] = errno; ++ regs[3] = errno_h2g(errno); + } + break; + + case TARGET_SYS_lseek: + regs[2] = lseek(regs[3], (off_t)(int32_t)regs[4], regs[5]); +- regs[3] = errno; ++ regs[3] = errno_h2g(errno); + break; + + case TARGET_SYS_select_one: +@@ -163,7 +253,7 @@ void HELPER(simcall)(CPUXtensaState *env) + rq == SELECT_ONE_WRITE ? &fdset : NULL, + rq == SELECT_ONE_EXCEPT ? &fdset : NULL, + target_tv ? &tv : NULL); +- regs[3] = errno; ++ regs[3] = errno_h2g(errno); + } + break; + +@@ -219,7 +309,7 @@ void HELPER(simcall)(CPUXtensaState *env) + default: + qemu_log("%s(%d): not implemented\n", __func__, regs[2]); + regs[2] = -1; +- regs[3] = ENOSYS; ++ regs[3] = TARGET_ENOSYS; + break; + } + } +-- +1.7.12.1 + diff --git a/0002-configure-Add-disable-kvm-options.patch b/0002-configure-Add-disable-kvm-options.patch deleted file mode 100644 index 4108dea..0000000 --- a/0002-configure-Add-disable-kvm-options.patch +++ /dev/null @@ -1,72 +0,0 @@ -From 7b9b4ec74c7c0f63672d3aa627d7b153b71ba427 Mon Sep 17 00:00:00 2001 -From: Cole Robinson -Date: Mon, 13 Aug 2012 18:39:54 -0400 -Subject: [PATCH] configure: Add --disable-kvm-options - -In Fedora, our qemu package is based on qemu-kvm, and we go to convoluted -lengths to provide a qemu-kvm binary with KVM on by default, but all -qemu-system-* with KVM off by default (using ./configure --disable-kvm) - -For qemu-system*, what we really want is upstream qemu symantics of TCG -by default, but the opt in option for KVM. CONFIG_KVM_OPTIONS fits the -bill, so let's expose it through ./configure. This will also simplify -our packaging for non-x86 KVM. - -Signed-off-by: Cole Robinson ---- - configure | 11 ++++++++++- - 1 file changed, 10 insertions(+), 1 deletion(-) - -diff --git a/configure b/configure -index bf3acc8..cf2dc9f 100755 ---- a/configure -+++ b/configure -@@ -211,6 +211,7 @@ bsd_user="no" - guest_base="" - uname_release="" - mixemu="no" -+kvmoptions="yes" - aix="no" - blobs="yes" - pkgversion=" ($(kvm_version))" -@@ -747,6 +748,8 @@ for opt do - ;; - --enable-kvm) kvm="yes" - ;; -+ --disable-kvm-options) kvmoptions="no" -+ ;; - --disable-tcg-interpreter) tcg_interpreter="no" - ;; - --enable-tcg-interpreter) tcg_interpreter="yes" -@@ -1113,6 +1116,8 @@ echo " --enable-bluez enable bluez stack connectivity" - echo " --disable-slirp disable SLIRP userspace network connectivity" - echo " --disable-kvm disable KVM acceleration support" - echo " --enable-kvm enable KVM acceleration support" -+echo " --disable-kvm-options if KVM is enabled, default to KVM=off, and" -+echo " remove non-upstream cli options" - echo " --enable-tcg-interpreter enable TCG with bytecode interpreter (TCI)" - echo " --disable-nptl disable usermode NPTL support" - echo " --enable-nptl enable usermode NPTL support" -@@ -3156,6 +3161,7 @@ echo "ATTR/XATTR support $attr" - echo "Install blobs $blobs" - echo "KVM support $kvm" - echo "TCG interpreter $tcg_interpreter" -+echo "KVM CLI options $kvmoptions" - echo "fdt support $fdt" - echo "preadv support $preadv" - echo "fdatasync $fdatasync" -@@ -3889,7 +3895,10 @@ case "$target_arch2" in - \( "$target_arch2" = "x86_64" -a "$cpu" = "i386" \) -o \ - \( "$target_arch2" = "i386" -a "$cpu" = "x86_64" \) \) ; then - echo "CONFIG_KVM=y" >> $config_target_mak -- echo "CONFIG_KVM_OPTIONS=y" >> $config_host_mak -+ -+ if test "$kvmoptions" = "yes" ; then -+ echo "CONFIG_KVM_OPTIONS=y" >> $config_host_mak -+ fi - if test "$vhost_net" = "yes" ; then - echo "CONFIG_VHOST_NET=y" >> $config_target_mak - fi --- -1.7.11.2 - diff --git a/0002-target-cris-Fix-buffer-overflow.patch b/0002-target-cris-Fix-buffer-overflow.patch new file mode 100644 index 0000000..79640b1 --- /dev/null +++ b/0002-target-cris-Fix-buffer-overflow.patch @@ -0,0 +1,35 @@ +From 8057ac10e8cba3acb89c11c94f04967306e55a9f Mon Sep 17 00:00:00 2001 +From: Stefan Weil +Date: Fri, 7 Sep 2012 22:36:08 +0200 +Subject: [PATCH] target-cris: Fix buffer overflow + +Report from smatch: + +target-cris/translate.c:3464 cpu_dump_state(32) error: + buffer overflow 'env->sregs' 4 <= 255 + +sregs is declared 'uint32_t sregs[4][16]', so the first index must be +less than 4 or ARRAY_SIZE(env->sregs). + +Signed-off-by: Stefan Weil +Signed-off-by: Michael Roth +--- + target-cris/translate.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/target-cris/translate.c b/target-cris/translate.c +index 1ad9ec7..ad31877 100644 +--- a/target-cris/translate.c ++++ b/target-cris/translate.c +@@ -3458,7 +3458,7 @@ void cpu_dump_state (CPUCRISState *env, FILE *f, fprintf_function cpu_fprintf, + } + srs = env->pregs[PR_SRS]; + cpu_fprintf(f, "\nsupport function regs bank %x:\n", srs); +- if (srs < 256) { ++ if (srs < ARRAY_SIZE(env->sregs)) { + for (i = 0; i < 16; i++) { + cpu_fprintf(f, "s%2.2d=%8.8x ", + i, env->sregs[srs][i]); +-- +1.7.12.1 + diff --git a/0003-target-xtensa-fix-missing-errno-codes-for-mingw32.patch b/0003-target-xtensa-fix-missing-errno-codes-for-mingw32.patch new file mode 100644 index 0000000..b5fdd18 --- /dev/null +++ b/0003-target-xtensa-fix-missing-errno-codes-for-mingw32.patch @@ -0,0 +1,64 @@ +From 33e25a4a6c6dc7632b15ee50637d33b4c3cf729e Mon Sep 17 00:00:00 2001 +From: Max Filippov +Date: Thu, 6 Sep 2012 04:36:46 +0400 +Subject: [PATCH] target-xtensa: fix missing errno codes for mingw32 + +Put the following errno value mappings under #ifdef: + +xtensa-semi.c: In function 'errno_h2g': +xtensa-semi.c:113: error: 'ENOTBLK' undeclared (first use in this function) +xtensa-semi.c:113: error: (Each undeclared identifier is reported only once +xtensa-semi.c:113: error: for each function it appears in.) +xtensa-semi.c:113: error: array index in initializer not of integer type +xtensa-semi.c:113: error: (near initialization for 'guest_errno') +xtensa-semi.c:124: error: 'ETXTBSY' undeclared (first use in this function) +xtensa-semi.c:124: error: array index in initializer not of integer type +xtensa-semi.c:124: error: (near initialization for 'guest_errno') +xtensa-semi.c:134: error: 'ELOOP' undeclared (first use in this function) +xtensa-semi.c:134: error: array index in initializer not of integer type +xtensa-semi.c:134: error: (near initialization for 'guest_errno') + +Signed-off-by: Max Filippov +Signed-off-by: Blue Swirl +Signed-off-by: Michael Roth +--- + target-xtensa/xtensa-semi.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/target-xtensa/xtensa-semi.c b/target-xtensa/xtensa-semi.c +index e745bef..52be07a 100644 +--- a/target-xtensa/xtensa-semi.c ++++ b/target-xtensa/xtensa-semi.c +@@ -110,7 +110,9 @@ static uint32_t errno_h2g(int host_errno) + [ENOMEM] = TARGET_ENOMEM, + [EACCES] = TARGET_EACCES, + [EFAULT] = TARGET_EFAULT, ++#ifdef ENOTBLK + [ENOTBLK] = TARGET_ENOTBLK, ++#endif + [EBUSY] = TARGET_EBUSY, + [EEXIST] = TARGET_EEXIST, + [EXDEV] = TARGET_EXDEV, +@@ -121,7 +123,9 @@ static uint32_t errno_h2g(int host_errno) + [ENFILE] = TARGET_ENFILE, + [EMFILE] = TARGET_EMFILE, + [ENOTTY] = TARGET_ENOTTY, ++#ifdef ETXTBSY + [ETXTBSY] = TARGET_ETXTBSY, ++#endif + [EFBIG] = TARGET_EFBIG, + [ENOSPC] = TARGET_ENOSPC, + [ESPIPE] = TARGET_ESPIPE, +@@ -131,7 +135,9 @@ static uint32_t errno_h2g(int host_errno) + [EDOM] = TARGET_EDOM, + [ERANGE] = TARGET_ERANGE, + [ENOSYS] = TARGET_ENOSYS, ++#ifdef ELOOP + [ELOOP] = TARGET_ELOOP, ++#endif + }; + + if (host_errno == 0) { +-- +1.7.12.1 + diff --git a/0004-target-sparc-fix-fcmp-s-d-q-instructions-wrt-excepti.patch b/0004-target-sparc-fix-fcmp-s-d-q-instructions-wrt-excepti.patch new file mode 100644 index 0000000..e6095aa --- /dev/null +++ b/0004-target-sparc-fix-fcmp-s-d-q-instructions-wrt-excepti.patch @@ -0,0 +1,133 @@ +From 5e955b895d4a92cdc49c7b4e76284483d49aa4b8 Mon Sep 17 00:00:00 2001 +From: Aurelien Jarno +Date: Fri, 7 Sep 2012 17:13:28 +0200 +Subject: [PATCH] target-sparc: fix fcmp{s,d,q} instructions wrt exception + +fcmp{s,d,q} instructions are supposed to ignore quiet NaN (contrary to +the fcmpe{s,d,q} instructions), but the current code is wrongly setting +the NV exception in that case. Moreover the current code is duplicated: +first the arguments are checked for NaN to generate an exception, and +later in case the comparison is unordered (which can only happens if one +of the argument is a NaN), the same check is done to generate an +exception. + +Fix that by calling clear_float_exceptions() followed by +check_ieee_exceptions() as for the other floating point instructions. +Use the _compare_quiet functions for fcmp{s,d,q} and the _compare ones +for fcmpe{s,d,q}. Simplify the flag setting by not clearing a flag that +is set the line just below. + +This fix allows the math glibc testsuite to pass. + +Cc: Blue Swirl +Signed-off-by: Aurelien Jarno +Signed-off-by: Blue Swirl +Signed-off-by: Michael Roth +--- + target-sparc/fop_helper.c | 67 +++++++++++++++++++---------------------------- + 1 file changed, 27 insertions(+), 40 deletions(-) + +diff --git a/target-sparc/fop_helper.c b/target-sparc/fop_helper.c +index 9c64ef8..f4b62a5 100644 +--- a/target-sparc/fop_helper.c ++++ b/target-sparc/fop_helper.c +@@ -334,34 +334,28 @@ void helper_fsqrtq(CPUSPARCState *env) + } + + #define GEN_FCMP(name, size, reg1, reg2, FS, E) \ +- void glue(helper_, name) (CPUSPARCState *env) \ ++ void glue(helper_, name) (CPUSPARCState *env) \ + { \ +- env->fsr &= FSR_FTT_NMASK; \ +- if (E && (glue(size, _is_any_nan)(reg1) || \ +- glue(size, _is_any_nan)(reg2)) && \ +- (env->fsr & FSR_NVM)) { \ +- env->fsr |= FSR_NVC; \ +- env->fsr |= FSR_FTT_IEEE_EXCP; \ +- helper_raise_exception(env, TT_FP_EXCP); \ ++ int ret; \ ++ clear_float_exceptions(env); \ ++ if (E) { \ ++ ret = glue(size, _compare)(reg1, reg2, &env->fp_status); \ ++ } else { \ ++ ret = glue(size, _compare_quiet)(reg1, reg2, \ ++ &env->fp_status); \ + } \ +- switch (glue(size, _compare) (reg1, reg2, &env->fp_status)) { \ ++ check_ieee_exceptions(env); \ ++ switch (ret) { \ + case float_relation_unordered: \ +- if ((env->fsr & FSR_NVM)) { \ +- env->fsr |= FSR_NVC; \ +- env->fsr |= FSR_FTT_IEEE_EXCP; \ +- helper_raise_exception(env, TT_FP_EXCP); \ +- } else { \ +- env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS); \ +- env->fsr |= (FSR_FCC1 | FSR_FCC0) << FS; \ +- env->fsr |= FSR_NVA; \ +- } \ ++ env->fsr |= (FSR_FCC1 | FSR_FCC0) << FS; \ ++ env->fsr |= FSR_NVA; \ + break; \ + case float_relation_less: \ +- env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS); \ ++ env->fsr &= ~(FSR_FCC1) << FS; \ + env->fsr |= FSR_FCC0 << FS; \ + break; \ + case float_relation_greater: \ +- env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS); \ ++ env->fsr &= ~(FSR_FCC0) << FS; \ + env->fsr |= FSR_FCC1 << FS; \ + break; \ + default: \ +@@ -370,34 +364,27 @@ void helper_fsqrtq(CPUSPARCState *env) + } \ + } + #define GEN_FCMP_T(name, size, FS, E) \ +- void glue(helper_, name)(CPUSPARCState *env, size src1, size src2) \ ++ void glue(helper_, name)(CPUSPARCState *env, size src1, size src2) \ + { \ +- env->fsr &= FSR_FTT_NMASK; \ +- if (E && (glue(size, _is_any_nan)(src1) || \ +- glue(size, _is_any_nan)(src2)) && \ +- (env->fsr & FSR_NVM)) { \ +- env->fsr |= FSR_NVC; \ +- env->fsr |= FSR_FTT_IEEE_EXCP; \ +- helper_raise_exception(env, TT_FP_EXCP); \ ++ int ret; \ ++ clear_float_exceptions(env); \ ++ if (E) { \ ++ ret = glue(size, _compare)(src1, src2, &env->fp_status); \ ++ } else { \ ++ ret = glue(size, _compare_quiet)(src1, src2, \ ++ &env->fp_status); \ + } \ +- switch (glue(size, _compare) (src1, src2, &env->fp_status)) { \ ++ check_ieee_exceptions(env); \ ++ switch (ret) { \ + case float_relation_unordered: \ +- if ((env->fsr & FSR_NVM)) { \ +- env->fsr |= FSR_NVC; \ +- env->fsr |= FSR_FTT_IEEE_EXCP; \ +- helper_raise_exception(env, TT_FP_EXCP); \ +- } else { \ +- env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS); \ +- env->fsr |= (FSR_FCC1 | FSR_FCC0) << FS; \ +- env->fsr |= FSR_NVA; \ +- } \ ++ env->fsr |= (FSR_FCC1 | FSR_FCC0) << FS; \ + break; \ + case float_relation_less: \ +- env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS); \ ++ env->fsr &= ~(FSR_FCC1 << FS); \ + env->fsr |= FSR_FCC0 << FS; \ + break; \ + case float_relation_greater: \ +- env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS); \ ++ env->fsr &= ~(FSR_FCC0 << FS); \ + env->fsr |= FSR_FCC1 << FS; \ + break; \ + default: \ +-- +1.7.12.1 + diff --git a/0005-target-s390x-fix-style.patch b/0005-target-s390x-fix-style.patch new file mode 100644 index 0000000..0f0a63e --- /dev/null +++ b/0005-target-s390x-fix-style.patch @@ -0,0 +1,1603 @@ +From 985b8342244b5f76ed1df75eb8757d6feff30316 Mon Sep 17 00:00:00 2001 +From: Blue Swirl +Date: Sun, 2 Sep 2012 07:33:30 +0000 +Subject: [PATCH] target-s390x: fix style + +Before splitting op_helper.c and helper.c in the next patches, +fix style issues. No functional changes. + +Replace also GCC specific __FUNCTION__ with +standard __func__. + +Don't init static variable (cpu_s390x_init:inited) with 0. + +Signed-off-by: Blue Swirl +Signed-off-by: Alexander Graf +Signed-off-by: Michael Roth +--- + target-s390x/helper.c | 96 ++++++----- + target-s390x/op_helper.c | 438 +++++++++++++++++++++++++++-------------------- + 2 files changed, 297 insertions(+), 237 deletions(-) + +diff --git a/target-s390x/helper.c b/target-s390x/helper.c +index d0a1180..d98e6d9 100644 +--- a/target-s390x/helper.c ++++ b/target-s390x/helper.c +@@ -74,7 +74,7 @@ S390CPU *cpu_s390x_init(const char *cpu_model) + { + S390CPU *cpu; + CPUS390XState *env; +- static int inited = 0; ++ static int inited; + + cpu = S390_CPU(object_new(TYPE_S390_CPU)); + env = &cpu->env; +@@ -91,25 +91,27 @@ S390CPU *cpu_s390x_init(const char *cpu_model) + + #if defined(CONFIG_USER_ONLY) + +-void do_interrupt (CPUS390XState *env) ++void do_interrupt(CPUS390XState *env) + { + env->exception_index = -1; + } + +-int cpu_s390x_handle_mmu_fault (CPUS390XState *env, target_ulong address, int rw, +- int mmu_idx) ++int cpu_s390x_handle_mmu_fault(CPUS390XState *env, target_ulong address, ++ int rw, int mmu_idx) + { +- /* fprintf(stderr,"%s: address 0x%lx rw %d mmu_idx %d\n", +- __FUNCTION__, address, rw, mmu_idx); */ ++ /* fprintf(stderr, "%s: address 0x%lx rw %d mmu_idx %d\n", ++ __func__, address, rw, mmu_idx); */ + env->exception_index = EXCP_ADDR; +- env->__excp_addr = address; /* FIXME: find out how this works on a real machine */ ++ /* FIXME: find out how this works on a real machine */ ++ env->__excp_addr = address; + return 1; + } + + #else /* !CONFIG_USER_ONLY */ + + /* Ensure to exit the TB after this call! */ +-static void trigger_pgm_exception(CPUS390XState *env, uint32_t code, uint32_t ilc) ++static void trigger_pgm_exception(CPUS390XState *env, uint32_t code, ++ uint32_t ilc) + { + env->exception_index = EXCP_PGM; + env->int_pgm_code = code; +@@ -138,19 +140,20 @@ static int trans_bits(CPUS390XState *env, uint64_t mode) + return bits; + } + +-static void trigger_prot_fault(CPUS390XState *env, target_ulong vaddr, uint64_t mode) ++static void trigger_prot_fault(CPUS390XState *env, target_ulong vaddr, ++ uint64_t mode) + { + int ilc = ILC_LATER_INC_2; + int bits = trans_bits(env, mode) | 4; + +- DPRINTF("%s: vaddr=%016" PRIx64 " bits=%d\n", __FUNCTION__, vaddr, bits); ++ DPRINTF("%s: vaddr=%016" PRIx64 " bits=%d\n", __func__, vaddr, bits); + + stq_phys(env->psa + offsetof(LowCore, trans_exc_code), vaddr | bits); + trigger_pgm_exception(env, PGM_PROTECTION, ilc); + } + +-static void trigger_page_fault(CPUS390XState *env, target_ulong vaddr, uint32_t type, +- uint64_t asc, int rw) ++static void trigger_page_fault(CPUS390XState *env, target_ulong vaddr, ++ uint32_t type, uint64_t asc, int rw) + { + int ilc = ILC_LATER; + int bits = trans_bits(env, asc); +@@ -160,26 +163,26 @@ static void trigger_page_fault(CPUS390XState *env, target_ulong vaddr, uint32_t + ilc = 2; + } + +- DPRINTF("%s: vaddr=%016" PRIx64 " bits=%d\n", __FUNCTION__, vaddr, bits); ++ DPRINTF("%s: vaddr=%016" PRIx64 " bits=%d\n", __func__, vaddr, bits); + + stq_phys(env->psa + offsetof(LowCore, trans_exc_code), vaddr | bits); + trigger_pgm_exception(env, type, ilc); + } + +-static int mmu_translate_asce(CPUS390XState *env, target_ulong vaddr, uint64_t asc, +- uint64_t asce, int level, target_ulong *raddr, +- int *flags, int rw) ++static int mmu_translate_asce(CPUS390XState *env, target_ulong vaddr, ++ uint64_t asc, uint64_t asce, int level, ++ target_ulong *raddr, int *flags, int rw) + { + uint64_t offs = 0; + uint64_t origin; + uint64_t new_asce; + +- PTE_DPRINTF("%s: 0x%" PRIx64 "\n", __FUNCTION__, asce); ++ PTE_DPRINTF("%s: 0x%" PRIx64 "\n", __func__, asce); + + if (((level != _ASCE_TYPE_SEGMENT) && (asce & _REGION_ENTRY_INV)) || + ((level == _ASCE_TYPE_SEGMENT) && (asce & _SEGMENT_ENTRY_INV))) { + /* XXX different regions have different faults */ +- DPRINTF("%s: invalid region\n", __FUNCTION__); ++ DPRINTF("%s: invalid region\n", __func__); + trigger_page_fault(env, vaddr, PGM_SEGMENT_TRANS, asc, rw); + return -1; + } +@@ -222,7 +225,7 @@ static int mmu_translate_asce(CPUS390XState *env, target_ulong vaddr, uint64_t a + + new_asce = ldq_phys(origin + offs); + PTE_DPRINTF("%s: 0x%" PRIx64 " + 0x%" PRIx64 " => 0x%016" PRIx64 "\n", +- __FUNCTION__, origin, offs, new_asce); ++ __func__, origin, offs, new_asce); + + if (level != _ASCE_TYPE_SEGMENT) { + /* yet another region */ +@@ -232,7 +235,7 @@ static int mmu_translate_asce(CPUS390XState *env, target_ulong vaddr, uint64_t a + + /* PTE */ + if (new_asce & _PAGE_INVALID) { +- DPRINTF("%s: PTE=0x%" PRIx64 " invalid\n", __FUNCTION__, new_asce); ++ DPRINTF("%s: PTE=0x%" PRIx64 " invalid\n", __func__, new_asce); + trigger_page_fault(env, vaddr, PGM_PAGE_TRANS, asc, rw); + return -1; + } +@@ -243,13 +246,14 @@ static int mmu_translate_asce(CPUS390XState *env, target_ulong vaddr, uint64_t a + + *raddr = new_asce & _ASCE_ORIGIN; + +- PTE_DPRINTF("%s: PTE=0x%" PRIx64 "\n", __FUNCTION__, new_asce); ++ PTE_DPRINTF("%s: PTE=0x%" PRIx64 "\n", __func__, new_asce); + + return 0; + } + +-static int mmu_translate_asc(CPUS390XState *env, target_ulong vaddr, uint64_t asc, +- target_ulong *raddr, int *flags, int rw) ++static int mmu_translate_asc(CPUS390XState *env, target_ulong vaddr, ++ uint64_t asc, target_ulong *raddr, int *flags, ++ int rw) + { + uint64_t asce = 0; + int level, new_level; +@@ -257,15 +261,15 @@ static int mmu_translate_asc(CPUS390XState *env, target_ulong vaddr, uint64_t as + + switch (asc) { + case PSW_ASC_PRIMARY: +- PTE_DPRINTF("%s: asc=primary\n", __FUNCTION__); ++ PTE_DPRINTF("%s: asc=primary\n", __func__); + asce = env->cregs[1]; + break; + case PSW_ASC_SECONDARY: +- PTE_DPRINTF("%s: asc=secondary\n", __FUNCTION__); ++ PTE_DPRINTF("%s: asc=secondary\n", __func__); + asce = env->cregs[7]; + break; + case PSW_ASC_HOME: +- PTE_DPRINTF("%s: asc=home\n", __FUNCTION__); ++ PTE_DPRINTF("%s: asc=home\n", __func__); + asce = env->cregs[13]; + break; + } +@@ -276,8 +280,7 @@ static int mmu_translate_asc(CPUS390XState *env, target_ulong vaddr, uint64_t as + case _ASCE_TYPE_REGION2: + if (vaddr & 0xffe0000000000000ULL) { + DPRINTF("%s: vaddr doesn't fit 0x%16" PRIx64 +- " 0xffe0000000000000ULL\n", __FUNCTION__, +- vaddr); ++ " 0xffe0000000000000ULL\n", __func__, vaddr); + trigger_page_fault(env, vaddr, PGM_TRANS_SPEC, asc, rw); + return -1; + } +@@ -285,8 +288,7 @@ static int mmu_translate_asc(CPUS390XState *env, target_ulong vaddr, uint64_t as + case _ASCE_TYPE_REGION3: + if (vaddr & 0xfffffc0000000000ULL) { + DPRINTF("%s: vaddr doesn't fit 0x%16" PRIx64 +- " 0xfffffc0000000000ULL\n", __FUNCTION__, +- vaddr); ++ " 0xfffffc0000000000ULL\n", __func__, vaddr); + trigger_page_fault(env, vaddr, PGM_TRANS_SPEC, asc, rw); + return -1; + } +@@ -294,8 +296,7 @@ static int mmu_translate_asc(CPUS390XState *env, target_ulong vaddr, uint64_t as + case _ASCE_TYPE_SEGMENT: + if (vaddr & 0xffffffff80000000ULL) { + DPRINTF("%s: vaddr doesn't fit 0x%16" PRIx64 +- " 0xffffffff80000000ULL\n", __FUNCTION__, +- vaddr); ++ " 0xffffffff80000000ULL\n", __func__, vaddr); + trigger_page_fault(env, vaddr, PGM_TRANS_SPEC, asc, rw); + return -1; + } +@@ -358,7 +359,7 @@ int mmu_translate(CPUS390XState *env, target_ulong vaddr, int rw, uint64_t asc, + break; + } + +-out: ++ out: + /* Convert real address -> absolute address */ + if (*raddr < 0x2000) { + *raddr = *raddr + env->psa; +@@ -378,18 +379,18 @@ out: + return r; + } + +-int cpu_s390x_handle_mmu_fault (CPUS390XState *env, target_ulong _vaddr, int rw, +- int mmu_idx) ++int cpu_s390x_handle_mmu_fault(CPUS390XState *env, target_ulong orig_vaddr, ++ int rw, int mmu_idx) + { + uint64_t asc = env->psw.mask & PSW_MASK_ASC; + target_ulong vaddr, raddr; + int prot; + + DPRINTF("%s: address 0x%" PRIx64 " rw %d mmu_idx %d\n", +- __FUNCTION__, _vaddr, rw, mmu_idx); ++ __func__, _vaddr, rw, mmu_idx); + +- _vaddr &= TARGET_PAGE_MASK; +- vaddr = _vaddr; ++ orig_vaddr &= TARGET_PAGE_MASK; ++ vaddr = orig_vaddr; + + /* 31-Bit mode */ + if (!(env->psw.mask & PSW_MASK_64)) { +@@ -403,22 +404,23 @@ int cpu_s390x_handle_mmu_fault (CPUS390XState *env, target_ulong _vaddr, int rw, + + /* check out of RAM access */ + if (raddr > (ram_size + virtio_size)) { +- DPRINTF("%s: aaddr %" PRIx64 " > ram_size %" PRIx64 "\n", __FUNCTION__, ++ DPRINTF("%s: aaddr %" PRIx64 " > ram_size %" PRIx64 "\n", __func__, + (uint64_t)aaddr, (uint64_t)ram_size); + trigger_pgm_exception(env, PGM_ADDRESSING, ILC_LATER); + return 1; + } + +- DPRINTF("%s: set tlb %" PRIx64 " -> %" PRIx64 " (%x)\n", __FUNCTION__, ++ DPRINTF("%s: set tlb %" PRIx64 " -> %" PRIx64 " (%x)\n", __func__, + (uint64_t)vaddr, (uint64_t)raddr, prot); + +- tlb_set_page(env, _vaddr, raddr, prot, ++ tlb_set_page(env, orig_vaddr, raddr, prot, + mmu_idx, TARGET_PAGE_SIZE); + + return 0; + } + +-target_phys_addr_t cpu_get_phys_page_debug(CPUS390XState *env, target_ulong vaddr) ++target_phys_addr_t cpu_get_phys_page_debug(CPUS390XState *env, ++ target_ulong vaddr) + { + target_ulong raddr; + int prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC; +@@ -509,7 +511,7 @@ static void do_program_interrupt(CPUS390XState *env) + break; + } + +- qemu_log("%s: code=0x%x ilc=%d\n", __FUNCTION__, env->int_pgm_code, ilc); ++ qemu_log("%s: code=0x%x ilc=%d\n", __func__, env->int_pgm_code, ilc); + + lowcore = cpu_physical_memory_map(env->psa, &len, 1); + +@@ -522,7 +524,7 @@ static void do_program_interrupt(CPUS390XState *env) + + cpu_physical_memory_unmap(lowcore, len, 1, len); + +- DPRINTF("%s: %x %x %" PRIx64 " %" PRIx64 "\n", __FUNCTION__, ++ DPRINTF("%s: %x %x %" PRIx64 " %" PRIx64 "\n", __func__, + env->int_pgm_code, ilc, env->psw.mask, + env->psw.addr); + +@@ -565,15 +567,15 @@ static void do_ext_interrupt(CPUS390XState *env) + env->pending_int &= ~INTERRUPT_EXT; + } + +- DPRINTF("%s: %" PRIx64 " %" PRIx64 "\n", __FUNCTION__, ++ DPRINTF("%s: %" PRIx64 " %" PRIx64 "\n", __func__, + env->psw.mask, env->psw.addr); + + load_psw(env, mask, addr); + } + +-void do_interrupt (CPUS390XState *env) ++void do_interrupt(CPUS390XState *env) + { +- qemu_log("%s: %d at pc=%" PRIx64 "\n", __FUNCTION__, env->exception_index, ++ qemu_log("%s: %d at pc=%" PRIx64 "\n", __func__, env->exception_index, + env->psw.addr); + + s390_add_running_cpu(env); +diff --git a/target-s390x/op_helper.c b/target-s390x/op_helper.c +index abc35dd..195e93e 100644 +--- a/target-s390x/op_helper.c ++++ b/target-s390x/op_helper.c +@@ -31,13 +31,13 @@ + #include + #endif + +-#if !defined (CONFIG_USER_ONLY) ++#if !defined(CONFIG_USER_ONLY) + #include "sysemu.h" + #endif + + /*****************************************************************************/ + /* Softmmu support */ +-#if !defined (CONFIG_USER_ONLY) ++#if !defined(CONFIG_USER_ONLY) + #include "softmmu_exec.h" + + #define MMUSUFFIX _mmu +@@ -95,7 +95,7 @@ void tlb_fill(CPUS390XState *env1, target_ulong addr, int is_write, int mmu_idx, + /* raise an exception */ + void HELPER(exception)(uint32_t excp) + { +- HELPER_LOG("%s: exception %d\n", __FUNCTION__, excp); ++ HELPER_LOG("%s: exception %d\n", __func__, excp); + env->exception_index = excp; + cpu_loop_exit(env); + } +@@ -164,7 +164,7 @@ uint32_t HELPER(nc)(uint32_t l, uint64_t dest, uint64_t src) + uint32_t cc = 0; + + HELPER_LOG("%s l %d dest %" PRIx64 " src %" PRIx64 "\n", +- __FUNCTION__, l, dest, src); ++ __func__, l, dest, src); + for (i = 0; i <= l; i++) { + x = ldub(dest + i) & ldub(src + i); + if (x) { +@@ -183,7 +183,7 @@ uint32_t HELPER(xc)(uint32_t l, uint64_t dest, uint64_t src) + uint32_t cc = 0; + + HELPER_LOG("%s l %d dest %" PRIx64 " src %" PRIx64 "\n", +- __FUNCTION__, l, dest, src); ++ __func__, l, dest, src); + + #ifndef CONFIG_USER_ONLY + /* xor with itself is the same as memset(0) */ +@@ -217,7 +217,7 @@ uint32_t HELPER(oc)(uint32_t l, uint64_t dest, uint64_t src) + uint32_t cc = 0; + + HELPER_LOG("%s l %d dest %" PRIx64 " src %" PRIx64 "\n", +- __FUNCTION__, l, dest, src); ++ __func__, l, dest, src); + for (i = 0; i <= l; i++) { + x = ldub(dest + i) | ldub(src + i); + if (x) { +@@ -236,7 +236,7 @@ void HELPER(mvc)(uint32_t l, uint64_t dest, uint64_t src) + uint32_t l_64 = (l + 1) / 8; + + HELPER_LOG("%s l %d dest %" PRIx64 " src %" PRIx64 "\n", +- __FUNCTION__, l, dest, src); ++ __func__, l, dest, src); + + #ifndef CONFIG_USER_ONLY + if ((l > 32) && +@@ -278,10 +278,11 @@ void HELPER(mvc)(uint32_t l, uint64_t dest, uint64_t src) + uint32_t HELPER(clc)(uint32_t l, uint64_t s1, uint64_t s2) + { + int i; +- unsigned char x,y; ++ unsigned char x, y; + uint32_t cc; ++ + HELPER_LOG("%s l %d s1 %" PRIx64 " s2 %" PRIx64 "\n", +- __FUNCTION__, l, s1, s2); ++ __func__, l, s1, s2); + for (i = 0; i <= l; i++) { + x = ldub(s1 + i); + y = ldub(s2 + i); +@@ -295,7 +296,7 @@ uint32_t HELPER(clc)(uint32_t l, uint64_t s1, uint64_t s2) + } + } + cc = 0; +-done: ++ done: + HELPER_LOG("\n"); + return cc; + } +@@ -303,9 +304,10 @@ done: + /* compare logical under mask */ + uint32_t HELPER(clm)(uint32_t r1, uint32_t mask, uint64_t addr) + { +- uint8_t r,d; ++ uint8_t r, d; + uint32_t cc; +- HELPER_LOG("%s: r1 0x%x mask 0x%x addr 0x%" PRIx64 "\n", __FUNCTION__, r1, ++ ++ HELPER_LOG("%s: r1 0x%x mask 0x%x addr 0x%" PRIx64 "\n", __func__, r1, + mask, addr); + cc = 0; + while (mask) { +@@ -313,7 +315,7 @@ uint32_t HELPER(clm)(uint32_t r1, uint32_t mask, uint64_t addr) + d = ldub(addr); + r = (r1 & 0xff000000UL) >> 24; + HELPER_LOG("mask 0x%x %02x/%02x (0x%" PRIx64 ") ", mask, r, d, +- addr); ++ addr); + if (r < d) { + cc = 1; + break; +@@ -334,7 +336,8 @@ uint32_t HELPER(clm)(uint32_t r1, uint32_t mask, uint64_t addr) + void HELPER(stcm)(uint32_t r1, uint32_t mask, uint64_t addr) + { + uint8_t r; +- HELPER_LOG("%s: r1 0x%x mask 0x%x addr 0x%lx\n", __FUNCTION__, r1, mask, ++ ++ HELPER_LOG("%s: r1 0x%x mask 0x%x addr 0x%lx\n", __func__, r1, mask, + addr); + while (mask) { + if (mask & 8) { +@@ -355,6 +358,7 @@ void HELPER(mlg)(uint32_t r1, uint64_t v2) + #if HOST_LONG_BITS == 64 && defined(__GNUC__) + /* assuming 64-bit hosts have __uint128_t */ + __uint128_t res = (__uint128_t)env->regs[r1 + 1]; ++ + res *= (__uint128_t)v2; + env->regs[r1] = (uint64_t)(res >> 64); + env->regs[r1 + 1] = (uint64_t)res; +@@ -370,18 +374,18 @@ void HELPER(dlg)(uint32_t r1, uint64_t v2) + + if (!env->regs[r1]) { + /* 64 -> 64/64 case */ +- env->regs[r1] = env->regs[r1+1] % divisor; +- env->regs[r1+1] = env->regs[r1+1] / divisor; ++ env->regs[r1] = env->regs[r1 + 1] % divisor; ++ env->regs[r1 + 1] = env->regs[r1 + 1] / divisor; + return; + } else { +- + #if HOST_LONG_BITS == 64 && defined(__GNUC__) + /* assuming 64-bit hosts have __uint128_t */ + __uint128_t dividend = (((__uint128_t)env->regs[r1]) << 64) | +- (env->regs[r1+1]); ++ (env->regs[r1 + 1]); + __uint128_t quotient = dividend / divisor; +- env->regs[r1+1] = quotient; + __uint128_t remainder = dividend % divisor; ++ ++ env->regs[r1 + 1] = quotient; + env->regs[r1] = remainder; + #else + /* 32-bit hosts would need special wrapper functionality - just abort if +@@ -431,7 +435,7 @@ uint32_t HELPER(srst)(uint32_t c, uint32_t r1, uint32_t r2) + uint64_t str = get_address_31fix(r2); + uint64_t end = get_address_31fix(r1); + +- HELPER_LOG("%s: c %d *r1 0x%" PRIx64 " *r2 0x%" PRIx64 "\n", __FUNCTION__, ++ HELPER_LOG("%s: c %d *r1 0x%" PRIx64 " *r2 0x%" PRIx64 "\n", __func__, + c, env->regs[r1], env->regs[r2]); + + for (i = str; i != end; i++) { +@@ -452,11 +456,12 @@ uint32_t HELPER(clst)(uint32_t c, uint32_t r1, uint32_t r2) + uint64_t s2 = get_address_31fix(r2); + uint8_t v1, v2; + uint32_t cc; ++ + c = c & 0xff; + #ifdef CONFIG_USER_ONLY + if (!c) { + HELPER_LOG("%s: comparing '%s' and '%s'\n", +- __FUNCTION__, (char*)g2h(s1), (char*)g2h(s2)); ++ __func__, (char *)g2h(s1), (char *)g2h(s2)); + } + #endif + for (;;) { +@@ -501,10 +506,11 @@ void HELPER(mvst)(uint32_t c, uint32_t r1, uint32_t r2) + uint64_t dest = get_address_31fix(r1); + uint64_t src = get_address_31fix(r2); + uint8_t v; ++ + c = c & 0xff; + #ifdef CONFIG_USER_ONLY + if (!c) { +- HELPER_LOG("%s: copy '%s' to 0x%lx\n", __FUNCTION__, (char*)g2h(src), ++ HELPER_LOG("%s: copy '%s' to 0x%lx\n", __func__, (char *)g2h(src), + dest); + } + #endif +@@ -526,6 +532,7 @@ uint32_t HELPER(csg)(uint32_t r1, uint64_t a2, uint32_t r3) + /* FIXME: locking? */ + uint32_t cc; + uint64_t v2 = ldq(a2); ++ + if (env->regs[r1] == v2) { + cc = 0; + stq(a2, env->regs[r3]); +@@ -564,8 +571,9 @@ uint32_t HELPER(cs)(uint32_t r1, uint64_t a2, uint32_t r3) + { + /* FIXME: locking? */ + uint32_t cc; +- HELPER_LOG("%s: r1 %d a2 0x%lx r3 %d\n", __FUNCTION__, r1, a2, r3); + uint32_t v2 = ldl(a2); ++ ++ HELPER_LOG("%s: r1 %d a2 0x%lx r3 %d\n", __func__, r1, a2, r3); + if (((uint32_t)env->regs[r1]) == v2) { + cc = 0; + stl(a2, (uint32_t)env->regs[r3]); +@@ -612,14 +620,16 @@ static uint32_t helper_icm(uint32_t r1, uint64_t address, uint32_t mask) + it does not change the program counter + in other words: tricky... + currently implemented by interpreting the cases it is most commonly used in +- */ ++*/ + uint32_t HELPER(ex)(uint32_t cc, uint64_t v1, uint64_t addr, uint64_t ret) + { + uint16_t insn = lduw_code(addr); +- HELPER_LOG("%s: v1 0x%lx addr 0x%lx insn 0x%x\n", __FUNCTION__, v1, addr, +- insn); ++ ++ HELPER_LOG("%s: v1 0x%lx addr 0x%lx insn 0x%x\n", __func__, v1, addr, ++ insn); + if ((insn & 0xf0ff) == 0xd000) { + uint32_t l, insn2, b1, b2, d1, d2; ++ + l = v1 & 0xff; + insn2 = ldl_code(addr + 2); + b1 = (insn2 >> 28) & 0xf; +@@ -645,13 +655,14 @@ uint32_t HELPER(ex)(uint32_t cc, uint64_t v1, uint64_t addr, uint64_t ret) + } + } else if ((insn & 0xff00) == 0x0a00) { + /* supervisor call */ +- HELPER_LOG("%s: svc %ld via execute\n", __FUNCTION__, (insn|v1) & 0xff); ++ HELPER_LOG("%s: svc %ld via execute\n", __func__, (insn | v1) & 0xff); + env->psw.addr = ret - 4; +- env->int_svc_code = (insn|v1) & 0xff; ++ env->int_svc_code = (insn | v1) & 0xff; + env->int_svc_ilc = 4; + helper_exception(EXCP_SVC); + } else if ((insn & 0xff00) == 0xbf00) { + uint32_t insn2, r1, r3, b2, d2; ++ + insn2 = ldl_code(addr + 2); + r1 = (insn2 >> 20) & 0xf; + r3 = (insn2 >> 16) & 0xf; +@@ -659,7 +670,7 @@ uint32_t HELPER(ex)(uint32_t cc, uint64_t v1, uint64_t addr, uint64_t ret) + d2 = insn2 & 0xfff; + cc = helper_icm(r1, get_address(0, b2, d2), r3); + } else { +-abort: ++ abort: + cpu_abort(env, "EXECUTE on instruction prefix 0x%x not implemented\n", + insn); + } +@@ -689,7 +700,7 @@ int32_t HELPER(nabs_i32)(int32_t val) + /* absolute value 64-bit */ + uint64_t HELPER(abs_i64)(int64_t val) + { +- HELPER_LOG("%s: val 0x%" PRIx64 "\n", __FUNCTION__, val); ++ HELPER_LOG("%s: val 0x%" PRIx64 "\n", __func__, val); + + if (val < 0) { + return -val; +@@ -774,9 +785,9 @@ void HELPER(ipm)(uint32_t cc, uint32_t r1) + uint64_t r = env->regs[r1]; + + r &= 0xffffffff00ffffffULL; +- r |= (cc << 28) | ( (env->psw.mask >> 40) & 0xf ); ++ r |= (cc << 28) | ((env->psw.mask >> 40) & 0xf); + env->regs[r1] = r; +- HELPER_LOG("%s: cc %d psw.mask 0x%lx r1 0x%lx\n", __FUNCTION__, ++ HELPER_LOG("%s: cc %d psw.mask 0x%lx r1 0x%lx\n", __func__, + cc, env->psw.mask, r); + } + +@@ -908,7 +919,7 @@ uint32_t HELPER(clcle)(uint32_t r1, uint64_t a2, uint32_t r3) + uint64_t srclen = env->regs[r3 + 1]; + uint64_t src = get_address_31fix(r3); + uint8_t pad = a2 & 0xff; +- uint8_t v1 = 0,v2 = 0; ++ uint8_t v1 = 0, v2 = 0; + uint32_t cc = 0; + + if (!(destlen || srclen)) { +@@ -1036,7 +1047,7 @@ static uint32_t set_cc_nz_f128(float128 v) + /* convert 32-bit int to 64-bit float */ + void HELPER(cdfbr)(uint32_t f1, int32_t v2) + { +- HELPER_LOG("%s: converting %d to f%d\n", __FUNCTION__, v2, f1); ++ HELPER_LOG("%s: converting %d to f%d\n", __func__, v2, f1); + env->fregs[f1].d = int32_to_float64(v2, &env->fpu_status); + } + +@@ -1044,6 +1055,7 @@ void HELPER(cdfbr)(uint32_t f1, int32_t v2) + void HELPER(cxfbr)(uint32_t f1, int32_t v2) + { + CPU_QuadU v1; ++ + v1.q = int32_to_float128(v2, &env->fpu_status); + env->fregs[f1].ll = v1.ll.upper; + env->fregs[f1 + 2].ll = v1.ll.lower; +@@ -1052,14 +1064,14 @@ void HELPER(cxfbr)(uint32_t f1, int32_t v2) + /* convert 64-bit int to 32-bit float */ + void HELPER(cegbr)(uint32_t f1, int64_t v2) + { +- HELPER_LOG("%s: converting %ld to f%d\n", __FUNCTION__, v2, f1); ++ HELPER_LOG("%s: converting %ld to f%d\n", __func__, v2, f1); + env->fregs[f1].l.upper = int64_to_float32(v2, &env->fpu_status); + } + + /* convert 64-bit int to 64-bit float */ + void HELPER(cdgbr)(uint32_t f1, int64_t v2) + { +- HELPER_LOG("%s: converting %ld to f%d\n", __FUNCTION__, v2, f1); ++ HELPER_LOG("%s: converting %ld to f%d\n", __func__, v2, f1); + env->fregs[f1].d = int64_to_float64(v2, &env->fpu_status); + } + +@@ -1067,8 +1079,9 @@ void HELPER(cdgbr)(uint32_t f1, int64_t v2) + void HELPER(cxgbr)(uint32_t f1, int64_t v2) + { + CPU_QuadU x1; ++ + x1.q = int64_to_float128(v2, &env->fpu_status); +- HELPER_LOG("%s: converted %ld to 0x%lx and 0x%lx\n", __FUNCTION__, v2, ++ HELPER_LOG("%s: converted %ld to 0x%lx and 0x%lx\n", __func__, v2, + x1.ll.upper, x1.ll.lower); + env->fregs[f1].ll = x1.ll.upper; + env->fregs[f1 + 2].ll = x1.ll.lower; +@@ -1078,7 +1091,7 @@ void HELPER(cxgbr)(uint32_t f1, int64_t v2) + void HELPER(cefbr)(uint32_t f1, int32_t v2) + { + env->fregs[f1].l.upper = int32_to_float32(v2, &env->fpu_status); +- HELPER_LOG("%s: converting %d to 0x%d in f%d\n", __FUNCTION__, v2, ++ HELPER_LOG("%s: converting %d to 0x%d in f%d\n", __func__, v2, + env->fregs[f1].l.upper, f1); + } + +@@ -1088,7 +1101,7 @@ uint32_t HELPER(aebr)(uint32_t f1, uint32_t f2) + env->fregs[f1].l.upper = float32_add(env->fregs[f1].l.upper, + env->fregs[f2].l.upper, + &env->fpu_status); +- HELPER_LOG("%s: adding 0x%d resulting in 0x%d in f%d\n", __FUNCTION__, ++ HELPER_LOG("%s: adding 0x%d resulting in 0x%d in f%d\n", __func__, + env->fregs[f2].l.upper, env->fregs[f1].l.upper, f1); + + return set_cc_nz_f32(env->fregs[f1].l.upper); +@@ -1099,7 +1112,7 @@ uint32_t HELPER(adbr)(uint32_t f1, uint32_t f2) + { + env->fregs[f1].d = float64_add(env->fregs[f1].d, env->fregs[f2].d, + &env->fpu_status); +- HELPER_LOG("%s: adding 0x%ld resulting in 0x%ld in f%d\n", __FUNCTION__, ++ HELPER_LOG("%s: adding 0x%ld resulting in 0x%ld in f%d\n", __func__, + env->fregs[f2].d, env->fregs[f1].d, f1); + + return set_cc_nz_f64(env->fregs[f1].d); +@@ -1111,7 +1124,7 @@ uint32_t HELPER(sebr)(uint32_t f1, uint32_t f2) + env->fregs[f1].l.upper = float32_sub(env->fregs[f1].l.upper, + env->fregs[f2].l.upper, + &env->fpu_status); +- HELPER_LOG("%s: adding 0x%d resulting in 0x%d in f%d\n", __FUNCTION__, ++ HELPER_LOG("%s: adding 0x%d resulting in 0x%d in f%d\n", __func__, + env->fregs[f2].l.upper, env->fregs[f1].l.upper, f1); + + return set_cc_nz_f32(env->fregs[f1].l.upper); +@@ -1123,7 +1136,7 @@ uint32_t HELPER(sdbr)(uint32_t f1, uint32_t f2) + env->fregs[f1].d = float64_sub(env->fregs[f1].d, env->fregs[f2].d, + &env->fpu_status); + HELPER_LOG("%s: subtracting 0x%ld resulting in 0x%ld in f%d\n", +- __FUNCTION__, env->fregs[f2].d, env->fregs[f1].d, f1); ++ __func__, env->fregs[f2].d, env->fregs[f1].d, f1); + + return set_cc_nz_f64(env->fregs[f1].d); + } +@@ -1140,12 +1153,13 @@ void HELPER(debr)(uint32_t f1, uint32_t f2) + void HELPER(dxbr)(uint32_t f1, uint32_t f2) + { + CPU_QuadU v1; ++ CPU_QuadU v2; ++ CPU_QuadU res; ++ + v1.ll.upper = env->fregs[f1].ll; + v1.ll.lower = env->fregs[f1 + 2].ll; +- CPU_QuadU v2; + v2.ll.upper = env->fregs[f2].ll; + v2.ll.lower = env->fregs[f2 + 2].ll; +- CPU_QuadU res; + res.q = float128_div(v1.q, v2.q, &env->fpu_status); + env->fregs[f1].ll = res.ll.upper; + env->fregs[f1 + 2].ll = res.ll.lower; +@@ -1162,12 +1176,13 @@ void HELPER(mdbr)(uint32_t f1, uint32_t f2) + void HELPER(mxbr)(uint32_t f1, uint32_t f2) + { + CPU_QuadU v1; ++ CPU_QuadU v2; ++ CPU_QuadU res; ++ + v1.ll.upper = env->fregs[f1].ll; + v1.ll.lower = env->fregs[f1 + 2].ll; +- CPU_QuadU v2; + v2.ll.upper = env->fregs[f2].ll; + v2.ll.lower = env->fregs[f2 + 2].ll; +- CPU_QuadU res; + res.q = float128_mul(v1.q, v2.q, &env->fpu_status); + env->fregs[f1].ll = res.ll.upper; + env->fregs[f1 + 2].ll = res.ll.lower; +@@ -1184,16 +1199,18 @@ void HELPER(ldebr)(uint32_t r1, uint32_t r2) + void HELPER(ldxbr)(uint32_t f1, uint32_t f2) + { + CPU_QuadU x2; ++ + x2.ll.upper = env->fregs[f2].ll; + x2.ll.lower = env->fregs[f2 + 2].ll; + env->fregs[f1].d = float128_to_float64(x2.q, &env->fpu_status); +- HELPER_LOG("%s: to 0x%ld\n", __FUNCTION__, env->fregs[f1].d); ++ HELPER_LOG("%s: to 0x%ld\n", __func__, env->fregs[f1].d); + } + + /* convert 64-bit float to 128-bit float */ + void HELPER(lxdbr)(uint32_t f1, uint32_t f2) + { + CPU_QuadU res; ++ + res.q = float64_to_float128(env->fregs[f2].d, &env->fpu_status); + env->fregs[f1].ll = res.ll.upper; + env->fregs[f1 + 2].ll = res.ll.lower; +@@ -1203,6 +1220,7 @@ void HELPER(lxdbr)(uint32_t f1, uint32_t f2) + void HELPER(ledbr)(uint32_t f1, uint32_t f2) + { + float64 d2 = env->fregs[f2].d; ++ + env->fregs[f1].l.upper = float64_to_float32(d2, &env->fpu_status); + } + +@@ -1210,10 +1228,11 @@ void HELPER(ledbr)(uint32_t f1, uint32_t f2) + void HELPER(lexbr)(uint32_t f1, uint32_t f2) + { + CPU_QuadU x2; ++ + x2.ll.upper = env->fregs[f2].ll; + x2.ll.lower = env->fregs[f2 + 2].ll; + env->fregs[f1].l.upper = float128_to_float32(x2.q, &env->fpu_status); +- HELPER_LOG("%s: to 0x%d\n", __FUNCTION__, env->fregs[f1].l.upper); ++ HELPER_LOG("%s: to 0x%d\n", __func__, env->fregs[f1].l.upper); + } + + /* absolute value of 32-bit float */ +@@ -1221,6 +1240,7 @@ uint32_t HELPER(lpebr)(uint32_t f1, uint32_t f2) + { + float32 v1; + float32 v2 = env->fregs[f2].d; ++ + v1 = float32_abs(v2); + env->fregs[f1].d = v1; + return set_cc_nz_f32(v1); +@@ -1231,6 +1251,7 @@ uint32_t HELPER(lpdbr)(uint32_t f1, uint32_t f2) + { + float64 v1; + float64 v2 = env->fregs[f2].d; ++ + v1 = float64_abs(v2); + env->fregs[f1].d = v1; + return set_cc_nz_f64(v1); +@@ -1241,6 +1262,7 @@ uint32_t HELPER(lpxbr)(uint32_t f1, uint32_t f2) + { + CPU_QuadU v1; + CPU_QuadU v2; ++ + v2.ll.upper = env->fregs[f2].ll; + v2.ll.lower = env->fregs[f2 + 2].ll; + v1.q = float128_abs(v2.q); +@@ -1267,6 +1289,7 @@ uint32_t HELPER(ltebr)(uint32_t f1, uint32_t f2) + uint32_t HELPER(ltxbr)(uint32_t f1, uint32_t f2) + { + CPU_QuadU x; ++ + x.ll.upper = env->fregs[f2].ll; + x.ll.lower = env->fregs[f2 + 2].ll; + env->fregs[f1].ll = x.ll.upper; +@@ -1294,6 +1317,7 @@ uint32_t HELPER(lcdbr)(uint32_t f1, uint32_t f2) + uint32_t HELPER(lcxbr)(uint32_t f1, uint32_t f2) + { + CPU_QuadU x1, x2; ++ + x2.ll.upper = env->fregs[f2].ll; + x2.ll.lower = env->fregs[f2 + 2].ll; + x1.q = float128_chs(x2.q); +@@ -1307,8 +1331,9 @@ void HELPER(aeb)(uint32_t f1, uint32_t val) + { + float32 v1 = env->fregs[f1].l.upper; + CPU_FloatU v2; ++ + v2.l = val; +- HELPER_LOG("%s: adding 0x%d from f%d and 0x%d\n", __FUNCTION__, ++ HELPER_LOG("%s: adding 0x%d from f%d and 0x%d\n", __func__, + v1, f1, v2.f); + env->fregs[f1].l.upper = float32_add(v1, v2.f, &env->fpu_status); + } +@@ -1318,8 +1343,9 @@ void HELPER(deb)(uint32_t f1, uint32_t val) + { + float32 v1 = env->fregs[f1].l.upper; + CPU_FloatU v2; ++ + v2.l = val; +- HELPER_LOG("%s: dividing 0x%d from f%d by 0x%d\n", __FUNCTION__, ++ HELPER_LOG("%s: dividing 0x%d from f%d by 0x%d\n", __func__, + v1, f1, v2.f); + env->fregs[f1].l.upper = float32_div(v1, v2.f, &env->fpu_status); + } +@@ -1329,8 +1355,9 @@ void HELPER(meeb)(uint32_t f1, uint32_t val) + { + float32 v1 = env->fregs[f1].l.upper; + CPU_FloatU v2; ++ + v2.l = val; +- HELPER_LOG("%s: multiplying 0x%d from f%d and 0x%d\n", __FUNCTION__, ++ HELPER_LOG("%s: multiplying 0x%d from f%d and 0x%d\n", __func__, + v1, f1, v2.f); + env->fregs[f1].l.upper = float32_mul(v1, v2.f, &env->fpu_status); + } +@@ -1340,7 +1367,8 @@ uint32_t HELPER(cebr)(uint32_t f1, uint32_t f2) + { + float32 v1 = env->fregs[f1].l.upper; + float32 v2 = env->fregs[f2].l.upper; +- HELPER_LOG("%s: comparing 0x%d from f%d and 0x%d\n", __FUNCTION__, ++ ++ HELPER_LOG("%s: comparing 0x%d from f%d and 0x%d\n", __func__, + v1, f1, v2); + return set_cc_f32(v1, v2); + } +@@ -1350,7 +1378,8 @@ uint32_t HELPER(cdbr)(uint32_t f1, uint32_t f2) + { + float64 v1 = env->fregs[f1].d; + float64 v2 = env->fregs[f2].d; +- HELPER_LOG("%s: comparing 0x%ld from f%d and 0x%ld\n", __FUNCTION__, ++ ++ HELPER_LOG("%s: comparing 0x%ld from f%d and 0x%ld\n", __func__, + v1, f1, v2); + return set_cc_f64(v1, v2); + } +@@ -1359,14 +1388,15 @@ uint32_t HELPER(cdbr)(uint32_t f1, uint32_t f2) + uint32_t HELPER(cxbr)(uint32_t f1, uint32_t f2) + { + CPU_QuadU v1; ++ CPU_QuadU v2; ++ + v1.ll.upper = env->fregs[f1].ll; + v1.ll.lower = env->fregs[f1 + 2].ll; +- CPU_QuadU v2; + v2.ll.upper = env->fregs[f2].ll; + v2.ll.lower = env->fregs[f2 + 2].ll; + + return float_comp_to_cc(float128_compare_quiet(v1.q, v2.q, +- &env->fpu_status)); ++ &env->fpu_status)); + } + + /* 64-bit FP compare RM */ +@@ -1374,8 +1404,9 @@ uint32_t HELPER(cdb)(uint32_t f1, uint64_t a2) + { + float64 v1 = env->fregs[f1].d; + CPU_DoubleU v2; ++ + v2.ll = ldq(a2); +- HELPER_LOG("%s: comparing 0x%ld from f%d and 0x%lx\n", __FUNCTION__, v1, ++ HELPER_LOG("%s: comparing 0x%ld from f%d and 0x%lx\n", __func__, v1, + f1, v2.d); + return set_cc_f64(v1, v2.d); + } +@@ -1385,8 +1416,9 @@ uint32_t HELPER(adb)(uint32_t f1, uint64_t a2) + { + float64 v1 = env->fregs[f1].d; + CPU_DoubleU v2; ++ + v2.ll = ldq(a2); +- HELPER_LOG("%s: adding 0x%lx from f%d and 0x%lx\n", __FUNCTION__, ++ HELPER_LOG("%s: adding 0x%lx from f%d and 0x%lx\n", __func__, + v1, f1, v2.d); + env->fregs[f1].d = v1 = float64_add(v1, v2.d, &env->fpu_status); + return set_cc_nz_f64(v1); +@@ -1397,6 +1429,7 @@ void HELPER(seb)(uint32_t f1, uint32_t val) + { + float32 v1 = env->fregs[f1].l.upper; + CPU_FloatU v2; ++ + v2.l = val; + env->fregs[f1].l.upper = float32_sub(v1, v2.f, &env->fpu_status); + } +@@ -1406,6 +1439,7 @@ uint32_t HELPER(sdb)(uint32_t f1, uint64_t a2) + { + float64 v1 = env->fregs[f1].d; + CPU_DoubleU v2; ++ + v2.ll = ldq(a2); + env->fregs[f1].d = v1 = float64_sub(v1, v2.d, &env->fpu_status); + return set_cc_nz_f64(v1); +@@ -1416,8 +1450,9 @@ void HELPER(mdb)(uint32_t f1, uint64_t a2) + { + float64 v1 = env->fregs[f1].d; + CPU_DoubleU v2; ++ + v2.ll = ldq(a2); +- HELPER_LOG("%s: multiplying 0x%lx from f%d and 0x%ld\n", __FUNCTION__, ++ HELPER_LOG("%s: multiplying 0x%lx from f%d and 0x%ld\n", __func__, + v1, f1, v2.d); + env->fregs[f1].d = float64_mul(v1, v2.d, &env->fpu_status); + } +@@ -1427,8 +1462,9 @@ void HELPER(ddb)(uint32_t f1, uint64_t a2) + { + float64 v1 = env->fregs[f1].d; + CPU_DoubleU v2; ++ + v2.ll = ldq(a2); +- HELPER_LOG("%s: dividing 0x%lx from f%d by 0x%ld\n", __FUNCTION__, ++ HELPER_LOG("%s: dividing 0x%lx from f%d by 0x%ld\n", __func__, + v1, f1, v2.d); + env->fregs[f1].d = float64_div(v1, v2.d, &env->fpu_status); + } +@@ -1464,6 +1500,7 @@ static void set_round_mode(int m3) + uint32_t HELPER(cgebr)(uint32_t r1, uint32_t f2, uint32_t m3) + { + float32 v2 = env->fregs[f2].l.upper; ++ + set_round_mode(m3); + env->regs[r1] = float32_to_int64(v2, &env->fpu_status); + return set_cc_nz_f32(v2); +@@ -1473,6 +1510,7 @@ uint32_t HELPER(cgebr)(uint32_t r1, uint32_t f2, uint32_t m3) + uint32_t HELPER(cgdbr)(uint32_t r1, uint32_t f2, uint32_t m3) + { + float64 v2 = env->fregs[f2].d; ++ + set_round_mode(m3); + env->regs[r1] = float64_to_int64(v2, &env->fpu_status); + return set_cc_nz_f64(v2); +@@ -1482,6 +1520,7 @@ uint32_t HELPER(cgdbr)(uint32_t r1, uint32_t f2, uint32_t m3) + uint32_t HELPER(cgxbr)(uint32_t r1, uint32_t f2, uint32_t m3) + { + CPU_QuadU v2; ++ + v2.ll.upper = env->fregs[f2].ll; + v2.ll.lower = env->fregs[f2 + 2].ll; + set_round_mode(m3); +@@ -1501,9 +1540,10 @@ uint32_t HELPER(cgxbr)(uint32_t r1, uint32_t f2, uint32_t m3) + uint32_t HELPER(cfebr)(uint32_t r1, uint32_t f2, uint32_t m3) + { + float32 v2 = env->fregs[f2].l.upper; ++ + set_round_mode(m3); + env->regs[r1] = (env->regs[r1] & 0xffffffff00000000ULL) | +- float32_to_int32(v2, &env->fpu_status); ++ float32_to_int32(v2, &env->fpu_status); + return set_cc_nz_f32(v2); + } + +@@ -1511,9 +1551,10 @@ uint32_t HELPER(cfebr)(uint32_t r1, uint32_t f2, uint32_t m3) + uint32_t HELPER(cfdbr)(uint32_t r1, uint32_t f2, uint32_t m3) + { + float64 v2 = env->fregs[f2].d; ++ + set_round_mode(m3); + env->regs[r1] = (env->regs[r1] & 0xffffffff00000000ULL) | +- float64_to_int32(v2, &env->fpu_status); ++ float64_to_int32(v2, &env->fpu_status); + return set_cc_nz_f64(v2); + } + +@@ -1521,10 +1562,11 @@ uint32_t HELPER(cfdbr)(uint32_t r1, uint32_t f2, uint32_t m3) + uint32_t HELPER(cfxbr)(uint32_t r1, uint32_t f2, uint32_t m3) + { + CPU_QuadU v2; ++ + v2.ll.upper = env->fregs[f2].ll; + v2.ll.lower = env->fregs[f2 + 2].ll; + env->regs[r1] = (env->regs[r1] & 0xffffffff00000000ULL) | +- float128_to_int32(v2.q, &env->fpu_status); ++ float128_to_int32(v2.q, &env->fpu_status); + return set_cc_nz_f128(v2.q); + } + +@@ -1544,6 +1586,7 @@ void HELPER(lzdr)(uint32_t f1) + void HELPER(lzxr)(uint32_t f1) + { + CPU_QuadU x; ++ + x.q = float64_to_float128(float64_zero, &env->fpu_status); + env->fregs[f1].ll = x.ll.upper; + env->fregs[f1 + 1].ll = x.ll.lower; +@@ -1553,12 +1596,13 @@ void HELPER(lzxr)(uint32_t f1) + uint32_t HELPER(sxbr)(uint32_t f1, uint32_t f2) + { + CPU_QuadU v1; ++ CPU_QuadU v2; ++ CPU_QuadU res; ++ + v1.ll.upper = env->fregs[f1].ll; + v1.ll.lower = env->fregs[f1 + 2].ll; +- CPU_QuadU v2; + v2.ll.upper = env->fregs[f2].ll; + v2.ll.lower = env->fregs[f2 + 2].ll; +- CPU_QuadU res; + res.q = float128_sub(v1.q, v2.q, &env->fpu_status); + env->fregs[f1].ll = res.ll.upper; + env->fregs[f1 + 2].ll = res.ll.lower; +@@ -1569,12 +1613,13 @@ uint32_t HELPER(sxbr)(uint32_t f1, uint32_t f2) + uint32_t HELPER(axbr)(uint32_t f1, uint32_t f2) + { + CPU_QuadU v1; ++ CPU_QuadU v2; ++ CPU_QuadU res; ++ + v1.ll.upper = env->fregs[f1].ll; + v1.ll.lower = env->fregs[f1 + 2].ll; +- CPU_QuadU v2; + v2.ll.upper = env->fregs[f2].ll; + v2.ll.lower = env->fregs[f2 + 2].ll; +- CPU_QuadU res; + res.q = float128_add(v1.q, v2.q, &env->fpu_status); + env->fregs[f1].ll = res.ll.upper; + env->fregs[f1 + 2].ll = res.ll.lower; +@@ -1599,8 +1644,9 @@ void HELPER(ddbr)(uint32_t f1, uint32_t f2) + /* 64-bit FP multiply and add RM */ + void HELPER(madb)(uint32_t f1, uint64_t a2, uint32_t f3) + { +- HELPER_LOG("%s: f1 %d a2 0x%lx f3 %d\n", __FUNCTION__, f1, a2, f3); + CPU_DoubleU v2; ++ ++ HELPER_LOG("%s: f1 %d a2 0x%lx f3 %d\n", __func__, f1, a2, f3); + v2.ll = ldq(a2); + env->fregs[f1].d = float64_add(env->fregs[f1].d, + float64_mul(v2.d, env->fregs[f3].d, +@@ -1611,7 +1657,7 @@ void HELPER(madb)(uint32_t f1, uint64_t a2, uint32_t f3) + /* 64-bit FP multiply and add RR */ + void HELPER(madbr)(uint32_t f1, uint32_t f3, uint32_t f2) + { +- HELPER_LOG("%s: f1 %d f2 %d f3 %d\n", __FUNCTION__, f1, f2, f3); ++ HELPER_LOG("%s: f1 %d f2 %d f3 %d\n", __func__, f1, f2, f3); + env->fregs[f1].d = float64_add(float64_mul(env->fregs[f2].d, + env->fregs[f3].d, + &env->fpu_status), +@@ -1621,7 +1667,7 @@ void HELPER(madbr)(uint32_t f1, uint32_t f3, uint32_t f2) + /* 64-bit FP multiply and subtract RR */ + void HELPER(msdbr)(uint32_t f1, uint32_t f3, uint32_t f2) + { +- HELPER_LOG("%s: f1 %d f2 %d f3 %d\n", __FUNCTION__, f1, f2, f3); ++ HELPER_LOG("%s: f1 %d f2 %d f3 %d\n", __func__, f1, f2, f3); + env->fregs[f1].d = float64_sub(float64_mul(env->fregs[f2].d, + env->fregs[f3].d, + &env->fpu_status), +@@ -1642,6 +1688,7 @@ void HELPER(maebr)(uint32_t f1, uint32_t f3, uint32_t f2) + void HELPER(ldeb)(uint32_t f1, uint64_t a2) + { + uint32_t v2; ++ + v2 = ldl(a2); + env->fregs[f1].d = float32_to_float64(v2, + &env->fpu_status); +@@ -1651,8 +1698,9 @@ void HELPER(ldeb)(uint32_t f1, uint64_t a2) + void HELPER(lxdb)(uint32_t f1, uint64_t a2) + { + CPU_DoubleU v2; +- v2.ll = ldq(a2); + CPU_QuadU v1; ++ ++ v2.ll = ldq(a2); + v1.q = float64_to_float128(v2.d, &env->fpu_status); + env->fregs[f1].ll = v1.ll.upper; + env->fregs[f1 + 2].ll = v1.ll.lower; +@@ -1665,7 +1713,7 @@ uint32_t HELPER(tceb)(uint32_t f1, uint64_t m2) + int neg = float32_is_neg(v1); + uint32_t cc = 0; + +- HELPER_LOG("%s: v1 0x%lx m2 0x%lx neg %d\n", __FUNCTION__, (long)v1, m2, neg); ++ HELPER_LOG("%s: v1 0x%lx m2 0x%lx neg %d\n", __func__, (long)v1, m2, neg); + if ((float32_is_zero(v1) && (m2 & (1 << (11-neg)))) || + (float32_is_infinity(v1) && (m2 & (1 << (5-neg)))) || + (float32_is_any_nan(v1) && (m2 & (1 << (3-neg)))) || +@@ -1687,7 +1735,7 @@ uint32_t HELPER(tcdb)(uint32_t f1, uint64_t m2) + int neg = float64_is_neg(v1); + uint32_t cc = 0; + +- HELPER_LOG("%s: v1 0x%lx m2 0x%lx neg %d\n", __FUNCTION__, v1, m2, neg); ++ HELPER_LOG("%s: v1 0x%lx m2 0x%lx neg %d\n", __func__, v1, m2, neg); + if ((float64_is_zero(v1) && (m2 & (1 << (11-neg)))) || + (float64_is_infinity(v1) && (m2 & (1 << (5-neg)))) || + (float64_is_any_nan(v1) && (m2 & (1 << (3-neg)))) || +@@ -1706,10 +1754,12 @@ uint32_t HELPER(tcxb)(uint32_t f1, uint64_t m2) + { + CPU_QuadU v1; + uint32_t cc = 0; ++ int neg; ++ + v1.ll.upper = env->fregs[f1].ll; + v1.ll.lower = env->fregs[f1 + 2].ll; + +- int neg = float128_is_neg(v1.q); ++ neg = float128_is_neg(v1.q); + if ((float128_is_zero(v1.q) && (m2 & (1 << (11-neg)))) || + (float128_is_infinity(v1.q) && (m2 & (1 << (5-neg)))) || + (float128_is_any_nan(v1.q) && (m2 & (1 << (3-neg)))) || +@@ -1787,7 +1837,7 @@ void HELPER(cksm)(uint32_t r1, uint32_t r2) + + /* store result */ + env->regs[r1] = (env->regs[r1] & 0xffffffff00000000ULL) | +- ((uint32_t)cksm + (cksm >> 32)); ++ ((uint32_t)cksm + (cksm >> 32)); + } + + static inline uint32_t cc_calc_ltgt_32(CPUS390XState *env, int32_t src, +@@ -1848,10 +1898,12 @@ static inline uint32_t cc_calc_ltugtu_64(CPUS390XState *env, uint64_t src, + } + } + +-static inline uint32_t cc_calc_tm_32(CPUS390XState *env, uint32_t val, uint32_t mask) ++static inline uint32_t cc_calc_tm_32(CPUS390XState *env, uint32_t val, ++ uint32_t mask) + { +- HELPER_LOG("%s: val 0x%x mask 0x%x\n", __FUNCTION__, val, mask); + uint16_t r = val & mask; ++ ++ HELPER_LOG("%s: val 0x%x mask 0x%x\n", __func__, val, mask); + if (r == 0 || mask == 0) { + return 0; + } else if (r == mask) { +@@ -1862,10 +1914,12 @@ static inline uint32_t cc_calc_tm_32(CPUS390XState *env, uint32_t val, uint32_t + } + + /* set condition code for test under mask */ +-static inline uint32_t cc_calc_tm_64(CPUS390XState *env, uint64_t val, uint32_t mask) ++static inline uint32_t cc_calc_tm_64(CPUS390XState *env, uint64_t val, ++ uint32_t mask) + { + uint16_t r = val & mask; +- HELPER_LOG("%s: val 0x%lx mask 0x%x r 0x%x\n", __FUNCTION__, val, mask, r); ++ ++ HELPER_LOG("%s: val 0x%lx mask 0x%x r 0x%x\n", __func__, val, mask, r); + if (r == 0 || mask == 0) { + return 0; + } else if (r == mask) { +@@ -1888,8 +1942,8 @@ static inline uint32_t cc_calc_nz(CPUS390XState *env, uint64_t dst) + return !!dst; + } + +-static inline uint32_t cc_calc_add_64(CPUS390XState *env, int64_t a1, int64_t a2, +- int64_t ar) ++static inline uint32_t cc_calc_add_64(CPUS390XState *env, int64_t a1, ++ int64_t a2, int64_t ar) + { + if ((a1 > 0 && a2 > 0 && ar < 0) || (a1 < 0 && a2 < 0 && ar > 0)) { + return 3; /* overflow */ +@@ -1904,8 +1958,8 @@ static inline uint32_t cc_calc_add_64(CPUS390XState *env, int64_t a1, int64_t a2 + } + } + +-static inline uint32_t cc_calc_addu_64(CPUS390XState *env, uint64_t a1, uint64_t a2, +- uint64_t ar) ++static inline uint32_t cc_calc_addu_64(CPUS390XState *env, uint64_t a1, ++ uint64_t a2, uint64_t ar) + { + if (ar == 0) { + if (a1) { +@@ -1915,15 +1969,15 @@ static inline uint32_t cc_calc_addu_64(CPUS390XState *env, uint64_t a1, uint64_t + } + } else { + if (ar < a1 || ar < a2) { +- return 3; ++ return 3; + } else { +- return 1; ++ return 1; + } + } + } + +-static inline uint32_t cc_calc_sub_64(CPUS390XState *env, int64_t a1, int64_t a2, +- int64_t ar) ++static inline uint32_t cc_calc_sub_64(CPUS390XState *env, int64_t a1, ++ int64_t a2, int64_t ar) + { + if ((a1 > 0 && a2 < 0 && ar < 0) || (a1 < 0 && a2 > 0 && ar > 0)) { + return 3; /* overflow */ +@@ -1938,8 +1992,8 @@ static inline uint32_t cc_calc_sub_64(CPUS390XState *env, int64_t a1, int64_t a2 + } + } + +-static inline uint32_t cc_calc_subu_64(CPUS390XState *env, uint64_t a1, uint64_t a2, +- uint64_t ar) ++static inline uint32_t cc_calc_subu_64(CPUS390XState *env, uint64_t a1, ++ uint64_t a2, uint64_t ar) + { + if (ar == 0) { + return 2; +@@ -1982,8 +2036,8 @@ static inline uint32_t cc_calc_comp_64(CPUS390XState *env, int64_t dst) + } + + +-static inline uint32_t cc_calc_add_32(CPUS390XState *env, int32_t a1, int32_t a2, +- int32_t ar) ++static inline uint32_t cc_calc_add_32(CPUS390XState *env, int32_t a1, ++ int32_t a2, int32_t ar) + { + if ((a1 > 0 && a2 > 0 && ar < 0) || (a1 < 0 && a2 < 0 && ar > 0)) { + return 3; /* overflow */ +@@ -1998,26 +2052,26 @@ static inline uint32_t cc_calc_add_32(CPUS390XState *env, int32_t a1, int32_t a2 + } + } + +-static inline uint32_t cc_calc_addu_32(CPUS390XState *env, uint32_t a1, uint32_t a2, +- uint32_t ar) ++static inline uint32_t cc_calc_addu_32(CPUS390XState *env, uint32_t a1, ++ uint32_t a2, uint32_t ar) + { + if (ar == 0) { + if (a1) { +- return 2; ++ return 2; + } else { +- return 0; ++ return 0; + } + } else { + if (ar < a1 || ar < a2) { +- return 3; ++ return 3; + } else { +- return 1; ++ return 1; + } + } + } + +-static inline uint32_t cc_calc_sub_32(CPUS390XState *env, int32_t a1, int32_t a2, +- int32_t ar) ++static inline uint32_t cc_calc_sub_32(CPUS390XState *env, int32_t a1, ++ int32_t a2, int32_t ar) + { + if ((a1 > 0 && a2 < 0 && ar < 0) || (a1 < 0 && a2 > 0 && ar > 0)) { + return 3; /* overflow */ +@@ -2032,8 +2086,8 @@ static inline uint32_t cc_calc_sub_32(CPUS390XState *env, int32_t a1, int32_t a2 + } + } + +-static inline uint32_t cc_calc_subu_32(CPUS390XState *env, uint32_t a1, uint32_t a2, +- uint32_t ar) ++static inline uint32_t cc_calc_subu_32(CPUS390XState *env, uint32_t a1, ++ uint32_t a2, uint32_t ar) + { + if (ar == 0) { + return 2; +@@ -2076,11 +2130,12 @@ static inline uint32_t cc_calc_comp_32(CPUS390XState *env, int32_t dst) + } + + /* calculate condition code for insert character under mask insn */ +-static inline uint32_t cc_calc_icm_32(CPUS390XState *env, uint32_t mask, uint32_t val) ++static inline uint32_t cc_calc_icm_32(CPUS390XState *env, uint32_t mask, ++ uint32_t val) + { +- HELPER_LOG("%s: mask 0x%x val %d\n", __FUNCTION__, mask, val); + uint32_t cc; + ++ HELPER_LOG("%s: mask 0x%x val %d\n", __func__, mask, val); + if (mask == 0xf) { + if (!val) { + return 0; +@@ -2107,7 +2162,8 @@ static inline uint32_t cc_calc_icm_32(CPUS390XState *env, uint32_t mask, uint32_ + return cc; + } + +-static inline uint32_t cc_calc_slag(CPUS390XState *env, uint64_t src, uint64_t shift) ++static inline uint32_t cc_calc_slag(CPUS390XState *env, uint64_t src, ++ uint64_t shift) + { + uint64_t mask = ((1ULL << shift) - 1ULL) << (64 - shift); + uint64_t match, r; +@@ -2136,8 +2192,8 @@ static inline uint32_t cc_calc_slag(CPUS390XState *env, uint64_t src, uint64_t s + } + + +-static inline uint32_t do_calc_cc(CPUS390XState *env, uint32_t cc_op, uint64_t src, +- uint64_t dst, uint64_t vr) ++static inline uint32_t do_calc_cc(CPUS390XState *env, uint32_t cc_op, ++ uint64_t src, uint64_t dst, uint64_t vr) + { + uint32_t r = 0; + +@@ -2244,7 +2300,7 @@ static inline uint32_t do_calc_cc(CPUS390XState *env, uint32_t cc_op, uint64_t s + cpu_abort(env, "Unknown CC operation: %s\n", cc_name(cc_op)); + } + +- HELPER_LOG("%s: %15s 0x%016lx 0x%016lx 0x%016lx = %d\n", __FUNCTION__, ++ HELPER_LOG("%s: %15s 0x%016lx 0x%016lx 0x%016lx = %d\n", __func__, + cc_name(cc_op), src, dst, vr, r); + return r; + } +@@ -2334,6 +2390,7 @@ void HELPER(tr)(uint32_t len, uint64_t array, uint64_t trans) + for (i = 0; i <= len; i++) { + uint8_t byte = ldub(array + i); + uint8_t new_byte = ldub(trans + byte); ++ + stb(array + i, new_byte); + } + } +@@ -2363,7 +2420,7 @@ static void program_interrupt(CPUS390XState *env, uint32_t code, int ilc) + } + + /* +- * ret < 0 indicates program check, ret = 0,1,2,3 -> cc ++ * ret < 0 indicates program check, ret = 0, 1, 2, 3 -> cc + */ + int sclp_service_call(CPUS390XState *env, uint32_t sccb, uint64_t code) + { +@@ -2382,24 +2439,24 @@ int sclp_service_call(CPUS390XState *env, uint32_t sccb, uint64_t code) + return -PGM_SPECIFICATION; + } + +- switch(code) { +- case SCLP_CMDW_READ_SCP_INFO: +- case SCLP_CMDW_READ_SCP_INFO_FORCED: +- while ((ram_size >> (20 + shift)) > 65535) { +- shift++; +- } +- stw_phys(sccb + SCP_MEM_CODE, ram_size >> (20 + shift)); +- stb_phys(sccb + SCP_INCREMENT, 1 << shift); +- stw_phys(sccb + SCP_RESPONSE_CODE, 0x10); ++ switch (code) { ++ case SCLP_CMDW_READ_SCP_INFO: ++ case SCLP_CMDW_READ_SCP_INFO_FORCED: ++ while ((ram_size >> (20 + shift)) > 65535) { ++ shift++; ++ } ++ stw_phys(sccb + SCP_MEM_CODE, ram_size >> (20 + shift)); ++ stb_phys(sccb + SCP_INCREMENT, 1 << shift); ++ stw_phys(sccb + SCP_RESPONSE_CODE, 0x10); + +- s390_sclp_extint(sccb & ~3); +- break; +- default: ++ s390_sclp_extint(sccb & ~3); ++ break; ++ default: + #ifdef DEBUG_HELPER +- printf("KVM: invalid sclp call 0x%x / 0x%" PRIx64 "x\n", sccb, code); ++ printf("KVM: invalid sclp call 0x%x / 0x%" PRIx64 "x\n", sccb, code); + #endif +- r = 3; +- break; ++ r = 3; ++ break; + } + + return r; +@@ -2479,7 +2536,7 @@ static inline uint64_t clock_value(CPUS390XState *env) + uint64_t time; + + time = env->tod_offset + +- time2tod(qemu_get_clock_ns(vm_clock) - env->tod_basetime); ++ time2tod(qemu_get_clock_ns(vm_clock) - env->tod_basetime); + + return time; + } +@@ -2503,7 +2560,6 @@ uint32_t HELPER(stcke)(uint64_t a1) + /* XXX programmable fields */ + stw(a1 + 17, 0); + +- + return 0; + } + +@@ -2584,7 +2640,7 @@ uint32_t HELPER(stsi)(uint64_t a0, uint32_t r0, uint32_t r1) + ebcdic_put(sysib.model, "QEMU ", 16); + ebcdic_put(sysib.sequence, "QEMU ", 16); + ebcdic_put(sysib.plant, "QEMU", 4); +- cpu_physical_memory_rw(a0, (uint8_t*)&sysib, sizeof(sysib), 1); ++ cpu_physical_memory_rw(a0, (uint8_t *)&sysib, sizeof(sysib), 1); + } else if ((sel1 == 2) && (sel2 == 1)) { + /* Basic Machine CPU */ + struct sysib_121 sysib; +@@ -2594,7 +2650,7 @@ uint32_t HELPER(stsi)(uint64_t a0, uint32_t r0, uint32_t r1) + ebcdic_put(sysib.sequence, "QEMUQEMUQEMUQEMU", 16); + ebcdic_put(sysib.plant, "QEMU", 4); + stw_p(&sysib.cpu_addr, env->cpu_num); +- cpu_physical_memory_rw(a0, (uint8_t*)&sysib, sizeof(sysib), 1); ++ cpu_physical_memory_rw(a0, (uint8_t *)&sysib, sizeof(sysib), 1); + } else if ((sel1 == 2) && (sel2 == 2)) { + /* Basic Machine CPUs */ + struct sysib_122 sysib; +@@ -2606,68 +2662,68 @@ uint32_t HELPER(stsi)(uint64_t a0, uint32_t r0, uint32_t r1) + stw_p(&sysib.active_cpus, 1); + stw_p(&sysib.standby_cpus, 0); + stw_p(&sysib.reserved_cpus, 0); +- cpu_physical_memory_rw(a0, (uint8_t*)&sysib, sizeof(sysib), 1); ++ cpu_physical_memory_rw(a0, (uint8_t *)&sysib, sizeof(sysib), 1); + } else { + cc = 3; + } + break; + case STSI_LEVEL_2: +- { +- if ((sel1 == 2) && (sel2 == 1)) { +- /* LPAR CPU */ +- struct sysib_221 sysib; +- +- memset(&sysib, 0, sizeof(sysib)); +- /* XXX make different for different CPUs? */ +- ebcdic_put(sysib.sequence, "QEMUQEMUQEMUQEMU", 16); +- ebcdic_put(sysib.plant, "QEMU", 4); +- stw_p(&sysib.cpu_addr, env->cpu_num); +- stw_p(&sysib.cpu_id, 0); +- cpu_physical_memory_rw(a0, (uint8_t*)&sysib, sizeof(sysib), 1); +- } else if ((sel1 == 2) && (sel2 == 2)) { +- /* LPAR CPUs */ +- struct sysib_222 sysib; +- +- memset(&sysib, 0, sizeof(sysib)); +- stw_p(&sysib.lpar_num, 0); +- sysib.lcpuc = 0; +- /* XXX change when SMP comes */ +- stw_p(&sysib.total_cpus, 1); +- stw_p(&sysib.conf_cpus, 1); +- stw_p(&sysib.standby_cpus, 0); +- stw_p(&sysib.reserved_cpus, 0); +- ebcdic_put(sysib.name, "QEMU ", 8); +- stl_p(&sysib.caf, 1000); +- stw_p(&sysib.dedicated_cpus, 0); +- stw_p(&sysib.shared_cpus, 0); +- cpu_physical_memory_rw(a0, (uint8_t*)&sysib, sizeof(sysib), 1); +- } else { +- cc = 3; ++ { ++ if ((sel1 == 2) && (sel2 == 1)) { ++ /* LPAR CPU */ ++ struct sysib_221 sysib; ++ ++ memset(&sysib, 0, sizeof(sysib)); ++ /* XXX make different for different CPUs? */ ++ ebcdic_put(sysib.sequence, "QEMUQEMUQEMUQEMU", 16); ++ ebcdic_put(sysib.plant, "QEMU", 4); ++ stw_p(&sysib.cpu_addr, env->cpu_num); ++ stw_p(&sysib.cpu_id, 0); ++ cpu_physical_memory_rw(a0, (uint8_t *)&sysib, sizeof(sysib), 1); ++ } else if ((sel1 == 2) && (sel2 == 2)) { ++ /* LPAR CPUs */ ++ struct sysib_222 sysib; ++ ++ memset(&sysib, 0, sizeof(sysib)); ++ stw_p(&sysib.lpar_num, 0); ++ sysib.lcpuc = 0; ++ /* XXX change when SMP comes */ ++ stw_p(&sysib.total_cpus, 1); ++ stw_p(&sysib.conf_cpus, 1); ++ stw_p(&sysib.standby_cpus, 0); ++ stw_p(&sysib.reserved_cpus, 0); ++ ebcdic_put(sysib.name, "QEMU ", 8); ++ stl_p(&sysib.caf, 1000); ++ stw_p(&sysib.dedicated_cpus, 0); ++ stw_p(&sysib.shared_cpus, 0); ++ cpu_physical_memory_rw(a0, (uint8_t *)&sysib, sizeof(sysib), 1); ++ } else { ++ cc = 3; ++ } ++ break; + } +- break; +- } + case STSI_LEVEL_3: +- { +- if ((sel1 == 2) && (sel2 == 2)) { +- /* VM CPUs */ +- struct sysib_322 sysib; +- +- memset(&sysib, 0, sizeof(sysib)); +- sysib.count = 1; +- /* XXX change when SMP comes */ +- stw_p(&sysib.vm[0].total_cpus, 1); +- stw_p(&sysib.vm[0].conf_cpus, 1); +- stw_p(&sysib.vm[0].standby_cpus, 0); +- stw_p(&sysib.vm[0].reserved_cpus, 0); +- ebcdic_put(sysib.vm[0].name, "KVMguest", 8); +- stl_p(&sysib.vm[0].caf, 1000); +- ebcdic_put(sysib.vm[0].cpi, "KVM/Linux ", 16); +- cpu_physical_memory_rw(a0, (uint8_t*)&sysib, sizeof(sysib), 1); +- } else { +- cc = 3; ++ { ++ if ((sel1 == 2) && (sel2 == 2)) { ++ /* VM CPUs */ ++ struct sysib_322 sysib; ++ ++ memset(&sysib, 0, sizeof(sysib)); ++ sysib.count = 1; ++ /* XXX change when SMP comes */ ++ stw_p(&sysib.vm[0].total_cpus, 1); ++ stw_p(&sysib.vm[0].conf_cpus, 1); ++ stw_p(&sysib.vm[0].standby_cpus, 0); ++ stw_p(&sysib.vm[0].reserved_cpus, 0); ++ ebcdic_put(sysib.vm[0].name, "KVMguest", 8); ++ stl_p(&sysib.vm[0].caf, 1000); ++ ebcdic_put(sysib.vm[0].cpi, "KVM/Linux ", 16); ++ cpu_physical_memory_rw(a0, (uint8_t *)&sysib, sizeof(sysib), 1); ++ } else { ++ cc = 3; ++ } ++ break; + } +- break; +- } + case STSI_LEVEL_CURRENT: + env->regs[0] = STSI_LEVEL_3; + break; +@@ -2781,6 +2837,7 @@ uint32_t HELPER(rrbe)(uint32_t r1, uint64_t r2) + { + uint8_t re; + uint8_t key; ++ + if (r2 > ram_size) { + return 0; + } +@@ -2865,7 +2922,7 @@ static uint32_t mvc_asc(int64_t l, uint64_t a1, uint64_t mode1, uint64_t a2, + uint32_t HELPER(mvcs)(uint64_t l, uint64_t a1, uint64_t a2) + { + HELPER_LOG("%s: %16" PRIx64 " %16" PRIx64 " %16" PRIx64 "\n", +- __FUNCTION__, l, a1, a2); ++ __func__, l, a1, a2); + + return mvc_asc(l, a1, PSW_ASC_SECONDARY, a2, PSW_ASC_PRIMARY); + } +@@ -2873,7 +2930,7 @@ uint32_t HELPER(mvcs)(uint64_t l, uint64_t a1, uint64_t a2) + uint32_t HELPER(mvcp)(uint64_t l, uint64_t a1, uint64_t a2) + { + HELPER_LOG("%s: %16" PRIx64 " %16" PRIx64 " %16" PRIx64 "\n", +- __FUNCTION__, l, a1, a2); ++ __func__, l, a1, a2); + + return mvc_asc(l, a1, PSW_ASC_PRIMARY, a2, PSW_ASC_SECONDARY); + } +@@ -2883,9 +2940,9 @@ uint32_t HELPER(sigp)(uint64_t order_code, uint32_t r1, uint64_t cpu_addr) + int cc = 0; + + HELPER_LOG("%s: %016" PRIx64 " %08x %016" PRIx64 "\n", +- __FUNCTION__, order_code, r1, cpu_addr); ++ __func__, order_code, r1, cpu_addr); + +- /* Remember: Use "R1 or R1+1, whichever is the odd-numbered register" ++ /* Remember: Use "R1 or R1 + 1, whichever is the odd-numbered register" + as parameter (input). Status (output) is always R1. */ + + switch (order_code) { +@@ -2901,7 +2958,7 @@ uint32_t HELPER(sigp)(uint64_t order_code, uint32_t r1, uint64_t cpu_addr) + env->regs[r1] &= 0xffffffff00000000ULL; + cc = 1; + break; +-#if !defined (CONFIG_USER_ONLY) ++#if !defined(CONFIG_USER_ONLY) + case SIGP_RESTART: + qemu_system_reset_request(); + cpu_loop_exit(env); +@@ -2922,7 +2979,7 @@ uint32_t HELPER(sigp)(uint64_t order_code, uint32_t r1, uint64_t cpu_addr) + + void HELPER(sacf)(uint64_t a1) + { +- HELPER_LOG("%s: %16" PRIx64 "\n", __FUNCTION__, a1); ++ HELPER_LOG("%s: %16" PRIx64 "\n", __func__, a1); + + switch (a1 & 0xf00) { + case 0x000: +@@ -2953,13 +3010,13 @@ void HELPER(ipte)(uint64_t pte_addr, uint64_t vaddr) + /* XXX broadcast to other CPUs */ + + /* XXX Linux is nice enough to give us the exact pte address. +- According to spec we'd have to find it out ourselves */ ++ According to spec we'd have to find it out ourselves */ + /* XXX Linux is fine with overwriting the pte, the spec requires +- us to only set the invalid bit */ ++ us to only set the invalid bit */ + stq_phys(pte_addr, pte | _PAGE_INVALID); + + /* XXX we exploit the fact that Linux passes the exact virtual +- address here - it's not obliged to! */ ++ address here - it's not obliged to! */ + tlb_flush_page(env, page); + + /* XXX 31-bit hack */ +@@ -3008,7 +3065,8 @@ uint32_t HELPER(lra)(uint64_t addr, uint32_t r1) + env->exception_index = old_exc; + + if (!(env->psw.mask & PSW_MASK_64)) { +- env->regs[r1] = (env->regs[r1] & 0xffffffff00000000ULL) | (ret & 0xffffffffULL); ++ env->regs[r1] = (env->regs[r1] & 0xffffffff00000000ULL) | ++ (ret & 0xffffffffULL); + } else { + env->regs[r1] = ret; + } +-- +1.7.12.1 + diff --git a/0006-target-s390x-split-FPU-ops.patch b/0006-target-s390x-split-FPU-ops.patch new file mode 100644 index 0000000..5aabf6f --- /dev/null +++ b/0006-target-s390x-split-FPU-ops.patch @@ -0,0 +1,1756 @@ +From 3eb9b25ae5d2bcc024646c5a04f28899661ab14c Mon Sep 17 00:00:00 2001 +From: Blue Swirl +Date: Sun, 2 Sep 2012 07:33:31 +0000 +Subject: [PATCH] target-s390x: split FPU ops + +Move floating point instructions to fpu_helper.c. + +While exporting some condition code helpers, +avoid duplicate identifier conflict with translate.c. + +Remove unused set_cc_nz_f64() in translate.c. + +Signed-off-by: Blue Swirl +Signed-off-by: Alexander Graf +Signed-off-by: Michael Roth +--- + target-s390x/Makefile.objs | 2 + + target-s390x/cpu.h | 6 + + target-s390x/fpu_helper.c | 836 +++++++++++++++++++++++++++++++++++++++++++++ + target-s390x/op_helper.c | 802 ------------------------------------------- + target-s390x/translate.c | 11 +- + 5 files changed, 847 insertions(+), 810 deletions(-) + create mode 100644 target-s390x/fpu_helper.c + +diff --git a/target-s390x/Makefile.objs b/target-s390x/Makefile.objs +index 80be3bb..23b3bd9 100644 +--- a/target-s390x/Makefile.objs ++++ b/target-s390x/Makefile.objs +@@ -1,5 +1,7 @@ + obj-y += translate.o op_helper.o helper.o cpu.o interrupt.o ++obj-y += fpu_helper.o + obj-$(CONFIG_SOFTMMU) += machine.o + obj-$(CONFIG_KVM) += kvm.o + + $(obj)/op_helper.o: QEMU_CFLAGS += $(HELPER_CFLAGS) ++$(obj)/fpu_helper.o: QEMU_CFLAGS += $(HELPER_CFLAGS) +diff --git a/target-s390x/cpu.h b/target-s390x/cpu.h +index 18ac6e3..b4620c5 100644 +--- a/target-s390x/cpu.h ++++ b/target-s390x/cpu.h +@@ -999,4 +999,10 @@ static inline void cpu_pc_from_tb(CPUS390XState *env, TranslationBlock* tb) + env->psw.addr = tb->pc; + } + ++/* fpu_helper.c */ ++uint32_t set_cc_f32(float32 v1, float32 v2); ++uint32_t set_cc_f64(float64 v1, float64 v2); ++uint32_t set_cc_nz_f32(float32 v); ++uint32_t set_cc_nz_f64(float64 v); ++ + #endif +diff --git a/target-s390x/fpu_helper.c b/target-s390x/fpu_helper.c +new file mode 100644 +index 0000000..1389052 +--- /dev/null ++++ b/target-s390x/fpu_helper.c +@@ -0,0 +1,836 @@ ++/* ++ * S/390 FPU helper routines ++ * ++ * Copyright (c) 2009 Ulrich Hecht ++ * Copyright (c) 2009 Alexander Graf ++ * ++ * This library is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU Lesser General Public ++ * License as published by the Free Software Foundation; either ++ * version 2 of the License, or (at your option) any later version. ++ * ++ * This library is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * Lesser General Public License for more details. ++ * ++ * You should have received a copy of the GNU Lesser General Public ++ * License along with this library; if not, see . ++ */ ++ ++#include "cpu.h" ++#include "dyngen-exec.h" ++#include "helper.h" ++ ++#if !defined(CONFIG_USER_ONLY) ++#include "softmmu_exec.h" ++#endif ++ ++/* #define DEBUG_HELPER */ ++#ifdef DEBUG_HELPER ++#define HELPER_LOG(x...) qemu_log(x) ++#else ++#define HELPER_LOG(x...) ++#endif ++ ++static inline int float_comp_to_cc(int float_compare) ++{ ++ switch (float_compare) { ++ case float_relation_equal: ++ return 0; ++ case float_relation_less: ++ return 1; ++ case float_relation_greater: ++ return 2; ++ case float_relation_unordered: ++ return 3; ++ default: ++ cpu_abort(env, "unknown return value for float compare\n"); ++ } ++} ++ ++/* condition codes for binary FP ops */ ++uint32_t set_cc_f32(float32 v1, float32 v2) ++{ ++ return float_comp_to_cc(float32_compare_quiet(v1, v2, &env->fpu_status)); ++} ++ ++uint32_t set_cc_f64(float64 v1, float64 v2) ++{ ++ return float_comp_to_cc(float64_compare_quiet(v1, v2, &env->fpu_status)); ++} ++ ++/* condition codes for unary FP ops */ ++uint32_t set_cc_nz_f32(float32 v) ++{ ++ if (float32_is_any_nan(v)) { ++ return 3; ++ } else if (float32_is_zero(v)) { ++ return 0; ++ } else if (float32_is_neg(v)) { ++ return 1; ++ } else { ++ return 2; ++ } ++} ++ ++uint32_t set_cc_nz_f64(float64 v) ++{ ++ if (float64_is_any_nan(v)) { ++ return 3; ++ } else if (float64_is_zero(v)) { ++ return 0; ++ } else if (float64_is_neg(v)) { ++ return 1; ++ } else { ++ return 2; ++ } ++} ++ ++static uint32_t set_cc_nz_f128(float128 v) ++{ ++ if (float128_is_any_nan(v)) { ++ return 3; ++ } else if (float128_is_zero(v)) { ++ return 0; ++ } else if (float128_is_neg(v)) { ++ return 1; ++ } else { ++ return 2; ++ } ++} ++ ++/* convert 32-bit int to 64-bit float */ ++void HELPER(cdfbr)(uint32_t f1, int32_t v2) ++{ ++ HELPER_LOG("%s: converting %d to f%d\n", __func__, v2, f1); ++ env->fregs[f1].d = int32_to_float64(v2, &env->fpu_status); ++} ++ ++/* convert 32-bit int to 128-bit float */ ++void HELPER(cxfbr)(uint32_t f1, int32_t v2) ++{ ++ CPU_QuadU v1; ++ ++ v1.q = int32_to_float128(v2, &env->fpu_status); ++ env->fregs[f1].ll = v1.ll.upper; ++ env->fregs[f1 + 2].ll = v1.ll.lower; ++} ++ ++/* convert 64-bit int to 32-bit float */ ++void HELPER(cegbr)(uint32_t f1, int64_t v2) ++{ ++ HELPER_LOG("%s: converting %ld to f%d\n", __func__, v2, f1); ++ env->fregs[f1].l.upper = int64_to_float32(v2, &env->fpu_status); ++} ++ ++/* convert 64-bit int to 64-bit float */ ++void HELPER(cdgbr)(uint32_t f1, int64_t v2) ++{ ++ HELPER_LOG("%s: converting %ld to f%d\n", __func__, v2, f1); ++ env->fregs[f1].d = int64_to_float64(v2, &env->fpu_status); ++} ++ ++/* convert 64-bit int to 128-bit float */ ++void HELPER(cxgbr)(uint32_t f1, int64_t v2) ++{ ++ CPU_QuadU x1; ++ ++ x1.q = int64_to_float128(v2, &env->fpu_status); ++ HELPER_LOG("%s: converted %ld to 0x%lx and 0x%lx\n", __func__, v2, ++ x1.ll.upper, x1.ll.lower); ++ env->fregs[f1].ll = x1.ll.upper; ++ env->fregs[f1 + 2].ll = x1.ll.lower; ++} ++ ++/* convert 32-bit int to 32-bit float */ ++void HELPER(cefbr)(uint32_t f1, int32_t v2) ++{ ++ env->fregs[f1].l.upper = int32_to_float32(v2, &env->fpu_status); ++ HELPER_LOG("%s: converting %d to 0x%d in f%d\n", __func__, v2, ++ env->fregs[f1].l.upper, f1); ++} ++ ++/* 32-bit FP addition RR */ ++uint32_t HELPER(aebr)(uint32_t f1, uint32_t f2) ++{ ++ env->fregs[f1].l.upper = float32_add(env->fregs[f1].l.upper, ++ env->fregs[f2].l.upper, ++ &env->fpu_status); ++ HELPER_LOG("%s: adding 0x%d resulting in 0x%d in f%d\n", __func__, ++ env->fregs[f2].l.upper, env->fregs[f1].l.upper, f1); ++ ++ return set_cc_nz_f32(env->fregs[f1].l.upper); ++} ++ ++/* 64-bit FP addition RR */ ++uint32_t HELPER(adbr)(uint32_t f1, uint32_t f2) ++{ ++ env->fregs[f1].d = float64_add(env->fregs[f1].d, env->fregs[f2].d, ++ &env->fpu_status); ++ HELPER_LOG("%s: adding 0x%ld resulting in 0x%ld in f%d\n", __func__, ++ env->fregs[f2].d, env->fregs[f1].d, f1); ++ ++ return set_cc_nz_f64(env->fregs[f1].d); ++} ++ ++/* 32-bit FP subtraction RR */ ++uint32_t HELPER(sebr)(uint32_t f1, uint32_t f2) ++{ ++ env->fregs[f1].l.upper = float32_sub(env->fregs[f1].l.upper, ++ env->fregs[f2].l.upper, ++ &env->fpu_status); ++ HELPER_LOG("%s: adding 0x%d resulting in 0x%d in f%d\n", __func__, ++ env->fregs[f2].l.upper, env->fregs[f1].l.upper, f1); ++ ++ return set_cc_nz_f32(env->fregs[f1].l.upper); ++} ++ ++/* 64-bit FP subtraction RR */ ++uint32_t HELPER(sdbr)(uint32_t f1, uint32_t f2) ++{ ++ env->fregs[f1].d = float64_sub(env->fregs[f1].d, env->fregs[f2].d, ++ &env->fpu_status); ++ HELPER_LOG("%s: subtracting 0x%ld resulting in 0x%ld in f%d\n", ++ __func__, env->fregs[f2].d, env->fregs[f1].d, f1); ++ ++ return set_cc_nz_f64(env->fregs[f1].d); ++} ++ ++/* 32-bit FP division RR */ ++void HELPER(debr)(uint32_t f1, uint32_t f2) ++{ ++ env->fregs[f1].l.upper = float32_div(env->fregs[f1].l.upper, ++ env->fregs[f2].l.upper, ++ &env->fpu_status); ++} ++ ++/* 128-bit FP division RR */ ++void HELPER(dxbr)(uint32_t f1, uint32_t f2) ++{ ++ CPU_QuadU v1; ++ CPU_QuadU v2; ++ CPU_QuadU res; ++ ++ v1.ll.upper = env->fregs[f1].ll; ++ v1.ll.lower = env->fregs[f1 + 2].ll; ++ v2.ll.upper = env->fregs[f2].ll; ++ v2.ll.lower = env->fregs[f2 + 2].ll; ++ res.q = float128_div(v1.q, v2.q, &env->fpu_status); ++ env->fregs[f1].ll = res.ll.upper; ++ env->fregs[f1 + 2].ll = res.ll.lower; ++} ++ ++/* 64-bit FP multiplication RR */ ++void HELPER(mdbr)(uint32_t f1, uint32_t f2) ++{ ++ env->fregs[f1].d = float64_mul(env->fregs[f1].d, env->fregs[f2].d, ++ &env->fpu_status); ++} ++ ++/* 128-bit FP multiplication RR */ ++void HELPER(mxbr)(uint32_t f1, uint32_t f2) ++{ ++ CPU_QuadU v1; ++ CPU_QuadU v2; ++ CPU_QuadU res; ++ ++ v1.ll.upper = env->fregs[f1].ll; ++ v1.ll.lower = env->fregs[f1 + 2].ll; ++ v2.ll.upper = env->fregs[f2].ll; ++ v2.ll.lower = env->fregs[f2 + 2].ll; ++ res.q = float128_mul(v1.q, v2.q, &env->fpu_status); ++ env->fregs[f1].ll = res.ll.upper; ++ env->fregs[f1 + 2].ll = res.ll.lower; ++} ++ ++/* convert 32-bit float to 64-bit float */ ++void HELPER(ldebr)(uint32_t r1, uint32_t r2) ++{ ++ env->fregs[r1].d = float32_to_float64(env->fregs[r2].l.upper, ++ &env->fpu_status); ++} ++ ++/* convert 128-bit float to 64-bit float */ ++void HELPER(ldxbr)(uint32_t f1, uint32_t f2) ++{ ++ CPU_QuadU x2; ++ ++ x2.ll.upper = env->fregs[f2].ll; ++ x2.ll.lower = env->fregs[f2 + 2].ll; ++ env->fregs[f1].d = float128_to_float64(x2.q, &env->fpu_status); ++ HELPER_LOG("%s: to 0x%ld\n", __func__, env->fregs[f1].d); ++} ++ ++/* convert 64-bit float to 128-bit float */ ++void HELPER(lxdbr)(uint32_t f1, uint32_t f2) ++{ ++ CPU_QuadU res; ++ ++ res.q = float64_to_float128(env->fregs[f2].d, &env->fpu_status); ++ env->fregs[f1].ll = res.ll.upper; ++ env->fregs[f1 + 2].ll = res.ll.lower; ++} ++ ++/* convert 64-bit float to 32-bit float */ ++void HELPER(ledbr)(uint32_t f1, uint32_t f2) ++{ ++ float64 d2 = env->fregs[f2].d; ++ ++ env->fregs[f1].l.upper = float64_to_float32(d2, &env->fpu_status); ++} ++ ++/* convert 128-bit float to 32-bit float */ ++void HELPER(lexbr)(uint32_t f1, uint32_t f2) ++{ ++ CPU_QuadU x2; ++ ++ x2.ll.upper = env->fregs[f2].ll; ++ x2.ll.lower = env->fregs[f2 + 2].ll; ++ env->fregs[f1].l.upper = float128_to_float32(x2.q, &env->fpu_status); ++ HELPER_LOG("%s: to 0x%d\n", __func__, env->fregs[f1].l.upper); ++} ++ ++/* absolute value of 32-bit float */ ++uint32_t HELPER(lpebr)(uint32_t f1, uint32_t f2) ++{ ++ float32 v1; ++ float32 v2 = env->fregs[f2].d; ++ ++ v1 = float32_abs(v2); ++ env->fregs[f1].d = v1; ++ return set_cc_nz_f32(v1); ++} ++ ++/* absolute value of 64-bit float */ ++uint32_t HELPER(lpdbr)(uint32_t f1, uint32_t f2) ++{ ++ float64 v1; ++ float64 v2 = env->fregs[f2].d; ++ ++ v1 = float64_abs(v2); ++ env->fregs[f1].d = v1; ++ return set_cc_nz_f64(v1); ++} ++ ++/* absolute value of 128-bit float */ ++uint32_t HELPER(lpxbr)(uint32_t f1, uint32_t f2) ++{ ++ CPU_QuadU v1; ++ CPU_QuadU v2; ++ ++ v2.ll.upper = env->fregs[f2].ll; ++ v2.ll.lower = env->fregs[f2 + 2].ll; ++ v1.q = float128_abs(v2.q); ++ env->fregs[f1].ll = v1.ll.upper; ++ env->fregs[f1 + 2].ll = v1.ll.lower; ++ return set_cc_nz_f128(v1.q); ++} ++ ++/* load and test 64-bit float */ ++uint32_t HELPER(ltdbr)(uint32_t f1, uint32_t f2) ++{ ++ env->fregs[f1].d = env->fregs[f2].d; ++ return set_cc_nz_f64(env->fregs[f1].d); ++} ++ ++/* load and test 32-bit float */ ++uint32_t HELPER(ltebr)(uint32_t f1, uint32_t f2) ++{ ++ env->fregs[f1].l.upper = env->fregs[f2].l.upper; ++ return set_cc_nz_f32(env->fregs[f1].l.upper); ++} ++ ++/* load and test 128-bit float */ ++uint32_t HELPER(ltxbr)(uint32_t f1, uint32_t f2) ++{ ++ CPU_QuadU x; ++ ++ x.ll.upper = env->fregs[f2].ll; ++ x.ll.lower = env->fregs[f2 + 2].ll; ++ env->fregs[f1].ll = x.ll.upper; ++ env->fregs[f1 + 2].ll = x.ll.lower; ++ return set_cc_nz_f128(x.q); ++} ++ ++/* load complement of 32-bit float */ ++uint32_t HELPER(lcebr)(uint32_t f1, uint32_t f2) ++{ ++ env->fregs[f1].l.upper = float32_chs(env->fregs[f2].l.upper); ++ ++ return set_cc_nz_f32(env->fregs[f1].l.upper); ++} ++ ++/* load complement of 64-bit float */ ++uint32_t HELPER(lcdbr)(uint32_t f1, uint32_t f2) ++{ ++ env->fregs[f1].d = float64_chs(env->fregs[f2].d); ++ ++ return set_cc_nz_f64(env->fregs[f1].d); ++} ++ ++/* load complement of 128-bit float */ ++uint32_t HELPER(lcxbr)(uint32_t f1, uint32_t f2) ++{ ++ CPU_QuadU x1, x2; ++ ++ x2.ll.upper = env->fregs[f2].ll; ++ x2.ll.lower = env->fregs[f2 + 2].ll; ++ x1.q = float128_chs(x2.q); ++ env->fregs[f1].ll = x1.ll.upper; ++ env->fregs[f1 + 2].ll = x1.ll.lower; ++ return set_cc_nz_f128(x1.q); ++} ++ ++/* 32-bit FP addition RM */ ++void HELPER(aeb)(uint32_t f1, uint32_t val) ++{ ++ float32 v1 = env->fregs[f1].l.upper; ++ CPU_FloatU v2; ++ ++ v2.l = val; ++ HELPER_LOG("%s: adding 0x%d from f%d and 0x%d\n", __func__, ++ v1, f1, v2.f); ++ env->fregs[f1].l.upper = float32_add(v1, v2.f, &env->fpu_status); ++} ++ ++/* 32-bit FP division RM */ ++void HELPER(deb)(uint32_t f1, uint32_t val) ++{ ++ float32 v1 = env->fregs[f1].l.upper; ++ CPU_FloatU v2; ++ ++ v2.l = val; ++ HELPER_LOG("%s: dividing 0x%d from f%d by 0x%d\n", __func__, ++ v1, f1, v2.f); ++ env->fregs[f1].l.upper = float32_div(v1, v2.f, &env->fpu_status); ++} ++ ++/* 32-bit FP multiplication RM */ ++void HELPER(meeb)(uint32_t f1, uint32_t val) ++{ ++ float32 v1 = env->fregs[f1].l.upper; ++ CPU_FloatU v2; ++ ++ v2.l = val; ++ HELPER_LOG("%s: multiplying 0x%d from f%d and 0x%d\n", __func__, ++ v1, f1, v2.f); ++ env->fregs[f1].l.upper = float32_mul(v1, v2.f, &env->fpu_status); ++} ++ ++/* 32-bit FP compare RR */ ++uint32_t HELPER(cebr)(uint32_t f1, uint32_t f2) ++{ ++ float32 v1 = env->fregs[f1].l.upper; ++ float32 v2 = env->fregs[f2].l.upper; ++ ++ HELPER_LOG("%s: comparing 0x%d from f%d and 0x%d\n", __func__, ++ v1, f1, v2); ++ return set_cc_f32(v1, v2); ++} ++ ++/* 64-bit FP compare RR */ ++uint32_t HELPER(cdbr)(uint32_t f1, uint32_t f2) ++{ ++ float64 v1 = env->fregs[f1].d; ++ float64 v2 = env->fregs[f2].d; ++ ++ HELPER_LOG("%s: comparing 0x%ld from f%d and 0x%ld\n", __func__, ++ v1, f1, v2); ++ return set_cc_f64(v1, v2); ++} ++ ++/* 128-bit FP compare RR */ ++uint32_t HELPER(cxbr)(uint32_t f1, uint32_t f2) ++{ ++ CPU_QuadU v1; ++ CPU_QuadU v2; ++ ++ v1.ll.upper = env->fregs[f1].ll; ++ v1.ll.lower = env->fregs[f1 + 2].ll; ++ v2.ll.upper = env->fregs[f2].ll; ++ v2.ll.lower = env->fregs[f2 + 2].ll; ++ ++ return float_comp_to_cc(float128_compare_quiet(v1.q, v2.q, ++ &env->fpu_status)); ++} ++ ++/* 64-bit FP compare RM */ ++uint32_t HELPER(cdb)(uint32_t f1, uint64_t a2) ++{ ++ float64 v1 = env->fregs[f1].d; ++ CPU_DoubleU v2; ++ ++ v2.ll = ldq(a2); ++ HELPER_LOG("%s: comparing 0x%ld from f%d and 0x%lx\n", __func__, v1, ++ f1, v2.d); ++ return set_cc_f64(v1, v2.d); ++} ++ ++/* 64-bit FP addition RM */ ++uint32_t HELPER(adb)(uint32_t f1, uint64_t a2) ++{ ++ float64 v1 = env->fregs[f1].d; ++ CPU_DoubleU v2; ++ ++ v2.ll = ldq(a2); ++ HELPER_LOG("%s: adding 0x%lx from f%d and 0x%lx\n", __func__, ++ v1, f1, v2.d); ++ env->fregs[f1].d = v1 = float64_add(v1, v2.d, &env->fpu_status); ++ return set_cc_nz_f64(v1); ++} ++ ++/* 32-bit FP subtraction RM */ ++void HELPER(seb)(uint32_t f1, uint32_t val) ++{ ++ float32 v1 = env->fregs[f1].l.upper; ++ CPU_FloatU v2; ++ ++ v2.l = val; ++ env->fregs[f1].l.upper = float32_sub(v1, v2.f, &env->fpu_status); ++} ++ ++/* 64-bit FP subtraction RM */ ++uint32_t HELPER(sdb)(uint32_t f1, uint64_t a2) ++{ ++ float64 v1 = env->fregs[f1].d; ++ CPU_DoubleU v2; ++ ++ v2.ll = ldq(a2); ++ env->fregs[f1].d = v1 = float64_sub(v1, v2.d, &env->fpu_status); ++ return set_cc_nz_f64(v1); ++} ++ ++/* 64-bit FP multiplication RM */ ++void HELPER(mdb)(uint32_t f1, uint64_t a2) ++{ ++ float64 v1 = env->fregs[f1].d; ++ CPU_DoubleU v2; ++ ++ v2.ll = ldq(a2); ++ HELPER_LOG("%s: multiplying 0x%lx from f%d and 0x%ld\n", __func__, ++ v1, f1, v2.d); ++ env->fregs[f1].d = float64_mul(v1, v2.d, &env->fpu_status); ++} ++ ++/* 64-bit FP division RM */ ++void HELPER(ddb)(uint32_t f1, uint64_t a2) ++{ ++ float64 v1 = env->fregs[f1].d; ++ CPU_DoubleU v2; ++ ++ v2.ll = ldq(a2); ++ HELPER_LOG("%s: dividing 0x%lx from f%d by 0x%ld\n", __func__, ++ v1, f1, v2.d); ++ env->fregs[f1].d = float64_div(v1, v2.d, &env->fpu_status); ++} ++ ++static void set_round_mode(int m3) ++{ ++ switch (m3) { ++ case 0: ++ /* current mode */ ++ break; ++ case 1: ++ /* biased round no nearest */ ++ case 4: ++ /* round to nearest */ ++ set_float_rounding_mode(float_round_nearest_even, &env->fpu_status); ++ break; ++ case 5: ++ /* round to zero */ ++ set_float_rounding_mode(float_round_to_zero, &env->fpu_status); ++ break; ++ case 6: ++ /* round to +inf */ ++ set_float_rounding_mode(float_round_up, &env->fpu_status); ++ break; ++ case 7: ++ /* round to -inf */ ++ set_float_rounding_mode(float_round_down, &env->fpu_status); ++ break; ++ } ++} ++ ++/* convert 32-bit float to 64-bit int */ ++uint32_t HELPER(cgebr)(uint32_t r1, uint32_t f2, uint32_t m3) ++{ ++ float32 v2 = env->fregs[f2].l.upper; ++ ++ set_round_mode(m3); ++ env->regs[r1] = float32_to_int64(v2, &env->fpu_status); ++ return set_cc_nz_f32(v2); ++} ++ ++/* convert 64-bit float to 64-bit int */ ++uint32_t HELPER(cgdbr)(uint32_t r1, uint32_t f2, uint32_t m3) ++{ ++ float64 v2 = env->fregs[f2].d; ++ ++ set_round_mode(m3); ++ env->regs[r1] = float64_to_int64(v2, &env->fpu_status); ++ return set_cc_nz_f64(v2); ++} ++ ++/* convert 128-bit float to 64-bit int */ ++uint32_t HELPER(cgxbr)(uint32_t r1, uint32_t f2, uint32_t m3) ++{ ++ CPU_QuadU v2; ++ ++ v2.ll.upper = env->fregs[f2].ll; ++ v2.ll.lower = env->fregs[f2 + 2].ll; ++ set_round_mode(m3); ++ env->regs[r1] = float128_to_int64(v2.q, &env->fpu_status); ++ if (float128_is_any_nan(v2.q)) { ++ return 3; ++ } else if (float128_is_zero(v2.q)) { ++ return 0; ++ } else if (float128_is_neg(v2.q)) { ++ return 1; ++ } else { ++ return 2; ++ } ++} ++ ++/* convert 32-bit float to 32-bit int */ ++uint32_t HELPER(cfebr)(uint32_t r1, uint32_t f2, uint32_t m3) ++{ ++ float32 v2 = env->fregs[f2].l.upper; ++ ++ set_round_mode(m3); ++ env->regs[r1] = (env->regs[r1] & 0xffffffff00000000ULL) | ++ float32_to_int32(v2, &env->fpu_status); ++ return set_cc_nz_f32(v2); ++} ++ ++/* convert 64-bit float to 32-bit int */ ++uint32_t HELPER(cfdbr)(uint32_t r1, uint32_t f2, uint32_t m3) ++{ ++ float64 v2 = env->fregs[f2].d; ++ ++ set_round_mode(m3); ++ env->regs[r1] = (env->regs[r1] & 0xffffffff00000000ULL) | ++ float64_to_int32(v2, &env->fpu_status); ++ return set_cc_nz_f64(v2); ++} ++ ++/* convert 128-bit float to 32-bit int */ ++uint32_t HELPER(cfxbr)(uint32_t r1, uint32_t f2, uint32_t m3) ++{ ++ CPU_QuadU v2; ++ ++ v2.ll.upper = env->fregs[f2].ll; ++ v2.ll.lower = env->fregs[f2 + 2].ll; ++ env->regs[r1] = (env->regs[r1] & 0xffffffff00000000ULL) | ++ float128_to_int32(v2.q, &env->fpu_status); ++ return set_cc_nz_f128(v2.q); ++} ++ ++/* load 32-bit FP zero */ ++void HELPER(lzer)(uint32_t f1) ++{ ++ env->fregs[f1].l.upper = float32_zero; ++} ++ ++/* load 64-bit FP zero */ ++void HELPER(lzdr)(uint32_t f1) ++{ ++ env->fregs[f1].d = float64_zero; ++} ++ ++/* load 128-bit FP zero */ ++void HELPER(lzxr)(uint32_t f1) ++{ ++ CPU_QuadU x; ++ ++ x.q = float64_to_float128(float64_zero, &env->fpu_status); ++ env->fregs[f1].ll = x.ll.upper; ++ env->fregs[f1 + 1].ll = x.ll.lower; ++} ++ ++/* 128-bit FP subtraction RR */ ++uint32_t HELPER(sxbr)(uint32_t f1, uint32_t f2) ++{ ++ CPU_QuadU v1; ++ CPU_QuadU v2; ++ CPU_QuadU res; ++ ++ v1.ll.upper = env->fregs[f1].ll; ++ v1.ll.lower = env->fregs[f1 + 2].ll; ++ v2.ll.upper = env->fregs[f2].ll; ++ v2.ll.lower = env->fregs[f2 + 2].ll; ++ res.q = float128_sub(v1.q, v2.q, &env->fpu_status); ++ env->fregs[f1].ll = res.ll.upper; ++ env->fregs[f1 + 2].ll = res.ll.lower; ++ return set_cc_nz_f128(res.q); ++} ++ ++/* 128-bit FP addition RR */ ++uint32_t HELPER(axbr)(uint32_t f1, uint32_t f2) ++{ ++ CPU_QuadU v1; ++ CPU_QuadU v2; ++ CPU_QuadU res; ++ ++ v1.ll.upper = env->fregs[f1].ll; ++ v1.ll.lower = env->fregs[f1 + 2].ll; ++ v2.ll.upper = env->fregs[f2].ll; ++ v2.ll.lower = env->fregs[f2 + 2].ll; ++ res.q = float128_add(v1.q, v2.q, &env->fpu_status); ++ env->fregs[f1].ll = res.ll.upper; ++ env->fregs[f1 + 2].ll = res.ll.lower; ++ return set_cc_nz_f128(res.q); ++} ++ ++/* 32-bit FP multiplication RR */ ++void HELPER(meebr)(uint32_t f1, uint32_t f2) ++{ ++ env->fregs[f1].l.upper = float32_mul(env->fregs[f1].l.upper, ++ env->fregs[f2].l.upper, ++ &env->fpu_status); ++} ++ ++/* 64-bit FP division RR */ ++void HELPER(ddbr)(uint32_t f1, uint32_t f2) ++{ ++ env->fregs[f1].d = float64_div(env->fregs[f1].d, env->fregs[f2].d, ++ &env->fpu_status); ++} ++ ++/* 64-bit FP multiply and add RM */ ++void HELPER(madb)(uint32_t f1, uint64_t a2, uint32_t f3) ++{ ++ CPU_DoubleU v2; ++ ++ HELPER_LOG("%s: f1 %d a2 0x%lx f3 %d\n", __func__, f1, a2, f3); ++ v2.ll = ldq(a2); ++ env->fregs[f1].d = float64_add(env->fregs[f1].d, ++ float64_mul(v2.d, env->fregs[f3].d, ++ &env->fpu_status), ++ &env->fpu_status); ++} ++ ++/* 64-bit FP multiply and add RR */ ++void HELPER(madbr)(uint32_t f1, uint32_t f3, uint32_t f2) ++{ ++ HELPER_LOG("%s: f1 %d f2 %d f3 %d\n", __func__, f1, f2, f3); ++ env->fregs[f1].d = float64_add(float64_mul(env->fregs[f2].d, ++ env->fregs[f3].d, ++ &env->fpu_status), ++ env->fregs[f1].d, &env->fpu_status); ++} ++ ++/* 64-bit FP multiply and subtract RR */ ++void HELPER(msdbr)(uint32_t f1, uint32_t f3, uint32_t f2) ++{ ++ HELPER_LOG("%s: f1 %d f2 %d f3 %d\n", __func__, f1, f2, f3); ++ env->fregs[f1].d = float64_sub(float64_mul(env->fregs[f2].d, ++ env->fregs[f3].d, ++ &env->fpu_status), ++ env->fregs[f1].d, &env->fpu_status); ++} ++ ++/* 32-bit FP multiply and add RR */ ++void HELPER(maebr)(uint32_t f1, uint32_t f3, uint32_t f2) ++{ ++ env->fregs[f1].l.upper = float32_add(env->fregs[f1].l.upper, ++ float32_mul(env->fregs[f2].l.upper, ++ env->fregs[f3].l.upper, ++ &env->fpu_status), ++ &env->fpu_status); ++} ++ ++/* convert 32-bit float to 64-bit float */ ++void HELPER(ldeb)(uint32_t f1, uint64_t a2) ++{ ++ uint32_t v2; ++ ++ v2 = ldl(a2); ++ env->fregs[f1].d = float32_to_float64(v2, ++ &env->fpu_status); ++} ++ ++/* convert 64-bit float to 128-bit float */ ++void HELPER(lxdb)(uint32_t f1, uint64_t a2) ++{ ++ CPU_DoubleU v2; ++ CPU_QuadU v1; ++ ++ v2.ll = ldq(a2); ++ v1.q = float64_to_float128(v2.d, &env->fpu_status); ++ env->fregs[f1].ll = v1.ll.upper; ++ env->fregs[f1 + 2].ll = v1.ll.lower; ++} ++ ++/* test data class 32-bit */ ++uint32_t HELPER(tceb)(uint32_t f1, uint64_t m2) ++{ ++ float32 v1 = env->fregs[f1].l.upper; ++ int neg = float32_is_neg(v1); ++ uint32_t cc = 0; ++ ++ HELPER_LOG("%s: v1 0x%lx m2 0x%lx neg %d\n", __func__, (long)v1, m2, neg); ++ if ((float32_is_zero(v1) && (m2 & (1 << (11-neg)))) || ++ (float32_is_infinity(v1) && (m2 & (1 << (5-neg)))) || ++ (float32_is_any_nan(v1) && (m2 & (1 << (3-neg)))) || ++ (float32_is_signaling_nan(v1) && (m2 & (1 << (1-neg))))) { ++ cc = 1; ++ } else if (m2 & (1 << (9-neg))) { ++ /* assume normalized number */ ++ cc = 1; ++ } ++ ++ /* FIXME: denormalized? */ ++ return cc; ++} ++ ++/* test data class 64-bit */ ++uint32_t HELPER(tcdb)(uint32_t f1, uint64_t m2) ++{ ++ float64 v1 = env->fregs[f1].d; ++ int neg = float64_is_neg(v1); ++ uint32_t cc = 0; ++ ++ HELPER_LOG("%s: v1 0x%lx m2 0x%lx neg %d\n", __func__, v1, m2, neg); ++ if ((float64_is_zero(v1) && (m2 & (1 << (11-neg)))) || ++ (float64_is_infinity(v1) && (m2 & (1 << (5-neg)))) || ++ (float64_is_any_nan(v1) && (m2 & (1 << (3-neg)))) || ++ (float64_is_signaling_nan(v1) && (m2 & (1 << (1-neg))))) { ++ cc = 1; ++ } else if (m2 & (1 << (9-neg))) { ++ /* assume normalized number */ ++ cc = 1; ++ } ++ /* FIXME: denormalized? */ ++ return cc; ++} ++ ++/* test data class 128-bit */ ++uint32_t HELPER(tcxb)(uint32_t f1, uint64_t m2) ++{ ++ CPU_QuadU v1; ++ uint32_t cc = 0; ++ int neg; ++ ++ v1.ll.upper = env->fregs[f1].ll; ++ v1.ll.lower = env->fregs[f1 + 2].ll; ++ ++ neg = float128_is_neg(v1.q); ++ if ((float128_is_zero(v1.q) && (m2 & (1 << (11-neg)))) || ++ (float128_is_infinity(v1.q) && (m2 & (1 << (5-neg)))) || ++ (float128_is_any_nan(v1.q) && (m2 & (1 << (3-neg)))) || ++ (float128_is_signaling_nan(v1.q) && (m2 & (1 << (1-neg))))) { ++ cc = 1; ++ } else if (m2 & (1 << (9-neg))) { ++ /* assume normalized number */ ++ cc = 1; ++ } ++ /* FIXME: denormalized? */ ++ return cc; ++} ++ ++/* square root 64-bit RR */ ++void HELPER(sqdbr)(uint32_t f1, uint32_t f2) ++{ ++ env->fregs[f1].d = float64_sqrt(env->fregs[f2].d, &env->fpu_status); ++} +diff --git a/target-s390x/op_helper.c b/target-s390x/op_helper.c +index 195e93e..270bf14 100644 +--- a/target-s390x/op_helper.c ++++ b/target-s390x/op_helper.c +@@ -977,802 +977,6 @@ uint32_t HELPER(slbg)(uint32_t cc, uint32_t r1, uint64_t v1, uint64_t v2) + } + } + +-static inline int float_comp_to_cc(int float_compare) +-{ +- switch (float_compare) { +- case float_relation_equal: +- return 0; +- case float_relation_less: +- return 1; +- case float_relation_greater: +- return 2; +- case float_relation_unordered: +- return 3; +- default: +- cpu_abort(env, "unknown return value for float compare\n"); +- } +-} +- +-/* condition codes for binary FP ops */ +-static uint32_t set_cc_f32(float32 v1, float32 v2) +-{ +- return float_comp_to_cc(float32_compare_quiet(v1, v2, &env->fpu_status)); +-} +- +-static uint32_t set_cc_f64(float64 v1, float64 v2) +-{ +- return float_comp_to_cc(float64_compare_quiet(v1, v2, &env->fpu_status)); +-} +- +-/* condition codes for unary FP ops */ +-static uint32_t set_cc_nz_f32(float32 v) +-{ +- if (float32_is_any_nan(v)) { +- return 3; +- } else if (float32_is_zero(v)) { +- return 0; +- } else if (float32_is_neg(v)) { +- return 1; +- } else { +- return 2; +- } +-} +- +-static uint32_t set_cc_nz_f64(float64 v) +-{ +- if (float64_is_any_nan(v)) { +- return 3; +- } else if (float64_is_zero(v)) { +- return 0; +- } else if (float64_is_neg(v)) { +- return 1; +- } else { +- return 2; +- } +-} +- +-static uint32_t set_cc_nz_f128(float128 v) +-{ +- if (float128_is_any_nan(v)) { +- return 3; +- } else if (float128_is_zero(v)) { +- return 0; +- } else if (float128_is_neg(v)) { +- return 1; +- } else { +- return 2; +- } +-} +- +-/* convert 32-bit int to 64-bit float */ +-void HELPER(cdfbr)(uint32_t f1, int32_t v2) +-{ +- HELPER_LOG("%s: converting %d to f%d\n", __func__, v2, f1); +- env->fregs[f1].d = int32_to_float64(v2, &env->fpu_status); +-} +- +-/* convert 32-bit int to 128-bit float */ +-void HELPER(cxfbr)(uint32_t f1, int32_t v2) +-{ +- CPU_QuadU v1; +- +- v1.q = int32_to_float128(v2, &env->fpu_status); +- env->fregs[f1].ll = v1.ll.upper; +- env->fregs[f1 + 2].ll = v1.ll.lower; +-} +- +-/* convert 64-bit int to 32-bit float */ +-void HELPER(cegbr)(uint32_t f1, int64_t v2) +-{ +- HELPER_LOG("%s: converting %ld to f%d\n", __func__, v2, f1); +- env->fregs[f1].l.upper = int64_to_float32(v2, &env->fpu_status); +-} +- +-/* convert 64-bit int to 64-bit float */ +-void HELPER(cdgbr)(uint32_t f1, int64_t v2) +-{ +- HELPER_LOG("%s: converting %ld to f%d\n", __func__, v2, f1); +- env->fregs[f1].d = int64_to_float64(v2, &env->fpu_status); +-} +- +-/* convert 64-bit int to 128-bit float */ +-void HELPER(cxgbr)(uint32_t f1, int64_t v2) +-{ +- CPU_QuadU x1; +- +- x1.q = int64_to_float128(v2, &env->fpu_status); +- HELPER_LOG("%s: converted %ld to 0x%lx and 0x%lx\n", __func__, v2, +- x1.ll.upper, x1.ll.lower); +- env->fregs[f1].ll = x1.ll.upper; +- env->fregs[f1 + 2].ll = x1.ll.lower; +-} +- +-/* convert 32-bit int to 32-bit float */ +-void HELPER(cefbr)(uint32_t f1, int32_t v2) +-{ +- env->fregs[f1].l.upper = int32_to_float32(v2, &env->fpu_status); +- HELPER_LOG("%s: converting %d to 0x%d in f%d\n", __func__, v2, +- env->fregs[f1].l.upper, f1); +-} +- +-/* 32-bit FP addition RR */ +-uint32_t HELPER(aebr)(uint32_t f1, uint32_t f2) +-{ +- env->fregs[f1].l.upper = float32_add(env->fregs[f1].l.upper, +- env->fregs[f2].l.upper, +- &env->fpu_status); +- HELPER_LOG("%s: adding 0x%d resulting in 0x%d in f%d\n", __func__, +- env->fregs[f2].l.upper, env->fregs[f1].l.upper, f1); +- +- return set_cc_nz_f32(env->fregs[f1].l.upper); +-} +- +-/* 64-bit FP addition RR */ +-uint32_t HELPER(adbr)(uint32_t f1, uint32_t f2) +-{ +- env->fregs[f1].d = float64_add(env->fregs[f1].d, env->fregs[f2].d, +- &env->fpu_status); +- HELPER_LOG("%s: adding 0x%ld resulting in 0x%ld in f%d\n", __func__, +- env->fregs[f2].d, env->fregs[f1].d, f1); +- +- return set_cc_nz_f64(env->fregs[f1].d); +-} +- +-/* 32-bit FP subtraction RR */ +-uint32_t HELPER(sebr)(uint32_t f1, uint32_t f2) +-{ +- env->fregs[f1].l.upper = float32_sub(env->fregs[f1].l.upper, +- env->fregs[f2].l.upper, +- &env->fpu_status); +- HELPER_LOG("%s: adding 0x%d resulting in 0x%d in f%d\n", __func__, +- env->fregs[f2].l.upper, env->fregs[f1].l.upper, f1); +- +- return set_cc_nz_f32(env->fregs[f1].l.upper); +-} +- +-/* 64-bit FP subtraction RR */ +-uint32_t HELPER(sdbr)(uint32_t f1, uint32_t f2) +-{ +- env->fregs[f1].d = float64_sub(env->fregs[f1].d, env->fregs[f2].d, +- &env->fpu_status); +- HELPER_LOG("%s: subtracting 0x%ld resulting in 0x%ld in f%d\n", +- __func__, env->fregs[f2].d, env->fregs[f1].d, f1); +- +- return set_cc_nz_f64(env->fregs[f1].d); +-} +- +-/* 32-bit FP division RR */ +-void HELPER(debr)(uint32_t f1, uint32_t f2) +-{ +- env->fregs[f1].l.upper = float32_div(env->fregs[f1].l.upper, +- env->fregs[f2].l.upper, +- &env->fpu_status); +-} +- +-/* 128-bit FP division RR */ +-void HELPER(dxbr)(uint32_t f1, uint32_t f2) +-{ +- CPU_QuadU v1; +- CPU_QuadU v2; +- CPU_QuadU res; +- +- v1.ll.upper = env->fregs[f1].ll; +- v1.ll.lower = env->fregs[f1 + 2].ll; +- v2.ll.upper = env->fregs[f2].ll; +- v2.ll.lower = env->fregs[f2 + 2].ll; +- res.q = float128_div(v1.q, v2.q, &env->fpu_status); +- env->fregs[f1].ll = res.ll.upper; +- env->fregs[f1 + 2].ll = res.ll.lower; +-} +- +-/* 64-bit FP multiplication RR */ +-void HELPER(mdbr)(uint32_t f1, uint32_t f2) +-{ +- env->fregs[f1].d = float64_mul(env->fregs[f1].d, env->fregs[f2].d, +- &env->fpu_status); +-} +- +-/* 128-bit FP multiplication RR */ +-void HELPER(mxbr)(uint32_t f1, uint32_t f2) +-{ +- CPU_QuadU v1; +- CPU_QuadU v2; +- CPU_QuadU res; +- +- v1.ll.upper = env->fregs[f1].ll; +- v1.ll.lower = env->fregs[f1 + 2].ll; +- v2.ll.upper = env->fregs[f2].ll; +- v2.ll.lower = env->fregs[f2 + 2].ll; +- res.q = float128_mul(v1.q, v2.q, &env->fpu_status); +- env->fregs[f1].ll = res.ll.upper; +- env->fregs[f1 + 2].ll = res.ll.lower; +-} +- +-/* convert 32-bit float to 64-bit float */ +-void HELPER(ldebr)(uint32_t r1, uint32_t r2) +-{ +- env->fregs[r1].d = float32_to_float64(env->fregs[r2].l.upper, +- &env->fpu_status); +-} +- +-/* convert 128-bit float to 64-bit float */ +-void HELPER(ldxbr)(uint32_t f1, uint32_t f2) +-{ +- CPU_QuadU x2; +- +- x2.ll.upper = env->fregs[f2].ll; +- x2.ll.lower = env->fregs[f2 + 2].ll; +- env->fregs[f1].d = float128_to_float64(x2.q, &env->fpu_status); +- HELPER_LOG("%s: to 0x%ld\n", __func__, env->fregs[f1].d); +-} +- +-/* convert 64-bit float to 128-bit float */ +-void HELPER(lxdbr)(uint32_t f1, uint32_t f2) +-{ +- CPU_QuadU res; +- +- res.q = float64_to_float128(env->fregs[f2].d, &env->fpu_status); +- env->fregs[f1].ll = res.ll.upper; +- env->fregs[f1 + 2].ll = res.ll.lower; +-} +- +-/* convert 64-bit float to 32-bit float */ +-void HELPER(ledbr)(uint32_t f1, uint32_t f2) +-{ +- float64 d2 = env->fregs[f2].d; +- +- env->fregs[f1].l.upper = float64_to_float32(d2, &env->fpu_status); +-} +- +-/* convert 128-bit float to 32-bit float */ +-void HELPER(lexbr)(uint32_t f1, uint32_t f2) +-{ +- CPU_QuadU x2; +- +- x2.ll.upper = env->fregs[f2].ll; +- x2.ll.lower = env->fregs[f2 + 2].ll; +- env->fregs[f1].l.upper = float128_to_float32(x2.q, &env->fpu_status); +- HELPER_LOG("%s: to 0x%d\n", __func__, env->fregs[f1].l.upper); +-} +- +-/* absolute value of 32-bit float */ +-uint32_t HELPER(lpebr)(uint32_t f1, uint32_t f2) +-{ +- float32 v1; +- float32 v2 = env->fregs[f2].d; +- +- v1 = float32_abs(v2); +- env->fregs[f1].d = v1; +- return set_cc_nz_f32(v1); +-} +- +-/* absolute value of 64-bit float */ +-uint32_t HELPER(lpdbr)(uint32_t f1, uint32_t f2) +-{ +- float64 v1; +- float64 v2 = env->fregs[f2].d; +- +- v1 = float64_abs(v2); +- env->fregs[f1].d = v1; +- return set_cc_nz_f64(v1); +-} +- +-/* absolute value of 128-bit float */ +-uint32_t HELPER(lpxbr)(uint32_t f1, uint32_t f2) +-{ +- CPU_QuadU v1; +- CPU_QuadU v2; +- +- v2.ll.upper = env->fregs[f2].ll; +- v2.ll.lower = env->fregs[f2 + 2].ll; +- v1.q = float128_abs(v2.q); +- env->fregs[f1].ll = v1.ll.upper; +- env->fregs[f1 + 2].ll = v1.ll.lower; +- return set_cc_nz_f128(v1.q); +-} +- +-/* load and test 64-bit float */ +-uint32_t HELPER(ltdbr)(uint32_t f1, uint32_t f2) +-{ +- env->fregs[f1].d = env->fregs[f2].d; +- return set_cc_nz_f64(env->fregs[f1].d); +-} +- +-/* load and test 32-bit float */ +-uint32_t HELPER(ltebr)(uint32_t f1, uint32_t f2) +-{ +- env->fregs[f1].l.upper = env->fregs[f2].l.upper; +- return set_cc_nz_f32(env->fregs[f1].l.upper); +-} +- +-/* load and test 128-bit float */ +-uint32_t HELPER(ltxbr)(uint32_t f1, uint32_t f2) +-{ +- CPU_QuadU x; +- +- x.ll.upper = env->fregs[f2].ll; +- x.ll.lower = env->fregs[f2 + 2].ll; +- env->fregs[f1].ll = x.ll.upper; +- env->fregs[f1 + 2].ll = x.ll.lower; +- return set_cc_nz_f128(x.q); +-} +- +-/* load complement of 32-bit float */ +-uint32_t HELPER(lcebr)(uint32_t f1, uint32_t f2) +-{ +- env->fregs[f1].l.upper = float32_chs(env->fregs[f2].l.upper); +- +- return set_cc_nz_f32(env->fregs[f1].l.upper); +-} +- +-/* load complement of 64-bit float */ +-uint32_t HELPER(lcdbr)(uint32_t f1, uint32_t f2) +-{ +- env->fregs[f1].d = float64_chs(env->fregs[f2].d); +- +- return set_cc_nz_f64(env->fregs[f1].d); +-} +- +-/* load complement of 128-bit float */ +-uint32_t HELPER(lcxbr)(uint32_t f1, uint32_t f2) +-{ +- CPU_QuadU x1, x2; +- +- x2.ll.upper = env->fregs[f2].ll; +- x2.ll.lower = env->fregs[f2 + 2].ll; +- x1.q = float128_chs(x2.q); +- env->fregs[f1].ll = x1.ll.upper; +- env->fregs[f1 + 2].ll = x1.ll.lower; +- return set_cc_nz_f128(x1.q); +-} +- +-/* 32-bit FP addition RM */ +-void HELPER(aeb)(uint32_t f1, uint32_t val) +-{ +- float32 v1 = env->fregs[f1].l.upper; +- CPU_FloatU v2; +- +- v2.l = val; +- HELPER_LOG("%s: adding 0x%d from f%d and 0x%d\n", __func__, +- v1, f1, v2.f); +- env->fregs[f1].l.upper = float32_add(v1, v2.f, &env->fpu_status); +-} +- +-/* 32-bit FP division RM */ +-void HELPER(deb)(uint32_t f1, uint32_t val) +-{ +- float32 v1 = env->fregs[f1].l.upper; +- CPU_FloatU v2; +- +- v2.l = val; +- HELPER_LOG("%s: dividing 0x%d from f%d by 0x%d\n", __func__, +- v1, f1, v2.f); +- env->fregs[f1].l.upper = float32_div(v1, v2.f, &env->fpu_status); +-} +- +-/* 32-bit FP multiplication RM */ +-void HELPER(meeb)(uint32_t f1, uint32_t val) +-{ +- float32 v1 = env->fregs[f1].l.upper; +- CPU_FloatU v2; +- +- v2.l = val; +- HELPER_LOG("%s: multiplying 0x%d from f%d and 0x%d\n", __func__, +- v1, f1, v2.f); +- env->fregs[f1].l.upper = float32_mul(v1, v2.f, &env->fpu_status); +-} +- +-/* 32-bit FP compare RR */ +-uint32_t HELPER(cebr)(uint32_t f1, uint32_t f2) +-{ +- float32 v1 = env->fregs[f1].l.upper; +- float32 v2 = env->fregs[f2].l.upper; +- +- HELPER_LOG("%s: comparing 0x%d from f%d and 0x%d\n", __func__, +- v1, f1, v2); +- return set_cc_f32(v1, v2); +-} +- +-/* 64-bit FP compare RR */ +-uint32_t HELPER(cdbr)(uint32_t f1, uint32_t f2) +-{ +- float64 v1 = env->fregs[f1].d; +- float64 v2 = env->fregs[f2].d; +- +- HELPER_LOG("%s: comparing 0x%ld from f%d and 0x%ld\n", __func__, +- v1, f1, v2); +- return set_cc_f64(v1, v2); +-} +- +-/* 128-bit FP compare RR */ +-uint32_t HELPER(cxbr)(uint32_t f1, uint32_t f2) +-{ +- CPU_QuadU v1; +- CPU_QuadU v2; +- +- v1.ll.upper = env->fregs[f1].ll; +- v1.ll.lower = env->fregs[f1 + 2].ll; +- v2.ll.upper = env->fregs[f2].ll; +- v2.ll.lower = env->fregs[f2 + 2].ll; +- +- return float_comp_to_cc(float128_compare_quiet(v1.q, v2.q, +- &env->fpu_status)); +-} +- +-/* 64-bit FP compare RM */ +-uint32_t HELPER(cdb)(uint32_t f1, uint64_t a2) +-{ +- float64 v1 = env->fregs[f1].d; +- CPU_DoubleU v2; +- +- v2.ll = ldq(a2); +- HELPER_LOG("%s: comparing 0x%ld from f%d and 0x%lx\n", __func__, v1, +- f1, v2.d); +- return set_cc_f64(v1, v2.d); +-} +- +-/* 64-bit FP addition RM */ +-uint32_t HELPER(adb)(uint32_t f1, uint64_t a2) +-{ +- float64 v1 = env->fregs[f1].d; +- CPU_DoubleU v2; +- +- v2.ll = ldq(a2); +- HELPER_LOG("%s: adding 0x%lx from f%d and 0x%lx\n", __func__, +- v1, f1, v2.d); +- env->fregs[f1].d = v1 = float64_add(v1, v2.d, &env->fpu_status); +- return set_cc_nz_f64(v1); +-} +- +-/* 32-bit FP subtraction RM */ +-void HELPER(seb)(uint32_t f1, uint32_t val) +-{ +- float32 v1 = env->fregs[f1].l.upper; +- CPU_FloatU v2; +- +- v2.l = val; +- env->fregs[f1].l.upper = float32_sub(v1, v2.f, &env->fpu_status); +-} +- +-/* 64-bit FP subtraction RM */ +-uint32_t HELPER(sdb)(uint32_t f1, uint64_t a2) +-{ +- float64 v1 = env->fregs[f1].d; +- CPU_DoubleU v2; +- +- v2.ll = ldq(a2); +- env->fregs[f1].d = v1 = float64_sub(v1, v2.d, &env->fpu_status); +- return set_cc_nz_f64(v1); +-} +- +-/* 64-bit FP multiplication RM */ +-void HELPER(mdb)(uint32_t f1, uint64_t a2) +-{ +- float64 v1 = env->fregs[f1].d; +- CPU_DoubleU v2; +- +- v2.ll = ldq(a2); +- HELPER_LOG("%s: multiplying 0x%lx from f%d and 0x%ld\n", __func__, +- v1, f1, v2.d); +- env->fregs[f1].d = float64_mul(v1, v2.d, &env->fpu_status); +-} +- +-/* 64-bit FP division RM */ +-void HELPER(ddb)(uint32_t f1, uint64_t a2) +-{ +- float64 v1 = env->fregs[f1].d; +- CPU_DoubleU v2; +- +- v2.ll = ldq(a2); +- HELPER_LOG("%s: dividing 0x%lx from f%d by 0x%ld\n", __func__, +- v1, f1, v2.d); +- env->fregs[f1].d = float64_div(v1, v2.d, &env->fpu_status); +-} +- +-static void set_round_mode(int m3) +-{ +- switch (m3) { +- case 0: +- /* current mode */ +- break; +- case 1: +- /* biased round no nearest */ +- case 4: +- /* round to nearest */ +- set_float_rounding_mode(float_round_nearest_even, &env->fpu_status); +- break; +- case 5: +- /* round to zero */ +- set_float_rounding_mode(float_round_to_zero, &env->fpu_status); +- break; +- case 6: +- /* round to +inf */ +- set_float_rounding_mode(float_round_up, &env->fpu_status); +- break; +- case 7: +- /* round to -inf */ +- set_float_rounding_mode(float_round_down, &env->fpu_status); +- break; +- } +-} +- +-/* convert 32-bit float to 64-bit int */ +-uint32_t HELPER(cgebr)(uint32_t r1, uint32_t f2, uint32_t m3) +-{ +- float32 v2 = env->fregs[f2].l.upper; +- +- set_round_mode(m3); +- env->regs[r1] = float32_to_int64(v2, &env->fpu_status); +- return set_cc_nz_f32(v2); +-} +- +-/* convert 64-bit float to 64-bit int */ +-uint32_t HELPER(cgdbr)(uint32_t r1, uint32_t f2, uint32_t m3) +-{ +- float64 v2 = env->fregs[f2].d; +- +- set_round_mode(m3); +- env->regs[r1] = float64_to_int64(v2, &env->fpu_status); +- return set_cc_nz_f64(v2); +-} +- +-/* convert 128-bit float to 64-bit int */ +-uint32_t HELPER(cgxbr)(uint32_t r1, uint32_t f2, uint32_t m3) +-{ +- CPU_QuadU v2; +- +- v2.ll.upper = env->fregs[f2].ll; +- v2.ll.lower = env->fregs[f2 + 2].ll; +- set_round_mode(m3); +- env->regs[r1] = float128_to_int64(v2.q, &env->fpu_status); +- if (float128_is_any_nan(v2.q)) { +- return 3; +- } else if (float128_is_zero(v2.q)) { +- return 0; +- } else if (float128_is_neg(v2.q)) { +- return 1; +- } else { +- return 2; +- } +-} +- +-/* convert 32-bit float to 32-bit int */ +-uint32_t HELPER(cfebr)(uint32_t r1, uint32_t f2, uint32_t m3) +-{ +- float32 v2 = env->fregs[f2].l.upper; +- +- set_round_mode(m3); +- env->regs[r1] = (env->regs[r1] & 0xffffffff00000000ULL) | +- float32_to_int32(v2, &env->fpu_status); +- return set_cc_nz_f32(v2); +-} +- +-/* convert 64-bit float to 32-bit int */ +-uint32_t HELPER(cfdbr)(uint32_t r1, uint32_t f2, uint32_t m3) +-{ +- float64 v2 = env->fregs[f2].d; +- +- set_round_mode(m3); +- env->regs[r1] = (env->regs[r1] & 0xffffffff00000000ULL) | +- float64_to_int32(v2, &env->fpu_status); +- return set_cc_nz_f64(v2); +-} +- +-/* convert 128-bit float to 32-bit int */ +-uint32_t HELPER(cfxbr)(uint32_t r1, uint32_t f2, uint32_t m3) +-{ +- CPU_QuadU v2; +- +- v2.ll.upper = env->fregs[f2].ll; +- v2.ll.lower = env->fregs[f2 + 2].ll; +- env->regs[r1] = (env->regs[r1] & 0xffffffff00000000ULL) | +- float128_to_int32(v2.q, &env->fpu_status); +- return set_cc_nz_f128(v2.q); +-} +- +-/* load 32-bit FP zero */ +-void HELPER(lzer)(uint32_t f1) +-{ +- env->fregs[f1].l.upper = float32_zero; +-} +- +-/* load 64-bit FP zero */ +-void HELPER(lzdr)(uint32_t f1) +-{ +- env->fregs[f1].d = float64_zero; +-} +- +-/* load 128-bit FP zero */ +-void HELPER(lzxr)(uint32_t f1) +-{ +- CPU_QuadU x; +- +- x.q = float64_to_float128(float64_zero, &env->fpu_status); +- env->fregs[f1].ll = x.ll.upper; +- env->fregs[f1 + 1].ll = x.ll.lower; +-} +- +-/* 128-bit FP subtraction RR */ +-uint32_t HELPER(sxbr)(uint32_t f1, uint32_t f2) +-{ +- CPU_QuadU v1; +- CPU_QuadU v2; +- CPU_QuadU res; +- +- v1.ll.upper = env->fregs[f1].ll; +- v1.ll.lower = env->fregs[f1 + 2].ll; +- v2.ll.upper = env->fregs[f2].ll; +- v2.ll.lower = env->fregs[f2 + 2].ll; +- res.q = float128_sub(v1.q, v2.q, &env->fpu_status); +- env->fregs[f1].ll = res.ll.upper; +- env->fregs[f1 + 2].ll = res.ll.lower; +- return set_cc_nz_f128(res.q); +-} +- +-/* 128-bit FP addition RR */ +-uint32_t HELPER(axbr)(uint32_t f1, uint32_t f2) +-{ +- CPU_QuadU v1; +- CPU_QuadU v2; +- CPU_QuadU res; +- +- v1.ll.upper = env->fregs[f1].ll; +- v1.ll.lower = env->fregs[f1 + 2].ll; +- v2.ll.upper = env->fregs[f2].ll; +- v2.ll.lower = env->fregs[f2 + 2].ll; +- res.q = float128_add(v1.q, v2.q, &env->fpu_status); +- env->fregs[f1].ll = res.ll.upper; +- env->fregs[f1 + 2].ll = res.ll.lower; +- return set_cc_nz_f128(res.q); +-} +- +-/* 32-bit FP multiplication RR */ +-void HELPER(meebr)(uint32_t f1, uint32_t f2) +-{ +- env->fregs[f1].l.upper = float32_mul(env->fregs[f1].l.upper, +- env->fregs[f2].l.upper, +- &env->fpu_status); +-} +- +-/* 64-bit FP division RR */ +-void HELPER(ddbr)(uint32_t f1, uint32_t f2) +-{ +- env->fregs[f1].d = float64_div(env->fregs[f1].d, env->fregs[f2].d, +- &env->fpu_status); +-} +- +-/* 64-bit FP multiply and add RM */ +-void HELPER(madb)(uint32_t f1, uint64_t a2, uint32_t f3) +-{ +- CPU_DoubleU v2; +- +- HELPER_LOG("%s: f1 %d a2 0x%lx f3 %d\n", __func__, f1, a2, f3); +- v2.ll = ldq(a2); +- env->fregs[f1].d = float64_add(env->fregs[f1].d, +- float64_mul(v2.d, env->fregs[f3].d, +- &env->fpu_status), +- &env->fpu_status); +-} +- +-/* 64-bit FP multiply and add RR */ +-void HELPER(madbr)(uint32_t f1, uint32_t f3, uint32_t f2) +-{ +- HELPER_LOG("%s: f1 %d f2 %d f3 %d\n", __func__, f1, f2, f3); +- env->fregs[f1].d = float64_add(float64_mul(env->fregs[f2].d, +- env->fregs[f3].d, +- &env->fpu_status), +- env->fregs[f1].d, &env->fpu_status); +-} +- +-/* 64-bit FP multiply and subtract RR */ +-void HELPER(msdbr)(uint32_t f1, uint32_t f3, uint32_t f2) +-{ +- HELPER_LOG("%s: f1 %d f2 %d f3 %d\n", __func__, f1, f2, f3); +- env->fregs[f1].d = float64_sub(float64_mul(env->fregs[f2].d, +- env->fregs[f3].d, +- &env->fpu_status), +- env->fregs[f1].d, &env->fpu_status); +-} +- +-/* 32-bit FP multiply and add RR */ +-void HELPER(maebr)(uint32_t f1, uint32_t f3, uint32_t f2) +-{ +- env->fregs[f1].l.upper = float32_add(env->fregs[f1].l.upper, +- float32_mul(env->fregs[f2].l.upper, +- env->fregs[f3].l.upper, +- &env->fpu_status), +- &env->fpu_status); +-} +- +-/* convert 32-bit float to 64-bit float */ +-void HELPER(ldeb)(uint32_t f1, uint64_t a2) +-{ +- uint32_t v2; +- +- v2 = ldl(a2); +- env->fregs[f1].d = float32_to_float64(v2, +- &env->fpu_status); +-} +- +-/* convert 64-bit float to 128-bit float */ +-void HELPER(lxdb)(uint32_t f1, uint64_t a2) +-{ +- CPU_DoubleU v2; +- CPU_QuadU v1; +- +- v2.ll = ldq(a2); +- v1.q = float64_to_float128(v2.d, &env->fpu_status); +- env->fregs[f1].ll = v1.ll.upper; +- env->fregs[f1 + 2].ll = v1.ll.lower; +-} +- +-/* test data class 32-bit */ +-uint32_t HELPER(tceb)(uint32_t f1, uint64_t m2) +-{ +- float32 v1 = env->fregs[f1].l.upper; +- int neg = float32_is_neg(v1); +- uint32_t cc = 0; +- +- HELPER_LOG("%s: v1 0x%lx m2 0x%lx neg %d\n", __func__, (long)v1, m2, neg); +- if ((float32_is_zero(v1) && (m2 & (1 << (11-neg)))) || +- (float32_is_infinity(v1) && (m2 & (1 << (5-neg)))) || +- (float32_is_any_nan(v1) && (m2 & (1 << (3-neg)))) || +- (float32_is_signaling_nan(v1) && (m2 & (1 << (1-neg))))) { +- cc = 1; +- } else if (m2 & (1 << (9-neg))) { +- /* assume normalized number */ +- cc = 1; +- } +- +- /* FIXME: denormalized? */ +- return cc; +-} +- +-/* test data class 64-bit */ +-uint32_t HELPER(tcdb)(uint32_t f1, uint64_t m2) +-{ +- float64 v1 = env->fregs[f1].d; +- int neg = float64_is_neg(v1); +- uint32_t cc = 0; +- +- HELPER_LOG("%s: v1 0x%lx m2 0x%lx neg %d\n", __func__, v1, m2, neg); +- if ((float64_is_zero(v1) && (m2 & (1 << (11-neg)))) || +- (float64_is_infinity(v1) && (m2 & (1 << (5-neg)))) || +- (float64_is_any_nan(v1) && (m2 & (1 << (3-neg)))) || +- (float64_is_signaling_nan(v1) && (m2 & (1 << (1-neg))))) { +- cc = 1; +- } else if (m2 & (1 << (9-neg))) { +- /* assume normalized number */ +- cc = 1; +- } +- /* FIXME: denormalized? */ +- return cc; +-} +- +-/* test data class 128-bit */ +-uint32_t HELPER(tcxb)(uint32_t f1, uint64_t m2) +-{ +- CPU_QuadU v1; +- uint32_t cc = 0; +- int neg; +- +- v1.ll.upper = env->fregs[f1].ll; +- v1.ll.lower = env->fregs[f1 + 2].ll; +- +- neg = float128_is_neg(v1.q); +- if ((float128_is_zero(v1.q) && (m2 & (1 << (11-neg)))) || +- (float128_is_infinity(v1.q) && (m2 & (1 << (5-neg)))) || +- (float128_is_any_nan(v1.q) && (m2 & (1 << (3-neg)))) || +- (float128_is_signaling_nan(v1.q) && (m2 & (1 << (1-neg))))) { +- cc = 1; +- } else if (m2 & (1 << (9-neg))) { +- /* assume normalized number */ +- cc = 1; +- } +- /* FIXME: denormalized? */ +- return cc; +-} +- + /* find leftmost one */ + uint32_t HELPER(flogr)(uint32_t r1, uint64_t v2) + { +@@ -1795,12 +999,6 @@ uint32_t HELPER(flogr)(uint32_t r1, uint64_t v2) + } + } + +-/* square root 64-bit RR */ +-void HELPER(sqdbr)(uint32_t f1, uint32_t f2) +-{ +- env->fregs[f1].d = float64_sqrt(env->fregs[f2].d, &env->fpu_status); +-} +- + /* checksum */ + void HELPER(cksm)(uint32_t r1, uint32_t r2) + { +diff --git a/target-s390x/translate.c b/target-s390x/translate.c +index 1c1baf5..c370df3 100644 +--- a/target-s390x/translate.c ++++ b/target-s390x/translate.c +@@ -667,16 +667,11 @@ static void set_cc_cmp_f32_i64(DisasContext *s, TCGv_i32 v1, TCGv_i64 v2) + s->cc_op = CC_OP_LTGT_F32; + } + +-static void set_cc_nz_f32(DisasContext *s, TCGv_i32 v1) ++static void gen_set_cc_nz_f32(DisasContext *s, TCGv_i32 v1) + { + gen_op_update1_cc_i32(s, CC_OP_NZ_F32, v1); + } + +-static inline void set_cc_nz_f64(DisasContext *s, TCGv_i64 v1) +-{ +- gen_op_update1_cc_i64(s, CC_OP_NZ_F64, v1); +-} +- + /* CC value is in env->cc_op */ + static inline void set_cc_static(DisasContext *s) + { +@@ -2235,7 +2230,7 @@ static void disas_ed(DisasContext *s, int op, int r1, int x2, int b2, int d2, + tcg_temp_free_i32(tmp32); + + tmp32 = load_freg32(r1); +- set_cc_nz_f32(s, tmp32); ++ gen_set_cc_nz_f32(s, tmp32); + tcg_temp_free_i32(tmp32); + break; + case 0xb: /* SEB R1,D2(X2,B2) [RXE] */ +@@ -2248,7 +2243,7 @@ static void disas_ed(DisasContext *s, int op, int r1, int x2, int b2, int d2, + tcg_temp_free_i32(tmp32); + + tmp32 = load_freg32(r1); +- set_cc_nz_f32(s, tmp32); ++ gen_set_cc_nz_f32(s, tmp32); + tcg_temp_free_i32(tmp32); + break; + case 0xd: /* DEB R1,D2(X2,B2) [RXE] */ +-- +1.7.12.1 + diff --git a/0007-target-s390x-split-condition-code-helpers.patch b/0007-target-s390x-split-condition-code-helpers.patch new file mode 100644 index 0000000..33ddc67 --- /dev/null +++ b/0007-target-s390x-split-condition-code-helpers.patch @@ -0,0 +1,1158 @@ +From f642126aece222f6ff87d26c29f00e1b6c47e10a Mon Sep 17 00:00:00 2001 +From: Blue Swirl +Date: Sun, 2 Sep 2012 07:33:32 +0000 +Subject: [PATCH] target-s390x: split condition code helpers + +Move condition code helpers to cc_helper.c. + +Signed-off-by: Blue Swirl +Signed-off-by: Alexander Graf +Signed-off-by: Michael Roth +--- + target-s390x/Makefile.objs | 3 +- + target-s390x/cc_helper.c | 551 +++++++++++++++++++++++++++++++++++++++++++++ + target-s390x/cpu.h | 3 + + target-s390x/op_helper.c | 522 +----------------------------------------- + 4 files changed, 557 insertions(+), 522 deletions(-) + create mode 100644 target-s390x/cc_helper.c + +diff --git a/target-s390x/Makefile.objs b/target-s390x/Makefile.objs +index 23b3bd9..f9437d6 100644 +--- a/target-s390x/Makefile.objs ++++ b/target-s390x/Makefile.objs +@@ -1,7 +1,8 @@ + obj-y += translate.o op_helper.o helper.o cpu.o interrupt.o +-obj-y += fpu_helper.o ++obj-y += fpu_helper.o cc_helper.o + obj-$(CONFIG_SOFTMMU) += machine.o + obj-$(CONFIG_KVM) += kvm.o + + $(obj)/op_helper.o: QEMU_CFLAGS += $(HELPER_CFLAGS) + $(obj)/fpu_helper.o: QEMU_CFLAGS += $(HELPER_CFLAGS) ++$(obj)/cc_helper.o: QEMU_CFLAGS += $(HELPER_CFLAGS) +diff --git a/target-s390x/cc_helper.c b/target-s390x/cc_helper.c +new file mode 100644 +index 0000000..2ac1659 +--- /dev/null ++++ b/target-s390x/cc_helper.c +@@ -0,0 +1,551 @@ ++/* ++ * S/390 condition code helper routines ++ * ++ * Copyright (c) 2009 Ulrich Hecht ++ * Copyright (c) 2009 Alexander Graf ++ * ++ * This library is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU Lesser General Public ++ * License as published by the Free Software Foundation; either ++ * version 2 of the License, or (at your option) any later version. ++ * ++ * This library is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * Lesser General Public License for more details. ++ * ++ * You should have received a copy of the GNU Lesser General Public ++ * License along with this library; if not, see . ++ */ ++ ++#include "cpu.h" ++#include "dyngen-exec.h" ++#include "helper.h" ++ ++/* #define DEBUG_HELPER */ ++#ifdef DEBUG_HELPER ++#define HELPER_LOG(x...) qemu_log(x) ++#else ++#define HELPER_LOG(x...) ++#endif ++ ++static inline uint32_t cc_calc_ltgt_32(CPUS390XState *env, int32_t src, ++ int32_t dst) ++{ ++ if (src == dst) { ++ return 0; ++ } else if (src < dst) { ++ return 1; ++ } else { ++ return 2; ++ } ++} ++ ++static inline uint32_t cc_calc_ltgt0_32(CPUS390XState *env, int32_t dst) ++{ ++ return cc_calc_ltgt_32(env, dst, 0); ++} ++ ++static inline uint32_t cc_calc_ltgt_64(CPUS390XState *env, int64_t src, ++ int64_t dst) ++{ ++ if (src == dst) { ++ return 0; ++ } else if (src < dst) { ++ return 1; ++ } else { ++ return 2; ++ } ++} ++ ++static inline uint32_t cc_calc_ltgt0_64(CPUS390XState *env, int64_t dst) ++{ ++ return cc_calc_ltgt_64(env, dst, 0); ++} ++ ++static inline uint32_t cc_calc_ltugtu_32(CPUS390XState *env, uint32_t src, ++ uint32_t dst) ++{ ++ if (src == dst) { ++ return 0; ++ } else if (src < dst) { ++ return 1; ++ } else { ++ return 2; ++ } ++} ++ ++static inline uint32_t cc_calc_ltugtu_64(CPUS390XState *env, uint64_t src, ++ uint64_t dst) ++{ ++ if (src == dst) { ++ return 0; ++ } else if (src < dst) { ++ return 1; ++ } else { ++ return 2; ++ } ++} ++ ++static inline uint32_t cc_calc_tm_32(CPUS390XState *env, uint32_t val, ++ uint32_t mask) ++{ ++ uint16_t r = val & mask; ++ ++ HELPER_LOG("%s: val 0x%x mask 0x%x\n", __func__, val, mask); ++ if (r == 0 || mask == 0) { ++ return 0; ++ } else if (r == mask) { ++ return 3; ++ } else { ++ return 1; ++ } ++} ++ ++/* set condition code for test under mask */ ++static inline uint32_t cc_calc_tm_64(CPUS390XState *env, uint64_t val, ++ uint32_t mask) ++{ ++ uint16_t r = val & mask; ++ ++ HELPER_LOG("%s: val 0x%lx mask 0x%x r 0x%x\n", __func__, val, mask, r); ++ if (r == 0 || mask == 0) { ++ return 0; ++ } else if (r == mask) { ++ return 3; ++ } else { ++ while (!(mask & 0x8000)) { ++ mask <<= 1; ++ val <<= 1; ++ } ++ if (val & 0x8000) { ++ return 2; ++ } else { ++ return 1; ++ } ++ } ++} ++ ++static inline uint32_t cc_calc_nz(CPUS390XState *env, uint64_t dst) ++{ ++ return !!dst; ++} ++ ++static inline uint32_t cc_calc_add_64(CPUS390XState *env, int64_t a1, ++ int64_t a2, int64_t ar) ++{ ++ if ((a1 > 0 && a2 > 0 && ar < 0) || (a1 < 0 && a2 < 0 && ar > 0)) { ++ return 3; /* overflow */ ++ } else { ++ if (ar < 0) { ++ return 1; ++ } else if (ar > 0) { ++ return 2; ++ } else { ++ return 0; ++ } ++ } ++} ++ ++static inline uint32_t cc_calc_addu_64(CPUS390XState *env, uint64_t a1, ++ uint64_t a2, uint64_t ar) ++{ ++ if (ar == 0) { ++ if (a1) { ++ return 2; ++ } else { ++ return 0; ++ } ++ } else { ++ if (ar < a1 || ar < a2) { ++ return 3; ++ } else { ++ return 1; ++ } ++ } ++} ++ ++static inline uint32_t cc_calc_sub_64(CPUS390XState *env, int64_t a1, ++ int64_t a2, int64_t ar) ++{ ++ if ((a1 > 0 && a2 < 0 && ar < 0) || (a1 < 0 && a2 > 0 && ar > 0)) { ++ return 3; /* overflow */ ++ } else { ++ if (ar < 0) { ++ return 1; ++ } else if (ar > 0) { ++ return 2; ++ } else { ++ return 0; ++ } ++ } ++} ++ ++static inline uint32_t cc_calc_subu_64(CPUS390XState *env, uint64_t a1, ++ uint64_t a2, uint64_t ar) ++{ ++ if (ar == 0) { ++ return 2; ++ } else { ++ if (a2 > a1) { ++ return 1; ++ } else { ++ return 3; ++ } ++ } ++} ++ ++static inline uint32_t cc_calc_abs_64(CPUS390XState *env, int64_t dst) ++{ ++ if ((uint64_t)dst == 0x8000000000000000ULL) { ++ return 3; ++ } else if (dst) { ++ return 1; ++ } else { ++ return 0; ++ } ++} ++ ++static inline uint32_t cc_calc_nabs_64(CPUS390XState *env, int64_t dst) ++{ ++ return !!dst; ++} ++ ++static inline uint32_t cc_calc_comp_64(CPUS390XState *env, int64_t dst) ++{ ++ if ((uint64_t)dst == 0x8000000000000000ULL) { ++ return 3; ++ } else if (dst < 0) { ++ return 1; ++ } else if (dst > 0) { ++ return 2; ++ } else { ++ return 0; ++ } ++} ++ ++ ++static inline uint32_t cc_calc_add_32(CPUS390XState *env, int32_t a1, ++ int32_t a2, int32_t ar) ++{ ++ if ((a1 > 0 && a2 > 0 && ar < 0) || (a1 < 0 && a2 < 0 && ar > 0)) { ++ return 3; /* overflow */ ++ } else { ++ if (ar < 0) { ++ return 1; ++ } else if (ar > 0) { ++ return 2; ++ } else { ++ return 0; ++ } ++ } ++} ++ ++static inline uint32_t cc_calc_addu_32(CPUS390XState *env, uint32_t a1, ++ uint32_t a2, uint32_t ar) ++{ ++ if (ar == 0) { ++ if (a1) { ++ return 2; ++ } else { ++ return 0; ++ } ++ } else { ++ if (ar < a1 || ar < a2) { ++ return 3; ++ } else { ++ return 1; ++ } ++ } ++} ++ ++static inline uint32_t cc_calc_sub_32(CPUS390XState *env, int32_t a1, ++ int32_t a2, int32_t ar) ++{ ++ if ((a1 > 0 && a2 < 0 && ar < 0) || (a1 < 0 && a2 > 0 && ar > 0)) { ++ return 3; /* overflow */ ++ } else { ++ if (ar < 0) { ++ return 1; ++ } else if (ar > 0) { ++ return 2; ++ } else { ++ return 0; ++ } ++ } ++} ++ ++static inline uint32_t cc_calc_subu_32(CPUS390XState *env, uint32_t a1, ++ uint32_t a2, uint32_t ar) ++{ ++ if (ar == 0) { ++ return 2; ++ } else { ++ if (a2 > a1) { ++ return 1; ++ } else { ++ return 3; ++ } ++ } ++} ++ ++static inline uint32_t cc_calc_abs_32(CPUS390XState *env, int32_t dst) ++{ ++ if ((uint32_t)dst == 0x80000000UL) { ++ return 3; ++ } else if (dst) { ++ return 1; ++ } else { ++ return 0; ++ } ++} ++ ++static inline uint32_t cc_calc_nabs_32(CPUS390XState *env, int32_t dst) ++{ ++ return !!dst; ++} ++ ++static inline uint32_t cc_calc_comp_32(CPUS390XState *env, int32_t dst) ++{ ++ if ((uint32_t)dst == 0x80000000UL) { ++ return 3; ++ } else if (dst < 0) { ++ return 1; ++ } else if (dst > 0) { ++ return 2; ++ } else { ++ return 0; ++ } ++} ++ ++/* calculate condition code for insert character under mask insn */ ++static inline uint32_t cc_calc_icm_32(CPUS390XState *env, uint32_t mask, ++ uint32_t val) ++{ ++ uint32_t cc; ++ ++ HELPER_LOG("%s: mask 0x%x val %d\n", __func__, mask, val); ++ if (mask == 0xf) { ++ if (!val) { ++ return 0; ++ } else if (val & 0x80000000) { ++ return 1; ++ } else { ++ return 2; ++ } ++ } ++ ++ if (!val || !mask) { ++ cc = 0; ++ } else { ++ while (mask != 1) { ++ mask >>= 1; ++ val >>= 8; ++ } ++ if (val & 0x80) { ++ cc = 1; ++ } else { ++ cc = 2; ++ } ++ } ++ return cc; ++} ++ ++static inline uint32_t cc_calc_slag(CPUS390XState *env, uint64_t src, ++ uint64_t shift) ++{ ++ uint64_t mask = ((1ULL << shift) - 1ULL) << (64 - shift); ++ uint64_t match, r; ++ ++ /* check if the sign bit stays the same */ ++ if (src & (1ULL << 63)) { ++ match = mask; ++ } else { ++ match = 0; ++ } ++ ++ if ((src & mask) != match) { ++ /* overflow */ ++ return 3; ++ } ++ ++ r = ((src << shift) & ((1ULL << 63) - 1)) | (src & (1ULL << 63)); ++ ++ if ((int64_t)r == 0) { ++ return 0; ++ } else if ((int64_t)r < 0) { ++ return 1; ++ } ++ ++ return 2; ++} ++ ++ ++static inline uint32_t do_calc_cc(CPUS390XState *env, uint32_t cc_op, ++ uint64_t src, uint64_t dst, uint64_t vr) ++{ ++ uint32_t r = 0; ++ ++ switch (cc_op) { ++ case CC_OP_CONST0: ++ case CC_OP_CONST1: ++ case CC_OP_CONST2: ++ case CC_OP_CONST3: ++ /* cc_op value _is_ cc */ ++ r = cc_op; ++ break; ++ case CC_OP_LTGT0_32: ++ r = cc_calc_ltgt0_32(env, dst); ++ break; ++ case CC_OP_LTGT0_64: ++ r = cc_calc_ltgt0_64(env, dst); ++ break; ++ case CC_OP_LTGT_32: ++ r = cc_calc_ltgt_32(env, src, dst); ++ break; ++ case CC_OP_LTGT_64: ++ r = cc_calc_ltgt_64(env, src, dst); ++ break; ++ case CC_OP_LTUGTU_32: ++ r = cc_calc_ltugtu_32(env, src, dst); ++ break; ++ case CC_OP_LTUGTU_64: ++ r = cc_calc_ltugtu_64(env, src, dst); ++ break; ++ case CC_OP_TM_32: ++ r = cc_calc_tm_32(env, src, dst); ++ break; ++ case CC_OP_TM_64: ++ r = cc_calc_tm_64(env, src, dst); ++ break; ++ case CC_OP_NZ: ++ r = cc_calc_nz(env, dst); ++ break; ++ case CC_OP_ADD_64: ++ r = cc_calc_add_64(env, src, dst, vr); ++ break; ++ case CC_OP_ADDU_64: ++ r = cc_calc_addu_64(env, src, dst, vr); ++ break; ++ case CC_OP_SUB_64: ++ r = cc_calc_sub_64(env, src, dst, vr); ++ break; ++ case CC_OP_SUBU_64: ++ r = cc_calc_subu_64(env, src, dst, vr); ++ break; ++ case CC_OP_ABS_64: ++ r = cc_calc_abs_64(env, dst); ++ break; ++ case CC_OP_NABS_64: ++ r = cc_calc_nabs_64(env, dst); ++ break; ++ case CC_OP_COMP_64: ++ r = cc_calc_comp_64(env, dst); ++ break; ++ ++ case CC_OP_ADD_32: ++ r = cc_calc_add_32(env, src, dst, vr); ++ break; ++ case CC_OP_ADDU_32: ++ r = cc_calc_addu_32(env, src, dst, vr); ++ break; ++ case CC_OP_SUB_32: ++ r = cc_calc_sub_32(env, src, dst, vr); ++ break; ++ case CC_OP_SUBU_32: ++ r = cc_calc_subu_32(env, src, dst, vr); ++ break; ++ case CC_OP_ABS_32: ++ r = cc_calc_abs_64(env, dst); ++ break; ++ case CC_OP_NABS_32: ++ r = cc_calc_nabs_64(env, dst); ++ break; ++ case CC_OP_COMP_32: ++ r = cc_calc_comp_32(env, dst); ++ break; ++ ++ case CC_OP_ICM: ++ r = cc_calc_icm_32(env, src, dst); ++ break; ++ case CC_OP_SLAG: ++ r = cc_calc_slag(env, src, dst); ++ break; ++ ++ case CC_OP_LTGT_F32: ++ r = set_cc_f32(src, dst); ++ break; ++ case CC_OP_LTGT_F64: ++ r = set_cc_f64(src, dst); ++ break; ++ case CC_OP_NZ_F32: ++ r = set_cc_nz_f32(dst); ++ break; ++ case CC_OP_NZ_F64: ++ r = set_cc_nz_f64(dst); ++ break; ++ ++ default: ++ cpu_abort(env, "Unknown CC operation: %s\n", cc_name(cc_op)); ++ } ++ ++ HELPER_LOG("%s: %15s 0x%016lx 0x%016lx 0x%016lx = %d\n", __func__, ++ cc_name(cc_op), src, dst, vr, r); ++ return r; ++} ++ ++uint32_t calc_cc(CPUS390XState *env, uint32_t cc_op, uint64_t src, uint64_t dst, ++ uint64_t vr) ++{ ++ return do_calc_cc(env, cc_op, src, dst, vr); ++} ++ ++uint32_t HELPER(calc_cc)(uint32_t cc_op, uint64_t src, uint64_t dst, ++ uint64_t vr) ++{ ++ return do_calc_cc(env, cc_op, src, dst, vr); ++} ++ ++/* insert psw mask and condition code into r1 */ ++void HELPER(ipm)(uint32_t cc, uint32_t r1) ++{ ++ uint64_t r = env->regs[r1]; ++ ++ r &= 0xffffffff00ffffffULL; ++ r |= (cc << 28) | ((env->psw.mask >> 40) & 0xf); ++ env->regs[r1] = r; ++ HELPER_LOG("%s: cc %d psw.mask 0x%lx r1 0x%lx\n", __func__, ++ cc, env->psw.mask, r); ++} ++ ++#ifndef CONFIG_USER_ONLY ++void HELPER(load_psw)(uint64_t mask, uint64_t addr) ++{ ++ load_psw(env, mask, addr); ++ cpu_loop_exit(env); ++} ++ ++void HELPER(sacf)(uint64_t a1) ++{ ++ HELPER_LOG("%s: %16" PRIx64 "\n", __func__, a1); ++ ++ switch (a1 & 0xf00) { ++ case 0x000: ++ env->psw.mask &= ~PSW_MASK_ASC; ++ env->psw.mask |= PSW_ASC_PRIMARY; ++ break; ++ case 0x100: ++ env->psw.mask &= ~PSW_MASK_ASC; ++ env->psw.mask |= PSW_ASC_SECONDARY; ++ break; ++ case 0x300: ++ env->psw.mask &= ~PSW_MASK_ASC; ++ env->psw.mask |= PSW_ASC_HOME; ++ break; ++ default: ++ qemu_log("unknown sacf mode: %" PRIx64 "\n", a1); ++ program_interrupt(env, PGM_SPECIFICATION, 2); ++ break; ++ } ++} ++#endif +diff --git a/target-s390x/cpu.h b/target-s390x/cpu.h +index b4620c5..97fde5e 100644 +--- a/target-s390x/cpu.h ++++ b/target-s390x/cpu.h +@@ -1005,4 +1005,7 @@ uint32_t set_cc_f64(float64 v1, float64 v2); + uint32_t set_cc_nz_f32(float32 v); + uint32_t set_cc_nz_f64(float64 v); + ++/* op_helper.c */ ++void program_interrupt(CPUS390XState *env, uint32_t code, int ilc); ++ + #endif +diff --git a/target-s390x/op_helper.c b/target-s390x/op_helper.c +index 270bf14..eced890 100644 +--- a/target-s390x/op_helper.c ++++ b/target-s390x/op_helper.c +@@ -779,18 +779,6 @@ uint32_t HELPER(icmh)(uint32_t r1, uint64_t address, uint32_t mask) + return cc; + } + +-/* insert psw mask and condition code into r1 */ +-void HELPER(ipm)(uint32_t cc, uint32_t r1) +-{ +- uint64_t r = env->regs[r1]; +- +- r &= 0xffffffff00ffffffULL; +- r |= (cc << 28) | ((env->psw.mask >> 40) & 0xf); +- env->regs[r1] = r; +- HELPER_LOG("%s: cc %d psw.mask 0x%lx r1 0x%lx\n", __func__, +- cc, env->psw.mask, r); +-} +- + /* load access registers r1 to r3 from memory at a2 */ + void HELPER(lam)(uint32_t r1, uint64_t a2, uint32_t r3) + { +@@ -1038,483 +1026,6 @@ void HELPER(cksm)(uint32_t r1, uint32_t r2) + ((uint32_t)cksm + (cksm >> 32)); + } + +-static inline uint32_t cc_calc_ltgt_32(CPUS390XState *env, int32_t src, +- int32_t dst) +-{ +- if (src == dst) { +- return 0; +- } else if (src < dst) { +- return 1; +- } else { +- return 2; +- } +-} +- +-static inline uint32_t cc_calc_ltgt0_32(CPUS390XState *env, int32_t dst) +-{ +- return cc_calc_ltgt_32(env, dst, 0); +-} +- +-static inline uint32_t cc_calc_ltgt_64(CPUS390XState *env, int64_t src, +- int64_t dst) +-{ +- if (src == dst) { +- return 0; +- } else if (src < dst) { +- return 1; +- } else { +- return 2; +- } +-} +- +-static inline uint32_t cc_calc_ltgt0_64(CPUS390XState *env, int64_t dst) +-{ +- return cc_calc_ltgt_64(env, dst, 0); +-} +- +-static inline uint32_t cc_calc_ltugtu_32(CPUS390XState *env, uint32_t src, +- uint32_t dst) +-{ +- if (src == dst) { +- return 0; +- } else if (src < dst) { +- return 1; +- } else { +- return 2; +- } +-} +- +-static inline uint32_t cc_calc_ltugtu_64(CPUS390XState *env, uint64_t src, +- uint64_t dst) +-{ +- if (src == dst) { +- return 0; +- } else if (src < dst) { +- return 1; +- } else { +- return 2; +- } +-} +- +-static inline uint32_t cc_calc_tm_32(CPUS390XState *env, uint32_t val, +- uint32_t mask) +-{ +- uint16_t r = val & mask; +- +- HELPER_LOG("%s: val 0x%x mask 0x%x\n", __func__, val, mask); +- if (r == 0 || mask == 0) { +- return 0; +- } else if (r == mask) { +- return 3; +- } else { +- return 1; +- } +-} +- +-/* set condition code for test under mask */ +-static inline uint32_t cc_calc_tm_64(CPUS390XState *env, uint64_t val, +- uint32_t mask) +-{ +- uint16_t r = val & mask; +- +- HELPER_LOG("%s: val 0x%lx mask 0x%x r 0x%x\n", __func__, val, mask, r); +- if (r == 0 || mask == 0) { +- return 0; +- } else if (r == mask) { +- return 3; +- } else { +- while (!(mask & 0x8000)) { +- mask <<= 1; +- val <<= 1; +- } +- if (val & 0x8000) { +- return 2; +- } else { +- return 1; +- } +- } +-} +- +-static inline uint32_t cc_calc_nz(CPUS390XState *env, uint64_t dst) +-{ +- return !!dst; +-} +- +-static inline uint32_t cc_calc_add_64(CPUS390XState *env, int64_t a1, +- int64_t a2, int64_t ar) +-{ +- if ((a1 > 0 && a2 > 0 && ar < 0) || (a1 < 0 && a2 < 0 && ar > 0)) { +- return 3; /* overflow */ +- } else { +- if (ar < 0) { +- return 1; +- } else if (ar > 0) { +- return 2; +- } else { +- return 0; +- } +- } +-} +- +-static inline uint32_t cc_calc_addu_64(CPUS390XState *env, uint64_t a1, +- uint64_t a2, uint64_t ar) +-{ +- if (ar == 0) { +- if (a1) { +- return 2; +- } else { +- return 0; +- } +- } else { +- if (ar < a1 || ar < a2) { +- return 3; +- } else { +- return 1; +- } +- } +-} +- +-static inline uint32_t cc_calc_sub_64(CPUS390XState *env, int64_t a1, +- int64_t a2, int64_t ar) +-{ +- if ((a1 > 0 && a2 < 0 && ar < 0) || (a1 < 0 && a2 > 0 && ar > 0)) { +- return 3; /* overflow */ +- } else { +- if (ar < 0) { +- return 1; +- } else if (ar > 0) { +- return 2; +- } else { +- return 0; +- } +- } +-} +- +-static inline uint32_t cc_calc_subu_64(CPUS390XState *env, uint64_t a1, +- uint64_t a2, uint64_t ar) +-{ +- if (ar == 0) { +- return 2; +- } else { +- if (a2 > a1) { +- return 1; +- } else { +- return 3; +- } +- } +-} +- +-static inline uint32_t cc_calc_abs_64(CPUS390XState *env, int64_t dst) +-{ +- if ((uint64_t)dst == 0x8000000000000000ULL) { +- return 3; +- } else if (dst) { +- return 1; +- } else { +- return 0; +- } +-} +- +-static inline uint32_t cc_calc_nabs_64(CPUS390XState *env, int64_t dst) +-{ +- return !!dst; +-} +- +-static inline uint32_t cc_calc_comp_64(CPUS390XState *env, int64_t dst) +-{ +- if ((uint64_t)dst == 0x8000000000000000ULL) { +- return 3; +- } else if (dst < 0) { +- return 1; +- } else if (dst > 0) { +- return 2; +- } else { +- return 0; +- } +-} +- +- +-static inline uint32_t cc_calc_add_32(CPUS390XState *env, int32_t a1, +- int32_t a2, int32_t ar) +-{ +- if ((a1 > 0 && a2 > 0 && ar < 0) || (a1 < 0 && a2 < 0 && ar > 0)) { +- return 3; /* overflow */ +- } else { +- if (ar < 0) { +- return 1; +- } else if (ar > 0) { +- return 2; +- } else { +- return 0; +- } +- } +-} +- +-static inline uint32_t cc_calc_addu_32(CPUS390XState *env, uint32_t a1, +- uint32_t a2, uint32_t ar) +-{ +- if (ar == 0) { +- if (a1) { +- return 2; +- } else { +- return 0; +- } +- } else { +- if (ar < a1 || ar < a2) { +- return 3; +- } else { +- return 1; +- } +- } +-} +- +-static inline uint32_t cc_calc_sub_32(CPUS390XState *env, int32_t a1, +- int32_t a2, int32_t ar) +-{ +- if ((a1 > 0 && a2 < 0 && ar < 0) || (a1 < 0 && a2 > 0 && ar > 0)) { +- return 3; /* overflow */ +- } else { +- if (ar < 0) { +- return 1; +- } else if (ar > 0) { +- return 2; +- } else { +- return 0; +- } +- } +-} +- +-static inline uint32_t cc_calc_subu_32(CPUS390XState *env, uint32_t a1, +- uint32_t a2, uint32_t ar) +-{ +- if (ar == 0) { +- return 2; +- } else { +- if (a2 > a1) { +- return 1; +- } else { +- return 3; +- } +- } +-} +- +-static inline uint32_t cc_calc_abs_32(CPUS390XState *env, int32_t dst) +-{ +- if ((uint32_t)dst == 0x80000000UL) { +- return 3; +- } else if (dst) { +- return 1; +- } else { +- return 0; +- } +-} +- +-static inline uint32_t cc_calc_nabs_32(CPUS390XState *env, int32_t dst) +-{ +- return !!dst; +-} +- +-static inline uint32_t cc_calc_comp_32(CPUS390XState *env, int32_t dst) +-{ +- if ((uint32_t)dst == 0x80000000UL) { +- return 3; +- } else if (dst < 0) { +- return 1; +- } else if (dst > 0) { +- return 2; +- } else { +- return 0; +- } +-} +- +-/* calculate condition code for insert character under mask insn */ +-static inline uint32_t cc_calc_icm_32(CPUS390XState *env, uint32_t mask, +- uint32_t val) +-{ +- uint32_t cc; +- +- HELPER_LOG("%s: mask 0x%x val %d\n", __func__, mask, val); +- if (mask == 0xf) { +- if (!val) { +- return 0; +- } else if (val & 0x80000000) { +- return 1; +- } else { +- return 2; +- } +- } +- +- if (!val || !mask) { +- cc = 0; +- } else { +- while (mask != 1) { +- mask >>= 1; +- val >>= 8; +- } +- if (val & 0x80) { +- cc = 1; +- } else { +- cc = 2; +- } +- } +- return cc; +-} +- +-static inline uint32_t cc_calc_slag(CPUS390XState *env, uint64_t src, +- uint64_t shift) +-{ +- uint64_t mask = ((1ULL << shift) - 1ULL) << (64 - shift); +- uint64_t match, r; +- +- /* check if the sign bit stays the same */ +- if (src & (1ULL << 63)) { +- match = mask; +- } else { +- match = 0; +- } +- +- if ((src & mask) != match) { +- /* overflow */ +- return 3; +- } +- +- r = ((src << shift) & ((1ULL << 63) - 1)) | (src & (1ULL << 63)); +- +- if ((int64_t)r == 0) { +- return 0; +- } else if ((int64_t)r < 0) { +- return 1; +- } +- +- return 2; +-} +- +- +-static inline uint32_t do_calc_cc(CPUS390XState *env, uint32_t cc_op, +- uint64_t src, uint64_t dst, uint64_t vr) +-{ +- uint32_t r = 0; +- +- switch (cc_op) { +- case CC_OP_CONST0: +- case CC_OP_CONST1: +- case CC_OP_CONST2: +- case CC_OP_CONST3: +- /* cc_op value _is_ cc */ +- r = cc_op; +- break; +- case CC_OP_LTGT0_32: +- r = cc_calc_ltgt0_32(env, dst); +- break; +- case CC_OP_LTGT0_64: +- r = cc_calc_ltgt0_64(env, dst); +- break; +- case CC_OP_LTGT_32: +- r = cc_calc_ltgt_32(env, src, dst); +- break; +- case CC_OP_LTGT_64: +- r = cc_calc_ltgt_64(env, src, dst); +- break; +- case CC_OP_LTUGTU_32: +- r = cc_calc_ltugtu_32(env, src, dst); +- break; +- case CC_OP_LTUGTU_64: +- r = cc_calc_ltugtu_64(env, src, dst); +- break; +- case CC_OP_TM_32: +- r = cc_calc_tm_32(env, src, dst); +- break; +- case CC_OP_TM_64: +- r = cc_calc_tm_64(env, src, dst); +- break; +- case CC_OP_NZ: +- r = cc_calc_nz(env, dst); +- break; +- case CC_OP_ADD_64: +- r = cc_calc_add_64(env, src, dst, vr); +- break; +- case CC_OP_ADDU_64: +- r = cc_calc_addu_64(env, src, dst, vr); +- break; +- case CC_OP_SUB_64: +- r = cc_calc_sub_64(env, src, dst, vr); +- break; +- case CC_OP_SUBU_64: +- r = cc_calc_subu_64(env, src, dst, vr); +- break; +- case CC_OP_ABS_64: +- r = cc_calc_abs_64(env, dst); +- break; +- case CC_OP_NABS_64: +- r = cc_calc_nabs_64(env, dst); +- break; +- case CC_OP_COMP_64: +- r = cc_calc_comp_64(env, dst); +- break; +- +- case CC_OP_ADD_32: +- r = cc_calc_add_32(env, src, dst, vr); +- break; +- case CC_OP_ADDU_32: +- r = cc_calc_addu_32(env, src, dst, vr); +- break; +- case CC_OP_SUB_32: +- r = cc_calc_sub_32(env, src, dst, vr); +- break; +- case CC_OP_SUBU_32: +- r = cc_calc_subu_32(env, src, dst, vr); +- break; +- case CC_OP_ABS_32: +- r = cc_calc_abs_64(env, dst); +- break; +- case CC_OP_NABS_32: +- r = cc_calc_nabs_64(env, dst); +- break; +- case CC_OP_COMP_32: +- r = cc_calc_comp_32(env, dst); +- break; +- +- case CC_OP_ICM: +- r = cc_calc_icm_32(env, src, dst); +- break; +- case CC_OP_SLAG: +- r = cc_calc_slag(env, src, dst); +- break; +- +- case CC_OP_LTGT_F32: +- r = set_cc_f32(src, dst); +- break; +- case CC_OP_LTGT_F64: +- r = set_cc_f64(src, dst); +- break; +- case CC_OP_NZ_F32: +- r = set_cc_nz_f32(dst); +- break; +- case CC_OP_NZ_F64: +- r = set_cc_nz_f64(dst); +- break; +- +- default: +- cpu_abort(env, "Unknown CC operation: %s\n", cc_name(cc_op)); +- } +- +- HELPER_LOG("%s: %15s 0x%016lx 0x%016lx 0x%016lx = %d\n", __func__, +- cc_name(cc_op), src, dst, vr, r); +- return r; +-} +- +-uint32_t calc_cc(CPUS390XState *env, uint32_t cc_op, uint64_t src, uint64_t dst, +- uint64_t vr) +-{ +- return do_calc_cc(env, cc_op, src, dst, vr); +-} +- +-uint32_t HELPER(calc_cc)(uint32_t cc_op, uint64_t src, uint64_t dst, +- uint64_t vr) +-{ +- return do_calc_cc(env, cc_op, src, dst, vr); +-} +- + uint64_t HELPER(cvd)(int32_t bin) + { + /* positive 0 */ +@@ -1594,14 +1105,7 @@ void HELPER(tr)(uint32_t len, uint64_t array, uint64_t trans) + } + + #ifndef CONFIG_USER_ONLY +- +-void HELPER(load_psw)(uint64_t mask, uint64_t addr) +-{ +- load_psw(env, mask, addr); +- cpu_loop_exit(env); +-} +- +-static void program_interrupt(CPUS390XState *env, uint32_t code, int ilc) ++void program_interrupt(CPUS390XState *env, uint32_t code, int ilc) + { + qemu_log("program interrupt at %#" PRIx64 "\n", env->psw.addr); + +@@ -2175,30 +1679,6 @@ uint32_t HELPER(sigp)(uint64_t order_code, uint32_t r1, uint64_t cpu_addr) + return cc; + } + +-void HELPER(sacf)(uint64_t a1) +-{ +- HELPER_LOG("%s: %16" PRIx64 "\n", __func__, a1); +- +- switch (a1 & 0xf00) { +- case 0x000: +- env->psw.mask &= ~PSW_MASK_ASC; +- env->psw.mask |= PSW_ASC_PRIMARY; +- break; +- case 0x100: +- env->psw.mask &= ~PSW_MASK_ASC; +- env->psw.mask |= PSW_ASC_SECONDARY; +- break; +- case 0x300: +- env->psw.mask &= ~PSW_MASK_ASC; +- env->psw.mask |= PSW_ASC_HOME; +- break; +- default: +- qemu_log("unknown sacf mode: %" PRIx64 "\n", a1); +- program_interrupt(env, PGM_SPECIFICATION, 2); +- break; +- } +-} +- + /* invalidate pte */ + void HELPER(ipte)(uint64_t pte_addr, uint64_t vaddr) + { +-- +1.7.12.1 + diff --git a/0008-target-s390x-split-integer-helpers.patch b/0008-target-s390x-split-integer-helpers.patch new file mode 100644 index 0000000..5610e6d --- /dev/null +++ b/0008-target-s390x-split-integer-helpers.patch @@ -0,0 +1,444 @@ +From e9f67c1f326a995ff0000a08a223435386867d8f Mon Sep 17 00:00:00 2001 +From: Blue Swirl +Date: Sun, 2 Sep 2012 07:33:33 +0000 +Subject: [PATCH] target-s390x: split integer helpers + +Move integer helpers to int_helper.c. + +Signed-off-by: Blue Swirl +Signed-off-by: Alexander Graf +Signed-off-by: Michael Roth +--- + target-s390x/Makefile.objs | 3 +- + target-s390x/int_helper.c | 201 +++++++++++++++++++++++++++++++++++++++++++++ + target-s390x/op_helper.c | 170 -------------------------------------- + 3 files changed, 203 insertions(+), 171 deletions(-) + create mode 100644 target-s390x/int_helper.c + +diff --git a/target-s390x/Makefile.objs b/target-s390x/Makefile.objs +index f9437d6..e8f66e9 100644 +--- a/target-s390x/Makefile.objs ++++ b/target-s390x/Makefile.objs +@@ -1,8 +1,9 @@ + obj-y += translate.o op_helper.o helper.o cpu.o interrupt.o +-obj-y += fpu_helper.o cc_helper.o ++obj-y += int_helper.o fpu_helper.o cc_helper.o + obj-$(CONFIG_SOFTMMU) += machine.o + obj-$(CONFIG_KVM) += kvm.o + + $(obj)/op_helper.o: QEMU_CFLAGS += $(HELPER_CFLAGS) ++$(obj)/int_helper.o: QEMU_CFLAGS += $(HELPER_CFLAGS) + $(obj)/fpu_helper.o: QEMU_CFLAGS += $(HELPER_CFLAGS) + $(obj)/cc_helper.o: QEMU_CFLAGS += $(HELPER_CFLAGS) +diff --git a/target-s390x/int_helper.c b/target-s390x/int_helper.c +new file mode 100644 +index 0000000..e2eeb07 +--- /dev/null ++++ b/target-s390x/int_helper.c +@@ -0,0 +1,201 @@ ++/* ++ * S/390 integer helper routines ++ * ++ * Copyright (c) 2009 Ulrich Hecht ++ * Copyright (c) 2009 Alexander Graf ++ * ++ * This library is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU Lesser General Public ++ * License as published by the Free Software Foundation; either ++ * version 2 of the License, or (at your option) any later version. ++ * ++ * This library is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * Lesser General Public License for more details. ++ * ++ * You should have received a copy of the GNU Lesser General Public ++ * License along with this library; if not, see . ++ */ ++ ++#include "cpu.h" ++#include "dyngen-exec.h" ++#include "host-utils.h" ++#include "helper.h" ++ ++/* #define DEBUG_HELPER */ ++#ifdef DEBUG_HELPER ++#define HELPER_LOG(x...) qemu_log(x) ++#else ++#define HELPER_LOG(x...) ++#endif ++ ++/* 64/64 -> 128 unsigned multiplication */ ++void HELPER(mlg)(uint32_t r1, uint64_t v2) ++{ ++#if HOST_LONG_BITS == 64 && defined(__GNUC__) ++ /* assuming 64-bit hosts have __uint128_t */ ++ __uint128_t res = (__uint128_t)env->regs[r1 + 1]; ++ ++ res *= (__uint128_t)v2; ++ env->regs[r1] = (uint64_t)(res >> 64); ++ env->regs[r1 + 1] = (uint64_t)res; ++#else ++ mulu64(&env->regs[r1 + 1], &env->regs[r1], env->regs[r1 + 1], v2); ++#endif ++} ++ ++/* 128 -> 64/64 unsigned division */ ++void HELPER(dlg)(uint32_t r1, uint64_t v2) ++{ ++ uint64_t divisor = v2; ++ ++ if (!env->regs[r1]) { ++ /* 64 -> 64/64 case */ ++ env->regs[r1] = env->regs[r1 + 1] % divisor; ++ env->regs[r1 + 1] = env->regs[r1 + 1] / divisor; ++ return; ++ } else { ++#if HOST_LONG_BITS == 64 && defined(__GNUC__) ++ /* assuming 64-bit hosts have __uint128_t */ ++ __uint128_t dividend = (((__uint128_t)env->regs[r1]) << 64) | ++ (env->regs[r1 + 1]); ++ __uint128_t quotient = dividend / divisor; ++ __uint128_t remainder = dividend % divisor; ++ ++ env->regs[r1 + 1] = quotient; ++ env->regs[r1] = remainder; ++#else ++ /* 32-bit hosts would need special wrapper functionality - just abort if ++ we encounter such a case; it's very unlikely anyways. */ ++ cpu_abort(env, "128 -> 64/64 division not implemented\n"); ++#endif ++ } ++} ++ ++/* absolute value 32-bit */ ++uint32_t HELPER(abs_i32)(int32_t val) ++{ ++ if (val < 0) { ++ return -val; ++ } else { ++ return val; ++ } ++} ++ ++/* negative absolute value 32-bit */ ++int32_t HELPER(nabs_i32)(int32_t val) ++{ ++ if (val < 0) { ++ return val; ++ } else { ++ return -val; ++ } ++} ++ ++/* absolute value 64-bit */ ++uint64_t HELPER(abs_i64)(int64_t val) ++{ ++ HELPER_LOG("%s: val 0x%" PRIx64 "\n", __func__, val); ++ ++ if (val < 0) { ++ return -val; ++ } else { ++ return val; ++ } ++} ++ ++/* negative absolute value 64-bit */ ++int64_t HELPER(nabs_i64)(int64_t val) ++{ ++ if (val < 0) { ++ return val; ++ } else { ++ return -val; ++ } ++} ++ ++/* add with carry 32-bit unsigned */ ++uint32_t HELPER(addc_u32)(uint32_t cc, uint32_t v1, uint32_t v2) ++{ ++ uint32_t res; ++ ++ res = v1 + v2; ++ if (cc & 2) { ++ res++; ++ } ++ ++ return res; ++} ++ ++/* subtract unsigned v2 from v1 with borrow */ ++uint32_t HELPER(slb)(uint32_t cc, uint32_t r1, uint32_t v2) ++{ ++ uint32_t v1 = env->regs[r1]; ++ uint32_t res = v1 + (~v2) + (cc >> 1); ++ ++ env->regs[r1] = (env->regs[r1] & 0xffffffff00000000ULL) | res; ++ if (cc & 2) { ++ /* borrow */ ++ return v1 ? 1 : 0; ++ } else { ++ return v1 ? 3 : 2; ++ } ++} ++ ++/* subtract unsigned v2 from v1 with borrow */ ++uint32_t HELPER(slbg)(uint32_t cc, uint32_t r1, uint64_t v1, uint64_t v2) ++{ ++ uint64_t res = v1 + (~v2) + (cc >> 1); ++ ++ env->regs[r1] = res; ++ if (cc & 2) { ++ /* borrow */ ++ return v1 ? 1 : 0; ++ } else { ++ return v1 ? 3 : 2; ++ } ++} ++ ++/* find leftmost one */ ++uint32_t HELPER(flogr)(uint32_t r1, uint64_t v2) ++{ ++ uint64_t res = 0; ++ uint64_t ov2 = v2; ++ ++ while (!(v2 & 0x8000000000000000ULL) && v2) { ++ v2 <<= 1; ++ res++; ++ } ++ ++ if (!v2) { ++ env->regs[r1] = 64; ++ env->regs[r1 + 1] = 0; ++ return 0; ++ } else { ++ env->regs[r1] = res; ++ env->regs[r1 + 1] = ov2 & ~(0x8000000000000000ULL >> res); ++ return 2; ++ } ++} ++ ++uint64_t HELPER(cvd)(int32_t bin) ++{ ++ /* positive 0 */ ++ uint64_t dec = 0x0c; ++ int shift = 4; ++ ++ if (bin < 0) { ++ bin = -bin; ++ dec = 0x0d; ++ } ++ ++ for (shift = 4; (shift < 64) && bin; shift += 4) { ++ int current_number = bin % 10; ++ ++ dec |= (current_number) << shift; ++ bin /= 10; ++ } ++ ++ return dec; ++} +diff --git a/target-s390x/op_helper.c b/target-s390x/op_helper.c +index eced890..3b8b997 100644 +--- a/target-s390x/op_helper.c ++++ b/target-s390x/op_helper.c +@@ -352,49 +352,6 @@ void HELPER(stcm)(uint32_t r1, uint32_t mask, uint64_t addr) + HELPER_LOG("\n"); + } + +-/* 64/64 -> 128 unsigned multiplication */ +-void HELPER(mlg)(uint32_t r1, uint64_t v2) +-{ +-#if HOST_LONG_BITS == 64 && defined(__GNUC__) +- /* assuming 64-bit hosts have __uint128_t */ +- __uint128_t res = (__uint128_t)env->regs[r1 + 1]; +- +- res *= (__uint128_t)v2; +- env->regs[r1] = (uint64_t)(res >> 64); +- env->regs[r1 + 1] = (uint64_t)res; +-#else +- mulu64(&env->regs[r1 + 1], &env->regs[r1], env->regs[r1 + 1], v2); +-#endif +-} +- +-/* 128 -> 64/64 unsigned division */ +-void HELPER(dlg)(uint32_t r1, uint64_t v2) +-{ +- uint64_t divisor = v2; +- +- if (!env->regs[r1]) { +- /* 64 -> 64/64 case */ +- env->regs[r1] = env->regs[r1 + 1] % divisor; +- env->regs[r1 + 1] = env->regs[r1 + 1] / divisor; +- return; +- } else { +-#if HOST_LONG_BITS == 64 && defined(__GNUC__) +- /* assuming 64-bit hosts have __uint128_t */ +- __uint128_t dividend = (((__uint128_t)env->regs[r1]) << 64) | +- (env->regs[r1 + 1]); +- __uint128_t quotient = dividend / divisor; +- __uint128_t remainder = dividend % divisor; +- +- env->regs[r1 + 1] = quotient; +- env->regs[r1] = remainder; +-#else +- /* 32-bit hosts would need special wrapper functionality - just abort if +- we encounter such a case; it's very unlikely anyways. */ +- cpu_abort(env, "128 -> 64/64 division not implemented\n"); +-#endif +- } +-} +- + static inline uint64_t get_address(int x2, int b2, int d2) + { + uint64_t r = d2; +@@ -677,61 +634,6 @@ uint32_t HELPER(ex)(uint32_t cc, uint64_t v1, uint64_t addr, uint64_t ret) + return cc; + } + +-/* absolute value 32-bit */ +-uint32_t HELPER(abs_i32)(int32_t val) +-{ +- if (val < 0) { +- return -val; +- } else { +- return val; +- } +-} +- +-/* negative absolute value 32-bit */ +-int32_t HELPER(nabs_i32)(int32_t val) +-{ +- if (val < 0) { +- return val; +- } else { +- return -val; +- } +-} +- +-/* absolute value 64-bit */ +-uint64_t HELPER(abs_i64)(int64_t val) +-{ +- HELPER_LOG("%s: val 0x%" PRIx64 "\n", __func__, val); +- +- if (val < 0) { +- return -val; +- } else { +- return val; +- } +-} +- +-/* negative absolute value 64-bit */ +-int64_t HELPER(nabs_i64)(int64_t val) +-{ +- if (val < 0) { +- return val; +- } else { +- return -val; +- } +-} +- +-/* add with carry 32-bit unsigned */ +-uint32_t HELPER(addc_u32)(uint32_t cc, uint32_t v1, uint32_t v2) +-{ +- uint32_t res; +- +- res = v1 + v2; +- if (cc & 2) { +- res++; +- } +- +- return res; +-} +- + /* store character under mask high operates on the upper half of r1 */ + void HELPER(stcmh)(uint32_t r1, uint64_t address, uint32_t mask) + { +@@ -936,57 +838,6 @@ uint32_t HELPER(clcle)(uint32_t r1, uint64_t a2, uint32_t r3) + return cc; + } + +-/* subtract unsigned v2 from v1 with borrow */ +-uint32_t HELPER(slb)(uint32_t cc, uint32_t r1, uint32_t v2) +-{ +- uint32_t v1 = env->regs[r1]; +- uint32_t res = v1 + (~v2) + (cc >> 1); +- +- env->regs[r1] = (env->regs[r1] & 0xffffffff00000000ULL) | res; +- if (cc & 2) { +- /* borrow */ +- return v1 ? 1 : 0; +- } else { +- return v1 ? 3 : 2; +- } +-} +- +-/* subtract unsigned v2 from v1 with borrow */ +-uint32_t HELPER(slbg)(uint32_t cc, uint32_t r1, uint64_t v1, uint64_t v2) +-{ +- uint64_t res = v1 + (~v2) + (cc >> 1); +- +- env->regs[r1] = res; +- if (cc & 2) { +- /* borrow */ +- return v1 ? 1 : 0; +- } else { +- return v1 ? 3 : 2; +- } +-} +- +-/* find leftmost one */ +-uint32_t HELPER(flogr)(uint32_t r1, uint64_t v2) +-{ +- uint64_t res = 0; +- uint64_t ov2 = v2; +- +- while (!(v2 & 0x8000000000000000ULL) && v2) { +- v2 <<= 1; +- res++; +- } +- +- if (!v2) { +- env->regs[r1] = 64; +- env->regs[r1 + 1] = 0; +- return 0; +- } else { +- env->regs[r1] = res; +- env->regs[r1 + 1] = ov2 & ~(0x8000000000000000ULL >> res); +- return 2; +- } +-} +- + /* checksum */ + void HELPER(cksm)(uint32_t r1, uint32_t r2) + { +@@ -1026,27 +877,6 @@ void HELPER(cksm)(uint32_t r1, uint32_t r2) + ((uint32_t)cksm + (cksm >> 32)); + } + +-uint64_t HELPER(cvd)(int32_t bin) +-{ +- /* positive 0 */ +- uint64_t dec = 0x0c; +- int shift = 4; +- +- if (bin < 0) { +- bin = -bin; +- dec = 0x0d; +- } +- +- for (shift = 4; (shift < 64) && bin; shift += 4) { +- int current_number = bin % 10; +- +- dec |= (current_number) << shift; +- bin /= 10; +- } +- +- return dec; +-} +- + void HELPER(unpk)(uint32_t len, uint64_t dest, uint64_t src) + { + int len_dest = len >> 4; +-- +1.7.12.1 + diff --git a/0009-target-s390x-split-memory-access-helpers.patch b/0009-target-s390x-split-memory-access-helpers.patch new file mode 100644 index 0000000..0e87180 --- /dev/null +++ b/0009-target-s390x-split-memory-access-helpers.patch @@ -0,0 +1,2424 @@ +From a44aee2570031bfcf99098d278c53ab39a582ba6 Mon Sep 17 00:00:00 2001 +From: Blue Swirl +Date: Sun, 2 Sep 2012 07:33:34 +0000 +Subject: [PATCH] target-s390x: split memory access helpers + +Move memory access helpers to mem_helper.c. + +Signed-off-by: Blue Swirl +[agraf: fold softmmu include ifdefs together] +Signed-off-by: Alexander Graf + +Signed-off-by: Michael Roth +--- + target-s390x/Makefile.objs | 3 +- + target-s390x/mem_helper.c | 1190 ++++++++++++++++++++++++++++++++++++++++++++ + target-s390x/op_helper.c | 1159 +----------------------------------------- + 3 files changed, 1193 insertions(+), 1159 deletions(-) + create mode 100644 target-s390x/mem_helper.c + +diff --git a/target-s390x/Makefile.objs b/target-s390x/Makefile.objs +index e8f66e9..b9b3061 100644 +--- a/target-s390x/Makefile.objs ++++ b/target-s390x/Makefile.objs +@@ -1,5 +1,5 @@ + obj-y += translate.o op_helper.o helper.o cpu.o interrupt.o +-obj-y += int_helper.o fpu_helper.o cc_helper.o ++obj-y += int_helper.o fpu_helper.o cc_helper.o mem_helper.o + obj-$(CONFIG_SOFTMMU) += machine.o + obj-$(CONFIG_KVM) += kvm.o + +@@ -7,3 +7,4 @@ $(obj)/op_helper.o: QEMU_CFLAGS += $(HELPER_CFLAGS) + $(obj)/int_helper.o: QEMU_CFLAGS += $(HELPER_CFLAGS) + $(obj)/fpu_helper.o: QEMU_CFLAGS += $(HELPER_CFLAGS) + $(obj)/cc_helper.o: QEMU_CFLAGS += $(HELPER_CFLAGS) ++$(obj)/mem_helper.o: QEMU_CFLAGS += $(HELPER_CFLAGS) +diff --git a/target-s390x/mem_helper.c b/target-s390x/mem_helper.c +new file mode 100644 +index 0000000..ba05e65 +--- /dev/null ++++ b/target-s390x/mem_helper.c +@@ -0,0 +1,1190 @@ ++/* ++ * S/390 memory access helper routines ++ * ++ * Copyright (c) 2009 Ulrich Hecht ++ * Copyright (c) 2009 Alexander Graf ++ * ++ * This library is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU Lesser General Public ++ * License as published by the Free Software Foundation; either ++ * version 2 of the License, or (at your option) any later version. ++ * ++ * This library is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * Lesser General Public License for more details. ++ * ++ * You should have received a copy of the GNU Lesser General Public ++ * License along with this library; if not, see . ++ */ ++ ++#include "cpu.h" ++#include "dyngen-exec.h" ++#include "helper.h" ++ ++/*****************************************************************************/ ++/* Softmmu support */ ++#if !defined(CONFIG_USER_ONLY) ++#include "softmmu_exec.h" ++ ++#define MMUSUFFIX _mmu ++ ++#define SHIFT 0 ++#include "softmmu_template.h" ++ ++#define SHIFT 1 ++#include "softmmu_template.h" ++ ++#define SHIFT 2 ++#include "softmmu_template.h" ++ ++#define SHIFT 3 ++#include "softmmu_template.h" ++ ++/* try to fill the TLB and return an exception if error. If retaddr is ++ NULL, it means that the function was called in C code (i.e. not ++ from generated code or from helper.c) */ ++/* XXX: fix it to restore all registers */ ++void tlb_fill(CPUS390XState *env1, target_ulong addr, int is_write, int mmu_idx, ++ uintptr_t retaddr) ++{ ++ TranslationBlock *tb; ++ CPUS390XState *saved_env; ++ int ret; ++ ++ saved_env = env; ++ env = env1; ++ ret = cpu_s390x_handle_mmu_fault(env, addr, is_write, mmu_idx); ++ if (unlikely(ret != 0)) { ++ if (likely(retaddr)) { ++ /* now we have a real cpu fault */ ++ tb = tb_find_pc(retaddr); ++ if (likely(tb)) { ++ /* the PC is inside the translated code. It means that we have ++ a virtual CPU fault */ ++ cpu_restore_state(tb, env, retaddr); ++ } ++ } ++ cpu_loop_exit(env); ++ } ++ env = saved_env; ++} ++ ++#endif ++ ++/* #define DEBUG_HELPER */ ++#ifdef DEBUG_HELPER ++#define HELPER_LOG(x...) qemu_log(x) ++#else ++#define HELPER_LOG(x...) ++#endif ++ ++#ifndef CONFIG_USER_ONLY ++static void mvc_fast_memset(CPUS390XState *env, uint32_t l, uint64_t dest, ++ uint8_t byte) ++{ ++ target_phys_addr_t dest_phys; ++ target_phys_addr_t len = l; ++ void *dest_p; ++ uint64_t asc = env->psw.mask & PSW_MASK_ASC; ++ int flags; ++ ++ if (mmu_translate(env, dest, 1, asc, &dest_phys, &flags)) { ++ stb(dest, byte); ++ cpu_abort(env, "should never reach here"); ++ } ++ dest_phys |= dest & ~TARGET_PAGE_MASK; ++ ++ dest_p = cpu_physical_memory_map(dest_phys, &len, 1); ++ ++ memset(dest_p, byte, len); ++ ++ cpu_physical_memory_unmap(dest_p, 1, len, len); ++} ++ ++static void mvc_fast_memmove(CPUS390XState *env, uint32_t l, uint64_t dest, ++ uint64_t src) ++{ ++ target_phys_addr_t dest_phys; ++ target_phys_addr_t src_phys; ++ target_phys_addr_t len = l; ++ void *dest_p; ++ void *src_p; ++ uint64_t asc = env->psw.mask & PSW_MASK_ASC; ++ int flags; ++ ++ if (mmu_translate(env, dest, 1, asc, &dest_phys, &flags)) { ++ stb(dest, 0); ++ cpu_abort(env, "should never reach here"); ++ } ++ dest_phys |= dest & ~TARGET_PAGE_MASK; ++ ++ if (mmu_translate(env, src, 0, asc, &src_phys, &flags)) { ++ ldub(src); ++ cpu_abort(env, "should never reach here"); ++ } ++ src_phys |= src & ~TARGET_PAGE_MASK; ++ ++ dest_p = cpu_physical_memory_map(dest_phys, &len, 1); ++ src_p = cpu_physical_memory_map(src_phys, &len, 0); ++ ++ memmove(dest_p, src_p, len); ++ ++ cpu_physical_memory_unmap(dest_p, 1, len, len); ++ cpu_physical_memory_unmap(src_p, 0, len, len); ++} ++#endif ++ ++/* and on array */ ++uint32_t HELPER(nc)(uint32_t l, uint64_t dest, uint64_t src) ++{ ++ int i; ++ unsigned char x; ++ uint32_t cc = 0; ++ ++ HELPER_LOG("%s l %d dest %" PRIx64 " src %" PRIx64 "\n", ++ __func__, l, dest, src); ++ for (i = 0; i <= l; i++) { ++ x = ldub(dest + i) & ldub(src + i); ++ if (x) { ++ cc = 1; ++ } ++ stb(dest + i, x); ++ } ++ return cc; ++} ++ ++/* xor on array */ ++uint32_t HELPER(xc)(uint32_t l, uint64_t dest, uint64_t src) ++{ ++ int i; ++ unsigned char x; ++ uint32_t cc = 0; ++ ++ HELPER_LOG("%s l %d dest %" PRIx64 " src %" PRIx64 "\n", ++ __func__, l, dest, src); ++ ++#ifndef CONFIG_USER_ONLY ++ /* xor with itself is the same as memset(0) */ ++ if ((l > 32) && (src == dest) && ++ (src & TARGET_PAGE_MASK) == ((src + l) & TARGET_PAGE_MASK)) { ++ mvc_fast_memset(env, l + 1, dest, 0); ++ return 0; ++ } ++#else ++ if (src == dest) { ++ memset(g2h(dest), 0, l + 1); ++ return 0; ++ } ++#endif ++ ++ for (i = 0; i <= l; i++) { ++ x = ldub(dest + i) ^ ldub(src + i); ++ if (x) { ++ cc = 1; ++ } ++ stb(dest + i, x); ++ } ++ return cc; ++} ++ ++/* or on array */ ++uint32_t HELPER(oc)(uint32_t l, uint64_t dest, uint64_t src) ++{ ++ int i; ++ unsigned char x; ++ uint32_t cc = 0; ++ ++ HELPER_LOG("%s l %d dest %" PRIx64 " src %" PRIx64 "\n", ++ __func__, l, dest, src); ++ for (i = 0; i <= l; i++) { ++ x = ldub(dest + i) | ldub(src + i); ++ if (x) { ++ cc = 1; ++ } ++ stb(dest + i, x); ++ } ++ return cc; ++} ++ ++/* memmove */ ++void HELPER(mvc)(uint32_t l, uint64_t dest, uint64_t src) ++{ ++ int i = 0; ++ int x = 0; ++ uint32_t l_64 = (l + 1) / 8; ++ ++ HELPER_LOG("%s l %d dest %" PRIx64 " src %" PRIx64 "\n", ++ __func__, l, dest, src); ++ ++#ifndef CONFIG_USER_ONLY ++ if ((l > 32) && ++ (src & TARGET_PAGE_MASK) == ((src + l) & TARGET_PAGE_MASK) && ++ (dest & TARGET_PAGE_MASK) == ((dest + l) & TARGET_PAGE_MASK)) { ++ if (dest == (src + 1)) { ++ mvc_fast_memset(env, l + 1, dest, ldub(src)); ++ return; ++ } else if ((src & TARGET_PAGE_MASK) != (dest & TARGET_PAGE_MASK)) { ++ mvc_fast_memmove(env, l + 1, dest, src); ++ return; ++ } ++ } ++#else ++ if (dest == (src + 1)) { ++ memset(g2h(dest), ldub(src), l + 1); ++ return; ++ } else { ++ memmove(g2h(dest), g2h(src), l + 1); ++ return; ++ } ++#endif ++ ++ /* handle the parts that fit into 8-byte loads/stores */ ++ if (dest != (src + 1)) { ++ for (i = 0; i < l_64; i++) { ++ stq(dest + x, ldq(src + x)); ++ x += 8; ++ } ++ } ++ ++ /* slow version crossing pages with byte accesses */ ++ for (i = x; i <= l; i++) { ++ stb(dest + i, ldub(src + i)); ++ } ++} ++ ++/* compare unsigned byte arrays */ ++uint32_t HELPER(clc)(uint32_t l, uint64_t s1, uint64_t s2) ++{ ++ int i; ++ unsigned char x, y; ++ uint32_t cc; ++ ++ HELPER_LOG("%s l %d s1 %" PRIx64 " s2 %" PRIx64 "\n", ++ __func__, l, s1, s2); ++ for (i = 0; i <= l; i++) { ++ x = ldub(s1 + i); ++ y = ldub(s2 + i); ++ HELPER_LOG("%02x (%c)/%02x (%c) ", x, x, y, y); ++ if (x < y) { ++ cc = 1; ++ goto done; ++ } else if (x > y) { ++ cc = 2; ++ goto done; ++ } ++ } ++ cc = 0; ++ done: ++ HELPER_LOG("\n"); ++ return cc; ++} ++ ++/* compare logical under mask */ ++uint32_t HELPER(clm)(uint32_t r1, uint32_t mask, uint64_t addr) ++{ ++ uint8_t r, d; ++ uint32_t cc; ++ ++ HELPER_LOG("%s: r1 0x%x mask 0x%x addr 0x%" PRIx64 "\n", __func__, r1, ++ mask, addr); ++ cc = 0; ++ while (mask) { ++ if (mask & 8) { ++ d = ldub(addr); ++ r = (r1 & 0xff000000UL) >> 24; ++ HELPER_LOG("mask 0x%x %02x/%02x (0x%" PRIx64 ") ", mask, r, d, ++ addr); ++ if (r < d) { ++ cc = 1; ++ break; ++ } else if (r > d) { ++ cc = 2; ++ break; ++ } ++ addr++; ++ } ++ mask = (mask << 1) & 0xf; ++ r1 <<= 8; ++ } ++ HELPER_LOG("\n"); ++ return cc; ++} ++ ++/* store character under mask */ ++void HELPER(stcm)(uint32_t r1, uint32_t mask, uint64_t addr) ++{ ++ uint8_t r; ++ ++ HELPER_LOG("%s: r1 0x%x mask 0x%x addr 0x%lx\n", __func__, r1, mask, ++ addr); ++ while (mask) { ++ if (mask & 8) { ++ r = (r1 & 0xff000000UL) >> 24; ++ stb(addr, r); ++ HELPER_LOG("mask 0x%x %02x (0x%lx) ", mask, r, addr); ++ addr++; ++ } ++ mask = (mask << 1) & 0xf; ++ r1 <<= 8; ++ } ++ HELPER_LOG("\n"); ++} ++ ++static inline uint64_t get_address(int x2, int b2, int d2) ++{ ++ uint64_t r = d2; ++ ++ if (x2) { ++ r += env->regs[x2]; ++ } ++ ++ if (b2) { ++ r += env->regs[b2]; ++ } ++ ++ /* 31-Bit mode */ ++ if (!(env->psw.mask & PSW_MASK_64)) { ++ r &= 0x7fffffff; ++ } ++ ++ return r; ++} ++ ++static inline uint64_t get_address_31fix(int reg) ++{ ++ uint64_t r = env->regs[reg]; ++ ++ /* 31-Bit mode */ ++ if (!(env->psw.mask & PSW_MASK_64)) { ++ r &= 0x7fffffff; ++ } ++ ++ return r; ++} ++ ++/* search string (c is byte to search, r2 is string, r1 end of string) */ ++uint32_t HELPER(srst)(uint32_t c, uint32_t r1, uint32_t r2) ++{ ++ uint64_t i; ++ uint32_t cc = 2; ++ uint64_t str = get_address_31fix(r2); ++ uint64_t end = get_address_31fix(r1); ++ ++ HELPER_LOG("%s: c %d *r1 0x%" PRIx64 " *r2 0x%" PRIx64 "\n", __func__, ++ c, env->regs[r1], env->regs[r2]); ++ ++ for (i = str; i != end; i++) { ++ if (ldub(i) == c) { ++ env->regs[r1] = i; ++ cc = 1; ++ break; ++ } ++ } ++ ++ return cc; ++} ++ ++/* unsigned string compare (c is string terminator) */ ++uint32_t HELPER(clst)(uint32_t c, uint32_t r1, uint32_t r2) ++{ ++ uint64_t s1 = get_address_31fix(r1); ++ uint64_t s2 = get_address_31fix(r2); ++ uint8_t v1, v2; ++ uint32_t cc; ++ ++ c = c & 0xff; ++#ifdef CONFIG_USER_ONLY ++ if (!c) { ++ HELPER_LOG("%s: comparing '%s' and '%s'\n", ++ __func__, (char *)g2h(s1), (char *)g2h(s2)); ++ } ++#endif ++ for (;;) { ++ v1 = ldub(s1); ++ v2 = ldub(s2); ++ if ((v1 == c || v2 == c) || (v1 != v2)) { ++ break; ++ } ++ s1++; ++ s2++; ++ } ++ ++ if (v1 == v2) { ++ cc = 0; ++ } else { ++ cc = (v1 < v2) ? 1 : 2; ++ /* FIXME: 31-bit mode! */ ++ env->regs[r1] = s1; ++ env->regs[r2] = s2; ++ } ++ return cc; ++} ++ ++/* move page */ ++void HELPER(mvpg)(uint64_t r0, uint64_t r1, uint64_t r2) ++{ ++ /* XXX missing r0 handling */ ++#ifdef CONFIG_USER_ONLY ++ int i; ++ ++ for (i = 0; i < TARGET_PAGE_SIZE; i++) { ++ stb(r1 + i, ldub(r2 + i)); ++ } ++#else ++ mvc_fast_memmove(env, TARGET_PAGE_SIZE, r1, r2); ++#endif ++} ++ ++/* string copy (c is string terminator) */ ++void HELPER(mvst)(uint32_t c, uint32_t r1, uint32_t r2) ++{ ++ uint64_t dest = get_address_31fix(r1); ++ uint64_t src = get_address_31fix(r2); ++ uint8_t v; ++ ++ c = c & 0xff; ++#ifdef CONFIG_USER_ONLY ++ if (!c) { ++ HELPER_LOG("%s: copy '%s' to 0x%lx\n", __func__, (char *)g2h(src), ++ dest); ++ } ++#endif ++ for (;;) { ++ v = ldub(src); ++ stb(dest, v); ++ if (v == c) { ++ break; ++ } ++ src++; ++ dest++; ++ } ++ env->regs[r1] = dest; /* FIXME: 31-bit mode! */ ++} ++ ++/* compare and swap 64-bit */ ++uint32_t HELPER(csg)(uint32_t r1, uint64_t a2, uint32_t r3) ++{ ++ /* FIXME: locking? */ ++ uint32_t cc; ++ uint64_t v2 = ldq(a2); ++ ++ if (env->regs[r1] == v2) { ++ cc = 0; ++ stq(a2, env->regs[r3]); ++ } else { ++ cc = 1; ++ env->regs[r1] = v2; ++ } ++ return cc; ++} ++ ++/* compare double and swap 64-bit */ ++uint32_t HELPER(cdsg)(uint32_t r1, uint64_t a2, uint32_t r3) ++{ ++ /* FIXME: locking? */ ++ uint32_t cc; ++ uint64_t v2_hi = ldq(a2); ++ uint64_t v2_lo = ldq(a2 + 8); ++ uint64_t v1_hi = env->regs[r1]; ++ uint64_t v1_lo = env->regs[r1 + 1]; ++ ++ if ((v1_hi == v2_hi) && (v1_lo == v2_lo)) { ++ cc = 0; ++ stq(a2, env->regs[r3]); ++ stq(a2 + 8, env->regs[r3 + 1]); ++ } else { ++ cc = 1; ++ env->regs[r1] = v2_hi; ++ env->regs[r1 + 1] = v2_lo; ++ } ++ ++ return cc; ++} ++ ++/* compare and swap 32-bit */ ++uint32_t HELPER(cs)(uint32_t r1, uint64_t a2, uint32_t r3) ++{ ++ /* FIXME: locking? */ ++ uint32_t cc; ++ uint32_t v2 = ldl(a2); ++ ++ HELPER_LOG("%s: r1 %d a2 0x%lx r3 %d\n", __func__, r1, a2, r3); ++ if (((uint32_t)env->regs[r1]) == v2) { ++ cc = 0; ++ stl(a2, (uint32_t)env->regs[r3]); ++ } else { ++ cc = 1; ++ env->regs[r1] = (env->regs[r1] & 0xffffffff00000000ULL) | v2; ++ } ++ return cc; ++} ++ ++static uint32_t helper_icm(uint32_t r1, uint64_t address, uint32_t mask) ++{ ++ int pos = 24; /* top of the lower half of r1 */ ++ uint64_t rmask = 0xff000000ULL; ++ uint8_t val = 0; ++ int ccd = 0; ++ uint32_t cc = 0; ++ ++ while (mask) { ++ if (mask & 8) { ++ env->regs[r1] &= ~rmask; ++ val = ldub(address); ++ if ((val & 0x80) && !ccd) { ++ cc = 1; ++ } ++ ccd = 1; ++ if (val && cc == 0) { ++ cc = 2; ++ } ++ env->regs[r1] |= (uint64_t)val << pos; ++ address++; ++ } ++ mask = (mask << 1) & 0xf; ++ pos -= 8; ++ rmask >>= 8; ++ } ++ ++ return cc; ++} ++ ++/* execute instruction ++ this instruction executes an insn modified with the contents of r1 ++ it does not change the executed instruction in memory ++ it does not change the program counter ++ in other words: tricky... ++ currently implemented by interpreting the cases it is most commonly used in ++*/ ++uint32_t HELPER(ex)(uint32_t cc, uint64_t v1, uint64_t addr, uint64_t ret) ++{ ++ uint16_t insn = lduw_code(addr); ++ ++ HELPER_LOG("%s: v1 0x%lx addr 0x%lx insn 0x%x\n", __func__, v1, addr, ++ insn); ++ if ((insn & 0xf0ff) == 0xd000) { ++ uint32_t l, insn2, b1, b2, d1, d2; ++ ++ l = v1 & 0xff; ++ insn2 = ldl_code(addr + 2); ++ b1 = (insn2 >> 28) & 0xf; ++ b2 = (insn2 >> 12) & 0xf; ++ d1 = (insn2 >> 16) & 0xfff; ++ d2 = insn2 & 0xfff; ++ switch (insn & 0xf00) { ++ case 0x200: ++ helper_mvc(l, get_address(0, b1, d1), get_address(0, b2, d2)); ++ break; ++ case 0x500: ++ cc = helper_clc(l, get_address(0, b1, d1), get_address(0, b2, d2)); ++ break; ++ case 0x700: ++ cc = helper_xc(l, get_address(0, b1, d1), get_address(0, b2, d2)); ++ break; ++ case 0xc00: ++ helper_tr(l, get_address(0, b1, d1), get_address(0, b2, d2)); ++ break; ++ default: ++ goto abort; ++ break; ++ } ++ } else if ((insn & 0xff00) == 0x0a00) { ++ /* supervisor call */ ++ HELPER_LOG("%s: svc %ld via execute\n", __func__, (insn | v1) & 0xff); ++ env->psw.addr = ret - 4; ++ env->int_svc_code = (insn | v1) & 0xff; ++ env->int_svc_ilc = 4; ++ helper_exception(EXCP_SVC); ++ } else if ((insn & 0xff00) == 0xbf00) { ++ uint32_t insn2, r1, r3, b2, d2; ++ ++ insn2 = ldl_code(addr + 2); ++ r1 = (insn2 >> 20) & 0xf; ++ r3 = (insn2 >> 16) & 0xf; ++ b2 = (insn2 >> 12) & 0xf; ++ d2 = insn2 & 0xfff; ++ cc = helper_icm(r1, get_address(0, b2, d2), r3); ++ } else { ++ abort: ++ cpu_abort(env, "EXECUTE on instruction prefix 0x%x not implemented\n", ++ insn); ++ } ++ return cc; ++} ++ ++/* store character under mask high operates on the upper half of r1 */ ++void HELPER(stcmh)(uint32_t r1, uint64_t address, uint32_t mask) ++{ ++ int pos = 56; /* top of the upper half of r1 */ ++ ++ while (mask) { ++ if (mask & 8) { ++ stb(address, (env->regs[r1] >> pos) & 0xff); ++ address++; ++ } ++ mask = (mask << 1) & 0xf; ++ pos -= 8; ++ } ++} ++ ++/* insert character under mask high; same as icm, but operates on the ++ upper half of r1 */ ++uint32_t HELPER(icmh)(uint32_t r1, uint64_t address, uint32_t mask) ++{ ++ int pos = 56; /* top of the upper half of r1 */ ++ uint64_t rmask = 0xff00000000000000ULL; ++ uint8_t val = 0; ++ int ccd = 0; ++ uint32_t cc = 0; ++ ++ while (mask) { ++ if (mask & 8) { ++ env->regs[r1] &= ~rmask; ++ val = ldub(address); ++ if ((val & 0x80) && !ccd) { ++ cc = 1; ++ } ++ ccd = 1; ++ if (val && cc == 0) { ++ cc = 2; ++ } ++ env->regs[r1] |= (uint64_t)val << pos; ++ address++; ++ } ++ mask = (mask << 1) & 0xf; ++ pos -= 8; ++ rmask >>= 8; ++ } ++ ++ return cc; ++} ++ ++/* load access registers r1 to r3 from memory at a2 */ ++void HELPER(lam)(uint32_t r1, uint64_t a2, uint32_t r3) ++{ ++ int i; ++ ++ for (i = r1;; i = (i + 1) % 16) { ++ env->aregs[i] = ldl(a2); ++ a2 += 4; ++ ++ if (i == r3) { ++ break; ++ } ++ } ++} ++ ++/* store access registers r1 to r3 in memory at a2 */ ++void HELPER(stam)(uint32_t r1, uint64_t a2, uint32_t r3) ++{ ++ int i; ++ ++ for (i = r1;; i = (i + 1) % 16) { ++ stl(a2, env->aregs[i]); ++ a2 += 4; ++ ++ if (i == r3) { ++ break; ++ } ++ } ++} ++ ++/* move long */ ++uint32_t HELPER(mvcl)(uint32_t r1, uint32_t r2) ++{ ++ uint64_t destlen = env->regs[r1 + 1] & 0xffffff; ++ uint64_t dest = get_address_31fix(r1); ++ uint64_t srclen = env->regs[r2 + 1] & 0xffffff; ++ uint64_t src = get_address_31fix(r2); ++ uint8_t pad = src >> 24; ++ uint8_t v; ++ uint32_t cc; ++ ++ if (destlen == srclen) { ++ cc = 0; ++ } else if (destlen < srclen) { ++ cc = 1; ++ } else { ++ cc = 2; ++ } ++ ++ if (srclen > destlen) { ++ srclen = destlen; ++ } ++ ++ for (; destlen && srclen; src++, dest++, destlen--, srclen--) { ++ v = ldub(src); ++ stb(dest, v); ++ } ++ ++ for (; destlen; dest++, destlen--) { ++ stb(dest, pad); ++ } ++ ++ env->regs[r1 + 1] = destlen; ++ /* can't use srclen here, we trunc'ed it */ ++ env->regs[r2 + 1] -= src - env->regs[r2]; ++ env->regs[r1] = dest; ++ env->regs[r2] = src; ++ ++ return cc; ++} ++ ++/* move long extended another memcopy insn with more bells and whistles */ ++uint32_t HELPER(mvcle)(uint32_t r1, uint64_t a2, uint32_t r3) ++{ ++ uint64_t destlen = env->regs[r1 + 1]; ++ uint64_t dest = env->regs[r1]; ++ uint64_t srclen = env->regs[r3 + 1]; ++ uint64_t src = env->regs[r3]; ++ uint8_t pad = a2 & 0xff; ++ uint8_t v; ++ uint32_t cc; ++ ++ if (!(env->psw.mask & PSW_MASK_64)) { ++ destlen = (uint32_t)destlen; ++ srclen = (uint32_t)srclen; ++ dest &= 0x7fffffff; ++ src &= 0x7fffffff; ++ } ++ ++ if (destlen == srclen) { ++ cc = 0; ++ } else if (destlen < srclen) { ++ cc = 1; ++ } else { ++ cc = 2; ++ } ++ ++ if (srclen > destlen) { ++ srclen = destlen; ++ } ++ ++ for (; destlen && srclen; src++, dest++, destlen--, srclen--) { ++ v = ldub(src); ++ stb(dest, v); ++ } ++ ++ for (; destlen; dest++, destlen--) { ++ stb(dest, pad); ++ } ++ ++ env->regs[r1 + 1] = destlen; ++ /* can't use srclen here, we trunc'ed it */ ++ /* FIXME: 31-bit mode! */ ++ env->regs[r3 + 1] -= src - env->regs[r3]; ++ env->regs[r1] = dest; ++ env->regs[r3] = src; ++ ++ return cc; ++} ++ ++/* compare logical long extended memcompare insn with padding */ ++uint32_t HELPER(clcle)(uint32_t r1, uint64_t a2, uint32_t r3) ++{ ++ uint64_t destlen = env->regs[r1 + 1]; ++ uint64_t dest = get_address_31fix(r1); ++ uint64_t srclen = env->regs[r3 + 1]; ++ uint64_t src = get_address_31fix(r3); ++ uint8_t pad = a2 & 0xff; ++ uint8_t v1 = 0, v2 = 0; ++ uint32_t cc = 0; ++ ++ if (!(destlen || srclen)) { ++ return cc; ++ } ++ ++ if (srclen > destlen) { ++ srclen = destlen; ++ } ++ ++ for (; destlen || srclen; src++, dest++, destlen--, srclen--) { ++ v1 = srclen ? ldub(src) : pad; ++ v2 = destlen ? ldub(dest) : pad; ++ if (v1 != v2) { ++ cc = (v1 < v2) ? 1 : 2; ++ break; ++ } ++ } ++ ++ env->regs[r1 + 1] = destlen; ++ /* can't use srclen here, we trunc'ed it */ ++ env->regs[r3 + 1] -= src - env->regs[r3]; ++ env->regs[r1] = dest; ++ env->regs[r3] = src; ++ ++ return cc; ++} ++ ++/* checksum */ ++void HELPER(cksm)(uint32_t r1, uint32_t r2) ++{ ++ uint64_t src = get_address_31fix(r2); ++ uint64_t src_len = env->regs[(r2 + 1) & 15]; ++ uint64_t cksm = (uint32_t)env->regs[r1]; ++ ++ while (src_len >= 4) { ++ cksm += ldl(src); ++ ++ /* move to next word */ ++ src_len -= 4; ++ src += 4; ++ } ++ ++ switch (src_len) { ++ case 0: ++ break; ++ case 1: ++ cksm += ldub(src) << 24; ++ break; ++ case 2: ++ cksm += lduw(src) << 16; ++ break; ++ case 3: ++ cksm += lduw(src) << 16; ++ cksm += ldub(src + 2) << 8; ++ break; ++ } ++ ++ /* indicate we've processed everything */ ++ env->regs[r2] = src + src_len; ++ env->regs[(r2 + 1) & 15] = 0; ++ ++ /* store result */ ++ env->regs[r1] = (env->regs[r1] & 0xffffffff00000000ULL) | ++ ((uint32_t)cksm + (cksm >> 32)); ++} ++ ++void HELPER(unpk)(uint32_t len, uint64_t dest, uint64_t src) ++{ ++ int len_dest = len >> 4; ++ int len_src = len & 0xf; ++ uint8_t b; ++ int second_nibble = 0; ++ ++ dest += len_dest; ++ src += len_src; ++ ++ /* last byte is special, it only flips the nibbles */ ++ b = ldub(src); ++ stb(dest, (b << 4) | (b >> 4)); ++ src--; ++ len_src--; ++ ++ /* now pad every nibble with 0xf0 */ ++ ++ while (len_dest > 0) { ++ uint8_t cur_byte = 0; ++ ++ if (len_src > 0) { ++ cur_byte = ldub(src); ++ } ++ ++ len_dest--; ++ dest--; ++ ++ /* only advance one nibble at a time */ ++ if (second_nibble) { ++ cur_byte >>= 4; ++ len_src--; ++ src--; ++ } ++ second_nibble = !second_nibble; ++ ++ /* digit */ ++ cur_byte = (cur_byte & 0xf); ++ /* zone bits */ ++ cur_byte |= 0xf0; ++ ++ stb(dest, cur_byte); ++ } ++} ++ ++void HELPER(tr)(uint32_t len, uint64_t array, uint64_t trans) ++{ ++ int i; ++ ++ for (i = 0; i <= len; i++) { ++ uint8_t byte = ldub(array + i); ++ uint8_t new_byte = ldub(trans + byte); ++ ++ stb(array + i, new_byte); ++ } ++} ++ ++#if !defined(CONFIG_USER_ONLY) ++void HELPER(lctlg)(uint32_t r1, uint64_t a2, uint32_t r3) ++{ ++ int i; ++ uint64_t src = a2; ++ ++ for (i = r1;; i = (i + 1) % 16) { ++ env->cregs[i] = ldq(src); ++ HELPER_LOG("load ctl %d from 0x%" PRIx64 " == 0x%" PRIx64 "\n", ++ i, src, env->cregs[i]); ++ src += sizeof(uint64_t); ++ ++ if (i == r3) { ++ break; ++ } ++ } ++ ++ tlb_flush(env, 1); ++} ++ ++void HELPER(lctl)(uint32_t r1, uint64_t a2, uint32_t r3) ++{ ++ int i; ++ uint64_t src = a2; ++ ++ for (i = r1;; i = (i + 1) % 16) { ++ env->cregs[i] = (env->cregs[i] & 0xFFFFFFFF00000000ULL) | ldl(src); ++ src += sizeof(uint32_t); ++ ++ if (i == r3) { ++ break; ++ } ++ } ++ ++ tlb_flush(env, 1); ++} ++ ++void HELPER(stctg)(uint32_t r1, uint64_t a2, uint32_t r3) ++{ ++ int i; ++ uint64_t dest = a2; ++ ++ for (i = r1;; i = (i + 1) % 16) { ++ stq(dest, env->cregs[i]); ++ dest += sizeof(uint64_t); ++ ++ if (i == r3) { ++ break; ++ } ++ } ++} ++ ++void HELPER(stctl)(uint32_t r1, uint64_t a2, uint32_t r3) ++{ ++ int i; ++ uint64_t dest = a2; ++ ++ for (i = r1;; i = (i + 1) % 16) { ++ stl(dest, env->cregs[i]); ++ dest += sizeof(uint32_t); ++ ++ if (i == r3) { ++ break; ++ } ++ } ++} ++ ++uint32_t HELPER(tprot)(uint64_t a1, uint64_t a2) ++{ ++ /* XXX implement */ ++ ++ return 0; ++} ++ ++/* insert storage key extended */ ++uint64_t HELPER(iske)(uint64_t r2) ++{ ++ uint64_t addr = get_address(0, 0, r2); ++ ++ if (addr > ram_size) { ++ return 0; ++ } ++ ++ return env->storage_keys[addr / TARGET_PAGE_SIZE]; ++} ++ ++/* set storage key extended */ ++void HELPER(sske)(uint32_t r1, uint64_t r2) ++{ ++ uint64_t addr = get_address(0, 0, r2); ++ ++ if (addr > ram_size) { ++ return; ++ } ++ ++ env->storage_keys[addr / TARGET_PAGE_SIZE] = r1; ++} ++ ++/* reset reference bit extended */ ++uint32_t HELPER(rrbe)(uint32_t r1, uint64_t r2) ++{ ++ uint8_t re; ++ uint8_t key; ++ ++ if (r2 > ram_size) { ++ return 0; ++ } ++ ++ key = env->storage_keys[r2 / TARGET_PAGE_SIZE]; ++ re = key & (SK_R | SK_C); ++ env->storage_keys[r2 / TARGET_PAGE_SIZE] = (key & ~SK_R); ++ ++ /* ++ * cc ++ * ++ * 0 Reference bit zero; change bit zero ++ * 1 Reference bit zero; change bit one ++ * 2 Reference bit one; change bit zero ++ * 3 Reference bit one; change bit one ++ */ ++ ++ return re >> 1; ++} ++ ++/* compare and swap and purge */ ++uint32_t HELPER(csp)(uint32_t r1, uint32_t r2) ++{ ++ uint32_t cc; ++ uint32_t o1 = env->regs[r1]; ++ uint64_t a2 = get_address_31fix(r2) & ~3ULL; ++ uint32_t o2 = ldl(a2); ++ ++ if (o1 == o2) { ++ stl(a2, env->regs[(r1 + 1) & 15]); ++ if (env->regs[r2] & 0x3) { ++ /* flush TLB / ALB */ ++ tlb_flush(env, 1); ++ } ++ cc = 0; ++ } else { ++ env->regs[r1] = (env->regs[r1] & 0xffffffff00000000ULL) | o2; ++ cc = 1; ++ } ++ ++ return cc; ++} ++ ++static uint32_t mvc_asc(int64_t l, uint64_t a1, uint64_t mode1, uint64_t a2, ++ uint64_t mode2) ++{ ++ target_ulong src, dest; ++ int flags, cc = 0, i; ++ ++ if (!l) { ++ return 0; ++ } else if (l > 256) { ++ /* max 256 */ ++ l = 256; ++ cc = 3; ++ } ++ ++ if (mmu_translate(env, a1 & TARGET_PAGE_MASK, 1, mode1, &dest, &flags)) { ++ cpu_loop_exit(env); ++ } ++ dest |= a1 & ~TARGET_PAGE_MASK; ++ ++ if (mmu_translate(env, a2 & TARGET_PAGE_MASK, 0, mode2, &src, &flags)) { ++ cpu_loop_exit(env); ++ } ++ src |= a2 & ~TARGET_PAGE_MASK; ++ ++ /* XXX replace w/ memcpy */ ++ for (i = 0; i < l; i++) { ++ /* XXX be more clever */ ++ if ((((dest + i) & TARGET_PAGE_MASK) != (dest & TARGET_PAGE_MASK)) || ++ (((src + i) & TARGET_PAGE_MASK) != (src & TARGET_PAGE_MASK))) { ++ mvc_asc(l - i, a1 + i, mode1, a2 + i, mode2); ++ break; ++ } ++ stb_phys(dest + i, ldub_phys(src + i)); ++ } ++ ++ return cc; ++} ++ ++uint32_t HELPER(mvcs)(uint64_t l, uint64_t a1, uint64_t a2) ++{ ++ HELPER_LOG("%s: %16" PRIx64 " %16" PRIx64 " %16" PRIx64 "\n", ++ __func__, l, a1, a2); ++ ++ return mvc_asc(l, a1, PSW_ASC_SECONDARY, a2, PSW_ASC_PRIMARY); ++} ++ ++uint32_t HELPER(mvcp)(uint64_t l, uint64_t a1, uint64_t a2) ++{ ++ HELPER_LOG("%s: %16" PRIx64 " %16" PRIx64 " %16" PRIx64 "\n", ++ __func__, l, a1, a2); ++ ++ return mvc_asc(l, a1, PSW_ASC_PRIMARY, a2, PSW_ASC_SECONDARY); ++} ++ ++/* invalidate pte */ ++void HELPER(ipte)(uint64_t pte_addr, uint64_t vaddr) ++{ ++ uint64_t page = vaddr & TARGET_PAGE_MASK; ++ uint64_t pte = 0; ++ ++ /* XXX broadcast to other CPUs */ ++ ++ /* XXX Linux is nice enough to give us the exact pte address. ++ According to spec we'd have to find it out ourselves */ ++ /* XXX Linux is fine with overwriting the pte, the spec requires ++ us to only set the invalid bit */ ++ stq_phys(pte_addr, pte | _PAGE_INVALID); ++ ++ /* XXX we exploit the fact that Linux passes the exact virtual ++ address here - it's not obliged to! */ ++ tlb_flush_page(env, page); ++ ++ /* XXX 31-bit hack */ ++ if (page & 0x80000000) { ++ tlb_flush_page(env, page & ~0x80000000); ++ } else { ++ tlb_flush_page(env, page | 0x80000000); ++ } ++} ++ ++/* flush local tlb */ ++void HELPER(ptlb)(void) ++{ ++ tlb_flush(env, 1); ++} ++ ++/* store using real address */ ++void HELPER(stura)(uint64_t addr, uint32_t v1) ++{ ++ stw_phys(get_address(0, 0, addr), v1); ++} ++ ++/* load real address */ ++uint32_t HELPER(lra)(uint64_t addr, uint32_t r1) ++{ ++ uint32_t cc = 0; ++ int old_exc = env->exception_index; ++ uint64_t asc = env->psw.mask & PSW_MASK_ASC; ++ uint64_t ret; ++ int flags; ++ ++ /* XXX incomplete - has more corner cases */ ++ if (!(env->psw.mask & PSW_MASK_64) && (addr >> 32)) { ++ program_interrupt(env, PGM_SPECIAL_OP, 2); ++ } ++ ++ env->exception_index = old_exc; ++ if (mmu_translate(env, addr, 0, asc, &ret, &flags)) { ++ cc = 3; ++ } ++ if (env->exception_index == EXCP_PGM) { ++ ret = env->int_pgm_code | 0x80000000; ++ } else { ++ ret |= addr & ~TARGET_PAGE_MASK; ++ } ++ env->exception_index = old_exc; ++ ++ if (!(env->psw.mask & PSW_MASK_64)) { ++ env->regs[r1] = (env->regs[r1] & 0xffffffff00000000ULL) | ++ (ret & 0xffffffffULL); ++ } else { ++ env->regs[r1] = ret; ++ } ++ ++ return cc; ++} ++ ++#endif +diff --git a/target-s390x/op_helper.c b/target-s390x/op_helper.c +index 3b8b997..bb8dbf5 100644 +--- a/target-s390x/op_helper.c ++++ b/target-s390x/op_helper.c +@@ -32,57 +32,8 @@ + #endif + + #if !defined(CONFIG_USER_ONLY) +-#include "sysemu.h" +-#endif +- +-/*****************************************************************************/ +-/* Softmmu support */ +-#if !defined(CONFIG_USER_ONLY) + #include "softmmu_exec.h" +- +-#define MMUSUFFIX _mmu +- +-#define SHIFT 0 +-#include "softmmu_template.h" +- +-#define SHIFT 1 +-#include "softmmu_template.h" +- +-#define SHIFT 2 +-#include "softmmu_template.h" +- +-#define SHIFT 3 +-#include "softmmu_template.h" +- +-/* try to fill the TLB and return an exception if error. If retaddr is +- NULL, it means that the function was called in C code (i.e. not +- from generated code or from helper.c) */ +-/* XXX: fix it to restore all registers */ +-void tlb_fill(CPUS390XState *env1, target_ulong addr, int is_write, int mmu_idx, +- uintptr_t retaddr) +-{ +- TranslationBlock *tb; +- CPUS390XState *saved_env; +- int ret; +- +- saved_env = env; +- env = env1; +- ret = cpu_s390x_handle_mmu_fault(env, addr, is_write, mmu_idx); +- if (unlikely(ret != 0)) { +- if (likely(retaddr)) { +- /* now we have a real cpu fault */ +- tb = tb_find_pc(retaddr); +- if (likely(tb)) { +- /* the PC is inside the translated code. It means that we have +- a virtual CPU fault */ +- cpu_restore_state(tb, env, retaddr); +- } +- } +- cpu_loop_exit(env); +- } +- env = saved_env; +-} +- ++#include "sysemu.h" + #endif + + /* #define DEBUG_HELPER */ +@@ -101,840 +52,6 @@ void HELPER(exception)(uint32_t excp) + } + + #ifndef CONFIG_USER_ONLY +-static void mvc_fast_memset(CPUS390XState *env, uint32_t l, uint64_t dest, +- uint8_t byte) +-{ +- target_phys_addr_t dest_phys; +- target_phys_addr_t len = l; +- void *dest_p; +- uint64_t asc = env->psw.mask & PSW_MASK_ASC; +- int flags; +- +- if (mmu_translate(env, dest, 1, asc, &dest_phys, &flags)) { +- stb(dest, byte); +- cpu_abort(env, "should never reach here"); +- } +- dest_phys |= dest & ~TARGET_PAGE_MASK; +- +- dest_p = cpu_physical_memory_map(dest_phys, &len, 1); +- +- memset(dest_p, byte, len); +- +- cpu_physical_memory_unmap(dest_p, 1, len, len); +-} +- +-static void mvc_fast_memmove(CPUS390XState *env, uint32_t l, uint64_t dest, +- uint64_t src) +-{ +- target_phys_addr_t dest_phys; +- target_phys_addr_t src_phys; +- target_phys_addr_t len = l; +- void *dest_p; +- void *src_p; +- uint64_t asc = env->psw.mask & PSW_MASK_ASC; +- int flags; +- +- if (mmu_translate(env, dest, 1, asc, &dest_phys, &flags)) { +- stb(dest, 0); +- cpu_abort(env, "should never reach here"); +- } +- dest_phys |= dest & ~TARGET_PAGE_MASK; +- +- if (mmu_translate(env, src, 0, asc, &src_phys, &flags)) { +- ldub(src); +- cpu_abort(env, "should never reach here"); +- } +- src_phys |= src & ~TARGET_PAGE_MASK; +- +- dest_p = cpu_physical_memory_map(dest_phys, &len, 1); +- src_p = cpu_physical_memory_map(src_phys, &len, 0); +- +- memmove(dest_p, src_p, len); +- +- cpu_physical_memory_unmap(dest_p, 1, len, len); +- cpu_physical_memory_unmap(src_p, 0, len, len); +-} +-#endif +- +-/* and on array */ +-uint32_t HELPER(nc)(uint32_t l, uint64_t dest, uint64_t src) +-{ +- int i; +- unsigned char x; +- uint32_t cc = 0; +- +- HELPER_LOG("%s l %d dest %" PRIx64 " src %" PRIx64 "\n", +- __func__, l, dest, src); +- for (i = 0; i <= l; i++) { +- x = ldub(dest + i) & ldub(src + i); +- if (x) { +- cc = 1; +- } +- stb(dest + i, x); +- } +- return cc; +-} +- +-/* xor on array */ +-uint32_t HELPER(xc)(uint32_t l, uint64_t dest, uint64_t src) +-{ +- int i; +- unsigned char x; +- uint32_t cc = 0; +- +- HELPER_LOG("%s l %d dest %" PRIx64 " src %" PRIx64 "\n", +- __func__, l, dest, src); +- +-#ifndef CONFIG_USER_ONLY +- /* xor with itself is the same as memset(0) */ +- if ((l > 32) && (src == dest) && +- (src & TARGET_PAGE_MASK) == ((src + l) & TARGET_PAGE_MASK)) { +- mvc_fast_memset(env, l + 1, dest, 0); +- return 0; +- } +-#else +- if (src == dest) { +- memset(g2h(dest), 0, l + 1); +- return 0; +- } +-#endif +- +- for (i = 0; i <= l; i++) { +- x = ldub(dest + i) ^ ldub(src + i); +- if (x) { +- cc = 1; +- } +- stb(dest + i, x); +- } +- return cc; +-} +- +-/* or on array */ +-uint32_t HELPER(oc)(uint32_t l, uint64_t dest, uint64_t src) +-{ +- int i; +- unsigned char x; +- uint32_t cc = 0; +- +- HELPER_LOG("%s l %d dest %" PRIx64 " src %" PRIx64 "\n", +- __func__, l, dest, src); +- for (i = 0; i <= l; i++) { +- x = ldub(dest + i) | ldub(src + i); +- if (x) { +- cc = 1; +- } +- stb(dest + i, x); +- } +- return cc; +-} +- +-/* memmove */ +-void HELPER(mvc)(uint32_t l, uint64_t dest, uint64_t src) +-{ +- int i = 0; +- int x = 0; +- uint32_t l_64 = (l + 1) / 8; +- +- HELPER_LOG("%s l %d dest %" PRIx64 " src %" PRIx64 "\n", +- __func__, l, dest, src); +- +-#ifndef CONFIG_USER_ONLY +- if ((l > 32) && +- (src & TARGET_PAGE_MASK) == ((src + l) & TARGET_PAGE_MASK) && +- (dest & TARGET_PAGE_MASK) == ((dest + l) & TARGET_PAGE_MASK)) { +- if (dest == (src + 1)) { +- mvc_fast_memset(env, l + 1, dest, ldub(src)); +- return; +- } else if ((src & TARGET_PAGE_MASK) != (dest & TARGET_PAGE_MASK)) { +- mvc_fast_memmove(env, l + 1, dest, src); +- return; +- } +- } +-#else +- if (dest == (src + 1)) { +- memset(g2h(dest), ldub(src), l + 1); +- return; +- } else { +- memmove(g2h(dest), g2h(src), l + 1); +- return; +- } +-#endif +- +- /* handle the parts that fit into 8-byte loads/stores */ +- if (dest != (src + 1)) { +- for (i = 0; i < l_64; i++) { +- stq(dest + x, ldq(src + x)); +- x += 8; +- } +- } +- +- /* slow version crossing pages with byte accesses */ +- for (i = x; i <= l; i++) { +- stb(dest + i, ldub(src + i)); +- } +-} +- +-/* compare unsigned byte arrays */ +-uint32_t HELPER(clc)(uint32_t l, uint64_t s1, uint64_t s2) +-{ +- int i; +- unsigned char x, y; +- uint32_t cc; +- +- HELPER_LOG("%s l %d s1 %" PRIx64 " s2 %" PRIx64 "\n", +- __func__, l, s1, s2); +- for (i = 0; i <= l; i++) { +- x = ldub(s1 + i); +- y = ldub(s2 + i); +- HELPER_LOG("%02x (%c)/%02x (%c) ", x, x, y, y); +- if (x < y) { +- cc = 1; +- goto done; +- } else if (x > y) { +- cc = 2; +- goto done; +- } +- } +- cc = 0; +- done: +- HELPER_LOG("\n"); +- return cc; +-} +- +-/* compare logical under mask */ +-uint32_t HELPER(clm)(uint32_t r1, uint32_t mask, uint64_t addr) +-{ +- uint8_t r, d; +- uint32_t cc; +- +- HELPER_LOG("%s: r1 0x%x mask 0x%x addr 0x%" PRIx64 "\n", __func__, r1, +- mask, addr); +- cc = 0; +- while (mask) { +- if (mask & 8) { +- d = ldub(addr); +- r = (r1 & 0xff000000UL) >> 24; +- HELPER_LOG("mask 0x%x %02x/%02x (0x%" PRIx64 ") ", mask, r, d, +- addr); +- if (r < d) { +- cc = 1; +- break; +- } else if (r > d) { +- cc = 2; +- break; +- } +- addr++; +- } +- mask = (mask << 1) & 0xf; +- r1 <<= 8; +- } +- HELPER_LOG("\n"); +- return cc; +-} +- +-/* store character under mask */ +-void HELPER(stcm)(uint32_t r1, uint32_t mask, uint64_t addr) +-{ +- uint8_t r; +- +- HELPER_LOG("%s: r1 0x%x mask 0x%x addr 0x%lx\n", __func__, r1, mask, +- addr); +- while (mask) { +- if (mask & 8) { +- r = (r1 & 0xff000000UL) >> 24; +- stb(addr, r); +- HELPER_LOG("mask 0x%x %02x (0x%lx) ", mask, r, addr); +- addr++; +- } +- mask = (mask << 1) & 0xf; +- r1 <<= 8; +- } +- HELPER_LOG("\n"); +-} +- +-static inline uint64_t get_address(int x2, int b2, int d2) +-{ +- uint64_t r = d2; +- +- if (x2) { +- r += env->regs[x2]; +- } +- +- if (b2) { +- r += env->regs[b2]; +- } +- +- /* 31-Bit mode */ +- if (!(env->psw.mask & PSW_MASK_64)) { +- r &= 0x7fffffff; +- } +- +- return r; +-} +- +-static inline uint64_t get_address_31fix(int reg) +-{ +- uint64_t r = env->regs[reg]; +- +- /* 31-Bit mode */ +- if (!(env->psw.mask & PSW_MASK_64)) { +- r &= 0x7fffffff; +- } +- +- return r; +-} +- +-/* search string (c is byte to search, r2 is string, r1 end of string) */ +-uint32_t HELPER(srst)(uint32_t c, uint32_t r1, uint32_t r2) +-{ +- uint64_t i; +- uint32_t cc = 2; +- uint64_t str = get_address_31fix(r2); +- uint64_t end = get_address_31fix(r1); +- +- HELPER_LOG("%s: c %d *r1 0x%" PRIx64 " *r2 0x%" PRIx64 "\n", __func__, +- c, env->regs[r1], env->regs[r2]); +- +- for (i = str; i != end; i++) { +- if (ldub(i) == c) { +- env->regs[r1] = i; +- cc = 1; +- break; +- } +- } +- +- return cc; +-} +- +-/* unsigned string compare (c is string terminator) */ +-uint32_t HELPER(clst)(uint32_t c, uint32_t r1, uint32_t r2) +-{ +- uint64_t s1 = get_address_31fix(r1); +- uint64_t s2 = get_address_31fix(r2); +- uint8_t v1, v2; +- uint32_t cc; +- +- c = c & 0xff; +-#ifdef CONFIG_USER_ONLY +- if (!c) { +- HELPER_LOG("%s: comparing '%s' and '%s'\n", +- __func__, (char *)g2h(s1), (char *)g2h(s2)); +- } +-#endif +- for (;;) { +- v1 = ldub(s1); +- v2 = ldub(s2); +- if ((v1 == c || v2 == c) || (v1 != v2)) { +- break; +- } +- s1++; +- s2++; +- } +- +- if (v1 == v2) { +- cc = 0; +- } else { +- cc = (v1 < v2) ? 1 : 2; +- /* FIXME: 31-bit mode! */ +- env->regs[r1] = s1; +- env->regs[r2] = s2; +- } +- return cc; +-} +- +-/* move page */ +-void HELPER(mvpg)(uint64_t r0, uint64_t r1, uint64_t r2) +-{ +- /* XXX missing r0 handling */ +-#ifdef CONFIG_USER_ONLY +- int i; +- +- for (i = 0; i < TARGET_PAGE_SIZE; i++) { +- stb(r1 + i, ldub(r2 + i)); +- } +-#else +- mvc_fast_memmove(env, TARGET_PAGE_SIZE, r1, r2); +-#endif +-} +- +-/* string copy (c is string terminator) */ +-void HELPER(mvst)(uint32_t c, uint32_t r1, uint32_t r2) +-{ +- uint64_t dest = get_address_31fix(r1); +- uint64_t src = get_address_31fix(r2); +- uint8_t v; +- +- c = c & 0xff; +-#ifdef CONFIG_USER_ONLY +- if (!c) { +- HELPER_LOG("%s: copy '%s' to 0x%lx\n", __func__, (char *)g2h(src), +- dest); +- } +-#endif +- for (;;) { +- v = ldub(src); +- stb(dest, v); +- if (v == c) { +- break; +- } +- src++; +- dest++; +- } +- env->regs[r1] = dest; /* FIXME: 31-bit mode! */ +-} +- +-/* compare and swap 64-bit */ +-uint32_t HELPER(csg)(uint32_t r1, uint64_t a2, uint32_t r3) +-{ +- /* FIXME: locking? */ +- uint32_t cc; +- uint64_t v2 = ldq(a2); +- +- if (env->regs[r1] == v2) { +- cc = 0; +- stq(a2, env->regs[r3]); +- } else { +- cc = 1; +- env->regs[r1] = v2; +- } +- return cc; +-} +- +-/* compare double and swap 64-bit */ +-uint32_t HELPER(cdsg)(uint32_t r1, uint64_t a2, uint32_t r3) +-{ +- /* FIXME: locking? */ +- uint32_t cc; +- uint64_t v2_hi = ldq(a2); +- uint64_t v2_lo = ldq(a2 + 8); +- uint64_t v1_hi = env->regs[r1]; +- uint64_t v1_lo = env->regs[r1 + 1]; +- +- if ((v1_hi == v2_hi) && (v1_lo == v2_lo)) { +- cc = 0; +- stq(a2, env->regs[r3]); +- stq(a2 + 8, env->regs[r3 + 1]); +- } else { +- cc = 1; +- env->regs[r1] = v2_hi; +- env->regs[r1 + 1] = v2_lo; +- } +- +- return cc; +-} +- +-/* compare and swap 32-bit */ +-uint32_t HELPER(cs)(uint32_t r1, uint64_t a2, uint32_t r3) +-{ +- /* FIXME: locking? */ +- uint32_t cc; +- uint32_t v2 = ldl(a2); +- +- HELPER_LOG("%s: r1 %d a2 0x%lx r3 %d\n", __func__, r1, a2, r3); +- if (((uint32_t)env->regs[r1]) == v2) { +- cc = 0; +- stl(a2, (uint32_t)env->regs[r3]); +- } else { +- cc = 1; +- env->regs[r1] = (env->regs[r1] & 0xffffffff00000000ULL) | v2; +- } +- return cc; +-} +- +-static uint32_t helper_icm(uint32_t r1, uint64_t address, uint32_t mask) +-{ +- int pos = 24; /* top of the lower half of r1 */ +- uint64_t rmask = 0xff000000ULL; +- uint8_t val = 0; +- int ccd = 0; +- uint32_t cc = 0; +- +- while (mask) { +- if (mask & 8) { +- env->regs[r1] &= ~rmask; +- val = ldub(address); +- if ((val & 0x80) && !ccd) { +- cc = 1; +- } +- ccd = 1; +- if (val && cc == 0) { +- cc = 2; +- } +- env->regs[r1] |= (uint64_t)val << pos; +- address++; +- } +- mask = (mask << 1) & 0xf; +- pos -= 8; +- rmask >>= 8; +- } +- +- return cc; +-} +- +-/* execute instruction +- this instruction executes an insn modified with the contents of r1 +- it does not change the executed instruction in memory +- it does not change the program counter +- in other words: tricky... +- currently implemented by interpreting the cases it is most commonly used in +-*/ +-uint32_t HELPER(ex)(uint32_t cc, uint64_t v1, uint64_t addr, uint64_t ret) +-{ +- uint16_t insn = lduw_code(addr); +- +- HELPER_LOG("%s: v1 0x%lx addr 0x%lx insn 0x%x\n", __func__, v1, addr, +- insn); +- if ((insn & 0xf0ff) == 0xd000) { +- uint32_t l, insn2, b1, b2, d1, d2; +- +- l = v1 & 0xff; +- insn2 = ldl_code(addr + 2); +- b1 = (insn2 >> 28) & 0xf; +- b2 = (insn2 >> 12) & 0xf; +- d1 = (insn2 >> 16) & 0xfff; +- d2 = insn2 & 0xfff; +- switch (insn & 0xf00) { +- case 0x200: +- helper_mvc(l, get_address(0, b1, d1), get_address(0, b2, d2)); +- break; +- case 0x500: +- cc = helper_clc(l, get_address(0, b1, d1), get_address(0, b2, d2)); +- break; +- case 0x700: +- cc = helper_xc(l, get_address(0, b1, d1), get_address(0, b2, d2)); +- break; +- case 0xc00: +- helper_tr(l, get_address(0, b1, d1), get_address(0, b2, d2)); +- break; +- default: +- goto abort; +- break; +- } +- } else if ((insn & 0xff00) == 0x0a00) { +- /* supervisor call */ +- HELPER_LOG("%s: svc %ld via execute\n", __func__, (insn | v1) & 0xff); +- env->psw.addr = ret - 4; +- env->int_svc_code = (insn | v1) & 0xff; +- env->int_svc_ilc = 4; +- helper_exception(EXCP_SVC); +- } else if ((insn & 0xff00) == 0xbf00) { +- uint32_t insn2, r1, r3, b2, d2; +- +- insn2 = ldl_code(addr + 2); +- r1 = (insn2 >> 20) & 0xf; +- r3 = (insn2 >> 16) & 0xf; +- b2 = (insn2 >> 12) & 0xf; +- d2 = insn2 & 0xfff; +- cc = helper_icm(r1, get_address(0, b2, d2), r3); +- } else { +- abort: +- cpu_abort(env, "EXECUTE on instruction prefix 0x%x not implemented\n", +- insn); +- } +- return cc; +-} +- +-/* store character under mask high operates on the upper half of r1 */ +-void HELPER(stcmh)(uint32_t r1, uint64_t address, uint32_t mask) +-{ +- int pos = 56; /* top of the upper half of r1 */ +- +- while (mask) { +- if (mask & 8) { +- stb(address, (env->regs[r1] >> pos) & 0xff); +- address++; +- } +- mask = (mask << 1) & 0xf; +- pos -= 8; +- } +-} +- +-/* insert character under mask high; same as icm, but operates on the +- upper half of r1 */ +-uint32_t HELPER(icmh)(uint32_t r1, uint64_t address, uint32_t mask) +-{ +- int pos = 56; /* top of the upper half of r1 */ +- uint64_t rmask = 0xff00000000000000ULL; +- uint8_t val = 0; +- int ccd = 0; +- uint32_t cc = 0; +- +- while (mask) { +- if (mask & 8) { +- env->regs[r1] &= ~rmask; +- val = ldub(address); +- if ((val & 0x80) && !ccd) { +- cc = 1; +- } +- ccd = 1; +- if (val && cc == 0) { +- cc = 2; +- } +- env->regs[r1] |= (uint64_t)val << pos; +- address++; +- } +- mask = (mask << 1) & 0xf; +- pos -= 8; +- rmask >>= 8; +- } +- +- return cc; +-} +- +-/* load access registers r1 to r3 from memory at a2 */ +-void HELPER(lam)(uint32_t r1, uint64_t a2, uint32_t r3) +-{ +- int i; +- +- for (i = r1;; i = (i + 1) % 16) { +- env->aregs[i] = ldl(a2); +- a2 += 4; +- +- if (i == r3) { +- break; +- } +- } +-} +- +-/* store access registers r1 to r3 in memory at a2 */ +-void HELPER(stam)(uint32_t r1, uint64_t a2, uint32_t r3) +-{ +- int i; +- +- for (i = r1;; i = (i + 1) % 16) { +- stl(a2, env->aregs[i]); +- a2 += 4; +- +- if (i == r3) { +- break; +- } +- } +-} +- +-/* move long */ +-uint32_t HELPER(mvcl)(uint32_t r1, uint32_t r2) +-{ +- uint64_t destlen = env->regs[r1 + 1] & 0xffffff; +- uint64_t dest = get_address_31fix(r1); +- uint64_t srclen = env->regs[r2 + 1] & 0xffffff; +- uint64_t src = get_address_31fix(r2); +- uint8_t pad = src >> 24; +- uint8_t v; +- uint32_t cc; +- +- if (destlen == srclen) { +- cc = 0; +- } else if (destlen < srclen) { +- cc = 1; +- } else { +- cc = 2; +- } +- +- if (srclen > destlen) { +- srclen = destlen; +- } +- +- for (; destlen && srclen; src++, dest++, destlen--, srclen--) { +- v = ldub(src); +- stb(dest, v); +- } +- +- for (; destlen; dest++, destlen--) { +- stb(dest, pad); +- } +- +- env->regs[r1 + 1] = destlen; +- /* can't use srclen here, we trunc'ed it */ +- env->regs[r2 + 1] -= src - env->regs[r2]; +- env->regs[r1] = dest; +- env->regs[r2] = src; +- +- return cc; +-} +- +-/* move long extended another memcopy insn with more bells and whistles */ +-uint32_t HELPER(mvcle)(uint32_t r1, uint64_t a2, uint32_t r3) +-{ +- uint64_t destlen = env->regs[r1 + 1]; +- uint64_t dest = env->regs[r1]; +- uint64_t srclen = env->regs[r3 + 1]; +- uint64_t src = env->regs[r3]; +- uint8_t pad = a2 & 0xff; +- uint8_t v; +- uint32_t cc; +- +- if (!(env->psw.mask & PSW_MASK_64)) { +- destlen = (uint32_t)destlen; +- srclen = (uint32_t)srclen; +- dest &= 0x7fffffff; +- src &= 0x7fffffff; +- } +- +- if (destlen == srclen) { +- cc = 0; +- } else if (destlen < srclen) { +- cc = 1; +- } else { +- cc = 2; +- } +- +- if (srclen > destlen) { +- srclen = destlen; +- } +- +- for (; destlen && srclen; src++, dest++, destlen--, srclen--) { +- v = ldub(src); +- stb(dest, v); +- } +- +- for (; destlen; dest++, destlen--) { +- stb(dest, pad); +- } +- +- env->regs[r1 + 1] = destlen; +- /* can't use srclen here, we trunc'ed it */ +- /* FIXME: 31-bit mode! */ +- env->regs[r3 + 1] -= src - env->regs[r3]; +- env->regs[r1] = dest; +- env->regs[r3] = src; +- +- return cc; +-} +- +-/* compare logical long extended memcompare insn with padding */ +-uint32_t HELPER(clcle)(uint32_t r1, uint64_t a2, uint32_t r3) +-{ +- uint64_t destlen = env->regs[r1 + 1]; +- uint64_t dest = get_address_31fix(r1); +- uint64_t srclen = env->regs[r3 + 1]; +- uint64_t src = get_address_31fix(r3); +- uint8_t pad = a2 & 0xff; +- uint8_t v1 = 0, v2 = 0; +- uint32_t cc = 0; +- +- if (!(destlen || srclen)) { +- return cc; +- } +- +- if (srclen > destlen) { +- srclen = destlen; +- } +- +- for (; destlen || srclen; src++, dest++, destlen--, srclen--) { +- v1 = srclen ? ldub(src) : pad; +- v2 = destlen ? ldub(dest) : pad; +- if (v1 != v2) { +- cc = (v1 < v2) ? 1 : 2; +- break; +- } +- } +- +- env->regs[r1 + 1] = destlen; +- /* can't use srclen here, we trunc'ed it */ +- env->regs[r3 + 1] -= src - env->regs[r3]; +- env->regs[r1] = dest; +- env->regs[r3] = src; +- +- return cc; +-} +- +-/* checksum */ +-void HELPER(cksm)(uint32_t r1, uint32_t r2) +-{ +- uint64_t src = get_address_31fix(r2); +- uint64_t src_len = env->regs[(r2 + 1) & 15]; +- uint64_t cksm = (uint32_t)env->regs[r1]; +- +- while (src_len >= 4) { +- cksm += ldl(src); +- +- /* move to next word */ +- src_len -= 4; +- src += 4; +- } +- +- switch (src_len) { +- case 0: +- break; +- case 1: +- cksm += ldub(src) << 24; +- break; +- case 2: +- cksm += lduw(src) << 16; +- break; +- case 3: +- cksm += lduw(src) << 16; +- cksm += ldub(src + 2) << 8; +- break; +- } +- +- /* indicate we've processed everything */ +- env->regs[r2] = src + src_len; +- env->regs[(r2 + 1) & 15] = 0; +- +- /* store result */ +- env->regs[r1] = (env->regs[r1] & 0xffffffff00000000ULL) | +- ((uint32_t)cksm + (cksm >> 32)); +-} +- +-void HELPER(unpk)(uint32_t len, uint64_t dest, uint64_t src) +-{ +- int len_dest = len >> 4; +- int len_src = len & 0xf; +- uint8_t b; +- int second_nibble = 0; +- +- dest += len_dest; +- src += len_src; +- +- /* last byte is special, it only flips the nibbles */ +- b = ldub(src); +- stb(dest, (b << 4) | (b >> 4)); +- src--; +- len_src--; +- +- /* now pad every nibble with 0xf0 */ +- +- while (len_dest > 0) { +- uint8_t cur_byte = 0; +- +- if (len_src > 0) { +- cur_byte = ldub(src); +- } +- +- len_dest--; +- dest--; +- +- /* only advance one nibble at a time */ +- if (second_nibble) { +- cur_byte >>= 4; +- len_src--; +- src--; +- } +- second_nibble = !second_nibble; +- +- /* digit */ +- cur_byte = (cur_byte & 0xf); +- /* zone bits */ +- cur_byte |= 0xf0; +- +- stb(dest, cur_byte); +- } +-} +- +-void HELPER(tr)(uint32_t len, uint64_t array, uint64_t trans) +-{ +- int i; +- +- for (i = 0; i <= len; i++) { +- uint8_t byte = ldub(array + i); +- uint8_t new_byte = ldub(trans + byte); +- +- stb(array + i, new_byte); +- } +-} +- +-#ifndef CONFIG_USER_ONLY + void program_interrupt(CPUS390XState *env, uint32_t code, int ilc) + { + qemu_log("program interrupt at %#" PRIx64 "\n", env->psw.addr); +@@ -1267,206 +384,6 @@ uint32_t HELPER(stsi)(uint64_t a0, uint32_t r0, uint32_t r1) + return cc; + } + +-void HELPER(lctlg)(uint32_t r1, uint64_t a2, uint32_t r3) +-{ +- int i; +- uint64_t src = a2; +- +- for (i = r1;; i = (i + 1) % 16) { +- env->cregs[i] = ldq(src); +- HELPER_LOG("load ctl %d from 0x%" PRIx64 " == 0x%" PRIx64 "\n", +- i, src, env->cregs[i]); +- src += sizeof(uint64_t); +- +- if (i == r3) { +- break; +- } +- } +- +- tlb_flush(env, 1); +-} +- +-void HELPER(lctl)(uint32_t r1, uint64_t a2, uint32_t r3) +-{ +- int i; +- uint64_t src = a2; +- +- for (i = r1;; i = (i + 1) % 16) { +- env->cregs[i] = (env->cregs[i] & 0xFFFFFFFF00000000ULL) | ldl(src); +- src += sizeof(uint32_t); +- +- if (i == r3) { +- break; +- } +- } +- +- tlb_flush(env, 1); +-} +- +-void HELPER(stctg)(uint32_t r1, uint64_t a2, uint32_t r3) +-{ +- int i; +- uint64_t dest = a2; +- +- for (i = r1;; i = (i + 1) % 16) { +- stq(dest, env->cregs[i]); +- dest += sizeof(uint64_t); +- +- if (i == r3) { +- break; +- } +- } +-} +- +-void HELPER(stctl)(uint32_t r1, uint64_t a2, uint32_t r3) +-{ +- int i; +- uint64_t dest = a2; +- +- for (i = r1;; i = (i + 1) % 16) { +- stl(dest, env->cregs[i]); +- dest += sizeof(uint32_t); +- +- if (i == r3) { +- break; +- } +- } +-} +- +-uint32_t HELPER(tprot)(uint64_t a1, uint64_t a2) +-{ +- /* XXX implement */ +- +- return 0; +-} +- +-/* insert storage key extended */ +-uint64_t HELPER(iske)(uint64_t r2) +-{ +- uint64_t addr = get_address(0, 0, r2); +- +- if (addr > ram_size) { +- return 0; +- } +- +- return env->storage_keys[addr / TARGET_PAGE_SIZE]; +-} +- +-/* set storage key extended */ +-void HELPER(sske)(uint32_t r1, uint64_t r2) +-{ +- uint64_t addr = get_address(0, 0, r2); +- +- if (addr > ram_size) { +- return; +- } +- +- env->storage_keys[addr / TARGET_PAGE_SIZE] = r1; +-} +- +-/* reset reference bit extended */ +-uint32_t HELPER(rrbe)(uint32_t r1, uint64_t r2) +-{ +- uint8_t re; +- uint8_t key; +- +- if (r2 > ram_size) { +- return 0; +- } +- +- key = env->storage_keys[r2 / TARGET_PAGE_SIZE]; +- re = key & (SK_R | SK_C); +- env->storage_keys[r2 / TARGET_PAGE_SIZE] = (key & ~SK_R); +- +- /* +- * cc +- * +- * 0 Reference bit zero; change bit zero +- * 1 Reference bit zero; change bit one +- * 2 Reference bit one; change bit zero +- * 3 Reference bit one; change bit one +- */ +- +- return re >> 1; +-} +- +-/* compare and swap and purge */ +-uint32_t HELPER(csp)(uint32_t r1, uint32_t r2) +-{ +- uint32_t cc; +- uint32_t o1 = env->regs[r1]; +- uint64_t a2 = get_address_31fix(r2) & ~3ULL; +- uint32_t o2 = ldl(a2); +- +- if (o1 == o2) { +- stl(a2, env->regs[(r1 + 1) & 15]); +- if (env->regs[r2] & 0x3) { +- /* flush TLB / ALB */ +- tlb_flush(env, 1); +- } +- cc = 0; +- } else { +- env->regs[r1] = (env->regs[r1] & 0xffffffff00000000ULL) | o2; +- cc = 1; +- } +- +- return cc; +-} +- +-static uint32_t mvc_asc(int64_t l, uint64_t a1, uint64_t mode1, uint64_t a2, +- uint64_t mode2) +-{ +- target_ulong src, dest; +- int flags, cc = 0, i; +- +- if (!l) { +- return 0; +- } else if (l > 256) { +- /* max 256 */ +- l = 256; +- cc = 3; +- } +- +- if (mmu_translate(env, a1 & TARGET_PAGE_MASK, 1, mode1, &dest, &flags)) { +- cpu_loop_exit(env); +- } +- dest |= a1 & ~TARGET_PAGE_MASK; +- +- if (mmu_translate(env, a2 & TARGET_PAGE_MASK, 0, mode2, &src, &flags)) { +- cpu_loop_exit(env); +- } +- src |= a2 & ~TARGET_PAGE_MASK; +- +- /* XXX replace w/ memcpy */ +- for (i = 0; i < l; i++) { +- /* XXX be more clever */ +- if ((((dest + i) & TARGET_PAGE_MASK) != (dest & TARGET_PAGE_MASK)) || +- (((src + i) & TARGET_PAGE_MASK) != (src & TARGET_PAGE_MASK))) { +- mvc_asc(l - i, a1 + i, mode1, a2 + i, mode2); +- break; +- } +- stb_phys(dest + i, ldub_phys(src + i)); +- } +- +- return cc; +-} +- +-uint32_t HELPER(mvcs)(uint64_t l, uint64_t a1, uint64_t a2) +-{ +- HELPER_LOG("%s: %16" PRIx64 " %16" PRIx64 " %16" PRIx64 "\n", +- __func__, l, a1, a2); +- +- return mvc_asc(l, a1, PSW_ASC_SECONDARY, a2, PSW_ASC_PRIMARY); +-} +- +-uint32_t HELPER(mvcp)(uint64_t l, uint64_t a1, uint64_t a2) +-{ +- HELPER_LOG("%s: %16" PRIx64 " %16" PRIx64 " %16" PRIx64 "\n", +- __func__, l, a1, a2); +- +- return mvc_asc(l, a1, PSW_ASC_PRIMARY, a2, PSW_ASC_SECONDARY); +-} +- + uint32_t HELPER(sigp)(uint64_t order_code, uint32_t r1, uint64_t cpu_addr) + { + int cc = 0; +@@ -1508,78 +425,4 @@ uint32_t HELPER(sigp)(uint64_t order_code, uint32_t r1, uint64_t cpu_addr) + + return cc; + } +- +-/* invalidate pte */ +-void HELPER(ipte)(uint64_t pte_addr, uint64_t vaddr) +-{ +- uint64_t page = vaddr & TARGET_PAGE_MASK; +- uint64_t pte = 0; +- +- /* XXX broadcast to other CPUs */ +- +- /* XXX Linux is nice enough to give us the exact pte address. +- According to spec we'd have to find it out ourselves */ +- /* XXX Linux is fine with overwriting the pte, the spec requires +- us to only set the invalid bit */ +- stq_phys(pte_addr, pte | _PAGE_INVALID); +- +- /* XXX we exploit the fact that Linux passes the exact virtual +- address here - it's not obliged to! */ +- tlb_flush_page(env, page); +- +- /* XXX 31-bit hack */ +- if (page & 0x80000000) { +- tlb_flush_page(env, page & ~0x80000000); +- } else { +- tlb_flush_page(env, page | 0x80000000); +- } +-} +- +-/* flush local tlb */ +-void HELPER(ptlb)(void) +-{ +- tlb_flush(env, 1); +-} +- +-/* store using real address */ +-void HELPER(stura)(uint64_t addr, uint32_t v1) +-{ +- stw_phys(get_address(0, 0, addr), v1); +-} +- +-/* load real address */ +-uint32_t HELPER(lra)(uint64_t addr, uint32_t r1) +-{ +- uint32_t cc = 0; +- int old_exc = env->exception_index; +- uint64_t asc = env->psw.mask & PSW_MASK_ASC; +- uint64_t ret; +- int flags; +- +- /* XXX incomplete - has more corner cases */ +- if (!(env->psw.mask & PSW_MASK_64) && (addr >> 32)) { +- program_interrupt(env, PGM_SPECIAL_OP, 2); +- } +- +- env->exception_index = old_exc; +- if (mmu_translate(env, addr, 0, asc, &ret, &flags)) { +- cc = 3; +- } +- if (env->exception_index == EXCP_PGM) { +- ret = env->int_pgm_code | 0x80000000; +- } else { +- ret |= addr & ~TARGET_PAGE_MASK; +- } +- env->exception_index = old_exc; +- +- if (!(env->psw.mask & PSW_MASK_64)) { +- env->regs[r1] = (env->regs[r1] & 0xffffffff00000000ULL) | +- (ret & 0xffffffffULL); +- } else { +- env->regs[r1] = ret; +- } +- +- return cc; +-} +- + #endif +-- +1.7.12.1 + diff --git a/0010-target-s390x-rename-op_helper.c-to-misc_helper.c.patch b/0010-target-s390x-rename-op_helper.c-to-misc_helper.c.patch new file mode 100644 index 0000000..e96aa52 --- /dev/null +++ b/0010-target-s390x-rename-op_helper.c-to-misc_helper.c.patch @@ -0,0 +1,924 @@ +From 56018228deac6e704a7ec8befd9e9dc69f2fe73f Mon Sep 17 00:00:00 2001 +From: Blue Swirl +Date: Sun, 2 Sep 2012 07:33:35 +0000 +Subject: [PATCH] target-s390x: rename op_helper.c to misc_helper.c + +Now op_helper.c contains miscellaneous helpers, rename +it to misc_helper.c. + +Signed-off-by: Blue Swirl +[agraf: fix conflict] +Signed-off-by: Alexander Graf + +Signed-off-by: Michael Roth +--- + target-s390x/Makefile.objs | 6 +- + target-s390x/cpu.h | 2 +- + target-s390x/misc_helper.c | 428 +++++++++++++++++++++++++++++++++++++++++++++ + target-s390x/op_helper.c | 428 --------------------------------------------- + 4 files changed, 432 insertions(+), 432 deletions(-) + create mode 100644 target-s390x/misc_helper.c + delete mode 100644 target-s390x/op_helper.c + +diff --git a/target-s390x/Makefile.objs b/target-s390x/Makefile.objs +index b9b3061..a87d26f 100644 +--- a/target-s390x/Makefile.objs ++++ b/target-s390x/Makefile.objs +@@ -1,10 +1,10 @@ +-obj-y += translate.o op_helper.o helper.o cpu.o interrupt.o +-obj-y += int_helper.o fpu_helper.o cc_helper.o mem_helper.o ++obj-y += translate.o helper.o cpu.o interrupt.o ++obj-y += int_helper.o fpu_helper.o cc_helper.o mem_helper.o misc_helper.o + obj-$(CONFIG_SOFTMMU) += machine.o + obj-$(CONFIG_KVM) += kvm.o + +-$(obj)/op_helper.o: QEMU_CFLAGS += $(HELPER_CFLAGS) + $(obj)/int_helper.o: QEMU_CFLAGS += $(HELPER_CFLAGS) + $(obj)/fpu_helper.o: QEMU_CFLAGS += $(HELPER_CFLAGS) + $(obj)/cc_helper.o: QEMU_CFLAGS += $(HELPER_CFLAGS) + $(obj)/mem_helper.o: QEMU_CFLAGS += $(HELPER_CFLAGS) ++$(obj)/misc_helper.o: QEMU_CFLAGS += $(HELPER_CFLAGS) +diff --git a/target-s390x/cpu.h b/target-s390x/cpu.h +index 97fde5e..0ccb551 100644 +--- a/target-s390x/cpu.h ++++ b/target-s390x/cpu.h +@@ -1005,7 +1005,7 @@ uint32_t set_cc_f64(float64 v1, float64 v2); + uint32_t set_cc_nz_f32(float32 v); + uint32_t set_cc_nz_f64(float64 v); + +-/* op_helper.c */ ++/* misc_helper.c */ + void program_interrupt(CPUS390XState *env, uint32_t code, int ilc); + + #endif +diff --git a/target-s390x/misc_helper.c b/target-s390x/misc_helper.c +new file mode 100644 +index 0000000..1d5137f +--- /dev/null ++++ b/target-s390x/misc_helper.c +@@ -0,0 +1,428 @@ ++/* ++ * S/390 misc helper routines ++ * ++ * Copyright (c) 2009 Ulrich Hecht ++ * Copyright (c) 2009 Alexander Graf ++ * ++ * This library is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU Lesser General Public ++ * License as published by the Free Software Foundation; either ++ * version 2 of the License, or (at your option) any later version. ++ * ++ * This library is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * Lesser General Public License for more details. ++ * ++ * You should have received a copy of the GNU Lesser General Public ++ * License along with this library; if not, see . ++ */ ++ ++#include "cpu.h" ++#include "memory.h" ++#include "cputlb.h" ++#include "dyngen-exec.h" ++#include "host-utils.h" ++#include "helper.h" ++#include ++#include "kvm.h" ++#include "qemu-timer.h" ++#ifdef CONFIG_KVM ++#include ++#endif ++ ++#if !defined(CONFIG_USER_ONLY) ++#include "softmmu_exec.h" ++#include "sysemu.h" ++#endif ++ ++/* #define DEBUG_HELPER */ ++#ifdef DEBUG_HELPER ++#define HELPER_LOG(x...) qemu_log(x) ++#else ++#define HELPER_LOG(x...) ++#endif ++ ++/* raise an exception */ ++void HELPER(exception)(uint32_t excp) ++{ ++ HELPER_LOG("%s: exception %d\n", __func__, excp); ++ env->exception_index = excp; ++ cpu_loop_exit(env); ++} ++ ++#ifndef CONFIG_USER_ONLY ++void program_interrupt(CPUS390XState *env, uint32_t code, int ilc) ++{ ++ qemu_log("program interrupt at %#" PRIx64 "\n", env->psw.addr); ++ ++ if (kvm_enabled()) { ++#ifdef CONFIG_KVM ++ kvm_s390_interrupt(env, KVM_S390_PROGRAM_INT, code); ++#endif ++ } else { ++ env->int_pgm_code = code; ++ env->int_pgm_ilc = ilc; ++ env->exception_index = EXCP_PGM; ++ cpu_loop_exit(env); ++ } ++} ++ ++/* ++ * ret < 0 indicates program check, ret = 0, 1, 2, 3 -> cc ++ */ ++int sclp_service_call(CPUS390XState *env, uint32_t sccb, uint64_t code) ++{ ++ int r = 0; ++ int shift = 0; ++ ++#ifdef DEBUG_HELPER ++ printf("sclp(0x%x, 0x%" PRIx64 ")\n", sccb, code); ++#endif ++ ++ /* basic checks */ ++ if (!memory_region_is_ram(phys_page_find(sccb >> TARGET_PAGE_BITS)->mr)) { ++ return -PGM_ADDRESSING; ++ } ++ if (sccb & ~0x7ffffff8ul) { ++ return -PGM_SPECIFICATION; ++ } ++ ++ switch (code) { ++ case SCLP_CMDW_READ_SCP_INFO: ++ case SCLP_CMDW_READ_SCP_INFO_FORCED: ++ while ((ram_size >> (20 + shift)) > 65535) { ++ shift++; ++ } ++ stw_phys(sccb + SCP_MEM_CODE, ram_size >> (20 + shift)); ++ stb_phys(sccb + SCP_INCREMENT, 1 << shift); ++ stw_phys(sccb + SCP_RESPONSE_CODE, 0x10); ++ ++ s390_sclp_extint(sccb & ~3); ++ break; ++ default: ++#ifdef DEBUG_HELPER ++ printf("KVM: invalid sclp call 0x%x / 0x%" PRIx64 "x\n", sccb, code); ++#endif ++ r = 3; ++ break; ++ } ++ ++ return r; ++} ++ ++/* SCLP service call */ ++uint32_t HELPER(servc)(uint32_t r1, uint64_t r2) ++{ ++ int r; ++ ++ r = sclp_service_call(env, r1, r2); ++ if (r < 0) { ++ program_interrupt(env, -r, 4); ++ return 0; ++ } ++ return r; ++} ++ ++/* DIAG */ ++uint64_t HELPER(diag)(uint32_t num, uint64_t mem, uint64_t code) ++{ ++ uint64_t r; ++ ++ switch (num) { ++ case 0x500: ++ /* KVM hypercall */ ++ r = s390_virtio_hypercall(env, mem, code); ++ break; ++ case 0x44: ++ /* yield */ ++ r = 0; ++ break; ++ case 0x308: ++ /* ipl */ ++ r = 0; ++ break; ++ default: ++ r = -1; ++ break; ++ } ++ ++ if (r) { ++ program_interrupt(env, PGM_OPERATION, ILC_LATER_INC); ++ } ++ ++ return r; ++} ++ ++/* Store CPU ID */ ++void HELPER(stidp)(uint64_t a1) ++{ ++ stq(a1, env->cpu_num); ++} ++ ++/* Set Prefix */ ++void HELPER(spx)(uint64_t a1) ++{ ++ uint32_t prefix; ++ ++ prefix = ldl(a1); ++ env->psa = prefix & 0xfffff000; ++ qemu_log("prefix: %#x\n", prefix); ++ tlb_flush_page(env, 0); ++ tlb_flush_page(env, TARGET_PAGE_SIZE); ++} ++ ++/* Set Clock */ ++uint32_t HELPER(sck)(uint64_t a1) ++{ ++ /* XXX not implemented - is it necessary? */ ++ ++ return 0; ++} ++ ++static inline uint64_t clock_value(CPUS390XState *env) ++{ ++ uint64_t time; ++ ++ time = env->tod_offset + ++ time2tod(qemu_get_clock_ns(vm_clock) - env->tod_basetime); ++ ++ return time; ++} ++ ++/* Store Clock */ ++uint32_t HELPER(stck)(uint64_t a1) ++{ ++ stq(a1, clock_value(env)); ++ ++ return 0; ++} ++ ++/* Store Clock Extended */ ++uint32_t HELPER(stcke)(uint64_t a1) ++{ ++ stb(a1, 0); ++ /* basically the same value as stck */ ++ stq(a1 + 1, clock_value(env) | env->cpu_num); ++ /* more fine grained than stck */ ++ stq(a1 + 9, 0); ++ /* XXX programmable fields */ ++ stw(a1 + 17, 0); ++ ++ return 0; ++} ++ ++/* Set Clock Comparator */ ++void HELPER(sckc)(uint64_t a1) ++{ ++ uint64_t time = ldq(a1); ++ ++ if (time == -1ULL) { ++ return; ++ } ++ ++ /* difference between now and then */ ++ time -= clock_value(env); ++ /* nanoseconds */ ++ time = (time * 125) >> 9; ++ ++ qemu_mod_timer(env->tod_timer, qemu_get_clock_ns(vm_clock) + time); ++} ++ ++/* Store Clock Comparator */ ++void HELPER(stckc)(uint64_t a1) ++{ ++ /* XXX implement */ ++ stq(a1, 0); ++} ++ ++/* Set CPU Timer */ ++void HELPER(spt)(uint64_t a1) ++{ ++ uint64_t time = ldq(a1); ++ ++ if (time == -1ULL) { ++ return; ++ } ++ ++ /* nanoseconds */ ++ time = (time * 125) >> 9; ++ ++ qemu_mod_timer(env->cpu_timer, qemu_get_clock_ns(vm_clock) + time); ++} ++ ++/* Store CPU Timer */ ++void HELPER(stpt)(uint64_t a1) ++{ ++ /* XXX implement */ ++ stq(a1, 0); ++} ++ ++/* Store System Information */ ++uint32_t HELPER(stsi)(uint64_t a0, uint32_t r0, uint32_t r1) ++{ ++ int cc = 0; ++ int sel1, sel2; ++ ++ if ((r0 & STSI_LEVEL_MASK) <= STSI_LEVEL_3 && ++ ((r0 & STSI_R0_RESERVED_MASK) || (r1 & STSI_R1_RESERVED_MASK))) { ++ /* valid function code, invalid reserved bits */ ++ program_interrupt(env, PGM_SPECIFICATION, 2); ++ } ++ ++ sel1 = r0 & STSI_R0_SEL1_MASK; ++ sel2 = r1 & STSI_R1_SEL2_MASK; ++ ++ /* XXX: spec exception if sysib is not 4k-aligned */ ++ ++ switch (r0 & STSI_LEVEL_MASK) { ++ case STSI_LEVEL_1: ++ if ((sel1 == 1) && (sel2 == 1)) { ++ /* Basic Machine Configuration */ ++ struct sysib_111 sysib; ++ ++ memset(&sysib, 0, sizeof(sysib)); ++ ebcdic_put(sysib.manuf, "QEMU ", 16); ++ /* same as machine type number in STORE CPU ID */ ++ ebcdic_put(sysib.type, "QEMU", 4); ++ /* same as model number in STORE CPU ID */ ++ ebcdic_put(sysib.model, "QEMU ", 16); ++ ebcdic_put(sysib.sequence, "QEMU ", 16); ++ ebcdic_put(sysib.plant, "QEMU", 4); ++ cpu_physical_memory_rw(a0, (uint8_t *)&sysib, sizeof(sysib), 1); ++ } else if ((sel1 == 2) && (sel2 == 1)) { ++ /* Basic Machine CPU */ ++ struct sysib_121 sysib; ++ ++ memset(&sysib, 0, sizeof(sysib)); ++ /* XXX make different for different CPUs? */ ++ ebcdic_put(sysib.sequence, "QEMUQEMUQEMUQEMU", 16); ++ ebcdic_put(sysib.plant, "QEMU", 4); ++ stw_p(&sysib.cpu_addr, env->cpu_num); ++ cpu_physical_memory_rw(a0, (uint8_t *)&sysib, sizeof(sysib), 1); ++ } else if ((sel1 == 2) && (sel2 == 2)) { ++ /* Basic Machine CPUs */ ++ struct sysib_122 sysib; ++ ++ memset(&sysib, 0, sizeof(sysib)); ++ stl_p(&sysib.capability, 0x443afc29); ++ /* XXX change when SMP comes */ ++ stw_p(&sysib.total_cpus, 1); ++ stw_p(&sysib.active_cpus, 1); ++ stw_p(&sysib.standby_cpus, 0); ++ stw_p(&sysib.reserved_cpus, 0); ++ cpu_physical_memory_rw(a0, (uint8_t *)&sysib, sizeof(sysib), 1); ++ } else { ++ cc = 3; ++ } ++ break; ++ case STSI_LEVEL_2: ++ { ++ if ((sel1 == 2) && (sel2 == 1)) { ++ /* LPAR CPU */ ++ struct sysib_221 sysib; ++ ++ memset(&sysib, 0, sizeof(sysib)); ++ /* XXX make different for different CPUs? */ ++ ebcdic_put(sysib.sequence, "QEMUQEMUQEMUQEMU", 16); ++ ebcdic_put(sysib.plant, "QEMU", 4); ++ stw_p(&sysib.cpu_addr, env->cpu_num); ++ stw_p(&sysib.cpu_id, 0); ++ cpu_physical_memory_rw(a0, (uint8_t *)&sysib, sizeof(sysib), 1); ++ } else if ((sel1 == 2) && (sel2 == 2)) { ++ /* LPAR CPUs */ ++ struct sysib_222 sysib; ++ ++ memset(&sysib, 0, sizeof(sysib)); ++ stw_p(&sysib.lpar_num, 0); ++ sysib.lcpuc = 0; ++ /* XXX change when SMP comes */ ++ stw_p(&sysib.total_cpus, 1); ++ stw_p(&sysib.conf_cpus, 1); ++ stw_p(&sysib.standby_cpus, 0); ++ stw_p(&sysib.reserved_cpus, 0); ++ ebcdic_put(sysib.name, "QEMU ", 8); ++ stl_p(&sysib.caf, 1000); ++ stw_p(&sysib.dedicated_cpus, 0); ++ stw_p(&sysib.shared_cpus, 0); ++ cpu_physical_memory_rw(a0, (uint8_t *)&sysib, sizeof(sysib), 1); ++ } else { ++ cc = 3; ++ } ++ break; ++ } ++ case STSI_LEVEL_3: ++ { ++ if ((sel1 == 2) && (sel2 == 2)) { ++ /* VM CPUs */ ++ struct sysib_322 sysib; ++ ++ memset(&sysib, 0, sizeof(sysib)); ++ sysib.count = 1; ++ /* XXX change when SMP comes */ ++ stw_p(&sysib.vm[0].total_cpus, 1); ++ stw_p(&sysib.vm[0].conf_cpus, 1); ++ stw_p(&sysib.vm[0].standby_cpus, 0); ++ stw_p(&sysib.vm[0].reserved_cpus, 0); ++ ebcdic_put(sysib.vm[0].name, "KVMguest", 8); ++ stl_p(&sysib.vm[0].caf, 1000); ++ ebcdic_put(sysib.vm[0].cpi, "KVM/Linux ", 16); ++ cpu_physical_memory_rw(a0, (uint8_t *)&sysib, sizeof(sysib), 1); ++ } else { ++ cc = 3; ++ } ++ break; ++ } ++ case STSI_LEVEL_CURRENT: ++ env->regs[0] = STSI_LEVEL_3; ++ break; ++ default: ++ cc = 3; ++ break; ++ } ++ ++ return cc; ++} ++ ++uint32_t HELPER(sigp)(uint64_t order_code, uint32_t r1, uint64_t cpu_addr) ++{ ++ int cc = 0; ++ ++ HELPER_LOG("%s: %016" PRIx64 " %08x %016" PRIx64 "\n", ++ __func__, order_code, r1, cpu_addr); ++ ++ /* Remember: Use "R1 or R1 + 1, whichever is the odd-numbered register" ++ as parameter (input). Status (output) is always R1. */ ++ ++ switch (order_code) { ++ case SIGP_SET_ARCH: ++ /* switch arch */ ++ break; ++ case SIGP_SENSE: ++ /* enumerate CPU status */ ++ if (cpu_addr) { ++ /* XXX implement when SMP comes */ ++ return 3; ++ } ++ env->regs[r1] &= 0xffffffff00000000ULL; ++ cc = 1; ++ break; ++#if !defined(CONFIG_USER_ONLY) ++ case SIGP_RESTART: ++ qemu_system_reset_request(); ++ cpu_loop_exit(env); ++ break; ++ case SIGP_STOP: ++ qemu_system_shutdown_request(); ++ cpu_loop_exit(env); ++ break; ++#endif ++ default: ++ /* unknown sigp */ ++ fprintf(stderr, "XXX unknown sigp: 0x%" PRIx64 "\n", order_code); ++ cc = 3; ++ } ++ ++ return cc; ++} ++#endif +diff --git a/target-s390x/op_helper.c b/target-s390x/op_helper.c +deleted file mode 100644 +index bb8dbf5..0000000 +--- a/target-s390x/op_helper.c ++++ /dev/null +@@ -1,428 +0,0 @@ +-/* +- * S/390 helper routines +- * +- * Copyright (c) 2009 Ulrich Hecht +- * Copyright (c) 2009 Alexander Graf +- * +- * This library is free software; you can redistribute it and/or +- * modify it under the terms of the GNU Lesser General Public +- * License as published by the Free Software Foundation; either +- * version 2 of the License, or (at your option) any later version. +- * +- * This library is distributed in the hope that it will be useful, +- * but WITHOUT ANY WARRANTY; without even the implied warranty of +- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +- * Lesser General Public License for more details. +- * +- * You should have received a copy of the GNU Lesser General Public +- * License along with this library; if not, see . +- */ +- +-#include "cpu.h" +-#include "memory.h" +-#include "cputlb.h" +-#include "dyngen-exec.h" +-#include "host-utils.h" +-#include "helper.h" +-#include +-#include "kvm.h" +-#include "qemu-timer.h" +-#ifdef CONFIG_KVM +-#include +-#endif +- +-#if !defined(CONFIG_USER_ONLY) +-#include "softmmu_exec.h" +-#include "sysemu.h" +-#endif +- +-/* #define DEBUG_HELPER */ +-#ifdef DEBUG_HELPER +-#define HELPER_LOG(x...) qemu_log(x) +-#else +-#define HELPER_LOG(x...) +-#endif +- +-/* raise an exception */ +-void HELPER(exception)(uint32_t excp) +-{ +- HELPER_LOG("%s: exception %d\n", __func__, excp); +- env->exception_index = excp; +- cpu_loop_exit(env); +-} +- +-#ifndef CONFIG_USER_ONLY +-void program_interrupt(CPUS390XState *env, uint32_t code, int ilc) +-{ +- qemu_log("program interrupt at %#" PRIx64 "\n", env->psw.addr); +- +- if (kvm_enabled()) { +-#ifdef CONFIG_KVM +- kvm_s390_interrupt(env, KVM_S390_PROGRAM_INT, code); +-#endif +- } else { +- env->int_pgm_code = code; +- env->int_pgm_ilc = ilc; +- env->exception_index = EXCP_PGM; +- cpu_loop_exit(env); +- } +-} +- +-/* +- * ret < 0 indicates program check, ret = 0, 1, 2, 3 -> cc +- */ +-int sclp_service_call(CPUS390XState *env, uint32_t sccb, uint64_t code) +-{ +- int r = 0; +- int shift = 0; +- +-#ifdef DEBUG_HELPER +- printf("sclp(0x%x, 0x%" PRIx64 ")\n", sccb, code); +-#endif +- +- /* basic checks */ +- if (!memory_region_is_ram(phys_page_find(sccb >> TARGET_PAGE_BITS)->mr)) { +- return -PGM_ADDRESSING; +- } +- if (sccb & ~0x7ffffff8ul) { +- return -PGM_SPECIFICATION; +- } +- +- switch (code) { +- case SCLP_CMDW_READ_SCP_INFO: +- case SCLP_CMDW_READ_SCP_INFO_FORCED: +- while ((ram_size >> (20 + shift)) > 65535) { +- shift++; +- } +- stw_phys(sccb + SCP_MEM_CODE, ram_size >> (20 + shift)); +- stb_phys(sccb + SCP_INCREMENT, 1 << shift); +- stw_phys(sccb + SCP_RESPONSE_CODE, 0x10); +- +- s390_sclp_extint(sccb & ~3); +- break; +- default: +-#ifdef DEBUG_HELPER +- printf("KVM: invalid sclp call 0x%x / 0x%" PRIx64 "x\n", sccb, code); +-#endif +- r = 3; +- break; +- } +- +- return r; +-} +- +-/* SCLP service call */ +-uint32_t HELPER(servc)(uint32_t r1, uint64_t r2) +-{ +- int r; +- +- r = sclp_service_call(env, r1, r2); +- if (r < 0) { +- program_interrupt(env, -r, 4); +- return 0; +- } +- return r; +-} +- +-/* DIAG */ +-uint64_t HELPER(diag)(uint32_t num, uint64_t mem, uint64_t code) +-{ +- uint64_t r; +- +- switch (num) { +- case 0x500: +- /* KVM hypercall */ +- r = s390_virtio_hypercall(env, mem, code); +- break; +- case 0x44: +- /* yield */ +- r = 0; +- break; +- case 0x308: +- /* ipl */ +- r = 0; +- break; +- default: +- r = -1; +- break; +- } +- +- if (r) { +- program_interrupt(env, PGM_OPERATION, ILC_LATER_INC); +- } +- +- return r; +-} +- +-/* Store CPU ID */ +-void HELPER(stidp)(uint64_t a1) +-{ +- stq(a1, env->cpu_num); +-} +- +-/* Set Prefix */ +-void HELPER(spx)(uint64_t a1) +-{ +- uint32_t prefix; +- +- prefix = ldl(a1); +- env->psa = prefix & 0xfffff000; +- qemu_log("prefix: %#x\n", prefix); +- tlb_flush_page(env, 0); +- tlb_flush_page(env, TARGET_PAGE_SIZE); +-} +- +-/* Set Clock */ +-uint32_t HELPER(sck)(uint64_t a1) +-{ +- /* XXX not implemented - is it necessary? */ +- +- return 0; +-} +- +-static inline uint64_t clock_value(CPUS390XState *env) +-{ +- uint64_t time; +- +- time = env->tod_offset + +- time2tod(qemu_get_clock_ns(vm_clock) - env->tod_basetime); +- +- return time; +-} +- +-/* Store Clock */ +-uint32_t HELPER(stck)(uint64_t a1) +-{ +- stq(a1, clock_value(env)); +- +- return 0; +-} +- +-/* Store Clock Extended */ +-uint32_t HELPER(stcke)(uint64_t a1) +-{ +- stb(a1, 0); +- /* basically the same value as stck */ +- stq(a1 + 1, clock_value(env) | env->cpu_num); +- /* more fine grained than stck */ +- stq(a1 + 9, 0); +- /* XXX programmable fields */ +- stw(a1 + 17, 0); +- +- return 0; +-} +- +-/* Set Clock Comparator */ +-void HELPER(sckc)(uint64_t a1) +-{ +- uint64_t time = ldq(a1); +- +- if (time == -1ULL) { +- return; +- } +- +- /* difference between now and then */ +- time -= clock_value(env); +- /* nanoseconds */ +- time = (time * 125) >> 9; +- +- qemu_mod_timer(env->tod_timer, qemu_get_clock_ns(vm_clock) + time); +-} +- +-/* Store Clock Comparator */ +-void HELPER(stckc)(uint64_t a1) +-{ +- /* XXX implement */ +- stq(a1, 0); +-} +- +-/* Set CPU Timer */ +-void HELPER(spt)(uint64_t a1) +-{ +- uint64_t time = ldq(a1); +- +- if (time == -1ULL) { +- return; +- } +- +- /* nanoseconds */ +- time = (time * 125) >> 9; +- +- qemu_mod_timer(env->cpu_timer, qemu_get_clock_ns(vm_clock) + time); +-} +- +-/* Store CPU Timer */ +-void HELPER(stpt)(uint64_t a1) +-{ +- /* XXX implement */ +- stq(a1, 0); +-} +- +-/* Store System Information */ +-uint32_t HELPER(stsi)(uint64_t a0, uint32_t r0, uint32_t r1) +-{ +- int cc = 0; +- int sel1, sel2; +- +- if ((r0 & STSI_LEVEL_MASK) <= STSI_LEVEL_3 && +- ((r0 & STSI_R0_RESERVED_MASK) || (r1 & STSI_R1_RESERVED_MASK))) { +- /* valid function code, invalid reserved bits */ +- program_interrupt(env, PGM_SPECIFICATION, 2); +- } +- +- sel1 = r0 & STSI_R0_SEL1_MASK; +- sel2 = r1 & STSI_R1_SEL2_MASK; +- +- /* XXX: spec exception if sysib is not 4k-aligned */ +- +- switch (r0 & STSI_LEVEL_MASK) { +- case STSI_LEVEL_1: +- if ((sel1 == 1) && (sel2 == 1)) { +- /* Basic Machine Configuration */ +- struct sysib_111 sysib; +- +- memset(&sysib, 0, sizeof(sysib)); +- ebcdic_put(sysib.manuf, "QEMU ", 16); +- /* same as machine type number in STORE CPU ID */ +- ebcdic_put(sysib.type, "QEMU", 4); +- /* same as model number in STORE CPU ID */ +- ebcdic_put(sysib.model, "QEMU ", 16); +- ebcdic_put(sysib.sequence, "QEMU ", 16); +- ebcdic_put(sysib.plant, "QEMU", 4); +- cpu_physical_memory_rw(a0, (uint8_t *)&sysib, sizeof(sysib), 1); +- } else if ((sel1 == 2) && (sel2 == 1)) { +- /* Basic Machine CPU */ +- struct sysib_121 sysib; +- +- memset(&sysib, 0, sizeof(sysib)); +- /* XXX make different for different CPUs? */ +- ebcdic_put(sysib.sequence, "QEMUQEMUQEMUQEMU", 16); +- ebcdic_put(sysib.plant, "QEMU", 4); +- stw_p(&sysib.cpu_addr, env->cpu_num); +- cpu_physical_memory_rw(a0, (uint8_t *)&sysib, sizeof(sysib), 1); +- } else if ((sel1 == 2) && (sel2 == 2)) { +- /* Basic Machine CPUs */ +- struct sysib_122 sysib; +- +- memset(&sysib, 0, sizeof(sysib)); +- stl_p(&sysib.capability, 0x443afc29); +- /* XXX change when SMP comes */ +- stw_p(&sysib.total_cpus, 1); +- stw_p(&sysib.active_cpus, 1); +- stw_p(&sysib.standby_cpus, 0); +- stw_p(&sysib.reserved_cpus, 0); +- cpu_physical_memory_rw(a0, (uint8_t *)&sysib, sizeof(sysib), 1); +- } else { +- cc = 3; +- } +- break; +- case STSI_LEVEL_2: +- { +- if ((sel1 == 2) && (sel2 == 1)) { +- /* LPAR CPU */ +- struct sysib_221 sysib; +- +- memset(&sysib, 0, sizeof(sysib)); +- /* XXX make different for different CPUs? */ +- ebcdic_put(sysib.sequence, "QEMUQEMUQEMUQEMU", 16); +- ebcdic_put(sysib.plant, "QEMU", 4); +- stw_p(&sysib.cpu_addr, env->cpu_num); +- stw_p(&sysib.cpu_id, 0); +- cpu_physical_memory_rw(a0, (uint8_t *)&sysib, sizeof(sysib), 1); +- } else if ((sel1 == 2) && (sel2 == 2)) { +- /* LPAR CPUs */ +- struct sysib_222 sysib; +- +- memset(&sysib, 0, sizeof(sysib)); +- stw_p(&sysib.lpar_num, 0); +- sysib.lcpuc = 0; +- /* XXX change when SMP comes */ +- stw_p(&sysib.total_cpus, 1); +- stw_p(&sysib.conf_cpus, 1); +- stw_p(&sysib.standby_cpus, 0); +- stw_p(&sysib.reserved_cpus, 0); +- ebcdic_put(sysib.name, "QEMU ", 8); +- stl_p(&sysib.caf, 1000); +- stw_p(&sysib.dedicated_cpus, 0); +- stw_p(&sysib.shared_cpus, 0); +- cpu_physical_memory_rw(a0, (uint8_t *)&sysib, sizeof(sysib), 1); +- } else { +- cc = 3; +- } +- break; +- } +- case STSI_LEVEL_3: +- { +- if ((sel1 == 2) && (sel2 == 2)) { +- /* VM CPUs */ +- struct sysib_322 sysib; +- +- memset(&sysib, 0, sizeof(sysib)); +- sysib.count = 1; +- /* XXX change when SMP comes */ +- stw_p(&sysib.vm[0].total_cpus, 1); +- stw_p(&sysib.vm[0].conf_cpus, 1); +- stw_p(&sysib.vm[0].standby_cpus, 0); +- stw_p(&sysib.vm[0].reserved_cpus, 0); +- ebcdic_put(sysib.vm[0].name, "KVMguest", 8); +- stl_p(&sysib.vm[0].caf, 1000); +- ebcdic_put(sysib.vm[0].cpi, "KVM/Linux ", 16); +- cpu_physical_memory_rw(a0, (uint8_t *)&sysib, sizeof(sysib), 1); +- } else { +- cc = 3; +- } +- break; +- } +- case STSI_LEVEL_CURRENT: +- env->regs[0] = STSI_LEVEL_3; +- break; +- default: +- cc = 3; +- break; +- } +- +- return cc; +-} +- +-uint32_t HELPER(sigp)(uint64_t order_code, uint32_t r1, uint64_t cpu_addr) +-{ +- int cc = 0; +- +- HELPER_LOG("%s: %016" PRIx64 " %08x %016" PRIx64 "\n", +- __func__, order_code, r1, cpu_addr); +- +- /* Remember: Use "R1 or R1 + 1, whichever is the odd-numbered register" +- as parameter (input). Status (output) is always R1. */ +- +- switch (order_code) { +- case SIGP_SET_ARCH: +- /* switch arch */ +- break; +- case SIGP_SENSE: +- /* enumerate CPU status */ +- if (cpu_addr) { +- /* XXX implement when SMP comes */ +- return 3; +- } +- env->regs[r1] &= 0xffffffff00000000ULL; +- cc = 1; +- break; +-#if !defined(CONFIG_USER_ONLY) +- case SIGP_RESTART: +- qemu_system_reset_request(); +- cpu_loop_exit(env); +- break; +- case SIGP_STOP: +- qemu_system_shutdown_request(); +- cpu_loop_exit(env); +- break; +-#endif +- default: +- /* unknown sigp */ +- fprintf(stderr, "XXX unknown sigp: 0x%" PRIx64 "\n", order_code); +- cc = 3; +- } +- +- return cc; +-} +-#endif +-- +1.7.12.1 + diff --git a/0011-target-s390x-avoid-AREG0-for-FPU-helpers.patch b/0011-target-s390x-avoid-AREG0-for-FPU-helpers.patch new file mode 100644 index 0000000..597face --- /dev/null +++ b/0011-target-s390x-avoid-AREG0-for-FPU-helpers.patch @@ -0,0 +1,1218 @@ +From 5d38110b1e23c963302f13f5917001a9298445a7 Mon Sep 17 00:00:00 2001 +From: Blue Swirl +Date: Sun, 2 Sep 2012 07:33:36 +0000 +Subject: [PATCH] target-s390x: avoid AREG0 for FPU helpers + +Make FPU helpers take a parameter for CPUState instead +of relying on global env. + +Introduce temporary wrappers for FPU load and store ops. + +Signed-off-by: Blue Swirl +Signed-off-by: Alexander Graf +Signed-off-by: Michael Roth +--- + target-s390x/Makefile.objs | 1 - + target-s390x/cc_helper.c | 4 +- + target-s390x/cpu.h | 14 +++- + target-s390x/fpu_helper.c | 184 +++++++++++++++++++++++---------------------- + target-s390x/helper.h | 126 +++++++++++++++---------------- + target-s390x/mem_helper.c | 49 ++++++++++++ + target-s390x/translate.c | 70 ++++++++--------- + 7 files changed, 257 insertions(+), 191 deletions(-) + +diff --git a/target-s390x/Makefile.objs b/target-s390x/Makefile.objs +index a87d26f..7d965e9 100644 +--- a/target-s390x/Makefile.objs ++++ b/target-s390x/Makefile.objs +@@ -4,7 +4,6 @@ obj-$(CONFIG_SOFTMMU) += machine.o + obj-$(CONFIG_KVM) += kvm.o + + $(obj)/int_helper.o: QEMU_CFLAGS += $(HELPER_CFLAGS) +-$(obj)/fpu_helper.o: QEMU_CFLAGS += $(HELPER_CFLAGS) + $(obj)/cc_helper.o: QEMU_CFLAGS += $(HELPER_CFLAGS) + $(obj)/mem_helper.o: QEMU_CFLAGS += $(HELPER_CFLAGS) + $(obj)/misc_helper.o: QEMU_CFLAGS += $(HELPER_CFLAGS) +diff --git a/target-s390x/cc_helper.c b/target-s390x/cc_helper.c +index 2ac1659..9c3a2c4 100644 +--- a/target-s390x/cc_helper.c ++++ b/target-s390x/cc_helper.c +@@ -473,10 +473,10 @@ static inline uint32_t do_calc_cc(CPUS390XState *env, uint32_t cc_op, + break; + + case CC_OP_LTGT_F32: +- r = set_cc_f32(src, dst); ++ r = set_cc_f32(env, src, dst); + break; + case CC_OP_LTGT_F64: +- r = set_cc_f64(src, dst); ++ r = set_cc_f64(env, src, dst); + break; + case CC_OP_NZ_F32: + r = set_cc_nz_f32(dst); +diff --git a/target-s390x/cpu.h b/target-s390x/cpu.h +index 0ccb551..9b7a2e3 100644 +--- a/target-s390x/cpu.h ++++ b/target-s390x/cpu.h +@@ -1000,12 +1000,22 @@ static inline void cpu_pc_from_tb(CPUS390XState *env, TranslationBlock* tb) + } + + /* fpu_helper.c */ +-uint32_t set_cc_f32(float32 v1, float32 v2); +-uint32_t set_cc_f64(float64 v1, float64 v2); ++uint32_t set_cc_f32(CPUS390XState *env, float32 v1, float32 v2); ++uint32_t set_cc_f64(CPUS390XState *env, float64 v1, float64 v2); + uint32_t set_cc_nz_f32(float32 v); + uint32_t set_cc_nz_f64(float64 v); + + /* misc_helper.c */ + void program_interrupt(CPUS390XState *env, uint32_t code, int ilc); + ++/* temporary wrappers */ ++uint32_t cpu_ldub_data(CPUS390XState *env, target_ulong ptr); ++uint32_t cpu_lduw_data(CPUS390XState *env, target_ulong ptr); ++uint32_t cpu_ldl_data(CPUS390XState *env, target_ulong ptr); ++uint64_t cpu_ldq_data(CPUS390XState *env, target_ulong ptr); ++ ++void cpu_stb_data(CPUS390XState *env, target_ulong ptr, uint32_t data); ++void cpu_stw_data(CPUS390XState *env, target_ulong ptr, uint32_t data); ++void cpu_stl_data(CPUS390XState *env, target_ulong ptr, uint32_t data); ++void cpu_stq_data(CPUS390XState *env, target_ulong ptr, uint64_t data); + #endif +diff --git a/target-s390x/fpu_helper.c b/target-s390x/fpu_helper.c +index 1389052..e235419 100644 +--- a/target-s390x/fpu_helper.c ++++ b/target-s390x/fpu_helper.c +@@ -19,10 +19,10 @@ + */ + + #include "cpu.h" +-#include "dyngen-exec.h" + #include "helper.h" + +-#if !defined(CONFIG_USER_ONLY) ++/* temporarily disabled due to wrapper use */ ++#if 0 && !defined(CONFIG_USER_ONLY) + #include "softmmu_exec.h" + #endif + +@@ -33,7 +33,7 @@ + #define HELPER_LOG(x...) + #endif + +-static inline int float_comp_to_cc(int float_compare) ++static inline int float_comp_to_cc(CPUS390XState *env, int float_compare) + { + switch (float_compare) { + case float_relation_equal: +@@ -50,14 +50,16 @@ static inline int float_comp_to_cc(int float_compare) + } + + /* condition codes for binary FP ops */ +-uint32_t set_cc_f32(float32 v1, float32 v2) ++uint32_t set_cc_f32(CPUS390XState *env, float32 v1, float32 v2) + { +- return float_comp_to_cc(float32_compare_quiet(v1, v2, &env->fpu_status)); ++ return float_comp_to_cc(env, float32_compare_quiet(v1, v2, ++ &env->fpu_status)); + } + +-uint32_t set_cc_f64(float64 v1, float64 v2) ++uint32_t set_cc_f64(CPUS390XState *env, float64 v1, float64 v2) + { +- return float_comp_to_cc(float64_compare_quiet(v1, v2, &env->fpu_status)); ++ return float_comp_to_cc(env, float64_compare_quiet(v1, v2, ++ &env->fpu_status)); + } + + /* condition codes for unary FP ops */ +@@ -101,14 +103,14 @@ static uint32_t set_cc_nz_f128(float128 v) + } + + /* convert 32-bit int to 64-bit float */ +-void HELPER(cdfbr)(uint32_t f1, int32_t v2) ++void HELPER(cdfbr)(CPUS390XState *env, uint32_t f1, int32_t v2) + { + HELPER_LOG("%s: converting %d to f%d\n", __func__, v2, f1); + env->fregs[f1].d = int32_to_float64(v2, &env->fpu_status); + } + + /* convert 32-bit int to 128-bit float */ +-void HELPER(cxfbr)(uint32_t f1, int32_t v2) ++void HELPER(cxfbr)(CPUS390XState *env, uint32_t f1, int32_t v2) + { + CPU_QuadU v1; + +@@ -118,21 +120,21 @@ void HELPER(cxfbr)(uint32_t f1, int32_t v2) + } + + /* convert 64-bit int to 32-bit float */ +-void HELPER(cegbr)(uint32_t f1, int64_t v2) ++void HELPER(cegbr)(CPUS390XState *env, uint32_t f1, int64_t v2) + { + HELPER_LOG("%s: converting %ld to f%d\n", __func__, v2, f1); + env->fregs[f1].l.upper = int64_to_float32(v2, &env->fpu_status); + } + + /* convert 64-bit int to 64-bit float */ +-void HELPER(cdgbr)(uint32_t f1, int64_t v2) ++void HELPER(cdgbr)(CPUS390XState *env, uint32_t f1, int64_t v2) + { + HELPER_LOG("%s: converting %ld to f%d\n", __func__, v2, f1); + env->fregs[f1].d = int64_to_float64(v2, &env->fpu_status); + } + + /* convert 64-bit int to 128-bit float */ +-void HELPER(cxgbr)(uint32_t f1, int64_t v2) ++void HELPER(cxgbr)(CPUS390XState *env, uint32_t f1, int64_t v2) + { + CPU_QuadU x1; + +@@ -144,7 +146,7 @@ void HELPER(cxgbr)(uint32_t f1, int64_t v2) + } + + /* convert 32-bit int to 32-bit float */ +-void HELPER(cefbr)(uint32_t f1, int32_t v2) ++void HELPER(cefbr)(CPUS390XState *env, uint32_t f1, int32_t v2) + { + env->fregs[f1].l.upper = int32_to_float32(v2, &env->fpu_status); + HELPER_LOG("%s: converting %d to 0x%d in f%d\n", __func__, v2, +@@ -152,7 +154,7 @@ void HELPER(cefbr)(uint32_t f1, int32_t v2) + } + + /* 32-bit FP addition RR */ +-uint32_t HELPER(aebr)(uint32_t f1, uint32_t f2) ++uint32_t HELPER(aebr)(CPUS390XState *env, uint32_t f1, uint32_t f2) + { + env->fregs[f1].l.upper = float32_add(env->fregs[f1].l.upper, + env->fregs[f2].l.upper, +@@ -164,7 +166,7 @@ uint32_t HELPER(aebr)(uint32_t f1, uint32_t f2) + } + + /* 64-bit FP addition RR */ +-uint32_t HELPER(adbr)(uint32_t f1, uint32_t f2) ++uint32_t HELPER(adbr)(CPUS390XState *env, uint32_t f1, uint32_t f2) + { + env->fregs[f1].d = float64_add(env->fregs[f1].d, env->fregs[f2].d, + &env->fpu_status); +@@ -175,7 +177,7 @@ uint32_t HELPER(adbr)(uint32_t f1, uint32_t f2) + } + + /* 32-bit FP subtraction RR */ +-uint32_t HELPER(sebr)(uint32_t f1, uint32_t f2) ++uint32_t HELPER(sebr)(CPUS390XState *env, uint32_t f1, uint32_t f2) + { + env->fregs[f1].l.upper = float32_sub(env->fregs[f1].l.upper, + env->fregs[f2].l.upper, +@@ -187,7 +189,7 @@ uint32_t HELPER(sebr)(uint32_t f1, uint32_t f2) + } + + /* 64-bit FP subtraction RR */ +-uint32_t HELPER(sdbr)(uint32_t f1, uint32_t f2) ++uint32_t HELPER(sdbr)(CPUS390XState *env, uint32_t f1, uint32_t f2) + { + env->fregs[f1].d = float64_sub(env->fregs[f1].d, env->fregs[f2].d, + &env->fpu_status); +@@ -198,7 +200,7 @@ uint32_t HELPER(sdbr)(uint32_t f1, uint32_t f2) + } + + /* 32-bit FP division RR */ +-void HELPER(debr)(uint32_t f1, uint32_t f2) ++void HELPER(debr)(CPUS390XState *env, uint32_t f1, uint32_t f2) + { + env->fregs[f1].l.upper = float32_div(env->fregs[f1].l.upper, + env->fregs[f2].l.upper, +@@ -206,7 +208,7 @@ void HELPER(debr)(uint32_t f1, uint32_t f2) + } + + /* 128-bit FP division RR */ +-void HELPER(dxbr)(uint32_t f1, uint32_t f2) ++void HELPER(dxbr)(CPUS390XState *env, uint32_t f1, uint32_t f2) + { + CPU_QuadU v1; + CPU_QuadU v2; +@@ -222,14 +224,14 @@ void HELPER(dxbr)(uint32_t f1, uint32_t f2) + } + + /* 64-bit FP multiplication RR */ +-void HELPER(mdbr)(uint32_t f1, uint32_t f2) ++void HELPER(mdbr)(CPUS390XState *env, uint32_t f1, uint32_t f2) + { + env->fregs[f1].d = float64_mul(env->fregs[f1].d, env->fregs[f2].d, + &env->fpu_status); + } + + /* 128-bit FP multiplication RR */ +-void HELPER(mxbr)(uint32_t f1, uint32_t f2) ++void HELPER(mxbr)(CPUS390XState *env, uint32_t f1, uint32_t f2) + { + CPU_QuadU v1; + CPU_QuadU v2; +@@ -245,14 +247,14 @@ void HELPER(mxbr)(uint32_t f1, uint32_t f2) + } + + /* convert 32-bit float to 64-bit float */ +-void HELPER(ldebr)(uint32_t r1, uint32_t r2) ++void HELPER(ldebr)(CPUS390XState *env, uint32_t r1, uint32_t r2) + { + env->fregs[r1].d = float32_to_float64(env->fregs[r2].l.upper, + &env->fpu_status); + } + + /* convert 128-bit float to 64-bit float */ +-void HELPER(ldxbr)(uint32_t f1, uint32_t f2) ++void HELPER(ldxbr)(CPUS390XState *env, uint32_t f1, uint32_t f2) + { + CPU_QuadU x2; + +@@ -263,7 +265,7 @@ void HELPER(ldxbr)(uint32_t f1, uint32_t f2) + } + + /* convert 64-bit float to 128-bit float */ +-void HELPER(lxdbr)(uint32_t f1, uint32_t f2) ++void HELPER(lxdbr)(CPUS390XState *env, uint32_t f1, uint32_t f2) + { + CPU_QuadU res; + +@@ -273,7 +275,7 @@ void HELPER(lxdbr)(uint32_t f1, uint32_t f2) + } + + /* convert 64-bit float to 32-bit float */ +-void HELPER(ledbr)(uint32_t f1, uint32_t f2) ++void HELPER(ledbr)(CPUS390XState *env, uint32_t f1, uint32_t f2) + { + float64 d2 = env->fregs[f2].d; + +@@ -281,7 +283,7 @@ void HELPER(ledbr)(uint32_t f1, uint32_t f2) + } + + /* convert 128-bit float to 32-bit float */ +-void HELPER(lexbr)(uint32_t f1, uint32_t f2) ++void HELPER(lexbr)(CPUS390XState *env, uint32_t f1, uint32_t f2) + { + CPU_QuadU x2; + +@@ -292,7 +294,7 @@ void HELPER(lexbr)(uint32_t f1, uint32_t f2) + } + + /* absolute value of 32-bit float */ +-uint32_t HELPER(lpebr)(uint32_t f1, uint32_t f2) ++uint32_t HELPER(lpebr)(CPUS390XState *env, uint32_t f1, uint32_t f2) + { + float32 v1; + float32 v2 = env->fregs[f2].d; +@@ -303,7 +305,7 @@ uint32_t HELPER(lpebr)(uint32_t f1, uint32_t f2) + } + + /* absolute value of 64-bit float */ +-uint32_t HELPER(lpdbr)(uint32_t f1, uint32_t f2) ++uint32_t HELPER(lpdbr)(CPUS390XState *env, uint32_t f1, uint32_t f2) + { + float64 v1; + float64 v2 = env->fregs[f2].d; +@@ -314,7 +316,7 @@ uint32_t HELPER(lpdbr)(uint32_t f1, uint32_t f2) + } + + /* absolute value of 128-bit float */ +-uint32_t HELPER(lpxbr)(uint32_t f1, uint32_t f2) ++uint32_t HELPER(lpxbr)(CPUS390XState *env, uint32_t f1, uint32_t f2) + { + CPU_QuadU v1; + CPU_QuadU v2; +@@ -328,21 +330,21 @@ uint32_t HELPER(lpxbr)(uint32_t f1, uint32_t f2) + } + + /* load and test 64-bit float */ +-uint32_t HELPER(ltdbr)(uint32_t f1, uint32_t f2) ++uint32_t HELPER(ltdbr)(CPUS390XState *env, uint32_t f1, uint32_t f2) + { + env->fregs[f1].d = env->fregs[f2].d; + return set_cc_nz_f64(env->fregs[f1].d); + } + + /* load and test 32-bit float */ +-uint32_t HELPER(ltebr)(uint32_t f1, uint32_t f2) ++uint32_t HELPER(ltebr)(CPUS390XState *env, uint32_t f1, uint32_t f2) + { + env->fregs[f1].l.upper = env->fregs[f2].l.upper; + return set_cc_nz_f32(env->fregs[f1].l.upper); + } + + /* load and test 128-bit float */ +-uint32_t HELPER(ltxbr)(uint32_t f1, uint32_t f2) ++uint32_t HELPER(ltxbr)(CPUS390XState *env, uint32_t f1, uint32_t f2) + { + CPU_QuadU x; + +@@ -354,7 +356,7 @@ uint32_t HELPER(ltxbr)(uint32_t f1, uint32_t f2) + } + + /* load complement of 32-bit float */ +-uint32_t HELPER(lcebr)(uint32_t f1, uint32_t f2) ++uint32_t HELPER(lcebr)(CPUS390XState *env, uint32_t f1, uint32_t f2) + { + env->fregs[f1].l.upper = float32_chs(env->fregs[f2].l.upper); + +@@ -362,7 +364,7 @@ uint32_t HELPER(lcebr)(uint32_t f1, uint32_t f2) + } + + /* load complement of 64-bit float */ +-uint32_t HELPER(lcdbr)(uint32_t f1, uint32_t f2) ++uint32_t HELPER(lcdbr)(CPUS390XState *env, uint32_t f1, uint32_t f2) + { + env->fregs[f1].d = float64_chs(env->fregs[f2].d); + +@@ -370,7 +372,7 @@ uint32_t HELPER(lcdbr)(uint32_t f1, uint32_t f2) + } + + /* load complement of 128-bit float */ +-uint32_t HELPER(lcxbr)(uint32_t f1, uint32_t f2) ++uint32_t HELPER(lcxbr)(CPUS390XState *env, uint32_t f1, uint32_t f2) + { + CPU_QuadU x1, x2; + +@@ -383,7 +385,7 @@ uint32_t HELPER(lcxbr)(uint32_t f1, uint32_t f2) + } + + /* 32-bit FP addition RM */ +-void HELPER(aeb)(uint32_t f1, uint32_t val) ++void HELPER(aeb)(CPUS390XState *env, uint32_t f1, uint32_t val) + { + float32 v1 = env->fregs[f1].l.upper; + CPU_FloatU v2; +@@ -395,7 +397,7 @@ void HELPER(aeb)(uint32_t f1, uint32_t val) + } + + /* 32-bit FP division RM */ +-void HELPER(deb)(uint32_t f1, uint32_t val) ++void HELPER(deb)(CPUS390XState *env, uint32_t f1, uint32_t val) + { + float32 v1 = env->fregs[f1].l.upper; + CPU_FloatU v2; +@@ -407,7 +409,7 @@ void HELPER(deb)(uint32_t f1, uint32_t val) + } + + /* 32-bit FP multiplication RM */ +-void HELPER(meeb)(uint32_t f1, uint32_t val) ++void HELPER(meeb)(CPUS390XState *env, uint32_t f1, uint32_t val) + { + float32 v1 = env->fregs[f1].l.upper; + CPU_FloatU v2; +@@ -419,29 +421,29 @@ void HELPER(meeb)(uint32_t f1, uint32_t val) + } + + /* 32-bit FP compare RR */ +-uint32_t HELPER(cebr)(uint32_t f1, uint32_t f2) ++uint32_t HELPER(cebr)(CPUS390XState *env, uint32_t f1, uint32_t f2) + { + float32 v1 = env->fregs[f1].l.upper; + float32 v2 = env->fregs[f2].l.upper; + + HELPER_LOG("%s: comparing 0x%d from f%d and 0x%d\n", __func__, + v1, f1, v2); +- return set_cc_f32(v1, v2); ++ return set_cc_f32(env, v1, v2); + } + + /* 64-bit FP compare RR */ +-uint32_t HELPER(cdbr)(uint32_t f1, uint32_t f2) ++uint32_t HELPER(cdbr)(CPUS390XState *env, uint32_t f1, uint32_t f2) + { + float64 v1 = env->fregs[f1].d; + float64 v2 = env->fregs[f2].d; + + HELPER_LOG("%s: comparing 0x%ld from f%d and 0x%ld\n", __func__, + v1, f1, v2); +- return set_cc_f64(v1, v2); ++ return set_cc_f64(env, v1, v2); + } + + /* 128-bit FP compare RR */ +-uint32_t HELPER(cxbr)(uint32_t f1, uint32_t f2) ++uint32_t HELPER(cxbr)(CPUS390XState *env, uint32_t f1, uint32_t f2) + { + CPU_QuadU v1; + CPU_QuadU v2; +@@ -451,29 +453,29 @@ uint32_t HELPER(cxbr)(uint32_t f1, uint32_t f2) + v2.ll.upper = env->fregs[f2].ll; + v2.ll.lower = env->fregs[f2 + 2].ll; + +- return float_comp_to_cc(float128_compare_quiet(v1.q, v2.q, ++ return float_comp_to_cc(env, float128_compare_quiet(v1.q, v2.q, + &env->fpu_status)); + } + + /* 64-bit FP compare RM */ +-uint32_t HELPER(cdb)(uint32_t f1, uint64_t a2) ++uint32_t HELPER(cdb)(CPUS390XState *env, uint32_t f1, uint64_t a2) + { + float64 v1 = env->fregs[f1].d; + CPU_DoubleU v2; + +- v2.ll = ldq(a2); ++ v2.ll = cpu_ldq_data(env, a2); + HELPER_LOG("%s: comparing 0x%ld from f%d and 0x%lx\n", __func__, v1, + f1, v2.d); +- return set_cc_f64(v1, v2.d); ++ return set_cc_f64(env, v1, v2.d); + } + + /* 64-bit FP addition RM */ +-uint32_t HELPER(adb)(uint32_t f1, uint64_t a2) ++uint32_t HELPER(adb)(CPUS390XState *env, uint32_t f1, uint64_t a2) + { + float64 v1 = env->fregs[f1].d; + CPU_DoubleU v2; + +- v2.ll = ldq(a2); ++ v2.ll = cpu_ldq_data(env, a2); + HELPER_LOG("%s: adding 0x%lx from f%d and 0x%lx\n", __func__, + v1, f1, v2.d); + env->fregs[f1].d = v1 = float64_add(v1, v2.d, &env->fpu_status); +@@ -481,7 +483,7 @@ uint32_t HELPER(adb)(uint32_t f1, uint64_t a2) + } + + /* 32-bit FP subtraction RM */ +-void HELPER(seb)(uint32_t f1, uint32_t val) ++void HELPER(seb)(CPUS390XState *env, uint32_t f1, uint32_t val) + { + float32 v1 = env->fregs[f1].l.upper; + CPU_FloatU v2; +@@ -491,41 +493,41 @@ void HELPER(seb)(uint32_t f1, uint32_t val) + } + + /* 64-bit FP subtraction RM */ +-uint32_t HELPER(sdb)(uint32_t f1, uint64_t a2) ++uint32_t HELPER(sdb)(CPUS390XState *env, uint32_t f1, uint64_t a2) + { + float64 v1 = env->fregs[f1].d; + CPU_DoubleU v2; + +- v2.ll = ldq(a2); ++ v2.ll = cpu_ldq_data(env, a2); + env->fregs[f1].d = v1 = float64_sub(v1, v2.d, &env->fpu_status); + return set_cc_nz_f64(v1); + } + + /* 64-bit FP multiplication RM */ +-void HELPER(mdb)(uint32_t f1, uint64_t a2) ++void HELPER(mdb)(CPUS390XState *env, uint32_t f1, uint64_t a2) + { + float64 v1 = env->fregs[f1].d; + CPU_DoubleU v2; + +- v2.ll = ldq(a2); ++ v2.ll = cpu_ldq_data(env, a2); + HELPER_LOG("%s: multiplying 0x%lx from f%d and 0x%ld\n", __func__, + v1, f1, v2.d); + env->fregs[f1].d = float64_mul(v1, v2.d, &env->fpu_status); + } + + /* 64-bit FP division RM */ +-void HELPER(ddb)(uint32_t f1, uint64_t a2) ++void HELPER(ddb)(CPUS390XState *env, uint32_t f1, uint64_t a2) + { + float64 v1 = env->fregs[f1].d; + CPU_DoubleU v2; + +- v2.ll = ldq(a2); ++ v2.ll = cpu_ldq_data(env, a2); + HELPER_LOG("%s: dividing 0x%lx from f%d by 0x%ld\n", __func__, + v1, f1, v2.d); + env->fregs[f1].d = float64_div(v1, v2.d, &env->fpu_status); + } + +-static void set_round_mode(int m3) ++static void set_round_mode(CPUS390XState *env, int m3) + { + switch (m3) { + case 0: +@@ -553,33 +555,36 @@ static void set_round_mode(int m3) + } + + /* convert 32-bit float to 64-bit int */ +-uint32_t HELPER(cgebr)(uint32_t r1, uint32_t f2, uint32_t m3) ++uint32_t HELPER(cgebr)(CPUS390XState *env, uint32_t r1, uint32_t f2, ++ uint32_t m3) + { + float32 v2 = env->fregs[f2].l.upper; + +- set_round_mode(m3); ++ set_round_mode(env, m3); + env->regs[r1] = float32_to_int64(v2, &env->fpu_status); + return set_cc_nz_f32(v2); + } + + /* convert 64-bit float to 64-bit int */ +-uint32_t HELPER(cgdbr)(uint32_t r1, uint32_t f2, uint32_t m3) ++uint32_t HELPER(cgdbr)(CPUS390XState *env, uint32_t r1, uint32_t f2, ++ uint32_t m3) + { + float64 v2 = env->fregs[f2].d; + +- set_round_mode(m3); ++ set_round_mode(env, m3); + env->regs[r1] = float64_to_int64(v2, &env->fpu_status); + return set_cc_nz_f64(v2); + } + + /* convert 128-bit float to 64-bit int */ +-uint32_t HELPER(cgxbr)(uint32_t r1, uint32_t f2, uint32_t m3) ++uint32_t HELPER(cgxbr)(CPUS390XState *env, uint32_t r1, uint32_t f2, ++ uint32_t m3) + { + CPU_QuadU v2; + + v2.ll.upper = env->fregs[f2].ll; + v2.ll.lower = env->fregs[f2 + 2].ll; +- set_round_mode(m3); ++ set_round_mode(env, m3); + env->regs[r1] = float128_to_int64(v2.q, &env->fpu_status); + if (float128_is_any_nan(v2.q)) { + return 3; +@@ -593,29 +598,32 @@ uint32_t HELPER(cgxbr)(uint32_t r1, uint32_t f2, uint32_t m3) + } + + /* convert 32-bit float to 32-bit int */ +-uint32_t HELPER(cfebr)(uint32_t r1, uint32_t f2, uint32_t m3) ++uint32_t HELPER(cfebr)(CPUS390XState *env, uint32_t r1, uint32_t f2, ++ uint32_t m3) + { + float32 v2 = env->fregs[f2].l.upper; + +- set_round_mode(m3); ++ set_round_mode(env, m3); + env->regs[r1] = (env->regs[r1] & 0xffffffff00000000ULL) | + float32_to_int32(v2, &env->fpu_status); + return set_cc_nz_f32(v2); + } + + /* convert 64-bit float to 32-bit int */ +-uint32_t HELPER(cfdbr)(uint32_t r1, uint32_t f2, uint32_t m3) ++uint32_t HELPER(cfdbr)(CPUS390XState *env, uint32_t r1, uint32_t f2, ++ uint32_t m3) + { + float64 v2 = env->fregs[f2].d; + +- set_round_mode(m3); ++ set_round_mode(env, m3); + env->regs[r1] = (env->regs[r1] & 0xffffffff00000000ULL) | + float64_to_int32(v2, &env->fpu_status); + return set_cc_nz_f64(v2); + } + + /* convert 128-bit float to 32-bit int */ +-uint32_t HELPER(cfxbr)(uint32_t r1, uint32_t f2, uint32_t m3) ++uint32_t HELPER(cfxbr)(CPUS390XState *env, uint32_t r1, uint32_t f2, ++ uint32_t m3) + { + CPU_QuadU v2; + +@@ -627,19 +635,19 @@ uint32_t HELPER(cfxbr)(uint32_t r1, uint32_t f2, uint32_t m3) + } + + /* load 32-bit FP zero */ +-void HELPER(lzer)(uint32_t f1) ++void HELPER(lzer)(CPUS390XState *env, uint32_t f1) + { + env->fregs[f1].l.upper = float32_zero; + } + + /* load 64-bit FP zero */ +-void HELPER(lzdr)(uint32_t f1) ++void HELPER(lzdr)(CPUS390XState *env, uint32_t f1) + { + env->fregs[f1].d = float64_zero; + } + + /* load 128-bit FP zero */ +-void HELPER(lzxr)(uint32_t f1) ++void HELPER(lzxr)(CPUS390XState *env, uint32_t f1) + { + CPU_QuadU x; + +@@ -649,7 +657,7 @@ void HELPER(lzxr)(uint32_t f1) + } + + /* 128-bit FP subtraction RR */ +-uint32_t HELPER(sxbr)(uint32_t f1, uint32_t f2) ++uint32_t HELPER(sxbr)(CPUS390XState *env, uint32_t f1, uint32_t f2) + { + CPU_QuadU v1; + CPU_QuadU v2; +@@ -666,7 +674,7 @@ uint32_t HELPER(sxbr)(uint32_t f1, uint32_t f2) + } + + /* 128-bit FP addition RR */ +-uint32_t HELPER(axbr)(uint32_t f1, uint32_t f2) ++uint32_t HELPER(axbr)(CPUS390XState *env, uint32_t f1, uint32_t f2) + { + CPU_QuadU v1; + CPU_QuadU v2; +@@ -683,7 +691,7 @@ uint32_t HELPER(axbr)(uint32_t f1, uint32_t f2) + } + + /* 32-bit FP multiplication RR */ +-void HELPER(meebr)(uint32_t f1, uint32_t f2) ++void HELPER(meebr)(CPUS390XState *env, uint32_t f1, uint32_t f2) + { + env->fregs[f1].l.upper = float32_mul(env->fregs[f1].l.upper, + env->fregs[f2].l.upper, +@@ -691,19 +699,19 @@ void HELPER(meebr)(uint32_t f1, uint32_t f2) + } + + /* 64-bit FP division RR */ +-void HELPER(ddbr)(uint32_t f1, uint32_t f2) ++void HELPER(ddbr)(CPUS390XState *env, uint32_t f1, uint32_t f2) + { + env->fregs[f1].d = float64_div(env->fregs[f1].d, env->fregs[f2].d, + &env->fpu_status); + } + + /* 64-bit FP multiply and add RM */ +-void HELPER(madb)(uint32_t f1, uint64_t a2, uint32_t f3) ++void HELPER(madb)(CPUS390XState *env, uint32_t f1, uint64_t a2, uint32_t f3) + { + CPU_DoubleU v2; + + HELPER_LOG("%s: f1 %d a2 0x%lx f3 %d\n", __func__, f1, a2, f3); +- v2.ll = ldq(a2); ++ v2.ll = cpu_ldq_data(env, a2); + env->fregs[f1].d = float64_add(env->fregs[f1].d, + float64_mul(v2.d, env->fregs[f3].d, + &env->fpu_status), +@@ -711,7 +719,7 @@ void HELPER(madb)(uint32_t f1, uint64_t a2, uint32_t f3) + } + + /* 64-bit FP multiply and add RR */ +-void HELPER(madbr)(uint32_t f1, uint32_t f3, uint32_t f2) ++void HELPER(madbr)(CPUS390XState *env, uint32_t f1, uint32_t f3, uint32_t f2) + { + HELPER_LOG("%s: f1 %d f2 %d f3 %d\n", __func__, f1, f2, f3); + env->fregs[f1].d = float64_add(float64_mul(env->fregs[f2].d, +@@ -721,7 +729,7 @@ void HELPER(madbr)(uint32_t f1, uint32_t f3, uint32_t f2) + } + + /* 64-bit FP multiply and subtract RR */ +-void HELPER(msdbr)(uint32_t f1, uint32_t f3, uint32_t f2) ++void HELPER(msdbr)(CPUS390XState *env, uint32_t f1, uint32_t f3, uint32_t f2) + { + HELPER_LOG("%s: f1 %d f2 %d f3 %d\n", __func__, f1, f2, f3); + env->fregs[f1].d = float64_sub(float64_mul(env->fregs[f2].d, +@@ -731,7 +739,7 @@ void HELPER(msdbr)(uint32_t f1, uint32_t f3, uint32_t f2) + } + + /* 32-bit FP multiply and add RR */ +-void HELPER(maebr)(uint32_t f1, uint32_t f3, uint32_t f2) ++void HELPER(maebr)(CPUS390XState *env, uint32_t f1, uint32_t f3, uint32_t f2) + { + env->fregs[f1].l.upper = float32_add(env->fregs[f1].l.upper, + float32_mul(env->fregs[f2].l.upper, +@@ -741,29 +749,29 @@ void HELPER(maebr)(uint32_t f1, uint32_t f3, uint32_t f2) + } + + /* convert 32-bit float to 64-bit float */ +-void HELPER(ldeb)(uint32_t f1, uint64_t a2) ++void HELPER(ldeb)(CPUS390XState *env, uint32_t f1, uint64_t a2) + { + uint32_t v2; + +- v2 = ldl(a2); ++ v2 = cpu_ldl_data(env, a2); + env->fregs[f1].d = float32_to_float64(v2, + &env->fpu_status); + } + + /* convert 64-bit float to 128-bit float */ +-void HELPER(lxdb)(uint32_t f1, uint64_t a2) ++void HELPER(lxdb)(CPUS390XState *env, uint32_t f1, uint64_t a2) + { + CPU_DoubleU v2; + CPU_QuadU v1; + +- v2.ll = ldq(a2); ++ v2.ll = cpu_ldq_data(env, a2); + v1.q = float64_to_float128(v2.d, &env->fpu_status); + env->fregs[f1].ll = v1.ll.upper; + env->fregs[f1 + 2].ll = v1.ll.lower; + } + + /* test data class 32-bit */ +-uint32_t HELPER(tceb)(uint32_t f1, uint64_t m2) ++uint32_t HELPER(tceb)(CPUS390XState *env, uint32_t f1, uint64_t m2) + { + float32 v1 = env->fregs[f1].l.upper; + int neg = float32_is_neg(v1); +@@ -785,7 +793,7 @@ uint32_t HELPER(tceb)(uint32_t f1, uint64_t m2) + } + + /* test data class 64-bit */ +-uint32_t HELPER(tcdb)(uint32_t f1, uint64_t m2) ++uint32_t HELPER(tcdb)(CPUS390XState *env, uint32_t f1, uint64_t m2) + { + float64 v1 = env->fregs[f1].d; + int neg = float64_is_neg(v1); +@@ -806,7 +814,7 @@ uint32_t HELPER(tcdb)(uint32_t f1, uint64_t m2) + } + + /* test data class 128-bit */ +-uint32_t HELPER(tcxb)(uint32_t f1, uint64_t m2) ++uint32_t HELPER(tcxb)(CPUS390XState *env, uint32_t f1, uint64_t m2) + { + CPU_QuadU v1; + uint32_t cc = 0; +@@ -830,7 +838,7 @@ uint32_t HELPER(tcxb)(uint32_t f1, uint64_t m2) + } + + /* square root 64-bit RR */ +-void HELPER(sqdbr)(uint32_t f1, uint32_t f2) ++void HELPER(sqdbr)(CPUS390XState *env, uint32_t f1, uint32_t f2) + { + env->fregs[f1].d = float64_sqrt(env->fregs[f2].d, &env->fpu_status); + } +diff --git a/target-s390x/helper.h b/target-s390x/helper.h +index 01c8d0e..af98773 100644 +--- a/target-s390x/helper.h ++++ b/target-s390x/helper.h +@@ -45,70 +45,70 @@ DEF_HELPER_3(mvcle, i32, i32, i64, i32) + DEF_HELPER_3(clcle, i32, i32, i64, i32) + DEF_HELPER_3(slb, i32, i32, i32, i32) + DEF_HELPER_4(slbg, i32, i32, i32, i64, i64) +-DEF_HELPER_2(cefbr, void, i32, s32) +-DEF_HELPER_2(cdfbr, void, i32, s32) +-DEF_HELPER_2(cxfbr, void, i32, s32) +-DEF_HELPER_2(cegbr, void, i32, s64) +-DEF_HELPER_2(cdgbr, void, i32, s64) +-DEF_HELPER_2(cxgbr, void, i32, s64) +-DEF_HELPER_2(adbr, i32, i32, i32) +-DEF_HELPER_2(aebr, i32, i32, i32) +-DEF_HELPER_2(sebr, i32, i32, i32) +-DEF_HELPER_2(sdbr, i32, i32, i32) +-DEF_HELPER_2(debr, void, i32, i32) +-DEF_HELPER_2(dxbr, void, i32, i32) +-DEF_HELPER_2(mdbr, void, i32, i32) +-DEF_HELPER_2(mxbr, void, i32, i32) +-DEF_HELPER_2(ldebr, void, i32, i32) +-DEF_HELPER_2(ldxbr, void, i32, i32) +-DEF_HELPER_2(lxdbr, void, i32, i32) +-DEF_HELPER_2(ledbr, void, i32, i32) +-DEF_HELPER_2(lexbr, void, i32, i32) +-DEF_HELPER_2(lpebr, i32, i32, i32) +-DEF_HELPER_2(lpdbr, i32, i32, i32) +-DEF_HELPER_2(lpxbr, i32, i32, i32) +-DEF_HELPER_2(ltebr, i32, i32, i32) +-DEF_HELPER_2(ltdbr, i32, i32, i32) +-DEF_HELPER_2(ltxbr, i32, i32, i32) +-DEF_HELPER_2(lcebr, i32, i32, i32) +-DEF_HELPER_2(lcdbr, i32, i32, i32) +-DEF_HELPER_2(lcxbr, i32, i32, i32) +-DEF_HELPER_2(aeb, void, i32, i32) +-DEF_HELPER_2(deb, void, i32, i32) +-DEF_HELPER_2(meeb, void, i32, i32) +-DEF_HELPER_2(cdb, i32, i32, i64) +-DEF_HELPER_2(adb, i32, i32, i64) +-DEF_HELPER_2(seb, void, i32, i32) +-DEF_HELPER_2(sdb, i32, i32, i64) +-DEF_HELPER_2(mdb, void, i32, i64) +-DEF_HELPER_2(ddb, void, i32, i64) +-DEF_HELPER_FLAGS_2(cebr, TCG_CALL_PURE, i32, i32, i32) +-DEF_HELPER_FLAGS_2(cdbr, TCG_CALL_PURE, i32, i32, i32) +-DEF_HELPER_FLAGS_2(cxbr, TCG_CALL_PURE, i32, i32, i32) +-DEF_HELPER_3(cgebr, i32, i32, i32, i32) +-DEF_HELPER_3(cgdbr, i32, i32, i32, i32) +-DEF_HELPER_3(cgxbr, i32, i32, i32, i32) +-DEF_HELPER_1(lzer, void, i32) +-DEF_HELPER_1(lzdr, void, i32) +-DEF_HELPER_1(lzxr, void, i32) +-DEF_HELPER_3(cfebr, i32, i32, i32, i32) +-DEF_HELPER_3(cfdbr, i32, i32, i32, i32) +-DEF_HELPER_3(cfxbr, i32, i32, i32, i32) +-DEF_HELPER_2(axbr, i32, i32, i32) +-DEF_HELPER_2(sxbr, i32, i32, i32) +-DEF_HELPER_2(meebr, void, i32, i32) +-DEF_HELPER_2(ddbr, void, i32, i32) +-DEF_HELPER_3(madb, void, i32, i64, i32) +-DEF_HELPER_3(maebr, void, i32, i32, i32) +-DEF_HELPER_3(madbr, void, i32, i32, i32) +-DEF_HELPER_3(msdbr, void, i32, i32, i32) +-DEF_HELPER_2(ldeb, void, i32, i64) +-DEF_HELPER_2(lxdb, void, i32, i64) +-DEF_HELPER_FLAGS_2(tceb, TCG_CALL_PURE, i32, i32, i64) +-DEF_HELPER_FLAGS_2(tcdb, TCG_CALL_PURE, i32, i32, i64) +-DEF_HELPER_FLAGS_2(tcxb, TCG_CALL_PURE, i32, i32, i64) ++DEF_HELPER_3(cefbr, void, env, i32, s32) ++DEF_HELPER_3(cdfbr, void, env, i32, s32) ++DEF_HELPER_3(cxfbr, void, env, i32, s32) ++DEF_HELPER_3(cegbr, void, env, i32, s64) ++DEF_HELPER_3(cdgbr, void, env, i32, s64) ++DEF_HELPER_3(cxgbr, void, env, i32, s64) ++DEF_HELPER_3(adbr, i32, env, i32, i32) ++DEF_HELPER_3(aebr, i32, env, i32, i32) ++DEF_HELPER_3(sebr, i32, env, i32, i32) ++DEF_HELPER_3(sdbr, i32, env, i32, i32) ++DEF_HELPER_3(debr, void, env, i32, i32) ++DEF_HELPER_3(dxbr, void, env, i32, i32) ++DEF_HELPER_3(mdbr, void, env, i32, i32) ++DEF_HELPER_3(mxbr, void, env, i32, i32) ++DEF_HELPER_3(ldebr, void, env, i32, i32) ++DEF_HELPER_3(ldxbr, void, env, i32, i32) ++DEF_HELPER_3(lxdbr, void, env, i32, i32) ++DEF_HELPER_3(ledbr, void, env, i32, i32) ++DEF_HELPER_3(lexbr, void, env, i32, i32) ++DEF_HELPER_3(lpebr, i32, env, i32, i32) ++DEF_HELPER_3(lpdbr, i32, env, i32, i32) ++DEF_HELPER_3(lpxbr, i32, env, i32, i32) ++DEF_HELPER_3(ltebr, i32, env, i32, i32) ++DEF_HELPER_3(ltdbr, i32, env, i32, i32) ++DEF_HELPER_3(ltxbr, i32, env, i32, i32) ++DEF_HELPER_3(lcebr, i32, env, i32, i32) ++DEF_HELPER_3(lcdbr, i32, env, i32, i32) ++DEF_HELPER_3(lcxbr, i32, env, i32, i32) ++DEF_HELPER_3(aeb, void, env, i32, i32) ++DEF_HELPER_3(deb, void, env, i32, i32) ++DEF_HELPER_3(meeb, void, env, i32, i32) ++DEF_HELPER_3(cdb, i32, env, i32, i64) ++DEF_HELPER_3(adb, i32, env, i32, i64) ++DEF_HELPER_3(seb, void, env, i32, i32) ++DEF_HELPER_3(sdb, i32, env, i32, i64) ++DEF_HELPER_3(mdb, void, env, i32, i64) ++DEF_HELPER_3(ddb, void, env, i32, i64) ++DEF_HELPER_FLAGS_3(cebr, TCG_CALL_PURE, i32, env, i32, i32) ++DEF_HELPER_FLAGS_3(cdbr, TCG_CALL_PURE, i32, env, i32, i32) ++DEF_HELPER_FLAGS_3(cxbr, TCG_CALL_PURE, i32, env, i32, i32) ++DEF_HELPER_4(cgebr, i32, env, i32, i32, i32) ++DEF_HELPER_4(cgdbr, i32, env, i32, i32, i32) ++DEF_HELPER_4(cgxbr, i32, env, i32, i32, i32) ++DEF_HELPER_2(lzer, void, env, i32) ++DEF_HELPER_2(lzdr, void, env, i32) ++DEF_HELPER_2(lzxr, void, env, i32) ++DEF_HELPER_4(cfebr, i32, env, i32, i32, i32) ++DEF_HELPER_4(cfdbr, i32, env, i32, i32, i32) ++DEF_HELPER_4(cfxbr, i32, env, i32, i32, i32) ++DEF_HELPER_3(axbr, i32, env, i32, i32) ++DEF_HELPER_3(sxbr, i32, env, i32, i32) ++DEF_HELPER_3(meebr, void, env, i32, i32) ++DEF_HELPER_3(ddbr, void, env, i32, i32) ++DEF_HELPER_4(madb, void, env, i32, i64, i32) ++DEF_HELPER_4(maebr, void, env, i32, i32, i32) ++DEF_HELPER_4(madbr, void, env, i32, i32, i32) ++DEF_HELPER_4(msdbr, void, env, i32, i32, i32) ++DEF_HELPER_3(ldeb, void, env, i32, i64) ++DEF_HELPER_3(lxdb, void, env, i32, i64) ++DEF_HELPER_FLAGS_3(tceb, TCG_CALL_PURE, i32, env, i32, i64) ++DEF_HELPER_FLAGS_3(tcdb, TCG_CALL_PURE, i32, env, i32, i64) ++DEF_HELPER_FLAGS_3(tcxb, TCG_CALL_PURE, i32, env, i32, i64) + DEF_HELPER_2(flogr, i32, i32, i64) +-DEF_HELPER_2(sqdbr, void, i32, i32) ++DEF_HELPER_3(sqdbr, void, env, i32, i32) + DEF_HELPER_FLAGS_1(cvd, TCG_CALL_PURE|TCG_CALL_CONST, i64, s32) + DEF_HELPER_3(unpk, void, i32, i64, i64) + DEF_HELPER_3(tr, void, i32, i64, i64) +diff --git a/target-s390x/mem_helper.c b/target-s390x/mem_helper.c +index ba05e65..3f8b3ba 100644 +--- a/target-s390x/mem_helper.c ++++ b/target-s390x/mem_helper.c +@@ -1188,3 +1188,52 @@ uint32_t HELPER(lra)(uint64_t addr, uint32_t r1) + } + + #endif ++ ++/* temporary wrappers */ ++#if defined(CONFIG_USER_ONLY) ++#define ldub_data(addr) ldub_raw(addr) ++#define lduw_data(addr) lduw_raw(addr) ++#define ldl_data(addr) ldl_raw(addr) ++#define ldq_data(addr) ldq_raw(addr) ++ ++#define stb_data(addr, data) stb_raw(addr, data) ++#define stw_data(addr, data) stw_raw(addr, data) ++#define stl_data(addr, data) stl_raw(addr, data) ++#define stq_data(addr, data) stq_raw(addr, data) ++#endif ++ ++#define WRAP_LD(rettype, fn) \ ++ rettype cpu_ ## fn(CPUS390XState *env1, target_ulong addr) \ ++ { \ ++ CPUS390XState *saved_env; \ ++ rettype ret; \ ++ \ ++ saved_env = env; \ ++ env = env1; \ ++ ret = fn(addr); \ ++ env = saved_env; \ ++ return ret; \ ++ } ++ ++WRAP_LD(uint32_t, ldub_data) ++WRAP_LD(uint32_t, lduw_data) ++WRAP_LD(uint32_t, ldl_data) ++WRAP_LD(uint64_t, ldq_data) ++#undef WRAP_LD ++ ++#define WRAP_ST(datatype, fn) \ ++ void cpu_ ## fn(CPUS390XState *env1, target_ulong addr, datatype val) \ ++ { \ ++ CPUS390XState *saved_env; \ ++ \ ++ saved_env = env; \ ++ env = env1; \ ++ fn(addr, val); \ ++ env = saved_env; \ ++ } ++ ++WRAP_ST(uint32_t, stb_data) ++WRAP_ST(uint32_t, stw_data) ++WRAP_ST(uint32_t, stl_data) ++WRAP_ST(uint64_t, stq_data) ++#undef WRAP_ST +diff --git a/target-s390x/translate.c b/target-s390x/translate.c +index c370df3..b1f2071 100644 +--- a/target-s390x/translate.c ++++ b/target-s390x/translate.c +@@ -2206,11 +2206,11 @@ static void disas_ed(DisasContext *s, int op, int r1, int x2, int b2, int d2, + switch (op) { + case 0x4: /* LDEB R1,D2(X2,B2) [RXE] */ + potential_page_fault(s); +- gen_helper_ldeb(tmp_r1, addr); ++ gen_helper_ldeb(cpu_env, tmp_r1, addr); + break; + case 0x5: /* LXDB R1,D2(X2,B2) [RXE] */ + potential_page_fault(s); +- gen_helper_lxdb(tmp_r1, addr); ++ gen_helper_lxdb(cpu_env, tmp_r1, addr); + break; + case 0x9: /* CEB R1,D2(X2,B2) [RXE] */ + tmp = tcg_temp_new_i64(); +@@ -2225,7 +2225,7 @@ static void disas_ed(DisasContext *s, int op, int r1, int x2, int b2, int d2, + tmp32 = tcg_temp_new_i32(); + tcg_gen_qemu_ld32u(tmp, addr, get_mem_index(s)); + tcg_gen_trunc_i64_i32(tmp32, tmp); +- gen_helper_aeb(tmp_r1, tmp32); ++ gen_helper_aeb(cpu_env, tmp_r1, tmp32); + tcg_temp_free_i64(tmp); + tcg_temp_free_i32(tmp32); + +@@ -2238,7 +2238,7 @@ static void disas_ed(DisasContext *s, int op, int r1, int x2, int b2, int d2, + tmp32 = tcg_temp_new_i32(); + tcg_gen_qemu_ld32u(tmp, addr, get_mem_index(s)); + tcg_gen_trunc_i64_i32(tmp32, tmp); +- gen_helper_seb(tmp_r1, tmp32); ++ gen_helper_seb(cpu_env, tmp_r1, tmp32); + tcg_temp_free_i64(tmp); + tcg_temp_free_i32(tmp32); + +@@ -2251,23 +2251,23 @@ static void disas_ed(DisasContext *s, int op, int r1, int x2, int b2, int d2, + tmp32 = tcg_temp_new_i32(); + tcg_gen_qemu_ld32u(tmp, addr, get_mem_index(s)); + tcg_gen_trunc_i64_i32(tmp32, tmp); +- gen_helper_deb(tmp_r1, tmp32); ++ gen_helper_deb(cpu_env, tmp_r1, tmp32); + tcg_temp_free_i64(tmp); + tcg_temp_free_i32(tmp32); + break; + case 0x10: /* TCEB R1,D2(X2,B2) [RXE] */ + potential_page_fault(s); +- gen_helper_tceb(cc_op, tmp_r1, addr); ++ gen_helper_tceb(cc_op, cpu_env, tmp_r1, addr); + set_cc_static(s); + break; + case 0x11: /* TCDB R1,D2(X2,B2) [RXE] */ + potential_page_fault(s); +- gen_helper_tcdb(cc_op, tmp_r1, addr); ++ gen_helper_tcdb(cc_op, cpu_env, tmp_r1, addr); + set_cc_static(s); + break; + case 0x12: /* TCXB R1,D2(X2,B2) [RXE] */ + potential_page_fault(s); +- gen_helper_tcxb(cc_op, tmp_r1, addr); ++ gen_helper_tcxb(cc_op, cpu_env, tmp_r1, addr); + set_cc_static(s); + break; + case 0x17: /* MEEB R1,D2(X2,B2) [RXE] */ +@@ -2275,38 +2275,38 @@ static void disas_ed(DisasContext *s, int op, int r1, int x2, int b2, int d2, + tmp32 = tcg_temp_new_i32(); + tcg_gen_qemu_ld32u(tmp, addr, get_mem_index(s)); + tcg_gen_trunc_i64_i32(tmp32, tmp); +- gen_helper_meeb(tmp_r1, tmp32); ++ gen_helper_meeb(cpu_env, tmp_r1, tmp32); + tcg_temp_free_i64(tmp); + tcg_temp_free_i32(tmp32); + break; + case 0x19: /* CDB R1,D2(X2,B2) [RXE] */ + potential_page_fault(s); +- gen_helper_cdb(cc_op, tmp_r1, addr); ++ gen_helper_cdb(cc_op, cpu_env, tmp_r1, addr); + set_cc_static(s); + break; + case 0x1a: /* ADB R1,D2(X2,B2) [RXE] */ + potential_page_fault(s); +- gen_helper_adb(cc_op, tmp_r1, addr); ++ gen_helper_adb(cc_op, cpu_env, tmp_r1, addr); + set_cc_static(s); + break; + case 0x1b: /* SDB R1,D2(X2,B2) [RXE] */ + potential_page_fault(s); +- gen_helper_sdb(cc_op, tmp_r1, addr); ++ gen_helper_sdb(cc_op, cpu_env, tmp_r1, addr); + set_cc_static(s); + break; + case 0x1c: /* MDB R1,D2(X2,B2) [RXE] */ + potential_page_fault(s); +- gen_helper_mdb(tmp_r1, addr); ++ gen_helper_mdb(cpu_env, tmp_r1, addr); + break; + case 0x1d: /* DDB R1,D2(X2,B2) [RXE] */ + potential_page_fault(s); +- gen_helper_ddb(tmp_r1, addr); ++ gen_helper_ddb(cpu_env, tmp_r1, addr); + break; + case 0x1e: /* MADB R1,R3,D2(X2,B2) [RXF] */ + /* for RXF insns, r1 is R3 and r1b is R1 */ + tmp32 = tcg_const_i32(r1b); + potential_page_fault(s); +- gen_helper_madb(tmp32, addr, tmp_r1); ++ gen_helper_madb(cpu_env, tmp32, addr, tmp_r1); + tcg_temp_free_i32(tmp32); + break; + default: +@@ -3001,14 +3001,14 @@ static void disas_b3(DisasContext *s, int op, int m3, int r1, int r2) + #define FP_HELPER(i) \ + tmp32_1 = tcg_const_i32(r1); \ + tmp32_2 = tcg_const_i32(r2); \ +- gen_helper_ ## i (tmp32_1, tmp32_2); \ ++ gen_helper_ ## i(cpu_env, tmp32_1, tmp32_2); \ + tcg_temp_free_i32(tmp32_1); \ + tcg_temp_free_i32(tmp32_2); + + #define FP_HELPER_CC(i) \ + tmp32_1 = tcg_const_i32(r1); \ + tmp32_2 = tcg_const_i32(r2); \ +- gen_helper_ ## i (cc_op, tmp32_1, tmp32_2); \ ++ gen_helper_ ## i(cc_op, cpu_env, tmp32_1, tmp32_2); \ + set_cc_static(s); \ + tcg_temp_free_i32(tmp32_1); \ + tcg_temp_free_i32(tmp32_2); +@@ -3080,13 +3080,13 @@ static void disas_b3(DisasContext *s, int op, int m3, int r1, int r2) + tmp32_3 = tcg_const_i32(r1); + switch (op) { + case 0xe: +- gen_helper_maebr(tmp32_1, tmp32_3, tmp32_2); ++ gen_helper_maebr(cpu_env, tmp32_1, tmp32_3, tmp32_2); + break; + case 0x1e: +- gen_helper_madbr(tmp32_1, tmp32_3, tmp32_2); ++ gen_helper_madbr(cpu_env, tmp32_1, tmp32_3, tmp32_2); + break; + case 0x1f: +- gen_helper_msdbr(tmp32_1, tmp32_3, tmp32_2); ++ gen_helper_msdbr(cpu_env, tmp32_1, tmp32_3, tmp32_2); + break; + default: + tcg_abort(); +@@ -3138,17 +3138,17 @@ static void disas_b3(DisasContext *s, int op, int m3, int r1, int r2) + break; + case 0x74: /* LZER R1 [RRE] */ + tmp32_1 = tcg_const_i32(r1); +- gen_helper_lzer(tmp32_1); ++ gen_helper_lzer(cpu_env, tmp32_1); + tcg_temp_free_i32(tmp32_1); + break; + case 0x75: /* LZDR R1 [RRE] */ + tmp32_1 = tcg_const_i32(r1); +- gen_helper_lzdr(tmp32_1); ++ gen_helper_lzdr(cpu_env, tmp32_1); + tcg_temp_free_i32(tmp32_1); + break; + case 0x76: /* LZXR R1 [RRE] */ + tmp32_1 = tcg_const_i32(r1); +- gen_helper_lzxr(tmp32_1); ++ gen_helper_lzxr(cpu_env, tmp32_1); + tcg_temp_free_i32(tmp32_1); + break; + case 0x84: /* SFPC R1 [RRE] */ +@@ -3169,13 +3169,13 @@ static void disas_b3(DisasContext *s, int op, int m3, int r1, int r2) + tmp32_2 = load_reg32(r2); + switch (op) { + case 0x94: +- gen_helper_cefbr(tmp32_1, tmp32_2); ++ gen_helper_cefbr(cpu_env, tmp32_1, tmp32_2); + break; + case 0x95: +- gen_helper_cdfbr(tmp32_1, tmp32_2); ++ gen_helper_cdfbr(cpu_env, tmp32_1, tmp32_2); + break; + case 0x96: +- gen_helper_cxfbr(tmp32_1, tmp32_2); ++ gen_helper_cxfbr(cpu_env, tmp32_1, tmp32_2); + break; + default: + tcg_abort(); +@@ -3191,13 +3191,13 @@ static void disas_b3(DisasContext *s, int op, int m3, int r1, int r2) + tmp32_3 = tcg_const_i32(m3); + switch (op) { + case 0x98: +- gen_helper_cfebr(cc_op, tmp32_1, tmp32_2, tmp32_3); ++ gen_helper_cfebr(cc_op, cpu_env, tmp32_1, tmp32_2, tmp32_3); + break; + case 0x99: +- gen_helper_cfdbr(cc_op, tmp32_1, tmp32_2, tmp32_3); ++ gen_helper_cfdbr(cc_op, cpu_env, tmp32_1, tmp32_2, tmp32_3); + break; + case 0x9a: +- gen_helper_cfxbr(cc_op, tmp32_1, tmp32_2, tmp32_3); ++ gen_helper_cfxbr(cc_op, cpu_env, tmp32_1, tmp32_2, tmp32_3); + break; + default: + tcg_abort(); +@@ -3213,10 +3213,10 @@ static void disas_b3(DisasContext *s, int op, int m3, int r1, int r2) + tmp = load_reg(r2); + switch (op) { + case 0xa4: +- gen_helper_cegbr(tmp32_1, tmp); ++ gen_helper_cegbr(cpu_env, tmp32_1, tmp); + break; + case 0xa5: +- gen_helper_cdgbr(tmp32_1, tmp); ++ gen_helper_cdgbr(cpu_env, tmp32_1, tmp); + break; + default: + tcg_abort(); +@@ -3227,7 +3227,7 @@ static void disas_b3(DisasContext *s, int op, int m3, int r1, int r2) + case 0xa6: /* CXGBR R1,R2 [RRE] */ + tmp32_1 = tcg_const_i32(r1); + tmp = load_reg(r2); +- gen_helper_cxgbr(tmp32_1, tmp); ++ gen_helper_cxgbr(cpu_env, tmp32_1, tmp); + tcg_temp_free_i32(tmp32_1); + tcg_temp_free_i64(tmp); + break; +@@ -3235,7 +3235,7 @@ static void disas_b3(DisasContext *s, int op, int m3, int r1, int r2) + tmp32_1 = tcg_const_i32(r1); + tmp32_2 = tcg_const_i32(r2); + tmp32_3 = tcg_const_i32(m3); +- gen_helper_cgebr(cc_op, tmp32_1, tmp32_2, tmp32_3); ++ gen_helper_cgebr(cc_op, cpu_env, tmp32_1, tmp32_2, tmp32_3); + set_cc_static(s); + tcg_temp_free_i32(tmp32_1); + tcg_temp_free_i32(tmp32_2); +@@ -3245,7 +3245,7 @@ static void disas_b3(DisasContext *s, int op, int m3, int r1, int r2) + tmp32_1 = tcg_const_i32(r1); + tmp32_2 = tcg_const_i32(r2); + tmp32_3 = tcg_const_i32(m3); +- gen_helper_cgdbr(cc_op, tmp32_1, tmp32_2, tmp32_3); ++ gen_helper_cgdbr(cc_op, cpu_env, tmp32_1, tmp32_2, tmp32_3); + set_cc_static(s); + tcg_temp_free_i32(tmp32_1); + tcg_temp_free_i32(tmp32_2); +@@ -3255,7 +3255,7 @@ static void disas_b3(DisasContext *s, int op, int m3, int r1, int r2) + tmp32_1 = tcg_const_i32(r1); + tmp32_2 = tcg_const_i32(r2); + tmp32_3 = tcg_const_i32(m3); +- gen_helper_cgxbr(cc_op, tmp32_1, tmp32_2, tmp32_3); ++ gen_helper_cgxbr(cc_op, cpu_env, tmp32_1, tmp32_2, tmp32_3); + set_cc_static(s); + tcg_temp_free_i32(tmp32_1); + tcg_temp_free_i32(tmp32_2); +-- +1.7.12.1 + diff --git a/0012-target-s390x-avoid-AREG0-for-integer-helpers.patch b/0012-target-s390x-avoid-AREG0-for-integer-helpers.patch new file mode 100644 index 0000000..379d0f7 --- /dev/null +++ b/0012-target-s390x-avoid-AREG0-for-integer-helpers.patch @@ -0,0 +1,202 @@ +From d44b8c2cacaa50e7420f0dfaf42c344bcf134431 Mon Sep 17 00:00:00 2001 +From: Blue Swirl +Date: Sun, 2 Sep 2012 07:33:37 +0000 +Subject: [PATCH] target-s390x: avoid AREG0 for integer helpers + +Make integer helpers take a parameter for CPUState instead +of relying on global env. + +Signed-off-by: Blue Swirl +Signed-off-by: Alexander Graf +Signed-off-by: Michael Roth +--- + target-s390x/Makefile.objs | 1 - + target-s390x/helper.h | 10 +++++----- + target-s390x/int_helper.c | 12 ++++++------ + target-s390x/translate.c | 16 ++++++++-------- + 4 files changed, 19 insertions(+), 20 deletions(-) + +diff --git a/target-s390x/Makefile.objs b/target-s390x/Makefile.objs +index 7d965e9..7b2c5c1 100644 +--- a/target-s390x/Makefile.objs ++++ b/target-s390x/Makefile.objs +@@ -3,7 +3,6 @@ obj-y += int_helper.o fpu_helper.o cc_helper.o mem_helper.o misc_helper.o + obj-$(CONFIG_SOFTMMU) += machine.o + obj-$(CONFIG_KVM) += kvm.o + +-$(obj)/int_helper.o: QEMU_CFLAGS += $(HELPER_CFLAGS) + $(obj)/cc_helper.o: QEMU_CFLAGS += $(HELPER_CFLAGS) + $(obj)/mem_helper.o: QEMU_CFLAGS += $(HELPER_CFLAGS) + $(obj)/misc_helper.o: QEMU_CFLAGS += $(HELPER_CFLAGS) +diff --git a/target-s390x/helper.h b/target-s390x/helper.h +index af98773..c03cd59 100644 +--- a/target-s390x/helper.h ++++ b/target-s390x/helper.h +@@ -12,8 +12,8 @@ DEF_HELPER_FLAGS_1(set_cc_comp_s64, TCG_CALL_PURE|TCG_CALL_CONST, i32, s64) + DEF_HELPER_FLAGS_2(set_cc_icm, TCG_CALL_PURE|TCG_CALL_CONST, i32, i32, i32) + DEF_HELPER_3(clm, i32, i32, i32, i64) + DEF_HELPER_3(stcm, void, i32, i32, i64) +-DEF_HELPER_2(mlg, void, i32, i64) +-DEF_HELPER_2(dlg, void, i32, i64) ++DEF_HELPER_3(mlg, void, env, i32, i64) ++DEF_HELPER_3(dlg, void, env, i32, i64) + DEF_HELPER_FLAGS_3(set_cc_add64, TCG_CALL_PURE|TCG_CALL_CONST, i32, s64, s64, s64) + DEF_HELPER_FLAGS_3(set_cc_addu64, TCG_CALL_PURE|TCG_CALL_CONST, i32, i64, i64, i64) + DEF_HELPER_FLAGS_3(set_cc_add32, TCG_CALL_PURE|TCG_CALL_CONST, i32, s32, s32, s32) +@@ -43,8 +43,8 @@ DEF_HELPER_3(stam, void, i32, i64, i32) + DEF_HELPER_3(lam, void, i32, i64, i32) + DEF_HELPER_3(mvcle, i32, i32, i64, i32) + DEF_HELPER_3(clcle, i32, i32, i64, i32) +-DEF_HELPER_3(slb, i32, i32, i32, i32) +-DEF_HELPER_4(slbg, i32, i32, i32, i64, i64) ++DEF_HELPER_4(slb, i32, env, i32, i32, i32) ++DEF_HELPER_5(slbg, i32, env, i32, i32, i64, i64) + DEF_HELPER_3(cefbr, void, env, i32, s32) + DEF_HELPER_3(cdfbr, void, env, i32, s32) + DEF_HELPER_3(cxfbr, void, env, i32, s32) +@@ -107,7 +107,7 @@ DEF_HELPER_3(lxdb, void, env, i32, i64) + DEF_HELPER_FLAGS_3(tceb, TCG_CALL_PURE, i32, env, i32, i64) + DEF_HELPER_FLAGS_3(tcdb, TCG_CALL_PURE, i32, env, i32, i64) + DEF_HELPER_FLAGS_3(tcxb, TCG_CALL_PURE, i32, env, i32, i64) +-DEF_HELPER_2(flogr, i32, i32, i64) ++DEF_HELPER_3(flogr, i32, env, i32, i64) + DEF_HELPER_3(sqdbr, void, env, i32, i32) + DEF_HELPER_FLAGS_1(cvd, TCG_CALL_PURE|TCG_CALL_CONST, i64, s32) + DEF_HELPER_3(unpk, void, i32, i64, i64) +diff --git a/target-s390x/int_helper.c b/target-s390x/int_helper.c +index e2eeb07..f202a7e 100644 +--- a/target-s390x/int_helper.c ++++ b/target-s390x/int_helper.c +@@ -19,7 +19,6 @@ + */ + + #include "cpu.h" +-#include "dyngen-exec.h" + #include "host-utils.h" + #include "helper.h" + +@@ -31,7 +30,7 @@ + #endif + + /* 64/64 -> 128 unsigned multiplication */ +-void HELPER(mlg)(uint32_t r1, uint64_t v2) ++void HELPER(mlg)(CPUS390XState *env, uint32_t r1, uint64_t v2) + { + #if HOST_LONG_BITS == 64 && defined(__GNUC__) + /* assuming 64-bit hosts have __uint128_t */ +@@ -46,7 +45,7 @@ void HELPER(mlg)(uint32_t r1, uint64_t v2) + } + + /* 128 -> 64/64 unsigned division */ +-void HELPER(dlg)(uint32_t r1, uint64_t v2) ++void HELPER(dlg)(CPUS390XState *env, uint32_t r1, uint64_t v2) + { + uint64_t divisor = v2; + +@@ -129,7 +128,7 @@ uint32_t HELPER(addc_u32)(uint32_t cc, uint32_t v1, uint32_t v2) + } + + /* subtract unsigned v2 from v1 with borrow */ +-uint32_t HELPER(slb)(uint32_t cc, uint32_t r1, uint32_t v2) ++uint32_t HELPER(slb)(CPUS390XState *env, uint32_t cc, uint32_t r1, uint32_t v2) + { + uint32_t v1 = env->regs[r1]; + uint32_t res = v1 + (~v2) + (cc >> 1); +@@ -144,7 +143,8 @@ uint32_t HELPER(slb)(uint32_t cc, uint32_t r1, uint32_t v2) + } + + /* subtract unsigned v2 from v1 with borrow */ +-uint32_t HELPER(slbg)(uint32_t cc, uint32_t r1, uint64_t v1, uint64_t v2) ++uint32_t HELPER(slbg)(CPUS390XState *env, uint32_t cc, uint32_t r1, ++ uint64_t v1, uint64_t v2) + { + uint64_t res = v1 + (~v2) + (cc >> 1); + +@@ -158,7 +158,7 @@ uint32_t HELPER(slbg)(uint32_t cc, uint32_t r1, uint64_t v1, uint64_t v2) + } + + /* find leftmost one */ +-uint32_t HELPER(flogr)(uint32_t r1, uint64_t v2) ++uint32_t HELPER(flogr)(CPUS390XState *env, uint32_t r1, uint64_t v2) + { + uint64_t res = 0; + uint64_t ov2 = v2; +diff --git a/target-s390x/translate.c b/target-s390x/translate.c +index b1f2071..2a61e92 100644 +--- a/target-s390x/translate.c ++++ b/target-s390x/translate.c +@@ -1803,7 +1803,7 @@ static void disas_e3(DisasContext* s, int op, int r1, int x2, int b2, int d2) + tmp2 = tcg_temp_new_i64(); + tmp32_1 = tcg_const_i32(r1); + tcg_gen_qemu_ld64(tmp2, addr, get_mem_index(s)); +- gen_helper_mlg(tmp32_1, tmp2); ++ gen_helper_mlg(cpu_env, tmp32_1, tmp2); + tcg_temp_free_i64(tmp2); + tcg_temp_free_i32(tmp32_1); + break; +@@ -1811,7 +1811,7 @@ static void disas_e3(DisasContext* s, int op, int r1, int x2, int b2, int d2) + tmp2 = tcg_temp_new_i64(); + tmp32_1 = tcg_const_i32(r1); + tcg_gen_qemu_ld64(tmp2, addr, get_mem_index(s)); +- gen_helper_dlg(tmp32_1, tmp2); ++ gen_helper_dlg(cpu_env, tmp32_1, tmp2); + tcg_temp_free_i64(tmp2); + tcg_temp_free_i32(tmp32_1); + break; +@@ -1837,7 +1837,7 @@ static void disas_e3(DisasContext* s, int op, int r1, int x2, int b2, int d2) + tcg_gen_qemu_ld64(tmp2, addr, get_mem_index(s)); + /* XXX possible optimization point */ + gen_op_calc_cc(s); +- gen_helper_slbg(cc_op, cc_op, tmp32_1, regs[r1], tmp2); ++ gen_helper_slbg(cc_op, cpu_env, cc_op, tmp32_1, regs[r1], tmp2); + set_cc_static(s); + tcg_temp_free_i64(tmp2); + tcg_temp_free_i32(tmp32_1); +@@ -1917,7 +1917,7 @@ static void disas_e3(DisasContext* s, int op, int r1, int x2, int b2, int d2) + tcg_gen_trunc_i64_i32(tmp32_2, tmp2); + /* XXX possible optimization point */ + gen_op_calc_cc(s); +- gen_helper_slb(cc_op, cc_op, tmp32_1, tmp32_2); ++ gen_helper_slb(cc_op, cpu_env, cc_op, tmp32_1, tmp32_2); + set_cc_static(s); + tcg_temp_free_i64(tmp2); + tcg_temp_free_i32(tmp32_1); +@@ -3535,7 +3535,7 @@ static void disas_b9(DisasContext *s, int op, int r1, int r2) + case 0x83: /* FLOGR R1,R2 [RRE] */ + tmp = load_reg(r2); + tmp32_1 = tcg_const_i32(r1); +- gen_helper_flogr(cc_op, tmp32_1, tmp); ++ gen_helper_flogr(cc_op, cpu_env, tmp32_1, tmp); + set_cc_static(s); + tcg_temp_free_i64(tmp); + tcg_temp_free_i32(tmp32_1); +@@ -3555,7 +3555,7 @@ static void disas_b9(DisasContext *s, int op, int r1, int r2) + case 0x87: /* DLGR R1,R2 [RRE] */ + tmp32_1 = tcg_const_i32(r1); + tmp = load_reg(r2); +- gen_helper_dlg(tmp32_1, tmp); ++ gen_helper_dlg(cpu_env, tmp32_1, tmp); + tcg_temp_free_i64(tmp); + tcg_temp_free_i32(tmp32_1); + break; +@@ -3580,7 +3580,7 @@ static void disas_b9(DisasContext *s, int op, int r1, int r2) + tmp2 = load_reg(r2); + tmp32_1 = tcg_const_i32(r1); + gen_op_calc_cc(s); +- gen_helper_slbg(cc_op, cc_op, tmp32_1, tmp, tmp2); ++ gen_helper_slbg(cc_op, cpu_env, cc_op, tmp32_1, tmp, tmp2); + set_cc_static(s); + tcg_temp_free_i64(tmp); + tcg_temp_free_i64(tmp2); +@@ -3647,7 +3647,7 @@ static void disas_b9(DisasContext *s, int op, int r1, int r2) + tmp32_1 = load_reg32(r2); + tmp32_2 = tcg_const_i32(r1); + gen_op_calc_cc(s); +- gen_helper_slb(cc_op, cc_op, tmp32_2, tmp32_1); ++ gen_helper_slb(cc_op, cpu_env, cc_op, tmp32_2, tmp32_1); + set_cc_static(s); + tcg_temp_free_i32(tmp32_1); + tcg_temp_free_i32(tmp32_2); +-- +1.7.12.1 + diff --git a/0013-target-s390x-avoid-AREG0-for-condition-code-helpers.patch b/0013-target-s390x-avoid-AREG0-for-condition-code-helpers.patch new file mode 100644 index 0000000..eddecbb --- /dev/null +++ b/0013-target-s390x-avoid-AREG0-for-condition-code-helpers.patch @@ -0,0 +1,190 @@ +From ead7a100e907eddd0ba9f3cebb5f84c1afb120b8 Mon Sep 17 00:00:00 2001 +From: Blue Swirl +Date: Sun, 2 Sep 2012 07:33:38 +0000 +Subject: [PATCH] target-s390x: avoid AREG0 for condition code helpers + +Make condition code helpers take a parameter for CPUState instead +of relying on global env. + +Signed-off-by: Blue Swirl +Signed-off-by: Alexander Graf +Signed-off-by: Michael Roth +--- + target-s390x/Makefile.objs | 1 - + target-s390x/cc_helper.c | 11 +++++------ + target-s390x/helper.h | 10 +++++----- + target-s390x/translate.c | 16 ++++++++-------- + 4 files changed, 18 insertions(+), 20 deletions(-) + +diff --git a/target-s390x/Makefile.objs b/target-s390x/Makefile.objs +index 7b2c5c1..736cf33 100644 +--- a/target-s390x/Makefile.objs ++++ b/target-s390x/Makefile.objs +@@ -3,6 +3,5 @@ obj-y += int_helper.o fpu_helper.o cc_helper.o mem_helper.o misc_helper.o + obj-$(CONFIG_SOFTMMU) += machine.o + obj-$(CONFIG_KVM) += kvm.o + +-$(obj)/cc_helper.o: QEMU_CFLAGS += $(HELPER_CFLAGS) + $(obj)/mem_helper.o: QEMU_CFLAGS += $(HELPER_CFLAGS) + $(obj)/misc_helper.o: QEMU_CFLAGS += $(HELPER_CFLAGS) +diff --git a/target-s390x/cc_helper.c b/target-s390x/cc_helper.c +index 9c3a2c4..19ef145 100644 +--- a/target-s390x/cc_helper.c ++++ b/target-s390x/cc_helper.c +@@ -19,7 +19,6 @@ + */ + + #include "cpu.h" +-#include "dyngen-exec.h" + #include "helper.h" + + /* #define DEBUG_HELPER */ +@@ -500,14 +499,14 @@ uint32_t calc_cc(CPUS390XState *env, uint32_t cc_op, uint64_t src, uint64_t dst, + return do_calc_cc(env, cc_op, src, dst, vr); + } + +-uint32_t HELPER(calc_cc)(uint32_t cc_op, uint64_t src, uint64_t dst, +- uint64_t vr) ++uint32_t HELPER(calc_cc)(CPUS390XState *env, uint32_t cc_op, uint64_t src, ++ uint64_t dst, uint64_t vr) + { + return do_calc_cc(env, cc_op, src, dst, vr); + } + + /* insert psw mask and condition code into r1 */ +-void HELPER(ipm)(uint32_t cc, uint32_t r1) ++void HELPER(ipm)(CPUS390XState *env, uint32_t cc, uint32_t r1) + { + uint64_t r = env->regs[r1]; + +@@ -519,13 +518,13 @@ void HELPER(ipm)(uint32_t cc, uint32_t r1) + } + + #ifndef CONFIG_USER_ONLY +-void HELPER(load_psw)(uint64_t mask, uint64_t addr) ++void HELPER(load_psw)(CPUS390XState *env, uint64_t mask, uint64_t addr) + { + load_psw(env, mask, addr); + cpu_loop_exit(env); + } + +-void HELPER(sacf)(uint64_t a1) ++void HELPER(sacf)(CPUS390XState *env, uint64_t a1) + { + HELPER_LOG("%s: %16" PRIx64 "\n", __func__, a1); + +diff --git a/target-s390x/helper.h b/target-s390x/helper.h +index c03cd59..876b88e 100644 +--- a/target-s390x/helper.h ++++ b/target-s390x/helper.h +@@ -36,7 +36,7 @@ DEF_HELPER_FLAGS_1(abs_i64, TCG_CALL_PURE|TCG_CALL_CONST, i64, s64) + DEF_HELPER_FLAGS_1(nabs_i64, TCG_CALL_PURE|TCG_CALL_CONST, s64, s64) + DEF_HELPER_3(stcmh, void, i32, i64, i32) + DEF_HELPER_3(icmh, i32, i32, i64, i32) +-DEF_HELPER_2(ipm, void, i32, i32) ++DEF_HELPER_3(ipm, void, env, i32, i32) + DEF_HELPER_FLAGS_3(addc_u32, TCG_CALL_PURE|TCG_CALL_CONST, i32, i32, i32, i32) + DEF_HELPER_FLAGS_3(set_cc_addc_u64, TCG_CALL_PURE|TCG_CALL_CONST, i32, i64, i64, i64) + DEF_HELPER_3(stam, void, i32, i64, i32) +@@ -115,7 +115,7 @@ DEF_HELPER_3(tr, void, i32, i64, i64) + + DEF_HELPER_2(servc, i32, i32, i64) + DEF_HELPER_3(diag, i64, i32, i64, i64) +-DEF_HELPER_2(load_psw, void, i64, i64) ++DEF_HELPER_3(load_psw, void, env, i64, i64) + DEF_HELPER_1(program_interrupt, void, i32) + DEF_HELPER_FLAGS_1(stidp, TCG_CALL_CONST, void, i64) + DEF_HELPER_FLAGS_1(spx, TCG_CALL_CONST, void, i64) +@@ -139,14 +139,14 @@ DEF_HELPER_2(csp, i32, i32, i32) + DEF_HELPER_3(mvcs, i32, i64, i64, i64) + DEF_HELPER_3(mvcp, i32, i64, i64, i64) + DEF_HELPER_3(sigp, i32, i64, i32, i64) +-DEF_HELPER_1(sacf, void, i64) ++DEF_HELPER_2(sacf, void, env, i64) + DEF_HELPER_FLAGS_2(ipte, TCG_CALL_CONST, void, i64, i64) + DEF_HELPER_FLAGS_0(ptlb, TCG_CALL_CONST, void) + DEF_HELPER_2(lra, i32, i64, i32) + DEF_HELPER_2(stura, void, i64, i32) + DEF_HELPER_2(cksm, void, i32, i32) + +-DEF_HELPER_FLAGS_4(calc_cc, TCG_CALL_PURE|TCG_CALL_CONST, +- i32, i32, i64, i64, i64) ++DEF_HELPER_FLAGS_5(calc_cc, TCG_CALL_PURE|TCG_CALL_CONST, ++ i32, env, i32, i64, i64, i64) + + #include "def-helper.h" +diff --git a/target-s390x/translate.c b/target-s390x/translate.c +index 2a61e92..1d87272 100644 +--- a/target-s390x/translate.c ++++ b/target-s390x/translate.c +@@ -722,7 +722,7 @@ static void gen_op_calc_cc(DisasContext *s) + case CC_OP_NZ_F32: + case CC_OP_NZ_F64: + /* 1 argument */ +- gen_helper_calc_cc(cc_op, local_cc_op, dummy, cc_dst, dummy); ++ gen_helper_calc_cc(cc_op, cpu_env, local_cc_op, dummy, cc_dst, dummy); + break; + case CC_OP_ICM: + case CC_OP_LTGT_32: +@@ -735,7 +735,7 @@ static void gen_op_calc_cc(DisasContext *s) + case CC_OP_LTGT_F64: + case CC_OP_SLAG: + /* 2 arguments */ +- gen_helper_calc_cc(cc_op, local_cc_op, cc_src, cc_dst, dummy); ++ gen_helper_calc_cc(cc_op, cpu_env, local_cc_op, cc_src, cc_dst, dummy); + break; + case CC_OP_ADD_64: + case CC_OP_ADDU_64: +@@ -746,11 +746,11 @@ static void gen_op_calc_cc(DisasContext *s) + case CC_OP_SUB_32: + case CC_OP_SUBU_32: + /* 3 arguments */ +- gen_helper_calc_cc(cc_op, local_cc_op, cc_src, cc_dst, cc_vr); ++ gen_helper_calc_cc(cc_op, cpu_env, local_cc_op, cc_src, cc_dst, cc_vr); + break; + case CC_OP_DYNAMIC: + /* unknown operation - assume 3 arguments and cc_op in env */ +- gen_helper_calc_cc(cc_op, cc_op, cc_src, cc_dst, cc_vr); ++ gen_helper_calc_cc(cc_op, cpu_env, cc_op, cc_src, cc_dst, cc_vr); + break; + default: + tcg_abort(); +@@ -2628,7 +2628,7 @@ static void disas_b2(DisasContext *s, int op, uint32_t insn) + case 0x22: /* IPM R1 [RRE] */ + tmp32_1 = tcg_const_i32(r1); + gen_op_calc_cc(s); +- gen_helper_ipm(cc_op, tmp32_1); ++ gen_helper_ipm(cpu_env, cc_op, tmp32_1); + tcg_temp_free_i32(tmp32_1); + break; + case 0x41: /* CKSM R1,R2 [RRE] */ +@@ -2916,7 +2916,7 @@ static void disas_b2(DisasContext *s, int op, uint32_t insn) + decode_rs(s, insn, &r1, &r3, &b2, &d2); + tmp = get_address(s, 0, b2, d2); + potential_page_fault(s); +- gen_helper_sacf(tmp); ++ gen_helper_sacf(cpu_env, tmp); + tcg_temp_free_i64(tmp); + /* addressing mode has changed, so end the block */ + s->pc += ilc * 2; +@@ -2967,7 +2967,7 @@ static void disas_b2(DisasContext *s, int op, uint32_t insn) + tcg_gen_qemu_ld64(tmp2, tmp, get_mem_index(s)); + tcg_gen_addi_i64(tmp, tmp, 8); + tcg_gen_qemu_ld64(tmp3, tmp, get_mem_index(s)); +- gen_helper_load_psw(tmp2, tmp3); ++ gen_helper_load_psw(cpu_env, tmp2, tmp3); + /* we need to keep cc_op intact */ + s->is_jmp = DISAS_JUMP; + tcg_temp_free_i64(tmp); +@@ -4527,7 +4527,7 @@ static void disas_s390_insn(DisasContext *s) + tcg_gen_qemu_ld32u(tmp2, tmp, get_mem_index(s)); + tcg_gen_addi_i64(tmp, tmp, 4); + tcg_gen_qemu_ld32u(tmp3, tmp, get_mem_index(s)); +- gen_helper_load_psw(tmp2, tmp3); ++ gen_helper_load_psw(cpu_env, tmp2, tmp3); + tcg_temp_free_i64(tmp); + tcg_temp_free_i64(tmp2); + tcg_temp_free_i64(tmp3); +-- +1.7.12.1 + diff --git a/0014-target-s390x-avoid-AREG0-for-misc-helpers.patch b/0014-target-s390x-avoid-AREG0-for-misc-helpers.patch new file mode 100644 index 0000000..11ff8fb --- /dev/null +++ b/0014-target-s390x-avoid-AREG0-for-misc-helpers.patch @@ -0,0 +1,411 @@ +From 208547c7afbe6ee8a9a1f81095e67a6cbe4a37ec Mon Sep 17 00:00:00 2001 +From: Blue Swirl +Date: Sun, 2 Sep 2012 07:33:39 +0000 +Subject: [PATCH] target-s390x: avoid AREG0 for misc helpers + +Make misc helpers take a parameter for CPUState instead +of relying on global env. + +Signed-off-by: Blue Swirl +[agraf: fix conflict] +Signed-off-by: Alexander Graf + +Signed-off-by: Michael Roth +--- + target-s390x/Makefile.objs | 1 - + target-s390x/helper.h | 26 +++++++++++----------- + target-s390x/mem_helper.c | 2 +- + target-s390x/misc_helper.c | 55 +++++++++++++++++++++++++--------------------- + target-s390x/translate.c | 32 +++++++++++++-------------- + 5 files changed, 60 insertions(+), 56 deletions(-) + +diff --git a/target-s390x/Makefile.objs b/target-s390x/Makefile.objs +index 736cf33..156d946 100644 +--- a/target-s390x/Makefile.objs ++++ b/target-s390x/Makefile.objs +@@ -4,4 +4,3 @@ obj-$(CONFIG_SOFTMMU) += machine.o + obj-$(CONFIG_KVM) += kvm.o + + $(obj)/mem_helper.o: QEMU_CFLAGS += $(HELPER_CFLAGS) +-$(obj)/misc_helper.o: QEMU_CFLAGS += $(HELPER_CFLAGS) +diff --git a/target-s390x/helper.h b/target-s390x/helper.h +index 876b88e..f4e0b37 100644 +--- a/target-s390x/helper.h ++++ b/target-s390x/helper.h +@@ -1,6 +1,6 @@ + #include "def-helper.h" + +-DEF_HELPER_1(exception, void, i32) ++DEF_HELPER_2(exception, void, env, i32) + DEF_HELPER_3(nc, i32, i32, i64, i64) + DEF_HELPER_3(oc, i32, i32, i64, i64) + DEF_HELPER_3(xc, i32, i32, i64, i64) +@@ -113,20 +113,20 @@ DEF_HELPER_FLAGS_1(cvd, TCG_CALL_PURE|TCG_CALL_CONST, i64, s32) + DEF_HELPER_3(unpk, void, i32, i64, i64) + DEF_HELPER_3(tr, void, i32, i64, i64) + +-DEF_HELPER_2(servc, i32, i32, i64) +-DEF_HELPER_3(diag, i64, i32, i64, i64) ++DEF_HELPER_3(servc, i32, env, i32, i64) ++DEF_HELPER_4(diag, i64, env, i32, i64, i64) + DEF_HELPER_3(load_psw, void, env, i64, i64) + DEF_HELPER_1(program_interrupt, void, i32) +-DEF_HELPER_FLAGS_1(stidp, TCG_CALL_CONST, void, i64) +-DEF_HELPER_FLAGS_1(spx, TCG_CALL_CONST, void, i64) ++DEF_HELPER_FLAGS_2(stidp, TCG_CALL_CONST, void, env, i64) ++DEF_HELPER_FLAGS_2(spx, TCG_CALL_CONST, void, env, i64) + DEF_HELPER_FLAGS_1(sck, TCG_CALL_CONST, i32, i64) +-DEF_HELPER_1(stck, i32, i64) +-DEF_HELPER_1(stcke, i32, i64) +-DEF_HELPER_FLAGS_1(sckc, TCG_CALL_CONST, void, i64) +-DEF_HELPER_FLAGS_1(stckc, TCG_CALL_CONST, void, i64) +-DEF_HELPER_FLAGS_1(spt, TCG_CALL_CONST, void, i64) +-DEF_HELPER_FLAGS_1(stpt, TCG_CALL_CONST, void, i64) +-DEF_HELPER_3(stsi, i32, i64, i32, i32) ++DEF_HELPER_2(stck, i32, env, i64) ++DEF_HELPER_2(stcke, i32, env, i64) ++DEF_HELPER_FLAGS_2(sckc, TCG_CALL_CONST, void, env, i64) ++DEF_HELPER_FLAGS_2(stckc, TCG_CALL_CONST, void, env, i64) ++DEF_HELPER_FLAGS_2(spt, TCG_CALL_CONST, void, env, i64) ++DEF_HELPER_FLAGS_2(stpt, TCG_CALL_CONST, void, env, i64) ++DEF_HELPER_4(stsi, i32, env, i64, i32, i32) + DEF_HELPER_3(lctl, void, i32, i64, i32) + DEF_HELPER_3(lctlg, void, i32, i64, i32) + DEF_HELPER_3(stctl, void, i32, i64, i32) +@@ -138,7 +138,7 @@ DEF_HELPER_FLAGS_2(rrbe, TCG_CALL_CONST, i32, i32, i64) + DEF_HELPER_2(csp, i32, i32, i32) + DEF_HELPER_3(mvcs, i32, i64, i64, i64) + DEF_HELPER_3(mvcp, i32, i64, i64, i64) +-DEF_HELPER_3(sigp, i32, i64, i32, i64) ++DEF_HELPER_4(sigp, i32, env, i64, i32, i64) + DEF_HELPER_2(sacf, void, env, i64) + DEF_HELPER_FLAGS_2(ipte, TCG_CALL_CONST, void, i64, i64) + DEF_HELPER_FLAGS_0(ptlb, TCG_CALL_CONST, void) +diff --git a/target-s390x/mem_helper.c b/target-s390x/mem_helper.c +index 3f8b3ba..52f2602 100644 +--- a/target-s390x/mem_helper.c ++++ b/target-s390x/mem_helper.c +@@ -595,7 +595,7 @@ uint32_t HELPER(ex)(uint32_t cc, uint64_t v1, uint64_t addr, uint64_t ret) + env->psw.addr = ret - 4; + env->int_svc_code = (insn | v1) & 0xff; + env->int_svc_ilc = 4; +- helper_exception(EXCP_SVC); ++ helper_exception(env, EXCP_SVC); + } else if ((insn & 0xff00) == 0xbf00) { + uint32_t insn2, r1, r3, b2, d2; + +diff --git a/target-s390x/misc_helper.c b/target-s390x/misc_helper.c +index 1d5137f..ced26c6 100644 +--- a/target-s390x/misc_helper.c ++++ b/target-s390x/misc_helper.c +@@ -21,7 +21,6 @@ + #include "cpu.h" + #include "memory.h" + #include "cputlb.h" +-#include "dyngen-exec.h" + #include "host-utils.h" + #include "helper.h" + #include +@@ -32,7 +31,10 @@ + #endif + + #if !defined(CONFIG_USER_ONLY) ++/* temporarily disabled due to wrapper use */ ++#if 0 + #include "softmmu_exec.h" ++#endif + #include "sysemu.h" + #endif + +@@ -44,7 +46,7 @@ + #endif + + /* raise an exception */ +-void HELPER(exception)(uint32_t excp) ++void HELPER(exception)(CPUS390XState *env, uint32_t excp) + { + HELPER_LOG("%s: exception %d\n", __func__, excp); + env->exception_index = excp; +@@ -112,7 +114,7 @@ int sclp_service_call(CPUS390XState *env, uint32_t sccb, uint64_t code) + } + + /* SCLP service call */ +-uint32_t HELPER(servc)(uint32_t r1, uint64_t r2) ++uint32_t HELPER(servc)(CPUS390XState *env, uint32_t r1, uint64_t r2) + { + int r; + +@@ -125,7 +127,8 @@ uint32_t HELPER(servc)(uint32_t r1, uint64_t r2) + } + + /* DIAG */ +-uint64_t HELPER(diag)(uint32_t num, uint64_t mem, uint64_t code) ++uint64_t HELPER(diag)(CPUS390XState *env, uint32_t num, uint64_t mem, ++ uint64_t code) + { + uint64_t r; + +@@ -155,17 +158,17 @@ uint64_t HELPER(diag)(uint32_t num, uint64_t mem, uint64_t code) + } + + /* Store CPU ID */ +-void HELPER(stidp)(uint64_t a1) ++void HELPER(stidp)(CPUS390XState *env, uint64_t a1) + { +- stq(a1, env->cpu_num); ++ cpu_stq_data(env, a1, env->cpu_num); + } + + /* Set Prefix */ +-void HELPER(spx)(uint64_t a1) ++void HELPER(spx)(CPUS390XState *env, uint64_t a1) + { + uint32_t prefix; + +- prefix = ldl(a1); ++ prefix = cpu_ldl_data(env, a1); + env->psa = prefix & 0xfffff000; + qemu_log("prefix: %#x\n", prefix); + tlb_flush_page(env, 0); +@@ -191,31 +194,31 @@ static inline uint64_t clock_value(CPUS390XState *env) + } + + /* Store Clock */ +-uint32_t HELPER(stck)(uint64_t a1) ++uint32_t HELPER(stck)(CPUS390XState *env, uint64_t a1) + { +- stq(a1, clock_value(env)); ++ cpu_stq_data(env, a1, clock_value(env)); + + return 0; + } + + /* Store Clock Extended */ +-uint32_t HELPER(stcke)(uint64_t a1) ++uint32_t HELPER(stcke)(CPUS390XState *env, uint64_t a1) + { +- stb(a1, 0); ++ cpu_stb_data(env, a1, 0); + /* basically the same value as stck */ +- stq(a1 + 1, clock_value(env) | env->cpu_num); ++ cpu_stq_data(env, a1 + 1, clock_value(env) | env->cpu_num); + /* more fine grained than stck */ +- stq(a1 + 9, 0); ++ cpu_stq_data(env, a1 + 9, 0); + /* XXX programmable fields */ +- stw(a1 + 17, 0); ++ cpu_stw_data(env, a1 + 17, 0); + + return 0; + } + + /* Set Clock Comparator */ +-void HELPER(sckc)(uint64_t a1) ++void HELPER(sckc)(CPUS390XState *env, uint64_t a1) + { +- uint64_t time = ldq(a1); ++ uint64_t time = cpu_ldq_data(env, a1); + + if (time == -1ULL) { + return; +@@ -230,16 +233,16 @@ void HELPER(sckc)(uint64_t a1) + } + + /* Store Clock Comparator */ +-void HELPER(stckc)(uint64_t a1) ++void HELPER(stckc)(CPUS390XState *env, uint64_t a1) + { + /* XXX implement */ +- stq(a1, 0); ++ cpu_stq_data(env, a1, 0); + } + + /* Set CPU Timer */ +-void HELPER(spt)(uint64_t a1) ++void HELPER(spt)(CPUS390XState *env, uint64_t a1) + { +- uint64_t time = ldq(a1); ++ uint64_t time = cpu_ldq_data(env, a1); + + if (time == -1ULL) { + return; +@@ -252,14 +255,15 @@ void HELPER(spt)(uint64_t a1) + } + + /* Store CPU Timer */ +-void HELPER(stpt)(uint64_t a1) ++void HELPER(stpt)(CPUS390XState *env, uint64_t a1) + { + /* XXX implement */ +- stq(a1, 0); ++ cpu_stq_data(env, a1, 0); + } + + /* Store System Information */ +-uint32_t HELPER(stsi)(uint64_t a0, uint32_t r0, uint32_t r1) ++uint32_t HELPER(stsi)(CPUS390XState *env, uint64_t a0, uint32_t r0, ++ uint32_t r1) + { + int cc = 0; + int sel1, sel2; +@@ -384,7 +388,8 @@ uint32_t HELPER(stsi)(uint64_t a0, uint32_t r0, uint32_t r1) + return cc; + } + +-uint32_t HELPER(sigp)(uint64_t order_code, uint32_t r1, uint64_t cpu_addr) ++uint32_t HELPER(sigp)(CPUS390XState *env, uint64_t order_code, uint32_t r1, ++ uint64_t cpu_addr) + { + int cc = 0; + +diff --git a/target-s390x/translate.c b/target-s390x/translate.c +index 1d87272..0c61e63 100644 +--- a/target-s390x/translate.c ++++ b/target-s390x/translate.c +@@ -312,7 +312,7 @@ static inline void gen_debug(DisasContext *s) + TCGv_i32 tmp = tcg_const_i32(EXCP_DEBUG); + update_psw_addr(s); + gen_op_calc_cc(s); +- gen_helper_exception(tmp); ++ gen_helper_exception(cpu_env, tmp); + tcg_temp_free_i32(tmp); + s->is_jmp = DISAS_EXCP; + } +@@ -324,7 +324,7 @@ static void gen_illegal_opcode(DisasContext *s, int ilc) + TCGv_i32 tmp = tcg_const_i32(EXCP_SPEC); + update_psw_addr(s); + gen_op_calc_cc(s); +- gen_helper_exception(tmp); ++ gen_helper_exception(cpu_env, tmp); + tcg_temp_free_i32(tmp); + s->is_jmp = DISAS_EXCP; + } +@@ -377,7 +377,7 @@ static void gen_program_exception(DisasContext *s, int ilc, int code) + + /* trigger exception */ + tmp = tcg_const_i32(EXCP_PGM); +- gen_helper_exception(tmp); ++ gen_helper_exception(cpu_env, tmp); + tcg_temp_free_i32(tmp); + + /* end TB here */ +@@ -2712,7 +2712,7 @@ static void disas_b2(DisasContext *s, int op, uint32_t insn) + decode_rs(s, insn, &r1, &r3, &b2, &d2); + tmp = get_address(s, 0, b2, d2); + potential_page_fault(s); +- gen_helper_stidp(tmp); ++ gen_helper_stidp(cpu_env, tmp); + tcg_temp_free_i64(tmp); + break; + case 0x04: /* SCK D2(B2) [S] */ +@@ -2730,7 +2730,7 @@ static void disas_b2(DisasContext *s, int op, uint32_t insn) + decode_rs(s, insn, &r1, &r3, &b2, &d2); + tmp = get_address(s, 0, b2, d2); + potential_page_fault(s); +- gen_helper_stck(cc_op, tmp); ++ gen_helper_stck(cc_op, cpu_env, tmp); + set_cc_static(s); + tcg_temp_free_i64(tmp); + break; +@@ -2740,7 +2740,7 @@ static void disas_b2(DisasContext *s, int op, uint32_t insn) + decode_rs(s, insn, &r1, &r3, &b2, &d2); + tmp = get_address(s, 0, b2, d2); + potential_page_fault(s); +- gen_helper_sckc(tmp); ++ gen_helper_sckc(cpu_env, tmp); + tcg_temp_free_i64(tmp); + break; + case 0x07: /* STCKC D2(B2) [S] */ +@@ -2749,7 +2749,7 @@ static void disas_b2(DisasContext *s, int op, uint32_t insn) + decode_rs(s, insn, &r1, &r3, &b2, &d2); + tmp = get_address(s, 0, b2, d2); + potential_page_fault(s); +- gen_helper_stckc(tmp); ++ gen_helper_stckc(cpu_env, tmp); + tcg_temp_free_i64(tmp); + break; + case 0x08: /* SPT D2(B2) [S] */ +@@ -2758,7 +2758,7 @@ static void disas_b2(DisasContext *s, int op, uint32_t insn) + decode_rs(s, insn, &r1, &r3, &b2, &d2); + tmp = get_address(s, 0, b2, d2); + potential_page_fault(s); +- gen_helper_spt(tmp); ++ gen_helper_spt(cpu_env, tmp); + tcg_temp_free_i64(tmp); + break; + case 0x09: /* STPT D2(B2) [S] */ +@@ -2767,7 +2767,7 @@ static void disas_b2(DisasContext *s, int op, uint32_t insn) + decode_rs(s, insn, &r1, &r3, &b2, &d2); + tmp = get_address(s, 0, b2, d2); + potential_page_fault(s); +- gen_helper_stpt(tmp); ++ gen_helper_stpt(cpu_env, tmp); + tcg_temp_free_i64(tmp); + break; + case 0x0a: /* SPKA D2(B2) [S] */ +@@ -2793,7 +2793,7 @@ static void disas_b2(DisasContext *s, int op, uint32_t insn) + decode_rs(s, insn, &r1, &r3, &b2, &d2); + tmp = get_address(s, 0, b2, d2); + potential_page_fault(s); +- gen_helper_spx(tmp); ++ gen_helper_spx(cpu_env, tmp); + tcg_temp_free_i64(tmp); + break; + case 0x11: /* STPX D2(B2) [S] */ +@@ -2906,7 +2906,7 @@ static void disas_b2(DisasContext *s, int op, uint32_t insn) + decode_rs(s, insn, &r1, &r3, &b2, &d2); + tmp = get_address(s, 0, b2, d2); + potential_page_fault(s); +- gen_helper_stcke(cc_op, tmp); ++ gen_helper_stcke(cc_op, cpu_env, tmp); + set_cc_static(s); + tcg_temp_free_i64(tmp); + break; +@@ -2930,7 +2930,7 @@ static void disas_b2(DisasContext *s, int op, uint32_t insn) + tmp32_1 = load_reg32(0); + tmp32_2 = load_reg32(1); + potential_page_fault(s); +- gen_helper_stsi(cc_op, tmp, tmp32_1, tmp32_2); ++ gen_helper_stsi(cc_op, cpu_env, tmp, tmp32_1, tmp32_2); + set_cc_static(s); + tcg_temp_free_i64(tmp); + tcg_temp_free_i32(tmp32_1); +@@ -2980,7 +2980,7 @@ static void disas_b2(DisasContext *s, int op, uint32_t insn) + potential_page_fault(s); + tmp32_1 = load_reg32(r2); + tmp = load_reg(r1); +- gen_helper_servc(cc_op, tmp32_1, tmp); ++ gen_helper_servc(cc_op, cpu_env, tmp32_1, tmp); + set_cc_static(s); + tcg_temp_free_i32(tmp32_1); + tcg_temp_free_i64(tmp); +@@ -3926,7 +3926,7 @@ static void disas_s390_insn(DisasContext *s) + tmp32_3 = tcg_const_i32(EXCP_SVC); + tcg_gen_st_i32(tmp32_1, cpu_env, offsetof(CPUS390XState, int_svc_code)); + tcg_gen_st_i32(tmp32_2, cpu_env, offsetof(CPUS390XState, int_svc_ilc)); +- gen_helper_exception(tmp32_3); ++ gen_helper_exception(cpu_env, tmp32_3); + s->is_jmp = DISAS_EXCP; + tcg_temp_free_i32(tmp32_1); + tcg_temp_free_i32(tmp32_2); +@@ -4543,7 +4543,7 @@ static void disas_s390_insn(DisasContext *s) + tmp32_1 = tcg_const_i32(insn & 0xfff); + tmp2 = load_reg(2); + tmp3 = load_reg(1); +- gen_helper_diag(tmp2, tmp32_1, tmp2, tmp3); ++ gen_helper_diag(tmp2, cpu_env, tmp32_1, tmp2, tmp3); + store_reg(2, tmp2); + tcg_temp_free_i32(tmp32_1); + tcg_temp_free_i64(tmp2); +@@ -4777,7 +4777,7 @@ static void disas_s390_insn(DisasContext *s) + tmp2 = load_reg(r3); + tmp32_1 = tcg_const_i32(r1); + potential_page_fault(s); +- gen_helper_sigp(cc_op, tmp, tmp32_1, tmp2); ++ gen_helper_sigp(cc_op, cpu_env, tmp, tmp32_1, tmp2); + set_cc_static(s); + tcg_temp_free_i64(tmp); + tcg_temp_free_i64(tmp2); +-- +1.7.12.1 + diff --git a/0015-target-s390x-switch-to-AREG0-free-mode.patch b/0015-target-s390x-switch-to-AREG0-free-mode.patch new file mode 100644 index 0000000..2329cb2 --- /dev/null +++ b/0015-target-s390x-switch-to-AREG0-free-mode.patch @@ -0,0 +1,1584 @@ +From 77fb132a1dc3780a57d8a1e889b366f0492963a5 Mon Sep 17 00:00:00 2001 +From: Blue Swirl +Date: Sun, 2 Sep 2012 07:33:40 +0000 +Subject: [PATCH] target-s390x: switch to AREG0 free mode + +Add an explicit CPUState parameter instead of relying on AREG0. + +Remove temporary wrappers and switch to AREG0 free mode. + +Signed-off-by: Blue Swirl +[agraf: fix conflicts] +Signed-off-by: Alexander Graf + +Signed-off-by: Michael Roth +--- + configure | 2 +- + target-s390x/Makefile.objs | 2 - + target-s390x/cpu.h | 10 -- + target-s390x/fpu_helper.c | 3 +- + target-s390x/helper.c | 6 +- + target-s390x/helper.h | 78 +++++------ + target-s390x/mem_helper.c | 338 ++++++++++++++++++++------------------------- + target-s390x/misc_helper.c | 3 - + target-s390x/translate.c | 88 ++++++------ + 9 files changed, 239 insertions(+), 291 deletions(-) + +diff --git a/configure b/configure +index bf3acc8..3ad6f74 100755 +--- a/configure ++++ b/configure +@@ -3839,7 +3839,7 @@ symlink "$source_path/Makefile.target" "$target_dir/Makefile" + + + case "$target_arch2" in +- alpha | i386 | or32 | sparc* | x86_64 | xtensa* | ppc*) ++ alpha | i386 | or32 | s390x | sparc* | x86_64 | xtensa* | ppc*) + echo "CONFIG_TCG_PASS_AREG0=y" >> $config_target_mak + ;; + esac +diff --git a/target-s390x/Makefile.objs b/target-s390x/Makefile.objs +index 156d946..e728abf 100644 +--- a/target-s390x/Makefile.objs ++++ b/target-s390x/Makefile.objs +@@ -2,5 +2,3 @@ obj-y += translate.o helper.o cpu.o interrupt.o + obj-y += int_helper.o fpu_helper.o cc_helper.o mem_helper.o misc_helper.o + obj-$(CONFIG_SOFTMMU) += machine.o + obj-$(CONFIG_KVM) += kvm.o +- +-$(obj)/mem_helper.o: QEMU_CFLAGS += $(HELPER_CFLAGS) +diff --git a/target-s390x/cpu.h b/target-s390x/cpu.h +index 9b7a2e3..ed81af3 100644 +--- a/target-s390x/cpu.h ++++ b/target-s390x/cpu.h +@@ -1008,14 +1008,4 @@ uint32_t set_cc_nz_f64(float64 v); + /* misc_helper.c */ + void program_interrupt(CPUS390XState *env, uint32_t code, int ilc); + +-/* temporary wrappers */ +-uint32_t cpu_ldub_data(CPUS390XState *env, target_ulong ptr); +-uint32_t cpu_lduw_data(CPUS390XState *env, target_ulong ptr); +-uint32_t cpu_ldl_data(CPUS390XState *env, target_ulong ptr); +-uint64_t cpu_ldq_data(CPUS390XState *env, target_ulong ptr); +- +-void cpu_stb_data(CPUS390XState *env, target_ulong ptr, uint32_t data); +-void cpu_stw_data(CPUS390XState *env, target_ulong ptr, uint32_t data); +-void cpu_stl_data(CPUS390XState *env, target_ulong ptr, uint32_t data); +-void cpu_stq_data(CPUS390XState *env, target_ulong ptr, uint64_t data); + #endif +diff --git a/target-s390x/fpu_helper.c b/target-s390x/fpu_helper.c +index e235419..ee9420d 100644 +--- a/target-s390x/fpu_helper.c ++++ b/target-s390x/fpu_helper.c +@@ -21,8 +21,7 @@ + #include "cpu.h" + #include "helper.h" + +-/* temporarily disabled due to wrapper use */ +-#if 0 && !defined(CONFIG_USER_ONLY) ++#if !defined(CONFIG_USER_ONLY) + #include "softmmu_exec.h" + #endif + +diff --git a/target-s390x/helper.c b/target-s390x/helper.c +index d98e6d9..a5741ec 100644 +--- a/target-s390x/helper.c ++++ b/target-s390x/helper.c +@@ -499,14 +499,14 @@ static void do_program_interrupt(CPUS390XState *env) + + switch (ilc) { + case ILC_LATER: +- ilc = get_ilc(ldub_code(env->psw.addr)); ++ ilc = get_ilc(cpu_ldub_code(env, env->psw.addr)); + break; + case ILC_LATER_INC: +- ilc = get_ilc(ldub_code(env->psw.addr)); ++ ilc = get_ilc(cpu_ldub_code(env, env->psw.addr)); + env->psw.addr += ilc * 2; + break; + case ILC_LATER_INC_2: +- ilc = get_ilc(ldub_code(env->psw.addr)) * 2; ++ ilc = get_ilc(cpu_ldub_code(env, env->psw.addr)) * 2; + env->psw.addr += ilc; + break; + } +diff --git a/target-s390x/helper.h b/target-s390x/helper.h +index f4e0b37..5419f37 100644 +--- a/target-s390x/helper.h ++++ b/target-s390x/helper.h +@@ -1,17 +1,17 @@ + #include "def-helper.h" + + DEF_HELPER_2(exception, void, env, i32) +-DEF_HELPER_3(nc, i32, i32, i64, i64) +-DEF_HELPER_3(oc, i32, i32, i64, i64) +-DEF_HELPER_3(xc, i32, i32, i64, i64) +-DEF_HELPER_3(mvc, void, i32, i64, i64) +-DEF_HELPER_3(clc, i32, i32, i64, i64) +-DEF_HELPER_2(mvcl, i32, i32, i32) ++DEF_HELPER_4(nc, i32, env, i32, i64, i64) ++DEF_HELPER_4(oc, i32, env, i32, i64, i64) ++DEF_HELPER_4(xc, i32, env, i32, i64, i64) ++DEF_HELPER_4(mvc, void, env, i32, i64, i64) ++DEF_HELPER_4(clc, i32, env, i32, i64, i64) ++DEF_HELPER_3(mvcl, i32, env, i32, i32) + DEF_HELPER_FLAGS_1(set_cc_comp_s32, TCG_CALL_PURE|TCG_CALL_CONST, i32, s32) + DEF_HELPER_FLAGS_1(set_cc_comp_s64, TCG_CALL_PURE|TCG_CALL_CONST, i32, s64) + DEF_HELPER_FLAGS_2(set_cc_icm, TCG_CALL_PURE|TCG_CALL_CONST, i32, i32, i32) +-DEF_HELPER_3(clm, i32, i32, i32, i64) +-DEF_HELPER_3(stcm, void, i32, i32, i64) ++DEF_HELPER_4(clm, i32, env, i32, i32, i64) ++DEF_HELPER_4(stcm, void, env, i32, i32, i64) + DEF_HELPER_3(mlg, void, env, i32, i64) + DEF_HELPER_3(dlg, void, env, i32, i64) + DEF_HELPER_FLAGS_3(set_cc_add64, TCG_CALL_PURE|TCG_CALL_CONST, i32, s64, s64, s64) +@@ -22,27 +22,27 @@ DEF_HELPER_FLAGS_3(set_cc_sub64, TCG_CALL_PURE|TCG_CALL_CONST, i32, s64, s64, s6 + DEF_HELPER_FLAGS_3(set_cc_subu64, TCG_CALL_PURE|TCG_CALL_CONST, i32, i64, i64, i64) + DEF_HELPER_FLAGS_3(set_cc_sub32, TCG_CALL_PURE|TCG_CALL_CONST, i32, s32, s32, s32) + DEF_HELPER_FLAGS_3(set_cc_subu32, TCG_CALL_PURE|TCG_CALL_CONST, i32, i32, i32, i32) +-DEF_HELPER_3(srst, i32, i32, i32, i32) +-DEF_HELPER_3(clst, i32, i32, i32, i32) +-DEF_HELPER_3(mvpg, void, i64, i64, i64) +-DEF_HELPER_3(mvst, void, i32, i32, i32) +-DEF_HELPER_3(csg, i32, i32, i64, i32) +-DEF_HELPER_3(cdsg, i32, i32, i64, i32) +-DEF_HELPER_3(cs, i32, i32, i64, i32) +-DEF_HELPER_4(ex, i32, i32, i64, i64, i64) ++DEF_HELPER_4(srst, i32, env, i32, i32, i32) ++DEF_HELPER_4(clst, i32, env, i32, i32, i32) ++DEF_HELPER_4(mvpg, void, env, i64, i64, i64) ++DEF_HELPER_4(mvst, void, env, i32, i32, i32) ++DEF_HELPER_4(csg, i32, env, i32, i64, i32) ++DEF_HELPER_4(cdsg, i32, env, i32, i64, i32) ++DEF_HELPER_4(cs, i32, env, i32, i64, i32) ++DEF_HELPER_5(ex, i32, env, i32, i64, i64, i64) + DEF_HELPER_FLAGS_1(abs_i32, TCG_CALL_PURE|TCG_CALL_CONST, i32, s32) + DEF_HELPER_FLAGS_1(nabs_i32, TCG_CALL_PURE|TCG_CALL_CONST, s32, s32) + DEF_HELPER_FLAGS_1(abs_i64, TCG_CALL_PURE|TCG_CALL_CONST, i64, s64) + DEF_HELPER_FLAGS_1(nabs_i64, TCG_CALL_PURE|TCG_CALL_CONST, s64, s64) +-DEF_HELPER_3(stcmh, void, i32, i64, i32) +-DEF_HELPER_3(icmh, i32, i32, i64, i32) ++DEF_HELPER_4(stcmh, void, env, i32, i64, i32) ++DEF_HELPER_4(icmh, i32, env, i32, i64, i32) + DEF_HELPER_3(ipm, void, env, i32, i32) + DEF_HELPER_FLAGS_3(addc_u32, TCG_CALL_PURE|TCG_CALL_CONST, i32, i32, i32, i32) + DEF_HELPER_FLAGS_3(set_cc_addc_u64, TCG_CALL_PURE|TCG_CALL_CONST, i32, i64, i64, i64) +-DEF_HELPER_3(stam, void, i32, i64, i32) +-DEF_HELPER_3(lam, void, i32, i64, i32) +-DEF_HELPER_3(mvcle, i32, i32, i64, i32) +-DEF_HELPER_3(clcle, i32, i32, i64, i32) ++DEF_HELPER_4(stam, void, env, i32, i64, i32) ++DEF_HELPER_4(lam, void, env, i32, i64, i32) ++DEF_HELPER_4(mvcle, i32, env, i32, i64, i32) ++DEF_HELPER_4(clcle, i32, env, i32, i64, i32) + DEF_HELPER_4(slb, i32, env, i32, i32, i32) + DEF_HELPER_5(slbg, i32, env, i32, i32, i64, i64) + DEF_HELPER_3(cefbr, void, env, i32, s32) +@@ -110,8 +110,8 @@ DEF_HELPER_FLAGS_3(tcxb, TCG_CALL_PURE, i32, env, i32, i64) + DEF_HELPER_3(flogr, i32, env, i32, i64) + DEF_HELPER_3(sqdbr, void, env, i32, i32) + DEF_HELPER_FLAGS_1(cvd, TCG_CALL_PURE|TCG_CALL_CONST, i64, s32) +-DEF_HELPER_3(unpk, void, i32, i64, i64) +-DEF_HELPER_3(tr, void, i32, i64, i64) ++DEF_HELPER_4(unpk, void, env, i32, i64, i64) ++DEF_HELPER_4(tr, void, env, i32, i64, i64) + + DEF_HELPER_3(servc, i32, env, i32, i64) + DEF_HELPER_4(diag, i64, env, i32, i64, i64) +@@ -127,24 +127,24 @@ DEF_HELPER_FLAGS_2(stckc, TCG_CALL_CONST, void, env, i64) + DEF_HELPER_FLAGS_2(spt, TCG_CALL_CONST, void, env, i64) + DEF_HELPER_FLAGS_2(stpt, TCG_CALL_CONST, void, env, i64) + DEF_HELPER_4(stsi, i32, env, i64, i32, i32) +-DEF_HELPER_3(lctl, void, i32, i64, i32) +-DEF_HELPER_3(lctlg, void, i32, i64, i32) +-DEF_HELPER_3(stctl, void, i32, i64, i32) +-DEF_HELPER_3(stctg, void, i32, i64, i32) ++DEF_HELPER_4(lctl, void, env, i32, i64, i32) ++DEF_HELPER_4(lctlg, void, env, i32, i64, i32) ++DEF_HELPER_4(stctl, void, env, i32, i64, i32) ++DEF_HELPER_4(stctg, void, env, i32, i64, i32) + DEF_HELPER_FLAGS_2(tprot, TCG_CALL_CONST, i32, i64, i64) +-DEF_HELPER_FLAGS_1(iske, TCG_CALL_PURE|TCG_CALL_CONST, i64, i64) +-DEF_HELPER_FLAGS_2(sske, TCG_CALL_CONST, void, i32, i64) +-DEF_HELPER_FLAGS_2(rrbe, TCG_CALL_CONST, i32, i32, i64) +-DEF_HELPER_2(csp, i32, i32, i32) +-DEF_HELPER_3(mvcs, i32, i64, i64, i64) +-DEF_HELPER_3(mvcp, i32, i64, i64, i64) ++DEF_HELPER_FLAGS_2(iske, TCG_CALL_PURE|TCG_CALL_CONST, i64, env, i64) ++DEF_HELPER_FLAGS_3(sske, TCG_CALL_CONST, void, env, i32, i64) ++DEF_HELPER_FLAGS_3(rrbe, TCG_CALL_CONST, i32, env, i32, i64) ++DEF_HELPER_3(csp, i32, env, i32, i32) ++DEF_HELPER_4(mvcs, i32, env, i64, i64, i64) ++DEF_HELPER_4(mvcp, i32, env, i64, i64, i64) + DEF_HELPER_4(sigp, i32, env, i64, i32, i64) + DEF_HELPER_2(sacf, void, env, i64) +-DEF_HELPER_FLAGS_2(ipte, TCG_CALL_CONST, void, i64, i64) +-DEF_HELPER_FLAGS_0(ptlb, TCG_CALL_CONST, void) +-DEF_HELPER_2(lra, i32, i64, i32) +-DEF_HELPER_2(stura, void, i64, i32) +-DEF_HELPER_2(cksm, void, i32, i32) ++DEF_HELPER_FLAGS_3(ipte, TCG_CALL_CONST, void, env, i64, i64) ++DEF_HELPER_FLAGS_1(ptlb, TCG_CALL_CONST, void, env) ++DEF_HELPER_3(lra, i32, env, i64, i32) ++DEF_HELPER_3(stura, void, env, i64, i32) ++DEF_HELPER_3(cksm, void, env, i32, i32) + + DEF_HELPER_FLAGS_5(calc_cc, TCG_CALL_PURE|TCG_CALL_CONST, + i32, env, i32, i64, i64, i64) +diff --git a/target-s390x/mem_helper.c b/target-s390x/mem_helper.c +index 52f2602..b21b37c 100644 +--- a/target-s390x/mem_helper.c ++++ b/target-s390x/mem_helper.c +@@ -19,7 +19,6 @@ + */ + + #include "cpu.h" +-#include "dyngen-exec.h" + #include "helper.h" + + /*****************************************************************************/ +@@ -45,15 +44,12 @@ + NULL, it means that the function was called in C code (i.e. not + from generated code or from helper.c) */ + /* XXX: fix it to restore all registers */ +-void tlb_fill(CPUS390XState *env1, target_ulong addr, int is_write, int mmu_idx, ++void tlb_fill(CPUS390XState *env, target_ulong addr, int is_write, int mmu_idx, + uintptr_t retaddr) + { + TranslationBlock *tb; +- CPUS390XState *saved_env; + int ret; + +- saved_env = env; +- env = env1; + ret = cpu_s390x_handle_mmu_fault(env, addr, is_write, mmu_idx); + if (unlikely(ret != 0)) { + if (likely(retaddr)) { +@@ -67,7 +63,6 @@ void tlb_fill(CPUS390XState *env1, target_ulong addr, int is_write, int mmu_idx, + } + cpu_loop_exit(env); + } +- env = saved_env; + } + + #endif +@@ -90,7 +85,7 @@ static void mvc_fast_memset(CPUS390XState *env, uint32_t l, uint64_t dest, + int flags; + + if (mmu_translate(env, dest, 1, asc, &dest_phys, &flags)) { +- stb(dest, byte); ++ cpu_stb_data(env, dest, byte); + cpu_abort(env, "should never reach here"); + } + dest_phys |= dest & ~TARGET_PAGE_MASK; +@@ -114,13 +109,13 @@ static void mvc_fast_memmove(CPUS390XState *env, uint32_t l, uint64_t dest, + int flags; + + if (mmu_translate(env, dest, 1, asc, &dest_phys, &flags)) { +- stb(dest, 0); ++ cpu_stb_data(env, dest, 0); + cpu_abort(env, "should never reach here"); + } + dest_phys |= dest & ~TARGET_PAGE_MASK; + + if (mmu_translate(env, src, 0, asc, &src_phys, &flags)) { +- ldub(src); ++ cpu_ldub_data(env, src); + cpu_abort(env, "should never reach here"); + } + src_phys |= src & ~TARGET_PAGE_MASK; +@@ -136,7 +131,8 @@ static void mvc_fast_memmove(CPUS390XState *env, uint32_t l, uint64_t dest, + #endif + + /* and on array */ +-uint32_t HELPER(nc)(uint32_t l, uint64_t dest, uint64_t src) ++uint32_t HELPER(nc)(CPUS390XState *env, uint32_t l, uint64_t dest, ++ uint64_t src) + { + int i; + unsigned char x; +@@ -145,17 +141,18 @@ uint32_t HELPER(nc)(uint32_t l, uint64_t dest, uint64_t src) + HELPER_LOG("%s l %d dest %" PRIx64 " src %" PRIx64 "\n", + __func__, l, dest, src); + for (i = 0; i <= l; i++) { +- x = ldub(dest + i) & ldub(src + i); ++ x = cpu_ldub_data(env, dest + i) & cpu_ldub_data(env, src + i); + if (x) { + cc = 1; + } +- stb(dest + i, x); ++ cpu_stb_data(env, dest + i, x); + } + return cc; + } + + /* xor on array */ +-uint32_t HELPER(xc)(uint32_t l, uint64_t dest, uint64_t src) ++uint32_t HELPER(xc)(CPUS390XState *env, uint32_t l, uint64_t dest, ++ uint64_t src) + { + int i; + unsigned char x; +@@ -179,17 +176,18 @@ uint32_t HELPER(xc)(uint32_t l, uint64_t dest, uint64_t src) + #endif + + for (i = 0; i <= l; i++) { +- x = ldub(dest + i) ^ ldub(src + i); ++ x = cpu_ldub_data(env, dest + i) ^ cpu_ldub_data(env, src + i); + if (x) { + cc = 1; + } +- stb(dest + i, x); ++ cpu_stb_data(env, dest + i, x); + } + return cc; + } + + /* or on array */ +-uint32_t HELPER(oc)(uint32_t l, uint64_t dest, uint64_t src) ++uint32_t HELPER(oc)(CPUS390XState *env, uint32_t l, uint64_t dest, ++ uint64_t src) + { + int i; + unsigned char x; +@@ -198,17 +196,17 @@ uint32_t HELPER(oc)(uint32_t l, uint64_t dest, uint64_t src) + HELPER_LOG("%s l %d dest %" PRIx64 " src %" PRIx64 "\n", + __func__, l, dest, src); + for (i = 0; i <= l; i++) { +- x = ldub(dest + i) | ldub(src + i); ++ x = cpu_ldub_data(env, dest + i) | cpu_ldub_data(env, src + i); + if (x) { + cc = 1; + } +- stb(dest + i, x); ++ cpu_stb_data(env, dest + i, x); + } + return cc; + } + + /* memmove */ +-void HELPER(mvc)(uint32_t l, uint64_t dest, uint64_t src) ++void HELPER(mvc)(CPUS390XState *env, uint32_t l, uint64_t dest, uint64_t src) + { + int i = 0; + int x = 0; +@@ -222,7 +220,7 @@ void HELPER(mvc)(uint32_t l, uint64_t dest, uint64_t src) + (src & TARGET_PAGE_MASK) == ((src + l) & TARGET_PAGE_MASK) && + (dest & TARGET_PAGE_MASK) == ((dest + l) & TARGET_PAGE_MASK)) { + if (dest == (src + 1)) { +- mvc_fast_memset(env, l + 1, dest, ldub(src)); ++ mvc_fast_memset(env, l + 1, dest, cpu_ldub_data(env, src)); + return; + } else if ((src & TARGET_PAGE_MASK) != (dest & TARGET_PAGE_MASK)) { + mvc_fast_memmove(env, l + 1, dest, src); +@@ -231,7 +229,7 @@ void HELPER(mvc)(uint32_t l, uint64_t dest, uint64_t src) + } + #else + if (dest == (src + 1)) { +- memset(g2h(dest), ldub(src), l + 1); ++ memset(g2h(dest), cpu_ldub_data(env, src), l + 1); + return; + } else { + memmove(g2h(dest), g2h(src), l + 1); +@@ -242,19 +240,19 @@ void HELPER(mvc)(uint32_t l, uint64_t dest, uint64_t src) + /* handle the parts that fit into 8-byte loads/stores */ + if (dest != (src + 1)) { + for (i = 0; i < l_64; i++) { +- stq(dest + x, ldq(src + x)); ++ cpu_stq_data(env, dest + x, cpu_ldq_data(env, src + x)); + x += 8; + } + } + + /* slow version crossing pages with byte accesses */ + for (i = x; i <= l; i++) { +- stb(dest + i, ldub(src + i)); ++ cpu_stb_data(env, dest + i, cpu_ldub_data(env, src + i)); + } + } + + /* compare unsigned byte arrays */ +-uint32_t HELPER(clc)(uint32_t l, uint64_t s1, uint64_t s2) ++uint32_t HELPER(clc)(CPUS390XState *env, uint32_t l, uint64_t s1, uint64_t s2) + { + int i; + unsigned char x, y; +@@ -263,8 +261,8 @@ uint32_t HELPER(clc)(uint32_t l, uint64_t s1, uint64_t s2) + HELPER_LOG("%s l %d s1 %" PRIx64 " s2 %" PRIx64 "\n", + __func__, l, s1, s2); + for (i = 0; i <= l; i++) { +- x = ldub(s1 + i); +- y = ldub(s2 + i); ++ x = cpu_ldub_data(env, s1 + i); ++ y = cpu_ldub_data(env, s2 + i); + HELPER_LOG("%02x (%c)/%02x (%c) ", x, x, y, y); + if (x < y) { + cc = 1; +@@ -281,7 +279,8 @@ uint32_t HELPER(clc)(uint32_t l, uint64_t s1, uint64_t s2) + } + + /* compare logical under mask */ +-uint32_t HELPER(clm)(uint32_t r1, uint32_t mask, uint64_t addr) ++uint32_t HELPER(clm)(CPUS390XState *env, uint32_t r1, uint32_t mask, ++ uint64_t addr) + { + uint8_t r, d; + uint32_t cc; +@@ -291,7 +290,7 @@ uint32_t HELPER(clm)(uint32_t r1, uint32_t mask, uint64_t addr) + cc = 0; + while (mask) { + if (mask & 8) { +- d = ldub(addr); ++ d = cpu_ldub_data(env, addr); + r = (r1 & 0xff000000UL) >> 24; + HELPER_LOG("mask 0x%x %02x/%02x (0x%" PRIx64 ") ", mask, r, d, + addr); +@@ -312,7 +311,8 @@ uint32_t HELPER(clm)(uint32_t r1, uint32_t mask, uint64_t addr) + } + + /* store character under mask */ +-void HELPER(stcm)(uint32_t r1, uint32_t mask, uint64_t addr) ++void HELPER(stcm)(CPUS390XState *env, uint32_t r1, uint32_t mask, ++ uint64_t addr) + { + uint8_t r; + +@@ -321,7 +321,7 @@ void HELPER(stcm)(uint32_t r1, uint32_t mask, uint64_t addr) + while (mask) { + if (mask & 8) { + r = (r1 & 0xff000000UL) >> 24; +- stb(addr, r); ++ cpu_stb_data(env, addr, r); + HELPER_LOG("mask 0x%x %02x (0x%lx) ", mask, r, addr); + addr++; + } +@@ -331,7 +331,7 @@ void HELPER(stcm)(uint32_t r1, uint32_t mask, uint64_t addr) + HELPER_LOG("\n"); + } + +-static inline uint64_t get_address(int x2, int b2, int d2) ++static inline uint64_t get_address(CPUS390XState *env, int x2, int b2, int d2) + { + uint64_t r = d2; + +@@ -351,7 +351,7 @@ static inline uint64_t get_address(int x2, int b2, int d2) + return r; + } + +-static inline uint64_t get_address_31fix(int reg) ++static inline uint64_t get_address_31fix(CPUS390XState *env, int reg) + { + uint64_t r = env->regs[reg]; + +@@ -364,18 +364,18 @@ static inline uint64_t get_address_31fix(int reg) + } + + /* search string (c is byte to search, r2 is string, r1 end of string) */ +-uint32_t HELPER(srst)(uint32_t c, uint32_t r1, uint32_t r2) ++uint32_t HELPER(srst)(CPUS390XState *env, uint32_t c, uint32_t r1, uint32_t r2) + { + uint64_t i; + uint32_t cc = 2; +- uint64_t str = get_address_31fix(r2); +- uint64_t end = get_address_31fix(r1); ++ uint64_t str = get_address_31fix(env, r2); ++ uint64_t end = get_address_31fix(env, r1); + + HELPER_LOG("%s: c %d *r1 0x%" PRIx64 " *r2 0x%" PRIx64 "\n", __func__, + c, env->regs[r1], env->regs[r2]); + + for (i = str; i != end; i++) { +- if (ldub(i) == c) { ++ if (cpu_ldub_data(env, i) == c) { + env->regs[r1] = i; + cc = 1; + break; +@@ -386,10 +386,10 @@ uint32_t HELPER(srst)(uint32_t c, uint32_t r1, uint32_t r2) + } + + /* unsigned string compare (c is string terminator) */ +-uint32_t HELPER(clst)(uint32_t c, uint32_t r1, uint32_t r2) ++uint32_t HELPER(clst)(CPUS390XState *env, uint32_t c, uint32_t r1, uint32_t r2) + { +- uint64_t s1 = get_address_31fix(r1); +- uint64_t s2 = get_address_31fix(r2); ++ uint64_t s1 = get_address_31fix(env, r1); ++ uint64_t s2 = get_address_31fix(env, r2); + uint8_t v1, v2; + uint32_t cc; + +@@ -401,8 +401,8 @@ uint32_t HELPER(clst)(uint32_t c, uint32_t r1, uint32_t r2) + } + #endif + for (;;) { +- v1 = ldub(s1); +- v2 = ldub(s2); ++ v1 = cpu_ldub_data(env, s1); ++ v2 = cpu_ldub_data(env, s2); + if ((v1 == c || v2 == c) || (v1 != v2)) { + break; + } +@@ -422,14 +422,14 @@ uint32_t HELPER(clst)(uint32_t c, uint32_t r1, uint32_t r2) + } + + /* move page */ +-void HELPER(mvpg)(uint64_t r0, uint64_t r1, uint64_t r2) ++void HELPER(mvpg)(CPUS390XState *env, uint64_t r0, uint64_t r1, uint64_t r2) + { + /* XXX missing r0 handling */ + #ifdef CONFIG_USER_ONLY + int i; + + for (i = 0; i < TARGET_PAGE_SIZE; i++) { +- stb(r1 + i, ldub(r2 + i)); ++ cpu_stb_data(env, r1 + i, cpu_ldub_data(env, r2 + i)); + } + #else + mvc_fast_memmove(env, TARGET_PAGE_SIZE, r1, r2); +@@ -437,10 +437,10 @@ void HELPER(mvpg)(uint64_t r0, uint64_t r1, uint64_t r2) + } + + /* string copy (c is string terminator) */ +-void HELPER(mvst)(uint32_t c, uint32_t r1, uint32_t r2) ++void HELPER(mvst)(CPUS390XState *env, uint32_t c, uint32_t r1, uint32_t r2) + { +- uint64_t dest = get_address_31fix(r1); +- uint64_t src = get_address_31fix(r2); ++ uint64_t dest = get_address_31fix(env, r1); ++ uint64_t src = get_address_31fix(env, r2); + uint8_t v; + + c = c & 0xff; +@@ -451,8 +451,8 @@ void HELPER(mvst)(uint32_t c, uint32_t r1, uint32_t r2) + } + #endif + for (;;) { +- v = ldub(src); +- stb(dest, v); ++ v = cpu_ldub_data(env, src); ++ cpu_stb_data(env, dest, v); + if (v == c) { + break; + } +@@ -463,15 +463,15 @@ void HELPER(mvst)(uint32_t c, uint32_t r1, uint32_t r2) + } + + /* compare and swap 64-bit */ +-uint32_t HELPER(csg)(uint32_t r1, uint64_t a2, uint32_t r3) ++uint32_t HELPER(csg)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint32_t r3) + { + /* FIXME: locking? */ + uint32_t cc; +- uint64_t v2 = ldq(a2); ++ uint64_t v2 = cpu_ldq_data(env, a2); + + if (env->regs[r1] == v2) { + cc = 0; +- stq(a2, env->regs[r3]); ++ cpu_stq_data(env, a2, env->regs[r3]); + } else { + cc = 1; + env->regs[r1] = v2; +@@ -480,19 +480,19 @@ uint32_t HELPER(csg)(uint32_t r1, uint64_t a2, uint32_t r3) + } + + /* compare double and swap 64-bit */ +-uint32_t HELPER(cdsg)(uint32_t r1, uint64_t a2, uint32_t r3) ++uint32_t HELPER(cdsg)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint32_t r3) + { + /* FIXME: locking? */ + uint32_t cc; +- uint64_t v2_hi = ldq(a2); +- uint64_t v2_lo = ldq(a2 + 8); ++ uint64_t v2_hi = cpu_ldq_data(env, a2); ++ uint64_t v2_lo = cpu_ldq_data(env, a2 + 8); + uint64_t v1_hi = env->regs[r1]; + uint64_t v1_lo = env->regs[r1 + 1]; + + if ((v1_hi == v2_hi) && (v1_lo == v2_lo)) { + cc = 0; +- stq(a2, env->regs[r3]); +- stq(a2 + 8, env->regs[r3 + 1]); ++ cpu_stq_data(env, a2, env->regs[r3]); ++ cpu_stq_data(env, a2 + 8, env->regs[r3 + 1]); + } else { + cc = 1; + env->regs[r1] = v2_hi; +@@ -503,16 +503,16 @@ uint32_t HELPER(cdsg)(uint32_t r1, uint64_t a2, uint32_t r3) + } + + /* compare and swap 32-bit */ +-uint32_t HELPER(cs)(uint32_t r1, uint64_t a2, uint32_t r3) ++uint32_t HELPER(cs)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint32_t r3) + { + /* FIXME: locking? */ + uint32_t cc; +- uint32_t v2 = ldl(a2); ++ uint32_t v2 = cpu_ldl_data(env, a2); + + HELPER_LOG("%s: r1 %d a2 0x%lx r3 %d\n", __func__, r1, a2, r3); + if (((uint32_t)env->regs[r1]) == v2) { + cc = 0; +- stl(a2, (uint32_t)env->regs[r3]); ++ cpu_stl_data(env, a2, (uint32_t)env->regs[r3]); + } else { + cc = 1; + env->regs[r1] = (env->regs[r1] & 0xffffffff00000000ULL) | v2; +@@ -520,7 +520,8 @@ uint32_t HELPER(cs)(uint32_t r1, uint64_t a2, uint32_t r3) + return cc; + } + +-static uint32_t helper_icm(uint32_t r1, uint64_t address, uint32_t mask) ++static uint32_t helper_icm(CPUS390XState *env, uint32_t r1, uint64_t address, ++ uint32_t mask) + { + int pos = 24; /* top of the lower half of r1 */ + uint64_t rmask = 0xff000000ULL; +@@ -531,7 +532,7 @@ static uint32_t helper_icm(uint32_t r1, uint64_t address, uint32_t mask) + while (mask) { + if (mask & 8) { + env->regs[r1] &= ~rmask; +- val = ldub(address); ++ val = cpu_ldub_data(env, address); + if ((val & 0x80) && !ccd) { + cc = 1; + } +@@ -557,9 +558,10 @@ static uint32_t helper_icm(uint32_t r1, uint64_t address, uint32_t mask) + in other words: tricky... + currently implemented by interpreting the cases it is most commonly used in + */ +-uint32_t HELPER(ex)(uint32_t cc, uint64_t v1, uint64_t addr, uint64_t ret) ++uint32_t HELPER(ex)(CPUS390XState *env, uint32_t cc, uint64_t v1, ++ uint64_t addr, uint64_t ret) + { +- uint16_t insn = lduw_code(addr); ++ uint16_t insn = cpu_lduw_code(env, addr); + + HELPER_LOG("%s: v1 0x%lx addr 0x%lx insn 0x%x\n", __func__, v1, addr, + insn); +@@ -567,23 +569,27 @@ uint32_t HELPER(ex)(uint32_t cc, uint64_t v1, uint64_t addr, uint64_t ret) + uint32_t l, insn2, b1, b2, d1, d2; + + l = v1 & 0xff; +- insn2 = ldl_code(addr + 2); ++ insn2 = cpu_ldl_code(env, addr + 2); + b1 = (insn2 >> 28) & 0xf; + b2 = (insn2 >> 12) & 0xf; + d1 = (insn2 >> 16) & 0xfff; + d2 = insn2 & 0xfff; + switch (insn & 0xf00) { + case 0x200: +- helper_mvc(l, get_address(0, b1, d1), get_address(0, b2, d2)); ++ helper_mvc(env, l, get_address(env, 0, b1, d1), ++ get_address(env, 0, b2, d2)); + break; + case 0x500: +- cc = helper_clc(l, get_address(0, b1, d1), get_address(0, b2, d2)); ++ cc = helper_clc(env, l, get_address(env, 0, b1, d1), ++ get_address(env, 0, b2, d2)); + break; + case 0x700: +- cc = helper_xc(l, get_address(0, b1, d1), get_address(0, b2, d2)); ++ cc = helper_xc(env, l, get_address(env, 0, b1, d1), ++ get_address(env, 0, b2, d2)); + break; + case 0xc00: +- helper_tr(l, get_address(0, b1, d1), get_address(0, b2, d2)); ++ helper_tr(env, l, get_address(env, 0, b1, d1), ++ get_address(env, 0, b2, d2)); + break; + default: + goto abort; +@@ -599,12 +605,12 @@ uint32_t HELPER(ex)(uint32_t cc, uint64_t v1, uint64_t addr, uint64_t ret) + } else if ((insn & 0xff00) == 0xbf00) { + uint32_t insn2, r1, r3, b2, d2; + +- insn2 = ldl_code(addr + 2); ++ insn2 = cpu_ldl_code(env, addr + 2); + r1 = (insn2 >> 20) & 0xf; + r3 = (insn2 >> 16) & 0xf; + b2 = (insn2 >> 12) & 0xf; + d2 = insn2 & 0xfff; +- cc = helper_icm(r1, get_address(0, b2, d2), r3); ++ cc = helper_icm(env, r1, get_address(env, 0, b2, d2), r3); + } else { + abort: + cpu_abort(env, "EXECUTE on instruction prefix 0x%x not implemented\n", +@@ -614,13 +620,14 @@ uint32_t HELPER(ex)(uint32_t cc, uint64_t v1, uint64_t addr, uint64_t ret) + } + + /* store character under mask high operates on the upper half of r1 */ +-void HELPER(stcmh)(uint32_t r1, uint64_t address, uint32_t mask) ++void HELPER(stcmh)(CPUS390XState *env, uint32_t r1, uint64_t address, ++ uint32_t mask) + { + int pos = 56; /* top of the upper half of r1 */ + + while (mask) { + if (mask & 8) { +- stb(address, (env->regs[r1] >> pos) & 0xff); ++ cpu_stb_data(env, address, (env->regs[r1] >> pos) & 0xff); + address++; + } + mask = (mask << 1) & 0xf; +@@ -630,7 +637,8 @@ void HELPER(stcmh)(uint32_t r1, uint64_t address, uint32_t mask) + + /* insert character under mask high; same as icm, but operates on the + upper half of r1 */ +-uint32_t HELPER(icmh)(uint32_t r1, uint64_t address, uint32_t mask) ++uint32_t HELPER(icmh)(CPUS390XState *env, uint32_t r1, uint64_t address, ++ uint32_t mask) + { + int pos = 56; /* top of the upper half of r1 */ + uint64_t rmask = 0xff00000000000000ULL; +@@ -641,7 +649,7 @@ uint32_t HELPER(icmh)(uint32_t r1, uint64_t address, uint32_t mask) + while (mask) { + if (mask & 8) { + env->regs[r1] &= ~rmask; +- val = ldub(address); ++ val = cpu_ldub_data(env, address); + if ((val & 0x80) && !ccd) { + cc = 1; + } +@@ -661,12 +669,12 @@ uint32_t HELPER(icmh)(uint32_t r1, uint64_t address, uint32_t mask) + } + + /* load access registers r1 to r3 from memory at a2 */ +-void HELPER(lam)(uint32_t r1, uint64_t a2, uint32_t r3) ++void HELPER(lam)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint32_t r3) + { + int i; + + for (i = r1;; i = (i + 1) % 16) { +- env->aregs[i] = ldl(a2); ++ env->aregs[i] = cpu_ldl_data(env, a2); + a2 += 4; + + if (i == r3) { +@@ -676,12 +684,12 @@ void HELPER(lam)(uint32_t r1, uint64_t a2, uint32_t r3) + } + + /* store access registers r1 to r3 in memory at a2 */ +-void HELPER(stam)(uint32_t r1, uint64_t a2, uint32_t r3) ++void HELPER(stam)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint32_t r3) + { + int i; + + for (i = r1;; i = (i + 1) % 16) { +- stl(a2, env->aregs[i]); ++ cpu_stl_data(env, a2, env->aregs[i]); + a2 += 4; + + if (i == r3) { +@@ -691,12 +699,12 @@ void HELPER(stam)(uint32_t r1, uint64_t a2, uint32_t r3) + } + + /* move long */ +-uint32_t HELPER(mvcl)(uint32_t r1, uint32_t r2) ++uint32_t HELPER(mvcl)(CPUS390XState *env, uint32_t r1, uint32_t r2) + { + uint64_t destlen = env->regs[r1 + 1] & 0xffffff; +- uint64_t dest = get_address_31fix(r1); ++ uint64_t dest = get_address_31fix(env, r1); + uint64_t srclen = env->regs[r2 + 1] & 0xffffff; +- uint64_t src = get_address_31fix(r2); ++ uint64_t src = get_address_31fix(env, r2); + uint8_t pad = src >> 24; + uint8_t v; + uint32_t cc; +@@ -714,12 +722,12 @@ uint32_t HELPER(mvcl)(uint32_t r1, uint32_t r2) + } + + for (; destlen && srclen; src++, dest++, destlen--, srclen--) { +- v = ldub(src); +- stb(dest, v); ++ v = cpu_ldub_data(env, src); ++ cpu_stb_data(env, dest, v); + } + + for (; destlen; dest++, destlen--) { +- stb(dest, pad); ++ cpu_stb_data(env, dest, pad); + } + + env->regs[r1 + 1] = destlen; +@@ -732,7 +740,8 @@ uint32_t HELPER(mvcl)(uint32_t r1, uint32_t r2) + } + + /* move long extended another memcopy insn with more bells and whistles */ +-uint32_t HELPER(mvcle)(uint32_t r1, uint64_t a2, uint32_t r3) ++uint32_t HELPER(mvcle)(CPUS390XState *env, uint32_t r1, uint64_t a2, ++ uint32_t r3) + { + uint64_t destlen = env->regs[r1 + 1]; + uint64_t dest = env->regs[r1]; +@@ -762,12 +771,12 @@ uint32_t HELPER(mvcle)(uint32_t r1, uint64_t a2, uint32_t r3) + } + + for (; destlen && srclen; src++, dest++, destlen--, srclen--) { +- v = ldub(src); +- stb(dest, v); ++ v = cpu_ldub_data(env, src); ++ cpu_stb_data(env, dest, v); + } + + for (; destlen; dest++, destlen--) { +- stb(dest, pad); ++ cpu_stb_data(env, dest, pad); + } + + env->regs[r1 + 1] = destlen; +@@ -781,12 +790,13 @@ uint32_t HELPER(mvcle)(uint32_t r1, uint64_t a2, uint32_t r3) + } + + /* compare logical long extended memcompare insn with padding */ +-uint32_t HELPER(clcle)(uint32_t r1, uint64_t a2, uint32_t r3) ++uint32_t HELPER(clcle)(CPUS390XState *env, uint32_t r1, uint64_t a2, ++ uint32_t r3) + { + uint64_t destlen = env->regs[r1 + 1]; +- uint64_t dest = get_address_31fix(r1); ++ uint64_t dest = get_address_31fix(env, r1); + uint64_t srclen = env->regs[r3 + 1]; +- uint64_t src = get_address_31fix(r3); ++ uint64_t src = get_address_31fix(env, r3); + uint8_t pad = a2 & 0xff; + uint8_t v1 = 0, v2 = 0; + uint32_t cc = 0; +@@ -800,8 +810,8 @@ uint32_t HELPER(clcle)(uint32_t r1, uint64_t a2, uint32_t r3) + } + + for (; destlen || srclen; src++, dest++, destlen--, srclen--) { +- v1 = srclen ? ldub(src) : pad; +- v2 = destlen ? ldub(dest) : pad; ++ v1 = srclen ? cpu_ldub_data(env, src) : pad; ++ v2 = destlen ? cpu_ldub_data(env, dest) : pad; + if (v1 != v2) { + cc = (v1 < v2) ? 1 : 2; + break; +@@ -818,14 +828,14 @@ uint32_t HELPER(clcle)(uint32_t r1, uint64_t a2, uint32_t r3) + } + + /* checksum */ +-void HELPER(cksm)(uint32_t r1, uint32_t r2) ++void HELPER(cksm)(CPUS390XState *env, uint32_t r1, uint32_t r2) + { +- uint64_t src = get_address_31fix(r2); ++ uint64_t src = get_address_31fix(env, r2); + uint64_t src_len = env->regs[(r2 + 1) & 15]; + uint64_t cksm = (uint32_t)env->regs[r1]; + + while (src_len >= 4) { +- cksm += ldl(src); ++ cksm += cpu_ldl_data(env, src); + + /* move to next word */ + src_len -= 4; +@@ -836,14 +846,14 @@ void HELPER(cksm)(uint32_t r1, uint32_t r2) + case 0: + break; + case 1: +- cksm += ldub(src) << 24; ++ cksm += cpu_ldub_data(env, src) << 24; + break; + case 2: +- cksm += lduw(src) << 16; ++ cksm += cpu_lduw_data(env, src) << 16; + break; + case 3: +- cksm += lduw(src) << 16; +- cksm += ldub(src + 2) << 8; ++ cksm += cpu_lduw_data(env, src) << 16; ++ cksm += cpu_ldub_data(env, src + 2) << 8; + break; + } + +@@ -856,7 +866,8 @@ void HELPER(cksm)(uint32_t r1, uint32_t r2) + ((uint32_t)cksm + (cksm >> 32)); + } + +-void HELPER(unpk)(uint32_t len, uint64_t dest, uint64_t src) ++void HELPER(unpk)(CPUS390XState *env, uint32_t len, uint64_t dest, ++ uint64_t src) + { + int len_dest = len >> 4; + int len_src = len & 0xf; +@@ -867,8 +878,8 @@ void HELPER(unpk)(uint32_t len, uint64_t dest, uint64_t src) + src += len_src; + + /* last byte is special, it only flips the nibbles */ +- b = ldub(src); +- stb(dest, (b << 4) | (b >> 4)); ++ b = cpu_ldub_data(env, src); ++ cpu_stb_data(env, dest, (b << 4) | (b >> 4)); + src--; + len_src--; + +@@ -878,7 +889,7 @@ void HELPER(unpk)(uint32_t len, uint64_t dest, uint64_t src) + uint8_t cur_byte = 0; + + if (len_src > 0) { +- cur_byte = ldub(src); ++ cur_byte = cpu_ldub_data(env, src); + } + + len_dest--; +@@ -897,30 +908,31 @@ void HELPER(unpk)(uint32_t len, uint64_t dest, uint64_t src) + /* zone bits */ + cur_byte |= 0xf0; + +- stb(dest, cur_byte); ++ cpu_stb_data(env, dest, cur_byte); + } + } + +-void HELPER(tr)(uint32_t len, uint64_t array, uint64_t trans) ++void HELPER(tr)(CPUS390XState *env, uint32_t len, uint64_t array, ++ uint64_t trans) + { + int i; + + for (i = 0; i <= len; i++) { +- uint8_t byte = ldub(array + i); +- uint8_t new_byte = ldub(trans + byte); ++ uint8_t byte = cpu_ldub_data(env, array + i); ++ uint8_t new_byte = cpu_ldub_data(env, trans + byte); + +- stb(array + i, new_byte); ++ cpu_stb_data(env, array + i, new_byte); + } + } + + #if !defined(CONFIG_USER_ONLY) +-void HELPER(lctlg)(uint32_t r1, uint64_t a2, uint32_t r3) ++void HELPER(lctlg)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint32_t r3) + { + int i; + uint64_t src = a2; + + for (i = r1;; i = (i + 1) % 16) { +- env->cregs[i] = ldq(src); ++ env->cregs[i] = cpu_ldq_data(env, src); + HELPER_LOG("load ctl %d from 0x%" PRIx64 " == 0x%" PRIx64 "\n", + i, src, env->cregs[i]); + src += sizeof(uint64_t); +@@ -933,13 +945,14 @@ void HELPER(lctlg)(uint32_t r1, uint64_t a2, uint32_t r3) + tlb_flush(env, 1); + } + +-void HELPER(lctl)(uint32_t r1, uint64_t a2, uint32_t r3) ++void HELPER(lctl)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint32_t r3) + { + int i; + uint64_t src = a2; + + for (i = r1;; i = (i + 1) % 16) { +- env->cregs[i] = (env->cregs[i] & 0xFFFFFFFF00000000ULL) | ldl(src); ++ env->cregs[i] = (env->cregs[i] & 0xFFFFFFFF00000000ULL) | ++ cpu_ldl_data(env, src); + src += sizeof(uint32_t); + + if (i == r3) { +@@ -950,13 +963,13 @@ void HELPER(lctl)(uint32_t r1, uint64_t a2, uint32_t r3) + tlb_flush(env, 1); + } + +-void HELPER(stctg)(uint32_t r1, uint64_t a2, uint32_t r3) ++void HELPER(stctg)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint32_t r3) + { + int i; + uint64_t dest = a2; + + for (i = r1;; i = (i + 1) % 16) { +- stq(dest, env->cregs[i]); ++ cpu_stq_data(env, dest, env->cregs[i]); + dest += sizeof(uint64_t); + + if (i == r3) { +@@ -965,13 +978,13 @@ void HELPER(stctg)(uint32_t r1, uint64_t a2, uint32_t r3) + } + } + +-void HELPER(stctl)(uint32_t r1, uint64_t a2, uint32_t r3) ++void HELPER(stctl)(CPUS390XState *env, uint32_t r1, uint64_t a2, uint32_t r3) + { + int i; + uint64_t dest = a2; + + for (i = r1;; i = (i + 1) % 16) { +- stl(dest, env->cregs[i]); ++ cpu_stl_data(env, dest, env->cregs[i]); + dest += sizeof(uint32_t); + + if (i == r3) { +@@ -988,9 +1001,9 @@ uint32_t HELPER(tprot)(uint64_t a1, uint64_t a2) + } + + /* insert storage key extended */ +-uint64_t HELPER(iske)(uint64_t r2) ++uint64_t HELPER(iske)(CPUS390XState *env, uint64_t r2) + { +- uint64_t addr = get_address(0, 0, r2); ++ uint64_t addr = get_address(env, 0, 0, r2); + + if (addr > ram_size) { + return 0; +@@ -1000,9 +1013,9 @@ uint64_t HELPER(iske)(uint64_t r2) + } + + /* set storage key extended */ +-void HELPER(sske)(uint32_t r1, uint64_t r2) ++void HELPER(sske)(CPUS390XState *env, uint32_t r1, uint64_t r2) + { +- uint64_t addr = get_address(0, 0, r2); ++ uint64_t addr = get_address(env, 0, 0, r2); + + if (addr > ram_size) { + return; +@@ -1012,7 +1025,7 @@ void HELPER(sske)(uint32_t r1, uint64_t r2) + } + + /* reset reference bit extended */ +-uint32_t HELPER(rrbe)(uint32_t r1, uint64_t r2) ++uint32_t HELPER(rrbe)(CPUS390XState *env, uint32_t r1, uint64_t r2) + { + uint8_t re; + uint8_t key; +@@ -1038,15 +1051,15 @@ uint32_t HELPER(rrbe)(uint32_t r1, uint64_t r2) + } + + /* compare and swap and purge */ +-uint32_t HELPER(csp)(uint32_t r1, uint32_t r2) ++uint32_t HELPER(csp)(CPUS390XState *env, uint32_t r1, uint32_t r2) + { + uint32_t cc; + uint32_t o1 = env->regs[r1]; +- uint64_t a2 = get_address_31fix(r2) & ~3ULL; +- uint32_t o2 = ldl(a2); ++ uint64_t a2 = get_address_31fix(env, r2) & ~3ULL; ++ uint32_t o2 = cpu_ldl_data(env, a2); + + if (o1 == o2) { +- stl(a2, env->regs[(r1 + 1) & 15]); ++ cpu_stl_data(env, a2, env->regs[(r1 + 1) & 15]); + if (env->regs[r2] & 0x3) { + /* flush TLB / ALB */ + tlb_flush(env, 1); +@@ -1060,8 +1073,8 @@ uint32_t HELPER(csp)(uint32_t r1, uint32_t r2) + return cc; + } + +-static uint32_t mvc_asc(int64_t l, uint64_t a1, uint64_t mode1, uint64_t a2, +- uint64_t mode2) ++static uint32_t mvc_asc(CPUS390XState *env, int64_t l, uint64_t a1, ++ uint64_t mode1, uint64_t a2, uint64_t mode2) + { + target_ulong src, dest; + int flags, cc = 0, i; +@@ -1089,7 +1102,7 @@ static uint32_t mvc_asc(int64_t l, uint64_t a1, uint64_t mode1, uint64_t a2, + /* XXX be more clever */ + if ((((dest + i) & TARGET_PAGE_MASK) != (dest & TARGET_PAGE_MASK)) || + (((src + i) & TARGET_PAGE_MASK) != (src & TARGET_PAGE_MASK))) { +- mvc_asc(l - i, a1 + i, mode1, a2 + i, mode2); ++ mvc_asc(env, l - i, a1 + i, mode1, a2 + i, mode2); + break; + } + stb_phys(dest + i, ldub_phys(src + i)); +@@ -1098,24 +1111,24 @@ static uint32_t mvc_asc(int64_t l, uint64_t a1, uint64_t mode1, uint64_t a2, + return cc; + } + +-uint32_t HELPER(mvcs)(uint64_t l, uint64_t a1, uint64_t a2) ++uint32_t HELPER(mvcs)(CPUS390XState *env, uint64_t l, uint64_t a1, uint64_t a2) + { + HELPER_LOG("%s: %16" PRIx64 " %16" PRIx64 " %16" PRIx64 "\n", + __func__, l, a1, a2); + +- return mvc_asc(l, a1, PSW_ASC_SECONDARY, a2, PSW_ASC_PRIMARY); ++ return mvc_asc(env, l, a1, PSW_ASC_SECONDARY, a2, PSW_ASC_PRIMARY); + } + +-uint32_t HELPER(mvcp)(uint64_t l, uint64_t a1, uint64_t a2) ++uint32_t HELPER(mvcp)(CPUS390XState *env, uint64_t l, uint64_t a1, uint64_t a2) + { + HELPER_LOG("%s: %16" PRIx64 " %16" PRIx64 " %16" PRIx64 "\n", + __func__, l, a1, a2); + +- return mvc_asc(l, a1, PSW_ASC_PRIMARY, a2, PSW_ASC_SECONDARY); ++ return mvc_asc(env, l, a1, PSW_ASC_PRIMARY, a2, PSW_ASC_SECONDARY); + } + + /* invalidate pte */ +-void HELPER(ipte)(uint64_t pte_addr, uint64_t vaddr) ++void HELPER(ipte)(CPUS390XState *env, uint64_t pte_addr, uint64_t vaddr) + { + uint64_t page = vaddr & TARGET_PAGE_MASK; + uint64_t pte = 0; +@@ -1141,19 +1154,19 @@ void HELPER(ipte)(uint64_t pte_addr, uint64_t vaddr) + } + + /* flush local tlb */ +-void HELPER(ptlb)(void) ++void HELPER(ptlb)(CPUS390XState *env) + { + tlb_flush(env, 1); + } + + /* store using real address */ +-void HELPER(stura)(uint64_t addr, uint32_t v1) ++void HELPER(stura)(CPUS390XState *env, uint64_t addr, uint32_t v1) + { +- stw_phys(get_address(0, 0, addr), v1); ++ stw_phys(get_address(env, 0, 0, addr), v1); + } + + /* load real address */ +-uint32_t HELPER(lra)(uint64_t addr, uint32_t r1) ++uint32_t HELPER(lra)(CPUS390XState *env, uint64_t addr, uint32_t r1) + { + uint32_t cc = 0; + int old_exc = env->exception_index; +@@ -1188,52 +1201,3 @@ uint32_t HELPER(lra)(uint64_t addr, uint32_t r1) + } + + #endif +- +-/* temporary wrappers */ +-#if defined(CONFIG_USER_ONLY) +-#define ldub_data(addr) ldub_raw(addr) +-#define lduw_data(addr) lduw_raw(addr) +-#define ldl_data(addr) ldl_raw(addr) +-#define ldq_data(addr) ldq_raw(addr) +- +-#define stb_data(addr, data) stb_raw(addr, data) +-#define stw_data(addr, data) stw_raw(addr, data) +-#define stl_data(addr, data) stl_raw(addr, data) +-#define stq_data(addr, data) stq_raw(addr, data) +-#endif +- +-#define WRAP_LD(rettype, fn) \ +- rettype cpu_ ## fn(CPUS390XState *env1, target_ulong addr) \ +- { \ +- CPUS390XState *saved_env; \ +- rettype ret; \ +- \ +- saved_env = env; \ +- env = env1; \ +- ret = fn(addr); \ +- env = saved_env; \ +- return ret; \ +- } +- +-WRAP_LD(uint32_t, ldub_data) +-WRAP_LD(uint32_t, lduw_data) +-WRAP_LD(uint32_t, ldl_data) +-WRAP_LD(uint64_t, ldq_data) +-#undef WRAP_LD +- +-#define WRAP_ST(datatype, fn) \ +- void cpu_ ## fn(CPUS390XState *env1, target_ulong addr, datatype val) \ +- { \ +- CPUS390XState *saved_env; \ +- \ +- saved_env = env; \ +- env = env1; \ +- fn(addr, val); \ +- env = saved_env; \ +- } +- +-WRAP_ST(uint32_t, stb_data) +-WRAP_ST(uint32_t, stw_data) +-WRAP_ST(uint32_t, stl_data) +-WRAP_ST(uint64_t, stq_data) +-#undef WRAP_ST +diff --git a/target-s390x/misc_helper.c b/target-s390x/misc_helper.c +index ced26c6..2938ac9 100644 +--- a/target-s390x/misc_helper.c ++++ b/target-s390x/misc_helper.c +@@ -31,10 +31,7 @@ + #endif + + #if !defined(CONFIG_USER_ONLY) +-/* temporarily disabled due to wrapper use */ +-#if 0 + #include "softmmu_exec.h" +-#endif + #include "sysemu.h" + #endif + +diff --git a/target-s390x/translate.c b/target-s390x/translate.c +index 0c61e63..66119cd 100644 +--- a/target-s390x/translate.c ++++ b/target-s390x/translate.c +@@ -276,19 +276,19 @@ static inline void potential_page_fault(DisasContext *s) + + static inline uint64_t ld_code2(uint64_t pc) + { +- return (uint64_t)lduw_code(pc); ++ return (uint64_t)cpu_lduw_code(cpu_single_env, pc); + } + + static inline uint64_t ld_code4(uint64_t pc) + { +- return (uint64_t)ldl_code(pc); ++ return (uint64_t)cpu_ldl_code(cpu_single_env, pc); + } + + static inline uint64_t ld_code6(uint64_t pc) + { + uint64_t opc; +- opc = (uint64_t)lduw_code(pc) << 32; +- opc |= (uint64_t)(uint32_t)ldl_code(pc+2); ++ opc = (uint64_t)cpu_lduw_code(cpu_single_env, pc) << 32; ++ opc |= (uint64_t)(uint32_t)cpu_ldl_code(cpu_single_env, pc + 2); + return opc; + } + +@@ -1263,7 +1263,7 @@ static void gen_op_mvc(DisasContext *s, int l, TCGv_i64 s1, TCGv_i64 s2) + /* Fall back to helper */ + vl = tcg_const_i32(l); + potential_page_fault(s); +- gen_helper_mvc(vl, s1, s2); ++ gen_helper_mvc(cpu_env, vl, s1, s2); + tcg_temp_free_i32(vl); + return; + } +@@ -1455,7 +1455,7 @@ static void gen_op_clc(DisasContext *s, int l, TCGv_i64 s1, TCGv_i64 s2) + + potential_page_fault(s); + vl = tcg_const_i32(l); +- gen_helper_clc(cc_op, vl, s1, s2); ++ gen_helper_clc(cc_op, cpu_env, vl, s1, s2); + tcg_temp_free_i32(vl); + set_cc_static(s); + } +@@ -2094,7 +2094,7 @@ do_mh: + tmp32_1 = tcg_const_i32(r1); + tmp32_2 = tcg_const_i32(r3); + potential_page_fault(s); +- gen_helper_stcmh(tmp32_1, tmp, tmp32_2); ++ gen_helper_stcmh(cpu_env, tmp32_1, tmp, tmp32_2); + tcg_temp_free_i64(tmp); + tcg_temp_free_i32(tmp32_1); + tcg_temp_free_i32(tmp32_2); +@@ -2107,7 +2107,7 @@ do_mh: + tmp32_1 = tcg_const_i32(r1); + tmp32_2 = tcg_const_i32(r3); + potential_page_fault(s); +- gen_helper_lctlg(tmp32_1, tmp, tmp32_2); ++ gen_helper_lctlg(cpu_env, tmp32_1, tmp, tmp32_2); + tcg_temp_free_i64(tmp); + tcg_temp_free_i32(tmp32_1); + tcg_temp_free_i32(tmp32_2); +@@ -2119,7 +2119,7 @@ do_mh: + tmp32_1 = tcg_const_i32(r1); + tmp32_2 = tcg_const_i32(r3); + potential_page_fault(s); +- gen_helper_stctg(tmp32_1, tmp, tmp32_2); ++ gen_helper_stctg(cpu_env, tmp32_1, tmp, tmp32_2); + tcg_temp_free_i64(tmp); + tcg_temp_free_i32(tmp32_1); + tcg_temp_free_i32(tmp32_2); +@@ -2131,7 +2131,7 @@ do_mh: + tmp32_2 = tcg_const_i32(r3); + potential_page_fault(s); + /* XXX rewrite in tcg */ +- gen_helper_csg(cc_op, tmp32_1, tmp, tmp32_2); ++ gen_helper_csg(cc_op, cpu_env, tmp32_1, tmp, tmp32_2); + set_cc_static(s); + tcg_temp_free_i64(tmp); + tcg_temp_free_i32(tmp32_1); +@@ -2143,7 +2143,7 @@ do_mh: + tmp32_2 = tcg_const_i32(r3); + potential_page_fault(s); + /* XXX rewrite in tcg */ +- gen_helper_cdsg(cc_op, tmp32_1, tmp, tmp32_2); ++ gen_helper_cdsg(cc_op, cpu_env, tmp32_1, tmp, tmp32_2); + set_cc_static(s); + tcg_temp_free_i64(tmp); + tcg_temp_free_i32(tmp32_1); +@@ -2183,7 +2183,7 @@ do_mh: + tmp32_2 = tcg_const_i32(r3); + potential_page_fault(s); + /* XXX split CC calculation out */ +- gen_helper_icmh(cc_op, tmp32_1, tmp, tmp32_2); ++ gen_helper_icmh(cc_op, cpu_env, tmp32_1, tmp, tmp32_2); + set_cc_static(s); + tcg_temp_free_i64(tmp); + tcg_temp_free_i32(tmp32_1); +@@ -2635,7 +2635,7 @@ static void disas_b2(DisasContext *s, int op, uint32_t insn) + tmp32_1 = tcg_const_i32(r1); + tmp32_2 = tcg_const_i32(r2); + potential_page_fault(s); +- gen_helper_cksm(tmp32_1, tmp32_2); ++ gen_helper_cksm(cpu_env, tmp32_1, tmp32_2); + tcg_temp_free_i32(tmp32_1); + tcg_temp_free_i32(tmp32_2); + gen_op_movi_cc(s, 0); +@@ -2664,7 +2664,7 @@ static void disas_b2(DisasContext *s, int op, uint32_t insn) + tmp2 = load_reg(r1); + tmp3 = load_reg(r2); + potential_page_fault(s); +- gen_helper_mvpg(tmp, tmp2, tmp3); ++ gen_helper_mvpg(cpu_env, tmp, tmp2, tmp3); + tcg_temp_free_i64(tmp); + tcg_temp_free_i64(tmp2); + tcg_temp_free_i64(tmp3); +@@ -2676,7 +2676,7 @@ static void disas_b2(DisasContext *s, int op, uint32_t insn) + tmp32_2 = tcg_const_i32(r1); + tmp32_3 = tcg_const_i32(r2); + potential_page_fault(s); +- gen_helper_mvst(tmp32_1, tmp32_2, tmp32_3); ++ gen_helper_mvst(cpu_env, tmp32_1, tmp32_2, tmp32_3); + tcg_temp_free_i32(tmp32_1); + tcg_temp_free_i32(tmp32_2); + tcg_temp_free_i32(tmp32_3); +@@ -2687,7 +2687,7 @@ static void disas_b2(DisasContext *s, int op, uint32_t insn) + tmp32_2 = tcg_const_i32(r1); + tmp32_3 = tcg_const_i32(r2); + potential_page_fault(s); +- gen_helper_clst(cc_op, tmp32_1, tmp32_2, tmp32_3); ++ gen_helper_clst(cc_op, cpu_env, tmp32_1, tmp32_2, tmp32_3); + set_cc_static(s); + tcg_temp_free_i32(tmp32_1); + tcg_temp_free_i32(tmp32_2); +@@ -2698,7 +2698,7 @@ static void disas_b2(DisasContext *s, int op, uint32_t insn) + tmp32_2 = tcg_const_i32(r1); + tmp32_3 = tcg_const_i32(r2); + potential_page_fault(s); +- gen_helper_srst(cc_op, tmp32_1, tmp32_2, tmp32_3); ++ gen_helper_srst(cc_op, cpu_env, tmp32_1, tmp32_2, tmp32_3); + set_cc_static(s); + tcg_temp_free_i32(tmp32_1); + tcg_temp_free_i32(tmp32_2); +@@ -2785,7 +2785,7 @@ static void disas_b2(DisasContext *s, int op, uint32_t insn) + case 0x0d: /* PTLB [S] */ + /* Purge TLB */ + check_privileged(s, ilc); +- gen_helper_ptlb(); ++ gen_helper_ptlb(cpu_env); + break; + case 0x10: /* SPX D2(B2) [S] */ + /* Set Prefix Register */ +@@ -2828,7 +2828,7 @@ static void disas_b2(DisasContext *s, int op, uint32_t insn) + r2 = insn & 0xf; + tmp = load_reg(r1); + tmp2 = load_reg(r2); +- gen_helper_ipte(tmp, tmp2); ++ gen_helper_ipte(cpu_env, tmp, tmp2); + tcg_temp_free_i64(tmp); + tcg_temp_free_i64(tmp2); + break; +@@ -2839,7 +2839,7 @@ static void disas_b2(DisasContext *s, int op, uint32_t insn) + r2 = insn & 0xf; + tmp = load_reg(r2); + tmp2 = tcg_temp_new_i64(); +- gen_helper_iske(tmp2, tmp); ++ gen_helper_iske(tmp2, cpu_env, tmp); + store_reg(r1, tmp2); + tcg_temp_free_i64(tmp); + tcg_temp_free_i64(tmp2); +@@ -2851,7 +2851,7 @@ static void disas_b2(DisasContext *s, int op, uint32_t insn) + r2 = insn & 0xf; + tmp32_1 = load_reg32(r1); + tmp = load_reg(r2); +- gen_helper_rrbe(cc_op, tmp32_1, tmp); ++ gen_helper_rrbe(cc_op, cpu_env, tmp32_1, tmp); + set_cc_static(s); + tcg_temp_free_i32(tmp32_1); + tcg_temp_free_i64(tmp); +@@ -2863,7 +2863,7 @@ static void disas_b2(DisasContext *s, int op, uint32_t insn) + r2 = insn & 0xf; + tmp32_1 = load_reg32(r1); + tmp = load_reg(r2); +- gen_helper_sske(tmp32_1, tmp); ++ gen_helper_sske(cpu_env, tmp32_1, tmp); + tcg_temp_free_i32(tmp32_1); + tcg_temp_free_i64(tmp); + break; +@@ -2880,7 +2880,7 @@ static void disas_b2(DisasContext *s, int op, uint32_t insn) + tmp32_1 = load_reg32(r1); + tmp = load_reg(r2); + potential_page_fault(s); +- gen_helper_stura(tmp, tmp32_1); ++ gen_helper_stura(cpu_env, tmp, tmp32_1); + tcg_temp_free_i32(tmp32_1); + tcg_temp_free_i64(tmp); + break; +@@ -2891,7 +2891,7 @@ static void disas_b2(DisasContext *s, int op, uint32_t insn) + r2 = insn & 0xf; + tmp32_1 = tcg_const_i32(r1); + tmp32_2 = tcg_const_i32(r2); +- gen_helper_csp(cc_op, tmp32_1, tmp32_2); ++ gen_helper_csp(cc_op, cpu_env, tmp32_1, tmp32_2); + set_cc_static(s); + tcg_temp_free_i32(tmp32_1); + tcg_temp_free_i32(tmp32_2); +@@ -3865,7 +3865,7 @@ static void disas_s390_insn(DisasContext *s) + int ilc; + int l1; + +- opc = ldub_code(s->pc); ++ opc = cpu_ldub_code(cpu_single_env, s->pc); + LOG_DISAS("opc 0x%x\n", opc); + + ilc = get_ilc(opc); +@@ -3951,7 +3951,7 @@ static void disas_s390_insn(DisasContext *s) + tmp32_1 = tcg_const_i32(r1); + tmp32_2 = tcg_const_i32(r2); + potential_page_fault(s); +- gen_helper_mvcl(cc_op, tmp32_1, tmp32_2); ++ gen_helper_mvcl(cc_op, cpu_env, tmp32_1, tmp32_2); + set_cc_static(s); + tcg_temp_free_i32(tmp32_1); + tcg_temp_free_i32(tmp32_2); +@@ -4165,7 +4165,7 @@ static void disas_s390_insn(DisasContext *s) + tmp3 = tcg_const_i64(s->pc + 4); + update_psw_addr(s); + gen_op_calc_cc(s); +- gen_helper_ex(cc_op, cc_op, tmp2, tmp, tmp3); ++ gen_helper_ex(cc_op, cpu_env, cc_op, tmp2, tmp, tmp3); + set_cc_static(s); + tcg_temp_free_i64(tmp); + tcg_temp_free_i64(tmp2); +@@ -4694,7 +4694,7 @@ static void disas_s390_insn(DisasContext *s) + tmp32_1 = tcg_const_i32(r1); + tmp32_2 = tcg_const_i32(r3); + potential_page_fault(s); +- gen_helper_lam(tmp32_1, tmp, tmp32_2); ++ gen_helper_lam(cpu_env, tmp32_1, tmp, tmp32_2); + tcg_temp_free_i64(tmp); + tcg_temp_free_i32(tmp32_1); + tcg_temp_free_i32(tmp32_2); +@@ -4706,7 +4706,7 @@ static void disas_s390_insn(DisasContext *s) + tmp32_1 = tcg_const_i32(r1); + tmp32_2 = tcg_const_i32(r3); + potential_page_fault(s); +- gen_helper_stam(tmp32_1, tmp, tmp32_2); ++ gen_helper_stam(cpu_env, tmp32_1, tmp, tmp32_2); + tcg_temp_free_i64(tmp); + tcg_temp_free_i32(tmp32_1); + tcg_temp_free_i32(tmp32_2); +@@ -4732,7 +4732,7 @@ static void disas_s390_insn(DisasContext *s) + tmp32_1 = tcg_const_i32(r1); + tmp32_2 = tcg_const_i32(r3); + potential_page_fault(s); +- gen_helper_mvcle(cc_op, tmp32_1, tmp, tmp32_2); ++ gen_helper_mvcle(cc_op, cpu_env, tmp32_1, tmp, tmp32_2); + set_cc_static(s); + tcg_temp_free_i64(tmp); + tcg_temp_free_i32(tmp32_1); +@@ -4745,7 +4745,7 @@ static void disas_s390_insn(DisasContext *s) + tmp32_1 = tcg_const_i32(r1); + tmp32_2 = tcg_const_i32(r3); + potential_page_fault(s); +- gen_helper_clcle(cc_op, tmp32_1, tmp, tmp32_2); ++ gen_helper_clcle(cc_op, cpu_env, tmp32_1, tmp, tmp32_2); + set_cc_static(s); + tcg_temp_free_i64(tmp); + tcg_temp_free_i32(tmp32_1); +@@ -4789,7 +4789,7 @@ static void disas_s390_insn(DisasContext *s) + tmp = decode_rx(s, insn, &r1, &x2, &b2, &d2); + tmp32_1 = tcg_const_i32(r1); + potential_page_fault(s); +- gen_helper_lra(cc_op, tmp, tmp32_1); ++ gen_helper_lra(cc_op, cpu_env, tmp, tmp32_1); + set_cc_static(s); + tcg_temp_free_i64(tmp); + tcg_temp_free_i32(tmp32_1); +@@ -4835,7 +4835,7 @@ static void disas_s390_insn(DisasContext *s) + tmp32_1 = tcg_const_i32(r1); + tmp32_2 = tcg_const_i32(r3); + potential_page_fault(s); +- gen_helper_stctl(tmp32_1, tmp, tmp32_2); ++ gen_helper_stctl(cpu_env, tmp32_1, tmp, tmp32_2); + tcg_temp_free_i64(tmp); + tcg_temp_free_i32(tmp32_1); + tcg_temp_free_i32(tmp32_2); +@@ -4849,7 +4849,7 @@ static void disas_s390_insn(DisasContext *s) + tmp32_1 = tcg_const_i32(r1); + tmp32_2 = tcg_const_i32(r3); + potential_page_fault(s); +- gen_helper_lctl(tmp32_1, tmp, tmp32_2); ++ gen_helper_lctl(cpu_env, tmp32_1, tmp, tmp32_2); + tcg_temp_free_i64(tmp); + tcg_temp_free_i32(tmp32_1); + tcg_temp_free_i32(tmp32_2); +@@ -4869,7 +4869,7 @@ static void disas_s390_insn(DisasContext *s) + tmp32_1 = tcg_const_i32(r1); + tmp32_2 = tcg_const_i32(r3); + potential_page_fault(s); +- gen_helper_cs(cc_op, tmp32_1, tmp, tmp32_2); ++ gen_helper_cs(cc_op, cpu_env, tmp32_1, tmp, tmp32_2); + set_cc_static(s); + tcg_temp_free_i64(tmp); + tcg_temp_free_i32(tmp32_1); +@@ -4882,7 +4882,7 @@ static void disas_s390_insn(DisasContext *s) + tmp32_1 = load_reg32(r1); + tmp32_2 = tcg_const_i32(r3); + potential_page_fault(s); +- gen_helper_clm(cc_op, tmp32_1, tmp32_2, tmp); ++ gen_helper_clm(cc_op, cpu_env, tmp32_1, tmp32_2, tmp); + set_cc_static(s); + tcg_temp_free_i64(tmp); + tcg_temp_free_i32(tmp32_1); +@@ -4895,7 +4895,7 @@ static void disas_s390_insn(DisasContext *s) + tmp32_1 = load_reg32(r1); + tmp32_2 = tcg_const_i32(r3); + potential_page_fault(s); +- gen_helper_stcm(tmp32_1, tmp32_2, tmp); ++ gen_helper_stcm(cpu_env, tmp32_1, tmp32_2, tmp); + tcg_temp_free_i64(tmp); + tcg_temp_free_i32(tmp32_1); + tcg_temp_free_i32(tmp32_2); +@@ -4992,7 +4992,7 @@ static void disas_s390_insn(DisasContext *s) + break; + case 0xd4: + potential_page_fault(s); +- gen_helper_nc(cc_op, vl, tmp, tmp2); ++ gen_helper_nc(cc_op, cpu_env, vl, tmp, tmp2); + set_cc_static(s); + break; + case 0xd5: +@@ -5000,22 +5000,22 @@ static void disas_s390_insn(DisasContext *s) + break; + case 0xd6: + potential_page_fault(s); +- gen_helper_oc(cc_op, vl, tmp, tmp2); ++ gen_helper_oc(cc_op, cpu_env, vl, tmp, tmp2); + set_cc_static(s); + break; + case 0xd7: + potential_page_fault(s); +- gen_helper_xc(cc_op, vl, tmp, tmp2); ++ gen_helper_xc(cc_op, cpu_env, vl, tmp, tmp2); + set_cc_static(s); + break; + case 0xdc: + potential_page_fault(s); +- gen_helper_tr(vl, tmp, tmp2); ++ gen_helper_tr(cpu_env, vl, tmp, tmp2); + set_cc_static(s); + break; + case 0xf3: + potential_page_fault(s); +- gen_helper_unpk(vl, tmp, tmp2); ++ gen_helper_unpk(cpu_env, vl, tmp, tmp2); + break; + default: + tcg_abort(); +@@ -5040,9 +5040,9 @@ static void disas_s390_insn(DisasContext *s) + tmp2 = get_address(s, 0, b1, d1); + tmp3 = get_address(s, 0, b2, d2); + if (opc == 0xda) { +- gen_helper_mvcp(cc_op, tmp, tmp2, tmp3); ++ gen_helper_mvcp(cc_op, cpu_env, tmp, tmp2, tmp3); + } else { +- gen_helper_mvcs(cc_op, tmp, tmp2, tmp3); ++ gen_helper_mvcs(cc_op, cpu_env, tmp, tmp2, tmp3); + } + set_cc_static(s); + tcg_temp_free_i64(tmp); +-- +1.7.12.1 + diff --git a/0016-tcg-s390-fix-ld-st-with-CONFIG_TCG_PASS_AREG0.patch b/0016-tcg-s390-fix-ld-st-with-CONFIG_TCG_PASS_AREG0.patch new file mode 100644 index 0000000..96c305e --- /dev/null +++ b/0016-tcg-s390-fix-ld-st-with-CONFIG_TCG_PASS_AREG0.patch @@ -0,0 +1,64 @@ +From 0b95df52ecad351c916108e9f3a9d1bc3327b495 Mon Sep 17 00:00:00 2001 +From: Aurelien Jarno +Date: Sat, 8 Sep 2012 03:45:43 +0000 +Subject: [PATCH] tcg/s390: fix ld/st with CONFIG_TCG_PASS_AREG0 + +The load/store slow path has been broken in e141ab52d: +- We need to move 4 registers for store functions and 3 registers for + load functions and not the reverse. +- According to the s390x calling convention the arguments of a function + should be zero extended. This means that the register shift should be + done with TCG_TYPE_I64 to ensure the higher word is correctly zero + extended when needed. + +I am aware that CONFIG_TCG_PASS_AREG0 is being removed and thus that +this patch can be improved, but doing so means it can also be applied to +the 1.1 and 1.2 stable branches. + +Signed-off-by: Aurelien Jarno +Signed-off-by: Alexander Graf +Signed-off-by: Michael Roth +--- + tcg/s390/tcg-target.c | 14 +++++++------- + 1 file changed, 7 insertions(+), 7 deletions(-) + +diff --git a/tcg/s390/tcg-target.c b/tcg/s390/tcg-target.c +index 04662c1..99b5339 100644 +--- a/tcg/s390/tcg-target.c ++++ b/tcg/s390/tcg-target.c +@@ -1509,11 +1509,13 @@ static void tcg_prepare_qemu_ldst(TCGContext* s, TCGReg data_reg, + tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_R4, mem_index); + #ifdef CONFIG_TCG_PASS_AREG0 + /* XXX/FIXME: suboptimal */ +- tcg_out_mov(s, TCG_TYPE_I32, tcg_target_call_iarg_regs[2], ++ tcg_out_mov(s, TCG_TYPE_I64, tcg_target_call_iarg_regs[3], ++ tcg_target_call_iarg_regs[2]); ++ tcg_out_mov(s, TCG_TYPE_I64, tcg_target_call_iarg_regs[2], + tcg_target_call_iarg_regs[1]); +- tcg_out_mov(s, TCG_TYPE_TL, tcg_target_call_iarg_regs[1], ++ tcg_out_mov(s, TCG_TYPE_I64, tcg_target_call_iarg_regs[1], + tcg_target_call_iarg_regs[0]); +- tcg_out_mov(s, TCG_TYPE_PTR, tcg_target_call_iarg_regs[0], ++ tcg_out_mov(s, TCG_TYPE_I64, tcg_target_call_iarg_regs[0], + TCG_AREG0); + #endif + tgen_calli(s, (tcg_target_ulong)qemu_st_helpers[s_bits]); +@@ -1521,13 +1523,11 @@ static void tcg_prepare_qemu_ldst(TCGContext* s, TCGReg data_reg, + tcg_out_movi(s, TCG_TYPE_I32, arg1, mem_index); + #ifdef CONFIG_TCG_PASS_AREG0 + /* XXX/FIXME: suboptimal */ +- tcg_out_mov(s, TCG_TYPE_I32, tcg_target_call_iarg_regs[3], +- tcg_target_call_iarg_regs[2]); + tcg_out_mov(s, TCG_TYPE_I64, tcg_target_call_iarg_regs[2], + tcg_target_call_iarg_regs[1]); +- tcg_out_mov(s, TCG_TYPE_TL, tcg_target_call_iarg_regs[1], ++ tcg_out_mov(s, TCG_TYPE_I64, tcg_target_call_iarg_regs[1], + tcg_target_call_iarg_regs[0]); +- tcg_out_mov(s, TCG_TYPE_PTR, tcg_target_call_iarg_regs[0], ++ tcg_out_mov(s, TCG_TYPE_I64, tcg_target_call_iarg_regs[0], + TCG_AREG0); + #endif + tgen_calli(s, (tcg_target_ulong)qemu_ld_helpers[s_bits]); +-- +1.7.12.1 + diff --git a/0017-target-arm-Fix-potential-buffer-overflow.patch b/0017-target-arm-Fix-potential-buffer-overflow.patch new file mode 100644 index 0000000..6b9726e --- /dev/null +++ b/0017-target-arm-Fix-potential-buffer-overflow.patch @@ -0,0 +1,47 @@ +From e7c3f6b4365f3162f8e25d58f76410aca28719a2 Mon Sep 17 00:00:00 2001 +From: Stefan Weil +Date: Tue, 4 Sep 2012 07:35:57 +0200 +Subject: [PATCH] target-arm: Fix potential buffer overflow + +Report from smatch: + +target-arm/helper.c:651 arm946_prbs_read(6) error: + buffer overflow 'env->cp15.c6_region' 8 <= 8 +target-arm/helper.c:661 arm946_prbs_write(6) error: + buffer overflow 'env->cp15.c6_region' 8 <= 8 + +c7_region is an array with 8 elements, so the index must be less than 8. + +Signed-off-by: Stefan Weil +Reviewed-by: Peter Maydell +Signed-off-by: Aurelien Jarno +Signed-off-by: Michael Roth +--- + target-arm/helper.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/target-arm/helper.c b/target-arm/helper.c +index dceaa95..e27df96 100644 +--- a/target-arm/helper.c ++++ b/target-arm/helper.c +@@ -645,7 +645,7 @@ static int pmsav5_insn_ap_read(CPUARMState *env, const ARMCPRegInfo *ri, + static int arm946_prbs_read(CPUARMState *env, const ARMCPRegInfo *ri, + uint64_t *value) + { +- if (ri->crm > 8) { ++ if (ri->crm >= 8) { + return EXCP_UDEF; + } + *value = env->cp15.c6_region[ri->crm]; +@@ -655,7 +655,7 @@ static int arm946_prbs_read(CPUARMState *env, const ARMCPRegInfo *ri, + static int arm946_prbs_write(CPUARMState *env, const ARMCPRegInfo *ri, + uint64_t value) + { +- if (ri->crm > 8) { ++ if (ri->crm >= 8) { + return EXCP_UDEF; + } + env->cp15.c6_region[ri->crm] = value; +-- +1.7.12.1 + diff --git a/0018-tcg-optimize-split-expression-simplification.patch b/0018-tcg-optimize-split-expression-simplification.patch new file mode 100644 index 0000000..0dcd9b0 --- /dev/null +++ b/0018-tcg-optimize-split-expression-simplification.patch @@ -0,0 +1,57 @@ +From 16f29b266435c7eaffc5081c6bba4651d56a8ce8 Mon Sep 17 00:00:00 2001 +From: Aurelien Jarno +Date: Thu, 6 Sep 2012 16:47:13 +0200 +Subject: [PATCH] tcg/optimize: split expression simplification + +Split expression simplification in multiple parts so that a given op +can appear multiple times. This patch should not change anything. + +Reviewed-by: Richard Henderson +Signed-off-by: Aurelien Jarno +Signed-off-by: Michael Roth +--- + tcg/optimize.c | 14 +++++++++++++- + 1 file changed, 13 insertions(+), 1 deletion(-) + +diff --git a/tcg/optimize.c b/tcg/optimize.c +index 9c65474..63f970d 100644 +--- a/tcg/optimize.c ++++ b/tcg/optimize.c +@@ -322,7 +322,7 @@ static TCGArg *tcg_constant_folding(TCGContext *s, uint16_t *tcg_opc_ptr, + break; + } + +- /* Simplify expression if possible. */ ++ /* Simplify expression for "op r, a, 0 => mov r, a" cases */ + switch (op) { + CASE_OP_32_64(add): + CASE_OP_32_64(sub): +@@ -352,6 +352,12 @@ static TCGArg *tcg_constant_folding(TCGContext *s, uint16_t *tcg_opc_ptr, + continue; + } + break; ++ default: ++ break; ++ } ++ ++ /* Simplify expression for "op r, a, 0 => movi r, 0" cases */ ++ switch (op) { + CASE_OP_32_64(mul): + if ((temps[args[2]].state == TCG_TEMP_CONST + && temps[args[2]].val == 0)) { +@@ -362,6 +368,12 @@ static TCGArg *tcg_constant_folding(TCGContext *s, uint16_t *tcg_opc_ptr, + continue; + } + break; ++ default: ++ break; ++ } ++ ++ /* Simplify expression for "op r, a, a => mov r, a" cases */ ++ switch (op) { + CASE_OP_32_64(or): + CASE_OP_32_64(and): + if (args[1] == args[2]) { +-- +1.7.12.1 + diff --git a/0019-tcg-optimize-simplify-or-xor-r-a-0-cases.patch b/0019-tcg-optimize-simplify-or-xor-r-a-0-cases.patch new file mode 100644 index 0000000..4f9dd62 --- /dev/null +++ b/0019-tcg-optimize-simplify-or-xor-r-a-0-cases.patch @@ -0,0 +1,30 @@ +From f69f9bd1a7a095ee153eea5422651780aef178b0 Mon Sep 17 00:00:00 2001 +From: Aurelien Jarno +Date: Thu, 6 Sep 2012 16:47:14 +0200 +Subject: [PATCH] tcg/optimize: simplify or/xor r, a, 0 cases + +or/xor r, a, 0 is equivalent to a mov r, a. + +Reviewed-by: Richard Henderson +Signed-off-by: Aurelien Jarno +Signed-off-by: Michael Roth +--- + tcg/optimize.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/tcg/optimize.c b/tcg/optimize.c +index 63f970d..0db849e 100644 +--- a/tcg/optimize.c ++++ b/tcg/optimize.c +@@ -331,6 +331,8 @@ static TCGArg *tcg_constant_folding(TCGContext *s, uint16_t *tcg_opc_ptr, + CASE_OP_32_64(sar): + CASE_OP_32_64(rotl): + CASE_OP_32_64(rotr): ++ CASE_OP_32_64(or): ++ CASE_OP_32_64(xor): + if (temps[args[1]].state == TCG_TEMP_CONST) { + /* Proceed with possible constant folding. */ + break; +-- +1.7.12.1 + diff --git a/0020-tcg-optimize-simplify-and-r-a-0-cases.patch b/0020-tcg-optimize-simplify-and-r-a-0-cases.patch new file mode 100644 index 0000000..e609e66 --- /dev/null +++ b/0020-tcg-optimize-simplify-and-r-a-0-cases.patch @@ -0,0 +1,29 @@ +From f08c59ce7dee67a95cf06d9588b4312e7d071788 Mon Sep 17 00:00:00 2001 +From: Aurelien Jarno +Date: Thu, 6 Sep 2012 16:47:14 +0200 +Subject: [PATCH] tcg/optimize: simplify and r, a, 0 cases + +and r, a, 0 is equivalent to a movi r, 0. + +Reviewed-by: Richard Henderson +Signed-off-by: Aurelien Jarno +Signed-off-by: Michael Roth +--- + tcg/optimize.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/tcg/optimize.c b/tcg/optimize.c +index 0db849e..c12cb2b 100644 +--- a/tcg/optimize.c ++++ b/tcg/optimize.c +@@ -360,6 +360,7 @@ static TCGArg *tcg_constant_folding(TCGContext *s, uint16_t *tcg_opc_ptr, + + /* Simplify expression for "op r, a, 0 => movi r, 0" cases */ + switch (op) { ++ CASE_OP_32_64(and): + CASE_OP_32_64(mul): + if ((temps[args[2]].state == TCG_TEMP_CONST + && temps[args[2]].val == 0)) { +-- +1.7.12.1 + diff --git a/0021-tcg-optimize-simplify-shift-rot-r-0-a-movi-r-0-cases.patch b/0021-tcg-optimize-simplify-shift-rot-r-0-a-movi-r-0-cases.patch new file mode 100644 index 0000000..d77bf30 --- /dev/null +++ b/0021-tcg-optimize-simplify-shift-rot-r-0-a-movi-r-0-cases.patch @@ -0,0 +1,48 @@ +From bbed332c7ad12e9885d3f457f366fa0b29445dcd Mon Sep 17 00:00:00 2001 +From: Aurelien Jarno +Date: Thu, 6 Sep 2012 16:47:14 +0200 +Subject: [PATCH] tcg/optimize: simplify shift/rot r, 0, a => movi r, 0 cases + +shift/rot r, 0, a is equivalent to movi r, 0. + +Reviewed-by: Richard Henderson +Signed-off-by: Aurelien Jarno +Signed-off-by: Michael Roth +--- + tcg/optimize.c | 20 ++++++++++++++++++++ + 1 file changed, 20 insertions(+) + +diff --git a/tcg/optimize.c b/tcg/optimize.c +index c12cb2b..1698ba3 100644 +--- a/tcg/optimize.c ++++ b/tcg/optimize.c +@@ -322,6 +322,26 @@ static TCGArg *tcg_constant_folding(TCGContext *s, uint16_t *tcg_opc_ptr, + break; + } + ++ /* Simplify expressions for "shift/rot r, 0, a => movi r, 0" */ ++ switch (op) { ++ CASE_OP_32_64(shl): ++ CASE_OP_32_64(shr): ++ CASE_OP_32_64(sar): ++ CASE_OP_32_64(rotl): ++ CASE_OP_32_64(rotr): ++ if (temps[args[1]].state == TCG_TEMP_CONST ++ && temps[args[1]].val == 0) { ++ gen_opc_buf[op_index] = op_to_movi(op); ++ tcg_opt_gen_movi(gen_args, args[0], 0, nb_temps, nb_globals); ++ args += 3; ++ gen_args += 2; ++ continue; ++ } ++ break; ++ default: ++ break; ++ } ++ + /* Simplify expression for "op r, a, 0 => mov r, a" cases */ + switch (op) { + CASE_OP_32_64(add): +-- +1.7.12.1 + diff --git a/0022-tcg-optimize-swap-brcond-setcond-arguments-when-poss.patch b/0022-tcg-optimize-swap-brcond-setcond-arguments-when-poss.patch new file mode 100644 index 0000000..19135ee --- /dev/null +++ b/0022-tcg-optimize-swap-brcond-setcond-arguments-when-poss.patch @@ -0,0 +1,49 @@ +From 1127ad0d084f0cef11b5658b3dbbf8505d8d3af0 Mon Sep 17 00:00:00 2001 +From: Aurelien Jarno +Date: Thu, 6 Sep 2012 16:47:14 +0200 +Subject: [PATCH] tcg/optimize: swap brcond/setcond arguments when possible + +brcond and setcond ops are not commutative, but it's easy to compute the +new condition after swapping the arguments. Try to always put the constant +argument in second position like for commutative ops, to help backends to +generate better code. + +Reviewed-by: Richard Henderson +Signed-off-by: Aurelien Jarno +Signed-off-by: Michael Roth +--- + tcg/optimize.c | 18 ++++++++++++++++++ + 1 file changed, 18 insertions(+) + +diff --git a/tcg/optimize.c b/tcg/optimize.c +index 1698ba3..7debc8a 100644 +--- a/tcg/optimize.c ++++ b/tcg/optimize.c +@@ -318,6 +318,24 @@ static TCGArg *tcg_constant_folding(TCGContext *s, uint16_t *tcg_opc_ptr, + args[2] = tmp; + } + 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; ++ 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; ++ args[3] = tcg_swap_cond(args[3]); ++ } ++ break; + default: + break; + } +-- +1.7.12.1 + diff --git a/0023-tcg-optimize-add-constant-folding-for-setcond.patch b/0023-tcg-optimize-add-constant-folding-for-setcond.patch new file mode 100644 index 0000000..0968e1e --- /dev/null +++ b/0023-tcg-optimize-add-constant-folding-for-setcond.patch @@ -0,0 +1,114 @@ +From 1bbb9ac3e775b55d0d5c57c209f47e742a9be810 Mon Sep 17 00:00:00 2001 +From: Aurelien Jarno +Date: Thu, 6 Sep 2012 16:47:14 +0200 +Subject: [PATCH] tcg/optimize: add constant folding for setcond + +Reviewed-by: Richard Henderson +Signed-off-by: Aurelien Jarno +Signed-off-by: Michael Roth +--- + tcg/optimize.c | 81 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 81 insertions(+) + +diff --git a/tcg/optimize.c b/tcg/optimize.c +index 7debc8a..1cb1f36 100644 +--- a/tcg/optimize.c ++++ b/tcg/optimize.c +@@ -267,6 +267,67 @@ static TCGArg do_constant_folding(TCGOpcode op, TCGArg x, TCGArg y) + return res; + } + ++static TCGArg do_constant_folding_cond(TCGOpcode op, TCGArg x, ++ TCGArg y, TCGCond c) ++{ ++ switch (op_bits(op)) { ++ case 32: ++ switch (c) { ++ case TCG_COND_EQ: ++ return (uint32_t)x == (uint32_t)y; ++ case TCG_COND_NE: ++ return (uint32_t)x != (uint32_t)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 (uint32_t)x < (uint32_t)y; ++ case TCG_COND_GEU: ++ return (uint32_t)x >= (uint32_t)y; ++ case TCG_COND_LEU: ++ return (uint32_t)x <= (uint32_t)y; ++ case TCG_COND_GTU: ++ return (uint32_t)x > (uint32_t)y; ++ } ++ break; ++ case 64: ++ switch (c) { ++ case TCG_COND_EQ: ++ return (uint64_t)x == (uint64_t)y; ++ case TCG_COND_NE: ++ return (uint64_t)x != (uint64_t)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 (uint64_t)x < (uint64_t)y; ++ case TCG_COND_GEU: ++ return (uint64_t)x >= (uint64_t)y; ++ case TCG_COND_LEU: ++ return (uint64_t)x <= (uint64_t)y; ++ case TCG_COND_GTU: ++ return (uint64_t)x > (uint64_t)y; ++ } ++ break; ++ } ++ ++ fprintf(stderr, ++ "Unrecognized bitness %d or condition %d in " ++ "do_constant_folding_cond.\n", op_bits(op), c); ++ tcg_abort(); ++} ++ ++ + /* 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) +@@ -522,6 +583,26 @@ static TCGArg *tcg_constant_folding(TCGContext *s, uint16_t *tcg_opc_ptr, + args += 3; + break; + } ++ CASE_OP_32_64(setcond): ++ if (temps[args[1]].state == TCG_TEMP_CONST ++ && temps[args[2]].state == TCG_TEMP_CONST) { ++ gen_opc_buf[op_index] = op_to_movi(op); ++ tmp = do_constant_folding_cond(op, temps[args[1]].val, ++ temps[args[2]].val, args[3]); ++ tcg_opt_gen_movi(gen_args, args[0], tmp, nb_temps, nb_globals); ++ gen_args += 2; ++ args += 4; ++ break; ++ } else { ++ reset_temp(args[0], nb_temps, nb_globals); ++ 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; ++ } + 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))) { +-- +1.7.12.1 + diff --git a/0024-tcg-optimize-add-constant-folding-for-brcond.patch b/0024-tcg-optimize-add-constant-folding-for-brcond.patch new file mode 100644 index 0000000..0b4c73b --- /dev/null +++ b/0024-tcg-optimize-add-constant-folding-for-brcond.patch @@ -0,0 +1,60 @@ +From 98dc31743b94d5719c02c589e7cd652e95570b25 Mon Sep 17 00:00:00 2001 +From: Aurelien Jarno +Date: Thu, 6 Sep 2012 16:47:14 +0200 +Subject: [PATCH] tcg/optimize: add constant folding for brcond + +Reviewed-by: Richard Henderson +Signed-off-by: Aurelien Jarno +Signed-off-by: Michael Roth +--- + tcg/optimize.c | 27 ++++++++++++++++++++++++++- + 1 file changed, 26 insertions(+), 1 deletion(-) + +diff --git a/tcg/optimize.c b/tcg/optimize.c +index 1cb1f36..156e8d9 100644 +--- a/tcg/optimize.c ++++ b/tcg/optimize.c +@@ -603,6 +603,32 @@ static TCGArg *tcg_constant_folding(TCGContext *s, uint16_t *tcg_opc_ptr, + args += 4; + break; + } ++ CASE_OP_32_64(brcond): ++ if (temps[args[0]].state == TCG_TEMP_CONST ++ && temps[args[1]].state == TCG_TEMP_CONST) { ++ if (do_constant_folding_cond(op, temps[args[0]].val, ++ temps[args[1]].val, args[2])) { ++ memset(temps, 0, nb_temps * sizeof(struct tcg_temp_info)); ++ gen_opc_buf[op_index] = INDEX_op_br; ++ gen_args[0] = args[3]; ++ gen_args += 1; ++ args += 4; ++ } else { ++ gen_opc_buf[op_index] = INDEX_op_nop; ++ args += 4; ++ } ++ break; ++ } else { ++ memset(temps, 0, nb_temps * sizeof(struct tcg_temp_info)); ++ reset_temp(args[0], nb_temps, nb_globals); ++ 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; ++ } + 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))) { +@@ -624,7 +650,6 @@ static TCGArg *tcg_constant_folding(TCGContext *s, uint16_t *tcg_opc_ptr, + case INDEX_op_set_label: + case INDEX_op_jmp: + case INDEX_op_br: +- CASE_OP_32_64(brcond): + memset(temps, 0, nb_temps * sizeof(struct tcg_temp_info)); + for (i = 0; i < def->nb_args; i++) { + *gen_args = *args; +-- +1.7.12.1 + diff --git a/0025-tcg-optimize-fix-if-else-break-coding-style.patch b/0025-tcg-optimize-fix-if-else-break-coding-style.patch new file mode 100644 index 0000000..ef77b6e --- /dev/null +++ b/0025-tcg-optimize-fix-if-else-break-coding-style.patch @@ -0,0 +1,144 @@ +From b7dc881b44c3698a0a81d226d6012d3c5833fd29 Mon Sep 17 00:00:00 2001 +From: Aurelien Jarno +Date: Fri, 7 Sep 2012 12:24:32 +0200 +Subject: [PATCH] tcg/optimize: fix if/else/break coding style + +optimizer.c contains some cases were the break is appearing in both the +if and the else parts. Fix that by moving it to the outer part. Also +move some common code there. + +Reviewed-by: Richard Henderson +Signed-off-by: Aurelien Jarno +Signed-off-by: Michael Roth +--- + tcg/optimize.c | 34 +++++++++++----------------------- + 1 file changed, 11 insertions(+), 23 deletions(-) + +diff --git a/tcg/optimize.c b/tcg/optimize.c +index 156e8d9..fba0ed9 100644 +--- a/tcg/optimize.c ++++ b/tcg/optimize.c +@@ -441,15 +441,14 @@ static TCGArg *tcg_constant_folding(TCGContext *s, uint16_t *tcg_opc_ptr, + if ((temps[args[0]].state == TCG_TEMP_COPY + && temps[args[0]].val == args[1]) + || args[0] == args[1]) { +- args += 3; + gen_opc_buf[op_index] = INDEX_op_nop; + } else { + gen_opc_buf[op_index] = op_to_mov(op); + tcg_opt_gen_mov(s, gen_args, args[0], args[1], + nb_temps, nb_globals); + gen_args += 2; +- args += 3; + } ++ args += 3; + continue; + } + break; +@@ -480,15 +479,14 @@ static TCGArg *tcg_constant_folding(TCGContext *s, uint16_t *tcg_opc_ptr, + CASE_OP_32_64(and): + if (args[1] == args[2]) { + if (args[1] == args[0]) { +- args += 3; + gen_opc_buf[op_index] = INDEX_op_nop; + } else { + gen_opc_buf[op_index] = op_to_mov(op); + tcg_opt_gen_mov(s, gen_args, args[0], args[1], nb_temps, + nb_globals); + gen_args += 2; +- args += 3; + } ++ args += 3; + continue; + } + break; +@@ -538,17 +536,14 @@ 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, nb_temps, nb_globals); +- gen_args += 2; +- args += 2; +- break; + } else { + reset_temp(args[0], nb_temps, nb_globals); + gen_args[0] = args[0]; + gen_args[1] = args[1]; +- gen_args += 2; +- args += 2; +- break; + } ++ gen_args += 2; ++ args += 2; ++ break; + CASE_OP_32_64(add): + CASE_OP_32_64(sub): + CASE_OP_32_64(mul): +@@ -572,17 +567,15 @@ 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, nb_temps, nb_globals); + gen_args += 2; +- args += 3; +- break; + } else { + reset_temp(args[0], nb_temps, nb_globals); + gen_args[0] = args[0]; + gen_args[1] = args[1]; + gen_args[2] = args[2]; + gen_args += 3; +- args += 3; +- break; + } ++ args += 3; ++ break; + CASE_OP_32_64(setcond): + if (temps[args[1]].state == TCG_TEMP_CONST + && temps[args[2]].state == TCG_TEMP_CONST) { +@@ -591,8 +584,6 @@ static TCGArg *tcg_constant_folding(TCGContext *s, uint16_t *tcg_opc_ptr, + temps[args[2]].val, args[3]); + tcg_opt_gen_movi(gen_args, args[0], tmp, nb_temps, nb_globals); + gen_args += 2; +- args += 4; +- break; + } else { + reset_temp(args[0], nb_temps, nb_globals); + gen_args[0] = args[0]; +@@ -600,9 +591,9 @@ static TCGArg *tcg_constant_folding(TCGContext *s, uint16_t *tcg_opc_ptr, + gen_args[2] = args[2]; + gen_args[3] = args[3]; + gen_args += 4; +- args += 4; +- break; + } ++ args += 4; ++ break; + CASE_OP_32_64(brcond): + if (temps[args[0]].state == TCG_TEMP_CONST + && temps[args[1]].state == TCG_TEMP_CONST) { +@@ -612,12 +603,9 @@ static TCGArg *tcg_constant_folding(TCGContext *s, uint16_t *tcg_opc_ptr, + gen_opc_buf[op_index] = INDEX_op_br; + gen_args[0] = args[3]; + gen_args += 1; +- args += 4; + } else { + gen_opc_buf[op_index] = INDEX_op_nop; +- args += 4; + } +- break; + } else { + memset(temps, 0, nb_temps * sizeof(struct tcg_temp_info)); + reset_temp(args[0], nb_temps, nb_globals); +@@ -626,9 +614,9 @@ static TCGArg *tcg_constant_folding(TCGContext *s, uint16_t *tcg_opc_ptr, + gen_args[2] = args[2]; + gen_args[3] = args[3]; + gen_args += 4; +- args += 4; +- break; + } ++ args += 4; ++ break; + 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))) { +-- +1.7.12.1 + diff --git a/0026-target-s390x-avoid-cpu_single_env.patch b/0026-target-s390x-avoid-cpu_single_env.patch new file mode 100644 index 0000000..2b3e6a4 --- /dev/null +++ b/0026-target-s390x-avoid-cpu_single_env.patch @@ -0,0 +1,1337 @@ +From d8503917ec9ba86829387f05db7da2eb6fa8123f Mon Sep 17 00:00:00 2001 +From: Blue Swirl +Date: Sat, 8 Sep 2012 11:15:37 +0000 +Subject: [PATCH] target-s390x: avoid cpu_single_env + +Pass around CPUState instead of using global cpu_single_env. + +Signed-off-by: Blue Swirl +Signed-off-by: Michael Roth +--- + target-s390x/translate.c | 356 ++++++++++++++++++++++++----------------------- + 1 file changed, 183 insertions(+), 173 deletions(-) + +diff --git a/target-s390x/translate.c b/target-s390x/translate.c +index 66119cd..3214783 100644 +--- a/target-s390x/translate.c ++++ b/target-s390x/translate.c +@@ -274,21 +274,21 @@ static inline void potential_page_fault(DisasContext *s) + #endif + } + +-static inline uint64_t ld_code2(uint64_t pc) ++static inline uint64_t ld_code2(CPUS390XState *env, uint64_t pc) + { +- return (uint64_t)cpu_lduw_code(cpu_single_env, pc); ++ return (uint64_t)cpu_lduw_code(env, pc); + } + +-static inline uint64_t ld_code4(uint64_t pc) ++static inline uint64_t ld_code4(CPUS390XState *env, uint64_t pc) + { +- return (uint64_t)cpu_ldl_code(cpu_single_env, pc); ++ return (uint64_t)cpu_ldl_code(env, pc); + } + +-static inline uint64_t ld_code6(uint64_t pc) ++static inline uint64_t ld_code6(CPUS390XState *env, uint64_t pc) + { + uint64_t opc; +- opc = (uint64_t)cpu_lduw_code(cpu_single_env, pc) << 32; +- opc |= (uint64_t)(uint32_t)cpu_ldl_code(cpu_single_env, pc + 2); ++ opc = (uint64_t)cpu_lduw_code(env, pc) << 32; ++ opc |= (uint64_t)(uint32_t)cpu_ldl_code(env, pc + 2); + return opc; + } + +@@ -319,7 +319,7 @@ static inline void gen_debug(DisasContext *s) + + #ifdef CONFIG_USER_ONLY + +-static void gen_illegal_opcode(DisasContext *s, int ilc) ++static void gen_illegal_opcode(CPUS390XState *env, DisasContext *s, int ilc) + { + TCGv_i32 tmp = tcg_const_i32(EXCP_SPEC); + update_psw_addr(s); +@@ -331,20 +331,20 @@ static void gen_illegal_opcode(DisasContext *s, int ilc) + + #else /* CONFIG_USER_ONLY */ + +-static void debug_print_inst(DisasContext *s, int ilc) ++static void debug_print_inst(CPUS390XState *env, DisasContext *s, int ilc) + { + #ifdef DEBUG_ILLEGAL_INSTRUCTIONS + uint64_t inst = 0; + + switch (ilc & 3) { + case 1: +- inst = ld_code2(s->pc); ++ inst = ld_code2(env, s->pc); + break; + case 2: +- inst = ld_code4(s->pc); ++ inst = ld_code4(env, s->pc); + break; + case 3: +- inst = ld_code6(s->pc); ++ inst = ld_code6(env, s->pc); + break; + } + +@@ -353,11 +353,12 @@ static void debug_print_inst(DisasContext *s, int ilc) + #endif + } + +-static void gen_program_exception(DisasContext *s, int ilc, int code) ++static void gen_program_exception(CPUS390XState *env, DisasContext *s, int ilc, ++ int code) + { + TCGv_i32 tmp; + +- debug_print_inst(s, ilc); ++ debug_print_inst(env, s, ilc); + + /* remember what pgm exeption this was */ + tmp = tcg_const_i32(code); +@@ -385,20 +386,21 @@ static void gen_program_exception(DisasContext *s, int ilc, int code) + } + + +-static void gen_illegal_opcode(DisasContext *s, int ilc) ++static void gen_illegal_opcode(CPUS390XState *env, DisasContext *s, int ilc) + { +- gen_program_exception(s, ilc, PGM_SPECIFICATION); ++ gen_program_exception(env, s, ilc, PGM_SPECIFICATION); + } + +-static void gen_privileged_exception(DisasContext *s, int ilc) ++static void gen_privileged_exception(CPUS390XState *env, DisasContext *s, ++ int ilc) + { +- gen_program_exception(s, ilc, PGM_PRIVILEGED); ++ gen_program_exception(env, s, ilc, PGM_PRIVILEGED); + } + +-static void check_privileged(DisasContext *s, int ilc) ++static void check_privileged(CPUS390XState *env, DisasContext *s, int ilc) + { + if (s->tb->flags & (PSW_MASK_PSTATE >> 32)) { +- gen_privileged_exception(s, ilc); ++ gen_privileged_exception(env, s, ilc); + } + } + +@@ -1460,7 +1462,8 @@ static void gen_op_clc(DisasContext *s, int l, TCGv_i64 s1, TCGv_i64 s2) + set_cc_static(s); + } + +-static void disas_e3(DisasContext* s, int op, int r1, int x2, int b2, int d2) ++static void disas_e3(CPUS390XState *env, DisasContext* s, int op, int r1, ++ int x2, int b2, int d2) + { + TCGv_i64 addr, tmp, tmp2, tmp3, tmp4; + TCGv_i32 tmp32_1, tmp32_2, tmp32_3; +@@ -1925,14 +1928,14 @@ static void disas_e3(DisasContext* s, int op, int r1, int x2, int b2, int d2) + break; + default: + LOG_DISAS("illegal e3 operation 0x%x\n", op); +- gen_illegal_opcode(s, 3); ++ gen_illegal_opcode(env, s, 3); + break; + } + tcg_temp_free_i64(addr); + } + + #ifndef CONFIG_USER_ONLY +-static void disas_e5(DisasContext* s, uint64_t insn) ++static void disas_e5(CPUS390XState *env, DisasContext* s, uint64_t insn) + { + TCGv_i64 tmp, tmp2; + int op = (insn >> 32) & 0xff; +@@ -1950,7 +1953,7 @@ static void disas_e5(DisasContext* s, uint64_t insn) + break; + default: + LOG_DISAS("illegal e5 operation 0x%x\n", op); +- gen_illegal_opcode(s, 3); ++ gen_illegal_opcode(env, s, 3); + break; + } + +@@ -1959,7 +1962,8 @@ static void disas_e5(DisasContext* s, uint64_t insn) + } + #endif + +-static void disas_eb(DisasContext *s, int op, int r1, int r3, int b2, int d2) ++static void disas_eb(CPUS390XState *env, DisasContext *s, int op, int r1, ++ int r3, int b2, int d2) + { + TCGv_i64 tmp, tmp2, tmp3, tmp4; + TCGv_i32 tmp32_1, tmp32_2; +@@ -2102,7 +2106,7 @@ do_mh: + #ifndef CONFIG_USER_ONLY + case 0x2f: /* LCTLG R1,R3,D2(B2) [RSE] */ + /* Load Control */ +- check_privileged(s, ilc); ++ check_privileged(env, s, ilc); + tmp = get_address(s, 0, b2, d2); + tmp32_1 = tcg_const_i32(r1); + tmp32_2 = tcg_const_i32(r3); +@@ -2114,7 +2118,7 @@ do_mh: + break; + case 0x25: /* STCTG R1,R3,D2(B2) [RSE] */ + /* Store Control */ +- check_privileged(s, ilc); ++ check_privileged(env, s, ilc); + tmp = get_address(s, 0, b2, d2); + tmp32_1 = tcg_const_i32(r1); + tmp32_2 = tcg_const_i32(r3); +@@ -2191,13 +2195,13 @@ do_mh: + break; + default: + LOG_DISAS("illegal eb operation 0x%x\n", op); +- gen_illegal_opcode(s, ilc); ++ gen_illegal_opcode(env, s, ilc); + break; + } + } + +-static void disas_ed(DisasContext *s, int op, int r1, int x2, int b2, int d2, +- int r1b) ++static void disas_ed(CPUS390XState *env, DisasContext *s, int op, int r1, ++ int x2, int b2, int d2, int r1b) + { + TCGv_i32 tmp_r1, tmp32; + TCGv_i64 addr, tmp; +@@ -2311,14 +2315,15 @@ static void disas_ed(DisasContext *s, int op, int r1, int x2, int b2, int d2, + break; + default: + LOG_DISAS("illegal ed operation 0x%x\n", op); +- gen_illegal_opcode(s, 3); ++ gen_illegal_opcode(env, s, 3); + return; + } + tcg_temp_free_i32(tmp_r1); + tcg_temp_free_i64(addr); + } + +-static void disas_a5(DisasContext *s, int op, int r1, int i2) ++static void disas_a5(CPUS390XState *env, DisasContext *s, int op, int r1, ++ int i2) + { + TCGv_i64 tmp, tmp2; + TCGv_i32 tmp32; +@@ -2467,12 +2472,13 @@ static void disas_a5(DisasContext *s, int op, int r1, int i2) + break; + default: + LOG_DISAS("illegal a5 operation 0x%x\n", op); +- gen_illegal_opcode(s, 2); ++ gen_illegal_opcode(env, s, 2); + return; + } + } + +-static void disas_a7(DisasContext *s, int op, int r1, int i2) ++static void disas_a7(CPUS390XState *env, DisasContext *s, int op, int r1, ++ int i2) + { + TCGv_i64 tmp, tmp2; + TCGv_i32 tmp32_1, tmp32_2, tmp32_3; +@@ -2604,12 +2610,13 @@ static void disas_a7(DisasContext *s, int op, int r1, int i2) + break; + default: + LOG_DISAS("illegal a7 operation 0x%x\n", op); +- gen_illegal_opcode(s, 2); ++ gen_illegal_opcode(env, s, 2); + return; + } + } + +-static void disas_b2(DisasContext *s, int op, uint32_t insn) ++static void disas_b2(CPUS390XState *env, DisasContext *s, int op, ++ uint32_t insn) + { + TCGv_i64 tmp, tmp2, tmp3; + TCGv_i32 tmp32_1, tmp32_2, tmp32_3; +@@ -2708,7 +2715,7 @@ static void disas_b2(DisasContext *s, int op, uint32_t insn) + #ifndef CONFIG_USER_ONLY + case 0x02: /* STIDP D2(B2) [S] */ + /* Store CPU ID */ +- check_privileged(s, ilc); ++ check_privileged(env, s, ilc); + decode_rs(s, insn, &r1, &r3, &b2, &d2); + tmp = get_address(s, 0, b2, d2); + potential_page_fault(s); +@@ -2717,7 +2724,7 @@ static void disas_b2(DisasContext *s, int op, uint32_t insn) + break; + case 0x04: /* SCK D2(B2) [S] */ + /* Set Clock */ +- check_privileged(s, ilc); ++ check_privileged(env, s, ilc); + decode_rs(s, insn, &r1, &r3, &b2, &d2); + tmp = get_address(s, 0, b2, d2); + potential_page_fault(s); +@@ -2736,7 +2743,7 @@ static void disas_b2(DisasContext *s, int op, uint32_t insn) + break; + case 0x06: /* SCKC D2(B2) [S] */ + /* Set Clock Comparator */ +- check_privileged(s, ilc); ++ check_privileged(env, s, ilc); + decode_rs(s, insn, &r1, &r3, &b2, &d2); + tmp = get_address(s, 0, b2, d2); + potential_page_fault(s); +@@ -2745,7 +2752,7 @@ static void disas_b2(DisasContext *s, int op, uint32_t insn) + break; + case 0x07: /* STCKC D2(B2) [S] */ + /* Store Clock Comparator */ +- check_privileged(s, ilc); ++ check_privileged(env, s, ilc); + decode_rs(s, insn, &r1, &r3, &b2, &d2); + tmp = get_address(s, 0, b2, d2); + potential_page_fault(s); +@@ -2754,7 +2761,7 @@ static void disas_b2(DisasContext *s, int op, uint32_t insn) + break; + case 0x08: /* SPT D2(B2) [S] */ + /* Set CPU Timer */ +- check_privileged(s, ilc); ++ check_privileged(env, s, ilc); + decode_rs(s, insn, &r1, &r3, &b2, &d2); + tmp = get_address(s, 0, b2, d2); + potential_page_fault(s); +@@ -2763,7 +2770,7 @@ static void disas_b2(DisasContext *s, int op, uint32_t insn) + break; + case 0x09: /* STPT D2(B2) [S] */ + /* Store CPU Timer */ +- check_privileged(s, ilc); ++ check_privileged(env, s, ilc); + decode_rs(s, insn, &r1, &r3, &b2, &d2); + tmp = get_address(s, 0, b2, d2); + potential_page_fault(s); +@@ -2772,7 +2779,7 @@ static void disas_b2(DisasContext *s, int op, uint32_t insn) + break; + case 0x0a: /* SPKA D2(B2) [S] */ + /* Set PSW Key from Address */ +- check_privileged(s, ilc); ++ check_privileged(env, s, ilc); + decode_rs(s, insn, &r1, &r3, &b2, &d2); + tmp = get_address(s, 0, b2, d2); + tmp2 = tcg_temp_new_i64(); +@@ -2784,12 +2791,12 @@ static void disas_b2(DisasContext *s, int op, uint32_t insn) + break; + case 0x0d: /* PTLB [S] */ + /* Purge TLB */ +- check_privileged(s, ilc); ++ check_privileged(env, s, ilc); + gen_helper_ptlb(cpu_env); + break; + case 0x10: /* SPX D2(B2) [S] */ + /* Set Prefix Register */ +- check_privileged(s, ilc); ++ check_privileged(env, s, ilc); + decode_rs(s, insn, &r1, &r3, &b2, &d2); + tmp = get_address(s, 0, b2, d2); + potential_page_fault(s); +@@ -2798,7 +2805,7 @@ static void disas_b2(DisasContext *s, int op, uint32_t insn) + break; + case 0x11: /* STPX D2(B2) [S] */ + /* Store Prefix */ +- check_privileged(s, ilc); ++ check_privileged(env, s, ilc); + decode_rs(s, insn, &r1, &r3, &b2, &d2); + tmp = get_address(s, 0, b2, d2); + tmp2 = tcg_temp_new_i64(); +@@ -2809,7 +2816,7 @@ static void disas_b2(DisasContext *s, int op, uint32_t insn) + break; + case 0x12: /* STAP D2(B2) [S] */ + /* Store CPU Address */ +- check_privileged(s, ilc); ++ check_privileged(env, s, ilc); + decode_rs(s, insn, &r1, &r3, &b2, &d2); + tmp = get_address(s, 0, b2, d2); + tmp2 = tcg_temp_new_i64(); +@@ -2823,7 +2830,7 @@ static void disas_b2(DisasContext *s, int op, uint32_t insn) + break; + case 0x21: /* IPTE R1,R2 [RRE] */ + /* Invalidate PTE */ +- check_privileged(s, ilc); ++ check_privileged(env, s, ilc); + r1 = (insn >> 4) & 0xf; + r2 = insn & 0xf; + tmp = load_reg(r1); +@@ -2834,7 +2841,7 @@ static void disas_b2(DisasContext *s, int op, uint32_t insn) + break; + case 0x29: /* ISKE R1,R2 [RRE] */ + /* Insert Storage Key Extended */ +- check_privileged(s, ilc); ++ check_privileged(env, s, ilc); + r1 = (insn >> 4) & 0xf; + r2 = insn & 0xf; + tmp = load_reg(r2); +@@ -2846,7 +2853,7 @@ static void disas_b2(DisasContext *s, int op, uint32_t insn) + break; + case 0x2a: /* RRBE R1,R2 [RRE] */ + /* Set Storage Key Extended */ +- check_privileged(s, ilc); ++ check_privileged(env, s, ilc); + r1 = (insn >> 4) & 0xf; + r2 = insn & 0xf; + tmp32_1 = load_reg32(r1); +@@ -2858,7 +2865,7 @@ static void disas_b2(DisasContext *s, int op, uint32_t insn) + break; + case 0x2b: /* SSKE R1,R2 [RRE] */ + /* Set Storage Key Extended */ +- check_privileged(s, ilc); ++ check_privileged(env, s, ilc); + r1 = (insn >> 4) & 0xf; + r2 = insn & 0xf; + tmp32_1 = load_reg32(r1); +@@ -2869,12 +2876,12 @@ static void disas_b2(DisasContext *s, int op, uint32_t insn) + break; + case 0x34: /* STCH ? */ + /* Store Subchannel */ +- check_privileged(s, ilc); ++ check_privileged(env, s, ilc); + gen_op_movi_cc(s, 3); + break; + case 0x46: /* STURA R1,R2 [RRE] */ + /* Store Using Real Address */ +- check_privileged(s, ilc); ++ check_privileged(env, s, ilc); + r1 = (insn >> 4) & 0xf; + r2 = insn & 0xf; + tmp32_1 = load_reg32(r1); +@@ -2886,7 +2893,7 @@ static void disas_b2(DisasContext *s, int op, uint32_t insn) + break; + case 0x50: /* CSP R1,R2 [RRE] */ + /* Compare And Swap And Purge */ +- check_privileged(s, ilc); ++ check_privileged(env, s, ilc); + r1 = (insn >> 4) & 0xf; + r2 = insn & 0xf; + tmp32_1 = tcg_const_i32(r1); +@@ -2898,7 +2905,7 @@ static void disas_b2(DisasContext *s, int op, uint32_t insn) + break; + case 0x5f: /* CHSC ? */ + /* Channel Subsystem Call */ +- check_privileged(s, ilc); ++ check_privileged(env, s, ilc); + gen_op_movi_cc(s, 3); + break; + case 0x78: /* STCKE D2(B2) [S] */ +@@ -2912,7 +2919,7 @@ static void disas_b2(DisasContext *s, int op, uint32_t insn) + break; + case 0x79: /* SACF D2(B2) [S] */ + /* Store Clock Extended */ +- check_privileged(s, ilc); ++ check_privileged(env, s, ilc); + decode_rs(s, insn, &r1, &r3, &b2, &d2); + tmp = get_address(s, 0, b2, d2); + potential_page_fault(s); +@@ -2924,7 +2931,7 @@ static void disas_b2(DisasContext *s, int op, uint32_t insn) + s->is_jmp = DISAS_EXCP; + break; + case 0x7d: /* STSI D2,(B2) [S] */ +- check_privileged(s, ilc); ++ check_privileged(env, s, ilc); + decode_rs(s, insn, &r1, &r3, &b2, &d2); + tmp = get_address(s, 0, b2, d2); + tmp32_1 = load_reg32(0); +@@ -2950,7 +2957,7 @@ static void disas_b2(DisasContext *s, int op, uint32_t insn) + break; + case 0xb1: /* STFL D2(B2) [S] */ + /* Store Facility List (CPU features) at 200 */ +- check_privileged(s, ilc); ++ check_privileged(env, s, ilc); + tmp2 = tcg_const_i64(0xc0000000); + tmp = tcg_const_i64(200); + tcg_gen_qemu_st32(tmp2, tmp, get_mem_index(s)); +@@ -2959,7 +2966,7 @@ static void disas_b2(DisasContext *s, int op, uint32_t insn) + break; + case 0xb2: /* LPSWE D2(B2) [S] */ + /* Load PSW Extended */ +- check_privileged(s, ilc); ++ check_privileged(env, s, ilc); + decode_rs(s, insn, &r1, &r3, &b2, &d2); + tmp = get_address(s, 0, b2, d2); + tmp2 = tcg_temp_new_i64(); +@@ -2976,7 +2983,7 @@ static void disas_b2(DisasContext *s, int op, uint32_t insn) + break; + case 0x20: /* SERVC R1,R2 [RRE] */ + /* SCLP Service call (PV hypercall) */ +- check_privileged(s, ilc); ++ check_privileged(env, s, ilc); + potential_page_fault(s); + tmp32_1 = load_reg32(r2); + tmp = load_reg(r1); +@@ -2988,12 +2995,13 @@ static void disas_b2(DisasContext *s, int op, uint32_t insn) + #endif + default: + LOG_DISAS("illegal b2 operation 0x%x\n", op); +- gen_illegal_opcode(s, ilc); ++ gen_illegal_opcode(env, s, ilc); + break; + } + } + +-static void disas_b3(DisasContext *s, int op, int m3, int r1, int r2) ++static void disas_b3(CPUS390XState *env, DisasContext *s, int op, int m3, ++ int r1, int r2) + { + TCGv_i64 tmp; + TCGv_i32 tmp32_1, tmp32_2, tmp32_3; +@@ -3263,7 +3271,7 @@ static void disas_b3(DisasContext *s, int op, int m3, int r1, int r2) + break; + default: + LOG_DISAS("illegal b3 operation 0x%x\n", op); +- gen_illegal_opcode(s, 2); ++ gen_illegal_opcode(env, s, 2); + break; + } + +@@ -3271,7 +3279,8 @@ static void disas_b3(DisasContext *s, int op, int m3, int r1, int r2) + #undef FP_HELPER + } + +-static void disas_b9(DisasContext *s, int op, int r1, int r2) ++static void disas_b9(CPUS390XState *env, DisasContext *s, int op, int r1, ++ int r2) + { + TCGv_i64 tmp, tmp2, tmp3; + TCGv_i32 tmp32_1, tmp32_2, tmp32_3; +@@ -3654,12 +3663,12 @@ static void disas_b9(DisasContext *s, int op, int r1, int r2) + break; + default: + LOG_DISAS("illegal b9 operation 0x%x\n", op); +- gen_illegal_opcode(s, 2); ++ gen_illegal_opcode(env, s, 2); + break; + } + } + +-static void disas_c0(DisasContext *s, int op, int r1, int i2) ++static void disas_c0(CPUS390XState *env, DisasContext *s, int op, int r1, int i2) + { + TCGv_i64 tmp; + TCGv_i32 tmp32_1, tmp32_2; +@@ -3755,12 +3764,13 @@ static void disas_c0(DisasContext *s, int op, int r1, int i2) + break; + default: + LOG_DISAS("illegal c0 operation 0x%x\n", op); +- gen_illegal_opcode(s, 3); ++ gen_illegal_opcode(env, s, 3); + break; + } + } + +-static void disas_c2(DisasContext *s, int op, int r1, int i2) ++static void disas_c2(CPUS390XState *env, DisasContext *s, int op, int r1, ++ int i2) + { + TCGv_i64 tmp, tmp2, tmp3; + TCGv_i32 tmp32_1, tmp32_2, tmp32_3; +@@ -3832,7 +3842,7 @@ static void disas_c2(DisasContext *s, int op, int r1, int i2) + break; + default: + LOG_DISAS("illegal c2 operation 0x%x\n", op); +- gen_illegal_opcode(s, 3); ++ gen_illegal_opcode(env, s, 3); + break; + } + } +@@ -3854,7 +3864,7 @@ static void gen_and_or_xor_i32(int opc, TCGv_i32 tmp, TCGv_i32 tmp2) + } + } + +-static void disas_s390_insn(DisasContext *s) ++static void disas_s390_insn(CPUS390XState *env, DisasContext *s) + { + TCGv_i64 tmp, tmp2, tmp3, tmp4; + TCGv_i32 tmp32_1, tmp32_2, tmp32_3, tmp32_4; +@@ -3865,7 +3875,7 @@ static void disas_s390_insn(DisasContext *s) + int ilc; + int l1; + +- opc = cpu_ldub_code(cpu_single_env, s->pc); ++ opc = cpu_ldub_code(env, s->pc); + LOG_DISAS("opc 0x%x\n", opc); + + ilc = get_ilc(opc); +@@ -3873,12 +3883,12 @@ static void disas_s390_insn(DisasContext *s) + switch (opc) { + #ifndef CONFIG_USER_ONLY + case 0x01: /* SAM */ +- insn = ld_code2(s->pc); ++ insn = ld_code2(env, s->pc); + /* set addressing mode, but we only do 64bit anyways */ + break; + #endif + case 0x6: /* BCTR R1,R2 [RR] */ +- insn = ld_code2(s->pc); ++ insn = ld_code2(env, s->pc); + decode_rr(s, insn, &r1, &r2); + tmp32_1 = load_reg32(r1); + tcg_gen_subi_i32(tmp32_1, tmp32_1, 1); +@@ -3904,7 +3914,7 @@ static void disas_s390_insn(DisasContext *s) + } + break; + case 0x7: /* BCR M1,R2 [RR] */ +- insn = ld_code2(s->pc); ++ insn = ld_code2(env, s->pc); + decode_rr(s, insn, &r1, &r2); + if (r2) { + tmp = load_reg(r2); +@@ -3916,7 +3926,7 @@ static void disas_s390_insn(DisasContext *s) + } + break; + case 0xa: /* SVC I [RR] */ +- insn = ld_code2(s->pc); ++ insn = ld_code2(env, s->pc); + debug_insn(insn); + i = insn & 0xff; + update_psw_addr(s); +@@ -3933,7 +3943,7 @@ static void disas_s390_insn(DisasContext *s) + tcg_temp_free_i32(tmp32_3); + break; + case 0xd: /* BASR R1,R2 [RR] */ +- insn = ld_code2(s->pc); ++ insn = ld_code2(env, s->pc); + decode_rr(s, insn, &r1, &r2); + tmp = tcg_const_i64(pc_to_link_info(s, s->pc + 2)); + store_reg(r1, tmp); +@@ -3946,7 +3956,7 @@ static void disas_s390_insn(DisasContext *s) + tcg_temp_free_i64(tmp); + break; + case 0xe: /* MVCL R1,R2 [RR] */ +- insn = ld_code2(s->pc); ++ insn = ld_code2(env, s->pc); + decode_rr(s, insn, &r1, &r2); + tmp32_1 = tcg_const_i32(r1); + tmp32_2 = tcg_const_i32(r2); +@@ -3957,7 +3967,7 @@ static void disas_s390_insn(DisasContext *s) + tcg_temp_free_i32(tmp32_2); + break; + case 0x10: /* LPR R1,R2 [RR] */ +- insn = ld_code2(s->pc); ++ insn = ld_code2(env, s->pc); + decode_rr(s, insn, &r1, &r2); + tmp32_1 = load_reg32(r2); + set_cc_abs32(s, tmp32_1); +@@ -3966,7 +3976,7 @@ static void disas_s390_insn(DisasContext *s) + tcg_temp_free_i32(tmp32_1); + break; + case 0x11: /* LNR R1,R2 [RR] */ +- insn = ld_code2(s->pc); ++ insn = ld_code2(env, s->pc); + decode_rr(s, insn, &r1, &r2); + tmp32_1 = load_reg32(r2); + set_cc_nabs32(s, tmp32_1); +@@ -3975,7 +3985,7 @@ static void disas_s390_insn(DisasContext *s) + tcg_temp_free_i32(tmp32_1); + break; + case 0x12: /* LTR R1,R2 [RR] */ +- insn = ld_code2(s->pc); ++ insn = ld_code2(env, s->pc); + decode_rr(s, insn, &r1, &r2); + tmp32_1 = load_reg32(r2); + if (r1 != r2) { +@@ -3985,7 +3995,7 @@ static void disas_s390_insn(DisasContext *s) + tcg_temp_free_i32(tmp32_1); + break; + case 0x13: /* LCR R1,R2 [RR] */ +- insn = ld_code2(s->pc); ++ insn = ld_code2(env, s->pc); + decode_rr(s, insn, &r1, &r2); + tmp32_1 = load_reg32(r2); + tcg_gen_neg_i32(tmp32_1, tmp32_1); +@@ -3996,7 +4006,7 @@ static void disas_s390_insn(DisasContext *s) + case 0x14: /* NR R1,R2 [RR] */ + case 0x16: /* OR R1,R2 [RR] */ + case 0x17: /* XR R1,R2 [RR] */ +- insn = ld_code2(s->pc); ++ insn = ld_code2(env, s->pc); + decode_rr(s, insn, &r1, &r2); + tmp32_2 = load_reg32(r2); + tmp32_1 = load_reg32(r1); +@@ -4007,7 +4017,7 @@ static void disas_s390_insn(DisasContext *s) + tcg_temp_free_i32(tmp32_2); + break; + case 0x18: /* LR R1,R2 [RR] */ +- insn = ld_code2(s->pc); ++ insn = ld_code2(env, s->pc); + decode_rr(s, insn, &r1, &r2); + tmp32_1 = load_reg32(r2); + store_reg32(r1, tmp32_1); +@@ -4015,7 +4025,7 @@ static void disas_s390_insn(DisasContext *s) + break; + case 0x15: /* CLR R1,R2 [RR] */ + case 0x19: /* CR R1,R2 [RR] */ +- insn = ld_code2(s->pc); ++ insn = ld_code2(env, s->pc); + decode_rr(s, insn, &r1, &r2); + tmp32_1 = load_reg32(r1); + tmp32_2 = load_reg32(r2); +@@ -4029,7 +4039,7 @@ static void disas_s390_insn(DisasContext *s) + break; + case 0x1a: /* AR R1,R2 [RR] */ + case 0x1e: /* ALR R1,R2 [RR] */ +- insn = ld_code2(s->pc); ++ insn = ld_code2(env, s->pc); + decode_rr(s, insn, &r1, &r2); + tmp32_1 = load_reg32(r1); + tmp32_2 = load_reg32(r2); +@@ -4047,7 +4057,7 @@ static void disas_s390_insn(DisasContext *s) + break; + case 0x1b: /* SR R1,R2 [RR] */ + case 0x1f: /* SLR R1,R2 [RR] */ +- insn = ld_code2(s->pc); ++ insn = ld_code2(env, s->pc); + decode_rr(s, insn, &r1, &r2); + tmp32_1 = load_reg32(r1); + tmp32_2 = load_reg32(r2); +@@ -4065,7 +4075,7 @@ static void disas_s390_insn(DisasContext *s) + break; + case 0x1c: /* MR R1,R2 [RR] */ + /* reg(r1, r1+1) = reg(r1+1) * reg(r2) */ +- insn = ld_code2(s->pc); ++ insn = ld_code2(env, s->pc); + decode_rr(s, insn, &r1, &r2); + tmp2 = load_reg(r2); + tmp3 = load_reg((r1 + 1) & 15); +@@ -4079,7 +4089,7 @@ static void disas_s390_insn(DisasContext *s) + tcg_temp_free_i64(tmp3); + break; + case 0x1d: /* DR R1,R2 [RR] */ +- insn = ld_code2(s->pc); ++ insn = ld_code2(env, s->pc); + decode_rr(s, insn, &r1, &r2); + tmp32_1 = load_reg32(r1); + tmp32_2 = load_reg32(r1 + 1); +@@ -4114,21 +4124,21 @@ static void disas_s390_insn(DisasContext *s) + tcg_temp_free_i64(tmp3); + break; + case 0x28: /* LDR R1,R2 [RR] */ +- insn = ld_code2(s->pc); ++ insn = ld_code2(env, s->pc); + decode_rr(s, insn, &r1, &r2); + tmp = load_freg(r2); + store_freg(r1, tmp); + tcg_temp_free_i64(tmp); + break; + case 0x38: /* LER R1,R2 [RR] */ +- insn = ld_code2(s->pc); ++ insn = ld_code2(env, s->pc); + decode_rr(s, insn, &r1, &r2); + tmp32_1 = load_freg32(r2); + store_freg32(r1, tmp32_1); + tcg_temp_free_i32(tmp32_1); + break; + case 0x40: /* STH R1,D2(X2,B2) [RX] */ +- insn = ld_code4(s->pc); ++ insn = ld_code4(env, s->pc); + tmp = decode_rx(s, insn, &r1, &x2, &b2, &d2); + tmp2 = load_reg(r1); + tcg_gen_qemu_st16(tmp2, tmp, get_mem_index(s)); +@@ -4136,13 +4146,13 @@ static void disas_s390_insn(DisasContext *s) + tcg_temp_free_i64(tmp2); + break; + case 0x41: /* la */ +- insn = ld_code4(s->pc); ++ insn = ld_code4(env, s->pc); + tmp = decode_rx(s, insn, &r1, &x2, &b2, &d2); + store_reg(r1, tmp); /* FIXME: 31/24-bit addressing */ + tcg_temp_free_i64(tmp); + break; + case 0x42: /* STC R1,D2(X2,B2) [RX] */ +- insn = ld_code4(s->pc); ++ insn = ld_code4(env, s->pc); + tmp = decode_rx(s, insn, &r1, &x2, &b2, &d2); + tmp2 = load_reg(r1); + tcg_gen_qemu_st8(tmp2, tmp, get_mem_index(s)); +@@ -4150,7 +4160,7 @@ static void disas_s390_insn(DisasContext *s) + tcg_temp_free_i64(tmp2); + break; + case 0x43: /* IC R1,D2(X2,B2) [RX] */ +- insn = ld_code4(s->pc); ++ insn = ld_code4(env, s->pc); + tmp = decode_rx(s, insn, &r1, &x2, &b2, &d2); + tmp2 = tcg_temp_new_i64(); + tcg_gen_qemu_ld8u(tmp2, tmp, get_mem_index(s)); +@@ -4159,7 +4169,7 @@ static void disas_s390_insn(DisasContext *s) + tcg_temp_free_i64(tmp2); + break; + case 0x44: /* EX R1,D2(X2,B2) [RX] */ +- insn = ld_code4(s->pc); ++ insn = ld_code4(env, s->pc); + tmp = decode_rx(s, insn, &r1, &x2, &b2, &d2); + tmp2 = load_reg(r1); + tmp3 = tcg_const_i64(s->pc + 4); +@@ -4172,7 +4182,7 @@ static void disas_s390_insn(DisasContext *s) + tcg_temp_free_i64(tmp3); + break; + case 0x46: /* BCT R1,D2(X2,B2) [RX] */ +- insn = ld_code4(s->pc); ++ insn = ld_code4(env, s->pc); + tmp = decode_rx(s, insn, &r1, &x2, &b2, &d2); + tcg_temp_free_i64(tmp); + +@@ -4196,14 +4206,14 @@ static void disas_s390_insn(DisasContext *s) + tcg_temp_free_i64(tmp); + break; + case 0x47: /* BC M1,D2(X2,B2) [RX] */ +- insn = ld_code4(s->pc); ++ insn = ld_code4(env, s->pc); + tmp = decode_rx(s, insn, &r1, &x2, &b2, &d2); + gen_bcr(s, r1, tmp, s->pc + 4); + tcg_temp_free_i64(tmp); + s->is_jmp = DISAS_TB_JUMP; + break; + case 0x48: /* LH R1,D2(X2,B2) [RX] */ +- insn = ld_code4(s->pc); ++ insn = ld_code4(env, s->pc); + tmp = decode_rx(s, insn, &r1, &x2, &b2, &d2); + tmp2 = tcg_temp_new_i64(); + tcg_gen_qemu_ld16s(tmp2, tmp, get_mem_index(s)); +@@ -4212,7 +4222,7 @@ static void disas_s390_insn(DisasContext *s) + tcg_temp_free_i64(tmp2); + break; + case 0x49: /* CH R1,D2(X2,B2) [RX] */ +- insn = ld_code4(s->pc); ++ insn = ld_code4(env, s->pc); + tmp = decode_rx(s, insn, &r1, &x2, &b2, &d2); + tmp32_1 = load_reg32(r1); + tmp32_2 = tcg_temp_new_i32(); +@@ -4228,7 +4238,7 @@ static void disas_s390_insn(DisasContext *s) + case 0x4a: /* AH R1,D2(X2,B2) [RX] */ + case 0x4b: /* SH R1,D2(X2,B2) [RX] */ + case 0x4c: /* MH R1,D2(X2,B2) [RX] */ +- insn = ld_code4(s->pc); ++ insn = ld_code4(env, s->pc); + tmp = decode_rx(s, insn, &r1, &x2, &b2, &d2); + tmp2 = tcg_temp_new_i64(); + tmp32_1 = load_reg32(r1); +@@ -4261,7 +4271,7 @@ static void disas_s390_insn(DisasContext *s) + tcg_temp_free_i64(tmp2); + break; + case 0x4d: /* BAS R1,D2(X2,B2) [RX] */ +- insn = ld_code4(s->pc); ++ insn = ld_code4(env, s->pc); + tmp = decode_rx(s, insn, &r1, &x2, &b2, &d2); + tmp2 = tcg_const_i64(pc_to_link_info(s, s->pc + 4)); + store_reg(r1, tmp2); +@@ -4271,7 +4281,7 @@ static void disas_s390_insn(DisasContext *s) + s->is_jmp = DISAS_JUMP; + break; + case 0x4e: /* CVD R1,D2(X2,B2) [RX] */ +- insn = ld_code4(s->pc); ++ insn = ld_code4(env, s->pc); + tmp = decode_rx(s, insn, &r1, &x2, &b2, &d2); + tmp2 = tcg_temp_new_i64(); + tmp32_1 = tcg_temp_new_i32(); +@@ -4283,7 +4293,7 @@ static void disas_s390_insn(DisasContext *s) + tcg_temp_free_i32(tmp32_1); + break; + case 0x50: /* st r1, d2(x2, b2) */ +- insn = ld_code4(s->pc); ++ insn = ld_code4(env, s->pc); + tmp = decode_rx(s, insn, &r1, &x2, &b2, &d2); + tmp2 = load_reg(r1); + tcg_gen_qemu_st32(tmp2, tmp, get_mem_index(s)); +@@ -4291,7 +4301,7 @@ static void disas_s390_insn(DisasContext *s) + tcg_temp_free_i64(tmp2); + break; + case 0x55: /* CL R1,D2(X2,B2) [RX] */ +- insn = ld_code4(s->pc); ++ insn = ld_code4(env, s->pc); + tmp = decode_rx(s, insn, &r1, &x2, &b2, &d2); + tmp2 = tcg_temp_new_i64(); + tmp32_1 = tcg_temp_new_i32(); +@@ -4307,7 +4317,7 @@ static void disas_s390_insn(DisasContext *s) + case 0x54: /* N R1,D2(X2,B2) [RX] */ + case 0x56: /* O R1,D2(X2,B2) [RX] */ + case 0x57: /* X R1,D2(X2,B2) [RX] */ +- insn = ld_code4(s->pc); ++ insn = ld_code4(env, s->pc); + tmp = decode_rx(s, insn, &r1, &x2, &b2, &d2); + tmp2 = tcg_temp_new_i64(); + tmp32_1 = load_reg32(r1); +@@ -4323,7 +4333,7 @@ static void disas_s390_insn(DisasContext *s) + tcg_temp_free_i32(tmp32_2); + break; + case 0x58: /* l r1, d2(x2, b2) */ +- insn = ld_code4(s->pc); ++ insn = ld_code4(env, s->pc); + tmp = decode_rx(s, insn, &r1, &x2, &b2, &d2); + tmp2 = tcg_temp_new_i64(); + tmp32_1 = tcg_temp_new_i32(); +@@ -4335,7 +4345,7 @@ static void disas_s390_insn(DisasContext *s) + tcg_temp_free_i32(tmp32_1); + break; + case 0x59: /* C R1,D2(X2,B2) [RX] */ +- insn = ld_code4(s->pc); ++ insn = ld_code4(env, s->pc); + tmp = decode_rx(s, insn, &r1, &x2, &b2, &d2); + tmp2 = tcg_temp_new_i64(); + tmp32_1 = tcg_temp_new_i32(); +@@ -4352,7 +4362,7 @@ static void disas_s390_insn(DisasContext *s) + case 0x5b: /* S R1,D2(X2,B2) [RX] */ + case 0x5e: /* AL R1,D2(X2,B2) [RX] */ + case 0x5f: /* SL R1,D2(X2,B2) [RX] */ +- insn = ld_code4(s->pc); ++ insn = ld_code4(env, s->pc); + tmp = decode_rx(s, insn, &r1, &x2, &b2, &d2); + tmp32_1 = load_reg32(r1); + tmp32_2 = tcg_temp_new_i32(); +@@ -4395,7 +4405,7 @@ static void disas_s390_insn(DisasContext *s) + break; + case 0x5c: /* M R1,D2(X2,B2) [RX] */ + /* reg(r1, r1+1) = reg(r1+1) * *(s32*)addr */ +- insn = ld_code4(s->pc); ++ insn = ld_code4(env, s->pc); + tmp = decode_rx(s, insn, &r1, &x2, &b2, &d2); + tmp2 = tcg_temp_new_i64(); + tcg_gen_qemu_ld32s(tmp2, tmp, get_mem_index(s)); +@@ -4411,7 +4421,7 @@ static void disas_s390_insn(DisasContext *s) + tcg_temp_free_i64(tmp3); + break; + case 0x5d: /* D R1,D2(X2,B2) [RX] */ +- insn = ld_code4(s->pc); ++ insn = ld_code4(env, s->pc); + tmp3 = decode_rx(s, insn, &r1, &x2, &b2, &d2); + tmp32_1 = load_reg32(r1); + tmp32_2 = load_reg32(r1 + 1); +@@ -4445,7 +4455,7 @@ static void disas_s390_insn(DisasContext *s) + tcg_temp_free_i64(tmp3); + break; + case 0x60: /* STD R1,D2(X2,B2) [RX] */ +- insn = ld_code4(s->pc); ++ insn = ld_code4(env, s->pc); + tmp = decode_rx(s, insn, &r1, &x2, &b2, &d2); + tmp2 = load_freg(r1); + tcg_gen_qemu_st64(tmp2, tmp, get_mem_index(s)); +@@ -4453,7 +4463,7 @@ static void disas_s390_insn(DisasContext *s) + tcg_temp_free_i64(tmp2); + break; + case 0x68: /* LD R1,D2(X2,B2) [RX] */ +- insn = ld_code4(s->pc); ++ insn = ld_code4(env, s->pc); + tmp = decode_rx(s, insn, &r1, &x2, &b2, &d2); + tmp2 = tcg_temp_new_i64(); + tcg_gen_qemu_ld64(tmp2, tmp, get_mem_index(s)); +@@ -4462,7 +4472,7 @@ static void disas_s390_insn(DisasContext *s) + tcg_temp_free_i64(tmp2); + break; + case 0x70: /* STE R1,D2(X2,B2) [RX] */ +- insn = ld_code4(s->pc); ++ insn = ld_code4(env, s->pc); + tmp = decode_rx(s, insn, &r1, &x2, &b2, &d2); + tmp2 = tcg_temp_new_i64(); + tmp32_1 = load_freg32(r1); +@@ -4473,7 +4483,7 @@ static void disas_s390_insn(DisasContext *s) + tcg_temp_free_i32(tmp32_1); + break; + case 0x71: /* MS R1,D2(X2,B2) [RX] */ +- insn = ld_code4(s->pc); ++ insn = ld_code4(env, s->pc); + tmp = decode_rx(s, insn, &r1, &x2, &b2, &d2); + tmp2 = tcg_temp_new_i64(); + tmp32_1 = load_reg32(r1); +@@ -4488,7 +4498,7 @@ static void disas_s390_insn(DisasContext *s) + tcg_temp_free_i32(tmp32_2); + break; + case 0x78: /* LE R1,D2(X2,B2) [RX] */ +- insn = ld_code4(s->pc); ++ insn = ld_code4(env, s->pc); + tmp = decode_rx(s, insn, &r1, &x2, &b2, &d2); + tmp2 = tcg_temp_new_i64(); + tmp32_1 = tcg_temp_new_i32(); +@@ -4502,8 +4512,8 @@ static void disas_s390_insn(DisasContext *s) + #ifndef CONFIG_USER_ONLY + case 0x80: /* SSM D2(B2) [S] */ + /* Set System Mask */ +- check_privileged(s, ilc); +- insn = ld_code4(s->pc); ++ check_privileged(env, s, ilc); ++ insn = ld_code4(env, s->pc); + decode_rs(s, insn, &r1, &r3, &b2, &d2); + tmp = get_address(s, 0, b2, d2); + tmp2 = tcg_temp_new_i64(); +@@ -4518,8 +4528,8 @@ static void disas_s390_insn(DisasContext *s) + break; + case 0x82: /* LPSW D2(B2) [S] */ + /* Load PSW */ +- check_privileged(s, ilc); +- insn = ld_code4(s->pc); ++ check_privileged(env, s, ilc); ++ insn = ld_code4(env, s->pc); + decode_rs(s, insn, &r1, &r3, &b2, &d2); + tmp = get_address(s, 0, b2, d2); + tmp2 = tcg_temp_new_i64(); +@@ -4536,9 +4546,9 @@ static void disas_s390_insn(DisasContext *s) + break; + case 0x83: /* DIAG R1,R3,D2 [RS] */ + /* Diagnose call (KVM hypercall) */ +- check_privileged(s, ilc); ++ check_privileged(env, s, ilc); + potential_page_fault(s); +- insn = ld_code4(s->pc); ++ insn = ld_code4(env, s->pc); + decode_rs(s, insn, &r1, &r3, &b2, &d2); + tmp32_1 = tcg_const_i32(insn & 0xfff); + tmp2 = load_reg(2); +@@ -4553,7 +4563,7 @@ static void disas_s390_insn(DisasContext *s) + case 0x88: /* SRL R1,D2(B2) [RS] */ + case 0x89: /* SLL R1,D2(B2) [RS] */ + case 0x8a: /* SRA R1,D2(B2) [RS] */ +- insn = ld_code4(s->pc); ++ insn = ld_code4(env, s->pc); + decode_rs(s, insn, &r1, &r3, &b2, &d2); + tmp = get_address(s, 0, b2, d2); + tmp32_1 = load_reg32(r1); +@@ -4582,7 +4592,7 @@ static void disas_s390_insn(DisasContext *s) + case 0x8c: /* SRDL R1,D2(B2) [RS] */ + case 0x8d: /* SLDL R1,D2(B2) [RS] */ + case 0x8e: /* SRDA R1,D2(B2) [RS] */ +- insn = ld_code4(s->pc); ++ insn = ld_code4(env, s->pc); + decode_rs(s, insn, &r1, &r3, &b2, &d2); + tmp = get_address(s, 0, b2, d2); /* shift */ + tmp2 = tcg_temp_new_i64(); +@@ -4611,7 +4621,7 @@ static void disas_s390_insn(DisasContext *s) + break; + case 0x98: /* LM R1,R3,D2(B2) [RS] */ + case 0x90: /* STM R1,R3,D2(B2) [RS] */ +- insn = ld_code4(s->pc); ++ insn = ld_code4(env, s->pc); + decode_rs(s, insn, &r1, &r3, &b2, &d2); + + tmp = get_address(s, 0, b2, d2); +@@ -4637,7 +4647,7 @@ static void disas_s390_insn(DisasContext *s) + tcg_temp_free_i64(tmp4); + break; + case 0x91: /* TM D1(B1),I2 [SI] */ +- insn = ld_code4(s->pc); ++ insn = ld_code4(env, s->pc); + tmp = decode_si(s, insn, &i2, &b1, &d1); + tmp2 = tcg_const_i64(i2); + tcg_gen_qemu_ld8u(tmp, tmp, get_mem_index(s)); +@@ -4646,7 +4656,7 @@ static void disas_s390_insn(DisasContext *s) + tcg_temp_free_i64(tmp2); + break; + case 0x92: /* MVI D1(B1),I2 [SI] */ +- insn = ld_code4(s->pc); ++ insn = ld_code4(env, s->pc); + tmp = decode_si(s, insn, &i2, &b1, &d1); + tmp2 = tcg_const_i64(i2); + tcg_gen_qemu_st8(tmp2, tmp, get_mem_index(s)); +@@ -4656,7 +4666,7 @@ static void disas_s390_insn(DisasContext *s) + case 0x94: /* NI D1(B1),I2 [SI] */ + case 0x96: /* OI D1(B1),I2 [SI] */ + case 0x97: /* XI D1(B1),I2 [SI] */ +- insn = ld_code4(s->pc); ++ insn = ld_code4(env, s->pc); + tmp = decode_si(s, insn, &i2, &b1, &d1); + tmp2 = tcg_temp_new_i64(); + tcg_gen_qemu_ld8u(tmp2, tmp, get_mem_index(s)); +@@ -4679,7 +4689,7 @@ static void disas_s390_insn(DisasContext *s) + tcg_temp_free_i64(tmp2); + break; + case 0x95: /* CLI D1(B1),I2 [SI] */ +- insn = ld_code4(s->pc); ++ insn = ld_code4(env, s->pc); + tmp = decode_si(s, insn, &i2, &b1, &d1); + tmp2 = tcg_temp_new_i64(); + tcg_gen_qemu_ld8u(tmp2, tmp, get_mem_index(s)); +@@ -4688,7 +4698,7 @@ static void disas_s390_insn(DisasContext *s) + tcg_temp_free_i64(tmp2); + break; + case 0x9a: /* LAM R1,R3,D2(B2) [RS] */ +- insn = ld_code4(s->pc); ++ insn = ld_code4(env, s->pc); + decode_rs(s, insn, &r1, &r3, &b2, &d2); + tmp = get_address(s, 0, b2, d2); + tmp32_1 = tcg_const_i32(r1); +@@ -4700,7 +4710,7 @@ static void disas_s390_insn(DisasContext *s) + tcg_temp_free_i32(tmp32_2); + break; + case 0x9b: /* STAM R1,R3,D2(B2) [RS] */ +- insn = ld_code4(s->pc); ++ insn = ld_code4(env, s->pc); + decode_rs(s, insn, &r1, &r3, &b2, &d2); + tmp = get_address(s, 0, b2, d2); + tmp32_1 = tcg_const_i32(r1); +@@ -4712,21 +4722,21 @@ static void disas_s390_insn(DisasContext *s) + tcg_temp_free_i32(tmp32_2); + break; + case 0xa5: +- insn = ld_code4(s->pc); ++ insn = ld_code4(env, s->pc); + r1 = (insn >> 20) & 0xf; + op = (insn >> 16) & 0xf; + i2 = insn & 0xffff; +- disas_a5(s, op, r1, i2); ++ disas_a5(env, s, op, r1, i2); + break; + case 0xa7: +- insn = ld_code4(s->pc); ++ insn = ld_code4(env, s->pc); + r1 = (insn >> 20) & 0xf; + op = (insn >> 16) & 0xf; + i2 = (short)insn; +- disas_a7(s, op, r1, i2); ++ disas_a7(env, s, op, r1, i2); + break; + case 0xa8: /* MVCLE R1,R3,D2(B2) [RS] */ +- insn = ld_code4(s->pc); ++ insn = ld_code4(env, s->pc); + decode_rs(s, insn, &r1, &r3, &b2, &d2); + tmp = get_address(s, 0, b2, d2); + tmp32_1 = tcg_const_i32(r1); +@@ -4739,7 +4749,7 @@ static void disas_s390_insn(DisasContext *s) + tcg_temp_free_i32(tmp32_2); + break; + case 0xa9: /* CLCLE R1,R3,D2(B2) [RS] */ +- insn = ld_code4(s->pc); ++ insn = ld_code4(env, s->pc); + decode_rs(s, insn, &r1, &r3, &b2, &d2); + tmp = get_address(s, 0, b2, d2); + tmp32_1 = tcg_const_i32(r1); +@@ -4754,8 +4764,8 @@ static void disas_s390_insn(DisasContext *s) + #ifndef CONFIG_USER_ONLY + case 0xac: /* STNSM D1(B1),I2 [SI] */ + case 0xad: /* STOSM D1(B1),I2 [SI] */ +- check_privileged(s, ilc); +- insn = ld_code4(s->pc); ++ check_privileged(env, s, ilc); ++ insn = ld_code4(env, s->pc); + tmp = decode_si(s, insn, &i2, &b1, &d1); + tmp2 = tcg_temp_new_i64(); + tcg_gen_shri_i64(tmp2, psw_mask, 56); +@@ -4770,8 +4780,8 @@ static void disas_s390_insn(DisasContext *s) + tcg_temp_free_i64(tmp2); + break; + case 0xae: /* SIGP R1,R3,D2(B2) [RS] */ +- check_privileged(s, ilc); +- insn = ld_code4(s->pc); ++ check_privileged(env, s, ilc); ++ insn = ld_code4(env, s->pc); + decode_rs(s, insn, &r1, &r3, &b2, &d2); + tmp = get_address(s, 0, b2, d2); + tmp2 = load_reg(r3); +@@ -4784,8 +4794,8 @@ static void disas_s390_insn(DisasContext *s) + tcg_temp_free_i32(tmp32_1); + break; + case 0xb1: /* LRA R1,D2(X2, B2) [RX] */ +- check_privileged(s, ilc); +- insn = ld_code4(s->pc); ++ check_privileged(env, s, ilc); ++ insn = ld_code4(env, s->pc); + tmp = decode_rx(s, insn, &r1, &x2, &b2, &d2); + tmp32_1 = tcg_const_i32(r1); + potential_page_fault(s); +@@ -4796,7 +4806,7 @@ static void disas_s390_insn(DisasContext *s) + break; + #endif + case 0xb2: +- insn = ld_code4(s->pc); ++ insn = ld_code4(env, s->pc); + op = (insn >> 16) & 0xff; + switch (op) { + case 0x9c: /* STFPC D2(B2) [S] */ +@@ -4813,23 +4823,23 @@ static void disas_s390_insn(DisasContext *s) + tcg_temp_free_i64(tmp2); + break; + default: +- disas_b2(s, op, insn); ++ disas_b2(env, s, op, insn); + break; + } + break; + case 0xb3: +- insn = ld_code4(s->pc); ++ insn = ld_code4(env, s->pc); + op = (insn >> 16) & 0xff; + r3 = (insn >> 12) & 0xf; /* aka m3 */ + r1 = (insn >> 4) & 0xf; + r2 = insn & 0xf; +- disas_b3(s, op, r3, r1, r2); ++ disas_b3(env, s, op, r3, r1, r2); + break; + #ifndef CONFIG_USER_ONLY + case 0xb6: /* STCTL R1,R3,D2(B2) [RS] */ + /* Store Control */ +- check_privileged(s, ilc); +- insn = ld_code4(s->pc); ++ check_privileged(env, s, ilc); ++ insn = ld_code4(env, s->pc); + decode_rs(s, insn, &r1, &r3, &b2, &d2); + tmp = get_address(s, 0, b2, d2); + tmp32_1 = tcg_const_i32(r1); +@@ -4842,8 +4852,8 @@ static void disas_s390_insn(DisasContext *s) + break; + case 0xb7: /* LCTL R1,R3,D2(B2) [RS] */ + /* Load Control */ +- check_privileged(s, ilc); +- insn = ld_code4(s->pc); ++ check_privileged(env, s, ilc); ++ insn = ld_code4(env, s->pc); + decode_rs(s, insn, &r1, &r3, &b2, &d2); + tmp = get_address(s, 0, b2, d2); + tmp32_1 = tcg_const_i32(r1); +@@ -4856,14 +4866,14 @@ static void disas_s390_insn(DisasContext *s) + break; + #endif + case 0xb9: +- insn = ld_code4(s->pc); ++ insn = ld_code4(env, s->pc); + r1 = (insn >> 4) & 0xf; + r2 = insn & 0xf; + op = (insn >> 16) & 0xff; +- disas_b9(s, op, r1, r2); ++ disas_b9(env, s, op, r1, r2); + break; + case 0xba: /* CS R1,R3,D2(B2) [RS] */ +- insn = ld_code4(s->pc); ++ insn = ld_code4(env, s->pc); + decode_rs(s, insn, &r1, &r3, &b2, &d2); + tmp = get_address(s, 0, b2, d2); + tmp32_1 = tcg_const_i32(r1); +@@ -4876,7 +4886,7 @@ static void disas_s390_insn(DisasContext *s) + tcg_temp_free_i32(tmp32_2); + break; + case 0xbd: /* CLM R1,M3,D2(B2) [RS] */ +- insn = ld_code4(s->pc); ++ insn = ld_code4(env, s->pc); + decode_rs(s, insn, &r1, &r3, &b2, &d2); + tmp = get_address(s, 0, b2, d2); + tmp32_1 = load_reg32(r1); +@@ -4889,7 +4899,7 @@ static void disas_s390_insn(DisasContext *s) + tcg_temp_free_i32(tmp32_2); + break; + case 0xbe: /* STCM R1,M3,D2(B2) [RS] */ +- insn = ld_code4(s->pc); ++ insn = ld_code4(env, s->pc); + decode_rs(s, insn, &r1, &r3, &b2, &d2); + tmp = get_address(s, 0, b2, d2); + tmp32_1 = load_reg32(r1); +@@ -4901,7 +4911,7 @@ static void disas_s390_insn(DisasContext *s) + tcg_temp_free_i32(tmp32_2); + break; + case 0xbf: /* ICM R1,M3,D2(B2) [RS] */ +- insn = ld_code4(s->pc); ++ insn = ld_code4(env, s->pc); + decode_rs(s, insn, &r1, &r3, &b2, &d2); + if (r3 == 15) { + /* effectively a 32-bit load */ +@@ -4956,16 +4966,16 @@ static void disas_s390_insn(DisasContext *s) + break; + case 0xc0: + case 0xc2: +- insn = ld_code6(s->pc); ++ insn = ld_code6(env, s->pc); + r1 = (insn >> 36) & 0xf; + op = (insn >> 32) & 0xf; + i2 = (int)insn; + switch (opc) { + case 0xc0: +- disas_c0(s, op, r1, i2); ++ disas_c0(env, s, op, r1, i2); + break; + case 0xc2: +- disas_c2(s, op, r1, i2); ++ disas_c2(env, s, op, r1, i2); + break; + default: + tcg_abort(); +@@ -4978,7 +4988,7 @@ static void disas_s390_insn(DisasContext *s) + case 0xd7: /* XC D1(L,B1),D2(B2) [SS] */ + case 0xdc: /* TR D1(L,B1),D2(B2) [SS] */ + case 0xf3: /* UNPK D1(L1,B1),D2(L2,B2) [SS] */ +- insn = ld_code6(s->pc); ++ insn = ld_code6(env, s->pc); + vl = tcg_const_i32((insn >> 32) & 0xff); + b1 = (insn >> 28) & 0xf; + b2 = (insn >> 12) & 0xf; +@@ -5026,9 +5036,9 @@ static void disas_s390_insn(DisasContext *s) + #ifndef CONFIG_USER_ONLY + case 0xda: /* MVCP D1(R1,B1),D2(B2),R3 [SS] */ + case 0xdb: /* MVCS D1(R1,B1),D2(B2),R3 [SS] */ +- check_privileged(s, ilc); ++ check_privileged(env, s, ilc); + potential_page_fault(s); +- insn = ld_code6(s->pc); ++ insn = ld_code6(env, s->pc); + r1 = (insn >> 36) & 0xf; + r3 = (insn >> 32) & 0xf; + b1 = (insn >> 28) & 0xf; +@@ -5051,7 +5061,7 @@ static void disas_s390_insn(DisasContext *s) + break; + #endif + case 0xe3: +- insn = ld_code6(s->pc); ++ insn = ld_code6(env, s->pc); + debug_insn(insn); + op = insn & 0xff; + r1 = (insn >> 36) & 0xf; +@@ -5059,19 +5069,19 @@ static void disas_s390_insn(DisasContext *s) + b2 = (insn >> 28) & 0xf; + d2 = ((int)((((insn >> 16) & 0xfff) + | ((insn << 4) & 0xff000)) << 12)) >> 12; +- disas_e3(s, op, r1, x2, b2, d2 ); ++ disas_e3(env, s, op, r1, x2, b2, d2 ); + break; + #ifndef CONFIG_USER_ONLY + case 0xe5: + /* Test Protection */ +- check_privileged(s, ilc); +- insn = ld_code6(s->pc); ++ check_privileged(env, s, ilc); ++ insn = ld_code6(env, s->pc); + debug_insn(insn); +- disas_e5(s, insn); ++ disas_e5(env, s, insn); + break; + #endif + case 0xeb: +- insn = ld_code6(s->pc); ++ insn = ld_code6(env, s->pc); + debug_insn(insn); + op = insn & 0xff; + r1 = (insn >> 36) & 0xf; +@@ -5079,10 +5089,10 @@ static void disas_s390_insn(DisasContext *s) + b2 = (insn >> 28) & 0xf; + d2 = ((int)((((insn >> 16) & 0xfff) + | ((insn << 4) & 0xff000)) << 12)) >> 12; +- disas_eb(s, op, r1, r3, b2, d2); ++ disas_eb(env, s, op, r1, r3, b2, d2); + break; + case 0xed: +- insn = ld_code6(s->pc); ++ insn = ld_code6(env, s->pc); + debug_insn(insn); + op = insn & 0xff; + r1 = (insn >> 36) & 0xf; +@@ -5090,11 +5100,11 @@ static void disas_s390_insn(DisasContext *s) + b2 = (insn >> 28) & 0xf; + d2 = (short)((insn >> 16) & 0xfff); + r1b = (insn >> 12) & 0xf; +- disas_ed(s, op, r1, x2, b2, d2, r1b); ++ disas_ed(env, s, op, r1, x2, b2, d2, r1b); + break; + default: + qemu_log_mask(LOG_UNIMP, "unimplemented opcode 0x%x\n", opc); +- gen_illegal_opcode(s, ilc); ++ gen_illegal_opcode(env, s, ilc); + break; + } + +@@ -5167,7 +5177,7 @@ static inline void gen_intermediate_code_internal(CPUS390XState *env, + LOG_DISAS("pc " TARGET_FMT_lx "\n", + dc.pc); + #endif +- disas_s390_insn(&dc); ++ disas_s390_insn(env, &dc); + + num_insns++; + if (env->singlestep_enabled) { +-- +1.7.12.1 + diff --git a/0027-target-lm32-switch-to-AREG0-free-mode.patch b/0027-target-lm32-switch-to-AREG0-free-mode.patch new file mode 100644 index 0000000..9a92a12 --- /dev/null +++ b/0027-target-lm32-switch-to-AREG0-free-mode.patch @@ -0,0 +1,282 @@ +From 25e9a95d0571c40738daa479467d757eb477739e Mon Sep 17 00:00:00 2001 +From: Blue Swirl +Date: Sun, 2 Sep 2012 06:57:17 +0000 +Subject: [PATCH] target-lm32: switch to AREG0 free mode + +Add an explicit CPUState parameter instead of relying on AREG0 +and switch to AREG0 free mode. + +Signed-off-by: Blue Swirl +Signed-off-by: Michael Roth +--- + configure | 2 +- + target-lm32/Makefile.objs | 2 -- + target-lm32/helper.h | 20 ++++++++++---------- + target-lm32/op_helper.c | 29 +++++++++++------------------ + target-lm32/translate.c | 28 +++++++++++++--------------- + 5 files changed, 35 insertions(+), 46 deletions(-) + +diff --git a/configure b/configure +index 3ad6f74..1e3ea7f 100755 +--- a/configure ++++ b/configure +@@ -3839,7 +3839,7 @@ symlink "$source_path/Makefile.target" "$target_dir/Makefile" + + + case "$target_arch2" in +- alpha | i386 | or32 | s390x | sparc* | x86_64 | xtensa* | ppc*) ++ alpha | i386 | lm32 | or32 | s390x | sparc* | x86_64 | xtensa* | ppc*) + echo "CONFIG_TCG_PASS_AREG0=y" >> $config_target_mak + ;; + esac +diff --git a/target-lm32/Makefile.objs b/target-lm32/Makefile.objs +index 2e0e093..ca20f21 100644 +--- a/target-lm32/Makefile.objs ++++ b/target-lm32/Makefile.objs +@@ -1,4 +1,2 @@ + obj-y += translate.o op_helper.o helper.o cpu.o + obj-$(CONFIG_SOFTMMU) += machine.o +- +-$(obj)/op_helper.o: QEMU_CFLAGS += $(HELPER_CFLAGS) +diff --git a/target-lm32/helper.h b/target-lm32/helper.h +index 9d335ef..07f5670 100644 +--- a/target-lm32/helper.h ++++ b/target-lm32/helper.h +@@ -1,14 +1,14 @@ + #include "def-helper.h" + +-DEF_HELPER_1(raise_exception, void, i32) +-DEF_HELPER_0(hlt, void) +-DEF_HELPER_1(wcsr_im, void, i32) +-DEF_HELPER_1(wcsr_ip, void, i32) +-DEF_HELPER_1(wcsr_jtx, void, i32) +-DEF_HELPER_1(wcsr_jrx, void, i32) +-DEF_HELPER_0(rcsr_im, i32) +-DEF_HELPER_0(rcsr_ip, i32) +-DEF_HELPER_0(rcsr_jtx, i32) +-DEF_HELPER_0(rcsr_jrx, i32) ++DEF_HELPER_2(raise_exception, void, env, i32) ++DEF_HELPER_1(hlt, void, env) ++DEF_HELPER_2(wcsr_im, void, env, i32) ++DEF_HELPER_2(wcsr_ip, void, env, i32) ++DEF_HELPER_2(wcsr_jtx, void, env, i32) ++DEF_HELPER_2(wcsr_jrx, void, env, i32) ++DEF_HELPER_1(rcsr_im, i32, env) ++DEF_HELPER_1(rcsr_ip, i32, env) ++DEF_HELPER_1(rcsr_jtx, i32, env) ++DEF_HELPER_1(rcsr_jrx, i32, env) + + #include "def-helper.h" +diff --git a/target-lm32/op_helper.c b/target-lm32/op_helper.c +index 51edc1a..7b91d8c 100644 +--- a/target-lm32/op_helper.c ++++ b/target-lm32/op_helper.c +@@ -1,6 +1,5 @@ + #include + #include "cpu.h" +-#include "dyngen-exec.h" + #include "helper.h" + #include "host-utils.h" + +@@ -18,55 +17,55 @@ + #define SHIFT 3 + #include "softmmu_template.h" + +-void helper_raise_exception(uint32_t index) ++void helper_raise_exception(CPULM32State *env, uint32_t index) + { + env->exception_index = index; + cpu_loop_exit(env); + } + +-void helper_hlt(void) ++void helper_hlt(CPULM32State *env) + { + env->halted = 1; + env->exception_index = EXCP_HLT; + cpu_loop_exit(env); + } + +-void helper_wcsr_im(uint32_t im) ++void helper_wcsr_im(CPULM32State *env, uint32_t im) + { + lm32_pic_set_im(env->pic_state, im); + } + +-void helper_wcsr_ip(uint32_t im) ++void helper_wcsr_ip(CPULM32State *env, uint32_t im) + { + lm32_pic_set_ip(env->pic_state, im); + } + +-void helper_wcsr_jtx(uint32_t jtx) ++void helper_wcsr_jtx(CPULM32State *env, uint32_t jtx) + { + lm32_juart_set_jtx(env->juart_state, jtx); + } + +-void helper_wcsr_jrx(uint32_t jrx) ++void helper_wcsr_jrx(CPULM32State *env, uint32_t jrx) + { + lm32_juart_set_jrx(env->juart_state, jrx); + } + +-uint32_t helper_rcsr_im(void) ++uint32_t helper_rcsr_im(CPULM32State *env) + { + return lm32_pic_get_im(env->pic_state); + } + +-uint32_t helper_rcsr_ip(void) ++uint32_t helper_rcsr_ip(CPULM32State *env) + { + return lm32_pic_get_ip(env->pic_state); + } + +-uint32_t helper_rcsr_jtx(void) ++uint32_t helper_rcsr_jtx(CPULM32State *env) + { + return lm32_juart_get_jtx(env->juart_state); + } + +-uint32_t helper_rcsr_jrx(void) ++uint32_t helper_rcsr_jrx(CPULM32State *env) + { + return lm32_juart_get_jrx(env->juart_state); + } +@@ -74,17 +73,12 @@ uint32_t helper_rcsr_jrx(void) + /* Try to fill the TLB and return an exception if error. If retaddr is + NULL, it means that the function was called in C code (i.e. not + from generated code or from helper.c) */ +-/* XXX: fix it to restore all registers */ +-void tlb_fill(CPULM32State *env1, target_ulong addr, int is_write, int mmu_idx, ++void tlb_fill(CPULM32State *env, target_ulong addr, int is_write, int mmu_idx, + uintptr_t retaddr) + { + TranslationBlock *tb; +- CPULM32State *saved_env; + int ret; + +- saved_env = env; +- env = env1; +- + ret = cpu_lm32_handle_mmu_fault(env, addr, is_write, mmu_idx); + if (unlikely(ret)) { + if (retaddr) { +@@ -98,7 +92,6 @@ void tlb_fill(CPULM32State *env1, target_ulong addr, int is_write, int mmu_idx, + } + cpu_loop_exit(env); + } +- env = saved_env; + } + #endif + +diff --git a/target-lm32/translate.c b/target-lm32/translate.c +index 872a2ba..5f6dcba 100644 +--- a/target-lm32/translate.c ++++ b/target-lm32/translate.c +@@ -116,7 +116,7 @@ static inline void t_gen_raise_exception(DisasContext *dc, uint32_t index) + { + TCGv_i32 tmp = tcg_const_i32(index); + +- gen_helper_raise_exception(tmp); ++ gen_helper_raise_exception(cpu_env, tmp); + tcg_temp_free_i32(tmp); + } + +@@ -179,7 +179,7 @@ static void dec_and(DisasContext *dc) + } else { + if (dc->r0 == 0 && dc->r1 == 0 && dc->r2 == 0) { + tcg_gen_movi_tl(cpu_pc, dc->pc + 4); +- gen_helper_hlt(); ++ gen_helper_hlt(cpu_env); + } else { + tcg_gen_and_tl(cpu_R[dc->r2], cpu_R[dc->r0], cpu_R[dc->r1]); + } +@@ -601,10 +601,10 @@ static void dec_rcsr(DisasContext *dc) + tcg_gen_mov_tl(cpu_R[dc->r2], cpu_ie); + break; + case CSR_IM: +- gen_helper_rcsr_im(cpu_R[dc->r2]); ++ gen_helper_rcsr_im(cpu_R[dc->r2], cpu_env); + break; + case CSR_IP: +- gen_helper_rcsr_ip(cpu_R[dc->r2]); ++ gen_helper_rcsr_ip(cpu_R[dc->r2], cpu_env); + break; + case CSR_CC: + tcg_gen_mov_tl(cpu_R[dc->r2], cpu_cc); +@@ -622,10 +622,10 @@ static void dec_rcsr(DisasContext *dc) + tcg_gen_mov_tl(cpu_R[dc->r2], cpu_deba); + break; + case CSR_JTX: +- gen_helper_rcsr_jtx(cpu_R[dc->r2]); ++ gen_helper_rcsr_jtx(cpu_R[dc->r2], cpu_env); + break; + case CSR_JRX: +- gen_helper_rcsr_jrx(cpu_R[dc->r2]); ++ gen_helper_rcsr_jrx(cpu_R[dc->r2], cpu_env); + break; + case CSR_ICC: + case CSR_DCC: +@@ -812,7 +812,7 @@ static void dec_wcsr(DisasContext *dc) + if (use_icount) { + gen_io_start(); + } +- gen_helper_wcsr_im(cpu_R[dc->r1]); ++ gen_helper_wcsr_im(cpu_env, cpu_R[dc->r1]); + tcg_gen_movi_tl(cpu_pc, dc->pc + 4); + if (use_icount) { + gen_io_end(); +@@ -824,7 +824,7 @@ static void dec_wcsr(DisasContext *dc) + if (use_icount) { + gen_io_start(); + } +- gen_helper_wcsr_ip(cpu_R[dc->r1]); ++ gen_helper_wcsr_ip(cpu_env, cpu_R[dc->r1]); + tcg_gen_movi_tl(cpu_pc, dc->pc + 4); + if (use_icount) { + gen_io_end(); +@@ -844,10 +844,10 @@ static void dec_wcsr(DisasContext *dc) + tcg_gen_mov_tl(cpu_deba, cpu_R[dc->r1]); + break; + case CSR_JTX: +- gen_helper_wcsr_jtx(cpu_R[dc->r1]); ++ gen_helper_wcsr_jtx(cpu_env, cpu_R[dc->r1]); + break; + case CSR_JRX: +- gen_helper_wcsr_jrx(cpu_R[dc->r1]); ++ gen_helper_wcsr_jrx(cpu_env, cpu_R[dc->r1]); + break; + case CSR_DC: + tcg_gen_mov_tl(cpu_dc, cpu_R[dc->r1]); +@@ -940,15 +940,13 @@ static const DecoderInfo decinfo[] = { + dec_cmpne + }; + +-static inline void decode(DisasContext *dc) ++static inline void decode(DisasContext *dc, uint32_t ir) + { +- uint32_t ir; +- + if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP))) { + tcg_gen_debug_insn_start(dc->pc); + } + +- dc->ir = ir = ldl_code(dc->pc); ++ dc->ir = ir; + LOG_DIS("%8.8x\t", dc->ir); + + /* try guessing 'empty' instruction memory, although it may be a valid +@@ -1068,7 +1066,7 @@ static void gen_intermediate_code_internal(CPULM32State *env, + gen_io_start(); + } + +- decode(dc); ++ decode(dc, cpu_ldl_code(env, dc->pc)); + dc->pc += 4; + num_insns++; + +-- +1.7.12.1 + diff --git a/0028-target-m68k-switch-to-AREG0-free-mode.patch b/0028-target-m68k-switch-to-AREG0-free-mode.patch new file mode 100644 index 0000000..220b78d --- /dev/null +++ b/0028-target-m68k-switch-to-AREG0-free-mode.patch @@ -0,0 +1,502 @@ +From 2ace9fd11db103aecebf451aff3bc23838248667 Mon Sep 17 00:00:00 2001 +From: Blue Swirl +Date: Sun, 2 Sep 2012 07:27:38 +0000 +Subject: [PATCH] target-m68k: switch to AREG0 free mode + +Add an explicit CPUState parameter instead of relying on AREG0 +and switch to AREG0 free mode. + +Signed-off-by: Blue Swirl +Signed-off-by: Michael Roth +--- + configure | 2 +- + target-m68k/Makefile.objs | 2 -- + target-m68k/helpers.h | 2 +- + target-m68k/op_helper.c | 68 +++++++++++++++++------------------------- + target-m68k/translate.c | 76 ++++++++++++++++++++++++----------------------- + 5 files changed, 68 insertions(+), 82 deletions(-) + +diff --git a/configure b/configure +index 1e3ea7f..af03942 100755 +--- a/configure ++++ b/configure +@@ -3839,7 +3839,7 @@ symlink "$source_path/Makefile.target" "$target_dir/Makefile" + + + case "$target_arch2" in +- alpha | i386 | lm32 | or32 | s390x | sparc* | x86_64 | xtensa* | ppc*) ++ alpha | i386 | lm32 | m68k | or32 | s390x | sparc* | x86_64 | xtensa* | ppc*) + echo "CONFIG_TCG_PASS_AREG0=y" >> $config_target_mak + ;; + esac +diff --git a/target-m68k/Makefile.objs b/target-m68k/Makefile.objs +index cda6015..7eccfab 100644 +--- a/target-m68k/Makefile.objs ++++ b/target-m68k/Makefile.objs +@@ -1,5 +1,3 @@ + obj-y += m68k-semi.o + obj-y += translate.o op_helper.o helper.o cpu.o + obj-$(CONFIG_SOFTMMU) += machine.o +- +-$(obj)/op_helper.o: QEMU_CFLAGS += $(HELPER_CFLAGS) +diff --git a/target-m68k/helpers.h b/target-m68k/helpers.h +index cb8a0c7..8112b44 100644 +--- a/target-m68k/helpers.h ++++ b/target-m68k/helpers.h +@@ -49,6 +49,6 @@ DEF_HELPER_3(set_mac_exts, void, env, i32, i32) + DEF_HELPER_3(set_mac_extu, void, env, i32, i32) + + DEF_HELPER_2(flush_flags, void, env, i32) +-DEF_HELPER_1(raise_exception, void, i32) ++DEF_HELPER_2(raise_exception, void, env, i32) + + #include "def-helper.h" +diff --git a/target-m68k/op_helper.c b/target-m68k/op_helper.c +index 1971a57..3116287 100644 +--- a/target-m68k/op_helper.c ++++ b/target-m68k/op_helper.c +@@ -17,17 +17,16 @@ + * License along with this library; if not, see . + */ + #include "cpu.h" +-#include "dyngen-exec.h" + #include "helpers.h" + + #if defined(CONFIG_USER_ONLY) + +-void do_interrupt(CPUM68KState *env1) ++void do_interrupt(CPUM68KState *env) + { +- env1->exception_index = -1; ++ env->exception_index = -1; + } + +-void do_interrupt_m68k_hardirq(CPUM68KState *env1) ++void do_interrupt_m68k_hardirq(CPUM68KState *env) + { + } + +@@ -54,16 +53,12 @@ extern int semihosting_enabled; + /* Try to fill the TLB and return an exception if error. If retaddr is + NULL, it means that the function was called in C code (i.e. not + from generated code or from helper.c) */ +-/* XXX: fix it to restore all registers */ +-void tlb_fill(CPUM68KState *env1, target_ulong addr, int is_write, int mmu_idx, ++void tlb_fill(CPUM68KState *env, target_ulong addr, int is_write, int mmu_idx, + uintptr_t retaddr) + { + TranslationBlock *tb; +- CPUM68KState *saved_env; + int ret; + +- saved_env = env; +- env = env1; + ret = cpu_m68k_handle_mmu_fault(env, addr, is_write, mmu_idx); + if (unlikely(ret)) { + if (retaddr) { +@@ -77,24 +72,23 @@ void tlb_fill(CPUM68KState *env1, target_ulong addr, int is_write, int mmu_idx, + } + cpu_loop_exit(env); + } +- env = saved_env; + } + +-static void do_rte(void) ++static void do_rte(CPUM68KState *env) + { + uint32_t sp; + uint32_t fmt; + + sp = env->aregs[7]; +- fmt = ldl_kernel(sp); +- env->pc = ldl_kernel(sp + 4); ++ fmt = cpu_ldl_kernel(env, sp); ++ env->pc = cpu_ldl_kernel(env, sp + 4); + sp |= (fmt >> 28) & 3; + env->sr = fmt & 0xffff; + m68k_switch_sp(env); + env->aregs[7] = sp + 8; + } + +-static void do_interrupt_all(int is_hw) ++static void do_interrupt_all(CPUM68KState *env, int is_hw) + { + uint32_t sp; + uint32_t fmt; +@@ -108,14 +102,14 @@ static void do_interrupt_all(int is_hw) + switch (env->exception_index) { + case EXCP_RTE: + /* Return from an exception. */ +- do_rte(); ++ do_rte(env); + return; + case EXCP_HALT_INSN: + if (semihosting_enabled + && (env->sr & SR_S) != 0 + && (env->pc & 3) == 0 +- && lduw_code(env->pc - 4) == 0x4e71 +- && ldl_code(env->pc) == 0x4e7bf000) { ++ && cpu_lduw_code(env, env->pc - 4) == 0x4e71 ++ && cpu_ldl_code(env, env->pc) == 0x4e7bf000) { + env->pc += 4; + do_m68k_semihosting(env, env->dregs[0]); + return; +@@ -151,44 +145,34 @@ static void do_interrupt_all(int is_hw) + /* ??? This could cause MMU faults. */ + sp &= ~3; + sp -= 4; +- stl_kernel(sp, retaddr); ++ cpu_stl_kernel(env, sp, retaddr); + sp -= 4; +- stl_kernel(sp, fmt); ++ cpu_stl_kernel(env, sp, fmt); + env->aregs[7] = sp; + /* Jump to vector. */ +- env->pc = ldl_kernel(env->vbr + vector); ++ env->pc = cpu_ldl_kernel(env, env->vbr + vector); + } + +-void do_interrupt(CPUM68KState *env1) ++void do_interrupt(CPUM68KState *env) + { +- CPUM68KState *saved_env; +- +- saved_env = env; +- env = env1; +- do_interrupt_all(0); +- env = saved_env; ++ do_interrupt_all(env, 0); + } + +-void do_interrupt_m68k_hardirq(CPUM68KState *env1) ++void do_interrupt_m68k_hardirq(CPUM68KState *env) + { +- CPUM68KState *saved_env; +- +- saved_env = env; +- env = env1; +- do_interrupt_all(1); +- env = saved_env; ++ do_interrupt_all(env, 1); + } + #endif + +-static void raise_exception(int tt) ++static void raise_exception(CPUM68KState *env, int tt) + { + env->exception_index = tt; + cpu_loop_exit(env); + } + +-void HELPER(raise_exception)(uint32_t tt) ++void HELPER(raise_exception)(CPUM68KState *env, uint32_t tt) + { +- raise_exception(tt); ++ raise_exception(env, tt); + } + + void HELPER(divu)(CPUM68KState *env, uint32_t word) +@@ -202,8 +186,9 @@ void HELPER(divu)(CPUM68KState *env, uint32_t word) + num = env->div1; + den = env->div2; + /* ??? This needs to make sure the throwing location is accurate. */ +- if (den == 0) +- raise_exception(EXCP_DIV0); ++ if (den == 0) { ++ raise_exception(env, EXCP_DIV0); ++ } + quot = num / den; + rem = num % den; + flags = 0; +@@ -231,8 +216,9 @@ void HELPER(divs)(CPUM68KState *env, uint32_t word) + + num = env->div1; + den = env->div2; +- if (den == 0) +- raise_exception(EXCP_DIV0); ++ if (den == 0) { ++ raise_exception(env, EXCP_DIV0); ++ } + quot = num / den; + rem = num % den; + flags = 0; +diff --git a/target-m68k/translate.c b/target-m68k/translate.c +index 9fc1e31..10bb303 100644 +--- a/target-m68k/translate.c ++++ b/target-m68k/translate.c +@@ -260,9 +260,9 @@ static TCGv gen_ldst(DisasContext *s, int opsize, TCGv addr, TCGv val, + static inline uint32_t read_im32(DisasContext *s) + { + uint32_t im; +- im = ((uint32_t)lduw_code(s->pc)) << 16; ++ im = ((uint32_t)cpu_lduw_code(cpu_single_env, s->pc)) << 16; + s->pc += 2; +- im |= lduw_code(s->pc); ++ im |= cpu_lduw_code(cpu_single_env, s->pc); + s->pc += 2; + return im; + } +@@ -297,7 +297,7 @@ static TCGv gen_lea_indexed(DisasContext *s, int opsize, TCGv base) + uint32_t bd, od; + + offset = s->pc; +- ext = lduw_code(s->pc); ++ ext = cpu_lduw_code(cpu_single_env, s->pc); + s->pc += 2; + + if ((ext & 0x800) == 0 && !m68k_feature(s->env, M68K_FEATURE_WORD_INDEX)) +@@ -311,7 +311,7 @@ static TCGv gen_lea_indexed(DisasContext *s, int opsize, TCGv base) + if ((ext & 0x30) > 0x10) { + /* base displacement */ + if ((ext & 0x30) == 0x20) { +- bd = (int16_t)lduw_code(s->pc); ++ bd = (int16_t)cpu_lduw_code(cpu_single_env, s->pc); + s->pc += 2; + } else { + bd = read_im32(s); +@@ -360,7 +360,7 @@ static TCGv gen_lea_indexed(DisasContext *s, int opsize, TCGv base) + if ((ext & 3) > 1) { + /* outer displacement */ + if ((ext & 3) == 2) { +- od = (int16_t)lduw_code(s->pc); ++ od = (int16_t)cpu_lduw_code(cpu_single_env, s->pc); + s->pc += 2; + } else { + od = read_im32(s); +@@ -514,7 +514,7 @@ static TCGv gen_lea(DisasContext *s, uint16_t insn, int opsize) + case 5: /* Indirect displacement. */ + reg = AREG(insn, 0); + tmp = tcg_temp_new(); +- ext = lduw_code(s->pc); ++ ext = cpu_lduw_code(cpu_single_env, s->pc); + s->pc += 2; + tcg_gen_addi_i32(tmp, reg, (int16_t)ext); + return tmp; +@@ -524,7 +524,7 @@ static TCGv gen_lea(DisasContext *s, uint16_t insn, int opsize) + case 7: /* Other */ + switch (insn & 7) { + case 0: /* Absolute short. */ +- offset = ldsw_code(s->pc); ++ offset = cpu_ldsw_code(cpu_single_env, s->pc); + s->pc += 2; + return tcg_const_i32(offset); + case 1: /* Absolute long. */ +@@ -532,7 +532,7 @@ static TCGv gen_lea(DisasContext *s, uint16_t insn, int opsize) + return tcg_const_i32(offset); + case 2: /* pc displacement */ + offset = s->pc; +- offset += ldsw_code(s->pc); ++ offset += cpu_ldsw_code(cpu_single_env, s->pc); + s->pc += 2; + return tcg_const_i32(offset); + case 3: /* pc index+displacement. */ +@@ -638,17 +638,19 @@ static TCGv gen_ea(DisasContext *s, uint16_t insn, int opsize, TCGv val, + /* Sign extend values for consistency. */ + switch (opsize) { + case OS_BYTE: +- if (what == EA_LOADS) +- offset = ldsb_code(s->pc + 1); +- else +- offset = ldub_code(s->pc + 1); ++ if (what == EA_LOADS) { ++ offset = cpu_ldsb_code(cpu_single_env, s->pc + 1); ++ } else { ++ offset = cpu_ldub_code(cpu_single_env, s->pc + 1); ++ } + s->pc += 2; + break; + case OS_WORD: +- if (what == EA_LOADS) +- offset = ldsw_code(s->pc); +- else +- offset = lduw_code(s->pc); ++ if (what == EA_LOADS) { ++ offset = cpu_ldsw_code(cpu_single_env, s->pc); ++ } else { ++ offset = cpu_lduw_code(cpu_single_env, s->pc); ++ } + s->pc += 2; + break; + case OS_LONG: +@@ -815,7 +817,7 @@ static void gen_exception(DisasContext *s, uint32_t where, int nr) + { + gen_flush_cc_op(s); + gen_jmp_im(s, where); +- gen_helper_raise_exception(tcg_const_i32(nr)); ++ gen_helper_raise_exception(cpu_env, tcg_const_i32(nr)); + } + + static inline void gen_addr_fault(DisasContext *s) +@@ -934,7 +936,7 @@ DISAS_INSN(divl) + TCGv reg; + uint16_t ext; + +- ext = lduw_code(s->pc); ++ ext = cpu_lduw_code(cpu_single_env, s->pc); + s->pc += 2; + if (ext & 0x87f8) { + gen_exception(s, s->pc - 4, EXCP_UNSUPPORTED); +@@ -1086,7 +1088,7 @@ DISAS_INSN(movem) + TCGv tmp; + int is_load; + +- mask = lduw_code(s->pc); ++ mask = cpu_lduw_code(cpu_single_env, s->pc); + s->pc += 2; + tmp = gen_lea(s, insn, OS_LONG); + if (IS_NULL_QREG(tmp)) { +@@ -1130,7 +1132,7 @@ DISAS_INSN(bitop_im) + opsize = OS_LONG; + op = (insn >> 6) & 3; + +- bitnum = lduw_code(s->pc); ++ bitnum = cpu_lduw_code(cpu_single_env, s->pc); + s->pc += 2; + if (bitnum & 0xff00) { + disas_undef(s, insn); +@@ -1383,7 +1385,7 @@ static void gen_set_sr(DisasContext *s, uint16_t insn, int ccr_only) + else if ((insn & 0x3f) == 0x3c) + { + uint16_t val; +- val = lduw_code(s->pc); ++ val = cpu_lduw_code(cpu_single_env, s->pc); + s->pc += 2; + gen_set_sr_im(s, val, ccr_only); + } +@@ -1507,7 +1509,7 @@ DISAS_INSN(mull) + + /* The upper 32 bits of the product are discarded, so + muls.l and mulu.l are functionally equivalent. */ +- ext = lduw_code(s->pc); ++ ext = cpu_lduw_code(cpu_single_env, s->pc); + s->pc += 2; + if (ext & 0x87ff) { + gen_exception(s, s->pc - 4, EXCP_UNSUPPORTED); +@@ -1528,7 +1530,7 @@ DISAS_INSN(link) + TCGv reg; + TCGv tmp; + +- offset = ldsw_code(s->pc); ++ offset = cpu_ldsw_code(cpu_single_env, s->pc); + s->pc += 2; + reg = AREG(insn, 0); + tmp = tcg_temp_new(); +@@ -1649,7 +1651,7 @@ DISAS_INSN(branch) + op = (insn >> 8) & 0xf; + offset = (int8_t)insn; + if (offset == 0) { +- offset = ldsw_code(s->pc); ++ offset = cpu_ldsw_code(cpu_single_env, s->pc); + s->pc += 2; + } else if (offset == -1) { + offset = read_im32(s); +@@ -1934,13 +1936,13 @@ DISAS_INSN(strldsr) + uint32_t addr; + + addr = s->pc - 2; +- ext = lduw_code(s->pc); ++ ext = cpu_lduw_code(cpu_single_env, s->pc); + s->pc += 2; + if (ext != 0x46FC) { + gen_exception(s, addr, EXCP_UNSUPPORTED); + return; + } +- ext = lduw_code(s->pc); ++ ext = cpu_lduw_code(cpu_single_env, s->pc); + s->pc += 2; + if (IS_USER(s) || (ext & SR_S) == 0) { + gen_exception(s, addr, EXCP_PRIVILEGE); +@@ -2008,7 +2010,7 @@ DISAS_INSN(stop) + return; + } + +- ext = lduw_code(s->pc); ++ ext = cpu_lduw_code(cpu_single_env, s->pc); + s->pc += 2; + + gen_set_sr_im(s, ext, 0); +@@ -2035,7 +2037,7 @@ DISAS_INSN(movec) + return; + } + +- ext = lduw_code(s->pc); ++ ext = cpu_lduw_code(cpu_single_env, s->pc); + s->pc += 2; + + if (ext & 0x8000) { +@@ -2100,7 +2102,7 @@ DISAS_INSN(fpu) + int set_dest; + int opsize; + +- ext = lduw_code(s->pc); ++ ext = cpu_lduw_code(cpu_single_env, s->pc); + s->pc += 2; + opmode = ext & 0x7f; + switch ((ext >> 13) & 7) { +@@ -2136,7 +2138,7 @@ DISAS_INSN(fpu) + tcg_gen_addi_i32(tmp32, tmp32, -8); + break; + case 5: +- offset = ldsw_code(s->pc); ++ offset = cpu_ldsw_code(cpu_single_env, s->pc); + s->pc += 2; + tcg_gen_addi_i32(tmp32, tmp32, offset); + break; +@@ -2250,12 +2252,12 @@ DISAS_INSN(fpu) + tcg_gen_addi_i32(tmp32, tmp32, -8); + break; + case 5: +- offset = ldsw_code(s->pc); ++ offset = cpu_ldsw_code(cpu_single_env, s->pc); + s->pc += 2; + tcg_gen_addi_i32(tmp32, tmp32, offset); + break; + case 7: +- offset = ldsw_code(s->pc); ++ offset = cpu_ldsw_code(cpu_single_env, s->pc); + offset += s->pc - 2; + s->pc += 2; + tcg_gen_addi_i32(tmp32, tmp32, offset); +@@ -2381,10 +2383,10 @@ DISAS_INSN(fbcc) + int l1; + + addr = s->pc; +- offset = ldsw_code(s->pc); ++ offset = cpu_ldsw_code(cpu_single_env, s->pc); + s->pc += 2; + if (insn & (1 << 6)) { +- offset = (offset << 16) | lduw_code(s->pc); ++ offset = (offset << 16) | cpu_lduw_code(cpu_single_env, s->pc); + s->pc += 2; + } + +@@ -2506,7 +2508,7 @@ DISAS_INSN(mac) + s->done_mac = 1; + } + +- ext = lduw_code(s->pc); ++ ext = cpu_lduw_code(cpu_single_env, s->pc); + s->pc += 2; + + acc = ((insn >> 7) & 1) | ((ext >> 3) & 2); +@@ -2941,7 +2943,7 @@ static void disas_m68k_insn(CPUM68KState * env, DisasContext *s) + { + uint16_t insn; + +- insn = lduw_code(s->pc); ++ insn = cpu_lduw_code(cpu_single_env, s->pc); + s->pc += 2; + + opcode_table[insn](s, insn); +@@ -3028,7 +3030,7 @@ gen_intermediate_code_internal(CPUM68KState *env, TranslationBlock *tb, + gen_flush_cc_op(dc); + tcg_gen_movi_i32(QREG_PC, dc->pc); + } +- gen_helper_raise_exception(tcg_const_i32(EXCP_DEBUG)); ++ gen_helper_raise_exception(cpu_env, tcg_const_i32(EXCP_DEBUG)); + } else { + switch(dc->is_jmp) { + case DISAS_NEXT: +-- +1.7.12.1 + diff --git a/0029-target-m68k-avoid-using-cpu_single_env.patch b/0029-target-m68k-avoid-using-cpu_single_env.patch new file mode 100644 index 0000000..871bbe8 --- /dev/null +++ b/0029-target-m68k-avoid-using-cpu_single_env.patch @@ -0,0 +1,901 @@ +From 5560cd783146734a60c446f43227044cbb580edd Mon Sep 17 00:00:00 2001 +From: Blue Swirl +Date: Sat, 8 Sep 2012 10:48:20 +0000 +Subject: [PATCH] target-m68k: avoid using cpu_single_env + +Pass around CPUState instead of using global cpu_single_env. + +Signed-off-by: Blue Swirl +Signed-off-by: Michael Roth +--- + target-m68k/translate.c | 270 +++++++++++++++++++++++++----------------------- + 1 file changed, 140 insertions(+), 130 deletions(-) + +diff --git a/target-m68k/translate.c b/target-m68k/translate.c +index 10bb303..fb707f2 100644 +--- a/target-m68k/translate.c ++++ b/target-m68k/translate.c +@@ -150,18 +150,24 @@ static void *gen_throws_exception; + #define OS_SINGLE 4 + #define OS_DOUBLE 5 + +-typedef void (*disas_proc)(DisasContext *, uint16_t); ++typedef void (*disas_proc)(CPUM68KState *env, DisasContext *s, uint16_t insn); + + #ifdef DEBUG_DISPATCH +-#define DISAS_INSN(name) \ +- static void real_disas_##name (DisasContext *s, uint16_t insn); \ +- static void disas_##name (DisasContext *s, uint16_t insn) { \ +- qemu_log("Dispatch " #name "\n"); \ +- real_disas_##name(s, insn); } \ +- static void real_disas_##name (DisasContext *s, uint16_t insn) ++#define DISAS_INSN(name) \ ++ static void real_disas_##name(CPUM68KState *env, DisasContext *s, \ ++ uint16_t insn); \ ++ static void disas_##name(CPUM68KState *env, DisasContext *s, \ ++ uint16_t insn) \ ++ { \ ++ qemu_log("Dispatch " #name "\n"); \ ++ real_disas_##name(s, env, insn); \ ++ } \ ++ static void real_disas_##name(CPUM68KState *env, DisasContext *s, \ ++ uint16_t insn) + #else +-#define DISAS_INSN(name) \ +- static void disas_##name (DisasContext *s, uint16_t insn) ++#define DISAS_INSN(name) \ ++ static void disas_##name(CPUM68KState *env, DisasContext *s, \ ++ uint16_t insn) + #endif + + /* Generate a load from the specified address. Narrow values are +@@ -257,12 +263,12 @@ static TCGv gen_ldst(DisasContext *s, int opsize, TCGv addr, TCGv val, + } + + /* Read a 32-bit immediate constant. */ +-static inline uint32_t read_im32(DisasContext *s) ++static inline uint32_t read_im32(CPUM68KState *env, DisasContext *s) + { + uint32_t im; +- im = ((uint32_t)cpu_lduw_code(cpu_single_env, s->pc)) << 16; ++ im = ((uint32_t)cpu_lduw_code(env, s->pc)) << 16; + s->pc += 2; +- im |= cpu_lduw_code(cpu_single_env, s->pc); ++ im |= cpu_lduw_code(env, s->pc); + s->pc += 2; + return im; + } +@@ -288,7 +294,8 @@ static TCGv gen_addr_index(uint16_t ext, TCGv tmp) + + /* Handle a base + index + displacement effective addresss. + A NULL_QREG base means pc-relative. */ +-static TCGv gen_lea_indexed(DisasContext *s, int opsize, TCGv base) ++static TCGv gen_lea_indexed(CPUM68KState *env, DisasContext *s, int opsize, ++ TCGv base) + { + uint32_t offset; + uint16_t ext; +@@ -297,7 +304,7 @@ static TCGv gen_lea_indexed(DisasContext *s, int opsize, TCGv base) + uint32_t bd, od; + + offset = s->pc; +- ext = cpu_lduw_code(cpu_single_env, s->pc); ++ ext = cpu_lduw_code(env, s->pc); + s->pc += 2; + + if ((ext & 0x800) == 0 && !m68k_feature(s->env, M68K_FEATURE_WORD_INDEX)) +@@ -311,10 +318,10 @@ static TCGv gen_lea_indexed(DisasContext *s, int opsize, TCGv base) + if ((ext & 0x30) > 0x10) { + /* base displacement */ + if ((ext & 0x30) == 0x20) { +- bd = (int16_t)cpu_lduw_code(cpu_single_env, s->pc); ++ bd = (int16_t)cpu_lduw_code(env, s->pc); + s->pc += 2; + } else { +- bd = read_im32(s); ++ bd = read_im32(env, s); + } + } else { + bd = 0; +@@ -360,10 +367,10 @@ static TCGv gen_lea_indexed(DisasContext *s, int opsize, TCGv base) + if ((ext & 3) > 1) { + /* outer displacement */ + if ((ext & 3) == 2) { +- od = (int16_t)cpu_lduw_code(cpu_single_env, s->pc); ++ od = (int16_t)cpu_lduw_code(env, s->pc); + s->pc += 2; + } else { +- od = read_im32(s); ++ od = read_im32(env, s); + } + } else { + od = 0; +@@ -492,7 +499,8 @@ static inline TCGv gen_extend(TCGv val, int opsize, int sign) + + /* Generate code for an "effective address". Does not adjust the base + register for autoincrement addressing modes. */ +-static TCGv gen_lea(DisasContext *s, uint16_t insn, int opsize) ++static TCGv gen_lea(CPUM68KState *env, DisasContext *s, uint16_t insn, ++ int opsize) + { + TCGv reg; + TCGv tmp; +@@ -514,29 +522,29 @@ static TCGv gen_lea(DisasContext *s, uint16_t insn, int opsize) + case 5: /* Indirect displacement. */ + reg = AREG(insn, 0); + tmp = tcg_temp_new(); +- ext = cpu_lduw_code(cpu_single_env, s->pc); ++ ext = cpu_lduw_code(env, s->pc); + s->pc += 2; + tcg_gen_addi_i32(tmp, reg, (int16_t)ext); + return tmp; + case 6: /* Indirect index + displacement. */ + reg = AREG(insn, 0); +- return gen_lea_indexed(s, opsize, reg); ++ return gen_lea_indexed(env, s, opsize, reg); + case 7: /* Other */ + switch (insn & 7) { + case 0: /* Absolute short. */ +- offset = cpu_ldsw_code(cpu_single_env, s->pc); ++ offset = cpu_ldsw_code(env, s->pc); + s->pc += 2; + return tcg_const_i32(offset); + case 1: /* Absolute long. */ +- offset = read_im32(s); ++ offset = read_im32(env, s); + return tcg_const_i32(offset); + case 2: /* pc displacement */ + offset = s->pc; +- offset += cpu_ldsw_code(cpu_single_env, s->pc); ++ offset += cpu_ldsw_code(env, s->pc); + s->pc += 2; + return tcg_const_i32(offset); + case 3: /* pc index+displacement. */ +- return gen_lea_indexed(s, opsize, NULL_QREG); ++ return gen_lea_indexed(env, s, opsize, NULL_QREG); + case 4: /* Immediate. */ + default: + return NULL_QREG; +@@ -548,15 +556,16 @@ static TCGv gen_lea(DisasContext *s, uint16_t insn, int opsize) + + /* Helper function for gen_ea. Reuse the computed address between the + for read/write operands. */ +-static inline TCGv gen_ea_once(DisasContext *s, uint16_t insn, int opsize, +- TCGv val, TCGv *addrp, ea_what what) ++static inline TCGv gen_ea_once(CPUM68KState *env, DisasContext *s, ++ uint16_t insn, int opsize, TCGv val, ++ TCGv *addrp, ea_what what) + { + TCGv tmp; + + if (addrp && what == EA_STORE) { + tmp = *addrp; + } else { +- tmp = gen_lea(s, insn, opsize); ++ tmp = gen_lea(env, s, insn, opsize); + if (IS_NULL_QREG(tmp)) + return tmp; + if (addrp) +@@ -568,8 +577,8 @@ static inline TCGv gen_ea_once(DisasContext *s, uint16_t insn, int opsize, + /* Generate code to load/store a value ito/from an EA. If VAL > 0 this is + a write otherwise it is a read (0 == sign extend, -1 == zero extend). + ADDRP is non-null for readwrite operands. */ +-static TCGv gen_ea(DisasContext *s, uint16_t insn, int opsize, TCGv val, +- TCGv *addrp, ea_what what) ++static TCGv gen_ea(CPUM68KState *env, DisasContext *s, uint16_t insn, ++ int opsize, TCGv val, TCGv *addrp, ea_what what) + { + TCGv reg; + TCGv result; +@@ -609,7 +618,7 @@ static TCGv gen_ea(DisasContext *s, uint16_t insn, int opsize, TCGv val, + if (addrp && what == EA_STORE) { + tmp = *addrp; + } else { +- tmp = gen_lea(s, insn, opsize); ++ tmp = gen_lea(env, s, insn, opsize); + if (IS_NULL_QREG(tmp)) + return tmp; + if (addrp) +@@ -626,35 +635,35 @@ static TCGv gen_ea(DisasContext *s, uint16_t insn, int opsize, TCGv val, + return result; + case 5: /* Indirect displacement. */ + case 6: /* Indirect index + displacement. */ +- return gen_ea_once(s, insn, opsize, val, addrp, what); ++ return gen_ea_once(env, s, insn, opsize, val, addrp, what); + case 7: /* Other */ + switch (insn & 7) { + case 0: /* Absolute short. */ + case 1: /* Absolute long. */ + case 2: /* pc displacement */ + case 3: /* pc index+displacement. */ +- return gen_ea_once(s, insn, opsize, val, addrp, what); ++ return gen_ea_once(env, s, insn, opsize, val, addrp, what); + case 4: /* Immediate. */ + /* Sign extend values for consistency. */ + switch (opsize) { + case OS_BYTE: + if (what == EA_LOADS) { +- offset = cpu_ldsb_code(cpu_single_env, s->pc + 1); ++ offset = cpu_ldsb_code(env, s->pc + 1); + } else { +- offset = cpu_ldub_code(cpu_single_env, s->pc + 1); ++ offset = cpu_ldub_code(env, s->pc + 1); + } + s->pc += 2; + break; + case OS_WORD: + if (what == EA_LOADS) { +- offset = cpu_ldsw_code(cpu_single_env, s->pc); ++ offset = cpu_ldsw_code(env, s->pc); + } else { +- offset = cpu_lduw_code(cpu_single_env, s->pc); ++ offset = cpu_lduw_code(env, s->pc); + } + s->pc += 2; + break; + case OS_LONG: +- offset = read_im32(s); ++ offset = read_im32(env, s); + break; + default: + qemu_assert(0, "Bad immediate operand"); +@@ -825,20 +834,21 @@ static inline void gen_addr_fault(DisasContext *s) + gen_exception(s, s->insn_pc, EXCP_ADDRESS); + } + +-#define SRC_EA(result, opsize, op_sign, addrp) do { \ +- result = gen_ea(s, insn, opsize, NULL_QREG, addrp, op_sign ? EA_LOADS : EA_LOADU); \ +- if (IS_NULL_QREG(result)) { \ +- gen_addr_fault(s); \ +- return; \ +- } \ ++#define SRC_EA(env, result, opsize, op_sign, addrp) do { \ ++ result = gen_ea(env, s, insn, opsize, NULL_QREG, addrp, \ ++ op_sign ? EA_LOADS : EA_LOADU); \ ++ if (IS_NULL_QREG(result)) { \ ++ gen_addr_fault(s); \ ++ return; \ ++ } \ + } while (0) + +-#define DEST_EA(insn, opsize, val, addrp) do { \ +- TCGv ea_result = gen_ea(s, insn, opsize, val, addrp, EA_STORE); \ +- if (IS_NULL_QREG(ea_result)) { \ +- gen_addr_fault(s); \ +- return; \ +- } \ ++#define DEST_EA(env, insn, opsize, val, addrp) do { \ ++ TCGv ea_result = gen_ea(env, s, insn, opsize, val, addrp, EA_STORE); \ ++ if (IS_NULL_QREG(ea_result)) { \ ++ gen_addr_fault(s); \ ++ return; \ ++ } \ + } while (0) + + /* Generate a jump to an immediate address. */ +@@ -874,8 +884,7 @@ DISAS_INSN(undef_fpu) + DISAS_INSN(undef) + { + gen_exception(s, s->pc - 2, EXCP_UNSUPPORTED); +- cpu_abort(cpu_single_env, "Illegal instruction: %04x @ %08x", +- insn, s->pc - 2); ++ cpu_abort(env, "Illegal instruction: %04x @ %08x", insn, s->pc - 2); + } + + DISAS_INSN(mulw) +@@ -892,7 +901,7 @@ DISAS_INSN(mulw) + tcg_gen_ext16s_i32(tmp, reg); + else + tcg_gen_ext16u_i32(tmp, reg); +- SRC_EA(src, OS_WORD, sign, NULL); ++ SRC_EA(env, src, OS_WORD, sign, NULL); + tcg_gen_mul_i32(tmp, tmp, src); + tcg_gen_mov_i32(reg, tmp); + /* Unlike m68k, coldfire always clears the overflow bit. */ +@@ -913,7 +922,7 @@ DISAS_INSN(divw) + } else { + tcg_gen_ext16u_i32(QREG_DIV1, reg); + } +- SRC_EA(src, OS_WORD, sign, NULL); ++ SRC_EA(env, src, OS_WORD, sign, NULL); + tcg_gen_mov_i32(QREG_DIV2, src); + if (sign) { + gen_helper_divs(cpu_env, tcg_const_i32(1)); +@@ -936,7 +945,7 @@ DISAS_INSN(divl) + TCGv reg; + uint16_t ext; + +- ext = cpu_lduw_code(cpu_single_env, s->pc); ++ ext = cpu_lduw_code(env, s->pc); + s->pc += 2; + if (ext & 0x87f8) { + gen_exception(s, s->pc - 4, EXCP_UNSUPPORTED); +@@ -945,7 +954,7 @@ DISAS_INSN(divl) + num = DREG(ext, 12); + reg = DREG(ext, 0); + tcg_gen_mov_i32(QREG_DIV1, num); +- SRC_EA(den, OS_LONG, 0, NULL); ++ SRC_EA(env, den, OS_LONG, 0, NULL); + tcg_gen_mov_i32(QREG_DIV2, den); + if (ext & 0x0800) { + gen_helper_divs(cpu_env, tcg_const_i32(0)); +@@ -975,11 +984,11 @@ DISAS_INSN(addsub) + reg = DREG(insn, 9); + dest = tcg_temp_new(); + if (insn & 0x100) { +- SRC_EA(tmp, OS_LONG, 0, &addr); ++ SRC_EA(env, tmp, OS_LONG, 0, &addr); + src = reg; + } else { + tmp = reg; +- SRC_EA(src, OS_LONG, 0, NULL); ++ SRC_EA(env, src, OS_LONG, 0, NULL); + } + if (add) { + tcg_gen_add_i32(dest, tmp, src); +@@ -992,7 +1001,7 @@ DISAS_INSN(addsub) + } + gen_update_cc_add(dest, src); + if (insn & 0x100) { +- DEST_EA(insn, OS_LONG, dest, &addr); ++ DEST_EA(env, insn, OS_LONG, dest, &addr); + } else { + tcg_gen_mov_i32(reg, dest); + } +@@ -1022,7 +1031,7 @@ DISAS_INSN(bitop_reg) + else + opsize = OS_LONG; + op = (insn >> 6) & 3; +- SRC_EA(src1, opsize, 0, op ? &addr: NULL); ++ SRC_EA(env, src1, opsize, 0, op ? &addr: NULL); + src2 = DREG(insn, 9); + dest = tcg_temp_new(); + +@@ -1057,7 +1066,7 @@ DISAS_INSN(bitop_reg) + break; + } + if (op) +- DEST_EA(insn, opsize, dest, &addr); ++ DEST_EA(env, insn, opsize, dest, &addr); + } + + DISAS_INSN(sats) +@@ -1088,9 +1097,9 @@ DISAS_INSN(movem) + TCGv tmp; + int is_load; + +- mask = cpu_lduw_code(cpu_single_env, s->pc); ++ mask = cpu_lduw_code(env, s->pc); + s->pc += 2; +- tmp = gen_lea(s, insn, OS_LONG); ++ tmp = gen_lea(env, s, insn, OS_LONG); + if (IS_NULL_QREG(tmp)) { + gen_addr_fault(s); + return; +@@ -1132,14 +1141,14 @@ DISAS_INSN(bitop_im) + opsize = OS_LONG; + op = (insn >> 6) & 3; + +- bitnum = cpu_lduw_code(cpu_single_env, s->pc); ++ bitnum = cpu_lduw_code(env, s->pc); + s->pc += 2; + if (bitnum & 0xff00) { +- disas_undef(s, insn); ++ disas_undef(env, s, insn); + return; + } + +- SRC_EA(src1, opsize, 0, op ? &addr: NULL); ++ SRC_EA(env, src1, opsize, 0, op ? &addr: NULL); + + gen_flush_flags(s); + if (opsize == OS_BYTE) +@@ -1174,7 +1183,7 @@ DISAS_INSN(bitop_im) + default: /* btst */ + break; + } +- DEST_EA(insn, opsize, tmp, &addr); ++ DEST_EA(env, insn, opsize, tmp, &addr); + } + } + +@@ -1187,8 +1196,8 @@ DISAS_INSN(arith_im) + TCGv addr; + + op = (insn >> 9) & 7; +- SRC_EA(src1, OS_LONG, 0, (op == 6) ? NULL : &addr); +- im = read_im32(s); ++ SRC_EA(env, src1, OS_LONG, 0, (op == 6) ? NULL : &addr); ++ im = read_im32(env, s); + dest = tcg_temp_new(); + switch (op) { + case 0: /* ori */ +@@ -1227,7 +1236,7 @@ DISAS_INSN(arith_im) + abort(); + } + if (op != 6) { +- DEST_EA(insn, OS_LONG, dest, &addr); ++ DEST_EA(env, insn, OS_LONG, dest, &addr); + } + } + +@@ -1259,7 +1268,7 @@ DISAS_INSN(move) + default: + abort(); + } +- SRC_EA(src, opsize, 1, NULL); ++ SRC_EA(env, src, opsize, 1, NULL); + op = (insn >> 6) & 7; + if (op == 1) { + /* movea */ +@@ -1270,7 +1279,7 @@ DISAS_INSN(move) + /* normal move */ + uint16_t dest_ea; + dest_ea = ((insn >> 9) & 7) | (op << 3); +- DEST_EA(dest_ea, opsize, src, NULL); ++ DEST_EA(env, dest_ea, opsize, src, NULL); + /* This will be correct because loads sign extend. */ + gen_logic_cc(s, src); + } +@@ -1291,7 +1300,7 @@ DISAS_INSN(lea) + TCGv tmp; + + reg = AREG(insn, 9); +- tmp = gen_lea(s, insn, OS_LONG); ++ tmp = gen_lea(env, s, insn, OS_LONG); + if (IS_NULL_QREG(tmp)) { + gen_addr_fault(s); + return; +@@ -1316,7 +1325,7 @@ DISAS_INSN(clr) + default: + abort(); + } +- DEST_EA(insn, opsize, tcg_const_i32(0), NULL); ++ DEST_EA(env, insn, opsize, tcg_const_i32(0), NULL); + gen_logic_cc(s, tcg_const_i32(0)); + } + +@@ -1365,7 +1374,8 @@ static void gen_set_sr_im(DisasContext *s, uint16_t val, int ccr_only) + } + } + +-static void gen_set_sr(DisasContext *s, uint16_t insn, int ccr_only) ++static void gen_set_sr(CPUM68KState *env, DisasContext *s, uint16_t insn, ++ int ccr_only) + { + TCGv tmp; + TCGv reg; +@@ -1385,17 +1395,17 @@ static void gen_set_sr(DisasContext *s, uint16_t insn, int ccr_only) + else if ((insn & 0x3f) == 0x3c) + { + uint16_t val; +- val = cpu_lduw_code(cpu_single_env, s->pc); ++ val = cpu_lduw_code(env, s->pc); + s->pc += 2; + gen_set_sr_im(s, val, ccr_only); + } + else +- disas_undef(s, insn); ++ disas_undef(env, s, insn); + } + + DISAS_INSN(move_to_ccr) + { +- gen_set_sr(s, insn, 1); ++ gen_set_sr(env, s, insn, 1); + } + + DISAS_INSN(not) +@@ -1426,7 +1436,7 @@ DISAS_INSN(pea) + { + TCGv tmp; + +- tmp = gen_lea(s, insn, OS_LONG); ++ tmp = gen_lea(env, s, insn, OS_LONG); + if (IS_NULL_QREG(tmp)) { + gen_addr_fault(s); + return; +@@ -1472,7 +1482,7 @@ DISAS_INSN(tst) + default: + abort(); + } +- SRC_EA(tmp, opsize, 1, NULL); ++ SRC_EA(env, tmp, opsize, 1, NULL); + gen_logic_cc(s, tmp); + } + +@@ -1494,10 +1504,10 @@ DISAS_INSN(tas) + TCGv addr; + + dest = tcg_temp_new(); +- SRC_EA(src1, OS_BYTE, 1, &addr); ++ SRC_EA(env, src1, OS_BYTE, 1, &addr); + gen_logic_cc(s, src1); + tcg_gen_ori_i32(dest, src1, 0x80); +- DEST_EA(insn, OS_BYTE, dest, &addr); ++ DEST_EA(env, insn, OS_BYTE, dest, &addr); + } + + DISAS_INSN(mull) +@@ -1509,14 +1519,14 @@ DISAS_INSN(mull) + + /* The upper 32 bits of the product are discarded, so + muls.l and mulu.l are functionally equivalent. */ +- ext = cpu_lduw_code(cpu_single_env, s->pc); ++ ext = cpu_lduw_code(env, s->pc); + s->pc += 2; + if (ext & 0x87ff) { + gen_exception(s, s->pc - 4, EXCP_UNSUPPORTED); + return; + } + reg = DREG(ext, 12); +- SRC_EA(src1, OS_LONG, 0, NULL); ++ SRC_EA(env, src1, OS_LONG, 0, NULL); + dest = tcg_temp_new(); + tcg_gen_mul_i32(dest, src1, reg); + tcg_gen_mov_i32(reg, dest); +@@ -1530,7 +1540,7 @@ DISAS_INSN(link) + TCGv reg; + TCGv tmp; + +- offset = cpu_ldsw_code(cpu_single_env, s->pc); ++ offset = cpu_ldsw_code(env, s->pc); + s->pc += 2; + reg = AREG(insn, 0); + tmp = tcg_temp_new(); +@@ -1574,7 +1584,7 @@ DISAS_INSN(jump) + + /* Load the target address first to ensure correct exception + behavior. */ +- tmp = gen_lea(s, insn, OS_LONG); ++ tmp = gen_lea(env, s, insn, OS_LONG); + if (IS_NULL_QREG(tmp)) { + gen_addr_fault(s); + return; +@@ -1594,7 +1604,7 @@ DISAS_INSN(addsubq) + int val; + TCGv addr; + +- SRC_EA(src1, OS_LONG, 0, &addr); ++ SRC_EA(env, src1, OS_LONG, 0, &addr); + val = (insn >> 9) & 7; + if (val == 0) + val = 8; +@@ -1621,7 +1631,7 @@ DISAS_INSN(addsubq) + } + gen_update_cc_add(dest, src2); + } +- DEST_EA(insn, OS_LONG, dest, &addr); ++ DEST_EA(env, insn, OS_LONG, dest, &addr); + } + + DISAS_INSN(tpf) +@@ -1636,7 +1646,7 @@ DISAS_INSN(tpf) + case 4: /* No extension words. */ + break; + default: +- disas_undef(s, insn); ++ disas_undef(env, s, insn); + } + } + +@@ -1651,10 +1661,10 @@ DISAS_INSN(branch) + op = (insn >> 8) & 0xf; + offset = (int8_t)insn; + if (offset == 0) { +- offset = cpu_ldsw_code(cpu_single_env, s->pc); ++ offset = cpu_ldsw_code(env, s->pc); + s->pc += 2; + } else if (offset == -1) { +- offset = read_im32(s); ++ offset = read_im32(env, s); + } + if (op == 1) { + /* bsr */ +@@ -1693,7 +1703,7 @@ DISAS_INSN(mvzs) + opsize = OS_WORD; + else + opsize = OS_BYTE; +- SRC_EA(src, opsize, (insn & 0x80) == 0, NULL); ++ SRC_EA(env, src, opsize, (insn & 0x80) == 0, NULL); + reg = DREG(insn, 9); + tcg_gen_mov_i32(reg, src); + gen_logic_cc(s, src); +@@ -1709,11 +1719,11 @@ DISAS_INSN(or) + reg = DREG(insn, 9); + dest = tcg_temp_new(); + if (insn & 0x100) { +- SRC_EA(src, OS_LONG, 0, &addr); ++ SRC_EA(env, src, OS_LONG, 0, &addr); + tcg_gen_or_i32(dest, src, reg); +- DEST_EA(insn, OS_LONG, dest, &addr); ++ DEST_EA(env, insn, OS_LONG, dest, &addr); + } else { +- SRC_EA(src, OS_LONG, 0, NULL); ++ SRC_EA(env, src, OS_LONG, 0, NULL); + tcg_gen_or_i32(dest, src, reg); + tcg_gen_mov_i32(reg, dest); + } +@@ -1725,7 +1735,7 @@ DISAS_INSN(suba) + TCGv src; + TCGv reg; + +- SRC_EA(src, OS_LONG, 0, NULL); ++ SRC_EA(env, src, OS_LONG, 0, NULL); + reg = AREG(insn, 9); + tcg_gen_sub_i32(reg, reg, src); + } +@@ -1751,7 +1761,7 @@ DISAS_INSN(mov3q) + val = -1; + src = tcg_const_i32(val); + gen_logic_cc(s, src); +- DEST_EA(insn, OS_LONG, src, NULL); ++ DEST_EA(env, insn, OS_LONG, src, NULL); + } + + DISAS_INSN(cmp) +@@ -1779,7 +1789,7 @@ DISAS_INSN(cmp) + default: + abort(); + } +- SRC_EA(src, opsize, 1, NULL); ++ SRC_EA(env, src, opsize, 1, NULL); + reg = DREG(insn, 9); + dest = tcg_temp_new(); + tcg_gen_sub_i32(dest, reg, src); +@@ -1798,7 +1808,7 @@ DISAS_INSN(cmpa) + } else { + opsize = OS_WORD; + } +- SRC_EA(src, opsize, 1, NULL); ++ SRC_EA(env, src, opsize, 1, NULL); + reg = AREG(insn, 9); + dest = tcg_temp_new(); + tcg_gen_sub_i32(dest, reg, src); +@@ -1813,12 +1823,12 @@ DISAS_INSN(eor) + TCGv dest; + TCGv addr; + +- SRC_EA(src, OS_LONG, 0, &addr); ++ SRC_EA(env, src, OS_LONG, 0, &addr); + reg = DREG(insn, 9); + dest = tcg_temp_new(); + tcg_gen_xor_i32(dest, src, reg); + gen_logic_cc(s, dest); +- DEST_EA(insn, OS_LONG, dest, &addr); ++ DEST_EA(env, insn, OS_LONG, dest, &addr); + } + + DISAS_INSN(and) +@@ -1831,11 +1841,11 @@ DISAS_INSN(and) + reg = DREG(insn, 9); + dest = tcg_temp_new(); + if (insn & 0x100) { +- SRC_EA(src, OS_LONG, 0, &addr); ++ SRC_EA(env, src, OS_LONG, 0, &addr); + tcg_gen_and_i32(dest, src, reg); +- DEST_EA(insn, OS_LONG, dest, &addr); ++ DEST_EA(env, insn, OS_LONG, dest, &addr); + } else { +- SRC_EA(src, OS_LONG, 0, NULL); ++ SRC_EA(env, src, OS_LONG, 0, NULL); + tcg_gen_and_i32(dest, src, reg); + tcg_gen_mov_i32(reg, dest); + } +@@ -1847,7 +1857,7 @@ DISAS_INSN(adda) + TCGv src; + TCGv reg; + +- SRC_EA(src, OS_LONG, 0, NULL); ++ SRC_EA(env, src, OS_LONG, 0, NULL); + reg = AREG(insn, 9); + tcg_gen_add_i32(reg, reg, src); + } +@@ -1936,13 +1946,13 @@ DISAS_INSN(strldsr) + uint32_t addr; + + addr = s->pc - 2; +- ext = cpu_lduw_code(cpu_single_env, s->pc); ++ ext = cpu_lduw_code(env, s->pc); + s->pc += 2; + if (ext != 0x46FC) { + gen_exception(s, addr, EXCP_UNSUPPORTED); + return; + } +- ext = cpu_lduw_code(cpu_single_env, s->pc); ++ ext = cpu_lduw_code(env, s->pc); + s->pc += 2; + if (IS_USER(s) || (ext & SR_S) == 0) { + gen_exception(s, addr, EXCP_PRIVILEGE); +@@ -1972,7 +1982,7 @@ DISAS_INSN(move_to_sr) + gen_exception(s, s->pc - 2, EXCP_PRIVILEGE); + return; + } +- gen_set_sr(s, insn, 0); ++ gen_set_sr(env, s, insn, 0); + gen_lookup_tb(s); + } + +@@ -2010,7 +2020,7 @@ DISAS_INSN(stop) + return; + } + +- ext = cpu_lduw_code(cpu_single_env, s->pc); ++ ext = cpu_lduw_code(env, s->pc); + s->pc += 2; + + gen_set_sr_im(s, ext, 0); +@@ -2037,7 +2047,7 @@ DISAS_INSN(movec) + return; + } + +- ext = cpu_lduw_code(cpu_single_env, s->pc); ++ ext = cpu_lduw_code(env, s->pc); + s->pc += 2; + + if (ext & 0x8000) { +@@ -2102,7 +2112,7 @@ DISAS_INSN(fpu) + int set_dest; + int opsize; + +- ext = cpu_lduw_code(cpu_single_env, s->pc); ++ ext = cpu_lduw_code(env, s->pc); + s->pc += 2; + opmode = ext & 0x7f; + switch ((ext >> 13) & 7) { +@@ -2138,7 +2148,7 @@ DISAS_INSN(fpu) + tcg_gen_addi_i32(tmp32, tmp32, -8); + break; + case 5: +- offset = cpu_ldsw_code(cpu_single_env, s->pc); ++ offset = cpu_ldsw_code(env, s->pc); + s->pc += 2; + tcg_gen_addi_i32(tmp32, tmp32, offset); + break; +@@ -2164,7 +2174,7 @@ DISAS_INSN(fpu) + default: + goto undef; + } +- DEST_EA(insn, opsize, tmp32, NULL); ++ DEST_EA(env, insn, opsize, tmp32, NULL); + tcg_temp_free_i32(tmp32); + return; + case 4: /* fmove to control register. */ +@@ -2192,7 +2202,7 @@ DISAS_INSN(fpu) + (ext >> 10) & 7); + goto undef; + } +- DEST_EA(insn, OS_LONG, tmp32, NULL); ++ DEST_EA(env, insn, OS_LONG, tmp32, NULL); + break; + case 6: /* fmovem */ + case 7: +@@ -2202,7 +2212,7 @@ DISAS_INSN(fpu) + int i; + if ((ext & 0x1f00) != 0x1000 || (ext & 0xff) == 0) + goto undef; +- tmp32 = gen_lea(s, insn, OS_LONG); ++ tmp32 = gen_lea(env, s, insn, OS_LONG); + if (IS_NULL_QREG(tmp32)) { + gen_addr_fault(s); + return; +@@ -2252,12 +2262,12 @@ DISAS_INSN(fpu) + tcg_gen_addi_i32(tmp32, tmp32, -8); + break; + case 5: +- offset = cpu_ldsw_code(cpu_single_env, s->pc); ++ offset = cpu_ldsw_code(env, s->pc); + s->pc += 2; + tcg_gen_addi_i32(tmp32, tmp32, offset); + break; + case 7: +- offset = cpu_ldsw_code(cpu_single_env, s->pc); ++ offset = cpu_ldsw_code(env, s->pc); + offset += s->pc - 2; + s->pc += 2; + tcg_gen_addi_i32(tmp32, tmp32, offset); +@@ -2277,7 +2287,7 @@ DISAS_INSN(fpu) + } + tcg_temp_free_i32(tmp32); + } else { +- SRC_EA(tmp32, opsize, 1, NULL); ++ SRC_EA(env, tmp32, opsize, 1, NULL); + src = tcg_temp_new_i64(); + switch (opsize) { + case OS_LONG: +@@ -2372,7 +2382,7 @@ DISAS_INSN(fpu) + undef: + /* FIXME: Is this right for offset addressing modes? */ + s->pc -= 2; +- disas_undef_fpu(s, insn); ++ disas_undef_fpu(env, s, insn); + } + + DISAS_INSN(fbcc) +@@ -2383,10 +2393,10 @@ DISAS_INSN(fbcc) + int l1; + + addr = s->pc; +- offset = cpu_ldsw_code(cpu_single_env, s->pc); ++ offset = cpu_ldsw_code(env, s->pc); + s->pc += 2; + if (insn & (1 << 6)) { +- offset = (offset << 16) | cpu_lduw_code(cpu_single_env, s->pc); ++ offset = (offset << 16) | cpu_lduw_code(env, s->pc); + s->pc += 2; + } + +@@ -2508,18 +2518,18 @@ DISAS_INSN(mac) + s->done_mac = 1; + } + +- ext = cpu_lduw_code(cpu_single_env, s->pc); ++ ext = cpu_lduw_code(env, s->pc); + s->pc += 2; + + acc = ((insn >> 7) & 1) | ((ext >> 3) & 2); + dual = ((insn & 0x30) != 0 && (ext & 3) != 0); + if (dual && !m68k_feature(s->env, M68K_FEATURE_CF_EMAC_B)) { +- disas_undef(s, insn); ++ disas_undef(env, s, insn); + return; + } + if (insn & 0x30) { + /* MAC with load. */ +- tmp = gen_lea(s, insn, OS_LONG); ++ tmp = gen_lea(env, s, insn, OS_LONG); + addr = tcg_temp_new(); + tcg_gen_and_i32(addr, tmp, QREG_MAC_MASK); + /* Load the value now to ensure correct exception behavior. +@@ -2733,7 +2743,7 @@ DISAS_INSN(to_mac) + int accnum; + accnum = (insn >> 9) & 3; + acc = MACREG(accnum); +- SRC_EA(val, OS_LONG, 0, NULL); ++ SRC_EA(env, val, OS_LONG, 0, NULL); + if (s->env->macsr & MACSR_FI) { + tcg_gen_ext_i32_i64(acc, val); + tcg_gen_shli_i64(acc, acc, 8); +@@ -2750,7 +2760,7 @@ DISAS_INSN(to_mac) + DISAS_INSN(to_macsr) + { + TCGv val; +- SRC_EA(val, OS_LONG, 0, NULL); ++ SRC_EA(env, val, OS_LONG, 0, NULL); + gen_helper_set_macsr(cpu_env, val); + gen_lookup_tb(s); + } +@@ -2758,7 +2768,7 @@ DISAS_INSN(to_macsr) + DISAS_INSN(to_mask) + { + TCGv val; +- SRC_EA(val, OS_LONG, 0, NULL); ++ SRC_EA(env, val, OS_LONG, 0, NULL); + tcg_gen_ori_i32(QREG_MAC_MASK, val, 0xffff0000); + } + +@@ -2766,7 +2776,7 @@ DISAS_INSN(to_mext) + { + TCGv val; + TCGv acc; +- SRC_EA(val, OS_LONG, 0, NULL); ++ SRC_EA(env, val, OS_LONG, 0, NULL); + acc = tcg_const_i32((insn & 0x400) ? 2 : 0); + if (s->env->macsr & MACSR_FI) + gen_helper_set_mac_extf(cpu_env, val, acc); +@@ -2943,10 +2953,10 @@ static void disas_m68k_insn(CPUM68KState * env, DisasContext *s) + { + uint16_t insn; + +- insn = cpu_lduw_code(cpu_single_env, s->pc); ++ insn = cpu_lduw_code(env, s->pc); + s->pc += 2; + +- opcode_table[insn](s, insn); ++ opcode_table[insn](env, s, insn); + } + + /* generate intermediate code for basic block 'tb'. */ +-- +1.7.12.1 + diff --git a/0030-target-unicore32-switch-to-AREG0-free-mode.patch b/0030-target-unicore32-switch-to-AREG0-free-mode.patch new file mode 100644 index 0000000..4880417 --- /dev/null +++ b/0030-target-unicore32-switch-to-AREG0-free-mode.patch @@ -0,0 +1,437 @@ +From 23ff6fa6a883d210aab33e09d0bb9470df5083fc Mon Sep 17 00:00:00 2001 +From: Blue Swirl +Date: Sun, 2 Sep 2012 07:42:33 +0000 +Subject: [PATCH] target-unicore32: switch to AREG0 free mode + +Add an explicit CPUState parameter instead of relying on AREG0 +and switch to AREG0 free mode. + +Tested-by: Guan Xuetao +Signed-off-by: Blue Swirl +Signed-off-by: Michael Roth +--- + configure | 2 +- + target-unicore32/Makefile.objs | 2 -- + target-unicore32/helper.h | 26 ++++++++--------- + target-unicore32/op_helper.c | 65 ++++++++++++++++-------------------------- + target-unicore32/translate.c | 38 ++++++++++++------------ + 5 files changed, 58 insertions(+), 75 deletions(-) + +diff --git a/configure b/configure +index af03942..a8827ba 100755 +--- a/configure ++++ b/configure +@@ -3839,7 +3839,7 @@ symlink "$source_path/Makefile.target" "$target_dir/Makefile" + + + case "$target_arch2" in +- alpha | i386 | lm32 | m68k | or32 | s390x | sparc* | x86_64 | xtensa* | ppc*) ++ alpha | i386 | lm32 | m68k | or32 | s390x | sparc* | unicore32 | x86_64 | xtensa* | ppc*) + echo "CONFIG_TCG_PASS_AREG0=y" >> $config_target_mak + ;; + esac +diff --git a/target-unicore32/Makefile.objs b/target-unicore32/Makefile.objs +index 777f01f..8e143da 100644 +--- a/target-unicore32/Makefile.objs ++++ b/target-unicore32/Makefile.objs +@@ -2,5 +2,3 @@ obj-y += translate.o op_helper.o helper.o cpu.o + obj-y += ucf64_helper.o + + obj-$(CONFIG_SOFTMMU) += machine.o softmmu.o +- +-$(obj)/op_helper.o: QEMU_CFLAGS += $(HELPER_CFLAGS) +diff --git a/target-unicore32/helper.h b/target-unicore32/helper.h +index 305318a..a4b8149 100644 +--- a/target-unicore32/helper.h ++++ b/target-unicore32/helper.h +@@ -17,26 +17,26 @@ DEF_HELPER_1(cp1_putc, void, i32) + DEF_HELPER_1(clz, i32, i32) + DEF_HELPER_1(clo, i32, i32) + +-DEF_HELPER_1(exception, void, i32) ++DEF_HELPER_2(exception, void, env, i32) + +-DEF_HELPER_2(asr_write, void, i32, i32) +-DEF_HELPER_0(asr_read, i32) ++DEF_HELPER_3(asr_write, void, env, i32, i32) ++DEF_HELPER_1(asr_read, i32, env) + +-DEF_HELPER_1(get_user_reg, i32, i32) +-DEF_HELPER_2(set_user_reg, void, i32, i32) ++DEF_HELPER_2(get_user_reg, i32, env, i32) ++DEF_HELPER_3(set_user_reg, void, env, i32, i32) + +-DEF_HELPER_2(add_cc, i32, i32, i32) +-DEF_HELPER_2(adc_cc, i32, i32, i32) +-DEF_HELPER_2(sub_cc, i32, i32, i32) +-DEF_HELPER_2(sbc_cc, i32, i32, i32) ++DEF_HELPER_3(add_cc, i32, env, i32, i32) ++DEF_HELPER_3(adc_cc, i32, env, i32, i32) ++DEF_HELPER_3(sub_cc, i32, env, i32, i32) ++DEF_HELPER_3(sbc_cc, i32, env, i32, i32) + + DEF_HELPER_2(shl, i32, i32, i32) + DEF_HELPER_2(shr, i32, i32, i32) + DEF_HELPER_2(sar, i32, i32, i32) +-DEF_HELPER_2(shl_cc, i32, i32, i32) +-DEF_HELPER_2(shr_cc, i32, i32, i32) +-DEF_HELPER_2(sar_cc, i32, i32, i32) +-DEF_HELPER_2(ror_cc, i32, i32, i32) ++DEF_HELPER_3(shl_cc, i32, env, i32, i32) ++DEF_HELPER_3(shr_cc, i32, env, i32, i32) ++DEF_HELPER_3(sar_cc, i32, env, i32, i32) ++DEF_HELPER_3(ror_cc, i32, env, i32, i32) + + DEF_HELPER_1(ucf64_get_fpscr, i32, env) + DEF_HELPER_2(ucf64_set_fpscr, void, env, i32) +diff --git a/target-unicore32/op_helper.c b/target-unicore32/op_helper.c +index c63789d..f474d1b 100644 +--- a/target-unicore32/op_helper.c ++++ b/target-unicore32/op_helper.c +@@ -9,19 +9,18 @@ + * later version. See the COPYING file in the top-level directory. + */ + #include "cpu.h" +-#include "dyngen-exec.h" + #include "helper.h" + + #define SIGNBIT (uint32_t)0x80000000 + #define SIGNBIT64 ((uint64_t)1 << 63) + +-void HELPER(exception)(uint32_t excp) ++void HELPER(exception)(CPUUniCore32State *env, uint32_t excp) + { + env->exception_index = excp; + cpu_loop_exit(env); + } + +-static target_ulong asr_read(void) ++static target_ulong asr_read(CPUUniCore32State *env) + { + int ZF; + ZF = (env->ZF == 0); +@@ -29,24 +28,18 @@ static target_ulong asr_read(void) + (env->CF << 29) | ((env->VF & 0x80000000) >> 3); + } + +-target_ulong cpu_asr_read(CPUUniCore32State *env1) ++target_ulong cpu_asr_read(CPUUniCore32State *env) + { +- CPUUniCore32State *saved_env; +- target_ulong ret; +- +- saved_env = env; +- env = env1; +- ret = asr_read(); +- env = saved_env; +- return ret; ++ return asr_read(env); + } + +-target_ulong HELPER(asr_read)(void) ++target_ulong HELPER(asr_read)(CPUUniCore32State *env) + { +- return asr_read(); ++ return asr_read(env); + } + +-static void asr_write(target_ulong val, target_ulong mask) ++static void asr_write(CPUUniCore32State *env, target_ulong val, ++ target_ulong mask) + { + if (mask & ASR_NZCV) { + env->ZF = (~val) & ASR_Z; +@@ -62,23 +55,19 @@ static void asr_write(target_ulong val, target_ulong mask) + env->uncached_asr = (env->uncached_asr & ~mask) | (val & mask); + } + +-void cpu_asr_write(CPUUniCore32State *env1, target_ulong val, target_ulong mask) ++void cpu_asr_write(CPUUniCore32State *env, target_ulong val, target_ulong mask) + { +- CPUUniCore32State *saved_env; +- +- saved_env = env; +- env = env1; +- asr_write(val, mask); +- env = saved_env; ++ asr_write(env, val, mask); + } + +-void HELPER(asr_write)(target_ulong val, target_ulong mask) ++void HELPER(asr_write)(CPUUniCore32State *env, target_ulong val, ++ target_ulong mask) + { +- asr_write(val, mask); ++ asr_write(env, val, mask); + } + + /* Access to user mode registers from privileged modes. */ +-uint32_t HELPER(get_user_reg)(uint32_t regno) ++uint32_t HELPER(get_user_reg)(CPUUniCore32State *env, uint32_t regno) + { + uint32_t val; + +@@ -92,7 +81,7 @@ uint32_t HELPER(get_user_reg)(uint32_t regno) + return val; + } + +-void HELPER(set_user_reg)(uint32_t regno, uint32_t val) ++void HELPER(set_user_reg)(CPUUniCore32State *env, uint32_t regno, uint32_t val) + { + if (regno == 29) { + env->banked_r29[0] = val; +@@ -107,7 +96,7 @@ void HELPER(set_user_reg)(uint32_t regno, uint32_t val) + The only way to do that in TCG is a conditional branch, which clobbers + all our temporaries. For now implement these as helper functions. */ + +-uint32_t HELPER(add_cc)(uint32_t a, uint32_t b) ++uint32_t HELPER(add_cc)(CPUUniCore32State *env, uint32_t a, uint32_t b) + { + uint32_t result; + result = a + b; +@@ -117,7 +106,7 @@ uint32_t HELPER(add_cc)(uint32_t a, uint32_t b) + return result; + } + +-uint32_t HELPER(adc_cc)(uint32_t a, uint32_t b) ++uint32_t HELPER(adc_cc)(CPUUniCore32State *env, uint32_t a, uint32_t b) + { + uint32_t result; + if (!env->CF) { +@@ -132,7 +121,7 @@ uint32_t HELPER(adc_cc)(uint32_t a, uint32_t b) + return result; + } + +-uint32_t HELPER(sub_cc)(uint32_t a, uint32_t b) ++uint32_t HELPER(sub_cc)(CPUUniCore32State *env, uint32_t a, uint32_t b) + { + uint32_t result; + result = a - b; +@@ -142,7 +131,7 @@ uint32_t HELPER(sub_cc)(uint32_t a, uint32_t b) + return result; + } + +-uint32_t HELPER(sbc_cc)(uint32_t a, uint32_t b) ++uint32_t HELPER(sbc_cc)(CPUUniCore32State *env, uint32_t a, uint32_t b) + { + uint32_t result; + if (!env->CF) { +@@ -186,7 +175,7 @@ uint32_t HELPER(sar)(uint32_t x, uint32_t i) + return (int32_t)x >> shift; + } + +-uint32_t HELPER(shl_cc)(uint32_t x, uint32_t i) ++uint32_t HELPER(shl_cc)(CPUUniCore32State *env, uint32_t x, uint32_t i) + { + int shift = i & 0xff; + if (shift >= 32) { +@@ -203,7 +192,7 @@ uint32_t HELPER(shl_cc)(uint32_t x, uint32_t i) + return x; + } + +-uint32_t HELPER(shr_cc)(uint32_t x, uint32_t i) ++uint32_t HELPER(shr_cc)(CPUUniCore32State *env, uint32_t x, uint32_t i) + { + int shift = i & 0xff; + if (shift >= 32) { +@@ -220,7 +209,7 @@ uint32_t HELPER(shr_cc)(uint32_t x, uint32_t i) + return x; + } + +-uint32_t HELPER(sar_cc)(uint32_t x, uint32_t i) ++uint32_t HELPER(sar_cc)(CPUUniCore32State *env, uint32_t x, uint32_t i) + { + int shift = i & 0xff; + if (shift >= 32) { +@@ -233,7 +222,7 @@ uint32_t HELPER(sar_cc)(uint32_t x, uint32_t i) + return x; + } + +-uint32_t HELPER(ror_cc)(uint32_t x, uint32_t i) ++uint32_t HELPER(ror_cc)(CPUUniCore32State *env, uint32_t x, uint32_t i) + { + int shift1, shift; + shift1 = i & 0xff; +@@ -264,16 +253,13 @@ uint32_t HELPER(ror_cc)(uint32_t x, uint32_t i) + #define SHIFT 3 + #include "softmmu_template.h" + +-void tlb_fill(CPUUniCore32State *env1, target_ulong addr, int is_write, +- int mmu_idx, uintptr_t retaddr) ++void tlb_fill(CPUUniCore32State *env, target_ulong addr, int is_write, ++ int mmu_idx, uintptr_t retaddr) + { + TranslationBlock *tb; +- CPUUniCore32State *saved_env; + unsigned long pc; + int ret; + +- saved_env = env; +- env = env1; + ret = uc32_cpu_handle_mmu_fault(env, addr, is_write, mmu_idx); + if (unlikely(ret)) { + if (retaddr) { +@@ -287,6 +273,5 @@ void tlb_fill(CPUUniCore32State *env1, target_ulong addr, int is_write, + } + cpu_loop_exit(env); + } +- env = saved_env; + } + #endif +diff --git a/target-unicore32/translate.c b/target-unicore32/translate.c +index 188bf8c..b786a6b 100644 +--- a/target-unicore32/translate.c ++++ b/target-unicore32/translate.c +@@ -253,7 +253,7 @@ static void disas_ocd_insn(CPUUniCore32State *env, DisasContext *s, + static inline void gen_set_asr(TCGv var, uint32_t mask) + { + TCGv tmp_mask = tcg_const_i32(mask); +- gen_helper_asr_write(var, tmp_mask); ++ gen_helper_asr_write(cpu_env, var, tmp_mask); + tcg_temp_free_i32(tmp_mask); + } + /* Set NZCV flags from the high 4 bits of var. */ +@@ -263,7 +263,7 @@ static void gen_exception(int excp) + { + TCGv tmp = new_tmp(); + tcg_gen_movi_i32(tmp, excp); +- gen_helper_exception(tmp); ++ gen_helper_exception(cpu_env, tmp); + dead_tmp(tmp); + } + +@@ -416,16 +416,16 @@ static inline void gen_uc32_shift_reg(TCGv var, int shiftop, + if (flags) { + switch (shiftop) { + case 0: +- gen_helper_shl_cc(var, var, shift); ++ gen_helper_shl_cc(var, cpu_env, var, shift); + break; + case 1: +- gen_helper_shr_cc(var, var, shift); ++ gen_helper_shr_cc(var, cpu_env, var, shift); + break; + case 2: +- gen_helper_sar_cc(var, var, shift); ++ gen_helper_sar_cc(var, cpu_env, var, shift); + break; + case 3: +- gen_helper_ror_cc(var, var, shift); ++ gen_helper_ror_cc(var, cpu_env, var, shift); + break; + } + } else { +@@ -1323,11 +1323,11 @@ static void do_datap(CPUUniCore32State *env, DisasContext *s, uint32_t insn) + if (IS_USER(s)) { + ILLEGAL; + } +- gen_helper_sub_cc(tmp, tmp, tmp2); ++ gen_helper_sub_cc(tmp, cpu_env, tmp, tmp2); + gen_exception_return(s, tmp); + } else { + if (UCOP_SET_S) { +- gen_helper_sub_cc(tmp, tmp, tmp2); ++ gen_helper_sub_cc(tmp, cpu_env, tmp, tmp2); + } else { + tcg_gen_sub_i32(tmp, tmp, tmp2); + } +@@ -1336,7 +1336,7 @@ static void do_datap(CPUUniCore32State *env, DisasContext *s, uint32_t insn) + break; + case 0x03: + if (UCOP_SET_S) { +- gen_helper_sub_cc(tmp, tmp2, tmp); ++ gen_helper_sub_cc(tmp, cpu_env, tmp2, tmp); + } else { + tcg_gen_sub_i32(tmp, tmp2, tmp); + } +@@ -1344,7 +1344,7 @@ static void do_datap(CPUUniCore32State *env, DisasContext *s, uint32_t insn) + break; + case 0x04: + if (UCOP_SET_S) { +- gen_helper_add_cc(tmp, tmp, tmp2); ++ gen_helper_add_cc(tmp, cpu_env, tmp, tmp2); + } else { + tcg_gen_add_i32(tmp, tmp, tmp2); + } +@@ -1352,7 +1352,7 @@ static void do_datap(CPUUniCore32State *env, DisasContext *s, uint32_t insn) + break; + case 0x05: + if (UCOP_SET_S) { +- gen_helper_adc_cc(tmp, tmp, tmp2); ++ gen_helper_adc_cc(tmp, cpu_env, tmp, tmp2); + } else { + gen_add_carry(tmp, tmp, tmp2); + } +@@ -1360,7 +1360,7 @@ static void do_datap(CPUUniCore32State *env, DisasContext *s, uint32_t insn) + break; + case 0x06: + if (UCOP_SET_S) { +- gen_helper_sbc_cc(tmp, tmp, tmp2); ++ gen_helper_sbc_cc(tmp, cpu_env, tmp, tmp2); + } else { + gen_sub_carry(tmp, tmp, tmp2); + } +@@ -1368,7 +1368,7 @@ static void do_datap(CPUUniCore32State *env, DisasContext *s, uint32_t insn) + break; + case 0x07: + if (UCOP_SET_S) { +- gen_helper_sbc_cc(tmp, tmp2, tmp); ++ gen_helper_sbc_cc(tmp, cpu_env, tmp2, tmp); + } else { + gen_sub_carry(tmp, tmp2, tmp); + } +@@ -1390,13 +1390,13 @@ static void do_datap(CPUUniCore32State *env, DisasContext *s, uint32_t insn) + break; + case 0x0a: + if (UCOP_SET_S) { +- gen_helper_sub_cc(tmp, tmp, tmp2); ++ gen_helper_sub_cc(tmp, cpu_env, tmp, tmp2); + } + dead_tmp(tmp); + break; + case 0x0b: + if (UCOP_SET_S) { +- gen_helper_add_cc(tmp, tmp, tmp2); ++ gen_helper_add_cc(tmp, cpu_env, tmp, tmp2); + } + dead_tmp(tmp); + break; +@@ -1536,7 +1536,7 @@ static void do_misc(CPUUniCore32State *env, DisasContext *s, uint32_t insn) + tmp = load_cpu_field(bsr); + } else { + tmp = new_tmp(); +- gen_helper_asr_read(tmp); ++ gen_helper_asr_read(tmp, cpu_env); + } + store_reg(s, UCOP_REG_D, tmp); + return; +@@ -1760,7 +1760,7 @@ static void do_ldst_m(CPUUniCore32State *env, DisasContext *s, uint32_t insn) + gen_bx(s, tmp); + } else if (user) { + tmp2 = tcg_const_i32(reg); +- gen_helper_set_user_reg(tmp2, tmp); ++ gen_helper_set_user_reg(cpu_env, tmp2, tmp); + tcg_temp_free_i32(tmp2); + dead_tmp(tmp); + } else if (reg == UCOP_REG_N) { +@@ -1778,7 +1778,7 @@ static void do_ldst_m(CPUUniCore32State *env, DisasContext *s, uint32_t insn) + } else if (user) { + tmp = new_tmp(); + tmp2 = tcg_const_i32(reg); +- gen_helper_get_user_reg(tmp, tmp2); ++ gen_helper_get_user_reg(tmp, cpu_env, tmp2); + tcg_temp_free_i32(tmp2); + } else { + tmp = load_reg(s, reg); +@@ -1861,7 +1861,7 @@ static void disas_uc32_insn(CPUUniCore32State *env, DisasContext *s) + { + unsigned int insn; + +- insn = ldl_code(s->pc); ++ insn = cpu_ldl_code(env, s->pc); + s->pc += 4; + + /* UniCore instructions class: +-- +1.7.12.1 + diff --git a/0031-target-arm-convert-void-helpers.patch b/0031-target-arm-convert-void-helpers.patch new file mode 100644 index 0000000..3ea4640 --- /dev/null +++ b/0031-target-arm-convert-void-helpers.patch @@ -0,0 +1,181 @@ +From 140048c58e4ceb4f3bac87d7154d2731bb2bcd5d Mon Sep 17 00:00:00 2001 +From: Blue Swirl +Date: Tue, 4 Sep 2012 20:08:34 +0000 +Subject: [PATCH] target-arm: convert void helpers + +Add an explicit CPUState parameter instead of relying on AREG0. + +For easier review, convert only op helpers which don't return any value. + +Signed-off-by: Blue Swirl +Reviewed-by: Peter Maydell +Signed-off-by: Michael Roth +--- + target-arm/helper.h | 8 ++++---- + target-arm/op_helper.c | 20 ++++++++++---------- + target-arm/translate.c | 8 ++++---- + 3 files changed, 18 insertions(+), 18 deletions(-) + +diff --git a/target-arm/helper.h b/target-arm/helper.h +index 21e9cfe..106aacd 100644 +--- a/target-arm/helper.h ++++ b/target-arm/helper.h +@@ -50,10 +50,10 @@ DEF_HELPER_2(usad8, i32, i32, i32) + DEF_HELPER_1(logicq_cc, i32, i64) + + DEF_HELPER_3(sel_flags, i32, i32, i32, i32) +-DEF_HELPER_1(exception, void, i32) +-DEF_HELPER_0(wfi, void) ++DEF_HELPER_2(exception, void, env, i32) ++DEF_HELPER_1(wfi, void, env) + +-DEF_HELPER_2(cpsr_write, void, i32, i32) ++DEF_HELPER_3(cpsr_write, void, env, i32, i32) + DEF_HELPER_0(cpsr_read, i32) + + DEF_HELPER_3(v7m_msr, void, env, i32, i32) +@@ -68,7 +68,7 @@ DEF_HELPER_2(get_r13_banked, i32, env, i32) + DEF_HELPER_3(set_r13_banked, void, env, i32, i32) + + DEF_HELPER_1(get_user_reg, i32, i32) +-DEF_HELPER_2(set_user_reg, void, i32, i32) ++DEF_HELPER_3(set_user_reg, void, env, i32, i32) + + DEF_HELPER_1(vfp_get_fpscr, i32, env) + DEF_HELPER_2(vfp_set_fpscr, void, env, i32) +diff --git a/target-arm/op_helper.c b/target-arm/op_helper.c +index d77bfab..b1adce3 100644 +--- a/target-arm/op_helper.c ++++ b/target-arm/op_helper.c +@@ -23,7 +23,7 @@ + #define SIGNBIT (uint32_t)0x80000000 + #define SIGNBIT64 ((uint64_t)1 << 63) + +-static void raise_exception(int tt) ++static void raise_exception(CPUARMState *env, int tt) + { + env->exception_index = tt; + cpu_loop_exit(env); +@@ -93,7 +93,7 @@ void tlb_fill(CPUARMState *env1, target_ulong addr, int is_write, int mmu_idx, + cpu_restore_state(tb, env, retaddr); + } + } +- raise_exception(env->exception_index); ++ raise_exception(env, env->exception_index); + } + env = saved_env; + } +@@ -230,14 +230,14 @@ uint32_t HELPER(usat16)(uint32_t x, uint32_t shift) + return res; + } + +-void HELPER(wfi)(void) ++void HELPER(wfi)(CPUARMState *env) + { + env->exception_index = EXCP_HLT; + env->halted = 1; + cpu_loop_exit(env); + } + +-void HELPER(exception)(uint32_t excp) ++void HELPER(exception)(CPUARMState *env, uint32_t excp) + { + env->exception_index = excp; + cpu_loop_exit(env); +@@ -248,7 +248,7 @@ uint32_t HELPER(cpsr_read)(void) + return cpsr_read(env) & ~CPSR_EXEC; + } + +-void HELPER(cpsr_write)(uint32_t val, uint32_t mask) ++void HELPER(cpsr_write)(CPUARMState *env, uint32_t val, uint32_t mask) + { + cpsr_write(env, val, mask); + } +@@ -271,7 +271,7 @@ uint32_t HELPER(get_user_reg)(uint32_t regno) + return val; + } + +-void HELPER(set_user_reg)(uint32_t regno, uint32_t val) ++void HELPER(set_user_reg)(CPUARMState *env, uint32_t regno, uint32_t val) + { + if (regno == 13) { + env->banked_r13[0] = val; +@@ -290,7 +290,7 @@ void HELPER(set_cp_reg)(CPUARMState *env, void *rip, uint32_t value) + const ARMCPRegInfo *ri = rip; + int excp = ri->writefn(env, ri, value); + if (excp) { +- raise_exception(excp); ++ raise_exception(env, excp); + } + } + +@@ -300,7 +300,7 @@ uint32_t HELPER(get_cp_reg)(CPUARMState *env, void *rip) + uint64_t value; + int excp = ri->readfn(env, ri, &value); + if (excp) { +- raise_exception(excp); ++ raise_exception(env, excp); + } + return value; + } +@@ -310,7 +310,7 @@ void HELPER(set_cp_reg64)(CPUARMState *env, void *rip, uint64_t value) + const ARMCPRegInfo *ri = rip; + int excp = ri->writefn(env, ri, value); + if (excp) { +- raise_exception(excp); ++ raise_exception(env, excp); + } + } + +@@ -320,7 +320,7 @@ uint64_t HELPER(get_cp_reg64)(CPUARMState *env, void *rip) + uint64_t value; + int excp = ri->readfn(env, ri, &value); + if (excp) { +- raise_exception(excp); ++ raise_exception(env, excp); + } + return value; + } +diff --git a/target-arm/translate.c b/target-arm/translate.c +index edef79a..6f651d9 100644 +--- a/target-arm/translate.c ++++ b/target-arm/translate.c +@@ -199,7 +199,7 @@ static void store_reg(DisasContext *s, int reg, TCGv var) + static inline void gen_set_cpsr(TCGv var, uint32_t mask) + { + TCGv tmp_mask = tcg_const_i32(mask); +- gen_helper_cpsr_write(var, tmp_mask); ++ gen_helper_cpsr_write(cpu_env, var, tmp_mask); + tcg_temp_free_i32(tmp_mask); + } + /* Set NZCV flags from the high 4 bits of var. */ +@@ -209,7 +209,7 @@ static void gen_exception(int excp) + { + TCGv tmp = tcg_temp_new_i32(); + tcg_gen_movi_i32(tmp, excp); +- gen_helper_exception(tmp); ++ gen_helper_exception(cpu_env, tmp); + tcg_temp_free_i32(tmp); + } + +@@ -7719,7 +7719,7 @@ static void disas_arm_insn(CPUARMState * env, DisasContext *s) + tmp = gen_ld32(addr, IS_USER(s)); + if (user) { + tmp2 = tcg_const_i32(i); +- gen_helper_set_user_reg(tmp2, tmp); ++ gen_helper_set_user_reg(cpu_env, tmp2, tmp); + tcg_temp_free_i32(tmp2); + tcg_temp_free_i32(tmp); + } else if (i == rn) { +@@ -9913,7 +9913,7 @@ static inline void gen_intermediate_code_internal(CPUARMState *env, + /* nothing more to generate */ + break; + case DISAS_WFI: +- gen_helper_wfi(); ++ gen_helper_wfi(cpu_env); + break; + case DISAS_SWI: + gen_exception(EXCP_SWI); +-- +1.7.12.1 + diff --git a/0032-target-arm-convert-remaining-helpers.patch b/0032-target-arm-convert-remaining-helpers.patch new file mode 100644 index 0000000..73dd928 --- /dev/null +++ b/0032-target-arm-convert-remaining-helpers.patch @@ -0,0 +1,821 @@ +From 18e713cf6b5ae2e7c48bb412c959c10322bef5e5 Mon Sep 17 00:00:00 2001 +From: Blue Swirl +Date: Tue, 4 Sep 2012 20:19:15 +0000 +Subject: [PATCH] target-arm: convert remaining helpers + +Convert remaining helpers to AREG0 free mode: add an explicit +CPUState parameter instead of relying on AREG0. + +Signed-off-by: Blue Swirl +Reviewed-by: Peter Maydell +Signed-off-by: Michael Roth +--- + target-arm/helper.h | 52 +++++++++---------- + target-arm/op_helper.c | 64 +++++++++++------------ + target-arm/translate.c | 134 ++++++++++++++++++++++++------------------------- + 3 files changed, 125 insertions(+), 125 deletions(-) + +diff --git a/target-arm/helper.h b/target-arm/helper.h +index 106aacd..afdb2b5 100644 +--- a/target-arm/helper.h ++++ b/target-arm/helper.h +@@ -4,12 +4,12 @@ DEF_HELPER_1(clz, i32, i32) + DEF_HELPER_1(sxtb16, i32, i32) + DEF_HELPER_1(uxtb16, i32, i32) + +-DEF_HELPER_2(add_setq, i32, i32, i32) +-DEF_HELPER_2(add_saturate, i32, i32, i32) +-DEF_HELPER_2(sub_saturate, i32, i32, i32) +-DEF_HELPER_2(add_usaturate, i32, i32, i32) +-DEF_HELPER_2(sub_usaturate, i32, i32, i32) +-DEF_HELPER_1(double_saturate, i32, s32) ++DEF_HELPER_3(add_setq, i32, env, i32, i32) ++DEF_HELPER_3(add_saturate, i32, env, i32, i32) ++DEF_HELPER_3(sub_saturate, i32, env, i32, i32) ++DEF_HELPER_3(add_usaturate, i32, env, i32, i32) ++DEF_HELPER_3(sub_usaturate, i32, env, i32, i32) ++DEF_HELPER_2(double_saturate, i32, env, s32) + DEF_HELPER_2(sdiv, s32, s32, s32) + DEF_HELPER_2(udiv, i32, i32, i32) + DEF_HELPER_1(rbit, i32, i32) +@@ -40,10 +40,10 @@ PAS_OP(uq) + PAS_OP(uh) + #undef PAS_OP + +-DEF_HELPER_2(ssat, i32, i32, i32) +-DEF_HELPER_2(usat, i32, i32, i32) +-DEF_HELPER_2(ssat16, i32, i32, i32) +-DEF_HELPER_2(usat16, i32, i32, i32) ++DEF_HELPER_3(ssat, i32, env, i32, i32) ++DEF_HELPER_3(usat, i32, env, i32, i32) ++DEF_HELPER_3(ssat16, i32, env, i32, i32) ++DEF_HELPER_3(usat16, i32, env, i32, i32) + + DEF_HELPER_2(usad8, i32, i32, i32) + +@@ -54,7 +54,7 @@ DEF_HELPER_2(exception, void, env, i32) + DEF_HELPER_1(wfi, void, env) + + DEF_HELPER_3(cpsr_write, void, env, i32, i32) +-DEF_HELPER_0(cpsr_read, i32) ++DEF_HELPER_1(cpsr_read, i32, env) + + DEF_HELPER_3(v7m_msr, void, env, i32, i32) + DEF_HELPER_2(v7m_mrs, i32, env, i32) +@@ -67,7 +67,7 @@ DEF_HELPER_2(get_cp_reg64, i64, env, ptr) + DEF_HELPER_2(get_r13_banked, i32, env, i32) + DEF_HELPER_3(set_r13_banked, void, env, i32, i32) + +-DEF_HELPER_1(get_user_reg, i32, i32) ++DEF_HELPER_2(get_user_reg, i32, env, i32) + DEF_HELPER_3(set_user_reg, void, env, i32, i32) + + DEF_HELPER_1(vfp_get_fpscr, i32, env) +@@ -140,20 +140,20 @@ DEF_HELPER_2(recpe_f32, f32, f32, env) + DEF_HELPER_2(rsqrte_f32, f32, f32, env) + DEF_HELPER_2(recpe_u32, i32, i32, env) + DEF_HELPER_2(rsqrte_u32, i32, i32, env) +-DEF_HELPER_4(neon_tbl, i32, i32, i32, i32, i32) +- +-DEF_HELPER_2(add_cc, i32, i32, i32) +-DEF_HELPER_2(adc_cc, i32, i32, i32) +-DEF_HELPER_2(sub_cc, i32, i32, i32) +-DEF_HELPER_2(sbc_cc, i32, i32, i32) +- +-DEF_HELPER_2(shl, i32, i32, i32) +-DEF_HELPER_2(shr, i32, i32, i32) +-DEF_HELPER_2(sar, i32, i32, i32) +-DEF_HELPER_2(shl_cc, i32, i32, i32) +-DEF_HELPER_2(shr_cc, i32, i32, i32) +-DEF_HELPER_2(sar_cc, i32, i32, i32) +-DEF_HELPER_2(ror_cc, i32, i32, i32) ++DEF_HELPER_5(neon_tbl, i32, env, i32, i32, i32, i32) ++ ++DEF_HELPER_3(add_cc, i32, env, i32, i32) ++DEF_HELPER_3(adc_cc, i32, env, i32, i32) ++DEF_HELPER_3(sub_cc, i32, env, i32, i32) ++DEF_HELPER_3(sbc_cc, i32, env, i32, i32) ++ ++DEF_HELPER_3(shl, i32, env, i32, i32) ++DEF_HELPER_3(shr, i32, env, i32, i32) ++DEF_HELPER_3(sar, i32, env, i32, i32) ++DEF_HELPER_3(shl_cc, i32, env, i32, i32) ++DEF_HELPER_3(shr_cc, i32, env, i32, i32) ++DEF_HELPER_3(sar_cc, i32, env, i32, i32) ++DEF_HELPER_3(ror_cc, i32, env, i32, i32) + + /* neon_helper.c */ + DEF_HELPER_3(neon_qadd_u8, i32, env, i32, i32) +diff --git a/target-arm/op_helper.c b/target-arm/op_helper.c +index b1adce3..5b868bf 100644 +--- a/target-arm/op_helper.c ++++ b/target-arm/op_helper.c +@@ -29,7 +29,7 @@ static void raise_exception(CPUARMState *env, int tt) + cpu_loop_exit(env); + } + +-uint32_t HELPER(neon_tbl)(uint32_t ireg, uint32_t def, ++uint32_t HELPER(neon_tbl)(CPUARMState *env, uint32_t ireg, uint32_t def, + uint32_t rn, uint32_t maxindex) + { + uint32_t val; +@@ -101,7 +101,7 @@ void tlb_fill(CPUARMState *env1, target_ulong addr, int is_write, int mmu_idx, + + /* FIXME: Pass an explicit pointer to QF to CPUARMState, and move saturating + instructions into helper.c */ +-uint32_t HELPER(add_setq)(uint32_t a, uint32_t b) ++uint32_t HELPER(add_setq)(CPUARMState *env, uint32_t a, uint32_t b) + { + uint32_t res = a + b; + if (((res ^ a) & SIGNBIT) && !((a ^ b) & SIGNBIT)) +@@ -109,7 +109,7 @@ uint32_t HELPER(add_setq)(uint32_t a, uint32_t b) + return res; + } + +-uint32_t HELPER(add_saturate)(uint32_t a, uint32_t b) ++uint32_t HELPER(add_saturate)(CPUARMState *env, uint32_t a, uint32_t b) + { + uint32_t res = a + b; + if (((res ^ a) & SIGNBIT) && !((a ^ b) & SIGNBIT)) { +@@ -119,7 +119,7 @@ uint32_t HELPER(add_saturate)(uint32_t a, uint32_t b) + return res; + } + +-uint32_t HELPER(sub_saturate)(uint32_t a, uint32_t b) ++uint32_t HELPER(sub_saturate)(CPUARMState *env, uint32_t a, uint32_t b) + { + uint32_t res = a - b; + if (((res ^ a) & SIGNBIT) && ((a ^ b) & SIGNBIT)) { +@@ -129,7 +129,7 @@ uint32_t HELPER(sub_saturate)(uint32_t a, uint32_t b) + return res; + } + +-uint32_t HELPER(double_saturate)(int32_t val) ++uint32_t HELPER(double_saturate)(CPUARMState *env, int32_t val) + { + uint32_t res; + if (val >= 0x40000000) { +@@ -144,7 +144,7 @@ uint32_t HELPER(double_saturate)(int32_t val) + return res; + } + +-uint32_t HELPER(add_usaturate)(uint32_t a, uint32_t b) ++uint32_t HELPER(add_usaturate)(CPUARMState *env, uint32_t a, uint32_t b) + { + uint32_t res = a + b; + if (res < a) { +@@ -154,7 +154,7 @@ uint32_t HELPER(add_usaturate)(uint32_t a, uint32_t b) + return res; + } + +-uint32_t HELPER(sub_usaturate)(uint32_t a, uint32_t b) ++uint32_t HELPER(sub_usaturate)(CPUARMState *env, uint32_t a, uint32_t b) + { + uint32_t res = a - b; + if (res > a) { +@@ -165,7 +165,7 @@ uint32_t HELPER(sub_usaturate)(uint32_t a, uint32_t b) + } + + /* Signed saturation. */ +-static inline uint32_t do_ssat(int32_t val, int shift) ++static inline uint32_t do_ssat(CPUARMState *env, int32_t val, int shift) + { + int32_t top; + uint32_t mask; +@@ -183,7 +183,7 @@ static inline uint32_t do_ssat(int32_t val, int shift) + } + + /* Unsigned saturation. */ +-static inline uint32_t do_usat(int32_t val, int shift) ++static inline uint32_t do_usat(CPUARMState *env, int32_t val, int shift) + { + uint32_t max; + +@@ -199,34 +199,34 @@ static inline uint32_t do_usat(int32_t val, int shift) + } + + /* Signed saturate. */ +-uint32_t HELPER(ssat)(uint32_t x, uint32_t shift) ++uint32_t HELPER(ssat)(CPUARMState *env, uint32_t x, uint32_t shift) + { +- return do_ssat(x, shift); ++ return do_ssat(env, x, shift); + } + + /* Dual halfword signed saturate. */ +-uint32_t HELPER(ssat16)(uint32_t x, uint32_t shift) ++uint32_t HELPER(ssat16)(CPUARMState *env, uint32_t x, uint32_t shift) + { + uint32_t res; + +- res = (uint16_t)do_ssat((int16_t)x, shift); +- res |= do_ssat(((int32_t)x) >> 16, shift) << 16; ++ res = (uint16_t)do_ssat(env, (int16_t)x, shift); ++ res |= do_ssat(env, ((int32_t)x) >> 16, shift) << 16; + return res; + } + + /* Unsigned saturate. */ +-uint32_t HELPER(usat)(uint32_t x, uint32_t shift) ++uint32_t HELPER(usat)(CPUARMState *env, uint32_t x, uint32_t shift) + { +- return do_usat(x, shift); ++ return do_usat(env, x, shift); + } + + /* Dual halfword unsigned saturate. */ +-uint32_t HELPER(usat16)(uint32_t x, uint32_t shift) ++uint32_t HELPER(usat16)(CPUARMState *env, uint32_t x, uint32_t shift) + { + uint32_t res; + +- res = (uint16_t)do_usat((int16_t)x, shift); +- res |= do_usat(((int32_t)x) >> 16, shift) << 16; ++ res = (uint16_t)do_usat(env, (int16_t)x, shift); ++ res |= do_usat(env, ((int32_t)x) >> 16, shift) << 16; + return res; + } + +@@ -243,7 +243,7 @@ void HELPER(exception)(CPUARMState *env, uint32_t excp) + cpu_loop_exit(env); + } + +-uint32_t HELPER(cpsr_read)(void) ++uint32_t HELPER(cpsr_read)(CPUARMState *env) + { + return cpsr_read(env) & ~CPSR_EXEC; + } +@@ -254,7 +254,7 @@ void HELPER(cpsr_write)(CPUARMState *env, uint32_t val, uint32_t mask) + } + + /* Access to user mode registers from privileged modes. */ +-uint32_t HELPER(get_user_reg)(uint32_t regno) ++uint32_t HELPER(get_user_reg)(CPUARMState *env, uint32_t regno) + { + uint32_t val; + +@@ -329,7 +329,7 @@ uint64_t HELPER(get_cp_reg64)(CPUARMState *env, void *rip) + The only way to do that in TCG is a conditional branch, which clobbers + all our temporaries. For now implement these as helper functions. */ + +-uint32_t HELPER (add_cc)(uint32_t a, uint32_t b) ++uint32_t HELPER (add_cc)(CPUARMState *env, uint32_t a, uint32_t b) + { + uint32_t result; + result = a + b; +@@ -339,7 +339,7 @@ uint32_t HELPER (add_cc)(uint32_t a, uint32_t b) + return result; + } + +-uint32_t HELPER(adc_cc)(uint32_t a, uint32_t b) ++uint32_t HELPER(adc_cc)(CPUARMState *env, uint32_t a, uint32_t b) + { + uint32_t result; + if (!env->CF) { +@@ -354,7 +354,7 @@ uint32_t HELPER(adc_cc)(uint32_t a, uint32_t b) + return result; + } + +-uint32_t HELPER(sub_cc)(uint32_t a, uint32_t b) ++uint32_t HELPER(sub_cc)(CPUARMState *env, uint32_t a, uint32_t b) + { + uint32_t result; + result = a - b; +@@ -364,7 +364,7 @@ uint32_t HELPER(sub_cc)(uint32_t a, uint32_t b) + return result; + } + +-uint32_t HELPER(sbc_cc)(uint32_t a, uint32_t b) ++uint32_t HELPER(sbc_cc)(CPUARMState *env, uint32_t a, uint32_t b) + { + uint32_t result; + if (!env->CF) { +@@ -381,7 +381,7 @@ uint32_t HELPER(sbc_cc)(uint32_t a, uint32_t b) + + /* Similarly for variable shift instructions. */ + +-uint32_t HELPER(shl)(uint32_t x, uint32_t i) ++uint32_t HELPER(shl)(CPUARMState *env, uint32_t x, uint32_t i) + { + int shift = i & 0xff; + if (shift >= 32) +@@ -389,7 +389,7 @@ uint32_t HELPER(shl)(uint32_t x, uint32_t i) + return x << shift; + } + +-uint32_t HELPER(shr)(uint32_t x, uint32_t i) ++uint32_t HELPER(shr)(CPUARMState *env, uint32_t x, uint32_t i) + { + int shift = i & 0xff; + if (shift >= 32) +@@ -397,7 +397,7 @@ uint32_t HELPER(shr)(uint32_t x, uint32_t i) + return (uint32_t)x >> shift; + } + +-uint32_t HELPER(sar)(uint32_t x, uint32_t i) ++uint32_t HELPER(sar)(CPUARMState *env, uint32_t x, uint32_t i) + { + int shift = i & 0xff; + if (shift >= 32) +@@ -405,7 +405,7 @@ uint32_t HELPER(sar)(uint32_t x, uint32_t i) + return (int32_t)x >> shift; + } + +-uint32_t HELPER(shl_cc)(uint32_t x, uint32_t i) ++uint32_t HELPER(shl_cc)(CPUARMState *env, uint32_t x, uint32_t i) + { + int shift = i & 0xff; + if (shift >= 32) { +@@ -421,7 +421,7 @@ uint32_t HELPER(shl_cc)(uint32_t x, uint32_t i) + return x; + } + +-uint32_t HELPER(shr_cc)(uint32_t x, uint32_t i) ++uint32_t HELPER(shr_cc)(CPUARMState *env, uint32_t x, uint32_t i) + { + int shift = i & 0xff; + if (shift >= 32) { +@@ -437,7 +437,7 @@ uint32_t HELPER(shr_cc)(uint32_t x, uint32_t i) + return x; + } + +-uint32_t HELPER(sar_cc)(uint32_t x, uint32_t i) ++uint32_t HELPER(sar_cc)(CPUARMState *env, uint32_t x, uint32_t i) + { + int shift = i & 0xff; + if (shift >= 32) { +@@ -450,7 +450,7 @@ uint32_t HELPER(sar_cc)(uint32_t x, uint32_t i) + return x; + } + +-uint32_t HELPER(ror_cc)(uint32_t x, uint32_t i) ++uint32_t HELPER(ror_cc)(CPUARMState *env, uint32_t x, uint32_t i) + { + int shift1, shift; + shift1 = i & 0xff; +diff --git a/target-arm/translate.c b/target-arm/translate.c +index 6f651d9..9ae3b26 100644 +--- a/target-arm/translate.c ++++ b/target-arm/translate.c +@@ -490,16 +490,16 @@ static inline void gen_arm_shift_reg(TCGv var, int shiftop, + { + if (flags) { + switch (shiftop) { +- case 0: gen_helper_shl_cc(var, var, shift); break; +- case 1: gen_helper_shr_cc(var, var, shift); break; +- case 2: gen_helper_sar_cc(var, var, shift); break; +- case 3: gen_helper_ror_cc(var, var, shift); break; ++ case 0: gen_helper_shl_cc(var, cpu_env, var, shift); break; ++ case 1: gen_helper_shr_cc(var, cpu_env, var, shift); break; ++ case 2: gen_helper_sar_cc(var, cpu_env, var, shift); break; ++ case 3: gen_helper_ror_cc(var, cpu_env, var, shift); break; + } + } else { + switch (shiftop) { +- case 0: gen_helper_shl(var, var, shift); break; +- case 1: gen_helper_shr(var, var, shift); break; +- case 2: gen_helper_sar(var, var, shift); break; ++ case 0: gen_helper_shl(var, cpu_env, var, shift); break; ++ case 1: gen_helper_shr(var, cpu_env, var, shift); break; ++ case 2: gen_helper_sar(var, cpu_env, var, shift); break; + case 3: tcg_gen_andi_i32(shift, shift, 0x1f); + tcg_gen_rotr_i32(var, var, shift); break; + } +@@ -6121,7 +6121,7 @@ static int disas_neon_data_insn(CPUARMState * env, DisasContext *s, uint32_t ins + tmp2 = neon_load_reg(rm, 0); + tmp4 = tcg_const_i32(rn); + tmp5 = tcg_const_i32(n); +- gen_helper_neon_tbl(tmp2, tmp2, tmp, tmp4, tmp5); ++ gen_helper_neon_tbl(tmp2, cpu_env, tmp2, tmp, tmp4, tmp5); + tcg_temp_free_i32(tmp); + if (insn & (1 << 6)) { + tmp = neon_load_reg(rd, 1); +@@ -6130,7 +6130,7 @@ static int disas_neon_data_insn(CPUARMState * env, DisasContext *s, uint32_t ins + tcg_gen_movi_i32(tmp, 0); + } + tmp3 = neon_load_reg(rm, 1); +- gen_helper_neon_tbl(tmp3, tmp3, tmp, tmp4, tmp5); ++ gen_helper_neon_tbl(tmp3, cpu_env, tmp3, tmp, tmp4, tmp5); + tcg_temp_free_i32(tmp5); + tcg_temp_free_i32(tmp4); + neon_store_reg(rd, 0, tmp2); +@@ -6818,7 +6818,7 @@ static void disas_arm_insn(CPUARMState * env, DisasContext *s) + tmp = load_cpu_field(spsr); + } else { + tmp = tcg_temp_new_i32(); +- gen_helper_cpsr_read(tmp); ++ gen_helper_cpsr_read(tmp, cpu_env); + } + store_reg(s, rd, tmp); + } +@@ -6869,11 +6869,11 @@ static void disas_arm_insn(CPUARMState * env, DisasContext *s) + tmp = load_reg(s, rm); + tmp2 = load_reg(s, rn); + if (op1 & 2) +- gen_helper_double_saturate(tmp2, tmp2); ++ gen_helper_double_saturate(tmp2, cpu_env, tmp2); + if (op1 & 1) +- gen_helper_sub_saturate(tmp, tmp, tmp2); ++ gen_helper_sub_saturate(tmp, cpu_env, tmp, tmp2); + else +- gen_helper_add_saturate(tmp, tmp, tmp2); ++ gen_helper_add_saturate(tmp, cpu_env, tmp, tmp2); + tcg_temp_free_i32(tmp2); + store_reg(s, rd, tmp); + break; +@@ -6911,7 +6911,7 @@ static void disas_arm_insn(CPUARMState * env, DisasContext *s) + tcg_temp_free_i64(tmp64); + if ((sh & 2) == 0) { + tmp2 = load_reg(s, rn); +- gen_helper_add_setq(tmp, tmp, tmp2); ++ gen_helper_add_setq(tmp, cpu_env, tmp, tmp2); + tcg_temp_free_i32(tmp2); + } + store_reg(s, rd, tmp); +@@ -6931,7 +6931,7 @@ static void disas_arm_insn(CPUARMState * env, DisasContext *s) + } else { + if (op1 == 0) { + tmp2 = load_reg(s, rn); +- gen_helper_add_setq(tmp, tmp, tmp2); ++ gen_helper_add_setq(tmp, cpu_env, tmp, tmp2); + tcg_temp_free_i32(tmp2); + } + store_reg(s, rd, tmp); +@@ -7005,11 +7005,11 @@ static void disas_arm_insn(CPUARMState * env, DisasContext *s) + if (IS_USER(s)) { + goto illegal_op; + } +- gen_helper_sub_cc(tmp, tmp, tmp2); ++ gen_helper_sub_cc(tmp, cpu_env, tmp, tmp2); + gen_exception_return(s, tmp); + } else { + if (set_cc) { +- gen_helper_sub_cc(tmp, tmp, tmp2); ++ gen_helper_sub_cc(tmp, cpu_env, tmp, tmp2); + } else { + tcg_gen_sub_i32(tmp, tmp, tmp2); + } +@@ -7018,7 +7018,7 @@ static void disas_arm_insn(CPUARMState * env, DisasContext *s) + break; + case 0x03: + if (set_cc) { +- gen_helper_sub_cc(tmp, tmp2, tmp); ++ gen_helper_sub_cc(tmp, cpu_env, tmp2, tmp); + } else { + tcg_gen_sub_i32(tmp, tmp2, tmp); + } +@@ -7026,7 +7026,7 @@ static void disas_arm_insn(CPUARMState * env, DisasContext *s) + break; + case 0x04: + if (set_cc) { +- gen_helper_add_cc(tmp, tmp, tmp2); ++ gen_helper_add_cc(tmp, cpu_env, tmp, tmp2); + } else { + tcg_gen_add_i32(tmp, tmp, tmp2); + } +@@ -7034,7 +7034,7 @@ static void disas_arm_insn(CPUARMState * env, DisasContext *s) + break; + case 0x05: + if (set_cc) { +- gen_helper_adc_cc(tmp, tmp, tmp2); ++ gen_helper_adc_cc(tmp, cpu_env, tmp, tmp2); + } else { + gen_add_carry(tmp, tmp, tmp2); + } +@@ -7042,7 +7042,7 @@ static void disas_arm_insn(CPUARMState * env, DisasContext *s) + break; + case 0x06: + if (set_cc) { +- gen_helper_sbc_cc(tmp, tmp, tmp2); ++ gen_helper_sbc_cc(tmp, cpu_env, tmp, tmp2); + } else { + gen_sub_carry(tmp, tmp, tmp2); + } +@@ -7050,7 +7050,7 @@ static void disas_arm_insn(CPUARMState * env, DisasContext *s) + break; + case 0x07: + if (set_cc) { +- gen_helper_sbc_cc(tmp, tmp2, tmp); ++ gen_helper_sbc_cc(tmp, cpu_env, tmp2, tmp); + } else { + gen_sub_carry(tmp, tmp2, tmp); + } +@@ -7072,13 +7072,13 @@ static void disas_arm_insn(CPUARMState * env, DisasContext *s) + break; + case 0x0a: + if (set_cc) { +- gen_helper_sub_cc(tmp, tmp, tmp2); ++ gen_helper_sub_cc(tmp, cpu_env, tmp, tmp2); + } + tcg_temp_free_i32(tmp); + break; + case 0x0b: + if (set_cc) { +- gen_helper_add_cc(tmp, tmp, tmp2); ++ gen_helper_add_cc(tmp, cpu_env, tmp, tmp2); + } + tcg_temp_free_i32(tmp); + break; +@@ -7395,9 +7395,9 @@ static void disas_arm_insn(CPUARMState * env, DisasContext *s) + sh = (insn >> 16) & 0x1f; + tmp2 = tcg_const_i32(sh); + if (insn & (1 << 22)) +- gen_helper_usat(tmp, tmp, tmp2); ++ gen_helper_usat(tmp, cpu_env, tmp, tmp2); + else +- gen_helper_ssat(tmp, tmp, tmp2); ++ gen_helper_ssat(tmp, cpu_env, tmp, tmp2); + tcg_temp_free_i32(tmp2); + store_reg(s, rd, tmp); + } else if ((insn & 0x00300fe0) == 0x00200f20) { +@@ -7406,9 +7406,9 @@ static void disas_arm_insn(CPUARMState * env, DisasContext *s) + sh = (insn >> 16) & 0x1f; + tmp2 = tcg_const_i32(sh); + if (insn & (1 << 22)) +- gen_helper_usat16(tmp, tmp, tmp2); ++ gen_helper_usat16(tmp, cpu_env, tmp, tmp2); + else +- gen_helper_ssat16(tmp, tmp, tmp2); ++ gen_helper_ssat16(tmp, cpu_env, tmp, tmp2); + tcg_temp_free_i32(tmp2); + store_reg(s, rd, tmp); + } else if ((insn & 0x00700fe0) == 0x00000fa0) { +@@ -7518,7 +7518,7 @@ static void disas_arm_insn(CPUARMState * env, DisasContext *s) + * however it may overflow considered as a signed + * operation, in which case we must set the Q flag. + */ +- gen_helper_add_setq(tmp, tmp, tmp2); ++ gen_helper_add_setq(tmp, cpu_env, tmp, tmp2); + } + tcg_temp_free_i32(tmp2); + if (insn & (1 << 22)) { +@@ -7534,7 +7534,7 @@ static void disas_arm_insn(CPUARMState * env, DisasContext *s) + if (rd != 15) + { + tmp2 = load_reg(s, rd); +- gen_helper_add_setq(tmp, tmp, tmp2); ++ gen_helper_add_setq(tmp, cpu_env, tmp, tmp2); + tcg_temp_free_i32(tmp2); + } + store_reg(s, rn, tmp); +@@ -7738,7 +7738,7 @@ static void disas_arm_insn(CPUARMState * env, DisasContext *s) + } else if (user) { + tmp = tcg_temp_new_i32(); + tmp2 = tcg_const_i32(i); +- gen_helper_get_user_reg(tmp, tmp2); ++ gen_helper_get_user_reg(tmp, cpu_env, tmp2); + tcg_temp_free_i32(tmp2); + } else { + tmp = load_reg(s, i); +@@ -7865,31 +7865,31 @@ gen_thumb2_data_op(DisasContext *s, int op, int conds, uint32_t shifter_out, TCG + break; + case 8: /* add */ + if (conds) +- gen_helper_add_cc(t0, t0, t1); ++ gen_helper_add_cc(t0, cpu_env, t0, t1); + else + tcg_gen_add_i32(t0, t0, t1); + break; + case 10: /* adc */ + if (conds) +- gen_helper_adc_cc(t0, t0, t1); ++ gen_helper_adc_cc(t0, cpu_env, t0, t1); + else + gen_adc(t0, t1); + break; + case 11: /* sbc */ + if (conds) +- gen_helper_sbc_cc(t0, t0, t1); ++ gen_helper_sbc_cc(t0, cpu_env, t0, t1); + else + gen_sub_carry(t0, t0, t1); + break; + case 13: /* sub */ + if (conds) +- gen_helper_sub_cc(t0, t0, t1); ++ gen_helper_sub_cc(t0, cpu_env, t0, t1); + else + tcg_gen_sub_i32(t0, t0, t1); + break; + case 14: /* rsb */ + if (conds) +- gen_helper_sub_cc(t0, t1, t0); ++ gen_helper_sub_cc(t0, cpu_env, t1, t0); + else + tcg_gen_sub_i32(t0, t1, t0); + break; +@@ -8111,7 +8111,7 @@ static int disas_thumb2_insn(CPUARMState *env, DisasContext *s, uint16_t insn_hw + gen_st32(tmp, addr, 0); + tcg_gen_addi_i32(addr, addr, 4); + tmp = tcg_temp_new_i32(); +- gen_helper_cpsr_read(tmp); ++ gen_helper_cpsr_read(tmp, cpu_env); + gen_st32(tmp, addr, 0); + if (insn & (1 << 21)) { + if ((insn & (1 << 24)) == 0) { +@@ -8293,11 +8293,11 @@ static int disas_thumb2_insn(CPUARMState *env, DisasContext *s, uint16_t insn_hw + tmp = load_reg(s, rn); + tmp2 = load_reg(s, rm); + if (op & 1) +- gen_helper_double_saturate(tmp, tmp); ++ gen_helper_double_saturate(tmp, cpu_env, tmp); + if (op & 2) +- gen_helper_sub_saturate(tmp, tmp2, tmp); ++ gen_helper_sub_saturate(tmp, cpu_env, tmp2, tmp); + else +- gen_helper_add_saturate(tmp, tmp, tmp2); ++ gen_helper_add_saturate(tmp, cpu_env, tmp, tmp2); + tcg_temp_free_i32(tmp2); + } else { + tmp = load_reg(s, rn); +@@ -8353,7 +8353,7 @@ static int disas_thumb2_insn(CPUARMState *env, DisasContext *s, uint16_t insn_hw + tcg_temp_free_i32(tmp2); + if (rs != 15) { + tmp2 = load_reg(s, rs); +- gen_helper_add_setq(tmp, tmp, tmp2); ++ gen_helper_add_setq(tmp, cpu_env, tmp, tmp2); + tcg_temp_free_i32(tmp2); + } + break; +@@ -8370,13 +8370,13 @@ static int disas_thumb2_insn(CPUARMState *env, DisasContext *s, uint16_t insn_hw + * however it may overflow considered as a signed + * operation, in which case we must set the Q flag. + */ +- gen_helper_add_setq(tmp, tmp, tmp2); ++ gen_helper_add_setq(tmp, cpu_env, tmp, tmp2); + } + tcg_temp_free_i32(tmp2); + if (rs != 15) + { + tmp2 = load_reg(s, rs); +- gen_helper_add_setq(tmp, tmp, tmp2); ++ gen_helper_add_setq(tmp, cpu_env, tmp, tmp2); + tcg_temp_free_i32(tmp2); + } + break; +@@ -8393,7 +8393,7 @@ static int disas_thumb2_insn(CPUARMState *env, DisasContext *s, uint16_t insn_hw + if (rs != 15) + { + tmp2 = load_reg(s, rs); +- gen_helper_add_setq(tmp, tmp, tmp2); ++ gen_helper_add_setq(tmp, cpu_env, tmp, tmp2); + tcg_temp_free_i32(tmp2); + } + break; +@@ -8632,7 +8632,7 @@ static int disas_thumb2_insn(CPUARMState *env, DisasContext *s, uint16_t insn_hw + gen_helper_v7m_mrs(tmp, cpu_env, addr); + tcg_temp_free_i32(addr); + } else { +- gen_helper_cpsr_read(tmp); ++ gen_helper_cpsr_read(tmp, cpu_env); + } + store_reg(s, rd, tmp); + break; +@@ -8721,15 +8721,15 @@ static int disas_thumb2_insn(CPUARMState *env, DisasContext *s, uint16_t insn_hw + if (op & 4) { + /* Unsigned. */ + if ((op & 1) && shift == 0) +- gen_helper_usat16(tmp, tmp, tmp2); ++ gen_helper_usat16(tmp, cpu_env, tmp, tmp2); + else +- gen_helper_usat(tmp, tmp, tmp2); ++ gen_helper_usat(tmp, cpu_env, tmp, tmp2); + } else { + /* Signed. */ + if ((op & 1) && shift == 0) +- gen_helper_ssat16(tmp, tmp, tmp2); ++ gen_helper_ssat16(tmp, cpu_env, tmp, tmp2); + else +- gen_helper_ssat(tmp, tmp, tmp2); ++ gen_helper_ssat(tmp, cpu_env, tmp, tmp2); + } + tcg_temp_free_i32(tmp2); + break; +@@ -9017,12 +9017,12 @@ static void disas_thumb_insn(CPUARMState *env, DisasContext *s) + if (s->condexec_mask) + tcg_gen_sub_i32(tmp, tmp, tmp2); + else +- gen_helper_sub_cc(tmp, tmp, tmp2); ++ gen_helper_sub_cc(tmp, cpu_env, tmp, tmp2); + } else { + if (s->condexec_mask) + tcg_gen_add_i32(tmp, tmp, tmp2); + else +- gen_helper_add_cc(tmp, tmp, tmp2); ++ gen_helper_add_cc(tmp, cpu_env, tmp, tmp2); + } + tcg_temp_free_i32(tmp2); + store_reg(s, rd, tmp); +@@ -9053,7 +9053,7 @@ static void disas_thumb_insn(CPUARMState *env, DisasContext *s) + tcg_gen_movi_i32(tmp2, insn & 0xff); + switch (op) { + case 1: /* cmp */ +- gen_helper_sub_cc(tmp, tmp, tmp2); ++ gen_helper_sub_cc(tmp, cpu_env, tmp, tmp2); + tcg_temp_free_i32(tmp); + tcg_temp_free_i32(tmp2); + break; +@@ -9061,7 +9061,7 @@ static void disas_thumb_insn(CPUARMState *env, DisasContext *s) + if (s->condexec_mask) + tcg_gen_add_i32(tmp, tmp, tmp2); + else +- gen_helper_add_cc(tmp, tmp, tmp2); ++ gen_helper_add_cc(tmp, cpu_env, tmp, tmp2); + tcg_temp_free_i32(tmp2); + store_reg(s, rd, tmp); + break; +@@ -9069,7 +9069,7 @@ static void disas_thumb_insn(CPUARMState *env, DisasContext *s) + if (s->condexec_mask) + tcg_gen_sub_i32(tmp, tmp, tmp2); + else +- gen_helper_sub_cc(tmp, tmp, tmp2); ++ gen_helper_sub_cc(tmp, cpu_env, tmp, tmp2); + tcg_temp_free_i32(tmp2); + store_reg(s, rd, tmp); + break; +@@ -9105,7 +9105,7 @@ static void disas_thumb_insn(CPUARMState *env, DisasContext *s) + case 1: /* cmp */ + tmp = load_reg(s, rd); + tmp2 = load_reg(s, rm); +- gen_helper_sub_cc(tmp, tmp, tmp2); ++ gen_helper_sub_cc(tmp, cpu_env, tmp, tmp2); + tcg_temp_free_i32(tmp2); + tcg_temp_free_i32(tmp); + break; +@@ -9166,25 +9166,25 @@ static void disas_thumb_insn(CPUARMState *env, DisasContext *s) + break; + case 0x2: /* lsl */ + if (s->condexec_mask) { +- gen_helper_shl(tmp2, tmp2, tmp); ++ gen_helper_shl(tmp2, cpu_env, tmp2, tmp); + } else { +- gen_helper_shl_cc(tmp2, tmp2, tmp); ++ gen_helper_shl_cc(tmp2, cpu_env, tmp2, tmp); + gen_logic_CC(tmp2); + } + break; + case 0x3: /* lsr */ + if (s->condexec_mask) { +- gen_helper_shr(tmp2, tmp2, tmp); ++ gen_helper_shr(tmp2, cpu_env, tmp2, tmp); + } else { +- gen_helper_shr_cc(tmp2, tmp2, tmp); ++ gen_helper_shr_cc(tmp2, cpu_env, tmp2, tmp); + gen_logic_CC(tmp2); + } + break; + case 0x4: /* asr */ + if (s->condexec_mask) { +- gen_helper_sar(tmp2, tmp2, tmp); ++ gen_helper_sar(tmp2, cpu_env, tmp2, tmp); + } else { +- gen_helper_sar_cc(tmp2, tmp2, tmp); ++ gen_helper_sar_cc(tmp2, cpu_env, tmp2, tmp); + gen_logic_CC(tmp2); + } + break; +@@ -9192,20 +9192,20 @@ static void disas_thumb_insn(CPUARMState *env, DisasContext *s) + if (s->condexec_mask) + gen_adc(tmp, tmp2); + else +- gen_helper_adc_cc(tmp, tmp, tmp2); ++ gen_helper_adc_cc(tmp, cpu_env, tmp, tmp2); + break; + case 0x6: /* sbc */ + if (s->condexec_mask) + gen_sub_carry(tmp, tmp, tmp2); + else +- gen_helper_sbc_cc(tmp, tmp, tmp2); ++ gen_helper_sbc_cc(tmp, cpu_env, tmp, tmp2); + break; + case 0x7: /* ror */ + if (s->condexec_mask) { + tcg_gen_andi_i32(tmp, tmp, 0x1f); + tcg_gen_rotr_i32(tmp2, tmp2, tmp); + } else { +- gen_helper_ror_cc(tmp2, tmp2, tmp); ++ gen_helper_ror_cc(tmp2, cpu_env, tmp2, tmp); + gen_logic_CC(tmp2); + } + break; +@@ -9218,14 +9218,14 @@ static void disas_thumb_insn(CPUARMState *env, DisasContext *s) + if (s->condexec_mask) + tcg_gen_neg_i32(tmp, tmp2); + else +- gen_helper_sub_cc(tmp, tmp, tmp2); ++ gen_helper_sub_cc(tmp, cpu_env, tmp, tmp2); + break; + case 0xa: /* cmp */ +- gen_helper_sub_cc(tmp, tmp, tmp2); ++ gen_helper_sub_cc(tmp, cpu_env, tmp, tmp2); + rd = 16; + break; + case 0xb: /* cmn */ +- gen_helper_add_cc(tmp, tmp, tmp2); ++ gen_helper_add_cc(tmp, cpu_env, tmp, tmp2); + rd = 16; + break; + case 0xc: /* orr */ +-- +1.7.12.1 + diff --git a/0033-target-arm-final-conversion-to-AREG0-free-mode.patch b/0033-target-arm-final-conversion-to-AREG0-free-mode.patch new file mode 100644 index 0000000..8a83359 --- /dev/null +++ b/0033-target-arm-final-conversion-to-AREG0-free-mode.patch @@ -0,0 +1,179 @@ +From 28b8f097f9fb107882aa51bd25ba87619beb033e Mon Sep 17 00:00:00 2001 +From: Blue Swirl +Date: Tue, 4 Sep 2012 20:25:59 +0000 +Subject: [PATCH] target-arm: final conversion to AREG0 free mode + +Convert code load functions and switch to AREG0 free mode. + +Signed-off-by: Blue Swirl +Reviewed-by: Peter Maydell +Signed-off-by: Michael Roth +--- + configure | 2 +- + target-arm/Makefile.objs | 2 -- + target-arm/cpu.h | 10 ++++++---- + target-arm/helper.c | 9 +++++---- + target-arm/op_helper.c | 8 +------- + target-arm/translate.c | 6 +++--- + 6 files changed, 16 insertions(+), 21 deletions(-) + +diff --git a/configure b/configure +index a8827ba..e8806f0 100755 +--- a/configure ++++ b/configure +@@ -3839,7 +3839,7 @@ symlink "$source_path/Makefile.target" "$target_dir/Makefile" + + + case "$target_arch2" in +- alpha | i386 | lm32 | m68k | or32 | s390x | sparc* | unicore32 | x86_64 | xtensa* | ppc*) ++ alpha | arm* | i386 | lm32 | m68k | or32 | s390x | sparc* | unicore32 | x86_64 | xtensa* | ppc*) + echo "CONFIG_TCG_PASS_AREG0=y" >> $config_target_mak + ;; + esac +diff --git a/target-arm/Makefile.objs b/target-arm/Makefile.objs +index f447c4f..b6f1a9e 100644 +--- a/target-arm/Makefile.objs ++++ b/target-arm/Makefile.objs +@@ -2,5 +2,3 @@ obj-y += arm-semi.o + obj-$(CONFIG_SOFTMMU) += machine.o + obj-y += translate.o op_helper.o helper.o cpu.o + obj-y += neon_helper.o iwmmxt_helper.o +- +-$(obj)/op_helper.o: QEMU_CFLAGS += $(HELPER_CFLAGS) +diff --git a/target-arm/cpu.h b/target-arm/cpu.h +index d7f93d9..7fac94f 100644 +--- a/target-arm/cpu.h ++++ b/target-arm/cpu.h +@@ -734,9 +734,10 @@ static inline void cpu_pc_from_tb(CPUARMState *env, TranslationBlock *tb) + } + + /* Load an instruction and return it in the standard little-endian order */ +-static inline uint32_t arm_ldl_code(uint32_t addr, bool do_swap) ++static inline uint32_t arm_ldl_code(CPUARMState *env, uint32_t addr, ++ bool do_swap) + { +- uint32_t insn = ldl_code(addr); ++ uint32_t insn = cpu_ldl_code(env, addr); + if (do_swap) { + return bswap32(insn); + } +@@ -744,9 +745,10 @@ static inline uint32_t arm_ldl_code(uint32_t addr, bool do_swap) + } + + /* Ditto, for a halfword (Thumb) instruction */ +-static inline uint16_t arm_lduw_code(uint32_t addr, bool do_swap) ++static inline uint16_t arm_lduw_code(CPUARMState *env, uint32_t addr, ++ bool do_swap) + { +- uint16_t insn = lduw_code(addr); ++ uint16_t insn = cpu_lduw_code(env, addr); + if (do_swap) { + return bswap16(insn); + } +diff --git a/target-arm/helper.c b/target-arm/helper.c +index e27df96..58340bd 100644 +--- a/target-arm/helper.c ++++ b/target-arm/helper.c +@@ -1756,7 +1756,7 @@ static void do_interrupt_v7m(CPUARMState *env) + case EXCP_BKPT: + if (semihosting_enabled) { + int nr; +- nr = arm_lduw_code(env->regs[15], env->bswap_code) & 0xff; ++ nr = arm_lduw_code(env, env->regs[15], env->bswap_code) & 0xff; + if (nr == 0xab) { + env->regs[15] += 2; + env->regs[0] = do_arm_semihosting(env); +@@ -1828,9 +1828,10 @@ void do_interrupt(CPUARMState *env) + if (semihosting_enabled) { + /* Check for semihosting interrupt. */ + if (env->thumb) { +- mask = arm_lduw_code(env->regs[15] - 2, env->bswap_code) & 0xff; ++ mask = arm_lduw_code(env, env->regs[15] - 2, env->bswap_code) ++ & 0xff; + } else { +- mask = arm_ldl_code(env->regs[15] - 4, env->bswap_code) ++ mask = arm_ldl_code(env, env->regs[15] - 4, env->bswap_code) + & 0xffffff; + } + /* Only intercept calls from privileged modes, to provide some +@@ -1851,7 +1852,7 @@ void do_interrupt(CPUARMState *env) + case EXCP_BKPT: + /* See if this is a semihosting syscall. */ + if (env->thumb && semihosting_enabled) { +- mask = arm_lduw_code(env->regs[15], env->bswap_code) & 0xff; ++ mask = arm_lduw_code(env, env->regs[15], env->bswap_code) & 0xff; + if (mask == 0xab + && (env->uncached_cpsr & CPSR_M) != ARM_CPU_MODE_USR) { + env->regs[15] += 2; +diff --git a/target-arm/op_helper.c b/target-arm/op_helper.c +index 5b868bf..f13fc3a 100644 +--- a/target-arm/op_helper.c ++++ b/target-arm/op_helper.c +@@ -17,7 +17,6 @@ + * License along with this library; if not, see . + */ + #include "cpu.h" +-#include "dyngen-exec.h" + #include "helper.h" + + #define SIGNBIT (uint32_t)0x80000000 +@@ -72,16 +71,12 @@ uint32_t HELPER(neon_tbl)(CPUARMState *env, uint32_t ireg, uint32_t def, + /* try to fill the TLB and return an exception if error. If retaddr is + NULL, it means that the function was called in C code (i.e. not + from generated code or from helper.c) */ +-/* XXX: fix it to restore all registers */ +-void tlb_fill(CPUARMState *env1, target_ulong addr, int is_write, int mmu_idx, ++void tlb_fill(CPUARMState *env, target_ulong addr, int is_write, int mmu_idx, + uintptr_t retaddr) + { + TranslationBlock *tb; +- CPUARMState *saved_env; + int ret; + +- saved_env = env; +- env = env1; + ret = cpu_arm_handle_mmu_fault(env, addr, is_write, mmu_idx); + if (unlikely(ret)) { + if (retaddr) { +@@ -95,7 +90,6 @@ void tlb_fill(CPUARMState *env1, target_ulong addr, int is_write, int mmu_idx, + } + raise_exception(env, env->exception_index); + } +- env = saved_env; + } + #endif + +diff --git a/target-arm/translate.c b/target-arm/translate.c +index 9ae3b26..f4b447a 100644 +--- a/target-arm/translate.c ++++ b/target-arm/translate.c +@@ -6534,7 +6534,7 @@ static void disas_arm_insn(CPUARMState * env, DisasContext *s) + TCGv addr; + TCGv_i64 tmp64; + +- insn = arm_ldl_code(s->pc, s->bswap_code); ++ insn = arm_ldl_code(env, s->pc, s->bswap_code); + s->pc += 4; + + /* M variants do not implement ARM mode. */ +@@ -7962,7 +7962,7 @@ static int disas_thumb2_insn(CPUARMState *env, DisasContext *s, uint16_t insn_hw + /* Fall through to 32-bit decode. */ + } + +- insn = arm_lduw_code(s->pc, s->bswap_code); ++ insn = arm_lduw_code(env, s->pc, s->bswap_code); + s->pc += 2; + insn |= (uint32_t)insn_hw1 << 16; + +@@ -8992,7 +8992,7 @@ static void disas_thumb_insn(CPUARMState *env, DisasContext *s) + } + } + +- insn = arm_lduw_code(s->pc, s->bswap_code); ++ insn = arm_lduw_code(env, s->pc, s->bswap_code); + s->pc += 2; + + switch (insn >> 12) { +-- +1.7.12.1 + diff --git a/0034-target-microblaze-switch-to-AREG0-free-mode.patch b/0034-target-microblaze-switch-to-AREG0-free-mode.patch new file mode 100644 index 0000000..fea6bb8 --- /dev/null +++ b/0034-target-microblaze-switch-to-AREG0-free-mode.patch @@ -0,0 +1,715 @@ +From 449d4f2cfbdd2b5fd00e3e82c78bf580bd81551d Mon Sep 17 00:00:00 2001 +From: Blue Swirl +Date: Sun, 2 Sep 2012 08:39:22 +0000 +Subject: [PATCH] target-microblaze: switch to AREG0 free mode + +Add an explicit CPUState parameter instead of relying on AREG0 +and switch to AREG0 free mode. + +Signed-off-by: Blue Swirl +Signed-off-by: Michael Roth +--- + configure | 2 +- + target-microblaze/Makefile.objs | 2 - + target-microblaze/helper.h | 48 ++++++++--------- + target-microblaze/op_helper.c | 115 ++++++++++++++++++---------------------- + target-microblaze/translate.c | 61 +++++++++++---------- + 5 files changed, 110 insertions(+), 118 deletions(-) + +diff --git a/configure b/configure +index e8806f0..0b4ef4a 100755 +--- a/configure ++++ b/configure +@@ -3839,7 +3839,7 @@ symlink "$source_path/Makefile.target" "$target_dir/Makefile" + + + case "$target_arch2" in +- alpha | arm* | i386 | lm32 | m68k | or32 | s390x | sparc* | unicore32 | x86_64 | xtensa* | ppc*) ++ alpha | arm* | i386 | lm32 | m68k | microblaze* | or32 | s390x | sparc* | unicore32 | x86_64 | xtensa* | ppc*) + echo "CONFIG_TCG_PASS_AREG0=y" >> $config_target_mak + ;; + esac +diff --git a/target-microblaze/Makefile.objs b/target-microblaze/Makefile.objs +index 4b09e8c..afb87bc 100644 +--- a/target-microblaze/Makefile.objs ++++ b/target-microblaze/Makefile.objs +@@ -1,4 +1,2 @@ + obj-y += translate.o op_helper.o helper.o cpu.o + obj-$(CONFIG_SOFTMMU) += mmu.o machine.o +- +-$(obj)/op_helper.o: QEMU_CFLAGS += $(HELPER_CFLAGS) +diff --git a/target-microblaze/helper.h b/target-microblaze/helper.h +index 9dcfb0f..a1a732c 100644 +--- a/target-microblaze/helper.h ++++ b/target-microblaze/helper.h +@@ -1,39 +1,39 @@ + #include "def-helper.h" + +-DEF_HELPER_1(raise_exception, void, i32) +-DEF_HELPER_0(debug, void) ++DEF_HELPER_2(raise_exception, void, env, i32) ++DEF_HELPER_1(debug, void, env) + DEF_HELPER_FLAGS_3(carry, TCG_CALL_PURE | TCG_CALL_CONST, i32, i32, i32, i32) + DEF_HELPER_2(cmp, i32, i32, i32) + DEF_HELPER_2(cmpu, i32, i32, i32) + DEF_HELPER_FLAGS_1(clz, TCG_CALL_PURE | TCG_CALL_CONST, i32, i32) + +-DEF_HELPER_2(divs, i32, i32, i32) +-DEF_HELPER_2(divu, i32, i32, i32) +- +-DEF_HELPER_2(fadd, i32, i32, i32) +-DEF_HELPER_2(frsub, i32, i32, i32) +-DEF_HELPER_2(fmul, i32, i32, i32) +-DEF_HELPER_2(fdiv, i32, i32, i32) +-DEF_HELPER_1(flt, i32, i32) +-DEF_HELPER_1(fint, i32, i32) +-DEF_HELPER_1(fsqrt, i32, i32) +- +-DEF_HELPER_2(fcmp_un, i32, i32, i32) +-DEF_HELPER_2(fcmp_lt, i32, i32, i32) +-DEF_HELPER_2(fcmp_eq, i32, i32, i32) +-DEF_HELPER_2(fcmp_le, i32, i32, i32) +-DEF_HELPER_2(fcmp_gt, i32, i32, i32) +-DEF_HELPER_2(fcmp_ne, i32, i32, i32) +-DEF_HELPER_2(fcmp_ge, i32, i32, i32) ++DEF_HELPER_3(divs, i32, env, i32, i32) ++DEF_HELPER_3(divu, i32, env, i32, i32) ++ ++DEF_HELPER_3(fadd, i32, env, i32, i32) ++DEF_HELPER_3(frsub, i32, env, i32, i32) ++DEF_HELPER_3(fmul, i32, env, i32, i32) ++DEF_HELPER_3(fdiv, i32, env, i32, i32) ++DEF_HELPER_2(flt, i32, env, i32) ++DEF_HELPER_2(fint, i32, env, i32) ++DEF_HELPER_2(fsqrt, i32, env, i32) ++ ++DEF_HELPER_3(fcmp_un, i32, env, i32, i32) ++DEF_HELPER_3(fcmp_lt, i32, env, i32, i32) ++DEF_HELPER_3(fcmp_eq, i32, env, i32, i32) ++DEF_HELPER_3(fcmp_le, i32, env, i32, i32) ++DEF_HELPER_3(fcmp_gt, i32, env, i32, i32) ++DEF_HELPER_3(fcmp_ne, i32, env, i32, i32) ++DEF_HELPER_3(fcmp_ge, i32, env, i32, i32) + + DEF_HELPER_FLAGS_2(pcmpbf, TCG_CALL_PURE | TCG_CALL_CONST, i32, i32, i32) + #if !defined(CONFIG_USER_ONLY) +-DEF_HELPER_1(mmu_read, i32, i32) +-DEF_HELPER_2(mmu_write, void, i32, i32) ++DEF_HELPER_2(mmu_read, i32, env, i32) ++DEF_HELPER_3(mmu_write, void, env, i32, i32) + #endif + +-DEF_HELPER_4(memalign, void, i32, i32, i32, i32) +-DEF_HELPER_1(stackprot, void, i32) ++DEF_HELPER_5(memalign, void, env, i32, i32, i32, i32) ++DEF_HELPER_2(stackprot, void, env, i32) + + DEF_HELPER_2(get, i32, i32, i32) + DEF_HELPER_3(put, void, i32, i32, i32) +diff --git a/target-microblaze/op_helper.c b/target-microblaze/op_helper.c +index 3b1f072..c9789f4 100644 +--- a/target-microblaze/op_helper.c ++++ b/target-microblaze/op_helper.c +@@ -20,7 +20,6 @@ + + #include + #include "cpu.h" +-#include "dyngen-exec.h" + #include "helper.h" + #include "host-utils.h" + +@@ -42,17 +41,12 @@ + /* Try to fill the TLB and return an exception if error. If retaddr is + NULL, it means that the function was called in C code (i.e. not + from generated code or from helper.c) */ +-/* XXX: fix it to restore all registers */ +-void tlb_fill(CPUMBState *env1, target_ulong addr, int is_write, int mmu_idx, ++void tlb_fill(CPUMBState *env, target_ulong addr, int is_write, int mmu_idx, + uintptr_t retaddr) + { + TranslationBlock *tb; +- CPUMBState *saved_env; + int ret; + +- saved_env = env; +- env = env1; +- + ret = cpu_mb_handle_mmu_fault(env, addr, is_write, mmu_idx); + if (unlikely(ret)) { + if (retaddr) { +@@ -66,7 +60,6 @@ void tlb_fill(CPUMBState *env1, target_ulong addr, int is_write, int mmu_idx, + } + cpu_loop_exit(env); + } +- env = saved_env; + } + #endif + +@@ -105,13 +98,13 @@ uint32_t helper_get(uint32_t id, uint32_t ctrl) + return 0xdead0000 | id; + } + +-void helper_raise_exception(uint32_t index) ++void helper_raise_exception(CPUMBState *env, uint32_t index) + { + env->exception_index = index; + cpu_loop_exit(env); + } + +-void helper_debug(void) ++void helper_debug(CPUMBState *env) + { + int i; + +@@ -176,7 +169,7 @@ uint32_t helper_carry(uint32_t a, uint32_t b, uint32_t cf) + return ncf; + } + +-static inline int div_prepare(uint32_t a, uint32_t b) ++static inline int div_prepare(CPUMBState *env, uint32_t a, uint32_t b) + { + if (b == 0) { + env->sregs[SR_MSR] |= MSR_DZ; +@@ -184,7 +177,7 @@ static inline int div_prepare(uint32_t a, uint32_t b) + if ((env->sregs[SR_MSR] & MSR_EE) + && !(env->pvr.regs[2] & PVR2_DIV_ZERO_EXC_MASK)) { + env->sregs[SR_ESR] = ESR_EC_DIVZERO; +- helper_raise_exception(EXCP_HW_EXCP); ++ helper_raise_exception(env, EXCP_HW_EXCP); + } + return 0; + } +@@ -192,28 +185,30 @@ static inline int div_prepare(uint32_t a, uint32_t b) + return 1; + } + +-uint32_t helper_divs(uint32_t a, uint32_t b) ++uint32_t helper_divs(CPUMBState *env, uint32_t a, uint32_t b) + { +- if (!div_prepare(a, b)) ++ if (!div_prepare(env, a, b)) { + return 0; ++ } + return (int32_t)a / (int32_t)b; + } + +-uint32_t helper_divu(uint32_t a, uint32_t b) ++uint32_t helper_divu(CPUMBState *env, uint32_t a, uint32_t b) + { +- if (!div_prepare(a, b)) ++ if (!div_prepare(env, a, b)) { + return 0; ++ } + return a / b; + } + + /* raise FPU exception. */ +-static void raise_fpu_exception(void) ++static void raise_fpu_exception(CPUMBState *env) + { + env->sregs[SR_ESR] = ESR_EC_FPU; +- helper_raise_exception(EXCP_HW_EXCP); ++ helper_raise_exception(env, EXCP_HW_EXCP); + } + +-static void update_fpu_flags(int flags) ++static void update_fpu_flags(CPUMBState *env, int flags) + { + int raise = 0; + +@@ -236,11 +231,11 @@ static void update_fpu_flags(int flags) + if (raise + && (env->pvr.regs[2] & PVR2_FPU_EXC_MASK) + && (env->sregs[SR_MSR] & MSR_EE)) { +- raise_fpu_exception(); ++ raise_fpu_exception(env); + } + } + +-uint32_t helper_fadd(uint32_t a, uint32_t b) ++uint32_t helper_fadd(CPUMBState *env, uint32_t a, uint32_t b) + { + CPU_FloatU fd, fa, fb; + int flags; +@@ -251,11 +246,11 @@ uint32_t helper_fadd(uint32_t a, uint32_t b) + fd.f = float32_add(fa.f, fb.f, &env->fp_status); + + flags = get_float_exception_flags(&env->fp_status); +- update_fpu_flags(flags); ++ update_fpu_flags(env, flags); + return fd.l; + } + +-uint32_t helper_frsub(uint32_t a, uint32_t b) ++uint32_t helper_frsub(CPUMBState *env, uint32_t a, uint32_t b) + { + CPU_FloatU fd, fa, fb; + int flags; +@@ -265,11 +260,11 @@ uint32_t helper_frsub(uint32_t a, uint32_t b) + fb.l = b; + fd.f = float32_sub(fb.f, fa.f, &env->fp_status); + flags = get_float_exception_flags(&env->fp_status); +- update_fpu_flags(flags); ++ update_fpu_flags(env, flags); + return fd.l; + } + +-uint32_t helper_fmul(uint32_t a, uint32_t b) ++uint32_t helper_fmul(CPUMBState *env, uint32_t a, uint32_t b) + { + CPU_FloatU fd, fa, fb; + int flags; +@@ -279,12 +274,12 @@ uint32_t helper_fmul(uint32_t a, uint32_t b) + fb.l = b; + fd.f = float32_mul(fa.f, fb.f, &env->fp_status); + flags = get_float_exception_flags(&env->fp_status); +- update_fpu_flags(flags); ++ update_fpu_flags(env, flags); + + return fd.l; + } + +-uint32_t helper_fdiv(uint32_t a, uint32_t b) ++uint32_t helper_fdiv(CPUMBState *env, uint32_t a, uint32_t b) + { + CPU_FloatU fd, fa, fb; + int flags; +@@ -294,12 +289,12 @@ uint32_t helper_fdiv(uint32_t a, uint32_t b) + fb.l = b; + fd.f = float32_div(fb.f, fa.f, &env->fp_status); + flags = get_float_exception_flags(&env->fp_status); +- update_fpu_flags(flags); ++ update_fpu_flags(env, flags); + + return fd.l; + } + +-uint32_t helper_fcmp_un(uint32_t a, uint32_t b) ++uint32_t helper_fcmp_un(CPUMBState *env, uint32_t a, uint32_t b) + { + CPU_FloatU fa, fb; + uint32_t r = 0; +@@ -308,7 +303,7 @@ uint32_t helper_fcmp_un(uint32_t a, uint32_t b) + fb.l = b; + + if (float32_is_signaling_nan(fa.f) || float32_is_signaling_nan(fb.f)) { +- update_fpu_flags(float_flag_invalid); ++ update_fpu_flags(env, float_flag_invalid); + r = 1; + } + +@@ -319,7 +314,7 @@ uint32_t helper_fcmp_un(uint32_t a, uint32_t b) + return r; + } + +-uint32_t helper_fcmp_lt(uint32_t a, uint32_t b) ++uint32_t helper_fcmp_lt(CPUMBState *env, uint32_t a, uint32_t b) + { + CPU_FloatU fa, fb; + int r; +@@ -330,12 +325,12 @@ uint32_t helper_fcmp_lt(uint32_t a, uint32_t b) + fb.l = b; + r = float32_lt(fb.f, fa.f, &env->fp_status); + flags = get_float_exception_flags(&env->fp_status); +- update_fpu_flags(flags & float_flag_invalid); ++ update_fpu_flags(env, flags & float_flag_invalid); + + return r; + } + +-uint32_t helper_fcmp_eq(uint32_t a, uint32_t b) ++uint32_t helper_fcmp_eq(CPUMBState *env, uint32_t a, uint32_t b) + { + CPU_FloatU fa, fb; + int flags; +@@ -346,12 +341,12 @@ uint32_t helper_fcmp_eq(uint32_t a, uint32_t b) + fb.l = b; + r = float32_eq_quiet(fa.f, fb.f, &env->fp_status); + flags = get_float_exception_flags(&env->fp_status); +- update_fpu_flags(flags & float_flag_invalid); ++ update_fpu_flags(env, flags & float_flag_invalid); + + return r; + } + +-uint32_t helper_fcmp_le(uint32_t a, uint32_t b) ++uint32_t helper_fcmp_le(CPUMBState *env, uint32_t a, uint32_t b) + { + CPU_FloatU fa, fb; + int flags; +@@ -362,13 +357,13 @@ uint32_t helper_fcmp_le(uint32_t a, uint32_t b) + set_float_exception_flags(0, &env->fp_status); + r = float32_le(fa.f, fb.f, &env->fp_status); + flags = get_float_exception_flags(&env->fp_status); +- update_fpu_flags(flags & float_flag_invalid); ++ update_fpu_flags(env, flags & float_flag_invalid); + + + return r; + } + +-uint32_t helper_fcmp_gt(uint32_t a, uint32_t b) ++uint32_t helper_fcmp_gt(CPUMBState *env, uint32_t a, uint32_t b) + { + CPU_FloatU fa, fb; + int flags, r; +@@ -378,11 +373,11 @@ uint32_t helper_fcmp_gt(uint32_t a, uint32_t b) + set_float_exception_flags(0, &env->fp_status); + r = float32_lt(fa.f, fb.f, &env->fp_status); + flags = get_float_exception_flags(&env->fp_status); +- update_fpu_flags(flags & float_flag_invalid); ++ update_fpu_flags(env, flags & float_flag_invalid); + return r; + } + +-uint32_t helper_fcmp_ne(uint32_t a, uint32_t b) ++uint32_t helper_fcmp_ne(CPUMBState *env, uint32_t a, uint32_t b) + { + CPU_FloatU fa, fb; + int flags, r; +@@ -392,12 +387,12 @@ uint32_t helper_fcmp_ne(uint32_t a, uint32_t b) + set_float_exception_flags(0, &env->fp_status); + r = !float32_eq_quiet(fa.f, fb.f, &env->fp_status); + flags = get_float_exception_flags(&env->fp_status); +- update_fpu_flags(flags & float_flag_invalid); ++ update_fpu_flags(env, flags & float_flag_invalid); + + return r; + } + +-uint32_t helper_fcmp_ge(uint32_t a, uint32_t b) ++uint32_t helper_fcmp_ge(CPUMBState *env, uint32_t a, uint32_t b) + { + CPU_FloatU fa, fb; + int flags, r; +@@ -407,12 +402,12 @@ uint32_t helper_fcmp_ge(uint32_t a, uint32_t b) + set_float_exception_flags(0, &env->fp_status); + r = !float32_lt(fa.f, fb.f, &env->fp_status); + flags = get_float_exception_flags(&env->fp_status); +- update_fpu_flags(flags & float_flag_invalid); ++ update_fpu_flags(env, flags & float_flag_invalid); + + return r; + } + +-uint32_t helper_flt(uint32_t a) ++uint32_t helper_flt(CPUMBState *env, uint32_t a) + { + CPU_FloatU fd, fa; + +@@ -421,7 +416,7 @@ uint32_t helper_flt(uint32_t a) + return fd.l; + } + +-uint32_t helper_fint(uint32_t a) ++uint32_t helper_fint(CPUMBState *env, uint32_t a) + { + CPU_FloatU fa; + uint32_t r; +@@ -431,12 +426,12 @@ uint32_t helper_fint(uint32_t a) + fa.l = a; + r = float32_to_int32(fa.f, &env->fp_status); + flags = get_float_exception_flags(&env->fp_status); +- update_fpu_flags(flags); ++ update_fpu_flags(env, flags); + + return r; + } + +-uint32_t helper_fsqrt(uint32_t a) ++uint32_t helper_fsqrt(CPUMBState *env, uint32_t a) + { + CPU_FloatU fd, fa; + int flags; +@@ -445,7 +440,7 @@ uint32_t helper_fsqrt(uint32_t a) + fa.l = a; + fd.l = float32_sqrt(fa.f, &env->fp_status); + flags = get_float_exception_flags(&env->fp_status); +- update_fpu_flags(flags); ++ update_fpu_flags(env, flags); + + return fd.l; + } +@@ -463,7 +458,8 @@ uint32_t helper_pcmpbf(uint32_t a, uint32_t b) + return 0; + } + +-void helper_memalign(uint32_t addr, uint32_t dr, uint32_t wr, uint32_t mask) ++void helper_memalign(CPUMBState *env, uint32_t addr, uint32_t dr, uint32_t wr, ++ uint32_t mask) + { + if (addr & mask) { + qemu_log_mask(CPU_LOG_INT, +@@ -478,45 +474,39 @@ void helper_memalign(uint32_t addr, uint32_t dr, uint32_t wr, uint32_t mask) + if (!(env->sregs[SR_MSR] & MSR_EE)) { + return; + } +- helper_raise_exception(EXCP_HW_EXCP); ++ helper_raise_exception(env, EXCP_HW_EXCP); + } + } + +-void helper_stackprot(uint32_t addr) ++void helper_stackprot(CPUMBState *env, uint32_t addr) + { + if (addr < env->slr || addr > env->shr) { + qemu_log("Stack protector violation at %x %x %x\n", + addr, env->slr, env->shr); + env->sregs[SR_EAR] = addr; + env->sregs[SR_ESR] = ESR_EC_STACKPROT; +- helper_raise_exception(EXCP_HW_EXCP); ++ helper_raise_exception(env, EXCP_HW_EXCP); + } + } + + #if !defined(CONFIG_USER_ONLY) + /* Writes/reads to the MMU's special regs end up here. */ +-uint32_t helper_mmu_read(uint32_t rn) ++uint32_t helper_mmu_read(CPUMBState *env, uint32_t rn) + { + return mmu_read(env, rn); + } + +-void helper_mmu_write(uint32_t rn, uint32_t v) ++void helper_mmu_write(CPUMBState *env, uint32_t rn, uint32_t v) + { + mmu_write(env, rn, v); + } + +-void cpu_unassigned_access(CPUMBState *env1, target_phys_addr_t addr, ++void cpu_unassigned_access(CPUMBState *env, target_phys_addr_t addr, + int is_write, int is_exec, int is_asi, int size) + { +- CPUMBState *saved_env; +- +- saved_env = env; +- env = env1; +- + qemu_log_mask(CPU_LOG_INT, "Unassigned " TARGET_FMT_plx " wr=%d exe=%d\n", + addr, is_write, is_exec); + if (!(env->sregs[SR_MSR] & MSR_EE)) { +- env = saved_env; + return; + } + +@@ -524,14 +514,13 @@ void cpu_unassigned_access(CPUMBState *env1, target_phys_addr_t addr, + if (is_exec) { + if ((env->pvr.regs[2] & PVR2_IOPB_BUS_EXC_MASK)) { + env->sregs[SR_ESR] = ESR_EC_INSN_BUS; +- helper_raise_exception(EXCP_HW_EXCP); ++ helper_raise_exception(env, EXCP_HW_EXCP); + } + } else { + if ((env->pvr.regs[2] & PVR2_DOPB_BUS_EXC_MASK)) { + env->sregs[SR_ESR] = ESR_EC_DATA_BUS; +- helper_raise_exception(EXCP_HW_EXCP); ++ helper_raise_exception(env, EXCP_HW_EXCP); + } + } +- env = saved_env; + } + #endif +diff --git a/target-microblaze/translate.c b/target-microblaze/translate.c +index 7470149..9c7d77f 100644 +--- a/target-microblaze/translate.c ++++ b/target-microblaze/translate.c +@@ -126,7 +126,7 @@ static inline void t_gen_raise_exception(DisasContext *dc, uint32_t index) + + t_sync_flags(dc); + tcg_gen_movi_tl(cpu_SR[SR_PC], dc->pc); +- gen_helper_raise_exception(tmp); ++ gen_helper_raise_exception(cpu_env, tmp); + tcg_temp_free_i32(tmp); + dc->is_jmp = DISAS_UPDATE; + } +@@ -503,9 +503,9 @@ static void dec_msr(DisasContext *dc) + sr &= 7; + LOG_DIS("m%ss sr%d r%d imm=%x\n", to ? "t" : "f", sr, dc->ra, dc->imm); + if (to) +- gen_helper_mmu_write(tcg_const_tl(sr), cpu_R[dc->ra]); ++ gen_helper_mmu_write(cpu_env, tcg_const_tl(sr), cpu_R[dc->ra]); + else +- gen_helper_mmu_read(cpu_R[dc->rd], tcg_const_tl(sr)); ++ gen_helper_mmu_read(cpu_R[dc->rd], cpu_env, tcg_const_tl(sr)); + return; + } + #endif +@@ -704,9 +704,11 @@ static void dec_div(DisasContext *dc) + } + + if (u) +- gen_helper_divu(cpu_R[dc->rd], *(dec_alu_op_b(dc)), cpu_R[dc->ra]); ++ gen_helper_divu(cpu_R[dc->rd], cpu_env, *(dec_alu_op_b(dc)), ++ cpu_R[dc->ra]); + else +- gen_helper_divs(cpu_R[dc->rd], *(dec_alu_op_b(dc)), cpu_R[dc->ra]); ++ gen_helper_divs(cpu_R[dc->rd], cpu_env, *(dec_alu_op_b(dc)), ++ cpu_R[dc->ra]); + if (!dc->rd) + tcg_gen_movi_tl(cpu_R[dc->rd], 0); + } +@@ -912,7 +914,7 @@ static inline TCGv *compute_ldst_addr(DisasContext *dc, TCGv *t) + tcg_gen_add_tl(*t, cpu_R[dc->ra], cpu_R[dc->rb]); + + if (stackprot) { +- gen_helper_stackprot(*t); ++ gen_helper_stackprot(cpu_env, *t); + } + return t; + } +@@ -930,7 +932,7 @@ static inline TCGv *compute_ldst_addr(DisasContext *dc, TCGv *t) + } + + if (stackprot) { +- gen_helper_stackprot(*t); ++ gen_helper_stackprot(cpu_env, *t); + } + return t; + } +@@ -1056,7 +1058,7 @@ static void dec_load(DisasContext *dc) + gen_load(dc, v, *addr, size); + + tcg_gen_movi_tl(cpu_SR[SR_PC], dc->pc); +- gen_helper_memalign(*addr, tcg_const_tl(dc->rd), ++ gen_helper_memalign(cpu_env, *addr, tcg_const_tl(dc->rd), + tcg_const_tl(0), tcg_const_tl(size - 1)); + if (dc->rd) { + if (rev) { +@@ -1218,7 +1220,7 @@ static void dec_store(DisasContext *dc) + * the alignment checks in between the probe and the mem + * access. + */ +- gen_helper_memalign(*addr, tcg_const_tl(dc->rd), ++ gen_helper_memalign(cpu_env, *addr, tcg_const_tl(dc->rd), + tcg_const_tl(1), tcg_const_tl(size - 1)); + } + +@@ -1493,49 +1495,53 @@ static void dec_fpu(DisasContext *dc) + + switch (fpu_insn) { + case 0: +- gen_helper_fadd(cpu_R[dc->rd], cpu_R[dc->ra], cpu_R[dc->rb]); ++ gen_helper_fadd(cpu_R[dc->rd], cpu_env, cpu_R[dc->ra], ++ cpu_R[dc->rb]); + break; + + case 1: +- gen_helper_frsub(cpu_R[dc->rd], cpu_R[dc->ra], cpu_R[dc->rb]); ++ gen_helper_frsub(cpu_R[dc->rd], cpu_env, cpu_R[dc->ra], ++ cpu_R[dc->rb]); + break; + + case 2: +- gen_helper_fmul(cpu_R[dc->rd], cpu_R[dc->ra], cpu_R[dc->rb]); ++ gen_helper_fmul(cpu_R[dc->rd], cpu_env, cpu_R[dc->ra], ++ cpu_R[dc->rb]); + break; + + case 3: +- gen_helper_fdiv(cpu_R[dc->rd], cpu_R[dc->ra], cpu_R[dc->rb]); ++ gen_helper_fdiv(cpu_R[dc->rd], cpu_env, cpu_R[dc->ra], ++ cpu_R[dc->rb]); + break; + + case 4: + switch ((dc->ir >> 4) & 7) { + case 0: +- gen_helper_fcmp_un(cpu_R[dc->rd], ++ gen_helper_fcmp_un(cpu_R[dc->rd], cpu_env, + cpu_R[dc->ra], cpu_R[dc->rb]); + break; + case 1: +- gen_helper_fcmp_lt(cpu_R[dc->rd], ++ gen_helper_fcmp_lt(cpu_R[dc->rd], cpu_env, + cpu_R[dc->ra], cpu_R[dc->rb]); + break; + case 2: +- gen_helper_fcmp_eq(cpu_R[dc->rd], ++ gen_helper_fcmp_eq(cpu_R[dc->rd], cpu_env, + cpu_R[dc->ra], cpu_R[dc->rb]); + break; + case 3: +- gen_helper_fcmp_le(cpu_R[dc->rd], ++ gen_helper_fcmp_le(cpu_R[dc->rd], cpu_env, + cpu_R[dc->ra], cpu_R[dc->rb]); + break; + case 4: +- gen_helper_fcmp_gt(cpu_R[dc->rd], ++ gen_helper_fcmp_gt(cpu_R[dc->rd], cpu_env, + cpu_R[dc->ra], cpu_R[dc->rb]); + break; + case 5: +- gen_helper_fcmp_ne(cpu_R[dc->rd], ++ gen_helper_fcmp_ne(cpu_R[dc->rd], cpu_env, + cpu_R[dc->ra], cpu_R[dc->rb]); + break; + case 6: +- gen_helper_fcmp_ge(cpu_R[dc->rd], ++ gen_helper_fcmp_ge(cpu_R[dc->rd], cpu_env, + cpu_R[dc->ra], cpu_R[dc->rb]); + break; + default: +@@ -1552,21 +1558,21 @@ static void dec_fpu(DisasContext *dc) + if (!dec_check_fpuv2(dc)) { + return; + } +- gen_helper_flt(cpu_R[dc->rd], cpu_R[dc->ra]); ++ gen_helper_flt(cpu_R[dc->rd], cpu_env, cpu_R[dc->ra]); + break; + + case 6: + if (!dec_check_fpuv2(dc)) { + return; + } +- gen_helper_fint(cpu_R[dc->rd], cpu_R[dc->ra]); ++ gen_helper_fint(cpu_R[dc->rd], cpu_env, cpu_R[dc->ra]); + break; + + case 7: + if (!dec_check_fpuv2(dc)) { + return; + } +- gen_helper_fsqrt(cpu_R[dc->rd], cpu_R[dc->ra]); ++ gen_helper_fsqrt(cpu_R[dc->rd], cpu_env, cpu_R[dc->ra]); + break; + + default: +@@ -1654,15 +1660,14 @@ static struct decoder_info { + {{0, 0}, dec_null} + }; + +-static inline void decode(DisasContext *dc) ++static inline void decode(DisasContext *dc, uint32_t ir) + { +- uint32_t ir; + int i; + + if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP))) + tcg_gen_debug_insn_start(dc->pc); + +- dc->ir = ir = ldl_code(dc->pc); ++ dc->ir = ir; + LOG_DIS("%8.8x\t", dc->ir); + + if (dc->ir) +@@ -1796,7 +1801,7 @@ gen_intermediate_code_internal(CPUMBState *env, TranslationBlock *tb, + gen_io_start(); + + dc->clear_imm = 1; +- decode(dc); ++ decode(dc, cpu_ldl_code(env, dc->pc)); + if (dc->clear_imm) + dc->tb_flags &= ~IMM_FLAG; + dc->pc += 4; +@@ -1871,7 +1876,7 @@ gen_intermediate_code_internal(CPUMBState *env, TranslationBlock *tb, + if (dc->is_jmp != DISAS_JUMP) { + tcg_gen_movi_tl(cpu_SR[SR_PC], npc); + } +- gen_helper_raise_exception(tmp); ++ gen_helper_raise_exception(cpu_env, tmp); + tcg_temp_free_i32(tmp); + } else { + switch(dc->is_jmp) { +-- +1.7.12.1 + diff --git a/0035-target-cris-Avoid-AREG0-for-helpers.patch b/0035-target-cris-Avoid-AREG0-for-helpers.patch new file mode 100644 index 0000000..9314afb --- /dev/null +++ b/0035-target-cris-Avoid-AREG0-for-helpers.patch @@ -0,0 +1,523 @@ +From 1e3916b0cbfd39cb3fc8996423d5574068583145 Mon Sep 17 00:00:00 2001 +From: Aurelien Jarno +Date: Thu, 30 Aug 2012 16:56:39 +0200 +Subject: [PATCH] target-cris: Avoid AREG0 for helpers + +Add an explicit CPUCRISState parameter instead of relying on AREG0. + +Signed-off-by: Blue Swirl +Signed-off-by: Aurelien Jarno +Signed-off-by: Michael Roth +--- + target-cris/helper.h | 37 +++++++++++---------- + target-cris/op_helper.c | 80 ++++++++++++++++++++++++--------------------- + target-cris/translate.c | 44 +++++++++++++------------ + target-cris/translate_v10.c | 4 +-- + 4 files changed, 88 insertions(+), 77 deletions(-) + +diff --git a/target-cris/helper.h b/target-cris/helper.h +index 093063a..99fb326 100644 +--- a/target-cris/helper.h ++++ b/target-cris/helper.h +@@ -1,26 +1,29 @@ + #include "def-helper.h" + +-DEF_HELPER_1(raise_exception, void, i32) +-DEF_HELPER_1(tlb_flush_pid, void, i32) +-DEF_HELPER_1(spc_write, void, i32) ++DEF_HELPER_2(raise_exception, void, env, i32) ++DEF_HELPER_2(tlb_flush_pid, void, env, i32) ++DEF_HELPER_2(spc_write, void, env, i32) + DEF_HELPER_3(dump, void, i32, i32, i32) +-DEF_HELPER_0(rfe, void); +-DEF_HELPER_0(rfn, void); ++DEF_HELPER_1(rfe, void, env); ++DEF_HELPER_1(rfn, void, env); + +-DEF_HELPER_2(movl_sreg_reg, void, i32, i32) +-DEF_HELPER_2(movl_reg_sreg, void, i32, i32) ++DEF_HELPER_3(movl_sreg_reg, void, env, i32, i32) ++DEF_HELPER_3(movl_reg_sreg, void, env, i32, i32) + + DEF_HELPER_FLAGS_1(lz, TCG_CALL_PURE, i32, i32); +-DEF_HELPER_FLAGS_3(btst, TCG_CALL_PURE, i32, i32, i32, i32); ++DEF_HELPER_FLAGS_4(btst, TCG_CALL_PURE, i32, env, i32, i32, i32); + +-DEF_HELPER_FLAGS_3(evaluate_flags_muls, TCG_CALL_PURE, i32, i32, i32, i32) +-DEF_HELPER_FLAGS_3(evaluate_flags_mulu, TCG_CALL_PURE, i32, i32, i32, i32) +-DEF_HELPER_FLAGS_4(evaluate_flags_mcp, TCG_CALL_PURE, i32, i32, i32, i32, i32) +-DEF_HELPER_FLAGS_4(evaluate_flags_alu_4, TCG_CALL_PURE, i32, i32, i32, i32, i32) +-DEF_HELPER_FLAGS_4(evaluate_flags_sub_4, TCG_CALL_PURE, i32, i32, i32, i32, i32) +-DEF_HELPER_FLAGS_2(evaluate_flags_move_4, TCG_CALL_PURE, i32, i32, i32) +-DEF_HELPER_FLAGS_2(evaluate_flags_move_2, TCG_CALL_PURE, i32, i32, i32) +-DEF_HELPER_0(evaluate_flags, void) +-DEF_HELPER_0(top_evaluate_flags, void) ++DEF_HELPER_FLAGS_4(evaluate_flags_muls, TCG_CALL_PURE, i32, env, i32, i32, i32) ++DEF_HELPER_FLAGS_4(evaluate_flags_mulu, TCG_CALL_PURE, i32, env, i32, i32, i32) ++DEF_HELPER_FLAGS_5(evaluate_flags_mcp, TCG_CALL_PURE, i32, env, ++ i32, i32, i32, i32) ++DEF_HELPER_FLAGS_5(evaluate_flags_alu_4, TCG_CALL_PURE, i32, env, ++ i32, i32, i32, i32) ++DEF_HELPER_FLAGS_5(evaluate_flags_sub_4, TCG_CALL_PURE, i32, env, ++ i32, i32, i32, i32) ++DEF_HELPER_FLAGS_3(evaluate_flags_move_4, TCG_CALL_PURE, i32, env, i32, i32) ++DEF_HELPER_FLAGS_3(evaluate_flags_move_2, TCG_CALL_PURE, i32, env, i32, i32) ++DEF_HELPER_1(evaluate_flags, void, env) ++DEF_HELPER_1(top_evaluate_flags, void, env) + + #include "def-helper.h" +diff --git a/target-cris/op_helper.c b/target-cris/op_helper.c +index ac7c98c..5ca85a0 100644 +--- a/target-cris/op_helper.c ++++ b/target-cris/op_helper.c +@@ -79,7 +79,7 @@ void tlb_fill(CPUCRISState *env1, target_ulong addr, int is_write, int mmu_idx, + cpu_restore_state(tb, env, retaddr); + + /* Evaluate flags after retranslation. */ +- helper_top_evaluate_flags(); ++ helper_top_evaluate_flags(env); + } + } + cpu_loop_exit(env); +@@ -89,13 +89,13 @@ void tlb_fill(CPUCRISState *env1, target_ulong addr, int is_write, int mmu_idx, + + #endif + +-void helper_raise_exception(uint32_t index) ++void helper_raise_exception(CPUCRISState *env, uint32_t index) + { + env->exception_index = index; + cpu_loop_exit(env); + } + +-void helper_tlb_flush_pid(uint32_t pid) ++void helper_tlb_flush_pid(CPUCRISState *env, uint32_t pid) + { + #if !defined(CONFIG_USER_ONLY) + pid &= 0xff; +@@ -104,7 +104,7 @@ void helper_tlb_flush_pid(uint32_t pid) + #endif + } + +-void helper_spc_write(uint32_t new_spc) ++void helper_spc_write(CPUCRISState *env, uint32_t new_spc) + { + #if !defined(CONFIG_USER_ONLY) + tlb_flush_page(env, env->pregs[PR_SPC]); +@@ -121,7 +121,7 @@ void helper_dump(uint32_t a0, uint32_t a1, uint32_t a2) + #define EXTRACT_FIELD(src, start, end) \ + (((src) >> start) & ((1 << (end - start + 1)) - 1)) + +-void helper_movl_sreg_reg (uint32_t sreg, uint32_t reg) ++void helper_movl_sreg_reg(CPUCRISState *env, uint32_t sreg, uint32_t reg) + { + uint32_t srs; + srs = env->pregs[PR_SRS]; +@@ -171,7 +171,7 @@ void helper_movl_sreg_reg (uint32_t sreg, uint32_t reg) + #endif + } + +-void helper_movl_reg_sreg (uint32_t reg, uint32_t sreg) ++void helper_movl_reg_sreg(CPUCRISState *env, uint32_t reg, uint32_t sreg) + { + uint32_t srs; + env->pregs[PR_SRS] &= 3; +@@ -216,7 +216,7 @@ static void cris_ccs_rshift(CPUCRISState *env) + env->pregs[PR_CCS] = ccs; + } + +-void helper_rfe(void) ++void helper_rfe(CPUCRISState *env) + { + int rflag = env->pregs[PR_CCS] & R_FLAG; + +@@ -232,7 +232,7 @@ void helper_rfe(void) + env->pregs[PR_CCS] |= P_FLAG; + } + +-void helper_rfn(void) ++void helper_rfn(CPUCRISState *env) + { + int rflag = env->pregs[PR_CCS] & R_FLAG; + +@@ -256,7 +256,7 @@ uint32_t helper_lz(uint32_t t0) + return clz32(t0); + } + +-uint32_t helper_btst(uint32_t t0, uint32_t t1, uint32_t ccs) ++uint32_t helper_btst(CPUCRISState *env, uint32_t t0, uint32_t t1, uint32_t ccs) + { + /* FIXME: clean this up. */ + +@@ -284,7 +284,8 @@ uint32_t helper_btst(uint32_t t0, uint32_t t1, uint32_t ccs) + return ccs; + } + +-static inline uint32_t evaluate_flags_writeback(uint32_t flags, uint32_t ccs) ++static inline uint32_t evaluate_flags_writeback(CPUCRISState *env, ++ uint32_t flags, uint32_t ccs) + { + unsigned int x, z, mask; + +@@ -303,7 +304,8 @@ static inline uint32_t evaluate_flags_writeback(uint32_t flags, uint32_t ccs) + return ccs; + } + +-uint32_t helper_evaluate_flags_muls(uint32_t ccs, uint32_t res, uint32_t mof) ++uint32_t helper_evaluate_flags_muls(CPUCRISState *env, ++ uint32_t ccs, uint32_t res, uint32_t mof) + { + uint32_t flags = 0; + int64_t tmp; +@@ -321,10 +323,11 @@ uint32_t helper_evaluate_flags_muls(uint32_t ccs, uint32_t res, uint32_t mof) + if ((dneg && mof != -1) + || (!dneg && mof != 0)) + flags |= V_FLAG; +- return evaluate_flags_writeback(flags, ccs); ++ return evaluate_flags_writeback(env, flags, ccs); + } + +-uint32_t helper_evaluate_flags_mulu(uint32_t ccs, uint32_t res, uint32_t mof) ++uint32_t helper_evaluate_flags_mulu(CPUCRISState *env, ++ uint32_t ccs, uint32_t res, uint32_t mof) + { + uint32_t flags = 0; + uint64_t tmp; +@@ -339,10 +342,10 @@ uint32_t helper_evaluate_flags_mulu(uint32_t ccs, uint32_t res, uint32_t mof) + if (mof) + flags |= V_FLAG; + +- return evaluate_flags_writeback(flags, ccs); ++ return evaluate_flags_writeback(env, flags, ccs); + } + +-uint32_t helper_evaluate_flags_mcp(uint32_t ccs, ++uint32_t helper_evaluate_flags_mcp(CPUCRISState *env, uint32_t ccs, + uint32_t src, uint32_t dst, uint32_t res) + { + uint32_t flags = 0; +@@ -368,10 +371,10 @@ uint32_t helper_evaluate_flags_mcp(uint32_t ccs, + flags |= R_FLAG; + } + +- return evaluate_flags_writeback(flags, ccs); ++ return evaluate_flags_writeback(env, flags, ccs); + } + +-uint32_t helper_evaluate_flags_alu_4(uint32_t ccs, ++uint32_t helper_evaluate_flags_alu_4(CPUCRISState *env, uint32_t ccs, + uint32_t src, uint32_t dst, uint32_t res) + { + uint32_t flags = 0; +@@ -397,10 +400,10 @@ uint32_t helper_evaluate_flags_alu_4(uint32_t ccs, + flags |= C_FLAG; + } + +- return evaluate_flags_writeback(flags, ccs); ++ return evaluate_flags_writeback(env, flags, ccs); + } + +-uint32_t helper_evaluate_flags_sub_4(uint32_t ccs, ++uint32_t helper_evaluate_flags_sub_4(CPUCRISState *env, uint32_t ccs, + uint32_t src, uint32_t dst, uint32_t res) + { + uint32_t flags = 0; +@@ -427,10 +430,11 @@ uint32_t helper_evaluate_flags_sub_4(uint32_t ccs, + } + + flags ^= C_FLAG; +- return evaluate_flags_writeback(flags, ccs); ++ return evaluate_flags_writeback(env, flags, ccs); + } + +-uint32_t helper_evaluate_flags_move_4(uint32_t ccs, uint32_t res) ++uint32_t helper_evaluate_flags_move_4(CPUCRISState *env, ++ uint32_t ccs, uint32_t res) + { + uint32_t flags = 0; + +@@ -439,9 +443,10 @@ uint32_t helper_evaluate_flags_move_4(uint32_t ccs, uint32_t res) + else if (res == 0L) + flags |= Z_FLAG; + +- return evaluate_flags_writeback(flags, ccs); ++ return evaluate_flags_writeback(env, flags, ccs); + } +-uint32_t helper_evaluate_flags_move_2(uint32_t ccs, uint32_t res) ++uint32_t helper_evaluate_flags_move_2(CPUCRISState *env, ++ uint32_t ccs, uint32_t res) + { + uint32_t flags = 0; + +@@ -450,12 +455,12 @@ uint32_t helper_evaluate_flags_move_2(uint32_t ccs, uint32_t res) + else if (res == 0) + flags |= Z_FLAG; + +- return evaluate_flags_writeback(flags, ccs); ++ return evaluate_flags_writeback(env, flags, ccs); + } + + /* TODO: This is expensive. We could split things up and only evaluate part of + CCR on a need to know basis. For now, we simply re-evaluate everything. */ +-void helper_evaluate_flags(void) ++void helper_evaluate_flags(CPUCRISState *env) + { + uint32_t src, dst, res; + uint32_t flags = 0; +@@ -571,25 +576,26 @@ void helper_evaluate_flags(void) + if (env->cc_op == CC_OP_SUB || env->cc_op == CC_OP_CMP) + flags ^= C_FLAG; + +- env->pregs[PR_CCS] = evaluate_flags_writeback(flags, env->pregs[PR_CCS]); ++ env->pregs[PR_CCS] = evaluate_flags_writeback(env, flags, ++ env->pregs[PR_CCS]); + } + +-void helper_top_evaluate_flags(void) ++void helper_top_evaluate_flags(CPUCRISState *env) + { + switch (env->cc_op) + { + case CC_OP_MCP: +- env->pregs[PR_CCS] = helper_evaluate_flags_mcp( ++ env->pregs[PR_CCS] = helper_evaluate_flags_mcp(env, + env->pregs[PR_CCS], env->cc_src, + env->cc_dest, env->cc_result); + break; + case CC_OP_MULS: +- env->pregs[PR_CCS] = helper_evaluate_flags_muls( ++ env->pregs[PR_CCS] = helper_evaluate_flags_muls(env, + env->pregs[PR_CCS], env->cc_result, + env->pregs[PR_MOF]); + break; + case CC_OP_MULU: +- env->pregs[PR_CCS] = helper_evaluate_flags_mulu( ++ env->pregs[PR_CCS] = helper_evaluate_flags_mulu(env, + env->pregs[PR_CCS], env->cc_result, + env->pregs[PR_MOF]); + break; +@@ -604,18 +610,18 @@ void helper_top_evaluate_flags(void) + { + case 4: + env->pregs[PR_CCS] = +- helper_evaluate_flags_move_4( ++ helper_evaluate_flags_move_4(env, + env->pregs[PR_CCS], + env->cc_result); + break; + case 2: + env->pregs[PR_CCS] = +- helper_evaluate_flags_move_2( ++ helper_evaluate_flags_move_2(env, + env->pregs[PR_CCS], + env->cc_result); + break; + default: +- helper_evaluate_flags(); ++ helper_evaluate_flags(env); + break; + } + break; +@@ -626,12 +632,12 @@ void helper_top_evaluate_flags(void) + case CC_OP_CMP: + if (env->cc_size == 4) + env->pregs[PR_CCS] = +- helper_evaluate_flags_sub_4( ++ helper_evaluate_flags_sub_4(env, + env->pregs[PR_CCS], + env->cc_src, env->cc_dest, + env->cc_result); + else +- helper_evaluate_flags(); ++ helper_evaluate_flags(env); + break; + default: + { +@@ -639,13 +645,13 @@ void helper_top_evaluate_flags(void) + { + case 4: + env->pregs[PR_CCS] = +- helper_evaluate_flags_alu_4( ++ helper_evaluate_flags_alu_4(env, + env->pregs[PR_CCS], + env->cc_src, env->cc_dest, + env->cc_result); + break; + default: +- helper_evaluate_flags(); ++ helper_evaluate_flags(env); + break; + } + } +diff --git a/target-cris/translate.c b/target-cris/translate.c +index ad31877..283dd98 100644 +--- a/target-cris/translate.c ++++ b/target-cris/translate.c +@@ -211,9 +211,9 @@ static inline void t_gen_mov_preg_TN(DisasContext *dc, int r, TCGv tn) + tcg_gen_andi_tl(cpu_PR[r], tn, 3); + else { + if (r == PR_PID) +- gen_helper_tlb_flush_pid(tn); ++ gen_helper_tlb_flush_pid(cpu_env, tn); + if (dc->tb_flags & S_FLAG && r == PR_SPC) +- gen_helper_spc_write(tn); ++ gen_helper_spc_write(cpu_env, tn); + else if (r == PR_CCS) + dc->cpustate_changed = 1; + tcg_gen_mov_tl(cpu_PR[r], tn); +@@ -278,7 +278,7 @@ static void cris_lock_irq(DisasContext *dc) + static inline void t_gen_raise_exception(uint32_t index) + { + TCGv_i32 tmp = tcg_const_i32(index); +- gen_helper_raise_exception(tmp); ++ gen_helper_raise_exception(cpu_env, tmp); + tcg_temp_free_i32(tmp); + } + +@@ -624,17 +624,17 @@ static void cris_evaluate_flags(DisasContext *dc) + switch (dc->cc_op) + { + case CC_OP_MCP: +- gen_helper_evaluate_flags_mcp(cpu_PR[PR_CCS], ++ gen_helper_evaluate_flags_mcp(cpu_PR[PR_CCS], cpu_env, + cpu_PR[PR_CCS], cc_src, + cc_dest, cc_result); + break; + case CC_OP_MULS: +- gen_helper_evaluate_flags_muls(cpu_PR[PR_CCS], ++ gen_helper_evaluate_flags_muls(cpu_PR[PR_CCS], cpu_env, + cpu_PR[PR_CCS], cc_result, + cpu_PR[PR_MOF]); + break; + case CC_OP_MULU: +- gen_helper_evaluate_flags_mulu(cpu_PR[PR_CCS], ++ gen_helper_evaluate_flags_mulu(cpu_PR[PR_CCS], cpu_env, + cpu_PR[PR_CCS], cc_result, + cpu_PR[PR_MOF]); + break; +@@ -648,15 +648,15 @@ static void cris_evaluate_flags(DisasContext *dc) + switch (dc->cc_size) + { + case 4: +- gen_helper_evaluate_flags_move_4(cpu_PR[PR_CCS], +- cpu_PR[PR_CCS], cc_result); ++ gen_helper_evaluate_flags_move_4(cpu_PR[PR_CCS], ++ cpu_env, cpu_PR[PR_CCS], cc_result); + break; + case 2: +- gen_helper_evaluate_flags_move_2(cpu_PR[PR_CCS], +- cpu_PR[PR_CCS], cc_result); ++ gen_helper_evaluate_flags_move_2(cpu_PR[PR_CCS], ++ cpu_env, cpu_PR[PR_CCS], cc_result); + break; + default: +- gen_helper_evaluate_flags(); ++ gen_helper_evaluate_flags(cpu_env); + break; + } + break; +@@ -666,21 +666,21 @@ static void cris_evaluate_flags(DisasContext *dc) + case CC_OP_SUB: + case CC_OP_CMP: + if (dc->cc_size == 4) +- gen_helper_evaluate_flags_sub_4(cpu_PR[PR_CCS], ++ gen_helper_evaluate_flags_sub_4(cpu_PR[PR_CCS], cpu_env, + cpu_PR[PR_CCS], cc_src, cc_dest, cc_result); + else +- gen_helper_evaluate_flags(); ++ gen_helper_evaluate_flags(cpu_env); + + break; + default: + switch (dc->cc_size) + { + case 4: +- gen_helper_evaluate_flags_alu_4(cpu_PR[PR_CCS], ++ gen_helper_evaluate_flags_alu_4(cpu_PR[PR_CCS], cpu_env, + cpu_PR[PR_CCS], cc_src, cc_dest, cc_result); + break; + default: +- gen_helper_evaluate_flags(); ++ gen_helper_evaluate_flags(cpu_env); + break; + } + break; +@@ -1475,7 +1475,7 @@ static int dec_btstq(DisasContext *dc) + + cris_cc_mask(dc, CC_MASK_NZ); + cris_evaluate_flags(dc); +- gen_helper_btst(cpu_PR[PR_CCS], cpu_R[dc->op2], ++ gen_helper_btst(cpu_PR[PR_CCS], cpu_env, cpu_R[dc->op2], + tcg_const_tl(dc->op1), cpu_PR[PR_CCS]); + cris_alu(dc, CC_OP_MOVE, + cpu_R[dc->op2], cpu_R[dc->op2], cpu_R[dc->op2], 4); +@@ -1925,7 +1925,7 @@ static int dec_btst_r(DisasContext *dc) + dc->op1, dc->op2); + cris_cc_mask(dc, CC_MASK_NZ); + cris_evaluate_flags(dc); +- gen_helper_btst(cpu_PR[PR_CCS], cpu_R[dc->op2], ++ gen_helper_btst(cpu_PR[PR_CCS], cpu_env, cpu_R[dc->op2], + cpu_R[dc->op1], cpu_PR[PR_CCS]); + cris_alu(dc, CC_OP_MOVE, cpu_R[dc->op2], + cpu_R[dc->op2], cpu_R[dc->op2], 4); +@@ -2135,14 +2135,16 @@ static int dec_move_rs(DisasContext *dc) + { + LOG_DIS("move $r%u, $s%u\n", dc->op1, dc->op2); + cris_cc_mask(dc, 0); +- gen_helper_movl_sreg_reg(tcg_const_tl(dc->op2), tcg_const_tl(dc->op1)); ++ gen_helper_movl_sreg_reg(cpu_env, tcg_const_tl(dc->op2), ++ tcg_const_tl(dc->op1)); + return 2; + } + static int dec_move_sr(DisasContext *dc) + { + LOG_DIS("move $s%u, $r%u\n", dc->op2, dc->op1); + cris_cc_mask(dc, 0); +- gen_helper_movl_reg_sreg(tcg_const_tl(dc->op1), tcg_const_tl(dc->op2)); ++ gen_helper_movl_reg_sreg(cpu_env, tcg_const_tl(dc->op1), ++ tcg_const_tl(dc->op2)); + return 2; + } + +@@ -2906,14 +2908,14 @@ static int dec_rfe_etc(DisasContext *dc) + /* rfe. */ + LOG_DIS("rfe\n"); + cris_evaluate_flags(dc); +- gen_helper_rfe(); ++ gen_helper_rfe(cpu_env); + dc->is_jmp = DISAS_UPDATE; + break; + case 5: + /* rfn. */ + LOG_DIS("rfn\n"); + cris_evaluate_flags(dc); +- gen_helper_rfn(); ++ gen_helper_rfn(cpu_env); + dc->is_jmp = DISAS_UPDATE; + break; + case 6: +diff --git a/target-cris/translate_v10.c b/target-cris/translate_v10.c +index 3629629..9a39c6a 100644 +--- a/target-cris/translate_v10.c ++++ b/target-cris/translate_v10.c +@@ -289,7 +289,7 @@ static unsigned int dec10_quick_imm(DisasContext *dc) + } else { + /* BTST */ + cris_update_cc_op(dc, CC_OP_FLAGS, 4); +- gen_helper_btst(cpu_PR[PR_CCS], cpu_R[dc->dst], ++ gen_helper_btst(cpu_PR[PR_CCS], cpu_env, cpu_R[dc->dst], + tcg_const_tl(imm), cpu_PR[PR_CCS]); + } + break; +@@ -723,7 +723,7 @@ static unsigned int dec10_reg(DisasContext *dc) + LOG_DIS("btst $r%d, $r%d sz=%d\n", dc->src, dc->dst, size); + cris_cc_mask(dc, CC_MASK_NZVC); + cris_update_cc_op(dc, CC_OP_FLAGS, 4); +- gen_helper_btst(cpu_PR[PR_CCS], cpu_R[dc->dst], ++ gen_helper_btst(cpu_PR[PR_CCS], cpu_env, cpu_R[dc->dst], + cpu_R[dc->src], cpu_PR[PR_CCS]); + break; + case CRISV10_REG_DSTEP: +-- +1.7.12.1 + diff --git a/0036-target-cris-Switch-to-AREG0-free-mode.patch b/0036-target-cris-Switch-to-AREG0-free-mode.patch new file mode 100644 index 0000000..1464e22 --- /dev/null +++ b/0036-target-cris-Switch-to-AREG0-free-mode.patch @@ -0,0 +1,1538 @@ +From 327937b3765d53776e42ffd3990e0b551c98b0e6 Mon Sep 17 00:00:00 2001 +From: Aurelien Jarno +Date: Fri, 7 Sep 2012 16:13:27 +0200 +Subject: [PATCH] target-cris: Switch to AREG0 free mode + +Add an explicit CPUCRISState parameter instead of relying on AREG0, and +use cpu_ld* in translation and interrupt handling. Remove AREG0 swapping +in tlb_fill(). Switch to AREG0 free mode + +Signed-off-by: Blue Swirl +Signed-off-by: Aurelien Jarno +Signed-off-by: Michael Roth +--- + configure | 2 +- + target-cris/Makefile.objs | 2 - + target-cris/helper.c | 4 +- + target-cris/op_helper.c | 9 +- + target-cris/translate.c | 256 ++++++++++++++++++++++---------------------- + target-cris/translate_v10.c | 95 ++++++++-------- + 6 files changed, 181 insertions(+), 187 deletions(-) + +diff --git a/configure b/configure +index 0b4ef4a..2a12022 100755 +--- a/configure ++++ b/configure +@@ -3839,7 +3839,7 @@ symlink "$source_path/Makefile.target" "$target_dir/Makefile" + + + case "$target_arch2" in +- alpha | arm* | i386 | lm32 | m68k | microblaze* | or32 | s390x | sparc* | unicore32 | x86_64 | xtensa* | ppc*) ++ alpha | arm* | cris | i386 | lm32 | m68k | microblaze* | or32 | s390x | sparc* | unicore32 | x86_64 | xtensa* | ppc*) + echo "CONFIG_TCG_PASS_AREG0=y" >> $config_target_mak + ;; + esac +diff --git a/target-cris/Makefile.objs b/target-cris/Makefile.objs +index 4b09e8c..afb87bc 100644 +--- a/target-cris/Makefile.objs ++++ b/target-cris/Makefile.objs +@@ -1,4 +1,2 @@ + obj-y += translate.o op_helper.o helper.o cpu.o + obj-$(CONFIG_SOFTMMU) += mmu.o machine.o +- +-$(obj)/op_helper.o: QEMU_CFLAGS += $(HELPER_CFLAGS) +diff --git a/target-cris/helper.c b/target-cris/helper.c +index bfbc29e..1bdb7e2 100644 +--- a/target-cris/helper.c ++++ b/target-cris/helper.c +@@ -151,7 +151,7 @@ static void do_interruptv10(CPUCRISState *env) + } + + /* Now that we are in kernel mode, load the handlers address. */ +- env->pc = ldl_code(env->pregs[PR_EBP] + ex_vec * 4); ++ env->pc = cpu_ldl_code(env, env->pregs[PR_EBP] + ex_vec * 4); + env->locked_irq = 1; + env->pregs[PR_CCS] |= F_FLAG_V10; /* set F. */ + +@@ -233,7 +233,7 @@ void do_interrupt(CPUCRISState *env) + /* Now that we are in kernel mode, load the handlers address. + This load may not fault, real hw leaves that behaviour as + undefined. */ +- env->pc = ldl_code(env->pregs[PR_EBP] + ex_vec * 4); ++ env->pc = cpu_ldl_code(env, env->pregs[PR_EBP] + ex_vec * 4); + + /* Clear the excption_index to avoid spurios hw_aborts for recursive + bus faults. */ +diff --git a/target-cris/op_helper.c b/target-cris/op_helper.c +index 5ca85a0..a7468d4 100644 +--- a/target-cris/op_helper.c ++++ b/target-cris/op_helper.c +@@ -19,7 +19,6 @@ + */ + + #include "cpu.h" +-#include "dyngen-exec.h" + #include "mmu.h" + #include "helper.h" + #include "host-utils.h" +@@ -55,17 +54,12 @@ + /* Try to fill the TLB and return an exception if error. If retaddr is + NULL, it means that the function was called in C code (i.e. not + from generated code or from helper.c) */ +-/* XXX: fix it to restore all registers */ +-void tlb_fill(CPUCRISState *env1, target_ulong addr, int is_write, int mmu_idx, ++void tlb_fill(CPUCRISState *env, target_ulong addr, int is_write, int mmu_idx, + uintptr_t retaddr) + { + TranslationBlock *tb; +- CPUCRISState *saved_env; + int ret; + +- saved_env = env; +- env = env1; +- + D_LOG("%s pc=%x tpc=%x ra=%p\n", __func__, + env->pc, env->debug1, (void *)retaddr); + ret = cpu_cris_handle_mmu_fault(env, addr, is_write, mmu_idx); +@@ -84,7 +78,6 @@ void tlb_fill(CPUCRISState *env1, target_ulong addr, int is_write, int mmu_idx, + } + cpu_loop_exit(env); + } +- env = saved_env; + } + + #endif +diff --git a/target-cris/translate.c b/target-cris/translate.c +index 283dd98..19144b5 100644 +--- a/target-cris/translate.c ++++ b/target-cris/translate.c +@@ -78,7 +78,7 @@ typedef struct DisasContext { + target_ulong pc, ppc; + + /* Decoder. */ +- unsigned int (*decoder)(struct DisasContext *dc); ++ unsigned int (*decoder)(CPUCRISState *env, struct DisasContext *dc); + uint32_t ir; + uint32_t opcode; + unsigned int op1; +@@ -233,7 +233,7 @@ static int sign_extend(unsigned int val, unsigned int width) + return sval; + } + +-static int cris_fetch(DisasContext *dc, uint32_t addr, ++static int cris_fetch(CPUCRISState *env, DisasContext *dc, uint32_t addr, + unsigned int size, unsigned int sign) + { + int r; +@@ -241,24 +241,24 @@ static int cris_fetch(DisasContext *dc, uint32_t addr, + switch (size) { + case 4: + { +- r = ldl_code(addr); ++ r = cpu_ldl_code(env, addr); + break; + } + case 2: + { + if (sign) { +- r = ldsw_code(addr); ++ r = cpu_ldsw_code(env, addr); + } else { +- r = lduw_code(addr); ++ r = cpu_lduw_code(env, addr); + } + break; + } + case 1: + { + if (sign) { +- r = ldsb_code(addr); ++ r = cpu_ldsb_code(env, addr); + } else { +- r = ldub_code(addr); ++ r = cpu_ldub_code(env, addr); + } + break; + } +@@ -1304,8 +1304,8 @@ static void dec_prep_alu_r(DisasContext *dc, int rs, int rd, + t_gen_zext(dst, cpu_R[rd], size); + } + +-static int dec_prep_move_m(DisasContext *dc, int s_ext, int memsize, +- TCGv dst) ++static int dec_prep_move_m(CPUCRISState *env, DisasContext *dc, ++ int s_ext, int memsize, TCGv dst) + { + unsigned int rs; + uint32_t imm; +@@ -1321,7 +1321,7 @@ static int dec_prep_move_m(DisasContext *dc, int s_ext, int memsize, + if (memsize == 1) + insn_len++; + +- imm = cris_fetch(dc, dc->pc + 2, memsize, s_ext); ++ imm = cris_fetch(env, dc, dc->pc + 2, memsize, s_ext); + tcg_gen_movi_tl(dst, imm); + dc->postinc = 0; + } else { +@@ -1338,12 +1338,12 @@ static int dec_prep_move_m(DisasContext *dc, int s_ext, int memsize, + /* Prepare T0 and T1 for a memory + alu operation. + s_ext decides if the operand1 should be sign-extended or zero-extended when + needed. */ +-static int dec_prep_alu_m(DisasContext *dc, int s_ext, int memsize, +- TCGv dst, TCGv src) ++static int dec_prep_alu_m(CPUCRISState *env, DisasContext *dc, ++ int s_ext, int memsize, TCGv dst, TCGv src) + { + int insn_len; + +- insn_len = dec_prep_move_m(dc, s_ext, memsize, src); ++ insn_len = dec_prep_move_m(env, dc, s_ext, memsize, src); + tcg_gen_mov_tl(dst, cpu_R[dc->op2]); + return insn_len; + } +@@ -1362,7 +1362,7 @@ static const char *cc_name(int cc) + + /* Start of insn decoders. */ + +-static int dec_bccq(DisasContext *dc) ++static int dec_bccq(CPUCRISState *env, DisasContext *dc) + { + int32_t offset; + int sign; +@@ -1382,7 +1382,7 @@ static int dec_bccq(DisasContext *dc) + cris_prepare_cc_branch (dc, offset, cond); + return 2; + } +-static int dec_addoq(DisasContext *dc) ++static int dec_addoq(CPUCRISState *env, DisasContext *dc) + { + int32_t imm; + +@@ -1396,7 +1396,7 @@ static int dec_addoq(DisasContext *dc) + + return 2; + } +-static int dec_addq(DisasContext *dc) ++static int dec_addq(CPUCRISState *env, DisasContext *dc) + { + LOG_DIS("addq %u, $r%u\n", dc->op1, dc->op2); + +@@ -1408,7 +1408,7 @@ static int dec_addq(DisasContext *dc) + cpu_R[dc->op2], cpu_R[dc->op2], tcg_const_tl(dc->op1), 4); + return 2; + } +-static int dec_moveq(DisasContext *dc) ++static int dec_moveq(CPUCRISState *env, DisasContext *dc) + { + uint32_t imm; + +@@ -1419,7 +1419,7 @@ static int dec_moveq(DisasContext *dc) + tcg_gen_movi_tl(cpu_R[dc->op2], imm); + return 2; + } +-static int dec_subq(DisasContext *dc) ++static int dec_subq(CPUCRISState *env, DisasContext *dc) + { + dc->op1 = EXTRACT_FIELD(dc->ir, 0, 5); + +@@ -1430,7 +1430,7 @@ static int dec_subq(DisasContext *dc) + cpu_R[dc->op2], cpu_R[dc->op2], tcg_const_tl(dc->op1), 4); + return 2; + } +-static int dec_cmpq(DisasContext *dc) ++static int dec_cmpq(CPUCRISState *env, DisasContext *dc) + { + uint32_t imm; + dc->op1 = EXTRACT_FIELD(dc->ir, 0, 5); +@@ -1443,7 +1443,7 @@ static int dec_cmpq(DisasContext *dc) + cpu_R[dc->op2], cpu_R[dc->op2], tcg_const_tl(imm), 4); + return 2; + } +-static int dec_andq(DisasContext *dc) ++static int dec_andq(CPUCRISState *env, DisasContext *dc) + { + uint32_t imm; + dc->op1 = EXTRACT_FIELD(dc->ir, 0, 5); +@@ -1456,7 +1456,7 @@ static int dec_andq(DisasContext *dc) + cpu_R[dc->op2], cpu_R[dc->op2], tcg_const_tl(imm), 4); + return 2; + } +-static int dec_orq(DisasContext *dc) ++static int dec_orq(CPUCRISState *env, DisasContext *dc) + { + uint32_t imm; + dc->op1 = EXTRACT_FIELD(dc->ir, 0, 5); +@@ -1468,7 +1468,7 @@ static int dec_orq(DisasContext *dc) + cpu_R[dc->op2], cpu_R[dc->op2], tcg_const_tl(imm), 4); + return 2; + } +-static int dec_btstq(DisasContext *dc) ++static int dec_btstq(CPUCRISState *env, DisasContext *dc) + { + dc->op1 = EXTRACT_FIELD(dc->ir, 0, 4); + LOG_DIS("btstq %u, $r%d\n", dc->op1, dc->op2); +@@ -1483,7 +1483,7 @@ static int dec_btstq(DisasContext *dc) + dc->flags_uptodate = 1; + return 2; + } +-static int dec_asrq(DisasContext *dc) ++static int dec_asrq(CPUCRISState *env, DisasContext *dc) + { + dc->op1 = EXTRACT_FIELD(dc->ir, 0, 4); + LOG_DIS("asrq %u, $r%d\n", dc->op1, dc->op2); +@@ -1495,7 +1495,7 @@ static int dec_asrq(DisasContext *dc) + cpu_R[dc->op2], cpu_R[dc->op2], 4); + return 2; + } +-static int dec_lslq(DisasContext *dc) ++static int dec_lslq(CPUCRISState *env, DisasContext *dc) + { + dc->op1 = EXTRACT_FIELD(dc->ir, 0, 4); + LOG_DIS("lslq %u, $r%d\n", dc->op1, dc->op2); +@@ -1509,7 +1509,7 @@ static int dec_lslq(DisasContext *dc) + cpu_R[dc->op2], cpu_R[dc->op2], 4); + return 2; + } +-static int dec_lsrq(DisasContext *dc) ++static int dec_lsrq(CPUCRISState *env, DisasContext *dc) + { + dc->op1 = EXTRACT_FIELD(dc->ir, 0, 4); + LOG_DIS("lsrq %u, $r%d\n", dc->op1, dc->op2); +@@ -1523,7 +1523,7 @@ static int dec_lsrq(DisasContext *dc) + return 2; + } + +-static int dec_move_r(DisasContext *dc) ++static int dec_move_r(CPUCRISState *env, DisasContext *dc) + { + int size = memsize_zz(dc); + +@@ -1551,7 +1551,7 @@ static int dec_move_r(DisasContext *dc) + return 2; + } + +-static int dec_scc_r(DisasContext *dc) ++static int dec_scc_r(CPUCRISState *env, DisasContext *dc) + { + int cond = dc->op2; + +@@ -1594,7 +1594,7 @@ static inline void cris_alu_free_temps(DisasContext *dc, int size, TCGv *t) + } + } + +-static int dec_and_r(DisasContext *dc) ++static int dec_and_r(CPUCRISState *env, DisasContext *dc) + { + TCGv t[2]; + int size = memsize_zz(dc); +@@ -1611,7 +1611,7 @@ static int dec_and_r(DisasContext *dc) + return 2; + } + +-static int dec_lz_r(DisasContext *dc) ++static int dec_lz_r(CPUCRISState *env, DisasContext *dc) + { + TCGv t0; + LOG_DIS("lz $r%u, $r%u\n", +@@ -1624,7 +1624,7 @@ static int dec_lz_r(DisasContext *dc) + return 2; + } + +-static int dec_lsl_r(DisasContext *dc) ++static int dec_lsl_r(CPUCRISState *env, DisasContext *dc) + { + TCGv t[2]; + int size = memsize_zz(dc); +@@ -1641,7 +1641,7 @@ static int dec_lsl_r(DisasContext *dc) + return 2; + } + +-static int dec_lsr_r(DisasContext *dc) ++static int dec_lsr_r(CPUCRISState *env, DisasContext *dc) + { + TCGv t[2]; + int size = memsize_zz(dc); +@@ -1658,7 +1658,7 @@ static int dec_lsr_r(DisasContext *dc) + return 2; + } + +-static int dec_asr_r(DisasContext *dc) ++static int dec_asr_r(CPUCRISState *env, DisasContext *dc) + { + TCGv t[2]; + int size = memsize_zz(dc); +@@ -1675,7 +1675,7 @@ static int dec_asr_r(DisasContext *dc) + return 2; + } + +-static int dec_muls_r(DisasContext *dc) ++static int dec_muls_r(CPUCRISState *env, DisasContext *dc) + { + TCGv t[2]; + int size = memsize_zz(dc); +@@ -1691,7 +1691,7 @@ static int dec_muls_r(DisasContext *dc) + return 2; + } + +-static int dec_mulu_r(DisasContext *dc) ++static int dec_mulu_r(CPUCRISState *env, DisasContext *dc) + { + TCGv t[2]; + int size = memsize_zz(dc); +@@ -1708,7 +1708,7 @@ static int dec_mulu_r(DisasContext *dc) + } + + +-static int dec_dstep_r(DisasContext *dc) ++static int dec_dstep_r(CPUCRISState *env, DisasContext *dc) + { + LOG_DIS("dstep $r%u, $r%u\n", dc->op1, dc->op2); + cris_cc_mask(dc, CC_MASK_NZ); +@@ -1717,7 +1717,7 @@ static int dec_dstep_r(DisasContext *dc) + return 2; + } + +-static int dec_xor_r(DisasContext *dc) ++static int dec_xor_r(CPUCRISState *env, DisasContext *dc) + { + TCGv t[2]; + int size = memsize_zz(dc); +@@ -1733,7 +1733,7 @@ static int dec_xor_r(DisasContext *dc) + return 2; + } + +-static int dec_bound_r(DisasContext *dc) ++static int dec_bound_r(CPUCRISState *env, DisasContext *dc) + { + TCGv l0; + int size = memsize_zz(dc); +@@ -1747,7 +1747,7 @@ static int dec_bound_r(DisasContext *dc) + return 2; + } + +-static int dec_cmp_r(DisasContext *dc) ++static int dec_cmp_r(CPUCRISState *env, DisasContext *dc) + { + TCGv t[2]; + int size = memsize_zz(dc); +@@ -1762,7 +1762,7 @@ static int dec_cmp_r(DisasContext *dc) + return 2; + } + +-static int dec_abs_r(DisasContext *dc) ++static int dec_abs_r(CPUCRISState *env, DisasContext *dc) + { + TCGv t0; + +@@ -1781,7 +1781,7 @@ static int dec_abs_r(DisasContext *dc) + return 2; + } + +-static int dec_add_r(DisasContext *dc) ++static int dec_add_r(CPUCRISState *env, DisasContext *dc) + { + TCGv t[2]; + int size = memsize_zz(dc); +@@ -1796,7 +1796,7 @@ static int dec_add_r(DisasContext *dc) + return 2; + } + +-static int dec_addc_r(DisasContext *dc) ++static int dec_addc_r(CPUCRISState *env, DisasContext *dc) + { + LOG_DIS("addc $r%u, $r%u\n", + dc->op1, dc->op2); +@@ -1811,7 +1811,7 @@ static int dec_addc_r(DisasContext *dc) + return 2; + } + +-static int dec_mcp_r(DisasContext *dc) ++static int dec_mcp_r(CPUCRISState *env, DisasContext *dc) + { + LOG_DIS("mcp $p%u, $r%u\n", + dc->op2, dc->op1); +@@ -1838,7 +1838,7 @@ static char * swapmode_name(int mode, char *modename) { + } + #endif + +-static int dec_swap_r(DisasContext *dc) ++static int dec_swap_r(CPUCRISState *env, DisasContext *dc) + { + TCGv t0; + #if DISAS_CRIS +@@ -1864,7 +1864,7 @@ static int dec_swap_r(DisasContext *dc) + return 2; + } + +-static int dec_or_r(DisasContext *dc) ++static int dec_or_r(CPUCRISState *env, DisasContext *dc) + { + TCGv t[2]; + int size = memsize_zz(dc); +@@ -1878,7 +1878,7 @@ static int dec_or_r(DisasContext *dc) + return 2; + } + +-static int dec_addi_r(DisasContext *dc) ++static int dec_addi_r(CPUCRISState *env, DisasContext *dc) + { + TCGv t0; + LOG_DIS("addi.%c $r%u, $r%u\n", +@@ -1891,7 +1891,7 @@ static int dec_addi_r(DisasContext *dc) + return 2; + } + +-static int dec_addi_acr(DisasContext *dc) ++static int dec_addi_acr(CPUCRISState *env, DisasContext *dc) + { + TCGv t0; + LOG_DIS("addi.%c $r%u, $r%u, $acr\n", +@@ -1904,7 +1904,7 @@ static int dec_addi_acr(DisasContext *dc) + return 2; + } + +-static int dec_neg_r(DisasContext *dc) ++static int dec_neg_r(CPUCRISState *env, DisasContext *dc) + { + TCGv t[2]; + int size = memsize_zz(dc); +@@ -1919,7 +1919,7 @@ static int dec_neg_r(DisasContext *dc) + return 2; + } + +-static int dec_btst_r(DisasContext *dc) ++static int dec_btst_r(CPUCRISState *env, DisasContext *dc) + { + LOG_DIS("btst $r%u, $r%u\n", + dc->op1, dc->op2); +@@ -1934,7 +1934,7 @@ static int dec_btst_r(DisasContext *dc) + return 2; + } + +-static int dec_sub_r(DisasContext *dc) ++static int dec_sub_r(CPUCRISState *env, DisasContext *dc) + { + TCGv t[2]; + int size = memsize_zz(dc); +@@ -1949,7 +1949,7 @@ static int dec_sub_r(DisasContext *dc) + } + + /* Zero extension. From size to dword. */ +-static int dec_movu_r(DisasContext *dc) ++static int dec_movu_r(CPUCRISState *env, DisasContext *dc) + { + TCGv t0; + int size = memsize_z(dc); +@@ -1966,7 +1966,7 @@ static int dec_movu_r(DisasContext *dc) + } + + /* Sign extension. From size to dword. */ +-static int dec_movs_r(DisasContext *dc) ++static int dec_movs_r(CPUCRISState *env, DisasContext *dc) + { + TCGv t0; + int size = memsize_z(dc); +@@ -1985,7 +1985,7 @@ static int dec_movs_r(DisasContext *dc) + } + + /* zero extension. From size to dword. */ +-static int dec_addu_r(DisasContext *dc) ++static int dec_addu_r(CPUCRISState *env, DisasContext *dc) + { + TCGv t0; + int size = memsize_z(dc); +@@ -2004,7 +2004,7 @@ static int dec_addu_r(DisasContext *dc) + } + + /* Sign extension. From size to dword. */ +-static int dec_adds_r(DisasContext *dc) ++static int dec_adds_r(CPUCRISState *env, DisasContext *dc) + { + TCGv t0; + int size = memsize_z(dc); +@@ -2023,7 +2023,7 @@ static int dec_adds_r(DisasContext *dc) + } + + /* Zero extension. From size to dword. */ +-static int dec_subu_r(DisasContext *dc) ++static int dec_subu_r(CPUCRISState *env, DisasContext *dc) + { + TCGv t0; + int size = memsize_z(dc); +@@ -2042,7 +2042,7 @@ static int dec_subu_r(DisasContext *dc) + } + + /* Sign extension. From size to dword. */ +-static int dec_subs_r(DisasContext *dc) ++static int dec_subs_r(CPUCRISState *env, DisasContext *dc) + { + TCGv t0; + int size = memsize_z(dc); +@@ -2060,7 +2060,7 @@ static int dec_subs_r(DisasContext *dc) + return 2; + } + +-static int dec_setclrf(DisasContext *dc) ++static int dec_setclrf(CPUCRISState *env, DisasContext *dc) + { + uint32_t flags; + int set = (~dc->opcode >> 2) & 1; +@@ -2131,7 +2131,7 @@ static int dec_setclrf(DisasContext *dc) + return 2; + } + +-static int dec_move_rs(DisasContext *dc) ++static int dec_move_rs(CPUCRISState *env, DisasContext *dc) + { + LOG_DIS("move $r%u, $s%u\n", dc->op1, dc->op2); + cris_cc_mask(dc, 0); +@@ -2139,7 +2139,7 @@ static int dec_move_rs(DisasContext *dc) + tcg_const_tl(dc->op1)); + return 2; + } +-static int dec_move_sr(DisasContext *dc) ++static int dec_move_sr(CPUCRISState *env, DisasContext *dc) + { + LOG_DIS("move $s%u, $r%u\n", dc->op2, dc->op1); + cris_cc_mask(dc, 0); +@@ -2148,7 +2148,7 @@ static int dec_move_sr(DisasContext *dc) + return 2; + } + +-static int dec_move_rp(DisasContext *dc) ++static int dec_move_rp(CPUCRISState *env, DisasContext *dc) + { + TCGv t[2]; + LOG_DIS("move $r%u, $p%u\n", dc->op1, dc->op2); +@@ -2178,7 +2178,7 @@ static int dec_move_rp(DisasContext *dc) + tcg_temp_free(t[0]); + return 2; + } +-static int dec_move_pr(DisasContext *dc) ++static int dec_move_pr(CPUCRISState *env, DisasContext *dc) + { + TCGv t0; + LOG_DIS("move $p%u, $r%u\n", dc->op2, dc->op1); +@@ -2200,7 +2200,7 @@ static int dec_move_pr(DisasContext *dc) + return 2; + } + +-static int dec_move_mr(DisasContext *dc) ++static int dec_move_mr(CPUCRISState *env, DisasContext *dc) + { + int memsize = memsize_zz(dc); + int insn_len; +@@ -2210,7 +2210,7 @@ static int dec_move_mr(DisasContext *dc) + dc->op2); + + if (memsize == 4) { +- insn_len = dec_prep_move_m(dc, 0, 4, cpu_R[dc->op2]); ++ insn_len = dec_prep_move_m(env, dc, 0, 4, cpu_R[dc->op2]); + cris_cc_mask(dc, CC_MASK_NZ); + cris_update_cc_op(dc, CC_OP_MOVE, 4); + cris_update_cc_x(dc); +@@ -2220,7 +2220,7 @@ static int dec_move_mr(DisasContext *dc) + TCGv t0; + + t0 = tcg_temp_new(); +- insn_len = dec_prep_move_m(dc, 0, memsize, t0); ++ insn_len = dec_prep_move_m(env, dc, 0, memsize, t0); + cris_cc_mask(dc, CC_MASK_NZ); + cris_alu(dc, CC_OP_MOVE, + cpu_R[dc->op2], cpu_R[dc->op2], t0, memsize); +@@ -2242,7 +2242,7 @@ static inline void cris_alu_m_free_temps(TCGv *t) + tcg_temp_free(t[1]); + } + +-static int dec_movs_m(DisasContext *dc) ++static int dec_movs_m(CPUCRISState *env, DisasContext *dc) + { + TCGv t[2]; + int memsize = memsize_z(dc); +@@ -2254,7 +2254,7 @@ static int dec_movs_m(DisasContext *dc) + + cris_alu_m_alloc_temps(t); + /* sign extend. */ +- insn_len = dec_prep_alu_m(dc, 1, memsize, t[0], t[1]); ++ insn_len = dec_prep_alu_m(env, dc, 1, memsize, t[0], t[1]); + cris_cc_mask(dc, CC_MASK_NZ); + cris_alu(dc, CC_OP_MOVE, + cpu_R[dc->op2], cpu_R[dc->op2], t[1], 4); +@@ -2263,7 +2263,7 @@ static int dec_movs_m(DisasContext *dc) + return insn_len; + } + +-static int dec_addu_m(DisasContext *dc) ++static int dec_addu_m(CPUCRISState *env, DisasContext *dc) + { + TCGv t[2]; + int memsize = memsize_z(dc); +@@ -2275,7 +2275,7 @@ static int dec_addu_m(DisasContext *dc) + + cris_alu_m_alloc_temps(t); + /* sign extend. */ +- insn_len = dec_prep_alu_m(dc, 0, memsize, t[0], t[1]); ++ insn_len = dec_prep_alu_m(env, dc, 0, memsize, t[0], t[1]); + cris_cc_mask(dc, CC_MASK_NZVC); + cris_alu(dc, CC_OP_ADD, + cpu_R[dc->op2], cpu_R[dc->op2], t[1], 4); +@@ -2284,7 +2284,7 @@ static int dec_addu_m(DisasContext *dc) + return insn_len; + } + +-static int dec_adds_m(DisasContext *dc) ++static int dec_adds_m(CPUCRISState *env, DisasContext *dc) + { + TCGv t[2]; + int memsize = memsize_z(dc); +@@ -2296,7 +2296,7 @@ static int dec_adds_m(DisasContext *dc) + + cris_alu_m_alloc_temps(t); + /* sign extend. */ +- insn_len = dec_prep_alu_m(dc, 1, memsize, t[0], t[1]); ++ insn_len = dec_prep_alu_m(env, dc, 1, memsize, t[0], t[1]); + cris_cc_mask(dc, CC_MASK_NZVC); + cris_alu(dc, CC_OP_ADD, cpu_R[dc->op2], cpu_R[dc->op2], t[1], 4); + do_postinc(dc, memsize); +@@ -2304,7 +2304,7 @@ static int dec_adds_m(DisasContext *dc) + return insn_len; + } + +-static int dec_subu_m(DisasContext *dc) ++static int dec_subu_m(CPUCRISState *env, DisasContext *dc) + { + TCGv t[2]; + int memsize = memsize_z(dc); +@@ -2316,7 +2316,7 @@ static int dec_subu_m(DisasContext *dc) + + cris_alu_m_alloc_temps(t); + /* sign extend. */ +- insn_len = dec_prep_alu_m(dc, 0, memsize, t[0], t[1]); ++ insn_len = dec_prep_alu_m(env, dc, 0, memsize, t[0], t[1]); + cris_cc_mask(dc, CC_MASK_NZVC); + cris_alu(dc, CC_OP_SUB, cpu_R[dc->op2], cpu_R[dc->op2], t[1], 4); + do_postinc(dc, memsize); +@@ -2324,7 +2324,7 @@ static int dec_subu_m(DisasContext *dc) + return insn_len; + } + +-static int dec_subs_m(DisasContext *dc) ++static int dec_subs_m(CPUCRISState *env, DisasContext *dc) + { + TCGv t[2]; + int memsize = memsize_z(dc); +@@ -2336,7 +2336,7 @@ static int dec_subs_m(DisasContext *dc) + + cris_alu_m_alloc_temps(t); + /* sign extend. */ +- insn_len = dec_prep_alu_m(dc, 1, memsize, t[0], t[1]); ++ insn_len = dec_prep_alu_m(env, dc, 1, memsize, t[0], t[1]); + cris_cc_mask(dc, CC_MASK_NZVC); + cris_alu(dc, CC_OP_SUB, cpu_R[dc->op2], cpu_R[dc->op2], t[1], 4); + do_postinc(dc, memsize); +@@ -2344,7 +2344,7 @@ static int dec_subs_m(DisasContext *dc) + return insn_len; + } + +-static int dec_movu_m(DisasContext *dc) ++static int dec_movu_m(CPUCRISState *env, DisasContext *dc) + { + TCGv t[2]; + int memsize = memsize_z(dc); +@@ -2356,7 +2356,7 @@ static int dec_movu_m(DisasContext *dc) + dc->op2); + + cris_alu_m_alloc_temps(t); +- insn_len = dec_prep_alu_m(dc, 0, memsize, t[0], t[1]); ++ insn_len = dec_prep_alu_m(env, dc, 0, memsize, t[0], t[1]); + cris_cc_mask(dc, CC_MASK_NZ); + cris_alu(dc, CC_OP_MOVE, cpu_R[dc->op2], cpu_R[dc->op2], t[1], 4); + do_postinc(dc, memsize); +@@ -2364,7 +2364,7 @@ static int dec_movu_m(DisasContext *dc) + return insn_len; + } + +-static int dec_cmpu_m(DisasContext *dc) ++static int dec_cmpu_m(CPUCRISState *env, DisasContext *dc) + { + TCGv t[2]; + int memsize = memsize_z(dc); +@@ -2375,7 +2375,7 @@ static int dec_cmpu_m(DisasContext *dc) + dc->op2); + + cris_alu_m_alloc_temps(t); +- insn_len = dec_prep_alu_m(dc, 0, memsize, t[0], t[1]); ++ insn_len = dec_prep_alu_m(env, dc, 0, memsize, t[0], t[1]); + cris_cc_mask(dc, CC_MASK_NZVC); + cris_alu(dc, CC_OP_CMP, cpu_R[dc->op2], cpu_R[dc->op2], t[1], 4); + do_postinc(dc, memsize); +@@ -2383,7 +2383,7 @@ static int dec_cmpu_m(DisasContext *dc) + return insn_len; + } + +-static int dec_cmps_m(DisasContext *dc) ++static int dec_cmps_m(CPUCRISState *env, DisasContext *dc) + { + TCGv t[2]; + int memsize = memsize_z(dc); +@@ -2394,7 +2394,7 @@ static int dec_cmps_m(DisasContext *dc) + dc->op2); + + cris_alu_m_alloc_temps(t); +- insn_len = dec_prep_alu_m(dc, 1, memsize, t[0], t[1]); ++ insn_len = dec_prep_alu_m(env, dc, 1, memsize, t[0], t[1]); + cris_cc_mask(dc, CC_MASK_NZVC); + cris_alu(dc, CC_OP_CMP, + cpu_R[dc->op2], cpu_R[dc->op2], t[1], +@@ -2404,7 +2404,7 @@ static int dec_cmps_m(DisasContext *dc) + return insn_len; + } + +-static int dec_cmp_m(DisasContext *dc) ++static int dec_cmp_m(CPUCRISState *env, DisasContext *dc) + { + TCGv t[2]; + int memsize = memsize_zz(dc); +@@ -2415,7 +2415,7 @@ static int dec_cmp_m(DisasContext *dc) + dc->op2); + + cris_alu_m_alloc_temps(t); +- insn_len = dec_prep_alu_m(dc, 0, memsize, t[0], t[1]); ++ insn_len = dec_prep_alu_m(env, dc, 0, memsize, t[0], t[1]); + cris_cc_mask(dc, CC_MASK_NZVC); + cris_alu(dc, CC_OP_CMP, + cpu_R[dc->op2], cpu_R[dc->op2], t[1], +@@ -2425,7 +2425,7 @@ static int dec_cmp_m(DisasContext *dc) + return insn_len; + } + +-static int dec_test_m(DisasContext *dc) ++static int dec_test_m(CPUCRISState *env, DisasContext *dc) + { + TCGv t[2]; + int memsize = memsize_zz(dc); +@@ -2438,7 +2438,7 @@ static int dec_test_m(DisasContext *dc) + cris_evaluate_flags(dc); + + cris_alu_m_alloc_temps(t); +- insn_len = dec_prep_alu_m(dc, 0, memsize, t[0], t[1]); ++ insn_len = dec_prep_alu_m(env, dc, 0, memsize, t[0], t[1]); + cris_cc_mask(dc, CC_MASK_NZ); + tcg_gen_andi_tl(cpu_PR[PR_CCS], cpu_PR[PR_CCS], ~3); + +@@ -2449,7 +2449,7 @@ static int dec_test_m(DisasContext *dc) + return insn_len; + } + +-static int dec_and_m(DisasContext *dc) ++static int dec_and_m(CPUCRISState *env, DisasContext *dc) + { + TCGv t[2]; + int memsize = memsize_zz(dc); +@@ -2460,7 +2460,7 @@ static int dec_and_m(DisasContext *dc) + dc->op2); + + cris_alu_m_alloc_temps(t); +- insn_len = dec_prep_alu_m(dc, 0, memsize, t[0], t[1]); ++ insn_len = dec_prep_alu_m(env, dc, 0, memsize, t[0], t[1]); + cris_cc_mask(dc, CC_MASK_NZ); + cris_alu(dc, CC_OP_AND, cpu_R[dc->op2], t[0], t[1], memsize_zz(dc)); + do_postinc(dc, memsize); +@@ -2468,7 +2468,7 @@ static int dec_and_m(DisasContext *dc) + return insn_len; + } + +-static int dec_add_m(DisasContext *dc) ++static int dec_add_m(CPUCRISState *env, DisasContext *dc) + { + TCGv t[2]; + int memsize = memsize_zz(dc); +@@ -2479,7 +2479,7 @@ static int dec_add_m(DisasContext *dc) + dc->op2); + + cris_alu_m_alloc_temps(t); +- insn_len = dec_prep_alu_m(dc, 0, memsize, t[0], t[1]); ++ insn_len = dec_prep_alu_m(env, dc, 0, memsize, t[0], t[1]); + cris_cc_mask(dc, CC_MASK_NZVC); + cris_alu(dc, CC_OP_ADD, + cpu_R[dc->op2], t[0], t[1], memsize_zz(dc)); +@@ -2488,7 +2488,7 @@ static int dec_add_m(DisasContext *dc) + return insn_len; + } + +-static int dec_addo_m(DisasContext *dc) ++static int dec_addo_m(CPUCRISState *env, DisasContext *dc) + { + TCGv t[2]; + int memsize = memsize_zz(dc); +@@ -2499,7 +2499,7 @@ static int dec_addo_m(DisasContext *dc) + dc->op2); + + cris_alu_m_alloc_temps(t); +- insn_len = dec_prep_alu_m(dc, 1, memsize, t[0], t[1]); ++ insn_len = dec_prep_alu_m(env, dc, 1, memsize, t[0], t[1]); + cris_cc_mask(dc, 0); + cris_alu(dc, CC_OP_ADD, cpu_R[R_ACR], t[0], t[1], 4); + do_postinc(dc, memsize); +@@ -2507,7 +2507,7 @@ static int dec_addo_m(DisasContext *dc) + return insn_len; + } + +-static int dec_bound_m(DisasContext *dc) ++static int dec_bound_m(CPUCRISState *env, DisasContext *dc) + { + TCGv l[2]; + int memsize = memsize_zz(dc); +@@ -2519,7 +2519,7 @@ static int dec_bound_m(DisasContext *dc) + + l[0] = tcg_temp_local_new(); + l[1] = tcg_temp_local_new(); +- insn_len = dec_prep_alu_m(dc, 0, memsize, l[0], l[1]); ++ insn_len = dec_prep_alu_m(env, dc, 0, memsize, l[0], l[1]); + cris_cc_mask(dc, CC_MASK_NZ); + cris_alu(dc, CC_OP_BOUND, cpu_R[dc->op2], l[0], l[1], 4); + do_postinc(dc, memsize); +@@ -2528,7 +2528,7 @@ static int dec_bound_m(DisasContext *dc) + return insn_len; + } + +-static int dec_addc_mr(DisasContext *dc) ++static int dec_addc_mr(CPUCRISState *env, DisasContext *dc) + { + TCGv t[2]; + int insn_len = 2; +@@ -2543,7 +2543,7 @@ static int dec_addc_mr(DisasContext *dc) + dc->flags_x = X_FLAG; + + cris_alu_m_alloc_temps(t); +- insn_len = dec_prep_alu_m(dc, 0, 4, t[0], t[1]); ++ insn_len = dec_prep_alu_m(env, dc, 0, 4, t[0], t[1]); + cris_cc_mask(dc, CC_MASK_NZVC); + cris_alu(dc, CC_OP_ADDC, cpu_R[dc->op2], t[0], t[1], 4); + do_postinc(dc, 4); +@@ -2551,7 +2551,7 @@ static int dec_addc_mr(DisasContext *dc) + return insn_len; + } + +-static int dec_sub_m(DisasContext *dc) ++static int dec_sub_m(CPUCRISState *env, DisasContext *dc) + { + TCGv t[2]; + int memsize = memsize_zz(dc); +@@ -2562,7 +2562,7 @@ static int dec_sub_m(DisasContext *dc) + dc->op2, dc->ir, dc->zzsize); + + cris_alu_m_alloc_temps(t); +- insn_len = dec_prep_alu_m(dc, 0, memsize, t[0], t[1]); ++ insn_len = dec_prep_alu_m(env, dc, 0, memsize, t[0], t[1]); + cris_cc_mask(dc, CC_MASK_NZVC); + cris_alu(dc, CC_OP_SUB, cpu_R[dc->op2], t[0], t[1], memsize); + do_postinc(dc, memsize); +@@ -2570,7 +2570,7 @@ static int dec_sub_m(DisasContext *dc) + return insn_len; + } + +-static int dec_or_m(DisasContext *dc) ++static int dec_or_m(CPUCRISState *env, DisasContext *dc) + { + TCGv t[2]; + int memsize = memsize_zz(dc); +@@ -2581,7 +2581,7 @@ static int dec_or_m(DisasContext *dc) + dc->op2, dc->pc); + + cris_alu_m_alloc_temps(t); +- insn_len = dec_prep_alu_m(dc, 0, memsize, t[0], t[1]); ++ insn_len = dec_prep_alu_m(env, dc, 0, memsize, t[0], t[1]); + cris_cc_mask(dc, CC_MASK_NZ); + cris_alu(dc, CC_OP_OR, + cpu_R[dc->op2], t[0], t[1], memsize_zz(dc)); +@@ -2590,7 +2590,7 @@ static int dec_or_m(DisasContext *dc) + return insn_len; + } + +-static int dec_move_mp(DisasContext *dc) ++static int dec_move_mp(CPUCRISState *env, DisasContext *dc) + { + TCGv t[2]; + int memsize = memsize_zz(dc); +@@ -2603,7 +2603,7 @@ static int dec_move_mp(DisasContext *dc) + dc->op2); + + cris_alu_m_alloc_temps(t); +- insn_len = dec_prep_alu_m(dc, 0, memsize, t[0], t[1]); ++ insn_len = dec_prep_alu_m(env, dc, 0, memsize, t[0], t[1]); + cris_cc_mask(dc, 0); + if (dc->op2 == PR_CCS) { + cris_evaluate_flags(dc); +@@ -2622,7 +2622,7 @@ static int dec_move_mp(DisasContext *dc) + return insn_len; + } + +-static int dec_move_pm(DisasContext *dc) ++static int dec_move_pm(CPUCRISState *env, DisasContext *dc) + { + TCGv t0; + int memsize; +@@ -2648,7 +2648,7 @@ static int dec_move_pm(DisasContext *dc) + return 2; + } + +-static int dec_movem_mr(DisasContext *dc) ++static int dec_movem_mr(CPUCRISState *env, DisasContext *dc) + { + TCGv_i64 tmp[16]; + TCGv tmp32; +@@ -2695,7 +2695,7 @@ static int dec_movem_mr(DisasContext *dc) + return 2; + } + +-static int dec_movem_rm(DisasContext *dc) ++static int dec_movem_rm(CPUCRISState *env, DisasContext *dc) + { + TCGv tmp; + TCGv addr; +@@ -2724,7 +2724,7 @@ static int dec_movem_rm(DisasContext *dc) + return 2; + } + +-static int dec_move_rm(DisasContext *dc) ++static int dec_move_rm(CPUCRISState *env, DisasContext *dc) + { + int memsize; + +@@ -2743,7 +2743,7 @@ static int dec_move_rm(DisasContext *dc) + return 2; + } + +-static int dec_lapcq(DisasContext *dc) ++static int dec_lapcq(CPUCRISState *env, DisasContext *dc) + { + LOG_DIS("lapcq %x, $r%u\n", + dc->pc + dc->op1*2, dc->op2); +@@ -2752,7 +2752,7 @@ static int dec_lapcq(DisasContext *dc) + return 2; + } + +-static int dec_lapc_im(DisasContext *dc) ++static int dec_lapc_im(CPUCRISState *env, DisasContext *dc) + { + unsigned int rd; + int32_t imm; +@@ -2761,7 +2761,7 @@ static int dec_lapc_im(DisasContext *dc) + rd = dc->op2; + + cris_cc_mask(dc, 0); +- imm = cris_fetch(dc, dc->pc + 2, 4, 0); ++ imm = cris_fetch(env, dc, dc->pc + 2, 4, 0); + LOG_DIS("lapc 0x%x, $r%u\n", imm + dc->pc, dc->op2); + + pc = dc->pc; +@@ -2771,7 +2771,7 @@ static int dec_lapc_im(DisasContext *dc) + } + + /* Jump to special reg. */ +-static int dec_jump_p(DisasContext *dc) ++static int dec_jump_p(CPUCRISState *env, DisasContext *dc) + { + LOG_DIS("jump $p%u\n", dc->op2); + +@@ -2786,7 +2786,7 @@ static int dec_jump_p(DisasContext *dc) + } + + /* Jump and save. */ +-static int dec_jas_r(DisasContext *dc) ++static int dec_jas_r(CPUCRISState *env, DisasContext *dc) + { + LOG_DIS("jas $r%u, $p%u\n", dc->op1, dc->op2); + cris_cc_mask(dc, 0); +@@ -2800,11 +2800,11 @@ static int dec_jas_r(DisasContext *dc) + return 2; + } + +-static int dec_jas_im(DisasContext *dc) ++static int dec_jas_im(CPUCRISState *env, DisasContext *dc) + { + uint32_t imm; + +- imm = cris_fetch(dc, dc->pc + 2, 4, 0); ++ imm = cris_fetch(env, dc, dc->pc + 2, 4, 0); + + LOG_DIS("jas 0x%x\n", imm); + cris_cc_mask(dc, 0); +@@ -2816,11 +2816,11 @@ static int dec_jas_im(DisasContext *dc) + return 6; + } + +-static int dec_jasc_im(DisasContext *dc) ++static int dec_jasc_im(CPUCRISState *env, DisasContext *dc) + { + uint32_t imm; + +- imm = cris_fetch(dc, dc->pc + 2, 4, 0); ++ imm = cris_fetch(env, dc, dc->pc + 2, 4, 0); + + LOG_DIS("jasc 0x%x\n", imm); + cris_cc_mask(dc, 0); +@@ -2832,7 +2832,7 @@ static int dec_jasc_im(DisasContext *dc) + return 6; + } + +-static int dec_jasc_r(DisasContext *dc) ++static int dec_jasc_r(CPUCRISState *env, DisasContext *dc) + { + LOG_DIS("jasc_r $r%u, $p%u\n", dc->op1, dc->op2); + cris_cc_mask(dc, 0); +@@ -2843,12 +2843,12 @@ static int dec_jasc_r(DisasContext *dc) + return 2; + } + +-static int dec_bcc_im(DisasContext *dc) ++static int dec_bcc_im(CPUCRISState *env, DisasContext *dc) + { + int32_t offset; + uint32_t cond = dc->op2; + +- offset = cris_fetch(dc, dc->pc + 2, 2, 1); ++ offset = cris_fetch(env, dc, dc->pc + 2, 2, 1); + + LOG_DIS("b%s %d pc=%x dst=%x\n", + cc_name(cond), offset, +@@ -2860,12 +2860,12 @@ static int dec_bcc_im(DisasContext *dc) + return 4; + } + +-static int dec_bas_im(DisasContext *dc) ++static int dec_bas_im(CPUCRISState *env, DisasContext *dc) + { + int32_t simm; + + +- simm = cris_fetch(dc, dc->pc + 2, 4, 0); ++ simm = cris_fetch(env, dc, dc->pc + 2, 4, 0); + + LOG_DIS("bas 0x%x, $p%u\n", dc->pc + simm, dc->op2); + cris_cc_mask(dc, 0); +@@ -2877,10 +2877,10 @@ static int dec_bas_im(DisasContext *dc) + return 6; + } + +-static int dec_basc_im(DisasContext *dc) ++static int dec_basc_im(CPUCRISState *env, DisasContext *dc) + { + int32_t simm; +- simm = cris_fetch(dc, dc->pc + 2, 4, 0); ++ simm = cris_fetch(env, dc, dc->pc + 2, 4, 0); + + LOG_DIS("basc 0x%x, $p%u\n", dc->pc + simm, dc->op2); + cris_cc_mask(dc, 0); +@@ -2892,7 +2892,7 @@ static int dec_basc_im(DisasContext *dc) + return 6; + } + +-static int dec_rfe_etc(DisasContext *dc) ++static int dec_rfe_etc(CPUCRISState *env, DisasContext *dc) + { + cris_cc_mask(dc, 0); + +@@ -2939,17 +2939,17 @@ static int dec_rfe_etc(DisasContext *dc) + return 2; + } + +-static int dec_ftag_fidx_d_m(DisasContext *dc) ++static int dec_ftag_fidx_d_m(CPUCRISState *env, DisasContext *dc) + { + return 2; + } + +-static int dec_ftag_fidx_i_m(DisasContext *dc) ++static int dec_ftag_fidx_i_m(CPUCRISState *env, DisasContext *dc) + { + return 2; + } + +-static int dec_null(DisasContext *dc) ++static int dec_null(CPUCRISState *env, DisasContext *dc) + { + printf ("unknown insn pc=%x opc=%x op1=%x op2=%x\n", + dc->pc, dc->opcode, dc->op1, dc->op2); +@@ -2963,7 +2963,7 @@ static struct decoder_info { + uint32_t bits; + uint32_t mask; + }; +- int (*dec)(DisasContext *dc); ++ int (*dec)(CPUCRISState *env, DisasContext *dc); + } decinfo[] = { + /* Order matters here. */ + {DEC_MOVEQ, dec_moveq}, +@@ -3069,7 +3069,7 @@ static struct decoder_info { + {{0, 0}, dec_null} + }; + +-static unsigned int crisv32_decoder(DisasContext *dc) ++static unsigned int crisv32_decoder(CPUCRISState *env, DisasContext *dc) + { + int insn_len = 2; + int i; +@@ -3078,7 +3078,7 @@ static unsigned int crisv32_decoder(DisasContext *dc) + tcg_gen_debug_insn_start(dc->pc); + + /* Load a halfword onto the instruction register. */ +- dc->ir = cris_fetch(dc, dc->pc, 2, 0); ++ dc->ir = cris_fetch(env, dc, dc->pc, 2, 0); + + /* Now decode it. */ + dc->opcode = EXTRACT_FIELD(dc->ir, 4, 11); +@@ -3092,7 +3092,7 @@ static unsigned int crisv32_decoder(DisasContext *dc) + for (i = 0; i < ARRAY_SIZE(decinfo); i++) { + if ((dc->opcode & decinfo[i].mask) == decinfo[i].bits) + { +- insn_len = decinfo[i].dec(dc); ++ insn_len = decinfo[i].dec(env, dc); + break; + } + } +@@ -3286,7 +3286,7 @@ gen_intermediate_code_internal(CPUCRISState *env, TranslationBlock *tb, + gen_io_start(); + dc->clear_x = 1; + +- insn_len = dc->decoder(dc); ++ insn_len = dc->decoder(env, dc); + dc->ppc = dc->pc; + dc->pc += insn_len; + if (dc->clear_x) +diff --git a/target-cris/translate_v10.c b/target-cris/translate_v10.c +index 9a39c6a..d2cca89 100644 +--- a/target-cris/translate_v10.c ++++ b/target-cris/translate_v10.c +@@ -164,8 +164,8 @@ static unsigned int crisv10_post_memaddr(DisasContext *dc, unsigned int size) + return insn_len; + } + +-static int dec10_prep_move_m(DisasContext *dc, int s_ext, int memsize, +- TCGv dst) ++static int dec10_prep_move_m(CPUCRISState *env, DisasContext *dc, ++ int s_ext, int memsize, TCGv dst) + { + unsigned int rs; + uint32_t imm; +@@ -182,17 +182,17 @@ static int dec10_prep_move_m(DisasContext *dc, int s_ext, int memsize, + if (memsize != 4) { + if (s_ext) { + if (memsize == 1) +- imm = ldsb_code(dc->pc + 2); ++ imm = cpu_ldsb_code(env, dc->pc + 2); + else +- imm = ldsw_code(dc->pc + 2); ++ imm = cpu_ldsw_code(env, dc->pc + 2); + } else { + if (memsize == 1) +- imm = ldub_code(dc->pc + 2); ++ imm = cpu_ldub_code(env, dc->pc + 2); + else +- imm = lduw_code(dc->pc + 2); ++ imm = cpu_lduw_code(env, dc->pc + 2); + } + } else +- imm = ldl_code(dc->pc + 2); ++ imm = cpu_ldl_code(env, dc->pc + 2); + + tcg_gen_movi_tl(dst, imm); + +@@ -752,7 +752,8 @@ static unsigned int dec10_reg(DisasContext *dc) + return insn_len; + } + +-static unsigned int dec10_ind_move_m_r(DisasContext *dc, unsigned int size) ++static unsigned int dec10_ind_move_m_r(CPUCRISState *env, DisasContext *dc, ++ unsigned int size) + { + unsigned int insn_len = 2; + TCGv t; +@@ -762,7 +763,7 @@ static unsigned int dec10_ind_move_m_r(DisasContext *dc, unsigned int size) + + cris_cc_mask(dc, CC_MASK_NZVC); + t = tcg_temp_new(); +- insn_len += dec10_prep_move_m(dc, 0, size, t); ++ insn_len += dec10_prep_move_m(env, dc, 0, size, t); + cris_alu(dc, CC_OP_MOVE, cpu_R[dc->dst], cpu_R[dc->dst], t, size); + if (dc->dst == 15) { + tcg_gen_mov_tl(env_btarget, cpu_R[dc->dst]); +@@ -789,7 +790,7 @@ static unsigned int dec10_ind_move_r_m(DisasContext *dc, unsigned int size) + return insn_len; + } + +-static unsigned int dec10_ind_move_m_pr(DisasContext *dc) ++static unsigned int dec10_ind_move_m_pr(CPUCRISState *env, DisasContext *dc) + { + unsigned int insn_len = 2, rd = dc->dst; + TCGv t, addr; +@@ -799,7 +800,7 @@ static unsigned int dec10_ind_move_m_pr(DisasContext *dc) + + addr = tcg_temp_new(); + t = tcg_temp_new(); +- insn_len += dec10_prep_move_m(dc, 0, 4, t); ++ insn_len += dec10_prep_move_m(env, dc, 0, 4, t); + if (rd == 15) { + tcg_gen_mov_tl(env_btarget, t); + cris_prepare_jmp(dc, JMP_INDIRECT); +@@ -899,14 +900,15 @@ static void dec10_movem_m_r(DisasContext *dc) + tcg_temp_free(t0); + } + +-static int dec10_ind_alu(DisasContext *dc, int op, unsigned int size) ++static int dec10_ind_alu(CPUCRISState *env, DisasContext *dc, ++ int op, unsigned int size) + { + int insn_len = 0; + int rd = dc->dst; + TCGv t[2]; + + cris_alu_m_alloc_temps(t); +- insn_len += dec10_prep_move_m(dc, 0, size, t[0]); ++ insn_len += dec10_prep_move_m(env, dc, 0, size, t[0]); + cris_alu(dc, op, cpu_R[dc->dst], cpu_R[rd], t[0], size); + if (dc->dst == 15) { + tcg_gen_mov_tl(env_btarget, cpu_R[dc->dst]); +@@ -920,14 +922,15 @@ static int dec10_ind_alu(DisasContext *dc, int op, unsigned int size) + return insn_len; + } + +-static int dec10_ind_bound(DisasContext *dc, unsigned int size) ++static int dec10_ind_bound(CPUCRISState *env, DisasContext *dc, ++ unsigned int size) + { + int insn_len = 0; + int rd = dc->dst; + TCGv t; + + t = tcg_temp_local_new(); +- insn_len += dec10_prep_move_m(dc, 0, size, t); ++ insn_len += dec10_prep_move_m(env, dc, 0, size, t); + cris_alu(dc, CC_OP_BOUND, cpu_R[dc->dst], cpu_R[rd], t, 4); + if (dc->dst == 15) { + tcg_gen_mov_tl(env_btarget, cpu_R[dc->dst]); +@@ -940,7 +943,7 @@ static int dec10_ind_bound(DisasContext *dc, unsigned int size) + return insn_len; + } + +-static int dec10_alux_m(DisasContext *dc, int op) ++static int dec10_alux_m(CPUCRISState *env, DisasContext *dc, int op) + { + unsigned int size = (dc->size & 1) ? 2 : 1; + unsigned int sx = !!(dc->size & 2); +@@ -953,7 +956,7 @@ static int dec10_alux_m(DisasContext *dc, int op) + t = tcg_temp_new(); + + cris_cc_mask(dc, CC_MASK_NZVC); +- insn_len += dec10_prep_move_m(dc, sx, size, t); ++ insn_len += dec10_prep_move_m(env, dc, sx, size, t); + cris_alu(dc, op, cpu_R[dc->dst], cpu_R[rd], t, 4); + if (dc->dst == 15) { + tcg_gen_mov_tl(env_btarget, cpu_R[dc->dst]); +@@ -966,7 +969,7 @@ static int dec10_alux_m(DisasContext *dc, int op) + return insn_len; + } + +-static int dec10_dip(DisasContext *dc) ++static int dec10_dip(CPUCRISState *env, DisasContext *dc) + { + int insn_len = 2; + uint32_t imm; +@@ -974,7 +977,7 @@ static int dec10_dip(DisasContext *dc) + LOG_DIS("dip pc=%x opcode=%d r%d r%d\n", + dc->pc, dc->opcode, dc->src, dc->dst); + if (dc->src == 15) { +- imm = ldl_code(dc->pc + 2); ++ imm = cpu_ldl_code(env, dc->pc + 2); + tcg_gen_movi_tl(cpu_PR[PR_PREFIX], imm); + if (dc->postinc) + insn_len += 4; +@@ -989,7 +992,7 @@ static int dec10_dip(DisasContext *dc) + return insn_len; + } + +-static int dec10_bdap_m(DisasContext *dc, int size) ++static int dec10_bdap_m(CPUCRISState *env, DisasContext *dc, int size) + { + int insn_len = 2; + int rd = dc->dst; +@@ -1014,13 +1017,13 @@ static int dec10_bdap_m(DisasContext *dc, int size) + } + #endif + /* Now the rest of the modes are truly indirect. */ +- insn_len += dec10_prep_move_m(dc, 1, size, cpu_PR[PR_PREFIX]); ++ insn_len += dec10_prep_move_m(env, dc, 1, size, cpu_PR[PR_PREFIX]); + tcg_gen_add_tl(cpu_PR[PR_PREFIX], cpu_PR[PR_PREFIX], cpu_R[rd]); + cris_set_prefix(dc); + return insn_len; + } + +-static unsigned int dec10_ind(DisasContext *dc) ++static unsigned int dec10_ind(CPUCRISState *env, DisasContext *dc) + { + unsigned int insn_len = 2; + unsigned int size = dec10_size(dc->size); +@@ -1031,7 +1034,7 @@ static unsigned int dec10_ind(DisasContext *dc) + if (dc->size != 3) { + switch (dc->opcode) { + case CRISV10_IND_MOVE_M_R: +- return dec10_ind_move_m_r(dc, size); ++ return dec10_ind_move_m_r(env, dc, size); + break; + case CRISV10_IND_MOVE_R_M: + return dec10_ind_move_r_m(dc, size); +@@ -1039,7 +1042,7 @@ static unsigned int dec10_ind(DisasContext *dc) + case CRISV10_IND_CMP: + LOG_DIS("cmp size=%d op=%d %d\n", size, dc->src, dc->dst); + cris_cc_mask(dc, CC_MASK_NZVC); +- insn_len += dec10_ind_alu(dc, CC_OP_CMP, size); ++ insn_len += dec10_ind_alu(env, dc, CC_OP_CMP, size); + break; + case CRISV10_IND_TEST: + LOG_DIS("test size=%d op=%d %d\n", size, dc->src, dc->dst); +@@ -1047,7 +1050,7 @@ static unsigned int dec10_ind(DisasContext *dc) + cris_evaluate_flags(dc); + cris_cc_mask(dc, CC_MASK_NZVC); + cris_alu_m_alloc_temps(t); +- insn_len += dec10_prep_move_m(dc, 0, size, t[0]); ++ insn_len += dec10_prep_move_m(env, dc, 0, size, t[0]); + tcg_gen_andi_tl(cpu_PR[PR_CCS], cpu_PR[PR_CCS], ~3); + cris_alu(dc, CC_OP_CMP, cpu_R[dc->dst], + t[0], tcg_const_tl(0), size); +@@ -1056,39 +1059,39 @@ static unsigned int dec10_ind(DisasContext *dc) + case CRISV10_IND_ADD: + LOG_DIS("add size=%d op=%d %d\n", size, dc->src, dc->dst); + cris_cc_mask(dc, CC_MASK_NZVC); +- insn_len += dec10_ind_alu(dc, CC_OP_ADD, size); ++ insn_len += dec10_ind_alu(env, dc, CC_OP_ADD, size); + break; + case CRISV10_IND_SUB: + LOG_DIS("sub size=%d op=%d %d\n", size, dc->src, dc->dst); + cris_cc_mask(dc, CC_MASK_NZVC); +- insn_len += dec10_ind_alu(dc, CC_OP_SUB, size); ++ insn_len += dec10_ind_alu(env, dc, CC_OP_SUB, size); + break; + case CRISV10_IND_BOUND: + LOG_DIS("bound size=%d op=%d %d\n", size, dc->src, dc->dst); + cris_cc_mask(dc, CC_MASK_NZVC); +- insn_len += dec10_ind_bound(dc, size); ++ insn_len += dec10_ind_bound(env, dc, size); + break; + case CRISV10_IND_AND: + LOG_DIS("and size=%d op=%d %d\n", size, dc->src, dc->dst); + cris_cc_mask(dc, CC_MASK_NZVC); +- insn_len += dec10_ind_alu(dc, CC_OP_AND, size); ++ insn_len += dec10_ind_alu(env, dc, CC_OP_AND, size); + break; + case CRISV10_IND_OR: + LOG_DIS("or size=%d op=%d %d\n", size, dc->src, dc->dst); + cris_cc_mask(dc, CC_MASK_NZVC); +- insn_len += dec10_ind_alu(dc, CC_OP_OR, size); ++ insn_len += dec10_ind_alu(env, dc, CC_OP_OR, size); + break; + case CRISV10_IND_MOVX: +- insn_len = dec10_alux_m(dc, CC_OP_MOVE); ++ insn_len = dec10_alux_m(env, dc, CC_OP_MOVE); + break; + case CRISV10_IND_ADDX: +- insn_len = dec10_alux_m(dc, CC_OP_ADD); ++ insn_len = dec10_alux_m(env, dc, CC_OP_ADD); + break; + case CRISV10_IND_SUBX: +- insn_len = dec10_alux_m(dc, CC_OP_SUB); ++ insn_len = dec10_alux_m(env, dc, CC_OP_SUB); + break; + case CRISV10_IND_CMPX: +- insn_len = dec10_alux_m(dc, CC_OP_CMP); ++ insn_len = dec10_alux_m(env, dc, CC_OP_CMP); + break; + case CRISV10_IND_MUL: + /* This is a reg insn coded in the mem indir space. */ +@@ -1097,7 +1100,7 @@ static unsigned int dec10_ind(DisasContext *dc) + dec10_reg_mul(dc, size, dc->ir & (1 << 10)); + break; + case CRISV10_IND_BDAP_M: +- insn_len = dec10_bdap_m(dc, size); ++ insn_len = dec10_bdap_m(env, dc, size); + break; + default: + LOG_DIS("pc=%x var-ind.%d %d r%d r%d\n", +@@ -1110,7 +1113,7 @@ static unsigned int dec10_ind(DisasContext *dc) + + switch (dc->opcode) { + case CRISV10_IND_MOVE_M_SPR: +- insn_len = dec10_ind_move_m_pr(dc); ++ insn_len = dec10_ind_move_m_pr(env, dc); + break; + case CRISV10_IND_MOVE_SPR_M: + insn_len = dec10_ind_move_pr_m(dc); +@@ -1119,7 +1122,7 @@ static unsigned int dec10_ind(DisasContext *dc) + if (dc->src == 15) { + LOG_DIS("jump.%d %d r%d r%d direct\n", size, + dc->opcode, dc->src, dc->dst); +- imm = ldl_code(dc->pc + 2); ++ imm = cpu_ldl_code(env, dc->pc + 2); + if (dc->mode == CRISV10_MODE_AUTOINC) + insn_len += size; + +@@ -1168,24 +1171,24 @@ static unsigned int dec10_ind(DisasContext *dc) + dc->delayed_branch--; /* v10 has no dslot here. */ + break; + case CRISV10_IND_MOVX: +- insn_len = dec10_alux_m(dc, CC_OP_MOVE); ++ insn_len = dec10_alux_m(env, dc, CC_OP_MOVE); + break; + case CRISV10_IND_ADDX: +- insn_len = dec10_alux_m(dc, CC_OP_ADD); ++ insn_len = dec10_alux_m(env, dc, CC_OP_ADD); + break; + case CRISV10_IND_SUBX: +- insn_len = dec10_alux_m(dc, CC_OP_SUB); ++ insn_len = dec10_alux_m(env, dc, CC_OP_SUB); + break; + case CRISV10_IND_CMPX: +- insn_len = dec10_alux_m(dc, CC_OP_CMP); ++ insn_len = dec10_alux_m(env, dc, CC_OP_CMP); + break; + case CRISV10_IND_DIP: +- insn_len = dec10_dip(dc); ++ insn_len = dec10_dip(env, dc); + break; + case CRISV10_IND_BCC_M: + + cris_cc_mask(dc, 0); +- imm = ldsw_code(dc->pc + 2); ++ imm = cpu_ldsw_code(env, dc->pc + 2); + simm = (int16_t)imm; + simm += 4; + +@@ -1202,7 +1205,7 @@ static unsigned int dec10_ind(DisasContext *dc) + return insn_len; + } + +-static unsigned int crisv10_decoder(DisasContext *dc) ++static unsigned int crisv10_decoder(CPUCRISState *env, DisasContext *dc) + { + unsigned int insn_len = 2; + +@@ -1210,7 +1213,7 @@ static unsigned int crisv10_decoder(DisasContext *dc) + tcg_gen_debug_insn_start(dc->pc); + + /* Load a halfword onto the instruction register. */ +- dc->ir = lduw_code(dc->pc); ++ dc->ir = cpu_lduw_code(env, dc->pc); + + /* Now decode it. */ + dc->opcode = EXTRACT_FIELD(dc->ir, 6, 9); +@@ -1235,7 +1238,7 @@ static unsigned int crisv10_decoder(DisasContext *dc) + break; + case CRISV10_MODE_AUTOINC: + case CRISV10_MODE_INDIRECT: +- insn_len = dec10_ind(dc); ++ insn_len = dec10_ind(env, dc); + break; + } + +-- +1.7.12.1 + diff --git a/0037-target-sh4-switch-to-AREG0-free-mode.patch b/0037-target-sh4-switch-to-AREG0-free-mode.patch new file mode 100644 index 0000000..dbbffb0 --- /dev/null +++ b/0037-target-sh4-switch-to-AREG0-free-mode.patch @@ -0,0 +1,1060 @@ +From 22bb4c416286bbfc340f65e5c7f286d96a731cc7 Mon Sep 17 00:00:00 2001 +From: Blue Swirl +Date: Sun, 2 Sep 2012 10:37:06 +0000 +Subject: [PATCH] target-sh4: switch to AREG0 free mode + +Add an explicit CPUState parameter instead of relying on AREG0 +and switch to AREG0 free mode. + +Acked-by: Aurelien Jarno +Signed-off-by: Blue Swirl +Signed-off-by: Michael Roth +--- + configure | 2 +- + target-sh4/Makefile.objs | 2 - + target-sh4/helper.h | 84 +++++++++++----------- + target-sh4/op_helper.c | 182 +++++++++++++++++++++++------------------------ + target-sh4/translate.c | 114 ++++++++++++++++------------- + 5 files changed, 195 insertions(+), 189 deletions(-) + +diff --git a/configure b/configure +index 2a12022..03ce76e 100755 +--- a/configure ++++ b/configure +@@ -3839,7 +3839,7 @@ symlink "$source_path/Makefile.target" "$target_dir/Makefile" + + + case "$target_arch2" in +- alpha | arm* | cris | i386 | lm32 | m68k | microblaze* | or32 | s390x | sparc* | unicore32 | x86_64 | xtensa* | ppc*) ++ alpha | arm* | cris | i386 | lm32 | m68k | microblaze* | or32 | s390x | sh4* | sparc* | unicore32 | x86_64 | xtensa* | ppc*) + echo "CONFIG_TCG_PASS_AREG0=y" >> $config_target_mak + ;; + esac +diff --git a/target-sh4/Makefile.objs b/target-sh4/Makefile.objs +index 2e0e093..ca20f21 100644 +--- a/target-sh4/Makefile.objs ++++ b/target-sh4/Makefile.objs +@@ -1,4 +1,2 @@ + obj-y += translate.o op_helper.o helper.o cpu.o + obj-$(CONFIG_SOFTMMU) += machine.o +- +-$(obj)/op_helper.o: QEMU_CFLAGS += $(HELPER_CFLAGS) +diff --git a/target-sh4/helper.h b/target-sh4/helper.h +index 95e3c7c..6e4f108 100644 +--- a/target-sh4/helper.h ++++ b/target-sh4/helper.h +@@ -1,54 +1,54 @@ + #include "def-helper.h" + +-DEF_HELPER_0(ldtlb, void) +-DEF_HELPER_0(raise_illegal_instruction, void) +-DEF_HELPER_0(raise_slot_illegal_instruction, void) +-DEF_HELPER_0(raise_fpu_disable, void) +-DEF_HELPER_0(raise_slot_fpu_disable, void) +-DEF_HELPER_0(debug, void) +-DEF_HELPER_1(sleep, void, i32) +-DEF_HELPER_1(trapa, void, i32) ++DEF_HELPER_1(ldtlb, void, env) ++DEF_HELPER_1(raise_illegal_instruction, void, env) ++DEF_HELPER_1(raise_slot_illegal_instruction, void, env) ++DEF_HELPER_1(raise_fpu_disable, void, env) ++DEF_HELPER_1(raise_slot_fpu_disable, void, env) ++DEF_HELPER_1(debug, void, env) ++DEF_HELPER_2(sleep, void, env, i32) ++DEF_HELPER_2(trapa, void, env, i32) + +-DEF_HELPER_2(movcal, void, i32, i32) +-DEF_HELPER_0(discard_movcal_backup, void) +-DEF_HELPER_1(ocbi, void, i32) ++DEF_HELPER_3(movcal, void, env, i32, i32) ++DEF_HELPER_1(discard_movcal_backup, void, env) ++DEF_HELPER_2(ocbi, void, env, i32) + +-DEF_HELPER_2(addv, i32, i32, i32) +-DEF_HELPER_2(addc, i32, i32, i32) +-DEF_HELPER_2(subv, i32, i32, i32) +-DEF_HELPER_2(subc, i32, i32, i32) +-DEF_HELPER_2(div1, i32, i32, i32) +-DEF_HELPER_2(macl, void, i32, i32) +-DEF_HELPER_2(macw, void, i32, i32) ++DEF_HELPER_3(addv, i32, env, i32, i32) ++DEF_HELPER_3(addc, i32, env, i32, i32) ++DEF_HELPER_3(subv, i32, env, i32, i32) ++DEF_HELPER_3(subc, i32, env, i32, i32) ++DEF_HELPER_3(div1, i32, env, i32, i32) ++DEF_HELPER_3(macl, void, env, i32, i32) ++DEF_HELPER_3(macw, void, env, i32, i32) + +-DEF_HELPER_1(ld_fpscr, void, i32) ++DEF_HELPER_2(ld_fpscr, void, env, i32) + + DEF_HELPER_1(fabs_FT, f32, f32) + DEF_HELPER_1(fabs_DT, f64, f64) +-DEF_HELPER_2(fadd_FT, f32, f32, f32) +-DEF_HELPER_2(fadd_DT, f64, f64, f64) +-DEF_HELPER_1(fcnvsd_FT_DT, f64, f32) +-DEF_HELPER_1(fcnvds_DT_FT, f32, f64) ++DEF_HELPER_3(fadd_FT, f32, env, f32, f32) ++DEF_HELPER_3(fadd_DT, f64, env, f64, f64) ++DEF_HELPER_2(fcnvsd_FT_DT, f64, env, f32) ++DEF_HELPER_2(fcnvds_DT_FT, f32, env, f64) + +-DEF_HELPER_2(fcmp_eq_FT, void, f32, f32) +-DEF_HELPER_2(fcmp_eq_DT, void, f64, f64) +-DEF_HELPER_2(fcmp_gt_FT, void, f32, f32) +-DEF_HELPER_2(fcmp_gt_DT, void, f64, f64) +-DEF_HELPER_2(fdiv_FT, f32, f32, f32) +-DEF_HELPER_2(fdiv_DT, f64, f64, f64) +-DEF_HELPER_1(float_FT, f32, i32) +-DEF_HELPER_1(float_DT, f64, i32) +-DEF_HELPER_3(fmac_FT, f32, f32, f32, f32) +-DEF_HELPER_2(fmul_FT, f32, f32, f32) +-DEF_HELPER_2(fmul_DT, f64, f64, f64) ++DEF_HELPER_3(fcmp_eq_FT, void, env, f32, f32) ++DEF_HELPER_3(fcmp_eq_DT, void, env, f64, f64) ++DEF_HELPER_3(fcmp_gt_FT, void, env, f32, f32) ++DEF_HELPER_3(fcmp_gt_DT, void, env, f64, f64) ++DEF_HELPER_3(fdiv_FT, f32, env, f32, f32) ++DEF_HELPER_3(fdiv_DT, f64, env, f64, f64) ++DEF_HELPER_2(float_FT, f32, env, i32) ++DEF_HELPER_2(float_DT, f64, env, i32) ++DEF_HELPER_4(fmac_FT, f32, env, f32, f32, f32) ++DEF_HELPER_3(fmul_FT, f32, env, f32, f32) ++DEF_HELPER_3(fmul_DT, f64, env, f64, f64) + DEF_HELPER_1(fneg_T, f32, f32) +-DEF_HELPER_2(fsub_FT, f32, f32, f32) +-DEF_HELPER_2(fsub_DT, f64, f64, f64) +-DEF_HELPER_1(fsqrt_FT, f32, f32) +-DEF_HELPER_1(fsqrt_DT, f64, f64) +-DEF_HELPER_1(ftrc_FT, i32, f32) +-DEF_HELPER_1(ftrc_DT, i32, f64) +-DEF_HELPER_2(fipr, void, i32, i32) +-DEF_HELPER_1(ftrv, void, i32) ++DEF_HELPER_3(fsub_FT, f32, env, f32, f32) ++DEF_HELPER_3(fsub_DT, f64, env, f64, f64) ++DEF_HELPER_2(fsqrt_FT, f32, env, f32) ++DEF_HELPER_2(fsqrt_DT, f64, env, f64) ++DEF_HELPER_2(ftrc_FT, i32, env, f32) ++DEF_HELPER_2(ftrc_DT, i32, env, f64) ++DEF_HELPER_3(fipr, void, env, i32, i32) ++DEF_HELPER_2(ftrv, void, env, i32) + + #include "def-helper.h" +diff --git a/target-sh4/op_helper.c b/target-sh4/op_helper.c +index 4054791..9b4328d 100644 +--- a/target-sh4/op_helper.c ++++ b/target-sh4/op_helper.c +@@ -19,10 +19,9 @@ + #include + #include + #include "cpu.h" +-#include "dyngen-exec.h" + #include "helper.h" + +-static void cpu_restore_state_from_retaddr(uintptr_t retaddr) ++static void cpu_restore_state_from_retaddr(CPUSH4State *env, uintptr_t retaddr) + { + TranslationBlock *tb; + +@@ -53,26 +52,22 @@ static void cpu_restore_state_from_retaddr(uintptr_t retaddr) + #define SHIFT 3 + #include "softmmu_template.h" + +-void tlb_fill(CPUSH4State *env1, target_ulong addr, int is_write, int mmu_idx, ++void tlb_fill(CPUSH4State *env, target_ulong addr, int is_write, int mmu_idx, + uintptr_t retaddr) + { +- CPUSH4State *saved_env; + int ret; + +- saved_env = env; +- env = env1; + ret = cpu_sh4_handle_mmu_fault(env, addr, is_write, mmu_idx); + if (ret) { + /* now we have a real cpu fault */ +- cpu_restore_state_from_retaddr(retaddr); ++ cpu_restore_state_from_retaddr(env, retaddr); + cpu_loop_exit(env); + } +- env = saved_env; + } + + #endif + +-void helper_ldtlb(void) ++void helper_ldtlb(CPUSH4State *env) + { + #ifdef CONFIG_USER_ONLY + /* XXXXX */ +@@ -82,40 +77,41 @@ void helper_ldtlb(void) + #endif + } + +-static inline void raise_exception(int index, uintptr_t retaddr) ++static inline void raise_exception(CPUSH4State *env, int index, ++ uintptr_t retaddr) + { + env->exception_index = index; +- cpu_restore_state_from_retaddr(retaddr); ++ cpu_restore_state_from_retaddr(env, retaddr); + cpu_loop_exit(env); + } + +-void helper_raise_illegal_instruction(void) ++void helper_raise_illegal_instruction(CPUSH4State *env) + { +- raise_exception(0x180, GETPC()); ++ raise_exception(env, 0x180, GETPC()); + } + +-void helper_raise_slot_illegal_instruction(void) ++void helper_raise_slot_illegal_instruction(CPUSH4State *env) + { +- raise_exception(0x1a0, GETPC()); ++ raise_exception(env, 0x1a0, GETPC()); + } + +-void helper_raise_fpu_disable(void) ++void helper_raise_fpu_disable(CPUSH4State *env) + { +- raise_exception(0x800, GETPC()); ++ raise_exception(env, 0x800, GETPC()); + } + +-void helper_raise_slot_fpu_disable(void) ++void helper_raise_slot_fpu_disable(CPUSH4State *env) + { +- raise_exception(0x820, GETPC()); ++ raise_exception(env, 0x820, GETPC()); + } + +-void helper_debug(void) ++void helper_debug(CPUSH4State *env) + { + env->exception_index = EXCP_DEBUG; + cpu_loop_exit(env); + } + +-void helper_sleep(uint32_t next_pc) ++void helper_sleep(CPUSH4State *env, uint32_t next_pc) + { + env->halted = 1; + env->in_sleep = 1; +@@ -124,13 +120,13 @@ void helper_sleep(uint32_t next_pc) + cpu_loop_exit(env); + } + +-void helper_trapa(uint32_t tra) ++void helper_trapa(CPUSH4State *env, uint32_t tra) + { + env->tra = tra << 2; +- raise_exception(0x160, GETPC()); ++ raise_exception(env, 0x160, GETPC()); + } + +-void helper_movcal(uint32_t address, uint32_t value) ++void helper_movcal(CPUSH4State *env, uint32_t address, uint32_t value) + { + if (cpu_sh4_is_cached (env, address)) + { +@@ -144,7 +140,7 @@ void helper_movcal(uint32_t address, uint32_t value) + } + } + +-void helper_discard_movcal_backup(void) ++void helper_discard_movcal_backup(CPUSH4State *env) + { + memory_content *current = env->movcal_backup; + +@@ -158,7 +154,7 @@ void helper_discard_movcal_backup(void) + } + } + +-void helper_ocbi(uint32_t address) ++void helper_ocbi(CPUSH4State *env, uint32_t address) + { + memory_content **current = &(env->movcal_backup); + while (*current) +@@ -167,7 +163,7 @@ void helper_ocbi(uint32_t address) + if ((a & ~0x1F) == (address & ~0x1F)) + { + memory_content *next = (*current)->next; +- stl(a, (*current)->value); ++ cpu_stl_data(env, a, (*current)->value); + + if (next == NULL) + { +@@ -181,7 +177,7 @@ void helper_ocbi(uint32_t address) + } + } + +-uint32_t helper_addc(uint32_t arg0, uint32_t arg1) ++uint32_t helper_addc(CPUSH4State *env, uint32_t arg0, uint32_t arg1) + { + uint32_t tmp0, tmp1; + +@@ -197,7 +193,7 @@ uint32_t helper_addc(uint32_t arg0, uint32_t arg1) + return arg1; + } + +-uint32_t helper_addv(uint32_t arg0, uint32_t arg1) ++uint32_t helper_addv(CPUSH4State *env, uint32_t arg0, uint32_t arg1) + { + uint32_t dest, src, ans; + +@@ -236,7 +232,7 @@ uint32_t helper_addv(uint32_t arg0, uint32_t arg1) + #define SETM env->sr |= SR_M + #define CLRM env->sr &= ~SR_M + +-uint32_t helper_div1(uint32_t arg0, uint32_t arg1) ++uint32_t helper_div1(CPUSH4State *env, uint32_t arg0, uint32_t arg1) + { + uint32_t tmp0, tmp2; + uint8_t old_q, tmp1 = 0xff; +@@ -344,7 +340,7 @@ uint32_t helper_div1(uint32_t arg0, uint32_t arg1) + return arg1; + } + +-void helper_macl(uint32_t arg0, uint32_t arg1) ++void helper_macl(CPUSH4State *env, uint32_t arg0, uint32_t arg1) + { + int64_t res; + +@@ -360,7 +356,7 @@ void helper_macl(uint32_t arg0, uint32_t arg1) + } + } + +-void helper_macw(uint32_t arg0, uint32_t arg1) ++void helper_macw(CPUSH4State *env, uint32_t arg0, uint32_t arg1) + { + int64_t res; + +@@ -379,7 +375,7 @@ void helper_macw(uint32_t arg0, uint32_t arg1) + } + } + +-uint32_t helper_subc(uint32_t arg0, uint32_t arg1) ++uint32_t helper_subc(CPUSH4State *env, uint32_t arg0, uint32_t arg1) + { + uint32_t tmp0, tmp1; + +@@ -395,7 +391,7 @@ uint32_t helper_subc(uint32_t arg0, uint32_t arg1) + return arg1; + } + +-uint32_t helper_subv(uint32_t arg0, uint32_t arg1) ++uint32_t helper_subv(CPUSH4State *env, uint32_t arg0, uint32_t arg1) + { + int32_t dest, src, ans; + +@@ -424,17 +420,17 @@ uint32_t helper_subv(uint32_t arg0, uint32_t arg1) + return arg1; + } + +-static inline void set_t(void) ++static inline void set_t(CPUSH4State *env) + { + env->sr |= SR_T; + } + +-static inline void clr_t(void) ++static inline void clr_t(CPUSH4State *env) + { + env->sr &= ~SR_T; + } + +-void helper_ld_fpscr(uint32_t val) ++void helper_ld_fpscr(CPUSH4State *env, uint32_t val) + { + env->fpscr = val & FPSCR_MASK; + if ((val & FPSCR_RM_MASK) == FPSCR_RM_ZERO) { +@@ -445,7 +441,7 @@ void helper_ld_fpscr(uint32_t val) + set_flush_to_zero((val & FPSCR_DN) != 0, &env->fp_status); + } + +-static void update_fpscr(uintptr_t retaddr) ++static void update_fpscr(CPUSH4State *env, uintptr_t retaddr) + { + int xcpt, cause, enable; + +@@ -479,7 +475,7 @@ static void update_fpscr(uintptr_t retaddr) + cause = (env->fpscr & FPSCR_CAUSE_MASK) >> FPSCR_CAUSE_SHIFT; + enable = (env->fpscr & FPSCR_ENABLE_MASK) >> FPSCR_ENABLE_SHIFT; + if (cause & enable) { +- cpu_restore_state_from_retaddr(retaddr); ++ cpu_restore_state_from_retaddr(env, retaddr); + env->exception_index = 0x120; + cpu_loop_exit(env); + } +@@ -496,156 +492,156 @@ float64 helper_fabs_DT(float64 t0) + return float64_abs(t0); + } + +-float32 helper_fadd_FT(float32 t0, float32 t1) ++float32 helper_fadd_FT(CPUSH4State *env, float32 t0, float32 t1) + { + set_float_exception_flags(0, &env->fp_status); + t0 = float32_add(t0, t1, &env->fp_status); +- update_fpscr(GETPC()); ++ update_fpscr(env, GETPC()); + return t0; + } + +-float64 helper_fadd_DT(float64 t0, float64 t1) ++float64 helper_fadd_DT(CPUSH4State *env, float64 t0, float64 t1) + { + set_float_exception_flags(0, &env->fp_status); + t0 = float64_add(t0, t1, &env->fp_status); +- update_fpscr(GETPC()); ++ update_fpscr(env, GETPC()); + return t0; + } + +-void helper_fcmp_eq_FT(float32 t0, float32 t1) ++void helper_fcmp_eq_FT(CPUSH4State *env, float32 t0, float32 t1) + { + int relation; + + set_float_exception_flags(0, &env->fp_status); + relation = float32_compare(t0, t1, &env->fp_status); + if (unlikely(relation == float_relation_unordered)) { +- update_fpscr(GETPC()); ++ update_fpscr(env, GETPC()); + } else if (relation == float_relation_equal) { +- set_t(); ++ set_t(env); + } else { +- clr_t(); ++ clr_t(env); + } + } + +-void helper_fcmp_eq_DT(float64 t0, float64 t1) ++void helper_fcmp_eq_DT(CPUSH4State *env, float64 t0, float64 t1) + { + int relation; + + set_float_exception_flags(0, &env->fp_status); + relation = float64_compare(t0, t1, &env->fp_status); + if (unlikely(relation == float_relation_unordered)) { +- update_fpscr(GETPC()); ++ update_fpscr(env, GETPC()); + } else if (relation == float_relation_equal) { +- set_t(); ++ set_t(env); + } else { +- clr_t(); ++ clr_t(env); + } + } + +-void helper_fcmp_gt_FT(float32 t0, float32 t1) ++void helper_fcmp_gt_FT(CPUSH4State *env, float32 t0, float32 t1) + { + int relation; + + set_float_exception_flags(0, &env->fp_status); + relation = float32_compare(t0, t1, &env->fp_status); + if (unlikely(relation == float_relation_unordered)) { +- update_fpscr(GETPC()); ++ update_fpscr(env, GETPC()); + } else if (relation == float_relation_greater) { +- set_t(); ++ set_t(env); + } else { +- clr_t(); ++ clr_t(env); + } + } + +-void helper_fcmp_gt_DT(float64 t0, float64 t1) ++void helper_fcmp_gt_DT(CPUSH4State *env, float64 t0, float64 t1) + { + int relation; + + set_float_exception_flags(0, &env->fp_status); + relation = float64_compare(t0, t1, &env->fp_status); + if (unlikely(relation == float_relation_unordered)) { +- update_fpscr(GETPC()); ++ update_fpscr(env, GETPC()); + } else if (relation == float_relation_greater) { +- set_t(); ++ set_t(env); + } else { +- clr_t(); ++ clr_t(env); + } + } + +-float64 helper_fcnvsd_FT_DT(float32 t0) ++float64 helper_fcnvsd_FT_DT(CPUSH4State *env, float32 t0) + { + float64 ret; + set_float_exception_flags(0, &env->fp_status); + ret = float32_to_float64(t0, &env->fp_status); +- update_fpscr(GETPC()); ++ update_fpscr(env, GETPC()); + return ret; + } + +-float32 helper_fcnvds_DT_FT(float64 t0) ++float32 helper_fcnvds_DT_FT(CPUSH4State *env, float64 t0) + { + float32 ret; + set_float_exception_flags(0, &env->fp_status); + ret = float64_to_float32(t0, &env->fp_status); +- update_fpscr(GETPC()); ++ update_fpscr(env, GETPC()); + return ret; + } + +-float32 helper_fdiv_FT(float32 t0, float32 t1) ++float32 helper_fdiv_FT(CPUSH4State *env, float32 t0, float32 t1) + { + set_float_exception_flags(0, &env->fp_status); + t0 = float32_div(t0, t1, &env->fp_status); +- update_fpscr(GETPC()); ++ update_fpscr(env, GETPC()); + return t0; + } + +-float64 helper_fdiv_DT(float64 t0, float64 t1) ++float64 helper_fdiv_DT(CPUSH4State *env, float64 t0, float64 t1) + { + set_float_exception_flags(0, &env->fp_status); + t0 = float64_div(t0, t1, &env->fp_status); +- update_fpscr(GETPC()); ++ update_fpscr(env, GETPC()); + return t0; + } + +-float32 helper_float_FT(uint32_t t0) ++float32 helper_float_FT(CPUSH4State *env, uint32_t t0) + { + float32 ret; + set_float_exception_flags(0, &env->fp_status); + ret = int32_to_float32(t0, &env->fp_status); +- update_fpscr(GETPC()); ++ update_fpscr(env, GETPC()); + return ret; + } + +-float64 helper_float_DT(uint32_t t0) ++float64 helper_float_DT(CPUSH4State *env, uint32_t t0) + { + float64 ret; + set_float_exception_flags(0, &env->fp_status); + ret = int32_to_float64(t0, &env->fp_status); +- update_fpscr(GETPC()); ++ update_fpscr(env, GETPC()); + return ret; + } + +-float32 helper_fmac_FT(float32 t0, float32 t1, float32 t2) ++float32 helper_fmac_FT(CPUSH4State *env, float32 t0, float32 t1, float32 t2) + { + set_float_exception_flags(0, &env->fp_status); + t0 = float32_mul(t0, t1, &env->fp_status); + t0 = float32_add(t0, t2, &env->fp_status); +- update_fpscr(GETPC()); ++ update_fpscr(env, GETPC()); + return t0; + } + +-float32 helper_fmul_FT(float32 t0, float32 t1) ++float32 helper_fmul_FT(CPUSH4State *env, float32 t0, float32 t1) + { + set_float_exception_flags(0, &env->fp_status); + t0 = float32_mul(t0, t1, &env->fp_status); +- update_fpscr(GETPC()); ++ update_fpscr(env, GETPC()); + return t0; + } + +-float64 helper_fmul_DT(float64 t0, float64 t1) ++float64 helper_fmul_DT(CPUSH4State *env, float64 t0, float64 t1) + { + set_float_exception_flags(0, &env->fp_status); + t0 = float64_mul(t0, t1, &env->fp_status); +- update_fpscr(GETPC()); ++ update_fpscr(env, GETPC()); + return t0; + } + +@@ -654,57 +650,57 @@ float32 helper_fneg_T(float32 t0) + return float32_chs(t0); + } + +-float32 helper_fsqrt_FT(float32 t0) ++float32 helper_fsqrt_FT(CPUSH4State *env, float32 t0) + { + set_float_exception_flags(0, &env->fp_status); + t0 = float32_sqrt(t0, &env->fp_status); +- update_fpscr(GETPC()); ++ update_fpscr(env, GETPC()); + return t0; + } + +-float64 helper_fsqrt_DT(float64 t0) ++float64 helper_fsqrt_DT(CPUSH4State *env, float64 t0) + { + set_float_exception_flags(0, &env->fp_status); + t0 = float64_sqrt(t0, &env->fp_status); +- update_fpscr(GETPC()); ++ update_fpscr(env, GETPC()); + return t0; + } + +-float32 helper_fsub_FT(float32 t0, float32 t1) ++float32 helper_fsub_FT(CPUSH4State *env, float32 t0, float32 t1) + { + set_float_exception_flags(0, &env->fp_status); + t0 = float32_sub(t0, t1, &env->fp_status); +- update_fpscr(GETPC()); ++ update_fpscr(env, GETPC()); + return t0; + } + +-float64 helper_fsub_DT(float64 t0, float64 t1) ++float64 helper_fsub_DT(CPUSH4State *env, float64 t0, float64 t1) + { + set_float_exception_flags(0, &env->fp_status); + t0 = float64_sub(t0, t1, &env->fp_status); +- update_fpscr(GETPC()); ++ update_fpscr(env, GETPC()); + return t0; + } + +-uint32_t helper_ftrc_FT(float32 t0) ++uint32_t helper_ftrc_FT(CPUSH4State *env, float32 t0) + { + uint32_t ret; + set_float_exception_flags(0, &env->fp_status); + ret = float32_to_int32_round_to_zero(t0, &env->fp_status); +- update_fpscr(GETPC()); ++ update_fpscr(env, GETPC()); + return ret; + } + +-uint32_t helper_ftrc_DT(float64 t0) ++uint32_t helper_ftrc_DT(CPUSH4State *env, float64 t0) + { + uint32_t ret; + set_float_exception_flags(0, &env->fp_status); + ret = float64_to_int32_round_to_zero(t0, &env->fp_status); +- update_fpscr(GETPC()); ++ update_fpscr(env, GETPC()); + return ret; + } + +-void helper_fipr(uint32_t m, uint32_t n) ++void helper_fipr(CPUSH4State *env, uint32_t m, uint32_t n) + { + int bank, i; + float32 r, p; +@@ -719,12 +715,12 @@ void helper_fipr(uint32_t m, uint32_t n) + &env->fp_status); + r = float32_add(r, p, &env->fp_status); + } +- update_fpscr(GETPC()); ++ update_fpscr(env, GETPC()); + + env->fregs[bank + n + 3] = r; + } + +-void helper_ftrv(uint32_t n) ++void helper_ftrv(CPUSH4State *env, uint32_t n) + { + int bank_matrix, bank_vector; + int i, j; +@@ -743,7 +739,7 @@ void helper_ftrv(uint32_t n) + r[i] = float32_add(r[i], p, &env->fp_status); + } + } +- update_fpscr(GETPC()); ++ update_fpscr(env, GETPC()); + + for (i = 0 ; i < 4 ; i++) { + env->fregs[bank_vector + i] = r[i]; +diff --git a/target-sh4/translate.c b/target-sh4/translate.c +index 6532ad2..d05c74c 100644 +--- a/target-sh4/translate.c ++++ b/target-sh4/translate.c +@@ -276,7 +276,7 @@ static void gen_goto_tb(DisasContext * ctx, int n, target_ulong dest) + } else { + tcg_gen_movi_i32(cpu_pc, dest); + if (ctx->singlestep_enabled) +- gen_helper_debug(); ++ gen_helper_debug(cpu_env); + tcg_gen_exit_tb(0); + } + } +@@ -288,7 +288,7 @@ static void gen_jump(DisasContext * ctx) + delayed jump as immediate jump are conditinal jumps */ + tcg_gen_mov_i32(cpu_pc, cpu_delayed_pc); + if (ctx->singlestep_enabled) +- gen_helper_debug(); ++ gen_helper_debug(cpu_env); + tcg_gen_exit_tb(0); + } else { + gen_goto_tb(ctx, 0, ctx->delayed_pc); +@@ -437,7 +437,7 @@ static inline void gen_store_fpr64 (TCGv_i64 t, int reg) + #define CHECK_NOT_DELAY_SLOT \ + if (ctx->flags & (DELAY_SLOT | DELAY_SLOT_CONDITIONAL)) \ + { \ +- gen_helper_raise_slot_illegal_instruction(); \ ++ gen_helper_raise_slot_illegal_instruction(cpu_env); \ + ctx->bstate = BS_EXCP; \ + return; \ + } +@@ -445,9 +445,9 @@ static inline void gen_store_fpr64 (TCGv_i64 t, int reg) + #define CHECK_PRIVILEGED \ + if (IS_USER(ctx)) { \ + if (ctx->flags & (DELAY_SLOT | DELAY_SLOT_CONDITIONAL)) { \ +- gen_helper_raise_slot_illegal_instruction(); \ ++ gen_helper_raise_slot_illegal_instruction(cpu_env); \ + } else { \ +- gen_helper_raise_illegal_instruction(); \ ++ gen_helper_raise_illegal_instruction(cpu_env); \ + } \ + ctx->bstate = BS_EXCP; \ + return; \ +@@ -456,9 +456,9 @@ static inline void gen_store_fpr64 (TCGv_i64 t, int reg) + #define CHECK_FPU_ENABLED \ + if (ctx->flags & SR_FD) { \ + if (ctx->flags & (DELAY_SLOT | DELAY_SLOT_CONDITIONAL)) { \ +- gen_helper_raise_slot_fpu_disable(); \ ++ gen_helper_raise_slot_fpu_disable(cpu_env); \ + } else { \ +- gen_helper_raise_fpu_disable(); \ ++ gen_helper_raise_fpu_disable(cpu_env); \ + } \ + ctx->bstate = BS_EXCP; \ + return; \ +@@ -492,7 +492,7 @@ static void _decode_opc(DisasContext * ctx) + if (opcode != 0x0093 /* ocbi */ + && opcode != 0x00c3 /* movca.l */) + { +- gen_helper_discard_movcal_backup (); ++ gen_helper_discard_movcal_backup(cpu_env); + ctx->has_movcal = 0; + } + } +@@ -523,7 +523,7 @@ static void _decode_opc(DisasContext * ctx) + return; + case 0x0038: /* ldtlb */ + CHECK_PRIVILEGED +- gen_helper_ldtlb(); ++ gen_helper_ldtlb(cpu_env); + return; + case 0x002b: /* rte */ + CHECK_PRIVILEGED +@@ -551,7 +551,7 @@ static void _decode_opc(DisasContext * ctx) + return; + case 0x001b: /* sleep */ + CHECK_PRIVILEGED +- gen_helper_sleep(tcg_const_i32(ctx->pc + 2)); ++ gen_helper_sleep(cpu_env, tcg_const_i32(ctx->pc + 2)); + return; + } + +@@ -761,10 +761,10 @@ static void _decode_opc(DisasContext * ctx) + tcg_gen_add_i32(REG(B11_8), REG(B11_8), REG(B7_4)); + return; + case 0x300e: /* addc Rm,Rn */ +- gen_helper_addc(REG(B11_8), REG(B7_4), REG(B11_8)); ++ gen_helper_addc(REG(B11_8), cpu_env, REG(B7_4), REG(B11_8)); + return; + case 0x300f: /* addv Rm,Rn */ +- gen_helper_addv(REG(B11_8), REG(B7_4), REG(B11_8)); ++ gen_helper_addv(REG(B11_8), cpu_env, REG(B7_4), REG(B11_8)); + return; + case 0x2009: /* and Rm,Rn */ + tcg_gen_and_i32(REG(B11_8), REG(B11_8), REG(B7_4)); +@@ -817,7 +817,7 @@ static void _decode_opc(DisasContext * ctx) + } + return; + case 0x3004: /* div1 Rm,Rn */ +- gen_helper_div1(REG(B11_8), REG(B7_4), REG(B11_8)); ++ gen_helper_div1(REG(B11_8), cpu_env, REG(B7_4), REG(B11_8)); + return; + case 0x300d: /* dmuls.l Rm,Rn */ + { +@@ -870,7 +870,7 @@ static void _decode_opc(DisasContext * ctx) + tcg_gen_qemu_ld32s(arg0, REG(B7_4), ctx->memidx); + arg1 = tcg_temp_new(); + tcg_gen_qemu_ld32s(arg1, REG(B11_8), ctx->memidx); +- gen_helper_macl(arg0, arg1); ++ gen_helper_macl(cpu_env, arg0, arg1); + tcg_temp_free(arg1); + tcg_temp_free(arg0); + tcg_gen_addi_i32(REG(B7_4), REG(B7_4), 4); +@@ -884,7 +884,7 @@ static void _decode_opc(DisasContext * ctx) + tcg_gen_qemu_ld32s(arg0, REG(B7_4), ctx->memidx); + arg1 = tcg_temp_new(); + tcg_gen_qemu_ld32s(arg1, REG(B11_8), ctx->memidx); +- gen_helper_macw(arg0, arg1); ++ gen_helper_macw(cpu_env, arg0, arg1); + tcg_temp_free(arg1); + tcg_temp_free(arg0); + tcg_gen_addi_i32(REG(B11_8), REG(B11_8), 2); +@@ -1013,10 +1013,10 @@ static void _decode_opc(DisasContext * ctx) + tcg_gen_sub_i32(REG(B11_8), REG(B11_8), REG(B7_4)); + return; + case 0x300a: /* subc Rm,Rn */ +- gen_helper_subc(REG(B11_8), REG(B7_4), REG(B11_8)); ++ gen_helper_subc(REG(B11_8), cpu_env, REG(B7_4), REG(B11_8)); + return; + case 0x300b: /* subv Rm,Rn */ +- gen_helper_subv(REG(B11_8), REG(B7_4), REG(B11_8)); ++ gen_helper_subv(REG(B11_8), cpu_env, REG(B7_4), REG(B11_8)); + return; + case 0x2008: /* tst Rm,Rn */ + { +@@ -1152,22 +1152,22 @@ static void _decode_opc(DisasContext * ctx) + gen_load_fpr64(fp1, DREG(B7_4)); + switch (ctx->opcode & 0xf00f) { + case 0xf000: /* fadd Rm,Rn */ +- gen_helper_fadd_DT(fp0, fp0, fp1); ++ gen_helper_fadd_DT(fp0, cpu_env, fp0, fp1); + break; + case 0xf001: /* fsub Rm,Rn */ +- gen_helper_fsub_DT(fp0, fp0, fp1); ++ gen_helper_fsub_DT(fp0, cpu_env, fp0, fp1); + break; + case 0xf002: /* fmul Rm,Rn */ +- gen_helper_fmul_DT(fp0, fp0, fp1); ++ gen_helper_fmul_DT(fp0, cpu_env, fp0, fp1); + break; + case 0xf003: /* fdiv Rm,Rn */ +- gen_helper_fdiv_DT(fp0, fp0, fp1); ++ gen_helper_fdiv_DT(fp0, cpu_env, fp0, fp1); + break; + case 0xf004: /* fcmp/eq Rm,Rn */ +- gen_helper_fcmp_eq_DT(fp0, fp1); ++ gen_helper_fcmp_eq_DT(cpu_env, fp0, fp1); + return; + case 0xf005: /* fcmp/gt Rm,Rn */ +- gen_helper_fcmp_gt_DT(fp0, fp1); ++ gen_helper_fcmp_gt_DT(cpu_env, fp0, fp1); + return; + } + gen_store_fpr64(fp0, DREG(B11_8)); +@@ -1176,22 +1176,32 @@ static void _decode_opc(DisasContext * ctx) + } else { + switch (ctx->opcode & 0xf00f) { + case 0xf000: /* fadd Rm,Rn */ +- gen_helper_fadd_FT(cpu_fregs[FREG(B11_8)], cpu_fregs[FREG(B11_8)], cpu_fregs[FREG(B7_4)]); ++ gen_helper_fadd_FT(cpu_fregs[FREG(B11_8)], cpu_env, ++ cpu_fregs[FREG(B11_8)], ++ cpu_fregs[FREG(B7_4)]); + break; + case 0xf001: /* fsub Rm,Rn */ +- gen_helper_fsub_FT(cpu_fregs[FREG(B11_8)], cpu_fregs[FREG(B11_8)], cpu_fregs[FREG(B7_4)]); ++ gen_helper_fsub_FT(cpu_fregs[FREG(B11_8)], cpu_env, ++ cpu_fregs[FREG(B11_8)], ++ cpu_fregs[FREG(B7_4)]); + break; + case 0xf002: /* fmul Rm,Rn */ +- gen_helper_fmul_FT(cpu_fregs[FREG(B11_8)], cpu_fregs[FREG(B11_8)], cpu_fregs[FREG(B7_4)]); ++ gen_helper_fmul_FT(cpu_fregs[FREG(B11_8)], cpu_env, ++ cpu_fregs[FREG(B11_8)], ++ cpu_fregs[FREG(B7_4)]); + break; + case 0xf003: /* fdiv Rm,Rn */ +- gen_helper_fdiv_FT(cpu_fregs[FREG(B11_8)], cpu_fregs[FREG(B11_8)], cpu_fregs[FREG(B7_4)]); ++ gen_helper_fdiv_FT(cpu_fregs[FREG(B11_8)], cpu_env, ++ cpu_fregs[FREG(B11_8)], ++ cpu_fregs[FREG(B7_4)]); + break; + case 0xf004: /* fcmp/eq Rm,Rn */ +- gen_helper_fcmp_eq_FT(cpu_fregs[FREG(B11_8)], cpu_fregs[FREG(B7_4)]); ++ gen_helper_fcmp_eq_FT(cpu_env, cpu_fregs[FREG(B11_8)], ++ cpu_fregs[FREG(B7_4)]); + return; + case 0xf005: /* fcmp/gt Rm,Rn */ +- gen_helper_fcmp_gt_FT(cpu_fregs[FREG(B11_8)], cpu_fregs[FREG(B7_4)]); ++ gen_helper_fcmp_gt_FT(cpu_env, cpu_fregs[FREG(B11_8)], ++ cpu_fregs[FREG(B7_4)]); + return; + } + } +@@ -1203,8 +1213,9 @@ static void _decode_opc(DisasContext * ctx) + if (ctx->fpscr & FPSCR_PR) { + break; /* illegal instruction */ + } else { +- gen_helper_fmac_FT(cpu_fregs[FREG(B11_8)], +- cpu_fregs[FREG(0)], cpu_fregs[FREG(B7_4)], cpu_fregs[FREG(B11_8)]); ++ gen_helper_fmac_FT(cpu_fregs[FREG(B11_8)], cpu_env, ++ cpu_fregs[FREG(0)], cpu_fregs[FREG(B7_4)], ++ cpu_fregs[FREG(B11_8)]); + return; + } + } +@@ -1356,7 +1367,7 @@ static void _decode_opc(DisasContext * ctx) + TCGv imm; + CHECK_NOT_DELAY_SLOT + imm = tcg_const_i32(B7_0); +- gen_helper_trapa(imm); ++ gen_helper_trapa(cpu_env, imm); + tcg_temp_free(imm); + ctx->bstate = BS_BRANCH; + } +@@ -1531,7 +1542,7 @@ static void _decode_opc(DisasContext * ctx) + LDST(fpul, 0x405a, 0x4056, 0x005a, 0x4052, {CHECK_FPU_ENABLED}) + case 0x406a: /* lds Rm,FPSCR */ + CHECK_FPU_ENABLED +- gen_helper_ld_fpscr(REG(B11_8)); ++ gen_helper_ld_fpscr(cpu_env, REG(B11_8)); + ctx->bstate = BS_STOP; + return; + case 0x4066: /* lds.l @Rm+,FPSCR */ +@@ -1540,7 +1551,7 @@ static void _decode_opc(DisasContext * ctx) + TCGv addr = tcg_temp_new(); + tcg_gen_qemu_ld32s(addr, REG(B11_8), ctx->memidx); + tcg_gen_addi_i32(REG(B11_8), REG(B11_8), 4); +- gen_helper_ld_fpscr(addr); ++ gen_helper_ld_fpscr(cpu_env, addr); + tcg_temp_free(addr); + ctx->bstate = BS_STOP; + } +@@ -1567,7 +1578,7 @@ static void _decode_opc(DisasContext * ctx) + { + TCGv val = tcg_temp_new(); + tcg_gen_qemu_ld32u(val, REG(B11_8), ctx->memidx); +- gen_helper_movcal (REG(B11_8), val); ++ gen_helper_movcal(cpu_env, REG(B11_8), val); + tcg_gen_qemu_st32(REG(0), REG(B11_8), ctx->memidx); + } + ctx->has_movcal = 1; +@@ -1619,7 +1630,7 @@ static void _decode_opc(DisasContext * ctx) + break; + case 0x0093: /* ocbi @Rn */ + { +- gen_helper_ocbi (REG(B11_8)); ++ gen_helper_ocbi(cpu_env, REG(B11_8)); + } + return; + case 0x00a3: /* ocbp @Rn */ +@@ -1733,12 +1744,12 @@ static void _decode_opc(DisasContext * ctx) + if (ctx->opcode & 0x0100) + break; /* illegal instruction */ + fp = tcg_temp_new_i64(); +- gen_helper_float_DT(fp, cpu_fpul); ++ gen_helper_float_DT(fp, cpu_env, cpu_fpul); + gen_store_fpr64(fp, DREG(B11_8)); + tcg_temp_free_i64(fp); + } + else { +- gen_helper_float_FT(cpu_fregs[FREG(B11_8)], cpu_fpul); ++ gen_helper_float_FT(cpu_fregs[FREG(B11_8)], cpu_env, cpu_fpul); + } + return; + case 0xf03d: /* ftrc FRm/DRm,FPUL - FPSCR: R[PR,Enable.V]/W[Cause,Flag] */ +@@ -1749,11 +1760,11 @@ static void _decode_opc(DisasContext * ctx) + break; /* illegal instruction */ + fp = tcg_temp_new_i64(); + gen_load_fpr64(fp, DREG(B11_8)); +- gen_helper_ftrc_DT(cpu_fpul, fp); ++ gen_helper_ftrc_DT(cpu_fpul, cpu_env, fp); + tcg_temp_free_i64(fp); + } + else { +- gen_helper_ftrc_FT(cpu_fpul, cpu_fregs[FREG(B11_8)]); ++ gen_helper_ftrc_FT(cpu_fpul, cpu_env, cpu_fregs[FREG(B11_8)]); + } + return; + case 0xf04d: /* fneg FRn/DRn - FPSCR: Nothing */ +@@ -1783,11 +1794,12 @@ static void _decode_opc(DisasContext * ctx) + break; /* illegal instruction */ + TCGv_i64 fp = tcg_temp_new_i64(); + gen_load_fpr64(fp, DREG(B11_8)); +- gen_helper_fsqrt_DT(fp, fp); ++ gen_helper_fsqrt_DT(fp, cpu_env, fp); + gen_store_fpr64(fp, DREG(B11_8)); + tcg_temp_free_i64(fp); + } else { +- gen_helper_fsqrt_FT(cpu_fregs[FREG(B11_8)], cpu_fregs[FREG(B11_8)]); ++ gen_helper_fsqrt_FT(cpu_fregs[FREG(B11_8)], cpu_env, ++ cpu_fregs[FREG(B11_8)]); + } + return; + case 0xf07d: /* fsrra FRn */ +@@ -1809,7 +1821,7 @@ static void _decode_opc(DisasContext * ctx) + CHECK_FPU_ENABLED + { + TCGv_i64 fp = tcg_temp_new_i64(); +- gen_helper_fcnvsd_FT_DT(fp, cpu_fpul); ++ gen_helper_fcnvsd_FT_DT(fp, cpu_env, cpu_fpul); + gen_store_fpr64(fp, DREG(B11_8)); + tcg_temp_free_i64(fp); + } +@@ -1819,7 +1831,7 @@ static void _decode_opc(DisasContext * ctx) + { + TCGv_i64 fp = tcg_temp_new_i64(); + gen_load_fpr64(fp, DREG(B11_8)); +- gen_helper_fcnvds_DT_FT(cpu_fpul, fp); ++ gen_helper_fcnvds_DT_FT(cpu_fpul, cpu_env, fp); + tcg_temp_free_i64(fp); + } + return; +@@ -1829,7 +1841,7 @@ static void _decode_opc(DisasContext * ctx) + TCGv m, n; + m = tcg_const_i32((ctx->opcode >> 8) & 3); + n = tcg_const_i32((ctx->opcode >> 10) & 3); +- gen_helper_fipr(m, n); ++ gen_helper_fipr(cpu_env, m, n); + tcg_temp_free(m); + tcg_temp_free(n); + return; +@@ -1841,7 +1853,7 @@ static void _decode_opc(DisasContext * ctx) + (ctx->fpscr & FPSCR_PR) == 0) { + TCGv n; + n = tcg_const_i32((ctx->opcode >> 10) & 3); +- gen_helper_ftrv(n); ++ gen_helper_ftrv(cpu_env, n); + tcg_temp_free(n); + return; + } +@@ -1853,9 +1865,9 @@ static void _decode_opc(DisasContext * ctx) + fflush(stderr); + #endif + if (ctx->flags & (DELAY_SLOT | DELAY_SLOT_CONDITIONAL)) { +- gen_helper_raise_slot_illegal_instruction(); ++ gen_helper_raise_slot_illegal_instruction(cpu_env); + } else { +- gen_helper_raise_illegal_instruction(); ++ gen_helper_raise_illegal_instruction(cpu_env); + } + ctx->bstate = BS_EXCP; + } +@@ -1934,7 +1946,7 @@ gen_intermediate_code_internal(CPUSH4State * env, TranslationBlock * tb, + if (ctx.pc == bp->pc) { + /* We have hit a breakpoint - make sure PC is up-to-date */ + tcg_gen_movi_i32(cpu_pc, ctx.pc); +- gen_helper_debug(); ++ gen_helper_debug(cpu_env); + ctx.bstate = BS_EXCP; + break; + } +@@ -1958,7 +1970,7 @@ gen_intermediate_code_internal(CPUSH4State * env, TranslationBlock * tb, + fprintf(stderr, "Loading opcode at address 0x%08x\n", ctx.pc); + fflush(stderr); + #endif +- ctx.opcode = lduw_code(ctx.pc); ++ ctx.opcode = cpu_lduw_code(env, ctx.pc); + decode_opc(&ctx); + num_insns++; + ctx.pc += 2; +@@ -1975,7 +1987,7 @@ gen_intermediate_code_internal(CPUSH4State * env, TranslationBlock * tb, + gen_io_end(); + if (env->singlestep_enabled) { + tcg_gen_movi_i32(cpu_pc, ctx.pc); +- gen_helper_debug(); ++ gen_helper_debug(cpu_env); + } else { + switch (ctx.bstate) { + case BS_STOP: +-- +1.7.12.1 + diff --git a/0038-target-mips-switch-to-AREG0-free-mode.patch b/0038-target-mips-switch-to-AREG0-free-mode.patch new file mode 100644 index 0000000..6c8ea5a --- /dev/null +++ b/0038-target-mips-switch-to-AREG0-free-mode.patch @@ -0,0 +1,6336 @@ +From 8ad14b12fbe7555da2b2f0f1f28e07b8a34b686c Mon Sep 17 00:00:00 2001 +From: Blue Swirl +Date: Sun, 2 Sep 2012 14:52:59 +0000 +Subject: [PATCH] target-mips: switch to AREG0 free mode + +Add an explicit CPUState parameter instead of relying on AREG0 +and switch to AREG0 free mode. + +Signed-off-by: Blue Swirl +Acked-by: Aurelien Jarno +Signed-off-by: Michael Roth +--- + configure | 2 +- + target-mips/Makefile.objs | 2 - + target-mips/cpu.h | 16 +- + target-mips/helper.h | 410 ++++++++--------- + target-mips/op_helper.c | 1065 ++++++++++++++++++++++++--------------------- + target-mips/translate.c | 754 ++++++++++++++++---------------- + 6 files changed, 1163 insertions(+), 1086 deletions(-) + +diff --git a/configure b/configure +index 03ce76e..83b068d 100755 +--- a/configure ++++ b/configure +@@ -3839,7 +3839,7 @@ symlink "$source_path/Makefile.target" "$target_dir/Makefile" + + + case "$target_arch2" in +- alpha | arm* | cris | i386 | lm32 | m68k | microblaze* | or32 | s390x | sh4* | sparc* | unicore32 | x86_64 | xtensa* | ppc*) ++ alpha | arm* | cris | i386 | lm32 | m68k | microblaze* | mips* | or32 | s390x | sh4* | sparc* | unicore32 | x86_64 | xtensa* | ppc*) + echo "CONFIG_TCG_PASS_AREG0=y" >> $config_target_mak + ;; + esac +diff --git a/target-mips/Makefile.objs b/target-mips/Makefile.objs +index 2e0e093..ca20f21 100644 +--- a/target-mips/Makefile.objs ++++ b/target-mips/Makefile.objs +@@ -1,4 +1,2 @@ + obj-y += translate.o op_helper.o helper.o cpu.o + obj-$(CONFIG_SOFTMMU) += machine.o +- +-$(obj)/op_helper.o: QEMU_CFLAGS += $(HELPER_CFLAGS) +diff --git a/target-mips/cpu.h b/target-mips/cpu.h +index ce3467f..be4f805 100644 +--- a/target-mips/cpu.h ++++ b/target-mips/cpu.h +@@ -38,10 +38,10 @@ struct CPUMIPSTLBContext { + uint32_t nb_tlb; + uint32_t tlb_in_use; + int (*map_address) (struct CPUMIPSState *env, target_phys_addr_t *physical, int *prot, target_ulong address, int rw, int access_type); +- void (*helper_tlbwi) (void); +- void (*helper_tlbwr) (void); +- void (*helper_tlbp) (void); +- void (*helper_tlbr) (void); ++ void (*helper_tlbwi)(struct CPUMIPSState *env); ++ void (*helper_tlbwr)(struct CPUMIPSState *env); ++ void (*helper_tlbp)(struct CPUMIPSState *env); ++ void (*helper_tlbr)(struct CPUMIPSState *env); + union { + struct { + r4k_tlb_t tlb[MIPS_TLB_MAX]; +@@ -485,10 +485,10 @@ int fixed_mmu_map_address (CPUMIPSState *env, target_phys_addr_t *physical, int + target_ulong address, int rw, int access_type); + int r4k_map_address (CPUMIPSState *env, target_phys_addr_t *physical, int *prot, + target_ulong address, int rw, int access_type); +-void r4k_helper_tlbwi (void); +-void r4k_helper_tlbwr (void); +-void r4k_helper_tlbp (void); +-void r4k_helper_tlbr (void); ++void r4k_helper_tlbwi(CPUMIPSState *env); ++void r4k_helper_tlbwr(CPUMIPSState *env); ++void r4k_helper_tlbp(CPUMIPSState *env); ++void r4k_helper_tlbr(CPUMIPSState *env); + + void cpu_unassigned_access(CPUMIPSState *env, target_phys_addr_t addr, + int is_write, int is_exec, int unused, int size); +diff --git a/target-mips/helper.h b/target-mips/helper.h +index 76fb451..109ac37 100644 +--- a/target-mips/helper.h ++++ b/target-mips/helper.h +@@ -1,25 +1,25 @@ + #include "def-helper.h" + +-DEF_HELPER_2(raise_exception_err, noreturn, i32, int) +-DEF_HELPER_1(raise_exception, noreturn, i32) ++DEF_HELPER_3(raise_exception_err, noreturn, env, i32, int) ++DEF_HELPER_2(raise_exception, noreturn, env, i32) + + #ifdef TARGET_MIPS64 +-DEF_HELPER_3(ldl, tl, tl, tl, int) +-DEF_HELPER_3(ldr, tl, tl, tl, int) +-DEF_HELPER_3(sdl, void, tl, tl, int) +-DEF_HELPER_3(sdr, void, tl, tl, int) ++DEF_HELPER_4(ldl, tl, env, tl, tl, int) ++DEF_HELPER_4(ldr, tl, env, tl, tl, int) ++DEF_HELPER_4(sdl, void, env, tl, tl, int) ++DEF_HELPER_4(sdr, void, env, tl, tl, int) + #endif +-DEF_HELPER_3(lwl, tl, tl, tl, int) +-DEF_HELPER_3(lwr, tl, tl, tl, int) +-DEF_HELPER_3(swl, void, tl, tl, int) +-DEF_HELPER_3(swr, void, tl, tl, int) ++DEF_HELPER_4(lwl, tl, env, tl, tl, int) ++DEF_HELPER_4(lwr, tl, env, tl, tl, int) ++DEF_HELPER_4(swl, void, env, tl, tl, int) ++DEF_HELPER_4(swr, void, env, tl, tl, int) + + #ifndef CONFIG_USER_ONLY +-DEF_HELPER_2(ll, tl, tl, int) +-DEF_HELPER_3(sc, tl, tl, tl, int) ++DEF_HELPER_3(ll, tl, env, tl, int) ++DEF_HELPER_4(sc, tl, env, tl, tl, int) + #ifdef TARGET_MIPS64 +-DEF_HELPER_2(lld, tl, tl, int) +-DEF_HELPER_3(scd, tl, tl, tl, int) ++DEF_HELPER_3(lld, tl, env, tl, int) ++DEF_HELPER_4(scd, tl, env, tl, tl, int) + #endif + #endif + +@@ -28,195 +28,195 @@ DEF_HELPER_FLAGS_1(clz, TCG_CALL_CONST | TCG_CALL_PURE, tl, tl) + #ifdef TARGET_MIPS64 + DEF_HELPER_FLAGS_1(dclo, TCG_CALL_CONST | TCG_CALL_PURE, tl, tl) + DEF_HELPER_FLAGS_1(dclz, TCG_CALL_CONST | TCG_CALL_PURE, tl, tl) +-DEF_HELPER_2(dmult, void, tl, tl) +-DEF_HELPER_2(dmultu, void, tl, tl) ++DEF_HELPER_3(dmult, void, env, tl, tl) ++DEF_HELPER_3(dmultu, void, env, tl, tl) + #endif + +-DEF_HELPER_2(muls, tl, tl, tl) +-DEF_HELPER_2(mulsu, tl, tl, tl) +-DEF_HELPER_2(macc, tl, tl, tl) +-DEF_HELPER_2(maccu, tl, tl, tl) +-DEF_HELPER_2(msac, tl, tl, tl) +-DEF_HELPER_2(msacu, tl, tl, tl) +-DEF_HELPER_2(mulhi, tl, tl, tl) +-DEF_HELPER_2(mulhiu, tl, tl, tl) +-DEF_HELPER_2(mulshi, tl, tl, tl) +-DEF_HELPER_2(mulshiu, tl, tl, tl) +-DEF_HELPER_2(macchi, tl, tl, tl) +-DEF_HELPER_2(macchiu, tl, tl, tl) +-DEF_HELPER_2(msachi, tl, tl, tl) +-DEF_HELPER_2(msachiu, tl, tl, tl) ++DEF_HELPER_3(muls, tl, env, tl, tl) ++DEF_HELPER_3(mulsu, tl, env, tl, tl) ++DEF_HELPER_3(macc, tl, env, tl, tl) ++DEF_HELPER_3(maccu, tl, env, tl, tl) ++DEF_HELPER_3(msac, tl, env, tl, tl) ++DEF_HELPER_3(msacu, tl, env, tl, tl) ++DEF_HELPER_3(mulhi, tl, env, tl, tl) ++DEF_HELPER_3(mulhiu, tl, env, tl, tl) ++DEF_HELPER_3(mulshi, tl, env, tl, tl) ++DEF_HELPER_3(mulshiu, tl, env, tl, tl) ++DEF_HELPER_3(macchi, tl, env, tl, tl) ++DEF_HELPER_3(macchiu, tl, env, tl, tl) ++DEF_HELPER_3(msachi, tl, env, tl, tl) ++DEF_HELPER_3(msachiu, tl, env, tl, tl) + + #ifndef CONFIG_USER_ONLY + /* CP0 helpers */ +-DEF_HELPER_0(mfc0_mvpcontrol, tl) +-DEF_HELPER_0(mfc0_mvpconf0, tl) +-DEF_HELPER_0(mfc0_mvpconf1, tl) +-DEF_HELPER_0(mftc0_vpecontrol, tl) +-DEF_HELPER_0(mftc0_vpeconf0, tl) +-DEF_HELPER_0(mfc0_random, tl) +-DEF_HELPER_0(mfc0_tcstatus, tl) +-DEF_HELPER_0(mftc0_tcstatus, tl) +-DEF_HELPER_0(mfc0_tcbind, tl) +-DEF_HELPER_0(mftc0_tcbind, tl) +-DEF_HELPER_0(mfc0_tcrestart, tl) +-DEF_HELPER_0(mftc0_tcrestart, tl) +-DEF_HELPER_0(mfc0_tchalt, tl) +-DEF_HELPER_0(mftc0_tchalt, tl) +-DEF_HELPER_0(mfc0_tccontext, tl) +-DEF_HELPER_0(mftc0_tccontext, tl) +-DEF_HELPER_0(mfc0_tcschedule, tl) +-DEF_HELPER_0(mftc0_tcschedule, tl) +-DEF_HELPER_0(mfc0_tcschefback, tl) +-DEF_HELPER_0(mftc0_tcschefback, tl) +-DEF_HELPER_0(mfc0_count, tl) +-DEF_HELPER_0(mftc0_entryhi, tl) +-DEF_HELPER_0(mftc0_status, tl) +-DEF_HELPER_0(mftc0_cause, tl) +-DEF_HELPER_0(mftc0_epc, tl) +-DEF_HELPER_0(mftc0_ebase, tl) +-DEF_HELPER_1(mftc0_configx, tl, tl) +-DEF_HELPER_0(mfc0_lladdr, tl) +-DEF_HELPER_1(mfc0_watchlo, tl, i32) +-DEF_HELPER_1(mfc0_watchhi, tl, i32) +-DEF_HELPER_0(mfc0_debug, tl) +-DEF_HELPER_0(mftc0_debug, tl) ++DEF_HELPER_1(mfc0_mvpcontrol, tl, env) ++DEF_HELPER_1(mfc0_mvpconf0, tl, env) ++DEF_HELPER_1(mfc0_mvpconf1, tl, env) ++DEF_HELPER_1(mftc0_vpecontrol, tl, env) ++DEF_HELPER_1(mftc0_vpeconf0, tl, env) ++DEF_HELPER_1(mfc0_random, tl, env) ++DEF_HELPER_1(mfc0_tcstatus, tl, env) ++DEF_HELPER_1(mftc0_tcstatus, tl, env) ++DEF_HELPER_1(mfc0_tcbind, tl, env) ++DEF_HELPER_1(mftc0_tcbind, tl, env) ++DEF_HELPER_1(mfc0_tcrestart, tl, env) ++DEF_HELPER_1(mftc0_tcrestart, tl, env) ++DEF_HELPER_1(mfc0_tchalt, tl, env) ++DEF_HELPER_1(mftc0_tchalt, tl, env) ++DEF_HELPER_1(mfc0_tccontext, tl, env) ++DEF_HELPER_1(mftc0_tccontext, tl, env) ++DEF_HELPER_1(mfc0_tcschedule, tl, env) ++DEF_HELPER_1(mftc0_tcschedule, tl, env) ++DEF_HELPER_1(mfc0_tcschefback, tl, env) ++DEF_HELPER_1(mftc0_tcschefback, tl, env) ++DEF_HELPER_1(mfc0_count, tl, env) ++DEF_HELPER_1(mftc0_entryhi, tl, env) ++DEF_HELPER_1(mftc0_status, tl, env) ++DEF_HELPER_1(mftc0_cause, tl, env) ++DEF_HELPER_1(mftc0_epc, tl, env) ++DEF_HELPER_1(mftc0_ebase, tl, env) ++DEF_HELPER_2(mftc0_configx, tl, env, tl) ++DEF_HELPER_1(mfc0_lladdr, tl, env) ++DEF_HELPER_2(mfc0_watchlo, tl, env, i32) ++DEF_HELPER_2(mfc0_watchhi, tl, env, i32) ++DEF_HELPER_1(mfc0_debug, tl, env) ++DEF_HELPER_1(mftc0_debug, tl, env) + #ifdef TARGET_MIPS64 +-DEF_HELPER_0(dmfc0_tcrestart, tl) +-DEF_HELPER_0(dmfc0_tchalt, tl) +-DEF_HELPER_0(dmfc0_tccontext, tl) +-DEF_HELPER_0(dmfc0_tcschedule, tl) +-DEF_HELPER_0(dmfc0_tcschefback, tl) +-DEF_HELPER_0(dmfc0_lladdr, tl) +-DEF_HELPER_1(dmfc0_watchlo, tl, i32) ++DEF_HELPER_1(dmfc0_tcrestart, tl, env) ++DEF_HELPER_1(dmfc0_tchalt, tl, env) ++DEF_HELPER_1(dmfc0_tccontext, tl, env) ++DEF_HELPER_1(dmfc0_tcschedule, tl, env) ++DEF_HELPER_1(dmfc0_tcschefback, tl, env) ++DEF_HELPER_1(dmfc0_lladdr, tl, env) ++DEF_HELPER_2(dmfc0_watchlo, tl, env, i32) + #endif /* TARGET_MIPS64 */ + +-DEF_HELPER_1(mtc0_index, void, tl) +-DEF_HELPER_1(mtc0_mvpcontrol, void, tl) +-DEF_HELPER_1(mtc0_vpecontrol, void, tl) +-DEF_HELPER_1(mttc0_vpecontrol, void, tl) +-DEF_HELPER_1(mtc0_vpeconf0, void, tl) +-DEF_HELPER_1(mttc0_vpeconf0, void, tl) +-DEF_HELPER_1(mtc0_vpeconf1, void, tl) +-DEF_HELPER_1(mtc0_yqmask, void, tl) +-DEF_HELPER_1(mtc0_vpeopt, void, tl) +-DEF_HELPER_1(mtc0_entrylo0, void, tl) +-DEF_HELPER_1(mtc0_tcstatus, void, tl) +-DEF_HELPER_1(mttc0_tcstatus, void, tl) +-DEF_HELPER_1(mtc0_tcbind, void, tl) +-DEF_HELPER_1(mttc0_tcbind, void, tl) +-DEF_HELPER_1(mtc0_tcrestart, void, tl) +-DEF_HELPER_1(mttc0_tcrestart, void, tl) +-DEF_HELPER_1(mtc0_tchalt, void, tl) +-DEF_HELPER_1(mttc0_tchalt, void, tl) +-DEF_HELPER_1(mtc0_tccontext, void, tl) +-DEF_HELPER_1(mttc0_tccontext, void, tl) +-DEF_HELPER_1(mtc0_tcschedule, void, tl) +-DEF_HELPER_1(mttc0_tcschedule, void, tl) +-DEF_HELPER_1(mtc0_tcschefback, void, tl) +-DEF_HELPER_1(mttc0_tcschefback, void, tl) +-DEF_HELPER_1(mtc0_entrylo1, void, tl) +-DEF_HELPER_1(mtc0_context, void, tl) +-DEF_HELPER_1(mtc0_pagemask, void, tl) +-DEF_HELPER_1(mtc0_pagegrain, void, tl) +-DEF_HELPER_1(mtc0_wired, void, tl) +-DEF_HELPER_1(mtc0_srsconf0, void, tl) +-DEF_HELPER_1(mtc0_srsconf1, void, tl) +-DEF_HELPER_1(mtc0_srsconf2, void, tl) +-DEF_HELPER_1(mtc0_srsconf3, void, tl) +-DEF_HELPER_1(mtc0_srsconf4, void, tl) +-DEF_HELPER_1(mtc0_hwrena, void, tl) +-DEF_HELPER_1(mtc0_count, void, tl) +-DEF_HELPER_1(mtc0_entryhi, void, tl) +-DEF_HELPER_1(mttc0_entryhi, void, tl) +-DEF_HELPER_1(mtc0_compare, void, tl) +-DEF_HELPER_1(mtc0_status, void, tl) +-DEF_HELPER_1(mttc0_status, void, tl) +-DEF_HELPER_1(mtc0_intctl, void, tl) +-DEF_HELPER_1(mtc0_srsctl, void, tl) +-DEF_HELPER_1(mtc0_cause, void, tl) +-DEF_HELPER_1(mttc0_cause, void, tl) +-DEF_HELPER_1(mtc0_ebase, void, tl) +-DEF_HELPER_1(mttc0_ebase, void, tl) +-DEF_HELPER_1(mtc0_config0, void, tl) +-DEF_HELPER_1(mtc0_config2, void, tl) +-DEF_HELPER_1(mtc0_lladdr, void, tl) +-DEF_HELPER_2(mtc0_watchlo, void, tl, i32) +-DEF_HELPER_2(mtc0_watchhi, void, tl, i32) +-DEF_HELPER_1(mtc0_xcontext, void, tl) +-DEF_HELPER_1(mtc0_framemask, void, tl) +-DEF_HELPER_1(mtc0_debug, void, tl) +-DEF_HELPER_1(mttc0_debug, void, tl) +-DEF_HELPER_1(mtc0_performance0, void, tl) +-DEF_HELPER_1(mtc0_taglo, void, tl) +-DEF_HELPER_1(mtc0_datalo, void, tl) +-DEF_HELPER_1(mtc0_taghi, void, tl) +-DEF_HELPER_1(mtc0_datahi, void, tl) ++DEF_HELPER_2(mtc0_index, void, env, tl) ++DEF_HELPER_2(mtc0_mvpcontrol, void, env, tl) ++DEF_HELPER_2(mtc0_vpecontrol, void, env, tl) ++DEF_HELPER_2(mttc0_vpecontrol, void, env, tl) ++DEF_HELPER_2(mtc0_vpeconf0, void, env, tl) ++DEF_HELPER_2(mttc0_vpeconf0, void, env, tl) ++DEF_HELPER_2(mtc0_vpeconf1, void, env, tl) ++DEF_HELPER_2(mtc0_yqmask, void, env, tl) ++DEF_HELPER_2(mtc0_vpeopt, void, env, tl) ++DEF_HELPER_2(mtc0_entrylo0, void, env, tl) ++DEF_HELPER_2(mtc0_tcstatus, void, env, tl) ++DEF_HELPER_2(mttc0_tcstatus, void, env, tl) ++DEF_HELPER_2(mtc0_tcbind, void, env, tl) ++DEF_HELPER_2(mttc0_tcbind, void, env, tl) ++DEF_HELPER_2(mtc0_tcrestart, void, env, tl) ++DEF_HELPER_2(mttc0_tcrestart, void, env, tl) ++DEF_HELPER_2(mtc0_tchalt, void, env, tl) ++DEF_HELPER_2(mttc0_tchalt, void, env, tl) ++DEF_HELPER_2(mtc0_tccontext, void, env, tl) ++DEF_HELPER_2(mttc0_tccontext, void, env, tl) ++DEF_HELPER_2(mtc0_tcschedule, void, env, tl) ++DEF_HELPER_2(mttc0_tcschedule, void, env, tl) ++DEF_HELPER_2(mtc0_tcschefback, void, env, tl) ++DEF_HELPER_2(mttc0_tcschefback, void, env, tl) ++DEF_HELPER_2(mtc0_entrylo1, void, env, tl) ++DEF_HELPER_2(mtc0_context, void, env, tl) ++DEF_HELPER_2(mtc0_pagemask, void, env, tl) ++DEF_HELPER_2(mtc0_pagegrain, void, env, tl) ++DEF_HELPER_2(mtc0_wired, void, env, tl) ++DEF_HELPER_2(mtc0_srsconf0, void, env, tl) ++DEF_HELPER_2(mtc0_srsconf1, void, env, tl) ++DEF_HELPER_2(mtc0_srsconf2, void, env, tl) ++DEF_HELPER_2(mtc0_srsconf3, void, env, tl) ++DEF_HELPER_2(mtc0_srsconf4, void, env, tl) ++DEF_HELPER_2(mtc0_hwrena, void, env, tl) ++DEF_HELPER_2(mtc0_count, void, env, tl) ++DEF_HELPER_2(mtc0_entryhi, void, env, tl) ++DEF_HELPER_2(mttc0_entryhi, void, env, tl) ++DEF_HELPER_2(mtc0_compare, void, env, tl) ++DEF_HELPER_2(mtc0_status, void, env, tl) ++DEF_HELPER_2(mttc0_status, void, env, tl) ++DEF_HELPER_2(mtc0_intctl, void, env, tl) ++DEF_HELPER_2(mtc0_srsctl, void, env, tl) ++DEF_HELPER_2(mtc0_cause, void, env, tl) ++DEF_HELPER_2(mttc0_cause, void, env, tl) ++DEF_HELPER_2(mtc0_ebase, void, env, tl) ++DEF_HELPER_2(mttc0_ebase, void, env, tl) ++DEF_HELPER_2(mtc0_config0, void, env, tl) ++DEF_HELPER_2(mtc0_config2, void, env, tl) ++DEF_HELPER_2(mtc0_lladdr, void, env, tl) ++DEF_HELPER_3(mtc0_watchlo, void, env, tl, i32) ++DEF_HELPER_3(mtc0_watchhi, void, env, tl, i32) ++DEF_HELPER_2(mtc0_xcontext, void, env, tl) ++DEF_HELPER_2(mtc0_framemask, void, env, tl) ++DEF_HELPER_2(mtc0_debug, void, env, tl) ++DEF_HELPER_2(mttc0_debug, void, env, tl) ++DEF_HELPER_2(mtc0_performance0, void, env, tl) ++DEF_HELPER_2(mtc0_taglo, void, env, tl) ++DEF_HELPER_2(mtc0_datalo, void, env, tl) ++DEF_HELPER_2(mtc0_taghi, void, env, tl) ++DEF_HELPER_2(mtc0_datahi, void, env, tl) + + /* MIPS MT functions */ +-DEF_HELPER_1(mftgpr, tl, i32); +-DEF_HELPER_1(mftlo, tl, i32) +-DEF_HELPER_1(mfthi, tl, i32) +-DEF_HELPER_1(mftacx, tl, i32) +-DEF_HELPER_0(mftdsp, tl) +-DEF_HELPER_2(mttgpr, void, tl, i32) +-DEF_HELPER_2(mttlo, void, tl, i32) +-DEF_HELPER_2(mtthi, void, tl, i32) +-DEF_HELPER_2(mttacx, void, tl, i32) +-DEF_HELPER_1(mttdsp, void, tl) ++DEF_HELPER_2(mftgpr, tl, env, i32); ++DEF_HELPER_2(mftlo, tl, env, i32) ++DEF_HELPER_2(mfthi, tl, env, i32) ++DEF_HELPER_2(mftacx, tl, env, i32) ++DEF_HELPER_1(mftdsp, tl, env) ++DEF_HELPER_3(mttgpr, void, env, tl, i32) ++DEF_HELPER_3(mttlo, void, env, tl, i32) ++DEF_HELPER_3(mtthi, void, env, tl, i32) ++DEF_HELPER_3(mttacx, void, env, tl, i32) ++DEF_HELPER_2(mttdsp, void, env, tl) + DEF_HELPER_0(dmt, tl) + DEF_HELPER_0(emt, tl) +-DEF_HELPER_0(dvpe, tl) +-DEF_HELPER_0(evpe, tl) ++DEF_HELPER_1(dvpe, tl, env) ++DEF_HELPER_1(evpe, tl, env) + #endif /* !CONFIG_USER_ONLY */ + + /* microMIPS functions */ +-DEF_HELPER_3(lwm, void, tl, tl, i32); +-DEF_HELPER_3(swm, void, tl, tl, i32); ++DEF_HELPER_4(lwm, void, env, tl, tl, i32); ++DEF_HELPER_4(swm, void, env, tl, tl, i32); + #ifdef TARGET_MIPS64 +-DEF_HELPER_3(ldm, void, tl, tl, i32); +-DEF_HELPER_3(sdm, void, tl, tl, i32); ++DEF_HELPER_4(ldm, void, env, tl, tl, i32); ++DEF_HELPER_4(sdm, void, env, tl, tl, i32); + #endif + + DEF_HELPER_2(fork, void, tl, tl) +-DEF_HELPER_1(yield, tl, tl) ++DEF_HELPER_2(yield, tl, env, tl) + + /* CP1 functions */ +-DEF_HELPER_1(cfc1, tl, i32) +-DEF_HELPER_2(ctc1, void, tl, i32) ++DEF_HELPER_2(cfc1, tl, env, i32) ++DEF_HELPER_3(ctc1, void, env, tl, i32) + +-DEF_HELPER_1(float_cvtd_s, i64, i32) +-DEF_HELPER_1(float_cvtd_w, i64, i32) +-DEF_HELPER_1(float_cvtd_l, i64, i64) +-DEF_HELPER_1(float_cvtl_d, i64, i64) +-DEF_HELPER_1(float_cvtl_s, i64, i32) +-DEF_HELPER_1(float_cvtps_pw, i64, i64) +-DEF_HELPER_1(float_cvtpw_ps, i64, i64) +-DEF_HELPER_1(float_cvts_d, i32, i64) +-DEF_HELPER_1(float_cvts_w, i32, i32) +-DEF_HELPER_1(float_cvts_l, i32, i64) +-DEF_HELPER_1(float_cvts_pl, i32, i32) +-DEF_HELPER_1(float_cvts_pu, i32, i32) +-DEF_HELPER_1(float_cvtw_s, i32, i32) +-DEF_HELPER_1(float_cvtw_d, i32, i64) ++DEF_HELPER_2(float_cvtd_s, i64, env, i32) ++DEF_HELPER_2(float_cvtd_w, i64, env, i32) ++DEF_HELPER_2(float_cvtd_l, i64, env, i64) ++DEF_HELPER_2(float_cvtl_d, i64, env, i64) ++DEF_HELPER_2(float_cvtl_s, i64, env, i32) ++DEF_HELPER_2(float_cvtps_pw, i64, env, i64) ++DEF_HELPER_2(float_cvtpw_ps, i64, env, i64) ++DEF_HELPER_2(float_cvts_d, i32, env, i64) ++DEF_HELPER_2(float_cvts_w, i32, env, i32) ++DEF_HELPER_2(float_cvts_l, i32, env, i64) ++DEF_HELPER_2(float_cvts_pl, i32, env, i32) ++DEF_HELPER_2(float_cvts_pu, i32, env, i32) ++DEF_HELPER_2(float_cvtw_s, i32, env, i32) ++DEF_HELPER_2(float_cvtw_d, i32, env, i64) + +-DEF_HELPER_2(float_addr_ps, i64, i64, i64) +-DEF_HELPER_2(float_mulr_ps, i64, i64, i64) ++DEF_HELPER_3(float_addr_ps, i64, env, i64, i64) ++DEF_HELPER_3(float_mulr_ps, i64, env, i64, i64) + +-#define FOP_PROTO(op) \ +-DEF_HELPER_1(float_ ## op ## l_s, i64, i32) \ +-DEF_HELPER_1(float_ ## op ## l_d, i64, i64) \ +-DEF_HELPER_1(float_ ## op ## w_s, i32, i32) \ +-DEF_HELPER_1(float_ ## op ## w_d, i32, i64) ++#define FOP_PROTO(op) \ ++DEF_HELPER_2(float_ ## op ## l_s, i64, env, i32) \ ++DEF_HELPER_2(float_ ## op ## l_d, i64, env, i64) \ ++DEF_HELPER_2(float_ ## op ## w_s, i32, env, i32) \ ++DEF_HELPER_2(float_ ## op ## w_d, i32, env, i64) + FOP_PROTO(round) + FOP_PROTO(trunc) + FOP_PROTO(ceil) + FOP_PROTO(floor) + #undef FOP_PROTO + +-#define FOP_PROTO(op) \ +-DEF_HELPER_1(float_ ## op ## _s, i32, i32) \ +-DEF_HELPER_1(float_ ## op ## _d, i64, i64) ++#define FOP_PROTO(op) \ ++DEF_HELPER_2(float_ ## op ## _s, i32, env, i32) \ ++DEF_HELPER_2(float_ ## op ## _d, i64, env, i64) + FOP_PROTO(sqrt) + FOP_PROTO(rsqrt) + FOP_PROTO(recip) +@@ -228,14 +228,20 @@ DEF_HELPER_1(float_ ## op ## _d, i64, i64) \ + DEF_HELPER_1(float_ ## op ## _ps, i64, i64) + FOP_PROTO(abs) + FOP_PROTO(chs) ++#undef FOP_PROTO ++ ++#define FOP_PROTO(op) \ ++DEF_HELPER_2(float_ ## op ## _s, i32, env, i32) \ ++DEF_HELPER_2(float_ ## op ## _d, i64, env, i64) \ ++DEF_HELPER_2(float_ ## op ## _ps, i64, env, i64) + FOP_PROTO(recip1) + FOP_PROTO(rsqrt1) + #undef FOP_PROTO + +-#define FOP_PROTO(op) \ +-DEF_HELPER_2(float_ ## op ## _s, i32, i32, i32) \ +-DEF_HELPER_2(float_ ## op ## _d, i64, i64, i64) \ +-DEF_HELPER_2(float_ ## op ## _ps, i64, i64, i64) ++#define FOP_PROTO(op) \ ++DEF_HELPER_3(float_ ## op ## _s, i32, env, i32, i32) \ ++DEF_HELPER_3(float_ ## op ## _d, i64, env, i64, i64) \ ++DEF_HELPER_3(float_ ## op ## _ps, i64, env, i64, i64) + FOP_PROTO(add) + FOP_PROTO(sub) + FOP_PROTO(mul) +@@ -244,23 +250,23 @@ FOP_PROTO(recip2) + FOP_PROTO(rsqrt2) + #undef FOP_PROTO + +-#define FOP_PROTO(op) \ +-DEF_HELPER_3(float_ ## op ## _s, i32, i32, i32, i32) \ +-DEF_HELPER_3(float_ ## op ## _d, i64, i64, i64, i64) \ +-DEF_HELPER_3(float_ ## op ## _ps, i64, i64, i64, i64) ++#define FOP_PROTO(op) \ ++DEF_HELPER_4(float_ ## op ## _s, i32, env, i32, i32, i32) \ ++DEF_HELPER_4(float_ ## op ## _d, i64, env, i64, i64, i64) \ ++DEF_HELPER_4(float_ ## op ## _ps, i64, env, i64, i64, i64) + FOP_PROTO(muladd) + FOP_PROTO(mulsub) + FOP_PROTO(nmuladd) + FOP_PROTO(nmulsub) + #undef FOP_PROTO + +-#define FOP_PROTO(op) \ +-DEF_HELPER_3(cmp_d_ ## op, void, i64, i64, int) \ +-DEF_HELPER_3(cmpabs_d_ ## op, void, i64, i64, int) \ +-DEF_HELPER_3(cmp_s_ ## op, void, i32, i32, int) \ +-DEF_HELPER_3(cmpabs_s_ ## op, void, i32, i32, int) \ +-DEF_HELPER_3(cmp_ps_ ## op, void, i64, i64, int) \ +-DEF_HELPER_3(cmpabs_ps_ ## op, void, i64, i64, int) ++#define FOP_PROTO(op) \ ++DEF_HELPER_4(cmp_d_ ## op, void, env, i64, i64, int) \ ++DEF_HELPER_4(cmpabs_d_ ## op, void, env, i64, i64, int) \ ++DEF_HELPER_4(cmp_s_ ## op, void, env, i32, i32, int) \ ++DEF_HELPER_4(cmpabs_s_ ## op, void, env, i32, i32, int) \ ++DEF_HELPER_4(cmp_ps_ ## op, void, env, i64, i64, int) \ ++DEF_HELPER_4(cmpabs_ps_ ## op, void, env, i64, i64, int) + FOP_PROTO(f) + FOP_PROTO(un) + FOP_PROTO(eq) +@@ -281,20 +287,20 @@ FOP_PROTO(ngt) + + /* Special functions */ + #ifndef CONFIG_USER_ONLY +-DEF_HELPER_0(tlbwi, void) +-DEF_HELPER_0(tlbwr, void) +-DEF_HELPER_0(tlbp, void) +-DEF_HELPER_0(tlbr, void) +-DEF_HELPER_0(di, tl) +-DEF_HELPER_0(ei, tl) +-DEF_HELPER_0(eret, void) +-DEF_HELPER_0(deret, void) ++DEF_HELPER_1(tlbwi, void, env) ++DEF_HELPER_1(tlbwr, void, env) ++DEF_HELPER_1(tlbp, void, env) ++DEF_HELPER_1(tlbr, void, env) ++DEF_HELPER_1(di, tl, env) ++DEF_HELPER_1(ei, tl, env) ++DEF_HELPER_1(eret, void, env) ++DEF_HELPER_1(deret, void, env) + #endif /* !CONFIG_USER_ONLY */ +-DEF_HELPER_0(rdhwr_cpunum, tl) +-DEF_HELPER_0(rdhwr_synci_step, tl) +-DEF_HELPER_0(rdhwr_cc, tl) +-DEF_HELPER_0(rdhwr_ccres, tl) +-DEF_HELPER_1(pmon, void, int) +-DEF_HELPER_0(wait, void) ++DEF_HELPER_1(rdhwr_cpunum, tl, env) ++DEF_HELPER_1(rdhwr_synci_step, tl, env) ++DEF_HELPER_1(rdhwr_cc, tl, env) ++DEF_HELPER_1(rdhwr_ccres, tl, env) ++DEF_HELPER_2(pmon, void, env, int) ++DEF_HELPER_1(wait, void, env) + + #include "def-helper.h" +diff --git a/target-mips/op_helper.c b/target-mips/op_helper.c +index e5bc93e..d2a8a55 100644 +--- a/target-mips/op_helper.c ++++ b/target-mips/op_helper.c +@@ -18,8 +18,6 @@ + */ + #include + #include "cpu.h" +-#include "dyngen-exec.h" +- + #include "host-utils.h" + + #include "helper.h" +@@ -84,7 +82,8 @@ static inline void compute_hflags(CPUMIPSState *env) + /*****************************************************************************/ + /* Exceptions processing helpers */ + +-void helper_raise_exception_err (uint32_t exception, int error_code) ++void helper_raise_exception_err(CPUMIPSState *env, uint32_t exception, ++ int error_code) + { + #if 1 + if (exception < 0x100) +@@ -95,13 +94,13 @@ void helper_raise_exception_err (uint32_t exception, int error_code) + cpu_loop_exit(env); + } + +-void helper_raise_exception (uint32_t exception) ++void helper_raise_exception(CPUMIPSState *env, uint32_t exception) + { +- helper_raise_exception_err(exception, 0); ++ helper_raise_exception_err(env, exception, 0); + } + + #if !defined(CONFIG_USER_ONLY) +-static void do_restore_state(uintptr_t pc) ++static void do_restore_state(CPUMIPSState *env, uintptr_t pc) + { + TranslationBlock *tb; + +@@ -114,20 +113,22 @@ static void do_restore_state(uintptr_t pc) + + #if defined(CONFIG_USER_ONLY) + #define HELPER_LD(name, insn, type) \ +-static inline type do_##name(target_ulong addr, int mem_idx) \ ++static inline type do_##name(CPUMIPSState *env, target_ulong addr, \ ++ int mem_idx) \ + { \ + return (type) insn##_raw(addr); \ + } + #else + #define HELPER_LD(name, insn, type) \ +-static inline type do_##name(target_ulong addr, int mem_idx) \ ++static inline type do_##name(CPUMIPSState *env, target_ulong addr, \ ++ int mem_idx) \ + { \ + switch (mem_idx) \ + { \ +- case 0: return (type) insn##_kernel(addr); break; \ +- case 1: return (type) insn##_super(addr); break; \ ++ case 0: return (type) cpu_##insn##_kernel(env, addr); break; \ ++ case 1: return (type) cpu_##insn##_super(env, addr); break; \ + default: \ +- case 2: return (type) insn##_user(addr); break; \ ++ case 2: return (type) cpu_##insn##_user(env, addr); break; \ + } \ + } + #endif +@@ -140,20 +141,22 @@ HELPER_LD(ld, ldq, int64_t) + + #if defined(CONFIG_USER_ONLY) + #define HELPER_ST(name, insn, type) \ +-static inline void do_##name(target_ulong addr, type val, int mem_idx) \ ++static inline void do_##name(CPUMIPSState *env, target_ulong addr, \ ++ type val, int mem_idx) \ + { \ + insn##_raw(addr, val); \ + } + #else + #define HELPER_ST(name, insn, type) \ +-static inline void do_##name(target_ulong addr, type val, int mem_idx) \ ++static inline void do_##name(CPUMIPSState *env, target_ulong addr, \ ++ type val, int mem_idx) \ + { \ + switch (mem_idx) \ + { \ +- case 0: insn##_kernel(addr, val); break; \ +- case 1: insn##_super(addr, val); break; \ ++ case 0: cpu_##insn##_kernel(env, addr, val); break; \ ++ case 1: cpu_##insn##_super(env, addr, val); break; \ + default: \ +- case 2: insn##_user(addr, val); break; \ ++ case 2: cpu_##insn##_user(env, addr, val); break; \ + } \ + } + #endif +@@ -187,12 +190,12 @@ target_ulong helper_dclz (target_ulong arg1) + #endif /* TARGET_MIPS64 */ + + /* 64 bits arithmetic for 32 bits hosts */ +-static inline uint64_t get_HILO (void) ++static inline uint64_t get_HILO(CPUMIPSState *env) + { + return ((uint64_t)(env->active_tc.HI[0]) << 32) | (uint32_t)env->active_tc.LO[0]; + } + +-static inline target_ulong set_HIT0_LO(uint64_t HILO) ++static inline target_ulong set_HIT0_LO(CPUMIPSState *env, uint64_t HILO) + { + target_ulong tmp; + env->active_tc.LO[0] = (int32_t)(HILO & 0xFFFFFFFF); +@@ -200,7 +203,7 @@ static inline target_ulong set_HIT0_LO(uint64_t HILO) + return tmp; + } + +-static inline target_ulong set_HI_LOT0(uint64_t HILO) ++static inline target_ulong set_HI_LOT0(CPUMIPSState *env, uint64_t HILO) + { + target_ulong tmp = env->active_tc.LO[0] = (int32_t)(HILO & 0xFFFFFFFF); + env->active_tc.HI[0] = (int32_t)(HILO >> 32); +@@ -208,91 +211,110 @@ static inline target_ulong set_HI_LOT0(uint64_t HILO) + } + + /* Multiplication variants of the vr54xx. */ +-target_ulong helper_muls (target_ulong arg1, target_ulong arg2) ++target_ulong helper_muls(CPUMIPSState *env, target_ulong arg1, ++ target_ulong arg2) + { +- return set_HI_LOT0(0 - ((int64_t)(int32_t)arg1 * (int64_t)(int32_t)arg2)); ++ return set_HI_LOT0(env, 0 - ((int64_t)(int32_t)arg1 * ++ (int64_t)(int32_t)arg2)); + } + +-target_ulong helper_mulsu (target_ulong arg1, target_ulong arg2) ++target_ulong helper_mulsu(CPUMIPSState *env, target_ulong arg1, ++ target_ulong arg2) + { +- return set_HI_LOT0(0 - (uint64_t)(uint32_t)arg1 * (uint64_t)(uint32_t)arg2); ++ return set_HI_LOT0(env, 0 - (uint64_t)(uint32_t)arg1 * ++ (uint64_t)(uint32_t)arg2); + } + +-target_ulong helper_macc (target_ulong arg1, target_ulong arg2) ++target_ulong helper_macc(CPUMIPSState *env, target_ulong arg1, ++ target_ulong arg2) + { +- return set_HI_LOT0((int64_t)get_HILO() + (int64_t)(int32_t)arg1 * +- (int64_t)(int32_t)arg2); ++ return set_HI_LOT0(env, (int64_t)get_HILO(env) + (int64_t)(int32_t)arg1 * ++ (int64_t)(int32_t)arg2); + } + +-target_ulong helper_macchi (target_ulong arg1, target_ulong arg2) ++target_ulong helper_macchi(CPUMIPSState *env, target_ulong arg1, ++ target_ulong arg2) + { +- return set_HIT0_LO((int64_t)get_HILO() + (int64_t)(int32_t)arg1 * +- (int64_t)(int32_t)arg2); ++ return set_HIT0_LO(env, (int64_t)get_HILO(env) + (int64_t)(int32_t)arg1 * ++ (int64_t)(int32_t)arg2); + } + +-target_ulong helper_maccu (target_ulong arg1, target_ulong arg2) ++target_ulong helper_maccu(CPUMIPSState *env, target_ulong arg1, ++ target_ulong arg2) + { +- return set_HI_LOT0((uint64_t)get_HILO() + (uint64_t)(uint32_t)arg1 * +- (uint64_t)(uint32_t)arg2); ++ return set_HI_LOT0(env, (uint64_t)get_HILO(env) + ++ (uint64_t)(uint32_t)arg1 * (uint64_t)(uint32_t)arg2); + } + +-target_ulong helper_macchiu (target_ulong arg1, target_ulong arg2) ++target_ulong helper_macchiu(CPUMIPSState *env, target_ulong arg1, ++ target_ulong arg2) + { +- return set_HIT0_LO((uint64_t)get_HILO() + (uint64_t)(uint32_t)arg1 * +- (uint64_t)(uint32_t)arg2); ++ return set_HIT0_LO(env, (uint64_t)get_HILO(env) + ++ (uint64_t)(uint32_t)arg1 * (uint64_t)(uint32_t)arg2); + } + +-target_ulong helper_msac (target_ulong arg1, target_ulong arg2) ++target_ulong helper_msac(CPUMIPSState *env, target_ulong arg1, ++ target_ulong arg2) + { +- return set_HI_LOT0((int64_t)get_HILO() - (int64_t)(int32_t)arg1 * +- (int64_t)(int32_t)arg2); ++ return set_HI_LOT0(env, (int64_t)get_HILO(env) - (int64_t)(int32_t)arg1 * ++ (int64_t)(int32_t)arg2); + } + +-target_ulong helper_msachi (target_ulong arg1, target_ulong arg2) ++target_ulong helper_msachi(CPUMIPSState *env, target_ulong arg1, ++ target_ulong arg2) + { +- return set_HIT0_LO((int64_t)get_HILO() - (int64_t)(int32_t)arg1 * +- (int64_t)(int32_t)arg2); ++ return set_HIT0_LO(env, (int64_t)get_HILO(env) - (int64_t)(int32_t)arg1 * ++ (int64_t)(int32_t)arg2); + } + +-target_ulong helper_msacu (target_ulong arg1, target_ulong arg2) ++target_ulong helper_msacu(CPUMIPSState *env, target_ulong arg1, ++ target_ulong arg2) + { +- return set_HI_LOT0((uint64_t)get_HILO() - (uint64_t)(uint32_t)arg1 * +- (uint64_t)(uint32_t)arg2); ++ return set_HI_LOT0(env, (uint64_t)get_HILO(env) - ++ (uint64_t)(uint32_t)arg1 * (uint64_t)(uint32_t)arg2); + } + +-target_ulong helper_msachiu (target_ulong arg1, target_ulong arg2) ++target_ulong helper_msachiu(CPUMIPSState *env, target_ulong arg1, ++ target_ulong arg2) + { +- return set_HIT0_LO((uint64_t)get_HILO() - (uint64_t)(uint32_t)arg1 * +- (uint64_t)(uint32_t)arg2); ++ return set_HIT0_LO(env, (uint64_t)get_HILO(env) - ++ (uint64_t)(uint32_t)arg1 * (uint64_t)(uint32_t)arg2); + } + +-target_ulong helper_mulhi (target_ulong arg1, target_ulong arg2) ++target_ulong helper_mulhi(CPUMIPSState *env, target_ulong arg1, ++ target_ulong arg2) + { +- return set_HIT0_LO((int64_t)(int32_t)arg1 * (int64_t)(int32_t)arg2); ++ return set_HIT0_LO(env, (int64_t)(int32_t)arg1 * (int64_t)(int32_t)arg2); + } + +-target_ulong helper_mulhiu (target_ulong arg1, target_ulong arg2) ++target_ulong helper_mulhiu(CPUMIPSState *env, target_ulong arg1, ++ target_ulong arg2) + { +- return set_HIT0_LO((uint64_t)(uint32_t)arg1 * (uint64_t)(uint32_t)arg2); ++ return set_HIT0_LO(env, (uint64_t)(uint32_t)arg1 * ++ (uint64_t)(uint32_t)arg2); + } + +-target_ulong helper_mulshi (target_ulong arg1, target_ulong arg2) ++target_ulong helper_mulshi(CPUMIPSState *env, target_ulong arg1, ++ target_ulong arg2) + { +- return set_HIT0_LO(0 - (int64_t)(int32_t)arg1 * (int64_t)(int32_t)arg2); ++ return set_HIT0_LO(env, 0 - (int64_t)(int32_t)arg1 * ++ (int64_t)(int32_t)arg2); + } + +-target_ulong helper_mulshiu (target_ulong arg1, target_ulong arg2) ++target_ulong helper_mulshiu(CPUMIPSState *env, target_ulong arg1, ++ target_ulong arg2) + { +- return set_HIT0_LO(0 - (uint64_t)(uint32_t)arg1 * (uint64_t)(uint32_t)arg2); ++ return set_HIT0_LO(env, 0 - (uint64_t)(uint32_t)arg1 * ++ (uint64_t)(uint32_t)arg2); + } + + #ifdef TARGET_MIPS64 +-void helper_dmult (target_ulong arg1, target_ulong arg2) ++void helper_dmult(CPUMIPSState *env, target_ulong arg1, target_ulong arg2) + { + muls64(&(env->active_tc.LO[0]), &(env->active_tc.HI[0]), arg1, arg2); + } + +-void helper_dmultu (target_ulong arg1, target_ulong arg2) ++void helper_dmultu(CPUMIPSState *env, target_ulong arg1, target_ulong arg2) + { + mulu64(&(env->active_tc.LO[0]), &(env->active_tc.HI[0]), arg1, arg2); + } +@@ -300,7 +322,9 @@ void helper_dmultu (target_ulong arg1, target_ulong arg2) + + #ifndef CONFIG_USER_ONLY + +-static inline target_phys_addr_t do_translate_address(target_ulong address, int rw) ++static inline target_phys_addr_t do_translate_address(CPUMIPSState *env, ++ target_ulong address, ++ int rw) + { + target_phys_addr_t lladdr; + +@@ -314,10 +338,10 @@ static inline target_phys_addr_t do_translate_address(target_ulong address, int + } + + #define HELPER_LD_ATOMIC(name, insn) \ +-target_ulong helper_##name(target_ulong arg, int mem_idx) \ ++target_ulong helper_##name(CPUMIPSState *env, target_ulong arg, int mem_idx) \ + { \ +- env->lladdr = do_translate_address(arg, 0); \ +- env->llval = do_##insn(arg, mem_idx); \ ++ env->lladdr = do_translate_address(env, arg, 0); \ ++ env->llval = do_##insn(env, arg, mem_idx); \ + return env->llval; \ + } + HELPER_LD_ATOMIC(ll, lw) +@@ -327,18 +351,19 @@ HELPER_LD_ATOMIC(lld, ld) + #undef HELPER_LD_ATOMIC + + #define HELPER_ST_ATOMIC(name, ld_insn, st_insn, almask) \ +-target_ulong helper_##name(target_ulong arg1, target_ulong arg2, int mem_idx) \ ++target_ulong helper_##name(CPUMIPSState *env, target_ulong arg1, \ ++ target_ulong arg2, int mem_idx) \ + { \ + target_long tmp; \ + \ + if (arg2 & almask) { \ + env->CP0_BadVAddr = arg2; \ +- helper_raise_exception(EXCP_AdES); \ ++ helper_raise_exception(env, EXCP_AdES); \ + } \ +- if (do_translate_address(arg2, 1) == env->lladdr) { \ +- tmp = do_##ld_insn(arg2, mem_idx); \ ++ if (do_translate_address(env, arg2, 1) == env->lladdr) { \ ++ tmp = do_##ld_insn(env, arg2, mem_idx); \ + if (tmp == env->llval) { \ +- do_##st_insn(arg2, arg1, mem_idx); \ ++ do_##st_insn(env, arg2, arg1, mem_idx); \ + return 1; \ + } \ + } \ +@@ -359,80 +384,84 @@ HELPER_ST_ATOMIC(scd, ld, sd, 0x7) + #define GET_OFFSET(addr, offset) (addr - (offset)) + #endif + +-target_ulong helper_lwl(target_ulong arg1, target_ulong arg2, int mem_idx) ++target_ulong helper_lwl(CPUMIPSState *env, target_ulong arg1, ++ target_ulong arg2, int mem_idx) + { + target_ulong tmp; + +- tmp = do_lbu(arg2, mem_idx); ++ tmp = do_lbu(env, arg2, mem_idx); + arg1 = (arg1 & 0x00FFFFFF) | (tmp << 24); + + if (GET_LMASK(arg2) <= 2) { +- tmp = do_lbu(GET_OFFSET(arg2, 1), mem_idx); ++ tmp = do_lbu(env, GET_OFFSET(arg2, 1), mem_idx); + arg1 = (arg1 & 0xFF00FFFF) | (tmp << 16); + } + + if (GET_LMASK(arg2) <= 1) { +- tmp = do_lbu(GET_OFFSET(arg2, 2), mem_idx); ++ tmp = do_lbu(env, GET_OFFSET(arg2, 2), mem_idx); + arg1 = (arg1 & 0xFFFF00FF) | (tmp << 8); + } + + if (GET_LMASK(arg2) == 0) { +- tmp = do_lbu(GET_OFFSET(arg2, 3), mem_idx); ++ tmp = do_lbu(env, GET_OFFSET(arg2, 3), mem_idx); + arg1 = (arg1 & 0xFFFFFF00) | tmp; + } + return (int32_t)arg1; + } + +-target_ulong helper_lwr(target_ulong arg1, target_ulong arg2, int mem_idx) ++target_ulong helper_lwr(CPUMIPSState *env, target_ulong arg1, ++ target_ulong arg2, int mem_idx) + { + target_ulong tmp; + +- tmp = do_lbu(arg2, mem_idx); ++ tmp = do_lbu(env, arg2, mem_idx); + arg1 = (arg1 & 0xFFFFFF00) | tmp; + + if (GET_LMASK(arg2) >= 1) { +- tmp = do_lbu(GET_OFFSET(arg2, -1), mem_idx); ++ tmp = do_lbu(env, GET_OFFSET(arg2, -1), mem_idx); + arg1 = (arg1 & 0xFFFF00FF) | (tmp << 8); + } + + if (GET_LMASK(arg2) >= 2) { +- tmp = do_lbu(GET_OFFSET(arg2, -2), mem_idx); ++ tmp = do_lbu(env, GET_OFFSET(arg2, -2), mem_idx); + arg1 = (arg1 & 0xFF00FFFF) | (tmp << 16); + } + + if (GET_LMASK(arg2) == 3) { +- tmp = do_lbu(GET_OFFSET(arg2, -3), mem_idx); ++ tmp = do_lbu(env, GET_OFFSET(arg2, -3), mem_idx); + arg1 = (arg1 & 0x00FFFFFF) | (tmp << 24); + } + return (int32_t)arg1; + } + +-void helper_swl(target_ulong arg1, target_ulong arg2, int mem_idx) ++void helper_swl(CPUMIPSState *env, target_ulong arg1, target_ulong arg2, ++ int mem_idx) + { +- do_sb(arg2, (uint8_t)(arg1 >> 24), mem_idx); ++ do_sb(env, arg2, (uint8_t)(arg1 >> 24), mem_idx); + + if (GET_LMASK(arg2) <= 2) +- do_sb(GET_OFFSET(arg2, 1), (uint8_t)(arg1 >> 16), mem_idx); ++ do_sb(env, GET_OFFSET(arg2, 1), (uint8_t)(arg1 >> 16), mem_idx); + + if (GET_LMASK(arg2) <= 1) +- do_sb(GET_OFFSET(arg2, 2), (uint8_t)(arg1 >> 8), mem_idx); ++ do_sb(env, GET_OFFSET(arg2, 2), (uint8_t)(arg1 >> 8), mem_idx); + + if (GET_LMASK(arg2) == 0) +- do_sb(GET_OFFSET(arg2, 3), (uint8_t)arg1, mem_idx); ++ do_sb(env, GET_OFFSET(arg2, 3), (uint8_t)arg1, mem_idx); + } + +-void helper_swr(target_ulong arg1, target_ulong arg2, int mem_idx) ++void helper_swr(CPUMIPSState *env, target_ulong arg1, target_ulong arg2, ++ int mem_idx) + { +- do_sb(arg2, (uint8_t)arg1, mem_idx); ++ do_sb(env, arg2, (uint8_t)arg1, mem_idx); + + if (GET_LMASK(arg2) >= 1) +- do_sb(GET_OFFSET(arg2, -1), (uint8_t)(arg1 >> 8), mem_idx); ++ do_sb(env, GET_OFFSET(arg2, -1), (uint8_t)(arg1 >> 8), mem_idx); + + if (GET_LMASK(arg2) >= 2) +- do_sb(GET_OFFSET(arg2, -2), (uint8_t)(arg1 >> 16), mem_idx); ++ do_sb(env, GET_OFFSET(arg2, -2), (uint8_t)(arg1 >> 16), mem_idx); + + if (GET_LMASK(arg2) == 3) +- do_sb(GET_OFFSET(arg2, -3), (uint8_t)(arg1 >> 24), mem_idx); ++ do_sb(env, GET_OFFSET(arg2, -3), (uint8_t)(arg1 >> 24), mem_idx); + } + + #if defined(TARGET_MIPS64) +@@ -445,167 +474,172 @@ void helper_swr(target_ulong arg1, target_ulong arg2, int mem_idx) + #define GET_LMASK64(v) (((v) & 7) ^ 7) + #endif + +-target_ulong helper_ldl(target_ulong arg1, target_ulong arg2, int mem_idx) ++target_ulong helper_ldl(CPUMIPSState *env, target_ulong arg1, ++ target_ulong arg2, int mem_idx) + { + uint64_t tmp; + +- tmp = do_lbu(arg2, mem_idx); ++ tmp = do_lbu(env, arg2, mem_idx); + arg1 = (arg1 & 0x00FFFFFFFFFFFFFFULL) | (tmp << 56); + + if (GET_LMASK64(arg2) <= 6) { +- tmp = do_lbu(GET_OFFSET(arg2, 1), mem_idx); ++ tmp = do_lbu(env, GET_OFFSET(arg2, 1), mem_idx); + arg1 = (arg1 & 0xFF00FFFFFFFFFFFFULL) | (tmp << 48); + } + + if (GET_LMASK64(arg2) <= 5) { +- tmp = do_lbu(GET_OFFSET(arg2, 2), mem_idx); ++ tmp = do_lbu(env, GET_OFFSET(arg2, 2), mem_idx); + arg1 = (arg1 & 0xFFFF00FFFFFFFFFFULL) | (tmp << 40); + } + + if (GET_LMASK64(arg2) <= 4) { +- tmp = do_lbu(GET_OFFSET(arg2, 3), mem_idx); ++ tmp = do_lbu(env, GET_OFFSET(arg2, 3), mem_idx); + arg1 = (arg1 & 0xFFFFFF00FFFFFFFFULL) | (tmp << 32); + } + + if (GET_LMASK64(arg2) <= 3) { +- tmp = do_lbu(GET_OFFSET(arg2, 4), mem_idx); ++ tmp = do_lbu(env, GET_OFFSET(arg2, 4), mem_idx); + arg1 = (arg1 & 0xFFFFFFFF00FFFFFFULL) | (tmp << 24); + } + + if (GET_LMASK64(arg2) <= 2) { +- tmp = do_lbu(GET_OFFSET(arg2, 5), mem_idx); ++ tmp = do_lbu(env, GET_OFFSET(arg2, 5), mem_idx); + arg1 = (arg1 & 0xFFFFFFFFFF00FFFFULL) | (tmp << 16); + } + + if (GET_LMASK64(arg2) <= 1) { +- tmp = do_lbu(GET_OFFSET(arg2, 6), mem_idx); ++ tmp = do_lbu(env, GET_OFFSET(arg2, 6), mem_idx); + arg1 = (arg1 & 0xFFFFFFFFFFFF00FFULL) | (tmp << 8); + } + + if (GET_LMASK64(arg2) == 0) { +- tmp = do_lbu(GET_OFFSET(arg2, 7), mem_idx); ++ tmp = do_lbu(env, GET_OFFSET(arg2, 7), mem_idx); + arg1 = (arg1 & 0xFFFFFFFFFFFFFF00ULL) | tmp; + } + + return arg1; + } + +-target_ulong helper_ldr(target_ulong arg1, target_ulong arg2, int mem_idx) ++target_ulong helper_ldr(CPUMIPSState *env, target_ulong arg1, ++ target_ulong arg2, int mem_idx) + { + uint64_t tmp; + +- tmp = do_lbu(arg2, mem_idx); ++ tmp = do_lbu(env, arg2, mem_idx); + arg1 = (arg1 & 0xFFFFFFFFFFFFFF00ULL) | tmp; + + if (GET_LMASK64(arg2) >= 1) { +- tmp = do_lbu(GET_OFFSET(arg2, -1), mem_idx); ++ tmp = do_lbu(env, GET_OFFSET(arg2, -1), mem_idx); + arg1 = (arg1 & 0xFFFFFFFFFFFF00FFULL) | (tmp << 8); + } + + if (GET_LMASK64(arg2) >= 2) { +- tmp = do_lbu(GET_OFFSET(arg2, -2), mem_idx); ++ tmp = do_lbu(env, GET_OFFSET(arg2, -2), mem_idx); + arg1 = (arg1 & 0xFFFFFFFFFF00FFFFULL) | (tmp << 16); + } + + if (GET_LMASK64(arg2) >= 3) { +- tmp = do_lbu(GET_OFFSET(arg2, -3), mem_idx); ++ tmp = do_lbu(env, GET_OFFSET(arg2, -3), mem_idx); + arg1 = (arg1 & 0xFFFFFFFF00FFFFFFULL) | (tmp << 24); + } + + if (GET_LMASK64(arg2) >= 4) { +- tmp = do_lbu(GET_OFFSET(arg2, -4), mem_idx); ++ tmp = do_lbu(env, GET_OFFSET(arg2, -4), mem_idx); + arg1 = (arg1 & 0xFFFFFF00FFFFFFFFULL) | (tmp << 32); + } + + if (GET_LMASK64(arg2) >= 5) { +- tmp = do_lbu(GET_OFFSET(arg2, -5), mem_idx); ++ tmp = do_lbu(env, GET_OFFSET(arg2, -5), mem_idx); + arg1 = (arg1 & 0xFFFF00FFFFFFFFFFULL) | (tmp << 40); + } + + if (GET_LMASK64(arg2) >= 6) { +- tmp = do_lbu(GET_OFFSET(arg2, -6), mem_idx); ++ tmp = do_lbu(env, GET_OFFSET(arg2, -6), mem_idx); + arg1 = (arg1 & 0xFF00FFFFFFFFFFFFULL) | (tmp << 48); + } + + if (GET_LMASK64(arg2) == 7) { +- tmp = do_lbu(GET_OFFSET(arg2, -7), mem_idx); ++ tmp = do_lbu(env, GET_OFFSET(arg2, -7), mem_idx); + arg1 = (arg1 & 0x00FFFFFFFFFFFFFFULL) | (tmp << 56); + } + + return arg1; + } + +-void helper_sdl(target_ulong arg1, target_ulong arg2, int mem_idx) ++void helper_sdl(CPUMIPSState *env, target_ulong arg1, target_ulong arg2, ++ int mem_idx) + { +- do_sb(arg2, (uint8_t)(arg1 >> 56), mem_idx); ++ do_sb(env, arg2, (uint8_t)(arg1 >> 56), mem_idx); + + if (GET_LMASK64(arg2) <= 6) +- do_sb(GET_OFFSET(arg2, 1), (uint8_t)(arg1 >> 48), mem_idx); ++ do_sb(env, GET_OFFSET(arg2, 1), (uint8_t)(arg1 >> 48), mem_idx); + + if (GET_LMASK64(arg2) <= 5) +- do_sb(GET_OFFSET(arg2, 2), (uint8_t)(arg1 >> 40), mem_idx); ++ do_sb(env, GET_OFFSET(arg2, 2), (uint8_t)(arg1 >> 40), mem_idx); + + if (GET_LMASK64(arg2) <= 4) +- do_sb(GET_OFFSET(arg2, 3), (uint8_t)(arg1 >> 32), mem_idx); ++ do_sb(env, GET_OFFSET(arg2, 3), (uint8_t)(arg1 >> 32), mem_idx); + + if (GET_LMASK64(arg2) <= 3) +- do_sb(GET_OFFSET(arg2, 4), (uint8_t)(arg1 >> 24), mem_idx); ++ do_sb(env, GET_OFFSET(arg2, 4), (uint8_t)(arg1 >> 24), mem_idx); + + if (GET_LMASK64(arg2) <= 2) +- do_sb(GET_OFFSET(arg2, 5), (uint8_t)(arg1 >> 16), mem_idx); ++ do_sb(env, GET_OFFSET(arg2, 5), (uint8_t)(arg1 >> 16), mem_idx); + + if (GET_LMASK64(arg2) <= 1) +- do_sb(GET_OFFSET(arg2, 6), (uint8_t)(arg1 >> 8), mem_idx); ++ do_sb(env, GET_OFFSET(arg2, 6), (uint8_t)(arg1 >> 8), mem_idx); + + if (GET_LMASK64(arg2) <= 0) +- do_sb(GET_OFFSET(arg2, 7), (uint8_t)arg1, mem_idx); ++ do_sb(env, GET_OFFSET(arg2, 7), (uint8_t)arg1, mem_idx); + } + +-void helper_sdr(target_ulong arg1, target_ulong arg2, int mem_idx) ++void helper_sdr(CPUMIPSState *env, target_ulong arg1, target_ulong arg2, ++ int mem_idx) + { +- do_sb(arg2, (uint8_t)arg1, mem_idx); ++ do_sb(env, arg2, (uint8_t)arg1, mem_idx); + + if (GET_LMASK64(arg2) >= 1) +- do_sb(GET_OFFSET(arg2, -1), (uint8_t)(arg1 >> 8), mem_idx); ++ do_sb(env, GET_OFFSET(arg2, -1), (uint8_t)(arg1 >> 8), mem_idx); + + if (GET_LMASK64(arg2) >= 2) +- do_sb(GET_OFFSET(arg2, -2), (uint8_t)(arg1 >> 16), mem_idx); ++ do_sb(env, GET_OFFSET(arg2, -2), (uint8_t)(arg1 >> 16), mem_idx); + + if (GET_LMASK64(arg2) >= 3) +- do_sb(GET_OFFSET(arg2, -3), (uint8_t)(arg1 >> 24), mem_idx); ++ do_sb(env, GET_OFFSET(arg2, -3), (uint8_t)(arg1 >> 24), mem_idx); + + if (GET_LMASK64(arg2) >= 4) +- do_sb(GET_OFFSET(arg2, -4), (uint8_t)(arg1 >> 32), mem_idx); ++ do_sb(env, GET_OFFSET(arg2, -4), (uint8_t)(arg1 >> 32), mem_idx); + + if (GET_LMASK64(arg2) >= 5) +- do_sb(GET_OFFSET(arg2, -5), (uint8_t)(arg1 >> 40), mem_idx); ++ do_sb(env, GET_OFFSET(arg2, -5), (uint8_t)(arg1 >> 40), mem_idx); + + if (GET_LMASK64(arg2) >= 6) +- do_sb(GET_OFFSET(arg2, -6), (uint8_t)(arg1 >> 48), mem_idx); ++ do_sb(env, GET_OFFSET(arg2, -6), (uint8_t)(arg1 >> 48), mem_idx); + + if (GET_LMASK64(arg2) == 7) +- do_sb(GET_OFFSET(arg2, -7), (uint8_t)(arg1 >> 56), mem_idx); ++ do_sb(env, GET_OFFSET(arg2, -7), (uint8_t)(arg1 >> 56), mem_idx); + } + #endif /* TARGET_MIPS64 */ + + static const int multiple_regs[] = { 16, 17, 18, 19, 20, 21, 22, 23, 30 }; + +-void helper_lwm (target_ulong addr, target_ulong reglist, uint32_t mem_idx) ++void helper_lwm(CPUMIPSState *env, target_ulong addr, target_ulong reglist, ++ uint32_t mem_idx) + { + target_ulong base_reglist = reglist & 0xf; + target_ulong do_r31 = reglist & 0x10; + #ifdef CONFIG_USER_ONLY + #undef ldfun +-#define ldfun ldl_raw ++#define ldfun(env, addr) ldl_raw(addr) + #else +- uint32_t (*ldfun)(target_ulong); ++ uint32_t (*ldfun)(CPUMIPSState *env, target_ulong); + + switch (mem_idx) + { +- case 0: ldfun = ldl_kernel; break; +- case 1: ldfun = ldl_super; break; ++ case 0: ldfun = cpu_ldl_kernel; break; ++ case 1: ldfun = cpu_ldl_super; break; + default: +- case 2: ldfun = ldl_user; break; ++ case 2: ldfun = cpu_ldl_user; break; + } + #endif + +@@ -613,32 +647,33 @@ void helper_lwm (target_ulong addr, target_ulong reglist, uint32_t mem_idx) + target_ulong i; + + for (i = 0; i < base_reglist; i++) { +- env->active_tc.gpr[multiple_regs[i]] = (target_long) ldfun(addr); ++ env->active_tc.gpr[multiple_regs[i]] = (target_long)ldfun(env, addr); + addr += 4; + } + } + + if (do_r31) { +- env->active_tc.gpr[31] = (target_long) ldfun(addr); ++ env->active_tc.gpr[31] = (target_long)ldfun(env, addr); + } + } + +-void helper_swm (target_ulong addr, target_ulong reglist, uint32_t mem_idx) ++void helper_swm(CPUMIPSState *env, target_ulong addr, target_ulong reglist, ++ uint32_t mem_idx) + { + target_ulong base_reglist = reglist & 0xf; + target_ulong do_r31 = reglist & 0x10; + #ifdef CONFIG_USER_ONLY + #undef stfun +-#define stfun stl_raw ++#define stfun(env, addr, val) stl_raw(addr, val) + #else +- void (*stfun)(target_ulong, uint32_t); ++ void (*stfun)(CPUMIPSState *env, target_ulong, uint32_t); + + switch (mem_idx) + { +- case 0: stfun = stl_kernel; break; +- case 1: stfun = stl_super; break; ++ case 0: stfun = cpu_stl_kernel; break; ++ case 1: stfun = cpu_stl_super; break; + default: +- case 2: stfun = stl_user; break; ++ case 2: stfun = cpu_stl_user; break; + } + #endif + +@@ -646,33 +681,34 @@ void helper_swm (target_ulong addr, target_ulong reglist, uint32_t mem_idx) + target_ulong i; + + for (i = 0; i < base_reglist; i++) { +- stfun(addr, env->active_tc.gpr[multiple_regs[i]]); ++ stfun(env, addr, env->active_tc.gpr[multiple_regs[i]]); + addr += 4; + } + } + + if (do_r31) { +- stfun(addr, env->active_tc.gpr[31]); ++ stfun(env, addr, env->active_tc.gpr[31]); + } + } + + #if defined(TARGET_MIPS64) +-void helper_ldm (target_ulong addr, target_ulong reglist, uint32_t mem_idx) ++void helper_ldm(CPUMIPSState *env, target_ulong addr, target_ulong reglist, ++ uint32_t mem_idx) + { + target_ulong base_reglist = reglist & 0xf; + target_ulong do_r31 = reglist & 0x10; + #ifdef CONFIG_USER_ONLY + #undef ldfun +-#define ldfun ldq_raw ++#define ldfun(env, addr) ldq_raw(addr) + #else +- uint64_t (*ldfun)(target_ulong); ++ uint64_t (*ldfun)(CPUMIPSState *env, target_ulong); + + switch (mem_idx) + { +- case 0: ldfun = ldq_kernel; break; +- case 1: ldfun = ldq_super; break; ++ case 0: ldfun = cpu_ldq_kernel; break; ++ case 1: ldfun = cpu_ldq_super; break; + default: +- case 2: ldfun = ldq_user; break; ++ case 2: ldfun = cpu_ldq_user; break; + } + #endif + +@@ -680,32 +716,33 @@ void helper_ldm (target_ulong addr, target_ulong reglist, uint32_t mem_idx) + target_ulong i; + + for (i = 0; i < base_reglist; i++) { +- env->active_tc.gpr[multiple_regs[i]] = ldfun(addr); ++ env->active_tc.gpr[multiple_regs[i]] = ldfun(env, addr); + addr += 8; + } + } + + if (do_r31) { +- env->active_tc.gpr[31] = ldfun(addr); ++ env->active_tc.gpr[31] = ldfun(env, addr); + } + } + +-void helper_sdm (target_ulong addr, target_ulong reglist, uint32_t mem_idx) ++void helper_sdm(CPUMIPSState *env, target_ulong addr, target_ulong reglist, ++ uint32_t mem_idx) + { + target_ulong base_reglist = reglist & 0xf; + target_ulong do_r31 = reglist & 0x10; + #ifdef CONFIG_USER_ONLY + #undef stfun +-#define stfun stq_raw ++#define stfun(env, addr, val) stq_raw(addr, val) + #else +- void (*stfun)(target_ulong, uint64_t); ++ void (*stfun)(CPUMIPSState *env, target_ulong, uint64_t); + + switch (mem_idx) + { +- case 0: stfun = stq_kernel; break; +- case 1: stfun = stq_super; break; ++ case 0: stfun = cpu_stq_kernel; break; ++ case 1: stfun = cpu_stq_super; break; + default: +- case 2: stfun = stq_user; break; ++ case 2: stfun = cpu_stq_user; break; + } + #endif + +@@ -713,13 +750,13 @@ void helper_sdm (target_ulong addr, target_ulong reglist, uint32_t mem_idx) + target_ulong i; + + for (i = 0; i < base_reglist; i++) { +- stfun(addr, env->active_tc.gpr[multiple_regs[i]]); ++ stfun(env, addr, env->active_tc.gpr[multiple_regs[i]]); + addr += 8; + } + } + + if (do_r31) { +- stfun(addr, env->active_tc.gpr[31]); ++ stfun(env, addr, env->active_tc.gpr[31]); + } + } + #endif +@@ -772,7 +809,7 @@ static inline void mips_tc_sleep(CPUMIPSState *c, int tc) + FIXME: This code assumes that all VPEs have the same number of TCs, + which depends on runtime setup. Can probably be fixed by + walking the list of CPUMIPSStates. */ +-static CPUMIPSState *mips_cpu_map_tc(int *tc) ++static CPUMIPSState *mips_cpu_map_tc(CPUMIPSState *env, int *tc) + { + CPUMIPSState *other; + int vpe_idx, nr_threads = env->nr_threads; +@@ -799,7 +836,7 @@ static CPUMIPSState *mips_cpu_map_tc(int *tc) + These helper call synchronizes the regs for a given cpu. */ + + /* Called for updates to CP0_Status. */ +-static void sync_c0_status(CPUMIPSState *cpu, int tc) ++static void sync_c0_status(CPUMIPSState *env, CPUMIPSState *cpu, int tc) + { + int32_t tcstatus, *tcst; + uint32_t v = cpu->CP0_Status; +@@ -834,7 +871,8 @@ static void sync_c0_status(CPUMIPSState *cpu, int tc) + } + + /* Called for updates to CP0_TCStatus. */ +-static void sync_c0_tcstatus(CPUMIPSState *cpu, int tc, target_ulong v) ++static void sync_c0_tcstatus(CPUMIPSState *cpu, int tc, ++ target_ulong v) + { + uint32_t status; + uint32_t tcu, tmx, tasid, tksu; +@@ -883,35 +921,35 @@ static void sync_c0_entryhi(CPUMIPSState *cpu, int tc) + } + + /* CP0 helpers */ +-target_ulong helper_mfc0_mvpcontrol (void) ++target_ulong helper_mfc0_mvpcontrol(CPUMIPSState *env) + { + return env->mvp->CP0_MVPControl; + } + +-target_ulong helper_mfc0_mvpconf0 (void) ++target_ulong helper_mfc0_mvpconf0(CPUMIPSState *env) + { + return env->mvp->CP0_MVPConf0; + } + +-target_ulong helper_mfc0_mvpconf1 (void) ++target_ulong helper_mfc0_mvpconf1(CPUMIPSState *env) + { + return env->mvp->CP0_MVPConf1; + } + +-target_ulong helper_mfc0_random (void) ++target_ulong helper_mfc0_random(CPUMIPSState *env) + { + return (int32_t)cpu_mips_get_random(env); + } + +-target_ulong helper_mfc0_tcstatus (void) ++target_ulong helper_mfc0_tcstatus(CPUMIPSState *env) + { + return env->active_tc.CP0_TCStatus; + } + +-target_ulong helper_mftc0_tcstatus(void) ++target_ulong helper_mftc0_tcstatus(CPUMIPSState *env) + { + int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); +- CPUMIPSState *other = mips_cpu_map_tc(&other_tc); ++ CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc); + + if (other_tc == other->current_tc) + return other->active_tc.CP0_TCStatus; +@@ -919,15 +957,15 @@ target_ulong helper_mftc0_tcstatus(void) + return other->tcs[other_tc].CP0_TCStatus; + } + +-target_ulong helper_mfc0_tcbind (void) ++target_ulong helper_mfc0_tcbind(CPUMIPSState *env) + { + return env->active_tc.CP0_TCBind; + } + +-target_ulong helper_mftc0_tcbind(void) ++target_ulong helper_mftc0_tcbind(CPUMIPSState *env) + { + int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); +- CPUMIPSState *other = mips_cpu_map_tc(&other_tc); ++ CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc); + + if (other_tc == other->current_tc) + return other->active_tc.CP0_TCBind; +@@ -935,15 +973,15 @@ target_ulong helper_mftc0_tcbind(void) + return other->tcs[other_tc].CP0_TCBind; + } + +-target_ulong helper_mfc0_tcrestart (void) ++target_ulong helper_mfc0_tcrestart(CPUMIPSState *env) + { + return env->active_tc.PC; + } + +-target_ulong helper_mftc0_tcrestart(void) ++target_ulong helper_mftc0_tcrestart(CPUMIPSState *env) + { + int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); +- CPUMIPSState *other = mips_cpu_map_tc(&other_tc); ++ CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc); + + if (other_tc == other->current_tc) + return other->active_tc.PC; +@@ -951,15 +989,15 @@ target_ulong helper_mftc0_tcrestart(void) + return other->tcs[other_tc].PC; + } + +-target_ulong helper_mfc0_tchalt (void) ++target_ulong helper_mfc0_tchalt(CPUMIPSState *env) + { + return env->active_tc.CP0_TCHalt; + } + +-target_ulong helper_mftc0_tchalt(void) ++target_ulong helper_mftc0_tchalt(CPUMIPSState *env) + { + int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); +- CPUMIPSState *other = mips_cpu_map_tc(&other_tc); ++ CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc); + + if (other_tc == other->current_tc) + return other->active_tc.CP0_TCHalt; +@@ -967,15 +1005,15 @@ target_ulong helper_mftc0_tchalt(void) + return other->tcs[other_tc].CP0_TCHalt; + } + +-target_ulong helper_mfc0_tccontext (void) ++target_ulong helper_mfc0_tccontext(CPUMIPSState *env) + { + return env->active_tc.CP0_TCContext; + } + +-target_ulong helper_mftc0_tccontext(void) ++target_ulong helper_mftc0_tccontext(CPUMIPSState *env) + { + int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); +- CPUMIPSState *other = mips_cpu_map_tc(&other_tc); ++ CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc); + + if (other_tc == other->current_tc) + return other->active_tc.CP0_TCContext; +@@ -983,15 +1021,15 @@ target_ulong helper_mftc0_tccontext(void) + return other->tcs[other_tc].CP0_TCContext; + } + +-target_ulong helper_mfc0_tcschedule (void) ++target_ulong helper_mfc0_tcschedule(CPUMIPSState *env) + { + return env->active_tc.CP0_TCSchedule; + } + +-target_ulong helper_mftc0_tcschedule(void) ++target_ulong helper_mftc0_tcschedule(CPUMIPSState *env) + { + int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); +- CPUMIPSState *other = mips_cpu_map_tc(&other_tc); ++ CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc); + + if (other_tc == other->current_tc) + return other->active_tc.CP0_TCSchedule; +@@ -999,15 +1037,15 @@ target_ulong helper_mftc0_tcschedule(void) + return other->tcs[other_tc].CP0_TCSchedule; + } + +-target_ulong helper_mfc0_tcschefback (void) ++target_ulong helper_mfc0_tcschefback(CPUMIPSState *env) + { + return env->active_tc.CP0_TCScheFBack; + } + +-target_ulong helper_mftc0_tcschefback(void) ++target_ulong helper_mftc0_tcschefback(CPUMIPSState *env) + { + int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); +- CPUMIPSState *other = mips_cpu_map_tc(&other_tc); ++ CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc); + + if (other_tc == other->current_tc) + return other->active_tc.CP0_TCScheFBack; +@@ -1015,24 +1053,24 @@ target_ulong helper_mftc0_tcschefback(void) + return other->tcs[other_tc].CP0_TCScheFBack; + } + +-target_ulong helper_mfc0_count (void) ++target_ulong helper_mfc0_count(CPUMIPSState *env) + { + return (int32_t)cpu_mips_get_count(env); + } + +-target_ulong helper_mftc0_entryhi(void) ++target_ulong helper_mftc0_entryhi(CPUMIPSState *env) + { + int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); +- CPUMIPSState *other = mips_cpu_map_tc(&other_tc); ++ CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc); + + return other->CP0_EntryHi; + } + +-target_ulong helper_mftc0_cause(void) ++target_ulong helper_mftc0_cause(CPUMIPSState *env) + { + int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); + int32_t tccause; +- CPUMIPSState *other = mips_cpu_map_tc(&other_tc); ++ CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc); + + if (other_tc == other->current_tc) { + tccause = other->CP0_Cause; +@@ -1043,30 +1081,30 @@ target_ulong helper_mftc0_cause(void) + return tccause; + } + +-target_ulong helper_mftc0_status(void) ++target_ulong helper_mftc0_status(CPUMIPSState *env) + { + int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); +- CPUMIPSState *other = mips_cpu_map_tc(&other_tc); ++ CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc); + + return other->CP0_Status; + } + +-target_ulong helper_mfc0_lladdr (void) ++target_ulong helper_mfc0_lladdr(CPUMIPSState *env) + { + return (int32_t)(env->lladdr >> env->CP0_LLAddr_shift); + } + +-target_ulong helper_mfc0_watchlo (uint32_t sel) ++target_ulong helper_mfc0_watchlo(CPUMIPSState *env, uint32_t sel) + { + return (int32_t)env->CP0_WatchLo[sel]; + } + +-target_ulong helper_mfc0_watchhi (uint32_t sel) ++target_ulong helper_mfc0_watchhi(CPUMIPSState *env, uint32_t sel) + { + return env->CP0_WatchHi[sel]; + } + +-target_ulong helper_mfc0_debug (void) ++target_ulong helper_mfc0_debug(CPUMIPSState *env) + { + target_ulong t0 = env->CP0_Debug; + if (env->hflags & MIPS_HFLAG_DM) +@@ -1075,11 +1113,11 @@ target_ulong helper_mfc0_debug (void) + return t0; + } + +-target_ulong helper_mftc0_debug(void) ++target_ulong helper_mftc0_debug(CPUMIPSState *env) + { + int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); + int32_t tcstatus; +- CPUMIPSState *other = mips_cpu_map_tc(&other_tc); ++ CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc); + + if (other_tc == other->current_tc) + tcstatus = other->active_tc.CP0_Debug_tcstatus; +@@ -1092,43 +1130,43 @@ target_ulong helper_mftc0_debug(void) + } + + #if defined(TARGET_MIPS64) +-target_ulong helper_dmfc0_tcrestart (void) ++target_ulong helper_dmfc0_tcrestart(CPUMIPSState *env) + { + return env->active_tc.PC; + } + +-target_ulong helper_dmfc0_tchalt (void) ++target_ulong helper_dmfc0_tchalt(CPUMIPSState *env) + { + return env->active_tc.CP0_TCHalt; + } + +-target_ulong helper_dmfc0_tccontext (void) ++target_ulong helper_dmfc0_tccontext(CPUMIPSState *env) + { + return env->active_tc.CP0_TCContext; + } + +-target_ulong helper_dmfc0_tcschedule (void) ++target_ulong helper_dmfc0_tcschedule(CPUMIPSState *env) + { + return env->active_tc.CP0_TCSchedule; + } + +-target_ulong helper_dmfc0_tcschefback (void) ++target_ulong helper_dmfc0_tcschefback(CPUMIPSState *env) + { + return env->active_tc.CP0_TCScheFBack; + } + +-target_ulong helper_dmfc0_lladdr (void) ++target_ulong helper_dmfc0_lladdr(CPUMIPSState *env) + { + return env->lladdr >> env->CP0_LLAddr_shift; + } + +-target_ulong helper_dmfc0_watchlo (uint32_t sel) ++target_ulong helper_dmfc0_watchlo(CPUMIPSState *env, uint32_t sel) + { + return env->CP0_WatchLo[sel]; + } + #endif /* TARGET_MIPS64 */ + +-void helper_mtc0_index (target_ulong arg1) ++void helper_mtc0_index(CPUMIPSState *env, target_ulong arg1) + { + int num = 1; + unsigned int tmp = env->tlb->nb_tlb; +@@ -1140,7 +1178,7 @@ void helper_mtc0_index (target_ulong arg1) + env->CP0_Index = (env->CP0_Index & 0x80000000) | (arg1 & (num - 1)); + } + +-void helper_mtc0_mvpcontrol (target_ulong arg1) ++void helper_mtc0_mvpcontrol(CPUMIPSState *env, target_ulong arg1) + { + uint32_t mask = 0; + uint32_t newval; +@@ -1157,7 +1195,7 @@ void helper_mtc0_mvpcontrol (target_ulong arg1) + env->mvp->CP0_MVPControl = newval; + } + +-void helper_mtc0_vpecontrol (target_ulong arg1) ++void helper_mtc0_vpecontrol(CPUMIPSState *env, target_ulong arg1) + { + uint32_t mask; + uint32_t newval; +@@ -1174,10 +1212,10 @@ void helper_mtc0_vpecontrol (target_ulong arg1) + env->CP0_VPEControl = newval; + } + +-void helper_mttc0_vpecontrol(target_ulong arg1) ++void helper_mttc0_vpecontrol(CPUMIPSState *env, target_ulong arg1) + { + int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); +- CPUMIPSState *other = mips_cpu_map_tc(&other_tc); ++ CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc); + uint32_t mask; + uint32_t newval; + +@@ -1190,23 +1228,23 @@ void helper_mttc0_vpecontrol(target_ulong arg1) + other->CP0_VPEControl = newval; + } + +-target_ulong helper_mftc0_vpecontrol(void) ++target_ulong helper_mftc0_vpecontrol(CPUMIPSState *env) + { + int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); +- CPUMIPSState *other = mips_cpu_map_tc(&other_tc); ++ CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc); + /* FIXME: Mask away return zero on read bits. */ + return other->CP0_VPEControl; + } + +-target_ulong helper_mftc0_vpeconf0(void) ++target_ulong helper_mftc0_vpeconf0(CPUMIPSState *env) + { + int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); +- CPUMIPSState *other = mips_cpu_map_tc(&other_tc); ++ CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc); + + return other->CP0_VPEConf0; + } + +-void helper_mtc0_vpeconf0 (target_ulong arg1) ++void helper_mtc0_vpeconf0(CPUMIPSState *env, target_ulong arg1) + { + uint32_t mask = 0; + uint32_t newval; +@@ -1223,10 +1261,10 @@ void helper_mtc0_vpeconf0 (target_ulong arg1) + env->CP0_VPEConf0 = newval; + } + +-void helper_mttc0_vpeconf0(target_ulong arg1) ++void helper_mttc0_vpeconf0(CPUMIPSState *env, target_ulong arg1) + { + int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); +- CPUMIPSState *other = mips_cpu_map_tc(&other_tc); ++ CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc); + uint32_t mask = 0; + uint32_t newval; + +@@ -1237,7 +1275,7 @@ void helper_mttc0_vpeconf0(target_ulong arg1) + other->CP0_VPEConf0 = newval; + } + +-void helper_mtc0_vpeconf1 (target_ulong arg1) ++void helper_mtc0_vpeconf1(CPUMIPSState *env, target_ulong arg1) + { + uint32_t mask = 0; + uint32_t newval; +@@ -1255,25 +1293,25 @@ void helper_mtc0_vpeconf1 (target_ulong arg1) + env->CP0_VPEConf1 = newval; + } + +-void helper_mtc0_yqmask (target_ulong arg1) ++void helper_mtc0_yqmask(CPUMIPSState *env, target_ulong arg1) + { + /* Yield qualifier inputs not implemented. */ + env->CP0_YQMask = 0x00000000; + } + +-void helper_mtc0_vpeopt (target_ulong arg1) ++void helper_mtc0_vpeopt(CPUMIPSState *env, target_ulong arg1) + { + env->CP0_VPEOpt = arg1 & 0x0000ffff; + } + +-void helper_mtc0_entrylo0 (target_ulong arg1) ++void helper_mtc0_entrylo0(CPUMIPSState *env, target_ulong arg1) + { + /* Large physaddr (PABITS) not implemented */ + /* 1k pages not implemented */ + env->CP0_EntryLo0 = arg1 & 0x3FFFFFFF; + } + +-void helper_mtc0_tcstatus (target_ulong arg1) ++void helper_mtc0_tcstatus(CPUMIPSState *env, target_ulong arg1) + { + uint32_t mask = env->CP0_TCStatus_rw_bitmask; + uint32_t newval; +@@ -1284,10 +1322,10 @@ void helper_mtc0_tcstatus (target_ulong arg1) + sync_c0_tcstatus(env, env->current_tc, newval); + } + +-void helper_mttc0_tcstatus (target_ulong arg1) ++void helper_mttc0_tcstatus(CPUMIPSState *env, target_ulong arg1) + { + int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); +- CPUMIPSState *other = mips_cpu_map_tc(&other_tc); ++ CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc); + + if (other_tc == other->current_tc) + other->active_tc.CP0_TCStatus = arg1; +@@ -1296,7 +1334,7 @@ void helper_mttc0_tcstatus (target_ulong arg1) + sync_c0_tcstatus(other, other_tc, arg1); + } + +-void helper_mtc0_tcbind (target_ulong arg1) ++void helper_mtc0_tcbind(CPUMIPSState *env, target_ulong arg1) + { + uint32_t mask = (1 << CP0TCBd_TBE); + uint32_t newval; +@@ -1307,12 +1345,12 @@ void helper_mtc0_tcbind (target_ulong arg1) + env->active_tc.CP0_TCBind = newval; + } + +-void helper_mttc0_tcbind (target_ulong arg1) ++void helper_mttc0_tcbind(CPUMIPSState *env, target_ulong arg1) + { + int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); + uint32_t mask = (1 << CP0TCBd_TBE); + uint32_t newval; +- CPUMIPSState *other = mips_cpu_map_tc(&other_tc); ++ CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc); + + if (other->mvp->CP0_MVPControl & (1 << CP0MVPCo_VPC)) + mask |= (1 << CP0TCBd_CurVPE); +@@ -1325,7 +1363,7 @@ void helper_mttc0_tcbind (target_ulong arg1) + } + } + +-void helper_mtc0_tcrestart (target_ulong arg1) ++void helper_mtc0_tcrestart(CPUMIPSState *env, target_ulong arg1) + { + env->active_tc.PC = arg1; + env->active_tc.CP0_TCStatus &= ~(1 << CP0TCSt_TDS); +@@ -1333,10 +1371,10 @@ void helper_mtc0_tcrestart (target_ulong arg1) + /* MIPS16 not implemented. */ + } + +-void helper_mttc0_tcrestart (target_ulong arg1) ++void helper_mttc0_tcrestart(CPUMIPSState *env, target_ulong arg1) + { + int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); +- CPUMIPSState *other = mips_cpu_map_tc(&other_tc); ++ CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc); + + if (other_tc == other->current_tc) { + other->active_tc.PC = arg1; +@@ -1351,7 +1389,7 @@ void helper_mttc0_tcrestart (target_ulong arg1) + } + } + +-void helper_mtc0_tchalt (target_ulong arg1) ++void helper_mtc0_tchalt(CPUMIPSState *env, target_ulong arg1) + { + env->active_tc.CP0_TCHalt = arg1 & 0x1; + +@@ -1363,10 +1401,10 @@ void helper_mtc0_tchalt (target_ulong arg1) + } + } + +-void helper_mttc0_tchalt (target_ulong arg1) ++void helper_mttc0_tchalt(CPUMIPSState *env, target_ulong arg1) + { + int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); +- CPUMIPSState *other = mips_cpu_map_tc(&other_tc); ++ CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc); + + // TODO: Halt TC / Restart (if allocated+active) TC. + +@@ -1382,15 +1420,15 @@ void helper_mttc0_tchalt (target_ulong arg1) + } + } + +-void helper_mtc0_tccontext (target_ulong arg1) ++void helper_mtc0_tccontext(CPUMIPSState *env, target_ulong arg1) + { + env->active_tc.CP0_TCContext = arg1; + } + +-void helper_mttc0_tccontext (target_ulong arg1) ++void helper_mttc0_tccontext(CPUMIPSState *env, target_ulong arg1) + { + int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); +- CPUMIPSState *other = mips_cpu_map_tc(&other_tc); ++ CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc); + + if (other_tc == other->current_tc) + other->active_tc.CP0_TCContext = arg1; +@@ -1398,15 +1436,15 @@ void helper_mttc0_tccontext (target_ulong arg1) + other->tcs[other_tc].CP0_TCContext = arg1; + } + +-void helper_mtc0_tcschedule (target_ulong arg1) ++void helper_mtc0_tcschedule(CPUMIPSState *env, target_ulong arg1) + { + env->active_tc.CP0_TCSchedule = arg1; + } + +-void helper_mttc0_tcschedule (target_ulong arg1) ++void helper_mttc0_tcschedule(CPUMIPSState *env, target_ulong arg1) + { + int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); +- CPUMIPSState *other = mips_cpu_map_tc(&other_tc); ++ CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc); + + if (other_tc == other->current_tc) + other->active_tc.CP0_TCSchedule = arg1; +@@ -1414,15 +1452,15 @@ void helper_mttc0_tcschedule (target_ulong arg1) + other->tcs[other_tc].CP0_TCSchedule = arg1; + } + +-void helper_mtc0_tcschefback (target_ulong arg1) ++void helper_mtc0_tcschefback(CPUMIPSState *env, target_ulong arg1) + { + env->active_tc.CP0_TCScheFBack = arg1; + } + +-void helper_mttc0_tcschefback (target_ulong arg1) ++void helper_mttc0_tcschefback(CPUMIPSState *env, target_ulong arg1) + { + int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); +- CPUMIPSState *other = mips_cpu_map_tc(&other_tc); ++ CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc); + + if (other_tc == other->current_tc) + other->active_tc.CP0_TCScheFBack = arg1; +@@ -1430,25 +1468,25 @@ void helper_mttc0_tcschefback (target_ulong arg1) + other->tcs[other_tc].CP0_TCScheFBack = arg1; + } + +-void helper_mtc0_entrylo1 (target_ulong arg1) ++void helper_mtc0_entrylo1(CPUMIPSState *env, target_ulong arg1) + { + /* Large physaddr (PABITS) not implemented */ + /* 1k pages not implemented */ + env->CP0_EntryLo1 = arg1 & 0x3FFFFFFF; + } + +-void helper_mtc0_context (target_ulong arg1) ++void helper_mtc0_context(CPUMIPSState *env, target_ulong arg1) + { + env->CP0_Context = (env->CP0_Context & 0x007FFFFF) | (arg1 & ~0x007FFFFF); + } + +-void helper_mtc0_pagemask (target_ulong arg1) ++void helper_mtc0_pagemask(CPUMIPSState *env, target_ulong arg1) + { + /* 1k pages not implemented */ + env->CP0_PageMask = arg1 & (0x1FFFFFFF & (TARGET_PAGE_MASK << 1)); + } + +-void helper_mtc0_pagegrain (target_ulong arg1) ++void helper_mtc0_pagegrain(CPUMIPSState *env, target_ulong arg1) + { + /* SmartMIPS not implemented */ + /* Large physaddr (PABITS) not implemented */ +@@ -1456,47 +1494,47 @@ void helper_mtc0_pagegrain (target_ulong arg1) + env->CP0_PageGrain = 0; + } + +-void helper_mtc0_wired (target_ulong arg1) ++void helper_mtc0_wired(CPUMIPSState *env, target_ulong arg1) + { + env->CP0_Wired = arg1 % env->tlb->nb_tlb; + } + +-void helper_mtc0_srsconf0 (target_ulong arg1) ++void helper_mtc0_srsconf0(CPUMIPSState *env, target_ulong arg1) + { + env->CP0_SRSConf0 |= arg1 & env->CP0_SRSConf0_rw_bitmask; + } + +-void helper_mtc0_srsconf1 (target_ulong arg1) ++void helper_mtc0_srsconf1(CPUMIPSState *env, target_ulong arg1) + { + env->CP0_SRSConf1 |= arg1 & env->CP0_SRSConf1_rw_bitmask; + } + +-void helper_mtc0_srsconf2 (target_ulong arg1) ++void helper_mtc0_srsconf2(CPUMIPSState *env, target_ulong arg1) + { + env->CP0_SRSConf2 |= arg1 & env->CP0_SRSConf2_rw_bitmask; + } + +-void helper_mtc0_srsconf3 (target_ulong arg1) ++void helper_mtc0_srsconf3(CPUMIPSState *env, target_ulong arg1) + { + env->CP0_SRSConf3 |= arg1 & env->CP0_SRSConf3_rw_bitmask; + } + +-void helper_mtc0_srsconf4 (target_ulong arg1) ++void helper_mtc0_srsconf4(CPUMIPSState *env, target_ulong arg1) + { + env->CP0_SRSConf4 |= arg1 & env->CP0_SRSConf4_rw_bitmask; + } + +-void helper_mtc0_hwrena (target_ulong arg1) ++void helper_mtc0_hwrena(CPUMIPSState *env, target_ulong arg1) + { + env->CP0_HWREna = arg1 & 0x0000000F; + } + +-void helper_mtc0_count (target_ulong arg1) ++void helper_mtc0_count(CPUMIPSState *env, target_ulong arg1) + { + cpu_mips_store_count(env, arg1); + } + +-void helper_mtc0_entryhi (target_ulong arg1) ++void helper_mtc0_entryhi(CPUMIPSState *env, target_ulong arg1) + { + target_ulong old, val; + +@@ -1515,21 +1553,21 @@ void helper_mtc0_entryhi (target_ulong arg1) + cpu_mips_tlb_flush(env, 1); + } + +-void helper_mttc0_entryhi(target_ulong arg1) ++void helper_mttc0_entryhi(CPUMIPSState *env, target_ulong arg1) + { + int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); +- CPUMIPSState *other = mips_cpu_map_tc(&other_tc); ++ CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc); + + other->CP0_EntryHi = arg1; + sync_c0_entryhi(other, other_tc); + } + +-void helper_mtc0_compare (target_ulong arg1) ++void helper_mtc0_compare(CPUMIPSState *env, target_ulong arg1) + { + cpu_mips_store_compare(env, arg1); + } + +-void helper_mtc0_status (target_ulong arg1) ++void helper_mtc0_status(CPUMIPSState *env, target_ulong arg1) + { + uint32_t val, old; + uint32_t mask = env->CP0_Status_rw_bitmask; +@@ -1538,7 +1576,7 @@ void helper_mtc0_status (target_ulong arg1) + old = env->CP0_Status; + env->CP0_Status = (env->CP0_Status & ~mask) | val; + if (env->CP0_Config3 & (1 << CP0C3_MT)) { +- sync_c0_status(env, env->current_tc); ++ sync_c0_status(env, env, env->current_tc); + } else { + compute_hflags(env); + } +@@ -1557,22 +1595,22 @@ void helper_mtc0_status (target_ulong arg1) + } + } + +-void helper_mttc0_status(target_ulong arg1) ++void helper_mttc0_status(CPUMIPSState *env, target_ulong arg1) + { + int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); +- CPUMIPSState *other = mips_cpu_map_tc(&other_tc); ++ CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc); + + other->CP0_Status = arg1 & ~0xf1000018; +- sync_c0_status(other, other_tc); ++ sync_c0_status(env, other, other_tc); + } + +-void helper_mtc0_intctl (target_ulong arg1) ++void helper_mtc0_intctl(CPUMIPSState *env, target_ulong arg1) + { + /* vectored interrupts not implemented, no performance counters. */ + env->CP0_IntCtl = (env->CP0_IntCtl & ~0x000003e0) | (arg1 & 0x000003e0); + } + +-void helper_mtc0_srsctl (target_ulong arg1) ++void helper_mtc0_srsctl(CPUMIPSState *env, target_ulong arg1) + { + uint32_t mask = (0xf << CP0SRSCtl_ESS) | (0xf << CP0SRSCtl_PSS); + env->CP0_SRSCtl = (env->CP0_SRSCtl & ~mask) | (arg1 & mask); +@@ -1606,52 +1644,52 @@ static void mtc0_cause(CPUMIPSState *cpu, target_ulong arg1) + } + } + +-void helper_mtc0_cause(target_ulong arg1) ++void helper_mtc0_cause(CPUMIPSState *env, target_ulong arg1) + { + mtc0_cause(env, arg1); + } + +-void helper_mttc0_cause(target_ulong arg1) ++void helper_mttc0_cause(CPUMIPSState *env, target_ulong arg1) + { + int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); +- CPUMIPSState *other = mips_cpu_map_tc(&other_tc); ++ CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc); + + mtc0_cause(other, arg1); + } + +-target_ulong helper_mftc0_epc(void) ++target_ulong helper_mftc0_epc(CPUMIPSState *env) + { + int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); +- CPUMIPSState *other = mips_cpu_map_tc(&other_tc); ++ CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc); + + return other->CP0_EPC; + } + +-target_ulong helper_mftc0_ebase(void) ++target_ulong helper_mftc0_ebase(CPUMIPSState *env) + { + int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); +- CPUMIPSState *other = mips_cpu_map_tc(&other_tc); ++ CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc); + + return other->CP0_EBase; + } + +-void helper_mtc0_ebase (target_ulong arg1) ++void helper_mtc0_ebase(CPUMIPSState *env, target_ulong arg1) + { + /* vectored interrupts not implemented */ + env->CP0_EBase = (env->CP0_EBase & ~0x3FFFF000) | (arg1 & 0x3FFFF000); + } + +-void helper_mttc0_ebase(target_ulong arg1) ++void helper_mttc0_ebase(CPUMIPSState *env, target_ulong arg1) + { + int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); +- CPUMIPSState *other = mips_cpu_map_tc(&other_tc); ++ CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc); + other->CP0_EBase = (other->CP0_EBase & ~0x3FFFF000) | (arg1 & 0x3FFFF000); + } + +-target_ulong helper_mftc0_configx(target_ulong idx) ++target_ulong helper_mftc0_configx(CPUMIPSState *env, target_ulong idx) + { + int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); +- CPUMIPSState *other = mips_cpu_map_tc(&other_tc); ++ CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc); + + switch (idx) { + case 0: return other->CP0_Config0; +@@ -1667,49 +1705,49 @@ target_ulong helper_mftc0_configx(target_ulong idx) + return 0; + } + +-void helper_mtc0_config0 (target_ulong arg1) ++void helper_mtc0_config0(CPUMIPSState *env, target_ulong arg1) + { + env->CP0_Config0 = (env->CP0_Config0 & 0x81FFFFF8) | (arg1 & 0x00000007); + } + +-void helper_mtc0_config2 (target_ulong arg1) ++void helper_mtc0_config2(CPUMIPSState *env, target_ulong arg1) + { + /* tertiary/secondary caches not implemented */ + env->CP0_Config2 = (env->CP0_Config2 & 0x8FFF0FFF); + } + +-void helper_mtc0_lladdr (target_ulong arg1) ++void helper_mtc0_lladdr(CPUMIPSState *env, target_ulong arg1) + { + target_long mask = env->CP0_LLAddr_rw_bitmask; + arg1 = arg1 << env->CP0_LLAddr_shift; + env->lladdr = (env->lladdr & ~mask) | (arg1 & mask); + } + +-void helper_mtc0_watchlo (target_ulong arg1, uint32_t sel) ++void helper_mtc0_watchlo(CPUMIPSState *env, target_ulong arg1, uint32_t sel) + { + /* Watch exceptions for instructions, data loads, data stores + not implemented. */ + env->CP0_WatchLo[sel] = (arg1 & ~0x7); + } + +-void helper_mtc0_watchhi (target_ulong arg1, uint32_t sel) ++void helper_mtc0_watchhi(CPUMIPSState *env, target_ulong arg1, uint32_t sel) + { + env->CP0_WatchHi[sel] = (arg1 & 0x40FF0FF8); + env->CP0_WatchHi[sel] &= ~(env->CP0_WatchHi[sel] & arg1 & 0x7); + } + +-void helper_mtc0_xcontext (target_ulong arg1) ++void helper_mtc0_xcontext(CPUMIPSState *env, target_ulong arg1) + { + target_ulong mask = (1ULL << (env->SEGBITS - 7)) - 1; + env->CP0_XContext = (env->CP0_XContext & mask) | (arg1 & ~mask); + } + +-void helper_mtc0_framemask (target_ulong arg1) ++void helper_mtc0_framemask(CPUMIPSState *env, target_ulong arg1) + { + env->CP0_Framemask = arg1; /* XXX */ + } + +-void helper_mtc0_debug (target_ulong arg1) ++void helper_mtc0_debug(CPUMIPSState *env, target_ulong arg1) + { + env->CP0_Debug = (env->CP0_Debug & 0x8C03FC1F) | (arg1 & 0x13300120); + if (arg1 & (1 << CP0DB_DM)) +@@ -1718,11 +1756,11 @@ void helper_mtc0_debug (target_ulong arg1) + env->hflags &= ~MIPS_HFLAG_DM; + } + +-void helper_mttc0_debug(target_ulong arg1) ++void helper_mttc0_debug(CPUMIPSState *env, target_ulong arg1) + { + int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); + uint32_t val = arg1 & ((1 << CP0DB_SSt) | (1 << CP0DB_Halt)); +- CPUMIPSState *other = mips_cpu_map_tc(&other_tc); ++ CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc); + + /* XXX: Might be wrong, check with EJTAG spec. */ + if (other_tc == other->current_tc) +@@ -1734,36 +1772,36 @@ void helper_mttc0_debug(target_ulong arg1) + (arg1 & ~((1 << CP0DB_SSt) | (1 << CP0DB_Halt))); + } + +-void helper_mtc0_performance0 (target_ulong arg1) ++void helper_mtc0_performance0(CPUMIPSState *env, target_ulong arg1) + { + env->CP0_Performance0 = arg1 & 0x000007ff; + } + +-void helper_mtc0_taglo (target_ulong arg1) ++void helper_mtc0_taglo(CPUMIPSState *env, target_ulong arg1) + { + env->CP0_TagLo = arg1 & 0xFFFFFCF6; + } + +-void helper_mtc0_datalo (target_ulong arg1) ++void helper_mtc0_datalo(CPUMIPSState *env, target_ulong arg1) + { + env->CP0_DataLo = arg1; /* XXX */ + } + +-void helper_mtc0_taghi (target_ulong arg1) ++void helper_mtc0_taghi(CPUMIPSState *env, target_ulong arg1) + { + env->CP0_TagHi = arg1; /* XXX */ + } + +-void helper_mtc0_datahi (target_ulong arg1) ++void helper_mtc0_datahi(CPUMIPSState *env, target_ulong arg1) + { + env->CP0_DataHi = arg1; /* XXX */ + } + + /* MIPS MT functions */ +-target_ulong helper_mftgpr(uint32_t sel) ++target_ulong helper_mftgpr(CPUMIPSState *env, uint32_t sel) + { + int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); +- CPUMIPSState *other = mips_cpu_map_tc(&other_tc); ++ CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc); + + if (other_tc == other->current_tc) + return other->active_tc.gpr[sel]; +@@ -1771,10 +1809,10 @@ target_ulong helper_mftgpr(uint32_t sel) + return other->tcs[other_tc].gpr[sel]; + } + +-target_ulong helper_mftlo(uint32_t sel) ++target_ulong helper_mftlo(CPUMIPSState *env, uint32_t sel) + { + int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); +- CPUMIPSState *other = mips_cpu_map_tc(&other_tc); ++ CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc); + + if (other_tc == other->current_tc) + return other->active_tc.LO[sel]; +@@ -1782,10 +1820,10 @@ target_ulong helper_mftlo(uint32_t sel) + return other->tcs[other_tc].LO[sel]; + } + +-target_ulong helper_mfthi(uint32_t sel) ++target_ulong helper_mfthi(CPUMIPSState *env, uint32_t sel) + { + int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); +- CPUMIPSState *other = mips_cpu_map_tc(&other_tc); ++ CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc); + + if (other_tc == other->current_tc) + return other->active_tc.HI[sel]; +@@ -1793,10 +1831,10 @@ target_ulong helper_mfthi(uint32_t sel) + return other->tcs[other_tc].HI[sel]; + } + +-target_ulong helper_mftacx(uint32_t sel) ++target_ulong helper_mftacx(CPUMIPSState *env, uint32_t sel) + { + int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); +- CPUMIPSState *other = mips_cpu_map_tc(&other_tc); ++ CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc); + + if (other_tc == other->current_tc) + return other->active_tc.ACX[sel]; +@@ -1804,10 +1842,10 @@ target_ulong helper_mftacx(uint32_t sel) + return other->tcs[other_tc].ACX[sel]; + } + +-target_ulong helper_mftdsp(void) ++target_ulong helper_mftdsp(CPUMIPSState *env) + { + int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); +- CPUMIPSState *other = mips_cpu_map_tc(&other_tc); ++ CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc); + + if (other_tc == other->current_tc) + return other->active_tc.DSPControl; +@@ -1815,10 +1853,10 @@ target_ulong helper_mftdsp(void) + return other->tcs[other_tc].DSPControl; + } + +-void helper_mttgpr(target_ulong arg1, uint32_t sel) ++void helper_mttgpr(CPUMIPSState *env, target_ulong arg1, uint32_t sel) + { + int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); +- CPUMIPSState *other = mips_cpu_map_tc(&other_tc); ++ CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc); + + if (other_tc == other->current_tc) + other->active_tc.gpr[sel] = arg1; +@@ -1826,10 +1864,10 @@ void helper_mttgpr(target_ulong arg1, uint32_t sel) + other->tcs[other_tc].gpr[sel] = arg1; + } + +-void helper_mttlo(target_ulong arg1, uint32_t sel) ++void helper_mttlo(CPUMIPSState *env, target_ulong arg1, uint32_t sel) + { + int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); +- CPUMIPSState *other = mips_cpu_map_tc(&other_tc); ++ CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc); + + if (other_tc == other->current_tc) + other->active_tc.LO[sel] = arg1; +@@ -1837,10 +1875,10 @@ void helper_mttlo(target_ulong arg1, uint32_t sel) + other->tcs[other_tc].LO[sel] = arg1; + } + +-void helper_mtthi(target_ulong arg1, uint32_t sel) ++void helper_mtthi(CPUMIPSState *env, target_ulong arg1, uint32_t sel) + { + int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); +- CPUMIPSState *other = mips_cpu_map_tc(&other_tc); ++ CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc); + + if (other_tc == other->current_tc) + other->active_tc.HI[sel] = arg1; +@@ -1848,10 +1886,10 @@ void helper_mtthi(target_ulong arg1, uint32_t sel) + other->tcs[other_tc].HI[sel] = arg1; + } + +-void helper_mttacx(target_ulong arg1, uint32_t sel) ++void helper_mttacx(CPUMIPSState *env, target_ulong arg1, uint32_t sel) + { + int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); +- CPUMIPSState *other = mips_cpu_map_tc(&other_tc); ++ CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc); + + if (other_tc == other->current_tc) + other->active_tc.ACX[sel] = arg1; +@@ -1859,10 +1897,10 @@ void helper_mttacx(target_ulong arg1, uint32_t sel) + other->tcs[other_tc].ACX[sel] = arg1; + } + +-void helper_mttdsp(target_ulong arg1) ++void helper_mttdsp(CPUMIPSState *env, target_ulong arg1) + { + int other_tc = env->CP0_VPEControl & (0xff << CP0VPECo_TargTC); +- CPUMIPSState *other = mips_cpu_map_tc(&other_tc); ++ CPUMIPSState *other = mips_cpu_map_tc(env, &other_tc); + + if (other_tc == other->current_tc) + other->active_tc.DSPControl = arg1; +@@ -1883,7 +1921,7 @@ target_ulong helper_emt(void) + return 0; + } + +-target_ulong helper_dvpe(void) ++target_ulong helper_dvpe(CPUMIPSState *env) + { + CPUMIPSState *other_cpu = first_cpu; + target_ulong prev = env->mvp->CP0_MVPControl; +@@ -1899,7 +1937,7 @@ target_ulong helper_dvpe(void) + return prev; + } + +-target_ulong helper_evpe(void) ++target_ulong helper_evpe(CPUMIPSState *env) + { + CPUMIPSState *other_cpu = first_cpu; + target_ulong prev = env->mvp->CP0_MVPControl; +@@ -1925,7 +1963,7 @@ void helper_fork(target_ulong arg1, target_ulong arg2) + // TODO: store to TC register + } + +-target_ulong helper_yield(target_ulong arg) ++target_ulong helper_yield(CPUMIPSState *env, target_ulong arg) + { + target_long arg1 = arg; + +@@ -1936,13 +1974,13 @@ target_ulong helper_yield(target_ulong arg) + env->active_tc.CP0_TCStatus & (1 << CP0TCSt_DT)) { + env->CP0_VPEControl &= ~(0x7 << CP0VPECo_EXCPT); + env->CP0_VPEControl |= 4 << CP0VPECo_EXCPT; +- helper_raise_exception(EXCP_THREAD); ++ helper_raise_exception(env, EXCP_THREAD); + } + } + } else if (arg1 == 0) { + if (0 /* TODO: TC underflow */) { + env->CP0_VPEControl &= ~(0x7 << CP0VPECo_EXCPT); +- helper_raise_exception(EXCP_THREAD); ++ helper_raise_exception(env, EXCP_THREAD); + } else { + // TODO: Deallocate TC + } +@@ -1950,7 +1988,7 @@ target_ulong helper_yield(target_ulong arg) + /* Yield qualifier inputs not implemented. */ + env->CP0_VPEControl &= ~(0x7 << CP0VPECo_EXCPT); + env->CP0_VPEControl |= 2 << CP0VPECo_EXCPT; +- helper_raise_exception(EXCP_THREAD); ++ helper_raise_exception(env, EXCP_THREAD); + } + return env->CP0_YQMask; + } +@@ -1972,7 +2010,7 @@ static void r4k_mips_tlb_flush_extra (CPUMIPSState *env, int first) + } + } + +-static void r4k_fill_tlb (int idx) ++static void r4k_fill_tlb(CPUMIPSState *env, int idx) + { + r4k_tlb_t *tlb; + +@@ -1995,7 +2033,7 @@ static void r4k_fill_tlb (int idx) + tlb->PFN[1] = (env->CP0_EntryLo1 >> 6) << 12; + } + +-void r4k_helper_tlbwi (void) ++void r4k_helper_tlbwi(CPUMIPSState *env) + { + int idx; + +@@ -2007,18 +2045,18 @@ void r4k_helper_tlbwi (void) + r4k_mips_tlb_flush_extra (env, env->tlb->nb_tlb); + + r4k_invalidate_tlb(env, idx, 0); +- r4k_fill_tlb(idx); ++ r4k_fill_tlb(env, idx); + } + +-void r4k_helper_tlbwr (void) ++void r4k_helper_tlbwr(CPUMIPSState *env) + { + int r = cpu_mips_get_random(env); + + r4k_invalidate_tlb(env, r, 1); +- r4k_fill_tlb(r); ++ r4k_fill_tlb(env, r); + } + +-void r4k_helper_tlbp (void) ++void r4k_helper_tlbp(CPUMIPSState *env) + { + r4k_tlb_t *tlb; + target_ulong mask; +@@ -2060,7 +2098,7 @@ void r4k_helper_tlbp (void) + } + } + +-void r4k_helper_tlbr (void) ++void r4k_helper_tlbr(CPUMIPSState *env) + { + r4k_tlb_t *tlb; + uint8_t ASID; +@@ -2084,28 +2122,28 @@ void r4k_helper_tlbr (void) + (tlb->C1 << 3) | (tlb->PFN[1] >> 6); + } + +-void helper_tlbwi(void) ++void helper_tlbwi(CPUMIPSState *env) + { +- env->tlb->helper_tlbwi(); ++ env->tlb->helper_tlbwi(env); + } + +-void helper_tlbwr(void) ++void helper_tlbwr(CPUMIPSState *env) + { +- env->tlb->helper_tlbwr(); ++ env->tlb->helper_tlbwr(env); + } + +-void helper_tlbp(void) ++void helper_tlbp(CPUMIPSState *env) + { +- env->tlb->helper_tlbp(); ++ env->tlb->helper_tlbp(env); + } + +-void helper_tlbr(void) ++void helper_tlbr(CPUMIPSState *env) + { +- env->tlb->helper_tlbr(); ++ env->tlb->helper_tlbr(env); + } + + /* Specials */ +-target_ulong helper_di (void) ++target_ulong helper_di(CPUMIPSState *env) + { + target_ulong t0 = env->CP0_Status; + +@@ -2113,7 +2151,7 @@ target_ulong helper_di (void) + return t0; + } + +-target_ulong helper_ei (void) ++target_ulong helper_ei(CPUMIPSState *env) + { + target_ulong t0 = env->CP0_Status; + +@@ -2121,7 +2159,7 @@ target_ulong helper_ei (void) + return t0; + } + +-static void debug_pre_eret (void) ++static void debug_pre_eret(CPUMIPSState *env) + { + if (qemu_loglevel_mask(CPU_LOG_EXEC)) { + qemu_log("ERET: PC " TARGET_FMT_lx " EPC " TARGET_FMT_lx, +@@ -2134,7 +2172,7 @@ static void debug_pre_eret (void) + } + } + +-static void debug_post_eret (void) ++static void debug_post_eret(CPUMIPSState *env) + { + if (qemu_loglevel_mask(CPU_LOG_EXEC)) { + qemu_log(" => PC " TARGET_FMT_lx " EPC " TARGET_FMT_lx, +@@ -2152,7 +2190,7 @@ static void debug_post_eret (void) + } + } + +-static void set_pc (target_ulong error_pc) ++static void set_pc(CPUMIPSState *env, target_ulong error_pc) + { + env->active_tc.PC = error_pc & ~(target_ulong)1; + if (error_pc & 1) { +@@ -2162,78 +2200,78 @@ static void set_pc (target_ulong error_pc) + } + } + +-void helper_eret (void) ++void helper_eret(CPUMIPSState *env) + { +- debug_pre_eret(); ++ debug_pre_eret(env); + if (env->CP0_Status & (1 << CP0St_ERL)) { +- set_pc(env->CP0_ErrorEPC); ++ set_pc(env, env->CP0_ErrorEPC); + env->CP0_Status &= ~(1 << CP0St_ERL); + } else { +- set_pc(env->CP0_EPC); ++ set_pc(env, env->CP0_EPC); + env->CP0_Status &= ~(1 << CP0St_EXL); + } + compute_hflags(env); +- debug_post_eret(); ++ debug_post_eret(env); + env->lladdr = 1; + } + +-void helper_deret (void) ++void helper_deret(CPUMIPSState *env) + { +- debug_pre_eret(); +- set_pc(env->CP0_DEPC); ++ debug_pre_eret(env); ++ set_pc(env, env->CP0_DEPC); + + env->hflags &= MIPS_HFLAG_DM; + compute_hflags(env); +- debug_post_eret(); ++ debug_post_eret(env); + env->lladdr = 1; + } + #endif /* !CONFIG_USER_ONLY */ + +-target_ulong helper_rdhwr_cpunum(void) ++target_ulong helper_rdhwr_cpunum(CPUMIPSState *env) + { + if ((env->hflags & MIPS_HFLAG_CP0) || + (env->CP0_HWREna & (1 << 0))) + return env->CP0_EBase & 0x3ff; + else +- helper_raise_exception(EXCP_RI); ++ helper_raise_exception(env, EXCP_RI); + + return 0; + } + +-target_ulong helper_rdhwr_synci_step(void) ++target_ulong helper_rdhwr_synci_step(CPUMIPSState *env) + { + if ((env->hflags & MIPS_HFLAG_CP0) || + (env->CP0_HWREna & (1 << 1))) + return env->SYNCI_Step; + else +- helper_raise_exception(EXCP_RI); ++ helper_raise_exception(env, EXCP_RI); + + return 0; + } + +-target_ulong helper_rdhwr_cc(void) ++target_ulong helper_rdhwr_cc(CPUMIPSState *env) + { + if ((env->hflags & MIPS_HFLAG_CP0) || + (env->CP0_HWREna & (1 << 2))) + return env->CP0_Count; + else +- helper_raise_exception(EXCP_RI); ++ helper_raise_exception(env, EXCP_RI); + + return 0; + } + +-target_ulong helper_rdhwr_ccres(void) ++target_ulong helper_rdhwr_ccres(CPUMIPSState *env) + { + if ((env->hflags & MIPS_HFLAG_CP0) || + (env->CP0_HWREna & (1 << 3))) + return env->CCRes; + else +- helper_raise_exception(EXCP_RI); ++ helper_raise_exception(env, EXCP_RI); + + return 0; + } + +-void helper_pmon (int function) ++void helper_pmon(CPUMIPSState *env, int function) + { + function /= 2; + switch (function) { +@@ -2259,16 +2297,17 @@ void helper_pmon (int function) + } + } + +-void helper_wait (void) ++void helper_wait(CPUMIPSState *env) + { + env->halted = 1; + cpu_reset_interrupt(env, CPU_INTERRUPT_WAKE); +- helper_raise_exception(EXCP_HLT); ++ helper_raise_exception(env, EXCP_HLT); + } + + #if !defined(CONFIG_USER_ONLY) + +-static void QEMU_NORETURN do_unaligned_access(target_ulong addr, int is_write, ++static void QEMU_NORETURN do_unaligned_access(CPUMIPSState *env, ++ target_ulong addr, int is_write, + int is_user, uintptr_t retaddr); + + #define MMUSUFFIX _mmu +@@ -2286,23 +2325,20 @@ static void QEMU_NORETURN do_unaligned_access(target_ulong addr, int is_write, + #define SHIFT 3 + #include "softmmu_template.h" + +-static void do_unaligned_access(target_ulong addr, int is_write, +- int is_user, uintptr_t retaddr) ++static void do_unaligned_access(CPUMIPSState *env, target_ulong addr, ++ int is_write, int is_user, uintptr_t retaddr) + { + env->CP0_BadVAddr = addr; +- do_restore_state (retaddr); +- helper_raise_exception ((is_write == 1) ? EXCP_AdES : EXCP_AdEL); ++ do_restore_state(env, retaddr); ++ helper_raise_exception(env, (is_write == 1) ? EXCP_AdES : EXCP_AdEL); + } + +-void tlb_fill(CPUMIPSState *env1, target_ulong addr, int is_write, int mmu_idx, ++void tlb_fill(CPUMIPSState *env, target_ulong addr, int is_write, int mmu_idx, + uintptr_t retaddr) + { + TranslationBlock *tb; +- CPUMIPSState *saved_env; + int ret; + +- saved_env = env; +- env = env1; + ret = cpu_mips_handle_mmu_fault(env, addr, is_write, mmu_idx); + if (ret) { + if (retaddr) { +@@ -2314,20 +2350,17 @@ void tlb_fill(CPUMIPSState *env1, target_ulong addr, int is_write, int mmu_idx, + cpu_restore_state(tb, env, retaddr); + } + } +- helper_raise_exception_err(env->exception_index, env->error_code); ++ helper_raise_exception_err(env, env->exception_index, env->error_code); + } +- env = saved_env; + } + +-void cpu_unassigned_access(CPUMIPSState *env1, target_phys_addr_t addr, ++void cpu_unassigned_access(CPUMIPSState *env, target_phys_addr_t addr, + int is_write, int is_exec, int unused, int size) + { +- env = env1; +- + if (is_exec) +- helper_raise_exception(EXCP_IBE); ++ helper_raise_exception(env, EXCP_IBE); + else +- helper_raise_exception(EXCP_DBE); ++ helper_raise_exception(env, EXCP_DBE); + } + #endif /* !CONFIG_USER_ONLY */ + +@@ -2356,7 +2389,7 @@ static unsigned int ieee_rm[] = { + #define RESTORE_FLUSH_MODE \ + set_flush_to_zero((env->active_fpu.fcr31 & (1 << 24)) != 0, &env->active_fpu.fp_status); + +-target_ulong helper_cfc1 (uint32_t reg) ++target_ulong helper_cfc1(CPUMIPSState *env, uint32_t reg) + { + target_ulong arg1; + +@@ -2381,7 +2414,7 @@ target_ulong helper_cfc1 (uint32_t reg) + return arg1; + } + +-void helper_ctc1 (target_ulong arg1, uint32_t reg) ++void helper_ctc1(CPUMIPSState *env, target_ulong arg1, uint32_t reg) + { + switch(reg) { + case 25: +@@ -2415,7 +2448,7 @@ void helper_ctc1 (target_ulong arg1, uint32_t reg) + RESTORE_FLUSH_MODE; + set_float_exception_flags(0, &env->active_fpu.fp_status); + if ((GET_FP_ENABLE(env->active_fpu.fcr31) | 0x20) & GET_FP_CAUSE(env->active_fpu.fcr31)) +- helper_raise_exception(EXCP_FPE); ++ helper_raise_exception(env, EXCP_FPE); + } + + static inline int ieee_ex_to_mips(int xcpt) +@@ -2441,13 +2474,13 @@ static inline int ieee_ex_to_mips(int xcpt) + return ret; + } + +-static inline void update_fcr31(void) ++static inline void update_fcr31(CPUMIPSState *env) + { + int tmp = ieee_ex_to_mips(get_float_exception_flags(&env->active_fpu.fp_status)); + + SET_FP_CAUSE(env->active_fpu.fcr31, tmp); + if (GET_FP_ENABLE(env->active_fpu.fcr31) & tmp) +- helper_raise_exception(EXCP_FPE); ++ helper_raise_exception(env, EXCP_FPE); + else + UPDATE_FP_FLAGS(env->active_fpu.fcr31, tmp); + } +@@ -2458,71 +2491,71 @@ static inline void update_fcr31(void) + paired single lower "pl", paired single upper "pu". */ + + /* unary operations, modifying fp status */ +-uint64_t helper_float_sqrt_d(uint64_t fdt0) ++uint64_t helper_float_sqrt_d(CPUMIPSState *env, uint64_t fdt0) + { + return float64_sqrt(fdt0, &env->active_fpu.fp_status); + } + +-uint32_t helper_float_sqrt_s(uint32_t fst0) ++uint32_t helper_float_sqrt_s(CPUMIPSState *env, uint32_t fst0) + { + return float32_sqrt(fst0, &env->active_fpu.fp_status); + } + +-uint64_t helper_float_cvtd_s(uint32_t fst0) ++uint64_t helper_float_cvtd_s(CPUMIPSState *env, uint32_t fst0) + { + uint64_t fdt2; + + set_float_exception_flags(0, &env->active_fpu.fp_status); + fdt2 = float32_to_float64(fst0, &env->active_fpu.fp_status); +- update_fcr31(); ++ update_fcr31(env); + return fdt2; + } + +-uint64_t helper_float_cvtd_w(uint32_t wt0) ++uint64_t helper_float_cvtd_w(CPUMIPSState *env, uint32_t wt0) + { + uint64_t fdt2; + + set_float_exception_flags(0, &env->active_fpu.fp_status); + fdt2 = int32_to_float64(wt0, &env->active_fpu.fp_status); +- update_fcr31(); ++ update_fcr31(env); + return fdt2; + } + +-uint64_t helper_float_cvtd_l(uint64_t dt0) ++uint64_t helper_float_cvtd_l(CPUMIPSState *env, uint64_t dt0) + { + uint64_t fdt2; + + set_float_exception_flags(0, &env->active_fpu.fp_status); + fdt2 = int64_to_float64(dt0, &env->active_fpu.fp_status); +- update_fcr31(); ++ update_fcr31(env); + return fdt2; + } + +-uint64_t helper_float_cvtl_d(uint64_t fdt0) ++uint64_t helper_float_cvtl_d(CPUMIPSState *env, uint64_t fdt0) + { + uint64_t dt2; + + set_float_exception_flags(0, &env->active_fpu.fp_status); + dt2 = float64_to_int64(fdt0, &env->active_fpu.fp_status); +- update_fcr31(); ++ update_fcr31(env); + if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID)) + dt2 = FLOAT_SNAN64; + return dt2; + } + +-uint64_t helper_float_cvtl_s(uint32_t fst0) ++uint64_t helper_float_cvtl_s(CPUMIPSState *env, uint32_t fst0) + { + uint64_t dt2; + + set_float_exception_flags(0, &env->active_fpu.fp_status); + dt2 = float32_to_int64(fst0, &env->active_fpu.fp_status); +- update_fcr31(); ++ update_fcr31(env); + if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID)) + dt2 = FLOAT_SNAN64; + return dt2; + } + +-uint64_t helper_float_cvtps_pw(uint64_t dt0) ++uint64_t helper_float_cvtps_pw(CPUMIPSState *env, uint64_t dt0) + { + uint32_t fst2; + uint32_t fsth2; +@@ -2530,11 +2563,11 @@ uint64_t helper_float_cvtps_pw(uint64_t dt0) + set_float_exception_flags(0, &env->active_fpu.fp_status); + fst2 = int32_to_float32(dt0 & 0XFFFFFFFF, &env->active_fpu.fp_status); + fsth2 = int32_to_float32(dt0 >> 32, &env->active_fpu.fp_status); +- update_fcr31(); ++ update_fcr31(env); + return ((uint64_t)fsth2 << 32) | fst2; + } + +-uint64_t helper_float_cvtpw_ps(uint64_t fdt0) ++uint64_t helper_float_cvtpw_ps(CPUMIPSState *env, uint64_t fdt0) + { + uint32_t wt2; + uint32_t wth2; +@@ -2542,7 +2575,7 @@ uint64_t helper_float_cvtpw_ps(uint64_t fdt0) + set_float_exception_flags(0, &env->active_fpu.fp_status); + wt2 = float32_to_int32(fdt0 & 0XFFFFFFFF, &env->active_fpu.fp_status); + wth2 = float32_to_int32(fdt0 >> 32, &env->active_fpu.fp_status); +- update_fcr31(); ++ update_fcr31(env); + if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID)) { + wt2 = FLOAT_SNAN32; + wth2 = FLOAT_SNAN32; +@@ -2550,81 +2583,81 @@ uint64_t helper_float_cvtpw_ps(uint64_t fdt0) + return ((uint64_t)wth2 << 32) | wt2; + } + +-uint32_t helper_float_cvts_d(uint64_t fdt0) ++uint32_t helper_float_cvts_d(CPUMIPSState *env, uint64_t fdt0) + { + uint32_t fst2; + + set_float_exception_flags(0, &env->active_fpu.fp_status); + fst2 = float64_to_float32(fdt0, &env->active_fpu.fp_status); +- update_fcr31(); ++ update_fcr31(env); + return fst2; + } + +-uint32_t helper_float_cvts_w(uint32_t wt0) ++uint32_t helper_float_cvts_w(CPUMIPSState *env, uint32_t wt0) + { + uint32_t fst2; + + set_float_exception_flags(0, &env->active_fpu.fp_status); + fst2 = int32_to_float32(wt0, &env->active_fpu.fp_status); +- update_fcr31(); ++ update_fcr31(env); + return fst2; + } + +-uint32_t helper_float_cvts_l(uint64_t dt0) ++uint32_t helper_float_cvts_l(CPUMIPSState *env, uint64_t dt0) + { + uint32_t fst2; + + set_float_exception_flags(0, &env->active_fpu.fp_status); + fst2 = int64_to_float32(dt0, &env->active_fpu.fp_status); +- update_fcr31(); ++ update_fcr31(env); + return fst2; + } + +-uint32_t helper_float_cvts_pl(uint32_t wt0) ++uint32_t helper_float_cvts_pl(CPUMIPSState *env, uint32_t wt0) + { + uint32_t wt2; + + set_float_exception_flags(0, &env->active_fpu.fp_status); + wt2 = wt0; +- update_fcr31(); ++ update_fcr31(env); + return wt2; + } + +-uint32_t helper_float_cvts_pu(uint32_t wth0) ++uint32_t helper_float_cvts_pu(CPUMIPSState *env, uint32_t wth0) + { + uint32_t wt2; + + set_float_exception_flags(0, &env->active_fpu.fp_status); + wt2 = wth0; +- update_fcr31(); ++ update_fcr31(env); + return wt2; + } + +-uint32_t helper_float_cvtw_s(uint32_t fst0) ++uint32_t helper_float_cvtw_s(CPUMIPSState *env, uint32_t fst0) + { + uint32_t wt2; + + set_float_exception_flags(0, &env->active_fpu.fp_status); + wt2 = float32_to_int32(fst0, &env->active_fpu.fp_status); +- update_fcr31(); ++ update_fcr31(env); + if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID)) + wt2 = FLOAT_SNAN32; + return wt2; + } + +-uint32_t helper_float_cvtw_d(uint64_t fdt0) ++uint32_t helper_float_cvtw_d(CPUMIPSState *env, uint64_t fdt0) + { + uint32_t wt2; + + set_float_exception_flags(0, &env->active_fpu.fp_status); + wt2 = float64_to_int32(fdt0, &env->active_fpu.fp_status); +- update_fcr31(); ++ update_fcr31(env); + if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID)) + wt2 = FLOAT_SNAN32; + return wt2; + } + +-uint64_t helper_float_roundl_d(uint64_t fdt0) ++uint64_t helper_float_roundl_d(CPUMIPSState *env, uint64_t fdt0) + { + uint64_t dt2; + +@@ -2632,13 +2665,13 @@ uint64_t helper_float_roundl_d(uint64_t fdt0) + set_float_rounding_mode(float_round_nearest_even, &env->active_fpu.fp_status); + dt2 = float64_to_int64(fdt0, &env->active_fpu.fp_status); + RESTORE_ROUNDING_MODE; +- update_fcr31(); ++ update_fcr31(env); + if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID)) + dt2 = FLOAT_SNAN64; + return dt2; + } + +-uint64_t helper_float_roundl_s(uint32_t fst0) ++uint64_t helper_float_roundl_s(CPUMIPSState *env, uint32_t fst0) + { + uint64_t dt2; + +@@ -2646,13 +2679,13 @@ uint64_t helper_float_roundl_s(uint32_t fst0) + set_float_rounding_mode(float_round_nearest_even, &env->active_fpu.fp_status); + dt2 = float32_to_int64(fst0, &env->active_fpu.fp_status); + RESTORE_ROUNDING_MODE; +- update_fcr31(); ++ update_fcr31(env); + if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID)) + dt2 = FLOAT_SNAN64; + return dt2; + } + +-uint32_t helper_float_roundw_d(uint64_t fdt0) ++uint32_t helper_float_roundw_d(CPUMIPSState *env, uint64_t fdt0) + { + uint32_t wt2; + +@@ -2660,13 +2693,13 @@ uint32_t helper_float_roundw_d(uint64_t fdt0) + set_float_rounding_mode(float_round_nearest_even, &env->active_fpu.fp_status); + wt2 = float64_to_int32(fdt0, &env->active_fpu.fp_status); + RESTORE_ROUNDING_MODE; +- update_fcr31(); ++ update_fcr31(env); + if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID)) + wt2 = FLOAT_SNAN32; + return wt2; + } + +-uint32_t helper_float_roundw_s(uint32_t fst0) ++uint32_t helper_float_roundw_s(CPUMIPSState *env, uint32_t fst0) + { + uint32_t wt2; + +@@ -2674,61 +2707,61 @@ uint32_t helper_float_roundw_s(uint32_t fst0) + set_float_rounding_mode(float_round_nearest_even, &env->active_fpu.fp_status); + wt2 = float32_to_int32(fst0, &env->active_fpu.fp_status); + RESTORE_ROUNDING_MODE; +- update_fcr31(); ++ update_fcr31(env); + if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID)) + wt2 = FLOAT_SNAN32; + return wt2; + } + +-uint64_t helper_float_truncl_d(uint64_t fdt0) ++uint64_t helper_float_truncl_d(CPUMIPSState *env, uint64_t fdt0) + { + uint64_t dt2; + + set_float_exception_flags(0, &env->active_fpu.fp_status); + dt2 = float64_to_int64_round_to_zero(fdt0, &env->active_fpu.fp_status); +- update_fcr31(); ++ update_fcr31(env); + if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID)) + dt2 = FLOAT_SNAN64; + return dt2; + } + +-uint64_t helper_float_truncl_s(uint32_t fst0) ++uint64_t helper_float_truncl_s(CPUMIPSState *env, uint32_t fst0) + { + uint64_t dt2; + + set_float_exception_flags(0, &env->active_fpu.fp_status); + dt2 = float32_to_int64_round_to_zero(fst0, &env->active_fpu.fp_status); +- update_fcr31(); ++ update_fcr31(env); + if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID)) + dt2 = FLOAT_SNAN64; + return dt2; + } + +-uint32_t helper_float_truncw_d(uint64_t fdt0) ++uint32_t helper_float_truncw_d(CPUMIPSState *env, uint64_t fdt0) + { + uint32_t wt2; + + set_float_exception_flags(0, &env->active_fpu.fp_status); + wt2 = float64_to_int32_round_to_zero(fdt0, &env->active_fpu.fp_status); +- update_fcr31(); ++ update_fcr31(env); + if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID)) + wt2 = FLOAT_SNAN32; + return wt2; + } + +-uint32_t helper_float_truncw_s(uint32_t fst0) ++uint32_t helper_float_truncw_s(CPUMIPSState *env, uint32_t fst0) + { + uint32_t wt2; + + set_float_exception_flags(0, &env->active_fpu.fp_status); + wt2 = float32_to_int32_round_to_zero(fst0, &env->active_fpu.fp_status); +- update_fcr31(); ++ update_fcr31(env); + if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID)) + wt2 = FLOAT_SNAN32; + return wt2; + } + +-uint64_t helper_float_ceill_d(uint64_t fdt0) ++uint64_t helper_float_ceill_d(CPUMIPSState *env, uint64_t fdt0) + { + uint64_t dt2; + +@@ -2736,13 +2769,13 @@ uint64_t helper_float_ceill_d(uint64_t fdt0) + set_float_rounding_mode(float_round_up, &env->active_fpu.fp_status); + dt2 = float64_to_int64(fdt0, &env->active_fpu.fp_status); + RESTORE_ROUNDING_MODE; +- update_fcr31(); ++ update_fcr31(env); + if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID)) + dt2 = FLOAT_SNAN64; + return dt2; + } + +-uint64_t helper_float_ceill_s(uint32_t fst0) ++uint64_t helper_float_ceill_s(CPUMIPSState *env, uint32_t fst0) + { + uint64_t dt2; + +@@ -2750,13 +2783,13 @@ uint64_t helper_float_ceill_s(uint32_t fst0) + set_float_rounding_mode(float_round_up, &env->active_fpu.fp_status); + dt2 = float32_to_int64(fst0, &env->active_fpu.fp_status); + RESTORE_ROUNDING_MODE; +- update_fcr31(); ++ update_fcr31(env); + if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID)) + dt2 = FLOAT_SNAN64; + return dt2; + } + +-uint32_t helper_float_ceilw_d(uint64_t fdt0) ++uint32_t helper_float_ceilw_d(CPUMIPSState *env, uint64_t fdt0) + { + uint32_t wt2; + +@@ -2764,13 +2797,13 @@ uint32_t helper_float_ceilw_d(uint64_t fdt0) + set_float_rounding_mode(float_round_up, &env->active_fpu.fp_status); + wt2 = float64_to_int32(fdt0, &env->active_fpu.fp_status); + RESTORE_ROUNDING_MODE; +- update_fcr31(); ++ update_fcr31(env); + if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID)) + wt2 = FLOAT_SNAN32; + return wt2; + } + +-uint32_t helper_float_ceilw_s(uint32_t fst0) ++uint32_t helper_float_ceilw_s(CPUMIPSState *env, uint32_t fst0) + { + uint32_t wt2; + +@@ -2778,13 +2811,13 @@ uint32_t helper_float_ceilw_s(uint32_t fst0) + set_float_rounding_mode(float_round_up, &env->active_fpu.fp_status); + wt2 = float32_to_int32(fst0, &env->active_fpu.fp_status); + RESTORE_ROUNDING_MODE; +- update_fcr31(); ++ update_fcr31(env); + if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID)) + wt2 = FLOAT_SNAN32; + return wt2; + } + +-uint64_t helper_float_floorl_d(uint64_t fdt0) ++uint64_t helper_float_floorl_d(CPUMIPSState *env, uint64_t fdt0) + { + uint64_t dt2; + +@@ -2792,13 +2825,13 @@ uint64_t helper_float_floorl_d(uint64_t fdt0) + set_float_rounding_mode(float_round_down, &env->active_fpu.fp_status); + dt2 = float64_to_int64(fdt0, &env->active_fpu.fp_status); + RESTORE_ROUNDING_MODE; +- update_fcr31(); ++ update_fcr31(env); + if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID)) + dt2 = FLOAT_SNAN64; + return dt2; + } + +-uint64_t helper_float_floorl_s(uint32_t fst0) ++uint64_t helper_float_floorl_s(CPUMIPSState *env, uint32_t fst0) + { + uint64_t dt2; + +@@ -2806,13 +2839,13 @@ uint64_t helper_float_floorl_s(uint32_t fst0) + set_float_rounding_mode(float_round_down, &env->active_fpu.fp_status); + dt2 = float32_to_int64(fst0, &env->active_fpu.fp_status); + RESTORE_ROUNDING_MODE; +- update_fcr31(); ++ update_fcr31(env); + if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID)) + dt2 = FLOAT_SNAN64; + return dt2; + } + +-uint32_t helper_float_floorw_d(uint64_t fdt0) ++uint32_t helper_float_floorw_d(CPUMIPSState *env, uint64_t fdt0) + { + uint32_t wt2; + +@@ -2820,13 +2853,13 @@ uint32_t helper_float_floorw_d(uint64_t fdt0) + set_float_rounding_mode(float_round_down, &env->active_fpu.fp_status); + wt2 = float64_to_int32(fdt0, &env->active_fpu.fp_status); + RESTORE_ROUNDING_MODE; +- update_fcr31(); ++ update_fcr31(env); + if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID)) + wt2 = FLOAT_SNAN32; + return wt2; + } + +-uint32_t helper_float_floorw_s(uint32_t fst0) ++uint32_t helper_float_floorw_s(CPUMIPSState *env, uint32_t fst0) + { + uint32_t wt2; + +@@ -2834,7 +2867,7 @@ uint32_t helper_float_floorw_s(uint32_t fst0) + set_float_rounding_mode(float_round_down, &env->active_fpu.fp_status); + wt2 = float32_to_int32(fst0, &env->active_fpu.fp_status); + RESTORE_ROUNDING_MODE; +- update_fcr31(); ++ update_fcr31(env); + if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID)) + wt2 = FLOAT_SNAN32; + return wt2; +@@ -2864,69 +2897,69 @@ FLOAT_UNOP(chs) + #undef FLOAT_UNOP + + /* MIPS specific unary operations */ +-uint64_t helper_float_recip_d(uint64_t fdt0) ++uint64_t helper_float_recip_d(CPUMIPSState *env, uint64_t fdt0) + { + uint64_t fdt2; + + set_float_exception_flags(0, &env->active_fpu.fp_status); + fdt2 = float64_div(FLOAT_ONE64, fdt0, &env->active_fpu.fp_status); +- update_fcr31(); ++ update_fcr31(env); + return fdt2; + } + +-uint32_t helper_float_recip_s(uint32_t fst0) ++uint32_t helper_float_recip_s(CPUMIPSState *env, uint32_t fst0) + { + uint32_t fst2; + + set_float_exception_flags(0, &env->active_fpu.fp_status); + fst2 = float32_div(FLOAT_ONE32, fst0, &env->active_fpu.fp_status); +- update_fcr31(); ++ update_fcr31(env); + return fst2; + } + +-uint64_t helper_float_rsqrt_d(uint64_t fdt0) ++uint64_t helper_float_rsqrt_d(CPUMIPSState *env, uint64_t fdt0) + { + uint64_t fdt2; + + set_float_exception_flags(0, &env->active_fpu.fp_status); + fdt2 = float64_sqrt(fdt0, &env->active_fpu.fp_status); + fdt2 = float64_div(FLOAT_ONE64, fdt2, &env->active_fpu.fp_status); +- update_fcr31(); ++ update_fcr31(env); + return fdt2; + } + +-uint32_t helper_float_rsqrt_s(uint32_t fst0) ++uint32_t helper_float_rsqrt_s(CPUMIPSState *env, uint32_t fst0) + { + uint32_t fst2; + + set_float_exception_flags(0, &env->active_fpu.fp_status); + fst2 = float32_sqrt(fst0, &env->active_fpu.fp_status); + fst2 = float32_div(FLOAT_ONE32, fst2, &env->active_fpu.fp_status); +- update_fcr31(); ++ update_fcr31(env); + return fst2; + } + +-uint64_t helper_float_recip1_d(uint64_t fdt0) ++uint64_t helper_float_recip1_d(CPUMIPSState *env, uint64_t fdt0) + { + uint64_t fdt2; + + set_float_exception_flags(0, &env->active_fpu.fp_status); + fdt2 = float64_div(FLOAT_ONE64, fdt0, &env->active_fpu.fp_status); +- update_fcr31(); ++ update_fcr31(env); + return fdt2; + } + +-uint32_t helper_float_recip1_s(uint32_t fst0) ++uint32_t helper_float_recip1_s(CPUMIPSState *env, uint32_t fst0) + { + uint32_t fst2; + + set_float_exception_flags(0, &env->active_fpu.fp_status); + fst2 = float32_div(FLOAT_ONE32, fst0, &env->active_fpu.fp_status); +- update_fcr31(); ++ update_fcr31(env); + return fst2; + } + +-uint64_t helper_float_recip1_ps(uint64_t fdt0) ++uint64_t helper_float_recip1_ps(CPUMIPSState *env, uint64_t fdt0) + { + uint32_t fst2; + uint32_t fsth2; +@@ -2934,33 +2967,33 @@ uint64_t helper_float_recip1_ps(uint64_t fdt0) + set_float_exception_flags(0, &env->active_fpu.fp_status); + fst2 = float32_div(FLOAT_ONE32, fdt0 & 0XFFFFFFFF, &env->active_fpu.fp_status); + fsth2 = float32_div(FLOAT_ONE32, fdt0 >> 32, &env->active_fpu.fp_status); +- update_fcr31(); ++ update_fcr31(env); + return ((uint64_t)fsth2 << 32) | fst2; + } + +-uint64_t helper_float_rsqrt1_d(uint64_t fdt0) ++uint64_t helper_float_rsqrt1_d(CPUMIPSState *env, uint64_t fdt0) + { + uint64_t fdt2; + + set_float_exception_flags(0, &env->active_fpu.fp_status); + fdt2 = float64_sqrt(fdt0, &env->active_fpu.fp_status); + fdt2 = float64_div(FLOAT_ONE64, fdt2, &env->active_fpu.fp_status); +- update_fcr31(); ++ update_fcr31(env); + return fdt2; + } + +-uint32_t helper_float_rsqrt1_s(uint32_t fst0) ++uint32_t helper_float_rsqrt1_s(CPUMIPSState *env, uint32_t fst0) + { + uint32_t fst2; + + set_float_exception_flags(0, &env->active_fpu.fp_status); + fst2 = float32_sqrt(fst0, &env->active_fpu.fp_status); + fst2 = float32_div(FLOAT_ONE32, fst2, &env->active_fpu.fp_status); +- update_fcr31(); ++ update_fcr31(env); + return fst2; + } + +-uint64_t helper_float_rsqrt1_ps(uint64_t fdt0) ++uint64_t helper_float_rsqrt1_ps(CPUMIPSState *env, uint64_t fdt0) + { + uint32_t fst2; + uint32_t fsth2; +@@ -2970,39 +3003,43 @@ uint64_t helper_float_rsqrt1_ps(uint64_t fdt0) + fsth2 = float32_sqrt(fdt0 >> 32, &env->active_fpu.fp_status); + fst2 = float32_div(FLOAT_ONE32, fst2, &env->active_fpu.fp_status); + fsth2 = float32_div(FLOAT_ONE32, fsth2, &env->active_fpu.fp_status); +- update_fcr31(); ++ update_fcr31(env); + return ((uint64_t)fsth2 << 32) | fst2; + } + +-#define FLOAT_OP(name, p) void helper_float_##name##_##p(void) ++#define FLOAT_OP(name, p) void helper_float_##name##_##p(CPUMIPSState *env) + + /* binary operations */ + #define FLOAT_BINOP(name) \ +-uint64_t helper_float_ ## name ## _d(uint64_t fdt0, uint64_t fdt1) \ ++uint64_t helper_float_ ## name ## _d(CPUMIPSState *env, \ ++ uint64_t fdt0, uint64_t fdt1) \ + { \ + uint64_t dt2; \ + \ + set_float_exception_flags(0, &env->active_fpu.fp_status); \ + dt2 = float64_ ## name (fdt0, fdt1, &env->active_fpu.fp_status); \ +- update_fcr31(); \ ++ update_fcr31(env); \ + if (GET_FP_CAUSE(env->active_fpu.fcr31) & FP_INVALID) \ + dt2 = FLOAT_QNAN64; \ + return dt2; \ + } \ + \ +-uint32_t helper_float_ ## name ## _s(uint32_t fst0, uint32_t fst1) \ ++uint32_t helper_float_ ## name ## _s(CPUMIPSState *env, \ ++ uint32_t fst0, uint32_t fst1) \ + { \ + uint32_t wt2; \ + \ + set_float_exception_flags(0, &env->active_fpu.fp_status); \ + wt2 = float32_ ## name (fst0, fst1, &env->active_fpu.fp_status); \ +- update_fcr31(); \ ++ update_fcr31(env); \ + if (GET_FP_CAUSE(env->active_fpu.fcr31) & FP_INVALID) \ + wt2 = FLOAT_QNAN32; \ + return wt2; \ + } \ + \ +-uint64_t helper_float_ ## name ## _ps(uint64_t fdt0, uint64_t fdt1) \ ++uint64_t helper_float_ ## name ## _ps(CPUMIPSState *env, \ ++ uint64_t fdt0, \ ++ uint64_t fdt1) \ + { \ + uint32_t fst0 = fdt0 & 0XFFFFFFFF; \ + uint32_t fsth0 = fdt0 >> 32; \ +@@ -3014,7 +3051,7 @@ uint64_t helper_float_ ## name ## _ps(uint64_t fdt0, uint64_t fdt1) \ + set_float_exception_flags(0, &env->active_fpu.fp_status); \ + wt2 = float32_ ## name (fst0, fst1, &env->active_fpu.fp_status); \ + wth2 = float32_ ## name (fsth0, fsth1, &env->active_fpu.fp_status); \ +- update_fcr31(); \ ++ update_fcr31(env); \ + if (GET_FP_CAUSE(env->active_fpu.fcr31) & FP_INVALID) { \ + wt2 = FLOAT_QNAN32; \ + wth2 = FLOAT_QNAN32; \ +@@ -3030,22 +3067,28 @@ FLOAT_BINOP(div) + + /* ternary operations */ + #define FLOAT_TERNOP(name1, name2) \ +-uint64_t helper_float_ ## name1 ## name2 ## _d(uint64_t fdt0, uint64_t fdt1, \ +- uint64_t fdt2) \ ++uint64_t helper_float_ ## name1 ## name2 ## _d(CPUMIPSState *env, \ ++ uint64_t fdt0, \ ++ uint64_t fdt1, \ ++ uint64_t fdt2) \ + { \ + fdt0 = float64_ ## name1 (fdt0, fdt1, &env->active_fpu.fp_status); \ + return float64_ ## name2 (fdt0, fdt2, &env->active_fpu.fp_status); \ + } \ + \ +-uint32_t helper_float_ ## name1 ## name2 ## _s(uint32_t fst0, uint32_t fst1, \ +- uint32_t fst2) \ ++uint32_t helper_float_ ## name1 ## name2 ## _s(CPUMIPSState *env, \ ++ uint32_t fst0, \ ++ uint32_t fst1, \ ++ uint32_t fst2) \ + { \ + fst0 = float32_ ## name1 (fst0, fst1, &env->active_fpu.fp_status); \ + return float32_ ## name2 (fst0, fst2, &env->active_fpu.fp_status); \ + } \ + \ +-uint64_t helper_float_ ## name1 ## name2 ## _ps(uint64_t fdt0, uint64_t fdt1, \ +- uint64_t fdt2) \ ++uint64_t helper_float_ ## name1 ## name2 ## _ps(CPUMIPSState *env, \ ++ uint64_t fdt0, \ ++ uint64_t fdt1, \ ++ uint64_t fdt2) \ + { \ + uint32_t fst0 = fdt0 & 0XFFFFFFFF; \ + uint32_t fsth0 = fdt0 >> 32; \ +@@ -3067,24 +3110,30 @@ FLOAT_TERNOP(mul, sub) + + /* negated ternary operations */ + #define FLOAT_NTERNOP(name1, name2) \ +-uint64_t helper_float_n ## name1 ## name2 ## _d(uint64_t fdt0, uint64_t fdt1, \ +- uint64_t fdt2) \ ++uint64_t helper_float_n ## name1 ## name2 ## _d(CPUMIPSState *env, \ ++ uint64_t fdt0, \ ++ uint64_t fdt1, \ ++ uint64_t fdt2) \ + { \ + fdt0 = float64_ ## name1 (fdt0, fdt1, &env->active_fpu.fp_status); \ + fdt2 = float64_ ## name2 (fdt0, fdt2, &env->active_fpu.fp_status); \ + return float64_chs(fdt2); \ + } \ + \ +-uint32_t helper_float_n ## name1 ## name2 ## _s(uint32_t fst0, uint32_t fst1, \ +- uint32_t fst2) \ ++uint32_t helper_float_n ## name1 ## name2 ## _s(CPUMIPSState *env, \ ++ uint32_t fst0, \ ++ uint32_t fst1, \ ++ uint32_t fst2) \ + { \ + fst0 = float32_ ## name1 (fst0, fst1, &env->active_fpu.fp_status); \ + fst2 = float32_ ## name2 (fst0, fst2, &env->active_fpu.fp_status); \ + return float32_chs(fst2); \ + } \ + \ +-uint64_t helper_float_n ## name1 ## name2 ## _ps(uint64_t fdt0, uint64_t fdt1,\ +- uint64_t fdt2) \ ++uint64_t helper_float_n ## name1 ## name2 ## _ps(CPUMIPSState *env, \ ++ uint64_t fdt0, \ ++ uint64_t fdt1, \ ++ uint64_t fdt2) \ + { \ + uint32_t fst0 = fdt0 & 0XFFFFFFFF; \ + uint32_t fsth0 = fdt0 >> 32; \ +@@ -3107,25 +3156,25 @@ FLOAT_NTERNOP(mul, sub) + #undef FLOAT_NTERNOP + + /* MIPS specific binary operations */ +-uint64_t helper_float_recip2_d(uint64_t fdt0, uint64_t fdt2) ++uint64_t helper_float_recip2_d(CPUMIPSState *env, uint64_t fdt0, uint64_t fdt2) + { + set_float_exception_flags(0, &env->active_fpu.fp_status); + fdt2 = float64_mul(fdt0, fdt2, &env->active_fpu.fp_status); + fdt2 = float64_chs(float64_sub(fdt2, FLOAT_ONE64, &env->active_fpu.fp_status)); +- update_fcr31(); ++ update_fcr31(env); + return fdt2; + } + +-uint32_t helper_float_recip2_s(uint32_t fst0, uint32_t fst2) ++uint32_t helper_float_recip2_s(CPUMIPSState *env, uint32_t fst0, uint32_t fst2) + { + set_float_exception_flags(0, &env->active_fpu.fp_status); + fst2 = float32_mul(fst0, fst2, &env->active_fpu.fp_status); + fst2 = float32_chs(float32_sub(fst2, FLOAT_ONE32, &env->active_fpu.fp_status)); +- update_fcr31(); ++ update_fcr31(env); + return fst2; + } + +-uint64_t helper_float_recip2_ps(uint64_t fdt0, uint64_t fdt2) ++uint64_t helper_float_recip2_ps(CPUMIPSState *env, uint64_t fdt0, uint64_t fdt2) + { + uint32_t fst0 = fdt0 & 0XFFFFFFFF; + uint32_t fsth0 = fdt0 >> 32; +@@ -3137,31 +3186,31 @@ uint64_t helper_float_recip2_ps(uint64_t fdt0, uint64_t fdt2) + fsth2 = float32_mul(fsth0, fsth2, &env->active_fpu.fp_status); + fst2 = float32_chs(float32_sub(fst2, FLOAT_ONE32, &env->active_fpu.fp_status)); + fsth2 = float32_chs(float32_sub(fsth2, FLOAT_ONE32, &env->active_fpu.fp_status)); +- update_fcr31(); ++ update_fcr31(env); + return ((uint64_t)fsth2 << 32) | fst2; + } + +-uint64_t helper_float_rsqrt2_d(uint64_t fdt0, uint64_t fdt2) ++uint64_t helper_float_rsqrt2_d(CPUMIPSState *env, uint64_t fdt0, uint64_t fdt2) + { + set_float_exception_flags(0, &env->active_fpu.fp_status); + fdt2 = float64_mul(fdt0, fdt2, &env->active_fpu.fp_status); + fdt2 = float64_sub(fdt2, FLOAT_ONE64, &env->active_fpu.fp_status); + fdt2 = float64_chs(float64_div(fdt2, FLOAT_TWO64, &env->active_fpu.fp_status)); +- update_fcr31(); ++ update_fcr31(env); + return fdt2; + } + +-uint32_t helper_float_rsqrt2_s(uint32_t fst0, uint32_t fst2) ++uint32_t helper_float_rsqrt2_s(CPUMIPSState *env, uint32_t fst0, uint32_t fst2) + { + set_float_exception_flags(0, &env->active_fpu.fp_status); + fst2 = float32_mul(fst0, fst2, &env->active_fpu.fp_status); + fst2 = float32_sub(fst2, FLOAT_ONE32, &env->active_fpu.fp_status); + fst2 = float32_chs(float32_div(fst2, FLOAT_TWO32, &env->active_fpu.fp_status)); +- update_fcr31(); ++ update_fcr31(env); + return fst2; + } + +-uint64_t helper_float_rsqrt2_ps(uint64_t fdt0, uint64_t fdt2) ++uint64_t helper_float_rsqrt2_ps(CPUMIPSState *env, uint64_t fdt0, uint64_t fdt2) + { + uint32_t fst0 = fdt0 & 0XFFFFFFFF; + uint32_t fsth0 = fdt0 >> 32; +@@ -3175,11 +3224,11 @@ uint64_t helper_float_rsqrt2_ps(uint64_t fdt0, uint64_t fdt2) + fsth2 = float32_sub(fsth2, FLOAT_ONE32, &env->active_fpu.fp_status); + fst2 = float32_chs(float32_div(fst2, FLOAT_TWO32, &env->active_fpu.fp_status)); + fsth2 = float32_chs(float32_div(fsth2, FLOAT_TWO32, &env->active_fpu.fp_status)); +- update_fcr31(); ++ update_fcr31(env); + return ((uint64_t)fsth2 << 32) | fst2; + } + +-uint64_t helper_float_addr_ps(uint64_t fdt0, uint64_t fdt1) ++uint64_t helper_float_addr_ps(CPUMIPSState *env, uint64_t fdt0, uint64_t fdt1) + { + uint32_t fst0 = fdt0 & 0XFFFFFFFF; + uint32_t fsth0 = fdt0 >> 32; +@@ -3191,11 +3240,11 @@ uint64_t helper_float_addr_ps(uint64_t fdt0, uint64_t fdt1) + set_float_exception_flags(0, &env->active_fpu.fp_status); + fst2 = float32_add (fst0, fsth0, &env->active_fpu.fp_status); + fsth2 = float32_add (fst1, fsth1, &env->active_fpu.fp_status); +- update_fcr31(); ++ update_fcr31(env); + return ((uint64_t)fsth2 << 32) | fst2; + } + +-uint64_t helper_float_mulr_ps(uint64_t fdt0, uint64_t fdt1) ++uint64_t helper_float_mulr_ps(CPUMIPSState *env, uint64_t fdt0, uint64_t fdt1) + { + uint32_t fst0 = fdt0 & 0XFFFFFFFF; + uint32_t fsth0 = fdt0 >> 32; +@@ -3207,31 +3256,33 @@ uint64_t helper_float_mulr_ps(uint64_t fdt0, uint64_t fdt1) + set_float_exception_flags(0, &env->active_fpu.fp_status); + fst2 = float32_mul (fst0, fsth0, &env->active_fpu.fp_status); + fsth2 = float32_mul (fst1, fsth1, &env->active_fpu.fp_status); +- update_fcr31(); ++ update_fcr31(env); + return ((uint64_t)fsth2 << 32) | fst2; + } + + /* compare operations */ + #define FOP_COND_D(op, cond) \ +-void helper_cmp_d_ ## op (uint64_t fdt0, uint64_t fdt1, int cc) \ ++void helper_cmp_d_ ## op(CPUMIPSState *env, uint64_t fdt0, \ ++ uint64_t fdt1, int cc) \ + { \ + int c; \ + set_float_exception_flags(0, &env->active_fpu.fp_status); \ + c = cond; \ +- update_fcr31(); \ ++ update_fcr31(env); \ + if (c) \ + SET_FP_COND(cc, env->active_fpu); \ + else \ + CLEAR_FP_COND(cc, env->active_fpu); \ + } \ +-void helper_cmpabs_d_ ## op (uint64_t fdt0, uint64_t fdt1, int cc) \ ++void helper_cmpabs_d_ ## op(CPUMIPSState *env, uint64_t fdt0, \ ++ uint64_t fdt1, int cc) \ + { \ + int c; \ + set_float_exception_flags(0, &env->active_fpu.fp_status); \ + fdt0 = float64_abs(fdt0); \ + fdt1 = float64_abs(fdt1); \ + c = cond; \ +- update_fcr31(); \ ++ update_fcr31(env); \ + if (c) \ + SET_FP_COND(cc, env->active_fpu); \ + else \ +@@ -3260,25 +3311,27 @@ FOP_COND_D(le, float64_le(fdt0, fdt1, &env->active_fpu.fp_status)) + FOP_COND_D(ngt, float64_unordered(fdt1, fdt0, &env->active_fpu.fp_status) || float64_le(fdt0, fdt1, &env->active_fpu.fp_status)) + + #define FOP_COND_S(op, cond) \ +-void helper_cmp_s_ ## op (uint32_t fst0, uint32_t fst1, int cc) \ ++void helper_cmp_s_ ## op(CPUMIPSState *env, uint32_t fst0, \ ++ uint32_t fst1, int cc) \ + { \ + int c; \ + set_float_exception_flags(0, &env->active_fpu.fp_status); \ + c = cond; \ +- update_fcr31(); \ ++ update_fcr31(env); \ + if (c) \ + SET_FP_COND(cc, env->active_fpu); \ + else \ + CLEAR_FP_COND(cc, env->active_fpu); \ + } \ +-void helper_cmpabs_s_ ## op (uint32_t fst0, uint32_t fst1, int cc) \ ++void helper_cmpabs_s_ ## op(CPUMIPSState *env, uint32_t fst0, \ ++ uint32_t fst1, int cc) \ + { \ + int c; \ + set_float_exception_flags(0, &env->active_fpu.fp_status); \ + fst0 = float32_abs(fst0); \ + fst1 = float32_abs(fst1); \ + c = cond; \ +- update_fcr31(); \ ++ update_fcr31(env); \ + if (c) \ + SET_FP_COND(cc, env->active_fpu); \ + else \ +@@ -3307,7 +3360,8 @@ FOP_COND_S(le, float32_le(fst0, fst1, &env->active_fpu.fp_status)) + FOP_COND_S(ngt, float32_unordered(fst1, fst0, &env->active_fpu.fp_status) || float32_le(fst0, fst1, &env->active_fpu.fp_status)) + + #define FOP_COND_PS(op, condl, condh) \ +-void helper_cmp_ps_ ## op (uint64_t fdt0, uint64_t fdt1, int cc) \ ++void helper_cmp_ps_ ## op(CPUMIPSState *env, uint64_t fdt0, \ ++ uint64_t fdt1, int cc) \ + { \ + uint32_t fst0, fsth0, fst1, fsth1; \ + int ch, cl; \ +@@ -3318,7 +3372,7 @@ void helper_cmp_ps_ ## op (uint64_t fdt0, uint64_t fdt1, int cc) \ + fsth1 = fdt1 >> 32; \ + cl = condl; \ + ch = condh; \ +- update_fcr31(); \ ++ update_fcr31(env); \ + if (cl) \ + SET_FP_COND(cc, env->active_fpu); \ + else \ +@@ -3328,7 +3382,8 @@ void helper_cmp_ps_ ## op (uint64_t fdt0, uint64_t fdt1, int cc) \ + else \ + CLEAR_FP_COND(cc + 1, env->active_fpu); \ + } \ +-void helper_cmpabs_ps_ ## op (uint64_t fdt0, uint64_t fdt1, int cc) \ ++void helper_cmpabs_ps_ ## op(CPUMIPSState *env, uint64_t fdt0, \ ++ uint64_t fdt1, int cc) \ + { \ + uint32_t fst0, fsth0, fst1, fsth1; \ + int ch, cl; \ +@@ -3338,7 +3393,7 @@ void helper_cmpabs_ps_ ## op (uint64_t fdt0, uint64_t fdt1, int cc) \ + fsth1 = float32_abs(fdt1 >> 32); \ + cl = condl; \ + ch = condh; \ +- update_fcr31(); \ ++ update_fcr31(env); \ + if (cl) \ + SET_FP_COND(cc, env->active_fpu); \ + else \ +diff --git a/target-mips/translate.c b/target-mips/translate.c +index b293419..7ab769f 100644 +--- a/target-mips/translate.c ++++ b/target-mips/translate.c +@@ -483,27 +483,45 @@ static uint32_t gen_opc_hflags[OPC_BUF_SIZE]; + + #include "gen-icount.h" + +-#define gen_helper_0i(name, arg) do { \ ++#define gen_helper_0e0i(name, arg) do { \ + TCGv_i32 helper_tmp = tcg_const_i32(arg); \ +- gen_helper_##name(helper_tmp); \ ++ gen_helper_##name(cpu_env, helper_tmp); \ + tcg_temp_free_i32(helper_tmp); \ + } while(0) + +-#define gen_helper_1i(name, arg1, arg2) do { \ ++#define gen_helper_0e1i(name, arg1, arg2) do { \ + TCGv_i32 helper_tmp = tcg_const_i32(arg2); \ +- gen_helper_##name(arg1, helper_tmp); \ ++ gen_helper_##name(cpu_env, arg1, helper_tmp); \ + tcg_temp_free_i32(helper_tmp); \ + } while(0) + +-#define gen_helper_2i(name, arg1, arg2, arg3) do { \ ++#define gen_helper_1e0i(name, ret, arg1) do { \ ++ TCGv_i32 helper_tmp = tcg_const_i32(arg1); \ ++ gen_helper_##name(ret, cpu_env, helper_tmp); \ ++ tcg_temp_free_i32(helper_tmp); \ ++ } while(0) ++ ++#define gen_helper_1e1i(name, ret, arg1, arg2) do { \ ++ TCGv_i32 helper_tmp = tcg_const_i32(arg2); \ ++ gen_helper_##name(ret, cpu_env, arg1, helper_tmp); \ ++ tcg_temp_free_i32(helper_tmp); \ ++ } while(0) ++ ++#define gen_helper_0e2i(name, arg1, arg2, arg3) do { \ ++ TCGv_i32 helper_tmp = tcg_const_i32(arg3); \ ++ gen_helper_##name(cpu_env, arg1, arg2, helper_tmp); \ ++ tcg_temp_free_i32(helper_tmp); \ ++ } while(0) ++ ++#define gen_helper_1e2i(name, ret, arg1, arg2, arg3) do { \ + TCGv_i32 helper_tmp = tcg_const_i32(arg3); \ +- gen_helper_##name(arg1, arg2, helper_tmp); \ ++ gen_helper_##name(ret, cpu_env, arg1, arg2, helper_tmp); \ + tcg_temp_free_i32(helper_tmp); \ + } while(0) + +-#define gen_helper_3i(name, arg1, arg2, arg3, arg4) do { \ ++#define gen_helper_0e3i(name, arg1, arg2, arg3, arg4) do { \ + TCGv_i32 helper_tmp = tcg_const_i32(arg4); \ +- gen_helper_##name(arg1, arg2, arg3, helper_tmp); \ ++ gen_helper_##name(cpu_env, arg1, arg2, arg3, helper_tmp); \ + tcg_temp_free_i32(helper_tmp); \ + } while(0) + +@@ -748,7 +766,7 @@ generate_exception_err (DisasContext *ctx, int excp, int err) + TCGv_i32 texcp = tcg_const_i32(excp); + TCGv_i32 terr = tcg_const_i32(err); + save_cpu_state(ctx, 1); +- gen_helper_raise_exception_err(texcp, terr); ++ gen_helper_raise_exception_err(cpu_env, texcp, terr); + tcg_temp_free_i32(terr); + tcg_temp_free_i32(texcp); + } +@@ -757,7 +775,7 @@ static inline void + generate_exception (DisasContext *ctx, int excp) + { + save_cpu_state(ctx, 1); +- gen_helper_0i(raise_exception, excp); ++ gen_helper_0e0i(raise_exception, excp); + } + + /* Addresses computation */ +@@ -871,22 +889,22 @@ static inline void gen_cmp ## type ## _ ## fmt(DisasContext *ctx, int n, \ + gen_ldcmp_fpr##bits (ctx, fp0, fs); \ + gen_ldcmp_fpr##bits (ctx, fp1, ft); \ + switch (n) { \ +- case 0: gen_helper_2i(cmp ## type ## _ ## fmt ## _f, fp0, fp1, cc); break;\ +- case 1: gen_helper_2i(cmp ## type ## _ ## fmt ## _un, fp0, fp1, cc); break;\ +- case 2: gen_helper_2i(cmp ## type ## _ ## fmt ## _eq, fp0, fp1, cc); break;\ +- case 3: gen_helper_2i(cmp ## type ## _ ## fmt ## _ueq, fp0, fp1, cc); break;\ +- case 4: gen_helper_2i(cmp ## type ## _ ## fmt ## _olt, fp0, fp1, cc); break;\ +- case 5: gen_helper_2i(cmp ## type ## _ ## fmt ## _ult, fp0, fp1, cc); break;\ +- case 6: gen_helper_2i(cmp ## type ## _ ## fmt ## _ole, fp0, fp1, cc); break;\ +- case 7: gen_helper_2i(cmp ## type ## _ ## fmt ## _ule, fp0, fp1, cc); break;\ +- case 8: gen_helper_2i(cmp ## type ## _ ## fmt ## _sf, fp0, fp1, cc); break;\ +- case 9: gen_helper_2i(cmp ## type ## _ ## fmt ## _ngle, fp0, fp1, cc); break;\ +- case 10: gen_helper_2i(cmp ## type ## _ ## fmt ## _seq, fp0, fp1, cc); break;\ +- case 11: gen_helper_2i(cmp ## type ## _ ## fmt ## _ngl, fp0, fp1, cc); break;\ +- case 12: gen_helper_2i(cmp ## type ## _ ## fmt ## _lt, fp0, fp1, cc); break;\ +- case 13: gen_helper_2i(cmp ## type ## _ ## fmt ## _nge, fp0, fp1, cc); break;\ +- case 14: gen_helper_2i(cmp ## type ## _ ## fmt ## _le, fp0, fp1, cc); break;\ +- case 15: gen_helper_2i(cmp ## type ## _ ## fmt ## _ngt, fp0, fp1, cc); break;\ ++ case 0: gen_helper_0e2i(cmp ## type ## _ ## fmt ## _f, fp0, fp1, cc); break;\ ++ case 1: gen_helper_0e2i(cmp ## type ## _ ## fmt ## _un, fp0, fp1, cc); break;\ ++ case 2: gen_helper_0e2i(cmp ## type ## _ ## fmt ## _eq, fp0, fp1, cc); break;\ ++ case 3: gen_helper_0e2i(cmp ## type ## _ ## fmt ## _ueq, fp0, fp1, cc); break;\ ++ case 4: gen_helper_0e2i(cmp ## type ## _ ## fmt ## _olt, fp0, fp1, cc); break;\ ++ case 5: gen_helper_0e2i(cmp ## type ## _ ## fmt ## _ult, fp0, fp1, cc); break;\ ++ case 6: gen_helper_0e2i(cmp ## type ## _ ## fmt ## _ole, fp0, fp1, cc); break;\ ++ case 7: gen_helper_0e2i(cmp ## type ## _ ## fmt ## _ule, fp0, fp1, cc); break;\ ++ case 8: gen_helper_0e2i(cmp ## type ## _ ## fmt ## _sf, fp0, fp1, cc); break;\ ++ case 9: gen_helper_0e2i(cmp ## type ## _ ## fmt ## _ngle, fp0, fp1, cc); break;\ ++ case 10: gen_helper_0e2i(cmp ## type ## _ ## fmt ## _seq, fp0, fp1, cc); break;\ ++ case 11: gen_helper_0e2i(cmp ## type ## _ ## fmt ## _ngl, fp0, fp1, cc); break;\ ++ case 12: gen_helper_0e2i(cmp ## type ## _ ## fmt ## _lt, fp0, fp1, cc); break;\ ++ case 13: gen_helper_0e2i(cmp ## type ## _ ## fmt ## _nge, fp0, fp1, cc); break;\ ++ case 14: gen_helper_0e2i(cmp ## type ## _ ## fmt ## _le, fp0, fp1, cc); break;\ ++ case 15: gen_helper_0e2i(cmp ## type ## _ ## fmt ## _ngt, fp0, fp1, cc); break;\ + default: abort(); \ + } \ + tcg_temp_free_i##bits (fp0); \ +@@ -948,7 +966,7 @@ static inline void op_ld_##insn(TCGv ret, TCGv arg1, DisasContext *ctx) \ + #define OP_LD_ATOMIC(insn,fname) \ + static inline void op_ld_##insn(TCGv ret, TCGv arg1, DisasContext *ctx) \ + { \ +- gen_helper_2i(insn, ret, arg1, ctx->mem_idx); \ ++ gen_helper_1e1i(insn, ret, arg1, ctx->mem_idx); \ + } + #endif + OP_LD_ATOMIC(ll,ld32s); +@@ -975,7 +993,7 @@ static inline void op_st_##insn(TCGv arg1, TCGv arg2, int rt, DisasContext *ctx) + tcg_gen_movi_tl(t0, rt | ((almask << 3) & 0x20)); \ + tcg_gen_st_tl(t0, cpu_env, offsetof(CPUMIPSState, llreg)); \ + tcg_gen_st_tl(arg1, cpu_env, offsetof(CPUMIPSState, llnewval)); \ +- gen_helper_0i(raise_exception, EXCP_SC); \ ++ gen_helper_0e0i(raise_exception, EXCP_SC); \ + gen_set_label(l2); \ + tcg_gen_movi_tl(t0, 0); \ + gen_store_gpr(t0, rt); \ +@@ -986,7 +1004,7 @@ static inline void op_st_##insn(TCGv arg1, TCGv arg2, int rt, DisasContext *ctx) + static inline void op_st_##insn(TCGv arg1, TCGv arg2, int rt, DisasContext *ctx) \ + { \ + TCGv t0 = tcg_temp_new(); \ +- gen_helper_3i(insn, t0, arg1, arg2, ctx->mem_idx); \ ++ gen_helper_1e2i(insn, t0, arg1, arg2, ctx->mem_idx); \ + gen_store_gpr(t0, rt); \ + tcg_temp_free(t0); \ + } +@@ -1066,14 +1084,14 @@ static void gen_ld (CPUMIPSState *env, DisasContext *ctx, uint32_t opc, + case OPC_LDL: + save_cpu_state(ctx, 1); + gen_load_gpr(t1, rt); +- gen_helper_3i(ldl, t1, t1, t0, ctx->mem_idx); ++ gen_helper_1e2i(ldl, t1, t1, t0, ctx->mem_idx); + gen_store_gpr(t1, rt); + opn = "ldl"; + break; + case OPC_LDR: + save_cpu_state(ctx, 1); + gen_load_gpr(t1, rt); +- gen_helper_3i(ldr, t1, t1, t0, ctx->mem_idx); ++ gen_helper_1e2i(ldr, t1, t1, t0, ctx->mem_idx); + gen_store_gpr(t1, rt); + opn = "ldr"; + break; +@@ -1127,14 +1145,14 @@ static void gen_ld (CPUMIPSState *env, DisasContext *ctx, uint32_t opc, + case OPC_LWL: + save_cpu_state(ctx, 1); + gen_load_gpr(t1, rt); +- gen_helper_3i(lwl, t1, t1, t0, ctx->mem_idx); ++ gen_helper_1e2i(lwl, t1, t1, t0, ctx->mem_idx); + gen_store_gpr(t1, rt); + opn = "lwl"; + break; + case OPC_LWR: + save_cpu_state(ctx, 1); + gen_load_gpr(t1, rt); +- gen_helper_3i(lwr, t1, t1, t0, ctx->mem_idx); ++ gen_helper_1e2i(lwr, t1, t1, t0, ctx->mem_idx); + gen_store_gpr(t1, rt); + opn = "lwr"; + break; +@@ -1170,12 +1188,12 @@ static void gen_st (DisasContext *ctx, uint32_t opc, int rt, + break; + case OPC_SDL: + save_cpu_state(ctx, 1); +- gen_helper_2i(sdl, t1, t0, ctx->mem_idx); ++ gen_helper_0e2i(sdl, t1, t0, ctx->mem_idx); + opn = "sdl"; + break; + case OPC_SDR: + save_cpu_state(ctx, 1); +- gen_helper_2i(sdr, t1, t0, ctx->mem_idx); ++ gen_helper_0e2i(sdr, t1, t0, ctx->mem_idx); + opn = "sdr"; + break; + #endif +@@ -1196,12 +1214,12 @@ static void gen_st (DisasContext *ctx, uint32_t opc, int rt, + break; + case OPC_SWL: + save_cpu_state(ctx, 1); +- gen_helper_2i(swl, t1, t0, ctx->mem_idx); ++ gen_helper_0e2i(swl, t1, t0, ctx->mem_idx); + opn = "swl"; + break; + case OPC_SWR: + save_cpu_state(ctx, 1); +- gen_helper_2i(swr, t1, t0, ctx->mem_idx); ++ gen_helper_0e2i(swr, t1, t0, ctx->mem_idx); + opn = "swr"; + break; + } +@@ -2138,11 +2156,11 @@ static void gen_muldiv (DisasContext *ctx, uint32_t opc, + opn = "ddivu"; + break; + case OPC_DMULT: +- gen_helper_dmult(t0, t1); ++ gen_helper_dmult(cpu_env, t0, t1); + opn = "dmult"; + break; + case OPC_DMULTU: +- gen_helper_dmultu(t0, t1); ++ gen_helper_dmultu(cpu_env, t0, t1); + opn = "dmultu"; + break; + #endif +@@ -2254,59 +2272,59 @@ static void gen_mul_vr54xx (DisasContext *ctx, uint32_t opc, + + switch (opc) { + case OPC_VR54XX_MULS: +- gen_helper_muls(t0, t0, t1); ++ gen_helper_muls(t0, cpu_env, t0, t1); + opn = "muls"; + break; + case OPC_VR54XX_MULSU: +- gen_helper_mulsu(t0, t0, t1); ++ gen_helper_mulsu(t0, cpu_env, t0, t1); + opn = "mulsu"; + break; + case OPC_VR54XX_MACC: +- gen_helper_macc(t0, t0, t1); ++ gen_helper_macc(t0, cpu_env, t0, t1); + opn = "macc"; + break; + case OPC_VR54XX_MACCU: +- gen_helper_maccu(t0, t0, t1); ++ gen_helper_maccu(t0, cpu_env, t0, t1); + opn = "maccu"; + break; + case OPC_VR54XX_MSAC: +- gen_helper_msac(t0, t0, t1); ++ gen_helper_msac(t0, cpu_env, t0, t1); + opn = "msac"; + break; + case OPC_VR54XX_MSACU: +- gen_helper_msacu(t0, t0, t1); ++ gen_helper_msacu(t0, cpu_env, t0, t1); + opn = "msacu"; + break; + case OPC_VR54XX_MULHI: +- gen_helper_mulhi(t0, t0, t1); ++ gen_helper_mulhi(t0, cpu_env, t0, t1); + opn = "mulhi"; + break; + case OPC_VR54XX_MULHIU: +- gen_helper_mulhiu(t0, t0, t1); ++ gen_helper_mulhiu(t0, cpu_env, t0, t1); + opn = "mulhiu"; + break; + case OPC_VR54XX_MULSHI: +- gen_helper_mulshi(t0, t0, t1); ++ gen_helper_mulshi(t0, cpu_env, t0, t1); + opn = "mulshi"; + break; + case OPC_VR54XX_MULSHIU: +- gen_helper_mulshiu(t0, t0, t1); ++ gen_helper_mulshiu(t0, cpu_env, t0, t1); + opn = "mulshiu"; + break; + case OPC_VR54XX_MACCHI: +- gen_helper_macchi(t0, t0, t1); ++ gen_helper_macchi(t0, cpu_env, t0, t1); + opn = "macchi"; + break; + case OPC_VR54XX_MACCHIU: +- gen_helper_macchiu(t0, t0, t1); ++ gen_helper_macchiu(t0, cpu_env, t0, t1); + opn = "macchiu"; + break; + case OPC_VR54XX_MSACHI: +- gen_helper_msachi(t0, t0, t1); ++ gen_helper_msachi(t0, cpu_env, t0, t1); + opn = "msachi"; + break; + case OPC_VR54XX_MSACHIU: +- gen_helper_msachiu(t0, t0, t1); ++ gen_helper_msachiu(t0, cpu_env, t0, t1); + opn = "msachiu"; + break; + default: +@@ -2683,7 +2701,7 @@ static inline void gen_goto_tb(DisasContext *ctx, int n, target_ulong dest) + gen_save_pc(dest); + if (ctx->singlestep_enabled) { + save_cpu_state(ctx, 0); +- gen_helper_0i(raise_exception, EXCP_DEBUG); ++ gen_helper_0e0i(raise_exception, EXCP_DEBUG); + } + tcg_gen_exit_tb(0); + } +@@ -3187,17 +3205,17 @@ static void gen_mfc0 (CPUMIPSState *env, DisasContext *ctx, TCGv arg, int reg, i + break; + case 1: + check_insn(env, ctx, ASE_MT); +- gen_helper_mfc0_mvpcontrol(arg); ++ gen_helper_mfc0_mvpcontrol(arg, cpu_env); + rn = "MVPControl"; + break; + case 2: + check_insn(env, ctx, ASE_MT); +- gen_helper_mfc0_mvpconf0(arg); ++ gen_helper_mfc0_mvpconf0(arg, cpu_env); + rn = "MVPConf0"; + break; + case 3: + check_insn(env, ctx, ASE_MT); +- gen_helper_mfc0_mvpconf1(arg); ++ gen_helper_mfc0_mvpconf1(arg, cpu_env); + rn = "MVPConf1"; + break; + default: +@@ -3207,7 +3225,7 @@ static void gen_mfc0 (CPUMIPSState *env, DisasContext *ctx, TCGv arg, int reg, i + case 1: + switch (sel) { + case 0: +- gen_helper_mfc0_random(arg); ++ gen_helper_mfc0_random(arg, cpu_env); + rn = "Random"; + break; + case 1: +@@ -3258,37 +3276,37 @@ static void gen_mfc0 (CPUMIPSState *env, DisasContext *ctx, TCGv arg, int reg, i + break; + case 1: + check_insn(env, ctx, ASE_MT); +- gen_helper_mfc0_tcstatus(arg); ++ gen_helper_mfc0_tcstatus(arg, cpu_env); + rn = "TCStatus"; + break; + case 2: + check_insn(env, ctx, ASE_MT); +- gen_helper_mfc0_tcbind(arg); ++ gen_helper_mfc0_tcbind(arg, cpu_env); + rn = "TCBind"; + break; + case 3: + check_insn(env, ctx, ASE_MT); +- gen_helper_mfc0_tcrestart(arg); ++ gen_helper_mfc0_tcrestart(arg, cpu_env); + rn = "TCRestart"; + break; + case 4: + check_insn(env, ctx, ASE_MT); +- gen_helper_mfc0_tchalt(arg); ++ gen_helper_mfc0_tchalt(arg, cpu_env); + rn = "TCHalt"; + break; + case 5: + check_insn(env, ctx, ASE_MT); +- gen_helper_mfc0_tccontext(arg); ++ gen_helper_mfc0_tccontext(arg, cpu_env); + rn = "TCContext"; + break; + case 6: + check_insn(env, ctx, ASE_MT); +- gen_helper_mfc0_tcschedule(arg); ++ gen_helper_mfc0_tcschedule(arg, cpu_env); + rn = "TCSchedule"; + break; + case 7: + check_insn(env, ctx, ASE_MT); +- gen_helper_mfc0_tcschefback(arg); ++ gen_helper_mfc0_tcschefback(arg, cpu_env); + rn = "TCScheFBack"; + break; + default: +@@ -3399,7 +3417,7 @@ static void gen_mfc0 (CPUMIPSState *env, DisasContext *ctx, TCGv arg, int reg, i + /* Mark as an IO operation because we read the time. */ + if (use_icount) + gen_io_start(); +- gen_helper_mfc0_count(arg); ++ gen_helper_mfc0_count(arg, cpu_env); + if (use_icount) { + gen_io_end(); + } +@@ -3531,7 +3549,7 @@ static void gen_mfc0 (CPUMIPSState *env, DisasContext *ctx, TCGv arg, int reg, i + case 17: + switch (sel) { + case 0: +- gen_helper_mfc0_lladdr(arg); ++ gen_helper_mfc0_lladdr(arg, cpu_env); + rn = "LLAddr"; + break; + default: +@@ -3541,7 +3559,7 @@ static void gen_mfc0 (CPUMIPSState *env, DisasContext *ctx, TCGv arg, int reg, i + case 18: + switch (sel) { + case 0 ... 7: +- gen_helper_1i(mfc0_watchlo, arg, sel); ++ gen_helper_1e0i(mfc0_watchlo, arg, sel); + rn = "WatchLo"; + break; + default: +@@ -3551,7 +3569,7 @@ static void gen_mfc0 (CPUMIPSState *env, DisasContext *ctx, TCGv arg, int reg, i + case 19: + switch (sel) { + case 0 ...7: +- gen_helper_1i(mfc0_watchhi, arg, sel); ++ gen_helper_1e0i(mfc0_watchhi, arg, sel); + rn = "WatchHi"; + break; + default: +@@ -3590,7 +3608,7 @@ static void gen_mfc0 (CPUMIPSState *env, DisasContext *ctx, TCGv arg, int reg, i + case 23: + switch (sel) { + case 0: +- gen_helper_mfc0_debug(arg); /* EJTAG support */ ++ gen_helper_mfc0_debug(arg, cpu_env); /* EJTAG support */ + rn = "Debug"; + break; + case 1: +@@ -3765,12 +3783,12 @@ static void gen_mtc0 (CPUMIPSState *env, DisasContext *ctx, TCGv arg, int reg, i + case 0: + switch (sel) { + case 0: +- gen_helper_mtc0_index(arg); ++ gen_helper_mtc0_index(cpu_env, arg); + rn = "Index"; + break; + case 1: + check_insn(env, ctx, ASE_MT); +- gen_helper_mtc0_mvpcontrol(arg); ++ gen_helper_mtc0_mvpcontrol(cpu_env, arg); + rn = "MVPControl"; + break; + case 2: +@@ -3795,22 +3813,22 @@ static void gen_mtc0 (CPUMIPSState *env, DisasContext *ctx, TCGv arg, int reg, i + break; + case 1: + check_insn(env, ctx, ASE_MT); +- gen_helper_mtc0_vpecontrol(arg); ++ gen_helper_mtc0_vpecontrol(cpu_env, arg); + rn = "VPEControl"; + break; + case 2: + check_insn(env, ctx, ASE_MT); +- gen_helper_mtc0_vpeconf0(arg); ++ gen_helper_mtc0_vpeconf0(cpu_env, arg); + rn = "VPEConf0"; + break; + case 3: + check_insn(env, ctx, ASE_MT); +- gen_helper_mtc0_vpeconf1(arg); ++ gen_helper_mtc0_vpeconf1(cpu_env, arg); + rn = "VPEConf1"; + break; + case 4: + check_insn(env, ctx, ASE_MT); +- gen_helper_mtc0_yqmask(arg); ++ gen_helper_mtc0_yqmask(cpu_env, arg); + rn = "YQMask"; + break; + case 5: +@@ -3825,7 +3843,7 @@ static void gen_mtc0 (CPUMIPSState *env, DisasContext *ctx, TCGv arg, int reg, i + break; + case 7: + check_insn(env, ctx, ASE_MT); +- gen_helper_mtc0_vpeopt(arg); ++ gen_helper_mtc0_vpeopt(cpu_env, arg); + rn = "VPEOpt"; + break; + default: +@@ -3835,42 +3853,42 @@ static void gen_mtc0 (CPUMIPSState *env, DisasContext *ctx, TCGv arg, int reg, i + case 2: + switch (sel) { + case 0: +- gen_helper_mtc0_entrylo0(arg); ++ gen_helper_mtc0_entrylo0(cpu_env, arg); + rn = "EntryLo0"; + break; + case 1: + check_insn(env, ctx, ASE_MT); +- gen_helper_mtc0_tcstatus(arg); ++ gen_helper_mtc0_tcstatus(cpu_env, arg); + rn = "TCStatus"; + break; + case 2: + check_insn(env, ctx, ASE_MT); +- gen_helper_mtc0_tcbind(arg); ++ gen_helper_mtc0_tcbind(cpu_env, arg); + rn = "TCBind"; + break; + case 3: + check_insn(env, ctx, ASE_MT); +- gen_helper_mtc0_tcrestart(arg); ++ gen_helper_mtc0_tcrestart(cpu_env, arg); + rn = "TCRestart"; + break; + case 4: + check_insn(env, ctx, ASE_MT); +- gen_helper_mtc0_tchalt(arg); ++ gen_helper_mtc0_tchalt(cpu_env, arg); + rn = "TCHalt"; + break; + case 5: + check_insn(env, ctx, ASE_MT); +- gen_helper_mtc0_tccontext(arg); ++ gen_helper_mtc0_tccontext(cpu_env, arg); + rn = "TCContext"; + break; + case 6: + check_insn(env, ctx, ASE_MT); +- gen_helper_mtc0_tcschedule(arg); ++ gen_helper_mtc0_tcschedule(cpu_env, arg); + rn = "TCSchedule"; + break; + case 7: + check_insn(env, ctx, ASE_MT); +- gen_helper_mtc0_tcschefback(arg); ++ gen_helper_mtc0_tcschefback(cpu_env, arg); + rn = "TCScheFBack"; + break; + default: +@@ -3880,7 +3898,7 @@ static void gen_mtc0 (CPUMIPSState *env, DisasContext *ctx, TCGv arg, int reg, i + case 3: + switch (sel) { + case 0: +- gen_helper_mtc0_entrylo1(arg); ++ gen_helper_mtc0_entrylo1(cpu_env, arg); + rn = "EntryLo1"; + break; + default: +@@ -3890,11 +3908,11 @@ static void gen_mtc0 (CPUMIPSState *env, DisasContext *ctx, TCGv arg, int reg, i + case 4: + switch (sel) { + case 0: +- gen_helper_mtc0_context(arg); ++ gen_helper_mtc0_context(cpu_env, arg); + rn = "Context"; + break; + case 1: +-// gen_helper_mtc0_contextconfig(arg); /* SmartMIPS ASE */ ++// gen_helper_mtc0_contextconfig(cpu_env, arg); /* SmartMIPS ASE */ + rn = "ContextConfig"; + // break; + default: +@@ -3904,12 +3922,12 @@ static void gen_mtc0 (CPUMIPSState *env, DisasContext *ctx, TCGv arg, int reg, i + case 5: + switch (sel) { + case 0: +- gen_helper_mtc0_pagemask(arg); ++ gen_helper_mtc0_pagemask(cpu_env, arg); + rn = "PageMask"; + break; + case 1: + check_insn(env, ctx, ISA_MIPS32R2); +- gen_helper_mtc0_pagegrain(arg); ++ gen_helper_mtc0_pagegrain(cpu_env, arg); + rn = "PageGrain"; + break; + default: +@@ -3919,32 +3937,32 @@ static void gen_mtc0 (CPUMIPSState *env, DisasContext *ctx, TCGv arg, int reg, i + case 6: + switch (sel) { + case 0: +- gen_helper_mtc0_wired(arg); ++ gen_helper_mtc0_wired(cpu_env, arg); + rn = "Wired"; + break; + case 1: + check_insn(env, ctx, ISA_MIPS32R2); +- gen_helper_mtc0_srsconf0(arg); ++ gen_helper_mtc0_srsconf0(cpu_env, arg); + rn = "SRSConf0"; + break; + case 2: + check_insn(env, ctx, ISA_MIPS32R2); +- gen_helper_mtc0_srsconf1(arg); ++ gen_helper_mtc0_srsconf1(cpu_env, arg); + rn = "SRSConf1"; + break; + case 3: + check_insn(env, ctx, ISA_MIPS32R2); +- gen_helper_mtc0_srsconf2(arg); ++ gen_helper_mtc0_srsconf2(cpu_env, arg); + rn = "SRSConf2"; + break; + case 4: + check_insn(env, ctx, ISA_MIPS32R2); +- gen_helper_mtc0_srsconf3(arg); ++ gen_helper_mtc0_srsconf3(cpu_env, arg); + rn = "SRSConf3"; + break; + case 5: + check_insn(env, ctx, ISA_MIPS32R2); +- gen_helper_mtc0_srsconf4(arg); ++ gen_helper_mtc0_srsconf4(cpu_env, arg); + rn = "SRSConf4"; + break; + default: +@@ -3955,7 +3973,7 @@ static void gen_mtc0 (CPUMIPSState *env, DisasContext *ctx, TCGv arg, int reg, i + switch (sel) { + case 0: + check_insn(env, ctx, ISA_MIPS32R2); +- gen_helper_mtc0_hwrena(arg); ++ gen_helper_mtc0_hwrena(cpu_env, arg); + rn = "HWREna"; + break; + default: +@@ -3969,7 +3987,7 @@ static void gen_mtc0 (CPUMIPSState *env, DisasContext *ctx, TCGv arg, int reg, i + case 9: + switch (sel) { + case 0: +- gen_helper_mtc0_count(arg); ++ gen_helper_mtc0_count(cpu_env, arg); + rn = "Count"; + break; + /* 6,7 are implementation dependent */ +@@ -3980,7 +3998,7 @@ static void gen_mtc0 (CPUMIPSState *env, DisasContext *ctx, TCGv arg, int reg, i + case 10: + switch (sel) { + case 0: +- gen_helper_mtc0_entryhi(arg); ++ gen_helper_mtc0_entryhi(cpu_env, arg); + rn = "EntryHi"; + break; + default: +@@ -3990,7 +4008,7 @@ static void gen_mtc0 (CPUMIPSState *env, DisasContext *ctx, TCGv arg, int reg, i + case 11: + switch (sel) { + case 0: +- gen_helper_mtc0_compare(arg); ++ gen_helper_mtc0_compare(cpu_env, arg); + rn = "Compare"; + break; + /* 6,7 are implementation dependent */ +@@ -4002,7 +4020,7 @@ static void gen_mtc0 (CPUMIPSState *env, DisasContext *ctx, TCGv arg, int reg, i + switch (sel) { + case 0: + save_cpu_state(ctx, 1); +- gen_helper_mtc0_status(arg); ++ gen_helper_mtc0_status(cpu_env, arg); + /* BS_STOP isn't good enough here, hflags may have changed. */ + gen_save_pc(ctx->pc + 4); + ctx->bstate = BS_EXCP; +@@ -4010,14 +4028,14 @@ static void gen_mtc0 (CPUMIPSState *env, DisasContext *ctx, TCGv arg, int reg, i + break; + case 1: + check_insn(env, ctx, ISA_MIPS32R2); +- gen_helper_mtc0_intctl(arg); ++ gen_helper_mtc0_intctl(cpu_env, arg); + /* Stop translation as we may have switched the execution mode */ + ctx->bstate = BS_STOP; + rn = "IntCtl"; + break; + case 2: + check_insn(env, ctx, ISA_MIPS32R2); +- gen_helper_mtc0_srsctl(arg); ++ gen_helper_mtc0_srsctl(cpu_env, arg); + /* Stop translation as we may have switched the execution mode */ + ctx->bstate = BS_STOP; + rn = "SRSCtl"; +@@ -4037,7 +4055,7 @@ static void gen_mtc0 (CPUMIPSState *env, DisasContext *ctx, TCGv arg, int reg, i + switch (sel) { + case 0: + save_cpu_state(ctx, 1); +- gen_helper_mtc0_cause(arg); ++ gen_helper_mtc0_cause(cpu_env, arg); + rn = "Cause"; + break; + default: +@@ -4062,7 +4080,7 @@ static void gen_mtc0 (CPUMIPSState *env, DisasContext *ctx, TCGv arg, int reg, i + break; + case 1: + check_insn(env, ctx, ISA_MIPS32R2); +- gen_helper_mtc0_ebase(arg); ++ gen_helper_mtc0_ebase(cpu_env, arg); + rn = "EBase"; + break; + default: +@@ -4072,7 +4090,7 @@ static void gen_mtc0 (CPUMIPSState *env, DisasContext *ctx, TCGv arg, int reg, i + case 16: + switch (sel) { + case 0: +- gen_helper_mtc0_config0(arg); ++ gen_helper_mtc0_config0(cpu_env, arg); + rn = "Config"; + /* Stop translation as we may have switched the execution mode */ + ctx->bstate = BS_STOP; +@@ -4082,7 +4100,7 @@ static void gen_mtc0 (CPUMIPSState *env, DisasContext *ctx, TCGv arg, int reg, i + rn = "Config1"; + break; + case 2: +- gen_helper_mtc0_config2(arg); ++ gen_helper_mtc0_config2(cpu_env, arg); + rn = "Config2"; + /* Stop translation as we may have switched the execution mode */ + ctx->bstate = BS_STOP; +@@ -4109,7 +4127,7 @@ static void gen_mtc0 (CPUMIPSState *env, DisasContext *ctx, TCGv arg, int reg, i + case 17: + switch (sel) { + case 0: +- gen_helper_mtc0_lladdr(arg); ++ gen_helper_mtc0_lladdr(cpu_env, arg); + rn = "LLAddr"; + break; + default: +@@ -4119,7 +4137,7 @@ static void gen_mtc0 (CPUMIPSState *env, DisasContext *ctx, TCGv arg, int reg, i + case 18: + switch (sel) { + case 0 ... 7: +- gen_helper_1i(mtc0_watchlo, arg, sel); ++ gen_helper_0e1i(mtc0_watchlo, arg, sel); + rn = "WatchLo"; + break; + default: +@@ -4129,7 +4147,7 @@ static void gen_mtc0 (CPUMIPSState *env, DisasContext *ctx, TCGv arg, int reg, i + case 19: + switch (sel) { + case 0 ... 7: +- gen_helper_1i(mtc0_watchhi, arg, sel); ++ gen_helper_0e1i(mtc0_watchhi, arg, sel); + rn = "WatchHi"; + break; + default: +@@ -4141,7 +4159,7 @@ static void gen_mtc0 (CPUMIPSState *env, DisasContext *ctx, TCGv arg, int reg, i + case 0: + #if defined(TARGET_MIPS64) + check_insn(env, ctx, ISA_MIPS3); +- gen_helper_mtc0_xcontext(arg); ++ gen_helper_mtc0_xcontext(cpu_env, arg); + rn = "XContext"; + break; + #endif +@@ -4153,7 +4171,7 @@ static void gen_mtc0 (CPUMIPSState *env, DisasContext *ctx, TCGv arg, int reg, i + /* Officially reserved, but sel 0 is used for R1x000 framemask */ + switch (sel) { + case 0: +- gen_helper_mtc0_framemask(arg); ++ gen_helper_mtc0_framemask(cpu_env, arg); + rn = "Framemask"; + break; + default: +@@ -4167,20 +4185,20 @@ static void gen_mtc0 (CPUMIPSState *env, DisasContext *ctx, TCGv arg, int reg, i + case 23: + switch (sel) { + case 0: +- gen_helper_mtc0_debug(arg); /* EJTAG support */ ++ gen_helper_mtc0_debug(cpu_env, arg); /* EJTAG support */ + /* BS_STOP isn't good enough here, hflags may have changed. */ + gen_save_pc(ctx->pc + 4); + ctx->bstate = BS_EXCP; + rn = "Debug"; + break; + case 1: +-// gen_helper_mtc0_tracecontrol(arg); /* PDtrace support */ ++// gen_helper_mtc0_tracecontrol(cpu_env, arg); /* PDtrace support */ + rn = "TraceControl"; + /* Stop translation as we may have switched the execution mode */ + ctx->bstate = BS_STOP; + // break; + case 2: +-// gen_helper_mtc0_tracecontrol2(arg); /* PDtrace support */ ++// gen_helper_mtc0_tracecontrol2(cpu_env, arg); /* PDtrace support */ + rn = "TraceControl2"; + /* Stop translation as we may have switched the execution mode */ + ctx->bstate = BS_STOP; +@@ -4188,13 +4206,13 @@ static void gen_mtc0 (CPUMIPSState *env, DisasContext *ctx, TCGv arg, int reg, i + case 3: + /* Stop translation as we may have switched the execution mode */ + ctx->bstate = BS_STOP; +-// gen_helper_mtc0_usertracedata(arg); /* PDtrace support */ ++// gen_helper_mtc0_usertracedata(cpu_env, arg); /* PDtrace support */ + rn = "UserTraceData"; + /* Stop translation as we may have switched the execution mode */ + ctx->bstate = BS_STOP; + // break; + case 4: +-// gen_helper_mtc0_tracebpc(arg); /* PDtrace support */ ++// gen_helper_mtc0_tracebpc(cpu_env, arg); /* PDtrace support */ + /* Stop translation as we may have switched the execution mode */ + ctx->bstate = BS_STOP; + rn = "TraceBPC"; +@@ -4217,7 +4235,7 @@ static void gen_mtc0 (CPUMIPSState *env, DisasContext *ctx, TCGv arg, int reg, i + case 25: + switch (sel) { + case 0: +- gen_helper_mtc0_performance0(arg); ++ gen_helper_mtc0_performance0(cpu_env, arg); + rn = "Performance0"; + break; + case 1: +@@ -4272,14 +4290,14 @@ static void gen_mtc0 (CPUMIPSState *env, DisasContext *ctx, TCGv arg, int reg, i + case 2: + case 4: + case 6: +- gen_helper_mtc0_taglo(arg); ++ gen_helper_mtc0_taglo(cpu_env, arg); + rn = "TagLo"; + break; + case 1: + case 3: + case 5: + case 7: +- gen_helper_mtc0_datalo(arg); ++ gen_helper_mtc0_datalo(cpu_env, arg); + rn = "DataLo"; + break; + default: +@@ -4292,14 +4310,14 @@ static void gen_mtc0 (CPUMIPSState *env, DisasContext *ctx, TCGv arg, int reg, i + case 2: + case 4: + case 6: +- gen_helper_mtc0_taghi(arg); ++ gen_helper_mtc0_taghi(cpu_env, arg); + rn = "TagHi"; + break; + case 1: + case 3: + case 5: + case 7: +- gen_helper_mtc0_datahi(arg); ++ gen_helper_mtc0_datahi(cpu_env, arg); + rn = "DataHi"; + break; + default: +@@ -4364,17 +4382,17 @@ static void gen_dmfc0 (CPUMIPSState *env, DisasContext *ctx, TCGv arg, int reg, + break; + case 1: + check_insn(env, ctx, ASE_MT); +- gen_helper_mfc0_mvpcontrol(arg); ++ gen_helper_mfc0_mvpcontrol(arg, cpu_env); + rn = "MVPControl"; + break; + case 2: + check_insn(env, ctx, ASE_MT); +- gen_helper_mfc0_mvpconf0(arg); ++ gen_helper_mfc0_mvpconf0(arg, cpu_env); + rn = "MVPConf0"; + break; + case 3: + check_insn(env, ctx, ASE_MT); +- gen_helper_mfc0_mvpconf1(arg); ++ gen_helper_mfc0_mvpconf1(arg, cpu_env); + rn = "MVPConf1"; + break; + default: +@@ -4384,7 +4402,7 @@ static void gen_dmfc0 (CPUMIPSState *env, DisasContext *ctx, TCGv arg, int reg, + case 1: + switch (sel) { + case 0: +- gen_helper_mfc0_random(arg); ++ gen_helper_mfc0_random(arg, cpu_env); + rn = "Random"; + break; + case 1: +@@ -4434,37 +4452,37 @@ static void gen_dmfc0 (CPUMIPSState *env, DisasContext *ctx, TCGv arg, int reg, + break; + case 1: + check_insn(env, ctx, ASE_MT); +- gen_helper_mfc0_tcstatus(arg); ++ gen_helper_mfc0_tcstatus(arg, cpu_env); + rn = "TCStatus"; + break; + case 2: + check_insn(env, ctx, ASE_MT); +- gen_helper_mfc0_tcbind(arg); ++ gen_helper_mfc0_tcbind(arg, cpu_env); + rn = "TCBind"; + break; + case 3: + check_insn(env, ctx, ASE_MT); +- gen_helper_dmfc0_tcrestart(arg); ++ gen_helper_dmfc0_tcrestart(arg, cpu_env); + rn = "TCRestart"; + break; + case 4: + check_insn(env, ctx, ASE_MT); +- gen_helper_dmfc0_tchalt(arg); ++ gen_helper_dmfc0_tchalt(arg, cpu_env); + rn = "TCHalt"; + break; + case 5: + check_insn(env, ctx, ASE_MT); +- gen_helper_dmfc0_tccontext(arg); ++ gen_helper_dmfc0_tccontext(arg, cpu_env); + rn = "TCContext"; + break; + case 6: + check_insn(env, ctx, ASE_MT); +- gen_helper_dmfc0_tcschedule(arg); ++ gen_helper_dmfc0_tcschedule(arg, cpu_env); + rn = "TCSchedule"; + break; + case 7: + check_insn(env, ctx, ASE_MT); +- gen_helper_dmfc0_tcschefback(arg); ++ gen_helper_dmfc0_tcschefback(arg, cpu_env); + rn = "TCScheFBack"; + break; + default: +@@ -4572,7 +4590,7 @@ static void gen_dmfc0 (CPUMIPSState *env, DisasContext *ctx, TCGv arg, int reg, + /* Mark as an IO operation because we read the time. */ + if (use_icount) + gen_io_start(); +- gen_helper_mfc0_count(arg); ++ gen_helper_mfc0_count(arg, cpu_env); + if (use_icount) { + gen_io_end(); + } +@@ -4701,7 +4719,7 @@ static void gen_dmfc0 (CPUMIPSState *env, DisasContext *ctx, TCGv arg, int reg, + case 17: + switch (sel) { + case 0: +- gen_helper_dmfc0_lladdr(arg); ++ gen_helper_dmfc0_lladdr(arg, cpu_env); + rn = "LLAddr"; + break; + default: +@@ -4711,7 +4729,7 @@ static void gen_dmfc0 (CPUMIPSState *env, DisasContext *ctx, TCGv arg, int reg, + case 18: + switch (sel) { + case 0 ... 7: +- gen_helper_1i(dmfc0_watchlo, arg, sel); ++ gen_helper_1e0i(dmfc0_watchlo, arg, sel); + rn = "WatchLo"; + break; + default: +@@ -4721,7 +4739,7 @@ static void gen_dmfc0 (CPUMIPSState *env, DisasContext *ctx, TCGv arg, int reg, + case 19: + switch (sel) { + case 0 ... 7: +- gen_helper_1i(mfc0_watchhi, arg, sel); ++ gen_helper_1e0i(mfc0_watchhi, arg, sel); + rn = "WatchHi"; + break; + default: +@@ -4757,23 +4775,23 @@ static void gen_dmfc0 (CPUMIPSState *env, DisasContext *ctx, TCGv arg, int reg, + case 23: + switch (sel) { + case 0: +- gen_helper_mfc0_debug(arg); /* EJTAG support */ ++ gen_helper_mfc0_debug(arg, cpu_env); /* EJTAG support */ + rn = "Debug"; + break; + case 1: +-// gen_helper_dmfc0_tracecontrol(arg); /* PDtrace support */ ++// gen_helper_dmfc0_tracecontrol(arg, cpu_env); /* PDtrace support */ + rn = "TraceControl"; + // break; + case 2: +-// gen_helper_dmfc0_tracecontrol2(arg); /* PDtrace support */ ++// gen_helper_dmfc0_tracecontrol2(arg, cpu_env); /* PDtrace support */ + rn = "TraceControl2"; + // break; + case 3: +-// gen_helper_dmfc0_usertracedata(arg); /* PDtrace support */ ++// gen_helper_dmfc0_usertracedata(arg, cpu_env); /* PDtrace support */ + rn = "UserTraceData"; + // break; + case 4: +-// gen_helper_dmfc0_tracebpc(arg); /* PDtrace support */ ++// gen_helper_dmfc0_tracebpc(arg, cpu_env); /* PDtrace support */ + rn = "TraceBPC"; + // break; + default: +@@ -4931,12 +4949,12 @@ static void gen_dmtc0 (CPUMIPSState *env, DisasContext *ctx, TCGv arg, int reg, + case 0: + switch (sel) { + case 0: +- gen_helper_mtc0_index(arg); ++ gen_helper_mtc0_index(cpu_env, arg); + rn = "Index"; + break; + case 1: + check_insn(env, ctx, ASE_MT); +- gen_helper_mtc0_mvpcontrol(arg); ++ gen_helper_mtc0_mvpcontrol(cpu_env, arg); + rn = "MVPControl"; + break; + case 2: +@@ -4961,22 +4979,22 @@ static void gen_dmtc0 (CPUMIPSState *env, DisasContext *ctx, TCGv arg, int reg, + break; + case 1: + check_insn(env, ctx, ASE_MT); +- gen_helper_mtc0_vpecontrol(arg); ++ gen_helper_mtc0_vpecontrol(cpu_env, arg); + rn = "VPEControl"; + break; + case 2: + check_insn(env, ctx, ASE_MT); +- gen_helper_mtc0_vpeconf0(arg); ++ gen_helper_mtc0_vpeconf0(cpu_env, arg); + rn = "VPEConf0"; + break; + case 3: + check_insn(env, ctx, ASE_MT); +- gen_helper_mtc0_vpeconf1(arg); ++ gen_helper_mtc0_vpeconf1(cpu_env, arg); + rn = "VPEConf1"; + break; + case 4: + check_insn(env, ctx, ASE_MT); +- gen_helper_mtc0_yqmask(arg); ++ gen_helper_mtc0_yqmask(cpu_env, arg); + rn = "YQMask"; + break; + case 5: +@@ -4991,7 +5009,7 @@ static void gen_dmtc0 (CPUMIPSState *env, DisasContext *ctx, TCGv arg, int reg, + break; + case 7: + check_insn(env, ctx, ASE_MT); +- gen_helper_mtc0_vpeopt(arg); ++ gen_helper_mtc0_vpeopt(cpu_env, arg); + rn = "VPEOpt"; + break; + default: +@@ -5001,42 +5019,42 @@ static void gen_dmtc0 (CPUMIPSState *env, DisasContext *ctx, TCGv arg, int reg, + case 2: + switch (sel) { + case 0: +- gen_helper_mtc0_entrylo0(arg); ++ gen_helper_mtc0_entrylo0(cpu_env, arg); + rn = "EntryLo0"; + break; + case 1: + check_insn(env, ctx, ASE_MT); +- gen_helper_mtc0_tcstatus(arg); ++ gen_helper_mtc0_tcstatus(cpu_env, arg); + rn = "TCStatus"; + break; + case 2: + check_insn(env, ctx, ASE_MT); +- gen_helper_mtc0_tcbind(arg); ++ gen_helper_mtc0_tcbind(cpu_env, arg); + rn = "TCBind"; + break; + case 3: + check_insn(env, ctx, ASE_MT); +- gen_helper_mtc0_tcrestart(arg); ++ gen_helper_mtc0_tcrestart(cpu_env, arg); + rn = "TCRestart"; + break; + case 4: + check_insn(env, ctx, ASE_MT); +- gen_helper_mtc0_tchalt(arg); ++ gen_helper_mtc0_tchalt(cpu_env, arg); + rn = "TCHalt"; + break; + case 5: + check_insn(env, ctx, ASE_MT); +- gen_helper_mtc0_tccontext(arg); ++ gen_helper_mtc0_tccontext(cpu_env, arg); + rn = "TCContext"; + break; + case 6: + check_insn(env, ctx, ASE_MT); +- gen_helper_mtc0_tcschedule(arg); ++ gen_helper_mtc0_tcschedule(cpu_env, arg); + rn = "TCSchedule"; + break; + case 7: + check_insn(env, ctx, ASE_MT); +- gen_helper_mtc0_tcschefback(arg); ++ gen_helper_mtc0_tcschefback(cpu_env, arg); + rn = "TCScheFBack"; + break; + default: +@@ -5046,7 +5064,7 @@ static void gen_dmtc0 (CPUMIPSState *env, DisasContext *ctx, TCGv arg, int reg, + case 3: + switch (sel) { + case 0: +- gen_helper_mtc0_entrylo1(arg); ++ gen_helper_mtc0_entrylo1(cpu_env, arg); + rn = "EntryLo1"; + break; + default: +@@ -5056,11 +5074,11 @@ static void gen_dmtc0 (CPUMIPSState *env, DisasContext *ctx, TCGv arg, int reg, + case 4: + switch (sel) { + case 0: +- gen_helper_mtc0_context(arg); ++ gen_helper_mtc0_context(cpu_env, arg); + rn = "Context"; + break; + case 1: +-// gen_helper_mtc0_contextconfig(arg); /* SmartMIPS ASE */ ++// gen_helper_mtc0_contextconfig(cpu_env, arg); /* SmartMIPS ASE */ + rn = "ContextConfig"; + // break; + default: +@@ -5070,12 +5088,12 @@ static void gen_dmtc0 (CPUMIPSState *env, DisasContext *ctx, TCGv arg, int reg, + case 5: + switch (sel) { + case 0: +- gen_helper_mtc0_pagemask(arg); ++ gen_helper_mtc0_pagemask(cpu_env, arg); + rn = "PageMask"; + break; + case 1: + check_insn(env, ctx, ISA_MIPS32R2); +- gen_helper_mtc0_pagegrain(arg); ++ gen_helper_mtc0_pagegrain(cpu_env, arg); + rn = "PageGrain"; + break; + default: +@@ -5085,32 +5103,32 @@ static void gen_dmtc0 (CPUMIPSState *env, DisasContext *ctx, TCGv arg, int reg, + case 6: + switch (sel) { + case 0: +- gen_helper_mtc0_wired(arg); ++ gen_helper_mtc0_wired(cpu_env, arg); + rn = "Wired"; + break; + case 1: + check_insn(env, ctx, ISA_MIPS32R2); +- gen_helper_mtc0_srsconf0(arg); ++ gen_helper_mtc0_srsconf0(cpu_env, arg); + rn = "SRSConf0"; + break; + case 2: + check_insn(env, ctx, ISA_MIPS32R2); +- gen_helper_mtc0_srsconf1(arg); ++ gen_helper_mtc0_srsconf1(cpu_env, arg); + rn = "SRSConf1"; + break; + case 3: + check_insn(env, ctx, ISA_MIPS32R2); +- gen_helper_mtc0_srsconf2(arg); ++ gen_helper_mtc0_srsconf2(cpu_env, arg); + rn = "SRSConf2"; + break; + case 4: + check_insn(env, ctx, ISA_MIPS32R2); +- gen_helper_mtc0_srsconf3(arg); ++ gen_helper_mtc0_srsconf3(cpu_env, arg); + rn = "SRSConf3"; + break; + case 5: + check_insn(env, ctx, ISA_MIPS32R2); +- gen_helper_mtc0_srsconf4(arg); ++ gen_helper_mtc0_srsconf4(cpu_env, arg); + rn = "SRSConf4"; + break; + default: +@@ -5121,7 +5139,7 @@ static void gen_dmtc0 (CPUMIPSState *env, DisasContext *ctx, TCGv arg, int reg, + switch (sel) { + case 0: + check_insn(env, ctx, ISA_MIPS32R2); +- gen_helper_mtc0_hwrena(arg); ++ gen_helper_mtc0_hwrena(cpu_env, arg); + rn = "HWREna"; + break; + default: +@@ -5135,7 +5153,7 @@ static void gen_dmtc0 (CPUMIPSState *env, DisasContext *ctx, TCGv arg, int reg, + case 9: + switch (sel) { + case 0: +- gen_helper_mtc0_count(arg); ++ gen_helper_mtc0_count(cpu_env, arg); + rn = "Count"; + break; + /* 6,7 are implementation dependent */ +@@ -5148,7 +5166,7 @@ static void gen_dmtc0 (CPUMIPSState *env, DisasContext *ctx, TCGv arg, int reg, + case 10: + switch (sel) { + case 0: +- gen_helper_mtc0_entryhi(arg); ++ gen_helper_mtc0_entryhi(cpu_env, arg); + rn = "EntryHi"; + break; + default: +@@ -5158,7 +5176,7 @@ static void gen_dmtc0 (CPUMIPSState *env, DisasContext *ctx, TCGv arg, int reg, + case 11: + switch (sel) { + case 0: +- gen_helper_mtc0_compare(arg); ++ gen_helper_mtc0_compare(cpu_env, arg); + rn = "Compare"; + break; + /* 6,7 are implementation dependent */ +@@ -5172,7 +5190,7 @@ static void gen_dmtc0 (CPUMIPSState *env, DisasContext *ctx, TCGv arg, int reg, + switch (sel) { + case 0: + save_cpu_state(ctx, 1); +- gen_helper_mtc0_status(arg); ++ gen_helper_mtc0_status(cpu_env, arg); + /* BS_STOP isn't good enough here, hflags may have changed. */ + gen_save_pc(ctx->pc + 4); + ctx->bstate = BS_EXCP; +@@ -5180,14 +5198,14 @@ static void gen_dmtc0 (CPUMIPSState *env, DisasContext *ctx, TCGv arg, int reg, + break; + case 1: + check_insn(env, ctx, ISA_MIPS32R2); +- gen_helper_mtc0_intctl(arg); ++ gen_helper_mtc0_intctl(cpu_env, arg); + /* Stop translation as we may have switched the execution mode */ + ctx->bstate = BS_STOP; + rn = "IntCtl"; + break; + case 2: + check_insn(env, ctx, ISA_MIPS32R2); +- gen_helper_mtc0_srsctl(arg); ++ gen_helper_mtc0_srsctl(cpu_env, arg); + /* Stop translation as we may have switched the execution mode */ + ctx->bstate = BS_STOP; + rn = "SRSCtl"; +@@ -5212,7 +5230,7 @@ static void gen_dmtc0 (CPUMIPSState *env, DisasContext *ctx, TCGv arg, int reg, + if (use_icount) { + gen_io_start(); + } +- gen_helper_mtc0_cause(arg); ++ gen_helper_mtc0_cause(cpu_env, arg); + if (use_icount) { + gen_io_end(); + } +@@ -5242,7 +5260,7 @@ static void gen_dmtc0 (CPUMIPSState *env, DisasContext *ctx, TCGv arg, int reg, + break; + case 1: + check_insn(env, ctx, ISA_MIPS32R2); +- gen_helper_mtc0_ebase(arg); ++ gen_helper_mtc0_ebase(cpu_env, arg); + rn = "EBase"; + break; + default: +@@ -5252,7 +5270,7 @@ static void gen_dmtc0 (CPUMIPSState *env, DisasContext *ctx, TCGv arg, int reg, + case 16: + switch (sel) { + case 0: +- gen_helper_mtc0_config0(arg); ++ gen_helper_mtc0_config0(cpu_env, arg); + rn = "Config"; + /* Stop translation as we may have switched the execution mode */ + ctx->bstate = BS_STOP; +@@ -5262,7 +5280,7 @@ static void gen_dmtc0 (CPUMIPSState *env, DisasContext *ctx, TCGv arg, int reg, + rn = "Config1"; + break; + case 2: +- gen_helper_mtc0_config2(arg); ++ gen_helper_mtc0_config2(cpu_env, arg); + rn = "Config2"; + /* Stop translation as we may have switched the execution mode */ + ctx->bstate = BS_STOP; +@@ -5280,7 +5298,7 @@ static void gen_dmtc0 (CPUMIPSState *env, DisasContext *ctx, TCGv arg, int reg, + case 17: + switch (sel) { + case 0: +- gen_helper_mtc0_lladdr(arg); ++ gen_helper_mtc0_lladdr(cpu_env, arg); + rn = "LLAddr"; + break; + default: +@@ -5290,7 +5308,7 @@ static void gen_dmtc0 (CPUMIPSState *env, DisasContext *ctx, TCGv arg, int reg, + case 18: + switch (sel) { + case 0 ... 7: +- gen_helper_1i(mtc0_watchlo, arg, sel); ++ gen_helper_0e1i(mtc0_watchlo, arg, sel); + rn = "WatchLo"; + break; + default: +@@ -5300,7 +5318,7 @@ static void gen_dmtc0 (CPUMIPSState *env, DisasContext *ctx, TCGv arg, int reg, + case 19: + switch (sel) { + case 0 ... 7: +- gen_helper_1i(mtc0_watchhi, arg, sel); ++ gen_helper_0e1i(mtc0_watchhi, arg, sel); + rn = "WatchHi"; + break; + default: +@@ -5311,7 +5329,7 @@ static void gen_dmtc0 (CPUMIPSState *env, DisasContext *ctx, TCGv arg, int reg, + switch (sel) { + case 0: + check_insn(env, ctx, ISA_MIPS3); +- gen_helper_mtc0_xcontext(arg); ++ gen_helper_mtc0_xcontext(cpu_env, arg); + rn = "XContext"; + break; + default: +@@ -5322,7 +5340,7 @@ static void gen_dmtc0 (CPUMIPSState *env, DisasContext *ctx, TCGv arg, int reg, + /* Officially reserved, but sel 0 is used for R1x000 framemask */ + switch (sel) { + case 0: +- gen_helper_mtc0_framemask(arg); ++ gen_helper_mtc0_framemask(cpu_env, arg); + rn = "Framemask"; + break; + default: +@@ -5336,32 +5354,32 @@ static void gen_dmtc0 (CPUMIPSState *env, DisasContext *ctx, TCGv arg, int reg, + case 23: + switch (sel) { + case 0: +- gen_helper_mtc0_debug(arg); /* EJTAG support */ ++ gen_helper_mtc0_debug(cpu_env, arg); /* EJTAG support */ + /* BS_STOP isn't good enough here, hflags may have changed. */ + gen_save_pc(ctx->pc + 4); + ctx->bstate = BS_EXCP; + rn = "Debug"; + break; + case 1: +-// gen_helper_mtc0_tracecontrol(arg); /* PDtrace support */ ++// gen_helper_mtc0_tracecontrol(cpu_env, arg); /* PDtrace support */ + /* Stop translation as we may have switched the execution mode */ + ctx->bstate = BS_STOP; + rn = "TraceControl"; + // break; + case 2: +-// gen_helper_mtc0_tracecontrol2(arg); /* PDtrace support */ ++// gen_helper_mtc0_tracecontrol2(cpu_env, arg); /* PDtrace support */ + /* Stop translation as we may have switched the execution mode */ + ctx->bstate = BS_STOP; + rn = "TraceControl2"; + // break; + case 3: +-// gen_helper_mtc0_usertracedata(arg); /* PDtrace support */ ++// gen_helper_mtc0_usertracedata(cpu_env, arg); /* PDtrace support */ + /* Stop translation as we may have switched the execution mode */ + ctx->bstate = BS_STOP; + rn = "UserTraceData"; + // break; + case 4: +-// gen_helper_mtc0_tracebpc(arg); /* PDtrace support */ ++// gen_helper_mtc0_tracebpc(cpu_env, arg); /* PDtrace support */ + /* Stop translation as we may have switched the execution mode */ + ctx->bstate = BS_STOP; + rn = "TraceBPC"; +@@ -5384,35 +5402,35 @@ static void gen_dmtc0 (CPUMIPSState *env, DisasContext *ctx, TCGv arg, int reg, + case 25: + switch (sel) { + case 0: +- gen_helper_mtc0_performance0(arg); ++ gen_helper_mtc0_performance0(cpu_env, arg); + rn = "Performance0"; + break; + case 1: +-// gen_helper_mtc0_performance1(arg); ++// gen_helper_mtc0_performance1(cpu_env, arg); + rn = "Performance1"; + // break; + case 2: +-// gen_helper_mtc0_performance2(arg); ++// gen_helper_mtc0_performance2(cpu_env, arg); + rn = "Performance2"; + // break; + case 3: +-// gen_helper_mtc0_performance3(arg); ++// gen_helper_mtc0_performance3(cpu_env, arg); + rn = "Performance3"; + // break; + case 4: +-// gen_helper_mtc0_performance4(arg); ++// gen_helper_mtc0_performance4(cpu_env, arg); + rn = "Performance4"; + // break; + case 5: +-// gen_helper_mtc0_performance5(arg); ++// gen_helper_mtc0_performance5(cpu_env, arg); + rn = "Performance5"; + // break; + case 6: +-// gen_helper_mtc0_performance6(arg); ++// gen_helper_mtc0_performance6(cpu_env, arg); + rn = "Performance6"; + // break; + case 7: +-// gen_helper_mtc0_performance7(arg); ++// gen_helper_mtc0_performance7(cpu_env, arg); + rn = "Performance7"; + // break; + default: +@@ -5439,14 +5457,14 @@ static void gen_dmtc0 (CPUMIPSState *env, DisasContext *ctx, TCGv arg, int reg, + case 2: + case 4: + case 6: +- gen_helper_mtc0_taglo(arg); ++ gen_helper_mtc0_taglo(cpu_env, arg); + rn = "TagLo"; + break; + case 1: + case 3: + case 5: + case 7: +- gen_helper_mtc0_datalo(arg); ++ gen_helper_mtc0_datalo(cpu_env, arg); + rn = "DataLo"; + break; + default: +@@ -5459,14 +5477,14 @@ static void gen_dmtc0 (CPUMIPSState *env, DisasContext *ctx, TCGv arg, int reg, + case 2: + case 4: + case 6: +- gen_helper_mtc0_taghi(arg); ++ gen_helper_mtc0_taghi(cpu_env, arg); + rn = "TagHi"; + break; + case 1: + case 3: + case 5: + case 7: +- gen_helper_mtc0_datahi(arg); ++ gen_helper_mtc0_datahi(cpu_env, arg); + rn = "DataHi"; + break; + default: +@@ -5533,10 +5551,10 @@ static void gen_mftr(CPUMIPSState *env, DisasContext *ctx, int rt, int rd, + case 1: + switch (sel) { + case 1: +- gen_helper_mftc0_vpecontrol(t0); ++ gen_helper_mftc0_vpecontrol(t0, cpu_env); + break; + case 2: +- gen_helper_mftc0_vpeconf0(t0); ++ gen_helper_mftc0_vpeconf0(t0, cpu_env); + break; + default: + goto die; +@@ -5546,25 +5564,25 @@ static void gen_mftr(CPUMIPSState *env, DisasContext *ctx, int rt, int rd, + case 2: + switch (sel) { + case 1: +- gen_helper_mftc0_tcstatus(t0); ++ gen_helper_mftc0_tcstatus(t0, cpu_env); + break; + case 2: +- gen_helper_mftc0_tcbind(t0); ++ gen_helper_mftc0_tcbind(t0, cpu_env); + break; + case 3: +- gen_helper_mftc0_tcrestart(t0); ++ gen_helper_mftc0_tcrestart(t0, cpu_env); + break; + case 4: +- gen_helper_mftc0_tchalt(t0); ++ gen_helper_mftc0_tchalt(t0, cpu_env); + break; + case 5: +- gen_helper_mftc0_tccontext(t0); ++ gen_helper_mftc0_tccontext(t0, cpu_env); + break; + case 6: +- gen_helper_mftc0_tcschedule(t0); ++ gen_helper_mftc0_tcschedule(t0, cpu_env); + break; + case 7: +- gen_helper_mftc0_tcschefback(t0); ++ gen_helper_mftc0_tcschefback(t0, cpu_env); + break; + default: + gen_mfc0(env, ctx, t0, rt, sel); +@@ -5574,7 +5592,7 @@ static void gen_mftr(CPUMIPSState *env, DisasContext *ctx, int rt, int rd, + case 10: + switch (sel) { + case 0: +- gen_helper_mftc0_entryhi(t0); ++ gen_helper_mftc0_entryhi(t0, cpu_env); + break; + default: + gen_mfc0(env, ctx, t0, rt, sel); +@@ -5583,7 +5601,7 @@ static void gen_mftr(CPUMIPSState *env, DisasContext *ctx, int rt, int rd, + case 12: + switch (sel) { + case 0: +- gen_helper_mftc0_status(t0); ++ gen_helper_mftc0_status(t0, cpu_env); + break; + default: + gen_mfc0(env, ctx, t0, rt, sel); +@@ -5592,7 +5610,7 @@ static void gen_mftr(CPUMIPSState *env, DisasContext *ctx, int rt, int rd, + case 13: + switch (sel) { + case 0: +- gen_helper_mftc0_cause(t0); ++ gen_helper_mftc0_cause(t0, cpu_env); + break; + default: + goto die; +@@ -5602,7 +5620,7 @@ static void gen_mftr(CPUMIPSState *env, DisasContext *ctx, int rt, int rd, + case 14: + switch (sel) { + case 0: +- gen_helper_mftc0_epc(t0); ++ gen_helper_mftc0_epc(t0, cpu_env); + break; + default: + goto die; +@@ -5612,7 +5630,7 @@ static void gen_mftr(CPUMIPSState *env, DisasContext *ctx, int rt, int rd, + case 15: + switch (sel) { + case 1: +- gen_helper_mftc0_ebase(t0); ++ gen_helper_mftc0_ebase(t0, cpu_env); + break; + default: + goto die; +@@ -5622,7 +5640,7 @@ static void gen_mftr(CPUMIPSState *env, DisasContext *ctx, int rt, int rd, + case 16: + switch (sel) { + case 0 ... 7: +- gen_helper_mftc0_configx(t0, tcg_const_tl(sel)); ++ gen_helper_mftc0_configx(t0, cpu_env, tcg_const_tl(sel)); + break; + default: + goto die; +@@ -5632,7 +5650,7 @@ static void gen_mftr(CPUMIPSState *env, DisasContext *ctx, int rt, int rd, + case 23: + switch (sel) { + case 0: +- gen_helper_mftc0_debug(t0); ++ gen_helper_mftc0_debug(t0, cpu_env); + break; + default: + gen_mfc0(env, ctx, t0, rt, sel); +@@ -5645,49 +5663,49 @@ static void gen_mftr(CPUMIPSState *env, DisasContext *ctx, int rt, int rd, + } else switch (sel) { + /* GPR registers. */ + case 0: +- gen_helper_1i(mftgpr, t0, rt); ++ gen_helper_1e0i(mftgpr, t0, rt); + break; + /* Auxiliary CPU registers */ + case 1: + switch (rt) { + case 0: +- gen_helper_1i(mftlo, t0, 0); ++ gen_helper_1e0i(mftlo, t0, 0); + break; + case 1: +- gen_helper_1i(mfthi, t0, 0); ++ gen_helper_1e0i(mfthi, t0, 0); + break; + case 2: +- gen_helper_1i(mftacx, t0, 0); ++ gen_helper_1e0i(mftacx, t0, 0); + break; + case 4: +- gen_helper_1i(mftlo, t0, 1); ++ gen_helper_1e0i(mftlo, t0, 1); + break; + case 5: +- gen_helper_1i(mfthi, t0, 1); ++ gen_helper_1e0i(mfthi, t0, 1); + break; + case 6: +- gen_helper_1i(mftacx, t0, 1); ++ gen_helper_1e0i(mftacx, t0, 1); + break; + case 8: +- gen_helper_1i(mftlo, t0, 2); ++ gen_helper_1e0i(mftlo, t0, 2); + break; + case 9: +- gen_helper_1i(mfthi, t0, 2); ++ gen_helper_1e0i(mfthi, t0, 2); + break; + case 10: +- gen_helper_1i(mftacx, t0, 2); ++ gen_helper_1e0i(mftacx, t0, 2); + break; + case 12: +- gen_helper_1i(mftlo, t0, 3); ++ gen_helper_1e0i(mftlo, t0, 3); + break; + case 13: +- gen_helper_1i(mfthi, t0, 3); ++ gen_helper_1e0i(mfthi, t0, 3); + break; + case 14: +- gen_helper_1i(mftacx, t0, 3); ++ gen_helper_1e0i(mftacx, t0, 3); + break; + case 16: +- gen_helper_mftdsp(t0); ++ gen_helper_mftdsp(t0, cpu_env); + break; + default: + goto die; +@@ -5712,7 +5730,7 @@ static void gen_mftr(CPUMIPSState *env, DisasContext *ctx, int rt, int rd, + break; + case 3: + /* XXX: For now we support only a single FPU context. */ +- gen_helper_1i(cfc1, t0, rt); ++ gen_helper_1e0i(cfc1, t0, rt); + break; + /* COP2: Not implemented. */ + case 4: +@@ -5751,10 +5769,10 @@ static void gen_mttr(CPUMIPSState *env, DisasContext *ctx, int rd, int rt, + case 1: + switch (sel) { + case 1: +- gen_helper_mttc0_vpecontrol(t0); ++ gen_helper_mttc0_vpecontrol(cpu_env, t0); + break; + case 2: +- gen_helper_mttc0_vpeconf0(t0); ++ gen_helper_mttc0_vpeconf0(cpu_env, t0); + break; + default: + goto die; +@@ -5764,25 +5782,25 @@ static void gen_mttr(CPUMIPSState *env, DisasContext *ctx, int rd, int rt, + case 2: + switch (sel) { + case 1: +- gen_helper_mttc0_tcstatus(t0); ++ gen_helper_mttc0_tcstatus(cpu_env, t0); + break; + case 2: +- gen_helper_mttc0_tcbind(t0); ++ gen_helper_mttc0_tcbind(cpu_env, t0); + break; + case 3: +- gen_helper_mttc0_tcrestart(t0); ++ gen_helper_mttc0_tcrestart(cpu_env, t0); + break; + case 4: +- gen_helper_mttc0_tchalt(t0); ++ gen_helper_mttc0_tchalt(cpu_env, t0); + break; + case 5: +- gen_helper_mttc0_tccontext(t0); ++ gen_helper_mttc0_tccontext(cpu_env, t0); + break; + case 6: +- gen_helper_mttc0_tcschedule(t0); ++ gen_helper_mttc0_tcschedule(cpu_env, t0); + break; + case 7: +- gen_helper_mttc0_tcschefback(t0); ++ gen_helper_mttc0_tcschefback(cpu_env, t0); + break; + default: + gen_mtc0(env, ctx, t0, rd, sel); +@@ -5792,7 +5810,7 @@ static void gen_mttr(CPUMIPSState *env, DisasContext *ctx, int rd, int rt, + case 10: + switch (sel) { + case 0: +- gen_helper_mttc0_entryhi(t0); ++ gen_helper_mttc0_entryhi(cpu_env, t0); + break; + default: + gen_mtc0(env, ctx, t0, rd, sel); +@@ -5801,7 +5819,7 @@ static void gen_mttr(CPUMIPSState *env, DisasContext *ctx, int rd, int rt, + case 12: + switch (sel) { + case 0: +- gen_helper_mttc0_status(t0); ++ gen_helper_mttc0_status(cpu_env, t0); + break; + default: + gen_mtc0(env, ctx, t0, rd, sel); +@@ -5810,7 +5828,7 @@ static void gen_mttr(CPUMIPSState *env, DisasContext *ctx, int rd, int rt, + case 13: + switch (sel) { + case 0: +- gen_helper_mttc0_cause(t0); ++ gen_helper_mttc0_cause(cpu_env, t0); + break; + default: + goto die; +@@ -5820,7 +5838,7 @@ static void gen_mttr(CPUMIPSState *env, DisasContext *ctx, int rd, int rt, + case 15: + switch (sel) { + case 1: +- gen_helper_mttc0_ebase(t0); ++ gen_helper_mttc0_ebase(cpu_env, t0); + break; + default: + goto die; +@@ -5830,7 +5848,7 @@ static void gen_mttr(CPUMIPSState *env, DisasContext *ctx, int rd, int rt, + case 23: + switch (sel) { + case 0: +- gen_helper_mttc0_debug(t0); ++ gen_helper_mttc0_debug(cpu_env, t0); + break; + default: + gen_mtc0(env, ctx, t0, rd, sel); +@@ -5843,49 +5861,49 @@ static void gen_mttr(CPUMIPSState *env, DisasContext *ctx, int rd, int rt, + } else switch (sel) { + /* GPR registers. */ + case 0: +- gen_helper_1i(mttgpr, t0, rd); ++ gen_helper_0e1i(mttgpr, t0, rd); + break; + /* Auxiliary CPU registers */ + case 1: + switch (rd) { + case 0: +- gen_helper_1i(mttlo, t0, 0); ++ gen_helper_0e1i(mttlo, t0, 0); + break; + case 1: +- gen_helper_1i(mtthi, t0, 0); ++ gen_helper_0e1i(mtthi, t0, 0); + break; + case 2: +- gen_helper_1i(mttacx, t0, 0); ++ gen_helper_0e1i(mttacx, t0, 0); + break; + case 4: +- gen_helper_1i(mttlo, t0, 1); ++ gen_helper_0e1i(mttlo, t0, 1); + break; + case 5: +- gen_helper_1i(mtthi, t0, 1); ++ gen_helper_0e1i(mtthi, t0, 1); + break; + case 6: +- gen_helper_1i(mttacx, t0, 1); ++ gen_helper_0e1i(mttacx, t0, 1); + break; + case 8: +- gen_helper_1i(mttlo, t0, 2); ++ gen_helper_0e1i(mttlo, t0, 2); + break; + case 9: +- gen_helper_1i(mtthi, t0, 2); ++ gen_helper_0e1i(mtthi, t0, 2); + break; + case 10: +- gen_helper_1i(mttacx, t0, 2); ++ gen_helper_0e1i(mttacx, t0, 2); + break; + case 12: +- gen_helper_1i(mttlo, t0, 3); ++ gen_helper_0e1i(mttlo, t0, 3); + break; + case 13: +- gen_helper_1i(mtthi, t0, 3); ++ gen_helper_0e1i(mtthi, t0, 3); + break; + case 14: +- gen_helper_1i(mttacx, t0, 3); ++ gen_helper_0e1i(mttacx, t0, 3); + break; + case 16: +- gen_helper_mttdsp(t0); ++ gen_helper_mttdsp(cpu_env, t0); + break; + default: + goto die; +@@ -5910,7 +5928,7 @@ static void gen_mttr(CPUMIPSState *env, DisasContext *ctx, int rd, int rt, + break; + case 3: + /* XXX: For now we support only a single FPU context. */ +- gen_helper_1i(ctc1, t0, rd); ++ gen_helper_0e1i(ctc1, t0, rd); + break; + /* COP2: Not implemented. */ + case 4: +@@ -5995,30 +6013,30 @@ static void gen_cp0 (CPUMIPSState *env, DisasContext *ctx, uint32_t opc, int rt, + opn = "tlbwi"; + if (!env->tlb->helper_tlbwi) + goto die; +- gen_helper_tlbwi(); ++ gen_helper_tlbwi(cpu_env); + break; + case OPC_TLBWR: + opn = "tlbwr"; + if (!env->tlb->helper_tlbwr) + goto die; +- gen_helper_tlbwr(); ++ gen_helper_tlbwr(cpu_env); + break; + case OPC_TLBP: + opn = "tlbp"; + if (!env->tlb->helper_tlbp) + goto die; +- gen_helper_tlbp(); ++ gen_helper_tlbp(cpu_env); + break; + case OPC_TLBR: + opn = "tlbr"; + if (!env->tlb->helper_tlbr) + goto die; +- gen_helper_tlbr(); ++ gen_helper_tlbr(cpu_env); + break; + case OPC_ERET: + opn = "eret"; + check_insn(env, ctx, ISA_MIPS2); +- gen_helper_eret(); ++ gen_helper_eret(cpu_env); + ctx->bstate = BS_EXCP; + break; + case OPC_DERET: +@@ -6028,7 +6046,7 @@ static void gen_cp0 (CPUMIPSState *env, DisasContext *ctx, uint32_t opc, int rt, + MIPS_INVAL(opn); + generate_exception(ctx, EXCP_RI); + } else { +- gen_helper_deret(); ++ gen_helper_deret(cpu_env); + ctx->bstate = BS_EXCP; + } + break; +@@ -6039,7 +6057,7 @@ static void gen_cp0 (CPUMIPSState *env, DisasContext *ctx, uint32_t opc, int rt, + ctx->pc += 4; + save_cpu_state(ctx, 1); + ctx->pc -= 4; +- gen_helper_wait(); ++ gen_helper_wait(cpu_env); + ctx->bstate = BS_EXCP; + break; + default: +@@ -6340,13 +6358,13 @@ static void gen_cp1 (DisasContext *ctx, uint32_t opc, int rt, int fs) + opn = "mtc1"; + break; + case OPC_CFC1: +- gen_helper_1i(cfc1, t0, fs); ++ gen_helper_1e0i(cfc1, t0, fs); + gen_store_gpr(t0, rt); + opn = "cfc1"; + break; + case OPC_CTC1: + gen_load_gpr(t0, rt); +- gen_helper_1i(ctc1, t0, fs); ++ gen_helper_0e1i(ctc1, t0, fs); + opn = "ctc1"; + break; + #if defined(TARGET_MIPS64) +@@ -6543,7 +6561,7 @@ static void gen_farith (DisasContext *ctx, enum fopcode op1, + + gen_load_fpr32(fp0, fs); + gen_load_fpr32(fp1, ft); +- gen_helper_float_add_s(fp0, fp0, fp1); ++ gen_helper_float_add_s(fp0, cpu_env, fp0, fp1); + tcg_temp_free_i32(fp1); + gen_store_fpr32(fp0, fd); + tcg_temp_free_i32(fp0); +@@ -6558,7 +6576,7 @@ static void gen_farith (DisasContext *ctx, enum fopcode op1, + + gen_load_fpr32(fp0, fs); + gen_load_fpr32(fp1, ft); +- gen_helper_float_sub_s(fp0, fp0, fp1); ++ gen_helper_float_sub_s(fp0, cpu_env, fp0, fp1); + tcg_temp_free_i32(fp1); + gen_store_fpr32(fp0, fd); + tcg_temp_free_i32(fp0); +@@ -6573,7 +6591,7 @@ static void gen_farith (DisasContext *ctx, enum fopcode op1, + + gen_load_fpr32(fp0, fs); + gen_load_fpr32(fp1, ft); +- gen_helper_float_mul_s(fp0, fp0, fp1); ++ gen_helper_float_mul_s(fp0, cpu_env, fp0, fp1); + tcg_temp_free_i32(fp1); + gen_store_fpr32(fp0, fd); + tcg_temp_free_i32(fp0); +@@ -6588,7 +6606,7 @@ static void gen_farith (DisasContext *ctx, enum fopcode op1, + + gen_load_fpr32(fp0, fs); + gen_load_fpr32(fp1, ft); +- gen_helper_float_div_s(fp0, fp0, fp1); ++ gen_helper_float_div_s(fp0, cpu_env, fp0, fp1); + tcg_temp_free_i32(fp1); + gen_store_fpr32(fp0, fd); + tcg_temp_free_i32(fp0); +@@ -6601,7 +6619,7 @@ static void gen_farith (DisasContext *ctx, enum fopcode op1, + TCGv_i32 fp0 = tcg_temp_new_i32(); + + gen_load_fpr32(fp0, fs); +- gen_helper_float_sqrt_s(fp0, fp0); ++ gen_helper_float_sqrt_s(fp0, cpu_env, fp0); + gen_store_fpr32(fp0, fd); + tcg_temp_free_i32(fp0); + } +@@ -6646,7 +6664,7 @@ static void gen_farith (DisasContext *ctx, enum fopcode op1, + TCGv_i64 fp64 = tcg_temp_new_i64(); + + gen_load_fpr32(fp32, fs); +- gen_helper_float_roundl_s(fp64, fp32); ++ gen_helper_float_roundl_s(fp64, cpu_env, fp32); + tcg_temp_free_i32(fp32); + gen_store_fpr64(ctx, fp64, fd); + tcg_temp_free_i64(fp64); +@@ -6660,7 +6678,7 @@ static void gen_farith (DisasContext *ctx, enum fopcode op1, + TCGv_i64 fp64 = tcg_temp_new_i64(); + + gen_load_fpr32(fp32, fs); +- gen_helper_float_truncl_s(fp64, fp32); ++ gen_helper_float_truncl_s(fp64, cpu_env, fp32); + tcg_temp_free_i32(fp32); + gen_store_fpr64(ctx, fp64, fd); + tcg_temp_free_i64(fp64); +@@ -6674,7 +6692,7 @@ static void gen_farith (DisasContext *ctx, enum fopcode op1, + TCGv_i64 fp64 = tcg_temp_new_i64(); + + gen_load_fpr32(fp32, fs); +- gen_helper_float_ceill_s(fp64, fp32); ++ gen_helper_float_ceill_s(fp64, cpu_env, fp32); + tcg_temp_free_i32(fp32); + gen_store_fpr64(ctx, fp64, fd); + tcg_temp_free_i64(fp64); +@@ -6688,7 +6706,7 @@ static void gen_farith (DisasContext *ctx, enum fopcode op1, + TCGv_i64 fp64 = tcg_temp_new_i64(); + + gen_load_fpr32(fp32, fs); +- gen_helper_float_floorl_s(fp64, fp32); ++ gen_helper_float_floorl_s(fp64, cpu_env, fp32); + tcg_temp_free_i32(fp32); + gen_store_fpr64(ctx, fp64, fd); + tcg_temp_free_i64(fp64); +@@ -6700,7 +6718,7 @@ static void gen_farith (DisasContext *ctx, enum fopcode op1, + TCGv_i32 fp0 = tcg_temp_new_i32(); + + gen_load_fpr32(fp0, fs); +- gen_helper_float_roundw_s(fp0, fp0); ++ gen_helper_float_roundw_s(fp0, cpu_env, fp0); + gen_store_fpr32(fp0, fd); + tcg_temp_free_i32(fp0); + } +@@ -6711,7 +6729,7 @@ static void gen_farith (DisasContext *ctx, enum fopcode op1, + TCGv_i32 fp0 = tcg_temp_new_i32(); + + gen_load_fpr32(fp0, fs); +- gen_helper_float_truncw_s(fp0, fp0); ++ gen_helper_float_truncw_s(fp0, cpu_env, fp0); + gen_store_fpr32(fp0, fd); + tcg_temp_free_i32(fp0); + } +@@ -6722,7 +6740,7 @@ static void gen_farith (DisasContext *ctx, enum fopcode op1, + TCGv_i32 fp0 = tcg_temp_new_i32(); + + gen_load_fpr32(fp0, fs); +- gen_helper_float_ceilw_s(fp0, fp0); ++ gen_helper_float_ceilw_s(fp0, cpu_env, fp0); + gen_store_fpr32(fp0, fd); + tcg_temp_free_i32(fp0); + } +@@ -6733,7 +6751,7 @@ static void gen_farith (DisasContext *ctx, enum fopcode op1, + TCGv_i32 fp0 = tcg_temp_new_i32(); + + gen_load_fpr32(fp0, fs); +- gen_helper_float_floorw_s(fp0, fp0); ++ gen_helper_float_floorw_s(fp0, cpu_env, fp0); + gen_store_fpr32(fp0, fd); + tcg_temp_free_i32(fp0); + } +@@ -6781,7 +6799,7 @@ static void gen_farith (DisasContext *ctx, enum fopcode op1, + TCGv_i32 fp0 = tcg_temp_new_i32(); + + gen_load_fpr32(fp0, fs); +- gen_helper_float_recip_s(fp0, fp0); ++ gen_helper_float_recip_s(fp0, cpu_env, fp0); + gen_store_fpr32(fp0, fd); + tcg_temp_free_i32(fp0); + } +@@ -6793,7 +6811,7 @@ static void gen_farith (DisasContext *ctx, enum fopcode op1, + TCGv_i32 fp0 = tcg_temp_new_i32(); + + gen_load_fpr32(fp0, fs); +- gen_helper_float_rsqrt_s(fp0, fp0); ++ gen_helper_float_rsqrt_s(fp0, cpu_env, fp0); + gen_store_fpr32(fp0, fd); + tcg_temp_free_i32(fp0); + } +@@ -6807,7 +6825,7 @@ static void gen_farith (DisasContext *ctx, enum fopcode op1, + + gen_load_fpr32(fp0, fs); + gen_load_fpr32(fp1, ft); +- gen_helper_float_recip2_s(fp0, fp0, fp1); ++ gen_helper_float_recip2_s(fp0, cpu_env, fp0, fp1); + tcg_temp_free_i32(fp1); + gen_store_fpr32(fp0, fd); + tcg_temp_free_i32(fp0); +@@ -6820,7 +6838,7 @@ static void gen_farith (DisasContext *ctx, enum fopcode op1, + TCGv_i32 fp0 = tcg_temp_new_i32(); + + gen_load_fpr32(fp0, fs); +- gen_helper_float_recip1_s(fp0, fp0); ++ gen_helper_float_recip1_s(fp0, cpu_env, fp0); + gen_store_fpr32(fp0, fd); + tcg_temp_free_i32(fp0); + } +@@ -6832,7 +6850,7 @@ static void gen_farith (DisasContext *ctx, enum fopcode op1, + TCGv_i32 fp0 = tcg_temp_new_i32(); + + gen_load_fpr32(fp0, fs); +- gen_helper_float_rsqrt1_s(fp0, fp0); ++ gen_helper_float_rsqrt1_s(fp0, cpu_env, fp0); + gen_store_fpr32(fp0, fd); + tcg_temp_free_i32(fp0); + } +@@ -6846,7 +6864,7 @@ static void gen_farith (DisasContext *ctx, enum fopcode op1, + + gen_load_fpr32(fp0, fs); + gen_load_fpr32(fp1, ft); +- gen_helper_float_rsqrt2_s(fp0, fp0, fp1); ++ gen_helper_float_rsqrt2_s(fp0, cpu_env, fp0, fp1); + tcg_temp_free_i32(fp1); + gen_store_fpr32(fp0, fd); + tcg_temp_free_i32(fp0); +@@ -6860,7 +6878,7 @@ static void gen_farith (DisasContext *ctx, enum fopcode op1, + TCGv_i64 fp64 = tcg_temp_new_i64(); + + gen_load_fpr32(fp32, fs); +- gen_helper_float_cvtd_s(fp64, fp32); ++ gen_helper_float_cvtd_s(fp64, cpu_env, fp32); + tcg_temp_free_i32(fp32); + gen_store_fpr64(ctx, fp64, fd); + tcg_temp_free_i64(fp64); +@@ -6872,7 +6890,7 @@ static void gen_farith (DisasContext *ctx, enum fopcode op1, + TCGv_i32 fp0 = tcg_temp_new_i32(); + + gen_load_fpr32(fp0, fs); +- gen_helper_float_cvtw_s(fp0, fp0); ++ gen_helper_float_cvtw_s(fp0, cpu_env, fp0); + gen_store_fpr32(fp0, fd); + tcg_temp_free_i32(fp0); + } +@@ -6885,7 +6903,7 @@ static void gen_farith (DisasContext *ctx, enum fopcode op1, + TCGv_i64 fp64 = tcg_temp_new_i64(); + + gen_load_fpr32(fp32, fs); +- gen_helper_float_cvtl_s(fp64, fp32); ++ gen_helper_float_cvtl_s(fp64, cpu_env, fp32); + tcg_temp_free_i32(fp32); + gen_store_fpr64(ctx, fp64, fd); + tcg_temp_free_i64(fp64); +@@ -6941,7 +6959,7 @@ static void gen_farith (DisasContext *ctx, enum fopcode op1, + + gen_load_fpr64(ctx, fp0, fs); + gen_load_fpr64(ctx, fp1, ft); +- gen_helper_float_add_d(fp0, fp0, fp1); ++ gen_helper_float_add_d(fp0, cpu_env, fp0, fp1); + tcg_temp_free_i64(fp1); + gen_store_fpr64(ctx, fp0, fd); + tcg_temp_free_i64(fp0); +@@ -6957,7 +6975,7 @@ static void gen_farith (DisasContext *ctx, enum fopcode op1, + + gen_load_fpr64(ctx, fp0, fs); + gen_load_fpr64(ctx, fp1, ft); +- gen_helper_float_sub_d(fp0, fp0, fp1); ++ gen_helper_float_sub_d(fp0, cpu_env, fp0, fp1); + tcg_temp_free_i64(fp1); + gen_store_fpr64(ctx, fp0, fd); + tcg_temp_free_i64(fp0); +@@ -6973,7 +6991,7 @@ static void gen_farith (DisasContext *ctx, enum fopcode op1, + + gen_load_fpr64(ctx, fp0, fs); + gen_load_fpr64(ctx, fp1, ft); +- gen_helper_float_mul_d(fp0, fp0, fp1); ++ gen_helper_float_mul_d(fp0, cpu_env, fp0, fp1); + tcg_temp_free_i64(fp1); + gen_store_fpr64(ctx, fp0, fd); + tcg_temp_free_i64(fp0); +@@ -6989,7 +7007,7 @@ static void gen_farith (DisasContext *ctx, enum fopcode op1, + + gen_load_fpr64(ctx, fp0, fs); + gen_load_fpr64(ctx, fp1, ft); +- gen_helper_float_div_d(fp0, fp0, fp1); ++ gen_helper_float_div_d(fp0, cpu_env, fp0, fp1); + tcg_temp_free_i64(fp1); + gen_store_fpr64(ctx, fp0, fd); + tcg_temp_free_i64(fp0); +@@ -7003,7 +7021,7 @@ static void gen_farith (DisasContext *ctx, enum fopcode op1, + TCGv_i64 fp0 = tcg_temp_new_i64(); + + gen_load_fpr64(ctx, fp0, fs); +- gen_helper_float_sqrt_d(fp0, fp0); ++ gen_helper_float_sqrt_d(fp0, cpu_env, fp0); + gen_store_fpr64(ctx, fp0, fd); + tcg_temp_free_i64(fp0); + } +@@ -7050,7 +7068,7 @@ static void gen_farith (DisasContext *ctx, enum fopcode op1, + TCGv_i64 fp0 = tcg_temp_new_i64(); + + gen_load_fpr64(ctx, fp0, fs); +- gen_helper_float_roundl_d(fp0, fp0); ++ gen_helper_float_roundl_d(fp0, cpu_env, fp0); + gen_store_fpr64(ctx, fp0, fd); + tcg_temp_free_i64(fp0); + } +@@ -7062,7 +7080,7 @@ static void gen_farith (DisasContext *ctx, enum fopcode op1, + TCGv_i64 fp0 = tcg_temp_new_i64(); + + gen_load_fpr64(ctx, fp0, fs); +- gen_helper_float_truncl_d(fp0, fp0); ++ gen_helper_float_truncl_d(fp0, cpu_env, fp0); + gen_store_fpr64(ctx, fp0, fd); + tcg_temp_free_i64(fp0); + } +@@ -7074,7 +7092,7 @@ static void gen_farith (DisasContext *ctx, enum fopcode op1, + TCGv_i64 fp0 = tcg_temp_new_i64(); + + gen_load_fpr64(ctx, fp0, fs); +- gen_helper_float_ceill_d(fp0, fp0); ++ gen_helper_float_ceill_d(fp0, cpu_env, fp0); + gen_store_fpr64(ctx, fp0, fd); + tcg_temp_free_i64(fp0); + } +@@ -7086,7 +7104,7 @@ static void gen_farith (DisasContext *ctx, enum fopcode op1, + TCGv_i64 fp0 = tcg_temp_new_i64(); + + gen_load_fpr64(ctx, fp0, fs); +- gen_helper_float_floorl_d(fp0, fp0); ++ gen_helper_float_floorl_d(fp0, cpu_env, fp0); + gen_store_fpr64(ctx, fp0, fd); + tcg_temp_free_i64(fp0); + } +@@ -7099,7 +7117,7 @@ static void gen_farith (DisasContext *ctx, enum fopcode op1, + TCGv_i64 fp64 = tcg_temp_new_i64(); + + gen_load_fpr64(ctx, fp64, fs); +- gen_helper_float_roundw_d(fp32, fp64); ++ gen_helper_float_roundw_d(fp32, cpu_env, fp64); + tcg_temp_free_i64(fp64); + gen_store_fpr32(fp32, fd); + tcg_temp_free_i32(fp32); +@@ -7113,7 +7131,7 @@ static void gen_farith (DisasContext *ctx, enum fopcode op1, + TCGv_i64 fp64 = tcg_temp_new_i64(); + + gen_load_fpr64(ctx, fp64, fs); +- gen_helper_float_truncw_d(fp32, fp64); ++ gen_helper_float_truncw_d(fp32, cpu_env, fp64); + tcg_temp_free_i64(fp64); + gen_store_fpr32(fp32, fd); + tcg_temp_free_i32(fp32); +@@ -7127,7 +7145,7 @@ static void gen_farith (DisasContext *ctx, enum fopcode op1, + TCGv_i64 fp64 = tcg_temp_new_i64(); + + gen_load_fpr64(ctx, fp64, fs); +- gen_helper_float_ceilw_d(fp32, fp64); ++ gen_helper_float_ceilw_d(fp32, cpu_env, fp64); + tcg_temp_free_i64(fp64); + gen_store_fpr32(fp32, fd); + tcg_temp_free_i32(fp32); +@@ -7141,7 +7159,7 @@ static void gen_farith (DisasContext *ctx, enum fopcode op1, + TCGv_i64 fp64 = tcg_temp_new_i64(); + + gen_load_fpr64(ctx, fp64, fs); +- gen_helper_float_floorw_d(fp32, fp64); ++ gen_helper_float_floorw_d(fp32, cpu_env, fp64); + tcg_temp_free_i64(fp64); + gen_store_fpr32(fp32, fd); + tcg_temp_free_i32(fp32); +@@ -7190,7 +7208,7 @@ static void gen_farith (DisasContext *ctx, enum fopcode op1, + TCGv_i64 fp0 = tcg_temp_new_i64(); + + gen_load_fpr64(ctx, fp0, fs); +- gen_helper_float_recip_d(fp0, fp0); ++ gen_helper_float_recip_d(fp0, cpu_env, fp0); + gen_store_fpr64(ctx, fp0, fd); + tcg_temp_free_i64(fp0); + } +@@ -7202,7 +7220,7 @@ static void gen_farith (DisasContext *ctx, enum fopcode op1, + TCGv_i64 fp0 = tcg_temp_new_i64(); + + gen_load_fpr64(ctx, fp0, fs); +- gen_helper_float_rsqrt_d(fp0, fp0); ++ gen_helper_float_rsqrt_d(fp0, cpu_env, fp0); + gen_store_fpr64(ctx, fp0, fd); + tcg_temp_free_i64(fp0); + } +@@ -7216,7 +7234,7 @@ static void gen_farith (DisasContext *ctx, enum fopcode op1, + + gen_load_fpr64(ctx, fp0, fs); + gen_load_fpr64(ctx, fp1, ft); +- gen_helper_float_recip2_d(fp0, fp0, fp1); ++ gen_helper_float_recip2_d(fp0, cpu_env, fp0, fp1); + tcg_temp_free_i64(fp1); + gen_store_fpr64(ctx, fp0, fd); + tcg_temp_free_i64(fp0); +@@ -7229,7 +7247,7 @@ static void gen_farith (DisasContext *ctx, enum fopcode op1, + TCGv_i64 fp0 = tcg_temp_new_i64(); + + gen_load_fpr64(ctx, fp0, fs); +- gen_helper_float_recip1_d(fp0, fp0); ++ gen_helper_float_recip1_d(fp0, cpu_env, fp0); + gen_store_fpr64(ctx, fp0, fd); + tcg_temp_free_i64(fp0); + } +@@ -7241,7 +7259,7 @@ static void gen_farith (DisasContext *ctx, enum fopcode op1, + TCGv_i64 fp0 = tcg_temp_new_i64(); + + gen_load_fpr64(ctx, fp0, fs); +- gen_helper_float_rsqrt1_d(fp0, fp0); ++ gen_helper_float_rsqrt1_d(fp0, cpu_env, fp0); + gen_store_fpr64(ctx, fp0, fd); + tcg_temp_free_i64(fp0); + } +@@ -7255,7 +7273,7 @@ static void gen_farith (DisasContext *ctx, enum fopcode op1, + + gen_load_fpr64(ctx, fp0, fs); + gen_load_fpr64(ctx, fp1, ft); +- gen_helper_float_rsqrt2_d(fp0, fp0, fp1); ++ gen_helper_float_rsqrt2_d(fp0, cpu_env, fp0, fp1); + tcg_temp_free_i64(fp1); + gen_store_fpr64(ctx, fp0, fd); + tcg_temp_free_i64(fp0); +@@ -7293,7 +7311,7 @@ static void gen_farith (DisasContext *ctx, enum fopcode op1, + TCGv_i64 fp64 = tcg_temp_new_i64(); + + gen_load_fpr64(ctx, fp64, fs); +- gen_helper_float_cvts_d(fp32, fp64); ++ gen_helper_float_cvts_d(fp32, cpu_env, fp64); + tcg_temp_free_i64(fp64); + gen_store_fpr32(fp32, fd); + tcg_temp_free_i32(fp32); +@@ -7307,7 +7325,7 @@ static void gen_farith (DisasContext *ctx, enum fopcode op1, + TCGv_i64 fp64 = tcg_temp_new_i64(); + + gen_load_fpr64(ctx, fp64, fs); +- gen_helper_float_cvtw_d(fp32, fp64); ++ gen_helper_float_cvtw_d(fp32, cpu_env, fp64); + tcg_temp_free_i64(fp64); + gen_store_fpr32(fp32, fd); + tcg_temp_free_i32(fp32); +@@ -7320,7 +7338,7 @@ static void gen_farith (DisasContext *ctx, enum fopcode op1, + TCGv_i64 fp0 = tcg_temp_new_i64(); + + gen_load_fpr64(ctx, fp0, fs); +- gen_helper_float_cvtl_d(fp0, fp0); ++ gen_helper_float_cvtl_d(fp0, cpu_env, fp0); + gen_store_fpr64(ctx, fp0, fd); + tcg_temp_free_i64(fp0); + } +@@ -7331,7 +7349,7 @@ static void gen_farith (DisasContext *ctx, enum fopcode op1, + TCGv_i32 fp0 = tcg_temp_new_i32(); + + gen_load_fpr32(fp0, fs); +- gen_helper_float_cvts_w(fp0, fp0); ++ gen_helper_float_cvts_w(fp0, cpu_env, fp0); + gen_store_fpr32(fp0, fd); + tcg_temp_free_i32(fp0); + } +@@ -7344,7 +7362,7 @@ static void gen_farith (DisasContext *ctx, enum fopcode op1, + TCGv_i64 fp64 = tcg_temp_new_i64(); + + gen_load_fpr32(fp32, fs); +- gen_helper_float_cvtd_w(fp64, fp32); ++ gen_helper_float_cvtd_w(fp64, cpu_env, fp32); + tcg_temp_free_i32(fp32); + gen_store_fpr64(ctx, fp64, fd); + tcg_temp_free_i64(fp64); +@@ -7358,7 +7376,7 @@ static void gen_farith (DisasContext *ctx, enum fopcode op1, + TCGv_i64 fp64 = tcg_temp_new_i64(); + + gen_load_fpr64(ctx, fp64, fs); +- gen_helper_float_cvts_l(fp32, fp64); ++ gen_helper_float_cvts_l(fp32, cpu_env, fp64); + tcg_temp_free_i64(fp64); + gen_store_fpr32(fp32, fd); + tcg_temp_free_i32(fp32); +@@ -7371,7 +7389,7 @@ static void gen_farith (DisasContext *ctx, enum fopcode op1, + TCGv_i64 fp0 = tcg_temp_new_i64(); + + gen_load_fpr64(ctx, fp0, fs); +- gen_helper_float_cvtd_l(fp0, fp0); ++ gen_helper_float_cvtd_l(fp0, cpu_env, fp0); + gen_store_fpr64(ctx, fp0, fd); + tcg_temp_free_i64(fp0); + } +@@ -7383,7 +7401,7 @@ static void gen_farith (DisasContext *ctx, enum fopcode op1, + TCGv_i64 fp0 = tcg_temp_new_i64(); + + gen_load_fpr64(ctx, fp0, fs); +- gen_helper_float_cvtps_pw(fp0, fp0); ++ gen_helper_float_cvtps_pw(fp0, cpu_env, fp0); + gen_store_fpr64(ctx, fp0, fd); + tcg_temp_free_i64(fp0); + } +@@ -7397,7 +7415,7 @@ static void gen_farith (DisasContext *ctx, enum fopcode op1, + + gen_load_fpr64(ctx, fp0, fs); + gen_load_fpr64(ctx, fp1, ft); +- gen_helper_float_add_ps(fp0, fp0, fp1); ++ gen_helper_float_add_ps(fp0, cpu_env, fp0, fp1); + tcg_temp_free_i64(fp1); + gen_store_fpr64(ctx, fp0, fd); + tcg_temp_free_i64(fp0); +@@ -7412,7 +7430,7 @@ static void gen_farith (DisasContext *ctx, enum fopcode op1, + + gen_load_fpr64(ctx, fp0, fs); + gen_load_fpr64(ctx, fp1, ft); +- gen_helper_float_sub_ps(fp0, fp0, fp1); ++ gen_helper_float_sub_ps(fp0, cpu_env, fp0, fp1); + tcg_temp_free_i64(fp1); + gen_store_fpr64(ctx, fp0, fd); + tcg_temp_free_i64(fp0); +@@ -7427,7 +7445,7 @@ static void gen_farith (DisasContext *ctx, enum fopcode op1, + + gen_load_fpr64(ctx, fp0, fs); + gen_load_fpr64(ctx, fp1, ft); +- gen_helper_float_mul_ps(fp0, fp0, fp1); ++ gen_helper_float_mul_ps(fp0, cpu_env, fp0, fp1); + tcg_temp_free_i64(fp1); + gen_store_fpr64(ctx, fp0, fd); + tcg_temp_free_i64(fp0); +@@ -7515,7 +7533,7 @@ static void gen_farith (DisasContext *ctx, enum fopcode op1, + + gen_load_fpr64(ctx, fp0, ft); + gen_load_fpr64(ctx, fp1, fs); +- gen_helper_float_addr_ps(fp0, fp0, fp1); ++ gen_helper_float_addr_ps(fp0, cpu_env, fp0, fp1); + tcg_temp_free_i64(fp1); + gen_store_fpr64(ctx, fp0, fd); + tcg_temp_free_i64(fp0); +@@ -7530,7 +7548,7 @@ static void gen_farith (DisasContext *ctx, enum fopcode op1, + + gen_load_fpr64(ctx, fp0, ft); + gen_load_fpr64(ctx, fp1, fs); +- gen_helper_float_mulr_ps(fp0, fp0, fp1); ++ gen_helper_float_mulr_ps(fp0, cpu_env, fp0, fp1); + tcg_temp_free_i64(fp1); + gen_store_fpr64(ctx, fp0, fd); + tcg_temp_free_i64(fp0); +@@ -7545,7 +7563,7 @@ static void gen_farith (DisasContext *ctx, enum fopcode op1, + + gen_load_fpr64(ctx, fp0, fs); + gen_load_fpr64(ctx, fp1, ft); +- gen_helper_float_recip2_ps(fp0, fp0, fp1); ++ gen_helper_float_recip2_ps(fp0, cpu_env, fp0, fp1); + tcg_temp_free_i64(fp1); + gen_store_fpr64(ctx, fp0, fd); + tcg_temp_free_i64(fp0); +@@ -7558,7 +7576,7 @@ static void gen_farith (DisasContext *ctx, enum fopcode op1, + TCGv_i64 fp0 = tcg_temp_new_i64(); + + gen_load_fpr64(ctx, fp0, fs); +- gen_helper_float_recip1_ps(fp0, fp0); ++ gen_helper_float_recip1_ps(fp0, cpu_env, fp0); + gen_store_fpr64(ctx, fp0, fd); + tcg_temp_free_i64(fp0); + } +@@ -7570,7 +7588,7 @@ static void gen_farith (DisasContext *ctx, enum fopcode op1, + TCGv_i64 fp0 = tcg_temp_new_i64(); + + gen_load_fpr64(ctx, fp0, fs); +- gen_helper_float_rsqrt1_ps(fp0, fp0); ++ gen_helper_float_rsqrt1_ps(fp0, cpu_env, fp0); + gen_store_fpr64(ctx, fp0, fd); + tcg_temp_free_i64(fp0); + } +@@ -7584,7 +7602,7 @@ static void gen_farith (DisasContext *ctx, enum fopcode op1, + + gen_load_fpr64(ctx, fp0, fs); + gen_load_fpr64(ctx, fp1, ft); +- gen_helper_float_rsqrt2_ps(fp0, fp0, fp1); ++ gen_helper_float_rsqrt2_ps(fp0, cpu_env, fp0, fp1); + tcg_temp_free_i64(fp1); + gen_store_fpr64(ctx, fp0, fd); + tcg_temp_free_i64(fp0); +@@ -7597,7 +7615,7 @@ static void gen_farith (DisasContext *ctx, enum fopcode op1, + TCGv_i32 fp0 = tcg_temp_new_i32(); + + gen_load_fpr32h(fp0, fs); +- gen_helper_float_cvts_pu(fp0, fp0); ++ gen_helper_float_cvts_pu(fp0, cpu_env, fp0); + gen_store_fpr32(fp0, fd); + tcg_temp_free_i32(fp0); + } +@@ -7609,7 +7627,7 @@ static void gen_farith (DisasContext *ctx, enum fopcode op1, + TCGv_i64 fp0 = tcg_temp_new_i64(); + + gen_load_fpr64(ctx, fp0, fs); +- gen_helper_float_cvtpw_ps(fp0, fp0); ++ gen_helper_float_cvtpw_ps(fp0, cpu_env, fp0); + gen_store_fpr64(ctx, fp0, fd); + tcg_temp_free_i64(fp0); + } +@@ -7621,7 +7639,7 @@ static void gen_farith (DisasContext *ctx, enum fopcode op1, + TCGv_i32 fp0 = tcg_temp_new_i32(); + + gen_load_fpr32(fp0, fs); +- gen_helper_float_cvts_pl(fp0, fp0); ++ gen_helper_float_cvts_pl(fp0, cpu_env, fp0); + gen_store_fpr32(fp0, fd); + tcg_temp_free_i32(fp0); + } +@@ -7887,7 +7905,7 @@ static void gen_flt3_arith (DisasContext *ctx, uint32_t opc, + gen_load_fpr32(fp0, fs); + gen_load_fpr32(fp1, ft); + gen_load_fpr32(fp2, fr); +- gen_helper_float_muladd_s(fp2, fp0, fp1, fp2); ++ gen_helper_float_muladd_s(fp2, cpu_env, fp0, fp1, fp2); + tcg_temp_free_i32(fp0); + tcg_temp_free_i32(fp1); + gen_store_fpr32(fp2, fd); +@@ -7906,7 +7924,7 @@ static void gen_flt3_arith (DisasContext *ctx, uint32_t opc, + gen_load_fpr64(ctx, fp0, fs); + gen_load_fpr64(ctx, fp1, ft); + gen_load_fpr64(ctx, fp2, fr); +- gen_helper_float_muladd_d(fp2, fp0, fp1, fp2); ++ gen_helper_float_muladd_d(fp2, cpu_env, fp0, fp1, fp2); + tcg_temp_free_i64(fp0); + tcg_temp_free_i64(fp1); + gen_store_fpr64(ctx, fp2, fd); +@@ -7924,7 +7942,7 @@ static void gen_flt3_arith (DisasContext *ctx, uint32_t opc, + gen_load_fpr64(ctx, fp0, fs); + gen_load_fpr64(ctx, fp1, ft); + gen_load_fpr64(ctx, fp2, fr); +- gen_helper_float_muladd_ps(fp2, fp0, fp1, fp2); ++ gen_helper_float_muladd_ps(fp2, cpu_env, fp0, fp1, fp2); + tcg_temp_free_i64(fp0); + tcg_temp_free_i64(fp1); + gen_store_fpr64(ctx, fp2, fd); +@@ -7942,7 +7960,7 @@ static void gen_flt3_arith (DisasContext *ctx, uint32_t opc, + gen_load_fpr32(fp0, fs); + gen_load_fpr32(fp1, ft); + gen_load_fpr32(fp2, fr); +- gen_helper_float_mulsub_s(fp2, fp0, fp1, fp2); ++ gen_helper_float_mulsub_s(fp2, cpu_env, fp0, fp1, fp2); + tcg_temp_free_i32(fp0); + tcg_temp_free_i32(fp1); + gen_store_fpr32(fp2, fd); +@@ -7961,7 +7979,7 @@ static void gen_flt3_arith (DisasContext *ctx, uint32_t opc, + gen_load_fpr64(ctx, fp0, fs); + gen_load_fpr64(ctx, fp1, ft); + gen_load_fpr64(ctx, fp2, fr); +- gen_helper_float_mulsub_d(fp2, fp0, fp1, fp2); ++ gen_helper_float_mulsub_d(fp2, cpu_env, fp0, fp1, fp2); + tcg_temp_free_i64(fp0); + tcg_temp_free_i64(fp1); + gen_store_fpr64(ctx, fp2, fd); +@@ -7979,7 +7997,7 @@ static void gen_flt3_arith (DisasContext *ctx, uint32_t opc, + gen_load_fpr64(ctx, fp0, fs); + gen_load_fpr64(ctx, fp1, ft); + gen_load_fpr64(ctx, fp2, fr); +- gen_helper_float_mulsub_ps(fp2, fp0, fp1, fp2); ++ gen_helper_float_mulsub_ps(fp2, cpu_env, fp0, fp1, fp2); + tcg_temp_free_i64(fp0); + tcg_temp_free_i64(fp1); + gen_store_fpr64(ctx, fp2, fd); +@@ -7997,7 +8015,7 @@ static void gen_flt3_arith (DisasContext *ctx, uint32_t opc, + gen_load_fpr32(fp0, fs); + gen_load_fpr32(fp1, ft); + gen_load_fpr32(fp2, fr); +- gen_helper_float_nmuladd_s(fp2, fp0, fp1, fp2); ++ gen_helper_float_nmuladd_s(fp2, cpu_env, fp0, fp1, fp2); + tcg_temp_free_i32(fp0); + tcg_temp_free_i32(fp1); + gen_store_fpr32(fp2, fd); +@@ -8016,7 +8034,7 @@ static void gen_flt3_arith (DisasContext *ctx, uint32_t opc, + gen_load_fpr64(ctx, fp0, fs); + gen_load_fpr64(ctx, fp1, ft); + gen_load_fpr64(ctx, fp2, fr); +- gen_helper_float_nmuladd_d(fp2, fp0, fp1, fp2); ++ gen_helper_float_nmuladd_d(fp2, cpu_env, fp0, fp1, fp2); + tcg_temp_free_i64(fp0); + tcg_temp_free_i64(fp1); + gen_store_fpr64(ctx, fp2, fd); +@@ -8034,7 +8052,7 @@ static void gen_flt3_arith (DisasContext *ctx, uint32_t opc, + gen_load_fpr64(ctx, fp0, fs); + gen_load_fpr64(ctx, fp1, ft); + gen_load_fpr64(ctx, fp2, fr); +- gen_helper_float_nmuladd_ps(fp2, fp0, fp1, fp2); ++ gen_helper_float_nmuladd_ps(fp2, cpu_env, fp0, fp1, fp2); + tcg_temp_free_i64(fp0); + tcg_temp_free_i64(fp1); + gen_store_fpr64(ctx, fp2, fd); +@@ -8052,7 +8070,7 @@ static void gen_flt3_arith (DisasContext *ctx, uint32_t opc, + gen_load_fpr32(fp0, fs); + gen_load_fpr32(fp1, ft); + gen_load_fpr32(fp2, fr); +- gen_helper_float_nmulsub_s(fp2, fp0, fp1, fp2); ++ gen_helper_float_nmulsub_s(fp2, cpu_env, fp0, fp1, fp2); + tcg_temp_free_i32(fp0); + tcg_temp_free_i32(fp1); + gen_store_fpr32(fp2, fd); +@@ -8071,7 +8089,7 @@ static void gen_flt3_arith (DisasContext *ctx, uint32_t opc, + gen_load_fpr64(ctx, fp0, fs); + gen_load_fpr64(ctx, fp1, ft); + gen_load_fpr64(ctx, fp2, fr); +- gen_helper_float_nmulsub_d(fp2, fp0, fp1, fp2); ++ gen_helper_float_nmulsub_d(fp2, cpu_env, fp0, fp1, fp2); + tcg_temp_free_i64(fp0); + tcg_temp_free_i64(fp1); + gen_store_fpr64(ctx, fp2, fd); +@@ -8089,7 +8107,7 @@ static void gen_flt3_arith (DisasContext *ctx, uint32_t opc, + gen_load_fpr64(ctx, fp0, fs); + gen_load_fpr64(ctx, fp1, ft); + gen_load_fpr64(ctx, fp2, fr); +- gen_helper_float_nmulsub_ps(fp2, fp0, fp1, fp2); ++ gen_helper_float_nmulsub_ps(fp2, cpu_env, fp0, fp1, fp2); + tcg_temp_free_i64(fp0); + tcg_temp_free_i64(fp1); + gen_store_fpr64(ctx, fp2, fd); +@@ -8122,22 +8140,22 @@ gen_rdhwr (CPUMIPSState *env, DisasContext *ctx, int rt, int rd) + switch (rd) { + case 0: + save_cpu_state(ctx, 1); +- gen_helper_rdhwr_cpunum(t0); ++ gen_helper_rdhwr_cpunum(t0, cpu_env); + gen_store_gpr(t0, rt); + break; + case 1: + save_cpu_state(ctx, 1); +- gen_helper_rdhwr_synci_step(t0); ++ gen_helper_rdhwr_synci_step(t0, cpu_env); + gen_store_gpr(t0, rt); + break; + case 2: + save_cpu_state(ctx, 1); +- gen_helper_rdhwr_cc(t0); ++ gen_helper_rdhwr_cc(t0, cpu_env); + gen_store_gpr(t0, rt); + break; + case 3: + save_cpu_state(ctx, 1); +- gen_helper_rdhwr_ccres(t0); ++ gen_helper_rdhwr_ccres(t0, cpu_env); + gen_store_gpr(t0, rt); + break; + case 29: +@@ -8214,7 +8232,7 @@ static void handle_delay_slot (CPUMIPSState *env, DisasContext *ctx, + } + if (ctx->singlestep_enabled) { + save_cpu_state(ctx, 0); +- gen_helper_0i(raise_exception, EXCP_DEBUG); ++ gen_helper_0e0i(raise_exception, EXCP_DEBUG); + } + tcg_gen_exit_tb(0); + break; +@@ -8678,7 +8696,7 @@ static void decode_i64_mips16 (CPUMIPSState *env, DisasContext *ctx, + static int decode_extended_mips16_opc (CPUMIPSState *env, DisasContext *ctx, + int *is_branch) + { +- int extend = lduw_code(ctx->pc + 2); ++ int extend = cpu_lduw_code(env, ctx->pc + 2); + int op, rx, ry, funct, sa; + int16_t imm, offset; + +@@ -8904,7 +8922,7 @@ static int decode_mips16_opc (CPUMIPSState *env, DisasContext *ctx, + /* No delay slot, so just process as a normal instruction */ + break; + case M16_OPC_JAL: +- offset = lduw_code(ctx->pc + 2); ++ offset = cpu_lduw_code(env, ctx->pc + 2); + offset = (((ctx->opcode & 0x1f) << 21) + | ((ctx->opcode >> 5) & 0x1f) << 16 + | offset) << 2; +@@ -9855,17 +9873,17 @@ static void gen_ldst_multiple (DisasContext *ctx, uint32_t opc, int reglist, + save_cpu_state(ctx, 1); + switch (opc) { + case LWM32: +- gen_helper_lwm(t0, t1, t2); ++ gen_helper_lwm(cpu_env, t0, t1, t2); + break; + case SWM32: +- gen_helper_swm(t0, t1, t2); ++ gen_helper_swm(cpu_env, t0, t1, t2); + break; + #ifdef TARGET_MIPS64 + case LDM: +- gen_helper_ldm(t0, t1, t2); ++ gen_helper_ldm(cpu_env, t0, t1, t2); + break; + case SDM: +- gen_helper_sdm(t0, t1, t2); ++ gen_helper_sdm(cpu_env, t0, t1, t2); + break; + #endif + } +@@ -10287,7 +10305,7 @@ static void gen_pool32axf (CPUMIPSState *env, DisasContext *ctx, int rt, int rs, + TCGv t0 = tcg_temp_new(); + + save_cpu_state(ctx, 1); +- gen_helper_di(t0); ++ gen_helper_di(t0, cpu_env); + gen_store_gpr(t0, rs); + /* Stop translation as we may have switched the execution mode */ + ctx->bstate = BS_STOP; +@@ -10300,7 +10318,7 @@ static void gen_pool32axf (CPUMIPSState *env, DisasContext *ctx, int rt, int rs, + TCGv t0 = tcg_temp_new(); + + save_cpu_state(ctx, 1); +- gen_helper_ei(t0); ++ gen_helper_ei(t0, cpu_env); + gen_store_gpr(t0, rs); + /* Stop translation as we may have switched the execution mode */ + ctx->bstate = BS_STOP; +@@ -10635,7 +10653,7 @@ static void decode_micromips32_opc (CPUMIPSState *env, DisasContext *ctx, + uint32_t op, minor, mips32_op; + uint32_t cond, fmt, cc; + +- insn = lduw_code(ctx->pc + 2); ++ insn = cpu_lduw_code(env, ctx->pc + 2); + ctx->opcode = (ctx->opcode << 16) | insn; + + rt = (ctx->opcode >> 21) & 0x1f; +@@ -11827,7 +11845,7 @@ static void decode_opc (CPUMIPSState *env, DisasContext *ctx, int *is_branch) + MIPS_INVAL("PMON / selsl"); + generate_exception(ctx, EXCP_RI); + #else +- gen_helper_0i(pmon, sa); ++ gen_helper_0e0i(pmon, sa); + #endif + break; + case OPC_SYSCALL: +@@ -12045,7 +12063,7 @@ static void decode_opc (CPUMIPSState *env, DisasContext *ctx, int *is_branch) + + save_cpu_state(ctx, 1); + gen_load_gpr(t0, rs); +- gen_helper_yield(t0, t0); ++ gen_helper_yield(t0, cpu_env, t0); + gen_store_gpr(t0, rd); + tcg_temp_free(t0); + } +@@ -12144,18 +12162,18 @@ static void decode_opc (CPUMIPSState *env, DisasContext *ctx, int *is_branch) + break; + case OPC_DVPE: + check_insn(env, ctx, ASE_MT); +- gen_helper_dvpe(t0); ++ gen_helper_dvpe(t0, cpu_env); + gen_store_gpr(t0, rt); + break; + case OPC_EVPE: + check_insn(env, ctx, ASE_MT); +- gen_helper_evpe(t0); ++ gen_helper_evpe(t0, cpu_env); + gen_store_gpr(t0, rt); + break; + case OPC_DI: + check_insn(env, ctx, ISA_MIPS32R2); + save_cpu_state(ctx, 1); +- gen_helper_di(t0); ++ gen_helper_di(t0, cpu_env); + gen_store_gpr(t0, rt); + /* Stop translation as we may have switched the execution mode */ + ctx->bstate = BS_STOP; +@@ -12163,7 +12181,7 @@ static void decode_opc (CPUMIPSState *env, DisasContext *ctx, int *is_branch) + case OPC_EI: + check_insn(env, ctx, ISA_MIPS32R2); + save_cpu_state(ctx, 1); +- gen_helper_ei(t0); ++ gen_helper_ei(t0, cpu_env); + gen_store_gpr(t0, rt); + /* Stop translation as we may have switched the execution mode */ + ctx->bstate = BS_STOP; +@@ -12432,7 +12450,7 @@ gen_intermediate_code_internal (CPUMIPSState *env, TranslationBlock *tb, + if (bp->pc == ctx.pc) { + save_cpu_state(&ctx, 1); + ctx.bstate = BS_BRANCH; +- gen_helper_0i(raise_exception, EXCP_DEBUG); ++ gen_helper_0e0i(raise_exception, EXCP_DEBUG); + /* Include the breakpoint location or the tb won't + * be flushed when it must be. */ + ctx.pc += 4; +@@ -12458,14 +12476,14 @@ gen_intermediate_code_internal (CPUMIPSState *env, TranslationBlock *tb, + + is_branch = 0; + if (!(ctx.hflags & MIPS_HFLAG_M16)) { +- ctx.opcode = ldl_code(ctx.pc); ++ ctx.opcode = cpu_ldl_code(env, ctx.pc); + insn_bytes = 4; + decode_opc(env, &ctx, &is_branch); + } else if (env->insn_flags & ASE_MICROMIPS) { +- ctx.opcode = lduw_code(ctx.pc); ++ ctx.opcode = cpu_lduw_code(env, ctx.pc); + insn_bytes = decode_micromips_opc(env, &ctx, &is_branch); + } else if (env->insn_flags & ASE_MIPS16) { +- ctx.opcode = lduw_code(ctx.pc); ++ ctx.opcode = cpu_lduw_code(env, ctx.pc); + insn_bytes = decode_mips16_opc(env, &ctx, &is_branch); + } else { + generate_exception(&ctx, EXCP_RI); +@@ -12502,7 +12520,7 @@ gen_intermediate_code_internal (CPUMIPSState *env, TranslationBlock *tb, + gen_io_end(); + if (env->singlestep_enabled && ctx.bstate != BS_BRANCH) { + save_cpu_state(&ctx, ctx.bstate == BS_NONE); +- gen_helper_0i(raise_exception, EXCP_DEBUG); ++ gen_helper_0e0i(raise_exception, EXCP_DEBUG); + } else { + switch (ctx.bstate) { + case BS_STOP: +-- +1.7.12.1 + diff --git a/0039-Remove-unused-CONFIG_TCG_PASS_AREG0-and-dead-code.patch b/0039-Remove-unused-CONFIG_TCG_PASS_AREG0-and-dead-code.patch new file mode 100644 index 0000000..72c61e8 --- /dev/null +++ b/0039-Remove-unused-CONFIG_TCG_PASS_AREG0-and-dead-code.patch @@ -0,0 +1,1683 @@ +From 3ec8ca067ea6617b5bd4423d0b40c894b39a4924 Mon Sep 17 00:00:00 2001 +From: Blue Swirl +Date: Sun, 2 Sep 2012 15:28:56 +0000 +Subject: [PATCH] Remove unused CONFIG_TCG_PASS_AREG0 and dead code + +Now that CONFIG_TCG_PASS_AREG0 is enabled for all targets, +remove dead code and support for !CONFIG_TCG_PASS_AREG0 case. + +Remove dyngen-exec.h and all references to it. Although included by +hw/spapr_hcall.c, it does not seem to use it. + +Remove unused HELPER_CFLAGS. + +Signed-off-by: Blue Swirl +Reviewed-by: Richard Henderson +Signed-off-by: Michael Roth +--- + Makefile.target | 8 ------ + configure | 11 ------- + cpu-all.h | 11 ------- + cputlb.c | 5 ---- + dyngen-exec.h | 70 -------------------------------------------- + exec-all.h | 4 --- + hw/spapr_hcall.c | 1 - + softmmu_defs.h | 21 -------------- + softmmu_header.h | 63 +++++++++++++--------------------------- + softmmu_template.h | 72 +++++++++++++++++----------------------------- + target-m68k/op_helper.c | 3 -- + target-sparc/Makefile.objs | 2 -- + tcg/arm/tcg-target.c | 31 ++------------------ + tcg/arm/tcg-target.h | 1 - + tcg/hppa/tcg-target.c | 24 ---------------- + tcg/hppa/tcg-target.h | 1 - + tcg/i386/tcg-target.c | 30 ------------------- + tcg/i386/tcg-target.h | 1 - + tcg/ia64/tcg-target.c | 34 ---------------------- + tcg/ia64/tcg-target.h | 1 - + tcg/mips/tcg-target.c | 31 ++------------------ + tcg/mips/tcg-target.h | 1 - + tcg/ppc/tcg-target.c | 38 ------------------------ + tcg/ppc64/tcg-target.c | 28 ------------------ + tcg/s390/tcg-target.c | 24 ---------------- + tcg/s390/tcg-target.h | 1 - + tcg/sparc/tcg-target.c | 30 ------------------- + tcg/sparc/tcg-target.h | 1 - + tcg/tci/tcg-target.c | 4 --- + tci.c | 12 -------- + user-exec.c | 14 --------- + 31 files changed, 53 insertions(+), 525 deletions(-) + delete mode 100644 dyngen-exec.h + +diff --git a/Makefile.target b/Makefile.target +index 7892a8d..d9d54b8 100644 +--- a/Makefile.target ++++ b/Makefile.target +@@ -80,14 +80,6 @@ obj-$(CONFIG_GDBSTUB_XML) += gdbstub-xml.o + + tci-dis.o: QEMU_CFLAGS += -I$(SRC_PATH)/tcg -I$(SRC_PATH)/tcg/tci + +-# HELPER_CFLAGS is used for all the legacy code compiled with static register +-# variables +-user-exec.o: QEMU_CFLAGS += $(HELPER_CFLAGS) +- +-# Note: this is a workaround. The real fix is to avoid compiling +-# cpu_signal_handler() in user-exec.c. +-%/signal.o: QEMU_CFLAGS += $(HELPER_CFLAGS) +- + ######################################################### + # Linux user emulator target + +diff --git a/configure b/configure +index 83b068d..816f0f9 100755 +--- a/configure ++++ b/configure +@@ -118,7 +118,6 @@ audio_card_list="ac97 es1370 sb16 hda" + audio_possible_cards="ac97 es1370 sb16 cs4231a adlib gus hda" + block_drv_whitelist="" + host_cc="gcc" +-helper_cflags="" + libs_softmmu="" + libs_tools="" + audio_pt_int="" +@@ -904,7 +903,6 @@ case "$cpu" in + QEMU_CFLAGS="-m32 -ffixed-g2 -ffixed-g3 $QEMU_CFLAGS" + if test "$solaris" = "no" ; then + QEMU_CFLAGS="-ffixed-g1 -ffixed-g6 $QEMU_CFLAGS" +- helper_cflags="-ffixed-i0" + fi + ;; + sparc64) +@@ -929,7 +927,6 @@ case "$cpu" in + QEMU_CFLAGS="-m32 $QEMU_CFLAGS" + LDFLAGS="-m32 $LDFLAGS" + cc_i386='$(CC) -m32' +- helper_cflags="-fomit-frame-pointer" + host_guest_base="yes" + ;; + x86_64) +@@ -3582,7 +3579,6 @@ if test "$sparse" = "yes" ; then + echo "HOST_CC := REAL_CC=\"\$(HOST_CC)\" cgcc" >> $config_host_mak + echo "QEMU_CFLAGS += -Wbitwise -Wno-transparent-union -Wno-old-initializer -Wno-non-pointer-null" >> $config_host_mak + fi +-echo "HELPER_CFLAGS=$helper_cflags" >> $config_host_mak + echo "LDFLAGS=$LDFLAGS" >> $config_host_mak + echo "ARLIBS_BEGIN=$arlibs_begin" >> $config_host_mak + echo "ARLIBS_END=$arlibs_end" >> $config_host_mak +@@ -3837,13 +3833,6 @@ fi + + symlink "$source_path/Makefile.target" "$target_dir/Makefile" + +- +-case "$target_arch2" in +- alpha | arm* | cris | i386 | lm32 | m68k | microblaze* | mips* | or32 | s390x | sh4* | sparc* | unicore32 | x86_64 | xtensa* | ppc*) +- echo "CONFIG_TCG_PASS_AREG0=y" >> $config_target_mak +- ;; +-esac +- + upper() { + echo "$@"| LC_ALL=C tr '[a-z]' '[A-Z]' + } +diff --git a/cpu-all.h b/cpu-all.h +index 5e07d28..74d3681 100644 +--- a/cpu-all.h ++++ b/cpu-all.h +@@ -260,14 +260,6 @@ extern unsigned long reserved_va; + #define stfl(p, v) stfl_raw(p, v) + #define stfq(p, v) stfq_raw(p, v) + +-#ifndef CONFIG_TCG_PASS_AREG0 +-#define ldub_code(p) ldub_raw(p) +-#define ldsb_code(p) ldsb_raw(p) +-#define lduw_code(p) lduw_raw(p) +-#define ldsw_code(p) ldsw_raw(p) +-#define ldl_code(p) ldl_raw(p) +-#define ldq_code(p) ldq_raw(p) +-#else + #define cpu_ldub_code(env1, p) ldub_raw(p) + #define cpu_ldsb_code(env1, p) ldsb_raw(p) + #define cpu_lduw_code(env1, p) lduw_raw(p) +@@ -296,7 +288,6 @@ extern unsigned long reserved_va; + #define cpu_stw_kernel(env, addr, data) stw_raw(addr, data) + #define cpu_stl_kernel(env, addr, data) stl_raw(addr, data) + #define cpu_stq_kernel(env, addr, data) stq_raw(addr, data) +-#endif + + #define ldub_kernel(p) ldub_raw(p) + #define ldsb_kernel(p) ldsb_raw(p) +@@ -313,7 +304,6 @@ extern unsigned long reserved_va; + #define stfl_kernel(p, v) stfl_raw(p, v) + #define stfq_kernel(p, vt) stfq_raw(p, v) + +-#ifdef CONFIG_TCG_PASS_AREG0 + #define cpu_ldub_data(env, addr) ldub_raw(addr) + #define cpu_lduw_data(env, addr) lduw_raw(addr) + #define cpu_ldl_data(env, addr) ldl_raw(addr) +@@ -321,7 +311,6 @@ extern unsigned long reserved_va; + #define cpu_stb_data(env, addr, data) stb_raw(addr, data) + #define cpu_stw_data(env, addr, data) stw_raw(addr, data) + #define cpu_stl_data(env, addr, data) stl_raw(addr, data) +-#endif + #endif /* defined(CONFIG_USER_ONLY) */ + + /* page related stuff */ +diff --git a/cputlb.c b/cputlb.c +index d3e7b25..51b5897 100644 +--- a/cputlb.c ++++ b/cputlb.c +@@ -325,11 +325,7 @@ tb_page_addr_t get_page_addr_code(CPUArchState *env1, target_ulong addr) + mmu_idx = cpu_mmu_index(env1); + if (unlikely(env1->tlb_table[mmu_idx][page_index].addr_code != + (addr & TARGET_PAGE_MASK))) { +-#ifdef CONFIG_TCG_PASS_AREG0 + cpu_ldub_code(env1, addr); +-#else +- ldub_code(addr); +-#endif + } + pd = env1->iotlb[mmu_idx][page_index] & ~TARGET_PAGE_MASK; + mr = iotlb_to_region(pd); +@@ -348,7 +344,6 @@ tb_page_addr_t get_page_addr_code(CPUArchState *env1, target_ulong addr) + #define MMUSUFFIX _cmmu + #undef GETPC + #define GETPC() ((uintptr_t)0) +-#define env cpu_single_env + #define SOFTMMU_CODE_ACCESS + + #define SHIFT 0 +diff --git a/dyngen-exec.h b/dyngen-exec.h +deleted file mode 100644 +index 083e20b..0000000 +--- a/dyngen-exec.h ++++ /dev/null +@@ -1,70 +0,0 @@ +-/* +- * dyngen defines for micro operation code +- * +- * Copyright (c) 2003 Fabrice Bellard +- * +- * This library is free software; you can redistribute it and/or +- * modify it under the terms of the GNU Lesser General Public +- * License as published by the Free Software Foundation; either +- * version 2 of the License, or (at your option) any later version. +- * +- * This library is distributed in the hope that it will be useful, +- * but WITHOUT ANY WARRANTY; without even the implied warranty of +- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +- * Lesser General Public License for more details. +- * +- * You should have received a copy of the GNU Lesser General Public +- * License along with this library; if not, see . +- */ +-#if !defined(__DYNGEN_EXEC_H__) +-#define __DYNGEN_EXEC_H__ +- +-#if defined(CONFIG_TCG_INTERPRETER) +-/* The TCG interpreter does not need a special register AREG0, +- * but it is possible to use one by defining AREG0. +- * On i386, register edi seems to work. */ +-/* Run without special register AREG0 or use a value defined elsewhere. */ +-#elif defined(__i386__) +-#define AREG0 "ebp" +-#elif defined(__x86_64__) +-#define AREG0 "r14" +-#elif defined(_ARCH_PPC) +-#define AREG0 "r27" +-#elif defined(__arm__) +-#define AREG0 "r6" +-#elif defined(__hppa__) +-#define AREG0 "r17" +-#elif defined(__mips__) +-#define AREG0 "s0" +-#elif defined(__sparc__) +-#ifdef CONFIG_SOLARIS +-#define AREG0 "g2" +-#else +-#ifdef __sparc_v9__ +-#define AREG0 "g5" +-#else +-#define AREG0 "g6" +-#endif +-#endif +-#elif defined(__s390__) +-#define AREG0 "r10" +-#elif defined(__alpha__) +-/* Note $15 is the frame pointer, so anything in op-i386.c that would +- require a frame pointer, like alloca, would probably loose. */ +-#define AREG0 "$15" +-#elif defined(__mc68000) +-#define AREG0 "%a5" +-#elif defined(__ia64__) +-#define AREG0 "r7" +-#else +-#error unsupported CPU +-#endif +- +-#if defined(AREG0) +-register CPUArchState *env asm(AREG0); +-#else +-/* TODO: Try env = cpu_single_env. */ +-extern CPUArchState *env; +-#endif +- +-#endif /* !defined(__DYNGEN_EXEC_H__) */ +diff --git a/exec-all.h b/exec-all.h +index c5ec8e1..c5d3a13 100644 +--- a/exec-all.h ++++ b/exec-all.h +@@ -323,9 +323,6 @@ void tlb_fill(CPUArchState *env1, target_ulong addr, int is_write, int mmu_idx, + + #define ACCESS_TYPE (NB_MMU_MODES + 1) + #define MEMSUFFIX _code +-#ifndef CONFIG_TCG_PASS_AREG0 +-#define env cpu_single_env +-#endif + + #define DATA_SIZE 1 + #include "softmmu_header.h" +@@ -341,7 +338,6 @@ void tlb_fill(CPUArchState *env1, target_ulong addr, int is_write, int mmu_idx, + + #undef ACCESS_TYPE + #undef MEMSUFFIX +-#undef env + + #endif + +diff --git a/hw/spapr_hcall.c b/hw/spapr_hcall.c +index a5990a9..abd847f 100644 +--- a/hw/spapr_hcall.c ++++ b/hw/spapr_hcall.c +@@ -1,6 +1,5 @@ + #include "sysemu.h" + #include "cpu.h" +-#include "dyngen-exec.h" + #include "qemu-char.h" + #include "sysemu.h" + #include "qemu-char.h" +diff --git a/softmmu_defs.h b/softmmu_defs.h +index 8d59f9d..1f25e33 100644 +--- a/softmmu_defs.h ++++ b/softmmu_defs.h +@@ -9,25 +9,6 @@ + #ifndef SOFTMMU_DEFS_H + #define SOFTMMU_DEFS_H + +-#ifndef CONFIG_TCG_PASS_AREG0 +-uint8_t __ldb_mmu(target_ulong addr, int mmu_idx); +-void __stb_mmu(target_ulong addr, uint8_t val, int mmu_idx); +-uint16_t __ldw_mmu(target_ulong addr, int mmu_idx); +-void __stw_mmu(target_ulong addr, uint16_t val, int mmu_idx); +-uint32_t __ldl_mmu(target_ulong addr, int mmu_idx); +-void __stl_mmu(target_ulong addr, uint32_t val, int mmu_idx); +-uint64_t __ldq_mmu(target_ulong addr, int mmu_idx); +-void __stq_mmu(target_ulong addr, uint64_t val, int mmu_idx); +- +-uint8_t __ldb_cmmu(target_ulong addr, int mmu_idx); +-void __stb_cmmu(target_ulong addr, uint8_t val, int mmu_idx); +-uint16_t __ldw_cmmu(target_ulong addr, int mmu_idx); +-void __stw_cmmu(target_ulong addr, uint16_t val, int mmu_idx); +-uint32_t __ldl_cmmu(target_ulong addr, int mmu_idx); +-void __stl_cmmu(target_ulong addr, uint32_t val, int mmu_idx); +-uint64_t __ldq_cmmu(target_ulong addr, int mmu_idx); +-void __stq_cmmu(target_ulong addr, uint64_t val, int mmu_idx); +-#else + uint8_t helper_ldb_mmu(CPUArchState *env, target_ulong addr, int mmu_idx); + void helper_stb_mmu(CPUArchState *env, target_ulong addr, uint8_t val, + int mmu_idx); +@@ -54,5 +35,3 @@ uint64_t helper_ldq_cmmu(CPUArchState *env, target_ulong addr, int mmu_idx); + void helper_stq_cmmu(CPUArchState *env, target_ulong addr, uint64_t val, + int mmu_idx); + #endif +- +-#endif +diff --git a/softmmu_header.h b/softmmu_header.h +index cf1aa38..d8d9c81 100644 +--- a/softmmu_header.h ++++ b/softmmu_header.h +@@ -78,23 +78,10 @@ + #define ADDR_READ addr_read + #endif + +-#ifndef CONFIG_TCG_PASS_AREG0 +-#define ENV_PARAM +-#define ENV_VAR +-#define CPU_PREFIX +-#define HELPER_PREFIX __ +-#else +-#define ENV_PARAM CPUArchState *env, +-#define ENV_VAR env, +-#define CPU_PREFIX cpu_ +-#define HELPER_PREFIX helper_ +-#endif +- + /* generic load/store macros */ + + static inline RES_TYPE +-glue(glue(glue(CPU_PREFIX, ld), USUFFIX), MEMSUFFIX)(ENV_PARAM +- target_ulong ptr) ++glue(glue(cpu_ld, USUFFIX), MEMSUFFIX)(CPUArchState *env, target_ulong ptr) + { + int page_index; + RES_TYPE res; +@@ -106,9 +93,7 @@ glue(glue(glue(CPU_PREFIX, ld), USUFFIX), MEMSUFFIX)(ENV_PARAM + mmu_idx = CPU_MMU_INDEX; + if (unlikely(env->tlb_table[mmu_idx][page_index].ADDR_READ != + (addr & (TARGET_PAGE_MASK | (DATA_SIZE - 1))))) { +- res = glue(glue(glue(HELPER_PREFIX, ld), SUFFIX), MMUSUFFIX)(ENV_VAR +- addr, +- mmu_idx); ++ res = glue(glue(helper_ld, SUFFIX), MMUSUFFIX)(env, addr, mmu_idx); + } else { + uintptr_t hostaddr = addr + env->tlb_table[mmu_idx][page_index].addend; + res = glue(glue(ld, USUFFIX), _raw)(hostaddr); +@@ -118,8 +103,7 @@ glue(glue(glue(CPU_PREFIX, ld), USUFFIX), MEMSUFFIX)(ENV_PARAM + + #if DATA_SIZE <= 2 + static inline int +-glue(glue(glue(CPU_PREFIX, lds), SUFFIX), MEMSUFFIX)(ENV_PARAM +- target_ulong ptr) ++glue(glue(cpu_lds, SUFFIX), MEMSUFFIX)(CPUArchState *env, target_ulong ptr) + { + int res, page_index; + target_ulong addr; +@@ -130,8 +114,8 @@ glue(glue(glue(CPU_PREFIX, lds), SUFFIX), MEMSUFFIX)(ENV_PARAM + mmu_idx = CPU_MMU_INDEX; + if (unlikely(env->tlb_table[mmu_idx][page_index].ADDR_READ != + (addr & (TARGET_PAGE_MASK | (DATA_SIZE - 1))))) { +- res = (DATA_STYPE)glue(glue(glue(HELPER_PREFIX, ld), SUFFIX), +- MMUSUFFIX)(ENV_VAR addr, mmu_idx); ++ res = (DATA_STYPE)glue(glue(helper_ld, SUFFIX), ++ MMUSUFFIX)(env, addr, mmu_idx); + } else { + uintptr_t hostaddr = addr + env->tlb_table[mmu_idx][page_index].addend; + res = glue(glue(lds, SUFFIX), _raw)(hostaddr); +@@ -145,8 +129,8 @@ glue(glue(glue(CPU_PREFIX, lds), SUFFIX), MEMSUFFIX)(ENV_PARAM + /* generic store macro */ + + static inline void +-glue(glue(glue(CPU_PREFIX, st), SUFFIX), MEMSUFFIX)(ENV_PARAM target_ulong ptr, +- RES_TYPE v) ++glue(glue(cpu_st, SUFFIX), MEMSUFFIX)(CPUArchState *env, target_ulong ptr, ++ RES_TYPE v) + { + int page_index; + target_ulong addr; +@@ -157,8 +141,7 @@ glue(glue(glue(CPU_PREFIX, st), SUFFIX), MEMSUFFIX)(ENV_PARAM target_ulong ptr, + mmu_idx = CPU_MMU_INDEX; + if (unlikely(env->tlb_table[mmu_idx][page_index].addr_write != + (addr & (TARGET_PAGE_MASK | (DATA_SIZE - 1))))) { +- glue(glue(glue(HELPER_PREFIX, st), SUFFIX), MMUSUFFIX)(ENV_VAR addr, v, +- mmu_idx); ++ glue(glue(helper_st, SUFFIX), MMUSUFFIX)(env, addr, v, mmu_idx); + } else { + uintptr_t hostaddr = addr + env->tlb_table[mmu_idx][page_index].addend; + glue(glue(st, SUFFIX), _raw)(hostaddr, v); +@@ -170,52 +153,50 @@ glue(glue(glue(CPU_PREFIX, st), SUFFIX), MEMSUFFIX)(ENV_PARAM target_ulong ptr, + #if ACCESS_TYPE != (NB_MMU_MODES + 1) + + #if DATA_SIZE == 8 +-static inline float64 glue(glue(CPU_PREFIX, ldfq), MEMSUFFIX)(ENV_PARAM +- target_ulong ptr) ++static inline float64 glue(cpu_ldfq, MEMSUFFIX)(CPUArchState *env, ++ target_ulong ptr) + { + union { + float64 d; + uint64_t i; + } u; +- u.i = glue(glue(CPU_PREFIX, ldq), MEMSUFFIX)(ENV_VAR ptr); ++ u.i = glue(cpu_ldq, MEMSUFFIX)(env, ptr); + return u.d; + } + +-static inline void glue(glue(CPU_PREFIX, stfq), MEMSUFFIX)(ENV_PARAM +- target_ulong ptr, +- float64 v) ++static inline void glue(cpu_stfq, MEMSUFFIX)(CPUArchState *env, ++ target_ulong ptr, float64 v) + { + union { + float64 d; + uint64_t i; + } u; + u.d = v; +- glue(glue(CPU_PREFIX, stq), MEMSUFFIX)(ENV_VAR ptr, u.i); ++ glue(cpu_stq, MEMSUFFIX)(env, ptr, u.i); + } + #endif /* DATA_SIZE == 8 */ + + #if DATA_SIZE == 4 +-static inline float32 glue(glue(CPU_PREFIX, ldfl), MEMSUFFIX)(ENV_PARAM +- target_ulong ptr) ++static inline float32 glue(cpu_ldfl, MEMSUFFIX)(CPUArchState *env, ++ target_ulong ptr) + { + union { + float32 f; + uint32_t i; + } u; +- u.i = glue(glue(CPU_PREFIX, ldl), MEMSUFFIX)(ENV_VAR ptr); ++ u.i = glue(cpu_ldl, MEMSUFFIX)(env, ptr); + return u.f; + } + +-static inline void glue(glue(CPU_PREFIX, stfl), MEMSUFFIX)(ENV_PARAM +- target_ulong ptr, +- float32 v) ++static inline void glue(cpu_stfl, MEMSUFFIX)(CPUArchState *env, ++ target_ulong ptr, float32 v) + { + union { + float32 f; + uint32_t i; + } u; + u.f = v; +- glue(glue(CPU_PREFIX, stl), MEMSUFFIX)(ENV_VAR ptr, u.i); ++ glue(cpu_stl, MEMSUFFIX)(env, ptr, u.i); + } + #endif /* DATA_SIZE == 4 */ + +@@ -230,7 +211,3 @@ static inline void glue(glue(CPU_PREFIX, stfl), MEMSUFFIX)(ENV_PARAM + #undef CPU_MMU_INDEX + #undef MMUSUFFIX + #undef ADDR_READ +-#undef ENV_PARAM +-#undef ENV_VAR +-#undef CPU_PREFIX +-#undef HELPER_PREFIX +diff --git a/softmmu_template.h b/softmmu_template.h +index b8bd700..e2490f0 100644 +--- a/softmmu_template.h ++++ b/softmmu_template.h +@@ -54,23 +54,11 @@ + #define ADDR_READ addr_read + #endif + +-#ifndef CONFIG_TCG_PASS_AREG0 +-#define ENV_PARAM +-#define ENV_VAR +-#define CPU_PREFIX +-#define HELPER_PREFIX __ +-#else +-#define ENV_PARAM CPUArchState *env, +-#define ENV_VAR env, +-#define CPU_PREFIX cpu_ +-#define HELPER_PREFIX helper_ +-#endif +- +-static DATA_TYPE glue(glue(slow_ld, SUFFIX), MMUSUFFIX)(ENV_PARAM ++static DATA_TYPE glue(glue(slow_ld, SUFFIX), MMUSUFFIX)(CPUArchState *env, + target_ulong addr, + int mmu_idx, + uintptr_t retaddr); +-static inline DATA_TYPE glue(io_read, SUFFIX)(ENV_PARAM ++static inline DATA_TYPE glue(io_read, SUFFIX)(CPUArchState *env, + target_phys_addr_t physaddr, + target_ulong addr, + uintptr_t retaddr) +@@ -104,9 +92,8 @@ static inline DATA_TYPE glue(io_read, SUFFIX)(ENV_PARAM + + /* handle all cases except unaligned access which span two pages */ + DATA_TYPE +-glue(glue(glue(HELPER_PREFIX, ld), SUFFIX), MMUSUFFIX)(ENV_PARAM +- target_ulong addr, +- int mmu_idx) ++glue(glue(helper_ld, SUFFIX), MMUSUFFIX)(CPUArchState *env, target_ulong addr, ++ int mmu_idx) + { + DATA_TYPE res; + int index; +@@ -126,15 +113,15 @@ glue(glue(glue(HELPER_PREFIX, ld), SUFFIX), MMUSUFFIX)(ENV_PARAM + goto do_unaligned_access; + retaddr = GETPC(); + ioaddr = env->iotlb[mmu_idx][index]; +- res = glue(io_read, SUFFIX)(ENV_VAR ioaddr, addr, retaddr); ++ res = glue(io_read, SUFFIX)(env, ioaddr, addr, retaddr); + } else if (((addr & ~TARGET_PAGE_MASK) + DATA_SIZE - 1) >= TARGET_PAGE_SIZE) { + /* slow unaligned access (it spans two pages or IO) */ + do_unaligned_access: + retaddr = GETPC(); + #ifdef ALIGNED_ONLY +- do_unaligned_access(ENV_VAR addr, READ_ACCESS_TYPE, mmu_idx, retaddr); ++ do_unaligned_access(env, addr, READ_ACCESS_TYPE, mmu_idx, retaddr); + #endif +- res = glue(glue(slow_ld, SUFFIX), MMUSUFFIX)(ENV_VAR addr, ++ res = glue(glue(slow_ld, SUFFIX), MMUSUFFIX)(env, addr, + mmu_idx, retaddr); + } else { + /* unaligned/aligned access in the same page */ +@@ -142,7 +129,7 @@ glue(glue(glue(HELPER_PREFIX, ld), SUFFIX), MMUSUFFIX)(ENV_PARAM + #ifdef ALIGNED_ONLY + if ((addr & (DATA_SIZE - 1)) != 0) { + retaddr = GETPC(); +- do_unaligned_access(ENV_VAR addr, READ_ACCESS_TYPE, mmu_idx, retaddr); ++ do_unaligned_access(env, addr, READ_ACCESS_TYPE, mmu_idx, retaddr); + } + #endif + addend = env->tlb_table[mmu_idx][index].addend; +@@ -154,7 +141,7 @@ glue(glue(glue(HELPER_PREFIX, ld), SUFFIX), MMUSUFFIX)(ENV_PARAM + retaddr = GETPC(); + #ifdef ALIGNED_ONLY + if ((addr & (DATA_SIZE - 1)) != 0) +- do_unaligned_access(ENV_VAR addr, READ_ACCESS_TYPE, mmu_idx, retaddr); ++ do_unaligned_access(env, addr, READ_ACCESS_TYPE, mmu_idx, retaddr); + #endif + tlb_fill(env, addr, READ_ACCESS_TYPE, mmu_idx, retaddr); + goto redo; +@@ -164,7 +151,7 @@ glue(glue(glue(HELPER_PREFIX, ld), SUFFIX), MMUSUFFIX)(ENV_PARAM + + /* handle all unaligned cases */ + static DATA_TYPE +-glue(glue(slow_ld, SUFFIX), MMUSUFFIX)(ENV_PARAM ++glue(glue(slow_ld, SUFFIX), MMUSUFFIX)(CPUArchState *env, + target_ulong addr, + int mmu_idx, + uintptr_t retaddr) +@@ -183,15 +170,15 @@ glue(glue(slow_ld, SUFFIX), MMUSUFFIX)(ENV_PARAM + if ((addr & (DATA_SIZE - 1)) != 0) + goto do_unaligned_access; + ioaddr = env->iotlb[mmu_idx][index]; +- res = glue(io_read, SUFFIX)(ENV_VAR ioaddr, addr, retaddr); ++ res = glue(io_read, SUFFIX)(env, ioaddr, addr, retaddr); + } else if (((addr & ~TARGET_PAGE_MASK) + DATA_SIZE - 1) >= TARGET_PAGE_SIZE) { + do_unaligned_access: + /* slow unaligned access (it spans two pages) */ + addr1 = addr & ~(DATA_SIZE - 1); + addr2 = addr1 + DATA_SIZE; +- res1 = glue(glue(slow_ld, SUFFIX), MMUSUFFIX)(ENV_VAR addr1, ++ res1 = glue(glue(slow_ld, SUFFIX), MMUSUFFIX)(env, addr1, + mmu_idx, retaddr); +- res2 = glue(glue(slow_ld, SUFFIX), MMUSUFFIX)(ENV_VAR addr2, ++ res2 = glue(glue(slow_ld, SUFFIX), MMUSUFFIX)(env, addr2, + mmu_idx, retaddr); + shift = (addr & (DATA_SIZE - 1)) * 8; + #ifdef TARGET_WORDS_BIGENDIAN +@@ -216,13 +203,13 @@ glue(glue(slow_ld, SUFFIX), MMUSUFFIX)(ENV_PARAM + + #ifndef SOFTMMU_CODE_ACCESS + +-static void glue(glue(slow_st, SUFFIX), MMUSUFFIX)(ENV_PARAM ++static void glue(glue(slow_st, SUFFIX), MMUSUFFIX)(CPUArchState *env, + target_ulong addr, + DATA_TYPE val, + int mmu_idx, + uintptr_t retaddr); + +-static inline void glue(io_write, SUFFIX)(ENV_PARAM ++static inline void glue(io_write, SUFFIX)(CPUArchState *env, + target_phys_addr_t physaddr, + DATA_TYPE val, + target_ulong addr, +@@ -253,10 +240,9 @@ static inline void glue(io_write, SUFFIX)(ENV_PARAM + #endif /* SHIFT > 2 */ + } + +-void glue(glue(glue(HELPER_PREFIX, st), SUFFIX), MMUSUFFIX)(ENV_PARAM +- target_ulong addr, +- DATA_TYPE val, +- int mmu_idx) ++void glue(glue(helper_st, SUFFIX), MMUSUFFIX)(CPUArchState *env, ++ target_ulong addr, DATA_TYPE val, ++ int mmu_idx) + { + target_phys_addr_t ioaddr; + target_ulong tlb_addr; +@@ -273,14 +259,14 @@ void glue(glue(glue(HELPER_PREFIX, st), SUFFIX), MMUSUFFIX)(ENV_PARAM + goto do_unaligned_access; + retaddr = GETPC(); + ioaddr = env->iotlb[mmu_idx][index]; +- glue(io_write, SUFFIX)(ENV_VAR ioaddr, val, addr, retaddr); ++ glue(io_write, SUFFIX)(env, ioaddr, val, addr, retaddr); + } else if (((addr & ~TARGET_PAGE_MASK) + DATA_SIZE - 1) >= TARGET_PAGE_SIZE) { + do_unaligned_access: + retaddr = GETPC(); + #ifdef ALIGNED_ONLY +- do_unaligned_access(ENV_VAR addr, 1, mmu_idx, retaddr); ++ do_unaligned_access(env, addr, 1, mmu_idx, retaddr); + #endif +- glue(glue(slow_st, SUFFIX), MMUSUFFIX)(ENV_VAR addr, val, ++ glue(glue(slow_st, SUFFIX), MMUSUFFIX)(env, addr, val, + mmu_idx, retaddr); + } else { + /* aligned/unaligned access in the same page */ +@@ -288,7 +274,7 @@ void glue(glue(glue(HELPER_PREFIX, st), SUFFIX), MMUSUFFIX)(ENV_PARAM + #ifdef ALIGNED_ONLY + if ((addr & (DATA_SIZE - 1)) != 0) { + retaddr = GETPC(); +- do_unaligned_access(ENV_VAR addr, 1, mmu_idx, retaddr); ++ do_unaligned_access(env, addr, 1, mmu_idx, retaddr); + } + #endif + addend = env->tlb_table[mmu_idx][index].addend; +@@ -300,7 +286,7 @@ void glue(glue(glue(HELPER_PREFIX, st), SUFFIX), MMUSUFFIX)(ENV_PARAM + retaddr = GETPC(); + #ifdef ALIGNED_ONLY + if ((addr & (DATA_SIZE - 1)) != 0) +- do_unaligned_access(ENV_VAR addr, 1, mmu_idx, retaddr); ++ do_unaligned_access(env, addr, 1, mmu_idx, retaddr); + #endif + tlb_fill(env, addr, 1, mmu_idx, retaddr); + goto redo; +@@ -308,7 +294,7 @@ void glue(glue(glue(HELPER_PREFIX, st), SUFFIX), MMUSUFFIX)(ENV_PARAM + } + + /* handles all unaligned cases */ +-static void glue(glue(slow_st, SUFFIX), MMUSUFFIX)(ENV_PARAM ++static void glue(glue(slow_st, SUFFIX), MMUSUFFIX)(CPUArchState *env, + target_ulong addr, + DATA_TYPE val, + int mmu_idx, +@@ -327,7 +313,7 @@ static void glue(glue(slow_st, SUFFIX), MMUSUFFIX)(ENV_PARAM + if ((addr & (DATA_SIZE - 1)) != 0) + goto do_unaligned_access; + ioaddr = env->iotlb[mmu_idx][index]; +- glue(io_write, SUFFIX)(ENV_VAR ioaddr, val, addr, retaddr); ++ glue(io_write, SUFFIX)(env, ioaddr, val, addr, retaddr); + } else if (((addr & ~TARGET_PAGE_MASK) + DATA_SIZE - 1) >= TARGET_PAGE_SIZE) { + do_unaligned_access: + /* XXX: not efficient, but simple */ +@@ -335,11 +321,11 @@ static void glue(glue(slow_st, SUFFIX), MMUSUFFIX)(ENV_PARAM + * previous page from the TLB cache. */ + for(i = DATA_SIZE - 1; i >= 0; i--) { + #ifdef TARGET_WORDS_BIGENDIAN +- glue(slow_stb, MMUSUFFIX)(ENV_VAR addr + i, ++ glue(slow_stb, MMUSUFFIX)(env, addr + i, + val >> (((DATA_SIZE - 1) * 8) - (i * 8)), + mmu_idx, retaddr); + #else +- glue(slow_stb, MMUSUFFIX)(ENV_VAR addr + i, ++ glue(slow_stb, MMUSUFFIX)(env, addr + i, + val >> (i * 8), + mmu_idx, retaddr); + #endif +@@ -366,7 +352,3 @@ static void glue(glue(slow_st, SUFFIX), MMUSUFFIX)(ENV_PARAM + #undef USUFFIX + #undef DATA_SIZE + #undef ADDR_READ +-#undef ENV_PARAM +-#undef ENV_VAR +-#undef CPU_PREFIX +-#undef HELPER_PREFIX +diff --git a/target-m68k/op_helper.c b/target-m68k/op_helper.c +index 3116287..aa00504 100644 +--- a/target-m68k/op_helper.c ++++ b/target-m68k/op_helper.c +@@ -192,9 +192,6 @@ void HELPER(divu)(CPUM68KState *env, uint32_t word) + quot = num / den; + rem = num % den; + flags = 0; +- /* Avoid using a PARAM1 of zero. This breaks dyngen because it uses +- the address of a symbol, and gcc knows symbols can't have address +- zero. */ + if (word && quot > 0xffff) + flags |= CCF_V; + if (quot == 0) +diff --git a/target-sparc/Makefile.objs b/target-sparc/Makefile.objs +index a93e07d..9fc42ea 100644 +--- a/target-sparc/Makefile.objs ++++ b/target-sparc/Makefile.objs +@@ -4,5 +4,3 @@ obj-y += fop_helper.o cc_helper.o win_helper.o mmu_helper.o ldst_helper.o + obj-$(TARGET_SPARC) += int32_helper.o + obj-$(TARGET_SPARC64) += int64_helper.o + obj-$(TARGET_SPARC64) += vis_helper.o +- +-$(obj)/op_helper.o: QEMU_CFLAGS += $(HELPER_CFLAGS) +diff --git a/tcg/arm/tcg-target.c b/tcg/arm/tcg-target.c +index cf0ca3d..aed3b53 100644 +--- a/tcg/arm/tcg-target.c ++++ b/tcg/arm/tcg-target.c +@@ -176,7 +176,7 @@ static int target_parse_constraint(TCGArgConstraint *ct, const char **pct_str) + so don't use these. */ + tcg_regset_reset_reg(ct->u.regs, TCG_REG_R0); + tcg_regset_reset_reg(ct->u.regs, TCG_REG_R1); +-#if defined(CONFIG_TCG_PASS_AREG0) && (TARGET_LONG_BITS == 64) ++#if TARGET_LONG_BITS == 64 + /* If we're passing env to the helper as r0 and need a regpair + * for the address then r2 will be overwritten as we're setting + * up the args to the helper. +@@ -204,8 +204,7 @@ static int target_parse_constraint(TCGArgConstraint *ct, const char **pct_str) + use these. */ + tcg_regset_reset_reg(ct->u.regs, TCG_REG_R0); + tcg_regset_reset_reg(ct->u.regs, TCG_REG_R1); +-#if defined(CONFIG_SOFTMMU) && \ +- defined(CONFIG_TCG_PASS_AREG0) && (TARGET_LONG_BITS == 64) ++#if defined(CONFIG_SOFTMMU) && (TARGET_LONG_BITS == 64) + /* Avoid clashes with registers being used for helper args */ + tcg_regset_reset_reg(ct->u.regs, TCG_REG_R2); + tcg_regset_reset_reg(ct->u.regs, TCG_REG_R3); +@@ -223,7 +222,7 @@ static int target_parse_constraint(TCGArgConstraint *ct, const char **pct_str) + #ifdef CONFIG_SOFTMMU + /* r2 is still needed to load data_reg, so don't use it. */ + tcg_regset_reset_reg(ct->u.regs, TCG_REG_R2); +-#if defined(CONFIG_TCG_PASS_AREG0) && (TARGET_LONG_BITS == 64) ++#if TARGET_LONG_BITS == 64 + /* Avoid clashes with registers being used for helper args */ + tcg_regset_reset_reg(ct->u.regs, TCG_REG_R3); + #endif +@@ -954,7 +953,6 @@ static inline void tcg_out_goto_label(TCGContext *s, int cond, int label_index) + + #include "../../softmmu_defs.h" + +-#ifdef CONFIG_TCG_PASS_AREG0 + /* helper signature: helper_ld_mmu(CPUState *env, target_ulong addr, + int mmu_idx) */ + static const void * const qemu_ld_helpers[4] = { +@@ -972,25 +970,6 @@ static const void * const qemu_st_helpers[4] = { + helper_stl_mmu, + helper_stq_mmu, + }; +-#else +-/* legacy helper signature: __ld_mmu(target_ulong addr, int +- mmu_idx) */ +-static void *qemu_ld_helpers[4] = { +- __ldb_mmu, +- __ldw_mmu, +- __ldl_mmu, +- __ldq_mmu, +-}; +- +-/* legacy helper signature: __st_mmu(target_ulong addr, uintxx_t val, +- int mmu_idx) */ +-static void *qemu_st_helpers[4] = { +- __stb_mmu, +- __stw_mmu, +- __stl_mmu, +- __stq_mmu, +-}; +-#endif + + /* Helper routines for marshalling helper function arguments into + * the correct registers and stack. +@@ -1203,9 +1182,7 @@ static inline void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args, int opc) + * trash by moving the earlier arguments into them. + */ + argreg = TCG_REG_R0; +-#ifdef CONFIG_TCG_PASS_AREG0 + argreg = tcg_out_arg_reg32(s, argreg, TCG_AREG0); +-#endif + #if TARGET_LONG_BITS == 64 + argreg = tcg_out_arg_reg64(s, argreg, addr_reg, addr_reg2); + #else +@@ -1421,9 +1398,7 @@ static inline void tcg_out_qemu_st(TCGContext *s, const TCGArg *args, int opc) + * trash by moving the earlier arguments into them. + */ + argreg = TCG_REG_R0; +-#ifdef CONFIG_TCG_PASS_AREG0 + argreg = tcg_out_arg_reg32(s, argreg, TCG_AREG0); +-#endif + #if TARGET_LONG_BITS == 64 + argreg = tcg_out_arg_reg64(s, argreg, addr_reg, addr_reg2); + #else +diff --git a/tcg/arm/tcg-target.h b/tcg/arm/tcg-target.h +index f90b834..c0b8f72 100644 +--- a/tcg/arm/tcg-target.h ++++ b/tcg/arm/tcg-target.h +@@ -77,7 +77,6 @@ typedef enum { + #define TCG_TARGET_HAS_GUEST_BASE + + enum { +- /* Note: must be synced with dyngen-exec.h */ + TCG_AREG0 = TCG_REG_R6, + }; + +diff --git a/tcg/hppa/tcg-target.c b/tcg/hppa/tcg-target.c +index 2885212..8b81b70 100644 +--- a/tcg/hppa/tcg-target.c ++++ b/tcg/hppa/tcg-target.c +@@ -882,7 +882,6 @@ static void tcg_out_setcond2(TCGContext *s, int cond, TCGArg ret, + #if defined(CONFIG_SOFTMMU) + #include "../../softmmu_defs.h" + +-#ifdef CONFIG_TCG_PASS_AREG0 + /* helper signature: helper_ld_mmu(CPUState *env, target_ulong addr, + int mmu_idx) */ + static const void * const qemu_ld_helpers[4] = { +@@ -900,25 +899,6 @@ static const void * const qemu_st_helpers[4] = { + helper_stl_mmu, + helper_stq_mmu, + }; +-#else +-/* legacy helper signature: __ld_mmu(target_ulong addr, int +- mmu_idx) */ +-static void *qemu_ld_helpers[4] = { +- __ldb_mmu, +- __ldw_mmu, +- __ldl_mmu, +- __ldq_mmu, +-}; +- +-/* legacy helper signature: __st_mmu(target_ulong addr, uintxx_t val, +- int mmu_idx) */ +-static void *qemu_st_helpers[4] = { +- __stb_mmu, +- __stw_mmu, +- __stl_mmu, +- __stq_mmu, +-}; +-#endif + + /* Load and compare a TLB entry, and branch if TLB miss. OFFSET is set to + the offset of the first ADDR_READ or ADDR_WRITE member of the appropriate +@@ -1085,7 +1065,6 @@ static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args, int opc) + } + tcg_out_movi(s, TCG_TYPE_I32, argreg, mem_index); + +-#ifdef CONFIG_TCG_PASS_AREG0 + /* XXX/FIXME: suboptimal */ + tcg_out_mov(s, TCG_TYPE_I32, tcg_target_call_iarg_regs[2], + tcg_target_call_iarg_regs[1]); +@@ -1093,7 +1072,6 @@ static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args, int opc) + tcg_target_call_iarg_regs[0]); + tcg_out_mov(s, TCG_TYPE_PTR, tcg_target_call_iarg_regs[0], + TCG_AREG0); +-#endif + tcg_out_call(s, qemu_ld_helpers[opc & 3]); + + switch (opc) { +@@ -1245,7 +1223,6 @@ static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args, int opc) + tcg_abort(); + } + +-#ifdef CONFIG_TCG_PASS_AREG0 + /* XXX/FIXME: suboptimal */ + tcg_out_mov(s, TCG_TYPE_I32, tcg_target_call_iarg_regs[3], + tcg_target_call_iarg_regs[2]); +@@ -1255,7 +1232,6 @@ static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args, int opc) + tcg_target_call_iarg_regs[0]); + tcg_out_mov(s, TCG_TYPE_PTR, tcg_target_call_iarg_regs[0], + TCG_AREG0); +-#endif + tcg_out_call(s, qemu_st_helpers[opc]); + + /* label2: */ +diff --git a/tcg/hppa/tcg-target.h b/tcg/hppa/tcg-target.h +index d4bf6fe..01ef960 100644 +--- a/tcg/hppa/tcg-target.h ++++ b/tcg/hppa/tcg-target.h +@@ -104,7 +104,6 @@ typedef enum { + + #define TCG_TARGET_HAS_GUEST_BASE + +-/* Note: must be synced with dyngen-exec.h */ + #define TCG_AREG0 TCG_REG_R17 + + +diff --git a/tcg/i386/tcg-target.c b/tcg/i386/tcg-target.c +index da17bba..34c2df8 100644 +--- a/tcg/i386/tcg-target.c ++++ b/tcg/i386/tcg-target.c +@@ -183,9 +183,7 @@ static int target_parse_constraint(TCGArgConstraint *ct, const char **pct_str) + tcg_regset_set32(ct->u.regs, 0, 0xffff); + tcg_regset_reset_reg(ct->u.regs, tcg_target_call_iarg_regs[0]); + tcg_regset_reset_reg(ct->u.regs, tcg_target_call_iarg_regs[1]); +-#ifdef CONFIG_TCG_PASS_AREG0 + tcg_regset_reset_reg(ct->u.regs, tcg_target_call_iarg_regs[2]); +-#endif + } else { + tcg_regset_set32(ct->u.regs, 0, 0xff); + tcg_regset_reset_reg(ct->u.regs, TCG_REG_EAX); +@@ -965,7 +963,6 @@ static void tcg_out_jmp(TCGContext *s, tcg_target_long dest) + + #include "../../softmmu_defs.h" + +-#ifdef CONFIG_TCG_PASS_AREG0 + /* helper signature: helper_ld_mmu(CPUState *env, target_ulong addr, + int mmu_idx) */ + static const void *qemu_ld_helpers[4] = { +@@ -983,25 +980,6 @@ static const void *qemu_st_helpers[4] = { + helper_stl_mmu, + helper_stq_mmu, + }; +-#else +-/* legacy helper signature: __ld_mmu(target_ulong addr, int +- mmu_idx) */ +-static void *qemu_ld_helpers[4] = { +- __ldb_mmu, +- __ldw_mmu, +- __ldl_mmu, +- __ldq_mmu, +-}; +- +-/* legacy helper signature: __st_mmu(target_ulong addr, uintxx_t val, +- int mmu_idx) */ +-static void *qemu_st_helpers[4] = { +- __stb_mmu, +- __stw_mmu, +- __stl_mmu, +- __stq_mmu, +-}; +-#endif + + /* Perform the TLB load and compare. + +@@ -1220,16 +1198,13 @@ static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args, + } + tcg_out_push(s, args[addrlo_idx]); + stack_adjust += 4; +-#ifdef CONFIG_TCG_PASS_AREG0 + tcg_out_push(s, TCG_AREG0); + stack_adjust += 4; +-#endif + #else + /* The first argument is already loaded with addrlo. */ + arg_idx = 1; + tcg_out_movi(s, TCG_TYPE_I32, tcg_target_call_iarg_regs[arg_idx], + mem_index); +-#ifdef CONFIG_TCG_PASS_AREG0 + /* XXX/FIXME: suboptimal */ + tcg_out_mov(s, TCG_TYPE_I64, tcg_target_call_iarg_regs[3], + tcg_target_call_iarg_regs[2]); +@@ -1240,7 +1215,6 @@ static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args, + tcg_out_mov(s, TCG_TYPE_I64, tcg_target_call_iarg_regs[0], + TCG_AREG0); + #endif +-#endif + + tcg_out_calli(s, (tcg_target_long)qemu_ld_helpers[s_bits]); + +@@ -1436,16 +1410,13 @@ static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args, + } + tcg_out_push(s, args[addrlo_idx]); + stack_adjust += 4; +-#ifdef CONFIG_TCG_PASS_AREG0 + tcg_out_push(s, TCG_AREG0); + stack_adjust += 4; +-#endif + #else + tcg_out_mov(s, (opc == 3 ? TCG_TYPE_I64 : TCG_TYPE_I32), + tcg_target_call_iarg_regs[1], data_reg); + tcg_out_movi(s, TCG_TYPE_I32, tcg_target_call_iarg_regs[2], mem_index); + stack_adjust = 0; +-#ifdef CONFIG_TCG_PASS_AREG0 + /* XXX/FIXME: suboptimal */ + tcg_out_mov(s, TCG_TYPE_I64, tcg_target_call_iarg_regs[3], + tcg_target_call_iarg_regs[2]); +@@ -1456,7 +1427,6 @@ static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args, + tcg_out_mov(s, TCG_TYPE_I64, tcg_target_call_iarg_regs[0], + TCG_AREG0); + #endif +-#endif + + tcg_out_calli(s, (tcg_target_long)qemu_st_helpers[s_bits]); + +diff --git a/tcg/i386/tcg-target.h b/tcg/i386/tcg-target.h +index c3cfe05..8be42f3 100644 +--- a/tcg/i386/tcg-target.h ++++ b/tcg/i386/tcg-target.h +@@ -116,7 +116,6 @@ typedef enum { + + #define TCG_TARGET_HAS_GUEST_BASE + +-/* Note: must be synced with dyngen-exec.h */ + #if TCG_TARGET_REG_BITS == 64 + # define TCG_AREG0 TCG_REG_R14 + #else +diff --git a/tcg/ia64/tcg-target.c b/tcg/ia64/tcg-target.c +index dc588db..1745038 100644 +--- a/tcg/ia64/tcg-target.c ++++ b/tcg/ia64/tcg-target.c +@@ -1452,7 +1452,6 @@ static inline void tcg_out_qemu_tlb(TCGContext *s, TCGArg addr_reg, + TCG_REG_P7, TCG_REG_R3, TCG_REG_R57)); + } + +-#ifdef CONFIG_TCG_PASS_AREG0 + /* helper signature: helper_ld_mmu(CPUState *env, target_ulong addr, + int mmu_idx) */ + static const void * const qemu_ld_helpers[4] = { +@@ -1461,16 +1460,6 @@ static const void * const qemu_ld_helpers[4] = { + helper_ldl_mmu, + helper_ldq_mmu, + }; +-#else +-/* legacy helper signature: __ld_mmu(target_ulong addr, int +- mmu_idx) */ +-static void *qemu_ld_helpers[4] = { +- __ldb_mmu, +- __ldw_mmu, +- __ldl_mmu, +- __ldq_mmu, +-}; +-#endif + + static inline void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args, int opc) + { +@@ -1530,7 +1519,6 @@ 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)); + } +-#ifdef CONFIG_TCG_PASS_AREG0 + /* XXX/FIXME: suboptimal */ + tcg_out_bundle(s, mII, + tcg_opc_a5 (TCG_REG_P7, OPC_ADDL_A5, TCG_REG_R58, +@@ -1539,7 +1527,6 @@ static inline void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args, int opc) + TCG_REG_R57, 0, TCG_REG_R56), + tcg_opc_a4 (TCG_REG_P7, OPC_ADDS_A4, + TCG_REG_R56, 0, TCG_AREG0)); +-#endif + if (!bswap || s_bits == 0) { + tcg_out_bundle(s, miB, + tcg_opc_m48(TCG_REG_P0, OPC_NOP_M48, 0), +@@ -1570,7 +1557,6 @@ static inline void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args, int opc) + } + } + +-#ifdef CONFIG_TCG_PASS_AREG0 + /* helper signature: helper_st_mmu(CPUState *env, target_ulong addr, + uintxx_t val, int mmu_idx) */ + static const void * const qemu_st_helpers[4] = { +@@ -1579,16 +1565,6 @@ static const void * const qemu_st_helpers[4] = { + helper_stl_mmu, + helper_stq_mmu, + }; +-#else +-/* legacy helper signature: __st_mmu(target_ulong addr, uintxx_t val, +- int mmu_idx) */ +-static void *qemu_st_helpers[4] = { +- __stb_mmu, +- __stw_mmu, +- __stl_mmu, +- __stq_mmu, +-}; +-#endif + + static inline void tcg_out_qemu_st(TCGContext *s, const TCGArg *args, int opc) + { +@@ -1658,7 +1634,6 @@ static inline void tcg_out_qemu_st(TCGContext *s, const TCGArg *args, int opc) + data_reg = TCG_REG_R2; + } + +-#ifdef CONFIG_TCG_PASS_AREG0 + /* XXX/FIXME: suboptimal */ + tcg_out_bundle(s, mII, + tcg_opc_a5 (TCG_REG_P7, OPC_ADDL_A5, TCG_REG_R59, +@@ -1674,15 +1649,6 @@ static inline void tcg_out_qemu_st(TCGContext *s, const TCGArg *args, int opc) + TCG_REG_R56, 0, TCG_AREG0), + 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_m4 (TCG_REG_P6, opc_st_m4[opc], +- data_reg, TCG_REG_R3), +- tcg_opc_a5 (TCG_REG_P7, OPC_ADDL_A5, TCG_REG_R58, +- mem_index, TCG_REG_R0), +- tcg_opc_b5 (TCG_REG_P7, OPC_BR_CALL_SPTK_MANY_B5, +- TCG_REG_B0, TCG_REG_B6)); +-#endif + } + + #else /* !CONFIG_SOFTMMU */ +diff --git a/tcg/ia64/tcg-target.h b/tcg/ia64/tcg-target.h +index 0631b9f..c22962a 100644 +--- a/tcg/ia64/tcg-target.h ++++ b/tcg/ia64/tcg-target.h +@@ -140,7 +140,6 @@ typedef enum { + #define TCG_TARGET_HAS_not_i32 0 /* xor r1, -1, r3 */ + #define TCG_TARGET_HAS_not_i64 0 /* xor r1, -1, r3 */ + +-/* Note: must be synced with dyngen-exec.h */ + #define TCG_AREG0 TCG_REG_R7 + + /* Guest base is supported */ +diff --git a/tcg/mips/tcg-target.c b/tcg/mips/tcg-target.c +index 1006e28..74db83d 100644 +--- a/tcg/mips/tcg-target.c ++++ b/tcg/mips/tcg-target.c +@@ -217,7 +217,7 @@ static int target_parse_constraint(TCGArgConstraint *ct, const char **pct_str) + tcg_regset_set(ct->u.regs, 0xffffffff); + #if defined(CONFIG_SOFTMMU) + tcg_regset_reset_reg(ct->u.regs, TCG_REG_A0); +-# if defined(CONFIG_TCG_PASS_AREG0) && (TARGET_LONG_BITS == 64) ++# if (TARGET_LONG_BITS == 64) + tcg_regset_reset_reg(ct->u.regs, TCG_REG_A2); + # endif + #endif +@@ -227,12 +227,11 @@ static int target_parse_constraint(TCGArgConstraint *ct, const char **pct_str) + tcg_regset_set(ct->u.regs, 0xffffffff); + tcg_regset_reset_reg(ct->u.regs, TCG_REG_A0); + #if defined(CONFIG_SOFTMMU) +-# if (defined(CONFIG_TCG_PASS_AREG0) && TARGET_LONG_BITS == 32) || \ +- (!defined(CONFIG_TCG_PASS_AREG0) && TARGET_LONG_BITS == 64) ++# if (TARGET_LONG_BITS == 32) + tcg_regset_reset_reg(ct->u.regs, TCG_REG_A1); + # endif + tcg_regset_reset_reg(ct->u.regs, TCG_REG_A2); +-# if defined(CONFIG_TCG_PASS_AREG0) && TARGET_LONG_BITS == 64 ++# if TARGET_LONG_BITS == 64 + tcg_regset_reset_reg(ct->u.regs, TCG_REG_A3); + # endif + #endif +@@ -821,7 +820,6 @@ static void tcg_out_setcond2(TCGContext *s, TCGCond cond, int ret, + + #include "../../softmmu_defs.h" + +-#ifdef CONFIG_TCG_PASS_AREG0 + /* helper signature: helper_ld_mmu(CPUState *env, target_ulong addr, + int mmu_idx) */ + static const void * const qemu_ld_helpers[4] = { +@@ -839,25 +837,6 @@ static const void * const qemu_st_helpers[4] = { + helper_stl_mmu, + helper_stq_mmu, + }; +-#else +-/* legacy helper signature: __ld_mmu(target_ulong addr, int +- mmu_idx) */ +-static void *qemu_ld_helpers[4] = { +- __ldb_mmu, +- __ldw_mmu, +- __ldl_mmu, +- __ldq_mmu, +-}; +- +-/* legacy helper signature: __st_mmu(target_ulong addr, uintxx_t val, +- int mmu_idx) */ +-static void *qemu_st_helpers[4] = { +- __stb_mmu, +- __stw_mmu, +- __stl_mmu, +- __stq_mmu, +-}; +-#endif + #endif + + static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args, +@@ -942,9 +921,7 @@ static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args, + + /* slow path */ + arg_num = 0; +-# ifdef CONFIG_TCG_PASS_AREG0 + tcg_out_call_iarg_reg32(s, &arg_num, TCG_AREG0); +-# endif + # if TARGET_LONG_BITS == 64 + tcg_out_call_iarg_reg64(s, &arg_num, addr_regl, addr_regh); + # else +@@ -1127,9 +1104,7 @@ static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args, + + /* slow path */ + arg_num = 0; +-# ifdef CONFIG_TCG_PASS_AREG0 + tcg_out_call_iarg_reg32(s, &arg_num, TCG_AREG0); +-# endif + # if TARGET_LONG_BITS == 64 + tcg_out_call_iarg_reg64(s, &arg_num, addr_regl, addr_regh); + # else +diff --git a/tcg/mips/tcg-target.h b/tcg/mips/tcg-target.h +index d3c804d..1c61931 100644 +--- a/tcg/mips/tcg-target.h ++++ b/tcg/mips/tcg-target.h +@@ -96,7 +96,6 @@ typedef enum { + #define TCG_TARGET_HAS_ext8u_i32 0 /* andi rt, rs, 0xff */ + #define TCG_TARGET_HAS_ext16u_i32 0 /* andi rt, rs, 0xffff */ + +-/* Note: must be synced with dyngen-exec.h */ + #define TCG_AREG0 TCG_REG_S0 + + /* guest base is supported */ +diff --git a/tcg/ppc/tcg-target.c b/tcg/ppc/tcg-target.c +index 0cff181..26c4b33 100644 +--- a/tcg/ppc/tcg-target.c ++++ b/tcg/ppc/tcg-target.c +@@ -248,7 +248,6 @@ static int target_parse_constraint(TCGArgConstraint *ct, const char **pct_str) + tcg_regset_set32(ct->u.regs, 0, 0xffffffff); + tcg_regset_reset_reg(ct->u.regs, TCG_REG_R3); + tcg_regset_reset_reg(ct->u.regs, TCG_REG_R4); +-#ifdef CONFIG_TCG_PASS_AREG0 + tcg_regset_reset_reg(ct->u.regs, TCG_REG_R5); + #if TARGET_LONG_BITS == 64 + tcg_regset_reset_reg(ct->u.regs, TCG_REG_R6); +@@ -256,11 +255,6 @@ static int target_parse_constraint(TCGArgConstraint *ct, const char **pct_str) + tcg_regset_reset_reg(ct->u.regs, TCG_REG_R7); + #endif + #endif +-#else /* !AREG0 */ +-#if TARGET_LONG_BITS == 64 +- tcg_regset_reset_reg(ct->u.regs, TCG_REG_R5); +-#endif +-#endif + break; + case 'K': /* qemu_st[8..32] constraint */ + ct->ct |= TCG_CT_REG; +@@ -268,7 +262,6 @@ static int target_parse_constraint(TCGArgConstraint *ct, const char **pct_str) + tcg_regset_reset_reg(ct->u.regs, TCG_REG_R3); + tcg_regset_reset_reg(ct->u.regs, TCG_REG_R4); + tcg_regset_reset_reg(ct->u.regs, TCG_REG_R5); +-#ifdef CONFIG_TCG_PASS_AREG0 + tcg_regset_reset_reg(ct->u.regs, TCG_REG_R6); + #if TARGET_LONG_BITS == 64 + tcg_regset_reset_reg(ct->u.regs, TCG_REG_R7); +@@ -276,11 +269,6 @@ static int target_parse_constraint(TCGArgConstraint *ct, const char **pct_str) + tcg_regset_reset_reg(ct->u.regs, TCG_REG_R8); + #endif + #endif +-#else /* !AREG0 */ +-#if TARGET_LONG_BITS == 64 +- tcg_regset_reset_reg(ct->u.regs, TCG_REG_R6); +-#endif +-#endif + break; + case 'M': /* qemu_st64 constraint */ + ct->ct |= TCG_CT_REG; +@@ -290,12 +278,10 @@ static int target_parse_constraint(TCGArgConstraint *ct, const char **pct_str) + tcg_regset_reset_reg(ct->u.regs, TCG_REG_R5); + tcg_regset_reset_reg(ct->u.regs, TCG_REG_R6); + tcg_regset_reset_reg(ct->u.regs, TCG_REG_R7); +-#if defined(CONFIG_TCG_PASS_AREG0) + tcg_regset_reset_reg(ct->u.regs, TCG_REG_R8); + #ifdef TCG_TARGET_CALL_ALIGN_ARGS + tcg_regset_reset_reg(ct->u.regs, TCG_REG_R9); + #endif +-#endif + break; + #else + case 'L': +@@ -541,7 +527,6 @@ static void tcg_out_call (TCGContext *s, tcg_target_long arg, int const_arg) + + #include "../../softmmu_defs.h" + +-#ifdef CONFIG_TCG_PASS_AREG0 + /* helper signature: helper_ld_mmu(CPUState *env, target_ulong addr, + int mmu_idx) */ + static const void * const qemu_ld_helpers[4] = { +@@ -559,25 +544,6 @@ static const void * const qemu_st_helpers[4] = { + helper_stl_mmu, + helper_stq_mmu, + }; +-#else +-/* legacy helper signature: __ld_mmu(target_ulong addr, int +- mmu_idx) */ +-static void *qemu_ld_helpers[4] = { +- __ldb_mmu, +- __ldw_mmu, +- __ldl_mmu, +- __ldq_mmu, +-}; +- +-/* legacy helper signature: __ld_mmu(target_ulong addr, int +- mmu_idx) */ +-static void *qemu_st_helpers[4] = { +- __stb_mmu, +- __stw_mmu, +- __stl_mmu, +- __stq_mmu, +-}; +-#endif + #endif + + static void tcg_out_qemu_ld (TCGContext *s, const TCGArg *args, int opc) +@@ -647,9 +613,7 @@ static void tcg_out_qemu_ld (TCGContext *s, const TCGArg *args, int opc) + + /* slow path */ + ir = 3; +-#ifdef CONFIG_TCG_PASS_AREG0 + tcg_out_mov (s, TCG_TYPE_I32, ir++, TCG_AREG0); +-#endif + #if TARGET_LONG_BITS == 32 + tcg_out_mov (s, TCG_TYPE_I32, ir++, addr_reg); + #else +@@ -849,9 +813,7 @@ static void tcg_out_qemu_st (TCGContext *s, const TCGArg *args, int opc) + + /* slow path */ + ir = 3; +-#ifdef CONFIG_TCG_PASS_AREG0 + tcg_out_mov (s, TCG_TYPE_I32, ir++, TCG_AREG0); +-#endif + #if TARGET_LONG_BITS == 32 + tcg_out_mov (s, TCG_TYPE_I32, ir++, addr_reg); + #else +diff --git a/tcg/ppc64/tcg-target.c b/tcg/ppc64/tcg-target.c +index 27a0ae8..337cd41 100644 +--- a/tcg/ppc64/tcg-target.c ++++ b/tcg/ppc64/tcg-target.c +@@ -235,10 +235,8 @@ static int target_parse_constraint (TCGArgConstraint *ct, const char **pct_str) + tcg_regset_reset_reg (ct->u.regs, TCG_REG_R3); + #ifdef CONFIG_SOFTMMU + tcg_regset_reset_reg (ct->u.regs, TCG_REG_R4); +-#ifdef CONFIG_TCG_PASS_AREG0 + tcg_regset_reset_reg (ct->u.regs, TCG_REG_R5); + #endif +-#endif + break; + case 'S': /* qemu_st constraint */ + ct->ct |= TCG_CT_REG; +@@ -247,10 +245,8 @@ static int target_parse_constraint (TCGArgConstraint *ct, const char **pct_str) + #ifdef CONFIG_SOFTMMU + tcg_regset_reset_reg (ct->u.regs, TCG_REG_R4); + tcg_regset_reset_reg (ct->u.regs, TCG_REG_R5); +-#ifdef CONFIG_TCG_PASS_AREG0 + tcg_regset_reset_reg (ct->u.regs, TCG_REG_R6); + #endif +-#endif + break; + case 'Z': + ct->ct |= TCG_CT_CONST_U32; +@@ -558,7 +554,6 @@ static void tcg_out_ldsta (TCGContext *s, int ret, int addr, + + #include "../../softmmu_defs.h" + +-#ifdef CONFIG_TCG_PASS_AREG0 + /* helper signature: helper_ld_mmu(CPUState *env, target_ulong addr, + int mmu_idx) */ + static const void * const qemu_ld_helpers[4] = { +@@ -576,25 +571,6 @@ static const void * const qemu_st_helpers[4] = { + helper_stl_mmu, + helper_stq_mmu, + }; +-#else +-/* legacy helper signature: __ld_mmu(target_ulong addr, int +- mmu_idx) */ +-static void *qemu_ld_helpers[4] = { +- __ldb_mmu, +- __ldw_mmu, +- __ldl_mmu, +- __ldq_mmu, +-}; +- +-/* legacy helper signature: __st_mmu(target_ulong addr, uintxx_t val, +- int mmu_idx) */ +-static void *qemu_st_helpers[4] = { +- __stb_mmu, +- __stw_mmu, +- __stl_mmu, +- __stq_mmu, +-}; +-#endif + + static void tcg_out_tlb_read (TCGContext *s, int r0, int r1, int r2, + int addr_reg, int s_bits, int offset) +@@ -676,9 +652,7 @@ static void tcg_out_qemu_ld (TCGContext *s, const TCGArg *args, int opc) + + /* slow path */ + ir = 3; +-#ifdef CONFIG_TCG_PASS_AREG0 + tcg_out_mov (s, TCG_TYPE_I64, ir++, TCG_AREG0); +-#endif + tcg_out_mov (s, TCG_TYPE_I64, ir++, addr_reg); + tcg_out_movi (s, TCG_TYPE_I64, ir++, mem_index); + +@@ -827,9 +801,7 @@ static void tcg_out_qemu_st (TCGContext *s, const TCGArg *args, int opc) + + /* slow path */ + ir = 3; +-#ifdef CONFIG_TCG_PASS_AREG0 + tcg_out_mov (s, TCG_TYPE_I64, ir++, TCG_AREG0); +-#endif + tcg_out_mov (s, TCG_TYPE_I64, ir++, addr_reg); + tcg_out_rld (s, RLDICL, ir++, data_reg, 0, 64 - (1 << (3 + opc))); + tcg_out_movi (s, TCG_TYPE_I64, ir++, mem_index); +diff --git a/tcg/s390/tcg-target.c b/tcg/s390/tcg-target.c +index 99b5339..aac11d9 100644 +--- a/tcg/s390/tcg-target.c ++++ b/tcg/s390/tcg-target.c +@@ -301,7 +301,6 @@ static const uint8_t tcg_cond_to_ltr_cond[10] = { + + #include "../../softmmu_defs.h" + +-#ifdef CONFIG_TCG_PASS_AREG0 + /* helper signature: helper_ld_mmu(CPUState *env, target_ulong addr, + int mmu_idx) */ + static const void * const qemu_ld_helpers[4] = { +@@ -319,25 +318,6 @@ static const void * const qemu_st_helpers[4] = { + helper_stl_mmu, + helper_stq_mmu, + }; +-#else +-/* legacy helper signature: __ld_mmu(target_ulong addr, int +- mmu_idx) */ +-static void *qemu_ld_helpers[4] = { +- __ldb_mmu, +- __ldw_mmu, +- __ldl_mmu, +- __ldq_mmu, +-}; +- +-/* legacy helper signature: __st_mmu(target_ulong addr, uintxx_t val, +- int mmu_idx) */ +-static void *qemu_st_helpers[4] = { +- __stb_mmu, +- __stw_mmu, +- __stl_mmu, +- __stq_mmu, +-}; +-#endif + #endif + + static uint8_t *tb_ret_addr; +@@ -1507,7 +1487,6 @@ static void tcg_prepare_qemu_ldst(TCGContext* s, TCGReg data_reg, + tcg_abort(); + } + tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_R4, mem_index); +-#ifdef CONFIG_TCG_PASS_AREG0 + /* XXX/FIXME: suboptimal */ + tcg_out_mov(s, TCG_TYPE_I64, tcg_target_call_iarg_regs[3], + tcg_target_call_iarg_regs[2]); +@@ -1517,11 +1496,9 @@ static void tcg_prepare_qemu_ldst(TCGContext* s, TCGReg data_reg, + tcg_target_call_iarg_regs[0]); + tcg_out_mov(s, TCG_TYPE_I64, tcg_target_call_iarg_regs[0], + TCG_AREG0); +-#endif + tgen_calli(s, (tcg_target_ulong)qemu_st_helpers[s_bits]); + } else { + tcg_out_movi(s, TCG_TYPE_I32, arg1, mem_index); +-#ifdef CONFIG_TCG_PASS_AREG0 + /* XXX/FIXME: suboptimal */ + tcg_out_mov(s, TCG_TYPE_I64, tcg_target_call_iarg_regs[2], + tcg_target_call_iarg_regs[1]); +@@ -1529,7 +1506,6 @@ static void tcg_prepare_qemu_ldst(TCGContext* s, TCGReg data_reg, + tcg_target_call_iarg_regs[0]); + tcg_out_mov(s, TCG_TYPE_I64, tcg_target_call_iarg_regs[0], + TCG_AREG0); +-#endif + tgen_calli(s, (tcg_target_ulong)qemu_ld_helpers[s_bits]); + + /* sign extension */ +diff --git a/tcg/s390/tcg-target.h b/tcg/s390/tcg-target.h +index d12f90b..4f7dfab 100644 +--- a/tcg/s390/tcg-target.h ++++ b/tcg/s390/tcg-target.h +@@ -96,7 +96,6 @@ typedef enum TCGReg { + #define TCG_TARGET_EXTEND_ARGS 1 + + enum { +- /* Note: must be synced with dyngen-exec.h */ + TCG_AREG0 = TCG_REG_R10, + }; + +diff --git a/tcg/sparc/tcg-target.c b/tcg/sparc/tcg-target.c +index 247a278..baed3b4 100644 +--- a/tcg/sparc/tcg-target.c ++++ b/tcg/sparc/tcg-target.c +@@ -59,11 +59,7 @@ static const char * const tcg_target_reg_names[TCG_TARGET_NB_REGS] = { + }; + #endif + +-#ifdef CONFIG_TCG_PASS_AREG0 + #define ARG_OFFSET 1 +-#else +-#define ARG_OFFSET 0 +-#endif + + static const int tcg_target_reg_alloc_order[] = { + TCG_REG_L0, +@@ -161,9 +157,7 @@ static int target_parse_constraint(TCGArgConstraint *ct, const char **pct_str) + tcg_regset_reset_reg(ct->u.regs, TCG_REG_O0); + tcg_regset_reset_reg(ct->u.regs, TCG_REG_O1); + tcg_regset_reset_reg(ct->u.regs, TCG_REG_O2); +-#ifdef CONFIG_TCG_PASS_AREG0 + tcg_regset_reset_reg(ct->u.regs, TCG_REG_O3); +-#endif + break; + case 'I': + ct->ct |= TCG_CT_CONST_S11; +@@ -715,7 +709,6 @@ static void tcg_target_qemu_prologue(TCGContext *s) + + #include "../../softmmu_defs.h" + +-#ifdef CONFIG_TCG_PASS_AREG0 + /* helper signature: helper_ld_mmu(CPUState *env, target_ulong addr, + int mmu_idx) */ + static const void * const qemu_ld_helpers[4] = { +@@ -733,25 +726,6 @@ static const void * const qemu_st_helpers[4] = { + helper_stl_mmu, + helper_stq_mmu, + }; +-#else +-/* legacy helper signature: __ld_mmu(target_ulong addr, int +- mmu_idx) */ +-static const void * const qemu_ld_helpers[4] = { +- __ldb_mmu, +- __ldw_mmu, +- __ldl_mmu, +- __ldq_mmu, +-}; +- +-/* legacy helper signature: __st_mmu(target_ulong addr, uintxx_t val, +- int mmu_idx) */ +-static const void * const qemu_st_helpers[4] = { +- __stb_mmu, +- __stw_mmu, +- __stl_mmu, +- __stq_mmu, +-}; +-#endif + #endif + + #if TARGET_LONG_BITS == 32 +@@ -834,7 +808,6 @@ static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args, + + /* mov */ + tcg_out_movi(s, TCG_TYPE_I32, arg1, mem_index); +-#ifdef CONFIG_TCG_PASS_AREG0 + /* XXX/FIXME: suboptimal */ + tcg_out_mov(s, TCG_TYPE_I32, tcg_target_call_iarg_regs[3], + tcg_target_call_iarg_regs[2]); +@@ -844,7 +817,6 @@ static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args, + tcg_target_call_iarg_regs[0]); + tcg_out_mov(s, TCG_TYPE_PTR, tcg_target_call_iarg_regs[0], + TCG_AREG0); +-#endif + + /* XXX: move that code at the end of the TB */ + /* qemu_ld_helper[s_bits](arg0, arg1) */ +@@ -1061,7 +1033,6 @@ static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args, + /* mov */ + tcg_out_movi(s, TCG_TYPE_I32, arg2, mem_index); + +-#ifdef CONFIG_TCG_PASS_AREG0 + /* XXX/FIXME: suboptimal */ + tcg_out_mov(s, TCG_TYPE_I32, tcg_target_call_iarg_regs[3], + tcg_target_call_iarg_regs[2]); +@@ -1071,7 +1042,6 @@ static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args, + tcg_target_call_iarg_regs[0]); + tcg_out_mov(s, TCG_TYPE_PTR, tcg_target_call_iarg_regs[0], + TCG_AREG0); +-#endif + /* XXX: move that code at the end of the TB */ + /* qemu_st_helper[s_bits](arg0, arg1, arg2) */ + tcg_out32(s, CALL | ((((tcg_target_ulong)qemu_st_helpers[s_bits] +diff --git a/tcg/sparc/tcg-target.h b/tcg/sparc/tcg-target.h +index ee2274d..0ea87be 100644 +--- a/tcg/sparc/tcg-target.h ++++ b/tcg/sparc/tcg-target.h +@@ -125,7 +125,6 @@ typedef enum { + #define TCG_TARGET_HAS_deposit_i64 0 + #endif + +-/* Note: must be synced with dyngen-exec.h */ + #ifdef CONFIG_SOLARIS + #define TCG_AREG0 TCG_REG_G2 + #elif defined(__sparc_v9__) +diff --git a/tcg/tci/tcg-target.c b/tcg/tci/tcg-target.c +index ef8580f..003244c 100644 +--- a/tcg/tci/tcg-target.c ++++ b/tcg/tci/tcg-target.c +@@ -798,9 +798,7 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, const TCGArg *args, + case INDEX_op_qemu_st8: + case INDEX_op_qemu_st16: + case INDEX_op_qemu_st32: +-#ifdef CONFIG_TCG_PASS_AREG0 + tcg_out_r(s, TCG_AREG0); +-#endif + tcg_out_r(s, *args++); + tcg_out_r(s, *args++); + #if TARGET_LONG_BITS > TCG_TARGET_REG_BITS +@@ -811,9 +809,7 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, const TCGArg *args, + #endif + break; + case INDEX_op_qemu_st64: +-#ifdef CONFIG_TCG_PASS_AREG0 + tcg_out_r(s, TCG_AREG0); +-#endif + tcg_out_r(s, *args++); + #if TCG_TARGET_REG_BITS == 32 + tcg_out_r(s, *args++); +diff --git a/tci.c b/tci.c +index c79350d..ce8a988 100644 +--- a/tci.c ++++ b/tci.c +@@ -25,7 +25,6 @@ + #endif + + #include "qemu-common.h" +-#include "dyngen-exec.h" /* env */ + #include "exec-all.h" /* MAX_OPC_PARAM_IARGS */ + #include "tcg-op.h" + +@@ -63,17 +62,6 @@ uintptr_t tci_tb_ptr; + + static tcg_target_ulong tci_reg[TCG_TARGET_NB_REGS]; + +-#if !defined(CONFIG_TCG_PASS_AREG0) +-# define helper_ldb_mmu(env, addr, mmu_idx) __ldb_mmu(addr, mmu_idx) +-# define helper_ldw_mmu(env, addr, mmu_idx) __ldw_mmu(addr, mmu_idx) +-# define helper_ldl_mmu(env, addr, mmu_idx) __ldl_mmu(addr, mmu_idx) +-# define helper_ldq_mmu(env, addr, mmu_idx) __ldq_mmu(addr, mmu_idx) +-# define helper_stb_mmu(env, addr, val, mmu_idx) __stb_mmu(addr, val, mmu_idx) +-# define helper_stw_mmu(env, addr, val, mmu_idx) __stw_mmu(addr, val, mmu_idx) +-# define helper_stl_mmu(env, addr, val, mmu_idx) __stl_mmu(addr, val, mmu_idx) +-# define helper_stq_mmu(env, addr, val, mmu_idx) __stq_mmu(addr, val, mmu_idx) +-#endif /* !CONFIG_TCG_PASS_AREG0 */ +- + static tcg_target_ulong tci_read_reg(TCGReg index) + { + assert(index < ARRAY_SIZE(tci_reg)); +diff --git a/user-exec.c b/user-exec.c +index b9ea9dd..ef9b172 100644 +--- a/user-exec.c ++++ b/user-exec.c +@@ -18,9 +18,6 @@ + */ + #include "config.h" + #include "cpu.h" +-#ifndef CONFIG_TCG_PASS_AREG0 +-#include "dyngen-exec.h" +-#endif + #include "disas.h" + #include "tcg.h" + +@@ -60,12 +57,6 @@ void cpu_resume_from_signal(CPUArchState *env1, void *puc) + struct sigcontext *uc = puc; + #endif + +-#ifndef CONFIG_TCG_PASS_AREG0 +- env = env1; +- +- /* XXX: restore cpu registers saved in host registers */ +-#endif +- + if (puc) { + /* XXX: use siglongjmp ? */ + #ifdef __linux__ +@@ -93,11 +84,6 @@ static inline int handle_cpu_signal(uintptr_t pc, unsigned long address, + TranslationBlock *tb; + int ret; + +-#ifndef CONFIG_TCG_PASS_AREG0 +- if (cpu_single_env) { +- env = cpu_single_env; /* XXX: find a correct solution for multithread */ +- } +-#endif + #if defined(DEBUG_SIGNAL) + qemu_printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n", + pc, address, is_write, *(unsigned long *)old_set); +-- +1.7.12.1 + diff --git a/0040-tcg-i386-allow-constants-in-load-store-ops.patch b/0040-tcg-i386-allow-constants-in-load-store-ops.patch new file mode 100644 index 0000000..0c9066c --- /dev/null +++ b/0040-tcg-i386-allow-constants-in-load-store-ops.patch @@ -0,0 +1,114 @@ +From 83b25655bcd988054a2bb2a0a38dc662d4901b08 Mon Sep 17 00:00:00 2001 +From: Aurelien Jarno +Date: Mon, 10 Sep 2012 13:56:24 +0200 +Subject: [PATCH] tcg/i386: allow constants in load/store ops + +On x86, it is possible to move a constant value to memory. Add code to +handle a constant argument to load/store ops. + +Reviewed-by: Richard Henderson +Signed-off-by: Aurelien Jarno +Signed-off-by: Michael Roth +--- + tcg/i386/tcg-target.c | 50 +++++++++++++++++++++++++++++++++++++------------- + 1 file changed, 37 insertions(+), 13 deletions(-) + +diff --git a/tcg/i386/tcg-target.c b/tcg/i386/tcg-target.c +index 34c2df8..3017858 100644 +--- a/tcg/i386/tcg-target.c ++++ b/tcg/i386/tcg-target.c +@@ -263,6 +263,7 @@ static inline int tcg_target_const_match(tcg_target_long val, + #define OPC_MOVB_EvGv (0x88) /* stores, more or less */ + #define OPC_MOVL_EvGv (0x89) /* stores, more or less */ + #define OPC_MOVL_GvEv (0x8b) /* loads, more or less */ ++#define OPC_MOVB_EvIz (0xc6) + #define OPC_MOVL_EvIz (0xc7) + #define OPC_MOVL_Iv (0xb8) + #define OPC_MOVSBL (0xbe | P_EXT) +@@ -1543,18 +1544,35 @@ static inline void tcg_out_op(TCGContext *s, TCGOpcode opc, + break; + + OP_32_64(st8): +- tcg_out_modrm_offset(s, OPC_MOVB_EvGv | P_REXB_R, +- args[0], args[1], args[2]); ++ if (const_args[0]) { ++ tcg_out_modrm_offset(s, OPC_MOVB_EvIz, ++ 0, args[1], args[2]); ++ tcg_out8(s, args[0]); ++ } else { ++ tcg_out_modrm_offset(s, OPC_MOVB_EvGv | P_REXB_R, ++ args[0], args[1], args[2]); ++ } + break; + OP_32_64(st16): +- tcg_out_modrm_offset(s, OPC_MOVL_EvGv | P_DATA16, +- args[0], args[1], args[2]); ++ if (const_args[0]) { ++ tcg_out_modrm_offset(s, OPC_MOVL_EvIz | P_DATA16, ++ 0, args[1], args[2]); ++ tcg_out16(s, args[0]); ++ } else { ++ tcg_out_modrm_offset(s, OPC_MOVL_EvGv | P_DATA16, ++ args[0], args[1], args[2]); ++ } + break; + #if TCG_TARGET_REG_BITS == 64 + case INDEX_op_st32_i64: + #endif + case INDEX_op_st_i32: +- tcg_out_st(s, TCG_TYPE_I32, args[0], args[1], args[2]); ++ if (const_args[0]) { ++ tcg_out_modrm_offset(s, OPC_MOVL_EvIz, 0, args[1], args[2]); ++ tcg_out32(s, args[0]); ++ } else { ++ tcg_out_st(s, TCG_TYPE_I32, args[0], args[1], args[2]); ++ } + break; + + OP_32_64(add): +@@ -1758,7 +1776,13 @@ static inline void tcg_out_op(TCGContext *s, TCGOpcode opc, + tcg_out_ld(s, TCG_TYPE_I64, args[0], args[1], args[2]); + break; + case INDEX_op_st_i64: +- tcg_out_st(s, TCG_TYPE_I64, args[0], args[1], args[2]); ++ if (const_args[0]) { ++ tcg_out_modrm_offset(s, OPC_MOVL_EvIz | P_REXW, ++ 0, args[1], args[2]); ++ tcg_out32(s, args[0]); ++ } else { ++ tcg_out_st(s, TCG_TYPE_I64, args[0], args[1], args[2]); ++ } + break; + case INDEX_op_qemu_ld32s: + tcg_out_qemu_ld(s, args, 2 | 4); +@@ -1820,9 +1844,9 @@ static const TCGTargetOpDef x86_op_defs[] = { + { INDEX_op_ld16u_i32, { "r", "r" } }, + { INDEX_op_ld16s_i32, { "r", "r" } }, + { INDEX_op_ld_i32, { "r", "r" } }, +- { INDEX_op_st8_i32, { "q", "r" } }, +- { INDEX_op_st16_i32, { "r", "r" } }, +- { INDEX_op_st_i32, { "r", "r" } }, ++ { INDEX_op_st8_i32, { "qi", "r" } }, ++ { INDEX_op_st16_i32, { "ri", "r" } }, ++ { INDEX_op_st_i32, { "ri", "r" } }, + + { INDEX_op_add_i32, { "r", "r", "ri" } }, + { INDEX_op_sub_i32, { "r", "0", "ri" } }, +@@ -1873,10 +1897,10 @@ static const TCGTargetOpDef x86_op_defs[] = { + { INDEX_op_ld32u_i64, { "r", "r" } }, + { INDEX_op_ld32s_i64, { "r", "r" } }, + { INDEX_op_ld_i64, { "r", "r" } }, +- { INDEX_op_st8_i64, { "r", "r" } }, +- { INDEX_op_st16_i64, { "r", "r" } }, +- { INDEX_op_st32_i64, { "r", "r" } }, +- { INDEX_op_st_i64, { "r", "r" } }, ++ { INDEX_op_st8_i64, { "ri", "r" } }, ++ { INDEX_op_st16_i64, { "ri", "r" } }, ++ { INDEX_op_st32_i64, { "ri", "r" } }, ++ { INDEX_op_st_i64, { "re", "r" } }, + + { INDEX_op_add_i64, { "r", "0", "re" } }, + { INDEX_op_mul_i64, { "r", "0", "re" } }, +-- +1.7.12.1 + diff --git a/0041-tcg-mark-set_label-with-TCG_OPF_BB_END-flag.patch b/0041-tcg-mark-set_label-with-TCG_OPF_BB_END-flag.patch new file mode 100644 index 0000000..bfab53b --- /dev/null +++ b/0041-tcg-mark-set_label-with-TCG_OPF_BB_END-flag.patch @@ -0,0 +1,53 @@ +From 1610a0e56c0be3e4bfd3034e5323188b1d05badd Mon Sep 17 00:00:00 2001 +From: Aurelien Jarno +Date: Mon, 10 Sep 2012 14:23:49 +0200 +Subject: [PATCH] tcg: mark set_label with TCG_OPF_BB_END flag + +set_label is effectively the end of a basic block, as no optimization +can be made accross it. It was treated as such in the liveness analysis +code, but as a special case. + +Mark it with TCG_OPF_BB_END flag so that this information can be used +by other parts of the TCG code, and remove the special case in the liveness +analysis code. + +Cc: Blue Swirl +Signed-off-by: Aurelien Jarno +Signed-off-by: Michael Roth +--- + tcg/tcg-opc.h | 2 +- + tcg/tcg.c | 5 ----- + 2 files changed, 1 insertion(+), 6 deletions(-) + +diff --git a/tcg/tcg-opc.h b/tcg/tcg-opc.h +index 8e06d03..d12e8d0 100644 +--- a/tcg/tcg-opc.h ++++ b/tcg/tcg-opc.h +@@ -36,7 +36,7 @@ DEF(nopn, 0, 0, 1, 0) /* variable number of parameters */ + + DEF(discard, 1, 0, 0, 0) + +-DEF(set_label, 0, 0, 1, 0) ++DEF(set_label, 0, 0, 1, TCG_OPF_BB_END) + DEF(call, 0, 1, 2, TCG_OPF_SIDE_EFFECTS) /* variable number of parameters */ + DEF(jmp, 0, 1, 0, TCG_OPF_BB_END | TCG_OPF_SIDE_EFFECTS) + DEF(br, 0, 0, 1, TCG_OPF_BB_END | TCG_OPF_SIDE_EFFECTS) +diff --git a/tcg/tcg.c b/tcg/tcg.c +index 8386b70..c002a88 100644 +--- a/tcg/tcg.c ++++ b/tcg/tcg.c +@@ -1297,11 +1297,6 @@ static void tcg_liveness_analysis(TCGContext *s) + args--; + } + break; +- case INDEX_op_set_label: +- args--; +- /* mark end of basic block */ +- tcg_la_bb_end(s, dead_temps); +- break; + case INDEX_op_debug_insn_start: + args -= def->nb_args; + break; +-- +1.7.12.1 + diff --git a/0042-revert-TCG-fix-copy-propagation.patch b/0042-revert-TCG-fix-copy-propagation.patch new file mode 100644 index 0000000..9e0a169 --- /dev/null +++ b/0042-revert-TCG-fix-copy-propagation.patch @@ -0,0 +1,85 @@ +From 2b8d0049e88c17749ccb978509d3f8fda180d35f Mon Sep 17 00:00:00 2001 +From: Aurelien Jarno +Date: Mon, 10 Sep 2012 13:14:12 +0200 +Subject: [PATCH] revert "TCG: fix copy propagation" + +Given the copy propagation breakage on 32-bit hosts has been fixed +commit e31b0a7c050711884ad570fe73df806520953618 can be reverted. + +Cc: Blue Swirl +Signed-off-by: Aurelien Jarno +Signed-off-by: Michael Roth +--- + tcg/optimize.c | 15 ++++++--------- + tcg/tcg.h | 5 ----- + 2 files changed, 6 insertions(+), 14 deletions(-) + +diff --git a/tcg/optimize.c b/tcg/optimize.c +index fba0ed9..10d9773 100644 +--- a/tcg/optimize.c ++++ b/tcg/optimize.c +@@ -107,15 +107,12 @@ static TCGOpcode op_to_movi(TCGOpcode op) + } + } + +-static void tcg_opt_gen_mov(TCGContext *s, TCGArg *gen_args, TCGArg dst, +- TCGArg src, int nb_temps, int nb_globals) ++static void tcg_opt_gen_mov(TCGArg *gen_args, TCGArg dst, TCGArg src, ++ int nb_temps, int nb_globals) + { + reset_temp(dst, nb_temps, nb_globals); + assert(temps[src].state != TCG_TEMP_COPY); +- /* Don't try to copy if one of temps is a global or either one +- is local and another is register */ +- if (src >= nb_globals && dst >= nb_globals && +- tcg_arg_is_local(s, src) == tcg_arg_is_local(s, dst)) { ++ if (src >= nb_globals) { + assert(temps[src].state != TCG_TEMP_CONST); + if (temps[src].state != TCG_TEMP_HAS_COPY) { + temps[src].state = TCG_TEMP_HAS_COPY; +@@ -444,7 +441,7 @@ static TCGArg *tcg_constant_folding(TCGContext *s, uint16_t *tcg_opc_ptr, + gen_opc_buf[op_index] = INDEX_op_nop; + } else { + gen_opc_buf[op_index] = op_to_mov(op); +- tcg_opt_gen_mov(s, gen_args, args[0], args[1], ++ tcg_opt_gen_mov(gen_args, args[0], args[1], + nb_temps, nb_globals); + gen_args += 2; + } +@@ -482,7 +479,7 @@ static TCGArg *tcg_constant_folding(TCGContext *s, uint16_t *tcg_opc_ptr, + gen_opc_buf[op_index] = INDEX_op_nop; + } else { + gen_opc_buf[op_index] = op_to_mov(op); +- tcg_opt_gen_mov(s, gen_args, args[0], args[1], nb_temps, ++ tcg_opt_gen_mov(gen_args, args[0], args[1], nb_temps, + nb_globals); + gen_args += 2; + } +@@ -507,7 +504,7 @@ static TCGArg *tcg_constant_folding(TCGContext *s, uint16_t *tcg_opc_ptr, + break; + } + if (temps[args[1]].state != TCG_TEMP_CONST) { +- tcg_opt_gen_mov(s, gen_args, args[0], args[1], ++ tcg_opt_gen_mov(gen_args, args[0], args[1], + nb_temps, nb_globals); + gen_args += 2; + args += 2; +diff --git a/tcg/tcg.h b/tcg/tcg.h +index d710694..8fbbc81 100644 +--- a/tcg/tcg.h ++++ b/tcg/tcg.h +@@ -458,11 +458,6 @@ static inline TCGv_i64 tcg_temp_local_new_i64(void) + void tcg_temp_free_i64(TCGv_i64 arg); + char *tcg_get_arg_str_i64(TCGContext *s, char *buf, int buf_size, TCGv_i64 arg); + +-static inline bool tcg_arg_is_local(TCGContext *s, TCGArg arg) +-{ +- return s->temps[arg].temp_local; +-} +- + #if defined(CONFIG_DEBUG_TCG) + /* If you call tcg_clear_temp_count() at the start of a section of + * code which is not supposed to leak any TCG temporaries, then +-- +1.7.12.1 + diff --git a/0043-target-mips-Set-opn-in-gen_ldst_multiple.patch b/0043-target-mips-Set-opn-in-gen_ldst_multiple.patch new file mode 100644 index 0000000..874c31e --- /dev/null +++ b/0043-target-mips-Set-opn-in-gen_ldst_multiple.patch @@ -0,0 +1,55 @@ +From 3380afc68a701604e51fa22637ef48d93514d678 Mon Sep 17 00:00:00 2001 +From: Richard Henderson +Date: Tue, 18 Sep 2012 21:55:32 -0700 +Subject: [PATCH] target-mips: Set opn in gen_ldst_multiple. + +Used by MIPS_DEBUG, when enabled. + +Signed-off-by: Richard Henderson +Acked-by: Aurelien Jarno +Signed-off-by: Aurelien Jarno +Signed-off-by: Michael Roth +--- + target-mips/translate.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/target-mips/translate.c b/target-mips/translate.c +index 7ab769f..c31f91c 100644 +--- a/target-mips/translate.c ++++ b/target-mips/translate.c +@@ -9855,6 +9855,7 @@ static void gen_andi16 (CPUMIPSState *env, DisasContext *ctx) + static void gen_ldst_multiple (DisasContext *ctx, uint32_t opc, int reglist, + int base, int16_t offset) + { ++ const char *opn = "ldst_multiple"; + TCGv t0, t1; + TCGv_i32 t2; + +@@ -9874,19 +9875,24 @@ static void gen_ldst_multiple (DisasContext *ctx, uint32_t opc, int reglist, + switch (opc) { + case LWM32: + gen_helper_lwm(cpu_env, t0, t1, t2); ++ opn = "lwm"; + break; + case SWM32: + gen_helper_swm(cpu_env, t0, t1, t2); ++ opn = "swm"; + break; + #ifdef TARGET_MIPS64 + case LDM: + gen_helper_ldm(cpu_env, t0, t1, t2); ++ opn = "ldm"; + break; + case SDM: + gen_helper_sdm(cpu_env, t0, t1, t2); ++ opn = "sdm"; + break; + #endif + } ++ (void)opn; + MIPS_DEBUG("%s, %x, %d(%s)", opn, reglist, offset, regnames[base]); + tcg_temp_free(t0); + tcg_temp_free(t1); +-- +1.7.12.1 + diff --git a/0044-target-mips-Fix-MIPS_DEBUG.patch b/0044-target-mips-Fix-MIPS_DEBUG.patch new file mode 100644 index 0000000..0fa094a --- /dev/null +++ b/0044-target-mips-Fix-MIPS_DEBUG.patch @@ -0,0 +1,288 @@ +From 5dd8e9207a39d8fe41eaa110edfdba5e37064562 Mon Sep 17 00:00:00 2001 +From: Richard Henderson +Date: Tue, 18 Sep 2012 21:55:33 -0700 +Subject: [PATCH] target-mips: Fix MIPS_DEBUG. + +The macro uses the DisasContext. Pass it around as needed. + +Signed-off-by: Richard Henderson +Acked-by: Aurelien Jarno +Signed-off-by: Aurelien Jarno +Signed-off-by: Michael Roth +--- + target-mips/translate.c | 74 +++++++++++++++++++++++++------------------------ + 1 file changed, 38 insertions(+), 36 deletions(-) + +diff --git a/target-mips/translate.c b/target-mips/translate.c +index c31f91c..4937f6b 100644 +--- a/target-mips/translate.c ++++ b/target-mips/translate.c +@@ -1431,7 +1431,8 @@ static void gen_arith_imm (CPUMIPSState *env, DisasContext *ctx, uint32_t opc, + } + + /* Logic with immediate operand */ +-static void gen_logic_imm (CPUMIPSState *env, uint32_t opc, int rt, int rs, int16_t imm) ++static void gen_logic_imm(CPUMIPSState *env, DisasContext *ctx, uint32_t opc, ++ int rt, int rs, int16_t imm) + { + target_ulong uimm; + const char *opn = "imm logic"; +@@ -1474,7 +1475,8 @@ static void gen_logic_imm (CPUMIPSState *env, uint32_t opc, int rt, int rs, int1 + } + + /* Set on less than with immediate operand */ +-static void gen_slt_imm (CPUMIPSState *env, uint32_t opc, int rt, int rs, int16_t imm) ++static void gen_slt_imm(CPUMIPSState *env, DisasContext *ctx, uint32_t opc, ++ int rt, int rs, int16_t imm) + { + target_ulong uimm = (target_long)imm; /* Sign extend to 32/64 bits */ + const char *opn = "imm arith"; +@@ -1775,7 +1777,8 @@ static void gen_arith (CPUMIPSState *env, DisasContext *ctx, uint32_t opc, + } + + /* Conditional move */ +-static void gen_cond_move (CPUMIPSState *env, uint32_t opc, int rd, int rs, int rt) ++static void gen_cond_move(CPUMIPSState *env, DisasContext *ctx, uint32_t opc, ++ int rd, int rs, int rt) + { + const char *opn = "cond move"; + int l1; +@@ -1813,7 +1816,8 @@ static void gen_cond_move (CPUMIPSState *env, uint32_t opc, int rd, int rs, int + } + + /* Logic */ +-static void gen_logic (CPUMIPSState *env, uint32_t opc, int rd, int rs, int rt) ++static void gen_logic(CPUMIPSState *env, DisasContext *ctx, uint32_t opc, ++ int rd, int rs, int rt) + { + const char *opn = "logic"; + +@@ -1874,7 +1878,8 @@ static void gen_logic (CPUMIPSState *env, uint32_t opc, int rd, int rs, int rt) + } + + /* Set on lower than */ +-static void gen_slt (CPUMIPSState *env, uint32_t opc, int rd, int rs, int rt) ++static void gen_slt(CPUMIPSState *env, DisasContext *ctx, uint32_t opc, ++ int rd, int rs, int rt) + { + const char *opn = "slt"; + TCGv t0, t1; +@@ -8778,10 +8783,10 @@ static int decode_extended_mips16_opc (CPUMIPSState *env, DisasContext *ctx, + gen_arith_imm(env, ctx, OPC_ADDIU, rx, rx, imm); + break; + case M16_OPC_SLTI: +- gen_slt_imm(env, OPC_SLTI, 24, rx, imm); ++ gen_slt_imm(env, ctx, OPC_SLTI, 24, rx, imm); + break; + case M16_OPC_SLTIU: +- gen_slt_imm(env, OPC_SLTIU, 24, rx, imm); ++ gen_slt_imm(env, ctx, OPC_SLTIU, 24, rx, imm); + break; + case M16_OPC_I8: + switch (funct) { +@@ -8992,15 +8997,13 @@ static int decode_mips16_opc (CPUMIPSState *env, DisasContext *ctx, + case M16_OPC_SLTI: + { + int16_t imm = (uint8_t) ctx->opcode; +- +- gen_slt_imm(env, OPC_SLTI, 24, rx, imm); ++ gen_slt_imm(env, ctx, OPC_SLTI, 24, rx, imm); + } + break; + case M16_OPC_SLTIU: + { + int16_t imm = (uint8_t) ctx->opcode; +- +- gen_slt_imm(env, OPC_SLTIU, 24, rx, imm); ++ gen_slt_imm(env, ctx, OPC_SLTIU, 24, rx, imm); + } + break; + case M16_OPC_I8: +@@ -9075,8 +9078,7 @@ static int decode_mips16_opc (CPUMIPSState *env, DisasContext *ctx, + case M16_OPC_CMPI: + { + int16_t imm = (uint8_t) ctx->opcode; +- +- gen_logic_imm(env, OPC_XORI, 24, rx, imm); ++ gen_logic_imm(env, ctx, OPC_XORI, 24, rx, imm); + } + break; + #if defined(TARGET_MIPS64) +@@ -9188,10 +9190,10 @@ static int decode_mips16_opc (CPUMIPSState *env, DisasContext *ctx, + } + break; + case RR_SLT: +- gen_slt(env, OPC_SLT, 24, rx, ry); ++ gen_slt(env, ctx, OPC_SLT, 24, rx, ry); + break; + case RR_SLTU: +- gen_slt(env, OPC_SLTU, 24, rx, ry); ++ gen_slt(env, ctx, OPC_SLTU, 24, rx, ry); + break; + case RR_BREAK: + generate_exception(ctx, EXCP_BREAK); +@@ -9212,22 +9214,22 @@ static int decode_mips16_opc (CPUMIPSState *env, DisasContext *ctx, + break; + #endif + case RR_CMP: +- gen_logic(env, OPC_XOR, 24, rx, ry); ++ gen_logic(env, ctx, OPC_XOR, 24, rx, ry); + break; + case RR_NEG: + gen_arith(env, ctx, OPC_SUBU, rx, 0, ry); + break; + case RR_AND: +- gen_logic(env, OPC_AND, rx, rx, ry); ++ gen_logic(env, ctx, OPC_AND, rx, rx, ry); + break; + case RR_OR: +- gen_logic(env, OPC_OR, rx, rx, ry); ++ gen_logic(env, ctx, OPC_OR, rx, rx, ry); + break; + case RR_XOR: +- gen_logic(env, OPC_XOR, rx, rx, ry); ++ gen_logic(env, ctx, OPC_XOR, rx, rx, ry); + break; + case RR_NOT: +- gen_logic(env, OPC_NOR, rx, ry, 0); ++ gen_logic(env, ctx, OPC_NOR, rx, ry, 0); + break; + case RR_MFHI: + gen_HILO(ctx, OPC_MFHI, rx); +@@ -9849,7 +9851,7 @@ static void gen_andi16 (CPUMIPSState *env, DisasContext *ctx) + int rs = mmreg(uMIPS_RS(ctx->opcode)); + int encoded = ZIMM(ctx->opcode, 0, 4); + +- gen_logic_imm(env, OPC_ANDI, rd, rs, decoded_imm[encoded]); ++ gen_logic_imm(env, ctx, OPC_ANDI, rd, rs, decoded_imm[encoded]); + } + + static void gen_ldst_multiple (DisasContext *ctx, uint32_t opc, int reglist, +@@ -9911,25 +9913,25 @@ static void gen_pool16c_insn (CPUMIPSState *env, DisasContext *ctx, int *is_bran + case NOT16 + 1: + case NOT16 + 2: + case NOT16 + 3: +- gen_logic(env, OPC_NOR, rd, rs, 0); ++ gen_logic(env, ctx, OPC_NOR, rd, rs, 0); + break; + case XOR16 + 0: + case XOR16 + 1: + case XOR16 + 2: + case XOR16 + 3: +- gen_logic(env, OPC_XOR, rd, rd, rs); ++ gen_logic(env, ctx, OPC_XOR, rd, rd, rs); + break; + case AND16 + 0: + case AND16 + 1: + case AND16 + 2: + case AND16 + 3: +- gen_logic(env, OPC_AND, rd, rd, rs); ++ gen_logic(env, ctx, OPC_AND, rd, rd, rs); + break; + case OR16 + 0: + case OR16 + 1: + case OR16 + 2: + case OR16 + 3: +- gen_logic(env, OPC_OR, rd, rd, rs); ++ gen_logic(env, ctx, OPC_OR, rd, rd, rs); + break; + case LWM16 + 0: + case LWM16 + 1: +@@ -10743,7 +10745,7 @@ static void decode_micromips32_opc (CPUMIPSState *env, DisasContext *ctx, + case XOR32: + mips32_op = OPC_XOR; + do_logic: +- gen_logic(env, mips32_op, rd, rs, rt); ++ gen_logic(env, ctx, mips32_op, rd, rs, rt); + break; + /* Set less than */ + case SLT: +@@ -10752,7 +10754,7 @@ static void decode_micromips32_opc (CPUMIPSState *env, DisasContext *ctx, + case SLTU: + mips32_op = OPC_SLTU; + do_slt: +- gen_slt(env, mips32_op, rd, rs, rt); ++ gen_slt(env, ctx, mips32_op, rd, rs, rt); + break; + default: + goto pool32a_invalid; +@@ -10768,7 +10770,7 @@ static void decode_micromips32_opc (CPUMIPSState *env, DisasContext *ctx, + case MOVZ: + mips32_op = OPC_MOVZ; + do_cmov: +- gen_cond_move(env, mips32_op, rd, rs, rt); ++ gen_cond_move(env, ctx, mips32_op, rd, rs, rt); + break; + case LWXS: + gen_ldxs(ctx, rs, rt, rd); +@@ -11181,7 +11183,7 @@ static void decode_micromips32_opc (CPUMIPSState *env, DisasContext *ctx, + target. */ + break; + case LUI: +- gen_logic_imm(env, OPC_LUI, rs, -1, imm); ++ gen_logic_imm(env, ctx, OPC_LUI, rs, -1, imm); + break; + case SYNCI: + break; +@@ -11300,7 +11302,7 @@ static void decode_micromips32_opc (CPUMIPSState *env, DisasContext *ctx, + case ANDI32: + mips32_op = OPC_ANDI; + do_logici: +- gen_logic_imm(env, mips32_op, rt, rs, imm); ++ gen_logic_imm(env, ctx, mips32_op, rt, rs, imm); + break; + + /* Set less than immediate */ +@@ -11310,7 +11312,7 @@ static void decode_micromips32_opc (CPUMIPSState *env, DisasContext *ctx, + case SLTIU32: + mips32_op = OPC_SLTIU; + do_slti: +- gen_slt_imm(env, mips32_op, rt, rs, imm); ++ gen_slt_imm(env, ctx, mips32_op, rt, rs, imm); + break; + case JALX32: + offset = (int32_t)(ctx->opcode & 0x3FFFFFF) << 2; +@@ -11787,7 +11789,7 @@ static void decode_opc (CPUMIPSState *env, DisasContext *ctx, int *is_branch) + case OPC_MOVZ: + check_insn(env, ctx, ISA_MIPS4 | ISA_MIPS32 | + INSN_LOONGSON2E | INSN_LOONGSON2F); +- gen_cond_move(env, op1, rd, rs, rt); ++ gen_cond_move(env, ctx, op1, rd, rs, rt); + break; + case OPC_ADD ... OPC_SUBU: + gen_arith(env, ctx, op1, rd, rs, rt); +@@ -11814,13 +11816,13 @@ static void decode_opc (CPUMIPSState *env, DisasContext *ctx, int *is_branch) + break; + case OPC_SLT: /* Set on less than */ + case OPC_SLTU: +- gen_slt(env, op1, rd, rs, rt); ++ gen_slt(env, ctx, op1, rd, rs, rt); + break; + case OPC_AND: /* Logic*/ + case OPC_OR: + case OPC_NOR: + case OPC_XOR: +- gen_logic(env, op1, rd, rs, rt); ++ gen_logic(env, ctx, op1, rd, rs, rt); + break; + case OPC_MULT ... OPC_DIVU: + if (sa) { +@@ -12221,13 +12223,13 @@ static void decode_opc (CPUMIPSState *env, DisasContext *ctx, int *is_branch) + break; + case OPC_SLTI: /* Set on less than with immediate opcode */ + case OPC_SLTIU: +- gen_slt_imm(env, op, rt, rs, imm); ++ gen_slt_imm(env, ctx, op, rt, rs, imm); + break; + case OPC_ANDI: /* Arithmetic with immediate opcode */ + case OPC_LUI: + case OPC_ORI: + case OPC_XORI: +- gen_logic_imm(env, op, rt, rs, imm); ++ gen_logic_imm(env, ctx, op, rt, rs, imm); + break; + case OPC_J ... OPC_JAL: /* Jump */ + offset = (int32_t)(ctx->opcode & 0x3FFFFFF) << 2; +-- +1.7.12.1 + diff --git a/0045-target-mips-Always-evaluate-debugging-macro-argument.patch b/0045-target-mips-Always-evaluate-debugging-macro-argument.patch new file mode 100644 index 0000000..e424bcf --- /dev/null +++ b/0045-target-mips-Always-evaluate-debugging-macro-argument.patch @@ -0,0 +1,70 @@ +From e6f923b4e3e71661343f6d2eecd7f102022e5635 Mon Sep 17 00:00:00 2001 +From: Richard Henderson +Date: Tue, 18 Sep 2012 21:55:34 -0700 +Subject: [PATCH] target-mips: Always evaluate debugging macro arguments + +this will prevent some of the compilation errors with debugging +enabled from creeping back in. + +Signed-off-by: Richard Henderson +Signed-off-by: Aurelien Jarno +Signed-off-by: Michael Roth +--- + target-mips/translate.c | 31 +++++++++++++++++-------------- + 1 file changed, 17 insertions(+), 14 deletions(-) + +diff --git a/target-mips/translate.c b/target-mips/translate.c +index 4937f6b..aba7935 100644 +--- a/target-mips/translate.c ++++ b/target-mips/translate.c +@@ -28,7 +28,7 @@ + #define GEN_HELPER 1 + #include "helper.h" + +-//#define MIPS_DEBUG_DISAS ++#define MIPS_DEBUG_DISAS 0 + //#define MIPS_DEBUG_SIGN_EXTENSIONS + + /* MIPS major opcodes */ +@@ -566,22 +566,25 @@ static const char *fregnames[] = + "f16", "f17", "f18", "f19", "f20", "f21", "f22", "f23", + "f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31", }; + +-#ifdef MIPS_DEBUG_DISAS +-#define MIPS_DEBUG(fmt, ...) \ +- qemu_log_mask(CPU_LOG_TB_IN_ASM, \ +- TARGET_FMT_lx ": %08x " fmt "\n", \ +- ctx->pc, ctx->opcode , ## __VA_ARGS__) +-#define LOG_DISAS(...) qemu_log_mask(CPU_LOG_TB_IN_ASM, ## __VA_ARGS__) +-#else +-#define MIPS_DEBUG(fmt, ...) do { } while(0) +-#define LOG_DISAS(...) do { } while (0) +-#endif ++#define MIPS_DEBUG(fmt, ...) \ ++ do { \ ++ if (MIPS_DEBUG_DISAS) { \ ++ qemu_log_mask(CPU_LOG_TB_IN_ASM, \ ++ TARGET_FMT_lx ": %08x " fmt "\n", \ ++ ctx->pc, ctx->opcode , ## __VA_ARGS__); \ ++ } \ ++ } while (0) ++ ++#define LOG_DISAS(...) \ ++ do { \ ++ if (MIPS_DEBUG_DISAS) { \ ++ qemu_log_mask(CPU_LOG_TB_IN_ASM, ## __VA_ARGS__); \ ++ } \ ++ } while (0) + + #define MIPS_INVAL(op) \ +-do { \ + MIPS_DEBUG("Invalid %s %03x %03x %03x", op, ctx->opcode >> 26, \ +- ctx->opcode & 0x3F, ((ctx->opcode >> 16) & 0x1F)); \ +-} while (0) ++ ctx->opcode & 0x3F, ((ctx->opcode >> 16) & 0x1F)) + + /* General purpose registers moves. */ + static inline void gen_load_gpr (TCGv t, int reg) +-- +1.7.12.1 + diff --git a/0046-tcg-optimize-fix-end-of-basic-block-detection.patch b/0046-tcg-optimize-fix-end-of-basic-block-detection.patch new file mode 100644 index 0000000..c498962 --- /dev/null +++ b/0046-tcg-optimize-fix-end-of-basic-block-detection.patch @@ -0,0 +1,62 @@ +From 4ce7a1e0aaecb220016af9b4f390b76f7fffcce8 Mon Sep 17 00:00:00 2001 +From: Aurelien Jarno +Date: Wed, 19 Sep 2012 21:40:30 +0200 +Subject: [PATCH] tcg/optimize: fix end of basic block detection + +Commit e31b0a7c050711884ad570fe73df806520953618 fixed copy propagation on +32-bit host by restricting the copy between different types. This was the +wrong fix. + +The real problem is that the all temps states should be reset at the end +of a basic block. This was done by adding such operations in the switch, +but brcond2 was forgotten (that's why the crash was only observed on 32-bit +hosts). + +Fix that by looking at the TCG_OPF_BB_END instead. We need to keep the case +for op_set_label as temps might be modified through another path. + +Cc: Blue Swirl +Signed-off-by: Aurelien Jarno +Signed-off-by: Michael Roth +--- + tcg/optimize.c | 22 +++++++++------------- + 1 file changed, 9 insertions(+), 13 deletions(-) + +diff --git a/tcg/optimize.c b/tcg/optimize.c +index 10d9773..9da333c 100644 +--- a/tcg/optimize.c ++++ b/tcg/optimize.c +@@ -632,21 +632,17 @@ static TCGArg *tcg_constant_folding(TCGContext *s, uint16_t *tcg_opc_ptr, + i--; + } + break; +- case INDEX_op_set_label: +- case INDEX_op_jmp: +- case INDEX_op_br: +- memset(temps, 0, nb_temps * sizeof(struct tcg_temp_info)); +- for (i = 0; i < def->nb_args; i++) { +- *gen_args = *args; +- args++; +- gen_args++; +- } +- break; + default: + /* Default case: we do know nothing about operation so no +- propagation is done. We only trash output args. */ +- for (i = 0; i < def->nb_oargs; i++) { +- reset_temp(args[i], nb_temps, nb_globals); ++ 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 { ++ for (i = 0; i < def->nb_oargs; i++) { ++ reset_temp(args[i], nb_temps, nb_globals); ++ } + } + for (i = 0; i < def->nb_args; i++) { + gen_args[i] = args[i]; +-- +1.7.12.1 + diff --git a/0047-target-xtensa-fix-extui-shift-amount.patch b/0047-target-xtensa-fix-extui-shift-amount.patch new file mode 100644 index 0000000..c654322 --- /dev/null +++ b/0047-target-xtensa-fix-extui-shift-amount.patch @@ -0,0 +1,57 @@ +From 1c596a9498830485a1b2f4a4445643a149179b99 Mon Sep 17 00:00:00 2001 +From: Max Filippov +Date: Fri, 21 Sep 2012 02:59:49 +0400 +Subject: [PATCH] target-xtensa: fix extui shift amount + +extui opcode only uses lowermost op1 bit for sa4. + +Reported-by: malc +Signed-off-by: Max Filippov +Cc: qemu-stable +Signed-off-by: malc +Signed-off-by: Michael Roth +--- + target-xtensa/translate.c | 24 +++++++++++++++++++++--- + 1 file changed, 21 insertions(+), 3 deletions(-) + +diff --git a/target-xtensa/translate.c b/target-xtensa/translate.c +index 1900bd5..7a1c528 100644 +--- a/target-xtensa/translate.c ++++ b/target-xtensa/translate.c +@@ -1778,12 +1778,30 @@ static void disas_xtensa_insn(DisasContext *dc) + case 5: + gen_window_check2(dc, RRR_R, RRR_T); + { +- int shiftimm = RRR_S | (OP1 << 4); ++ int shiftimm = RRR_S | ((OP1 & 1) << 4); + int maskimm = (1 << (OP2 + 1)) - 1; + + TCGv_i32 tmp = tcg_temp_new_i32(); +- tcg_gen_shri_i32(tmp, cpu_R[RRR_T], shiftimm); +- tcg_gen_andi_i32(cpu_R[RRR_R], tmp, maskimm); ++ ++ if (shiftimm) { ++ tcg_gen_shri_i32(tmp, cpu_R[RRR_T], shiftimm); ++ } else { ++ tcg_gen_mov_i32(tmp, cpu_R[RRR_T]); ++ } ++ ++ switch (maskimm) { ++ case 0xff: ++ tcg_gen_ext8u_i32(cpu_R[RRR_R], tmp); ++ break; ++ ++ case 0xffff: ++ tcg_gen_ext16u_i32(cpu_R[RRR_R], tmp); ++ break; ++ ++ default: ++ tcg_gen_andi_i32(cpu_R[RRR_R], tmp, maskimm); ++ break; ++ } + tcg_temp_free(tmp); + } + break; +-- +1.7.12.1 + diff --git a/0048-target-xtensa-don-t-emit-extra-tcg_gen_goto_tb.patch b/0048-target-xtensa-don-t-emit-extra-tcg_gen_goto_tb.patch new file mode 100644 index 0000000..2e8e219 --- /dev/null +++ b/0048-target-xtensa-don-t-emit-extra-tcg_gen_goto_tb.patch @@ -0,0 +1,35 @@ +From ba9c2acb955f0453ae80077a791a4d1c27b5d6e6 Mon Sep 17 00:00:00 2001 +From: Max Filippov +Date: Fri, 21 Sep 2012 02:59:50 +0400 +Subject: [PATCH] target-xtensa: don't emit extra tcg_gen_goto_tb + +Unconditional gen_check_loop_end at the end of disas_xtensa_insn +can emit tcg_gen_goto_tb with slot id already used in the TB (e.g. when +TB ends at LEND with a branch). + +Signed-off-by: Max Filippov +Cc: qemu-stable +Signed-off-by: malc +Signed-off-by: Michael Roth +--- + target-xtensa/translate.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/target-xtensa/translate.c b/target-xtensa/translate.c +index 7a1c528..b6643eb 100644 +--- a/target-xtensa/translate.c ++++ b/target-xtensa/translate.c +@@ -2520,7 +2520,9 @@ static void disas_xtensa_insn(DisasContext *dc) + break; + } + +- gen_check_loop_end(dc, 0); ++ if (dc->is_jmp == DISAS_NEXT) { ++ gen_check_loop_end(dc, 0); ++ } + dc->pc = dc->next_pc; + + return; +-- +1.7.12.1 + diff --git a/0049-tcg-Introduce-movcond.patch b/0049-tcg-Introduce-movcond.patch new file mode 100644 index 0000000..3ead932 --- /dev/null +++ b/0049-tcg-Introduce-movcond.patch @@ -0,0 +1,333 @@ +From a977d2c7f02eb2ed7fc879979d6f5525c017a881 Mon Sep 17 00:00:00 2001 +From: Richard Henderson +Date: Fri, 21 Sep 2012 10:13:34 -0700 +Subject: [PATCH] tcg: Introduce movcond + +Implemented with setcond if the target does not provide +the optional opcode. + +Signed-off-by: Richard Henderson +Signed-off-by: Aurelien Jarno +Signed-off-by: Michael Roth +--- + tcg/README | 6 ++++++ + tcg/arm/tcg-target.h | 1 + + tcg/hppa/tcg-target.h | 1 + + tcg/i386/tcg-target.h | 2 ++ + tcg/ia64/tcg-target.h | 2 ++ + tcg/mips/tcg-target.h | 1 + + tcg/ppc/tcg-target.h | 1 + + tcg/ppc64/tcg-target.h | 2 ++ + tcg/s390/tcg-target.h | 2 ++ + tcg/sparc/tcg-target.h | 2 ++ + tcg/tcg-op.h | 40 ++++++++++++++++++++++++++++++++++++++++ + tcg/tcg-opc.h | 2 ++ + tcg/tcg.c | 11 +++++------ + tcg/tcg.h | 1 + + tcg/tci/tcg-target.h | 2 ++ + 15 files changed, 70 insertions(+), 6 deletions(-) + +diff --git a/tcg/README b/tcg/README +index cfdfd96..d03ae05 100644 +--- a/tcg/README ++++ b/tcg/README +@@ -307,6 +307,12 @@ dest = (t1 cond t2) + + Set DEST to 1 if (T1 cond T2) is true, otherwise set to 0. + ++* movcond_i32/i64 cond, dest, c1, c2, v1, v2 ++ ++dest = (c1 cond c2 ? v1 : v2) ++ ++Set DEST to V1 if (C1 cond C2) is true, otherwise set to V2. ++ + ********* Type conversions + + * ext_i32_i64 t0, t1 +diff --git a/tcg/arm/tcg-target.h b/tcg/arm/tcg-target.h +index c0b8f72..e2299ca 100644 +--- a/tcg/arm/tcg-target.h ++++ b/tcg/arm/tcg-target.h +@@ -73,6 +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_GUEST_BASE + +diff --git a/tcg/hppa/tcg-target.h b/tcg/hppa/tcg-target.h +index 01ef960..4defd28 100644 +--- a/tcg/hppa/tcg-target.h ++++ b/tcg/hppa/tcg-target.h +@@ -96,6 +96,7 @@ typedef enum { + #define TCG_TARGET_HAS_nand_i32 0 + #define TCG_TARGET_HAS_nor_i32 0 + #define TCG_TARGET_HAS_deposit_i32 1 ++#define TCG_TARGET_HAS_movcond_i32 0 + + /* optional instructions automatically implemented */ + #define TCG_TARGET_HAS_neg_i32 0 /* sub rd, 0, rs */ +diff --git a/tcg/i386/tcg-target.h b/tcg/i386/tcg-target.h +index 8be42f3..504f953 100644 +--- a/tcg/i386/tcg-target.h ++++ b/tcg/i386/tcg-target.h +@@ -86,6 +86,7 @@ typedef enum { + #define TCG_TARGET_HAS_nand_i32 0 + #define TCG_TARGET_HAS_nor_i32 0 + #define TCG_TARGET_HAS_deposit_i32 1 ++#define TCG_TARGET_HAS_movcond_i32 0 + + #if TCG_TARGET_REG_BITS == 64 + #define TCG_TARGET_HAS_div2_i64 1 +@@ -107,6 +108,7 @@ typedef enum { + #define TCG_TARGET_HAS_nand_i64 0 + #define TCG_TARGET_HAS_nor_i64 0 + #define TCG_TARGET_HAS_deposit_i64 1 ++#define TCG_TARGET_HAS_movcond_i64 0 + #endif + + #define TCG_TARGET_deposit_i32_valid(ofs, len) \ +diff --git a/tcg/ia64/tcg-target.h b/tcg/ia64/tcg-target.h +index c22962a..368aee4 100644 +--- a/tcg/ia64/tcg-target.h ++++ b/tcg/ia64/tcg-target.h +@@ -133,6 +133,8 @@ typedef enum { + #define TCG_TARGET_HAS_rot_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 */ +diff --git a/tcg/mips/tcg-target.h b/tcg/mips/tcg-target.h +index 1c61931..9c68a32 100644 +--- a/tcg/mips/tcg-target.h ++++ b/tcg/mips/tcg-target.h +@@ -90,6 +90,7 @@ typedef enum { + #define TCG_TARGET_HAS_eqv_i32 0 + #define TCG_TARGET_HAS_nand_i32 0 + #define TCG_TARGET_HAS_deposit_i32 0 ++#define TCG_TARGET_HAS_movcond_i32 0 + + /* optional instructions automatically implemented */ + #define TCG_TARGET_HAS_neg_i32 0 /* sub rd, zero, rt */ +diff --git a/tcg/ppc/tcg-target.h b/tcg/ppc/tcg-target.h +index 2f37fd2..177eea1 100644 +--- a/tcg/ppc/tcg-target.h ++++ b/tcg/ppc/tcg-target.h +@@ -92,6 +92,7 @@ typedef enum { + #define TCG_TARGET_HAS_nand_i32 1 + #define TCG_TARGET_HAS_nor_i32 1 + #define TCG_TARGET_HAS_deposit_i32 1 ++#define TCG_TARGET_HAS_movcond_i32 0 + + #define TCG_AREG0 TCG_REG_R27 + +diff --git a/tcg/ppc64/tcg-target.h b/tcg/ppc64/tcg-target.h +index 97eec08..57569e8 100644 +--- a/tcg/ppc64/tcg-target.h ++++ b/tcg/ppc64/tcg-target.h +@@ -83,6 +83,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_div_i64 1 + #define TCG_TARGET_HAS_rot_i64 0 +@@ -103,6 +104,7 @@ typedef enum { + #define TCG_TARGET_HAS_nand_i64 0 + #define TCG_TARGET_HAS_nor_i64 0 + #define TCG_TARGET_HAS_deposit_i64 0 ++#define TCG_TARGET_HAS_movcond_i64 0 + + #define TCG_AREG0 TCG_REG_R27 + +diff --git a/tcg/s390/tcg-target.h b/tcg/s390/tcg-target.h +index 4f7dfab..ed55c33 100644 +--- a/tcg/s390/tcg-target.h ++++ b/tcg/s390/tcg-target.h +@@ -63,6 +63,7 @@ typedef enum TCGReg { + #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 + + #if TCG_TARGET_REG_BITS == 64 + #define TCG_TARGET_HAS_div2_i64 1 +@@ -84,6 +85,7 @@ typedef enum TCGReg { + #define TCG_TARGET_HAS_nand_i64 0 + #define TCG_TARGET_HAS_nor_i64 0 + #define TCG_TARGET_HAS_deposit_i64 0 ++#define TCG_TARGET_HAS_movcond_i64 0 + #endif + + #define TCG_TARGET_HAS_GUEST_BASE +diff --git a/tcg/sparc/tcg-target.h b/tcg/sparc/tcg-target.h +index 0ea87be..d762574 100644 +--- a/tcg/sparc/tcg-target.h ++++ b/tcg/sparc/tcg-target.h +@@ -102,6 +102,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 + + #if TCG_TARGET_REG_BITS == 64 + #define TCG_TARGET_HAS_div_i64 1 +@@ -123,6 +124,7 @@ typedef enum { + #define TCG_TARGET_HAS_nand_i64 0 + #define TCG_TARGET_HAS_nor_i64 0 + #define TCG_TARGET_HAS_deposit_i64 0 ++#define TCG_TARGET_HAS_movcond_i64 0 + #endif + + #ifdef CONFIG_SOLARIS +diff --git a/tcg/tcg-op.h b/tcg/tcg-op.h +index 169d3b2..6d28f82 100644 +--- a/tcg/tcg-op.h ++++ b/tcg/tcg-op.h +@@ -2118,6 +2118,44 @@ static inline void tcg_gen_deposit_i64(TCGv_i64 ret, TCGv_i64 arg1, + tcg_temp_free_i64(t1); + } + ++static inline void tcg_gen_movcond_i32(TCGCond cond, TCGv_i32 ret, ++ TCGv_i32 c1, TCGv_i32 c2, ++ TCGv_i32 v1, TCGv_i32 v2) ++{ ++ if (TCG_TARGET_HAS_movcond_i32) { ++ tcg_gen_op6i_i32(INDEX_op_movcond_i32, ret, c1, c2, v1, v2, cond); ++ } else { ++ TCGv_i32 t0 = tcg_temp_new_i32(); ++ TCGv_i32 t1 = tcg_temp_new_i32(); ++ tcg_gen_setcond_i32(cond, t0, c1, c2); ++ tcg_gen_neg_i32(t0, t0); ++ tcg_gen_and_i32(t1, v1, t0); ++ tcg_gen_andc_i32(ret, v2, t0); ++ tcg_gen_or_i32(ret, ret, t1); ++ tcg_temp_free_i32(t0); ++ tcg_temp_free_i32(t1); ++ } ++} ++ ++static inline void tcg_gen_movcond_i64(TCGCond cond, TCGv_i64 ret, ++ TCGv_i64 c1, TCGv_i64 c2, ++ TCGv_i64 v1, TCGv_i64 v2) ++{ ++ if (TCG_TARGET_HAS_movcond_i64) { ++ tcg_gen_op6i_i64(INDEX_op_movcond_i64, ret, c1, c2, v1, v2, cond); ++ } else { ++ TCGv_i64 t0 = tcg_temp_new_i64(); ++ TCGv_i64 t1 = tcg_temp_new_i64(); ++ tcg_gen_setcond_i64(cond, t0, c1, c2); ++ tcg_gen_neg_i64(t0, t0); ++ tcg_gen_and_i64(t1, v1, t0); ++ tcg_gen_andc_i64(ret, v2, t0); ++ tcg_gen_or_i64(ret, ret, t1); ++ tcg_temp_free_i64(t0); ++ tcg_temp_free_i64(t1); ++ } ++} ++ + /***************************************/ + /* QEMU specific operations. Their type depend on the QEMU CPU + type. */ +@@ -2434,6 +2472,7 @@ static inline void tcg_gen_qemu_st64(TCGv_i64 arg, TCGv addr, int mem_index) + #define tcg_gen_deposit_tl tcg_gen_deposit_i64 + #define tcg_const_tl tcg_const_i64 + #define tcg_const_local_tl tcg_const_local_i64 ++#define tcg_gen_movcond_tl tcg_gen_movcond_i64 + #else + #define tcg_gen_movi_tl tcg_gen_movi_i32 + #define tcg_gen_mov_tl tcg_gen_mov_i32 +@@ -2505,6 +2544,7 @@ static inline void tcg_gen_qemu_st64(TCGv_i64 arg, TCGv addr, int mem_index) + #define tcg_gen_deposit_tl tcg_gen_deposit_i32 + #define tcg_const_tl tcg_const_i32 + #define tcg_const_local_tl tcg_const_local_i32 ++#define tcg_gen_movcond_tl tcg_gen_movcond_i32 + #endif + + #if TCG_TARGET_REG_BITS == 32 +diff --git a/tcg/tcg-opc.h b/tcg/tcg-opc.h +index d12e8d0..dbb0e39 100644 +--- a/tcg/tcg-opc.h ++++ b/tcg/tcg-opc.h +@@ -51,6 +51,7 @@ DEF(br, 0, 0, 1, TCG_OPF_BB_END | TCG_OPF_SIDE_EFFECTS) + DEF(mov_i32, 1, 1, 0, 0) + DEF(movi_i32, 1, 0, 1, 0) + DEF(setcond_i32, 1, 2, 1, 0) ++DEF(movcond_i32, 1, 4, 1, IMPL(TCG_TARGET_HAS_movcond_i32)) + /* load/store */ + DEF(ld8u_i32, 1, 1, 1, 0) + DEF(ld8s_i32, 1, 1, 1, 0) +@@ -107,6 +108,7 @@ DEF(nor_i32, 1, 2, 0, IMPL(TCG_TARGET_HAS_nor_i32)) + DEF(mov_i64, 1, 1, 0, IMPL64) + DEF(movi_i64, 1, 0, 1, IMPL64) + DEF(setcond_i64, 1, 2, 1, IMPL64) ++DEF(movcond_i64, 1, 4, 1, IMPL64 | IMPL(TCG_TARGET_HAS_movcond_i64)) + /* load/store */ + DEF(ld8u_i64, 1, 1, 1, IMPL64) + DEF(ld8s_i64, 1, 1, 1, IMPL64) +diff --git a/tcg/tcg.c b/tcg/tcg.c +index c002a88..24ce830 100644 +--- a/tcg/tcg.c ++++ b/tcg/tcg.c +@@ -991,16 +991,15 @@ void tcg_dump_ops(TCGContext *s) + } + switch (c) { + case INDEX_op_brcond_i32: +-#if TCG_TARGET_REG_BITS == 32 +- case INDEX_op_brcond2_i32: +-#elif TCG_TARGET_REG_BITS == 64 +- case INDEX_op_brcond_i64: +-#endif + case INDEX_op_setcond_i32: ++ case INDEX_op_movcond_i32: + #if TCG_TARGET_REG_BITS == 32 ++ case INDEX_op_brcond2_i32: + case INDEX_op_setcond2_i32: +-#elif TCG_TARGET_REG_BITS == 64 ++#else ++ case INDEX_op_brcond_i64: + case INDEX_op_setcond_i64: ++ case INDEX_op_movcond_i64: + #endif + if (args[k] < ARRAY_SIZE(cond_name) && cond_name[args[k]]) { + qemu_log(",%s", cond_name[args[k++]]); +diff --git a/tcg/tcg.h b/tcg/tcg.h +index 8fbbc81..f454107 100644 +--- a/tcg/tcg.h ++++ b/tcg/tcg.h +@@ -79,6 +79,7 @@ typedef uint64_t TCGRegSet; + #define TCG_TARGET_HAS_nand_i64 0 + #define TCG_TARGET_HAS_nor_i64 0 + #define TCG_TARGET_HAS_deposit_i64 0 ++#define TCG_TARGET_HAS_movcond_i64 0 + #endif + + #ifndef TCG_TARGET_deposit_i32_valid +diff --git a/tcg/tci/tcg-target.h b/tcg/tci/tcg-target.h +index 30a0f21..6d89495 100644 +--- a/tcg/tci/tcg-target.h ++++ b/tcg/tci/tcg-target.h +@@ -75,6 +75,7 @@ + #define TCG_TARGET_HAS_not_i32 1 + #define TCG_TARGET_HAS_orc_i32 0 + #define TCG_TARGET_HAS_rot_i32 1 ++#define TCG_TARGET_HAS_movcond_i32 0 + + #if TCG_TARGET_REG_BITS == 64 + #define TCG_TARGET_HAS_bswap16_i64 1 +@@ -98,6 +99,7 @@ + #define TCG_TARGET_HAS_not_i64 1 + #define TCG_TARGET_HAS_orc_i64 0 + #define TCG_TARGET_HAS_rot_i64 1 ++#define TCG_TARGET_HAS_movcond_i64 0 + #endif /* TCG_TARGET_REG_BITS == 64 */ + + /* Offset to user memory in user mode. */ +-- +1.7.12.1 + diff --git a/0050-target-alpha-Use-movcond.patch b/0050-target-alpha-Use-movcond.patch new file mode 100644 index 0000000..0bd5272 --- /dev/null +++ b/0050-target-alpha-Use-movcond.patch @@ -0,0 +1,160 @@ +From 4bf321d3f494134fe2e03c9cbc042e28ec3a1045 Mon Sep 17 00:00:00 2001 +From: Richard Henderson +Date: Fri, 21 Sep 2012 10:13:35 -0700 +Subject: [PATCH] target-alpha: Use movcond + +For proper cmov insns, as well as the non-goto-tb case +of conditional branch. + +Signed-off-by: Richard Henderson +Signed-off-by: Aurelien Jarno +Signed-off-by: Michael Roth +--- + target-alpha/translate.c | 102 ++++++++++++++++++++++------------------------- + 1 file changed, 48 insertions(+), 54 deletions(-) + +diff --git a/target-alpha/translate.c b/target-alpha/translate.c +index 12de6a3..4a9011a 100644 +--- a/target-alpha/translate.c ++++ b/target-alpha/translate.c +@@ -426,27 +426,15 @@ static ExitStatus gen_bcond_internal(DisasContext *ctx, TCGCond cond, + + return EXIT_GOTO_TB; + } else { +- int lab_over = gen_new_label(); +- +- /* ??? Consider using either +- movi pc, next +- addi tmp, pc, disp +- movcond pc, cond, 0, tmp, pc +- or +- setcond tmp, cond, 0 +- movi pc, next +- neg tmp, tmp +- andi tmp, tmp, disp +- add pc, pc, tmp +- The current diamond subgraph surely isn't efficient. */ ++ TCGv_i64 z = tcg_const_i64(0); ++ TCGv_i64 d = tcg_const_i64(dest); ++ TCGv_i64 p = tcg_const_i64(ctx->pc); + +- tcg_gen_brcondi_i64(cond, cmp, 0, lab_true); +- tcg_gen_movi_i64(cpu_pc, ctx->pc); +- tcg_gen_br(lab_over); +- gen_set_label(lab_true); +- tcg_gen_movi_i64(cpu_pc, dest); +- gen_set_label(lab_over); ++ tcg_gen_movcond_i64(cond, cpu_pc, cmp, z, d, p); + ++ tcg_temp_free_i64(z); ++ tcg_temp_free_i64(d); ++ tcg_temp_free_i64(p); + return EXIT_PC_UPDATED; + } + } +@@ -521,61 +509,67 @@ static ExitStatus gen_fbcond(DisasContext *ctx, TCGCond cond, int ra, + static void gen_cmov(TCGCond cond, int ra, int rb, int rc, + int islit, uint8_t lit, int mask) + { +- TCGCond inv_cond = tcg_invert_cond(cond); +- int l1; ++ TCGv_i64 c1, z, v1; + +- if (unlikely(rc == 31)) ++ if (unlikely(rc == 31)) { + return; ++ } + +- l1 = gen_new_label(); +- +- if (ra != 31) { +- if (mask) { +- TCGv tmp = tcg_temp_new(); +- tcg_gen_andi_i64(tmp, cpu_ir[ra], 1); +- tcg_gen_brcondi_i64(inv_cond, tmp, 0, l1); +- tcg_temp_free(tmp); +- } else +- tcg_gen_brcondi_i64(inv_cond, cpu_ir[ra], 0, l1); +- } else { ++ if (ra == 31) { + /* Very uncommon case - Do not bother to optimize. */ +- TCGv tmp = tcg_const_i64(0); +- tcg_gen_brcondi_i64(inv_cond, tmp, 0, l1); +- tcg_temp_free(tmp); ++ c1 = tcg_const_i64(0); ++ } else if (mask) { ++ c1 = tcg_const_i64(1); ++ tcg_gen_and_i64(c1, c1, cpu_ir[ra]); ++ } else { ++ c1 = cpu_ir[ra]; + } ++ if (islit) { ++ v1 = tcg_const_i64(lit); ++ } else { ++ v1 = cpu_ir[rb]; ++ } ++ z = tcg_const_i64(0); + +- if (islit) +- tcg_gen_movi_i64(cpu_ir[rc], lit); +- else +- tcg_gen_mov_i64(cpu_ir[rc], cpu_ir[rb]); +- gen_set_label(l1); ++ tcg_gen_movcond_i64(cond, cpu_ir[rc], c1, z, v1, cpu_ir[rc]); ++ ++ tcg_temp_free_i64(z); ++ if (ra == 31 || mask) { ++ tcg_temp_free_i64(c1); ++ } ++ if (islit) { ++ tcg_temp_free_i64(v1); ++ } + } + + static void gen_fcmov(TCGCond cond, int ra, int rb, int rc) + { +- TCGv cmp_tmp; +- int l1; ++ TCGv_i64 c1, z, v1; + + if (unlikely(rc == 31)) { + return; + } + +- cmp_tmp = tcg_temp_new(); ++ c1 = tcg_temp_new_i64(); + if (unlikely(ra == 31)) { +- tcg_gen_movi_i64(cmp_tmp, 0); ++ tcg_gen_movi_i64(c1, 0); ++ } else { ++ gen_fold_mzero(cond, c1, cpu_fir[ra]); ++ } ++ if (rb == 31) { ++ v1 = tcg_const_i64(0); + } else { +- gen_fold_mzero(cond, cmp_tmp, cpu_fir[ra]); ++ v1 = cpu_fir[rb]; + } ++ z = tcg_const_i64(0); + +- l1 = gen_new_label(); +- tcg_gen_brcondi_i64(tcg_invert_cond(cond), cmp_tmp, 0, l1); +- tcg_temp_free(cmp_tmp); ++ tcg_gen_movcond_i64(cond, cpu_fir[rc], c1, z, v1, cpu_fir[rc]); + +- if (rb != 31) +- tcg_gen_mov_i64(cpu_fir[rc], cpu_fir[rb]); +- else +- tcg_gen_movi_i64(cpu_fir[rc], 0); +- gen_set_label(l1); ++ tcg_temp_free_i64(z); ++ tcg_temp_free_i64(c1); ++ if (rb == 31) { ++ tcg_temp_free_i64(v1); ++ } + } + + #define QUAL_RM_N 0x080 /* Round mode nearest even */ +-- +1.7.12.1 + diff --git a/0051-tcg-i386-Implement-movcond.patch b/0051-tcg-i386-Implement-movcond.patch new file mode 100644 index 0000000..4d3983f --- /dev/null +++ b/0051-tcg-i386-Implement-movcond.patch @@ -0,0 +1,118 @@ +From 7a6273e2995b6c439441316467ab19bd6a48f03f Mon Sep 17 00:00:00 2001 +From: Richard Henderson +Date: Fri, 21 Sep 2012 10:13:36 -0700 +Subject: [PATCH] tcg-i386: Implement movcond + +Signed-off-by: Richard Henderson +Reviewed-by: Aurelien Jarno +Signed-off-by: Aurelien Jarno +Signed-off-by: Michael Roth +--- + tcg/i386/tcg-target.c | 29 +++++++++++++++++++++++++++++ + tcg/i386/tcg-target.h | 7 ++++++- + 2 files changed, 35 insertions(+), 1 deletion(-) + +diff --git a/tcg/i386/tcg-target.c b/tcg/i386/tcg-target.c +index 3017858..aa1fa9f 100644 +--- a/tcg/i386/tcg-target.c ++++ b/tcg/i386/tcg-target.c +@@ -249,6 +249,7 @@ static inline int tcg_target_const_match(tcg_target_long val, + #define OPC_ADD_GvEv (OPC_ARITH_GvEv | (ARITH_ADD << 3)) + #define OPC_BSWAP (0xc8 | P_EXT) + #define OPC_CALL_Jz (0xe8) ++#define OPC_CMOVCC (0x40 | P_EXT) /* ... plus condition code */ + #define OPC_CMP_GvEv (OPC_ARITH_GvEv | (ARITH_CMP << 3)) + #define OPC_DEC_r32 (0x48) + #define OPC_IMUL_GvEv (0xaf | P_EXT) +@@ -936,6 +937,24 @@ static void tcg_out_setcond2(TCGContext *s, const TCGArg *args, + } + #endif + ++static void tcg_out_movcond32(TCGContext *s, TCGCond cond, TCGArg dest, ++ TCGArg c1, TCGArg c2, int const_c2, ++ TCGArg v1) ++{ ++ tcg_out_cmp(s, c1, c2, const_c2, 0); ++ tcg_out_modrm(s, OPC_CMOVCC | tcg_cond_to_jcc[cond], dest, v1); ++} ++ ++#if TCG_TARGET_REG_BITS == 64 ++static void tcg_out_movcond64(TCGContext *s, TCGCond cond, TCGArg dest, ++ TCGArg c1, TCGArg c2, int const_c2, ++ TCGArg v1) ++{ ++ tcg_out_cmp(s, c1, c2, const_c2, P_REXW); ++ tcg_out_modrm(s, OPC_CMOVCC | tcg_cond_to_jcc[cond] | P_REXW, dest, v1); ++} ++#endif ++ + static void tcg_out_branch(TCGContext *s, int call, tcg_target_long dest) + { + tcg_target_long disp = dest - (tcg_target_long)s->code_ptr - 5; +@@ -1668,6 +1687,10 @@ static inline void tcg_out_op(TCGContext *s, TCGOpcode opc, + tcg_out_setcond32(s, args[3], args[0], args[1], + args[2], const_args[2]); + break; ++ case INDEX_op_movcond_i32: ++ tcg_out_movcond32(s, args[5], args[0], args[1], ++ args[2], const_args[2], args[3]); ++ break; + + OP_32_64(bswap16): + tcg_out_rolw_8(s, args[0]); +@@ -1796,6 +1819,10 @@ static inline void tcg_out_op(TCGContext *s, TCGOpcode opc, + tcg_out_setcond64(s, args[3], args[0], args[1], + args[2], const_args[2]); + break; ++ case INDEX_op_movcond_i64: ++ tcg_out_movcond64(s, args[5], args[0], args[1], ++ args[2], const_args[2], args[3]); ++ break; + + case INDEX_op_bswap64_i64: + tcg_out_bswap64(s, args[0]); +@@ -1880,6 +1907,7 @@ static const TCGTargetOpDef x86_op_defs[] = { + { INDEX_op_setcond_i32, { "q", "r", "ri" } }, + + { INDEX_op_deposit_i32, { "Q", "0", "Q" } }, ++ { INDEX_op_movcond_i32, { "r", "r", "ri", "r", "0" } }, + + #if TCG_TARGET_REG_BITS == 32 + { INDEX_op_mulu2_i32, { "a", "d", "a", "r" } }, +@@ -1934,6 +1962,7 @@ static const TCGTargetOpDef x86_op_defs[] = { + { INDEX_op_ext32u_i64, { "r", "r" } }, + + { INDEX_op_deposit_i64, { "Q", "0", "Q" } }, ++ { INDEX_op_movcond_i64, { "r", "r", "re", "r", "0" } }, + #endif + + #if TCG_TARGET_REG_BITS == 64 +diff --git a/tcg/i386/tcg-target.h b/tcg/i386/tcg-target.h +index 504f953..b356d76 100644 +--- a/tcg/i386/tcg-target.h ++++ b/tcg/i386/tcg-target.h +@@ -86,7 +86,12 @@ typedef enum { + #define TCG_TARGET_HAS_nand_i32 0 + #define TCG_TARGET_HAS_nor_i32 0 + #define TCG_TARGET_HAS_deposit_i32 1 ++#if defined(__x86_64__) || defined(__i686__) ++/* Use cmov only if the compiler is already doing so. */ ++#define TCG_TARGET_HAS_movcond_i32 1 ++#else + #define TCG_TARGET_HAS_movcond_i32 0 ++#endif + + #if TCG_TARGET_REG_BITS == 64 + #define TCG_TARGET_HAS_div2_i64 1 +@@ -108,7 +113,7 @@ typedef enum { + #define TCG_TARGET_HAS_nand_i64 0 + #define TCG_TARGET_HAS_nor_i64 0 + #define TCG_TARGET_HAS_deposit_i64 1 +-#define TCG_TARGET_HAS_movcond_i64 0 ++#define TCG_TARGET_HAS_movcond_i64 1 + #endif + + #define TCG_TARGET_deposit_i32_valid(ofs, len) \ +-- +1.7.12.1 + diff --git a/0052-tcg-Optimize-movcond-for-constant-comparisons.patch b/0052-tcg-Optimize-movcond-for-constant-comparisons.patch new file mode 100644 index 0000000..ce0f00b --- /dev/null +++ b/0052-tcg-Optimize-movcond-for-constant-comparisons.patch @@ -0,0 +1,73 @@ +From c489b380d3f827be91b5f8b80b88585fb4014fbb Mon Sep 17 00:00:00 2001 +From: Richard Henderson +Date: Fri, 21 Sep 2012 10:13:37 -0700 +Subject: [PATCH] tcg: Optimize movcond for constant comparisons + +Signed-off-by: Richard Henderson +Signed-off-by: Aurelien Jarno +Signed-off-by: Michael Roth +--- + tcg/optimize.c | 40 ++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 40 insertions(+) + +diff --git a/tcg/optimize.c b/tcg/optimize.c +index 9da333c..26038a6 100644 +--- a/tcg/optimize.c ++++ b/tcg/optimize.c +@@ -394,6 +394,14 @@ static TCGArg *tcg_constant_folding(TCGContext *s, uint16_t *tcg_opc_ptr, + args[3] = tcg_swap_cond(args[3]); + } + break; ++ CASE_OP_32_64(movcond): ++ 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; ++ args[5] = tcg_swap_cond(args[5]); ++ } + default: + break; + } +@@ -614,6 +622,38 @@ static TCGArg *tcg_constant_folding(TCGContext *s, uint16_t *tcg_opc_ptr, + } + args += 4; + break; ++ CASE_OP_32_64(movcond): ++ if (temps[args[1]].state == TCG_TEMP_CONST ++ && temps[args[2]].state == TCG_TEMP_CONST) { ++ tmp = do_constant_folding_cond(op, temps[args[1]].val, ++ temps[args[2]].val, args[5]); ++ if (args[0] == args[4-tmp] ++ || (temps[args[4-tmp]].state == TCG_TEMP_COPY ++ && temps[args[4-tmp]].val == args[0])) { ++ gen_opc_buf[op_index] = INDEX_op_nop; ++ } else if (temps[args[4-tmp]].state == TCG_TEMP_CONST) { ++ gen_opc_buf[op_index] = op_to_movi(op); ++ tcg_opt_gen_movi(gen_args, args[0], temps[args[4-tmp]].val, ++ nb_temps, nb_globals); ++ gen_args += 2; ++ } else { ++ gen_opc_buf[op_index] = op_to_mov(op); ++ tcg_opt_gen_mov(gen_args, args[0], args[4-tmp], ++ nb_temps, nb_globals); ++ gen_args += 2; ++ } ++ } else { ++ reset_temp(args[0], nb_temps, nb_globals); ++ 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; + 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))) { +-- +1.7.12.1 + diff --git a/0053-tcg-Optimize-two-address-commutative-operations.patch b/0053-tcg-Optimize-two-address-commutative-operations.patch new file mode 100644 index 0000000..adacbb8 --- /dev/null +++ b/0053-tcg-Optimize-two-address-commutative-operations.patch @@ -0,0 +1,57 @@ +From af2bf6bcc6614622c87d28e9d763b57408c17500 Mon Sep 17 00:00:00 2001 +From: Richard Henderson +Date: Fri, 21 Sep 2012 10:13:38 -0700 +Subject: [PATCH] tcg: Optimize two-address commutative operations + +While swapping constants to the second operand, swap +sources matching destinations to the first operand. + +Signed-off-by: Richard Henderson +Signed-off-by: Aurelien Jarno +Signed-off-by: Michael Roth +--- + tcg/optimize.c | 15 ++++++++++++++- + 1 file changed, 14 insertions(+), 1 deletion(-) + +diff --git a/tcg/optimize.c b/tcg/optimize.c +index 26038a6..1be7631 100644 +--- a/tcg/optimize.c ++++ b/tcg/optimize.c +@@ -334,6 +334,8 @@ 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. + If this temp is a copy of other ones then this equivalence class' +@@ -395,13 +397,24 @@ static TCGArg *tcg_constant_folding(TCGContext *s, uint16_t *tcg_opc_ptr, + } + 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; +- args[5] = tcg_swap_cond(args[5]); ++ cond = tcg_swap_cond(cond); ++ } ++ /* 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); + } ++ args[5] = cond; + default: + break; + } +-- +1.7.12.1 + diff --git a/0054-gdbstub-sh4-fix-build-with-USE_SOFTFLOAT_STRUCT_TYPE.patch b/0054-gdbstub-sh4-fix-build-with-USE_SOFTFLOAT_STRUCT_TYPE.patch new file mode 100644 index 0000000..250f893 --- /dev/null +++ b/0054-gdbstub-sh4-fix-build-with-USE_SOFTFLOAT_STRUCT_TYPE.patch @@ -0,0 +1,192 @@ +From b6407e30c30268cdeddec6e2b115f419647cc07f Mon Sep 17 00:00:00 2001 +From: Aurelien Jarno +Date: Sun, 16 Sep 2012 13:12:21 +0200 +Subject: [PATCH] gdbstub/sh4: fix build with USE_SOFTFLOAT_STRUCT_TYPES + +We have to use different type to access float values when +USE_SOFTFLOAT_STRUCT_TYPES is defined. + +Rework SH4 version of cpu_gdb_{read,write}_register() using +a single case, and fixing the coding style. Use ldll_p() and +stfl_p() to access float values. + +Signed-off-by: Aurelien Jarno +Signed-off-by: Michael Roth +--- + gdbstub.c | 144 +++++++++++++++++++++++++++++++++++++++----------------------- + 1 file changed, 90 insertions(+), 54 deletions(-) + +diff --git a/gdbstub.c b/gdbstub.c +index 5d37dd9..a91709f 100644 +--- a/gdbstub.c ++++ b/gdbstub.c +@@ -1226,33 +1226,48 @@ static int cpu_gdb_write_register(CPUOpenRISCState *env, + + static int cpu_gdb_read_register(CPUSH4State *env, uint8_t *mem_buf, int n) + { +- if (n < 8) { ++ switch (n) { ++ case 0 ... 7: + if ((env->sr & (SR_MD | SR_RB)) == (SR_MD | SR_RB)) { + GET_REGL(env->gregs[n + 16]); + } else { + GET_REGL(env->gregs[n]); + } +- } else if (n < 16) { ++ case 8 ... 15: + GET_REGL(env->gregs[n]); +- } else if (n >= 25 && n < 41) { +- GET_REGL(env->fregs[(n - 25) + ((env->fpscr & FPSCR_FR) ? 16 : 0)]); +- } else if (n >= 43 && n < 51) { +- GET_REGL(env->gregs[n - 43]); +- } else if (n >= 51 && n < 59) { +- GET_REGL(env->gregs[n - (51 - 16)]); +- } +- switch (n) { +- case 16: GET_REGL(env->pc); +- case 17: GET_REGL(env->pr); +- case 18: GET_REGL(env->gbr); +- case 19: GET_REGL(env->vbr); +- case 20: GET_REGL(env->mach); +- case 21: GET_REGL(env->macl); +- case 22: GET_REGL(env->sr); +- case 23: GET_REGL(env->fpul); +- case 24: GET_REGL(env->fpscr); +- case 41: GET_REGL(env->ssr); +- case 42: GET_REGL(env->spc); ++ case 16: ++ GET_REGL(env->pc); ++ case 17: ++ GET_REGL(env->pr); ++ case 18: ++ GET_REGL(env->gbr); ++ case 19: ++ GET_REGL(env->vbr); ++ case 20: ++ GET_REGL(env->mach); ++ case 21: ++ GET_REGL(env->macl); ++ case 22: ++ GET_REGL(env->sr); ++ case 23: ++ GET_REGL(env->fpul); ++ case 24: ++ GET_REGL(env->fpscr); ++ case 25 ... 40: ++ if (env->fpscr & FPSCR_FR) { ++ stfl_p(mem_buf, env->fregs[n - 9]); ++ } else { ++ stfl_p(mem_buf, env->fregs[n - 25]); ++ } ++ return 4; ++ case 41: ++ GET_REGL(env->ssr); ++ case 42: ++ GET_REGL(env->spc); ++ case 43 ... 50: ++ GET_REGL(env->gregs[n - 43]); ++ case 51 ... 58: ++ GET_REGL(env->gregs[n - (51 - 16)]); + } + + return 0; +@@ -1260,42 +1275,63 @@ static int cpu_gdb_read_register(CPUSH4State *env, uint8_t *mem_buf, int n) + + static int cpu_gdb_write_register(CPUSH4State *env, uint8_t *mem_buf, int n) + { +- uint32_t tmp; +- +- tmp = ldl_p(mem_buf); +- +- if (n < 8) { ++ switch (n) { ++ case 0 ... 7: + if ((env->sr & (SR_MD | SR_RB)) == (SR_MD | SR_RB)) { +- env->gregs[n + 16] = tmp; ++ env->gregs[n + 16] = ldl_p(mem_buf); + } else { +- env->gregs[n] = tmp; ++ env->gregs[n] = ldl_p(mem_buf); + } +- return 4; +- } else if (n < 16) { +- env->gregs[n] = tmp; +- return 4; +- } else if (n >= 25 && n < 41) { +- env->fregs[(n - 25) + ((env->fpscr & FPSCR_FR) ? 16 : 0)] = tmp; +- return 4; +- } else if (n >= 43 && n < 51) { +- env->gregs[n - 43] = tmp; +- return 4; +- } else if (n >= 51 && n < 59) { +- env->gregs[n - (51 - 16)] = tmp; +- return 4; +- } +- switch (n) { +- case 16: env->pc = tmp; break; +- case 17: env->pr = tmp; break; +- case 18: env->gbr = tmp; break; +- case 19: env->vbr = tmp; break; +- case 20: env->mach = tmp; break; +- case 21: env->macl = tmp; break; +- case 22: env->sr = tmp; break; +- case 23: env->fpul = tmp; break; +- case 24: env->fpscr = tmp; break; +- case 41: env->ssr = tmp; break; +- case 42: env->spc = tmp; break; ++ break; ++ case 8 ... 15: ++ env->gregs[n] = ldl_p(mem_buf); ++ break; ++ case 16: ++ env->pc = ldl_p(mem_buf); ++ break; ++ case 17: ++ env->pr = ldl_p(mem_buf); ++ break; ++ case 18: ++ env->gbr = ldl_p(mem_buf); ++ break; ++ case 19: ++ env->vbr = ldl_p(mem_buf); ++ break; ++ case 20: ++ env->mach = ldl_p(mem_buf); ++ break; ++ case 21: ++ env->macl = ldl_p(mem_buf); ++ break; ++ case 22: ++ env->sr = ldl_p(mem_buf); ++ break; ++ case 23: ++ env->fpul = ldl_p(mem_buf); ++ break; ++ case 24: ++ env->fpscr = ldl_p(mem_buf); ++ break; ++ case 25 ... 40: ++ if (env->fpscr & FPSCR_FR) { ++ env->fregs[n - 9] = ldfl_p(mem_buf); ++ } else { ++ env->fregs[n - 25] = ldfl_p(mem_buf); ++ } ++ break; ++ case 41: ++ env->ssr = ldl_p(mem_buf); ++ break; ++ case 42: ++ env->spc = ldl_p(mem_buf); ++ break; ++ case 43 ... 50: ++ env->gregs[n - 43] = ldl_p(mem_buf); ++ break; ++ case 51 ... 58: ++ env->gregs[n - (51 - 16)] = ldl_p(mem_buf); ++ break; + default: return 0; + } + +-- +1.7.12.1 + diff --git a/0055-tcg-Fix-USE_DIRECT_JUMP.patch b/0055-tcg-Fix-USE_DIRECT_JUMP.patch new file mode 100644 index 0000000..3f88ee8 --- /dev/null +++ b/0055-tcg-Fix-USE_DIRECT_JUMP.patch @@ -0,0 +1,35 @@ +From 03ddebf0c48dc78070c846b7cfdc2665fe7df854 Mon Sep 17 00:00:00 2001 +From: Richard Henderson +Date: Mon, 17 Sep 2012 08:28:52 -0700 +Subject: [PATCH] tcg: Fix !USE_DIRECT_JUMP +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Commit 6375e09e changed the type of TranslationBlock.tb_next, +but failed to change the type of TCGContext.tb_next. + +Signed-off-by: Richard Henderson +Reviewed-by: Andreas Färber +Signed-off-by: Aurelien Jarno +Signed-off-by: Michael Roth +--- + tcg/tcg.h | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/tcg/tcg.h b/tcg/tcg.h +index f454107..609ed86 100644 +--- a/tcg/tcg.h ++++ b/tcg/tcg.h +@@ -344,7 +344,7 @@ struct TCGContext { + + /* goto_tb support */ + uint8_t *code_buf; +- unsigned long *tb_next; ++ uintptr_t *tb_next; + uint16_t *tb_next_offset; + uint16_t *tb_jmp_offset; /* != NULL if USE_DIRECT_JUMP */ + +-- +1.7.12.1 + diff --git a/0056-tcg-hppa-Fix-brcond2-and-setcond2.patch b/0056-tcg-hppa-Fix-brcond2-and-setcond2.patch new file mode 100644 index 0000000..fa1f7cb --- /dev/null +++ b/0056-tcg-hppa-Fix-brcond2-and-setcond2.patch @@ -0,0 +1,108 @@ +From 3616400bc0065f7114172ad7801d9d88332ef981 Mon Sep 17 00:00:00 2001 +From: Richard Henderson +Date: Tue, 18 Sep 2012 19:59:47 -0700 +Subject: [PATCH] tcg-hppa: Fix brcond2 and setcond2 + +Neither of these functions were performing double-word +compares properly. + +Signed-off-by: Richard Henderson +Signed-off-by: Aurelien Jarno +Signed-off-by: Michael Roth +--- + tcg/hppa/tcg-target.c | 51 ++++++++++++++++++++++++++++++++++++++++++--------- + 1 file changed, 42 insertions(+), 9 deletions(-) + +diff --git a/tcg/hppa/tcg-target.c b/tcg/hppa/tcg-target.c +index 8b81b70..a76569d 100644 +--- a/tcg/hppa/tcg-target.c ++++ b/tcg/hppa/tcg-target.c +@@ -820,19 +820,34 @@ static void tcg_out_comclr(TCGContext *s, int cond, TCGArg ret, + tcg_out32(s, op); + } + ++static TCGCond const tcg_high_cond[] = { ++ [TCG_COND_EQ] = TCG_COND_EQ, ++ [TCG_COND_NE] = TCG_COND_NE, ++ [TCG_COND_LT] = TCG_COND_LT, ++ [TCG_COND_LE] = TCG_COND_LT, ++ [TCG_COND_GT] = TCG_COND_GT, ++ [TCG_COND_GE] = TCG_COND_GT, ++ [TCG_COND_LTU] = TCG_COND_LTU, ++ [TCG_COND_LEU] = TCG_COND_LTU, ++ [TCG_COND_GTU] = TCG_COND_GTU, ++ [TCG_COND_GEU] = TCG_COND_GTU ++}; ++ + static void tcg_out_brcond2(TCGContext *s, int cond, TCGArg al, TCGArg ah, + TCGArg bl, int blconst, TCGArg bh, int bhconst, + int label_index) + { + switch (cond) { + case TCG_COND_EQ: ++ tcg_out_comclr(s, TCG_COND_NE, TCG_REG_R0, al, bl, blconst); ++ tcg_out_brcond(s, TCG_COND_EQ, ah, bh, bhconst, label_index); ++ break; + case TCG_COND_NE: +- tcg_out_comclr(s, tcg_invert_cond(cond), TCG_REG_R0, al, bl, blconst); +- tcg_out_brcond(s, cond, ah, bh, bhconst, label_index); ++ tcg_out_brcond(s, TCG_COND_NE, al, bl, bhconst, label_index); ++ tcg_out_brcond(s, TCG_COND_NE, ah, bh, bhconst, label_index); + break; +- + default: +- tcg_out_brcond(s, cond, ah, bh, bhconst, label_index); ++ tcg_out_brcond(s, tcg_high_cond[cond], ah, bh, bhconst, label_index); + tcg_out_comclr(s, TCG_COND_NE, TCG_REG_R0, ah, bh, bhconst); + tcg_out_brcond(s, tcg_unsigned_cond(cond), + al, bl, blconst, label_index); +@@ -853,9 +868,8 @@ static void tcg_out_setcond2(TCGContext *s, int cond, TCGArg ret, + { + int scratch = TCG_REG_R20; + +- if (ret != al && ret != ah +- && (blconst || ret != bl) +- && (bhconst || ret != bh)) { ++ /* Note that the low parts are fully consumed before scratch is set. */ ++ if (ret != ah && (bhconst || ret != bh)) { + scratch = ret; + } + +@@ -867,13 +881,32 @@ static void tcg_out_setcond2(TCGContext *s, int cond, TCGArg ret, + tcg_out_movi(s, TCG_TYPE_I32, scratch, cond == TCG_COND_NE); + break; + +- default: ++ case TCG_COND_GE: ++ case TCG_COND_GEU: ++ case TCG_COND_LT: ++ case TCG_COND_LTU: ++ /* Optimize compares with low part zero. */ ++ if (bl == 0) { ++ tcg_out_setcond(s, cond, ret, ah, bh, bhconst); ++ return; ++ } ++ /* FALLTHRU */ ++ ++ case TCG_COND_LE: ++ case TCG_COND_LEU: ++ case TCG_COND_GT: ++ case TCG_COND_GTU: ++ /* <= : ah < bh | (ah == bh && al <= bl) */ + tcg_out_setcond(s, tcg_unsigned_cond(cond), scratch, al, bl, blconst); + tcg_out_comclr(s, TCG_COND_EQ, TCG_REG_R0, ah, bh, bhconst); + tcg_out_movi(s, TCG_TYPE_I32, scratch, 0); +- tcg_out_comclr(s, cond, TCG_REG_R0, ah, bh, bhconst); ++ tcg_out_comclr(s, tcg_invert_cond(tcg_high_cond[cond]), ++ TCG_REG_R0, ah, bh, bhconst); + tcg_out_movi(s, TCG_TYPE_I32, scratch, 1); + break; ++ ++ default: ++ tcg_abort(); + } + + tcg_out_mov(s, TCG_TYPE_I32, ret, scratch); +-- +1.7.12.1 + diff --git a/0057-tcg-hppa-Fix-broken-load-store-helpers.patch b/0057-tcg-hppa-Fix-broken-load-store-helpers.patch new file mode 100644 index 0000000..3666a95 --- /dev/null +++ b/0057-tcg-hppa-Fix-broken-load-store-helpers.patch @@ -0,0 +1,249 @@ +From c13ecfea174994d3f7f7d392f0faaed6d40efd9e Mon Sep 17 00:00:00 2001 +From: Richard Henderson +Date: Tue, 18 Sep 2012 19:59:48 -0700 +Subject: [PATCH] tcg-hppa: Fix broken load/store helpers + +The CONFIG_TCG_PASS_AREG0 code for calling ld/st helpers +was not respecting the ABI requirement for 64-bit values +being aligned in registers. + +Mirror the ARM port in use of helper functions to marshal +arguments into the correct registers. + +Signed-off-by: Richard Henderson +Signed-off-by: Aurelien Jarno +Signed-off-by: Michael Roth +--- + tcg/hppa/tcg-target.c | 136 +++++++++++++++++++++++++++----------------------- + 1 file changed, 74 insertions(+), 62 deletions(-) + +diff --git a/tcg/hppa/tcg-target.c b/tcg/hppa/tcg-target.c +index a76569d..5385d45 100644 +--- a/tcg/hppa/tcg-target.c ++++ b/tcg/hppa/tcg-target.c +@@ -976,10 +976,11 @@ static int tcg_out_tlb_read(TCGContext *s, int r0, int r1, int addrlo, + tcg_out_ld(s, TCG_TYPE_PTR, TCG_REG_R20, r1, offset); + } + +- /* Compute the value that ought to appear in the TLB for a hit, namely, the page +- of the address. We include the low N bits of the address to catch unaligned +- accesses and force them onto the slow path. Do this computation after having +- issued the load from the TLB slot to give the load time to complete. */ ++ /* Compute the value that ought to appear in the TLB for a hit, namely, ++ the page of the address. We include the low N bits of the address ++ to catch unaligned accesses and force them onto the slow path. Do ++ this computation after having issued the load from the TLB slot to ++ give the load time to complete. */ + tcg_out_andi(s, r0, addrlo, TARGET_PAGE_MASK | ((1 << s_bits) - 1)); + + /* If not equal, jump to lab_miss. */ +@@ -992,6 +993,36 @@ static int tcg_out_tlb_read(TCGContext *s, int r0, int r1, int addrlo, + + return ret; + } ++ ++static int tcg_out_arg_reg32(TCGContext *s, int argno, TCGArg v, bool vconst) ++{ ++ if (argno < 4) { ++ if (vconst) { ++ tcg_out_movi(s, TCG_TYPE_I32, tcg_target_call_iarg_regs[argno], v); ++ } else { ++ tcg_out_mov(s, TCG_TYPE_I32, tcg_target_call_iarg_regs[argno], v); ++ } ++ } else { ++ if (vconst && v != 0) { ++ tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_R20, v); ++ v = TCG_REG_R20; ++ } ++ tcg_out_st(s, TCG_TYPE_I32, v, TCG_REG_CALL_STACK, ++ TCG_TARGET_CALL_STACK_OFFSET - ((argno - 3) * 4)); ++ } ++ return argno + 1; ++} ++ ++static int tcg_out_arg_reg64(TCGContext *s, int argno, TCGArg vl, TCGArg vh) ++{ ++ /* 64-bit arguments must go in even reg pairs and stack slots. */ ++ if (argno & 1) { ++ argno++; ++ } ++ argno = tcg_out_arg_reg32(s, argno, vl, false); ++ argno = tcg_out_arg_reg32(s, argno, vh, false); ++ return argno; ++} + #endif + + static void tcg_out_qemu_ld_direct(TCGContext *s, int datalo_reg, int datahi_reg, +@@ -1072,39 +1103,36 @@ static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args, int opc) + /* Note that addrhi_reg is only used for 64-bit guests. */ + int addrhi_reg = (TARGET_LONG_BITS == 64 ? *args++ : TCG_REG_R0); + int mem_index = *args; +- int lab1, lab2, argreg, offset; ++ int lab1, lab2, argno, offset; + + lab1 = gen_new_label(); + lab2 = gen_new_label(); + + offset = offsetof(CPUArchState, tlb_table[mem_index][0].addr_read); +- offset = tcg_out_tlb_read(s, TCG_REG_R26, TCG_REG_R25, addrlo_reg, addrhi_reg, +- opc & 3, lab1, offset); ++ offset = tcg_out_tlb_read(s, TCG_REG_R26, TCG_REG_R25, addrlo_reg, ++ addrhi_reg, opc & 3, lab1, offset); + + /* TLB Hit. */ +- tcg_out_ld(s, TCG_TYPE_PTR, TCG_REG_R20, (offset ? TCG_REG_R1 : TCG_REG_R25), ++ tcg_out_ld(s, TCG_TYPE_PTR, TCG_REG_R20, ++ (offset ? TCG_REG_R1 : TCG_REG_R25), + offsetof(CPUArchState, tlb_table[mem_index][0].addend) - offset); +- tcg_out_qemu_ld_direct(s, datalo_reg, datahi_reg, addrlo_reg, TCG_REG_R20, opc); ++ tcg_out_qemu_ld_direct(s, datalo_reg, datahi_reg, addrlo_reg, ++ TCG_REG_R20, opc); + tcg_out_branch(s, lab2, 1); + + /* TLB Miss. */ + /* label1: */ + tcg_out_label(s, lab1, s->code_ptr); + +- argreg = TCG_REG_R26; +- tcg_out_mov(s, TCG_TYPE_I32, argreg--, addrlo_reg); ++ argno = 0; ++ argno = tcg_out_arg_reg32(s, argno, TCG_AREG0, false); + if (TARGET_LONG_BITS == 64) { +- tcg_out_mov(s, TCG_TYPE_I32, argreg--, addrhi_reg); ++ argno = tcg_out_arg_reg64(s, argno, addrlo_reg, addrhi_reg); ++ } else { ++ argno = tcg_out_arg_reg32(s, argno, addrlo_reg, false); + } +- tcg_out_movi(s, TCG_TYPE_I32, argreg, mem_index); +- +- /* XXX/FIXME: suboptimal */ +- tcg_out_mov(s, TCG_TYPE_I32, tcg_target_call_iarg_regs[2], +- tcg_target_call_iarg_regs[1]); +- tcg_out_mov(s, TCG_TYPE_TL, tcg_target_call_iarg_regs[1], +- tcg_target_call_iarg_regs[0]); +- tcg_out_mov(s, TCG_TYPE_PTR, tcg_target_call_iarg_regs[0], +- TCG_AREG0); ++ argno = tcg_out_arg_reg32(s, argno, mem_index, true); ++ + tcg_out_call(s, qemu_ld_helpers[opc & 3]); + + switch (opc) { +@@ -1140,8 +1168,8 @@ static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args, int opc) + #endif + } + +-static void tcg_out_qemu_st_direct(TCGContext *s, int datalo_reg, int datahi_reg, +- int addr_reg, int opc) ++static void tcg_out_qemu_st_direct(TCGContext *s, int datalo_reg, ++ int datahi_reg, int addr_reg, int opc) + { + #ifdef TARGET_WORDS_BIGENDIAN + const int bswap = 0; +@@ -1194,17 +1222,18 @@ static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args, int opc) + /* Note that addrhi_reg is only used for 64-bit guests. */ + int addrhi_reg = (TARGET_LONG_BITS == 64 ? *args++ : TCG_REG_R0); + int mem_index = *args; +- int lab1, lab2, argreg, offset; ++ int lab1, lab2, argno, next, offset; + + lab1 = gen_new_label(); + lab2 = gen_new_label(); + + offset = offsetof(CPUArchState, tlb_table[mem_index][0].addr_write); +- offset = tcg_out_tlb_read(s, TCG_REG_R26, TCG_REG_R25, addrlo_reg, addrhi_reg, +- opc, lab1, offset); ++ offset = tcg_out_tlb_read(s, TCG_REG_R26, TCG_REG_R25, addrlo_reg, ++ addrhi_reg, opc, lab1, offset); + + /* TLB Hit. */ +- tcg_out_ld(s, TCG_TYPE_PTR, TCG_REG_R20, (offset ? TCG_REG_R1 : TCG_REG_R25), ++ tcg_out_ld(s, TCG_TYPE_PTR, TCG_REG_R20, ++ (offset ? TCG_REG_R1 : TCG_REG_R25), + offsetof(CPUArchState, tlb_table[mem_index][0].addend) - offset); + + /* There are no indexed stores, so we must do this addition explitly. +@@ -1217,63 +1246,46 @@ static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args, int opc) + /* label1: */ + tcg_out_label(s, lab1, s->code_ptr); + +- argreg = TCG_REG_R26; +- tcg_out_mov(s, TCG_TYPE_I32, argreg--, addrlo_reg); ++ argno = 0; ++ argno = tcg_out_arg_reg32(s, argno, TCG_AREG0, false); + if (TARGET_LONG_BITS == 64) { +- tcg_out_mov(s, TCG_TYPE_I32, argreg--, addrhi_reg); ++ argno = tcg_out_arg_reg64(s, argno, addrlo_reg, addrhi_reg); ++ } else { ++ argno = tcg_out_arg_reg32(s, argno, addrlo_reg, false); + } + ++ next = (argno < 4 ? tcg_target_call_iarg_regs[argno] : TCG_REG_R20); + switch(opc) { + case 0: +- tcg_out_andi(s, argreg--, datalo_reg, 0xff); +- tcg_out_movi(s, TCG_TYPE_I32, argreg, mem_index); ++ tcg_out_andi(s, next, datalo_reg, 0xff); ++ argno = tcg_out_arg_reg32(s, argno, next, false); + break; + case 1: +- tcg_out_andi(s, argreg--, datalo_reg, 0xffff); +- tcg_out_movi(s, TCG_TYPE_I32, argreg, mem_index); ++ tcg_out_andi(s, next, datalo_reg, 0xffff); ++ argno = tcg_out_arg_reg32(s, argno, next, false); + break; + case 2: +- tcg_out_mov(s, TCG_TYPE_I32, argreg--, datalo_reg); +- tcg_out_movi(s, TCG_TYPE_I32, argreg, mem_index); ++ argno = tcg_out_arg_reg32(s, argno, datalo_reg, false); + break; + case 3: +- /* Because of the alignment required by the 64-bit data argument, +- we will always use R23/R24. Also, we will always run out of +- argument registers for storing mem_index, so that will have +- to go on the stack. */ +- if (mem_index == 0) { +- argreg = TCG_REG_R0; +- } else { +- argreg = TCG_REG_R20; +- tcg_out_movi(s, TCG_TYPE_I32, argreg, mem_index); +- } +- tcg_out_mov(s, TCG_TYPE_I32, TCG_REG_R23, datahi_reg); +- tcg_out_mov(s, TCG_TYPE_I32, TCG_REG_R24, datalo_reg); +- tcg_out_st(s, TCG_TYPE_I32, argreg, TCG_REG_CALL_STACK, +- TCG_TARGET_CALL_STACK_OFFSET - 4); ++ argno = tcg_out_arg_reg64(s, argno, datalo_reg, datahi_reg); + break; + default: + tcg_abort(); + } ++ argno = tcg_out_arg_reg32(s, argno, mem_index, true); + +- /* XXX/FIXME: suboptimal */ +- tcg_out_mov(s, TCG_TYPE_I32, tcg_target_call_iarg_regs[3], +- tcg_target_call_iarg_regs[2]); +- tcg_out_mov(s, TCG_TYPE_I64, tcg_target_call_iarg_regs[2], +- tcg_target_call_iarg_regs[1]); +- tcg_out_mov(s, TCG_TYPE_TL, tcg_target_call_iarg_regs[1], +- tcg_target_call_iarg_regs[0]); +- tcg_out_mov(s, TCG_TYPE_PTR, tcg_target_call_iarg_regs[0], +- TCG_AREG0); + tcg_out_call(s, qemu_st_helpers[opc]); + + /* label2: */ + tcg_out_label(s, lab2, s->code_ptr); + #else +- /* There are no indexed stores, so if GUEST_BASE is set we must do the add +- explicitly. Careful to avoid R20, which is used for the bswaps to follow. */ ++ /* There are no indexed stores, so if GUEST_BASE is set we must do ++ the add explicitly. Careful to avoid R20, which is used for the ++ bswaps to follow. */ + if (GUEST_BASE != 0) { +- tcg_out_arith(s, TCG_REG_R31, addrlo_reg, TCG_GUEST_BASE_REG, INSN_ADDL); ++ tcg_out_arith(s, TCG_REG_R31, addrlo_reg, ++ TCG_GUEST_BASE_REG, INSN_ADDL); + addrlo_reg = TCG_REG_R31; + } + tcg_out_qemu_st_direct(s, datalo_reg, datahi_reg, addrlo_reg, opc); +-- +1.7.12.1 + diff --git a/0058-tcg-mips-fix-wrong-usage-of-Z-constraint.patch b/0058-tcg-mips-fix-wrong-usage-of-Z-constraint.patch new file mode 100644 index 0000000..a4e1059 --- /dev/null +++ b/0058-tcg-mips-fix-wrong-usage-of-Z-constraint.patch @@ -0,0 +1,65 @@ +From 061d22ad76512e8ec10af89eda1dcc7c185360d2 Mon Sep 17 00:00:00 2001 +From: Aurelien Jarno +Date: Fri, 21 Sep 2012 18:20:25 +0200 +Subject: [PATCH] tcg-mips: fix wrong usage of 'Z' constraint + +The 'Z' constraint has been introduced to map the zero register. However +when the op also accept a constant, there is no point to accept the zero +register in addition. + +Reviewed-by: Richard Henderson +Signed-off-by: Aurelien Jarno +Signed-off-by: Michael Roth +--- + tcg/mips/tcg-target.c | 16 ++++++++-------- + 1 file changed, 8 insertions(+), 8 deletions(-) + +diff --git a/tcg/mips/tcg-target.c b/tcg/mips/tcg-target.c +index 74db83d..9293745 100644 +--- a/tcg/mips/tcg-target.c ++++ b/tcg/mips/tcg-target.c +@@ -1453,24 +1453,24 @@ static const TCGTargetOpDef mips_op_defs[] = { + { INDEX_op_st16_i32, { "rZ", "r" } }, + { INDEX_op_st_i32, { "rZ", "r" } }, + +- { INDEX_op_add_i32, { "r", "rZ", "rJZ" } }, ++ { INDEX_op_add_i32, { "r", "rZ", "rJ" } }, + { INDEX_op_mul_i32, { "r", "rZ", "rZ" } }, + { INDEX_op_mulu2_i32, { "r", "r", "rZ", "rZ" } }, + { INDEX_op_div_i32, { "r", "rZ", "rZ" } }, + { INDEX_op_divu_i32, { "r", "rZ", "rZ" } }, + { INDEX_op_rem_i32, { "r", "rZ", "rZ" } }, + { INDEX_op_remu_i32, { "r", "rZ", "rZ" } }, +- { INDEX_op_sub_i32, { "r", "rZ", "rJZ" } }, ++ { INDEX_op_sub_i32, { "r", "rZ", "rJ" } }, + +- { INDEX_op_and_i32, { "r", "rZ", "rIZ" } }, ++ { INDEX_op_and_i32, { "r", "rZ", "rI" } }, + { INDEX_op_nor_i32, { "r", "rZ", "rZ" } }, + { INDEX_op_not_i32, { "r", "rZ" } }, + { INDEX_op_or_i32, { "r", "rZ", "rIZ" } }, + { INDEX_op_xor_i32, { "r", "rZ", "rIZ" } }, + +- { INDEX_op_shl_i32, { "r", "rZ", "riZ" } }, +- { INDEX_op_shr_i32, { "r", "rZ", "riZ" } }, +- { INDEX_op_sar_i32, { "r", "rZ", "riZ" } }, ++ { INDEX_op_shl_i32, { "r", "rZ", "ri" } }, ++ { INDEX_op_shr_i32, { "r", "rZ", "ri" } }, ++ { INDEX_op_sar_i32, { "r", "rZ", "ri" } }, + + { INDEX_op_ext8s_i32, { "r", "rZ" } }, + { INDEX_op_ext16s_i32, { "r", "rZ" } }, +@@ -1479,8 +1479,8 @@ static const TCGTargetOpDef mips_op_defs[] = { + { INDEX_op_setcond_i32, { "r", "rZ", "rZ" } }, + { INDEX_op_setcond2_i32, { "r", "rZ", "rZ", "rZ", "rZ" } }, + +- { INDEX_op_add2_i32, { "r", "r", "rZ", "rZ", "rJZ", "rJZ" } }, +- { INDEX_op_sub2_i32, { "r", "r", "rZ", "rZ", "rJZ", "rJZ" } }, ++ { INDEX_op_add2_i32, { "r", "r", "rZ", "rZ", "rJ", "rJ" } }, ++ { INDEX_op_sub2_i32, { "r", "r", "rZ", "rZ", "rJ", "rJ" } }, + { INDEX_op_brcond2_i32, { "rZ", "rZ", "rZ", "rZ" } }, + + #if TARGET_LONG_BITS == 32 +-- +1.7.12.1 + diff --git a/0059-tcg-mips-kill-warnings-in-user-mode.patch b/0059-tcg-mips-kill-warnings-in-user-mode.patch new file mode 100644 index 0000000..96de9cb --- /dev/null +++ b/0059-tcg-mips-kill-warnings-in-user-mode.patch @@ -0,0 +1,166 @@ +From e63a3c6c70c9933320c6d8b23c3ea4cf4724d316 Mon Sep 17 00:00:00 2001 +From: Aurelien Jarno +Date: Fri, 21 Sep 2012 18:20:25 +0200 +Subject: [PATCH] tcg/mips: kill warnings in user mode + +Recent versions of GCC emit warnings when compiling user mode targets. +Kill them by reordering a bit the #ifdef. + +Reviewed-by: Richard Henderson +Signed-off-by: Aurelien Jarno +Signed-off-by: Michael Roth +--- + tcg/mips/tcg-target.c | 84 ++++++++++++++++++++++++++------------------------- + 1 file changed, 43 insertions(+), 41 deletions(-) + +diff --git a/tcg/mips/tcg-target.c b/tcg/mips/tcg-target.c +index 9293745..a09c0d6 100644 +--- a/tcg/mips/tcg-target.c ++++ b/tcg/mips/tcg-target.c +@@ -842,18 +842,16 @@ static const void * const qemu_st_helpers[4] = { + static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args, + int opc) + { +- int addr_regl, addr_meml; +- int data_regl, data_regh, data_reg1, data_reg2; +- int mem_index, s_bits; ++ int addr_regl, data_regl, data_regh, data_reg1, data_reg2; + #if defined(CONFIG_SOFTMMU) + void *label1_ptr, *label2_ptr; + int arg_num; +-#endif +-#if TARGET_LONG_BITS == 64 +-# if defined(CONFIG_SOFTMMU) ++ int mem_index, s_bits; ++ int addr_meml; ++# if TARGET_LONG_BITS == 64 + uint8_t *label3_ptr; +-# endif + int addr_regh, addr_memh; ++# endif + #endif + data_regl = *args++; + if (opc == 3) +@@ -861,11 +859,22 @@ static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args, + else + data_regh = 0; + addr_regl = *args++; +-#if TARGET_LONG_BITS == 64 ++#if defined(CONFIG_SOFTMMU) ++# if TARGET_LONG_BITS == 64 + addr_regh = *args++; +-#endif ++# if defined(TCG_TARGET_WORDS_BIGENDIAN) ++ addr_memh = 0; ++ addr_meml = 4; ++# else ++ addr_memh = 4; ++ addr_meml = 0; ++# endif ++# else ++ addr_meml = 0; ++# endif + mem_index = *args; + s_bits = opc & 3; ++#endif + + if (opc == 3) { + #if defined(TCG_TARGET_WORDS_BIGENDIAN) +@@ -879,18 +888,6 @@ static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args, + data_reg1 = data_regl; + data_reg2 = 0; + } +-#if TARGET_LONG_BITS == 64 +-# if defined(TCG_TARGET_WORDS_BIGENDIAN) +- addr_memh = 0; +- addr_meml = 4; +-# else +- addr_memh = 4; +- addr_meml = 0; +-# endif +-#else +- addr_meml = 0; +-#endif +- + #if defined(CONFIG_SOFTMMU) + tcg_out_opc_sa(s, OPC_SRL, TCG_REG_A0, addr_regl, TARGET_PAGE_BITS - CPU_TLB_ENTRY_BITS); + tcg_out_opc_imm(s, OPC_ANDI, TCG_REG_A0, TCG_REG_A0, (CPU_TLB_SIZE - 1) << CPU_TLB_ENTRY_BITS); +@@ -1029,50 +1026,55 @@ static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args, + static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args, + int opc) + { +- int addr_regl, addr_meml; +- int data_regl, data_regh, data_reg1, data_reg2; +- int mem_index, s_bits; ++ int addr_regl, data_regl, data_regh, data_reg1, data_reg2; + #if defined(CONFIG_SOFTMMU) + uint8_t *label1_ptr, *label2_ptr; + int arg_num; ++ int mem_index, s_bits; ++ int addr_meml; + #endif + #if TARGET_LONG_BITS == 64 + # if defined(CONFIG_SOFTMMU) + uint8_t *label3_ptr; +-# endif + int addr_regh, addr_memh; ++# endif + #endif +- + data_regl = *args++; + if (opc == 3) { + data_regh = *args++; +-#if defined(TCG_TARGET_WORDS_BIGENDIAN) +- data_reg1 = data_regh; +- data_reg2 = data_regl; +-#else +- data_reg1 = data_regl; +- data_reg2 = data_regh; +-#endif + } else { +- data_reg1 = data_regl; +- data_reg2 = 0; + data_regh = 0; + } + addr_regl = *args++; +-#if TARGET_LONG_BITS == 64 ++#if defined(CONFIG_SOFTMMU) ++# if TARGET_LONG_BITS == 64 + addr_regh = *args++; +-# if defined(TCG_TARGET_WORDS_BIGENDIAN) ++# if defined(TCG_TARGET_WORDS_BIGENDIAN) + addr_memh = 0; + addr_meml = 4; +-# else ++# else + addr_memh = 4; + addr_meml = 0; +-# endif +-#else ++# endif ++# else + addr_meml = 0; +-#endif ++# endif + mem_index = *args; + s_bits = opc; ++#endif ++ ++ if (opc == 3) { ++#if defined(TCG_TARGET_WORDS_BIGENDIAN) ++ data_reg1 = data_regh; ++ data_reg2 = data_regl; ++#else ++ data_reg1 = data_regl; ++ data_reg2 = data_regh; ++#endif ++ } else { ++ data_reg1 = data_regl; ++ data_reg2 = 0; ++ } + + #if defined(CONFIG_SOFTMMU) + tcg_out_opc_sa(s, OPC_SRL, TCG_REG_A0, addr_regl, TARGET_PAGE_BITS - CPU_TLB_ENTRY_BITS); +-- +1.7.12.1 + diff --git a/0060-tcg-mips-use-TCGArg-or-TCGReg-instead-of-int.patch b/0060-tcg-mips-use-TCGArg-or-TCGReg-instead-of-int.patch new file mode 100644 index 0000000..a6eb42f --- /dev/null +++ b/0060-tcg-mips-use-TCGArg-or-TCGReg-instead-of-int.patch @@ -0,0 +1,246 @@ +From 7b817977fbb87ee2e34018d92b64907197974a75 Mon Sep 17 00:00:00 2001 +From: Aurelien Jarno +Date: Fri, 21 Sep 2012 18:20:26 +0200 +Subject: [PATCH] tcg/mips: use TCGArg or TCGReg instead of int + +Instead of int, use the correct TCGArg and TCGReg type: TCGReg when +representing a TCG target register, TCGArg when representing the latter +or a constant. + +Reviewed-by: Richard Henderson +Signed-off-by: Aurelien Jarno +Signed-off-by: Michael Roth +--- + tcg/mips/tcg-target.c | 63 ++++++++++++++++++++++++++++----------------------- + 1 file changed, 35 insertions(+), 28 deletions(-) + +diff --git a/tcg/mips/tcg-target.c b/tcg/mips/tcg-target.c +index a09c0d6..8b38f98 100644 +--- a/tcg/mips/tcg-target.c ++++ b/tcg/mips/tcg-target.c +@@ -68,7 +68,7 @@ static const char * const tcg_target_reg_names[TCG_TARGET_NB_REGS] = { + #endif + + /* check if we really need so many registers :P */ +-static const int tcg_target_reg_alloc_order[] = { ++static const TCGReg tcg_target_reg_alloc_order[] = { + TCG_REG_S0, + TCG_REG_S1, + TCG_REG_S2, +@@ -94,14 +94,14 @@ static const int tcg_target_reg_alloc_order[] = { + TCG_REG_V1 + }; + +-static const int tcg_target_call_iarg_regs[4] = { ++static const TCGReg tcg_target_call_iarg_regs[4] = { + TCG_REG_A0, + TCG_REG_A1, + TCG_REG_A2, + TCG_REG_A3 + }; + +-static const int tcg_target_call_oarg_regs[2] = { ++static const TCGReg tcg_target_call_oarg_regs[2] = { + TCG_REG_V0, + TCG_REG_V1 + }; +@@ -327,7 +327,8 @@ enum { + /* + * Type reg + */ +-static inline void tcg_out_opc_reg(TCGContext *s, int opc, int rd, int rs, int rt) ++static inline void tcg_out_opc_reg(TCGContext *s, int opc, ++ TCGReg rd, TCGReg rs, TCGReg rt) + { + int32_t inst; + +@@ -341,7 +342,8 @@ static inline void tcg_out_opc_reg(TCGContext *s, int opc, int rd, int rs, int r + /* + * Type immediate + */ +-static inline void tcg_out_opc_imm(TCGContext *s, int opc, int rt, int rs, int imm) ++static inline void tcg_out_opc_imm(TCGContext *s, int opc, ++ TCGReg rt, TCGReg rs, TCGArg imm) + { + int32_t inst; + +@@ -355,7 +357,8 @@ static inline void tcg_out_opc_imm(TCGContext *s, int opc, int rt, int rs, int i + /* + * Type branch + */ +-static inline void tcg_out_opc_br(TCGContext *s, int opc, int rt, int rs) ++static inline void tcg_out_opc_br(TCGContext *s, int opc, ++ TCGReg rt, TCGReg rs) + { + /* We pay attention here to not modify the branch target by reading + the existing value and using it again. This ensure that caches and +@@ -368,7 +371,8 @@ static inline void tcg_out_opc_br(TCGContext *s, int opc, int rt, int rs) + /* + * Type sa + */ +-static inline void tcg_out_opc_sa(TCGContext *s, int opc, int rd, int rt, int sa) ++static inline void tcg_out_opc_sa(TCGContext *s, int opc, ++ TCGReg rd, TCGReg rt, TCGArg sa) + { + int32_t inst; + +@@ -407,7 +411,7 @@ static inline void tcg_out_movi(TCGContext *s, TCGType type, + } + } + +-static inline void tcg_out_bswap16(TCGContext *s, int ret, int arg) ++static inline void tcg_out_bswap16(TCGContext *s, TCGReg ret, TCGReg arg) + { + /* ret and arg can't be register at */ + if (ret == TCG_REG_AT || arg == TCG_REG_AT) { +@@ -422,7 +426,7 @@ static inline void tcg_out_bswap16(TCGContext *s, int ret, int arg) + tcg_out_opc_reg(s, OPC_OR, ret, ret, TCG_REG_AT); + } + +-static inline void tcg_out_bswap16s(TCGContext *s, int ret, int arg) ++static inline void tcg_out_bswap16s(TCGContext *s, TCGReg ret, TCGReg arg) + { + /* ret and arg can't be register at */ + if (ret == TCG_REG_AT || arg == TCG_REG_AT) { +@@ -437,7 +441,7 @@ static inline void tcg_out_bswap16s(TCGContext *s, int ret, int arg) + tcg_out_opc_reg(s, OPC_OR, ret, ret, TCG_REG_AT); + } + +-static inline void tcg_out_bswap32(TCGContext *s, int ret, int arg) ++static inline void tcg_out_bswap32(TCGContext *s, TCGReg ret, TCGReg arg) + { + /* ret and arg must be different and can't be register at */ + if (ret == arg || ret == TCG_REG_AT || arg == TCG_REG_AT) { +@@ -458,7 +462,7 @@ static inline void tcg_out_bswap32(TCGContext *s, int ret, int arg) + tcg_out_opc_reg(s, OPC_OR, ret, ret, TCG_REG_AT); + } + +-static inline void tcg_out_ext8s(TCGContext *s, int ret, int arg) ++static inline void tcg_out_ext8s(TCGContext *s, TCGReg ret, TCGReg arg) + { + #ifdef _MIPS_ARCH_MIPS32R2 + tcg_out_opc_reg(s, OPC_SEB, ret, 0, arg); +@@ -468,7 +472,7 @@ static inline void tcg_out_ext8s(TCGContext *s, int ret, int arg) + #endif + } + +-static inline void tcg_out_ext16s(TCGContext *s, int ret, int arg) ++static inline void tcg_out_ext16s(TCGContext *s, TCGReg ret, TCGReg arg) + { + #ifdef _MIPS_ARCH_MIPS32R2 + tcg_out_opc_reg(s, OPC_SEH, ret, 0, arg); +@@ -478,8 +482,8 @@ static inline void tcg_out_ext16s(TCGContext *s, int ret, int arg) + #endif + } + +-static inline void tcg_out_ldst(TCGContext *s, int opc, int arg, +- int arg1, tcg_target_long arg2) ++static inline void tcg_out_ldst(TCGContext *s, int opc, TCGArg arg, ++ TCGReg arg1, TCGArg arg2) + { + if (arg2 == (int16_t) arg2) { + tcg_out_opc_imm(s, opc, arg, arg1, arg2); +@@ -502,7 +506,7 @@ static inline void tcg_out_st(TCGContext *s, TCGType type, TCGReg arg, + tcg_out_ldst(s, OPC_SW, arg, arg1, arg2); + } + +-static inline void tcg_out_addi(TCGContext *s, int reg, tcg_target_long val) ++static inline void tcg_out_addi(TCGContext *s, TCGReg reg, TCGArg val) + { + if (val == (int16_t)val) { + tcg_out_opc_imm(s, OPC_ADDIU, reg, reg, val); +@@ -543,7 +547,7 @@ DEFINE_TCG_OUT_CALL_IARG(tcg_out_call_iarg_reg16, TCGReg arg) + #undef DEFINE_TCG_OUT_CALL_IARG_GET_ARG + #define DEFINE_TCG_OUT_CALL_IARG_GET_ARG(A) \ + tcg_out_movi(s, TCG_TYPE_I32, A, arg); +-DEFINE_TCG_OUT_CALL_IARG(tcg_out_call_iarg_imm32, uint32_t arg) ++DEFINE_TCG_OUT_CALL_IARG(tcg_out_call_iarg_imm32, TCGArg arg) + #undef DEFINE_TCG_OUT_CALL_IARG_GET_ARG + + /* We don't use the macro for this one to avoid an unnecessary reg-reg +@@ -573,8 +577,8 @@ static inline void tcg_out_call_iarg_reg64(TCGContext *s, int *arg_num, + #endif + } + +-static void tcg_out_brcond(TCGContext *s, TCGCond cond, int arg1, +- int arg2, int label_index) ++static void tcg_out_brcond(TCGContext *s, TCGCond cond, TCGArg arg1, ++ TCGArg arg2, int label_index) + { + TCGLabel *l = &s->labels[label_index]; + +@@ -631,8 +635,9 @@ static void tcg_out_brcond(TCGContext *s, TCGCond cond, int arg1, + + /* XXX: we implement it at the target level to avoid having to + handle cross basic blocks temporaries */ +-static void tcg_out_brcond2(TCGContext *s, TCGCond cond, int arg1, +- int arg2, int arg3, int arg4, int label_index) ++static void tcg_out_brcond2(TCGContext *s, TCGCond cond, TCGArg arg1, ++ TCGArg arg2, TCGArg arg3, TCGArg arg4, ++ int label_index) + { + void *label_ptr; + +@@ -694,8 +699,8 @@ static void tcg_out_brcond2(TCGContext *s, TCGCond cond, int arg1, + reloc_pc16(label_ptr, (tcg_target_long) s->code_ptr); + } + +-static void tcg_out_setcond(TCGContext *s, TCGCond cond, int ret, +- int arg1, int arg2) ++static void tcg_out_setcond(TCGContext *s, TCGCond cond, TCGReg ret, ++ TCGArg arg1, TCGArg arg2) + { + switch (cond) { + case TCG_COND_EQ: +@@ -754,8 +759,8 @@ static void tcg_out_setcond(TCGContext *s, TCGCond cond, int ret, + + /* XXX: we implement it at the target level to avoid having to + handle cross basic blocks temporaries */ +-static void tcg_out_setcond2(TCGContext *s, TCGCond cond, int ret, +- int arg1, int arg2, int arg3, int arg4) ++static void tcg_out_setcond2(TCGContext *s, TCGCond cond, TCGReg ret, ++ TCGArg arg1, TCGArg arg2, TCGArg arg3, TCGArg arg4) + { + switch (cond) { + case TCG_COND_EQ: +@@ -842,7 +847,7 @@ static const void * const qemu_st_helpers[4] = { + static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args, + int opc) + { +- int addr_regl, data_regl, data_regh, data_reg1, data_reg2; ++ TCGReg addr_regl, data_regl, data_regh, data_reg1, data_reg2; + #if defined(CONFIG_SOFTMMU) + void *label1_ptr, *label2_ptr; + int arg_num; +@@ -850,7 +855,8 @@ static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args, + int addr_meml; + # if TARGET_LONG_BITS == 64 + uint8_t *label3_ptr; +- int addr_regh, addr_memh; ++ TCGReg addr_regh; ++ int addr_memh; + # endif + #endif + data_regl = *args++; +@@ -1026,7 +1032,7 @@ static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args, + static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args, + int opc) + { +- int addr_regl, data_regl, data_regh, data_reg1, data_reg2; ++ TCGReg addr_regl, data_regl, data_regh, data_reg1, data_reg2; + #if defined(CONFIG_SOFTMMU) + uint8_t *label1_ptr, *label2_ptr; + int arg_num; +@@ -1036,7 +1042,8 @@ static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args, + #if TARGET_LONG_BITS == 64 + # if defined(CONFIG_SOFTMMU) + uint8_t *label3_ptr; +- int addr_regh, addr_memh; ++ TCGReg addr_regh; ++ int addr_memh; + # endif + #endif + data_regl = *args++; +-- +1.7.12.1 + diff --git a/0061-tcg-mips-don-t-use-global-pointer.patch b/0061-tcg-mips-don-t-use-global-pointer.patch new file mode 100644 index 0000000..a9aaf69 --- /dev/null +++ b/0061-tcg-mips-don-t-use-global-pointer.patch @@ -0,0 +1,37 @@ +From 9a4f545e4526f946613548a427fcab4c2a089ac0 Mon Sep 17 00:00:00 2001 +From: Aurelien Jarno +Date: Fri, 21 Sep 2012 18:20:26 +0200 +Subject: [PATCH] tcg/mips: don't use global pointer + +Don't use the global pointer in TCG, in case helpers try access global +variables. + +Signed-off-by: Aurelien Jarno +Signed-off-by: Michael Roth +--- + tcg/mips/tcg-target.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/tcg/mips/tcg-target.c b/tcg/mips/tcg-target.c +index 8b38f98..0ea6a76 100644 +--- a/tcg/mips/tcg-target.c ++++ b/tcg/mips/tcg-target.c +@@ -1529,7 +1529,6 @@ static int tcg_target_callee_save_regs[] = { + TCG_REG_S5, + TCG_REG_S6, + TCG_REG_S7, +- TCG_REG_GP, + TCG_REG_FP, + TCG_REG_RA, /* should be last for ABI compliance */ + }; +@@ -1595,6 +1594,7 @@ static void tcg_target_init(TCGContext *s) + tcg_regset_set_reg(s->reserved_regs, TCG_REG_T0); /* internal use */ + tcg_regset_set_reg(s->reserved_regs, TCG_REG_RA); /* return address */ + tcg_regset_set_reg(s->reserved_regs, TCG_REG_SP); /* stack pointer */ ++ tcg_regset_set_reg(s->reserved_regs, TCG_REG_GP); /* global pointer */ + + tcg_add_target_add_op_defs(mips_op_defs); + tcg_set_frame(s, TCG_AREG0, offsetof(CPUArchState, temp_buf), +-- +1.7.12.1 + diff --git a/0062-tcg-mips-use-stack-for-TCG-temps.patch b/0062-tcg-mips-use-stack-for-TCG-temps.patch new file mode 100644 index 0000000..09ea3fb --- /dev/null +++ b/0062-tcg-mips-use-stack-for-TCG-temps.patch @@ -0,0 +1,47 @@ +From c914ae50df4dc2f2ab589c87c0cd2ce2f14d9639 Mon Sep 17 00:00:00 2001 +From: Aurelien Jarno +Date: Fri, 21 Sep 2012 18:20:26 +0200 +Subject: [PATCH] tcg/mips: use stack for TCG temps + +Use stack instead of temp_buf array in CPUState for TCG +temps. + +Reviewed-by: Richard Henderson +Signed-off-by: Aurelien Jarno +Signed-off-by: Michael Roth +--- + tcg/mips/tcg-target.c | 10 ++++++---- + 1 file changed, 6 insertions(+), 4 deletions(-) + +diff --git a/tcg/mips/tcg-target.c b/tcg/mips/tcg-target.c +index 0ea6a76..c05169f 100644 +--- a/tcg/mips/tcg-target.c ++++ b/tcg/mips/tcg-target.c +@@ -1538,11 +1538,15 @@ static void tcg_target_qemu_prologue(TCGContext *s) + { + int i, frame_size; + +- /* reserve some stack space */ ++ /* reserve some stack space, also for TCG temps. */ + frame_size = ARRAY_SIZE(tcg_target_callee_save_regs) * 4 +- + TCG_STATIC_CALL_ARGS_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_SP, ARRAY_SIZE(tcg_target_callee_save_regs) * 4 ++ + TCG_STATIC_CALL_ARGS_SIZE, ++ CPU_TEMP_BUF_NLONGS * sizeof(long)); + + /* TB prologue */ + tcg_out_addi(s, TCG_REG_SP, -frame_size); +@@ -1597,6 +1601,4 @@ static void tcg_target_init(TCGContext *s) + tcg_regset_set_reg(s->reserved_regs, TCG_REG_GP); /* global pointer */ + + tcg_add_target_add_op_defs(mips_op_defs); +- tcg_set_frame(s, TCG_AREG0, offsetof(CPUArchState, temp_buf), +- CPU_TEMP_BUF_NLONGS * sizeof(long)); + } +-- +1.7.12.1 + diff --git a/0063-tcg-mips-optimize-brcond-arg-0.patch b/0063-tcg-mips-optimize-brcond-arg-0.patch new file mode 100644 index 0000000..e21fcac --- /dev/null +++ b/0063-tcg-mips-optimize-brcond-arg-0.patch @@ -0,0 +1,99 @@ +From e30cf829e9d8200364b53b9189c76d2155a32876 Mon Sep 17 00:00:00 2001 +From: Aurelien Jarno +Date: Fri, 21 Sep 2012 18:20:26 +0200 +Subject: [PATCH] tcg/mips: optimize brcond arg, 0 + +MIPS has some conditional branch instructions when comparing with zero. +Use them. + +Reviewed-by: Richard Henderson +Signed-off-by: Aurelien Jarno +Signed-off-by: Michael Roth +--- + tcg/mips/tcg-target.c | 38 ++++++++++++++++++++++++++++++-------- + 1 file changed, 30 insertions(+), 8 deletions(-) + +diff --git a/tcg/mips/tcg-target.c b/tcg/mips/tcg-target.c +index c05169f..6aa4527 100644 +--- a/tcg/mips/tcg-target.c ++++ b/tcg/mips/tcg-target.c +@@ -278,6 +278,8 @@ static inline int tcg_target_const_match(tcg_target_long val, + enum { + OPC_BEQ = 0x04 << 26, + OPC_BNE = 0x05 << 26, ++ OPC_BLEZ = 0x06 << 26, ++ OPC_BGTZ = 0x07 << 26, + OPC_ADDIU = 0x09 << 26, + OPC_SLTI = 0x0A << 26, + OPC_SLTIU = 0x0B << 26, +@@ -319,6 +321,10 @@ enum { + OPC_SLT = OPC_SPECIAL | 0x2A, + OPC_SLTU = OPC_SPECIAL | 0x2B, + ++ OPC_REGIMM = 0x01 << 26, ++ OPC_BLTZ = OPC_REGIMM | (0x00 << 16), ++ OPC_BGEZ = OPC_REGIMM | (0x01 << 16), ++ + OPC_SPECIAL3 = 0x1f << 26, + OPC_SEB = OPC_SPECIAL3 | 0x420, + OPC_SEH = OPC_SPECIAL3 | 0x620, +@@ -590,32 +596,48 @@ static void tcg_out_brcond(TCGContext *s, TCGCond cond, TCGArg arg1, + tcg_out_opc_br(s, OPC_BNE, arg1, arg2); + break; + case TCG_COND_LT: +- tcg_out_opc_reg(s, OPC_SLT, TCG_REG_AT, arg1, arg2); +- tcg_out_opc_br(s, OPC_BNE, TCG_REG_AT, TCG_REG_ZERO); ++ if (arg2 == 0) { ++ tcg_out_opc_br(s, OPC_BLTZ, 0, arg1); ++ } else { ++ tcg_out_opc_reg(s, OPC_SLT, TCG_REG_AT, arg1, arg2); ++ tcg_out_opc_br(s, OPC_BNE, TCG_REG_AT, TCG_REG_ZERO); ++ } + break; + case TCG_COND_LTU: + tcg_out_opc_reg(s, OPC_SLTU, TCG_REG_AT, arg1, arg2); + tcg_out_opc_br(s, OPC_BNE, TCG_REG_AT, TCG_REG_ZERO); + break; + case TCG_COND_GE: +- tcg_out_opc_reg(s, OPC_SLT, TCG_REG_AT, arg1, arg2); +- tcg_out_opc_br(s, OPC_BEQ, TCG_REG_AT, TCG_REG_ZERO); ++ if (arg2 == 0) { ++ tcg_out_opc_br(s, OPC_BGEZ, 0, arg1); ++ } else { ++ tcg_out_opc_reg(s, OPC_SLT, TCG_REG_AT, arg1, arg2); ++ tcg_out_opc_br(s, OPC_BEQ, TCG_REG_AT, TCG_REG_ZERO); ++ } + break; + case TCG_COND_GEU: + tcg_out_opc_reg(s, OPC_SLTU, TCG_REG_AT, arg1, arg2); + tcg_out_opc_br(s, OPC_BEQ, TCG_REG_AT, TCG_REG_ZERO); + break; + case TCG_COND_LE: +- tcg_out_opc_reg(s, OPC_SLT, TCG_REG_AT, arg2, arg1); +- tcg_out_opc_br(s, OPC_BEQ, TCG_REG_AT, TCG_REG_ZERO); ++ if (arg2 == 0) { ++ tcg_out_opc_br(s, OPC_BLEZ, 0, arg1); ++ } else { ++ tcg_out_opc_reg(s, OPC_SLT, TCG_REG_AT, arg2, arg1); ++ tcg_out_opc_br(s, OPC_BEQ, TCG_REG_AT, TCG_REG_ZERO); ++ } + break; + case TCG_COND_LEU: + tcg_out_opc_reg(s, OPC_SLTU, TCG_REG_AT, arg2, arg1); + tcg_out_opc_br(s, OPC_BEQ, TCG_REG_AT, TCG_REG_ZERO); + break; + case TCG_COND_GT: +- tcg_out_opc_reg(s, OPC_SLT, TCG_REG_AT, arg2, arg1); +- tcg_out_opc_br(s, OPC_BNE, TCG_REG_AT, TCG_REG_ZERO); ++ if (arg2 == 0) { ++ tcg_out_opc_br(s, OPC_BGTZ, 0, arg1); ++ } else { ++ tcg_out_opc_reg(s, OPC_SLT, TCG_REG_AT, arg2, arg1); ++ tcg_out_opc_br(s, OPC_BNE, TCG_REG_AT, TCG_REG_ZERO); ++ } + break; + case TCG_COND_GTU: + tcg_out_opc_reg(s, OPC_SLTU, TCG_REG_AT, arg2, arg1); +-- +1.7.12.1 + diff --git a/0064-tcg-mips-optimize-bswap-16-16s-32-on-MIPS32R2.patch b/0064-tcg-mips-optimize-bswap-16-16s-32-on-MIPS32R2.patch new file mode 100644 index 0000000..45a881d --- /dev/null +++ b/0064-tcg-mips-optimize-bswap-16-16s-32-on-MIPS32R2.patch @@ -0,0 +1,161 @@ +From 879794c3d3974b1206bbc52011c8f2525709f396 Mon Sep 17 00:00:00 2001 +From: Aurelien Jarno +Date: Fri, 21 Sep 2012 18:20:26 +0200 +Subject: [PATCH] tcg/mips: optimize bswap{16,16s,32} on MIPS32R2 + +bswap operations can be optimized on MIPS32 Release 2 using the ROTR, +WSBH and SEH instructions. We can't use the non-R2 code to implement the +ops due to registers constraints, so don't define the corresponding +TCG_TARGET_HAS_bswap* values. + +Also bswap16* operations are supposed to be called with the 16 high bits +zeroed. This is the case everywhere (including for TCG by definition) +except when called from the store helper. Remove the AND instructions from +bswap16* and move it there. + +Reviewed-by: Richard Henderson +Signed-off-by: Aurelien Jarno +Signed-off-by: Michael Roth +--- + tcg/mips/tcg-target.c | 34 +++++++++++++++++++++++++++++----- + tcg/mips/tcg-target.h | 11 +++++++++-- + 2 files changed, 38 insertions(+), 7 deletions(-) + +diff --git a/tcg/mips/tcg-target.c b/tcg/mips/tcg-target.c +index 6aa4527..8b2f9fc 100644 +--- a/tcg/mips/tcg-target.c ++++ b/tcg/mips/tcg-target.c +@@ -326,6 +326,7 @@ enum { + OPC_BGEZ = OPC_REGIMM | (0x01 << 16), + + OPC_SPECIAL3 = 0x1f << 26, ++ OPC_WSBH = OPC_SPECIAL3 | 0x0a0, + OPC_SEB = OPC_SPECIAL3 | 0x420, + OPC_SEH = OPC_SPECIAL3 | 0x620, + }; +@@ -419,36 +420,45 @@ static inline void tcg_out_movi(TCGContext *s, TCGType type, + + static inline void tcg_out_bswap16(TCGContext *s, TCGReg ret, TCGReg arg) + { ++#ifdef _MIPS_ARCH_MIPS32R2 ++ tcg_out_opc_reg(s, OPC_WSBH, ret, 0, arg); ++#else + /* ret and arg can't be register at */ + if (ret == TCG_REG_AT || arg == TCG_REG_AT) { + tcg_abort(); + } + + tcg_out_opc_sa(s, OPC_SRL, TCG_REG_AT, arg, 8); +- tcg_out_opc_imm(s, OPC_ANDI, TCG_REG_AT, TCG_REG_AT, 0x00ff); +- + tcg_out_opc_sa(s, OPC_SLL, ret, arg, 8); + tcg_out_opc_imm(s, OPC_ANDI, ret, ret, 0xff00); + tcg_out_opc_reg(s, OPC_OR, ret, ret, TCG_REG_AT); ++#endif + } + + static inline void tcg_out_bswap16s(TCGContext *s, TCGReg ret, TCGReg arg) + { ++#ifdef _MIPS_ARCH_MIPS32R2 ++ tcg_out_opc_reg(s, OPC_WSBH, ret, 0, arg); ++ tcg_out_opc_reg(s, OPC_SEH, ret, 0, ret); ++#else + /* ret and arg can't be register at */ + if (ret == TCG_REG_AT || arg == TCG_REG_AT) { + tcg_abort(); + } + + tcg_out_opc_sa(s, OPC_SRL, TCG_REG_AT, arg, 8); +- tcg_out_opc_imm(s, OPC_ANDI, TCG_REG_AT, TCG_REG_AT, 0xff); +- + tcg_out_opc_sa(s, OPC_SLL, ret, arg, 24); + tcg_out_opc_sa(s, OPC_SRA, ret, ret, 16); + tcg_out_opc_reg(s, OPC_OR, ret, ret, TCG_REG_AT); ++#endif + } + + static inline void tcg_out_bswap32(TCGContext *s, TCGReg ret, TCGReg arg) + { ++#ifdef _MIPS_ARCH_MIPS32R2 ++ tcg_out_opc_reg(s, OPC_WSBH, ret, 0, arg); ++ tcg_out_opc_sa(s, OPC_ROTR, ret, ret, 16); ++#else + /* ret and arg must be different and can't be register at */ + if (ret == arg || ret == TCG_REG_AT || arg == TCG_REG_AT) { + tcg_abort(); +@@ -466,6 +476,7 @@ static inline void tcg_out_bswap32(TCGContext *s, TCGReg ret, TCGReg arg) + tcg_out_opc_sa(s, OPC_SRL, TCG_REG_AT, arg, 8); + tcg_out_opc_imm(s, OPC_ANDI, TCG_REG_AT, TCG_REG_AT, 0xff00); + tcg_out_opc_reg(s, OPC_OR, ret, ret, TCG_REG_AT); ++#endif + } + + static inline void tcg_out_ext8s(TCGContext *s, TCGReg ret, TCGReg arg) +@@ -1188,7 +1199,8 @@ static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args, + break; + case 1: + if (TCG_NEED_BSWAP) { +- tcg_out_bswap16(s, TCG_REG_T0, data_reg1); ++ tcg_out_opc_imm(s, OPC_ANDI, TCG_REG_T0, data_reg1, 0xffff); ++ tcg_out_bswap16(s, TCG_REG_T0, TCG_REG_T0); + tcg_out_opc_imm(s, OPC_SH, TCG_REG_T0, TCG_REG_A0, 0); + } else { + tcg_out_opc_imm(s, OPC_SH, data_reg1, TCG_REG_A0, 0); +@@ -1409,6 +1421,15 @@ static inline void tcg_out_op(TCGContext *s, TCGOpcode opc, + } + break; + ++ /* The bswap routines do not work on non-R2 CPU. In that case ++ we let TCG generating the corresponding code. */ ++ case INDEX_op_bswap16_i32: ++ tcg_out_bswap16(s, args[0], args[1]); ++ break; ++ case INDEX_op_bswap32_i32: ++ tcg_out_bswap32(s, args[0], args[1]); ++ break; ++ + case INDEX_op_ext8s_i32: + tcg_out_ext8s(s, args[0], args[1]); + break; +@@ -1503,6 +1524,9 @@ static const TCGTargetOpDef mips_op_defs[] = { + { INDEX_op_shr_i32, { "r", "rZ", "ri" } }, + { INDEX_op_sar_i32, { "r", "rZ", "ri" } }, + ++ { INDEX_op_bswap16_i32, { "r", "r" } }, ++ { INDEX_op_bswap32_i32, { "r", "r" } }, ++ + { INDEX_op_ext8s_i32, { "r", "rZ" } }, + { INDEX_op_ext16s_i32, { "r", "rZ" } }, + +diff --git a/tcg/mips/tcg-target.h b/tcg/mips/tcg-target.h +index 9c68a32..c5c13f7 100644 +--- a/tcg/mips/tcg-target.h ++++ b/tcg/mips/tcg-target.h +@@ -83,8 +83,6 @@ typedef enum { + #define TCG_TARGET_HAS_rot_i32 0 + #define TCG_TARGET_HAS_ext8s_i32 1 + #define TCG_TARGET_HAS_ext16s_i32 1 +-#define TCG_TARGET_HAS_bswap32_i32 0 +-#define TCG_TARGET_HAS_bswap16_i32 0 + #define TCG_TARGET_HAS_andc_i32 0 + #define TCG_TARGET_HAS_orc_i32 0 + #define TCG_TARGET_HAS_eqv_i32 0 +@@ -92,6 +90,15 @@ typedef enum { + #define TCG_TARGET_HAS_deposit_i32 0 + #define TCG_TARGET_HAS_movcond_i32 0 + ++/* optional instructions only implemented on MIPS32R2 */ ++#ifdef _MIPS_ARCH_MIPS32R2 ++#define TCG_TARGET_HAS_bswap16_i32 1 ++#define TCG_TARGET_HAS_bswap32_i32 1 ++#else ++#define TCG_TARGET_HAS_bswap16_i32 0 ++#define TCG_TARGET_HAS_bswap32_i32 0 ++#endif ++ + /* optional instructions automatically implemented */ + #define TCG_TARGET_HAS_neg_i32 0 /* sub rd, zero, rt */ + #define TCG_TARGET_HAS_ext8u_i32 0 /* andi rt, rs, 0xff */ +-- +1.7.12.1 + diff --git a/0065-tcg-mips-implement-rotl-rotr-ops-on-MIPS32R2.patch b/0065-tcg-mips-implement-rotl-rotr-ops-on-MIPS32R2.patch new file mode 100644 index 0000000..6134676 --- /dev/null +++ b/0065-tcg-mips-implement-rotl-rotr-ops-on-MIPS32R2.patch @@ -0,0 +1,92 @@ +From d19858a5515cd15dabf88b8f180754c1c3f3eb76 Mon Sep 17 00:00:00 2001 +From: Aurelien Jarno +Date: Fri, 21 Sep 2012 18:20:26 +0200 +Subject: [PATCH] tcg/mips: implement rotl/rotr ops on MIPS32R2 + +rotr operations can be optimized on MIPS32 Release 2 using the ROTR and +ROTRV instructions. Also implemented rotl operations by subtracting the +shift from 32. + +Reviewed-by: Richard Henderson +Signed-off-by: Aurelien Jarno +Signed-off-by: Michael Roth +--- + tcg/mips/tcg-target.c | 20 ++++++++++++++++++++ + tcg/mips/tcg-target.h | 3 ++- + 2 files changed, 22 insertions(+), 1 deletion(-) + +diff --git a/tcg/mips/tcg-target.c b/tcg/mips/tcg-target.c +index 8b2f9fc..592e42a 100644 +--- a/tcg/mips/tcg-target.c ++++ b/tcg/mips/tcg-target.c +@@ -300,9 +300,11 @@ enum { + OPC_SPECIAL = 0x00 << 26, + OPC_SLL = OPC_SPECIAL | 0x00, + OPC_SRL = OPC_SPECIAL | 0x02, ++ OPC_ROTR = OPC_SPECIAL | (0x01 << 21) | 0x02, + OPC_SRA = OPC_SPECIAL | 0x03, + OPC_SLLV = OPC_SPECIAL | 0x04, + OPC_SRLV = OPC_SPECIAL | 0x06, ++ OPC_ROTRV = OPC_SPECIAL | (0x01 << 6) | 0x06, + OPC_SRAV = OPC_SPECIAL | 0x07, + OPC_JR = OPC_SPECIAL | 0x08, + OPC_JALR = OPC_SPECIAL | 0x09, +@@ -1420,6 +1422,22 @@ static inline void tcg_out_op(TCGContext *s, TCGOpcode opc, + tcg_out_opc_reg(s, OPC_SRLV, args[0], args[2], args[1]); + } + break; ++ case INDEX_op_rotl_i32: ++ if (const_args[2]) { ++ tcg_out_opc_sa(s, OPC_ROTR, args[0], args[1], 0x20 - args[2]); ++ } else { ++ tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_AT, 32); ++ tcg_out_opc_reg(s, OPC_SUBU, TCG_REG_AT, TCG_REG_AT, args[2]); ++ tcg_out_opc_reg(s, OPC_ROTRV, args[0], TCG_REG_AT, args[1]); ++ } ++ break; ++ case INDEX_op_rotr_i32: ++ if (const_args[2]) { ++ tcg_out_opc_sa(s, OPC_ROTR, args[0], args[1], args[2]); ++ } else { ++ tcg_out_opc_reg(s, OPC_ROTRV, args[0], args[2], args[1]); ++ } ++ break; + + /* The bswap routines do not work on non-R2 CPU. In that case + we let TCG generating the corresponding code. */ +@@ -1523,6 +1541,8 @@ static const TCGTargetOpDef mips_op_defs[] = { + { INDEX_op_shl_i32, { "r", "rZ", "ri" } }, + { INDEX_op_shr_i32, { "r", "rZ", "ri" } }, + { INDEX_op_sar_i32, { "r", "rZ", "ri" } }, ++ { INDEX_op_rotr_i32, { "r", "rZ", "ri" } }, ++ { INDEX_op_rotl_i32, { "r", "rZ", "ri" } }, + + { INDEX_op_bswap16_i32, { "r", "r" } }, + { INDEX_op_bswap32_i32, { "r", "r" } }, +diff --git a/tcg/mips/tcg-target.h b/tcg/mips/tcg-target.h +index c5c13f7..470314c 100644 +--- a/tcg/mips/tcg-target.h ++++ b/tcg/mips/tcg-target.h +@@ -80,7 +80,6 @@ typedef enum { + #define TCG_TARGET_HAS_div_i32 1 + #define TCG_TARGET_HAS_not_i32 1 + #define TCG_TARGET_HAS_nor_i32 1 +-#define TCG_TARGET_HAS_rot_i32 0 + #define TCG_TARGET_HAS_ext8s_i32 1 + #define TCG_TARGET_HAS_ext16s_i32 1 + #define TCG_TARGET_HAS_andc_i32 0 +@@ -94,9 +93,11 @@ typedef enum { + #ifdef _MIPS_ARCH_MIPS32R2 + #define TCG_TARGET_HAS_bswap16_i32 1 + #define TCG_TARGET_HAS_bswap32_i32 1 ++#define TCG_TARGET_HAS_rot_i32 1 + #else + #define TCG_TARGET_HAS_bswap16_i32 0 + #define TCG_TARGET_HAS_bswap32_i32 0 ++#define TCG_TARGET_HAS_rot_i32 0 + #endif + + /* optional instructions automatically implemented */ +-- +1.7.12.1 + diff --git a/0066-tcg-mips-implement-deposit-op-on-MIPS32R2.patch b/0066-tcg-mips-implement-deposit-op-on-MIPS32R2.patch new file mode 100644 index 0000000..fe54bc0 --- /dev/null +++ b/0066-tcg-mips-implement-deposit-op-on-MIPS32R2.patch @@ -0,0 +1,77 @@ +From 7c3e573b364a65d4abce5266c376f4e77624b039 Mon Sep 17 00:00:00 2001 +From: Aurelien Jarno +Date: Fri, 21 Sep 2012 18:20:26 +0200 +Subject: [PATCH] tcg/mips: implement deposit op on MIPS32R2 + +deposit operations can be optimized on MIPS32 Release 2 using the INS +instruction. + +Reviewed-by: Richard Henderson +Signed-off-by: Aurelien Jarno +Signed-off-by: Michael Roth +--- + tcg/mips/tcg-target.c | 8 ++++++++ + tcg/mips/tcg-target.h | 3 ++- + 2 files changed, 10 insertions(+), 1 deletion(-) + +diff --git a/tcg/mips/tcg-target.c b/tcg/mips/tcg-target.c +index 592e42a..b2e1056 100644 +--- a/tcg/mips/tcg-target.c ++++ b/tcg/mips/tcg-target.c +@@ -328,6 +328,7 @@ enum { + OPC_BGEZ = OPC_REGIMM | (0x01 << 16), + + OPC_SPECIAL3 = 0x1f << 26, ++ OPC_INS = OPC_SPECIAL3 | 0x004, + OPC_WSBH = OPC_SPECIAL3 | 0x0a0, + OPC_SEB = OPC_SPECIAL3 | 0x420, + OPC_SEH = OPC_SPECIAL3 | 0x620, +@@ -1455,6 +1456,11 @@ static inline void tcg_out_op(TCGContext *s, TCGOpcode opc, + tcg_out_ext16s(s, args[0], args[1]); + break; + ++ case INDEX_op_deposit_i32: ++ tcg_out_opc_imm(s, OPC_INS, args[0], args[2], ++ ((args[3] + args[4] - 1) << 11) | (args[3] << 6)); ++ break; ++ + case INDEX_op_brcond_i32: + tcg_out_brcond(s, args[2], args[0], args[1], args[3]); + break; +@@ -1550,6 +1556,8 @@ static const TCGTargetOpDef mips_op_defs[] = { + { INDEX_op_ext8s_i32, { "r", "rZ" } }, + { INDEX_op_ext16s_i32, { "r", "rZ" } }, + ++ { INDEX_op_deposit_i32, { "r", "0", "rZ" } }, ++ + { INDEX_op_brcond_i32, { "rZ", "rZ" } }, + { INDEX_op_setcond_i32, { "r", "rZ", "rZ" } }, + { INDEX_op_setcond2_i32, { "r", "rZ", "rZ", "rZ", "rZ" } }, +diff --git a/tcg/mips/tcg-target.h b/tcg/mips/tcg-target.h +index 470314c..897a737 100644 +--- a/tcg/mips/tcg-target.h ++++ b/tcg/mips/tcg-target.h +@@ -86,7 +86,6 @@ typedef enum { + #define TCG_TARGET_HAS_orc_i32 0 + #define TCG_TARGET_HAS_eqv_i32 0 + #define TCG_TARGET_HAS_nand_i32 0 +-#define TCG_TARGET_HAS_deposit_i32 0 + #define TCG_TARGET_HAS_movcond_i32 0 + + /* optional instructions only implemented on MIPS32R2 */ +@@ -94,10 +93,12 @@ typedef enum { + #define TCG_TARGET_HAS_bswap16_i32 1 + #define TCG_TARGET_HAS_bswap32_i32 1 + #define TCG_TARGET_HAS_rot_i32 1 ++#define TCG_TARGET_HAS_deposit_i32 1 + #else + #define TCG_TARGET_HAS_bswap16_i32 0 + #define TCG_TARGET_HAS_bswap32_i32 0 + #define TCG_TARGET_HAS_rot_i32 0 ++#define TCG_TARGET_HAS_deposit_i32 0 + #endif + + /* optional instructions automatically implemented */ +-- +1.7.12.1 + diff --git a/0067-tcg-mips-implement-movcond-op-on-MIPS32R2.patch b/0067-tcg-mips-implement-movcond-op-on-MIPS32R2.patch new file mode 100644 index 0000000..7f06797 --- /dev/null +++ b/0067-tcg-mips-implement-movcond-op-on-MIPS32R2.patch @@ -0,0 +1,140 @@ +From 552720cea4c1ca99dd1919cb8a80b6b8f3b13cda Mon Sep 17 00:00:00 2001 +From: Aurelien Jarno +Date: Fri, 21 Sep 2012 18:20:26 +0200 +Subject: [PATCH] tcg/mips: implement movcond op on MIPS32R2 + +movcond operation can be implemented on MIPS32 Release 2 using the MOVN, +MOVZ, SLT and SLTU instructions. + +Reviewed-by: Richard Henderson +Signed-off-by: Aurelien Jarno +Signed-off-by: Michael Roth +--- + tcg/mips/tcg-target.c | 69 +++++++++++++++++++++++++++++++++++++++++++++++++++ + tcg/mips/tcg-target.h | 8 ++++++ + 2 files changed, 77 insertions(+) + +diff --git a/tcg/mips/tcg-target.c b/tcg/mips/tcg-target.c +index b2e1056..c272b38 100644 +--- a/tcg/mips/tcg-target.c ++++ b/tcg/mips/tcg-target.c +@@ -308,6 +308,8 @@ enum { + OPC_SRAV = OPC_SPECIAL | 0x07, + OPC_JR = OPC_SPECIAL | 0x08, + OPC_JALR = OPC_SPECIAL | 0x09, ++ OPC_MOVZ = OPC_SPECIAL | 0x0A, ++ OPC_MOVN = OPC_SPECIAL | 0x0B, + OPC_MFHI = OPC_SPECIAL | 0x10, + OPC_MFLO = OPC_SPECIAL | 0x12, + OPC_MULT = OPC_SPECIAL | 0x18, +@@ -735,6 +737,68 @@ static void tcg_out_brcond2(TCGContext *s, TCGCond cond, TCGArg arg1, + reloc_pc16(label_ptr, (tcg_target_long) s->code_ptr); + } + ++static void tcg_out_movcond(TCGContext *s, TCGCond cond, TCGReg ret, ++ TCGArg c1, TCGArg c2, TCGArg v) ++{ ++ switch (cond) { ++ case TCG_COND_EQ: ++ if (c1 == 0) { ++ tcg_out_opc_reg(s, OPC_MOVZ, ret, v, c2); ++ } else if (c2 == 0) { ++ tcg_out_opc_reg(s, OPC_MOVZ, ret, v, c1); ++ } else { ++ tcg_out_opc_reg(s, OPC_XOR, TCG_REG_AT, c1, c2); ++ tcg_out_opc_reg(s, OPC_MOVZ, ret, v, TCG_REG_AT); ++ } ++ break; ++ case TCG_COND_NE: ++ if (c1 == 0) { ++ tcg_out_opc_reg(s, OPC_MOVN, ret, v, c2); ++ } else if (c2 == 0) { ++ tcg_out_opc_reg(s, OPC_MOVN, ret, v, c1); ++ } else { ++ tcg_out_opc_reg(s, OPC_XOR, TCG_REG_AT, c1, c2); ++ tcg_out_opc_reg(s, OPC_MOVN, ret, v, TCG_REG_AT); ++ } ++ break; ++ case TCG_COND_LT: ++ tcg_out_opc_reg(s, OPC_SLT, TCG_REG_AT, c1, c2); ++ tcg_out_opc_reg(s, OPC_MOVN, ret, v, TCG_REG_AT); ++ break; ++ case TCG_COND_LTU: ++ tcg_out_opc_reg(s, OPC_SLTU, TCG_REG_AT, c1, c2); ++ tcg_out_opc_reg(s, OPC_MOVN, ret, v, TCG_REG_AT); ++ break; ++ case TCG_COND_GE: ++ tcg_out_opc_reg(s, OPC_SLT, TCG_REG_AT, c1, c2); ++ tcg_out_opc_reg(s, OPC_MOVZ, ret, v, TCG_REG_AT); ++ break; ++ case TCG_COND_GEU: ++ tcg_out_opc_reg(s, OPC_SLTU, TCG_REG_AT, c1, c2); ++ tcg_out_opc_reg(s, OPC_MOVZ, ret, v, TCG_REG_AT); ++ break; ++ case TCG_COND_LE: ++ tcg_out_opc_reg(s, OPC_SLT, TCG_REG_AT, c2, c1); ++ tcg_out_opc_reg(s, OPC_MOVZ, ret, v, TCG_REG_AT); ++ break; ++ case TCG_COND_LEU: ++ tcg_out_opc_reg(s, OPC_SLTU, TCG_REG_AT, c2, c1); ++ tcg_out_opc_reg(s, OPC_MOVZ, ret, v, TCG_REG_AT); ++ break; ++ case TCG_COND_GT: ++ tcg_out_opc_reg(s, OPC_SLT, TCG_REG_AT, c2, c1); ++ tcg_out_opc_reg(s, OPC_MOVN, ret, v, TCG_REG_AT); ++ break; ++ case TCG_COND_GTU: ++ tcg_out_opc_reg(s, OPC_SLTU, TCG_REG_AT, c2, c1); ++ tcg_out_opc_reg(s, OPC_MOVN, ret, v, TCG_REG_AT); ++ break; ++ default: ++ tcg_abort(); ++ break; ++ } ++} ++ + static void tcg_out_setcond(TCGContext *s, TCGCond cond, TCGReg ret, + TCGArg arg1, TCGArg arg2) + { +@@ -1468,6 +1532,10 @@ static inline void tcg_out_op(TCGContext *s, TCGOpcode opc, + tcg_out_brcond2(s, args[4], args[0], args[1], args[2], args[3], args[5]); + break; + ++ case INDEX_op_movcond_i32: ++ tcg_out_movcond(s, args[5], args[0], args[1], args[2], args[3]); ++ break; ++ + case INDEX_op_setcond_i32: + tcg_out_setcond(s, args[3], args[0], args[1], args[2]); + break; +@@ -1559,6 +1627,7 @@ static const TCGTargetOpDef mips_op_defs[] = { + { INDEX_op_deposit_i32, { "r", "0", "rZ" } }, + + { INDEX_op_brcond_i32, { "rZ", "rZ" } }, ++ { INDEX_op_movcond_i32, { "r", "rZ", "rZ", "rZ", "0" } }, + { INDEX_op_setcond_i32, { "r", "rZ", "rZ" } }, + { INDEX_op_setcond2_i32, { "r", "rZ", "rZ", "rZ", "rZ" } }, + +diff --git a/tcg/mips/tcg-target.h b/tcg/mips/tcg-target.h +index 897a737..d147e70 100644 +--- a/tcg/mips/tcg-target.h ++++ b/tcg/mips/tcg-target.h +@@ -86,7 +86,15 @@ typedef enum { + #define TCG_TARGET_HAS_orc_i32 0 + #define TCG_TARGET_HAS_eqv_i32 0 + #define TCG_TARGET_HAS_nand_i32 0 ++ ++/* optional instructions only implemented on MIPS4, MIPS32 and Loongson 2 */ ++#if defined(_MIPS_ARCH_MIPS4) || defined(_MIPS_ARCH_MIPS32) || \ ++ defined(_MIPS_ARCH_MIPS32R2) || defined(_MIPS_ARCH_LOONGSON2E) || \ ++ defined(_MIPS_ARCH_LOONGSON2F) ++#define TCG_TARGET_HAS_movcond_i32 1 ++#else + #define TCG_TARGET_HAS_movcond_i32 0 ++#endif + + /* optional instructions only implemented on MIPS32R2 */ + #ifdef _MIPS_ARCH_MIPS32R2 +-- +1.7.12.1 + diff --git a/0068-tcg-optimize-remove-TCG_TEMP_ANY.patch b/0068-tcg-optimize-remove-TCG_TEMP_ANY.patch new file mode 100644 index 0000000..0702187 --- /dev/null +++ b/0068-tcg-optimize-remove-TCG_TEMP_ANY.patch @@ -0,0 +1,62 @@ +From 848750a4acf9ea5c473be596d41720e702d770f0 Mon Sep 17 00:00:00 2001 +From: Aurelien Jarno +Date: Mon, 10 Sep 2012 23:51:42 +0200 +Subject: [PATCH] tcg/optimize: remove TCG_TEMP_ANY + +TCG_TEMP_ANY has no different meaning than TCG_TEMP_UNDEF, so use +the later instead. + +Reviewed-by: Richard Henderson +Signed-off-by: Aurelien Jarno +Signed-off-by: Michael Roth +--- + tcg/optimize.c | 11 +++++------ + 1 file changed, 5 insertions(+), 6 deletions(-) + +diff --git a/tcg/optimize.c b/tcg/optimize.c +index 1be7631..308b7f9 100644 +--- a/tcg/optimize.c ++++ b/tcg/optimize.c +@@ -39,8 +39,7 @@ typedef enum { + TCG_TEMP_UNDEF = 0, + TCG_TEMP_CONST, + TCG_TEMP_COPY, +- TCG_TEMP_HAS_COPY, +- TCG_TEMP_ANY ++ TCG_TEMP_HAS_COPY + } tcg_temp_state; + + struct tcg_temp_info { +@@ -52,7 +51,7 @@ struct tcg_temp_info { + + static struct tcg_temp_info temps[TCG_MAX_TEMPS]; + +-/* Reset TEMP's state to TCG_TEMP_ANY. If TEMP was a representative of some ++/* Reset TEMP's state to TCG_TEMP_UNDEF. If TEMP was a representative of some + class of equivalent temp's, a new representative should be chosen in this + class. */ + static void reset_temp(TCGArg temp, int nb_temps, int nb_globals) +@@ -69,7 +68,7 @@ static void reset_temp(TCGArg temp, int nb_temps, int nb_globals) + } + for (i = temps[temp].next_copy; i != temp; i = temps[i].next_copy) { + if (new_base == (TCGArg)-1) { +- temps[i].state = TCG_TEMP_ANY; ++ temps[i].state = TCG_TEMP_UNDEF; + } else { + temps[i].val = new_base; + } +@@ -81,9 +80,9 @@ static void reset_temp(TCGArg temp, int nb_temps, int nb_globals) + temps[temps[temp].prev_copy].next_copy = temps[temp].next_copy; + new_base = temps[temp].val; + } +- temps[temp].state = TCG_TEMP_ANY; ++ temps[temp].state = TCG_TEMP_UNDEF; + if (new_base != (TCGArg)-1 && temps[new_base].next_copy == new_base) { +- temps[new_base].state = TCG_TEMP_ANY; ++ temps[new_base].state = TCG_TEMP_UNDEF; + } + } + +-- +1.7.12.1 + diff --git a/0069-tcg-optimize-check-types-in-copy-propagation.patch b/0069-tcg-optimize-check-types-in-copy-propagation.patch new file mode 100644 index 0000000..6627679 --- /dev/null +++ b/0069-tcg-optimize-check-types-in-copy-propagation.patch @@ -0,0 +1,78 @@ +From 71f0bcf065ddd00d5659e846ddfdffb9a06ee896 Mon Sep 17 00:00:00 2001 +From: Aurelien Jarno +Date: Tue, 11 Sep 2012 12:26:23 +0200 +Subject: [PATCH] tcg/optimize: check types in copy propagation + +The copy propagation doesn't check the types of the temps during copy +propagation. However TCG is using the mov_i32 for the i64 to i32 +conversion and thus the two are not equivalent. + +With this patch tcg_opt_gen_mov() doesn't consider two temps of +different type as copies anymore. + +So far it seems the optimization was not aggressive enough to trigger +this bug, but it will be triggered later in this series once the copy +propagation is improved. + +Reviewed-by: Richard Henderson +Signed-off-by: Aurelien Jarno +Signed-off-by: Michael Roth +--- + tcg/optimize.c | 18 ++++++++---------- + 1 file changed, 8 insertions(+), 10 deletions(-) + +diff --git a/tcg/optimize.c b/tcg/optimize.c +index 308b7f9..da8dffe 100644 +--- a/tcg/optimize.c ++++ b/tcg/optimize.c +@@ -106,12 +106,13 @@ static TCGOpcode op_to_movi(TCGOpcode op) + } + } + +-static void tcg_opt_gen_mov(TCGArg *gen_args, TCGArg dst, TCGArg src, +- int nb_temps, int nb_globals) ++static void tcg_opt_gen_mov(TCGContext *s, TCGArg *gen_args, ++ TCGArg dst, TCGArg src) + { +- reset_temp(dst, nb_temps, nb_globals); ++ reset_temp(dst, s->nb_temps, s->nb_globals); + assert(temps[src].state != TCG_TEMP_COPY); +- if (src >= nb_globals) { ++ /* Only consider temps with the same type (width) as copies. */ ++ if (src >= s->nb_globals && s->temps[dst].type == s->temps[src].type) { + assert(temps[src].state != TCG_TEMP_CONST); + if (temps[src].state != TCG_TEMP_HAS_COPY) { + temps[src].state = TCG_TEMP_HAS_COPY; +@@ -461,8 +462,7 @@ static TCGArg *tcg_constant_folding(TCGContext *s, uint16_t *tcg_opc_ptr, + gen_opc_buf[op_index] = INDEX_op_nop; + } else { + gen_opc_buf[op_index] = op_to_mov(op); +- tcg_opt_gen_mov(gen_args, args[0], args[1], +- nb_temps, nb_globals); ++ tcg_opt_gen_mov(s, gen_args, args[0], args[1]); + gen_args += 2; + } + args += 3; +@@ -499,8 +499,7 @@ static TCGArg *tcg_constant_folding(TCGContext *s, uint16_t *tcg_opc_ptr, + gen_opc_buf[op_index] = INDEX_op_nop; + } else { + gen_opc_buf[op_index] = op_to_mov(op); +- tcg_opt_gen_mov(gen_args, args[0], args[1], nb_temps, +- nb_globals); ++ tcg_opt_gen_mov(s, gen_args, args[0], args[1]); + gen_args += 2; + } + args += 3; +@@ -524,8 +523,7 @@ static TCGArg *tcg_constant_folding(TCGContext *s, uint16_t *tcg_opc_ptr, + break; + } + if (temps[args[1]].state != TCG_TEMP_CONST) { +- tcg_opt_gen_mov(gen_args, args[0], args[1], +- nb_temps, nb_globals); ++ tcg_opt_gen_mov(s, gen_args, args[0], args[1]); + gen_args += 2; + args += 2; + break; +-- +1.7.12.1 + diff --git a/0070-tcg-optimize-rework-copy-progagation.patch b/0070-tcg-optimize-rework-copy-progagation.patch new file mode 100644 index 0000000..ca39c5a --- /dev/null +++ b/0070-tcg-optimize-rework-copy-progagation.patch @@ -0,0 +1,377 @@ +From bf408071104de13f79a0c3c8cac892f440462e7c Mon Sep 17 00:00:00 2001 +From: Aurelien Jarno +Date: Tue, 11 Sep 2012 12:31:21 +0200 +Subject: [PATCH] tcg/optimize: rework copy progagation + +The copy propagation pass tries to keep track what is a copy of what +and what has copy of what, and in addition it keep a circular list of +of all the copies. Unfortunately this doesn't fully work: a mov from +a temp which has a state "COPY" changed it into a state "HAS_COPY". +Later when this temp is used again, it is considered has not having +copy and thus no propagation is done. + +This patch fixes that by removing the hiearchy between copies, and thus +only keeping a "COPY" state both meaning "is a copy" and "has a copy". +The decision of which copy to use is deferred to the actual temp +replacement. At this stage there is not one best choice to do, but only +better choices than others. For doing the best choice the operation +would have to be parsed in reversed to know if a temp is going to be +used later or not. That what is done by the liveness analysis. At this +stage it is known that globals will be always live, that local temps +will be dead at the end of the translation block, and that the temps +will be dead at the end of the basic block. This means that this stage +should try to replace temps by local temps or globals and local temps +by globals. + +Reviewed-by: Richard Henderson +Signed-off-by: Aurelien Jarno +Signed-off-by: Michael Roth +--- + tcg/optimize.c | 167 +++++++++++++++++++++++++++++++-------------------------- + 1 file changed, 92 insertions(+), 75 deletions(-) + +diff --git a/tcg/optimize.c b/tcg/optimize.c +index da8dffe..1904b39 100644 +--- a/tcg/optimize.c ++++ b/tcg/optimize.c +@@ -39,7 +39,6 @@ typedef enum { + TCG_TEMP_UNDEF = 0, + TCG_TEMP_CONST, + TCG_TEMP_COPY, +- TCG_TEMP_HAS_COPY + } tcg_temp_state; + + struct tcg_temp_info { +@@ -51,39 +50,19 @@ struct tcg_temp_info { + + static struct tcg_temp_info temps[TCG_MAX_TEMPS]; + +-/* Reset TEMP's state to TCG_TEMP_UNDEF. If TEMP was a representative of some +- class of equivalent temp's, a new representative should be chosen in this +- class. */ +-static void reset_temp(TCGArg temp, int nb_temps, int nb_globals) ++/* Reset TEMP's state to TCG_TEMP_UNDEF. If TEMP only had one copy, remove ++ the copy flag from the left temp. */ ++static void reset_temp(TCGArg temp) + { +- int i; +- TCGArg new_base = (TCGArg)-1; +- if (temps[temp].state == TCG_TEMP_HAS_COPY) { +- for (i = temps[temp].next_copy; i != temp; i = temps[i].next_copy) { +- if (i >= nb_globals) { +- temps[i].state = TCG_TEMP_HAS_COPY; +- new_base = i; +- break; +- } +- } +- for (i = temps[temp].next_copy; i != temp; i = temps[i].next_copy) { +- if (new_base == (TCGArg)-1) { +- temps[i].state = TCG_TEMP_UNDEF; +- } else { +- temps[i].val = new_base; +- } ++ if (temps[temp].state == TCG_TEMP_COPY) { ++ if (temps[temp].prev_copy == temps[temp].next_copy) { ++ temps[temps[temp].next_copy].state = TCG_TEMP_UNDEF; ++ } else { ++ temps[temps[temp].next_copy].prev_copy = temps[temp].prev_copy; ++ temps[temps[temp].prev_copy].next_copy = temps[temp].next_copy; + } +- temps[temps[temp].next_copy].prev_copy = temps[temp].prev_copy; +- temps[temps[temp].prev_copy].next_copy = temps[temp].next_copy; +- } else if (temps[temp].state == TCG_TEMP_COPY) { +- temps[temps[temp].next_copy].prev_copy = temps[temp].prev_copy; +- temps[temps[temp].prev_copy].next_copy = temps[temp].next_copy; +- new_base = temps[temp].val; + } + temps[temp].state = TCG_TEMP_UNDEF; +- if (new_base != (TCGArg)-1 && temps[new_base].next_copy == new_base) { +- temps[new_base].state = TCG_TEMP_UNDEF; +- } + } + + static int op_bits(TCGOpcode op) +@@ -106,34 +85,83 @@ static TCGOpcode op_to_movi(TCGOpcode op) + } + } + ++static TCGArg find_better_copy(TCGContext *s, TCGArg temp) ++{ ++ TCGArg i; ++ ++ /* If this is already a global, we can't do better. */ ++ if (temp < s->nb_globals) { ++ return temp; ++ } ++ ++ /* Search for a global first. */ ++ for (i = temps[temp].next_copy ; i != temp ; i = temps[i].next_copy) { ++ if (i < s->nb_globals) { ++ return i; ++ } ++ } ++ ++ /* If it is a temp, search for a temp local. */ ++ if (!s->temps[temp].temp_local) { ++ for (i = temps[temp].next_copy ; i != temp ; i = temps[i].next_copy) { ++ if (s->temps[i].temp_local) { ++ return i; ++ } ++ } ++ } ++ ++ /* Failure to find a better representation, return the same temp. */ ++ return temp; ++} ++ ++static bool temps_are_copies(TCGArg arg1, TCGArg arg2) ++{ ++ TCGArg i; ++ ++ if (arg1 == arg2) { ++ return true; ++ } ++ ++ if (temps[arg1].state != TCG_TEMP_COPY ++ || temps[arg2].state != TCG_TEMP_COPY) { ++ return false; ++ } ++ ++ for (i = temps[arg1].next_copy ; i != arg1 ; i = temps[i].next_copy) { ++ if (i == arg2) { ++ return true; ++ } ++ } ++ ++ return false; ++} ++ + static void tcg_opt_gen_mov(TCGContext *s, TCGArg *gen_args, + TCGArg dst, TCGArg src) + { +- reset_temp(dst, s->nb_temps, s->nb_globals); +- assert(temps[src].state != TCG_TEMP_COPY); +- /* Only consider temps with the same type (width) as copies. */ +- if (src >= s->nb_globals && s->temps[dst].type == s->temps[src].type) { +- assert(temps[src].state != TCG_TEMP_CONST); +- if (temps[src].state != TCG_TEMP_HAS_COPY) { +- temps[src].state = TCG_TEMP_HAS_COPY; ++ reset_temp(dst); ++ assert(temps[src].state != TCG_TEMP_CONST); ++ ++ if (s->temps[src].type == s->temps[dst].type) { ++ if (temps[src].state != TCG_TEMP_COPY) { ++ temps[src].state = TCG_TEMP_COPY; + temps[src].next_copy = src; + temps[src].prev_copy = src; + } + temps[dst].state = TCG_TEMP_COPY; +- temps[dst].val = src; + temps[dst].next_copy = temps[src].next_copy; + temps[dst].prev_copy = src; + temps[temps[dst].next_copy].prev_copy = dst; + temps[src].next_copy = dst; + } ++ + gen_args[0] = dst; + gen_args[1] = src; + } + +-static void tcg_opt_gen_movi(TCGArg *gen_args, TCGArg dst, TCGArg val, +- int nb_temps, int nb_globals) ++static void tcg_opt_gen_movi(TCGArg *gen_args, TCGArg dst, TCGArg val) + { +- reset_temp(dst, nb_temps, nb_globals); ++ reset_temp(dst); + temps[dst].state = TCG_TEMP_CONST; + temps[dst].val = val; + gen_args[0] = dst; +@@ -324,7 +352,6 @@ static TCGArg do_constant_folding_cond(TCGOpcode op, TCGArg x, + tcg_abort(); + } + +- + /* 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) +@@ -338,10 +365,8 @@ static TCGArg *tcg_constant_folding(TCGContext *s, uint16_t *tcg_opc_ptr, + + /* Array VALS has an element for each temp. + If this temp holds a constant then its value is kept in VALS' element. +- If this temp is a copy of other ones then this equivalence class' +- representative is kept in VALS' element. +- If this temp is neither copy nor constant then corresponding VALS' +- element is unused. */ ++ If this temp is a copy of other ones then the other copies are ++ available through the doubly linked circular list. */ + + nb_temps = s->nb_temps; + nb_globals = s->nb_globals; +@@ -357,7 +382,7 @@ static TCGArg *tcg_constant_folding(TCGContext *s, uint16_t *tcg_opc_ptr, + assert(op != INDEX_op_call); + for (i = def->nb_oargs; i < def->nb_oargs + def->nb_iargs; i++) { + if (temps[args[i]].state == TCG_TEMP_COPY) { +- args[i] = temps[args[i]].val; ++ args[i] = find_better_copy(s, args[i]); + } + } + } +@@ -429,7 +454,7 @@ static TCGArg *tcg_constant_folding(TCGContext *s, uint16_t *tcg_opc_ptr, + if (temps[args[1]].state == TCG_TEMP_CONST + && temps[args[1]].val == 0) { + gen_opc_buf[op_index] = op_to_movi(op); +- tcg_opt_gen_movi(gen_args, args[0], 0, nb_temps, nb_globals); ++ tcg_opt_gen_movi(gen_args, args[0], 0); + args += 3; + gen_args += 2; + continue; +@@ -456,9 +481,7 @@ static TCGArg *tcg_constant_folding(TCGContext *s, uint16_t *tcg_opc_ptr, + } + if (temps[args[2]].state == TCG_TEMP_CONST + && temps[args[2]].val == 0) { +- if ((temps[args[0]].state == TCG_TEMP_COPY +- && temps[args[0]].val == args[1]) +- || args[0] == args[1]) { ++ if (temps_are_copies(args[0], args[1])) { + gen_opc_buf[op_index] = INDEX_op_nop; + } else { + gen_opc_buf[op_index] = op_to_mov(op); +@@ -480,7 +503,7 @@ static TCGArg *tcg_constant_folding(TCGContext *s, uint16_t *tcg_opc_ptr, + if ((temps[args[2]].state == TCG_TEMP_CONST + && temps[args[2]].val == 0)) { + gen_opc_buf[op_index] = op_to_movi(op); +- tcg_opt_gen_movi(gen_args, args[0], 0, nb_temps, nb_globals); ++ tcg_opt_gen_movi(gen_args, args[0], 0); + args += 3; + gen_args += 2; + continue; +@@ -495,7 +518,7 @@ static TCGArg *tcg_constant_folding(TCGContext *s, uint16_t *tcg_opc_ptr, + CASE_OP_32_64(or): + CASE_OP_32_64(and): + if (args[1] == args[2]) { +- if (args[1] == args[0]) { ++ if (temps_are_copies(args[0], args[1])) { + gen_opc_buf[op_index] = INDEX_op_nop; + } else { + gen_opc_buf[op_index] = op_to_mov(op); +@@ -515,9 +538,7 @@ static TCGArg *tcg_constant_folding(TCGContext *s, uint16_t *tcg_opc_ptr, + allocator where needed and possible. Also detect copies. */ + switch (op) { + CASE_OP_32_64(mov): +- if ((temps[args[1]].state == TCG_TEMP_COPY +- && temps[args[1]].val == args[0]) +- || args[0] == args[1]) { ++ if (temps_are_copies(args[0], args[1])) { + args += 2; + gen_opc_buf[op_index] = INDEX_op_nop; + break; +@@ -535,7 +556,7 @@ static TCGArg *tcg_constant_folding(TCGContext *s, uint16_t *tcg_opc_ptr, + args[1] = temps[args[1]].val; + /* fallthrough */ + CASE_OP_32_64(movi): +- tcg_opt_gen_movi(gen_args, args[0], args[1], nb_temps, nb_globals); ++ tcg_opt_gen_movi(gen_args, args[0], args[1]); + gen_args += 2; + args += 2; + break; +@@ -550,9 +571,9 @@ static TCGArg *tcg_constant_folding(TCGContext *s, uint16_t *tcg_opc_ptr, + if (temps[args[1]].state == TCG_TEMP_CONST) { + 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, nb_temps, nb_globals); ++ tcg_opt_gen_movi(gen_args, args[0], tmp); + } else { +- reset_temp(args[0], nb_temps, nb_globals); ++ reset_temp(args[0]); + gen_args[0] = args[0]; + gen_args[1] = args[1]; + } +@@ -580,10 +601,10 @@ 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, + temps[args[2]].val); +- tcg_opt_gen_movi(gen_args, args[0], tmp, nb_temps, nb_globals); ++ tcg_opt_gen_movi(gen_args, args[0], tmp); + gen_args += 2; + } else { +- reset_temp(args[0], nb_temps, nb_globals); ++ reset_temp(args[0]); + gen_args[0] = args[0]; + gen_args[1] = args[1]; + gen_args[2] = args[2]; +@@ -597,10 +618,10 @@ 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_cond(op, temps[args[1]].val, + temps[args[2]].val, args[3]); +- tcg_opt_gen_movi(gen_args, args[0], tmp, nb_temps, nb_globals); ++ tcg_opt_gen_movi(gen_args, args[0], tmp); + gen_args += 2; + } else { +- reset_temp(args[0], nb_temps, nb_globals); ++ reset_temp(args[0]); + gen_args[0] = args[0]; + gen_args[1] = args[1]; + gen_args[2] = args[2]; +@@ -623,7 +644,7 @@ static TCGArg *tcg_constant_folding(TCGContext *s, uint16_t *tcg_opc_ptr, + } + } else { + memset(temps, 0, nb_temps * sizeof(struct tcg_temp_info)); +- reset_temp(args[0], nb_temps, nb_globals); ++ reset_temp(args[0]); + gen_args[0] = args[0]; + gen_args[1] = args[1]; + gen_args[2] = args[2]; +@@ -637,23 +658,19 @@ static TCGArg *tcg_constant_folding(TCGContext *s, uint16_t *tcg_opc_ptr, + && temps[args[2]].state == TCG_TEMP_CONST) { + tmp = do_constant_folding_cond(op, temps[args[1]].val, + temps[args[2]].val, args[5]); +- if (args[0] == args[4-tmp] +- || (temps[args[4-tmp]].state == TCG_TEMP_COPY +- && temps[args[4-tmp]].val == args[0])) { ++ if (temps_are_copies(args[0], args[4-tmp])) { + gen_opc_buf[op_index] = INDEX_op_nop; + } else if (temps[args[4-tmp]].state == TCG_TEMP_CONST) { + gen_opc_buf[op_index] = op_to_movi(op); +- tcg_opt_gen_movi(gen_args, args[0], temps[args[4-tmp]].val, +- nb_temps, nb_globals); ++ tcg_opt_gen_movi(gen_args, args[0], temps[args[4-tmp]].val); + gen_args += 2; + } else { + gen_opc_buf[op_index] = op_to_mov(op); +- tcg_opt_gen_mov(gen_args, args[0], args[4-tmp], +- nb_temps, nb_globals); ++ tcg_opt_gen_mov(s, gen_args, args[0], args[4-tmp]); + gen_args += 2; + } + } else { +- reset_temp(args[0], nb_temps, nb_globals); ++ reset_temp(args[0]); + gen_args[0] = args[0]; + gen_args[1] = args[1]; + gen_args[2] = args[2]; +@@ -668,11 +685,11 @@ static TCGArg *tcg_constant_folding(TCGContext *s, uint16_t *tcg_opc_ptr, + nb_call_args = (args[0] >> 16) + (args[0] & 0xffff); + if (!(args[nb_call_args + 1] & (TCG_CALL_CONST | TCG_CALL_PURE))) { + for (i = 0; i < nb_globals; i++) { +- reset_temp(i, nb_temps, nb_globals); ++ reset_temp(i); + } + } + for (i = 0; i < (args[0] >> 16); i++) { +- reset_temp(args[i + 1], nb_temps, nb_globals); ++ reset_temp(args[i + 1]); + } + i = nb_call_args + 3; + while (i) { +@@ -691,7 +708,7 @@ static TCGArg *tcg_constant_folding(TCGContext *s, uint16_t *tcg_opc_ptr, + memset(temps, 0, nb_temps * sizeof(struct tcg_temp_info)); + } else { + for (i = 0; i < def->nb_oargs; i++) { +- reset_temp(args[i], nb_temps, nb_globals); ++ reset_temp(args[i]); + } + } + for (i = 0; i < def->nb_args; i++) { +-- +1.7.12.1 + diff --git a/0071-tcg-optimize-do-copy-propagation-for-all-operations.patch b/0071-tcg-optimize-do-copy-propagation-for-all-operations.patch new file mode 100644 index 0000000..62a4efb --- /dev/null +++ b/0071-tcg-optimize-do-copy-propagation-for-all-operations.patch @@ -0,0 +1,42 @@ +From 7c1a67bb734f364ea0643b549e030f04d4eed798 Mon Sep 17 00:00:00 2001 +From: Aurelien Jarno +Date: Tue, 11 Sep 2012 16:18:49 +0200 +Subject: [PATCH] tcg/optimize: do copy propagation for all operations + +It is possible to due copy propagation for all operations, even the one +that have side effects or clobber arguments (it only concerns input +arguments). That said, the call operation should be handled differently +due to the variable number of arguments. + +Reviewed-by: Richard Henderson +Signed-off-by: Aurelien Jarno +Signed-off-by: Michael Roth +--- + tcg/optimize.c | 11 +++++++++-- + 1 file changed, 9 insertions(+), 2 deletions(-) + +diff --git a/tcg/optimize.c b/tcg/optimize.c +index 1904b39..aeb2225 100644 +--- a/tcg/optimize.c ++++ b/tcg/optimize.c +@@ -378,8 +378,15 @@ static TCGArg *tcg_constant_folding(TCGContext *s, uint16_t *tcg_opc_ptr, + op = gen_opc_buf[op_index]; + def = &tcg_op_defs[op]; + /* Do copy propagation */ +- if (!(def->flags & (TCG_OPF_CALL_CLOBBER | TCG_OPF_SIDE_EFFECTS))) { +- assert(op != INDEX_op_call); ++ if (op == INDEX_op_call) { ++ int nb_oargs = args[0] >> 16; ++ int nb_iargs = args[0] & 0xffff; ++ for (i = nb_oargs + 1; i < nb_oargs + nb_iargs + 1; i++) { ++ if (temps[args[i]].state == TCG_TEMP_COPY) { ++ args[i] = find_better_copy(s, args[i]); ++ } ++ } ++ } else { + for (i = def->nb_oargs; i < def->nb_oargs + def->nb_iargs; i++) { + if (temps[args[i]].state == TCG_TEMP_COPY) { + args[i] = find_better_copy(s, args[i]); +-- +1.7.12.1 + diff --git a/0072-tcg-optimize-optimize-op-r-a-a-mov-r-a.patch b/0072-tcg-optimize-optimize-op-r-a-a-mov-r-a.patch new file mode 100644 index 0000000..65f5c50 --- /dev/null +++ b/0072-tcg-optimize-optimize-op-r-a-a-mov-r-a.patch @@ -0,0 +1,31 @@ +From e38329760e40a354e37d11c7f5d8c86cdb90736c Mon Sep 17 00:00:00 2001 +From: Aurelien Jarno +Date: Tue, 18 Sep 2012 19:11:32 +0200 +Subject: [PATCH] tcg/optimize: optimize "op r, a, a => mov r, a" + +Now that we can easily detect all copies, we can optimize the +"op r, a, a => mov r, a" case a bit more. + +Reviewed-by: Richard Henderson +Signed-off-by: Aurelien Jarno +Signed-off-by: Michael Roth +--- + tcg/optimize.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/tcg/optimize.c b/tcg/optimize.c +index aeb2225..b9a7da9 100644 +--- a/tcg/optimize.c ++++ b/tcg/optimize.c +@@ -524,7 +524,7 @@ static TCGArg *tcg_constant_folding(TCGContext *s, uint16_t *tcg_opc_ptr, + switch (op) { + CASE_OP_32_64(or): + CASE_OP_32_64(and): +- if (args[1] == args[2]) { ++ if (temps_are_copies(args[1], args[2])) { + if (temps_are_copies(args[0], args[1])) { + gen_opc_buf[op_index] = INDEX_op_nop; + } else { +-- +1.7.12.1 + diff --git a/0073-tcg-optimize-optimize-op-r-a-a-movi-r-0.patch b/0073-tcg-optimize-optimize-op-r-a-a-movi-r-0.patch new file mode 100644 index 0000000..48ad5fe --- /dev/null +++ b/0073-tcg-optimize-optimize-op-r-a-a-movi-r-0.patch @@ -0,0 +1,46 @@ +From 363479b4d4f729959eafb1209d48ad75e928c00a Mon Sep 17 00:00:00 2001 +From: Aurelien Jarno +Date: Tue, 18 Sep 2012 19:12:36 +0200 +Subject: [PATCH] tcg/optimize: optimize "op r, a, a => movi r, 0" + +Now that it's possible to detect copies, we can optimize the case +the "op r, a, a => movi r, 0". This helps in the computation of +overflow flags when one of the two args is 0. + +Reviewed-by: Richard Henderson +Signed-off-by: Aurelien Jarno +Signed-off-by: Michael Roth +--- + tcg/optimize.c | 16 ++++++++++++++++ + 1 file changed, 16 insertions(+) + +diff --git a/tcg/optimize.c b/tcg/optimize.c +index b9a7da9..ceea644 100644 +--- a/tcg/optimize.c ++++ b/tcg/optimize.c +@@ -540,6 +540,22 @@ static TCGArg *tcg_constant_folding(TCGContext *s, uint16_t *tcg_opc_ptr, + break; + } + ++ /* Simplify expression for "op r, a, a => movi r, 0" cases */ ++ switch (op) { ++ CASE_OP_32_64(sub): ++ CASE_OP_32_64(xor): ++ if (temps_are_copies(args[1], args[2])) { ++ gen_opc_buf[op_index] = op_to_movi(op); ++ tcg_opt_gen_movi(gen_args, args[0], 0); ++ gen_args += 2; ++ args += 3; ++ continue; ++ } ++ break; ++ default: ++ break; ++ } ++ + /* Propagate constants through copy operations and do constant + folding. Constants will be substituted to arguments by register + allocator where needed and possible. Also detect copies. */ +-- +1.7.12.1 + diff --git a/0074-tcg-optimize-further-optimize-brcond-movcond-setcond.patch b/0074-tcg-optimize-further-optimize-brcond-movcond-setcond.patch new file mode 100644 index 0000000..9b9180d --- /dev/null +++ b/0074-tcg-optimize-further-optimize-brcond-movcond-setcond.patch @@ -0,0 +1,192 @@ +From 8d5f3ca9ccace2374fd73d46fad56decc02e0a44 Mon Sep 17 00:00:00 2001 +From: Aurelien Jarno +Date: Tue, 18 Sep 2012 19:37:00 +0200 +Subject: [PATCH] tcg/optimize: further optimize brcond/movcond/setcond + +When both argument of brcond/movcond/setcond are the same or when one +of the two values is a constant equal to zero, it's possible to do +further optimizations. + +Reviewed-by: Richard Henderson +Signed-off-by: Aurelien Jarno +Signed-off-by: Michael Roth +--- + tcg/optimize.c | 127 ++++++++++++++++++++++++++++++++++----------------------- + 1 file changed, 76 insertions(+), 51 deletions(-) + +diff --git a/tcg/optimize.c b/tcg/optimize.c +index ceea644..abe016a 100644 +--- a/tcg/optimize.c ++++ b/tcg/optimize.c +@@ -292,58 +292,88 @@ static TCGArg do_constant_folding(TCGOpcode op, TCGArg x, TCGArg y) + return res; + } + ++/* 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, + TCGArg y, TCGCond c) + { +- switch (op_bits(op)) { +- case 32: ++ 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; ++ } ++ break; ++ 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; ++ } ++ break; ++ } ++ } else if (temps_are_copies(x, y)) { + switch (c) { +- case TCG_COND_EQ: +- return (uint32_t)x == (uint32_t)y; +- case TCG_COND_NE: +- return (uint32_t)x != (uint32_t)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 (uint32_t)x < (uint32_t)y; +- case TCG_COND_GEU: +- return (uint32_t)x >= (uint32_t)y; +- case TCG_COND_LEU: +- return (uint32_t)x <= (uint32_t)y; ++ case TCG_COND_LT: + case TCG_COND_GTU: +- return (uint32_t)x > (uint32_t)y; +- } +- break; +- case 64: +- switch (c) { +- case TCG_COND_EQ: +- return (uint64_t)x == (uint64_t)y; + case TCG_COND_NE: +- return (uint64_t)x != (uint64_t)y; +- case TCG_COND_LT: +- return (int64_t)x < (int64_t)y; ++ return 0; + case TCG_COND_GE: +- return (int64_t)x >= (int64_t)y; ++ case TCG_COND_GEU: + 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_LEU: ++ case TCG_COND_EQ: ++ return 1; ++ } ++ } else if (temps[y].state == TCG_TEMP_CONST && temps[y].val == 0) { ++ switch (c) { + case TCG_COND_LTU: +- return (uint64_t)x < (uint64_t)y; ++ return 0; + case TCG_COND_GEU: +- return (uint64_t)x >= (uint64_t)y; +- case TCG_COND_LEU: +- return (uint64_t)x <= (uint64_t)y; +- case TCG_COND_GTU: +- return (uint64_t)x > (uint64_t)y; ++ return 1; ++ default: ++ return 2; + } +- break; ++ } else { ++ return 2; + } + + fprintf(stderr, +@@ -636,11 +666,9 @@ static TCGArg *tcg_constant_folding(TCGContext *s, uint16_t *tcg_opc_ptr, + args += 3; + break; + CASE_OP_32_64(setcond): +- if (temps[args[1]].state == TCG_TEMP_CONST +- && temps[args[2]].state == TCG_TEMP_CONST) { ++ tmp = do_constant_folding_cond(op, args[1], args[2], args[3]); ++ if (tmp != 2) { + gen_opc_buf[op_index] = op_to_movi(op); +- tmp = do_constant_folding_cond(op, temps[args[1]].val, +- temps[args[2]].val, args[3]); + tcg_opt_gen_movi(gen_args, args[0], tmp); + gen_args += 2; + } else { +@@ -654,10 +682,9 @@ static TCGArg *tcg_constant_folding(TCGContext *s, uint16_t *tcg_opc_ptr, + args += 4; + break; + CASE_OP_32_64(brcond): +- if (temps[args[0]].state == TCG_TEMP_CONST +- && temps[args[1]].state == TCG_TEMP_CONST) { +- if (do_constant_folding_cond(op, temps[args[0]].val, +- temps[args[1]].val, args[2])) { ++ tmp = do_constant_folding_cond(op, args[0], args[1], args[2]); ++ 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[3]; +@@ -677,10 +704,8 @@ static TCGArg *tcg_constant_folding(TCGContext *s, uint16_t *tcg_opc_ptr, + args += 4; + break; + CASE_OP_32_64(movcond): +- if (temps[args[1]].state == TCG_TEMP_CONST +- && temps[args[2]].state == TCG_TEMP_CONST) { +- tmp = do_constant_folding_cond(op, temps[args[1]].val, +- temps[args[2]].val, args[5]); ++ tmp = do_constant_folding_cond(op, args[1], args[2], args[5]); ++ if (tmp != 2) { + if (temps_are_copies(args[0], args[4-tmp])) { + gen_opc_buf[op_index] = INDEX_op_nop; + } else if (temps[args[4-tmp]].state == TCG_TEMP_CONST) { +-- +1.7.12.1 + diff --git a/0075-tcg-optimize-prefer-the-op-a-a-b-form-for-commutativ.patch b/0075-tcg-optimize-prefer-the-op-a-a-b-form-for-commutativ.patch new file mode 100644 index 0000000..4cb003b --- /dev/null +++ b/0075-tcg-optimize-prefer-the-op-a-a-b-form-for-commutativ.patch @@ -0,0 +1,38 @@ +From a0b71ad6a3f8aeb8b5ea6d112a7afeadc7c004a4 Mon Sep 17 00:00:00 2001 +From: Aurelien Jarno +Date: Wed, 19 Sep 2012 22:00:22 +0200 +Subject: [PATCH] tcg/optimize: prefer the "op a, a, b" form for commutative + ops + +The "op a, a, b" form is better handled on non-RISC host than the "op +a, b, a" form, so swap the arguments to this form when possible, and +when b is not a constant. + +This reduces the number of generated instructions by a tiny bit. + +Reviewed-by: Richard Henderson +Signed-off-by: Aurelien Jarno +Signed-off-by: Michael Roth +--- + tcg/optimize.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/tcg/optimize.c b/tcg/optimize.c +index abe016a..c8ae50b 100644 +--- a/tcg/optimize.c ++++ b/tcg/optimize.c +@@ -434,7 +434,10 @@ 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): +- if (temps[args[1]].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 (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; +-- +1.7.12.1 + diff --git a/0076-tcg-remove-ifdef-endif-around-TCGOpcode-tests.patch b/0076-tcg-remove-ifdef-endif-around-TCGOpcode-tests.patch new file mode 100644 index 0000000..214a022 --- /dev/null +++ b/0076-tcg-remove-ifdef-endif-around-TCGOpcode-tests.patch @@ -0,0 +1,68 @@ +From 3942910a66f682b98ac53ac2d2fba65b9c75eefd Mon Sep 17 00:00:00 2001 +From: Aurelien Jarno +Date: Fri, 21 Sep 2012 10:02:45 +0200 +Subject: [PATCH] tcg: remove #ifdef #endif around TCGOpcode tests + +Commit 25c4d9cc changed all TCGOpcode enums to be available, so we don't +need to #ifdef #endif the one that are available only on some targets. +This makes the code easier to read. + +Reviewed-by: Richard Henderson +Signed-off-by: Aurelien Jarno +Signed-off-by: Michael Roth +--- + tcg/tcg.c | 13 +------------ + 1 file changed, 1 insertion(+), 12 deletions(-) + +diff --git a/tcg/tcg.c b/tcg/tcg.c +index 24ce830..93421cd 100644 +--- a/tcg/tcg.c ++++ b/tcg/tcg.c +@@ -937,11 +937,7 @@ void tcg_dump_ops(TCGContext *s) + args[nb_oargs + i])); + } + } +- } else if (c == INDEX_op_movi_i32 +-#if TCG_TARGET_REG_BITS == 64 +- || c == INDEX_op_movi_i64 +-#endif +- ) { ++ } else if (c == INDEX_op_movi_i32 || c == INDEX_op_movi_i64) { + tcg_target_ulong val; + TCGHelperInfo *th; + +@@ -993,14 +989,11 @@ void tcg_dump_ops(TCGContext *s) + case INDEX_op_brcond_i32: + case INDEX_op_setcond_i32: + case INDEX_op_movcond_i32: +-#if TCG_TARGET_REG_BITS == 32 + case INDEX_op_brcond2_i32: + case INDEX_op_setcond2_i32: +-#else + case INDEX_op_brcond_i64: + case INDEX_op_setcond_i64: + case INDEX_op_movcond_i64: +-#endif + if (args[k] < ARRAY_SIZE(cond_name) && cond_name[args[k]]) { + qemu_log(",%s", cond_name[args[k++]]); + } else { +@@ -2095,16 +2088,12 @@ static inline int tcg_gen_code_common(TCGContext *s, uint8_t *gen_code_buf, + #endif + switch(opc) { + case INDEX_op_mov_i32: +-#if TCG_TARGET_REG_BITS == 64 + case INDEX_op_mov_i64: +-#endif + dead_args = s->op_dead_args[op_index]; + tcg_reg_alloc_mov(s, def, args, dead_args); + break; + case INDEX_op_movi_i32: +-#if TCG_TARGET_REG_BITS == 64 + case INDEX_op_movi_i64: +-#endif + tcg_reg_alloc_movi(s, args); + break; + case INDEX_op_debug_insn_start: +-- +1.7.12.1 + diff --git a/0077-tcg-optimize-add-constant-folding-for-deposit.patch b/0077-tcg-optimize-add-constant-folding-for-deposit.patch new file mode 100644 index 0000000..63566ce --- /dev/null +++ b/0077-tcg-optimize-add-constant-folding-for-deposit.patch @@ -0,0 +1,46 @@ +From 04edfbcf025b5588e0f3b86c74356a4339745f35 Mon Sep 17 00:00:00 2001 +From: Aurelien Jarno +Date: Fri, 21 Sep 2012 11:07:29 +0200 +Subject: [PATCH] tcg/optimize: add constant folding for deposit + +Reviewed-by: Richard Henderson +Signed-off-by: Aurelien Jarno +Signed-off-by: Michael Roth +--- + tcg/optimize.c | 20 ++++++++++++++++++++ + 1 file changed, 20 insertions(+) + +diff --git a/tcg/optimize.c b/tcg/optimize.c +index c8ae50b..35532a1 100644 +--- a/tcg/optimize.c ++++ b/tcg/optimize.c +@@ -668,6 +668,26 @@ static TCGArg *tcg_constant_folding(TCGContext *s, uint16_t *tcg_opc_ptr, + } + args += 3; + break; ++ CASE_OP_32_64(deposit): ++ if (temps[args[1]].state == TCG_TEMP_CONST ++ && temps[args[2]].state == TCG_TEMP_CONST) { ++ gen_opc_buf[op_index] = op_to_movi(op); ++ tmp = ((1ull << args[4]) - 1); ++ tmp = (temps[args[1]].val & ~(tmp << args[3])) ++ | ((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; + CASE_OP_32_64(setcond): + tmp = do_constant_folding_cond(op, args[1], args[2], args[3]); + if (tmp != 2) { +-- +1.7.12.1 + diff --git a/0078-tcg-README-document-tcg_gen_goto_tb-restrictions.patch b/0078-tcg-README-document-tcg_gen_goto_tb-restrictions.patch new file mode 100644 index 0000000..b47b1f1 --- /dev/null +++ b/0078-tcg-README-document-tcg_gen_goto_tb-restrictions.patch @@ -0,0 +1,33 @@ +From 08de143bdd34e906c3e89443cb6b24665f7c088d Mon Sep 17 00:00:00 2001 +From: Max Filippov +Date: Fri, 21 Sep 2012 04:18:07 +0400 +Subject: [PATCH] tcg/README: document tcg_gen_goto_tb restrictions + +See +http://lists.nongnu.org/archive/html/qemu-devel/2012-09/msg03196.html +for the whole story. + +Signed-off-by: Max Filippov +Signed-off-by: Aurelien Jarno +Signed-off-by: Michael Roth +--- + tcg/README | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/tcg/README b/tcg/README +index d03ae05..33783ee 100644 +--- a/tcg/README ++++ b/tcg/README +@@ -392,7 +392,8 @@ Exit the current TB and return the value t0 (word type). + + Exit the current TB and jump to the TB index 'index' (constant) if the + current TB was linked to this TB. Otherwise execute the next +-instructions. ++instructions. Only indices 0 and 1 are valid and tcg_gen_goto_tb may be issued ++at most once with each slot index per TB. + + * qemu_ld8u t0, t1, flags + qemu_ld8s t0, t1, flags +-- +1.7.12.1 + diff --git a/0079-w64-Fix-TCG-helper-functions-with-5-arguments.patch b/0079-w64-Fix-TCG-helper-functions-with-5-arguments.patch new file mode 100644 index 0000000..3cea914 --- /dev/null +++ b/0079-w64-Fix-TCG-helper-functions-with-5-arguments.patch @@ -0,0 +1,57 @@ +From e35e8b9bb446ff2693962151b8c80c5c88294959 Mon Sep 17 00:00:00 2001 +From: Stefan Weil +Date: Thu, 13 Sep 2012 19:37:43 +0200 +Subject: [PATCH] w64: Fix TCG helper functions with 5 arguments + +TCG uses 6 registers for function arguments on 64 bit Linux hosts, +but only 4 registers on W64 hosts. + +Commit 2999a0b20074a7e4a58f56572bb1436749368f59 increased the number +of arguments for some important helper functions from 4 to 5 +which triggered a bug for W64 hosts: QEMU aborts when executing +helper_lcall_real in the guest's BIOS because function +tcg_target_get_call_iarg_regs_count always returned 6. + +As W64 has only 4 registers for arguments, the 5th argument must be +passed on the stack using a correct stack offset. + +Signed-off-by: Stefan Weil +Signed-off-by: Aurelien Jarno +Signed-off-by: Michael Roth +--- + tcg/i386/tcg-target.c | 2 +- + tcg/i386/tcg-target.h | 4 ++++ + 2 files changed, 5 insertions(+), 1 deletion(-) + +diff --git a/tcg/i386/tcg-target.c b/tcg/i386/tcg-target.c +index aa1fa9f..85c6b81 100644 +--- a/tcg/i386/tcg-target.c ++++ b/tcg/i386/tcg-target.c +@@ -118,7 +118,7 @@ static void patch_reloc(uint8_t *code_ptr, int type, + static inline int tcg_target_get_call_iarg_regs_count(int flags) + { + if (TCG_TARGET_REG_BITS == 64) { +- return 6; ++ return ARRAY_SIZE(tcg_target_call_iarg_regs); + } + + return 0; +diff --git a/tcg/i386/tcg-target.h b/tcg/i386/tcg-target.h +index b356d76..ace63ba 100644 +--- a/tcg/i386/tcg-target.h ++++ b/tcg/i386/tcg-target.h +@@ -67,7 +67,11 @@ typedef enum { + /* used for function call generation */ + #define TCG_REG_CALL_STACK TCG_REG_ESP + #define TCG_TARGET_STACK_ALIGN 16 ++#if defined(_WIN64) ++#define TCG_TARGET_CALL_STACK_OFFSET 32 ++#else + #define TCG_TARGET_CALL_STACK_OFFSET 0 ++#endif + + /* optional instructions */ + #define TCG_TARGET_HAS_div2_i32 1 +-- +1.7.12.1 + diff --git a/0080-tcg-ppc32-Implement-movcond32.patch b/0080-tcg-ppc32-Implement-movcond32.patch new file mode 100644 index 0000000..2877379 --- /dev/null +++ b/0080-tcg-ppc32-Implement-movcond32.patch @@ -0,0 +1,137 @@ +From d65d20819ac52207befffa9a7aa858cc7de9cbaf Mon Sep 17 00:00:00 2001 +From: malc +Date: Sat, 22 Sep 2012 19:14:33 +0400 +Subject: [PATCH] tcg/ppc32: Implement movcond32 + +Thanks to Richard Henderson + +Signed-off-by: malc +Signed-off-by: Michael Roth +--- + tcg/ppc/tcg-target.c | 75 ++++++++++++++++++++++++++++++++++++++++++++++++++++ + tcg/ppc/tcg-target.h | 2 +- + 2 files changed, 76 insertions(+), 1 deletion(-) + +diff --git a/tcg/ppc/tcg-target.c b/tcg/ppc/tcg-target.c +index 26c4b33..8f8b193 100644 +--- a/tcg/ppc/tcg-target.c ++++ b/tcg/ppc/tcg-target.c +@@ -390,6 +390,7 @@ static int tcg_target_const_match(tcg_target_long val, + #define ORC XO31(412) + #define EQV XO31(284) + #define NAND XO31(476) ++#define ISEL XO31( 15) + + #define LBZX XO31( 87) + #define LHZX XO31(279) +@@ -1269,6 +1270,72 @@ static void tcg_out_setcond2 (TCGContext *s, const TCGArg *args, + ); + } + ++static void tcg_out_movcond (TCGContext *s, TCGCond cond, ++ TCGArg dest, ++ TCGArg c1, TCGArg c2, ++ TCGArg v1, TCGArg v2, ++ int const_c2) ++{ ++ tcg_out_cmp (s, cond, c1, c2, const_c2, 7); ++ ++ if (1) { ++ /* At least here on 7747A bit twiddling hacks are outperformed ++ by jumpy code (the testing was not scientific) */ ++ if (dest == v2) { ++ cond = tcg_invert_cond (cond); ++ v2 = v1; ++ } ++ else { ++ if (dest != v1) { ++ tcg_out_mov (s, TCG_TYPE_I32, dest, v1); ++ } ++ } ++ /* Branch forward over one insn */ ++ tcg_out32 (s, tcg_to_bc[cond] | 8); ++ tcg_out_mov (s, TCG_TYPE_I32, dest, v2); ++ } ++ else { ++ /* isel version, "if (1)" above should be replaced once a way ++ to figure out availability of isel on the underlying ++ hardware is found */ ++ int tab, bc; ++ ++ switch (cond) { ++ case TCG_COND_EQ: ++ tab = TAB (dest, v1, v2); ++ bc = CR_EQ; ++ break; ++ case TCG_COND_NE: ++ tab = TAB (dest, v2, v1); ++ bc = CR_EQ; ++ break; ++ case TCG_COND_LTU: ++ case TCG_COND_LT: ++ tab = TAB (dest, v1, v2); ++ bc = CR_LT; ++ break; ++ case TCG_COND_GEU: ++ case TCG_COND_GE: ++ tab = TAB (dest, v2, v1); ++ bc = CR_LT; ++ break; ++ case TCG_COND_LEU: ++ case TCG_COND_LE: ++ tab = TAB (dest, v2, v1); ++ bc = CR_GT; ++ break; ++ case TCG_COND_GTU: ++ case TCG_COND_GT: ++ tab = TAB (dest, v1, v2); ++ bc = CR_GT; ++ break; ++ default: ++ tcg_abort (); ++ } ++ tcg_out32 (s, ISEL | tab | ((bc + 28) << 6)); ++ } ++} ++ + static void tcg_out_brcond (TCGContext *s, TCGCond cond, + TCGArg arg1, TCGArg arg2, int const_arg2, + int label_index) +@@ -1826,6 +1893,13 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, const TCGArg *args, + ); + break; + ++ case INDEX_op_movcond_i32: ++ tcg_out_movcond (s, args[5], args[0], ++ args[1], args[2], ++ args[3], args[4], ++ const_args[2]); ++ break; ++ + default: + tcg_dump_ops (s); + tcg_abort (); +@@ -1922,6 +1996,7 @@ static const TCGTargetOpDef ppc_op_defs[] = { + { INDEX_op_ext16u_i32, { "r", "r" } }, + + { INDEX_op_deposit_i32, { "r", "0", "r" } }, ++ { INDEX_op_movcond_i32, { "r", "r", "ri", "r", "r" } }, + + { -1 }, + }; +diff --git a/tcg/ppc/tcg-target.h b/tcg/ppc/tcg-target.h +index 177eea1..3259d89 100644 +--- a/tcg/ppc/tcg-target.h ++++ b/tcg/ppc/tcg-target.h +@@ -92,7 +92,7 @@ typedef enum { + #define TCG_TARGET_HAS_nand_i32 1 + #define TCG_TARGET_HAS_nor_i32 1 + #define TCG_TARGET_HAS_deposit_i32 1 +-#define TCG_TARGET_HAS_movcond_i32 0 ++#define TCG_TARGET_HAS_movcond_i32 1 + + #define TCG_AREG0 TCG_REG_R27 + +-- +1.7.12.1 + diff --git a/0081-tcg-sparc-Hack-in-qemu_ld-st64-for-32-bit.patch b/0081-tcg-sparc-Hack-in-qemu_ld-st64-for-32-bit.patch new file mode 100644 index 0000000..f84d719 --- /dev/null +++ b/0081-tcg-sparc-Hack-in-qemu_ld-st64-for-32-bit.patch @@ -0,0 +1,30 @@ +From da65fa6c51ef1c999ffc75a162e95285d4cb915b Mon Sep 17 00:00:00 2001 +From: Richard Henderson +Date: Sat, 24 Mar 2012 21:30:20 +0100 +Subject: [PATCH] tcg-sparc: Hack in qemu_ld/st64 for 32-bit. + +Not actually implemented, but at least we avoid the tcg assert at startup. + +Signed-off-by: Richard Henderson +Signed-off-by: Michael Roth +--- + tcg/sparc/tcg-target.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/tcg/sparc/tcg-target.c b/tcg/sparc/tcg-target.c +index baed3b4..608fc46 100644 +--- a/tcg/sparc/tcg-target.c ++++ b/tcg/sparc/tcg-target.c +@@ -1556,6 +1556,9 @@ static const TCGTargetOpDef sparc_op_defs[] = { + + { INDEX_op_brcond_i64, { "r", "rJ" } }, + { INDEX_op_setcond_i64, { "r", "r", "rJ" } }, ++#else ++ { INDEX_op_qemu_ld64, { "L", "L", "L" } }, ++ { INDEX_op_qemu_st64, { "L", "L", "L" } }, + #endif + { -1 }, + }; +-- +1.7.12.1 + diff --git a/0082-tcg-sparc-Fix-ADDX-opcode.patch b/0082-tcg-sparc-Fix-ADDX-opcode.patch new file mode 100644 index 0000000..af3a51a --- /dev/null +++ b/0082-tcg-sparc-Fix-ADDX-opcode.patch @@ -0,0 +1,27 @@ +From b92aceeb9604c74e4a66db8ea5dd399d892e94bc Mon Sep 17 00:00:00 2001 +From: Richard Henderson +Date: Fri, 23 Mar 2012 23:57:12 +0100 +Subject: [PATCH] tcg-sparc: Fix ADDX opcode. + +Signed-off-by: Richard Henderson +Signed-off-by: Michael Roth +--- + tcg/sparc/tcg-target.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/tcg/sparc/tcg-target.c b/tcg/sparc/tcg-target.c +index 608fc46..0a19313 100644 +--- a/tcg/sparc/tcg-target.c ++++ b/tcg/sparc/tcg-target.c +@@ -236,7 +236,7 @@ static inline int tcg_target_const_match(tcg_target_long val, + #define ARITH_XOR (INSN_OP(2) | INSN_OP3(0x03)) + #define ARITH_SUB (INSN_OP(2) | INSN_OP3(0x04)) + #define ARITH_SUBCC (INSN_OP(2) | INSN_OP3(0x14)) +-#define ARITH_ADDX (INSN_OP(2) | INSN_OP3(0x10)) ++#define ARITH_ADDX (INSN_OP(2) | INSN_OP3(0x08)) + #define ARITH_SUBX (INSN_OP(2) | INSN_OP3(0x0c)) + #define ARITH_UMUL (INSN_OP(2) | INSN_OP3(0x0a)) + #define ARITH_UDIV (INSN_OP(2) | INSN_OP3(0x0e)) +-- +1.7.12.1 + diff --git a/0083-tcg-sparc-Don-t-MAP_FIXED-on-top-of-the-program.patch b/0083-tcg-sparc-Don-t-MAP_FIXED-on-top-of-the-program.patch new file mode 100644 index 0000000..3e7946c --- /dev/null +++ b/0083-tcg-sparc-Don-t-MAP_FIXED-on-top-of-the-program.patch @@ -0,0 +1,45 @@ +From 59aadb4f5b15eff968ed00ad29816ac19bef507d Mon Sep 17 00:00:00 2001 +From: Richard Henderson +Date: Fri, 21 Sep 2012 10:40:48 -0700 +Subject: [PATCH] tcg-sparc: Don't MAP_FIXED on top of the program + +The address we pick in sparc64.ld is also 0x60000000, so doing a fixed map +on top of that is guaranteed to blow up. Choosing 0x40000000 is exactly +right for the max of code_gen_buffer_size set below. + +No need to ever use MAP_FIXED. While getting our desired address helps +optimize the generated code, we won't fail if we don't get it. + +Signed-off-by: Richard Henderson +Signed-off-by: Michael Roth +--- + exec.c | 6 ++---- + 1 file changed, 2 insertions(+), 4 deletions(-) + +diff --git a/exec.c b/exec.c +index 5834766..871a68a 100644 +--- a/exec.c ++++ b/exec.c +@@ -543,8 +543,7 @@ static void code_gen_alloc(unsigned long tb_size) + code_gen_buffer_size = (800 * 1024 * 1024); + #elif defined(__sparc_v9__) + // Map the buffer below 2G, so we can use direct calls and branches +- flags |= MAP_FIXED; +- start = (void *) 0x60000000UL; ++ start = (void *) 0x40000000UL; + if (code_gen_buffer_size > (512 * 1024 * 1024)) + code_gen_buffer_size = (512 * 1024 * 1024); + #elif defined(__arm__) +@@ -584,8 +583,7 @@ static void code_gen_alloc(unsigned long tb_size) + code_gen_buffer_size = (800 * 1024 * 1024); + #elif defined(__sparc_v9__) + // Map the buffer below 2G, so we can use direct calls and branches +- flags |= MAP_FIXED; +- addr = (void *) 0x60000000UL; ++ addr = (void *) 0x40000000UL; + if (code_gen_buffer_size > (512 * 1024 * 1024)) { + code_gen_buffer_size = (512 * 1024 * 1024); + } +-- +1.7.12.1 + diff --git a/0084-tcg-sparc-Assume-v9-cpu-always-i.e.-force-v8plus-in-.patch b/0084-tcg-sparc-Assume-v9-cpu-always-i.e.-force-v8plus-in-.patch new file mode 100644 index 0000000..a68474a --- /dev/null +++ b/0084-tcg-sparc-Assume-v9-cpu-always-i.e.-force-v8plus-in-.patch @@ -0,0 +1,286 @@ +From cf873edf4227be439a9ffa5abb3da61ff1fd6527 Mon Sep 17 00:00:00 2001 +From: Richard Henderson +Date: Fri, 21 Sep 2012 10:34:21 -0700 +Subject: [PATCH] tcg-sparc: Assume v9 cpu always, i.e. force v8plus in 32-bit + mode. + +Current code doesn't actually work in 32-bit mode at all. Since +no one really noticed, drop the complication of v7 and v8 cpus. +Eliminate the --sparc_cpu configure option and standardize macro +testing on TCG_TARGET_REG_BITS / HOST_LONG_BITS + +Signed-off-by: Richard Henderson +Signed-off-by: Michael Roth +--- + configure | 40 ++++------------------------------------ + disas.c | 2 -- + exec.c | 6 +++--- + qemu-timer.h | 8 +++++--- + tcg/sparc/tcg-target.c | 20 +++++--------------- + tcg/sparc/tcg-target.h | 7 ++++--- + tcg/tcg.c | 3 ++- + 7 files changed, 23 insertions(+), 63 deletions(-) + +diff --git a/configure b/configure +index 816f0f9..0590f16 100755 +--- a/configure ++++ b/configure +@@ -111,7 +111,6 @@ source_path=`dirname "$0"` + cpu="" + interp_prefix="/usr/gnemul/qemu-%M" + static="no" +-sparc_cpu="" + cross_prefix="" + audio_drv_list="" + audio_card_list="ac97 es1370 sb16 hda" +@@ -249,21 +248,6 @@ for opt do + ;; + --disable-debug-info) debug_info="no" + ;; +- --sparc_cpu=*) +- sparc_cpu="$optarg" +- case $sparc_cpu in +- v7|v8|v8plus|v8plusa) +- cpu="sparc" +- ;; +- v9) +- cpu="sparc64" +- ;; +- *) +- echo "undefined SPARC architecture. Exiting"; +- exit 1 +- ;; +- esac +- ;; + esac + done + # OS specific +@@ -351,8 +335,6 @@ elif check_define __i386__ ; then + elif check_define __x86_64__ ; then + cpu="x86_64" + elif check_define __sparc__ ; then +- # We can't check for 64 bit (when gcc is biarch) or V8PLUSA +- # They must be specified using --sparc_cpu + if check_define __arch64__ ; then + cpu="sparc64" + else +@@ -798,8 +780,6 @@ for opt do + ;; + --enable-uname-release=*) uname_release="$optarg" + ;; +- --sparc_cpu=*) +- ;; + --enable-werror) werror="yes" + ;; + --disable-werror) werror="no" +@@ -883,31 +863,19 @@ for opt do + esac + done + +-# +-# If cpu ~= sparc and sparc_cpu hasn't been defined, plug in the right +-# QEMU_CFLAGS/LDFLAGS (assume sparc_v8plus for 32-bit and sparc_v9 for 64-bit) +-# + host_guest_base="no" + case "$cpu" in +- sparc) case $sparc_cpu in +- v7|v8) +- QEMU_CFLAGS="-mcpu=${sparc_cpu} -D__sparc_${sparc_cpu}__ $QEMU_CFLAGS" +- ;; +- v8plus|v8plusa) +- QEMU_CFLAGS="-mcpu=ultrasparc -D__sparc_${sparc_cpu}__ $QEMU_CFLAGS" +- ;; +- *) # sparc_cpu not defined in the command line +- QEMU_CFLAGS="-mcpu=ultrasparc -D__sparc_v8plus__ $QEMU_CFLAGS" +- esac ++ sparc) + LDFLAGS="-m32 $LDFLAGS" +- QEMU_CFLAGS="-m32 -ffixed-g2 -ffixed-g3 $QEMU_CFLAGS" ++ QEMU_CFLAGS="-m32 -mcpu=ultrasparc $QEMU_CFLAGS" ++ QEMU_CFLAGS="-ffixed-g2 -ffixed-g3 $QEMU_CFLAGS" + if test "$solaris" = "no" ; then + QEMU_CFLAGS="-ffixed-g1 -ffixed-g6 $QEMU_CFLAGS" + fi + ;; + sparc64) +- QEMU_CFLAGS="-m64 -mcpu=ultrasparc -D__sparc_v9__ $QEMU_CFLAGS" + LDFLAGS="-m64 $LDFLAGS" ++ QEMU_CFLAGS="-m64 -mcpu=ultrasparc $QEMU_CFLAGS" + QEMU_CFLAGS="-ffixed-g5 -ffixed-g6 -ffixed-g7 $QEMU_CFLAGS" + if test "$solaris" != "no" ; then + QEMU_CFLAGS="-ffixed-g1 $QEMU_CFLAGS" +diff --git a/disas.c b/disas.c +index 7b2acc9..b801c8f 100644 +--- a/disas.c ++++ b/disas.c +@@ -316,9 +316,7 @@ void disas(FILE *out, void *code, unsigned long size) + print_insn = print_insn_alpha; + #elif defined(__sparc__) + print_insn = print_insn_sparc; +-#if defined(__sparc_v8plus__) || defined(__sparc_v8plusa__) || defined(__sparc_v9__) + disasm_info.mach = bfd_mach_sparc_v9b; +-#endif + #elif defined(__arm__) + print_insn = print_insn_arm; + #elif defined(__MIPSEB__) +diff --git a/exec.c b/exec.c +index 871a68a..ad175db 100644 +--- a/exec.c ++++ b/exec.c +@@ -86,7 +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_v9__) ++#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. */ +@@ -541,7 +541,7 @@ static void code_gen_alloc(unsigned long tb_size) + /* Cannot map more than that */ + if (code_gen_buffer_size > (800 * 1024 * 1024)) + code_gen_buffer_size = (800 * 1024 * 1024); +-#elif defined(__sparc_v9__) ++#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)) +@@ -581,7 +581,7 @@ static void code_gen_alloc(unsigned long tb_size) + /* Cannot map more than that */ + if (code_gen_buffer_size > (800 * 1024 * 1024)) + code_gen_buffer_size = (800 * 1024 * 1024); +-#elif defined(__sparc_v9__) ++#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)) { +diff --git a/qemu-timer.h b/qemu-timer.h +index f8af595..da7e97c 100644 +--- a/qemu-timer.h ++++ b/qemu-timer.h +@@ -218,7 +218,7 @@ static inline int64_t cpu_get_real_ticks(void) + return val; + } + +-#elif defined(__sparc_v8plus__) || defined(__sparc_v8plusa__) || defined(__sparc_v9__) ++#elif defined(__sparc__) + + static inline int64_t cpu_get_real_ticks (void) + { +@@ -227,6 +227,8 @@ static inline int64_t cpu_get_real_ticks (void) + asm volatile("rd %%tick,%0" : "=r"(rval)); + return rval; + #else ++ /* We need an %o or %g register for this. For recent enough gcc ++ there is an "h" constraint for that. Don't bother with that. */ + union { + uint64_t i64; + struct { +@@ -234,8 +236,8 @@ static inline int64_t cpu_get_real_ticks (void) + uint32_t low; + } i32; + } rval; +- asm volatile("rd %%tick,%1; srlx %1,32,%0" +- : "=r"(rval.i32.high), "=r"(rval.i32.low)); ++ asm volatile("rd %%tick,%%g1; srlx %%g1,32,%0; mov %%g1,%1" ++ : "=r"(rval.i32.high), "=r"(rval.i32.low) : : "g1"); + return rval.i64; + #endif + } +diff --git a/tcg/sparc/tcg-target.c b/tcg/sparc/tcg-target.c +index 0a19313..23c2fda 100644 +--- a/tcg/sparc/tcg-target.c ++++ b/tcg/sparc/tcg-target.c +@@ -621,18 +621,10 @@ static void tcg_out_setcond_i32(TCGContext *s, TCGCond cond, TCGArg ret, + + default: + tcg_out_cmp(s, c1, c2, c2const); +-#if defined(__sparc_v9__) || defined(__sparc_v8plus__) + tcg_out_movi_imm13(s, ret, 0); +- tcg_out32 (s, ARITH_MOVCC | INSN_RD(ret) +- | INSN_RS1(tcg_cond_to_bcond[cond]) +- | MOVCC_ICC | INSN_IMM11(1)); +-#else +- t = gen_new_label(); +- tcg_out_branch_i32(s, INSN_COND(tcg_cond_to_bcond[cond], 1), t); +- tcg_out_movi_imm13(s, ret, 1); +- tcg_out_movi_imm13(s, ret, 0); +- tcg_out_label(s, t, s->code_ptr); +-#endif ++ tcg_out32(s, ARITH_MOVCC | INSN_RD(ret) ++ | INSN_RS1(tcg_cond_to_bcond[cond]) ++ | MOVCC_ICC | INSN_IMM11(1)); + return; + } + +@@ -742,7 +734,7 @@ static const void * const qemu_st_helpers[4] = { + #endif + #endif + +-#ifdef __arch64__ ++#if TCG_TARGET_REG_BITS == 64 + #define HOST_LD_OP LDX + #define HOST_ST_OP STX + #define HOST_SLL_OP SHIFT_SLLX +@@ -1600,11 +1592,9 @@ static void tcg_target_init(TCGContext *s) + + #if TCG_TARGET_REG_BITS == 64 + # define ELF_HOST_MACHINE EM_SPARCV9 +-#elif defined(__sparc_v8plus__) ++#else + # define ELF_HOST_MACHINE EM_SPARC32PLUS + # define ELF_HOST_FLAGS EF_SPARC_32PLUS +-#else +-# define ELF_HOST_MACHINE EM_SPARC + #endif + + typedef struct { +diff --git a/tcg/sparc/tcg-target.h b/tcg/sparc/tcg-target.h +index d762574..adca1d2 100644 +--- a/tcg/sparc/tcg-target.h ++++ b/tcg/sparc/tcg-target.h +@@ -67,7 +67,8 @@ typedef enum { + + /* used for function call generation */ + #define TCG_REG_CALL_STACK TCG_REG_I6 +-#ifdef __arch64__ ++ ++#if TCG_TARGET_REG_BITS == 64 + // Reserve space for AREG0 + #define TCG_TARGET_STACK_MINFRAME (176 + 4 * (int)sizeof(long) + \ + TCG_STATIC_CALL_ARGS_SIZE) +@@ -81,7 +82,7 @@ typedef enum { + #define TCG_TARGET_STACK_ALIGN 8 + #endif + +-#ifdef __arch64__ ++#if TCG_TARGET_REG_BITS == 64 + #define TCG_TARGET_EXTEND_ARGS 1 + #endif + +@@ -129,7 +130,7 @@ typedef enum { + + #ifdef CONFIG_SOLARIS + #define TCG_AREG0 TCG_REG_G2 +-#elif defined(__sparc_v9__) ++#elif HOST_LONG_BITS == 64 + #define TCG_AREG0 TCG_REG_G5 + #else + #define TCG_AREG0 TCG_REG_G6 +diff --git a/tcg/tcg.c b/tcg/tcg.c +index 93421cd..16c4e1d 100644 +--- a/tcg/tcg.c ++++ b/tcg/tcg.c +@@ -1450,7 +1450,8 @@ static void temp_allocate_frame(TCGContext *s, int temp) + { + TCGTemp *ts; + ts = &s->temps[temp]; +-#ifndef __sparc_v9__ /* Sparc64 stack is accessed with offset of 2047 */ ++#if !(defined(__sparc__) && TCG_TARGET_REG_BITS == 64) ++ /* Sparc64 stack is accessed with offset of 2047 */ + s->current_frame_offset = (s->current_frame_offset + + (tcg_target_long)sizeof(tcg_target_long) - 1) & + ~(sizeof(tcg_target_long) - 1); +-- +1.7.12.1 + diff --git a/0085-tcg-sparc-Fix-qemu_ld-st-to-handle-32-bit-host.patch b/0085-tcg-sparc-Fix-qemu_ld-st-to-handle-32-bit-host.patch new file mode 100644 index 0000000..beaf45b --- /dev/null +++ b/0085-tcg-sparc-Fix-qemu_ld-st-to-handle-32-bit-host.patch @@ -0,0 +1,967 @@ +From 138dfa905538bf918af390ff365a27de49364578 Mon Sep 17 00:00:00 2001 +From: Richard Henderson +Date: Fri, 23 Mar 2012 23:27:39 +0100 +Subject: [PATCH] tcg-sparc: Fix qemu_ld/st to handle 32-bit host. + +At the same time, split out the tlb load logic to a new function. +Fixes the cases of two data registers and two address registers. +Fixes the signature of, and adds missing, qemu_ld/st opcodes. + +Signed-off-by: Richard Henderson +Signed-off-by: Michael Roth +--- + tcg/sparc/tcg-target.c | 777 ++++++++++++++++++++++--------------------------- + 1 file changed, 348 insertions(+), 429 deletions(-) + +diff --git a/tcg/sparc/tcg-target.c b/tcg/sparc/tcg-target.c +index 23c2fda..d89c19b 100644 +--- a/tcg/sparc/tcg-target.c ++++ b/tcg/sparc/tcg-target.c +@@ -59,8 +59,6 @@ static const char * const tcg_target_reg_names[TCG_TARGET_NB_REGS] = { + }; + #endif + +-#define ARG_OFFSET 1 +- + static const int tcg_target_reg_alloc_order[] = { + TCG_REG_L0, + TCG_REG_L1, +@@ -288,6 +286,16 @@ static inline int tcg_target_const_match(tcg_target_long val, + #define ASI_PRIMARY_LITTLE 0x88 + #endif + ++#define LDUH_LE (LDUHA | INSN_ASI(ASI_PRIMARY_LITTLE)) ++#define LDSH_LE (LDSHA | INSN_ASI(ASI_PRIMARY_LITTLE)) ++#define LDUW_LE (LDUWA | INSN_ASI(ASI_PRIMARY_LITTLE)) ++#define LDSW_LE (LDSWA | INSN_ASI(ASI_PRIMARY_LITTLE)) ++#define LDX_LE (LDXA | INSN_ASI(ASI_PRIMARY_LITTLE)) ++ ++#define STH_LE (STHA | INSN_ASI(ASI_PRIMARY_LITTLE)) ++#define STW_LE (STWA | INSN_ASI(ASI_PRIMARY_LITTLE)) ++#define STX_LE (STXA | INSN_ASI(ASI_PRIMARY_LITTLE)) ++ + static inline void tcg_out_arith(TCGContext *s, int rd, int rs1, int rs2, + int op) + { +@@ -360,64 +368,43 @@ static inline void tcg_out_movi(TCGContext *s, TCGType type, + } + } + +-static inline void tcg_out_ld_raw(TCGContext *s, int ret, +- tcg_target_long arg) +-{ +- tcg_out_sethi(s, ret, arg); +- tcg_out32(s, LDUW | INSN_RD(ret) | INSN_RS1(ret) | +- INSN_IMM13(arg & 0x3ff)); +-} +- +-static inline void tcg_out_ld_ptr(TCGContext *s, int ret, +- tcg_target_long arg) ++static inline void tcg_out_ldst_rr(TCGContext *s, int data, int a1, ++ int a2, int op) + { +- if (!check_fit_tl(arg, 10)) +- tcg_out_movi(s, TCG_TYPE_PTR, ret, arg & ~0x3ffULL); +- if (TCG_TARGET_REG_BITS == 64) { +- tcg_out32(s, LDX | INSN_RD(ret) | INSN_RS1(ret) | +- INSN_IMM13(arg & 0x3ff)); +- } else { +- tcg_out32(s, LDUW | INSN_RD(ret) | INSN_RS1(ret) | +- INSN_IMM13(arg & 0x3ff)); +- } ++ tcg_out32(s, op | INSN_RD(data) | INSN_RS1(a1) | INSN_RS2(a2)); + } + +-static inline void tcg_out_ldst(TCGContext *s, int ret, int addr, int offset, int op) ++static inline void tcg_out_ldst(TCGContext *s, int ret, int addr, ++ int offset, int op) + { +- if (check_fit_tl(offset, 13)) ++ if (check_fit_tl(offset, 13)) { + tcg_out32(s, op | INSN_RD(ret) | INSN_RS1(addr) | + INSN_IMM13(offset)); +- else { ++ } else { + tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_I5, offset); +- tcg_out32(s, op | INSN_RD(ret) | INSN_RS1(TCG_REG_I5) | +- INSN_RS2(addr)); ++ tcg_out_ldst_rr(s, ret, addr, TCG_REG_I5, op); + } + } + +-static inline void tcg_out_ldst_asi(TCGContext *s, int ret, int addr, +- int offset, int op, int asi) +-{ +- tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_I5, offset); +- tcg_out32(s, op | INSN_RD(ret) | INSN_RS1(TCG_REG_I5) | +- INSN_ASI(asi) | INSN_RS2(addr)); +-} +- + static inline void tcg_out_ld(TCGContext *s, TCGType type, TCGReg ret, + TCGReg arg1, tcg_target_long arg2) + { +- if (type == TCG_TYPE_I32) +- tcg_out_ldst(s, ret, arg1, arg2, LDUW); +- else +- tcg_out_ldst(s, ret, arg1, arg2, LDX); ++ tcg_out_ldst(s, ret, arg1, arg2, (type == TCG_TYPE_I32 ? LDUW : LDX)); + } + + static inline void tcg_out_st(TCGContext *s, TCGType type, TCGReg arg, + TCGReg arg1, tcg_target_long arg2) + { +- if (type == TCG_TYPE_I32) +- tcg_out_ldst(s, arg, arg1, arg2, STW); +- else +- tcg_out_ldst(s, arg, arg1, arg2, STX); ++ tcg_out_ldst(s, arg, arg1, arg2, (type == TCG_TYPE_I32 ? STW : STX)); ++} ++ ++static inline void tcg_out_ld_ptr(TCGContext *s, int ret, ++ tcg_target_long arg) ++{ ++ if (!check_fit_tl(arg, 10)) { ++ tcg_out_movi(s, TCG_TYPE_PTR, ret, arg & ~0x3ff); ++ } ++ tcg_out_ld(s, TCG_TYPE_PTR, ret, ret, arg & 0x3ff); + } + + static inline void tcg_out_sety(TCGContext *s, int rs) +@@ -442,14 +429,15 @@ static inline void tcg_out_addi(TCGContext *s, int reg, tcg_target_long val) + } + } + +-static inline void tcg_out_andi(TCGContext *s, int reg, tcg_target_long val) ++static inline void tcg_out_andi(TCGContext *s, int rd, int rs, ++ tcg_target_long val) + { + if (val != 0) { + if (check_fit_tl(val, 13)) +- tcg_out_arithi(s, reg, reg, val, ARITH_AND); ++ tcg_out_arithi(s, rd, rs, val, ARITH_AND); + else { + tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_I5, val); +- tcg_out_arith(s, reg, reg, TCG_REG_I5, ARITH_AND); ++ tcg_out_arith(s, rd, rs, TCG_REG_I5, ARITH_AND); + } + } + } +@@ -718,418 +706,328 @@ static const void * const qemu_st_helpers[4] = { + helper_stl_mmu, + helper_stq_mmu, + }; +-#endif + +-#if TARGET_LONG_BITS == 32 +-#define TARGET_LD_OP LDUW +-#else +-#define TARGET_LD_OP LDX +-#endif ++/* Perform the TLB load and compare. + +-#if defined(CONFIG_SOFTMMU) +-#if HOST_LONG_BITS == 32 +-#define TARGET_ADDEND_LD_OP LDUW ++ Inputs: ++ ADDRLO_IDX contains the index into ARGS of the low part of the ++ address; the high part of the address is at ADDR_LOW_IDX+1. ++ ++ MEM_INDEX and S_BITS are the memory context and log2 size of the load. ++ ++ WHICH is the offset into the CPUTLBEntry structure of the slot to read. ++ This should be offsetof addr_read or addr_write. ++ ++ The result of the TLB comparison is in %[ix]cc. The sanitized address ++ is in the returned register, maybe %o0. The TLB addend is in %o1. */ ++ ++static int tcg_out_tlb_load(TCGContext *s, int addrlo_idx, int mem_index, ++ int s_bits, const TCGArg *args, int which) ++{ ++ const int addrlo = args[addrlo_idx]; ++ const int r0 = TCG_REG_O0; ++ const int r1 = TCG_REG_O1; ++ const int r2 = TCG_REG_O2; ++ int addr = addrlo; ++ int tlb_ofs; ++ ++ if (TCG_TARGET_REG_BITS == 32 && TARGET_LONG_BITS == 64) { ++ /* Assemble the 64-bit address in R0. */ ++ tcg_out_arithi(s, r0, addrlo, 0, SHIFT_SRL); ++ tcg_out_arithi(s, r1, args[addrlo_idx + 1], 32, SHIFT_SLLX); ++ tcg_out_arith(s, r0, r0, r1, ARITH_OR); ++ } ++ ++ /* Shift the page number down to tlb-entry. */ ++ tcg_out_arithi(s, r1, addrlo, ++ TARGET_PAGE_BITS - CPU_TLB_ENTRY_BITS, SHIFT_SRL); ++ ++ /* Mask out the page offset, except for the required alignment. */ ++ tcg_out_andi(s, r0, addr, TARGET_PAGE_MASK | ((1 << s_bits) - 1)); ++ ++ /* Compute tlb index, modulo tlb size. */ ++ tcg_out_andi(s, r1, r1, (CPU_TLB_SIZE - 1) << CPU_TLB_ENTRY_BITS); ++ ++ /* Relative to the current ENV. */ ++ tcg_out_arith(s, r1, TCG_AREG0, r1, ARITH_ADD); ++ ++ /* Find a base address that can load both tlb comparator and addend. */ ++ tlb_ofs = offsetof(CPUArchState, tlb_table[mem_index][0]); ++ if (!check_fit_tl(tlb_ofs + sizeof(CPUTLBEntry), 13)) { ++ tcg_out_addi(s, r1, tlb_ofs); ++ tlb_ofs = 0; ++ } ++ ++ /* Load the tlb comparator and the addend. */ ++ tcg_out_ld(s, TCG_TYPE_TL, r2, r1, tlb_ofs + which); ++ tcg_out_ld(s, TCG_TYPE_PTR, r1, r1, tlb_ofs+offsetof(CPUTLBEntry, addend)); ++ ++ /* subcc arg0, arg2, %g0 */ ++ tcg_out_cmp(s, r0, r2, 0); ++ ++ /* If the guest address must be zero-extended, do so now. */ ++ if (TCG_TARGET_REG_BITS == 64 && TARGET_LONG_BITS == 32) { ++ tcg_out_arithi(s, r0, addrlo, 0, SHIFT_SRL); ++ return r0; ++ } ++ return addrlo; ++} ++#endif /* CONFIG_SOFTMMU */ ++ ++static const int qemu_ld_opc[8] = { ++#ifdef TARGET_WORDS_BIGENDIAN ++ LDUB, LDUH, LDUW, LDX, LDSB, LDSH, LDSW, LDX + #else +-#define TARGET_ADDEND_LD_OP LDX +-#endif ++ LDUB, LDUH_LE, LDUW_LE, LDX_LE, LDSB, LDSH_LE, LDSW_LE, LDX_LE + #endif ++}; + +-#if TCG_TARGET_REG_BITS == 64 +-#define HOST_LD_OP LDX +-#define HOST_ST_OP STX +-#define HOST_SLL_OP SHIFT_SLLX +-#define HOST_SRA_OP SHIFT_SRAX ++static const int qemu_st_opc[4] = { ++#ifdef TARGET_WORDS_BIGENDIAN ++ STB, STH, STW, STX + #else +-#define HOST_LD_OP LDUW +-#define HOST_ST_OP STW +-#define HOST_SLL_OP SHIFT_SLL +-#define HOST_SRA_OP SHIFT_SRA ++ STB, STH_LE, STW_LE, STX_LE + #endif ++}; + +-static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args, +- int opc) ++static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args, int sizeop) + { +- int addr_reg, data_reg, arg0, arg1, arg2, mem_index, s_bits; ++ int addrlo_idx = 1, datalo, datahi, addr_reg; + #if defined(CONFIG_SOFTMMU) +- uint32_t *label1_ptr, *label2_ptr; ++ int memi_idx, memi, s_bits, n; ++ uint32_t *label_ptr[2]; + #endif + +- data_reg = *args++; +- addr_reg = *args++; +- mem_index = *args; +- s_bits = opc & 3; +- +- arg0 = TCG_REG_O0; +- arg1 = TCG_REG_O1; +- arg2 = TCG_REG_O2; ++ datahi = datalo = args[0]; ++ if (TCG_TARGET_REG_BITS == 32 && sizeop == 3) { ++ datahi = args[1]; ++ addrlo_idx = 2; ++ } + + #if defined(CONFIG_SOFTMMU) +- /* srl addr_reg, x, arg1 */ +- tcg_out_arithi(s, arg1, addr_reg, TARGET_PAGE_BITS - CPU_TLB_ENTRY_BITS, +- SHIFT_SRL); +- /* and addr_reg, x, arg0 */ +- tcg_out_arithi(s, arg0, addr_reg, TARGET_PAGE_MASK | ((1 << s_bits) - 1), +- ARITH_AND); ++ memi_idx = addrlo_idx + 1 + (TARGET_LONG_BITS > TCG_TARGET_REG_BITS); ++ memi = args[memi_idx]; ++ s_bits = sizeop & 3; ++ ++ addr_reg = tcg_out_tlb_load(s, addrlo_idx, memi, s_bits, args, ++ offsetof(CPUTLBEntry, addr_read)); ++ ++ if (TCG_TARGET_REG_BITS == 32 && sizeop == 3) { ++ int reg64; ++ ++ /* bne,pn %[xi]cc, label0 */ ++ label_ptr[0] = (uint32_t *)s->code_ptr; ++ tcg_out32(s, (INSN_OP(0) | INSN_COND(COND_NE, 0) | INSN_OP2(0x1) ++ | ((TARGET_LONG_BITS == 64) << 21))); ++ ++ /* TLB Hit. */ ++ /* Load all 64-bits into an O/G register. */ ++ reg64 = (datalo < 16 ? datalo : TCG_REG_O0); ++ tcg_out_ldst_rr(s, reg64, addr_reg, TCG_REG_O1, qemu_ld_opc[sizeop]); ++ ++ /* Move the two 32-bit pieces into the destination registers. */ ++ tcg_out_arithi(s, datahi, reg64, 32, SHIFT_SRLX); ++ if (reg64 != datalo) { ++ tcg_out_mov(s, TCG_TYPE_I32, datalo, reg64); ++ } + +- /* and arg1, x, arg1 */ +- tcg_out_andi(s, arg1, (CPU_TLB_SIZE - 1) << CPU_TLB_ENTRY_BITS); ++ /* b,a,pt label1 */ ++ label_ptr[1] = (uint32_t *)s->code_ptr; ++ tcg_out32(s, (INSN_OP(0) | INSN_COND(COND_A, 0) | INSN_OP2(0x1) ++ | (1 << 29) | (1 << 19))); ++ } else { ++ /* The fast path is exactly one insn. Thus we can perform the ++ entire TLB Hit in the (annulled) delay slot of the branch ++ over the TLB Miss case. */ ++ ++ /* beq,a,pt %[xi]cc, label0 */ ++ label_ptr[0] = NULL; ++ label_ptr[1] = (uint32_t *)s->code_ptr; ++ tcg_out32(s, (INSN_OP(0) | INSN_COND(COND_E, 0) | INSN_OP2(0x1) ++ | ((TARGET_LONG_BITS == 64) << 21) ++ | (1 << 29) | (1 << 19))); ++ /* delay slot */ ++ tcg_out_ldst_rr(s, datalo, addr_reg, TCG_REG_O1, qemu_ld_opc[sizeop]); ++ } + +- /* add arg1, x, arg1 */ +- tcg_out_addi(s, arg1, offsetof(CPUArchState, +- tlb_table[mem_index][0].addr_read)); ++ /* TLB Miss. */ + +- /* add env, arg1, arg1 */ +- tcg_out_arith(s, arg1, TCG_AREG0, arg1, ARITH_ADD); ++ if (label_ptr[0]) { ++ *label_ptr[0] |= INSN_OFF19((unsigned long)s->code_ptr - ++ (unsigned long)label_ptr[0]); ++ } ++ n = 0; ++ tcg_out_mov(s, TCG_TYPE_PTR, tcg_target_call_iarg_regs[n++], TCG_AREG0); ++ if (TARGET_LONG_BITS > TCG_TARGET_REG_BITS) { ++ tcg_out_mov(s, TCG_TYPE_REG, tcg_target_call_iarg_regs[n++], ++ args[addrlo_idx + 1]); ++ } ++ tcg_out_mov(s, TCG_TYPE_REG, tcg_target_call_iarg_regs[n++], ++ args[addrlo_idx]); + +- /* ld [arg1], arg2 */ +- tcg_out32(s, TARGET_LD_OP | INSN_RD(arg2) | INSN_RS1(arg1) | +- INSN_RS2(TCG_REG_G0)); ++ /* Store AREG0 in stack to avoid ugly glibc bugs that mangle ++ global registers */ ++ tcg_out_st(s, TCG_TYPE_REG, TCG_AREG0, TCG_REG_CALL_STACK, ++ TCG_TARGET_CALL_STACK_OFFSET - TCG_STATIC_CALL_ARGS_SIZE - ++ sizeof(long)); + +- /* subcc arg0, arg2, %g0 */ +- tcg_out_arith(s, TCG_REG_G0, arg0, arg2, ARITH_SUBCC); +- +- /* will become: +- be label1 +- or +- be,pt %xcc label1 */ +- label1_ptr = (uint32_t *)s->code_ptr; +- tcg_out32(s, 0); +- +- /* mov (delay slot) */ +- tcg_out_mov(s, TCG_TYPE_PTR, arg0, addr_reg); +- +- /* mov */ +- tcg_out_movi(s, TCG_TYPE_I32, arg1, mem_index); +- /* XXX/FIXME: suboptimal */ +- tcg_out_mov(s, TCG_TYPE_I32, tcg_target_call_iarg_regs[3], +- tcg_target_call_iarg_regs[2]); +- tcg_out_mov(s, TCG_TYPE_I64, tcg_target_call_iarg_regs[2], +- tcg_target_call_iarg_regs[1]); +- tcg_out_mov(s, TCG_TYPE_TL, tcg_target_call_iarg_regs[1], +- tcg_target_call_iarg_regs[0]); +- tcg_out_mov(s, TCG_TYPE_PTR, tcg_target_call_iarg_regs[0], +- TCG_AREG0); +- +- /* XXX: move that code at the end of the TB */ + /* qemu_ld_helper[s_bits](arg0, arg1) */ + tcg_out32(s, CALL | ((((tcg_target_ulong)qemu_ld_helpers[s_bits] + - (tcg_target_ulong)s->code_ptr) >> 2) + & 0x3fffffff)); +- /* Store AREG0 in stack to avoid ugly glibc bugs that mangle +- global registers */ +- // delay slot +- tcg_out_ldst(s, TCG_AREG0, TCG_REG_CALL_STACK, +- TCG_TARGET_CALL_STACK_OFFSET - TCG_STATIC_CALL_ARGS_SIZE - +- sizeof(long), HOST_ST_OP); +- tcg_out_ldst(s, TCG_AREG0, TCG_REG_CALL_STACK, +- TCG_TARGET_CALL_STACK_OFFSET - TCG_STATIC_CALL_ARGS_SIZE - +- sizeof(long), HOST_LD_OP); +- +- /* data_reg = sign_extend(arg0) */ +- switch(opc) { ++ /* delay slot */ ++ tcg_out_movi(s, TCG_TYPE_I32, tcg_target_call_iarg_regs[n], memi); ++ ++ /* Reload AREG0. */ ++ tcg_out_ld(s, TCG_TYPE_REG, TCG_AREG0, TCG_REG_CALL_STACK, ++ TCG_TARGET_CALL_STACK_OFFSET - TCG_STATIC_CALL_ARGS_SIZE - ++ sizeof(long)); ++ ++ n = tcg_target_call_oarg_regs[0]; ++ /* datalo = sign_extend(arg0) */ ++ switch (sizeop) { + case 0 | 4: +- /* sll arg0, 24/56, data_reg */ +- tcg_out_arithi(s, data_reg, arg0, (int)sizeof(tcg_target_long) * 8 - 8, +- HOST_SLL_OP); +- /* sra data_reg, 24/56, data_reg */ +- tcg_out_arithi(s, data_reg, data_reg, +- (int)sizeof(tcg_target_long) * 8 - 8, HOST_SRA_OP); ++ /* Recall that SRA sign extends from bit 31 through bit 63. */ ++ tcg_out_arithi(s, datalo, n, 24, SHIFT_SLL); ++ tcg_out_arithi(s, datalo, datalo, 24, SHIFT_SRA); + break; + case 1 | 4: +- /* sll arg0, 16/48, data_reg */ +- tcg_out_arithi(s, data_reg, arg0, +- (int)sizeof(tcg_target_long) * 8 - 16, HOST_SLL_OP); +- /* sra data_reg, 16/48, data_reg */ +- tcg_out_arithi(s, data_reg, data_reg, +- (int)sizeof(tcg_target_long) * 8 - 16, HOST_SRA_OP); ++ tcg_out_arithi(s, datalo, n, 16, SHIFT_SLL); ++ tcg_out_arithi(s, datalo, datalo, 16, SHIFT_SRA); + break; + case 2 | 4: +- /* sll arg0, 32, data_reg */ +- tcg_out_arithi(s, data_reg, arg0, 32, HOST_SLL_OP); +- /* sra data_reg, 32, data_reg */ +- tcg_out_arithi(s, data_reg, data_reg, 32, HOST_SRA_OP); ++ tcg_out_arithi(s, datalo, n, 0, SHIFT_SRA); + break; ++ case 3: ++ if (TCG_TARGET_REG_BITS == 32) { ++ tcg_out_mov(s, TCG_TYPE_REG, datahi, n); ++ tcg_out_mov(s, TCG_TYPE_REG, datalo, n + 1); ++ break; ++ } ++ /* FALLTHRU */ + case 0: + case 1: + case 2: +- case 3: + default: + /* mov */ +- tcg_out_mov(s, TCG_TYPE_REG, data_reg, arg0); ++ tcg_out_mov(s, TCG_TYPE_REG, datalo, n); + break; + } + +- /* will become: +- ba label2 */ +- label2_ptr = (uint32_t *)s->code_ptr; +- tcg_out32(s, 0); +- +- /* nop (delay slot */ +- tcg_out_nop(s); +- +- /* label1: */ +-#if TARGET_LONG_BITS == 32 +- /* be label1 */ +- *label1_ptr = (INSN_OP(0) | INSN_COND(COND_E, 0) | INSN_OP2(0x2) | +- INSN_OFF22((unsigned long)s->code_ptr - +- (unsigned long)label1_ptr)); +-#else +- /* be,pt %xcc label1 */ +- *label1_ptr = (INSN_OP(0) | INSN_COND(COND_E, 0) | INSN_OP2(0x1) | +- (0x5 << 19) | INSN_OFF19((unsigned long)s->code_ptr - +- (unsigned long)label1_ptr)); +-#endif +- +- /* ld [arg1 + x], arg1 */ +- tcg_out_ldst(s, arg1, arg1, offsetof(CPUTLBEntry, addend) - +- offsetof(CPUTLBEntry, addr_read), TARGET_ADDEND_LD_OP); +- +-#if TARGET_LONG_BITS == 32 +- /* and addr_reg, x, arg0 */ +- tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_I5, 0xffffffff); +- tcg_out_arith(s, arg0, addr_reg, TCG_REG_I5, ARITH_AND); +- /* add arg0, arg1, arg0 */ +- tcg_out_arith(s, arg0, arg0, arg1, ARITH_ADD); ++ *label_ptr[1] |= INSN_OFF19((unsigned long)s->code_ptr - ++ (unsigned long)label_ptr[1]); + #else +- /* add addr_reg, arg1, arg0 */ +- tcg_out_arith(s, arg0, addr_reg, arg1, ARITH_ADD); +-#endif ++ addr_reg = args[addrlo_idx]; ++ if (TCG_TARGET_REG_BITS == 64 && TARGET_LONG_BITS == 32) { ++ tcg_out_arithi(s, TCG_REG_I5, addr_reg, 0, SHIFT_SRL); ++ addr_reg = TCG_REG_I5; ++ } ++ if (TCG_TARGET_REG_BITS == 32 && sizeop == 3) { ++ int reg64 = (datalo < 16 ? datalo : TCG_REG_O0); + +-#else +- arg0 = addr_reg; +-#endif ++ tcg_out_ldst_rr(s, reg64, addr_reg, TCG_REG_G0, qemu_ld_opc[sizeop]); + +- switch(opc) { +- case 0: +- /* ldub [arg0], data_reg */ +- tcg_out_ldst(s, data_reg, arg0, 0, LDUB); +- break; +- case 0 | 4: +- /* ldsb [arg0], data_reg */ +- tcg_out_ldst(s, data_reg, arg0, 0, LDSB); +- break; +- case 1: +-#ifdef TARGET_WORDS_BIGENDIAN +- /* lduh [arg0], data_reg */ +- tcg_out_ldst(s, data_reg, arg0, 0, LDUH); +-#else +- /* lduha [arg0] ASI_PRIMARY_LITTLE, data_reg */ +- tcg_out_ldst_asi(s, data_reg, arg0, 0, LDUHA, ASI_PRIMARY_LITTLE); +-#endif +- break; +- case 1 | 4: +-#ifdef TARGET_WORDS_BIGENDIAN +- /* ldsh [arg0], data_reg */ +- tcg_out_ldst(s, data_reg, arg0, 0, LDSH); +-#else +- /* ldsha [arg0] ASI_PRIMARY_LITTLE, data_reg */ +- tcg_out_ldst_asi(s, data_reg, arg0, 0, LDSHA, ASI_PRIMARY_LITTLE); +-#endif +- break; +- case 2: +-#ifdef TARGET_WORDS_BIGENDIAN +- /* lduw [arg0], data_reg */ +- tcg_out_ldst(s, data_reg, arg0, 0, LDUW); +-#else +- /* lduwa [arg0] ASI_PRIMARY_LITTLE, data_reg */ +- tcg_out_ldst_asi(s, data_reg, arg0, 0, LDUWA, ASI_PRIMARY_LITTLE); +-#endif +- break; +- case 2 | 4: +-#ifdef TARGET_WORDS_BIGENDIAN +- /* ldsw [arg0], data_reg */ +- tcg_out_ldst(s, data_reg, arg0, 0, LDSW); +-#else +- /* ldswa [arg0] ASI_PRIMARY_LITTLE, data_reg */ +- tcg_out_ldst_asi(s, data_reg, arg0, 0, LDSWA, ASI_PRIMARY_LITTLE); +-#endif +- break; +- case 3: +-#ifdef TARGET_WORDS_BIGENDIAN +- /* ldx [arg0], data_reg */ +- tcg_out_ldst(s, data_reg, arg0, 0, LDX); +-#else +- /* ldxa [arg0] ASI_PRIMARY_LITTLE, data_reg */ +- tcg_out_ldst_asi(s, data_reg, arg0, 0, LDXA, ASI_PRIMARY_LITTLE); +-#endif +- break; +- default: +- tcg_abort(); ++ tcg_out_arithi(s, datahi, reg64, 32, SHIFT_SRLX); ++ if (reg64 != datalo) { ++ tcg_out_mov(s, TCG_TYPE_I32, datalo, reg64); ++ } ++ } else { ++ tcg_out_ldst_rr(s, datalo, addr_reg, TCG_REG_G0, qemu_ld_opc[sizeop]); + } +- +-#if defined(CONFIG_SOFTMMU) +- /* label2: */ +- *label2_ptr = (INSN_OP(0) | INSN_COND(COND_A, 0) | INSN_OP2(0x2) | +- INSN_OFF22((unsigned long)s->code_ptr - +- (unsigned long)label2_ptr)); +-#endif ++#endif /* CONFIG_SOFTMMU */ + } + +-static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args, +- int opc) ++static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args, int sizeop) + { +- int addr_reg, data_reg, arg0, arg1, arg2, mem_index, s_bits; ++ int addrlo_idx = 1, datalo, datahi, addr_reg; + #if defined(CONFIG_SOFTMMU) +- uint32_t *label1_ptr, *label2_ptr; ++ int memi_idx, memi, n; ++ uint32_t *label_ptr; + #endif + +- data_reg = *args++; +- addr_reg = *args++; +- mem_index = *args; +- +- s_bits = opc; +- +- arg0 = TCG_REG_O0; +- arg1 = TCG_REG_O1; +- arg2 = TCG_REG_O2; ++ datahi = datalo = args[0]; ++ if (TCG_TARGET_REG_BITS == 32 && sizeop == 3) { ++ datahi = args[1]; ++ addrlo_idx = 2; ++ } + + #if defined(CONFIG_SOFTMMU) +- /* srl addr_reg, x, arg1 */ +- tcg_out_arithi(s, arg1, addr_reg, TARGET_PAGE_BITS - CPU_TLB_ENTRY_BITS, +- SHIFT_SRL); +- +- /* and addr_reg, x, arg0 */ +- tcg_out_arithi(s, arg0, addr_reg, TARGET_PAGE_MASK | ((1 << s_bits) - 1), +- ARITH_AND); +- +- /* and arg1, x, arg1 */ +- tcg_out_andi(s, arg1, (CPU_TLB_SIZE - 1) << CPU_TLB_ENTRY_BITS); +- +- /* add arg1, x, arg1 */ +- tcg_out_addi(s, arg1, offsetof(CPUArchState, +- tlb_table[mem_index][0].addr_write)); ++ memi_idx = addrlo_idx + 1 + (TARGET_LONG_BITS > TCG_TARGET_REG_BITS); ++ memi = args[memi_idx]; ++ ++ addr_reg = tcg_out_tlb_load(s, addrlo_idx, memi, sizeop, args, ++ offsetof(CPUTLBEntry, addr_write)); ++ ++ if (TCG_TARGET_REG_BITS == 32 && sizeop == 3) { ++ /* Reconstruct the full 64-bit value in %g1, using %o2 as temp. */ ++ /* ??? Redefine the temps from %i4/%i5 so that we have a o/g temp. */ ++ tcg_out_arithi(s, TCG_REG_G1, datalo, 0, SHIFT_SRL); ++ tcg_out_arithi(s, TCG_REG_O2, datahi, 32, SHIFT_SLLX); ++ tcg_out_arith(s, TCG_REG_G1, TCG_REG_G1, TCG_REG_O2, ARITH_OR); ++ datalo = TCG_REG_G1; ++ } + +- /* add env, arg1, arg1 */ +- tcg_out_arith(s, arg1, TCG_AREG0, arg1, ARITH_ADD); ++ /* The fast path is exactly one insn. Thus we can perform the entire ++ TLB Hit in the (annulled) delay slot of the branch over TLB Miss. */ ++ /* beq,a,pt %[xi]cc, label0 */ ++ label_ptr = (uint32_t *)s->code_ptr; ++ tcg_out32(s, (INSN_OP(0) | INSN_COND(COND_E, 0) | INSN_OP2(0x1) ++ | ((TARGET_LONG_BITS == 64) << 21) ++ | (1 << 29) | (1 << 19))); ++ /* delay slot */ ++ tcg_out_ldst_rr(s, datalo, addr_reg, TCG_REG_O1, qemu_st_opc[sizeop]); ++ ++ /* TLB Miss. */ ++ ++ n = 0; ++ tcg_out_mov(s, TCG_TYPE_PTR, tcg_target_call_iarg_regs[n++], TCG_AREG0); ++ if (TARGET_LONG_BITS > TCG_TARGET_REG_BITS) { ++ tcg_out_mov(s, TCG_TYPE_REG, tcg_target_call_iarg_regs[n++], ++ args[addrlo_idx + 1]); ++ } ++ tcg_out_mov(s, TCG_TYPE_REG, tcg_target_call_iarg_regs[n++], ++ args[addrlo_idx]); ++ if (TCG_TARGET_REG_BITS == 32 && sizeop == 3) { ++ tcg_out_mov(s, TCG_TYPE_REG, tcg_target_call_iarg_regs[n++], datahi); ++ } ++ tcg_out_mov(s, TCG_TYPE_REG, tcg_target_call_iarg_regs[n++], datalo); + +- /* ld [arg1], arg2 */ +- tcg_out32(s, TARGET_LD_OP | INSN_RD(arg2) | INSN_RS1(arg1) | +- INSN_RS2(TCG_REG_G0)); ++ /* Store AREG0 in stack to avoid ugly glibc bugs that mangle ++ global registers */ ++ tcg_out_st(s, TCG_TYPE_REG, TCG_AREG0, TCG_REG_CALL_STACK, ++ TCG_TARGET_CALL_STACK_OFFSET - TCG_STATIC_CALL_ARGS_SIZE - ++ sizeof(long)); + +- /* subcc arg0, arg2, %g0 */ +- tcg_out_arith(s, TCG_REG_G0, arg0, arg2, ARITH_SUBCC); +- +- /* will become: +- be label1 +- or +- be,pt %xcc label1 */ +- label1_ptr = (uint32_t *)s->code_ptr; +- tcg_out32(s, 0); +- +- /* mov (delay slot) */ +- tcg_out_mov(s, TCG_TYPE_PTR, arg0, addr_reg); +- +- /* mov */ +- tcg_out_mov(s, TCG_TYPE_REG, arg1, data_reg); +- +- /* mov */ +- tcg_out_movi(s, TCG_TYPE_I32, arg2, mem_index); +- +- /* XXX/FIXME: suboptimal */ +- tcg_out_mov(s, TCG_TYPE_I32, tcg_target_call_iarg_regs[3], +- tcg_target_call_iarg_regs[2]); +- tcg_out_mov(s, TCG_TYPE_I64, tcg_target_call_iarg_regs[2], +- tcg_target_call_iarg_regs[1]); +- tcg_out_mov(s, TCG_TYPE_TL, tcg_target_call_iarg_regs[1], +- tcg_target_call_iarg_regs[0]); +- tcg_out_mov(s, TCG_TYPE_PTR, tcg_target_call_iarg_regs[0], +- TCG_AREG0); +- /* XXX: move that code at the end of the TB */ + /* qemu_st_helper[s_bits](arg0, arg1, arg2) */ +- tcg_out32(s, CALL | ((((tcg_target_ulong)qemu_st_helpers[s_bits] ++ tcg_out32(s, CALL | ((((tcg_target_ulong)qemu_st_helpers[sizeop] + - (tcg_target_ulong)s->code_ptr) >> 2) + & 0x3fffffff)); +- /* Store AREG0 in stack to avoid ugly glibc bugs that mangle +- global registers */ +- // delay slot +- tcg_out_ldst(s, TCG_AREG0, TCG_REG_CALL_STACK, +- TCG_TARGET_CALL_STACK_OFFSET - TCG_STATIC_CALL_ARGS_SIZE - +- sizeof(long), HOST_ST_OP); +- tcg_out_ldst(s, TCG_AREG0, TCG_REG_CALL_STACK, +- TCG_TARGET_CALL_STACK_OFFSET - TCG_STATIC_CALL_ARGS_SIZE - +- sizeof(long), HOST_LD_OP); +- +- /* will become: +- ba label2 */ +- label2_ptr = (uint32_t *)s->code_ptr; +- tcg_out32(s, 0); +- +- /* nop (delay slot) */ +- tcg_out_nop(s); ++ /* delay slot */ ++ tcg_out_movi(s, TCG_TYPE_REG, tcg_target_call_iarg_regs[n], memi); + +-#if TARGET_LONG_BITS == 32 +- /* be label1 */ +- *label1_ptr = (INSN_OP(0) | INSN_COND(COND_E, 0) | INSN_OP2(0x2) | +- INSN_OFF22((unsigned long)s->code_ptr - +- (unsigned long)label1_ptr)); +-#else +- /* be,pt %xcc label1 */ +- *label1_ptr = (INSN_OP(0) | INSN_COND(COND_E, 0) | INSN_OP2(0x1) | +- (0x5 << 19) | INSN_OFF19((unsigned long)s->code_ptr - +- (unsigned long)label1_ptr)); +-#endif +- +- /* ld [arg1 + x], arg1 */ +- tcg_out_ldst(s, arg1, arg1, offsetof(CPUTLBEntry, addend) - +- offsetof(CPUTLBEntry, addr_write), TARGET_ADDEND_LD_OP); ++ /* Reload AREG0. */ ++ tcg_out_ld(s, TCG_TYPE_REG, TCG_AREG0, TCG_REG_CALL_STACK, ++ TCG_TARGET_CALL_STACK_OFFSET - TCG_STATIC_CALL_ARGS_SIZE - ++ sizeof(long)); + +-#if TARGET_LONG_BITS == 32 +- /* and addr_reg, x, arg0 */ +- tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_I5, 0xffffffff); +- tcg_out_arith(s, arg0, addr_reg, TCG_REG_I5, ARITH_AND); +- /* add arg0, arg1, arg0 */ +- tcg_out_arith(s, arg0, arg0, arg1, ARITH_ADD); ++ *label_ptr |= INSN_OFF19((unsigned long)s->code_ptr - ++ (unsigned long)label_ptr); + #else +- /* add addr_reg, arg1, arg0 */ +- tcg_out_arith(s, arg0, addr_reg, arg1, ARITH_ADD); +-#endif +- +-#else +- arg0 = addr_reg; +-#endif +- +- switch(opc) { +- case 0: +- /* stb data_reg, [arg0] */ +- tcg_out_ldst(s, data_reg, arg0, 0, STB); +- break; +- case 1: +-#ifdef TARGET_WORDS_BIGENDIAN +- /* sth data_reg, [arg0] */ +- tcg_out_ldst(s, data_reg, arg0, 0, STH); +-#else +- /* stha data_reg, [arg0] ASI_PRIMARY_LITTLE */ +- tcg_out_ldst_asi(s, data_reg, arg0, 0, STHA, ASI_PRIMARY_LITTLE); +-#endif +- break; +- case 2: +-#ifdef TARGET_WORDS_BIGENDIAN +- /* stw data_reg, [arg0] */ +- tcg_out_ldst(s, data_reg, arg0, 0, STW); +-#else +- /* stwa data_reg, [arg0] ASI_PRIMARY_LITTLE */ +- tcg_out_ldst_asi(s, data_reg, arg0, 0, STWA, ASI_PRIMARY_LITTLE); +-#endif +- break; +- case 3: +-#ifdef TARGET_WORDS_BIGENDIAN +- /* stx data_reg, [arg0] */ +- tcg_out_ldst(s, data_reg, arg0, 0, STX); +-#else +- /* stxa data_reg, [arg0] ASI_PRIMARY_LITTLE */ +- tcg_out_ldst_asi(s, data_reg, arg0, 0, STXA, ASI_PRIMARY_LITTLE); +-#endif +- break; +- default: +- tcg_abort(); ++ addr_reg = args[addrlo_idx]; ++ if (TCG_TARGET_REG_BITS == 64 && TARGET_LONG_BITS == 32) { ++ tcg_out_arithi(s, TCG_REG_I5, addr_reg, 0, SHIFT_SRL); ++ addr_reg = TCG_REG_I5; + } +- +-#if defined(CONFIG_SOFTMMU) +- /* label2: */ +- *label2_ptr = (INSN_OP(0) | INSN_COND(COND_A, 0) | INSN_OP2(0x2) | +- INSN_OFF22((unsigned long)s->code_ptr - +- (unsigned long)label2_ptr)); +-#endif ++ if (TCG_TARGET_REG_BITS == 32 && sizeop == 3) { ++ /* Reconstruct the full 64-bit value in %g1, using %o2 as temp. */ ++ /* ??? Redefine the temps from %i4/%i5 so that we have a o/g temp. */ ++ tcg_out_arithi(s, TCG_REG_G1, datalo, 0, SHIFT_SRL); ++ tcg_out_arithi(s, TCG_REG_O2, datahi, 32, SHIFT_SLLX); ++ tcg_out_arith(s, TCG_REG_G1, TCG_REG_G1, TCG_REG_O2, ARITH_OR); ++ datalo = TCG_REG_G1; ++ } ++ tcg_out_ldst_rr(s, datalo, addr_reg, TCG_REG_G0, qemu_st_opc[sizeop]); ++#endif /* CONFIG_SOFTMMU */ + } + + static inline void tcg_out_op(TCGContext *s, TCGOpcode opc, const TCGArg *args, +@@ -1175,12 +1073,12 @@ static inline void tcg_out_op(TCGContext *s, TCGOpcode opc, const TCGArg *args, + /* Store AREG0 in stack to avoid ugly glibc bugs that mangle + global registers */ + // delay slot +- tcg_out_ldst(s, TCG_AREG0, TCG_REG_CALL_STACK, +- TCG_TARGET_CALL_STACK_OFFSET - TCG_STATIC_CALL_ARGS_SIZE - +- sizeof(long), HOST_ST_OP); +- tcg_out_ldst(s, TCG_AREG0, TCG_REG_CALL_STACK, +- TCG_TARGET_CALL_STACK_OFFSET - TCG_STATIC_CALL_ARGS_SIZE - +- sizeof(long), HOST_LD_OP); ++ tcg_out_st(s, TCG_TYPE_REG, TCG_AREG0, TCG_REG_CALL_STACK, ++ TCG_TARGET_CALL_STACK_OFFSET - TCG_STATIC_CALL_ARGS_SIZE - ++ sizeof(long)); ++ tcg_out_ld(s, TCG_TYPE_REG, TCG_AREG0, TCG_REG_CALL_STACK, ++ TCG_TARGET_CALL_STACK_OFFSET - TCG_STATIC_CALL_ARGS_SIZE - ++ sizeof(long)); + break; + case INDEX_op_jmp: + case INDEX_op_br: +@@ -1348,6 +1246,9 @@ static inline void tcg_out_op(TCGContext *s, TCGOpcode opc, const TCGArg *args, + tcg_out_qemu_ld(s, args, 2 | 4); + break; + #endif ++ case INDEX_op_qemu_ld64: ++ tcg_out_qemu_ld(s, args, 3); ++ break; + case INDEX_op_qemu_st8: + tcg_out_qemu_st(s, args, 0); + break; +@@ -1357,6 +1258,9 @@ static inline void tcg_out_op(TCGContext *s, TCGOpcode opc, const TCGArg *args, + case INDEX_op_qemu_st32: + tcg_out_qemu_st(s, args, 2); + break; ++ case INDEX_op_qemu_st64: ++ tcg_out_qemu_st(s, args, 3); ++ break; + + #if TCG_TARGET_REG_BITS == 64 + case INDEX_op_movi_i64: +@@ -1421,13 +1325,6 @@ static inline void tcg_out_op(TCGContext *s, TCGOpcode opc, const TCGArg *args, + args[2], const_args[2]); + break; + +- case INDEX_op_qemu_ld64: +- tcg_out_qemu_ld(s, args, 3); +- break; +- case INDEX_op_qemu_st64: +- tcg_out_qemu_st(s, args, 3); +- break; +- + #endif + gen_arith: + tcg_out_arithc(s, args[0], args[1], args[2], const_args[2], c); +@@ -1492,20 +1389,6 @@ static const TCGTargetOpDef sparc_op_defs[] = { + { INDEX_op_mulu2_i32, { "r", "r", "r", "rJ" } }, + #endif + +- { INDEX_op_qemu_ld8u, { "r", "L" } }, +- { INDEX_op_qemu_ld8s, { "r", "L" } }, +- { INDEX_op_qemu_ld16u, { "r", "L" } }, +- { INDEX_op_qemu_ld16s, { "r", "L" } }, +- { INDEX_op_qemu_ld32, { "r", "L" } }, +-#if TCG_TARGET_REG_BITS == 64 +- { INDEX_op_qemu_ld32u, { "r", "L" } }, +- { INDEX_op_qemu_ld32s, { "r", "L" } }, +-#endif +- +- { INDEX_op_qemu_st8, { "L", "L" } }, +- { INDEX_op_qemu_st16, { "L", "L" } }, +- { INDEX_op_qemu_st32, { "L", "L" } }, +- + #if TCG_TARGET_REG_BITS == 64 + { INDEX_op_mov_i64, { "r", "r" } }, + { INDEX_op_movi_i64, { "r" } }, +@@ -1520,8 +1403,6 @@ static const TCGTargetOpDef sparc_op_defs[] = { + { INDEX_op_st16_i64, { "r", "r" } }, + { INDEX_op_st32_i64, { "r", "r" } }, + { INDEX_op_st_i64, { "r", "r" } }, +- { INDEX_op_qemu_ld64, { "L", "L" } }, +- { INDEX_op_qemu_st64, { "L", "L" } }, + + { INDEX_op_add_i64, { "r", "r", "rJ" } }, + { INDEX_op_mul_i64, { "r", "r", "rJ" } }, +@@ -1548,10 +1429,48 @@ static const TCGTargetOpDef sparc_op_defs[] = { + + { INDEX_op_brcond_i64, { "r", "rJ" } }, + { INDEX_op_setcond_i64, { "r", "r", "rJ" } }, +-#else +- { INDEX_op_qemu_ld64, { "L", "L", "L" } }, ++#endif ++ ++#if TCG_TARGET_REG_BITS == 64 ++ { INDEX_op_qemu_ld8u, { "r", "L" } }, ++ { INDEX_op_qemu_ld8s, { "r", "L" } }, ++ { INDEX_op_qemu_ld16u, { "r", "L" } }, ++ { INDEX_op_qemu_ld16s, { "r", "L" } }, ++ { INDEX_op_qemu_ld32, { "r", "L" } }, ++ { INDEX_op_qemu_ld32u, { "r", "L" } }, ++ { INDEX_op_qemu_ld32s, { "r", "L" } }, ++ { INDEX_op_qemu_ld64, { "r", "L" } }, ++ ++ { INDEX_op_qemu_st8, { "L", "L" } }, ++ { INDEX_op_qemu_st16, { "L", "L" } }, ++ { INDEX_op_qemu_st32, { "L", "L" } }, ++ { INDEX_op_qemu_st64, { "L", "L" } }, ++#elif TARGET_LONG_BITS <= TCG_TARGET_REG_BITS ++ { INDEX_op_qemu_ld8u, { "r", "L" } }, ++ { INDEX_op_qemu_ld8s, { "r", "L" } }, ++ { INDEX_op_qemu_ld16u, { "r", "L" } }, ++ { INDEX_op_qemu_ld16s, { "r", "L" } }, ++ { INDEX_op_qemu_ld32, { "r", "L" } }, ++ { INDEX_op_qemu_ld64, { "r", "r", "L" } }, ++ ++ { INDEX_op_qemu_st8, { "L", "L" } }, ++ { INDEX_op_qemu_st16, { "L", "L" } }, ++ { INDEX_op_qemu_st32, { "L", "L" } }, + { INDEX_op_qemu_st64, { "L", "L", "L" } }, ++#else ++ { INDEX_op_qemu_ld8u, { "r", "L", "L" } }, ++ { INDEX_op_qemu_ld8s, { "r", "L", "L" } }, ++ { INDEX_op_qemu_ld16u, { "r", "L", "L" } }, ++ { INDEX_op_qemu_ld16s, { "r", "L", "L" } }, ++ { INDEX_op_qemu_ld32, { "r", "L", "L" } }, ++ { INDEX_op_qemu_ld64, { "L", "L", "L", "L" } }, ++ ++ { INDEX_op_qemu_st8, { "L", "L", "L" } }, ++ { INDEX_op_qemu_st16, { "L", "L", "L" } }, ++ { INDEX_op_qemu_st32, { "L", "L", "L" } }, ++ { INDEX_op_qemu_st64, { "L", "L", "L", "L" } }, + #endif ++ + { -1 }, + }; + +-- +1.7.12.1 + diff --git a/0086-tcg-sparc-Support-GUEST_BASE.patch b/0086-tcg-sparc-Support-GUEST_BASE.patch new file mode 100644 index 0000000..3e8a175 --- /dev/null +++ b/0086-tcg-sparc-Support-GUEST_BASE.patch @@ -0,0 +1,113 @@ +From fecc7bd255206876152baab622c61902133066bd Mon Sep 17 00:00:00 2001 +From: Richard Henderson +Date: Sat, 24 Mar 2012 22:11:25 +0100 +Subject: [PATCH] tcg-sparc: Support GUEST_BASE. + +Signed-off-by: Richard Henderson +Signed-off-by: Michael Roth +--- + configure | 2 ++ + tcg/sparc/tcg-target.c | 26 +++++++++++++++++++++++--- + tcg/sparc/tcg-target.h | 2 ++ + 3 files changed, 27 insertions(+), 3 deletions(-) + +diff --git a/configure b/configure +index 0590f16..9139b5c 100755 +--- a/configure ++++ b/configure +@@ -872,6 +872,7 @@ case "$cpu" in + if test "$solaris" = "no" ; then + QEMU_CFLAGS="-ffixed-g1 -ffixed-g6 $QEMU_CFLAGS" + fi ++ host_guest_base="yes" + ;; + sparc64) + LDFLAGS="-m64 $LDFLAGS" +@@ -880,6 +881,7 @@ case "$cpu" in + if test "$solaris" != "no" ; then + QEMU_CFLAGS="-ffixed-g1 $QEMU_CFLAGS" + fi ++ host_guest_base="yes" + ;; + s390) + QEMU_CFLAGS="-m31 -march=z990 $QEMU_CFLAGS" +diff --git a/tcg/sparc/tcg-target.c b/tcg/sparc/tcg-target.c +index d89c19b..5acfeba 100644 +--- a/tcg/sparc/tcg-target.c ++++ b/tcg/sparc/tcg-target.c +@@ -59,6 +59,12 @@ static const char * const tcg_target_reg_names[TCG_TARGET_NB_REGS] = { + }; + #endif + ++#ifdef CONFIG_USE_GUEST_BASE ++# define TCG_GUEST_BASE_REG TCG_REG_I3 ++#else ++# define TCG_GUEST_BASE_REG TCG_REG_G0 ++#endif ++ + static const int tcg_target_reg_alloc_order[] = { + TCG_REG_L0, + TCG_REG_L1, +@@ -680,6 +686,14 @@ static void tcg_target_qemu_prologue(TCGContext *s) + tcg_out32(s, SAVE | INSN_RD(TCG_REG_O6) | INSN_RS1(TCG_REG_O6) | + INSN_IMM13(-(TCG_TARGET_STACK_MINFRAME + + CPU_TEMP_BUF_NLONGS * (int)sizeof(long)))); ++ ++#ifdef CONFIG_USE_GUEST_BASE ++ if (GUEST_BASE != 0) { ++ tcg_out_movi(s, TCG_TYPE_PTR, TCG_GUEST_BASE_REG, GUEST_BASE); ++ tcg_regset_set_reg(s->reserved_regs, TCG_GUEST_BASE_REG); ++ } ++#endif ++ + tcg_out32(s, JMPL | INSN_RD(TCG_REG_G0) | INSN_RS1(TCG_REG_I1) | + INSN_RS2(TCG_REG_G0)); + tcg_out_mov(s, TCG_TYPE_PTR, TCG_AREG0, TCG_REG_I0); +@@ -925,14 +939,18 @@ static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args, int sizeop) + if (TCG_TARGET_REG_BITS == 32 && sizeop == 3) { + int reg64 = (datalo < 16 ? datalo : TCG_REG_O0); + +- tcg_out_ldst_rr(s, reg64, addr_reg, TCG_REG_G0, qemu_ld_opc[sizeop]); ++ tcg_out_ldst_rr(s, reg64, addr_reg, ++ (GUEST_BASE ? TCG_GUEST_BASE_REG : TCG_REG_G0), ++ qemu_ld_opc[sizeop]); + + tcg_out_arithi(s, datahi, reg64, 32, SHIFT_SRLX); + if (reg64 != datalo) { + tcg_out_mov(s, TCG_TYPE_I32, datalo, reg64); + } + } else { +- tcg_out_ldst_rr(s, datalo, addr_reg, TCG_REG_G0, qemu_ld_opc[sizeop]); ++ tcg_out_ldst_rr(s, datalo, addr_reg, ++ (GUEST_BASE ? TCG_GUEST_BASE_REG : TCG_REG_G0), ++ qemu_ld_opc[sizeop]); + } + #endif /* CONFIG_SOFTMMU */ + } +@@ -1026,7 +1044,9 @@ static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args, int sizeop) + tcg_out_arith(s, TCG_REG_G1, TCG_REG_G1, TCG_REG_O2, ARITH_OR); + datalo = TCG_REG_G1; + } +- tcg_out_ldst_rr(s, datalo, addr_reg, TCG_REG_G0, qemu_st_opc[sizeop]); ++ tcg_out_ldst_rr(s, datalo, addr_reg, ++ (GUEST_BASE ? TCG_GUEST_BASE_REG : TCG_REG_G0), ++ qemu_st_opc[sizeop]); + #endif /* CONFIG_SOFTMMU */ + } + +diff --git a/tcg/sparc/tcg-target.h b/tcg/sparc/tcg-target.h +index adca1d2..99e9f57 100644 +--- a/tcg/sparc/tcg-target.h ++++ b/tcg/sparc/tcg-target.h +@@ -128,6 +128,8 @@ typedef enum { + #define TCG_TARGET_HAS_movcond_i64 0 + #endif + ++#define TCG_TARGET_HAS_GUEST_BASE ++ + #ifdef CONFIG_SOLARIS + #define TCG_AREG0 TCG_REG_G2 + #elif HOST_LONG_BITS == 64 +-- +1.7.12.1 + diff --git a/0087-tcg-sparc-Change-AREG0-in-generated-code-to-i0.patch b/0087-tcg-sparc-Change-AREG0-in-generated-code-to-i0.patch new file mode 100644 index 0000000..336d7fe --- /dev/null +++ b/0087-tcg-sparc-Change-AREG0-in-generated-code-to-i0.patch @@ -0,0 +1,51 @@ +From d526285d4339f02e3be64a7287d1e009dd5bff3d Mon Sep 17 00:00:00 2001 +From: Richard Henderson +Date: Sun, 25 Mar 2012 19:52:11 +0200 +Subject: [PATCH] tcg-sparc: Change AREG0 in generated code to %i0. + +We can now move the TCG variable from %g[56] to a call-preserved +windowed register. + +Signed-off-by: Richard Henderson +Signed-off-by: Michael Roth +--- + tcg/sparc/tcg-target.c | 3 ++- + tcg/sparc/tcg-target.h | 8 +------- + 2 files changed, 3 insertions(+), 8 deletions(-) + +diff --git a/tcg/sparc/tcg-target.c b/tcg/sparc/tcg-target.c +index 5acfeba..9ab5746 100644 +--- a/tcg/sparc/tcg-target.c ++++ b/tcg/sparc/tcg-target.c +@@ -696,7 +696,8 @@ static void tcg_target_qemu_prologue(TCGContext *s) + + tcg_out32(s, JMPL | INSN_RD(TCG_REG_G0) | INSN_RS1(TCG_REG_I1) | + INSN_RS2(TCG_REG_G0)); +- tcg_out_mov(s, TCG_TYPE_PTR, TCG_AREG0, TCG_REG_I0); ++ /* delay slot */ ++ tcg_out_nop(s); + } + + #if defined(CONFIG_SOFTMMU) +diff --git a/tcg/sparc/tcg-target.h b/tcg/sparc/tcg-target.h +index 99e9f57..ee154d0 100644 +--- a/tcg/sparc/tcg-target.h ++++ b/tcg/sparc/tcg-target.h +@@ -130,13 +130,7 @@ typedef enum { + + #define TCG_TARGET_HAS_GUEST_BASE + +-#ifdef CONFIG_SOLARIS +-#define TCG_AREG0 TCG_REG_G2 +-#elif HOST_LONG_BITS == 64 +-#define TCG_AREG0 TCG_REG_G5 +-#else +-#define TCG_AREG0 TCG_REG_G6 +-#endif ++#define TCG_AREG0 TCG_REG_I0 + + static inline void flush_icache_range(tcg_target_ulong start, + tcg_target_ulong stop) +-- +1.7.12.1 + diff --git a/0088-tcg-sparc-Clean-up-cruft-stemming-from-attempts-to-u.patch b/0088-tcg-sparc-Clean-up-cruft-stemming-from-attempts-to-u.patch new file mode 100644 index 0000000..15c4571 --- /dev/null +++ b/0088-tcg-sparc-Clean-up-cruft-stemming-from-attempts-to-u.patch @@ -0,0 +1,203 @@ +From 5767c23140f2c92b899d9caeaa8e08711cb63868 Mon Sep 17 00:00:00 2001 +From: Richard Henderson +Date: Sun, 25 Mar 2012 21:21:46 +0200 +Subject: [PATCH] tcg-sparc: Clean up cruft stemming from attempts to use + global registers. + +Don't use -ffixed-gN. Don't link statically. Don't save/restore +AREG0 around calls. Don't allocate space on the stack for AREG0 save. + +Signed-off-by: Richard Henderson +Signed-off-by: Michael Roth +--- + configure | 12 ----------- + tcg/sparc/tcg-target.c | 55 +++++++++++++++++--------------------------------- + tcg/sparc/tcg-target.h | 18 +++++++---------- + 3 files changed, 26 insertions(+), 59 deletions(-) + +diff --git a/configure b/configure +index 9139b5c..8ffddf4 100755 +--- a/configure ++++ b/configure +@@ -868,19 +868,11 @@ case "$cpu" in + sparc) + LDFLAGS="-m32 $LDFLAGS" + QEMU_CFLAGS="-m32 -mcpu=ultrasparc $QEMU_CFLAGS" +- QEMU_CFLAGS="-ffixed-g2 -ffixed-g3 $QEMU_CFLAGS" +- if test "$solaris" = "no" ; then +- QEMU_CFLAGS="-ffixed-g1 -ffixed-g6 $QEMU_CFLAGS" +- fi + host_guest_base="yes" + ;; + sparc64) + LDFLAGS="-m64 $LDFLAGS" + QEMU_CFLAGS="-m64 -mcpu=ultrasparc $QEMU_CFLAGS" +- QEMU_CFLAGS="-ffixed-g5 -ffixed-g6 -ffixed-g7 $QEMU_CFLAGS" +- if test "$solaris" != "no" ; then +- QEMU_CFLAGS="-ffixed-g1 $QEMU_CFLAGS" +- fi + host_guest_base="yes" + ;; + s390) +@@ -4055,10 +4047,6 @@ fi + + if test "$target_linux_user" = "yes" -o "$target_bsd_user" = "yes" ; then + case "$ARCH" in +- sparc) +- # -static is used to avoid g1/g3 usage by the dynamic linker +- ldflags="$linker_script -static $ldflags" +- ;; + alpha | s390x) + # The default placement of the application is fine. + ;; +diff --git a/tcg/sparc/tcg-target.c b/tcg/sparc/tcg-target.c +index 9ab5746..e625aa3 100644 +--- a/tcg/sparc/tcg-target.c ++++ b/tcg/sparc/tcg-target.c +@@ -161,7 +161,6 @@ static int target_parse_constraint(TCGArgConstraint *ct, const char **pct_str) + tcg_regset_reset_reg(ct->u.regs, TCG_REG_O0); + tcg_regset_reset_reg(ct->u.regs, TCG_REG_O1); + tcg_regset_reset_reg(ct->u.regs, TCG_REG_O2); +- tcg_regset_reset_reg(ct->u.regs, TCG_REG_O3); + break; + case 'I': + ct->ct |= TCG_CT_CONST_S11; +@@ -681,11 +680,22 @@ static void tcg_out_setcond2_i32(TCGContext *s, TCGCond cond, TCGArg ret, + /* Generate global QEMU prologue and epilogue code */ + static void tcg_target_qemu_prologue(TCGContext *s) + { +- tcg_set_frame(s, TCG_REG_I6, TCG_TARGET_CALL_STACK_OFFSET, +- CPU_TEMP_BUF_NLONGS * (int)sizeof(long)); ++ int tmp_buf_size, frame_size; ++ ++ /* The TCG temp buffer is at the top of the frame, immediately ++ below the frame pointer. */ ++ tmp_buf_size = CPU_TEMP_BUF_NLONGS * (int)sizeof(long); ++ tcg_set_frame(s, TCG_REG_I6, TCG_TARGET_STACK_BIAS - tmp_buf_size, ++ tmp_buf_size); ++ ++ /* TCG_TARGET_CALL_STACK_OFFSET includes the stack bias, but is ++ otherwise the minimal frame usable by callees. */ ++ frame_size = TCG_TARGET_CALL_STACK_OFFSET - TCG_TARGET_STACK_BIAS; ++ frame_size += TCG_STATIC_CALL_ARGS_SIZE + tmp_buf_size; ++ frame_size += TCG_TARGET_STACK_ALIGN - 1; ++ frame_size &= -TCG_TARGET_STACK_ALIGN; + tcg_out32(s, SAVE | INSN_RD(TCG_REG_O6) | INSN_RS1(TCG_REG_O6) | +- INSN_IMM13(-(TCG_TARGET_STACK_MINFRAME + +- CPU_TEMP_BUF_NLONGS * (int)sizeof(long)))); ++ INSN_IMM13(-frame_size)); + + #ifdef CONFIG_USE_GUEST_BASE + if (GUEST_BASE != 0) { +@@ -698,6 +708,8 @@ static void tcg_target_qemu_prologue(TCGContext *s) + INSN_RS2(TCG_REG_G0)); + /* delay slot */ + tcg_out_nop(s); ++ ++ /* No epilogue required. We issue ret + restore directly in the TB. */ + } + + #if defined(CONFIG_SOFTMMU) +@@ -880,12 +892,6 @@ static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args, int sizeop) + tcg_out_mov(s, TCG_TYPE_REG, tcg_target_call_iarg_regs[n++], + args[addrlo_idx]); + +- /* Store AREG0 in stack to avoid ugly glibc bugs that mangle +- global registers */ +- tcg_out_st(s, TCG_TYPE_REG, TCG_AREG0, TCG_REG_CALL_STACK, +- TCG_TARGET_CALL_STACK_OFFSET - TCG_STATIC_CALL_ARGS_SIZE - +- sizeof(long)); +- + /* qemu_ld_helper[s_bits](arg0, arg1) */ + tcg_out32(s, CALL | ((((tcg_target_ulong)qemu_ld_helpers[s_bits] + - (tcg_target_ulong)s->code_ptr) >> 2) +@@ -893,11 +899,6 @@ static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args, int sizeop) + /* delay slot */ + tcg_out_movi(s, TCG_TYPE_I32, tcg_target_call_iarg_regs[n], memi); + +- /* Reload AREG0. */ +- tcg_out_ld(s, TCG_TYPE_REG, TCG_AREG0, TCG_REG_CALL_STACK, +- TCG_TARGET_CALL_STACK_OFFSET - TCG_STATIC_CALL_ARGS_SIZE - +- sizeof(long)); +- + n = tcg_target_call_oarg_regs[0]; + /* datalo = sign_extend(arg0) */ + switch (sizeop) { +@@ -1011,12 +1012,6 @@ static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args, int sizeop) + } + tcg_out_mov(s, TCG_TYPE_REG, tcg_target_call_iarg_regs[n++], datalo); + +- /* Store AREG0 in stack to avoid ugly glibc bugs that mangle +- global registers */ +- tcg_out_st(s, TCG_TYPE_REG, TCG_AREG0, TCG_REG_CALL_STACK, +- TCG_TARGET_CALL_STACK_OFFSET - TCG_STATIC_CALL_ARGS_SIZE - +- sizeof(long)); +- + /* qemu_st_helper[s_bits](arg0, arg1, arg2) */ + tcg_out32(s, CALL | ((((tcg_target_ulong)qemu_st_helpers[sizeop] + - (tcg_target_ulong)s->code_ptr) >> 2) +@@ -1024,11 +1019,6 @@ static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args, int sizeop) + /* delay slot */ + tcg_out_movi(s, TCG_TYPE_REG, tcg_target_call_iarg_regs[n], memi); + +- /* Reload AREG0. */ +- tcg_out_ld(s, TCG_TYPE_REG, TCG_AREG0, TCG_REG_CALL_STACK, +- TCG_TARGET_CALL_STACK_OFFSET - TCG_STATIC_CALL_ARGS_SIZE - +- sizeof(long)); +- + *label_ptr |= INSN_OFF19((unsigned long)s->code_ptr - + (unsigned long)label_ptr); + #else +@@ -1091,15 +1081,8 @@ static inline void tcg_out_op(TCGContext *s, TCGOpcode opc, const TCGArg *args, + tcg_out32(s, JMPL | INSN_RD(TCG_REG_O7) | INSN_RS1(TCG_REG_I5) | + INSN_RS2(TCG_REG_G0)); + } +- /* Store AREG0 in stack to avoid ugly glibc bugs that mangle +- global registers */ +- // delay slot +- tcg_out_st(s, TCG_TYPE_REG, TCG_AREG0, TCG_REG_CALL_STACK, +- TCG_TARGET_CALL_STACK_OFFSET - TCG_STATIC_CALL_ARGS_SIZE - +- sizeof(long)); +- tcg_out_ld(s, TCG_TYPE_REG, TCG_AREG0, TCG_REG_CALL_STACK, +- TCG_TARGET_CALL_STACK_OFFSET - TCG_STATIC_CALL_ARGS_SIZE - +- sizeof(long)); ++ /* delay slot */ ++ tcg_out_nop(s); + break; + case INDEX_op_jmp: + case INDEX_op_br: +diff --git a/tcg/sparc/tcg-target.h b/tcg/sparc/tcg-target.h +index ee154d0..6314ffb 100644 +--- a/tcg/sparc/tcg-target.h ++++ b/tcg/sparc/tcg-target.h +@@ -66,20 +66,16 @@ typedef enum { + #define TCG_CT_CONST_S13 0x200 + + /* used for function call generation */ +-#define TCG_REG_CALL_STACK TCG_REG_I6 ++#define TCG_REG_CALL_STACK TCG_REG_O6 + + #if TCG_TARGET_REG_BITS == 64 +-// Reserve space for AREG0 +-#define TCG_TARGET_STACK_MINFRAME (176 + 4 * (int)sizeof(long) + \ +- TCG_STATIC_CALL_ARGS_SIZE) +-#define TCG_TARGET_CALL_STACK_OFFSET (2047 - 16) +-#define TCG_TARGET_STACK_ALIGN 16 ++#define TCG_TARGET_STACK_BIAS 2047 ++#define TCG_TARGET_STACK_ALIGN 16 ++#define TCG_TARGET_CALL_STACK_OFFSET (128 + 6*8 + TCG_TARGET_STACK_BIAS) + #else +-// AREG0 + one word for alignment +-#define TCG_TARGET_STACK_MINFRAME (92 + (2 + 1) * (int)sizeof(long) + \ +- TCG_STATIC_CALL_ARGS_SIZE) +-#define TCG_TARGET_CALL_STACK_OFFSET TCG_TARGET_STACK_MINFRAME +-#define TCG_TARGET_STACK_ALIGN 8 ++#define TCG_TARGET_STACK_BIAS 0 ++#define TCG_TARGET_STACK_ALIGN 8 ++#define TCG_TARGET_CALL_STACK_OFFSET (64 + 4 + 6*4) + #endif + + #if TCG_TARGET_REG_BITS == 64 +-- +1.7.12.1 + diff --git a/0089-tcg-sparc-Mask-shift-immediates-to-avoid-illegal-ins.patch b/0089-tcg-sparc-Mask-shift-immediates-to-avoid-illegal-ins.patch new file mode 100644 index 0000000..7ce69d1 --- /dev/null +++ b/0089-tcg-sparc-Mask-shift-immediates-to-avoid-illegal-ins.patch @@ -0,0 +1,62 @@ +From 12e60f780a097837840ab1e7bb7d54b8c15112e8 Mon Sep 17 00:00:00 2001 +From: Richard Henderson +Date: Sun, 25 Mar 2012 21:36:28 +0200 +Subject: [PATCH] tcg-sparc: Mask shift immediates to avoid illegal insns. + +The xtensa-test image generates a sra_i32 with count 0x40. +Whether this is accident of tcg constant propagation or +originating directly from the instruction stream is immaterial. + +Signed-off-by: Richard Henderson +Signed-off-by: Michael Roth +--- + tcg/sparc/tcg-target.c | 18 ++++++++++++------ + 1 file changed, 12 insertions(+), 6 deletions(-) + +diff --git a/tcg/sparc/tcg-target.c b/tcg/sparc/tcg-target.c +index e625aa3..be5c170 100644 +--- a/tcg/sparc/tcg-target.c ++++ b/tcg/sparc/tcg-target.c +@@ -1154,13 +1154,16 @@ static inline void tcg_out_op(TCGContext *s, TCGOpcode opc, const TCGArg *args, + goto gen_arith; + case INDEX_op_shl_i32: + c = SHIFT_SLL; +- goto gen_arith; ++ do_shift32: ++ /* Limit immediate shift count lest we create an illegal insn. */ ++ tcg_out_arithc(s, args[0], args[1], args[2] & 31, const_args[2], c); ++ break; + case INDEX_op_shr_i32: + c = SHIFT_SRL; +- goto gen_arith; ++ goto do_shift32; + case INDEX_op_sar_i32: + c = SHIFT_SRA; +- goto gen_arith; ++ goto do_shift32; + case INDEX_op_mul_i32: + c = ARITH_UMUL; + goto gen_arith; +@@ -1281,13 +1284,16 @@ static inline void tcg_out_op(TCGContext *s, TCGOpcode opc, const TCGArg *args, + break; + case INDEX_op_shl_i64: + c = SHIFT_SLLX; +- goto gen_arith; ++ do_shift64: ++ /* Limit immediate shift count lest we create an illegal insn. */ ++ tcg_out_arithc(s, args[0], args[1], args[2] & 63, const_args[2], c); ++ break; + case INDEX_op_shr_i64: + c = SHIFT_SRLX; +- goto gen_arith; ++ goto do_shift64; + case INDEX_op_sar_i64: + c = SHIFT_SRAX; +- goto gen_arith; ++ goto do_shift64; + case INDEX_op_mul_i64: + c = ARITH_MULX; + goto gen_arith; +-- +1.7.12.1 + diff --git a/0090-tcg-sparc-Use-defines-for-temporaries.patch b/0090-tcg-sparc-Use-defines-for-temporaries.patch new file mode 100644 index 0000000..c837d22 --- /dev/null +++ b/0090-tcg-sparc-Use-defines-for-temporaries.patch @@ -0,0 +1,275 @@ +From fc9726f880dea515a2cf98456c5f03a1388e4e14 Mon Sep 17 00:00:00 2001 +From: Richard Henderson +Date: Sun, 25 Mar 2012 22:04:59 +0200 +Subject: [PATCH] tcg-sparc: Use defines for temporaries. + +And change from %i4/%i5 to %g1/%o7 to remove a v8plus fixme. + +Signed-off-by: Richard Henderson +Signed-off-by: Michael Roth +--- + tcg/sparc/tcg-target.c | 115 +++++++++++++++++++++++++------------------------ + 1 file changed, 59 insertions(+), 56 deletions(-) + +diff --git a/tcg/sparc/tcg-target.c b/tcg/sparc/tcg-target.c +index be5c170..d401f8e 100644 +--- a/tcg/sparc/tcg-target.c ++++ b/tcg/sparc/tcg-target.c +@@ -59,8 +59,12 @@ static const char * const tcg_target_reg_names[TCG_TARGET_NB_REGS] = { + }; + #endif + ++/* Define some temporary registers. T2 is used for constant generation. */ ++#define TCG_REG_T1 TCG_REG_G1 ++#define TCG_REG_T2 TCG_REG_O7 ++ + #ifdef CONFIG_USE_GUEST_BASE +-# define TCG_GUEST_BASE_REG TCG_REG_I3 ++# define TCG_GUEST_BASE_REG TCG_REG_I5 + #else + # define TCG_GUEST_BASE_REG TCG_REG_G0 + #endif +@@ -79,6 +83,7 @@ static const int tcg_target_reg_alloc_order[] = { + TCG_REG_I2, + TCG_REG_I3, + TCG_REG_I4, ++ TCG_REG_I5, + }; + + static const int tcg_target_call_iarg_regs[6] = { +@@ -366,10 +371,10 @@ static inline void tcg_out_movi(TCGContext *s, TCGType type, + tcg_out_sethi(s, ret, ~arg); + tcg_out_arithi(s, ret, ret, (arg & 0x3ff) | -0x400, ARITH_XOR); + } else { +- tcg_out_movi_imm32(s, TCG_REG_I4, arg >> (TCG_TARGET_REG_BITS / 2)); +- tcg_out_arithi(s, TCG_REG_I4, TCG_REG_I4, 32, SHIFT_SLLX); +- tcg_out_movi_imm32(s, ret, arg); +- tcg_out_arith(s, ret, ret, TCG_REG_I4, ARITH_OR); ++ tcg_out_movi_imm32(s, ret, arg >> (TCG_TARGET_REG_BITS / 2)); ++ tcg_out_arithi(s, ret, ret, 32, SHIFT_SLLX); ++ tcg_out_movi_imm32(s, TCG_REG_T2, arg); ++ tcg_out_arith(s, ret, ret, TCG_REG_T2, ARITH_OR); + } + } + +@@ -386,8 +391,8 @@ static inline void tcg_out_ldst(TCGContext *s, int ret, int addr, + tcg_out32(s, op | INSN_RD(ret) | INSN_RS1(addr) | + INSN_IMM13(offset)); + } else { +- tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_I5, offset); +- tcg_out_ldst_rr(s, ret, addr, TCG_REG_I5, op); ++ tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_T1, offset); ++ tcg_out_ldst_rr(s, ret, addr, TCG_REG_T1, op); + } + } + +@@ -428,8 +433,8 @@ static inline void tcg_out_addi(TCGContext *s, int reg, tcg_target_long val) + if (check_fit_tl(val, 13)) + tcg_out_arithi(s, reg, reg, val, ARITH_ADD); + else { +- tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_I5, val); +- tcg_out_arith(s, reg, reg, TCG_REG_I5, ARITH_ADD); ++ tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_T1, val); ++ tcg_out_arith(s, reg, reg, TCG_REG_T1, ARITH_ADD); + } + } + } +@@ -441,8 +446,8 @@ static inline void tcg_out_andi(TCGContext *s, int rd, int rs, + if (check_fit_tl(val, 13)) + tcg_out_arithi(s, rd, rs, val, ARITH_AND); + else { +- tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_I5, val); +- tcg_out_arith(s, rd, rs, TCG_REG_I5, ARITH_AND); ++ tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_T1, val); ++ tcg_out_arith(s, rd, rs, TCG_REG_T1, ARITH_AND); + } + } + } +@@ -454,8 +459,8 @@ static void tcg_out_div32(TCGContext *s, int rd, int rs1, + if (uns) { + tcg_out_sety(s, TCG_REG_G0); + } else { +- tcg_out_arithi(s, TCG_REG_I5, rs1, 31, SHIFT_SRA); +- tcg_out_sety(s, TCG_REG_I5); ++ tcg_out_arithi(s, TCG_REG_T1, rs1, 31, SHIFT_SRA); ++ tcg_out_sety(s, TCG_REG_T1); + } + + tcg_out_arithc(s, rd, rs1, val2, val2const, +@@ -601,8 +606,8 @@ static void tcg_out_setcond_i32(TCGContext *s, TCGCond cond, TCGArg ret, + case TCG_COND_GTU: + case TCG_COND_GEU: + if (c2const && c2 != 0) { +- tcg_out_movi_imm13(s, TCG_REG_I5, c2); +- c2 = TCG_REG_I5; ++ tcg_out_movi_imm13(s, TCG_REG_T1, c2); ++ c2 = TCG_REG_T1; + } + t = c1, c1 = c2, c2 = t, c2const = 0; + cond = tcg_swap_cond(cond); +@@ -649,15 +654,15 @@ static void tcg_out_setcond2_i32(TCGContext *s, TCGCond cond, TCGArg ret, + + switch (cond) { + case TCG_COND_EQ: +- tcg_out_setcond_i32(s, TCG_COND_EQ, TCG_REG_I5, al, bl, blconst); ++ tcg_out_setcond_i32(s, TCG_COND_EQ, TCG_REG_T1, al, bl, blconst); + tcg_out_setcond_i32(s, TCG_COND_EQ, ret, ah, bh, bhconst); +- tcg_out_arith(s, ret, ret, TCG_REG_I5, ARITH_AND); ++ tcg_out_arith(s, ret, ret, TCG_REG_T1, ARITH_AND); + break; + + case TCG_COND_NE: +- tcg_out_setcond_i32(s, TCG_COND_NE, TCG_REG_I5, al, al, blconst); ++ tcg_out_setcond_i32(s, TCG_COND_NE, TCG_REG_T1, al, al, blconst); + tcg_out_setcond_i32(s, TCG_COND_NE, ret, ah, bh, bhconst); +- tcg_out_arith(s, ret, ret, TCG_REG_I5, ARITH_OR); ++ tcg_out_arith(s, ret, ret, TCG_REG_T1, ARITH_OR); + break; + + default: +@@ -935,8 +940,8 @@ static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args, int sizeop) + #else + addr_reg = args[addrlo_idx]; + if (TCG_TARGET_REG_BITS == 64 && TARGET_LONG_BITS == 32) { +- tcg_out_arithi(s, TCG_REG_I5, addr_reg, 0, SHIFT_SRL); +- addr_reg = TCG_REG_I5; ++ tcg_out_arithi(s, TCG_REG_T1, addr_reg, 0, SHIFT_SRL); ++ addr_reg = TCG_REG_T1; + } + if (TCG_TARGET_REG_BITS == 32 && sizeop == 3) { + int reg64 = (datalo < 16 ? datalo : TCG_REG_O0); +@@ -979,12 +984,11 @@ static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args, int sizeop) + offsetof(CPUTLBEntry, addr_write)); + + if (TCG_TARGET_REG_BITS == 32 && sizeop == 3) { +- /* Reconstruct the full 64-bit value in %g1, using %o2 as temp. */ +- /* ??? Redefine the temps from %i4/%i5 so that we have a o/g temp. */ +- tcg_out_arithi(s, TCG_REG_G1, datalo, 0, SHIFT_SRL); ++ /* Reconstruct the full 64-bit value. */ ++ tcg_out_arithi(s, TCG_REG_T1, datalo, 0, SHIFT_SRL); + tcg_out_arithi(s, TCG_REG_O2, datahi, 32, SHIFT_SLLX); +- tcg_out_arith(s, TCG_REG_G1, TCG_REG_G1, TCG_REG_O2, ARITH_OR); +- datalo = TCG_REG_G1; ++ tcg_out_arith(s, TCG_REG_O2, TCG_REG_T1, TCG_REG_O2, ARITH_OR); ++ datalo = TCG_REG_O2; + } + + /* The fast path is exactly one insn. Thus we can perform the entire +@@ -1024,16 +1028,14 @@ static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args, int sizeop) + #else + addr_reg = args[addrlo_idx]; + if (TCG_TARGET_REG_BITS == 64 && TARGET_LONG_BITS == 32) { +- tcg_out_arithi(s, TCG_REG_I5, addr_reg, 0, SHIFT_SRL); +- addr_reg = TCG_REG_I5; ++ tcg_out_arithi(s, TCG_REG_T1, addr_reg, 0, SHIFT_SRL); ++ addr_reg = TCG_REG_T1; + } + if (TCG_TARGET_REG_BITS == 32 && sizeop == 3) { +- /* Reconstruct the full 64-bit value in %g1, using %o2 as temp. */ +- /* ??? Redefine the temps from %i4/%i5 so that we have a o/g temp. */ +- tcg_out_arithi(s, TCG_REG_G1, datalo, 0, SHIFT_SRL); ++ tcg_out_arithi(s, TCG_REG_T1, datalo, 0, SHIFT_SRL); + tcg_out_arithi(s, TCG_REG_O2, datahi, 32, SHIFT_SLLX); +- tcg_out_arith(s, TCG_REG_G1, TCG_REG_G1, TCG_REG_O2, ARITH_OR); +- datalo = TCG_REG_G1; ++ tcg_out_arith(s, TCG_REG_O2, TCG_REG_T1, TCG_REG_O2, ARITH_OR); ++ datalo = TCG_REG_O2; + } + tcg_out_ldst_rr(s, datalo, addr_reg, + (GUEST_BASE ? TCG_GUEST_BASE_REG : TCG_REG_G0), +@@ -1057,28 +1059,29 @@ static inline void tcg_out_op(TCGContext *s, TCGOpcode opc, const TCGArg *args, + case INDEX_op_goto_tb: + if (s->tb_jmp_offset) { + /* direct jump method */ +- tcg_out_sethi(s, TCG_REG_I5, args[0] & 0xffffe000); +- tcg_out32(s, JMPL | INSN_RD(TCG_REG_G0) | INSN_RS1(TCG_REG_I5) | ++ tcg_out_sethi(s, TCG_REG_T1, args[0] & 0xffffe000); ++ tcg_out32(s, JMPL | INSN_RD(TCG_REG_G0) | INSN_RS1(TCG_REG_T1) | + INSN_IMM13((args[0] & 0x1fff))); + s->tb_jmp_offset[args[0]] = s->code_ptr - s->code_buf; + } else { + /* indirect jump method */ +- tcg_out_ld_ptr(s, TCG_REG_I5, (tcg_target_long)(s->tb_next + args[0])); +- tcg_out32(s, JMPL | INSN_RD(TCG_REG_G0) | INSN_RS1(TCG_REG_I5) | ++ tcg_out_ld_ptr(s, TCG_REG_T1, ++ (tcg_target_long)(s->tb_next + args[0])); ++ tcg_out32(s, JMPL | INSN_RD(TCG_REG_G0) | INSN_RS1(TCG_REG_T1) | + INSN_RS2(TCG_REG_G0)); + } + tcg_out_nop(s); + s->tb_next_offset[args[0]] = s->code_ptr - s->code_buf; + break; + case INDEX_op_call: +- if (const_args[0]) ++ if (const_args[0]) { + tcg_out32(s, CALL | ((((tcg_target_ulong)args[0] + - (tcg_target_ulong)s->code_ptr) >> 2) + & 0x3fffffff)); +- else { +- tcg_out_ld_ptr(s, TCG_REG_I5, ++ } else { ++ tcg_out_ld_ptr(s, TCG_REG_T1, + (tcg_target_long)(s->tb_next + args[0])); +- tcg_out32(s, JMPL | INSN_RD(TCG_REG_O7) | INSN_RS1(TCG_REG_I5) | ++ tcg_out32(s, JMPL | INSN_RD(TCG_REG_O7) | INSN_RS1(TCG_REG_T1) | + INSN_RS2(TCG_REG_G0)); + } + /* delay slot */ +@@ -1184,11 +1187,11 @@ static inline void tcg_out_op(TCGContext *s, TCGOpcode opc, const TCGArg *args, + + case INDEX_op_rem_i32: + case INDEX_op_remu_i32: +- tcg_out_div32(s, TCG_REG_I5, args[1], args[2], const_args[2], ++ tcg_out_div32(s, TCG_REG_T1, args[1], args[2], const_args[2], + opc == INDEX_op_remu_i32); +- tcg_out_arithc(s, TCG_REG_I5, TCG_REG_I5, args[2], const_args[2], ++ tcg_out_arithc(s, TCG_REG_T1, TCG_REG_T1, args[2], const_args[2], + ARITH_UMUL); +- tcg_out_arith(s, args[0], args[1], TCG_REG_I5, ARITH_SUB); ++ tcg_out_arith(s, args[0], args[1], TCG_REG_T1, ARITH_SUB); + break; + + case INDEX_op_brcond_i32: +@@ -1305,11 +1308,11 @@ static inline void tcg_out_op(TCGContext *s, TCGOpcode opc, const TCGArg *args, + goto gen_arith; + case INDEX_op_rem_i64: + case INDEX_op_remu_i64: +- tcg_out_arithc(s, TCG_REG_I5, args[1], args[2], const_args[2], ++ tcg_out_arithc(s, TCG_REG_T1, args[1], args[2], const_args[2], + opc == INDEX_op_rem_i64 ? ARITH_SDIVX : ARITH_UDIVX); +- tcg_out_arithc(s, TCG_REG_I5, TCG_REG_I5, args[2], const_args[2], ++ tcg_out_arithc(s, TCG_REG_T1, TCG_REG_T1, args[2], const_args[2], + ARITH_MULX); +- tcg_out_arith(s, args[0], args[1], TCG_REG_I5, ARITH_SUB); ++ tcg_out_arith(s, args[0], args[1], TCG_REG_T1, ARITH_SUB); + break; + case INDEX_op_ext32s_i64: + if (const_args[1]) { +@@ -1507,15 +1510,15 @@ static void tcg_target_init(TCGContext *s) + (1 << TCG_REG_O7)); + + tcg_regset_clear(s->reserved_regs); +- tcg_regset_set_reg(s->reserved_regs, TCG_REG_G0); +-#if TCG_TARGET_REG_BITS == 64 +- tcg_regset_set_reg(s->reserved_regs, TCG_REG_I4); // for internal use +-#endif +- tcg_regset_set_reg(s->reserved_regs, TCG_REG_I5); // for internal use +- tcg_regset_set_reg(s->reserved_regs, TCG_REG_I6); +- tcg_regset_set_reg(s->reserved_regs, TCG_REG_I7); +- tcg_regset_set_reg(s->reserved_regs, TCG_REG_O6); +- tcg_regset_set_reg(s->reserved_regs, TCG_REG_O7); ++ tcg_regset_set_reg(s->reserved_regs, TCG_REG_G0); /* zero */ ++ tcg_regset_set_reg(s->reserved_regs, TCG_REG_G6); /* reserved for os */ ++ tcg_regset_set_reg(s->reserved_regs, TCG_REG_G7); /* thread pointer */ ++ tcg_regset_set_reg(s->reserved_regs, TCG_REG_I6); /* frame pointer */ ++ tcg_regset_set_reg(s->reserved_regs, TCG_REG_I7); /* return address */ ++ tcg_regset_set_reg(s->reserved_regs, TCG_REG_O6); /* stack pointer */ ++ tcg_regset_set_reg(s->reserved_regs, TCG_REG_T1); /* for internal use */ ++ tcg_regset_set_reg(s->reserved_regs, TCG_REG_T2); /* for internal use */ ++ + tcg_add_target_add_op_defs(sparc_op_defs); + } + +-- +1.7.12.1 + diff --git a/0091-tcg-sparc-Add-g-o-registers-to-alloc_order.patch b/0091-tcg-sparc-Add-g-o-registers-to-alloc_order.patch new file mode 100644 index 0000000..2bf9e95 --- /dev/null +++ b/0091-tcg-sparc-Add-g-o-registers-to-alloc_order.patch @@ -0,0 +1,44 @@ +From ca72cdf648b56d851c4bc9145a1abfcbeeec0579 Mon Sep 17 00:00:00 2001 +From: Richard Henderson +Date: Sun, 25 Mar 2012 22:43:17 +0200 +Subject: [PATCH] tcg-sparc: Add %g/%o registers to alloc_order + +Signed-off-by: Richard Henderson +Signed-off-by: Michael Roth +--- + tcg/sparc/tcg-target.c | 13 +++++++++++++ + 1 file changed, 13 insertions(+) + +diff --git a/tcg/sparc/tcg-target.c b/tcg/sparc/tcg-target.c +index d401f8e..03c385a 100644 +--- a/tcg/sparc/tcg-target.c ++++ b/tcg/sparc/tcg-target.c +@@ -78,12 +78,25 @@ static const int tcg_target_reg_alloc_order[] = { + TCG_REG_L5, + TCG_REG_L6, + TCG_REG_L7, ++ + TCG_REG_I0, + TCG_REG_I1, + TCG_REG_I2, + TCG_REG_I3, + TCG_REG_I4, + TCG_REG_I5, ++ ++ TCG_REG_G2, ++ TCG_REG_G3, ++ TCG_REG_G4, ++ TCG_REG_G5, ++ ++ TCG_REG_O0, ++ TCG_REG_O1, ++ TCG_REG_O2, ++ TCG_REG_O3, ++ TCG_REG_O4, ++ TCG_REG_O5, + }; + + static const int tcg_target_call_iarg_regs[6] = { +-- +1.7.12.1 + diff --git a/0092-tcg-sparc-Fix-and-enable-direct-TB-chaining.patch b/0092-tcg-sparc-Fix-and-enable-direct-TB-chaining.patch new file mode 100644 index 0000000..7b876c0 --- /dev/null +++ b/0092-tcg-sparc-Fix-and-enable-direct-TB-chaining.patch @@ -0,0 +1,79 @@ +From 1338a6f18ff9b651c12ee1f7edd1d2b7684bd6aa Mon Sep 17 00:00:00 2001 +From: Richard Henderson +Date: Fri, 21 Sep 2012 10:48:51 -0700 +Subject: [PATCH] tcg-sparc: Fix and enable direct TB chaining. + +Signed-off-by: Richard Henderson +Signed-off-by: Michael Roth +--- + exec-all.h | 9 ++++++--- + tcg/sparc/tcg-target.c | 21 ++++++++++++++++++--- + 2 files changed, 24 insertions(+), 6 deletions(-) + +diff --git a/exec-all.h b/exec-all.h +index c5d3a13..1f81da7 100644 +--- a/exec-all.h ++++ b/exec-all.h +@@ -132,9 +132,10 @@ static inline void tlb_flush(CPUArchState *env, int flush_global) + #define CODE_GEN_AVG_BLOCK_SIZE 64 + #endif + +-#if defined(_ARCH_PPC) || defined(__x86_64__) || defined(__arm__) || defined(__i386__) +-#define USE_DIRECT_JUMP +-#elif defined(CONFIG_TCG_INTERPRETER) ++#if defined(__arm__) || defined(_ARCH_PPC) \ ++ || defined(__x86_64__) || defined(__i386__) \ ++ || defined(__sparc__) \ ++ || defined(CONFIG_TCG_INTERPRETER) + #define USE_DIRECT_JUMP + #endif + +@@ -244,6 +245,8 @@ static inline void tb_set_jmp_target1(uintptr_t jmp_addr, uintptr_t addr) + __asm __volatile__ ("swi 0x9f0002" : : "r" (_beg), "r" (_end), "r" (_flg)); + #endif + } ++#elif defined(__sparc__) ++void tb_set_jmp_target1(uintptr_t jmp_addr, uintptr_t addr); + #else + #error tb_set_jmp_target1 is missing + #endif +diff --git a/tcg/sparc/tcg-target.c b/tcg/sparc/tcg-target.c +index 03c385a..1db0c9d 100644 +--- a/tcg/sparc/tcg-target.c ++++ b/tcg/sparc/tcg-target.c +@@ -1072,10 +1072,10 @@ static inline void tcg_out_op(TCGContext *s, TCGOpcode opc, const TCGArg *args, + case INDEX_op_goto_tb: + if (s->tb_jmp_offset) { + /* direct jump method */ +- tcg_out_sethi(s, TCG_REG_T1, args[0] & 0xffffe000); +- tcg_out32(s, JMPL | INSN_RD(TCG_REG_G0) | INSN_RS1(TCG_REG_T1) | +- INSN_IMM13((args[0] & 0x1fff))); ++ uint32_t old_insn = *(uint32_t *)s->code_ptr; + s->tb_jmp_offset[args[0]] = s->code_ptr - s->code_buf; ++ /* Make sure to preserve links during retranslation. */ ++ tcg_out32(s, CALL | (old_insn & ~INSN_OP(-1))); + } else { + /* indirect jump method */ + tcg_out_ld_ptr(s, TCG_REG_T1, +@@ -1595,3 +1595,18 @@ void tcg_register_jit(void *buf, size_t buf_size) + + tcg_register_jit_int(buf, buf_size, &debug_frame, sizeof(debug_frame)); + } ++ ++void tb_set_jmp_target1(uintptr_t jmp_addr, uintptr_t addr) ++{ ++ uint32_t *ptr = (uint32_t *)jmp_addr; ++ tcg_target_long disp = (tcg_target_long)(addr - jmp_addr) >> 2; ++ ++ /* We can reach the entire address space for 32-bit. For 64-bit ++ the code_gen_buffer can't be larger than 2GB. */ ++ if (TCG_TARGET_REG_BITS == 64 && !check_fit_tl(disp, 30)) { ++ tcg_abort(); ++ } ++ ++ *ptr = CALL | (disp & 0x3fffffff); ++ flush_icache_range(jmp_addr, jmp_addr + 4); ++} +-- +1.7.12.1 + diff --git a/0093-tcg-sparc-Preserve-branch-destinations-during-retran.patch b/0093-tcg-sparc-Preserve-branch-destinations-during-retran.patch new file mode 100644 index 0000000..167dc41 --- /dev/null +++ b/0093-tcg-sparc-Preserve-branch-destinations-during-retran.patch @@ -0,0 +1,60 @@ +From 2cbc27913eb9eb7cdc4a41fc6efafccf3db7ebe6 Mon Sep 17 00:00:00 2001 +From: Richard Henderson +Date: Fri, 21 Sep 2012 11:00:23 -0700 +Subject: [PATCH] tcg-sparc: Preserve branch destinations during retranslation + +Signed-off-by: Richard Henderson +Signed-off-by: Michael Roth +--- + tcg/sparc/tcg-target.c | 19 +++++++++++-------- + 1 file changed, 11 insertions(+), 8 deletions(-) + +diff --git a/tcg/sparc/tcg-target.c b/tcg/sparc/tcg-target.c +index 1db0c9d..876da4f 100644 +--- a/tcg/sparc/tcg-target.c ++++ b/tcg/sparc/tcg-target.c +@@ -488,30 +488,33 @@ static inline void tcg_out_nop(TCGContext *s) + static void tcg_out_branch_i32(TCGContext *s, int opc, int label_index) + { + TCGLabel *l = &s->labels[label_index]; ++ uint32_t off22; + + if (l->has_value) { +- tcg_out32(s, (INSN_OP(0) | INSN_COND(opc, 0) | INSN_OP2(0x2) +- | INSN_OFF22(l->u.value - (unsigned long)s->code_ptr))); ++ off22 = INSN_OFF22(l->u.value - (unsigned long)s->code_ptr); + } else { ++ /* Make sure to preserve destinations during retranslation. */ ++ off22 = *(uint32_t *)s->code_ptr & INSN_OFF22(-1); + tcg_out_reloc(s, s->code_ptr, R_SPARC_WDISP22, label_index, 0); +- tcg_out32(s, (INSN_OP(0) | INSN_COND(opc, 0) | INSN_OP2(0x2) | 0)); + } ++ tcg_out32(s, INSN_OP(0) | INSN_COND(opc, 0) | INSN_OP2(0x2) | off22); + } + + #if TCG_TARGET_REG_BITS == 64 + static void tcg_out_branch_i64(TCGContext *s, int opc, int label_index) + { + TCGLabel *l = &s->labels[label_index]; ++ uint32_t off19; + + if (l->has_value) { +- tcg_out32(s, (INSN_OP(0) | INSN_COND(opc, 0) | INSN_OP2(0x1) | +- (0x5 << 19) | +- INSN_OFF19(l->u.value - (unsigned long)s->code_ptr))); ++ off19 = INSN_OFF19(l->u.value - (unsigned long)s->code_ptr); + } else { ++ /* Make sure to preserve destinations during retranslation. */ ++ off19 = *(uint32_t *)s->code_ptr & INSN_OFF19(-1); + tcg_out_reloc(s, s->code_ptr, R_SPARC_WDISP19, label_index, 0); +- tcg_out32(s, (INSN_OP(0) | INSN_COND(opc, 0) | INSN_OP2(0x1) | +- (0x5 << 19) | 0)); + } ++ tcg_out32(s, (INSN_OP(0) | INSN_COND(opc, 0) | INSN_OP2(0x1) | ++ (0x5 << 19) | off19)); + } + #endif + +-- +1.7.12.1 + diff --git a/0094-target-alpha-Initialize-env-cpu_model_str.patch b/0094-target-alpha-Initialize-env-cpu_model_str.patch new file mode 100644 index 0000000..9734b0e --- /dev/null +++ b/0094-target-alpha-Initialize-env-cpu_model_str.patch @@ -0,0 +1,33 @@ +From fcf8cef0c7d8d197e863c1e8b7bcb567fa1fe729 Mon Sep 17 00:00:00 2001 +From: Richard Henderson +Date: Fri, 21 Sep 2012 14:15:36 +0200 +Subject: [PATCH] target-alpha: Initialize env->cpu_model_str +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Save the cpu_model_str so that we have a non-null value when +creating a new cpu during clone. + +Signed-off-by: Richard Henderson +Signed-off-by: Andreas Färber +Signed-off-by: Michael Roth +--- + target-alpha/translate.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/target-alpha/translate.c b/target-alpha/translate.c +index 4a9011a..3f9aee1 100644 +--- a/target-alpha/translate.c ++++ b/target-alpha/translate.c +@@ -3543,6 +3543,7 @@ CPUAlphaState * cpu_alpha_init (const char *cpu_model) + } + env->implver = implver; + env->amask = amask; ++ env->cpu_model_str = cpu_model; + + qemu_init_vcpu(env); + return env; +-- +1.7.12.1 + diff --git a/0095-tcg-mips-fix-MIPS32-R2-detection.patch b/0095-tcg-mips-fix-MIPS32-R2-detection.patch new file mode 100644 index 0000000..e145e3b --- /dev/null +++ b/0095-tcg-mips-fix-MIPS32-R2-detection.patch @@ -0,0 +1,93 @@ +From 66588d01b8cb710d746c249a34f31f7f353bc697 Mon Sep 17 00:00:00 2001 +From: Aurelien Jarno +Date: Sat, 22 Sep 2012 23:08:38 +0200 +Subject: [PATCH] tcg/mips: fix MIPS32(R2) detection + +Fix the MIPS32(R2) cpu detection so that it also works with +-march=octeon. Thanks to Andrew Pinski for the hint. + +Cc: Andrew Pinski +Signed-off-by: Aurelien Jarno +Signed-off-by: Michael Roth +--- + tcg/mips/tcg-target.c | 10 +++++----- + tcg/mips/tcg-target.h | 8 ++++---- + 2 files changed, 9 insertions(+), 9 deletions(-) + +diff --git a/tcg/mips/tcg-target.c b/tcg/mips/tcg-target.c +index c272b38..e9a1ffb 100644 +--- a/tcg/mips/tcg-target.c ++++ b/tcg/mips/tcg-target.c +@@ -425,7 +425,7 @@ static inline void tcg_out_movi(TCGContext *s, TCGType type, + + static inline void tcg_out_bswap16(TCGContext *s, TCGReg ret, TCGReg arg) + { +-#ifdef _MIPS_ARCH_MIPS32R2 ++#if defined(__mips_isa_rev) && (__mips_isa_rev >= 2) + tcg_out_opc_reg(s, OPC_WSBH, ret, 0, arg); + #else + /* ret and arg can't be register at */ +@@ -442,7 +442,7 @@ static inline void tcg_out_bswap16(TCGContext *s, TCGReg ret, TCGReg arg) + + static inline void tcg_out_bswap16s(TCGContext *s, TCGReg ret, TCGReg arg) + { +-#ifdef _MIPS_ARCH_MIPS32R2 ++#if defined(__mips_isa_rev) && (__mips_isa_rev >= 2) + tcg_out_opc_reg(s, OPC_WSBH, ret, 0, arg); + tcg_out_opc_reg(s, OPC_SEH, ret, 0, ret); + #else +@@ -460,7 +460,7 @@ static inline void tcg_out_bswap16s(TCGContext *s, TCGReg ret, TCGReg arg) + + static inline void tcg_out_bswap32(TCGContext *s, TCGReg ret, TCGReg arg) + { +-#ifdef _MIPS_ARCH_MIPS32R2 ++#if defined(__mips_isa_rev) && (__mips_isa_rev >= 2) + tcg_out_opc_reg(s, OPC_WSBH, ret, 0, arg); + tcg_out_opc_sa(s, OPC_ROTR, ret, ret, 16); + #else +@@ -486,7 +486,7 @@ static inline void tcg_out_bswap32(TCGContext *s, TCGReg ret, TCGReg arg) + + static inline void tcg_out_ext8s(TCGContext *s, TCGReg ret, TCGReg arg) + { +-#ifdef _MIPS_ARCH_MIPS32R2 ++#if defined(__mips_isa_rev) && (__mips_isa_rev >= 2) + tcg_out_opc_reg(s, OPC_SEB, ret, 0, arg); + #else + tcg_out_opc_sa(s, OPC_SLL, ret, arg, 24); +@@ -496,7 +496,7 @@ static inline void tcg_out_ext8s(TCGContext *s, TCGReg ret, TCGReg arg) + + static inline void tcg_out_ext16s(TCGContext *s, TCGReg ret, TCGReg arg) + { +-#ifdef _MIPS_ARCH_MIPS32R2 ++#if defined(__mips_isa_rev) && (__mips_isa_rev >= 2) + tcg_out_opc_reg(s, OPC_SEH, ret, 0, arg); + #else + tcg_out_opc_sa(s, OPC_SLL, ret, arg, 16); +diff --git a/tcg/mips/tcg-target.h b/tcg/mips/tcg-target.h +index d147e70..7020d65 100644 +--- a/tcg/mips/tcg-target.h ++++ b/tcg/mips/tcg-target.h +@@ -88,16 +88,16 @@ typedef enum { + #define TCG_TARGET_HAS_nand_i32 0 + + /* optional instructions only implemented on MIPS4, MIPS32 and Loongson 2 */ +-#if defined(_MIPS_ARCH_MIPS4) || defined(_MIPS_ARCH_MIPS32) || \ +- defined(_MIPS_ARCH_MIPS32R2) || defined(_MIPS_ARCH_LOONGSON2E) || \ +- defined(_MIPS_ARCH_LOONGSON2F) ++#if (defined(__mips_isa_rev) && (__mips_isa_rev >= 1)) || \ ++ defined(_MIPS_ARCH_LOONGSON2E) || defined(_MIPS_ARCH_LOONGSON2F) || \ ++ defined(_MIPS_ARCH_MIPS4) + #define TCG_TARGET_HAS_movcond_i32 1 + #else + #define TCG_TARGET_HAS_movcond_i32 0 + #endif + + /* optional instructions only implemented on MIPS32R2 */ +-#ifdef _MIPS_ARCH_MIPS32R2 ++#if defined(__mips_isa_rev) && (__mips_isa_rev >= 2) + #define TCG_TARGET_HAS_bswap16_i32 1 + #define TCG_TARGET_HAS_bswap32_i32 1 + #define TCG_TARGET_HAS_rot_i32 1 +-- +1.7.12.1 + diff --git a/0096-tcg-Adjust-descriptions-of-cond-opcodes.patch b/0096-tcg-Adjust-descriptions-of-cond-opcodes.patch new file mode 100644 index 0000000..64c62cb --- /dev/null +++ b/0096-tcg-Adjust-descriptions-of-cond-opcodes.patch @@ -0,0 +1,67 @@ +From a2c90b264762d3ddcc9a830653315a6fe9107055 Mon Sep 17 00:00:00 2001 +From: Richard Henderson +Date: Fri, 21 Sep 2012 17:18:09 -0700 +Subject: [PATCH] tcg: Adjust descriptions of *cond opcodes + +The README file documented the operand ordering of the tcg_gen_* +functions. Since we're documenting opcodes here, use the true +operand ordering. + +Signed-off-by: Richard Henderson +Cc: malc +Signed-off-by: Aurelien Jarno +Signed-off-by: Michael Roth +--- + tcg/README | 10 +++++----- + 1 file changed, 5 insertions(+), 5 deletions(-) + +diff --git a/tcg/README b/tcg/README +index 33783ee..27846f1 100644 +--- a/tcg/README ++++ b/tcg/README +@@ -141,7 +141,7 @@ Define label 'label' at the current program point. + + Jump to label. + +-* brcond_i32/i64 cond, t0, t1, label ++* brcond_i32/i64 t0, t1, cond, label + + Conditional jump if t0 cond t1 is true. cond can be: + TCG_COND_EQ +@@ -301,13 +301,13 @@ This operation would be equivalent to + + ********* Conditional moves + +-* setcond_i32/i64 cond, dest, t1, t2 ++* setcond_i32/i64 dest, t1, t2, cond + + dest = (t1 cond t2) + + Set DEST to 1 if (T1 cond T2) is true, otherwise set to 0. + +-* movcond_i32/i64 cond, dest, c1, c2, v1, v2 ++* movcond_i32/i64 dest, c1, c2, v1, v2, cond + + dest = (c1 cond c2 ? v1 : v2) + +@@ -360,7 +360,7 @@ The following opcodes are internal to TCG. Thus they are to be implemented by + 32-bit host code generators, but are not to be emitted by guest translators. + They are emitted as needed by inline functions within "tcg-op.h". + +-* brcond2_i32 cond, t0_low, t0_high, t1_low, t1_high, label ++* brcond2_i32 t0_low, t0_high, t1_low, t1_high, cond, label + + Similar to brcond, except that the 64-bit values T0 and T1 + are formed from two 32-bit arguments. +@@ -377,7 +377,7 @@ is returned in two 32-bit outputs. + Similar to mul, except two 32-bit (unsigned) inputs T1 and T2 yielding + the full 64-bit product T0. The later is returned in two 32-bit outputs. + +-* setcond2_i32 cond, dest, t1_low, t1_high, t2_low, t2_high ++* setcond2_i32 dest, t1_low, t1_high, t2_low, t2_high, cond + + Similar to setcond, except that the 64-bit values T1 and T2 are + formed from two 32-bit arguments. The result is a 32-bit value. +-- +1.7.12.1 + diff --git a/0097-tcg-i386-fix-build-with-march-i686.patch b/0097-tcg-i386-fix-build-with-march-i686.patch new file mode 100644 index 0000000..a841086 --- /dev/null +++ b/0097-tcg-i386-fix-build-with-march-i686.patch @@ -0,0 +1,34 @@ +From 5d3868bb343df0c13240521e36d0cc942c7a2d04 Mon Sep 17 00:00:00 2001 +From: Aurelien Jarno +Date: Wed, 26 Sep 2012 00:30:12 +0200 +Subject: [PATCH] tcg/i386: fix build with -march < i686 + +The movcond_i32 op has to be protected with TCG_TARGET_HAS_movcond_i32 +to fix the build with -march < i686. + +Thanks to Richard Henderson for the hint. + +Reported-by: Alex Barcelo +Signed-off-by: Aurelien Jarno +Signed-off-by: Michael Roth +--- + tcg/i386/tcg-target.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/tcg/i386/tcg-target.c b/tcg/i386/tcg-target.c +index 85c6b81..616ef23 100644 +--- a/tcg/i386/tcg-target.c ++++ b/tcg/i386/tcg-target.c +@@ -1907,7 +1907,9 @@ static const TCGTargetOpDef x86_op_defs[] = { + { INDEX_op_setcond_i32, { "q", "r", "ri" } }, + + { INDEX_op_deposit_i32, { "Q", "0", "Q" } }, ++#if TCG_TARGET_HAS_movcond_i32 + { INDEX_op_movcond_i32, { "r", "r", "ri", "r", "0" } }, ++#endif + + #if TCG_TARGET_REG_BITS == 32 + { INDEX_op_mulu2_i32, { "a", "d", "a", "r" } }, +-- +1.7.12.1 + diff --git a/0098-tcg-Fix-MAX_OPC_PARAM_IARGS.patch b/0098-tcg-Fix-MAX_OPC_PARAM_IARGS.patch new file mode 100644 index 0000000..dfc44fa --- /dev/null +++ b/0098-tcg-Fix-MAX_OPC_PARAM_IARGS.patch @@ -0,0 +1,52 @@ +From 86aeba1e72542270a2ae2570cdfcfa6b9e59eeb8 Mon Sep 17 00:00:00 2001 +From: Stefan Weil +Date: Wed, 12 Sep 2012 19:18:55 +0200 +Subject: [PATCH] tcg: Fix MAX_OPC_PARAM_IARGS + +DEF_HELPER_FLAGS_5 was added some time ago without adjusting +MAX_OPC_PARAM_IARGS. + +Fixing the definition becomes more important as QEMU is using +an increasing number of helper functions called with 5 arguments. + +Add also a comment to avoid future problems when DEF_HELPER_FLAGS_6 +will be added. + +Signed-off-by: Stefan Weil +Reviewed-by: Richard Henderson +Signed-off-by: Blue Swirl +Signed-off-by: Michael Roth +--- + def-helper.h | 2 ++ + exec-all.h | 2 +- + 2 files changed, 3 insertions(+), 1 deletion(-) + +diff --git a/def-helper.h b/def-helper.h +index b98ff69..022a9ce 100644 +--- a/def-helper.h ++++ b/def-helper.h +@@ -128,6 +128,8 @@ + #define DEF_HELPER_5(name, ret, t1, t2, t3, t4, t5) \ + DEF_HELPER_FLAGS_5(name, 0, ret, t1, t2, t3, t4, t5) + ++/* MAX_OPC_PARAM_IARGS must be set to n if last entry is DEF_HELPER_FLAGS_n. */ ++ + #endif /* DEF_HELPER_H */ + + #ifndef GEN_HELPER +diff --git a/exec-all.h b/exec-all.h +index 1f81da7..6516da0 100644 +--- a/exec-all.h ++++ b/exec-all.h +@@ -51,7 +51,7 @@ typedef struct TranslationBlock TranslationBlock; + #else + #define MAX_OPC_PARAM_PER_ARG 1 + #endif +-#define MAX_OPC_PARAM_IARGS 4 ++#define MAX_OPC_PARAM_IARGS 5 + #define MAX_OPC_PARAM_OARGS 1 + #define MAX_OPC_PARAM_ARGS (MAX_OPC_PARAM_IARGS + MAX_OPC_PARAM_OARGS) + +-- +1.7.12.1 + diff --git a/0099-tci-Fix-for-AREG0-free-mode.patch b/0099-tci-Fix-for-AREG0-free-mode.patch new file mode 100644 index 0000000..c67e4a3 --- /dev/null +++ b/0099-tci-Fix-for-AREG0-free-mode.patch @@ -0,0 +1,119 @@ +From 2acbc7d596b022dca4fc147eb89e3d5f297acb1f Mon Sep 17 00:00:00 2001 +From: Stefan Weil +Date: Tue, 18 Sep 2012 22:43:38 +0200 +Subject: [PATCH] tci: Fix for AREG0 free mode + +Support for helper functions with 5 arguments was missing +in the code generator and in the interpreter. + +There is no need to pass the constant TCG_AREG0 from the +code generator to the interpreter. Remove that code for +the INDEX_op_qemu_st* opcodes. + +Signed-off-by: Stefan Weil +Signed-off-by: Aurelien Jarno +Signed-off-by: Michael Roth +--- + tcg/tci/tcg-target.c | 10 +++++----- + tci.c | 13 +++++++++---- + 2 files changed, 14 insertions(+), 9 deletions(-) + +diff --git a/tcg/tci/tcg-target.c b/tcg/tci/tcg-target.c +index 003244c..c8c2f1d 100644 +--- a/tcg/tci/tcg-target.c ++++ b/tcg/tci/tcg-target.c +@@ -300,7 +300,7 @@ static const int tcg_target_reg_alloc_order[] = { + #endif + }; + +-#if MAX_OPC_PARAM_IARGS != 4 ++#if MAX_OPC_PARAM_IARGS != 5 + # error Fix needed, number of supported input arguments changed! + #endif + +@@ -309,16 +309,18 @@ static const int tcg_target_call_iarg_regs[] = { + TCG_REG_R1, + TCG_REG_R2, + TCG_REG_R3, +-#if TCG_TARGET_REG_BITS == 32 +- /* 32 bit hosts need 2 * MAX_OPC_PARAM_IARGS registers. */ + #if 0 /* used for TCG_REG_CALL_STACK */ + TCG_REG_R4, + #endif + TCG_REG_R5, ++#if TCG_TARGET_REG_BITS == 32 ++ /* 32 bit hosts need 2 * MAX_OPC_PARAM_IARGS registers. */ + TCG_REG_R6, + TCG_REG_R7, + #if TCG_TARGET_NB_REGS >= 16 + TCG_REG_R8, ++ TCG_REG_R9, ++ TCG_REG_R10, + #else + # error Too few input registers available + #endif +@@ -798,7 +800,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, const TCGArg *args, + case INDEX_op_qemu_st8: + case INDEX_op_qemu_st16: + case INDEX_op_qemu_st32: +- tcg_out_r(s, TCG_AREG0); + tcg_out_r(s, *args++); + tcg_out_r(s, *args++); + #if TARGET_LONG_BITS > TCG_TARGET_REG_BITS +@@ -809,7 +810,6 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc, const TCGArg *args, + #endif + break; + case INDEX_op_qemu_st64: +- tcg_out_r(s, TCG_AREG0); + tcg_out_r(s, *args++); + #if TCG_TARGET_REG_BITS == 32 + tcg_out_r(s, *args++); +diff --git a/tci.c b/tci.c +index ce8a988..a4f7b78 100644 +--- a/tci.c ++++ b/tci.c +@@ -36,17 +36,19 @@ + tcg_abort(); \ + } while (0) + +-#if MAX_OPC_PARAM_IARGS != 4 ++#if MAX_OPC_PARAM_IARGS != 5 + # error Fix needed, number of supported input arguments changed! + #endif + #if TCG_TARGET_REG_BITS == 32 + typedef uint64_t (*helper_function)(tcg_target_ulong, tcg_target_ulong, + tcg_target_ulong, tcg_target_ulong, + tcg_target_ulong, tcg_target_ulong, ++ tcg_target_ulong, tcg_target_ulong, + tcg_target_ulong, tcg_target_ulong); + #else + typedef uint64_t (*helper_function)(tcg_target_ulong, tcg_target_ulong, +- tcg_target_ulong, tcg_target_ulong); ++ tcg_target_ulong, tcg_target_ulong, ++ tcg_target_ulong); + #endif + + /* TCI can optionally use a global register variable for env. */ +@@ -489,14 +491,17 @@ tcg_target_ulong tcg_qemu_tb_exec(CPUArchState *cpustate, uint8_t *tb_ptr) + tci_read_reg(TCG_REG_R5), + tci_read_reg(TCG_REG_R6), + tci_read_reg(TCG_REG_R7), +- tci_read_reg(TCG_REG_R8)); ++ tci_read_reg(TCG_REG_R8), ++ tci_read_reg(TCG_REG_R9), ++ tci_read_reg(TCG_REG_R10)); + tci_write_reg(TCG_REG_R0, tmp64); + tci_write_reg(TCG_REG_R1, tmp64 >> 32); + #else + tmp64 = ((helper_function)t0)(tci_read_reg(TCG_REG_R0), + tci_read_reg(TCG_REG_R1), + tci_read_reg(TCG_REG_R2), +- tci_read_reg(TCG_REG_R3)); ++ tci_read_reg(TCG_REG_R3), ++ tci_read_reg(TCG_REG_R5)); + tci_write_reg(TCG_REG_R0, tmp64); + #endif + break; +-- +1.7.12.1 + diff --git a/0100-spice-abort-on-invalid-streaming-cmdline-params.patch b/0100-spice-abort-on-invalid-streaming-cmdline-params.patch new file mode 100644 index 0000000..d73d347 --- /dev/null +++ b/0100-spice-abort-on-invalid-streaming-cmdline-params.patch @@ -0,0 +1,41 @@ +From 9fa75115d0f300817a372dd8b9460d6b65a30b20 Mon Sep 17 00:00:00 2001 +From: Christophe Fergeau +Date: Mon, 13 Aug 2012 10:32:32 +0200 +Subject: [PATCH] spice: abort on invalid streaming cmdline params + +When parsing its command line parameters, spice aborts when it +finds unexpected values, except for the 'streaming-video' option. +This happens because the parsing of the parameters for this option +is done using the 'name2enum' helper, which does not error out +on unknown values. Using the 'parse_name' helper makes sure we +error out in this case. Looking at git history, the use of +'name2enum' instead of 'parse_name' seems to have been an oversight, +so let's change to that now. + +Fixes rhbz#831708 + +Signed-off-by: Gerd Hoffmann +(cherry picked from commit 835cab85ad83ed8dfe1c13243aeda5959b153e3e) + +Signed-off-by: Michael Roth +--- + ui/spice-core.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/ui/spice-core.c b/ui/spice-core.c +index 4fc48f8..bb4f585 100644 +--- a/ui/spice-core.c ++++ b/ui/spice-core.c +@@ -344,7 +344,8 @@ static const char *stream_video_names[] = { + [ SPICE_STREAM_VIDEO_FILTER ] = "filter", + }; + #define parse_stream_video(_name) \ +- name2enum(_name, stream_video_names, ARRAY_SIZE(stream_video_names)) ++ parse_name(_name, "stream video control", \ ++ stream_video_names, ARRAY_SIZE(stream_video_names)) + + static const char *compression_names[] = { + [ SPICE_IMAGE_COMPRESS_OFF ] = "off", +-- +1.7.12.1 + diff --git a/0101-char-Split-out-tcp-socket-close-code-in-a-separate-f.patch b/0101-char-Split-out-tcp-socket-close-code-in-a-separate-f.patch deleted file mode 100644 index ea8dfc8..0000000 --- a/0101-char-Split-out-tcp-socket-close-code-in-a-separate-f.patch +++ /dev/null @@ -1,59 +0,0 @@ -From 90a59d545ad6759c105b0bfcfca70f574482584f Mon Sep 17 00:00:00 2001 -Message-Id: <90a59d545ad6759c105b0bfcfca70f574482584f.1346162949.git.crobinso@redhat.com> -From: Amit Shah -Date: Mon, 21 Mar 2011 21:57:47 +0100 -Subject: [PATCH 101/114] char: Split out tcp socket close code in a separate - function - -Signed-off-by: Amit Shah -Signed-off-by: Cole Robinson ---- - qemu-char.c | 25 ++++++++++++++++--------- - 1 file changed, 16 insertions(+), 9 deletions(-) - -diff --git a/qemu-char.c b/qemu-char.c -index 398baf1..8c53c05 100644 ---- a/qemu-char.c -+++ b/qemu-char.c -@@ -2143,6 +2143,21 @@ static void tcp_chr_accept(void *opaque); - - static void tcp_chr_connect(void *opaque); - -+static void tcp_closed(void *opaque) -+{ -+ CharDriverState *chr = opaque; -+ TCPCharDriver *s = chr->opaque; -+ -+ s->connected = 0; -+ if (s->listen_fd >= 0) { -+ qemu_set_fd_handler2(s->listen_fd, NULL, tcp_chr_accept, NULL, chr); -+ } -+ qemu_set_fd_handler2(s->fd, NULL, NULL, NULL, NULL); -+ closesocket(s->fd); -+ s->fd = -1; -+ qemu_chr_be_event(chr, CHR_EVENT_CLOSED); -+} -+ - static int tcp_chr_write(CharDriverState *chr, const uint8_t *buf, int len) - { - TCPCharDriver *s = chr->opaque; -@@ -2302,15 +2317,7 @@ static void tcp_chr_read(void *opaque) - len = s->max_size; - size = tcp_chr_recv(chr, (void *)buf, len); - if (size == 0) { -- /* connection closed */ -- s->connected = 0; -- if (s->listen_fd >= 0) { -- qemu_set_fd_handler2(s->listen_fd, NULL, tcp_chr_accept, NULL, chr); -- } -- qemu_set_fd_handler2(s->fd, NULL, NULL, NULL, NULL); -- closesocket(s->fd); -- s->fd = -1; -- qemu_chr_be_event(chr, CHR_EVENT_CLOSED); -+ tcp_closed(chr); - } else if (size > 0) { - if (s->do_telnetopt) - tcp_chr_process_IAC_bytes(chr, s, buf, &size); --- -1.7.11.2 - diff --git a/0101-spice-notify-spice-server-on-vm-start-stop.patch b/0101-spice-notify-spice-server-on-vm-start-stop.patch new file mode 100644 index 0000000..708bfe0 --- /dev/null +++ b/0101-spice-notify-spice-server-on-vm-start-stop.patch @@ -0,0 +1,55 @@ +From 7fbcbd48d2898935369b443a489ea79d49fe19c4 Mon Sep 17 00:00:00 2001 +From: Yonit Halperin +Date: Tue, 21 Aug 2012 11:51:55 +0300 +Subject: [PATCH] spice: notify spice server on vm start/stop + +Spice server needs to know about the vm state in order to prevent +attempts to write to devices when they are stopped, mainly during +the non-live stage of migration. +Instead, spice will take care of restoring this writes, on the migration +target side, after migration completes. + +Signed-off-by: Yonit Halperin +Signed-off-by: Gerd Hoffmann +(cherry picked from commit f5bb039c6d97ef3e664094eab3c9a4dc1824ed73) + +Signed-off-by: Michael Roth +--- + ui/spice-core.c | 14 ++++++++++++++ + 1 file changed, 14 insertions(+) + +diff --git a/ui/spice-core.c b/ui/spice-core.c +index bb4f585..a515c94 100644 +--- a/ui/spice-core.c ++++ b/ui/spice-core.c +@@ -546,6 +546,18 @@ static int add_channel(const char *name, const char *value, void *opaque) + return 0; + } + ++static void vm_change_state_handler(void *opaque, int running, ++ RunState state) ++{ ++#if SPICE_SERVER_VERSION >= 0x000b02 /* 0.11.2 */ ++ if (running) { ++ spice_server_vm_start(spice_server); ++ } else { ++ spice_server_vm_stop(spice_server); ++ } ++#endif ++} ++ + void qemu_spice_init(void) + { + QemuOpts *opts = QTAILQ_FIRST(&qemu_spice_opts.head); +@@ -719,6 +731,8 @@ void qemu_spice_init(void) + qemu_spice_input_init(); + qemu_spice_audio_init(); + ++ qemu_add_vm_change_state_handler(vm_change_state_handler, &spice_server); ++ + g_free(x509_key_file); + g_free(x509_cert_file); + g_free(x509_cacert_file); +-- +1.7.12.1 + diff --git a/0102-char-Add-a-QemuChrHandlers-struct-to-initialise-char.patch b/0102-char-Add-a-QemuChrHandlers-struct-to-initialise-char.patch deleted file mode 100644 index cd48ce3..0000000 --- a/0102-char-Add-a-QemuChrHandlers-struct-to-initialise-char.patch +++ /dev/null @@ -1,965 +0,0 @@ -From 25533bd7228f5cd62499a26ba5e32be024002beb Mon Sep 17 00:00:00 2001 -Message-Id: <25533bd7228f5cd62499a26ba5e32be024002beb.1346162949.git.crobinso@redhat.com> -In-Reply-To: <90a59d545ad6759c105b0bfcfca70f574482584f.1346162949.git.crobinso@redhat.com> -References: <90a59d545ad6759c105b0bfcfca70f574482584f.1346162949.git.crobinso@redhat.com> -From: Amit Shah -Date: Mon, 21 Mar 2011 20:31:45 +0100 -Subject: [PATCH 102/114] char: Add a QemuChrHandlers struct to initialise - chardev handlers - -Instead of passing each handler in the qemu_add_handlers() function, -create a struct of handlers that can be passed to the function instead. - -Signed-off-by: Amit Shah -Signed-off-by: Cole Robinson ---- - gdbstub.c | 9 +++++++-- - hw/cadence_uart.c | 9 +++++++-- - hw/ccid-card-passthru.c | 11 +++++++---- - hw/debugcon.c | 2 +- - hw/escc.c | 9 +++++++-- - hw/etraxfs_ser.c | 13 +++++++++---- - hw/exynos4210_uart.c | 9 +++++++-- - hw/grlib_apbuart.c | 12 +++++++----- - hw/imx_serial.c | 9 +++++++-- - hw/ivshmem.c | 28 ++++++++++++++++++++++------ - hw/lm32_juart.c | 8 +++++++- - hw/lm32_uart.c | 8 +++++++- - hw/mcf_uart.c | 9 +++++++-- - hw/milkymist-uart.c | 8 +++++++- - hw/pl011.c | 9 +++++++-- - hw/pxa2xx.c | 13 +++++++++---- - hw/qdev-properties.c | 2 +- - hw/serial.c | 9 +++++++-- - hw/sh_serial.c | 12 +++++++++--- - hw/spapr_vty.c | 8 ++++++-- - hw/strongarm.c | 12 +++++++----- - hw/usb/dev-serial.c | 9 +++++++-- - hw/usb/redirect.c | 9 +++++++-- - hw/virtio-console.c | 9 +++++++-- - hw/xen_console.c | 16 +++++++++++----- - hw/xilinx_uartlite.c | 11 +++++++++-- - monitor.c | 18 ++++++++++++++---- - net/slirp.c | 8 ++++++-- - qemu-char.c | 32 ++++++++++++++++++++++---------- - qemu-char.h | 13 +++++++++---- - qtest.c | 9 ++++++++- - 31 files changed, 255 insertions(+), 88 deletions(-) - -diff --git a/gdbstub.c b/gdbstub.c -index 5d37dd9..7f6b1cb 100644 ---- a/gdbstub.c -+++ b/gdbstub.c -@@ -2929,6 +2929,12 @@ static void gdb_sigterm_handler(int signal) - } - #endif - -+static const QemuChrHandlers gdb_handlers = { -+ .fd_can_read = gdb_chr_can_receive, -+ .fd_read = gdb_chr_receive, -+ .fd_event = gdb_chr_event, -+}; -+ - int gdbserver_start(const char *device) - { - GDBState *s; -@@ -2958,8 +2964,7 @@ int gdbserver_start(const char *device) - if (!chr) - return -1; - -- qemu_chr_add_handlers(chr, gdb_chr_can_receive, gdb_chr_receive, -- gdb_chr_event, NULL); -+ qemu_chr_add_handlers(chr, &gdb_handlers, NULL); - } - - s = gdbserver_state; -diff --git a/hw/cadence_uart.c b/hw/cadence_uart.c -index d98e531..8f7d64a 100644 ---- a/hw/cadence_uart.c -+++ b/hw/cadence_uart.c -@@ -435,6 +435,12 @@ static void cadence_uart_reset(UartState *s) - s->rx_wpos = 0; - } - -+static const QemuChrHandlers cadence_uart_handlers = { -+ .fd_can_read = uart_can_receive, -+ .fd_read = uart_receive, -+ .fd_event = uart_event, -+}; -+ - static int cadence_uart_init(SysBusDevice *dev) - { - UartState *s = FROM_SYSBUS(UartState, dev); -@@ -456,8 +462,7 @@ static int cadence_uart_init(SysBusDevice *dev) - cadence_uart_reset(s); - - if (s->chr) { -- qemu_chr_add_handlers(s->chr, uart_can_receive, uart_receive, -- uart_event, s); -+ qemu_chr_add_handlers(s->chr, &cadence_uart_handlers, s); - } - - return 0; -diff --git a/hw/ccid-card-passthru.c b/hw/ccid-card-passthru.c -index bd6c777..fb32107 100644 ---- a/hw/ccid-card-passthru.c -+++ b/hw/ccid-card-passthru.c -@@ -274,6 +274,12 @@ static const uint8_t *passthru_get_atr(CCIDCardState *base, uint32_t *len) - return card->atr; - } - -+static const QemuChrHandlers passthru_handlers = { -+ .fd_can_read = ccid_card_vscard_can_read, -+ .fd_read = ccid_card_vscard_read, -+ .fd_event = ccid_card_vscard_event, -+}; -+ - static int passthru_initfn(CCIDCardState *base) - { - PassthruState *card = DO_UPCAST(PassthruState, base, base); -@@ -282,10 +288,7 @@ static int passthru_initfn(CCIDCardState *base) - card->vscard_in_hdr = 0; - if (card->cs) { - DPRINTF(card, D_INFO, "initing chardev\n"); -- qemu_chr_add_handlers(card->cs, -- ccid_card_vscard_can_read, -- ccid_card_vscard_read, -- ccid_card_vscard_event, card); -+ qemu_chr_add_handlers(card->cs, &passthru_handlers, card); - ccid_card_vscard_send_init(card); - } else { - error_report("missing chardev"); -diff --git a/hw/debugcon.c b/hw/debugcon.c -index 14ab326..7887fd2 100644 ---- a/hw/debugcon.c -+++ b/hw/debugcon.c -@@ -73,7 +73,7 @@ static void debugcon_init_core(DebugconState *s) - exit(1); - } - -- qemu_chr_add_handlers(s->chr, NULL, NULL, NULL, s); -+ qemu_chr_add_handlers(s->chr, NULL, s); - } - - static int debugcon_isa_initfn(ISADevice *dev) -diff --git a/hw/escc.c b/hw/escc.c -index e1f5e73..ff9d8b1 100644 ---- a/hw/escc.c -+++ b/hw/escc.c -@@ -867,6 +867,12 @@ void slavio_serial_ms_kbd_init(target_phys_addr_t base, qemu_irq irq, - sysbus_mmio_map(s, 0, base); - } - -+static const QemuChrHandlers serial_handlers = { -+ .fd_can_read = serial_can_receive, -+ .fd_read = serial_receive1, -+ .fd_event = serial_event, -+}; -+ - static int escc_init1(SysBusDevice *dev) - { - SerialState *s = FROM_SYSBUS(SerialState, dev); -@@ -879,8 +885,7 @@ static int escc_init1(SysBusDevice *dev) - s->chn[i].chn = 1 - i; - s->chn[i].clock = s->frequency / 2; - if (s->chn[i].chr) { -- qemu_chr_add_handlers(s->chn[i].chr, serial_can_receive, -- serial_receive1, serial_event, &s->chn[i]); -+ qemu_chr_add_handlers(s->chn[i].chr, &serial_handlers, &s->chn[i]); - } - } - s->chn[0].otherchn = &s->chn[1]; -diff --git a/hw/etraxfs_ser.c b/hw/etraxfs_ser.c -index 5f16b17..f2571c2 100644 ---- a/hw/etraxfs_ser.c -+++ b/hw/etraxfs_ser.c -@@ -208,6 +208,12 @@ static void etraxfs_ser_reset(DeviceState *d) - - } - -+static const QemuChrHandlers serial_handlers = { -+ .fd_can_read = serial_can_receive, -+ .fd_read = serial_receive, -+ .fd_event = serial_event, -+}; -+ - static int etraxfs_ser_init(SysBusDevice *dev) - { - struct etrax_serial *s = FROM_SYSBUS(typeof (*s), dev); -@@ -217,10 +223,9 @@ static int etraxfs_ser_init(SysBusDevice *dev) - sysbus_init_mmio(dev, &s->mmio); - - s->chr = qemu_char_get_next_serial(); -- if (s->chr) -- qemu_chr_add_handlers(s->chr, -- serial_can_receive, serial_receive, -- serial_event, s); -+ if (s->chr) { -+ qemu_chr_add_handlers(s->chr, &serial_handlers, s); -+ } - return 0; - } - -diff --git a/hw/exynos4210_uart.c b/hw/exynos4210_uart.c -index ccc4780..fefe400 100644 ---- a/hw/exynos4210_uart.c -+++ b/hw/exynos4210_uart.c -@@ -625,6 +625,12 @@ DeviceState *exynos4210_uart_create(target_phys_addr_t addr, - return dev; - } - -+static const QemuChrHandlers exynos4210_handlers = { -+ .fd_can_read = exynos4210_uart_can_receive, -+ .fd_read = exynos4210_uart_receive, -+ .fd_event = exynos4210_uart_event, -+}; -+ - static int exynos4210_uart_init(SysBusDevice *dev) - { - Exynos4210UartState *s = FROM_SYSBUS(Exynos4210UartState, dev); -@@ -636,8 +642,7 @@ static int exynos4210_uart_init(SysBusDevice *dev) - - sysbus_init_irq(dev, &s->irq); - -- qemu_chr_add_handlers(s->chr, exynos4210_uart_can_receive, -- exynos4210_uart_receive, exynos4210_uart_event, s); -+ qemu_chr_add_handlers(s->chr, &exynos4210_handlers, s); - - return 0; - } -diff --git a/hw/grlib_apbuart.c b/hw/grlib_apbuart.c -index 73fc989..fd77d52 100644 ---- a/hw/grlib_apbuart.c -+++ b/hw/grlib_apbuart.c -@@ -222,15 +222,17 @@ static const MemoryRegionOps grlib_apbuart_ops = { - .endianness = DEVICE_NATIVE_ENDIAN, - }; - -+static const QemuChrHandlers grlib_handlers = { -+ .fd_can_read = grlib_apbuart_can_receive, -+ .fd_read = grlib_apbuart_receive, -+ .fd_event = grlib_apbuart_event, -+}; -+ - static int grlib_apbuart_init(SysBusDevice *dev) - { - UART *uart = FROM_SYSBUS(typeof(*uart), dev); - -- qemu_chr_add_handlers(uart->chr, -- grlib_apbuart_can_receive, -- grlib_apbuart_receive, -- grlib_apbuart_event, -- uart); -+ qemu_chr_add_handlers(uart->chr, &grlib_handlers, uart); - - sysbus_init_irq(dev, &uart->irq); - -diff --git a/hw/imx_serial.c b/hw/imx_serial.c -index d4eae43..f2304d2 100644 ---- a/hw/imx_serial.c -+++ b/hw/imx_serial.c -@@ -381,6 +381,12 @@ static const struct MemoryRegionOps imx_serial_ops = { - .endianness = DEVICE_NATIVE_ENDIAN, - }; - -+static const QemuChrHandlers imx_handlers = { -+ .fd_can_read = imx_can_receive, -+ .fd_read = imx_receive, -+ .fd_event = imx_event, -+}; -+ - static int imx_serial_init(SysBusDevice *dev) - { - IMXSerialState *s = FROM_SYSBUS(IMXSerialState, dev); -@@ -391,8 +397,7 @@ static int imx_serial_init(SysBusDevice *dev) - sysbus_init_irq(dev, &s->irq); - - if (s->chr) { -- qemu_chr_add_handlers(s->chr, imx_can_receive, imx_receive, -- imx_event, s); -+ qemu_chr_add_handlers(s->chr, &imx_handlers, s); - } else { - DPRINTF("No char dev for uart at 0x%lx\n", - (unsigned long)s->iomem.ram_addr); -diff --git a/hw/ivshmem.c b/hw/ivshmem.c -index b4d65a6..f20a356 100644 ---- a/hw/ivshmem.c -+++ b/hw/ivshmem.c -@@ -273,6 +273,18 @@ static void fake_irqfd(void *opaque, const uint8_t *buf, int size) { - msix_notify(pdev, entry->vector); - } - -+static const QemuChrHandlers ivshmem_handlers = { -+ .fd_can_read = ivshmem_can_receive, -+ .fd_read = ivshmem_receive, -+ .fd_event = ivshmem_event, -+}; -+ -+static const QemuChrHandlers ivshmem_msi_handlers = { -+ .fd_can_read = ivshmem_can_receive, -+ .fd_read = fake_irqfd, -+ .fd_event = ivshmem_event, -+}; -+ - static CharDriverState* create_eventfd_chr_device(void * opaque, EventNotifier *n, - int vector) - { -@@ -293,11 +305,10 @@ static CharDriverState* create_eventfd_chr_device(void * opaque, EventNotifier * - s->eventfd_table[vector].pdev = &s->dev; - s->eventfd_table[vector].vector = vector; - -- qemu_chr_add_handlers(chr, ivshmem_can_receive, fake_irqfd, -- ivshmem_event, &s->eventfd_table[vector]); -+ qemu_chr_add_handlers(chr, &ivshmem_msi_handlers, -+ &s->eventfd_table[vector]); - } else { -- qemu_chr_add_handlers(chr, ivshmem_can_receive, ivshmem_receive, -- ivshmem_event, s); -+ qemu_chr_add_handlers(chr, &ivshmem_handlers, s); - } - - return chr; -@@ -641,6 +652,12 @@ static void ivshmem_write_config(PCIDevice *pci_dev, uint32_t address, - msix_write_config(pci_dev, address, val, len); - } - -+static const QemuChrHandlers ivshmem_server_handlers = { -+ .fd_can_read = ivshmem_can_receive, -+ .fd_read = ivshmem_read, -+ .fd_event = ivshmem_event, -+}; -+ - static int pci_ivshmem_init(PCIDevice *dev) - { - IVShmemState *s = DO_UPCAST(IVShmemState, dev, dev); -@@ -731,8 +748,7 @@ static int pci_ivshmem_init(PCIDevice *dev) - - s->eventfd_chr = g_malloc0(s->vectors * sizeof(CharDriverState *)); - -- qemu_chr_add_handlers(s->server_chr, ivshmem_can_receive, ivshmem_read, -- ivshmem_event, s); -+ qemu_chr_add_handlers(s->server_chr, &ivshmem_server_handlers, s); - } else { - /* just map the file immediately, we're not using a server */ - int fd; -diff --git a/hw/lm32_juart.c b/hw/lm32_juart.c -index f07ed39..d4daeb8 100644 ---- a/hw/lm32_juart.c -+++ b/hw/lm32_juart.c -@@ -110,13 +110,19 @@ static void juart_reset(DeviceState *d) - s->jrx = 0; - } - -+static const QemuChrHandlers juart_handlers = { -+ .fd_can_read = juart_can_rx, -+ .fd_read = juart_rx, -+ .fd_event = juart_event, -+}; -+ - static int lm32_juart_init(SysBusDevice *dev) - { - LM32JuartState *s = FROM_SYSBUS(typeof(*s), dev); - - s->chr = qemu_char_get_next_serial(); - if (s->chr) { -- qemu_chr_add_handlers(s->chr, juart_can_rx, juart_rx, juart_event, s); -+ qemu_chr_add_handlers(s->chr, &juart_handlers, s); - } - - return 0; -diff --git a/hw/lm32_uart.c b/hw/lm32_uart.c -index 57066e2..4ea130b 100644 ---- a/hw/lm32_uart.c -+++ b/hw/lm32_uart.c -@@ -243,6 +243,12 @@ static void uart_reset(DeviceState *d) - s->regs[R_LSR] = LSR_THRE | LSR_TEMT; - } - -+static const QemuChrHandlers uart_handlers = { -+ .fd_can_read = uart_can_rx, -+ .fd_read = uart_rx, -+ .fd_event = uart_event, -+}; -+ - static int lm32_uart_init(SysBusDevice *dev) - { - LM32UartState *s = FROM_SYSBUS(typeof(*s), dev); -@@ -254,7 +260,7 @@ static int lm32_uart_init(SysBusDevice *dev) - - s->chr = qemu_char_get_next_serial(); - if (s->chr) { -- qemu_chr_add_handlers(s->chr, uart_can_rx, uart_rx, uart_event, s); -+ qemu_chr_add_handlers(s->chr, &uart_handlers, s); - } - - return 0; -diff --git a/hw/mcf_uart.c b/hw/mcf_uart.c -index ec6a87f..f52fb96 100644 ---- a/hw/mcf_uart.c -+++ b/hw/mcf_uart.c -@@ -272,6 +272,12 @@ static void mcf_uart_receive(void *opaque, const uint8_t *buf, int size) - mcf_uart_push_byte(s, buf[0]); - } - -+static const QemuChrHandlers mcf_uart_handlers = { -+ .fd_can_read = mcf_uart_can_receive, -+ .fd_read = mcf_uart_receive, -+ .fd_event = mcf_uart_event, -+}; -+ - void *mcf_uart_init(qemu_irq irq, CharDriverState *chr) - { - mcf_uart_state *s; -@@ -280,8 +286,7 @@ void *mcf_uart_init(qemu_irq irq, CharDriverState *chr) - s->chr = chr; - s->irq = irq; - if (chr) { -- qemu_chr_add_handlers(chr, mcf_uart_can_receive, mcf_uart_receive, -- mcf_uart_event, s); -+ qemu_chr_add_handlers(chr, &mcf_uart_handlers, s); - } - mcf_uart_reset(s); - return s; -diff --git a/hw/milkymist-uart.c b/hw/milkymist-uart.c -index 291fe3c..2dcb41c 100644 ---- a/hw/milkymist-uart.c -+++ b/hw/milkymist-uart.c -@@ -189,6 +189,12 @@ static void milkymist_uart_reset(DeviceState *d) - s->regs[R_STAT] = STAT_THRE; - } - -+static const QemuChrHandlers uart_handlers = { -+ .fd_can_read = uart_can_rx, -+ .fd_read = uart_rx, -+ .fd_event = uart_event, -+}; -+ - static int milkymist_uart_init(SysBusDevice *dev) - { - MilkymistUartState *s = FROM_SYSBUS(typeof(*s), dev); -@@ -201,7 +207,7 @@ static int milkymist_uart_init(SysBusDevice *dev) - - s->chr = qemu_char_get_next_serial(); - if (s->chr) { -- qemu_chr_add_handlers(s->chr, uart_can_rx, uart_rx, uart_event, s); -+ qemu_chr_add_handlers(s->chr, &uart_handlers, s); - } - - return 0; -diff --git a/hw/pl011.c b/hw/pl011.c -index 3245702..0d620f8 100644 ---- a/hw/pl011.c -+++ b/hw/pl011.c -@@ -258,6 +258,12 @@ static const VMStateDescription vmstate_pl011 = { - } - }; - -+static const QemuChrHandlers pl011_handlers = { -+ .fd_can_read = pl011_can_receive, -+ .fd_read = pl011_receive, -+ .fd_event = pl011_event, -+}; -+ - static int pl011_init(SysBusDevice *dev, const unsigned char *id) - { - pl011_state *s = FROM_SYSBUS(pl011_state, dev); -@@ -273,8 +279,7 @@ static int pl011_init(SysBusDevice *dev, const unsigned char *id) - s->cr = 0x300; - s->flags = 0x90; - if (s->chr) { -- qemu_chr_add_handlers(s->chr, pl011_can_receive, pl011_receive, -- pl011_event, s); -+ qemu_chr_add_handlers(s->chr, &pl011_handlers, s); - } - vmstate_register(&dev->qdev, -1, &vmstate_pl011, s); - return 0; -diff --git a/hw/pxa2xx.c b/hw/pxa2xx.c -index d5f1420..0b308cf 100644 ---- a/hw/pxa2xx.c -+++ b/hw/pxa2xx.c -@@ -1962,6 +1962,12 @@ static int pxa2xx_fir_load(QEMUFile *f, void *opaque, int version_id) - return 0; - } - -+static const QemuChrHandlers pxa2xx_handlers = { -+ .fd_can_read = pxa2xx_fir_is_empty, -+ .fd_read = pxa2xx_fir_rx, -+ .fd_event = pxa2xx_fir_event, -+}; -+ - static PXA2xxFIrState *pxa2xx_fir_init(MemoryRegion *sysmem, - target_phys_addr_t base, - qemu_irq irq, qemu_irq rx_dma, qemu_irq tx_dma, -@@ -1980,10 +1986,9 @@ static PXA2xxFIrState *pxa2xx_fir_init(MemoryRegion *sysmem, - memory_region_init_io(&s->iomem, &pxa2xx_fir_ops, s, "pxa2xx-fir", 0x1000); - memory_region_add_subregion(sysmem, base, &s->iomem); - -- if (chr) -- qemu_chr_add_handlers(chr, pxa2xx_fir_is_empty, -- pxa2xx_fir_rx, pxa2xx_fir_event, s); -- -+ if (chr) { -+ qemu_chr_add_handlers(chr, &pxa2xx_handlers, s); -+ } - register_savevm(NULL, "pxa2xx_fir", 0, 0, pxa2xx_fir_save, - pxa2xx_fir_load, s); - -diff --git a/hw/qdev-properties.c b/hw/qdev-properties.c -index 8aca0d4..677c665 100644 ---- a/hw/qdev-properties.c -+++ b/hw/qdev-properties.c -@@ -549,7 +549,7 @@ static void release_chr(Object *obj, const char *name, void *opaque) - CharDriverState **ptr = qdev_get_prop_ptr(dev, prop); - - if (*ptr) { -- qemu_chr_add_handlers(*ptr, NULL, NULL, NULL, NULL); -+ qemu_chr_add_handlers(*ptr, NULL, NULL); - } - } - -diff --git a/hw/serial.c b/hw/serial.c -index a421d1e..056d823 100644 ---- a/hw/serial.c -+++ b/hw/serial.c -@@ -736,6 +736,12 @@ static void serial_reset(void *opaque) - qemu_irq_lower(s->irq); - } - -+static const QemuChrHandlers serial_handlers = { -+ .fd_can_read = serial_can_receive1, -+ .fd_read = serial_receive1, -+ .fd_event = serial_event, -+}; -+ - static void serial_init_core(SerialState *s) - { - if (!s->chr) { -@@ -750,8 +756,7 @@ static void serial_init_core(SerialState *s) - - qemu_register_reset(serial_reset, s); - -- qemu_chr_add_handlers(s->chr, serial_can_receive1, serial_receive1, -- serial_event, s); -+ qemu_chr_add_handlers(s->chr, &serial_handlers, s); - } - - /* Change the main reference oscillator frequency. */ -diff --git a/hw/sh_serial.c b/hw/sh_serial.c -index 1d1883d..ce1c765 100644 ---- a/hw/sh_serial.c -+++ b/hw/sh_serial.c -@@ -352,6 +352,12 @@ static const MemoryRegionOps sh_serial_ops = { - .endianness = DEVICE_NATIVE_ENDIAN, - }; - -+static const QemuChrHandlers sh_serial_handlers = { -+ .fd_can_read = sh_serial_can_receive1, -+ .fd_read = sh_serial_receive1, -+ .fd_event = sh_serial_event, -+}; -+ - void sh_serial_init(MemoryRegion *sysmem, - target_phys_addr_t base, int feat, - uint32_t freq, CharDriverState *chr, -@@ -396,9 +402,9 @@ void sh_serial_init(MemoryRegion *sysmem, - - s->chr = chr; - -- if (chr) -- qemu_chr_add_handlers(chr, sh_serial_can_receive1, sh_serial_receive1, -- sh_serial_event, s); -+ if (chr) { -+ qemu_chr_add_handlers(chr, &sh_serial_handlers, s); -+ } - - s->eri = eri_source; - s->rxi = rxi_source; -diff --git a/hw/spapr_vty.c b/hw/spapr_vty.c -index 5da17a3..6c2ada1 100644 ---- a/hw/spapr_vty.c -+++ b/hw/spapr_vty.c -@@ -54,6 +54,11 @@ void vty_putchars(VIOsPAPRDevice *sdev, uint8_t *buf, int len) - qemu_chr_fe_write(dev->chardev, buf, len); - } - -+static const QemuChrHandlers vty_handlers = { -+ .fd_can_read = vty_can_receive, -+ .fd_read = vty_receive, -+}; -+ - static int spapr_vty_init(VIOsPAPRDevice *sdev) - { - VIOsPAPRVTYDevice *dev = (VIOsPAPRVTYDevice *)sdev; -@@ -63,8 +68,7 @@ static int spapr_vty_init(VIOsPAPRDevice *sdev) - exit(1); - } - -- qemu_chr_add_handlers(dev->chardev, vty_can_receive, -- vty_receive, NULL, dev); -+ qemu_chr_add_handlers(dev->chardev, &vty_handlers, dev); - - return 0; - } -diff --git a/hw/strongarm.c b/hw/strongarm.c -index 7150eeb..594cf31 100644 ---- a/hw/strongarm.c -+++ b/hw/strongarm.c -@@ -1199,6 +1199,12 @@ static const MemoryRegionOps strongarm_uart_ops = { - .endianness = DEVICE_NATIVE_ENDIAN, - }; - -+static const QemuChrHandlers strongarm_uart_handlers = { -+ .fd_can_read = strongarm_uart_can_receive, -+ .fd_read = strongarm_uart_receive, -+ .fd_event = strongarm_uart_event, -+}; -+ - static int strongarm_uart_init(SysBusDevice *dev) - { - StrongARMUARTState *s = FROM_SYSBUS(StrongARMUARTState, dev); -@@ -1211,11 +1217,7 @@ static int strongarm_uart_init(SysBusDevice *dev) - s->tx_timer = qemu_new_timer_ns(vm_clock, strongarm_uart_tx, s); - - if (s->chr) { -- qemu_chr_add_handlers(s->chr, -- strongarm_uart_can_receive, -- strongarm_uart_receive, -- strongarm_uart_event, -- s); -+ qemu_chr_add_handlers(s->chr, &strongarm_uart_handlers, s); - } - - return 0; -diff --git a/hw/usb/dev-serial.c b/hw/usb/dev-serial.c -index 8aa6552..8fc9bdd 100644 ---- a/hw/usb/dev-serial.c -+++ b/hw/usb/dev-serial.c -@@ -475,6 +475,12 @@ static void usb_serial_event(void *opaque, int event) - } - } - -+static const QemuChrHandlers usb_serial_handlers = { -+ .fd_can_read = usb_serial_can_read, -+ .fd_read = usb_serial_read, -+ .fd_event = usb_serial_event, -+}; -+ - static int usb_serial_initfn(USBDevice *dev) - { - USBSerialState *s = DO_UPCAST(USBSerialState, dev, dev); -@@ -487,8 +493,7 @@ static int usb_serial_initfn(USBDevice *dev) - return -1; - } - -- qemu_chr_add_handlers(s->cs, usb_serial_can_read, usb_serial_read, -- usb_serial_event, s); -+ qemu_chr_add_handlers(s->cs, &usb_serial_handlers, s); - usb_serial_handle_reset(dev); - return 0; - } -diff --git a/hw/usb/redirect.c b/hw/usb/redirect.c -index 10b4fbb..ecb2cd4 100644 ---- a/hw/usb/redirect.c -+++ b/hw/usb/redirect.c -@@ -892,6 +892,12 @@ static void usbredir_chardev_event(void *opaque, int event) - } - } - -+static const QemuChrHandlers usbredir_chr_handlers = { -+ .fd_can_read = usbredir_chardev_can_read, -+ .fd_read = usbredir_chardev_read, -+ .fd_event = usbredir_chardev_event, -+}; -+ - /* - * init + destroy - */ -@@ -930,8 +936,7 @@ static int usbredir_initfn(USBDevice *udev) - - /* Let the backend know we are ready */ - qemu_chr_fe_open(dev->cs); -- qemu_chr_add_handlers(dev->cs, usbredir_chardev_can_read, -- usbredir_chardev_read, usbredir_chardev_event, dev); -+ qemu_chr_add_handlers(dev->cs, &usbredir_chr_handlers, dev); - - add_boot_device_path(dev->bootindex, &udev->qdev, NULL); - return 0; -diff --git a/hw/virtio-console.c b/hw/virtio-console.c -index cffee3d..066590c 100644 ---- a/hw/virtio-console.c -+++ b/hw/virtio-console.c -@@ -106,6 +106,12 @@ static void chr_event(void *opaque, int event) - } - } - -+static const QemuChrHandlers chr_handlers = { -+ .fd_can_read = chr_can_read, -+ .fd_read = chr_read, -+ .fd_event = chr_event, -+}; -+ - static int virtconsole_initfn(VirtIOSerialPort *port) - { - VirtConsole *vcon = DO_UPCAST(VirtConsole, port, port); -@@ -117,8 +123,7 @@ static int virtconsole_initfn(VirtIOSerialPort *port) - } - - if (vcon->chr) { -- qemu_chr_add_handlers(vcon->chr, chr_can_read, chr_read, chr_event, -- vcon); -+ qemu_chr_add_handlers(vcon->chr, &chr_handlers, vcon); - } - - return 0; -diff --git a/hw/xen_console.c b/hw/xen_console.c -index 9426d73..e9fcadc 100644 ---- a/hw/xen_console.c -+++ b/hw/xen_console.c -@@ -211,6 +211,11 @@ out: - return ret; - } - -+static const QemuChrHandlers xencons_handlers = { -+ .fd_can_read = xencons_can_receive, -+ .fd_read = xencons_receive, -+}; -+ - static int con_initialise(struct XenDevice *xendev) - { - struct XenConsole *con = container_of(xendev, struct XenConsole, xendev); -@@ -231,9 +236,9 @@ static int con_initialise(struct XenDevice *xendev) - return -1; - - xen_be_bind_evtchn(&con->xendev); -- if (con->chr) -- qemu_chr_add_handlers(con->chr, xencons_can_receive, xencons_receive, -- NULL, con); -+ if (con->chr) { -+ qemu_chr_add_handlers(con->chr, &xencons_handlers, con); -+ } - - xen_be_printf(xendev, 1, "ring mfn %d, remote port %d, local port %d, limit %zd\n", - con->ring_ref, -@@ -250,8 +255,9 @@ static void con_disconnect(struct XenDevice *xendev) - if (!xendev->dev) { - return; - } -- if (con->chr) -- qemu_chr_add_handlers(con->chr, NULL, NULL, NULL, NULL); -+ if (con->chr) { -+ qemu_chr_add_handlers(con->chr, NULL, NULL); -+ } - xen_be_unbind_evtchn(&con->xendev); - - if (con->sring) { -diff --git a/hw/xilinx_uartlite.c b/hw/xilinx_uartlite.c -index d0f32db..33f0cd5 100644 ---- a/hw/xilinx_uartlite.c -+++ b/hw/xilinx_uartlite.c -@@ -195,6 +195,12 @@ static void uart_event(void *opaque, int event) - - } - -+static const QemuChrHandlers uart_handlers = { -+ .fd_can_read = uart_can_rx, -+ .fd_read = uart_rx, -+ .fd_event = uart_event, -+}; -+ - static int xilinx_uartlite_init(SysBusDevice *dev) - { - struct xlx_uartlite *s = FROM_SYSBUS(typeof (*s), dev); -@@ -207,8 +213,9 @@ static int xilinx_uartlite_init(SysBusDevice *dev) - sysbus_init_mmio(dev, &s->mmio); - - s->chr = qemu_char_get_next_serial(); -- if (s->chr) -- qemu_chr_add_handlers(s->chr, uart_can_rx, uart_rx, uart_event, s); -+ if (s->chr) { -+ qemu_chr_add_handlers(s->chr, &uart_handlers, s); -+ } - return 0; - } - -diff --git a/monitor.c b/monitor.c -index 29e4287..c14698d 100644 ---- a/monitor.c -+++ b/monitor.c -@@ -4941,6 +4941,18 @@ static void sortcmdlist(void) - * End: - */ - -+static const QemuChrHandlers monitor_handlers = { -+ .fd_can_read = monitor_can_read, -+ .fd_read = monitor_read, -+ .fd_event = monitor_event, -+}; -+ -+static const QemuChrHandlers monitor_control_handlers = { -+ .fd_can_read = monitor_can_read, -+ .fd_read = monitor_control_read, -+ .fd_event = monitor_control_event, -+}; -+ - void monitor_init(CharDriverState *chr, int flags) - { - static int is_first_init = 1; -@@ -4964,14 +4976,12 @@ void monitor_init(CharDriverState *chr, int flags) - if (monitor_ctrl_mode(mon)) { - mon->mc = g_malloc0(sizeof(MonitorControl)); - /* Control mode requires special handlers */ -- qemu_chr_add_handlers(chr, monitor_can_read, monitor_control_read, -- monitor_control_event, mon); -+ qemu_chr_add_handlers(chr, &monitor_control_handlers, mon); - qemu_chr_fe_set_echo(chr, true); - - json_message_parser_init(&mon->mc->parser, handle_qmp_command); - } else { -- qemu_chr_add_handlers(chr, monitor_can_read, monitor_read, -- monitor_event, mon); -+ qemu_chr_add_handlers(chr, &monitor_handlers, mon); - } - - QLIST_INSERT_HEAD(&mon_list, mon, entry); -diff --git a/net/slirp.c b/net/slirp.c -index 8db66ea..63542cb 100644 ---- a/net/slirp.c -+++ b/net/slirp.c -@@ -593,6 +593,11 @@ static void guestfwd_read(void *opaque, const uint8_t *buf, int size) - slirp_socket_recv(fwd->slirp, fwd->server, fwd->port, buf, size); - } - -+static const QemuChrHandlers guestfwd_handlers = { -+ .fd_can_read = guestfwd_can_read, -+ .fd_read = guestfwd_read, -+}; -+ - static int slirp_guestfwd(SlirpState *s, const char *config_str, - int legacy_format) - { -@@ -658,8 +663,7 @@ static int slirp_guestfwd(SlirpState *s, const char *config_str, - fwd->port = port; - fwd->slirp = s->slirp; - -- qemu_chr_add_handlers(fwd->hd, guestfwd_can_read, guestfwd_read, -- NULL, fwd); -+ qemu_chr_add_handlers(fwd->hd, &guestfwd_handlers, fwd); - } - return 0; - -diff --git a/qemu-char.c b/qemu-char.c -index 8c53c05..19ae993 100644 ---- a/qemu-char.c -+++ b/qemu-char.c -@@ -192,19 +192,26 @@ void qemu_chr_fe_printf(CharDriverState *s, const char *fmt, ...) - va_end(ap); - } - -+static const QemuChrHandlers null_handlers = { -+ /* All handlers are initialised to NULL */ -+}; -+ - void qemu_chr_add_handlers(CharDriverState *s, -- IOCanReadHandler *fd_can_read, -- IOReadHandler *fd_read, -- IOEventHandler *fd_event, -- void *opaque) -+ const QemuChrHandlers *handlers, void *opaque) - { -- if (!opaque && !fd_can_read && !fd_read && !fd_event) { -+ if (!s) { -+ return; -+ } -+ if (!opaque && !handlers) { - /* chr driver being released. */ - ++s->avail_connections; - } -- s->chr_can_read = fd_can_read; -- s->chr_read = fd_read; -- s->chr_event = fd_event; -+ if (!handlers) { -+ handlers = &null_handlers; -+ } -+ s->chr_can_read = handlers->fd_can_read; -+ s->chr_read = handlers->fd_read; -+ s->chr_event = handlers->fd_event; - s->handler_opaque = opaque; - if (s->chr_update_read_handler) - s->chr_update_read_handler(s); -@@ -442,6 +449,12 @@ static void mux_chr_event(void *opaque, int event) - mux_chr_send_event(d, i, event); - } - -+static const QemuChrHandlers mux_chr_handlers = { -+ .fd_can_read = mux_chr_can_read, -+ .fd_read = mux_chr_read, -+ .fd_event = mux_chr_event, -+}; -+ - static void mux_chr_update_read_handler(CharDriverState *chr) - { - MuxDriver *d = chr->opaque; -@@ -456,8 +469,7 @@ static void mux_chr_update_read_handler(CharDriverState *chr) - d->chr_event[d->mux_cnt] = chr->chr_event; - /* Fix up the real driver with mux routines */ - if (d->mux_cnt == 0) { -- qemu_chr_add_handlers(d->drv, mux_chr_can_read, mux_chr_read, -- mux_chr_event, chr); -+ qemu_chr_add_handlers(d->drv, &mux_chr_handlers, chr); - } - if (d->focus != -1) { - mux_chr_send_event(d, d->focus, CHR_EVENT_MUX_OUT); -diff --git a/qemu-char.h b/qemu-char.h -index 486644b..dfa8c2d 100644 ---- a/qemu-char.h -+++ b/qemu-char.h -@@ -222,10 +222,15 @@ void qemu_chr_be_write(CharDriverState *s, uint8_t *buf, int len); - */ - void qemu_chr_be_event(CharDriverState *s, int event); - --void qemu_chr_add_handlers(CharDriverState *s, -- IOCanReadHandler *fd_can_read, -- IOReadHandler *fd_read, -- IOEventHandler *fd_event, -+ -+typedef struct QemuChrHandlers { -+ IOCanReadHandler *fd_can_read; -+ IOReadHandler *fd_read; -+ IOHandler *fd_write_unblocked; -+ IOEventHandler *fd_event; -+} QemuChrHandlers; -+ -+void qemu_chr_add_handlers(CharDriverState *s, const QemuChrHandlers *handlers, - void *opaque); - - void qemu_chr_generic_open(CharDriverState *s); -diff --git a/qtest.c b/qtest.c -index fbfab4e..4ab5b69 100644 ---- a/qtest.c -+++ b/qtest.c -@@ -416,6 +416,13 @@ static void qtest_event(void *opaque, int event) - } - } - -+static const QemuChrHandlers test_handlers = { -+ .fd_can_read = qtest_can_read, -+ .fd_read = qtest_read, -+ .fd_event = qtest_event, -+}; -+ -+ - int qtest_init(void) - { - CharDriverState *chr; -@@ -425,7 +432,7 @@ int qtest_init(void) - configure_icount("0"); - chr = qemu_chr_new("qtest", qtest_chrdev, NULL); - -- qemu_chr_add_handlers(chr, qtest_can_read, qtest_read, qtest_event, chr); -+ qemu_chr_add_handlers(chr, &test_handlers, chr); - qemu_chr_fe_set_echo(chr, true); - - inbuf = g_string_new(""); --- -1.7.11.2 - diff --git a/0102-spice-notify-on-vm-state-change-only-via-spice_serve.patch b/0102-spice-notify-on-vm-state-change-only-via-spice_serve.patch new file mode 100644 index 0000000..c599743 --- /dev/null +++ b/0102-spice-notify-on-vm-state-change-only-via-spice_serve.patch @@ -0,0 +1,173 @@ +From c50f358fbd549b5ec3b5dd82e29ed06ce969e50a Mon Sep 17 00:00:00 2001 +From: Yonit Halperin +Date: Tue, 21 Aug 2012 11:51:56 +0300 +Subject: [PATCH] spice: notify on vm state change only via + spice_server_vm_start/stop + +QXLWorker->start/stop are deprecated since spice-server 0.11.2 + +Signed-off-by: Yonit Halperin +Signed-off-by: Gerd Hoffmann +(cherry picked from commit 71d388d420e68ac77cd42f15f7e68cf5a6fb01b2) + +Signed-off-by: Michael Roth +--- + hw/qxl.c | 7 ++++--- + ui/spice-core.c | 4 ++++ + ui/spice-display.c | 32 ++++++++++++++++++++++++++++++-- + ui/spice-display.h | 9 +++++++-- + 4 files changed, 45 insertions(+), 7 deletions(-) + +diff --git a/hw/qxl.c b/hw/qxl.c +index c2dd3b4..95bbc03 100644 +--- a/hw/qxl.c ++++ b/hw/qxl.c +@@ -958,9 +958,10 @@ static void qxl_update_irq(PCIQXLDevice *d) + static void qxl_check_state(PCIQXLDevice *d) + { + QXLRam *ram = d->ram; ++ int spice_display_running = qemu_spice_display_is_running(&d->ssd); + +- assert(!d->ssd.running || SPICE_RING_IS_EMPTY(&ram->cmd_ring)); +- assert(!d->ssd.running || SPICE_RING_IS_EMPTY(&ram->cursor_ring)); ++ assert(!spice_display_running || SPICE_RING_IS_EMPTY(&ram->cmd_ring)); ++ assert(!spice_display_running || SPICE_RING_IS_EMPTY(&ram->cursor_ring)); + } + + static void qxl_reset_state(PCIQXLDevice *d) +@@ -1538,7 +1539,7 @@ static void qxl_send_events(PCIQXLDevice *d, uint32_t events) + uint32_t old_pending; + uint32_t le_events = cpu_to_le32(events); + +- assert(d->ssd.running); ++ assert(qemu_spice_display_is_running(&d->ssd)); + old_pending = __sync_fetch_and_or(&d->ram->int_pending, le_events); + if ((old_pending & le_events) == le_events) { + return; +diff --git a/ui/spice-core.c b/ui/spice-core.c +index a515c94..1a7a773 100644 +--- a/ui/spice-core.c ++++ b/ui/spice-core.c +@@ -37,6 +37,7 @@ + #include "migration.h" + #include "monitor.h" + #include "hw/hw.h" ++#include "spice-display.h" + + /* core bits */ + +@@ -551,9 +552,11 @@ static void vm_change_state_handler(void *opaque, int running, + { + #if SPICE_SERVER_VERSION >= 0x000b02 /* 0.11.2 */ + if (running) { ++ qemu_spice_display_start(); + spice_server_vm_start(spice_server); + } else { + spice_server_vm_stop(spice_server); ++ qemu_spice_display_stop(); + } + #endif + } +@@ -755,6 +758,7 @@ int qemu_spice_add_interface(SpiceBaseInstance *sin) + spice_server = spice_server_new(); + spice_server_init(spice_server, &core_interface); + } ++ + return spice_server_add_interface(spice_server, sin); + } + +diff --git a/ui/spice-display.c b/ui/spice-display.c +index 3e8f0b3..1c31418 100644 +--- a/ui/spice-display.c ++++ b/ui/spice-display.c +@@ -126,18 +126,44 @@ void qemu_spice_wakeup(SimpleSpiceDisplay *ssd) + ssd->worker->wakeup(ssd->worker); + } + +-void qemu_spice_start(SimpleSpiceDisplay *ssd) ++#if SPICE_SERVER_VERSION < 0x000b02 /* before 0.11.2 */ ++static void qemu_spice_start(SimpleSpiceDisplay *ssd) + { + trace_qemu_spice_start(ssd->qxl.id); + ssd->worker->start(ssd->worker); + } + +-void qemu_spice_stop(SimpleSpiceDisplay *ssd) ++static void qemu_spice_stop(SimpleSpiceDisplay *ssd) + { + trace_qemu_spice_stop(ssd->qxl.id); + ssd->worker->stop(ssd->worker); + } + ++#else ++ ++static int spice_display_is_running; ++ ++void qemu_spice_display_start(void) ++{ ++ spice_display_is_running = true; ++} ++ ++void qemu_spice_display_stop(void) ++{ ++ spice_display_is_running = false; ++} ++ ++#endif ++ ++int qemu_spice_display_is_running(SimpleSpiceDisplay *ssd) ++{ ++#if SPICE_SERVER_VERSION < 0x000b02 /* before 0.11.2 */ ++ return ssd->running; ++#else ++ return spice_display_is_running; ++#endif ++} ++ + static SimpleSpiceUpdate *qemu_spice_create_update(SimpleSpiceDisplay *ssd) + { + SimpleSpiceUpdate *update; +@@ -272,6 +298,7 @@ void qemu_spice_destroy_host_primary(SimpleSpiceDisplay *ssd) + void qemu_spice_vm_change_state_handler(void *opaque, int running, + RunState state) + { ++#if SPICE_SERVER_VERSION < 0x000b02 /* before 0.11.2 */ + SimpleSpiceDisplay *ssd = opaque; + + if (running) { +@@ -281,6 +308,7 @@ void qemu_spice_vm_change_state_handler(void *opaque, int running, + qemu_spice_stop(ssd); + ssd->running = false; + } ++#endif + } + + void qemu_spice_display_init_common(SimpleSpiceDisplay *ssd, DisplayState *ds) +diff --git a/ui/spice-display.h b/ui/spice-display.h +index 12e50b6..672d65e 100644 +--- a/ui/spice-display.h ++++ b/ui/spice-display.h +@@ -82,7 +82,9 @@ struct SimpleSpiceDisplay { + + QXLRect dirty; + int notify; ++#if SPICE_SERVER_VERSION < 0x000b02 /* before 0.11.2 */ + int running; ++#endif + + /* + * All struct members below this comment can be accessed from +@@ -129,5 +131,8 @@ void qemu_spice_create_primary_surface(SimpleSpiceDisplay *ssd, uint32_t id, + void qemu_spice_destroy_primary_surface(SimpleSpiceDisplay *ssd, + uint32_t id, qxl_async_io async); + void qemu_spice_wakeup(SimpleSpiceDisplay *ssd); +-void qemu_spice_start(SimpleSpiceDisplay *ssd); +-void qemu_spice_stop(SimpleSpiceDisplay *ssd); ++#if SPICE_SERVER_VERSION >= 0x000b02 /* before 0.11.2 */ ++void qemu_spice_display_start(void); ++void qemu_spice_display_stop(void); ++#endif ++int qemu_spice_display_is_running(SimpleSpiceDisplay *ssd); +-- +1.7.12.1 + diff --git a/0103-iohandlers-Add-enable-disable_write_fd_handler-funct.patch b/0103-iohandlers-Add-enable-disable_write_fd_handler-funct.patch deleted file mode 100644 index 060937e..0000000 --- a/0103-iohandlers-Add-enable-disable_write_fd_handler-funct.patch +++ /dev/null @@ -1,81 +0,0 @@ -From 1980701650660459d35db0f956f536c8790e2056 Mon Sep 17 00:00:00 2001 -Message-Id: <1980701650660459d35db0f956f536c8790e2056.1346162949.git.crobinso@redhat.com> -In-Reply-To: <90a59d545ad6759c105b0bfcfca70f574482584f.1346162949.git.crobinso@redhat.com> -References: <90a59d545ad6759c105b0bfcfca70f574482584f.1346162949.git.crobinso@redhat.com> -From: Amit Shah -Date: Mon, 21 Mar 2011 20:32:58 +0100 -Subject: [PATCH 103/114] iohandlers: Add enable/disable_write_fd_handler() - functions - -These will be used to provide a cleaner API for the nonblocking case. - -Signed-off-by: Amit Shah -Signed-off-by: Cole Robinson ---- - iohandler.c | 35 +++++++++++++++++++++++++++++++++++ - main-loop.h | 3 +++ - 2 files changed, 38 insertions(+) - -diff --git a/iohandler.c b/iohandler.c -index dea4355..e663f83 100644 ---- a/iohandler.c -+++ b/iohandler.c -@@ -45,6 +45,41 @@ typedef struct IOHandlerRecord { - static QLIST_HEAD(, IOHandlerRecord) io_handlers = - QLIST_HEAD_INITIALIZER(io_handlers); - -+static IOHandlerRecord *find_iohandler(int fd) -+{ -+ IOHandlerRecord *ioh; -+ -+ QLIST_FOREACH(ioh, &io_handlers, next) { -+ if (ioh->fd == fd) { -+ return ioh; -+ } -+ } -+ return NULL; -+} -+ -+void enable_write_fd_handler(int fd, IOHandler *fd_write) -+{ -+ IOHandlerRecord *ioh; -+ -+ ioh = find_iohandler(fd); -+ if (!ioh) { -+ return; -+ } -+ -+ ioh->fd_write = fd_write; -+} -+ -+void disable_write_fd_handler(int fd) -+{ -+ IOHandlerRecord *ioh; -+ -+ ioh = find_iohandler(fd); -+ if (!ioh) { -+ return; -+ } -+ -+ ioh->fd_write = NULL; -+} - - /* XXX: fd_read_poll should be suppressed, but an API change is - necessary in the character devices to suppress fd_can_read(). */ -diff --git a/main-loop.h b/main-loop.h -index dce1cd9..eb31273 100644 ---- a/main-loop.h -+++ b/main-loop.h -@@ -175,6 +175,9 @@ typedef void IOReadHandler(void *opaque, const uint8_t *buf, int size); - typedef int IOCanReadHandler(void *opaque); - typedef void IOHandler(void *opaque); - -+void enable_write_fd_handler(int fd, IOHandler *fd_write); -+void disable_write_fd_handler(int fd); -+ - /** - * qemu_set_fd_handler2: Register a file descriptor with the main loop - * --- -1.7.11.2 - diff --git a/0103-spice-migration-add-QEVENT_SPICE_MIGRATE_COMPLETED.patch b/0103-spice-migration-add-QEVENT_SPICE_MIGRATE_COMPLETED.patch new file mode 100644 index 0000000..e8580c2 --- /dev/null +++ b/0103-spice-migration-add-QEVENT_SPICE_MIGRATE_COMPLETED.patch @@ -0,0 +1,93 @@ +From 8470a0f943e8605739b7bc0081507f787bed412d Mon Sep 17 00:00:00 2001 +From: Yonit Halperin +Date: Tue, 21 Aug 2012 11:51:57 +0300 +Subject: [PATCH] spice migration: add QEVENT_SPICE_MIGRATE_COMPLETED + +When migrating, libvirt queries the migration status, and upon migration +completions, it closes the migration src. On the other hand, when +migration is completed, spice transfers data from the src to destination +via the client. This data is required for keeping the spice session +after migration, without suffering from data loss and inconsistencies. +In order to allow this data transfer, we add QEVENT for signaling +libvirt that spice migration has completed, and libvirt needs to wait +for this event before quitting the src process. + +Signed-off-by: Yonit Halperin +Signed-off-by: Gerd Hoffmann +(cherry picked from commit 2fdd16e239c2a2763aa3266e637718123328688c) + +Signed-off-by: Michael Roth +--- + monitor.c | 1 + + monitor.h | 1 + + ui/spice-core.c | 9 ++++++++- + 3 files changed, 10 insertions(+), 1 deletion(-) + +diff --git a/monitor.c b/monitor.c +index 29e4287..f45cf92 100644 +--- a/monitor.c ++++ b/monitor.c +@@ -455,6 +455,7 @@ static const char *monitor_event_names[] = { + [QEVENT_SUSPEND_DISK] = "SUSPEND_DISK", + [QEVENT_WAKEUP] = "WAKEUP", + [QEVENT_BALLOON_CHANGE] = "BALLOON_CHANGE", ++ [QEVENT_SPICE_MIGRATE_COMPLETED] = "SPICE_MIGRATE_COMPLETED", + }; + QEMU_BUILD_BUG_ON(ARRAY_SIZE(monitor_event_names) != QEVENT_MAX) + +diff --git a/monitor.h b/monitor.h +index 47d556b..5fc2983 100644 +--- a/monitor.h ++++ b/monitor.h +@@ -43,6 +43,7 @@ typedef enum MonitorEvent { + QEVENT_SUSPEND_DISK, + QEVENT_WAKEUP, + QEVENT_BALLOON_CHANGE, ++ QEVENT_SPICE_MIGRATE_COMPLETED, + + /* Add to 'monitor_event_names' array in monitor.c when + * defining new events here */ +diff --git a/ui/spice-core.c b/ui/spice-core.c +index 1a7a773..851e869 100644 +--- a/ui/spice-core.c ++++ b/ui/spice-core.c +@@ -285,6 +285,7 @@ typedef struct SpiceMigration { + } SpiceMigration; + + static void migrate_connect_complete_cb(SpiceMigrateInstance *sin); ++static void migrate_end_complete_cb(SpiceMigrateInstance *sin); + + static const SpiceMigrateInterface migrate_interface = { + .base.type = SPICE_INTERFACE_MIGRATION, +@@ -292,7 +293,7 @@ static const SpiceMigrateInterface migrate_interface = { + .base.major_version = SPICE_INTERFACE_MIGRATION_MAJOR, + .base.minor_version = SPICE_INTERFACE_MIGRATION_MINOR, + .migrate_connect_complete = migrate_connect_complete_cb, +- .migrate_end_complete = NULL, ++ .migrate_end_complete = migrate_end_complete_cb, + }; + + static SpiceMigration spice_migrate; +@@ -305,6 +306,11 @@ static void migrate_connect_complete_cb(SpiceMigrateInstance *sin) + } + sm->connect_complete.cb = NULL; + } ++ ++static void migrate_end_complete_cb(SpiceMigrateInstance *sin) ++{ ++ monitor_protocol_event(QEVENT_SPICE_MIGRATE_COMPLETED, NULL); ++} + #endif + + /* config string parsing */ +@@ -489,6 +495,7 @@ static void migration_state_notifier(Notifier *notifier, void *data) + } else if (migration_has_finished(s)) { + #ifndef SPICE_INTERFACE_MIGRATION + spice_server_migrate_switch(spice_server); ++ monitor_protocol_event(QEVENT_SPICE_MIGRATE_COMPLETED, NULL); + #else + spice_server_migrate_end(spice_server, true); + } else if (migration_has_failed(s)) { +-- +1.7.12.1 + diff --git a/0104-char-Add-framework-for-a-write-unblocked-callback.patch b/0104-char-Add-framework-for-a-write-unblocked-callback.patch deleted file mode 100644 index aed649e..0000000 --- a/0104-char-Add-framework-for-a-write-unblocked-callback.patch +++ /dev/null @@ -1,65 +0,0 @@ -From 8767b055fe84811f1caec3854b55a5d5541f72c9 Mon Sep 17 00:00:00 2001 -Message-Id: <8767b055fe84811f1caec3854b55a5d5541f72c9.1346162949.git.crobinso@redhat.com> -In-Reply-To: <90a59d545ad6759c105b0bfcfca70f574482584f.1346162949.git.crobinso@redhat.com> -References: <90a59d545ad6759c105b0bfcfca70f574482584f.1346162949.git.crobinso@redhat.com> -From: Amit Shah -Date: Mon, 21 Mar 2011 21:41:42 +0100 -Subject: [PATCH 104/114] char: Add framework for a 'write unblocked' callback - -The char layer can let users know that the driver will block on further -input. For users interested in not blocking, they can assign a function -pointer that will be called back when the driver becomes writable. This -patch just adds the function pointers to the CharDriverState structure, -future patches will enable the nonblocking and callback functionality. - -Signed-off-by: Amit Shah -Signed-off-by: Cole Robinson ---- - qemu-char.c | 3 +++ - qemu-char.h | 4 ++++ - 2 files changed, 7 insertions(+) - -diff --git a/qemu-char.c b/qemu-char.c -index 19ae993..2c573fb 100644 ---- a/qemu-char.c -+++ b/qemu-char.c -@@ -211,11 +211,14 @@ void qemu_chr_add_handlers(CharDriverState *s, - } - s->chr_can_read = handlers->fd_can_read; - s->chr_read = handlers->fd_read; -+ s->chr_write_unblocked = handlers->fd_write_unblocked; - s->chr_event = handlers->fd_event; - s->handler_opaque = opaque; - if (s->chr_update_read_handler) - s->chr_update_read_handler(s); - -+ s->write_blocked = false; -+ - /* We're connecting to an already opened device, so let's make sure we - also get the open event */ - if (s->opened) { -diff --git a/qemu-char.h b/qemu-char.h -index dfa8c2d..b5e23a4 100644 ---- a/qemu-char.h -+++ b/qemu-char.h -@@ -62,6 +62,9 @@ struct CharDriverState { - IOEventHandler *chr_event; - IOCanReadHandler *chr_can_read; - IOReadHandler *chr_read; -+ IOHandler *chr_write_unblocked; -+ void (*chr_enable_write_fd_handler)(struct CharDriverState *chr); -+ void (*chr_disable_write_fd_handler)(struct CharDriverState *chr); - void *handler_opaque; - void (*chr_close)(struct CharDriverState *chr); - void (*chr_accept_input)(struct CharDriverState *chr); -@@ -74,6 +77,7 @@ struct CharDriverState { - char *filename; - int opened; - int avail_connections; -+ bool write_blocked; /* Are we in a blocked state? */ - QTAILQ_ENTRY(CharDriverState) next; - }; - --- -1.7.11.2 - diff --git a/0104-spice-add-migrated-flag-to-spice-info.patch b/0104-spice-add-migrated-flag-to-spice-info.patch new file mode 100644 index 0000000..0247edd --- /dev/null +++ b/0104-spice-add-migrated-flag-to-spice-info.patch @@ -0,0 +1,97 @@ +From a4155f1a9fac362bfc1558790de9ea4cdb0a3c8a Mon Sep 17 00:00:00 2001 +From: Yonit Halperin +Date: Tue, 21 Aug 2012 11:51:58 +0300 +Subject: [PATCH] spice: add 'migrated' flag to spice info + +The flag is 'true' when spice migration has completed on the src side. +It is needed for a case where libvirt dies before migration completes +and it misses the event QEVENT_SPICE_MIGRATE_COMPLETED. +When libvirt is restored and queries the migration status, it also needs +to query spice and check if its migration has completed. + +Signed-off-by: Yonit Halperin +Signed-off-by: Gerd Hoffmann +(cherry picked from commit 61c4efe2cb85b0a9c6bc68f6a2dd107c8d7ec080) + +Signed-off-by: Michael Roth +--- + hmp.c | 2 ++ + qapi-schema.json | 5 ++++- + ui/spice-core.c | 4 ++++ + 3 files changed, 10 insertions(+), 1 deletion(-) + +diff --git a/hmp.c b/hmp.c +index 81c8acb..ec4274b 100644 +--- a/hmp.c ++++ b/hmp.c +@@ -413,6 +413,8 @@ void hmp_info_spice(Monitor *mon) + monitor_printf(mon, " address: %s:%" PRId64 " [tls]\n", + info->host, info->tls_port); + } ++ monitor_printf(mon, " migrated: %s\n", ++ info->migrated ? "true" : "false"); + monitor_printf(mon, " auth: %s\n", info->auth); + monitor_printf(mon, " compiled: %s\n", info->compiled_version); + monitor_printf(mon, " mouse-mode: %s\n", +diff --git a/qapi-schema.json b/qapi-schema.json +index bd8ad74..8ddde12 100644 +--- a/qapi-schema.json ++++ b/qapi-schema.json +@@ -808,6 +808,9 @@ + # + # @enabled: true if the SPICE server is enabled, false otherwise + # ++# @migrated: true if the last guest migration completed and spice ++# migration had completed as well. false otherwise. ++# + # @host: #optional The hostname the SPICE server is bound to. This depends on + # the name resolution on the host and may be an IP address. + # +@@ -833,7 +836,7 @@ + # Since: 0.14.0 + ## + { 'type': 'SpiceInfo', +- 'data': {'enabled': 'bool', '*host': 'str', '*port': 'int', ++ 'data': {'enabled': 'bool', 'migrated': 'bool', '*host': 'str', '*port': 'int', + '*tls-port': 'int', '*auth': 'str', '*compiled-version': 'str', + 'mouse-mode': 'SpiceQueryMouseMode', '*channels': ['SpiceChannel']} } + +diff --git a/ui/spice-core.c b/ui/spice-core.c +index 851e869..ab069c5 100644 +--- a/ui/spice-core.c ++++ b/ui/spice-core.c +@@ -46,6 +46,7 @@ static Notifier migration_state; + static const char *auth = "spice"; + static char *auth_passwd; + static time_t auth_expires = TIME_MAX; ++static int spice_migration_completed; + int using_spice = 0; + + static QemuThread me; +@@ -310,6 +311,7 @@ static void migrate_connect_complete_cb(SpiceMigrateInstance *sin) + static void migrate_end_complete_cb(SpiceMigrateInstance *sin) + { + monitor_protocol_event(QEVENT_SPICE_MIGRATE_COMPLETED, NULL); ++ spice_migration_completed = true; + } + #endif + +@@ -443,6 +445,7 @@ SpiceInfo *qmp_query_spice(Error **errp) + } + + info->enabled = true; ++ info->migrated = spice_migration_completed; + + addr = qemu_opt_get(opts, "addr"); + port = qemu_opt_get_number(opts, "port", 0); +@@ -496,6 +499,7 @@ static void migration_state_notifier(Notifier *notifier, void *data) + #ifndef SPICE_INTERFACE_MIGRATION + spice_server_migrate_switch(spice_server); + monitor_protocol_event(QEVENT_SPICE_MIGRATE_COMPLETED, NULL); ++ spice_migration_completed = true; + #else + spice_server_migrate_end(spice_server, true); + } else if (migration_has_failed(s)) { +-- +1.7.12.1 + diff --git a/0105-char-Update-send_all-to-handle-nonblocking-chardev-w.patch b/0105-char-Update-send_all-to-handle-nonblocking-chardev-w.patch deleted file mode 100644 index 6d6f3ed..0000000 --- a/0105-char-Update-send_all-to-handle-nonblocking-chardev-w.patch +++ /dev/null @@ -1,192 +0,0 @@ -From 1af0111d871f088f25e7854fe61302e1909ba4c4 Mon Sep 17 00:00:00 2001 -Message-Id: <1af0111d871f088f25e7854fe61302e1909ba4c4.1346162949.git.crobinso@redhat.com> -In-Reply-To: <90a59d545ad6759c105b0bfcfca70f574482584f.1346162949.git.crobinso@redhat.com> -References: <90a59d545ad6759c105b0bfcfca70f574482584f.1346162949.git.crobinso@redhat.com> -From: Amit Shah -Date: Mon, 21 Mar 2011 22:00:27 +0100 -Subject: [PATCH 105/114] char: Update send_all() to handle nonblocking - chardev write requests - -The send_all function is modified to return to the caller in case the -driver cannot handle any more data. It returns -EAGAIN or -WSAEWOULDBLOCK on non-Windows and Windows platforms respectively. This -is only done when the caller sets a callback function handler indicating -it's not interested in blocking till the driver has written out all the -data. - -Currently there's no driver or caller that supports this. Future -commits will add such capability. - -Signed-off-by: Amit Shah -Signed-off-by: Cole Robinson ---- - net/socket.c | 4 ++-- - qemu-char.c | 69 +++++++++++++++++++++++++++++++++++++++++++++++++++++------ - qemu_socket.h | 2 +- - 3 files changed, 66 insertions(+), 9 deletions(-) - -diff --git a/net/socket.c b/net/socket.c -index c172c24..aa7c99e 100644 ---- a/net/socket.c -+++ b/net/socket.c -@@ -53,8 +53,8 @@ static ssize_t net_socket_receive(NetClientState *nc, const uint8_t *buf, size_t - uint32_t len; - len = htonl(size); - -- send_all(s->fd, (const uint8_t *)&len, sizeof(len)); -- return send_all(s->fd, buf, size); -+ send_all(NULL, s->fd, (const uint8_t *)&len, sizeof(len)); -+ return send_all(NULL, s->fd, buf, size); - } - - static ssize_t net_socket_receive_dgram(NetClientState *nc, const uint8_t *buf, size_t size) -diff --git a/qemu-char.c b/qemu-char.c -index 2c573fb..c2a3138 100644 ---- a/qemu-char.c -+++ b/qemu-char.c -@@ -508,7 +508,7 @@ static CharDriverState *qemu_chr_open_mux(CharDriverState *drv) - - - #ifdef _WIN32 --int send_all(int fd, const void *buf, int len1) -+static int do_send(int fd, const void *buf, int len1, bool nonblock) - { - int ret, len; - -@@ -516,9 +516,14 @@ int send_all(int fd, const void *buf, int len1) - while (len > 0) { - ret = send(fd, buf, len, 0); - if (ret < 0) { -+ if (nonblock && len1 - len) { -+ return len1 - len; -+ } - errno = WSAGetLastError(); - if (errno != WSAEWOULDBLOCK) { - return -1; -+ } else if (errno == WSAEWOULDBLOCK && nonblock) { -+ return WSAEWOULDBLOCK; - } - } else if (ret == 0) { - break; -@@ -532,7 +537,7 @@ int send_all(int fd, const void *buf, int len1) - - #else - --int send_all(int fd, const void *_buf, int len1) -+static int do_send(int fd, const void *_buf, int len1, bool nonblock) - { - int ret, len; - const uint8_t *buf = _buf; -@@ -541,8 +546,15 @@ int send_all(int fd, const void *_buf, int len1) - while (len > 0) { - ret = write(fd, buf, len); - if (ret < 0) { -- if (errno != EINTR && errno != EAGAIN) -+ if (nonblock && len1 - len) { -+ return len1 - len; -+ } -+ if (errno == EAGAIN && nonblock) { -+ return -EAGAIN; -+ } -+ if (errno != EINTR && errno != EAGAIN) { - return -1; -+ } - } else if (ret == 0) { - break; - } else { -@@ -557,6 +569,44 @@ int send_all(int fd, const void *_buf, int len1) - #define STDIO_MAX_CLIENTS 1 - static int stdio_nb_clients; - -+int send_all(CharDriverState *chr, int fd, const void *_buf, int len1) -+{ -+ int ret, eagain_errno; -+ bool nonblock; -+ -+ if (chr && chr->write_blocked) { -+ /* -+ * The caller should not send us data while we're blocked, -+ * but this can happen when multiple writers are woken at once, -+ * so simply return -EAGAIN. -+ */ -+ return -EAGAIN; -+ } -+ -+ nonblock = false; -+ /* -+ * Ensure the char backend is able to receive and handle the -+ * 'write unblocked' event before we turn on nonblock support. -+ */ -+ if (chr && chr->chr_enable_write_fd_handler && chr->chr_write_unblocked) { -+ nonblock = true; -+ } -+ ret = do_send(fd, _buf, len1, nonblock); -+ -+#ifdef _WIN32 -+ eagain_errno = WSAEWOULDBLOCK; -+#else -+ eagain_errno = -EAGAIN; -+#endif -+ -+ if (nonblock && (ret == eagain_errno || (ret >= 0 && ret < len1))) { -+ /* Update fd handler to wake up when chr becomes writable */ -+ chr->chr_enable_write_fd_handler(chr); -+ chr->write_blocked = true; -+ } -+ return ret; -+} -+ - #ifndef _WIN32 - - typedef struct { -@@ -568,7 +618,7 @@ typedef struct { - static int fd_chr_write(CharDriverState *chr, const uint8_t *buf, int len) - { - FDCharDriver *s = chr->opaque; -- return send_all(s->fd_out, buf, len); -+ return send_all(chr, s->fd_out, buf, len); - } - - static int fd_chr_read_poll(void *opaque) -@@ -887,7 +937,7 @@ static int pty_chr_write(CharDriverState *chr, const uint8_t *buf, int len) - pty_chr_update_read_handler(chr); - return 0; - } -- return send_all(s->fd, buf, len); -+ return send_all(chr, s->fd, buf, len); - } - - static int pty_chr_read_poll(void *opaque) -@@ -2176,8 +2226,15 @@ static void tcp_closed(void *opaque) - static int tcp_chr_write(CharDriverState *chr, const uint8_t *buf, int len) - { - TCPCharDriver *s = chr->opaque; -+ - if (s->connected) { -- return send_all(s->fd, buf, len); -+ int ret; -+ -+ ret = send_all(chr, s->fd, buf, len); -+ if (ret == -1 && errno == EPIPE) { -+ tcp_closed(chr); -+ } -+ return ret; - } else { - /* (Re-)connect for unconnected writing */ - tcp_chr_connect(chr); -diff --git a/qemu_socket.h b/qemu_socket.h -index 30ae6af..fc58c8d 100644 ---- a/qemu_socket.h -+++ b/qemu_socket.h -@@ -36,7 +36,7 @@ int qemu_accept(int s, struct sockaddr *addr, socklen_t *addrlen); - int socket_set_cork(int fd, int v); - void socket_set_block(int fd); - void socket_set_nonblock(int fd); --int send_all(int fd, const void *buf, int len1); -+int send_all(CharDriverState *chr, int fd, const void *buf, int len1); - - /* New, ipv6-ready socket helper functions, see qemu-sockets.c */ - int inet_listen_opts(QemuOpts *opts, int port_offset, Error **errp); --- -1.7.11.2 - diff --git a/0105-spice-adding-seamless-migration-option-to-the-comman.patch b/0105-spice-adding-seamless-migration-option-to-the-comman.patch new file mode 100644 index 0000000..70eb7c0 --- /dev/null +++ b/0105-spice-adding-seamless-migration-option-to-the-comman.patch @@ -0,0 +1,79 @@ +From b15c26620bb765e25c96163383d79c1c56df7901 Mon Sep 17 00:00:00 2001 +From: Yonit Halperin +Date: Tue, 21 Aug 2012 11:51:59 +0300 +Subject: [PATCH] spice: adding seamless-migration option to the command line + +The seamless-migration flag is required in order to identify +whether libvirt supports the new QEVENT_SPICE_MIGRATE_COMPLETED or not +(by default the flag is off). +New libvirt versions that wait for QEVENT_SPICE_MIGRATE_COMPLETED should turn on this flag. +When this flag is off, spice fallbacks to its old migration method, which +can result in data loss. + +Signed-off-by: Yonit Halperin +Signed-off-by: Gerd Hoffmann +(cherry picked from commit 8c9570530c819821b9b5cc3113d2b2966afe7621) + +Signed-off-by: Michael Roth +--- + qemu-config.c | 3 +++ + qemu-options.hx | 3 +++ + ui/spice-core.c | 7 +++++++ + 3 files changed, 13 insertions(+) + +diff --git a/qemu-config.c b/qemu-config.c +index 238390e..3eaee48 100644 +--- a/qemu-config.c ++++ b/qemu-config.c +@@ -541,6 +541,9 @@ QemuOptsList qemu_spice_opts = { + },{ + .name = "playback-compression", + .type = QEMU_OPT_BOOL, ++ }, { ++ .name = "seamless-migration", ++ .type = QEMU_OPT_BOOL, + }, + { /* end of list */ } + }, +diff --git a/qemu-options.hx b/qemu-options.hx +index ea06324..dd7aa63 100644 +--- a/qemu-options.hx ++++ b/qemu-options.hx +@@ -920,6 +920,9 @@ Enable/disable passing mouse events via vdagent. Default is on. + @item playback-compression=[on|off] + Enable/disable audio stream compression (using celt 0.5.1). Default is on. + ++@item seamless-migration=[on|off] ++Enable/disable spice seamless migration. Default is off. ++ + @end table + ETEXI + +diff --git a/ui/spice-core.c b/ui/spice-core.c +index ab069c5..ba0d0bd 100644 +--- a/ui/spice-core.c ++++ b/ui/spice-core.c +@@ -585,6 +585,9 @@ void qemu_spice_init(void) + int port, tls_port, len, addr_flags; + spice_image_compression_t compression; + spice_wan_compression_t wan_compr; ++#if SPICE_SERVER_VERSION >= 0x000b02 /* 0.11.2 */ ++ bool seamless_migration; ++#endif + + qemu_thread_get_self(&me); + +@@ -728,6 +731,10 @@ void qemu_spice_init(void) + spice_server_set_uuid(spice_server, qemu_uuid); + #endif + ++#if SPICE_SERVER_VERSION >= 0x000b02 /* 0.11.2 */ ++ seamless_migration = qemu_opt_get_bool(opts, "seamless-migration", 0); ++ spice_server_set_seamless_migration(spice_server, seamless_migration); ++#endif + if (0 != spice_server_init(spice_server, &core_interface)) { + error_report("failed to initialize spice server"); + exit(1); +-- +1.7.12.1 + diff --git a/0106-char-Equip-the-unix-tcp-backend-to-handle-nonblockin.patch b/0106-char-Equip-the-unix-tcp-backend-to-handle-nonblockin.patch deleted file mode 100644 index a3ddec7..0000000 --- a/0106-char-Equip-the-unix-tcp-backend-to-handle-nonblockin.patch +++ /dev/null @@ -1,85 +0,0 @@ -From 2fa4be9d3b84d214f4ea9da8513ef664f412ad09 Mon Sep 17 00:00:00 2001 -Message-Id: <2fa4be9d3b84d214f4ea9da8513ef664f412ad09.1346162949.git.crobinso@redhat.com> -In-Reply-To: <90a59d545ad6759c105b0bfcfca70f574482584f.1346162949.git.crobinso@redhat.com> -References: <90a59d545ad6759c105b0bfcfca70f574482584f.1346162949.git.crobinso@redhat.com> -From: Amit Shah -Date: Mon, 21 Mar 2011 22:02:47 +0100 -Subject: [PATCH 106/114] char: Equip the unix/tcp backend to handle - nonblocking writes# - -Now that the infrastructure is in place to return -EAGAIN to callers, -individual char drivers can set their update_fd_handlers() function to -set or remove an fd's write handler. This handler checks if the driver -became writable. - -A generic callback routine is used for unblocking writes and letting -users of chardevs know that a driver became writable again. - -Signed-off-by: Amit Shah -Signed-off-by: Cole Robinson ---- - qemu-char.c | 34 ++++++++++++++++++++++++++++++++++ - 1 file changed, 34 insertions(+) - -diff --git a/qemu-char.c b/qemu-char.c -index c2a3138..5e136fd 100644 ---- a/qemu-char.c -+++ b/qemu-char.c -@@ -106,6 +106,19 @@ - static QTAILQ_HEAD(CharDriverStateHead, CharDriverState) chardevs = - QTAILQ_HEAD_INITIALIZER(chardevs); - -+/* -+ * Generic routine that gets called when chardev becomes writable. -+ * Lets chardev user know it's OK to send more data. -+ */ -+static void char_write_unblocked(void *opaque) -+{ -+ CharDriverState *chr = opaque; -+ -+ chr->write_blocked = false; -+ chr->chr_disable_write_fd_handler(chr); -+ chr->chr_write_unblocked(chr->handler_opaque); -+} -+ - void qemu_chr_be_event(CharDriverState *s, int event) - { - /* Keep track if the char device is open */ -@@ -2504,6 +2517,25 @@ static void tcp_chr_close(CharDriverState *chr) - qemu_chr_be_event(chr, CHR_EVENT_CLOSED); - } - -+static void tcp_enable_write_fd_handler(CharDriverState *chr) -+{ -+ TCPCharDriver *s = chr->opaque; -+ -+ /* -+ * This function is called only after tcp_chr_connect() is called -+ * (either in 'server' mode or client mode. So we're sure of -+ * s->fd being initialised. -+ */ -+ enable_write_fd_handler(s->fd, char_write_unblocked); -+} -+ -+static void tcp_disable_write_fd_handler(CharDriverState *chr) -+{ -+ TCPCharDriver *s = chr->opaque; -+ -+ disable_write_fd_handler(s->fd); -+} -+ - static CharDriverState *qemu_chr_open_socket(QemuOpts *opts) - { - CharDriverState *chr = NULL; -@@ -2558,6 +2590,8 @@ static CharDriverState *qemu_chr_open_socket(QemuOpts *opts) - chr->chr_close = tcp_chr_close; - chr->get_msgfd = tcp_get_msgfd; - chr->chr_add_client = tcp_chr_add_client; -+ chr->chr_enable_write_fd_handler = tcp_enable_write_fd_handler; -+ chr->chr_disable_write_fd_handler = tcp_disable_write_fd_handler; - - if (is_listen) { - s->listen_fd = fd; --- -1.7.11.2 - diff --git a/0106-spice-increase-the-verbosity-of-spice-section-in-qem.patch b/0106-spice-increase-the-verbosity-of-spice-section-in-qem.patch new file mode 100644 index 0000000..24ad9ff --- /dev/null +++ b/0106-spice-increase-the-verbosity-of-spice-section-in-qem.patch @@ -0,0 +1,50 @@ +From 589cb6a669e11e1ce4b077e8ba0fbb9fc8d5bd40 Mon Sep 17 00:00:00 2001 +From: Yonit Halperin +Date: Tue, 21 Aug 2012 13:54:20 +0300 +Subject: [PATCH] spice: increase the verbosity of spice section in "qemu + --help" + +Added all spice options to the help string. This can be used by libvirt +to determine which spice related features are supported by qemu. + +Signed-off-by: Yonit Halperin +Signed-off-by: Gerd Hoffmann +(cherry picked from commit 27af778828db9aa893fa1de928744141e5de20e5) + +Signed-off-by: Michael Roth +--- + qemu-options.hx | 18 +++++++++++++++++- + 1 file changed, 17 insertions(+), 1 deletion(-) + +diff --git a/qemu-options.hx b/qemu-options.hx +index dd7aa63..1af4fec 100644 +--- a/qemu-options.hx ++++ b/qemu-options.hx +@@ -838,7 +838,23 @@ Enable SDL. + ETEXI + + DEF("spice", HAS_ARG, QEMU_OPTION_spice, +- "-spice enable spice\n", QEMU_ARCH_ALL) ++ "-spice [port=port][,tls-port=secured-port][,x509-dir=]\n" ++ " [,x509-key-file=][,x509-key-password=]\n" ++ " [,x509-cert-file=][,x509-cacert-file=]\n" ++ " [,x509-dh-key-file=][,addr=addr][,ipv4|ipv6]\n" ++ " [,tls-ciphers=]\n" ++ " [,tls-channel=[main|display|cursor|inputs|record|playback]]\n" ++ " [,plaintext-channel=[main|display|cursor|inputs|record|playback]]\n" ++ " [,sasl][,password=][,disable-ticketing]\n" ++ " [,image-compression=[auto_glz|auto_lz|quic|glz|lz|off]]\n" ++ " [,jpeg-wan-compression=[auto|never|always]]\n" ++ " [,zlib-glz-wan-compression=[auto|never|always]]\n" ++ " [,streaming-video=[off|all|filter]][,disable-copy-paste]\n" ++ " [,agent-mouse=[on|off]][,playback-compression=[on|off]]\n" ++ " [,seamless-migration=[on|off]]\n" ++ " enable spice\n" ++ " at least one of {port, tls-port} is mandatory\n", ++ QEMU_ARCH_ALL) + STEXI + @item -spice @var{option}[,@var{option}[,...]] + @findex -spice +-- +1.7.12.1 + diff --git a/0107-char-Throttle-when-host-connection-is-down.patch b/0107-char-Throttle-when-host-connection-is-down.patch deleted file mode 100644 index ba767b6..0000000 --- a/0107-char-Throttle-when-host-connection-is-down.patch +++ /dev/null @@ -1,60 +0,0 @@ -From 33883808e5203f398ceac6eaf0b6647326df9c1f Mon Sep 17 00:00:00 2001 -Message-Id: <33883808e5203f398ceac6eaf0b6647326df9c1f.1346162949.git.crobinso@redhat.com> -In-Reply-To: <90a59d545ad6759c105b0bfcfca70f574482584f.1346162949.git.crobinso@redhat.com> -References: <90a59d545ad6759c105b0bfcfca70f574482584f.1346162949.git.crobinso@redhat.com> -From: Amit Shah -Date: Mon, 21 Mar 2011 22:05:10 +0100 -Subject: [PATCH 107/114] char: Throttle when host connection is down# - -When the host-side connection goes down, throttle the virtio-serial bus -and later unthrottle when a connection gets established. This helps -prevent any lost IO (guest->host) while the host connection was down. - -Bugzilla: 621484 - -This commit actually helps the bug mentioned above as no writes will now -get lost because of the throttling done here. With just the patches -sent earlier for that bug, one write will end up getting lost in the -worst case (host d/c, guest write, host connect). - -Signed-off-by: Amit Shah -Signed-off-by: Cole Robinson ---- - qemu-char.c | 14 ++++++++++++++ - 1 file changed, 14 insertions(+) - -diff --git a/qemu-char.c b/qemu-char.c -index 5e136fd..d86ee88 100644 ---- a/qemu-char.c -+++ b/qemu-char.c -@@ -140,6 +140,9 @@ static void qemu_chr_generic_open_bh(void *opaque) - { - CharDriverState *s = opaque; - qemu_chr_be_event(s, CHR_EVENT_OPENED); -+ if (s->write_blocked) { -+ char_write_unblocked(s); -+ } - qemu_bh_delete(s->bh); - s->bh = NULL; - } -@@ -2246,6 +2249,17 @@ static int tcp_chr_write(CharDriverState *chr, const uint8_t *buf, int len) - ret = send_all(chr, s->fd, buf, len); - if (ret == -1 && errno == EPIPE) { - tcp_closed(chr); -+ -+ if (chr->chr_enable_write_fd_handler && chr->chr_write_unblocked) { -+ /* -+ * Since we haven't written out anything, let's say -+ * we're throttled. This will prevent any output from -+ * the guest getting lost if host-side chardev goes -+ * down. Unthrottle when we re-connect. -+ */ -+ chr->write_blocked = true; -+ return 0; -+ } - } - return ret; - } else { --- -1.7.11.2 - diff --git a/0107-qxl-update_area_io-guest_bug-on-invalid-parameters.patch b/0107-qxl-update_area_io-guest_bug-on-invalid-parameters.patch new file mode 100644 index 0000000..7572299 --- /dev/null +++ b/0107-qxl-update_area_io-guest_bug-on-invalid-parameters.patch @@ -0,0 +1,40 @@ +From 8a3d428e1e0f3e4793b1a1353c638e155a3a8a86 Mon Sep 17 00:00:00 2001 +From: Alon Levy +Date: Tue, 21 Aug 2012 13:51:31 +0300 +Subject: [PATCH] qxl/update_area_io: guest_bug on invalid parameters + +Signed-off-by: Alon Levy +Signed-off-by: Gerd Hoffmann +(cherry picked from commit 511b13e2c9b426b3c56060909693de5097f0b496) + +Signed-off-by: Michael Roth +--- + hw/qxl.c | 12 ++++++++++++ + 1 file changed, 12 insertions(+) + +diff --git a/hw/qxl.c b/hw/qxl.c +index 95bbc03..baf9bb4 100644 +--- a/hw/qxl.c ++++ b/hw/qxl.c +@@ -1386,6 +1386,18 @@ async_common: + QXLCookie *cookie = NULL; + QXLRect update = d->ram->update_area; + ++ if (d->ram->update_surface > NUM_SURFACES) { ++ qxl_set_guest_bug(d, "QXL_IO_UPDATE_AREA: invalid surface id %d\n", ++ d->ram->update_surface); ++ return; ++ } ++ if (update.left >= update.right || update.top >= update.bottom) { ++ qxl_set_guest_bug(d, ++ "QXL_IO_UPDATE_AREA: invalid area (%ux%u)x(%ux%u)\n", ++ update.left, update.top, update.right, update.bottom); ++ return; ++ } ++ + if (async == QXL_ASYNC) { + cookie = qxl_cookie_new(QXL_COOKIE_TYPE_IO, + QXL_IO_UPDATE_AREA_ASYNC); +-- +1.7.12.1 + diff --git a/0108-qxl-add-QXL_IO_MONITORS_CONFIG_ASYNC.patch b/0108-qxl-add-QXL_IO_MONITORS_CONFIG_ASYNC.patch new file mode 100644 index 0000000..50dbee0 --- /dev/null +++ b/0108-qxl-add-QXL_IO_MONITORS_CONFIG_ASYNC.patch @@ -0,0 +1,327 @@ +From e9062966428416da41ec5f9ace3d2ef58b3265b1 Mon Sep 17 00:00:00 2001 +From: Alon Levy +Date: Wed, 22 Aug 2012 11:16:25 +0300 +Subject: [PATCH] qxl: add QXL_IO_MONITORS_CONFIG_ASYNC + +Revision bumped to 4 for new IO support, enabled for spice-server >= +0.11.1. New io enabled if revision is 4. Revision can be set to 4. + +[ kraxel: 3 continues to be the default revision. Once we have a new + stable spice-server release and the qemu patches to enable + the new bits merged we'll go flip the switch and make rev4 + the default ] + +This io calls the corresponding new spice api +spice_qxl_monitors_config_async to let spice-server read a new guest set +monitors config and notify the client. + +On migration reissue spice_qxl_monitors_config_async. + +RHBZ: 770842 + +Signed-off-by: Alon Levy +Signed-off-by: Gerd Hoffmann + +fixup + +Signed-off-by: Gerd Hoffmann +(cherry picked from commit 020af1c45fec664d5d4cf3b8e5117f8bc1d691f2) + +Conflicts: + + hw/qxl.c + +Signed-off-by: Michael Roth +--- + configure | 7 ++++ + hw/qxl.c | 98 ++++++++++++++++++++++++++++++++++++++++++++++++++++-- + hw/qxl.h | 7 ++++ + trace-events | 1 + + ui/spice-display.h | 1 + + 5 files changed, 111 insertions(+), 3 deletions(-) + +diff --git a/configure b/configure +index 8ffddf4..b5cea26 100755 +--- a/configure ++++ b/configure +@@ -2670,6 +2670,9 @@ EOF + spice="yes" + libs_softmmu="$libs_softmmu $spice_libs" + QEMU_CFLAGS="$QEMU_CFLAGS $spice_cflags" ++ if $pkg_config --atleast-version=0.12.0 spice-protocol >/dev/null 2>&1; then ++ spice_qxl_io_monitors_config_async="yes" ++ fi + else + if test "$spice" = "yes" ; then + feature_not_found "spice" +@@ -3407,6 +3410,10 @@ if test "$spice" = "yes" ; then + echo "CONFIG_SPICE=y" >> $config_host_mak + fi + ++if test "$spice_qxl_io_monitors_config_async" = "yes" ; then ++ echo "CONFIG_QXL_IO_MONITORS_CONFIG_ASYNC=y" >> $config_host_mak ++fi ++ + if test "$smartcard" = "yes" ; then + echo "CONFIG_SMARTCARD=y" >> $config_host_mak + fi +diff --git a/hw/qxl.c b/hw/qxl.c +index baf9bb4..27f3779 100644 +--- a/hw/qxl.c ++++ b/hw/qxl.c +@@ -27,6 +27,11 @@ + + #include "qxl.h" + ++#ifndef CONFIG_QXL_IO_MONITORS_CONFIG_ASYNC ++/* spice-protocol is too old, add missing definitions */ ++#define QXL_IO_MONITORS_CONFIG_ASYNC (QXL_IO_FLUSH_RELEASE + 1) ++#endif ++ + /* + * NOTE: SPICE_RING_PROD_ITEM accesses memory on the pci bar and as + * such can be changed by the guest, so to avoid a guest trigerrable +@@ -249,6 +254,39 @@ static void qxl_spice_destroy_surfaces(PCIQXLDevice *qxl, qxl_async_io async) + } + } + ++static void qxl_spice_monitors_config_async(PCIQXLDevice *qxl, int replay) ++{ ++ trace_qxl_spice_monitors_config(qxl->id); ++/* 0x000b01 == 0.11.1 */ ++#if SPICE_SERVER_VERSION >= 0x000b01 && \ ++ defined(CONFIG_QXL_IO_MONITORS_CONFIG_ASYNC) ++ if (replay) { ++ /* ++ * don't use QXL_COOKIE_TYPE_IO: ++ * - we are not running yet (post_load), we will assert ++ * in send_events ++ * - this is not a guest io, but a reply, so async_io isn't set. ++ */ ++ spice_qxl_monitors_config_async(&qxl->ssd.qxl, ++ qxl->guest_monitors_config, ++ MEMSLOT_GROUP_GUEST, ++ (uintptr_t)qxl_cookie_new( ++ QXL_COOKIE_TYPE_POST_LOAD_MONITORS_CONFIG, ++ 0)); ++ } else { ++ qxl->guest_monitors_config = qxl->ram->monitors_config; ++ spice_qxl_monitors_config_async(&qxl->ssd.qxl, ++ qxl->ram->monitors_config, ++ MEMSLOT_GROUP_GUEST, ++ (uintptr_t)qxl_cookie_new(QXL_COOKIE_TYPE_IO, ++ QXL_IO_MONITORS_CONFIG_ASYNC)); ++ } ++#else ++ fprintf(stderr, "qxl: too old spice-protocol/spice-server for " ++ "QXL_IO_MONITORS_CONFIG_ASYNC\n"); ++#endif ++} ++ + void qxl_spice_reset_image_cache(PCIQXLDevice *qxl) + { + trace_qxl_spice_reset_image_cache(qxl->id); +@@ -538,6 +576,7 @@ static const char *io_port_to_string(uint32_t io_port) + = "QXL_IO_DESTROY_ALL_SURFACES_ASYNC", + [QXL_IO_FLUSH_SURFACES_ASYNC] = "QXL_IO_FLUSH_SURFACES_ASYNC", + [QXL_IO_FLUSH_RELEASE] = "QXL_IO_FLUSH_RELEASE", ++ [QXL_IO_MONITORS_CONFIG_ASYNC] = "QXL_IO_MONITORS_CONFIG_ASYNC", + }; + return io_port_to_string[io_port]; + } +@@ -819,6 +858,7 @@ static void interface_async_complete_io(PCIQXLDevice *qxl, QXLCookie *cookie) + case QXL_IO_DESTROY_PRIMARY_ASYNC: + case QXL_IO_UPDATE_AREA_ASYNC: + case QXL_IO_FLUSH_SURFACES_ASYNC: ++ case QXL_IO_MONITORS_CONFIG_ASYNC: + break; + case QXL_IO_CREATE_PRIMARY_ASYNC: + qxl_create_guest_primary_complete(qxl); +@@ -894,6 +934,8 @@ static void interface_async_complete(QXLInstance *sin, uint64_t cookie_token) + case QXL_COOKIE_TYPE_RENDER_UPDATE_AREA: + qxl_render_update_area_done(qxl, cookie); + break; ++ case QXL_COOKIE_TYPE_POST_LOAD_MONITORS_CONFIG: ++ break; + default: + fprintf(stderr, "qxl: %s: unexpected cookie type %d\n", + __func__, cookie->type); +@@ -1315,6 +1357,13 @@ static void ioport_write(void *opaque, target_phys_addr_t addr, + return; + } + ++ if (d->revision <= QXL_REVISION_STABLE_V10 && ++ io_port >= QXL_IO_FLUSH_SURFACES_ASYNC) { ++ qxl_set_guest_bug(d, "unsupported io %d for revision %d\n", ++ io_port, d->revision); ++ return; ++ } ++ + switch (io_port) { + case QXL_IO_RESET: + case QXL_IO_SET_MODE: +@@ -1334,7 +1383,7 @@ static void ioport_write(void *opaque, target_phys_addr_t addr, + io_port, io_port_to_string(io_port)); + /* be nice to buggy guest drivers */ + if (io_port >= QXL_IO_UPDATE_AREA_ASYNC && +- io_port <= QXL_IO_DESTROY_ALL_SURFACES_ASYNC) { ++ io_port < QXL_IO_RANGE_SIZE) { + qxl_send_events(d, QXL_INTERRUPT_IO_CMD); + } + return; +@@ -1362,6 +1411,7 @@ static void ioport_write(void *opaque, target_phys_addr_t addr, + io_port = QXL_IO_DESTROY_ALL_SURFACES; + goto async_common; + case QXL_IO_FLUSH_SURFACES_ASYNC: ++ case QXL_IO_MONITORS_CONFIG_ASYNC: + async_common: + async = QXL_ASYNC; + qemu_mutex_lock(&d->async_lock); +@@ -1503,6 +1553,9 @@ async_common: + d->mode = QXL_MODE_UNDEFINED; + qxl_spice_destroy_surfaces(d, async); + break; ++ case QXL_IO_MONITORS_CONFIG_ASYNC: ++ qxl_spice_monitors_config_async(d, 0); ++ break; + default: + qxl_set_guest_bug(d, "%s: unexpected ioport=0x%x\n", __func__, io_port); + } +@@ -1798,6 +1851,17 @@ static int qxl_init_common(PCIQXLDevice *qxl) + io_size = 16; + break; + case 3: /* qxl-3 */ ++ pci_device_rev = QXL_REVISION_STABLE_V10; ++ io_size = 32; /* PCI region size must be pow2 */ ++ break; ++/* 0x000b01 == 0.11.1 */ ++#if SPICE_SERVER_VERSION >= 0x000b01 && \ ++ defined(CONFIG_QXL_IO_MONITORS_CONFIG_ASYNC) ++ case 4: /* qxl-4 */ ++ pci_device_rev = QXL_REVISION_STABLE_V12; ++ io_size = msb_mask(QXL_IO_RANGE_SIZE * 2 - 1); ++ break; ++#endif + default: + pci_device_rev = QXL_DEFAULT_REVISION; + io_size = msb_mask(QXL_IO_RANGE_SIZE * 2 - 1); +@@ -1996,7 +2060,9 @@ static int qxl_post_load(void *opaque, int version) + } + qxl_spice_loadvm_commands(d, cmds, out); + g_free(cmds); +- ++ if (d->guest_monitors_config) { ++ qxl_spice_monitors_config_async(d, 1); ++ } + break; + case QXL_MODE_COMPAT: + /* note: no need to call qxl_create_memslots, qxl_set_mode +@@ -2009,6 +2075,14 @@ static int qxl_post_load(void *opaque, int version) + + #define QXL_SAVE_VERSION 21 + ++static bool qxl_monitors_config_needed(void *opaque) ++{ ++ PCIQXLDevice *qxl = opaque; ++ ++ return qxl->guest_monitors_config != 0; ++} ++ ++ + static VMStateDescription qxl_memslot = { + .name = "qxl-memslot", + .version_id = QXL_SAVE_VERSION, +@@ -2039,6 +2113,16 @@ static VMStateDescription qxl_surface = { + } + }; + ++static VMStateDescription qxl_vmstate_monitors_config = { ++ .name = "qxl/monitors-config", ++ .version_id = 1, ++ .minimum_version_id = 1, ++ .fields = (VMStateField[]) { ++ VMSTATE_UINT64(guest_monitors_config, PCIQXLDevice), ++ VMSTATE_END_OF_LIST() ++ }, ++}; ++ + static VMStateDescription qxl_vmstate = { + .name = "qxl", + .version_id = QXL_SAVE_VERSION, +@@ -2046,7 +2130,7 @@ static VMStateDescription qxl_vmstate = { + .pre_save = qxl_pre_save, + .pre_load = qxl_pre_load, + .post_load = qxl_post_load, +- .fields = (VMStateField []) { ++ .fields = (VMStateField[]) { + VMSTATE_PCI_DEVICE(pci, PCIQXLDevice), + VMSTATE_STRUCT(vga, PCIQXLDevice, 0, vmstate_vga_common, VGACommonState), + VMSTATE_UINT32(shadow_rom.mode, PCIQXLDevice), +@@ -2065,6 +2149,14 @@ static VMStateDescription qxl_vmstate = { + VMSTATE_UINT64(guest_cursor, PCIQXLDevice), + VMSTATE_END_OF_LIST() + }, ++ .subsections = (VMStateSubsection[]) { ++ { ++ .vmsd = &qxl_vmstate_monitors_config, ++ .needed = qxl_monitors_config_needed, ++ }, { ++ /* empty */ ++ } ++ } + }; + + static Property qxl_properties[] = { +diff --git a/hw/qxl.h b/hw/qxl.h +index 172baf6..9cfedb7 100644 +--- a/hw/qxl.h ++++ b/hw/qxl.h +@@ -71,6 +71,8 @@ typedef struct PCIQXLDevice { + } guest_surfaces; + QXLPHYSICAL guest_cursor; + ++ QXLPHYSICAL guest_monitors_config; ++ + QemuMutex track_lock; + + /* thread signaling */ +@@ -128,7 +130,12 @@ typedef struct PCIQXLDevice { + } \ + } while (0) + ++#if 0 ++/* spice-server 0.12 is still in development */ ++#define QXL_DEFAULT_REVISION QXL_REVISION_STABLE_V12 ++#else + #define QXL_DEFAULT_REVISION QXL_REVISION_STABLE_V10 ++#endif + + /* qxl.c */ + void *qxl_phys2virt(PCIQXLDevice *qxl, QXLPHYSICAL phys, int group_id); +diff --git a/trace-events b/trace-events +index 04b0723..8fcbc50 100644 +--- a/trace-events ++++ b/trace-events +@@ -956,6 +956,7 @@ qxl_spice_destroy_surfaces(int qid, int async) "%d async=%d" + qxl_spice_destroy_surface_wait_complete(int qid, uint32_t id) "%d sid=%d" + qxl_spice_destroy_surface_wait(int qid, uint32_t id, int async) "%d sid=%d async=%d" + qxl_spice_flush_surfaces_async(int qid, uint32_t surface_count, uint32_t num_free_res) "%d s#=%d, res#=%d" ++qxl_spice_monitors_config(int id) "%d" + qxl_spice_loadvm_commands(int qid, void *ext, uint32_t count) "%d ext=%p count=%d" + qxl_spice_oom(int qid) "%d" + qxl_spice_reset_cursor(int qid) "%d" +diff --git a/ui/spice-display.h b/ui/spice-display.h +index 672d65e..bcff114 100644 +--- a/ui/spice-display.h ++++ b/ui/spice-display.h +@@ -51,6 +51,7 @@ typedef enum qxl_async_io { + enum { + QXL_COOKIE_TYPE_IO, + QXL_COOKIE_TYPE_RENDER_UPDATE_AREA, ++ QXL_COOKIE_TYPE_POST_LOAD_MONITORS_CONFIG, + }; + + typedef struct QXLCookie { +-- +1.7.12.1 + diff --git a/0108-virtio-console-Enable-port-throttling-when-chardev-i.patch b/0108-virtio-console-Enable-port-throttling-when-chardev-i.patch deleted file mode 100644 index a9dab46..0000000 --- a/0108-virtio-console-Enable-port-throttling-when-chardev-i.patch +++ /dev/null @@ -1,53 +0,0 @@ -From 675cb3b8588b2ad494b304998bbf035144ed99be Mon Sep 17 00:00:00 2001 -Message-Id: <675cb3b8588b2ad494b304998bbf035144ed99be.1346162949.git.crobinso@redhat.com> -In-Reply-To: <90a59d545ad6759c105b0bfcfca70f574482584f.1346162949.git.crobinso@redhat.com> -References: <90a59d545ad6759c105b0bfcfca70f574482584f.1346162949.git.crobinso@redhat.com> -From: Amit Shah -Date: Mon, 21 Mar 2011 22:06:41 +0100 -Subject: [PATCH 108/114] virtio-console: Enable port throttling when chardev - is slow to consume data - -When a chardev indicates it can't accept more data, we tell the -virtio-serial code to stop sending us any more data till we tell -otherwise. This helps in guests continuing to run normally while the vq -keeps getting full and eventually the guest stops queueing more data. -As soon as the chardev indicates it can accept more data, start pushing! - -Signed-off-by: Amit Shah -Signed-off-by: Cole Robinson ---- - hw/virtio-console.c | 11 +++++++++++ - 1 file changed, 11 insertions(+) - -diff --git a/hw/virtio-console.c b/hw/virtio-console.c -index 066590c..2b5e515 100644 ---- a/hw/virtio-console.c -+++ b/hw/virtio-console.c -@@ -20,6 +20,16 @@ typedef struct VirtConsole { - CharDriverState *chr; - } VirtConsole; - -+/* -+ * Callback function that's called from chardevs when backend becomes -+ * writable. -+ */ -+static void chr_write_unblocked(void *opaque) -+{ -+ VirtConsole *vcon = opaque; -+ -+ virtio_serial_throttle_port(&vcon->port, false); -+} - - /* Callback function that's called when the guest sends us data */ - static ssize_t flush_buf(VirtIOSerialPort *port, const uint8_t *buf, size_t len) -@@ -110,6 +120,7 @@ static const QemuChrHandlers chr_handlers = { - .fd_can_read = chr_can_read, - .fd_read = chr_read, - .fd_event = chr_event, -+ .fd_write_unblocked = chr_write_unblocked, - }; - - static int virtconsole_initfn(VirtIOSerialPort *port) --- -1.7.11.2 - diff --git a/0109-configure-print-spice-protocol-and-spice-server-vers.patch b/0109-configure-print-spice-protocol-and-spice-server-vers.patch new file mode 100644 index 0000000..9e7f529 --- /dev/null +++ b/0109-configure-print-spice-protocol-and-spice-server-vers.patch @@ -0,0 +1,39 @@ +From b132bd0cdb4d684105b91a8173c172296cd191af Mon Sep 17 00:00:00 2001 +From: Alon Levy +Date: Wed, 22 Aug 2012 11:16:26 +0300 +Subject: [PATCH] configure: print spice-protocol and spice-server versions + +Signed-off-by: Alon Levy +Signed-off-by: Gerd Hoffmann +(cherry picked from commit 2e0e3c399aa8067148055b9ea0edb822c5b584d2) + +Signed-off-by: Michael Roth +--- + configure | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/configure b/configure +index b5cea26..d7a948f 100755 +--- a/configure ++++ b/configure +@@ -2670,6 +2670,8 @@ EOF + spice="yes" + libs_softmmu="$libs_softmmu $spice_libs" + QEMU_CFLAGS="$QEMU_CFLAGS $spice_cflags" ++ spice_protocol_version=$($pkg_config --modversion spice-protocol) ++ spice_server_version=$($pkg_config --modversion spice-server) + if $pkg_config --atleast-version=0.12.0 spice-protocol >/dev/null 2>&1; then + spice_qxl_io_monitors_config_async="yes" + fi +@@ -3128,7 +3130,7 @@ echo "libcap-ng support $cap_ng" + echo "vhost-net support $vhost_net" + echo "Trace backend $trace_backend" + echo "Trace output file $trace_file-" +-echo "spice support $spice" ++echo "spice support $spice ($spice_protocol_version/$spice_server_version)" + echo "rbd support $rbd" + echo "xfsctl support $xfs" + echo "nss used $smartcard_nss" +-- +1.7.12.1 + diff --git a/0109-spice-qemu-char.c-add-throttling.patch b/0109-spice-qemu-char.c-add-throttling.patch deleted file mode 100644 index 950f861..0000000 --- a/0109-spice-qemu-char.c-add-throttling.patch +++ /dev/null @@ -1,138 +0,0 @@ -From 3f1c594ea851fdee517a824b1eed3e034cd051ec Mon Sep 17 00:00:00 2001 -Message-Id: <3f1c594ea851fdee517a824b1eed3e034cd051ec.1346162949.git.crobinso@redhat.com> -In-Reply-To: <90a59d545ad6759c105b0bfcfca70f574482584f.1346162949.git.crobinso@redhat.com> -References: <90a59d545ad6759c105b0bfcfca70f574482584f.1346162949.git.crobinso@redhat.com> -From: Alon Levy -Date: Tue, 22 Mar 2011 12:27:59 +0200 -Subject: [PATCH 109/114] spice-qemu-char.c: add throttling - -BZ: 672191 - -upstream: not submitted (explained below) - -Adds throttling support to spicevmc chardev. Uses a timer to avoid recursing: -1. spice-server: reds.c: read_from_vdi_port -2. qemu: spice-qemu-char.c: vmc_read -3. chr_write_unblocked - (calls virtio_serial_throttle_port(port, false)) -4. qemu: virtio ... -5. qemu: spice-qemu-char.c: spice_chr_write -6. qemu: spice-qemu-char.c: wakeup (calls into spice-server) -7. spice-server: ... -8. qemu: spice-qemu-char.c: vmc_read - -Instead, in vmc_read if we were throttled and we are just about to return -all the bytes we will set a timer to be triggered immediately to call -chr_write_unblocked. Then we return after 2 above, and 3 is called from the -timer callback. This also means we can later remove some ugly recursion protection -from spice-server. - -The other tricky point in this patch is not returning the leftover chunk twice. -When we throttle, by definition we have data that spice server didn't consume. -It is being kept by virtio-serial, and by us. The next vmc_read callback needs -to not return it, but just do unthrottling. Then virtio will give us the remaining -chunk as usual in spice_chr_write, and we will pass it to spice server in the -next vmc_read. - -This patch relies on Amit's series to expose throttling to chardev's, which -was not accepted upstream, and will not be accepted upstream until the mainloop -is reworked to use glib. - -Signed-off-by: Cole Robinson ---- - spice-qemu-char.c | 39 +++++++++++++++++++++++++++++++++++---- - 1 file changed, 35 insertions(+), 4 deletions(-) - -diff --git a/spice-qemu-char.c b/spice-qemu-char.c -index 09aa22d..fba2bfb 100644 ---- a/spice-qemu-char.c -+++ b/spice-qemu-char.c -@@ -1,4 +1,6 @@ - #include "config-host.h" -+#include "qemu-common.h" -+#include "qemu-timer.h" - #include "trace.h" - #include "ui/qemu-spice.h" - #include -@@ -25,6 +27,7 @@ typedef struct SpiceCharDriver { - uint8_t *datapos; - ssize_t bufsize, datalen; - uint32_t debug; -+ QEMUTimer *unblock_timer; - } SpiceCharDriver; - - static int vmc_write(SpiceCharDeviceInstance *sin, const uint8_t *buf, int len) -@@ -50,6 +53,17 @@ static int vmc_write(SpiceCharDeviceInstance *sin, const uint8_t *buf, int len) - return out; - } - -+static void spice_chr_unblock(void *opaque) -+{ -+ SpiceCharDriver *scd = opaque; -+ -+ if (scd->chr->chr_write_unblocked == NULL) { -+ dprintf(scd, 1, "%s: backend doesn't support unthrottling.\n", __func__); -+ return; -+ } -+ scd->chr->chr_write_unblocked(scd->chr->handler_opaque); -+} -+ - static int vmc_read(SpiceCharDeviceInstance *sin, uint8_t *buf, int len) - { - SpiceCharDriver *scd = container_of(sin, SpiceCharDriver, sin); -@@ -61,9 +75,16 @@ static int vmc_read(SpiceCharDeviceInstance *sin, uint8_t *buf, int len) - scd->datapos += bytes; - scd->datalen -= bytes; - assert(scd->datalen >= 0); -- if (scd->datalen == 0) { -- scd->datapos = 0; -- } -+ } -+ if (scd->datalen == 0 && scd->chr->write_blocked) { -+ dprintf(scd, 1, "%s: unthrottling (%d)\n", __func__, bytes); -+ scd->chr->write_blocked = false; -+ /* -+ * set a timer instead of calling scd->chr->chr_write_unblocked directly, -+ * because that will call back into spice_chr_write (see -+ * virtio-console.c:chr_write_unblocked), which is unwanted. -+ */ -+ qemu_mod_timer(scd->unblock_timer, 0); - } - trace_spice_vmc_read(bytes, len); - return bytes; -@@ -135,6 +156,7 @@ static void vmc_unregister_interface(SpiceCharDriver *scd) - static int spice_chr_write(CharDriverState *chr, const uint8_t *buf, int len) - { - SpiceCharDriver *s = chr->opaque; -+ int read_bytes; - - dprintf(s, 2, "%s: %d\n", __func__, len); - vmc_register_interface(s); -@@ -147,7 +169,15 @@ static int spice_chr_write(CharDriverState *chr, const uint8_t *buf, int len) - s->datapos = s->buffer; - s->datalen = len; - spice_server_char_device_wakeup(&s->sin); -- return len; -+ read_bytes = len - s->datalen; -+ if (read_bytes != len) { -+ dprintf(s, 1, "%s: throttling: %d < %d (%zd)\n", __func__, -+ read_bytes, len, s->bufsize); -+ s->chr->write_blocked = true; -+ /* We'll get passed in the unconsumed data with the next call */ -+ s->datalen = 0; -+ } -+ return read_bytes; - } - - static void spice_chr_close(struct CharDriverState *chr) -@@ -225,6 +255,7 @@ CharDriverState *qemu_chr_open_spice(QemuOpts *opts) - chr->chr_close = spice_chr_close; - chr->chr_guest_open = spice_chr_guest_open; - chr->chr_guest_close = spice_chr_guest_close; -+ s->unblock_timer = qemu_new_timer_ms(vm_clock, spice_chr_unblock, s); - - #if SPICE_SERVER_VERSION < 0x000901 - /* See comment in vmc_state() */ --- -1.7.11.2 - diff --git a/0110-fix-doc-of-using-raw-values-with-sendkey.patch b/0110-fix-doc-of-using-raw-values-with-sendkey.patch new file mode 100644 index 0000000..9e59097 --- /dev/null +++ b/0110-fix-doc-of-using-raw-values-with-sendkey.patch @@ -0,0 +1,42 @@ +From 211b2548bfbdab72051a7ef1e9982ff4ec0fd98f Mon Sep 17 00:00:00 2001 +From: Amos Kong +Date: Fri, 31 Aug 2012 10:56:20 +0800 +Subject: [PATCH] fix doc of using raw values with sendkey + +(qemu) sendkey a +(qemu) sendkey 0x1e +(qemu) sendkey #0x1e + unknown key: '#0x1e' + +The last command doesn't work, '#' is not requested before +raw values, and the raw value in decimal format is not supported. + +Signed-off-by: Amos Kong +Signed-off-by: Luiz Capitulino +(cherry picked from commit 886cc706ce5d4d3d1c296f028ddc2991cfbe3bbe) + +Signed-off-by: Michael Roth +--- + hmp-commands.hx | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/hmp-commands.hx b/hmp-commands.hx +index 13f28cf..a72614d 100644 +--- a/hmp-commands.hx ++++ b/hmp-commands.hx +@@ -512,9 +512,9 @@ STEXI + @item sendkey @var{keys} + @findex sendkey + +-Send @var{keys} to the emulator. @var{keys} could be the name of the +-key or @code{#} followed by the raw value in either decimal or hexadecimal +-format. Use @code{-} to press several keys simultaneously. Example: ++Send @var{keys} to the guest. @var{keys} could be the name of the ++key or the raw value in hexadecimal format. Use @code{-} to press ++several keys simultaneously. Example: + @example + sendkey ctrl-alt-f1 + @end example +-- +1.7.12.1 + diff --git a/0110-spice-qemu-char.c-remove-intermediate-buffer.patch b/0110-spice-qemu-char.c-remove-intermediate-buffer.patch deleted file mode 100644 index 395019b..0000000 --- a/0110-spice-qemu-char.c-remove-intermediate-buffer.patch +++ /dev/null @@ -1,76 +0,0 @@ -From 682f29243b10ace00a42fed9920a94938abe2706 Mon Sep 17 00:00:00 2001 -Message-Id: <682f29243b10ace00a42fed9920a94938abe2706.1346162949.git.crobinso@redhat.com> -In-Reply-To: <90a59d545ad6759c105b0bfcfca70f574482584f.1346162949.git.crobinso@redhat.com> -References: <90a59d545ad6759c105b0bfcfca70f574482584f.1346162949.git.crobinso@redhat.com> -From: Alon Levy -Date: Tue, 22 Mar 2011 12:28:00 +0200 -Subject: [PATCH 110/114] spice-qemu-char.c: remove intermediate buffer - -BZ: 672191 -upstream: not submitted (explained below) - -virtio-serial's buffer is valid when it calls us, and we don't -access it otherwise: vmc_read is only called in response to wakeup, -or else we set datalen=0 and throttle. Then vmc_read is called back, -we return 0 (not accessing the buffer) and set the timer to unthrottle. - -Also make datalen int and not ssize_t (to fit spice_chr_write signature). - -This relied on the previous patch that introduces throttling, which -can't go upstream right now as explained in that patch. - -Signed-off-by: Cole Robinson ---- - spice-qemu-char.c | 18 ++++++------------ - 1 file changed, 6 insertions(+), 12 deletions(-) - -diff --git a/spice-qemu-char.c b/spice-qemu-char.c -index fba2bfb..ef44bc0 100644 ---- a/spice-qemu-char.c -+++ b/spice-qemu-char.c -@@ -23,9 +23,8 @@ typedef struct SpiceCharDriver { - SpiceCharDeviceInstance sin; - char *subtype; - bool active; -- uint8_t *buffer; -- uint8_t *datapos; -- ssize_t bufsize, datalen; -+ const uint8_t *datapos; -+ int datalen; - uint32_t debug; - QEMUTimer *unblock_timer; - } SpiceCharDriver; -@@ -69,7 +68,7 @@ static int vmc_read(SpiceCharDeviceInstance *sin, uint8_t *buf, int len) - SpiceCharDriver *scd = container_of(sin, SpiceCharDriver, sin); - int bytes = MIN(len, scd->datalen); - -- dprintf(scd, 2, "%s: %p %d/%d/%zd\n", __func__, scd->datapos, len, bytes, scd->datalen); -+ dprintf(scd, 2, "%s: %p %d/%d/%d\n", __func__, scd->datapos, len, bytes, scd->datalen); - if (bytes > 0) { - memcpy(buf, scd->datapos, bytes); - scd->datapos += bytes; -@@ -161,18 +160,13 @@ static int spice_chr_write(CharDriverState *chr, const uint8_t *buf, int len) - dprintf(s, 2, "%s: %d\n", __func__, len); - vmc_register_interface(s); - assert(s->datalen == 0); -- if (s->bufsize < len) { -- s->bufsize = len; -- s->buffer = g_realloc(s->buffer, s->bufsize); -- } -- memcpy(s->buffer, buf, len); -- s->datapos = s->buffer; -+ s->datapos = buf; - s->datalen = len; - spice_server_char_device_wakeup(&s->sin); - read_bytes = len - s->datalen; - if (read_bytes != len) { -- dprintf(s, 1, "%s: throttling: %d < %d (%zd)\n", __func__, -- read_bytes, len, s->bufsize); -+ dprintf(s, 1, "%s: throttling: %d < %d\n", __func__, -+ read_bytes, len); - s->chr->write_blocked = true; - /* We'll get passed in the unconsumed data with the next call */ - s->datalen = 0; --- -1.7.11.2 - diff --git a/0111-qapi-Fix-potential-NULL-pointer-segfault.patch b/0111-qapi-Fix-potential-NULL-pointer-segfault.patch new file mode 100644 index 0000000..8f15921 --- /dev/null +++ b/0111-qapi-Fix-potential-NULL-pointer-segfault.patch @@ -0,0 +1,38 @@ +From d01c76a8d9d0d80ba00a407103e7b79112a21fce Mon Sep 17 00:00:00 2001 +From: Stefan Weil +Date: Sat, 1 Sep 2012 09:30:39 +0200 +Subject: [PATCH] qapi: Fix potential NULL pointer segfault + +Report from smatch: + +qapi-visit.c:1640 visit_type_BlockdevAction(8) error: + we previously assumed 'obj' could be null (see line 1639) +qapi-visit.c:2432 visit_type_NetClientOptions(8) error: + we previously assumed 'obj' could be null (see line 2431) + +Signed-off-by: Stefan Weil +Reviewed-by: Paolo Bonzini +Signed-off-by: Luiz Capitulino +(cherry picked from commit 227ccf6bff234c29974c2c18ecd3a29e6b965e3d) + +Signed-off-by: Michael Roth +--- + scripts/qapi-visit.py | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/scripts/qapi-visit.py b/scripts/qapi-visit.py +index 04ef7c4..5b15ee3 100644 +--- a/scripts/qapi-visit.py ++++ b/scripts/qapi-visit.py +@@ -157,7 +157,7 @@ void visit_type_%(name)s(Visitor *m, %(name)s ** obj, const char *name, Error ** + if (!error_is_set(errp)) { + visit_start_struct(m, (void **)obj, "%(name)s", name, sizeof(%(name)s), &err); + if (!err) { +- if (!obj || *obj) { ++ if (obj && *obj) { + visit_type_%(name)sKind(m, &(*obj)->kind, "type", &err); + if (!err) { + switch ((*obj)->kind) { +-- +1.7.12.1 + diff --git a/0111-usb-redir-Add-flow-control-support.patch b/0111-usb-redir-Add-flow-control-support.patch deleted file mode 100644 index 76b5ca5..0000000 --- a/0111-usb-redir-Add-flow-control-support.patch +++ /dev/null @@ -1,65 +0,0 @@ -From 70a31fcb3f1238e92279cdc023b83ba3a3042cff Mon Sep 17 00:00:00 2001 -Message-Id: <70a31fcb3f1238e92279cdc023b83ba3a3042cff.1346162949.git.crobinso@redhat.com> -In-Reply-To: <90a59d545ad6759c105b0bfcfca70f574482584f.1346162949.git.crobinso@redhat.com> -References: <90a59d545ad6759c105b0bfcfca70f574482584f.1346162949.git.crobinso@redhat.com> -From: Hans de Goede -Date: Tue, 19 Jul 2011 10:56:19 +0200 -Subject: [PATCH 111/114] usb-redir: Add flow control support - -Signed-off-by: Hans de Goede -Signed-off-by: Cole Robinson ---- - hw/usb/redirect.c | 26 ++++++++++++++++++++++++-- - 1 file changed, 24 insertions(+), 2 deletions(-) - -diff --git a/hw/usb/redirect.c b/hw/usb/redirect.c -index ecb2cd4..1460515 100644 ---- a/hw/usb/redirect.c -+++ b/hw/usb/redirect.c -@@ -236,12 +236,22 @@ static int usbredir_read(void *priv, uint8_t *data, int count) - static int usbredir_write(void *priv, uint8_t *data, int count) - { - USBRedirDevice *dev = priv; -+ int r; - -- if (!dev->cs->opened) { -+ if (!dev->cs->opened || dev->cs->write_blocked) { - return 0; - } - -- return qemu_chr_fe_write(dev->cs, data, count); -+ r = qemu_chr_fe_write(dev->cs, data, count); -+ -+ if (r < 0) { -+ if (dev->cs->write_blocked) { -+ return 0; -+ } -+ return -1; -+ } -+ -+ return r; - } - - /* -@@ -892,10 +902,18 @@ static void usbredir_chardev_event(void *opaque, int event) - } - } - -+static void usbredir_chardev_write_unblocked(void *opaque) -+{ -+ USBRedirDevice *dev = opaque; -+ -+ usbredirparser_do_write(dev->parser); -+} -+ - static const QemuChrHandlers usbredir_chr_handlers = { - .fd_can_read = usbredir_chardev_can_read, - .fd_read = usbredir_chardev_read, - .fd_event = usbredir_chardev_event, -+ .fd_write_unblocked = usbredir_chardev_write_unblocked, - }; - - /* --- -1.7.11.2 - diff --git a/0112-json-parser-Fix-potential-NULL-pointer-segfault.patch b/0112-json-parser-Fix-potential-NULL-pointer-segfault.patch new file mode 100644 index 0000000..8198f24 --- /dev/null +++ b/0112-json-parser-Fix-potential-NULL-pointer-segfault.patch @@ -0,0 +1,40 @@ +From f6df33dc89bfa16645e3a8b76e9457986c07b271 Mon Sep 17 00:00:00 2001 +From: Stefan Weil +Date: Mon, 3 Sep 2012 21:19:11 +0200 +Subject: [PATCH] json-parser: Fix potential NULL pointer segfault + +Report from smatch: +json-parser.c:474 parse_object(62) error: potential null derefence 'dict'. +json-parser.c:553 parse_array(75) error: potential null derefence 'list'. + +Label 'out' in json-parser.c can be called with list == NULL +which is passed to QDECREF. + +Modify QDECREF to handle a NULL argument (inline function qobject_decref +already handles them, too). + +Signed-off-by: Stefan Weil +Signed-off-by: Luiz Capitulino +(cherry picked from commit 149474c93490e1c66f838391bd491db83136d91d) + +Signed-off-by: Michael Roth +--- + qobject.h | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/qobject.h b/qobject.h +index d42386d..9124649 100644 +--- a/qobject.h ++++ b/qobject.h +@@ -71,7 +71,7 @@ typedef struct QObject { + + /* High-level interface for qobject_decref() */ + #define QDECREF(obj) \ +- qobject_decref(QOBJECT(obj)) ++ qobject_decref(obj ? QOBJECT(obj) : NULL) + + /* Initialize an object to default values */ + #define QOBJECT_INIT(obj, qtype_type) \ +-- +1.7.12.1 + diff --git a/0112-virtio-serial-bus-replay-guest_open-on-migration.patch b/0112-virtio-serial-bus-replay-guest_open-on-migration.patch deleted file mode 100644 index 1398ec1..0000000 --- a/0112-virtio-serial-bus-replay-guest_open-on-migration.patch +++ /dev/null @@ -1,54 +0,0 @@ -From 452bc9fd704b7f51a63effb05c9283a9aaf7bc99 Mon Sep 17 00:00:00 2001 -Message-Id: <452bc9fd704b7f51a63effb05c9283a9aaf7bc99.1346162949.git.crobinso@redhat.com> -In-Reply-To: <90a59d545ad6759c105b0bfcfca70f574482584f.1346162949.git.crobinso@redhat.com> -References: <90a59d545ad6759c105b0bfcfca70f574482584f.1346162949.git.crobinso@redhat.com> -From: Alon Levy -Date: Thu, 28 Jul 2011 15:08:48 +0300 -Subject: [PATCH 112/114] virtio-serial-bus: replay guest_open on migration - -When migrating a host with with a spice agent running the mouse becomes -non operational after the migration. This is rhbz #725965. - -The problem is that after migration spice doesn't know the guest agent is open. -Spice is just a char dev here. And a chardev cannot query it's device, the -device has to let the chardev know when it is open. Right now after migration -the chardev which is recreated is in it's default state, which assumes the -guest is disconnected. - -Char devices carry no information across migration, but the virtio-serial does -already carry the guest_connected state. This patch passes that bit to the -chardev. - -Signed-off-by: Alon Levy -Signed-off-by: Cole Robinson ---- - hw/virtio-serial-bus.c | 6 ++++++ - 1 file changed, 6 insertions(+) - -diff --git a/hw/virtio-serial-bus.c b/hw/virtio-serial-bus.c -index 82073f5..18c2ed3 100644 ---- a/hw/virtio-serial-bus.c -+++ b/hw/virtio-serial-bus.c -@@ -682,6 +682,7 @@ static int virtio_serial_load(QEMUFile *f, void *opaque, int version_id) - for (i = 0; i < nr_active_ports; i++) { - uint32_t id; - bool host_connected; -+ VirtIOSerialPortClass *vsc; - - id = qemu_get_be32(f); - port = find_port_by_id(s, id); -@@ -690,6 +691,11 @@ static int virtio_serial_load(QEMUFile *f, void *opaque, int version_id) - } - - port->guest_connected = qemu_get_byte(f); -+ vsc = VIRTIO_SERIAL_PORT_GET_CLASS(port); -+ if (port->guest_connected && vsc->guest_open) { -+ /* replay guest open */ -+ vsc->guest_open(port); -+ } - host_connected = qemu_get_byte(f); - if (host_connected != port->host_connected) { - /* --- -1.7.11.2 - diff --git a/0113-char-Disable-write-callback-if-throttled-chardev-is-.patch b/0113-char-Disable-write-callback-if-throttled-chardev-is-.patch deleted file mode 100644 index 4f449bb..0000000 --- a/0113-char-Disable-write-callback-if-throttled-chardev-is-.patch +++ /dev/null @@ -1,40 +0,0 @@ -From 34b7ca715ee45925b76fbeb23a24c16015adba33 Mon Sep 17 00:00:00 2001 -Message-Id: <34b7ca715ee45925b76fbeb23a24c16015adba33.1346162949.git.crobinso@redhat.com> -In-Reply-To: <90a59d545ad6759c105b0bfcfca70f574482584f.1346162949.git.crobinso@redhat.com> -References: <90a59d545ad6759c105b0bfcfca70f574482584f.1346162949.git.crobinso@redhat.com> -From: Amit Shah -Date: Fri, 2 Dec 2011 15:42:55 +0530 -Subject: [PATCH 113/114] char: Disable write callback if throttled chardev is - detached - -If a throttled chardev is detached from the frontend device, all future -callbacks should be suppressed. Not doing this results in a segfault. - -Bugzilla: 745758 -Upstream: Not applicable, since throttling is a RHEL6-only feature. - -Signed-off-by: Amit Shah -Signed-off-by: Cole Robinson ---- - qemu-char.c | 5 +++++ - 1 file changed, 5 insertions(+) - -diff --git a/qemu-char.c b/qemu-char.c -index d86ee88..9defbec 100644 ---- a/qemu-char.c -+++ b/qemu-char.c -@@ -223,6 +223,11 @@ void qemu_chr_add_handlers(CharDriverState *s, - ++s->avail_connections; - } - if (!handlers) { -+ if (s->write_blocked) { -+ /* Ensure we disable the callback if we were throttled */ -+ s->chr_disable_write_fd_handler(s); -+ /* s->write_blocked is cleared below */ -+ } - handlers = &null_handlers; - } - s->chr_can_read = handlers->fd_can_read; --- -1.7.11.2 - diff --git a/0113-pcie-drop-version_id-field-for-live-migration.patch b/0113-pcie-drop-version_id-field-for-live-migration.patch new file mode 100644 index 0000000..c3a469f --- /dev/null +++ b/0113-pcie-drop-version_id-field-for-live-migration.patch @@ -0,0 +1,79 @@ +From 7544abf3b783fc82b031d40d0685d2047709492a Mon Sep 17 00:00:00 2001 +From: Jason Baron +Date: Wed, 8 Aug 2012 14:29:12 -0400 +Subject: [PATCH] pcie: drop version_id field for live migration + +While testing q35 live migration, I found that the migration would abort with +the following error: "Unknown savevm section type 76". + +The error is due to this check failing in 'vmstate_load_state()': + + while(field->name) { + if ((field->field_exists && + field->field_exists(opaque, version_id)) || + (!field->field_exists && + field->version_id <= version_id)) { + +The VMSTATE_PCIE_DEVICE() currently has a 'version_id' set to 2. However, +'version_id' in the above check is 1. And thus we fail to load the pcie device +field. Further the code returns to 'qemu_loadvm_state()' which produces the +error that I saw. + +I'm proposing to fix this by simply dropping the 'version_id' field from +VMSTATE_PCIE_DEVICE(). VMSTATE_PCI_DEVICE() defines no such field and further +the vmstate_pcie_device that VMSTATE_PCI_DEVICE() refers to is already +versioned. Thus, any versioning issues could be detected at the vmsd level. + +Taking a step back, I think that the 'field->version_id' should be compared +against a saved version number for the field not the 'version_id'. Futhermore, +once vmstate_load_state() is called recursively on another vmsd, the check of: + + if (version_id > vmsd->version_id) { + return -EINVAL; + } + +Will never fail since version_id is always equal to vmsd->version_id. So I'm +wondering why we aren't storing the vmsd version id of the source in the +migration stream? + +This patch also renames the 'name' field of vmstate_pcie_device from: +PCIDevice -> PCIEDevice to differentiate it from vmstate_pci_device. + +Signed-off-by: Jason Baron +Signed-off-by: Michael S. Tsirkin +(cherry picked from commit 1de53459272d89c52bb21b45d5d970de40fbb642) + +Signed-off-by: Michael Roth +--- + hw/pci.c | 2 +- + hw/pcie.h | 1 - + 2 files changed, 1 insertion(+), 2 deletions(-) + +diff --git a/hw/pci.c b/hw/pci.c +index 4d95984..f855cf3 100644 +--- a/hw/pci.c ++++ b/hw/pci.c +@@ -439,7 +439,7 @@ const VMStateDescription vmstate_pci_device = { + }; + + const VMStateDescription vmstate_pcie_device = { +- .name = "PCIDevice", ++ .name = "PCIEDevice", + .version_id = 2, + .minimum_version_id = 1, + .minimum_version_id_old = 1, +diff --git a/hw/pcie.h b/hw/pcie.h +index b8ab0c7..4889194 100644 +--- a/hw/pcie.h ++++ b/hw/pcie.h +@@ -133,7 +133,6 @@ extern const VMStateDescription vmstate_pcie_device; + + #define VMSTATE_PCIE_DEVICE(_field, _state) { \ + .name = (stringify(_field)), \ +- .version_id = 2, \ + .size = sizeof(PCIDevice), \ + .vmsd = &vmstate_pcie_device, \ + .flags = VMS_STRUCT, \ +-- +1.7.12.1 + diff --git a/0114-pcie_aer-clear-cmask-for-Advanced-Error-Interrupt-Me.patch b/0114-pcie_aer-clear-cmask-for-Advanced-Error-Interrupt-Me.patch new file mode 100644 index 0000000..80aad2b --- /dev/null +++ b/0114-pcie_aer-clear-cmask-for-Advanced-Error-Interrupt-Me.patch @@ -0,0 +1,40 @@ +From 89df4609568433f67999c27f9b9cd12e91a7d0b5 Mon Sep 17 00:00:00 2001 +From: Jason Baron +Date: Tue, 4 Sep 2012 16:22:46 -0400 +Subject: [PATCH] pcie_aer: clear cmask for Advanced Error Interrupt Message + Number + +The Advanced Error Interrupt Message Number (bits 31:27 of the Root +Error Status Register) is updated when the number of msi messages assigned to a +device changes. Migration of windows 7 on q35 chipset failed because the check +in get_pci_config_device() fails due to cmask being set on these bits. Its valid +to update these bits and we must restore this state across migration. + +Signed-off-by: Jason Baron +Signed-off-by: Michael S. Tsirkin +(cherry picked from commit 0e180d9c8a7429c55d23d2e7855f1e490a063aaa) + +Signed-off-by: Michael Roth +--- + hw/pcie_aer.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/hw/pcie_aer.c b/hw/pcie_aer.c +index 3b6981c..b04c164 100644 +--- a/hw/pcie_aer.c ++++ b/hw/pcie_aer.c +@@ -738,6 +738,11 @@ void pcie_aer_root_init(PCIDevice *dev) + PCI_ERR_ROOT_CMD_EN_MASK); + pci_set_long(dev->w1cmask + pos + PCI_ERR_ROOT_STATUS, + PCI_ERR_ROOT_STATUS_REPORT_MASK); ++ /* PCI_ERR_ROOT_IRQ is RO but devices change it using a ++ * device-specific method. ++ */ ++ pci_set_long(dev->cmask + pos + PCI_ERR_ROOT_STATUS, ++ ~PCI_ERR_ROOT_IRQ); + } + + void pcie_aer_root_reset(PCIDevice *dev) +-- +1.7.12.1 + diff --git a/0115-fix-entry-pointer-for-ELF-kernels-loaded-with-kernel.patch b/0115-fix-entry-pointer-for-ELF-kernels-loaded-with-kernel.patch new file mode 100644 index 0000000..4488d60 --- /dev/null +++ b/0115-fix-entry-pointer-for-ELF-kernels-loaded-with-kernel.patch @@ -0,0 +1,42 @@ +From 3d24d0452bb11e371c710a68b88f09c3accee51f Mon Sep 17 00:00:00 2001 +From: Henning Schild +Date: Wed, 5 Sep 2012 14:56:39 +0200 +Subject: [PATCH] fix entry pointer for ELF kernels loaded with -kernel option + + Find a hopefully proper patch attached. Take it or leave it. + +Reviewed-by: Kevin Wolf +Signed-off-by: Henning Schild +Signed-off-by: Aurelien Jarno +(cherry picked from commit 7e9c7ffe9fd9dfc3d0168dd584936db8144b230b) + +Signed-off-by: Michael Roth +--- + hw/elf_ops.h | 11 +++++++++++ + 1 file changed, 11 insertions(+) + +diff --git a/hw/elf_ops.h b/hw/elf_ops.h +index fa65ce2..731a983 100644 +--- a/hw/elf_ops.h ++++ b/hw/elf_ops.h +@@ -269,6 +269,17 @@ static int glue(load_elf, SZ)(const char *name, int fd, + addr = ph->p_paddr; + } + ++ /* the entry pointer in the ELF header is a virtual ++ * address, if the text segments paddr and vaddr differ ++ * we need to adjust the entry */ ++ if (pentry && !translate_fn && ++ ph->p_vaddr != ph->p_paddr && ++ ehdr.e_entry >= ph->p_vaddr && ++ ehdr.e_entry < ph->p_vaddr + ph->p_filesz && ++ ph->p_flags & PF_X) { ++ *pentry = ehdr.e_entry - ph->p_vaddr + ph->p_paddr; ++ } ++ + snprintf(label, sizeof(label), "phdr #%d: %s", i, name); + rom_add_blob_fixed(label, data, mem_size, addr); + +-- +1.7.12.1 + diff --git a/0116-lan9118-fix-multicast-filtering.patch b/0116-lan9118-fix-multicast-filtering.patch new file mode 100644 index 0000000..19cb229 --- /dev/null +++ b/0116-lan9118-fix-multicast-filtering.patch @@ -0,0 +1,37 @@ +From 0ea96930bcd85734da46de0cd44d1d0408cbb9be Mon Sep 17 00:00:00 2001 +From: Aurelien Jarno +Date: Sun, 10 Jun 2012 23:18:44 +0200 +Subject: [PATCH] lan9118: fix multicast filtering + +The lan9118 emulation tries to compute the multicast index by calling +directly the crc32() function from zlib, but fails to get the correct +result. + +Use the common compute_mcast_idx() function instead, which gives the +correct result. This fixes IPv6 support. + +Reviewed-by: Peter Maydell +Signed-off-by: Aurelien Jarno +(cherry picked from commit 449bc90e1f2e2fbafb64eb0c76d16c9352b0d2df) + +Signed-off-by: Michael Roth +--- + hw/lan9118.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/hw/lan9118.c b/hw/lan9118.c +index ff0a50b..ceaf96f 100644 +--- a/hw/lan9118.c ++++ b/hw/lan9118.c +@@ -500,7 +500,7 @@ static int lan9118_filter(lan9118_state *s, const uint8_t *addr) + } + } else { + /* Hash matching */ +- hash = (crc32(~0, addr, 6) >> 26); ++ hash = compute_mcast_idx(addr); + if (hash & 0x20) { + return (s->mac_hashh >> (hash & 0x1f)) & 1; + } else { +-- +1.7.12.1 + diff --git a/0117-MIPS-user-Fix-reset-CPU-state-initialization.patch b/0117-MIPS-user-Fix-reset-CPU-state-initialization.patch new file mode 100644 index 0000000..e98d248 --- /dev/null +++ b/0117-MIPS-user-Fix-reset-CPU-state-initialization.patch @@ -0,0 +1,196 @@ +From 608a36df28b4db83124d06081029023e01901fc9 Mon Sep 17 00:00:00 2001 +From: "Maciej W. Rozycki" +Date: Fri, 8 Jun 2012 02:04:40 +0100 +Subject: [PATCH] MIPS/user: Fix reset CPU state initialization + + This change updates the CPU reset sequence to use a common piece of code +that figures out CPU state flags, fixing the problem with MIPS_HFLAG_COP1X +not being set where applicable that causes floating-point MADD family +instructions (and other instructions from the MIPS IV FP subset) to trap. + + As compute_hflags is now shared between op_helper.c and translate.c, the +function is now moved to a common header. There are no changes to this +function. + + The problem was seen with the 24Kf MIPS32r2 processor in user emulation. +The new approach prevents system and user emulation from diverging -- all +the hflags state is initialized in one place now. + +Signed-off-by: Maciej W. Rozycki +Signed-off-by: Aurelien Jarno +(cherry picked from commit 03e6e5017757645f00b2f3b4f3a257973985e455) + +Signed-off-by: Michael Roth +--- + target-mips/cpu.h | 49 +++++++++++++++++++++++++++++++++++++++++++++++++ + target-mips/op_helper.c | 49 ------------------------------------------------- + target-mips/translate.c | 16 +++------------- + 3 files changed, 52 insertions(+), 62 deletions(-) + +diff --git a/target-mips/cpu.h b/target-mips/cpu.h +index be4f805..b7a5112 100644 +--- a/target-mips/cpu.h ++++ b/target-mips/cpu.h +@@ -742,4 +742,53 @@ static inline void cpu_pc_from_tb(CPUMIPSState *env, TranslationBlock *tb) + env->hflags |= tb->flags & MIPS_HFLAG_BMASK; + } + ++static inline void compute_hflags(CPUMIPSState *env) ++{ ++ env->hflags &= ~(MIPS_HFLAG_COP1X | MIPS_HFLAG_64 | MIPS_HFLAG_CP0 | ++ MIPS_HFLAG_F64 | MIPS_HFLAG_FPU | MIPS_HFLAG_KSU | ++ MIPS_HFLAG_UX); ++ if (!(env->CP0_Status & (1 << CP0St_EXL)) && ++ !(env->CP0_Status & (1 << CP0St_ERL)) && ++ !(env->hflags & MIPS_HFLAG_DM)) { ++ env->hflags |= (env->CP0_Status >> CP0St_KSU) & MIPS_HFLAG_KSU; ++ } ++#if defined(TARGET_MIPS64) ++ if (((env->hflags & MIPS_HFLAG_KSU) != MIPS_HFLAG_UM) || ++ (env->CP0_Status & (1 << CP0St_PX)) || ++ (env->CP0_Status & (1 << CP0St_UX))) { ++ env->hflags |= MIPS_HFLAG_64; ++ } ++ if (env->CP0_Status & (1 << CP0St_UX)) { ++ env->hflags |= MIPS_HFLAG_UX; ++ } ++#endif ++ if ((env->CP0_Status & (1 << CP0St_CU0)) || ++ !(env->hflags & MIPS_HFLAG_KSU)) { ++ env->hflags |= MIPS_HFLAG_CP0; ++ } ++ if (env->CP0_Status & (1 << CP0St_CU1)) { ++ env->hflags |= MIPS_HFLAG_FPU; ++ } ++ if (env->CP0_Status & (1 << CP0St_FR)) { ++ env->hflags |= MIPS_HFLAG_F64; ++ } ++ if (env->insn_flags & ISA_MIPS32R2) { ++ if (env->active_fpu.fcr0 & (1 << FCR0_F64)) { ++ env->hflags |= MIPS_HFLAG_COP1X; ++ } ++ } else if (env->insn_flags & ISA_MIPS32) { ++ if (env->hflags & MIPS_HFLAG_64) { ++ env->hflags |= MIPS_HFLAG_COP1X; ++ } ++ } else if (env->insn_flags & ISA_MIPS4) { ++ /* All supported MIPS IV CPUs use the XX (CU3) to enable ++ and disable the MIPS IV extensions to the MIPS III ISA. ++ Some other MIPS IV CPUs ignore the bit, so the check here ++ would be too restrictive for them. */ ++ if (env->CP0_Status & (1 << CP0St_CU3)) { ++ env->hflags |= MIPS_HFLAG_COP1X; ++ } ++ } ++} ++ + #endif /* !defined (__MIPS_CPU_H__) */ +diff --git a/target-mips/op_helper.c b/target-mips/op_helper.c +index d2a8a55..ce5ddaf 100644 +--- a/target-mips/op_helper.c ++++ b/target-mips/op_helper.c +@@ -30,55 +30,6 @@ + static inline void cpu_mips_tlb_flush (CPUMIPSState *env, int flush_global); + #endif + +-static inline void compute_hflags(CPUMIPSState *env) +-{ +- env->hflags &= ~(MIPS_HFLAG_COP1X | MIPS_HFLAG_64 | MIPS_HFLAG_CP0 | +- MIPS_HFLAG_F64 | MIPS_HFLAG_FPU | MIPS_HFLAG_KSU | +- MIPS_HFLAG_UX); +- if (!(env->CP0_Status & (1 << CP0St_EXL)) && +- !(env->CP0_Status & (1 << CP0St_ERL)) && +- !(env->hflags & MIPS_HFLAG_DM)) { +- env->hflags |= (env->CP0_Status >> CP0St_KSU) & MIPS_HFLAG_KSU; +- } +-#if defined(TARGET_MIPS64) +- if (((env->hflags & MIPS_HFLAG_KSU) != MIPS_HFLAG_UM) || +- (env->CP0_Status & (1 << CP0St_PX)) || +- (env->CP0_Status & (1 << CP0St_UX))) { +- env->hflags |= MIPS_HFLAG_64; +- } +- if (env->CP0_Status & (1 << CP0St_UX)) { +- env->hflags |= MIPS_HFLAG_UX; +- } +-#endif +- if ((env->CP0_Status & (1 << CP0St_CU0)) || +- !(env->hflags & MIPS_HFLAG_KSU)) { +- env->hflags |= MIPS_HFLAG_CP0; +- } +- if (env->CP0_Status & (1 << CP0St_CU1)) { +- env->hflags |= MIPS_HFLAG_FPU; +- } +- if (env->CP0_Status & (1 << CP0St_FR)) { +- env->hflags |= MIPS_HFLAG_F64; +- } +- if (env->insn_flags & ISA_MIPS32R2) { +- if (env->active_fpu.fcr0 & (1 << FCR0_F64)) { +- env->hflags |= MIPS_HFLAG_COP1X; +- } +- } else if (env->insn_flags & ISA_MIPS32) { +- if (env->hflags & MIPS_HFLAG_64) { +- env->hflags |= MIPS_HFLAG_COP1X; +- } +- } else if (env->insn_flags & ISA_MIPS4) { +- /* All supported MIPS IV CPUs use the XX (CU3) to enable +- and disable the MIPS IV extensions to the MIPS III ISA. +- Some other MIPS IV CPUs ignore the bit, so the check here +- would be too restrictive for them. */ +- if (env->CP0_Status & (1 << CP0St_CU3)) { +- env->hflags |= MIPS_HFLAG_COP1X; +- } +- } +-} +- + /*****************************************************************************/ + /* Exceptions processing helpers */ + +diff --git a/target-mips/translate.c b/target-mips/translate.c +index aba7935..4e04e97 100644 +--- a/target-mips/translate.c ++++ b/target-mips/translate.c +@@ -12816,18 +12816,13 @@ void cpu_state_reset(CPUMIPSState *env) + env->insn_flags = env->cpu_model->insn_flags; + + #if defined(CONFIG_USER_ONLY) +- env->hflags = MIPS_HFLAG_UM; ++ env->CP0_Status = (MIPS_HFLAG_UM << CP0St_KSU); + /* Enable access to the CPUNum, SYNCI_Step, CC, and CCRes RDHWR + hardware registers. */ + env->CP0_HWREna |= 0x0000000F; + if (env->CP0_Config1 & (1 << CP0C1_FP)) { +- env->hflags |= MIPS_HFLAG_FPU; ++ env->CP0_Status |= (1 << CP0St_CU1); + } +-#ifdef TARGET_MIPS64 +- if (env->active_fpu.fcr0 & (1 << FCR0_F64)) { +- env->hflags |= MIPS_HFLAG_F64; +- } +-#endif + #else + if (env->hflags & MIPS_HFLAG_BMASK) { + /* If the exception was raised from a delay slot, +@@ -12857,7 +12852,6 @@ void cpu_state_reset(CPUMIPSState *env) + } + /* Count register increments in debug mode, EJTAG version 1 */ + env->CP0_Debug = (1 << CP0DB_CNT) | (0x1 << CP0DB_VER); +- env->hflags = MIPS_HFLAG_CP0; + + if (env->CP0_Config3 & (1 << CP0C3_MT)) { + int i; +@@ -12885,11 +12879,7 @@ void cpu_state_reset(CPUMIPSState *env) + } + } + #endif +-#if defined(TARGET_MIPS64) +- if (env->cpu_model->insn_flags & ISA_MIPS3) { +- env->hflags |= MIPS_HFLAG_64; +- } +-#endif ++ compute_hflags(env); + env->exception_index = EXCP_NONE; + } + +-- +1.7.12.1 + diff --git a/0118-Add-MAINTAINERS-entry-for-leon3.patch b/0118-Add-MAINTAINERS-entry-for-leon3.patch new file mode 100644 index 0000000..cbc0ff8 --- /dev/null +++ b/0118-Add-MAINTAINERS-entry-for-leon3.patch @@ -0,0 +1,34 @@ +From 6bfc31b2f98dabc0e636cd8955c8de93bcac0961 Mon Sep 17 00:00:00 2001 +From: Fabien Chouteau +Date: Tue, 22 May 2012 10:14:28 +0200 +Subject: [PATCH] Add MAINTAINERS entry for leon3 + +Signed-off-by: Fabien Chouteau +Signed-off-by: Blue Swirl +(cherry picked from commit ce6c760c37b9a88db87c5b9b9bf39ca866e570f6) + +Signed-off-by: Michael Roth +--- + MAINTAINERS | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/MAINTAINERS b/MAINTAINERS +index 6d864c1..61f8b45 100644 +--- a/MAINTAINERS ++++ b/MAINTAINERS +@@ -398,6 +398,12 @@ M: Blue Swirl + S: Maintained + F: hw/sun4u.c + ++Leon3 ++M: Fabien Chouteau ++S: Maintained ++F: hw/leon3.c ++F: hw/grlib* ++ + S390 Machines + ------------- + S390 Virtio +-- +1.7.12.1 + diff --git a/0119-musicpal-Fix-flash-mapping.patch b/0119-musicpal-Fix-flash-mapping.patch new file mode 100644 index 0000000..9c95c49 --- /dev/null +++ b/0119-musicpal-Fix-flash-mapping.patch @@ -0,0 +1,42 @@ +From 2182aa5c2ca5a5a6bf9c2d06d18b3e2db3aa3c7a Mon Sep 17 00:00:00 2001 +From: Jan Kiszka +Date: Sat, 8 Sep 2012 11:52:39 +0200 +Subject: [PATCH] musicpal: Fix flash mapping + +The old arithmetic assumed 32 physical address bits which is no longer +true for ARM since 3cc0cd61f4. + +Signed-off-by: Jan Kiszka +Signed-off-by: Blue Swirl +(cherry picked from commit 0c267217ca9985e6d118ec8368bebd382db7a099) + +Signed-off-by: Michael Roth +--- + hw/musicpal.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/hw/musicpal.c b/hw/musicpal.c +index ad725b5..f305e21 100644 +--- a/hw/musicpal.c ++++ b/hw/musicpal.c +@@ -1583,7 +1583,7 @@ static void musicpal_init(ram_addr_t ram_size, + * image is smaller than 32 MB. + */ + #ifdef TARGET_WORDS_BIGENDIAN +- pflash_cfi02_register(0-MP_FLASH_SIZE_MAX, NULL, ++ pflash_cfi02_register(0x100000000ULL-MP_FLASH_SIZE_MAX, NULL, + "musicpal.flash", flash_size, + dinfo->bdrv, 0x10000, + (flash_size + 0xffff) >> 16, +@@ -1591,7 +1591,7 @@ static void musicpal_init(ram_addr_t ram_size, + 2, 0x00BF, 0x236D, 0x0000, 0x0000, + 0x5555, 0x2AAA, 1); + #else +- pflash_cfi02_register(0-MP_FLASH_SIZE_MAX, NULL, ++ pflash_cfi02_register(0x100000000ULL-MP_FLASH_SIZE_MAX, NULL, + "musicpal.flash", flash_size, + dinfo->bdrv, 0x10000, + (flash_size + 0xffff) >> 16, +-- +1.7.12.1 + diff --git a/0120-qemu-Use-valgrind-annotations-to-mark-kvm-guest-memo.patch b/0120-qemu-Use-valgrind-annotations-to-mark-kvm-guest-memo.patch new file mode 100644 index 0000000..40caa2c --- /dev/null +++ b/0120-qemu-Use-valgrind-annotations-to-mark-kvm-guest-memo.patch @@ -0,0 +1,84 @@ +From e688bfbda0f6893b08d1e51f4fb26d4b38e922d4 Mon Sep 17 00:00:00 2001 +From: Christian Borntraeger +Date: Fri, 10 Aug 2012 15:11:45 +0200 +Subject: [PATCH] qemu: Use valgrind annotations to mark kvm guest memory as + defined + +valgrind with kvm produces a big amount of false positives regarding +"Conditional jump or move depends on uninitialised value(s)". This +happens because the guest memory is allocated with qemu_vmalloc which +boils down posix_memalign etc. This function is (correctly) considered +by valgrind as returning undefined memory. + +Since valgrind is based on jitting code, it will not be able to see +changes made by the guest to guest memory if this is done by KVM_RUN, +thus keeping most of the guest memory undefined. + +Now lots of places in qemu will then use guest memory to change behaviour. +To avoid the flood of these messages, lets declare the whole guest +memory as defined. This will reduce the noise and allows us to see real +problems. + +In the future we might want to make this conditional, since there +is actually something that we can use those false positives for: +These messages will point to code that depends on guest memory, so +we can use these backtraces to actually make an audit that is focussed +only at those code places. For normal development we dont want to +see those messages, though. + +Signed-off-by: Christian Borntraeger +Signed-off-by: Avi Kivity +(cherry picked from commit 62fe83318d2fc5b31f473d66326910d94c1c4907) + +Signed-off-by: Michael Roth +--- + configure | 3 ++- + kvm-all.c | 7 +++++++ + 2 files changed, 9 insertions(+), 1 deletion(-) + +diff --git a/configure b/configure +index d7a948f..8874eff 100755 +--- a/configure ++++ b/configure +@@ -2937,11 +2937,12 @@ if compile_prog "-Werror" "" ; then + fi + + ######################################## +-# check if we have valgrind/valgrind.h ++# check if we have valgrind/valgrind.h and valgrind/memcheck.h + + valgrind_h=no + cat > $TMPC << EOF + #include ++#include + int main(void) { + return 0; + } +diff --git a/kvm-all.c b/kvm-all.c +index badf1d8..90c71f9 100644 +--- a/kvm-all.c ++++ b/kvm-all.c +@@ -39,6 +39,10 @@ + #include + #endif + ++#ifdef CONFIG_VALGRIND_H ++#include ++#endif ++ + /* KVM uses PAGE_SIZE in its definition of COALESCED_MMIO_MAX */ + #define PAGE_SIZE TARGET_PAGE_SIZE + +@@ -1769,6 +1773,9 @@ void *kvm_vmalloc(ram_addr_t size) + + void kvm_setup_guest_memory(void *start, size_t size) + { ++#ifdef CONFIG_VALGRIND_H ++ VALGRIND_MAKE_MEM_DEFINED(start, size); ++#endif + if (!kvm_has_sync_mmu()) { + int ret = qemu_madvise(start, size, QEMU_MADV_DONTFORK); + +-- +1.7.12.1 + diff --git a/0121-hw-wm8750-Fix-potential-buffer-overflow.patch b/0121-hw-wm8750-Fix-potential-buffer-overflow.patch new file mode 100644 index 0000000..2b3acbe --- /dev/null +++ b/0121-hw-wm8750-Fix-potential-buffer-overflow.patch @@ -0,0 +1,43 @@ +From 044cadadb3bb63396a1e8d72a0c90673ccd7be98 Mon Sep 17 00:00:00 2001 +From: Stefan Weil +Date: Mon, 3 Sep 2012 22:56:00 +0200 +Subject: [PATCH] hw/wm8750: Fix potential buffer overflow + +Report from smatch: + +hw/wm8750.c:369 wm8750_tx(12) error: buffer overflow 's->i2c_data' 2 <= 2 + +It looks like the preprocessor statements were simply misplaced. + +Replace also __FUNCTION__ by __func__ to please checkpatch.pl. + +Signed-off-by: Stefan Weil +Reviewed-by: Peter Maydell +Signed-off-by: Aurelien Jarno +(cherry picked from commit 149eeb5fe57b853081e8059575d91b8a58a4f96c) + +Signed-off-by: Michael Roth +--- + hw/wm8750.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/hw/wm8750.c b/hw/wm8750.c +index 11bcec3..44f138f 100644 +--- a/hw/wm8750.c ++++ b/hw/wm8750.c +@@ -361,10 +361,10 @@ static int wm8750_tx(I2CSlave *i2c, uint8_t data) + uint16_t value; + + if (s->i2c_len >= 2) { +- printf("%s: long message (%i bytes)\n", __FUNCTION__, s->i2c_len); + #ifdef VERBOSE +- return 1; ++ printf("%s: long message (%i bytes)\n", __func__, s->i2c_len); + #endif ++ return 1; + } + s->i2c_data[s->i2c_len ++] = data; + if (s->i2c_len != 2) +-- +1.7.12.1 + diff --git a/0122-hw-mcf5206-Fix-buffer-overflow-for-MBAR-read-write.patch b/0122-hw-mcf5206-Fix-buffer-overflow-for-MBAR-read-write.patch new file mode 100644 index 0000000..c5fe15f --- /dev/null +++ b/0122-hw-mcf5206-Fix-buffer-overflow-for-MBAR-read-write.patch @@ -0,0 +1,87 @@ +From 90c742c7f36f45249c62c0c5db2e138a604e44ac Mon Sep 17 00:00:00 2001 +From: Stefan Weil +Date: Tue, 4 Sep 2012 19:37:39 +0200 +Subject: [PATCH] hw/mcf5206: Fix buffer overflow for MBAR read / write + +Report from smatch: + +mcf5206.c:384 m5206_mbar_readb(7) error: buffer overflow 'm5206_mbar_width' 128 <= 128 +mcf5206.c:403 m5206_mbar_readw(8) error: buffer overflow 'm5206_mbar_width' 128 <= 128 +mcf5206.c:427 m5206_mbar_readl(8) error: buffer overflow 'm5206_mbar_width' 128 <= 128 +mcf5206.c:451 m5206_mbar_writeb(9) error: buffer overflow 'm5206_mbar_width' 128 <= 128 +mcf5206.c:475 m5206_mbar_writew(9) error: buffer overflow 'm5206_mbar_width' 128 <= 128 +mcf5206.c:503 m5206_mbar_writel(9) error: buffer overflow 'm5206_mbar_width' 128 <= 128 + +m5206_mbar_width has 0x80 elements and supports 0 <= offset < 0x200. + +Signed-off-by: Stefan Weil +Reviewed-by: Peter Maydell +Signed-off-by: Aurelien Jarno +(cherry picked from commit a32354e206895400d17c3de9a8df1de96d3df289) + +Signed-off-by: Michael Roth +--- + hw/mcf5206.c | 12 ++++++------ + 1 file changed, 6 insertions(+), 6 deletions(-) + +diff --git a/hw/mcf5206.c b/hw/mcf5206.c +index 539b391..27753e2 100644 +--- a/hw/mcf5206.c ++++ b/hw/mcf5206.c +@@ -378,7 +378,7 @@ static uint32_t m5206_mbar_readb(void *opaque, target_phys_addr_t offset) + { + m5206_mbar_state *s = (m5206_mbar_state *)opaque; + offset &= 0x3ff; +- if (offset > 0x200) { ++ if (offset >= 0x200) { + hw_error("Bad MBAR read offset 0x%x", (int)offset); + } + if (m5206_mbar_width[offset >> 2] > 1) { +@@ -397,7 +397,7 @@ static uint32_t m5206_mbar_readw(void *opaque, target_phys_addr_t offset) + m5206_mbar_state *s = (m5206_mbar_state *)opaque; + int width; + offset &= 0x3ff; +- if (offset > 0x200) { ++ if (offset >= 0x200) { + hw_error("Bad MBAR read offset 0x%x", (int)offset); + } + width = m5206_mbar_width[offset >> 2]; +@@ -421,7 +421,7 @@ static uint32_t m5206_mbar_readl(void *opaque, target_phys_addr_t offset) + m5206_mbar_state *s = (m5206_mbar_state *)opaque; + int width; + offset &= 0x3ff; +- if (offset > 0x200) { ++ if (offset >= 0x200) { + hw_error("Bad MBAR read offset 0x%x", (int)offset); + } + width = m5206_mbar_width[offset >> 2]; +@@ -445,7 +445,7 @@ static void m5206_mbar_writeb(void *opaque, target_phys_addr_t offset, + m5206_mbar_state *s = (m5206_mbar_state *)opaque; + int width; + offset &= 0x3ff; +- if (offset > 0x200) { ++ if (offset >= 0x200) { + hw_error("Bad MBAR write offset 0x%x", (int)offset); + } + width = m5206_mbar_width[offset >> 2]; +@@ -469,7 +469,7 @@ static void m5206_mbar_writew(void *opaque, target_phys_addr_t offset, + m5206_mbar_state *s = (m5206_mbar_state *)opaque; + int width; + offset &= 0x3ff; +- if (offset > 0x200) { ++ if (offset >= 0x200) { + hw_error("Bad MBAR write offset 0x%x", (int)offset); + } + width = m5206_mbar_width[offset >> 2]; +@@ -497,7 +497,7 @@ static void m5206_mbar_writel(void *opaque, target_phys_addr_t offset, + m5206_mbar_state *s = (m5206_mbar_state *)opaque; + int width; + offset &= 0x3ff; +- if (offset > 0x200) { ++ if (offset >= 0x200) { + hw_error("Bad MBAR write offset 0x%x", (int)offset); + } + width = m5206_mbar_width[offset >> 2]; +-- +1.7.12.1 + diff --git a/0123-use-libexecdir-instead-of-ignoring-it-first-and-rein.patch b/0123-use-libexecdir-instead-of-ignoring-it-first-and-rein.patch new file mode 100644 index 0000000..9764f22 --- /dev/null +++ b/0123-use-libexecdir-instead-of-ignoring-it-first-and-rein.patch @@ -0,0 +1,94 @@ +From 6762c144443bca8fa97a389289bda7693bd4c8d4 Mon Sep 17 00:00:00 2001 +From: Michael Tokarev +Date: Thu, 7 Jun 2012 01:11:00 +0400 +Subject: [PATCH] use --libexecdir instead of ignoring it first and + reinventing it later +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Commit 7b93fadf3a38d1ed65ea5536a52efc2772c6e3b8 "Add basic version +of bridge helper" put the bridge helper executable into a fixed +${prefix}/libexec/ location, instead of using ${libexecdir} for +this. At the same time, --libexecdir is being happily ignored +by ./configure. Even more, the same patch sets unused $libexecdir +variable in the generated config-host.mak, and uses fixed string +(\${prefix}/libexecdir) for the bridge helper binary. + +Fix this braindamage by introducing $libexecdir variable, using +it for the bridge helper binary, and recognizing --libexecdir. + +This patch is applicable to stable-1.1. + +Reviewed-by: Andreas Färber +Reviewed-by: Corey Bryant +Signed-off-by: Michael Tokarev +Cc: Corey Bryant +Cc: Richa Marwaha +Cc: qemu-stable@nongnu.org +Signed-off-by: Anthony Liguori +(cherry picked from commit 8bf188aa18ef7a8355d9edbd43871d590468c4ed) + +Signed-off-by: Michael Roth +--- + configure | 10 +++++++--- + 1 file changed, 7 insertions(+), 3 deletions(-) + +diff --git a/configure b/configure +index 8874eff..d01f9dc 100755 +--- a/configure ++++ b/configure +@@ -191,6 +191,7 @@ datadir="\${prefix}/share" + qemu_docdir="\${prefix}/share/doc/qemu" + bindir="\${prefix}/bin" + libdir="\${prefix}/lib" ++libexecdir="\${prefix}/libexec" + includedir="\${prefix}/include" + sysconfdir="\${prefix}/etc" + confsuffix="/qemu" +@@ -624,6 +625,8 @@ for opt do + ;; + --libdir=*) libdir="$optarg" + ;; ++ --libexecdir=*) libexecdir="$optarg" ++ ;; + --includedir=*) includedir="$optarg" + ;; + --datadir=*) datadir="$optarg" +@@ -634,7 +637,7 @@ for opt do + ;; + --sysconfdir=*) sysconfdir="$optarg" + ;; +- --sbindir=*|--libexecdir=*|--sharedstatedir=*|--localstatedir=*|\ ++ --sbindir=*|--sharedstatedir=*|--localstatedir=*|\ + --oldincludedir=*|--datarootdir=*|--infodir=*|--localedir=*|\ + --htmldir=*|--dvidir=*|--pdfdir=*|--psdir=*) + # These switches are silently ignored, for compatibility with +@@ -3055,6 +3058,7 @@ echo "Install prefix $prefix" + echo "BIOS directory `eval echo $qemu_datadir`" + echo "binary directory `eval echo $bindir`" + echo "library directory `eval echo $libdir`" ++echo "libexec directory `eval echo $libexecdir`" + echo "include directory `eval echo $includedir`" + echo "config directory `eval echo $sysconfdir`" + if test "$mingw32" = "no" ; then +@@ -3158,14 +3162,14 @@ echo all: >> $config_host_mak + echo "prefix=$prefix" >> $config_host_mak + echo "bindir=$bindir" >> $config_host_mak + echo "libdir=$libdir" >> $config_host_mak ++echo "libexecdir=$libexecdir" >> $config_host_mak + echo "includedir=$includedir" >> $config_host_mak + echo "mandir=$mandir" >> $config_host_mak + echo "sysconfdir=$sysconfdir" >> $config_host_mak + 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 "libexecdir=\${prefix}/libexec" >> $config_host_mak +-echo "CONFIG_QEMU_HELPERDIR=\"$prefix/libexec\"" >> $config_host_mak ++echo "CONFIG_QEMU_HELPERDIR=\"$libexecdir\"" >> $config_host_mak + + echo "ARCH=$ARCH" >> $config_host_mak + if test "$debug_tcg" = "yes" ; then +-- +1.7.12.1 + diff --git a/0124-socket-don-t-attempt-to-reconnect-a-TCP-socket-in-se.patch b/0124-socket-don-t-attempt-to-reconnect-a-TCP-socket-in-se.patch new file mode 100644 index 0000000..cff77f8 --- /dev/null +++ b/0124-socket-don-t-attempt-to-reconnect-a-TCP-socket-in-se.patch @@ -0,0 +1,43 @@ +From 40874e295225675fec7b42bb8e015fb3f2065a69 Mon Sep 17 00:00:00 2001 +From: Anthony Liguori +Date: Wed, 5 Sep 2012 13:52:49 -0500 +Subject: [PATCH] socket: don't attempt to reconnect a TCP socket in server + mode + +Commit c3767ed0eb5d0bb25fe409ae5dec06e3411ff1b6 introduced a possible SEGV when +using a socket chardev with server=on because it assumes that all TCP sockets +are in client mode. + +This patch adds a check to only reconnect when in client mode. + +Cc: Lei Li +Reported-by: Michael Roth +Signed-off-by: Anthony Liguori +(cherry picked from commit 455aa1e0818653c41fd794435b982426ce21ba2f) + +Signed-off-by: Michael Roth +--- + qemu-char.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/qemu-char.c b/qemu-char.c +index 398baf1..767da93 100644 +--- a/qemu-char.c ++++ b/qemu-char.c +@@ -2148,10 +2148,12 @@ static int tcp_chr_write(CharDriverState *chr, const uint8_t *buf, int len) + TCPCharDriver *s = chr->opaque; + if (s->connected) { + return send_all(s->fd, buf, len); +- } else { ++ } else if (s->listen_fd == -1) { + /* (Re-)connect for unconnected writing */ + tcp_chr_connect(chr); + return 0; ++ } else { ++ return len; + } + } + +-- +1.7.12.1 + diff --git a/0125-Add-ability-to-force-enable-disable-of-tools-build.patch b/0125-Add-ability-to-force-enable-disable-of-tools-build.patch new file mode 100644 index 0000000..35e05ee --- /dev/null +++ b/0125-Add-ability-to-force-enable-disable-of-tools-build.patch @@ -0,0 +1,83 @@ +From d9f498f4b7b7ca2ff96b4d87827713caea3743b5 Mon Sep 17 00:00:00 2001 +From: "Daniel P. Berrange" +Date: Mon, 10 Sep 2012 12:26:29 +0100 +Subject: [PATCH] Add ability to force enable/disable of tools build + +The qemu-img, qemu-nbd and qemu-io tools are built conditionally +based on whether any softmmu target is enabled. These are useful +self-contained tools which can be used in many other scenarios. +Add new --enable-tools/--disable-tools args to configure to allow +the user to explicitly turn on / off their build. The default +behaviour is now to build these tools are all times, regardless +of whether any softmmu target is enabled + +Signed-off-by: Daniel P. Berrange +Signed-off-by: Anthony Liguori +(cherry picked from commit 4b1c11fd20e8901f04a2d9c225cd10fc05a762ff) + +Signed-off-by: Michael Roth +--- + configure | 21 +++++++++++++++------ + 1 file changed, 15 insertions(+), 6 deletions(-) + +diff --git a/configure b/configure +index d01f9dc..a8061c1 100755 +--- a/configure ++++ b/configure +@@ -225,6 +225,7 @@ usb_redir="" + opengl="" + zlib="yes" + guest_agent="yes" ++want_tools="yes" + libiscsi="" + coroutine="" + seccomp="" +@@ -857,6 +858,10 @@ for opt do + ;; + --disable-guest-agent) guest_agent="no" + ;; ++ --enable-tools) want_tools="yes" ++ ;; ++ --disable-tools) want_tools="no" ++ ;; + --enable-seccomp) seccomp="yes" + ;; + --disable-seccomp) seccomp="no" +@@ -3017,9 +3022,14 @@ fi + qemu_confdir=$sysconfdir$confsuffix + qemu_datadir=$datadir$confsuffix + +-tools= +-if test "$softmmu" = yes ; then ++tools="" ++if test "$want_tools" = "yes" ; then + tools="qemu-img\$(EXESUF) qemu-io\$(EXESUF) $tools" ++ if [ "$linux" = "yes" -o "$bsd" = "yes" -o "$solaris" = "yes" ] ; then ++ tools="qemu-nbd\$(EXESUF) $tools" ++ fi ++fi ++if test "$softmmu" = yes ; then + if test "$virtfs" != no ; then + if test "$cap" = yes && test "$linux" = yes && test "$attr" = yes ; then + virtfs=yes +@@ -3033,14 +3043,13 @@ if test "$softmmu" = yes ; then + fi + fi + if [ "$linux" = "yes" -o "$bsd" = "yes" -o "$solaris" = "yes" ] ; then +- tools="qemu-nbd\$(EXESUF) $tools" + if [ "$guest_agent" = "yes" ]; then + tools="qemu-ga\$(EXESUF) $tools" + fi + fi +-fi +-if test "$smartcard_nss" = "yes" ; then +- tools="vscclient\$(EXESUF) $tools" ++ if test "$smartcard_nss" = "yes" ; then ++ tools="vscclient\$(EXESUF) $tools" ++ fi + fi + + # Mac OS X ships with a broken assembler +-- +1.7.12.1 + diff --git a/0126-usb-controllers-do-not-need-to-check-for-babble-them.patch b/0126-usb-controllers-do-not-need-to-check-for-babble-them.patch new file mode 100644 index 0000000..2630139 --- /dev/null +++ b/0126-usb-controllers-do-not-need-to-check-for-babble-them.patch @@ -0,0 +1,58 @@ +From 074f49c02e7f2fd50533a246b4060051f95f8b09 Mon Sep 17 00:00:00 2001 +From: Hans de Goede +Date: Fri, 17 Aug 2012 11:39:16 +0200 +Subject: [PATCH] usb: controllers do not need to check for babble themselves + +If an (emulated) usb-device tries to write more data to a packet then +its iov len, this will trigger an assert in usb_packet_copy(), and if +a driver somehow circumvents that check and writes more data to the +iov then there is space, we have a much bigger problem then not correctly +reporting babble to the guest. + +In practice babble will only happen with (real) redirected devices, and there +both the usb-host os and the qemu usb-device code already check for it. + +Signed-off-by: Hans de Goede +Signed-off-by: Gerd Hoffmann +(cherry picked from commit 45b339b18c660eb85af2ba25bfcaed5469660d77) + +Signed-off-by: Michael Roth +--- + hw/usb/hcd-ehci.c | 4 ---- + hw/usb/hcd-uhci.c | 5 ----- + 2 files changed, 9 deletions(-) + +diff --git a/hw/usb/hcd-ehci.c b/hw/usb/hcd-ehci.c +index 017342b..9523247 100644 +--- a/hw/usb/hcd-ehci.c ++++ b/hw/usb/hcd-ehci.c +@@ -1481,10 +1481,6 @@ static void ehci_execute_complete(EHCIQueue *q) + assert(0); + break; + } +- } else if ((p->usb_status > p->tbytes) && (p->pid == USB_TOKEN_IN)) { +- p->usb_status = USB_RET_BABBLE; +- q->qh.token |= (QTD_TOKEN_HALT | QTD_TOKEN_BABBLE); +- ehci_raise_irq(q->ehci, USBSTS_ERRINT); + } else { + // TODO check 4.12 for splits + +diff --git a/hw/usb/hcd-uhci.c b/hw/usb/hcd-uhci.c +index b0db921..c7c8786 100644 +--- a/hw/usb/hcd-uhci.c ++++ b/hw/usb/hcd-uhci.c +@@ -729,11 +729,6 @@ static int uhci_complete_td(UHCIState *s, UHCI_TD *td, UHCIAsync *async, uint32_ + *int_mask |= 0x01; + + if (pid == USB_TOKEN_IN) { +- if (len > max_len) { +- ret = USB_RET_BABBLE; +- goto out; +- } +- + if ((td->ctrl & TD_CTRL_SPD) && len < max_len) { + *int_mask |= 0x02; + /* short packet: do not update QH */ +-- +1.7.12.1 + diff --git a/0127-usb-core-Don-t-set-packet-state-to-complete-on-a-nak.patch b/0127-usb-core-Don-t-set-packet-state-to-complete-on-a-nak.patch new file mode 100644 index 0000000..1bbaed0 --- /dev/null +++ b/0127-usb-core-Don-t-set-packet-state-to-complete-on-a-nak.patch @@ -0,0 +1,37 @@ +From bcd7c845fbfbafe03e320fbffcaa32417cfd5267 Mon Sep 17 00:00:00 2001 +From: Hans de Goede +Date: Mon, 3 Sep 2012 12:33:44 +0200 +Subject: [PATCH] usb-core: Don't set packet state to complete on a nak + +This way the hcd can re-use the same packet to retry without needing +to re-init it. + +Signed-off-by: Hans de Goede +Signed-off-by: Gerd Hoffmann +(cherry picked from commit cc40997489260f405aecccd30d4626ceee862502) + +Signed-off-by: Michael Roth +--- + hw/usb/core.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +diff --git a/hw/usb/core.c b/hw/usb/core.c +index 2da38e7..be6d936 100644 +--- a/hw/usb/core.c ++++ b/hw/usb/core.c +@@ -399,8 +399,10 @@ int usb_handle_packet(USBDevice *dev, USBPacket *p) + * otherwise packets can complete out of order! + */ + assert(!p->ep->pipeline); +- p->result = ret; +- usb_packet_set_state(p, USB_PACKET_COMPLETE); ++ if (ret != USB_RET_NAK) { ++ p->result = ret; ++ usb_packet_set_state(p, USB_PACKET_COMPLETE); ++ } + } + } else { + ret = USB_RET_ASYNC; +-- +1.7.12.1 + diff --git a/0128-usb-core-Add-a-usb_ep_find_packet_by_id-helper-funct.patch b/0128-usb-core-Add-a-usb_ep_find_packet_by_id-helper-funct.patch new file mode 100644 index 0000000..994e450 --- /dev/null +++ b/0128-usb-core-Add-a-usb_ep_find_packet_by_id-helper-funct.patch @@ -0,0 +1,54 @@ +From 3c2f94fdc5e776ee66bccc704884f3b1b090b4c6 Mon Sep 17 00:00:00 2001 +From: Hans de Goede +Date: Tue, 28 Aug 2012 09:43:18 +0200 +Subject: [PATCH] usb-core: Add a usb_ep_find_packet_by_id() helper function + +Signed-off-by: Hans de Goede +Signed-off-by: Gerd Hoffmann +(cherry picked from commit c13a9e61366cc3e28299d8faeb65e65c6e5964cf) + +Signed-off-by: Michael Roth +--- + hw/usb.h | 2 ++ + hw/usb/core.c | 15 +++++++++++++++ + 2 files changed, 17 insertions(+) + +diff --git a/hw/usb.h b/hw/usb.h +index b8fceec..684e3f4 100644 +--- a/hw/usb.h ++++ b/hw/usb.h +@@ -377,6 +377,8 @@ void usb_ep_set_max_packet_size(USBDevice *dev, int pid, int ep, + uint16_t raw); + int usb_ep_get_max_packet_size(USBDevice *dev, int pid, int ep); + void usb_ep_set_pipeline(USBDevice *dev, int pid, int ep, bool enabled); ++USBPacket *usb_ep_find_packet_by_id(USBDevice *dev, int pid, int ep, ++ uint64_t id); + + void usb_attach(USBPort *port); + void usb_detach(USBPort *port); +diff --git a/hw/usb/core.c b/hw/usb/core.c +index be6d936..fe431d0 100644 +--- a/hw/usb/core.c ++++ b/hw/usb/core.c +@@ -726,3 +726,18 @@ void usb_ep_set_pipeline(USBDevice *dev, int pid, int ep, bool enabled) + struct USBEndpoint *uep = usb_ep_get(dev, pid, ep); + uep->pipeline = enabled; + } ++ ++USBPacket *usb_ep_find_packet_by_id(USBDevice *dev, int pid, int ep, ++ uint64_t id) ++{ ++ struct USBEndpoint *uep = usb_ep_get(dev, pid, ep); ++ USBPacket *p; ++ ++ while ((p = QTAILQ_FIRST(&uep->queue)) != NULL) { ++ if (p->id == id) { ++ return p; ++ } ++ } ++ ++ return NULL; ++} +-- +1.7.12.1 + diff --git a/0129-usb-core-Allow-the-first-packet-of-a-pipelined-ep-to.patch b/0129-usb-core-Allow-the-first-packet-of-a-pipelined-ep-to.patch new file mode 100644 index 0000000..c264ca1 --- /dev/null +++ b/0129-usb-core-Allow-the-first-packet-of-a-pipelined-ep-to.patch @@ -0,0 +1,35 @@ +From 2a2b40b145764ece12d0872ae5bb7b7ec2dc271f Mon Sep 17 00:00:00 2001 +From: Hans de Goede +Date: Mon, 3 Sep 2012 12:48:49 +0200 +Subject: [PATCH] usb-core: Allow the first packet of a pipelined ep to + complete immediately + +This can happen with usb-redir live-migration when the packet gets re-queued +after the migration and the original queuing from the migration source side +has already finished. + +Signed-off-by: Hans de Goede +Signed-off-by: Gerd Hoffmann +(cherry picked from commit 9c1f67654ab611553bbfca54a1e0922728c25760) + +Signed-off-by: Michael Roth +--- + hw/usb/core.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/hw/usb/core.c b/hw/usb/core.c +index fe431d0..b9f1f7a 100644 +--- a/hw/usb/core.c ++++ b/hw/usb/core.c +@@ -398,7 +398,7 @@ int usb_handle_packet(USBDevice *dev, USBPacket *p) + * When pipelining is enabled usb-devices must always return async, + * otherwise packets can complete out of order! + */ +- assert(!p->ep->pipeline); ++ assert(!p->ep->pipeline || QTAILQ_EMPTY(&p->ep->queue)); + if (ret != USB_RET_NAK) { + p->result = ret; + usb_packet_set_state(p, USB_PACKET_COMPLETE); +-- +1.7.12.1 + diff --git a/0130-Revert-ehci-don-t-flush-cache-on-doorbell-rings.patch b/0130-Revert-ehci-don-t-flush-cache-on-doorbell-rings.patch new file mode 100644 index 0000000..ae5d4d3 --- /dev/null +++ b/0130-Revert-ehci-don-t-flush-cache-on-doorbell-rings.patch @@ -0,0 +1,124 @@ +From 4547897358a12c0f31d688da9922236984742242 Mon Sep 17 00:00:00 2001 +From: Hans de Goede +Date: Wed, 29 Aug 2012 10:12:52 +0200 +Subject: [PATCH] Revert "ehci: don't flush cache on doorbell rings." + +This reverts commit 9bc3a3a216e2689bfcdd36c3e079333bbdbf3ba0, which got +added to fix an issue where the real, underlying cause was not stopping +the ep queue on an error. + +Now that the underlying cause is fixed by the "usb: Halt ep queue and +cancel pending packets on a packet error" patch, the "don't flush" fix +is no longer needed. + +Not only is it not needed, it causes us to see cancellations (unlinks) +done by the Linux EHCI driver too late, which in combination with the new +usb-core packet-id generation where qtd addresses are used as ids, causes +duplicate ids for in flight packets. + +Signed-off-by: Hans de Goede +(cherry picked from commit 66f092d25697e11847b61d761c38ddebedaed8d1) + +Signed-off-by: Michael Roth +--- + hw/usb/hcd-ehci.c | 35 ++++++----------------------------- + 1 file changed, 6 insertions(+), 29 deletions(-) + +diff --git a/hw/usb/hcd-ehci.c b/hw/usb/hcd-ehci.c +index 9523247..e7c36f4 100644 +--- a/hw/usb/hcd-ehci.c ++++ b/hw/usb/hcd-ehci.c +@@ -365,7 +365,6 @@ struct EHCIQueue { + uint32_t seen; + uint64_t ts; + int async; +- int revalidate; + + /* cached data from guest - needs to be flushed + * when guest removes an entry (doorbell, handshake sequence) +@@ -805,18 +804,7 @@ static EHCIQueue *ehci_find_queue_by_qh(EHCIState *ehci, uint32_t addr, + return NULL; + } + +-static void ehci_queues_tag_unused_async(EHCIState *ehci) +-{ +- EHCIQueue *q; +- +- QTAILQ_FOREACH(q, &ehci->aqueues, next) { +- if (!q->seen) { +- q->revalidate = 1; +- } +- } +-} +- +-static void ehci_queues_rip_unused(EHCIState *ehci, int async) ++static void ehci_queues_rip_unused(EHCIState *ehci, int async, int flush) + { + EHCIQueueHead *head = async ? &ehci->aqueues : &ehci->pqueues; + uint64_t maxage = FRAME_TIMER_NS * ehci->maxframes * 4; +@@ -828,7 +816,7 @@ static void ehci_queues_rip_unused(EHCIState *ehci, int async) + q->ts = ehci->last_run_ns; + continue; + } +- if (ehci->last_run_ns < q->ts + maxage) { ++ if (!flush && ehci->last_run_ns < q->ts + maxage) { + continue; + } + ehci_free_queue(q); +@@ -1684,7 +1672,7 @@ static int ehci_state_waitlisthead(EHCIState *ehci, int async) + ehci_set_usbsts(ehci, USBSTS_REC); + } + +- ehci_queues_rip_unused(ehci, async); ++ ehci_queues_rip_unused(ehci, async, 0); + + /* Find the head of the list (4.9.1.1) */ + for(i = 0; i < MAX_QH; i++) { +@@ -1769,7 +1757,6 @@ static EHCIQueue *ehci_state_fetchqh(EHCIState *ehci, int async) + EHCIPacket *p; + uint32_t entry, devaddr; + EHCIQueue *q; +- EHCIqh qh; + + entry = ehci_get_fetch_addr(ehci, async); + q = ehci_find_queue_by_qh(ehci, entry, async); +@@ -1787,17 +1774,7 @@ static EHCIQueue *ehci_state_fetchqh(EHCIState *ehci, int async) + } + + get_dwords(ehci, NLPTR_GET(q->qhaddr), +- (uint32_t *) &qh, sizeof(EHCIqh) >> 2); +- if (q->revalidate && (q->qh.epchar != qh.epchar || +- q->qh.epcap != qh.epcap || +- q->qh.current_qtd != qh.current_qtd)) { +- ehci_free_queue(q); +- q = ehci_alloc_queue(ehci, entry, async); +- q->seen++; +- p = NULL; +- } +- q->qh = qh; +- q->revalidate = 0; ++ (uint32_t *) &q->qh, sizeof(EHCIqh) >> 2); + ehci_trace_qh(q, NLPTR_GET(q->qhaddr), &q->qh); + + devaddr = get_field(q->qh.epchar, QH_EPCHAR_DEVADDR); +@@ -2306,7 +2283,7 @@ static void ehci_advance_async_state(EHCIState *ehci) + */ + if (ehci->usbcmd & USBCMD_IAAD) { + /* Remove all unseen qhs from the async qhs queue */ +- ehci_queues_tag_unused_async(ehci); ++ ehci_queues_rip_unused(ehci, async, 1); + DPRINTF("ASYNC: doorbell request acknowledged\n"); + ehci->usbcmd &= ~USBCMD_IAAD; + ehci_raise_irq(ehci, USBSTS_IAA); +@@ -2359,7 +2336,7 @@ static void ehci_advance_periodic_state(EHCIState *ehci) + ehci_set_fetch_addr(ehci, async,entry); + ehci_set_state(ehci, async, EST_FETCHENTRY); + ehci_advance_state(ehci, async); +- ehci_queues_rip_unused(ehci, async); ++ ehci_queues_rip_unused(ehci, async, 0); + break; + + default: +-- +1.7.12.1 + diff --git a/0131-ehci-Validate-qh-is-not-changed-unexpectedly-by-the-.patch b/0131-ehci-Validate-qh-is-not-changed-unexpectedly-by-the-.patch new file mode 100644 index 0000000..a0b0897 --- /dev/null +++ b/0131-ehci-Validate-qh-is-not-changed-unexpectedly-by-the-.patch @@ -0,0 +1,86 @@ +From 46bfd14f89404e4a0eb93c3d9c5b9745724cee2d Mon Sep 17 00:00:00 2001 +From: Hans de Goede +Date: Wed, 29 Aug 2012 10:37:37 +0200 +Subject: [PATCH] ehci: Validate qh is not changed unexpectedly by the guest + +-combine the qh check with the check for devaddr changes +-also ensure that p gets set to NULL when the queue gets cancelled on + devaddr change, which was not done properly before this patch + +Signed-off-by: Hans de Goede +(cherry picked from commit dafe31fc2a8653b535d58f8c7b250c0827b14420) + +Signed-off-by: Michael Roth +--- + hw/usb/hcd-ehci.c | 39 ++++++++++++++++++++++++++++----------- + 1 file changed, 28 insertions(+), 11 deletions(-) + +diff --git a/hw/usb/hcd-ehci.c b/hw/usb/hcd-ehci.c +index e7c36f4..35eb441 100644 +--- a/hw/usb/hcd-ehci.c ++++ b/hw/usb/hcd-ehci.c +@@ -780,6 +780,14 @@ static void ehci_cancel_queue(EHCIQueue *q) + } while ((p = QTAILQ_FIRST(&q->packets)) != NULL); + } + ++static void ehci_reset_queue(EHCIQueue *q) ++{ ++ trace_usb_ehci_queue_action(q, "reset"); ++ ehci_cancel_queue(q); ++ q->dev = NULL; ++ q->qtdaddr = 0; ++} ++ + static void ehci_free_queue(EHCIQueue *q) + { + EHCIQueueHead *head = q->async ? &q->ehci->aqueues : &q->ehci->pqueues; +@@ -1755,8 +1763,9 @@ out: + static EHCIQueue *ehci_state_fetchqh(EHCIState *ehci, int async) + { + EHCIPacket *p; +- uint32_t entry, devaddr; ++ uint32_t entry, devaddr, endp; + EHCIQueue *q; ++ EHCIqh qh; + + entry = ehci_get_fetch_addr(ehci, async); + q = ehci_find_queue_by_qh(ehci, entry, async); +@@ -1774,17 +1783,25 @@ static EHCIQueue *ehci_state_fetchqh(EHCIState *ehci, int async) + } + + get_dwords(ehci, NLPTR_GET(q->qhaddr), +- (uint32_t *) &q->qh, sizeof(EHCIqh) >> 2); +- ehci_trace_qh(q, NLPTR_GET(q->qhaddr), &q->qh); ++ (uint32_t *) &qh, sizeof(EHCIqh) >> 2); ++ ehci_trace_qh(q, NLPTR_GET(q->qhaddr), &qh); ++ ++ /* ++ * The overlay area of the qh should never be changed by the guest, ++ * except when idle, in which case the reset is a nop. ++ */ ++ devaddr = get_field(qh.epchar, QH_EPCHAR_DEVADDR); ++ endp = get_field(qh.epchar, QH_EPCHAR_EP); ++ if ((devaddr != get_field(q->qh.epchar, QH_EPCHAR_DEVADDR)) || ++ (endp != get_field(q->qh.epchar, QH_EPCHAR_EP)) || ++ (memcmp(&qh.current_qtd, &q->qh.current_qtd, ++ 9 * sizeof(uint32_t)) != 0) || ++ (q->dev != NULL && q->dev->addr != devaddr)) { ++ ehci_reset_queue(q); ++ p = NULL; ++ } ++ q->qh = qh; + +- devaddr = get_field(q->qh.epchar, QH_EPCHAR_DEVADDR); +- if (q->dev != NULL && q->dev->addr != devaddr) { +- if (!QTAILQ_EMPTY(&q->packets)) { +- /* should not happen (guest bug) */ +- ehci_cancel_queue(q); +- } +- q->dev = NULL; +- } + if (q->dev == NULL) { + q->dev = ehci_find_device(q->ehci, devaddr); + } +-- +1.7.12.1 + diff --git a/0132-ehci-Update-copyright-headers-to-reflect-recent-work.patch b/0132-ehci-Update-copyright-headers-to-reflect-recent-work.patch new file mode 100644 index 0000000..020cb38 --- /dev/null +++ b/0132-ehci-Update-copyright-headers-to-reflect-recent-work.patch @@ -0,0 +1,35 @@ +From cd7309e7fdd000a9b595ab24e6b03d66100c6fde Mon Sep 17 00:00:00 2001 +From: Hans de Goede +Date: Tue, 28 Aug 2012 16:21:12 +0200 +Subject: [PATCH] ehci: Update copyright headers to reflect recent work + +Update copyright headers to reflect all the work Gerd and I have been doing +on the EHCI emulation. + +Signed-off-by: Hans de Goede +(cherry picked from commit 522079dd4461c38b9a88bf31a65ea038c5b2be45) + +Signed-off-by: Michael Roth +--- + hw/usb/hcd-ehci.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/hw/usb/hcd-ehci.c b/hw/usb/hcd-ehci.c +index 35eb441..78a248f 100644 +--- a/hw/usb/hcd-ehci.c ++++ b/hw/usb/hcd-ehci.c +@@ -2,6 +2,11 @@ + * QEMU USB EHCI Emulation + * + * Copyright(c) 2008 Emutex Ltd. (address@hidden) ++ * Copyright(c) 2011-2012 Red Hat, Inc. ++ * ++ * Red Hat Authors: ++ * Gerd Hoffmann ++ * Hans de Goede + * + * EHCI project was started by Mark Burkley, with contributions by + * Niels de Vos. David S. Ahern continued working on it. Kevin Wolf, +-- +1.7.12.1 + diff --git a/0133-ehci-Properly-cleanup-packets-on-cancel.patch b/0133-ehci-Properly-cleanup-packets-on-cancel.patch new file mode 100644 index 0000000..1e20c4f --- /dev/null +++ b/0133-ehci-Properly-cleanup-packets-on-cancel.patch @@ -0,0 +1,29 @@ +From 35fe185a5455160db638820211bad5aed45a669f Mon Sep 17 00:00:00 2001 +From: Hans de Goede +Date: Thu, 30 Aug 2012 15:00:33 +0200 +Subject: [PATCH] ehci: Properly cleanup packets on cancel + +Signed-off-by: Hans de Goede +(cherry picked from commit 0e7953525f52aa6c098dc0c1ce0b4a80ce82da45) + +Signed-off-by: Michael Roth +--- + hw/usb/hcd-ehci.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/hw/usb/hcd-ehci.c b/hw/usb/hcd-ehci.c +index 78a248f..4fe85c8 100644 +--- a/hw/usb/hcd-ehci.c ++++ b/hw/usb/hcd-ehci.c +@@ -747,6 +747,8 @@ static void ehci_free_packet(EHCIPacket *p) + trace_usb_ehci_packet_action(p->queue, p, "free"); + if (p->async == EHCI_ASYNC_INFLIGHT) { + usb_cancel_packet(&p->packet); ++ usb_packet_unmap(&p->packet, &p->sgl); ++ qemu_sglist_destroy(&p->sgl); + } + QTAILQ_REMOVE(&p->queue->packets, p, next); + usb_packet_cleanup(&p->packet); +-- +1.7.12.1 + diff --git a/0134-ehci-Properly-report-completed-but-not-yet-processed.patch b/0134-ehci-Properly-report-completed-but-not-yet-processed.patch new file mode 100644 index 0000000..e70d469 --- /dev/null +++ b/0134-ehci-Properly-report-completed-but-not-yet-processed.patch @@ -0,0 +1,52 @@ +From c7251f2557d09ce4b8466eeccd0f3264c297c515 Mon Sep 17 00:00:00 2001 +From: Hans de Goede +Date: Thu, 30 Aug 2012 15:18:24 +0200 +Subject: [PATCH] ehci: Properly report completed but not yet processed + packets to the guest + +Reported packets which have completed before being cancelled as such to the +host. Note that the new code path this patch adds is untested since it I've +been unable to actually trigger the race which needs this code path. + +Signed-off-by: Hans de Goede +(cherry picked from commit 4b63a0df3bda8a2c278e45d9d94d9ba6d5791d8d) + +Signed-off-by: Michael Roth +--- + hw/usb/hcd-ehci.c | 13 +++++++++++++ + 1 file changed, 13 insertions(+) + +diff --git a/hw/usb/hcd-ehci.c b/hw/usb/hcd-ehci.c +index 4fe85c8..0a6c9ef 100644 +--- a/hw/usb/hcd-ehci.c ++++ b/hw/usb/hcd-ehci.c +@@ -489,6 +489,9 @@ static const char *ehci_mmio_names[] = { + [CONFIGFLAG] = "CONFIGFLAG", + }; + ++static int ehci_state_executing(EHCIQueue *q); ++static int ehci_state_writeback(EHCIQueue *q); ++ + static const char *nr2str(const char **n, size_t len, uint32_t nr) + { + if (nr < len && n[nr] != NULL) { +@@ -750,6 +753,16 @@ static void ehci_free_packet(EHCIPacket *p) + usb_packet_unmap(&p->packet, &p->sgl); + qemu_sglist_destroy(&p->sgl); + } ++ if (p->async == EHCI_ASYNC_FINISHED) { ++ int state = ehci_get_state(p->queue->ehci, p->queue->async); ++ /* This is a normal, but rare condition (cancel racing completion) */ ++ fprintf(stderr, "EHCI: Warning packet completed but not processed\n"); ++ ehci_state_executing(p->queue); ++ ehci_state_writeback(p->queue); ++ ehci_set_state(p->queue->ehci, p->queue->async, state); ++ /* state_writeback recurses into us with async == EHCI_ASYNC_NONE!! */ ++ return; ++ } + QTAILQ_REMOVE(&p->queue->packets, p, next); + usb_packet_cleanup(&p->packet); + g_free(p); +-- +1.7.12.1 + diff --git a/0135-ehci-check-for-EHCI_ASYNC_FINISHED-first-in-ehci_fre.patch b/0135-ehci-check-for-EHCI_ASYNC_FINISHED-first-in-ehci_fre.patch new file mode 100644 index 0000000..f53bbe2 --- /dev/null +++ b/0135-ehci-check-for-EHCI_ASYNC_FINISHED-first-in-ehci_fre.patch @@ -0,0 +1,50 @@ +From b3950fe894e2b26f9dba0888af092cb43d01a466 Mon Sep 17 00:00:00 2001 +From: Gerd Hoffmann +Date: Fri, 31 Aug 2012 10:31:54 +0200 +Subject: [PATCH] ehci: check for EHCI_ASYNC_FINISHED first in + ehci_free_packet + +Otherwise we'll see the packet free twice in the trace log even though +it actually happens only once. + +Signed-off-by: Gerd Hoffmann +(cherry picked from commit 616789cde2a83fad5e634880fd20214f0c984fd5) + +Signed-off-by: Michael Roth +--- + hw/usb/hcd-ehci.c | 12 ++++++------ + 1 file changed, 6 insertions(+), 6 deletions(-) + +diff --git a/hw/usb/hcd-ehci.c b/hw/usb/hcd-ehci.c +index 0a6c9ef..23221d0 100644 +--- a/hw/usb/hcd-ehci.c ++++ b/hw/usb/hcd-ehci.c +@@ -747,12 +747,6 @@ static EHCIPacket *ehci_alloc_packet(EHCIQueue *q) + + static void ehci_free_packet(EHCIPacket *p) + { +- trace_usb_ehci_packet_action(p->queue, p, "free"); +- if (p->async == EHCI_ASYNC_INFLIGHT) { +- usb_cancel_packet(&p->packet); +- usb_packet_unmap(&p->packet, &p->sgl); +- qemu_sglist_destroy(&p->sgl); +- } + if (p->async == EHCI_ASYNC_FINISHED) { + int state = ehci_get_state(p->queue->ehci, p->queue->async); + /* This is a normal, but rare condition (cancel racing completion) */ +@@ -763,6 +757,12 @@ static void ehci_free_packet(EHCIPacket *p) + /* state_writeback recurses into us with async == EHCI_ASYNC_NONE!! */ + return; + } ++ trace_usb_ehci_packet_action(p->queue, p, "free"); ++ if (p->async == EHCI_ASYNC_INFLIGHT) { ++ usb_cancel_packet(&p->packet); ++ usb_packet_unmap(&p->packet, &p->sgl); ++ qemu_sglist_destroy(&p->sgl); ++ } + QTAILQ_REMOVE(&p->queue->packets, p, next); + usb_packet_cleanup(&p->packet); + g_free(p); +-- +1.7.12.1 + diff --git a/0136-ehci-trace-guest-bugs.patch b/0136-ehci-trace-guest-bugs.patch new file mode 100644 index 0000000..52c2f4a --- /dev/null +++ b/0136-ehci-trace-guest-bugs.patch @@ -0,0 +1,109 @@ +From 82b29b635d26ad0f5e14fabdf0956e9b8e7dbbfb Mon Sep 17 00:00:00 2001 +From: Gerd Hoffmann +Date: Fri, 31 Aug 2012 10:44:21 +0200 +Subject: [PATCH] ehci: trace guest bugs + +make qemu_queue_{cancel,reset} return the number of packets released, +so the caller can figure whenever there have been active packets even +though there shouldn't have been any. Add tracepoint to log this. + +Signed-off-by: Gerd Hoffmann +(cherry picked from commit 5c514681abbb3ae2f61f517c1aa3197f2f3ca93c) + +Signed-off-by: Michael Roth +--- + hw/usb/hcd-ehci.c | 26 ++++++++++++++++++++------ + trace-events | 1 + + 2 files changed, 21 insertions(+), 6 deletions(-) + +diff --git a/hw/usb/hcd-ehci.c b/hw/usb/hcd-ehci.c +index 23221d0..4564615 100644 +--- a/hw/usb/hcd-ehci.c ++++ b/hw/usb/hcd-ehci.c +@@ -716,6 +716,12 @@ static void ehci_trace_sitd(EHCIState *s, target_phys_addr_t addr, + (bool)(sitd->results & SITD_RESULTS_ACTIVE)); + } + ++static void ehci_trace_guest_bug(EHCIState *s, const char *message) ++{ ++ trace_usb_ehci_guest_bug(message); ++ fprintf(stderr, "ehci warning: %s\n", message); ++} ++ + static inline bool ehci_enabled(EHCIState *s) + { + return s->usbcmd & USBCMD_RUNSTOP; +@@ -785,27 +791,33 @@ static EHCIQueue *ehci_alloc_queue(EHCIState *ehci, uint32_t addr, int async) + return q; + } + +-static void ehci_cancel_queue(EHCIQueue *q) ++static int ehci_cancel_queue(EHCIQueue *q) + { + EHCIPacket *p; ++ int packets = 0; + + p = QTAILQ_FIRST(&q->packets); + if (p == NULL) { +- return; ++ return 0; + } + + trace_usb_ehci_queue_action(q, "cancel"); + do { + ehci_free_packet(p); ++ packets++; + } while ((p = QTAILQ_FIRST(&q->packets)) != NULL); ++ return packets; + } + +-static void ehci_reset_queue(EHCIQueue *q) ++static int ehci_reset_queue(EHCIQueue *q) + { ++ int packets; ++ + trace_usb_ehci_queue_action(q, "reset"); +- ehci_cancel_queue(q); ++ packets = ehci_cancel_queue(q); + q->dev = NULL; + q->qtdaddr = 0; ++ return packets; + } + + static void ehci_free_queue(EHCIQueue *q) +@@ -1817,7 +1829,9 @@ static EHCIQueue *ehci_state_fetchqh(EHCIState *ehci, int async) + (memcmp(&qh.current_qtd, &q->qh.current_qtd, + 9 * sizeof(uint32_t)) != 0) || + (q->dev != NULL && q->dev->addr != devaddr)) { +- ehci_reset_queue(q); ++ if (ehci_reset_queue(q) > 0) { ++ ehci_trace_guest_bug(ehci, "guest updated active QH"); ++ } + p = NULL; + } + q->qh = qh; +@@ -1979,8 +1993,8 @@ static int ehci_state_fetchqtd(EHCIQueue *q) + (!NLPTR_TBIT(p->qtd.next) && (p->qtd.next != qtd.next)) || + (!NLPTR_TBIT(p->qtd.altnext) && (p->qtd.altnext != qtd.altnext)) || + p->qtd.bufptr[0] != qtd.bufptr[0]) { +- /* guest bug: guest updated active QH or qTD underneath us */ + ehci_cancel_queue(q); ++ ehci_trace_guest_bug(q->ehci, "guest updated active QH or qTD"); + p = NULL; + } else { + p->qtd = qtd; +diff --git a/trace-events b/trace-events +index 8fcbc50..5112a47 100644 +--- a/trace-events ++++ b/trace-events +@@ -263,6 +263,7 @@ usb_ehci_data(int rw, uint32_t cpage, uint32_t offset, uint32_t addr, uint32_t l + usb_ehci_queue_action(void *q, const char *action) "q %p: %s" + usb_ehci_packet_action(void *q, void *p, const char *action) "q %p p %p: %s" + usb_ehci_irq(uint32_t level, uint32_t frindex, uint32_t sts, uint32_t mask) "level %d, frindex 0x%04x, sts 0x%x, mask 0x%x" ++usb_ehci_guest_bug(const char *reason) "%s" + + # hw/usb/hcd-uhci.c + usb_uhci_reset(void) "=== RESET ===" +-- +1.7.12.1 + diff --git a/0137-ehci-add-doorbell-trace-events.patch b/0137-ehci-add-doorbell-trace-events.patch new file mode 100644 index 0000000..33fb2a2 --- /dev/null +++ b/0137-ehci-add-doorbell-trace-events.patch @@ -0,0 +1,51 @@ +From bd1c78528cbd45629fe31127f5bde708263d6e17 Mon Sep 17 00:00:00 2001 +From: Gerd Hoffmann +Date: Fri, 31 Aug 2012 12:41:43 +0200 +Subject: [PATCH] ehci: add doorbell trace events + +Signed-off-by: Gerd Hoffmann +(cherry picked from commit 1defcbd1e81d67476b6e4e486bcd4d869162900d) + +Signed-off-by: Michael Roth +--- + hw/usb/hcd-ehci.c | 3 ++- + trace-events | 2 ++ + 2 files changed, 4 insertions(+), 1 deletion(-) + +diff --git a/hw/usb/hcd-ehci.c b/hw/usb/hcd-ehci.c +index 4564615..398f5e0 100644 +--- a/hw/usb/hcd-ehci.c ++++ b/hw/usb/hcd-ehci.c +@@ -1241,6 +1241,7 @@ static void ehci_mem_writel(void *ptr, target_phys_addr_t addr, uint32_t val) + */ + s->async_stepdown = 0; + qemu_bh_schedule(s->async_bh); ++ trace_usb_ehci_doorbell_ring(); + } + + if (((USBCMD_RUNSTOP | USBCMD_PSE | USBCMD_ASE) & val) != +@@ -2335,7 +2336,7 @@ static void ehci_advance_async_state(EHCIState *ehci) + if (ehci->usbcmd & USBCMD_IAAD) { + /* Remove all unseen qhs from the async qhs queue */ + ehci_queues_rip_unused(ehci, async, 1); +- DPRINTF("ASYNC: doorbell request acknowledged\n"); ++ trace_usb_ehci_doorbell_ack(); + ehci->usbcmd &= ~USBCMD_IAAD; + ehci_raise_irq(ehci, USBSTS_IAA); + } +diff --git a/trace-events b/trace-events +index 5112a47..10bc04e 100644 +--- a/trace-events ++++ b/trace-events +@@ -264,6 +264,8 @@ usb_ehci_queue_action(void *q, const char *action) "q %p: %s" + usb_ehci_packet_action(void *q, void *p, const char *action) "q %p p %p: %s" + usb_ehci_irq(uint32_t level, uint32_t frindex, uint32_t sts, uint32_t mask) "level %d, frindex 0x%04x, sts 0x%x, mask 0x%x" + usb_ehci_guest_bug(const char *reason) "%s" ++usb_ehci_doorbell_ring(void) "" ++usb_ehci_doorbell_ack(void) "" + + # hw/usb/hcd-uhci.c + usb_uhci_reset(void) "=== RESET ===" +-- +1.7.12.1 + diff --git a/0138-ehci-Add-some-additional-ehci_trace_guest_bug-calls.patch b/0138-ehci-Add-some-additional-ehci_trace_guest_bug-calls.patch new file mode 100644 index 0000000..8a62ee7 --- /dev/null +++ b/0138-ehci-Add-some-additional-ehci_trace_guest_bug-calls.patch @@ -0,0 +1,88 @@ +From 9dc252544b41a626bbdf436a3e6f229fa0014143 Mon Sep 17 00:00:00 2001 +From: Hans de Goede +Date: Mon, 3 Sep 2012 10:22:16 +0200 +Subject: [PATCH] ehci: Add some additional ehci_trace_guest_bug() calls + +Signed-off-by: Hans de Goede +Signed-off-by: Gerd Hoffmann +(cherry picked from commit 3a8ca08e01ea4baafff2a513655008cdd00feebf) + +Signed-off-by: Michael Roth +--- + hw/usb/hcd-ehci.c | 19 +++++++++++++------ + 1 file changed, 13 insertions(+), 6 deletions(-) + +diff --git a/hw/usb/hcd-ehci.c b/hw/usb/hcd-ehci.c +index 398f5e0..5a88268 100644 +--- a/hw/usb/hcd-ehci.c ++++ b/hw/usb/hcd-ehci.c +@@ -820,12 +820,16 @@ static int ehci_reset_queue(EHCIQueue *q) + return packets; + } + +-static void ehci_free_queue(EHCIQueue *q) ++static void ehci_free_queue(EHCIQueue *q, const char *warn) + { + EHCIQueueHead *head = q->async ? &q->ehci->aqueues : &q->ehci->pqueues; ++ int cancelled; + + trace_usb_ehci_queue_action(q, "free"); +- ehci_cancel_queue(q); ++ cancelled = ehci_cancel_queue(q); ++ if (warn && cancelled > 0) { ++ ehci_trace_guest_bug(q->ehci, warn); ++ } + QTAILQ_REMOVE(head, q, next); + g_free(q); + } +@@ -847,6 +851,7 @@ static EHCIQueue *ehci_find_queue_by_qh(EHCIState *ehci, uint32_t addr, + static void ehci_queues_rip_unused(EHCIState *ehci, int async, int flush) + { + EHCIQueueHead *head = async ? &ehci->aqueues : &ehci->pqueues; ++ const char *warn = (async && !flush) ? "guest unlinked busy QH" : NULL; + uint64_t maxage = FRAME_TIMER_NS * ehci->maxframes * 4; + EHCIQueue *q, *tmp; + +@@ -859,7 +864,7 @@ static void ehci_queues_rip_unused(EHCIState *ehci, int async, int flush) + if (!flush && ehci->last_run_ns < q->ts + maxage) { + continue; + } +- ehci_free_queue(q); ++ ehci_free_queue(q, warn); + } + } + +@@ -872,17 +877,18 @@ static void ehci_queues_rip_device(EHCIState *ehci, USBDevice *dev, int async) + if (q->dev != dev) { + continue; + } +- ehci_free_queue(q); ++ ehci_free_queue(q, NULL); + } + } + + static void ehci_queues_rip_all(EHCIState *ehci, int async) + { + EHCIQueueHead *head = async ? &ehci->aqueues : &ehci->pqueues; ++ const char *warn = async ? "guest stopped busy async schedule" : NULL; + EHCIQueue *q, *tmp; + + QTAILQ_FOREACH_SAFE(q, head, next, tmp) { +- ehci_free_queue(q); ++ ehci_free_queue(q, warn); + } + } + +@@ -1549,7 +1555,8 @@ static int ehci_execute(EHCIPacket *p, const char *action) + + p->tbytes = (p->qtd.token & QTD_TOKEN_TBYTES_MASK) >> QTD_TOKEN_TBYTES_SH; + if (p->tbytes > BUFF_SIZE) { +- fprintf(stderr, "Request for more bytes than allowed\n"); ++ ehci_trace_guest_bug(p->queue->ehci, ++ "guest requested more bytes than allowed"); + return USB_RET_PROCERR; + } + +-- +1.7.12.1 + diff --git a/0139-ehci-Fix-memory-leak-in-handling-of-NAK-ed-packets.patch b/0139-ehci-Fix-memory-leak-in-handling-of-NAK-ed-packets.patch new file mode 100644 index 0000000..b144ab4 --- /dev/null +++ b/0139-ehci-Fix-memory-leak-in-handling-of-NAK-ed-packets.patch @@ -0,0 +1,120 @@ +From 5d369bd44cf2611f47fec52c7402472cd2436b4a Mon Sep 17 00:00:00 2001 +From: Hans de Goede +Date: Mon, 3 Sep 2012 11:01:13 +0200 +Subject: [PATCH] ehci: Fix memory leak in handling of NAK-ed packets + +Currently each time we try to execute a NAK-ed packet we redo +ehci_init_transfer, and usb_packet_map, re-allocing (without freeing) the +sg list every time. + +This patch fixes this, it does this by introducing another async state, so +that we also properly cleanup a NAK-ed packet on cancel. + +Signed-off-by: Hans de Goede +Signed-off-by: Gerd Hoffmann +(cherry picked from commit ef5b234477df80700b128f561f5877a0688a70c8) + +Signed-off-by: Michael Roth +--- + hw/usb/hcd-ehci.c | 38 +++++++++++++++++++++++++++----------- + 1 file changed, 27 insertions(+), 11 deletions(-) + +diff --git a/hw/usb/hcd-ehci.c b/hw/usb/hcd-ehci.c +index 5a88268..d87aca8 100644 +--- a/hw/usb/hcd-ehci.c ++++ b/hw/usb/hcd-ehci.c +@@ -345,6 +345,7 @@ typedef struct EHCIState EHCIState; + + enum async_state { + EHCI_ASYNC_NONE = 0, ++ EHCI_ASYNC_INITIALIZED, + EHCI_ASYNC_INFLIGHT, + EHCI_ASYNC_FINISHED, + }; +@@ -764,6 +765,10 @@ static void ehci_free_packet(EHCIPacket *p) + return; + } + trace_usb_ehci_packet_action(p->queue, p, "free"); ++ if (p->async == EHCI_ASYNC_INITIALIZED) { ++ usb_packet_unmap(&p->packet, &p->sgl); ++ qemu_sglist_destroy(&p->sgl); ++ } + if (p->async == EHCI_ASYNC_INFLIGHT) { + usb_cancel_packet(&p->packet); + usb_packet_unmap(&p->packet, &p->sgl); +@@ -1485,8 +1490,8 @@ static void ehci_execute_complete(EHCIQueue *q) + + assert(p != NULL); + assert(p->qtdaddr == q->qtdaddr); +- assert(p->async != EHCI_ASYNC_INFLIGHT); +- p->async = EHCI_ASYNC_NONE; ++ assert(p->async == EHCI_ASYNC_INITIALIZED || ++ p->async == EHCI_ASYNC_FINISHED); + + DPRINTF("execute_complete: qhaddr 0x%x, next %x, qtdaddr 0x%x, status %d\n", + q->qhaddr, q->qh.next, q->qtdaddr, q->usb_status); +@@ -1531,6 +1536,7 @@ static void ehci_execute_complete(EHCIQueue *q) + ehci_finish_transfer(q, p->usb_status); + usb_packet_unmap(&p->packet, &p->sgl); + qemu_sglist_destroy(&p->sgl); ++ p->async = EHCI_ASYNC_NONE; + + q->qh.token ^= QTD_TOKEN_DTOGGLE; + q->qh.token &= ~QTD_TOKEN_ACTIVE; +@@ -1548,6 +1554,9 @@ static int ehci_execute(EHCIPacket *p, const char *action) + int ret; + int endp; + ++ assert(p->async == EHCI_ASYNC_NONE || ++ p->async == EHCI_ASYNC_INITIALIZED); ++ + if (!(p->qtd.token & QTD_TOKEN_ACTIVE)) { + fprintf(stderr, "Attempting to execute inactive qtd\n"); + return USB_RET_PROCERR; +@@ -1576,15 +1585,18 @@ static int ehci_execute(EHCIPacket *p, const char *action) + break; + } + +- if (ehci_init_transfer(p) != 0) { +- return USB_RET_PROCERR; +- } +- + endp = get_field(p->queue->qh.epchar, QH_EPCHAR_EP); + ep = usb_ep_get(p->queue->dev, p->pid, endp); + +- usb_packet_setup(&p->packet, p->pid, ep, p->qtdaddr); +- usb_packet_map(&p->packet, &p->sgl); ++ if (p->async == EHCI_ASYNC_NONE) { ++ if (ehci_init_transfer(p) != 0) { ++ return USB_RET_PROCERR; ++ } ++ ++ usb_packet_setup(&p->packet, p->pid, ep, p->qtdaddr); ++ usb_packet_map(&p->packet, &p->sgl); ++ p->async = EHCI_ASYNC_INITIALIZED; ++ } + + trace_usb_ehci_packet_action(p->queue, p, action); + ret = usb_handle_packet(p->queue->dev, &p->packet); +@@ -2021,11 +2033,15 @@ static int ehci_state_fetchqtd(EHCIQueue *q) + } else if (p != NULL) { + switch (p->async) { + case EHCI_ASYNC_NONE: ++ /* Should never happen packet should at least be initialized */ ++ assert(0); ++ break; ++ case EHCI_ASYNC_INITIALIZED: + /* Previously nacked packet (likely interrupt ep) */ +- ehci_set_state(q->ehci, q->async, EST_EXECUTE); +- break; ++ ehci_set_state(q->ehci, q->async, EST_EXECUTE); ++ break; + case EHCI_ASYNC_INFLIGHT: +- /* Unfinyshed async handled packet, go horizontal */ ++ /* Unfinished async handled packet, go horizontal */ + ehci_set_state(q->ehci, q->async, EST_HORIZONTALQH); + break; + case EHCI_ASYNC_FINISHED: +-- +1.7.12.1 + diff --git a/0140-ehci-Handle-USB_RET_PROCERR-in-ehci_fill_queue.patch b/0140-ehci-Handle-USB_RET_PROCERR-in-ehci_fill_queue.patch new file mode 100644 index 0000000..74b2853 --- /dev/null +++ b/0140-ehci-Handle-USB_RET_PROCERR-in-ehci_fill_queue.patch @@ -0,0 +1,57 @@ +From 90905dca56de07f7c394ef8cbe480a0d08e0d8cd Mon Sep 17 00:00:00 2001 +From: Hans de Goede +Date: Mon, 3 Sep 2012 11:35:58 +0200 +Subject: [PATCH] ehci: Handle USB_RET_PROCERR in ehci_fill_queue + +USB_RET_PROCERR can be triggered by the guest (by for example requesting more +then BUFFSIZE bytes), so don't assert on it. + +Signed-off-by: Hans de Goede +Signed-off-by: Gerd Hoffmann +(cherry picked from commit eff6dce79bd7ad3c16d75c5e55b5a2a137ba6a60) + +Signed-off-by: Michael Roth +--- + hw/usb/hcd-ehci.c | 9 ++++++--- + 1 file changed, 6 insertions(+), 3 deletions(-) + +diff --git a/hw/usb/hcd-ehci.c b/hw/usb/hcd-ehci.c +index d87aca8..2534394 100644 +--- a/hw/usb/hcd-ehci.c ++++ b/hw/usb/hcd-ehci.c +@@ -2076,7 +2076,7 @@ static int ehci_state_horizqh(EHCIQueue *q) + return again; + } + +-static void ehci_fill_queue(EHCIPacket *p) ++static int ehci_fill_queue(EHCIPacket *p) + { + EHCIQueue *q = p->queue; + EHCIqtd qtd = p->qtd; +@@ -2100,9 +2100,13 @@ static void ehci_fill_queue(EHCIPacket *p) + p->qtdaddr = qtdaddr; + p->qtd = qtd; + p->usb_status = ehci_execute(p, "queue"); ++ if (p->usb_status == USB_RET_PROCERR) { ++ break; ++ } + assert(p->usb_status == USB_RET_ASYNC); + p->async = EHCI_ASYNC_INFLIGHT; + } ++ return p->usb_status; + } + + static int ehci_state_execute(EHCIQueue *q) +@@ -2144,8 +2148,7 @@ static int ehci_state_execute(EHCIQueue *q) + trace_usb_ehci_packet_action(p->queue, p, "async"); + p->async = EHCI_ASYNC_INFLIGHT; + ehci_set_state(q->ehci, q->async, EST_HORIZONTALQH); +- again = 1; +- ehci_fill_queue(p); ++ again = (ehci_fill_queue(p) == USB_RET_PROCERR) ? -1 : 1; + goto out; + } + +-- +1.7.12.1 + diff --git a/0141-ehci-Correct-a-comment-in-fetchqtd-packet-processing.patch b/0141-ehci-Correct-a-comment-in-fetchqtd-packet-processing.patch new file mode 100644 index 0000000..99c1351 --- /dev/null +++ b/0141-ehci-Correct-a-comment-in-fetchqtd-packet-processing.patch @@ -0,0 +1,37 @@ +From e598e28401bb25d4d639b29f297a549badbf0cfa Mon Sep 17 00:00:00 2001 +From: Hans de Goede +Date: Mon, 3 Sep 2012 12:17:48 +0200 +Subject: [PATCH] ehci: Correct a comment in fetchqtd packet processing + +Since my previous comment said "Should never happen", I tried changing the +next line to an assert(0), which did not go well, which as the new comments +explains is logical if you think about it for a moment. + +Signed-off-by: Hans de Goede +Signed-off-by: Gerd Hoffmann +(cherry picked from commit cf1f81691d1998fa8fe5bfcb8b498fb3723cf3c3) + +Signed-off-by: Michael Roth +--- + hw/usb/hcd-ehci.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/hw/usb/hcd-ehci.c b/hw/usb/hcd-ehci.c +index 2534394..2f3e9c0 100644 +--- a/hw/usb/hcd-ehci.c ++++ b/hw/usb/hcd-ehci.c +@@ -2045,7 +2045,10 @@ static int ehci_state_fetchqtd(EHCIQueue *q) + ehci_set_state(q->ehci, q->async, EST_HORIZONTALQH); + break; + case EHCI_ASYNC_FINISHED: +- /* Should never happen, as this case is caught by fetchqh */ ++ /* ++ * We get here when advqueue moves to a packet which is already ++ * finished, which can happen with packets queued up by fill_queue ++ */ + ehci_set_state(q->ehci, q->async, EST_EXECUTING); + break; + } +-- +1.7.12.1 + diff --git a/0142-usb-redir-Never-return-USB_RET_NAK-for-async-handled.patch b/0142-usb-redir-Never-return-USB_RET_NAK-for-async-handled.patch new file mode 100644 index 0000000..f2723ac --- /dev/null +++ b/0142-usb-redir-Never-return-USB_RET_NAK-for-async-handled.patch @@ -0,0 +1,47 @@ +From 262c9bb1e59c2cd561dad1cf9d47c50f07af0e0f Mon Sep 17 00:00:00 2001 +From: Hans de Goede +Date: Fri, 17 Aug 2012 17:27:08 +0200 +Subject: [PATCH] usb-redir: Never return USB_RET_NAK for async handled + packets + +USB_RET_NAK is not a valid response for async handled packets (and will +trigger an assert as such). + +Also drop the warning when receiving a status of cancelled for packets not +cancelled by qemu itself, this can happen when a device gets unredirected +by the usbredir-host while transfers are pending. + +Signed-off-by: Hans de Goede +Signed-off-by: Gerd Hoffmann +(cherry picked from commit 181133404f520fab40a3ad40d935d91cf3cf546c) + +Signed-off-by: Michael Roth +--- + hw/usb/redirect.c | 9 ++++++--- + 1 file changed, 6 insertions(+), 3 deletions(-) + +diff --git a/hw/usb/redirect.c b/hw/usb/redirect.c +index 10b4fbb..7f3719b 100644 +--- a/hw/usb/redirect.c ++++ b/hw/usb/redirect.c +@@ -1028,11 +1028,14 @@ static int usbredir_handle_status(USBRedirDevice *dev, + case usb_redir_stall: + return USB_RET_STALL; + case usb_redir_cancelled: +- WARNING("returning cancelled packet to HC?\n"); +- return USB_RET_NAK; ++ /* ++ * When the usbredir-host unredirects a device, it will report a status ++ * of cancelled for all pending packets, followed by a disconnect msg. ++ */ ++ return USB_RET_IOERROR; + case usb_redir_inval: + WARNING("got invalid param error from usb-host?\n"); +- return USB_RET_NAK; ++ return USB_RET_IOERROR; + case usb_redir_babble: + return USB_RET_BABBLE; + case usb_redir_ioerror: +-- +1.7.12.1 + diff --git a/0143-usb-redir-Don-t-delay-handling-of-open-events-to-a-b.patch b/0143-usb-redir-Don-t-delay-handling-of-open-events-to-a-b.patch new file mode 100644 index 0000000..33f3ae9 --- /dev/null +++ b/0143-usb-redir-Don-t-delay-handling-of-open-events-to-a-b.patch @@ -0,0 +1,184 @@ +From b89a0cc1ec9dbe30cbe002f12d487a52950da166 Mon Sep 17 00:00:00 2001 +From: Hans de Goede +Date: Thu, 23 Aug 2012 16:37:19 +0200 +Subject: [PATCH] usb-redir: Don't delay handling of open events to a bottom + half + +There is no need for this, and doing so means that a backend trying to +write immediately after an open event will see qemu_chr_be_can_write +returning 0, which not all backends handle well as there is no wakeup +mechanism to detect when the frontend does become writable. + +Signed-off-by: Hans de Goede +Signed-off-by: Gerd Hoffmann +(cherry picked from commit ed9873bfbf145c084d039baab08c63b9d67e7bd3) + +Signed-off-by: Michael Roth +--- + hw/usb/redirect.c | 100 +++++++++++++++++++++++++++++------------------------- + 1 file changed, 53 insertions(+), 47 deletions(-) + +diff --git a/hw/usb/redirect.c b/hw/usb/redirect.c +index 7f3719b..5cc3334 100644 +--- a/hw/usb/redirect.c ++++ b/hw/usb/redirect.c +@@ -79,8 +79,8 @@ struct USBRedirDevice { + /* Data passed from chardev the fd_read cb to the usbredirparser read cb */ + const uint8_t *read_buf; + int read_buf_size; +- /* For async handling of open/close */ +- QEMUBH *open_close_bh; ++ /* For async handling of close */ ++ QEMUBH *chardev_close_bh; + /* To delay the usb attach in case of quick chardev close + open */ + QEMUTimer *attach_timer; + int64_t next_attach_time; +@@ -784,18 +784,11 @@ static int usbredir_handle_control(USBDevice *udev, USBPacket *p, + * from within the USBDevice data / control packet callbacks and doing a + * usb_detach from within these callbacks is not a good idea. + * +- * So we use a bh handler to take care of close events. We also handle +- * open events from this callback to make sure that a close directly followed +- * by an open gets handled in the right order. ++ * So we use a bh handler to take care of close events. + */ +-static void usbredir_open_close_bh(void *opaque) ++static void usbredir_chardev_close_bh(void *opaque) + { + USBRedirDevice *dev = opaque; +- uint32_t caps[USB_REDIR_CAPS_SIZE] = { 0, }; +- char version[32]; +- +- strcpy(version, "qemu usb-redir guest "); +- pstrcat(version, sizeof(version), qemu_get_version()); + + usbredir_device_disconnect(dev); + +@@ -803,36 +796,47 @@ static void usbredir_open_close_bh(void *opaque) + usbredirparser_destroy(dev->parser); + dev->parser = NULL; + } ++} + +- if (dev->cs->opened) { +- dev->parser = qemu_oom_check(usbredirparser_create()); +- dev->parser->priv = dev; +- dev->parser->log_func = usbredir_log; +- dev->parser->read_func = usbredir_read; +- dev->parser->write_func = usbredir_write; +- dev->parser->hello_func = usbredir_hello; +- dev->parser->device_connect_func = usbredir_device_connect; +- dev->parser->device_disconnect_func = usbredir_device_disconnect; +- dev->parser->interface_info_func = usbredir_interface_info; +- dev->parser->ep_info_func = usbredir_ep_info; +- dev->parser->configuration_status_func = usbredir_configuration_status; +- dev->parser->alt_setting_status_func = usbredir_alt_setting_status; +- dev->parser->iso_stream_status_func = usbredir_iso_stream_status; +- dev->parser->interrupt_receiving_status_func = +- usbredir_interrupt_receiving_status; +- dev->parser->bulk_streams_status_func = usbredir_bulk_streams_status; +- dev->parser->control_packet_func = usbredir_control_packet; +- dev->parser->bulk_packet_func = usbredir_bulk_packet; +- dev->parser->iso_packet_func = usbredir_iso_packet; +- dev->parser->interrupt_packet_func = usbredir_interrupt_packet; +- dev->read_buf = NULL; +- dev->read_buf_size = 0; ++static void usbredir_chardev_open(USBRedirDevice *dev) ++{ ++ uint32_t caps[USB_REDIR_CAPS_SIZE] = { 0, }; ++ char version[32]; + +- usbredirparser_caps_set_cap(caps, usb_redir_cap_connect_device_version); +- usbredirparser_caps_set_cap(caps, usb_redir_cap_filter); +- usbredirparser_init(dev->parser, version, caps, USB_REDIR_CAPS_SIZE, 0); +- usbredirparser_do_write(dev->parser); +- } ++ /* Make sure any pending closes are handled (no-op if none pending) */ ++ usbredir_chardev_close_bh(dev); ++ qemu_bh_cancel(dev->chardev_close_bh); ++ ++ strcpy(version, "qemu usb-redir guest "); ++ pstrcat(version, sizeof(version), qemu_get_version()); ++ ++ dev->parser = qemu_oom_check(usbredirparser_create()); ++ dev->parser->priv = dev; ++ dev->parser->log_func = usbredir_log; ++ dev->parser->read_func = usbredir_read; ++ dev->parser->write_func = usbredir_write; ++ dev->parser->hello_func = usbredir_hello; ++ dev->parser->device_connect_func = usbredir_device_connect; ++ dev->parser->device_disconnect_func = usbredir_device_disconnect; ++ dev->parser->interface_info_func = usbredir_interface_info; ++ dev->parser->ep_info_func = usbredir_ep_info; ++ dev->parser->configuration_status_func = usbredir_configuration_status; ++ dev->parser->alt_setting_status_func = usbredir_alt_setting_status; ++ dev->parser->iso_stream_status_func = usbredir_iso_stream_status; ++ dev->parser->interrupt_receiving_status_func = ++ usbredir_interrupt_receiving_status; ++ dev->parser->bulk_streams_status_func = usbredir_bulk_streams_status; ++ dev->parser->control_packet_func = usbredir_control_packet; ++ dev->parser->bulk_packet_func = usbredir_bulk_packet; ++ dev->parser->iso_packet_func = usbredir_iso_packet; ++ dev->parser->interrupt_packet_func = usbredir_interrupt_packet; ++ dev->read_buf = NULL; ++ dev->read_buf_size = 0; ++ ++ usbredirparser_caps_set_cap(caps, usb_redir_cap_connect_device_version); ++ usbredirparser_caps_set_cap(caps, usb_redir_cap_filter); ++ usbredirparser_init(dev->parser, version, caps, USB_REDIR_CAPS_SIZE, 0); ++ usbredirparser_do_write(dev->parser); + } + + static void usbredir_do_attach(void *opaque) +@@ -856,13 +860,13 @@ static int usbredir_chardev_can_read(void *opaque) + { + USBRedirDevice *dev = opaque; + +- if (dev->parser) { +- /* usbredir_parser_do_read will consume *all* data we give it */ +- return 1024 * 1024; +- } else { +- /* usbredir_open_close_bh hasn't handled the open event yet */ ++ if (!dev->parser) { ++ WARNING("chardev_can_read called on non open chardev!\n"); + return 0; + } ++ ++ /* usbredir_parser_do_read will consume *all* data we give it */ ++ return 1024 * 1024; + } + + static void usbredir_chardev_read(void *opaque, const uint8_t *buf, int size) +@@ -886,8 +890,10 @@ static void usbredir_chardev_event(void *opaque, int event) + + switch (event) { + case CHR_EVENT_OPENED: ++ usbredir_chardev_open(dev); ++ break; + case CHR_EVENT_CLOSED: +- qemu_bh_schedule(dev->open_close_bh); ++ qemu_bh_schedule(dev->chardev_close_bh); + break; + } + } +@@ -917,7 +923,7 @@ static int usbredir_initfn(USBDevice *udev) + } + } + +- dev->open_close_bh = qemu_bh_new(usbredir_open_close_bh, dev); ++ dev->chardev_close_bh = qemu_bh_new(usbredir_chardev_close_bh, dev); + dev->attach_timer = qemu_new_timer_ms(vm_clock, usbredir_do_attach, dev); + + QTAILQ_INIT(&dev->asyncq); +@@ -957,7 +963,7 @@ static void usbredir_handle_destroy(USBDevice *udev) + qemu_chr_fe_close(dev->cs); + qemu_chr_delete(dev->cs); + /* Note must be done after qemu_chr_close, as that causes a close event */ +- qemu_bh_delete(dev->open_close_bh); ++ qemu_bh_delete(dev->chardev_close_bh); + + qemu_del_timer(dev->attach_timer); + qemu_free_timer(dev->attach_timer); +-- +1.7.12.1 + diff --git a/0144-usb-redir-Get-rid-of-async-struct-get-member.patch b/0144-usb-redir-Get-rid-of-async-struct-get-member.patch new file mode 100644 index 0000000..7ac41ee --- /dev/null +++ b/0144-usb-redir-Get-rid-of-async-struct-get-member.patch @@ -0,0 +1,76 @@ +From a9fd3192a956ed1bce0f945f6b35bf9b162b30c3 Mon Sep 17 00:00:00 2001 +From: Hans de Goede +Date: Mon, 27 Aug 2012 16:33:08 +0200 +Subject: [PATCH] usb-redir: Get rid of async-struct get member + +This is a preparation patch for completely getting rid of the async-packet +struct in usb-redir, instead relying on the (new) per ep queues in the +qemu usb core. + +Signed-off-by: Hans de Goede +Signed-off-by: Gerd Hoffmann +(cherry picked from commit cb897117cdedd488f19985c8ec5ea05971103a27) + +Signed-off-by: Michael Roth +--- + hw/usb/redirect.c | 9 +++------ + 1 file changed, 3 insertions(+), 6 deletions(-) + +diff --git a/hw/usb/redirect.c b/hw/usb/redirect.c +index 5cc3334..2cae8c5 100644 +--- a/hw/usb/redirect.c ++++ b/hw/usb/redirect.c +@@ -1,7 +1,7 @@ + /* + * USB redirector usb-guest + * +- * Copyright (c) 2011 Red Hat, Inc. ++ * Copyright (c) 2011-2012 Red Hat, Inc. + * + * Red Hat Authors: + * Hans de Goede +@@ -99,7 +99,6 @@ struct AsyncURB { + USBRedirDevice *dev; + USBPacket *packet; + uint32_t packet_id; +- int get; + union { + struct usb_redir_control_packet_header control_packet; + struct usb_redir_bulk_packet_header bulk_packet; +@@ -672,7 +671,6 @@ static int usbredir_get_config(USBRedirDevice *dev, USBPacket *p) + + DPRINTF("get config id %u\n", aurb->packet_id); + +- aurb->get = 1; + usbredirparser_send_get_configuration(dev->parser, aurb->packet_id); + usbredirparser_do_write(dev->parser); + return USB_RET_ASYNC; +@@ -721,7 +719,6 @@ static int usbredir_get_interface(USBRedirDevice *dev, USBPacket *p, + DPRINTF("get interface %d id %u\n", interface, aurb->packet_id); + + get_alt.interface = interface; +- aurb->get = 1; + usbredirparser_send_get_alt_setting(dev->parser, aurb->packet_id, + &get_alt); + usbredirparser_do_write(dev->parser); +@@ -1226,7 +1223,7 @@ static void usbredir_configuration_status(void *priv, uint32_t id, + return; + } + if (aurb->packet) { +- if (aurb->get) { ++ if (dev->dev.setup_buf[0] & USB_DIR_IN) { + dev->dev.data_buf[0] = config_status->configuration; + len = 1; + } +@@ -1254,7 +1251,7 @@ static void usbredir_alt_setting_status(void *priv, uint32_t id, + return; + } + if (aurb->packet) { +- if (aurb->get) { ++ if (dev->dev.setup_buf[0] & USB_DIR_IN) { + dev->dev.data_buf[0] = alt_setting_status->alt; + len = 1; + } +-- +1.7.12.1 + diff --git a/0145-usb-redir-Get-rid-of-local-shadow-copy-of-packet-hea.patch b/0145-usb-redir-Get-rid-of-local-shadow-copy-of-packet-hea.patch new file mode 100644 index 0000000..eb581df --- /dev/null +++ b/0145-usb-redir-Get-rid-of-local-shadow-copy-of-packet-hea.patch @@ -0,0 +1,109 @@ +From 40d22426e0e12f26c7bfa5848cf0a9857d52dc99 Mon Sep 17 00:00:00 2001 +From: Hans de Goede +Date: Tue, 28 Aug 2012 09:05:38 +0200 +Subject: [PATCH] usb-redir: Get rid of local shadow copy of packet headers + +The shadow copy only serves as an extra check (besides the packet-id) to +ensure the packet we get back is a reply to the packet we think it is. + +This check has never triggered in all the time usb-redir is in use now, +and since the verified data in the returned packet-header is not used +otherwise, removing the check does not open any possibilities for the +usbredirhost to confuse us. + +This is a preparation patch for completely getting rid of the async-packet +struct in usb-redir, instead relying on the (new) per ep queues in the +qemu usb core. + +Signed-off-by: Hans de Goede +Signed-off-by: Gerd Hoffmann +(cherry picked from commit 104981d52b63dc3d68f39d4442881c667f44bbb9) + +Signed-off-by: Michael Roth +--- + hw/usb/redirect.c | 27 --------------------------- + 1 file changed, 27 deletions(-) + +diff --git a/hw/usb/redirect.c b/hw/usb/redirect.c +index 2cae8c5..e4ef372 100644 +--- a/hw/usb/redirect.c ++++ b/hw/usb/redirect.c +@@ -99,11 +99,6 @@ struct AsyncURB { + USBRedirDevice *dev; + USBPacket *packet; + uint32_t packet_id; +- union { +- struct usb_redir_control_packet_header control_packet; +- struct usb_redir_bulk_packet_header bulk_packet; +- struct usb_redir_interrupt_packet_header interrupt_packet; +- }; + QTAILQ_ENTRY(AsyncURB)next; + }; + +@@ -500,7 +495,6 @@ static int usbredir_handle_bulk_data(USBRedirDevice *dev, USBPacket *p, + bulk_packet.endpoint = ep; + bulk_packet.length = p->iov.size; + bulk_packet.stream_id = 0; +- aurb->bulk_packet = bulk_packet; + + if (ep & USB_DIR_IN) { + usbredirparser_send_bulk_packet(dev->parser, aurb->packet_id, +@@ -581,7 +575,6 @@ static int usbredir_handle_interrupt_data(USBRedirDevice *dev, + + interrupt_packet.endpoint = ep; + interrupt_packet.length = p->iov.size; +- aurb->interrupt_packet = interrupt_packet; + + usb_packet_copy(p, buf, p->iov.size); + usbredir_log_data(dev, "interrupt data out:", buf, p->iov.size); +@@ -762,7 +755,6 @@ static int usbredir_handle_control(USBDevice *udev, USBPacket *p, + control_packet.value = value; + control_packet.index = index; + control_packet.length = length; +- aurb->control_packet = control_packet; + + if (control_packet.requesttype & USB_DIR_IN) { + usbredirparser_send_control_packet(dev->parser, aurb->packet_id, +@@ -1326,14 +1318,6 @@ static void usbredir_control_packet(void *priv, uint32_t id, + return; + } + +- aurb->control_packet.status = control_packet->status; +- aurb->control_packet.length = control_packet->length; +- if (memcmp(&aurb->control_packet, control_packet, +- sizeof(*control_packet))) { +- ERROR("return control packet mismatch, please report this!\n"); +- len = USB_RET_NAK; +- } +- + if (aurb->packet) { + len = usbredir_handle_status(dev, control_packet->status, len); + if (len > 0) { +@@ -1371,12 +1355,6 @@ static void usbredir_bulk_packet(void *priv, uint32_t id, + return; + } + +- if (aurb->bulk_packet.endpoint != bulk_packet->endpoint || +- aurb->bulk_packet.stream_id != bulk_packet->stream_id) { +- ERROR("return bulk packet mismatch, please report this!\n"); +- len = USB_RET_NAK; +- } +- + if (aurb->packet) { + len = usbredir_handle_status(dev, bulk_packet->status, len); + if (len > 0) { +@@ -1455,11 +1433,6 @@ static void usbredir_interrupt_packet(void *priv, uint32_t id, + return; + } + +- if (aurb->interrupt_packet.endpoint != interrupt_packet->endpoint) { +- ERROR("return int packet mismatch, please report this!\n"); +- len = USB_RET_NAK; +- } +- + if (aurb->packet) { + aurb->packet->result = usbredir_handle_status(dev, + interrupt_packet->status, len); +-- +1.7.12.1 + diff --git a/0146-usb-redir-Get-rid-of-unused-async-struct-dev-member.patch b/0146-usb-redir-Get-rid-of-unused-async-struct-dev-member.patch new file mode 100644 index 0000000..18c7c1f --- /dev/null +++ b/0146-usb-redir-Get-rid-of-unused-async-struct-dev-member.patch @@ -0,0 +1,41 @@ +From 008e2fcbeea527c3aff3078ed5a178d59757bc28 Mon Sep 17 00:00:00 2001 +From: Hans de Goede +Date: Tue, 28 Aug 2012 09:08:45 +0200 +Subject: [PATCH] usb-redir: Get rid of unused async-struct dev member + +This is a preparation patch for completely getting rid of the async-packet +struct in usb-redir, instead relying on the (new) per ep queues in the +qemu usb core. + +Signed-off-by: Hans de Goede +Signed-off-by: Gerd Hoffmann +(cherry picked from commit 206e7f20fe7b920b362bcc02608680c5d5527f2a) + +Signed-off-by: Michael Roth +--- + hw/usb/redirect.c | 2 -- + 1 file changed, 2 deletions(-) + +diff --git a/hw/usb/redirect.c b/hw/usb/redirect.c +index e4ef372..6593d50 100644 +--- a/hw/usb/redirect.c ++++ b/hw/usb/redirect.c +@@ -96,7 +96,6 @@ struct USBRedirDevice { + }; + + struct AsyncURB { +- USBRedirDevice *dev; + USBPacket *packet; + uint32_t packet_id; + QTAILQ_ENTRY(AsyncURB)next; +@@ -245,7 +244,6 @@ static int usbredir_write(void *priv, uint8_t *data, int count) + static AsyncURB *async_alloc(USBRedirDevice *dev, USBPacket *p) + { + AsyncURB *aurb = (AsyncURB *) g_malloc0(sizeof(AsyncURB)); +- aurb->dev = dev; + aurb->packet = p; + aurb->packet_id = dev->packet_id; + QTAILQ_INSERT_TAIL(&dev->asyncq, aurb, next); +-- +1.7.12.1 + diff --git a/0147-usb-redir-Move-to-core-packet-id-and-queue-handling.patch b/0147-usb-redir-Move-to-core-packet-id-and-queue-handling.patch new file mode 100644 index 0000000..f32e6cc --- /dev/null +++ b/0147-usb-redir-Move-to-core-packet-id-and-queue-handling.patch @@ -0,0 +1,502 @@ +From 111194442fa38ba6dc26bc695ba0d3b76584663b Mon Sep 17 00:00:00 2001 +From: Hans de Goede +Date: Tue, 28 Aug 2012 11:30:13 +0200 +Subject: [PATCH] usb-redir: Move to core packet id and queue handling + +Signed-off-by: Hans de Goede +Signed-off-by: Gerd Hoffmann +(cherry picked from commit de550a6afb468ed3b8171019e19b63ae8254886d) + +Signed-off-by: Michael Roth +--- + hw/usb/redirect.c | 226 ++++++++++++++++++++++-------------------------------- + 1 file changed, 92 insertions(+), 134 deletions(-) + +diff --git a/hw/usb/redirect.c b/hw/usb/redirect.c +index 6593d50..fd1f8cc 100644 +--- a/hw/usb/redirect.c ++++ b/hw/usb/redirect.c +@@ -43,7 +43,7 @@ + #define EP2I(ep_address) (((ep_address & 0x80) >> 3) | (ep_address & 0x0f)) + #define I2EP(i) (((i & 0x10) << 3) | (i & 0x0f)) + +-typedef struct AsyncURB AsyncURB; ++typedef struct Cancelled Cancelled; + typedef struct USBRedirDevice USBRedirDevice; + + /* Struct to hold buffered packets (iso or int input packets) */ +@@ -86,8 +86,7 @@ struct USBRedirDevice { + int64_t next_attach_time; + struct usbredirparser *parser; + struct endp_data endpoint[MAX_ENDPOINTS]; +- uint32_t packet_id; +- QTAILQ_HEAD(, AsyncURB) asyncq; ++ QTAILQ_HEAD(, Cancelled) cancelled; + /* Data for device filtering */ + struct usb_redir_device_connect_header device_info; + struct usb_redir_interface_info_header interface_info; +@@ -95,10 +94,9 @@ struct USBRedirDevice { + int filter_rules_count; + }; + +-struct AsyncURB { +- USBPacket *packet; +- uint32_t packet_id; +- QTAILQ_ENTRY(AsyncURB)next; ++struct Cancelled { ++ uint64_t id; ++ QTAILQ_ENTRY(Cancelled)next; + }; + + static void usbredir_hello(void *priv, struct usb_redir_hello_header *h); +@@ -238,57 +236,58 @@ static int usbredir_write(void *priv, uint8_t *data, int count) + } + + /* +- * Async and buffered packets helpers ++ * Cancelled and buffered packets helpers + */ + +-static AsyncURB *async_alloc(USBRedirDevice *dev, USBPacket *p) ++static void usbredir_cancel_packet(USBDevice *udev, USBPacket *p) + { +- AsyncURB *aurb = (AsyncURB *) g_malloc0(sizeof(AsyncURB)); +- aurb->packet = p; +- aurb->packet_id = dev->packet_id; +- QTAILQ_INSERT_TAIL(&dev->asyncq, aurb, next); +- dev->packet_id++; ++ USBRedirDevice *dev = DO_UPCAST(USBRedirDevice, dev, udev); ++ Cancelled *c; + +- return aurb; +-} ++ DPRINTF("cancel packet id %"PRIu64"\n", p->id); + +-static void async_free(USBRedirDevice *dev, AsyncURB *aurb) +-{ +- QTAILQ_REMOVE(&dev->asyncq, aurb, next); +- g_free(aurb); ++ c = g_malloc0(sizeof(Cancelled)); ++ c->id = p->id; ++ QTAILQ_INSERT_TAIL(&dev->cancelled, c, next); ++ ++ usbredirparser_send_cancel_data_packet(dev->parser, p->id); ++ usbredirparser_do_write(dev->parser); + } + +-static AsyncURB *async_find(USBRedirDevice *dev, uint32_t packet_id) ++static int usbredir_is_cancelled(USBRedirDevice *dev, uint64_t id) + { +- AsyncURB *aurb; ++ Cancelled *c; ++ ++ if (!dev->dev.attached) { ++ return 1; /* Treat everything as cancelled after a disconnect */ ++ } + +- QTAILQ_FOREACH(aurb, &dev->asyncq, next) { +- if (aurb->packet_id == packet_id) { +- return aurb; ++ QTAILQ_FOREACH(c, &dev->cancelled, next) { ++ if (c->id == id) { ++ QTAILQ_REMOVE(&dev->cancelled, c, next); ++ g_free(c); ++ return 1; + } + } +- DPRINTF("could not find async urb for packet_id %u\n", packet_id); +- return NULL; ++ return 0; + } + +-static void usbredir_cancel_packet(USBDevice *udev, USBPacket *p) ++static USBPacket *usbredir_find_packet_by_id(USBRedirDevice *dev, ++ uint8_t ep, uint64_t id) + { +- USBRedirDevice *dev = DO_UPCAST(USBRedirDevice, dev, udev); +- AsyncURB *aurb; +- +- QTAILQ_FOREACH(aurb, &dev->asyncq, next) { +- if (p != aurb->packet) { +- continue; +- } ++ USBPacket *p; + +- DPRINTF("async cancel id %u\n", aurb->packet_id); +- usbredirparser_send_cancel_data_packet(dev->parser, aurb->packet_id); +- usbredirparser_do_write(dev->parser); ++ if (usbredir_is_cancelled(dev, id)) { ++ return NULL; ++ } + +- /* Mark it as dead */ +- aurb->packet = NULL; +- break; ++ p = usb_ep_find_packet_by_id(&dev->dev, ++ (ep & USB_DIR_IN) ? USB_TOKEN_IN : USB_TOKEN_OUT, ++ ep & 0x0f, id); ++ if (p == NULL) { ++ ERROR("could not find packet with id %"PRIu64"\n", id); + } ++ return p; + } + + static void bufp_alloc(USBRedirDevice *dev, +@@ -484,24 +483,22 @@ static void usbredir_stop_iso_stream(USBRedirDevice *dev, uint8_t ep) + static int usbredir_handle_bulk_data(USBRedirDevice *dev, USBPacket *p, + uint8_t ep) + { +- AsyncURB *aurb = async_alloc(dev, p); + struct usb_redir_bulk_packet_header bulk_packet; + +- DPRINTF("bulk-out ep %02X len %zd id %u\n", ep, +- p->iov.size, aurb->packet_id); ++ DPRINTF("bulk-out ep %02X len %zd id %"PRIu64"\n", ep, p->iov.size, p->id); + + bulk_packet.endpoint = ep; + bulk_packet.length = p->iov.size; + bulk_packet.stream_id = 0; + + if (ep & USB_DIR_IN) { +- usbredirparser_send_bulk_packet(dev->parser, aurb->packet_id, ++ usbredirparser_send_bulk_packet(dev->parser, p->id, + &bulk_packet, NULL, 0); + } else { + uint8_t buf[p->iov.size]; + usb_packet_copy(p, buf, p->iov.size); + usbredir_log_data(dev, "bulk data out:", buf, p->iov.size); +- usbredirparser_send_bulk_packet(dev->parser, aurb->packet_id, ++ usbredirparser_send_bulk_packet(dev->parser, p->id, + &bulk_packet, buf, p->iov.size); + } + usbredirparser_do_write(dev->parser); +@@ -564,19 +561,18 @@ static int usbredir_handle_interrupt_data(USBRedirDevice *dev, + return len; + } else { + /* Output interrupt endpoint, normal async operation */ +- AsyncURB *aurb = async_alloc(dev, p); + struct usb_redir_interrupt_packet_header interrupt_packet; + uint8_t buf[p->iov.size]; + +- DPRINTF("interrupt-out ep %02X len %zd id %u\n", ep, p->iov.size, +- aurb->packet_id); ++ DPRINTF("interrupt-out ep %02X len %zd id %"PRIu64"\n", ep, ++ p->iov.size, p->id); + + interrupt_packet.endpoint = ep; + interrupt_packet.length = p->iov.size; + + usb_packet_copy(p, buf, p->iov.size); + usbredir_log_data(dev, "interrupt data out:", buf, p->iov.size); +- usbredirparser_send_interrupt_packet(dev->parser, aurb->packet_id, ++ usbredirparser_send_interrupt_packet(dev->parser, p->id, + &interrupt_packet, buf, p->iov.size); + usbredirparser_do_write(dev->parser); + return USB_RET_ASYNC; +@@ -630,10 +626,9 @@ static int usbredir_set_config(USBRedirDevice *dev, USBPacket *p, + int config) + { + struct usb_redir_set_configuration_header set_config; +- AsyncURB *aurb = async_alloc(dev, p); + int i; + +- DPRINTF("set config %d id %u\n", config, aurb->packet_id); ++ DPRINTF("set config %d id %"PRIu64"\n", config, p->id); + + for (i = 0; i < MAX_ENDPOINTS; i++) { + switch (dev->endpoint[i].type) { +@@ -650,19 +645,16 @@ static int usbredir_set_config(USBRedirDevice *dev, USBPacket *p, + } + + set_config.configuration = config; +- usbredirparser_send_set_configuration(dev->parser, aurb->packet_id, +- &set_config); ++ usbredirparser_send_set_configuration(dev->parser, p->id, &set_config); + usbredirparser_do_write(dev->parser); + return USB_RET_ASYNC; + } + + static int usbredir_get_config(USBRedirDevice *dev, USBPacket *p) + { +- AsyncURB *aurb = async_alloc(dev, p); +- +- DPRINTF("get config id %u\n", aurb->packet_id); ++ DPRINTF("get config id %"PRIu64"\n", p->id); + +- usbredirparser_send_get_configuration(dev->parser, aurb->packet_id); ++ usbredirparser_send_get_configuration(dev->parser, p->id); + usbredirparser_do_write(dev->parser); + return USB_RET_ASYNC; + } +@@ -671,11 +663,9 @@ static int usbredir_set_interface(USBRedirDevice *dev, USBPacket *p, + int interface, int alt) + { + struct usb_redir_set_alt_setting_header set_alt; +- AsyncURB *aurb = async_alloc(dev, p); + int i; + +- DPRINTF("set interface %d alt %d id %u\n", interface, alt, +- aurb->packet_id); ++ DPRINTF("set interface %d alt %d id %"PRIu64"\n", interface, alt, p->id); + + for (i = 0; i < MAX_ENDPOINTS; i++) { + if (dev->endpoint[i].interface == interface) { +@@ -695,8 +685,7 @@ static int usbredir_set_interface(USBRedirDevice *dev, USBPacket *p, + + set_alt.interface = interface; + set_alt.alt = alt; +- usbredirparser_send_set_alt_setting(dev->parser, aurb->packet_id, +- &set_alt); ++ usbredirparser_send_set_alt_setting(dev->parser, p->id, &set_alt); + usbredirparser_do_write(dev->parser); + return USB_RET_ASYNC; + } +@@ -705,13 +694,11 @@ static int usbredir_get_interface(USBRedirDevice *dev, USBPacket *p, + int interface) + { + struct usb_redir_get_alt_setting_header get_alt; +- AsyncURB *aurb = async_alloc(dev, p); + +- DPRINTF("get interface %d id %u\n", interface, aurb->packet_id); ++ DPRINTF("get interface %d id %"PRIu64"\n", interface, p->id); + + get_alt.interface = interface; +- usbredirparser_send_get_alt_setting(dev->parser, aurb->packet_id, +- &get_alt); ++ usbredirparser_send_get_alt_setting(dev->parser, p->id, &get_alt); + usbredirparser_do_write(dev->parser); + return USB_RET_ASYNC; + } +@@ -721,7 +708,6 @@ static int usbredir_handle_control(USBDevice *udev, USBPacket *p, + { + USBRedirDevice *dev = DO_UPCAST(USBRedirDevice, dev, udev); + struct usb_redir_control_packet_header control_packet; +- AsyncURB *aurb; + + /* Special cases for certain standard device requests */ + switch (request) { +@@ -739,13 +725,10 @@ static int usbredir_handle_control(USBDevice *udev, USBPacket *p, + return usbredir_get_interface(dev, p, index); + } + +- /* "Normal" ctrl requests */ +- aurb = async_alloc(dev, p); +- +- /* Note request is (bRequestType << 8) | bRequest */ +- DPRINTF("ctrl-out type 0x%x req 0x%x val 0x%x index %d len %d id %u\n", +- request >> 8, request & 0xff, value, index, length, +- aurb->packet_id); ++ /* Normal ctrl requests, note request is (bRequestType << 8) | bRequest */ ++ DPRINTF( ++ "ctrl-out type 0x%x req 0x%x val 0x%x index %d len %d id %"PRIu64"\n", ++ request >> 8, request & 0xff, value, index, length, p->id); + + control_packet.request = request & 0xFF; + control_packet.requesttype = request >> 8; +@@ -755,11 +738,11 @@ static int usbredir_handle_control(USBDevice *udev, USBPacket *p, + control_packet.length = length; + + if (control_packet.requesttype & USB_DIR_IN) { +- usbredirparser_send_control_packet(dev->parser, aurb->packet_id, ++ usbredirparser_send_control_packet(dev->parser, p->id, + &control_packet, NULL, 0); + } else { + usbredir_log_data(dev, "ctrl data out:", data, length); +- usbredirparser_send_control_packet(dev->parser, aurb->packet_id, ++ usbredirparser_send_control_packet(dev->parser, p->id, + &control_packet, data, length); + } + usbredirparser_do_write(dev->parser); +@@ -913,7 +896,7 @@ static int usbredir_initfn(USBDevice *udev) + dev->chardev_close_bh = qemu_bh_new(usbredir_chardev_close_bh, dev); + dev->attach_timer = qemu_new_timer_ms(vm_clock, usbredir_do_attach, dev); + +- QTAILQ_INIT(&dev->asyncq); ++ QTAILQ_INIT(&dev->cancelled); + for (i = 0; i < MAX_ENDPOINTS; i++) { + QTAILQ_INIT(&dev->endpoint[i].bufpq); + } +@@ -932,11 +915,12 @@ static int usbredir_initfn(USBDevice *udev) + + static void usbredir_cleanup_device_queues(USBRedirDevice *dev) + { +- AsyncURB *aurb, *next_aurb; ++ Cancelled *c, *next_c; + int i; + +- QTAILQ_FOREACH_SAFE(aurb, &dev->asyncq, next, next_aurb) { +- async_free(dev, aurb); ++ QTAILQ_FOREACH_SAFE(c, &dev->cancelled, next, next_c) { ++ QTAILQ_REMOVE(&dev->cancelled, c, next); ++ g_free(c); + } + for (i = 0; i < MAX_ENDPOINTS; i++) { + usbredir_free_bufpq(dev, I2EP(i)); +@@ -1202,33 +1186,28 @@ static void usbredir_configuration_status(void *priv, uint32_t id, + struct usb_redir_configuration_status_header *config_status) + { + USBRedirDevice *dev = priv; +- AsyncURB *aurb; ++ USBPacket *p; + int len = 0; + + DPRINTF("set config status %d config %d id %u\n", config_status->status, + config_status->configuration, id); + +- aurb = async_find(dev, id); +- if (!aurb) { +- return; +- } +- if (aurb->packet) { ++ p = usbredir_find_packet_by_id(dev, 0, id); ++ if (p) { + if (dev->dev.setup_buf[0] & USB_DIR_IN) { + dev->dev.data_buf[0] = config_status->configuration; + len = 1; + } +- aurb->packet->result = +- usbredir_handle_status(dev, config_status->status, len); +- usb_generic_async_ctrl_complete(&dev->dev, aurb->packet); ++ p->result = usbredir_handle_status(dev, config_status->status, len); ++ usb_generic_async_ctrl_complete(&dev->dev, p); + } +- async_free(dev, aurb); + } + + static void usbredir_alt_setting_status(void *priv, uint32_t id, + struct usb_redir_alt_setting_status_header *alt_setting_status) + { + USBRedirDevice *dev = priv; +- AsyncURB *aurb; ++ USBPacket *p; + int len = 0; + + DPRINTF("alt status %d intf %d alt %d id: %u\n", +@@ -1236,20 +1215,16 @@ static void usbredir_alt_setting_status(void *priv, uint32_t id, + alt_setting_status->interface, + alt_setting_status->alt, id); + +- aurb = async_find(dev, id); +- if (!aurb) { +- return; +- } +- if (aurb->packet) { ++ p = usbredir_find_packet_by_id(dev, 0, id); ++ if (p) { + if (dev->dev.setup_buf[0] & USB_DIR_IN) { + dev->dev.data_buf[0] = alt_setting_status->alt; + len = 1; + } +- aurb->packet->result = ++ p->result = + usbredir_handle_status(dev, alt_setting_status->status, len); +- usb_generic_async_ctrl_complete(&dev->dev, aurb->packet); ++ usb_generic_async_ctrl_complete(&dev->dev, p); + } +- async_free(dev, aurb); + } + + static void usbredir_iso_stream_status(void *priv, uint32_t id, +@@ -1304,19 +1279,14 @@ static void usbredir_control_packet(void *priv, uint32_t id, + uint8_t *data, int data_len) + { + USBRedirDevice *dev = priv; ++ USBPacket *p; + int len = control_packet->length; +- AsyncURB *aurb; + + DPRINTF("ctrl-in status %d len %d id %u\n", control_packet->status, + len, id); + +- aurb = async_find(dev, id); +- if (!aurb) { +- free(data); +- return; +- } +- +- if (aurb->packet) { ++ p = usbredir_find_packet_by_id(dev, 0, id); ++ if (p) { + len = usbredir_handle_status(dev, control_packet->status, len); + if (len > 0) { + usbredir_log_data(dev, "ctrl data in:", data, data_len); +@@ -1328,10 +1298,9 @@ static void usbredir_control_packet(void *priv, uint32_t id, + len = USB_RET_STALL; + } + } +- aurb->packet->result = len; +- usb_generic_async_ctrl_complete(&dev->dev, aurb->packet); ++ p->result = len; ++ usb_generic_async_ctrl_complete(&dev->dev, p); + } +- async_free(dev, aurb); + free(data); + } + +@@ -1342,33 +1311,27 @@ static void usbredir_bulk_packet(void *priv, uint32_t id, + USBRedirDevice *dev = priv; + uint8_t ep = bulk_packet->endpoint; + int len = bulk_packet->length; +- AsyncURB *aurb; ++ USBPacket *p; + + DPRINTF("bulk-in status %d ep %02X len %d id %u\n", bulk_packet->status, + ep, len, id); + +- aurb = async_find(dev, id); +- if (!aurb) { +- free(data); +- return; +- } +- +- if (aurb->packet) { ++ p = usbredir_find_packet_by_id(dev, ep, id); ++ if (p) { + len = usbredir_handle_status(dev, bulk_packet->status, len); + if (len > 0) { + usbredir_log_data(dev, "bulk data in:", data, data_len); +- if (data_len <= aurb->packet->iov.size) { +- usb_packet_copy(aurb->packet, data, data_len); ++ if (data_len <= p->iov.size) { ++ usb_packet_copy(p, data, data_len); + } else { + ERROR("bulk buffer too small (%d > %zd)\n", data_len, +- aurb->packet->iov.size); ++ p->iov.size); + len = USB_RET_STALL; + } + } +- aurb->packet->result = len; +- usb_packet_complete(&dev->dev, aurb->packet); ++ p->result = len; ++ usb_packet_complete(&dev->dev, p); + } +- async_free(dev, aurb); + free(data); + } + +@@ -1426,17 +1389,12 @@ static void usbredir_interrupt_packet(void *priv, uint32_t id, + } else { + int len = interrupt_packet->length; + +- AsyncURB *aurb = async_find(dev, id); +- if (!aurb) { +- return; +- } +- +- if (aurb->packet) { +- aurb->packet->result = usbredir_handle_status(dev, ++ USBPacket *p = usbredir_find_packet_by_id(dev, ep, id); ++ if (p) { ++ p->result = usbredir_handle_status(dev, + interrupt_packet->status, len); +- usb_packet_complete(&dev->dev, aurb->packet); ++ usb_packet_complete(&dev->dev, p); + } +- async_free(dev, aurb); + } + } + +-- +1.7.12.1 + diff --git a/0148-usb-redir-Return-babble-when-getting-more-bulk-data-.patch b/0148-usb-redir-Return-babble-when-getting-more-bulk-data-.patch new file mode 100644 index 0000000..4c4e98b --- /dev/null +++ b/0148-usb-redir-Return-babble-when-getting-more-bulk-data-.patch @@ -0,0 +1,37 @@ +From 138e9d997e487dafbf686e0e1eba44a8b26dcaf7 Mon Sep 17 00:00:00 2001 +From: Hans de Goede +Date: Tue, 28 Aug 2012 11:33:47 +0200 +Subject: [PATCH] usb-redir: Return babble when getting more bulk data then + requested + +Babble is the appropriate error in this case (rather then signalling a stall). + +Signed-off-by: Hans de Goede +Signed-off-by: Gerd Hoffmann +(cherry picked from commit 2979a36183a3902cd75665e7c6bbc8668668fd17) + +Signed-off-by: Michael Roth +--- + hw/usb/redirect.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/hw/usb/redirect.c b/hw/usb/redirect.c +index fd1f8cc..ee75217 100644 +--- a/hw/usb/redirect.c ++++ b/hw/usb/redirect.c +@@ -1324,9 +1324,9 @@ static void usbredir_bulk_packet(void *priv, uint32_t id, + if (data_len <= p->iov.size) { + usb_packet_copy(p, data, data_len); + } else { +- ERROR("bulk buffer too small (%d > %zd)\n", data_len, +- p->iov.size); +- len = USB_RET_STALL; ++ ERROR("bulk got more data then requested (%d > %zd)\n", ++ data_len, p->iov.size); ++ len = USB_RET_BABBLE; + } + } + p->result = len; +-- +1.7.12.1 + diff --git a/0149-Better-name-usb-braille-device.patch b/0149-Better-name-usb-braille-device.patch new file mode 100644 index 0000000..00c8599 --- /dev/null +++ b/0149-Better-name-usb-braille-device.patch @@ -0,0 +1,33 @@ +From 23d25cd58aa7da678cad0ad98d52efe37d0be4e6 Mon Sep 17 00:00:00 2001 +From: Samuel Thibault +Date: Thu, 23 Aug 2012 09:59:27 +0200 +Subject: [PATCH] Better name usb braille device + +Windows users need to know that they have to use the Baum driver to make +the qemu braille device work. + +Signed-off-by: Samuel Thibault +Signed-off-by: Gerd Hoffmann +(cherry picked from commit 2964cd9bfa5100e433471d3e3fedcc9d62891894) + +Signed-off-by: Michael Roth +--- + 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 8aa6552..69b6e48 100644 +--- a/hw/usb/dev-serial.c ++++ b/hw/usb/dev-serial.c +@@ -113,7 +113,7 @@ enum { + static const USBDescStrings desc_strings = { + [STR_MANUFACTURER] = "QEMU", + [STR_PRODUCT_SERIAL] = "QEMU USB SERIAL", +- [STR_PRODUCT_BRAILLE] = "QEMU USB BRAILLE", ++ [STR_PRODUCT_BRAILLE] = "QEMU USB BAUM BRAILLE", + [STR_SERIALNUMBER] = "1", + }; + +-- +1.7.12.1 + diff --git a/0150-usb-audio-fix-usb-version.patch b/0150-usb-audio-fix-usb-version.patch new file mode 100644 index 0000000..ceeb70d --- /dev/null +++ b/0150-usb-audio-fix-usb-version.patch @@ -0,0 +1,32 @@ +From 3f8a570db1637c0e7e2dd7a3bd997c92c69efc65 Mon Sep 17 00:00:00 2001 +From: Gerd Hoffmann +Date: Tue, 28 Aug 2012 16:43:34 +0200 +Subject: [PATCH] usb-audio: fix usb version + +usb-audio is a full speed (1.1) device, +but bcdUSB claims it is usb 2.0. Fix it. + +Signed-off-by: Gerd Hoffmann +(cherry picked from commit 2bbd086c41a00dc4384727ec895a94890c688eb5) + +Signed-off-by: Michael Roth +--- + hw/usb/dev-audio.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/hw/usb/dev-audio.c b/hw/usb/dev-audio.c +index 79b75fb..2594c78 100644 +--- a/hw/usb/dev-audio.c ++++ b/hw/usb/dev-audio.c +@@ -217,7 +217,7 @@ static const USBDescIface desc_iface[] = { + }; + + static const USBDescDevice desc_device = { +- .bcdUSB = 0x0200, ++ .bcdUSB = 0x0100, + .bMaxPacketSize0 = 64, + .bNumConfigurations = 1, + .confs = (USBDescConfig[]) { +-- +1.7.12.1 + diff --git a/0151-xhci-rip-out-background-transfer-code.patch b/0151-xhci-rip-out-background-transfer-code.patch new file mode 100644 index 0000000..e728029 --- /dev/null +++ b/0151-xhci-rip-out-background-transfer-code.patch @@ -0,0 +1,327 @@ +From f9416f401c9eac3f69b4705a999c6ea1ff457016 Mon Sep 17 00:00:00 2001 +From: Gerd Hoffmann +Date: Fri, 17 Aug 2012 14:05:21 +0200 +Subject: [PATCH] xhci: rip out background transfer code + +original xhci code (the one which used libusb directly) used to use +'background transfers' for iso streams. In upstream qemu the iso +stream buffering is handled by usb-host & usb-redir, so we will +never ever need this. It has been left in as reference, but is dead +code anyway. Rip it out. + +Signed-off-by: Gerd Hoffmann +(cherry picked from commit 331e9406f152b6bae6859a153d36e5076c58901d) + +Signed-off-by: Michael Roth +--- + hw/usb/hcd-xhci.c | 223 +----------------------------------------------------- + 1 file changed, 4 insertions(+), 219 deletions(-) + +diff --git a/hw/usb/hcd-xhci.c b/hw/usb/hcd-xhci.c +index 3eb27fa..c0a2476 100644 +--- a/hw/usb/hcd-xhci.c ++++ b/hw/usb/hcd-xhci.c +@@ -45,8 +45,6 @@ + #define MAXPORTS (USB2_PORTS+USB3_PORTS) + + #define TD_QUEUE 24 +-#define BG_XFERS 8 +-#define BG_PKTS 8 + + /* Very pessimistic, let's hope it's enough for all cases */ + #define EV_QUEUE (((3*TD_QUEUE)+16)*MAXSLOTS) +@@ -311,13 +309,11 @@ typedef struct XHCITransfer { + bool running_retry; + bool cancelled; + bool complete; +- bool backgrounded; + unsigned int iso_pkts; + unsigned int slotid; + unsigned int epid; + bool in_xfer; + bool iso_xfer; +- bool bg_xfer; + + unsigned int trb_count; + unsigned int trb_alloced; +@@ -340,14 +336,9 @@ typedef struct XHCIEPContext { + unsigned int comp_xfer; + XHCITransfer transfers[TD_QUEUE]; + XHCITransfer *retry; +- bool bg_running; +- bool bg_updating; +- unsigned int next_bg; +- XHCITransfer bg_transfers[BG_XFERS]; + EPType type; + dma_addr_t pctx; + unsigned int max_psize; +- bool has_bg; + uint32_t state; + } XHCIEPContext; + +@@ -866,10 +857,6 @@ static TRBCCode xhci_enable_ep(XHCIState *xhci, unsigned int slotid, + epctx->pctx = pctx; + epctx->max_psize = ctx[1]>>16; + epctx->max_psize *= 1+((ctx[1]>>8)&0xff); +- epctx->has_bg = false; +- if (epctx->type == ET_ISO_IN) { +- epctx->has_bg = true; +- } + DPRINTF("xhci: endpoint %d.%d max transaction (burst) size is %d\n", + epid/2, epid%2, epctx->max_psize); + for (i = 0; i < ARRAY_SIZE(epctx->transfers); i++) { +@@ -916,9 +903,6 @@ static int xhci_ep_nuke_xfers(XHCIState *xhci, unsigned int slotid, + t->running_retry = 0; + epctx->retry = NULL; + } +- if (t->backgrounded) { +- t->backgrounded = 0; +- } + if (t->trbs) { + g_free(t->trbs); + } +@@ -932,25 +916,6 @@ static int xhci_ep_nuke_xfers(XHCIState *xhci, unsigned int slotid, + t->data_length = t->data_alloced = 0; + xferi = (xferi + 1) % TD_QUEUE; + } +- if (epctx->has_bg) { +- xferi = epctx->next_bg; +- for (i = 0; i < BG_XFERS; i++) { +- XHCITransfer *t = &epctx->bg_transfers[xferi]; +- if (t->running_async) { +- usb_cancel_packet(&t->packet); +- t->running_async = 0; +- t->cancelled = 1; +- DPRINTF("xhci: cancelling bg transfer %d, waiting for it to complete...\n", i); +- killed++; +- } +- if (t->data) { +- g_free(t->data); +- } +- +- t->data = NULL; +- xferi = (xferi + 1) % BG_XFERS; +- } +- } + return killed; + } + +@@ -1231,160 +1196,6 @@ static void xhci_stall_ep(XHCITransfer *xfer) + static int xhci_submit(XHCIState *xhci, XHCITransfer *xfer, + XHCIEPContext *epctx); + +-static void xhci_bg_update(XHCIState *xhci, XHCIEPContext *epctx) +-{ +- if (epctx->bg_updating) { +- return; +- } +- DPRINTF("xhci_bg_update(%p, %p)\n", xhci, epctx); +- assert(epctx->has_bg); +- DPRINTF("xhci: fg=%d bg=%d\n", epctx->comp_xfer, epctx->next_bg); +- epctx->bg_updating = 1; +- while (epctx->transfers[epctx->comp_xfer].backgrounded && +- epctx->bg_transfers[epctx->next_bg].complete) { +- XHCITransfer *fg = &epctx->transfers[epctx->comp_xfer]; +- XHCITransfer *bg = &epctx->bg_transfers[epctx->next_bg]; +-#if 0 +- DPRINTF("xhci: completing fg %d from bg %d.%d (stat: %d)\n", +- epctx->comp_xfer, epctx->next_bg, bg->cur_pkt, +- bg->usbxfer->iso_packet_desc[bg->cur_pkt].status +- ); +-#endif +- assert(epctx->type == ET_ISO_IN); +- assert(bg->iso_xfer); +- assert(bg->in_xfer); +- uint8_t *p = bg->data + bg->cur_pkt * bg->pktsize; +-#if 0 +- int len = bg->usbxfer->iso_packet_desc[bg->cur_pkt].actual_length; +- fg->status = libusb_to_ccode(bg->usbxfer->iso_packet_desc[bg->cur_pkt].status); +-#else +- int len = 0; +- FIXME(); +-#endif +- fg->complete = 1; +- fg->backgrounded = 0; +- +- if (fg->status == CC_STALL_ERROR) { +- xhci_stall_ep(fg); +- } +- +- xhci_xfer_data(fg, p, len, 1, 0, 1); +- +- epctx->comp_xfer++; +- if (epctx->comp_xfer == TD_QUEUE) { +- epctx->comp_xfer = 0; +- } +- DPRINTF("next fg xfer: %d\n", epctx->comp_xfer); +- bg->cur_pkt++; +- if (bg->cur_pkt == bg->pkts) { +- bg->complete = 0; +- if (xhci_submit(xhci, bg, epctx) < 0) { +- fprintf(stderr, "xhci: bg resubmit failed\n"); +- } +- epctx->next_bg++; +- if (epctx->next_bg == BG_XFERS) { +- epctx->next_bg = 0; +- } +- DPRINTF("next bg xfer: %d\n", epctx->next_bg); +- +- xhci_kick_ep(xhci, fg->slotid, fg->epid); +- } +- } +- epctx->bg_updating = 0; +-} +- +-#if 0 +-static void xhci_xfer_cb(struct libusb_transfer *transfer) +-{ +- XHCIState *xhci; +- XHCITransfer *xfer; +- +- xfer = (XHCITransfer *)transfer->user_data; +- xhci = xfer->xhci; +- +- DPRINTF("xhci_xfer_cb(slot=%d, ep=%d, status=%d)\n", xfer->slotid, +- xfer->epid, transfer->status); +- +- assert(xfer->slotid >= 1 && xfer->slotid <= MAXSLOTS); +- assert(xfer->epid >= 1 && xfer->epid <= 31); +- +- if (xfer->cancelled) { +- DPRINTF("xhci: transfer cancelled, not reporting anything\n"); +- xfer->running = 0; +- return; +- } +- +- XHCIEPContext *epctx; +- XHCISlot *slot; +- slot = &xhci->slots[xfer->slotid-1]; +- assert(slot->eps[xfer->epid-1]); +- epctx = slot->eps[xfer->epid-1]; +- +- if (xfer->bg_xfer) { +- DPRINTF("xhci: background transfer, updating\n"); +- xfer->complete = 1; +- xfer->running = 0; +- xhci_bg_update(xhci, epctx); +- return; +- } +- +- if (xfer->iso_xfer) { +- transfer->status = transfer->iso_packet_desc[0].status; +- transfer->actual_length = transfer->iso_packet_desc[0].actual_length; +- } +- +- xfer->status = libusb_to_ccode(transfer->status); +- +- xfer->complete = 1; +- xfer->running = 0; +- +- if (transfer->status == LIBUSB_TRANSFER_STALL) +- xhci_stall_ep(xhci, epctx, xfer); +- +- DPRINTF("xhci: transfer actual length = %d\n", transfer->actual_length); +- +- if (xfer->in_xfer) { +- if (xfer->epid == 1) { +- xhci_xfer_data(xhci, xfer, xfer->data + 8, +- transfer->actual_length, 1, 0, 1); +- } else { +- xhci_xfer_data(xhci, xfer, xfer->data, +- transfer->actual_length, 1, 0, 1); +- } +- } else { +- xhci_xfer_data(xhci, xfer, NULL, transfer->actual_length, 0, 0, 1); +- } +- +- xhci_kick_ep(xhci, xfer->slotid, xfer->epid); +-} +- +-static int xhci_hle_control(XHCIState *xhci, XHCITransfer *xfer, +- uint8_t bmRequestType, uint8_t bRequest, +- uint16_t wValue, uint16_t wIndex, uint16_t wLength) +-{ +- uint16_t type_req = (bmRequestType << 8) | bRequest; +- +- switch (type_req) { +- case 0x0000 | USB_REQ_SET_CONFIGURATION: +- DPRINTF("xhci: HLE switch configuration\n"); +- return xhci_switch_config(xhci, xfer->slotid, wValue) == 0; +- case 0x0100 | USB_REQ_SET_INTERFACE: +- DPRINTF("xhci: HLE set interface altsetting\n"); +- return xhci_set_iface_alt(xhci, xfer->slotid, wIndex, wValue) == 0; +- case 0x0200 | USB_REQ_CLEAR_FEATURE: +- if (wValue == 0) { // endpoint halt +- DPRINTF("xhci: HLE clear halt\n"); +- return xhci_clear_halt(xhci, xfer->slotid, wIndex); +- } +- case 0x0000 | USB_REQ_SET_ADDRESS: +- fprintf(stderr, "xhci: warn: illegal SET_ADDRESS request\n"); +- return 0; +- default: +- return 0; +- } +-} +-#endif +- + static int xhci_setup_packet(XHCITransfer *xfer, USBDevice *dev) + { + USBEndpoint *ep; +@@ -1559,9 +1370,7 @@ static int xhci_submit(XHCIState *xhci, XHCITransfer *xfer, XHCIEPContext *epctx + xfer->data_alloced = xfer->data_length; + } + if (epctx->type == ET_ISO_IN || epctx->type == ET_ISO_OUT) { +- if (!xfer->bg_xfer) { +- xfer->pkts = 1; +- } ++ xfer->pkts = 1; + } else { + xfer->pkts = 0; + } +@@ -1620,32 +1429,8 @@ static int xhci_fire_transfer(XHCIState *xhci, XHCITransfer *xfer, XHCIEPContext + + trace_usb_xhci_xfer_start(xfer, xfer->slotid, xfer->epid, length); + +- if (!epctx->has_bg) { +- xfer->data_length = length; +- xfer->backgrounded = 0; +- return xhci_submit(xhci, xfer, epctx); +- } else { +- if (!epctx->bg_running) { +- for (i = 0; i < BG_XFERS; i++) { +- XHCITransfer *t = &epctx->bg_transfers[i]; +- t->xhci = xhci; +- t->epid = xfer->epid; +- t->slotid = xfer->slotid; +- t->pkts = BG_PKTS; +- t->pktsize = epctx->max_psize; +- t->data_length = t->pkts * t->pktsize; +- t->bg_xfer = 1; +- if (xhci_submit(xhci, t, epctx) < 0) { +- fprintf(stderr, "xhci: bg submit failed\n"); +- return -1; +- } +- } +- epctx->bg_running = 1; +- } +- xfer->backgrounded = 1; +- xhci_bg_update(xhci, epctx); +- return 0; +- } ++ xfer->data_length = length; ++ return xhci_submit(xhci, xfer, epctx); + } + + static void xhci_kick_ep(XHCIState *xhci, unsigned int slotid, unsigned int epid) +@@ -1695,7 +1480,7 @@ static void xhci_kick_ep(XHCIState *xhci, unsigned int slotid, unsigned int epid + + while (1) { + XHCITransfer *xfer = &epctx->transfers[epctx->next_xfer]; +- if (xfer->running_async || xfer->running_retry || xfer->backgrounded) { ++ if (xfer->running_async || xfer->running_retry) { + break; + } + length = xhci_ring_chain_length(xhci, &epctx->ring); +-- +1.7.12.1 + diff --git a/0152-xhci-drop-buffering.patch b/0152-xhci-drop-buffering.patch new file mode 100644 index 0000000..af60c86 --- /dev/null +++ b/0152-xhci-drop-buffering.patch @@ -0,0 +1,386 @@ +From 985807ab66338c6a9cab8d68a2b52b0cff0423ee Mon Sep 17 00:00:00 2001 +From: Gerd Hoffmann +Date: Fri, 17 Aug 2012 11:04:36 +0200 +Subject: [PATCH] xhci: drop buffering + +This patch splits the xhci_xfer_data function into three. +The xhci_xfer_data function used to do does two things: + + (1) copy transfer data between guest memory and a temporary buffer. + (2) report transfer results to the guest using events. + +Now we three functions to handle this: + + (1) xhci_xfer_map creates a scatter list for the transfer and + uses that (instead of the temporary buffer) to build a + USBPacket. + (2) xhci_xfer_unmap undoes the mapping. + (3) xhci_xfer_report sends out events. + +The patch also fixes reporting of transaction errors which must be +reported unconditinally, not only in case the guest asks for it +using the ISP flag. + +[ v2: fix warning ] + +Signed-off-by: Gerd Hoffmann +(cherry picked from commit d5a15814b413869667b2a3215772986885be574a) + +Signed-off-by: Michael Roth +--- + hw/usb/hcd-xhci.c | 185 +++++++++++++++++++++--------------------------------- + trace-events | 2 +- + 2 files changed, 72 insertions(+), 115 deletions(-) + +diff --git a/hw/usb/hcd-xhci.c b/hw/usb/hcd-xhci.c +index c0a2476..446d692 100644 +--- a/hw/usb/hcd-xhci.c ++++ b/hw/usb/hcd-xhci.c +@@ -305,6 +305,7 @@ typedef struct XHCIState XHCIState; + typedef struct XHCITransfer { + XHCIState *xhci; + USBPacket packet; ++ QEMUSGList sgl; + bool running_async; + bool running_retry; + bool cancelled; +@@ -319,10 +320,6 @@ typedef struct XHCITransfer { + unsigned int trb_alloced; + XHCITRB *trbs; + +- unsigned int data_length; +- unsigned int data_alloced; +- uint8_t *data; +- + TRBCCode status; + + unsigned int pkts; +@@ -906,14 +903,9 @@ static int xhci_ep_nuke_xfers(XHCIState *xhci, unsigned int slotid, + if (t->trbs) { + g_free(t->trbs); + } +- if (t->data) { +- g_free(t->data); +- } + + t->trbs = NULL; +- t->data = NULL; + t->trb_count = t->trb_alloced = 0; +- t->data_length = t->data_alloced = 0; + xferi = (xferi + 1) % TD_QUEUE; + } + return killed; +@@ -1072,24 +1064,13 @@ static TRBCCode xhci_set_ep_dequeue(XHCIState *xhci, unsigned int slotid, + return CC_SUCCESS; + } + +-static int xhci_xfer_data(XHCITransfer *xfer, uint8_t *data, +- unsigned int length, bool in_xfer, bool out_xfer, +- bool report) ++static int xhci_xfer_map(XHCITransfer *xfer) + { +- int i; +- uint32_t edtla = 0; +- unsigned int transferred = 0; +- unsigned int left = length; +- bool reported = 0; +- bool shortpkt = 0; +- XHCIEvent event = {ER_TRANSFER, CC_SUCCESS}; ++ int in_xfer = (xfer->packet.pid == USB_TOKEN_IN); + XHCIState *xhci = xfer->xhci; ++ int i; + +- DPRINTF("xhci_xfer_data(len=%d, in_xfer=%d, out_xfer=%d, report=%d)\n", +- length, in_xfer, out_xfer, report); +- +- assert(!(in_xfer && out_xfer)); +- ++ pci_dma_sglist_init(&xfer->sgl, &xhci->pci_dev, xfer->trb_count); + for (i = 0; i < xfer->trb_count; i++) { + XHCITRB *trb = &xfer->trbs[i]; + dma_addr_t addr; +@@ -1099,54 +1080,70 @@ static int xhci_xfer_data(XHCITransfer *xfer, uint8_t *data, + case TR_DATA: + if ((!(trb->control & TRB_TR_DIR)) != (!in_xfer)) { + fprintf(stderr, "xhci: data direction mismatch for TR_DATA\n"); +- xhci_die(xhci); +- return transferred; ++ goto err; + } + /* fallthrough */ + case TR_NORMAL: + case TR_ISOCH: + addr = xhci_mask64(trb->parameter); + chunk = trb->status & 0x1ffff; ++ if (trb->control & TRB_TR_IDT) { ++ if (chunk > 8 || in_xfer) { ++ fprintf(stderr, "xhci: invalid immediate data TRB\n"); ++ goto err; ++ } ++ qemu_sglist_add(&xfer->sgl, trb->addr, chunk); ++ } else { ++ qemu_sglist_add(&xfer->sgl, addr, chunk); ++ } ++ break; ++ } ++ } ++ ++ usb_packet_map(&xfer->packet, &xfer->sgl); ++ return 0; ++ ++err: ++ qemu_sglist_destroy(&xfer->sgl); ++ xhci_die(xhci); ++ return -1; ++} ++ ++static void xhci_xfer_unmap(XHCITransfer *xfer) ++{ ++ usb_packet_unmap(&xfer->packet, &xfer->sgl); ++ qemu_sglist_destroy(&xfer->sgl); ++} ++ ++static void xhci_xfer_report(XHCITransfer *xfer) ++{ ++ uint32_t edtla = 0; ++ unsigned int left; ++ bool reported = 0; ++ bool shortpkt = 0; ++ XHCIEvent event = {ER_TRANSFER, CC_SUCCESS}; ++ XHCIState *xhci = xfer->xhci; ++ int i; ++ ++ left = xfer->packet.result < 0 ? 0 : xfer->packet.result; ++ ++ for (i = 0; i < xfer->trb_count; i++) { ++ XHCITRB *trb = &xfer->trbs[i]; ++ unsigned int chunk = 0; ++ ++ switch (TRB_TYPE(*trb)) { ++ case TR_DATA: ++ case TR_NORMAL: ++ case TR_ISOCH: ++ chunk = trb->status & 0x1ffff; + if (chunk > left) { + chunk = left; +- shortpkt = 1; +- } +- if (in_xfer || out_xfer) { +- if (trb->control & TRB_TR_IDT) { +- uint64_t idata; +- if (chunk > 8 || in_xfer) { +- fprintf(stderr, "xhci: invalid immediate data TRB\n"); +- xhci_die(xhci); +- return transferred; +- } +- idata = le64_to_cpu(trb->parameter); +- memcpy(data, &idata, chunk); +- } else { +- DPRINTF("xhci_xfer_data: r/w(%d) %d bytes at " +- DMA_ADDR_FMT "\n", in_xfer, chunk, addr); +- if (in_xfer) { +- pci_dma_write(&xhci->pci_dev, addr, data, chunk); +- } else { +- pci_dma_read(&xhci->pci_dev, addr, data, chunk); +- } +-#ifdef DEBUG_DATA +- unsigned int count = chunk; +- int i; +- if (count > 16) { +- count = 16; +- } +- DPRINTF(" ::"); +- for (i = 0; i < count; i++) { +- DPRINTF(" %02x", data[i]); +- } +- DPRINTF("\n"); +-#endif ++ if (xfer->status == CC_SUCCESS) { ++ shortpkt = 1; + } + } + left -= chunk; +- data += chunk; + edtla += chunk; +- transferred += chunk; + break; + case TR_STATUS: + reported = 0; +@@ -1154,8 +1151,9 @@ static int xhci_xfer_data(XHCITransfer *xfer, uint8_t *data, + break; + } + +- if (report && !reported && (trb->control & TRB_TR_IOC || +- (shortpkt && (trb->control & TRB_TR_ISP)))) { ++ if (!reported && ((trb->control & TRB_TR_IOC) || ++ (shortpkt && (trb->control & TRB_TR_ISP)) || ++ (xfer->status != CC_SUCCESS))) { + event.slotid = xfer->slotid; + event.epid = xfer->epid; + event.length = (trb->status & 0x1ffff) - chunk; +@@ -1175,9 +1173,11 @@ static int xhci_xfer_data(XHCITransfer *xfer, uint8_t *data, + } + xhci_event(xhci, &event); + reported = 1; ++ if (xfer->status != CC_SUCCESS) { ++ return; ++ } + } + } +- return transferred; + } + + static void xhci_stall_ep(XHCITransfer *xfer) +@@ -1204,7 +1204,7 @@ static int xhci_setup_packet(XHCITransfer *xfer, USBDevice *dev) + dir = xfer->in_xfer ? USB_TOKEN_IN : USB_TOKEN_OUT; + ep = usb_ep_get(dev, dir, xfer->epid >> 1); + usb_packet_setup(&xfer->packet, dir, ep, xfer->trbs[0].addr); +- usb_packet_addbuf(&xfer->packet, xfer->data, xfer->data_length); ++ xhci_xfer_map(xfer); + DPRINTF("xhci: setup packet pid 0x%x addr %d ep %d\n", + xfer->packet.pid, dev->addr, ep->nr); + return 0; +@@ -1230,12 +1230,13 @@ static int xhci_complete_packet(XHCITransfer *xfer, int ret) + xfer->running_async = 0; + xfer->running_retry = 0; + xfer->complete = 1; ++ xhci_xfer_unmap(xfer); + } + + if (ret >= 0) { +- xfer->status = CC_SUCCESS; +- xhci_xfer_data(xfer, xfer->data, ret, xfer->in_xfer, 0, 1); + trace_usb_xhci_xfer_success(xfer, ret); ++ xfer->status = CC_SUCCESS; ++ xhci_xfer_report(xfer); + return 0; + } + +@@ -1244,12 +1245,12 @@ static int xhci_complete_packet(XHCITransfer *xfer, int ret) + switch (ret) { + case USB_RET_NODEV: + xfer->status = CC_USB_TRANSACTION_ERROR; +- xhci_xfer_data(xfer, xfer->data, 0, xfer->in_xfer, 0, 1); ++ xhci_xfer_report(xfer); + xhci_stall_ep(xfer); + break; + case USB_RET_STALL: + xfer->status = CC_STALL_ERROR; +- xhci_xfer_data(xfer, xfer->data, 0, xfer->in_xfer, 0, 1); ++ xhci_xfer_report(xfer); + xhci_stall_ep(xfer); + break; + default: +@@ -1271,7 +1272,6 @@ static int xhci_fire_ctl_transfer(XHCIState *xhci, XHCITransfer *xfer) + { + XHCITRB *trb_setup, *trb_status; + uint8_t bmRequestType; +- uint16_t wLength; + XHCIPort *port; + USBDevice *dev; + int ret; +@@ -1279,8 +1279,7 @@ static int xhci_fire_ctl_transfer(XHCIState *xhci, XHCITransfer *xfer) + trb_setup = &xfer->trbs[0]; + trb_status = &xfer->trbs[xfer->trb_count-1]; + +- trace_usb_xhci_xfer_start(xfer, xfer->slotid, xfer->epid, +- trb_setup->parameter >> 48); ++ trace_usb_xhci_xfer_start(xfer, xfer->slotid, xfer->epid); + + /* at most one Event Data TRB allowed after STATUS */ + if (TRB_TYPE(*trb_status) == TR_EVDATA && xfer->trb_count > 2) { +@@ -1309,19 +1308,6 @@ static int xhci_fire_ctl_transfer(XHCIState *xhci, XHCITransfer *xfer) + } + + bmRequestType = trb_setup->parameter; +- wLength = trb_setup->parameter >> 48; +- +- if (xfer->data && xfer->data_alloced < wLength) { +- xfer->data_alloced = 0; +- g_free(xfer->data); +- xfer->data = NULL; +- } +- if (!xfer->data) { +- DPRINTF("xhci: alloc %d bytes data\n", wLength); +- xfer->data = g_malloc(wLength+1); +- xfer->data_alloced = wLength; +- } +- xfer->data_length = wLength; + + port = &xhci->ports[xhci->slots[xfer->slotid-1].port-1]; + dev = xhci_find_device(port, xhci->slots[xfer->slotid-1].devaddr); +@@ -1336,9 +1322,6 @@ static int xhci_fire_ctl_transfer(XHCIState *xhci, XHCITransfer *xfer) + + xhci_setup_packet(xfer, dev); + xfer->packet.parameter = trb_setup->parameter; +- if (!xfer->in_xfer) { +- xhci_xfer_data(xfer, xfer->data, wLength, 0, 1, 0); +- } + + ret = usb_handle_packet(dev, &xfer->packet); + +@@ -1359,16 +1342,6 @@ static int xhci_submit(XHCIState *xhci, XHCITransfer *xfer, XHCIEPContext *epctx + + xfer->in_xfer = epctx->type>>2; + +- if (xfer->data && xfer->data_alloced < xfer->data_length) { +- xfer->data_alloced = 0; +- g_free(xfer->data); +- xfer->data = NULL; +- } +- if (!xfer->data && xfer->data_length) { +- DPRINTF("xhci: alloc %d bytes data\n", xfer->data_length); +- xfer->data = g_malloc(xfer->data_length); +- xfer->data_alloced = xfer->data_length; +- } + if (epctx->type == ET_ISO_IN || epctx->type == ET_ISO_OUT) { + xfer->pkts = 1; + } else { +@@ -1402,9 +1375,6 @@ static int xhci_submit(XHCIState *xhci, XHCITransfer *xfer, XHCIEPContext *epctx + return -1; + } + +- if (!xfer->in_xfer) { +- xhci_xfer_data(xfer, xfer->data, xfer->data_length, 0, 1, 0); +- } + ret = usb_handle_packet(dev, &xfer->packet); + + xhci_complete_packet(xfer, ret); +@@ -1416,20 +1386,7 @@ static int xhci_submit(XHCIState *xhci, XHCITransfer *xfer, XHCIEPContext *epctx + + static int xhci_fire_transfer(XHCIState *xhci, XHCITransfer *xfer, XHCIEPContext *epctx) + { +- int i; +- unsigned int length = 0; +- XHCITRB *trb; +- +- for (i = 0; i < xfer->trb_count; i++) { +- trb = &xfer->trbs[i]; +- if (TRB_TYPE(*trb) == TR_NORMAL || TRB_TYPE(*trb) == TR_ISOCH) { +- length += trb->status & 0x1ffff; +- } +- } +- +- trace_usb_xhci_xfer_start(xfer, xfer->slotid, xfer->epid, length); +- +- xfer->data_length = length; ++ trace_usb_xhci_xfer_start(xfer, xfer->slotid, xfer->epid); + return xhci_submit(xhci, xfer, epctx); + } + +diff --git a/trace-events b/trace-events +index 10bc04e..c83d65e 100644 +--- a/trace-events ++++ b/trace-events +@@ -326,7 +326,7 @@ usb_xhci_ep_disable(uint32_t slotid, uint32_t epid) "slotid %d, epid %d" + usb_xhci_ep_kick(uint32_t slotid, uint32_t epid) "slotid %d, epid %d" + usb_xhci_ep_stop(uint32_t slotid, uint32_t epid) "slotid %d, epid %d" + usb_xhci_ep_reset(uint32_t slotid, uint32_t epid) "slotid %d, epid %d" +-usb_xhci_xfer_start(void *xfer, uint32_t slotid, uint32_t epid, uint32_t length) "%p: slotid %d, epid %d, length %d" ++usb_xhci_xfer_start(void *xfer, uint32_t slotid, uint32_t epid) "%p: slotid %d, epid %d" + usb_xhci_xfer_async(void *xfer) "%p" + usb_xhci_xfer_nak(void *xfer) "%p" + usb_xhci_xfer_retry(void *xfer) "%p" +-- +1.7.12.1 + diff --git a/0153-xhci-fix-runtime-write-tracepoint.patch b/0153-xhci-fix-runtime-write-tracepoint.patch new file mode 100644 index 0000000..133df2e --- /dev/null +++ b/0153-xhci-fix-runtime-write-tracepoint.patch @@ -0,0 +1,29 @@ +From 6dacb38ce3cb2ffe8c6e3a3a1bc86eee49d1e07c Mon Sep 17 00:00:00 2001 +From: Gerd Hoffmann +Date: Thu, 30 Aug 2012 12:42:32 +0200 +Subject: [PATCH] xhci: fix runtime write tracepoint + +Signed-off-by: Gerd Hoffmann +(cherry picked from commit 8e9f18b6db1cd67f0a7efd7d0285bee489445197) + +Signed-off-by: Michael Roth +--- + hw/usb/hcd-xhci.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/hw/usb/hcd-xhci.c b/hw/usb/hcd-xhci.c +index 446d692..24b1f87 100644 +--- a/hw/usb/hcd-xhci.c ++++ b/hw/usb/hcd-xhci.c +@@ -2348,7 +2348,7 @@ static uint32_t xhci_runtime_read(XHCIState *xhci, uint32_t reg) + + static void xhci_runtime_write(XHCIState *xhci, uint32_t reg, uint32_t val) + { +- trace_usb_xhci_runtime_read(reg, val); ++ trace_usb_xhci_runtime_write(reg, val); + + switch (reg) { + case 0x20: /* IMAN */ +-- +1.7.12.1 + diff --git a/0154-xhci-allow-bytewise-capability-register-reads.patch b/0154-xhci-allow-bytewise-capability-register-reads.patch new file mode 100644 index 0000000..0870f14 --- /dev/null +++ b/0154-xhci-allow-bytewise-capability-register-reads.patch @@ -0,0 +1,39 @@ +From 0233069eb2724255f03253f0afe814773eaf345c Mon Sep 17 00:00:00 2001 +From: Gerd Hoffmann +Date: Tue, 4 Sep 2012 14:48:03 +0200 +Subject: [PATCH] xhci: allow bytewise capability register reads + +Some guests need this according to +Alejandro Martinez Ruiz + +Signed-off-by: Gerd Hoffmann +(cherry picked from commit 6ee021d41078844df60a3a466e3829a3e82776f3) + +Conflicts: + + hw/usb/hcd-xhci.c + +Signed-off-by: Michael Roth +--- + hw/usb/hcd-xhci.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/hw/usb/hcd-xhci.c b/hw/usb/hcd-xhci.c +index 24b1f87..333df59 100644 +--- a/hw/usb/hcd-xhci.c ++++ b/hw/usb/hcd-xhci.c +@@ -2474,8 +2474,10 @@ static void xhci_mem_write(void *ptr, target_phys_addr_t addr, + static const MemoryRegionOps xhci_mem_ops = { + .read = xhci_mem_read, + .write = xhci_mem_write, +- .valid.min_access_size = 4, ++ .valid.min_access_size = 1, + .valid.max_access_size = 4, ++ .impl.min_access_size = 4, ++ .impl.max_access_size = 4, + .endianness = DEVICE_LITTLE_ENDIAN, + }; + +-- +1.7.12.1 + diff --git a/0155-qxl-dont-update-invalid-area.patch b/0155-qxl-dont-update-invalid-area.patch new file mode 100644 index 0000000..902566d --- /dev/null +++ b/0155-qxl-dont-update-invalid-area.patch @@ -0,0 +1,44 @@ +From 4007ba909e0188ed03d5a1fc1dde094d0ac14488 Mon Sep 17 00:00:00 2001 +From: Dunrong Huang +Date: Fri, 31 Aug 2012 00:44:44 +0800 +Subject: [PATCH] qxl: dont update invalid area + +This patch fixes the following error: + +$ ~/usr/bin/qemu-system-x86_64 -enable-kvm -m 1024 -spice port=5900,disable-ticketing -vga qxl -cdrom ~/Images/linuxmint-13-mate-dvd-32bit.iso +(/home/mathslinux/usr/bin/qemu-system-x86_64:10068): SpiceWorker-CRITICAL **: red_worker.c:4599:red_update_area: condition `area->left >= 0 && area->top >= 0 && area->left < area->right && area->top < area->bottom' failed +Aborted + +spice server terminates QEMU process if we pass invalid area to it, +so dont update those invalid areas. + +Signed-off-by: Dunrong Huang +Signed-off-by: Gerd Hoffmann +(cherry picked from commit ccc2960d654a233a6ed415b37d8ff41728d817c5) + +Signed-off-by: Michael Roth +--- + hw/qxl.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/hw/qxl.c b/hw/qxl.c +index 27f3779..038a8bb 100644 +--- a/hw/qxl.c ++++ b/hw/qxl.c +@@ -1448,6 +1448,13 @@ async_common: + return; + } + ++ if (update.left < 0 || update.top < 0 || update.left >= update.right || ++ update.top >= update.bottom) { ++ qxl_set_guest_bug(d, "QXL_IO_UPDATE_AREA: " ++ "invalid area(%d,%d,%d,%d)\n", update.left, ++ update.right, update.top, update.bottom); ++ break; ++ } + if (async == QXL_ASYNC) { + cookie = qxl_cookie_new(QXL_COOKIE_TYPE_IO, + QXL_IO_UPDATE_AREA_ASYNC); +-- +1.7.12.1 + diff --git a/0156-usb-host-allow-emulated-non-async-control-requests-w.patch b/0156-usb-host-allow-emulated-non-async-control-requests-w.patch new file mode 100644 index 0000000..11fcb3f --- /dev/null +++ b/0156-usb-host-allow-emulated-non-async-control-requests-w.patch @@ -0,0 +1,40 @@ +From e84037892a04dac64104b43d0a6342aee4c4e6f4 Mon Sep 17 00:00:00 2001 +From: Gerd Hoffmann +Date: Thu, 6 Sep 2012 12:03:41 +0200 +Subject: [PATCH] usb-host: allow emulated (non-async) control requests + without USBPacket + +xhci needs this for USB_REQ_SET_ADDRESS due to the way +usb addressing is handled by the xhci hardware. + +Signed-off-by: Gerd Hoffmann +(cherry picked from commit 63587e31353b6652cadfcfb869f5692a2b69daeb) + +Signed-off-by: Michael Roth +--- + hw/usb/host-linux.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/hw/usb/host-linux.c b/hw/usb/host-linux.c +index 8df9207..44f1a64 100644 +--- a/hw/usb/host-linux.c ++++ b/hw/usb/host-linux.c +@@ -1045,7 +1045,6 @@ static int usb_host_handle_control(USBDevice *dev, USBPacket *p, + + /* Note request is (bRequestType << 8) | bRequest */ + trace_usb_host_req_control(s->bus_num, s->addr, p, request, value, index); +- assert(p->result == 0); + + switch (request) { + case DeviceOutRequest | USB_REQ_SET_ADDRESS: +@@ -1074,6 +1073,7 @@ static int usb_host_handle_control(USBDevice *dev, USBPacket *p, + } + + /* The rest are asynchronous */ ++ assert(p && p->result == 0); + + if (length > sizeof(dev->data_buf)) { + fprintf(stderr, "husb: ctrl buffer too small (%d > %zu)\n", +-- +1.7.12.1 + diff --git a/0157-qxl-better-cleanup-for-surface-destroy.patch b/0157-qxl-better-cleanup-for-surface-destroy.patch new file mode 100644 index 0000000..b796173 --- /dev/null +++ b/0157-qxl-better-cleanup-for-surface-destroy.patch @@ -0,0 +1,35 @@ +From 57ec733394ec42f8a144751de3b9406fb7e17217 Mon Sep 17 00:00:00 2001 +From: Uri Lublin +Date: Tue, 11 Sep 2012 10:09:58 +0300 +Subject: [PATCH] qxl: better cleanup for surface destroy + +Add back a call to qxl_spice_destroy_surface_wait_complete() in qxl_spice_destroy_surface_wait(), +that was removed by commit c480bb7da465186b84d8427e068ef7502e47ffbf + +It is needed to complete surface-removal cleanup, for non async. +For async, qxl_spice_destroy_surface_wait_complete is called upon operation completion. + +Signed-off-by: Uri Lublin +Signed-off-by: Gerd Hoffmann +(cherry picked from commit 753b8b0d77ba1b343a35f9679cc777ea10a62bba) + +Signed-off-by: Michael Roth +--- + hw/qxl.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/hw/qxl.c b/hw/qxl.c +index 038a8bb..67f7100 100644 +--- a/hw/qxl.c ++++ b/hw/qxl.c +@@ -201,6 +201,7 @@ static void qxl_spice_destroy_surface_wait(PCIQXLDevice *qxl, uint32_t id, + spice_qxl_destroy_surface_async(&qxl->ssd.qxl, id, (uintptr_t)cookie); + } else { + qxl->ssd.worker->destroy_surface_wait(qxl->ssd.worker, id); ++ qxl_spice_destroy_surface_wait_complete(qxl, id); + } + } + +-- +1.7.12.1 + diff --git a/0158-ehci-switch-to-new-style-memory-ops.patch b/0158-ehci-switch-to-new-style-memory-ops.patch new file mode 100644 index 0000000..4932df4 --- /dev/null +++ b/0158-ehci-switch-to-new-style-memory-ops.patch @@ -0,0 +1,370 @@ +From 093374b8c759db877691fde602912a7cafd72a2e Mon Sep 17 00:00:00 2001 +From: Gerd Hoffmann +Date: Thu, 6 Sep 2012 11:24:51 +0200 +Subject: [PATCH] ehci: switch to new-style memory ops + +Also register different memory regions for capabilities, +operational registers and port status registers. Create +separate tracepoints for operational regs and port status +regs. Ditch a bunch of sanity checks because the memory +core will do this for us now. + +Offloading the byte, word and dword access handling to the +memory core also has the side effect of fixing ehci register +access on bigendian hosts. + +Cc: David Gibson +Signed-off-by: Gerd Hoffmann +(cherry picked from commit 3e4f910c8d490a1490409a7e381dbbb229f9d272) + +Signed-off-by: Michael Roth +--- + hw/usb/hcd-ehci.c | 173 ++++++++++++++++++++++++++---------------------------- + trace-events | 9 ++- + 2 files changed, 90 insertions(+), 92 deletions(-) + +diff --git a/hw/usb/hcd-ehci.c b/hw/usb/hcd-ehci.c +index 2f3e9c0..f5ba8e1 100644 +--- a/hw/usb/hcd-ehci.c ++++ b/hw/usb/hcd-ehci.c +@@ -389,6 +389,9 @@ struct EHCIState { + USBBus bus; + qemu_irq irq; + MemoryRegion mem; ++ MemoryRegion mem_caps; ++ MemoryRegion mem_opreg; ++ MemoryRegion mem_ports; + int companion_count; + + /* properties */ +@@ -398,10 +401,10 @@ struct EHCIState { + * EHCI spec version 1.0 Section 2.3 + * Host Controller Operational Registers + */ ++ uint8_t caps[OPREGBASE]; + union { +- uint8_t mmio[MMIO_SIZE]; ++ uint32_t opreg[(PORTSC_BEGIN-OPREGBASE)/sizeof(uint32_t)]; + struct { +- uint8_t cap[OPREGBASE]; + uint32_t usbcmd; + uint32_t usbsts; + uint32_t usbintr; +@@ -411,9 +414,9 @@ struct EHCIState { + uint32_t asynclistaddr; + uint32_t notused[9]; + uint32_t configflag; +- uint32_t portsc[NB_PORTS]; + }; + }; ++ uint32_t portsc[NB_PORTS]; + + /* + * Internal states, shadow registers, etc +@@ -471,22 +474,12 @@ static const char *ehci_state_names[] = { + }; + + static const char *ehci_mmio_names[] = { +- [CAPLENGTH] = "CAPLENGTH", +- [HCIVERSION] = "HCIVERSION", +- [HCSPARAMS] = "HCSPARAMS", +- [HCCPARAMS] = "HCCPARAMS", + [USBCMD] = "USBCMD", + [USBSTS] = "USBSTS", + [USBINTR] = "USBINTR", + [FRINDEX] = "FRINDEX", + [PERIODICLISTBASE] = "P-LIST BASE", + [ASYNCLISTADDR] = "A-LIST ADDR", +- [PORTSC_BEGIN] = "PORTSC #0", +- [PORTSC_BEGIN + 4] = "PORTSC #1", +- [PORTSC_BEGIN + 8] = "PORTSC #2", +- [PORTSC_BEGIN + 12] = "PORTSC #3", +- [PORTSC_BEGIN + 16] = "PORTSC #4", +- [PORTSC_BEGIN + 20] = "PORTSC #5", + [CONFIGFLAG] = "CONFIGFLAG", + }; + +@@ -509,7 +502,8 @@ static const char *state2str(uint32_t state) + + static const char *addr2str(target_phys_addr_t addr) + { +- return nr2str(ehci_mmio_names, ARRAY_SIZE(ehci_mmio_names), addr); ++ return nr2str(ehci_mmio_names, ARRAY_SIZE(ehci_mmio_names), ++ addr + OPREGBASE); + } + + static void ehci_trace_usbsts(uint32_t mask, int state) +@@ -1018,7 +1012,7 @@ static int ehci_register_companion(USBBus *bus, USBPort *ports[], + } + + s->companion_count++; +- s->mmio[0x05] = (s->companion_count << 4) | portcount; ++ s->caps[0x05] = (s->companion_count << 4) | portcount; + + return 0; + } +@@ -1063,7 +1057,8 @@ static void ehci_reset(void *opaque) + } + } + +- memset(&s->mmio[OPREGBASE], 0x00, MMIO_SIZE - OPREGBASE); ++ memset(&s->opreg, 0x00, sizeof(s->opreg)); ++ memset(&s->portsc, 0x00, sizeof(s->portsc)); + + s->usbcmd = NB_MAXINTRATE << USBCMD_ITC_SH; + s->usbsts = USBSTS_HALT; +@@ -1090,50 +1085,35 @@ static void ehci_reset(void *opaque) + qemu_bh_cancel(s->async_bh); + } + +-static uint32_t ehci_mem_readb(void *ptr, target_phys_addr_t addr) ++static uint64_t ehci_caps_read(void *ptr, target_phys_addr_t addr, ++ unsigned size) + { + EHCIState *s = ptr; +- uint32_t val; +- +- val = s->mmio[addr]; +- +- return val; ++ return s->caps[addr]; + } + +-static uint32_t ehci_mem_readw(void *ptr, target_phys_addr_t addr) ++static uint64_t ehci_opreg_read(void *ptr, target_phys_addr_t addr, ++ unsigned size) + { + EHCIState *s = ptr; + uint32_t val; + +- val = s->mmio[addr] | (s->mmio[addr+1] << 8); +- ++ val = s->opreg[addr >> 2]; ++ trace_usb_ehci_opreg_read(addr + OPREGBASE, addr2str(addr), val); + return val; + } + +-static uint32_t ehci_mem_readl(void *ptr, target_phys_addr_t addr) ++static uint64_t ehci_port_read(void *ptr, target_phys_addr_t addr, ++ unsigned size) + { + EHCIState *s = ptr; + uint32_t val; + +- val = s->mmio[addr] | (s->mmio[addr+1] << 8) | +- (s->mmio[addr+2] << 16) | (s->mmio[addr+3] << 24); +- +- trace_usb_ehci_mmio_readl(addr, addr2str(addr), val); ++ val = s->portsc[addr >> 2]; ++ trace_usb_ehci_portsc_read(addr + PORTSC_BEGIN, addr >> 2, val); + return val; + } + +-static void ehci_mem_writeb(void *ptr, target_phys_addr_t addr, uint32_t val) +-{ +- fprintf(stderr, "EHCI doesn't handle byte writes to MMIO\n"); +- exit(1); +-} +- +-static void ehci_mem_writew(void *ptr, target_phys_addr_t addr, uint32_t val) +-{ +- fprintf(stderr, "EHCI doesn't handle 16-bit writes to MMIO\n"); +- exit(1); +-} +- + static void handle_port_owner_write(EHCIState *s, int port, uint32_t owner) + { + USBDevice *dev = s->ports[port].dev; +@@ -1162,11 +1142,17 @@ static void handle_port_owner_write(EHCIState *s, int port, uint32_t owner) + } + } + +-static void handle_port_status_write(EHCIState *s, int port, uint32_t val) ++static void ehci_port_write(void *ptr, target_phys_addr_t addr, ++ uint64_t val, unsigned size) + { ++ EHCIState *s = ptr; ++ int port = addr >> 2; + uint32_t *portsc = &s->portsc[port]; ++ uint32_t old = *portsc; + USBDevice *dev = s->ports[port].dev; + ++ trace_usb_ehci_portsc_write(addr + PORTSC_BEGIN, addr >> 2, val); ++ + /* Clear rwc bits */ + *portsc &= ~(val & PORTSC_RWC_MASK); + /* The guest may clear, but not set the PED bit */ +@@ -1198,39 +1184,20 @@ static void handle_port_status_write(EHCIState *s, int port, uint32_t val) + + *portsc &= ~PORTSC_RO_MASK; + *portsc |= val; ++ trace_usb_ehci_portsc_change(addr + PORTSC_BEGIN, addr >> 2, *portsc, old); + } + +-static void ehci_mem_writel(void *ptr, target_phys_addr_t addr, uint32_t val) ++static void ehci_opreg_write(void *ptr, target_phys_addr_t addr, ++ uint64_t val, unsigned size) + { + EHCIState *s = ptr; +- uint32_t *mmio = (uint32_t *)(&s->mmio[addr]); ++ uint32_t *mmio = s->opreg + (addr >> 2); + uint32_t old = *mmio; + int i; + +- trace_usb_ehci_mmio_writel(addr, addr2str(addr), val); +- +- /* Only aligned reads are allowed on OHCI */ +- if (addr & 3) { +- fprintf(stderr, "usb-ehci: Mis-aligned write to addr 0x" +- TARGET_FMT_plx "\n", addr); +- return; +- } +- +- if (addr >= PORTSC && addr < PORTSC + 4 * NB_PORTS) { +- handle_port_status_write(s, (addr-PORTSC)/4, val); +- trace_usb_ehci_mmio_change(addr, addr2str(addr), *mmio, old); +- return; +- } +- +- if (addr < OPREGBASE) { +- fprintf(stderr, "usb-ehci: write attempt to read-only register" +- TARGET_FMT_plx "\n", addr); +- return; +- } +- ++ trace_usb_ehci_opreg_write(addr + OPREGBASE, addr2str(addr), val); + +- /* Do any register specific pre-write processing here. */ +- switch(addr) { ++ switch (addr + OPREGBASE) { + case USBCMD: + if (val & USBCMD_HCRESET) { + ehci_reset(s); +@@ -1241,7 +1208,7 @@ static void ehci_mem_writel(void *ptr, target_phys_addr_t addr, uint32_t val) + /* not supporting dynamic frame list size at the moment */ + if ((val & USBCMD_FLS) && !(s->usbcmd & USBCMD_FLS)) { + fprintf(stderr, "attempt to set frame list size -- value %d\n", +- val & USBCMD_FLS); ++ (int)val & USBCMD_FLS); + val &= ~USBCMD_FLS; + } + +@@ -1308,7 +1275,7 @@ static void ehci_mem_writel(void *ptr, target_phys_addr_t addr, uint32_t val) + } + + *mmio = val; +- trace_usb_ehci_mmio_change(addr, addr2str(addr), *mmio, old); ++ trace_usb_ehci_opreg_change(addr + OPREGBASE, addr2str(addr), *mmio, old); + } + + +@@ -2520,11 +2487,28 @@ static void ehci_async_bh(void *opaque) + ehci_advance_async_state(ehci); + } + +-static const MemoryRegionOps ehci_mem_ops = { +- .old_mmio = { +- .read = { ehci_mem_readb, ehci_mem_readw, ehci_mem_readl }, +- .write = { ehci_mem_writeb, ehci_mem_writew, ehci_mem_writel }, +- }, ++static const MemoryRegionOps ehci_mmio_caps_ops = { ++ .read = ehci_caps_read, ++ .valid.min_access_size = 1, ++ .valid.max_access_size = 4, ++ .impl.min_access_size = 1, ++ .impl.max_access_size = 1, ++ .endianness = DEVICE_LITTLE_ENDIAN, ++}; ++ ++static const MemoryRegionOps ehci_mmio_opreg_ops = { ++ .read = ehci_opreg_read, ++ .write = ehci_opreg_write, ++ .valid.min_access_size = 4, ++ .valid.max_access_size = 4, ++ .endianness = DEVICE_LITTLE_ENDIAN, ++}; ++ ++static const MemoryRegionOps ehci_mmio_port_ops = { ++ .read = ehci_port_read, ++ .write = ehci_port_write, ++ .valid.min_access_size = 4, ++ .valid.max_access_size = 4, + .endianness = DEVICE_LITTLE_ENDIAN, + }; + +@@ -2681,19 +2665,19 @@ static int usb_ehci_initfn(PCIDevice *dev) + pci_conf[0x6e] = 0x00; + pci_conf[0x6f] = 0xc0; // USBLEFCTLSTS + +- // 2.2 host controller interface version +- s->mmio[0x00] = (uint8_t) OPREGBASE; +- s->mmio[0x01] = 0x00; +- s->mmio[0x02] = 0x00; +- s->mmio[0x03] = 0x01; // HC version +- s->mmio[0x04] = NB_PORTS; // Number of downstream ports +- s->mmio[0x05] = 0x00; // No companion ports at present +- s->mmio[0x06] = 0x00; +- s->mmio[0x07] = 0x00; +- s->mmio[0x08] = 0x80; // We can cache whole frame, not 64-bit capable +- s->mmio[0x09] = 0x68; // EECP +- s->mmio[0x0a] = 0x00; +- s->mmio[0x0b] = 0x00; ++ /* 2.2 host controller interface version */ ++ s->caps[0x00] = (uint8_t) OPREGBASE; ++ s->caps[0x01] = 0x00; ++ s->caps[0x02] = 0x00; ++ s->caps[0x03] = 0x01; /* HC version */ ++ s->caps[0x04] = NB_PORTS; /* Number of downstream ports */ ++ s->caps[0x05] = 0x00; /* No companion ports at present */ ++ s->caps[0x06] = 0x00; ++ s->caps[0x07] = 0x00; ++ s->caps[0x08] = 0x80; /* We can cache whole frame, no 64-bit */ ++ s->caps[0x09] = 0x68; /* EECP */ ++ s->caps[0x0a] = 0x00; ++ s->caps[0x0b] = 0x00; + + s->irq = s->dev.irq[3]; + +@@ -2712,7 +2696,18 @@ static int usb_ehci_initfn(PCIDevice *dev) + + qemu_register_reset(ehci_reset, s); + +- memory_region_init_io(&s->mem, &ehci_mem_ops, s, "ehci", MMIO_SIZE); ++ memory_region_init(&s->mem, "ehci", MMIO_SIZE); ++ memory_region_init_io(&s->mem_caps, &ehci_mmio_caps_ops, s, ++ "capabilities", OPREGBASE); ++ memory_region_init_io(&s->mem_opreg, &ehci_mmio_opreg_ops, s, ++ "operational", PORTSC_BEGIN - OPREGBASE); ++ memory_region_init_io(&s->mem_ports, &ehci_mmio_port_ops, s, ++ "ports", PORTSC_END - PORTSC_BEGIN); ++ ++ memory_region_add_subregion(&s->mem, 0, &s->mem_caps); ++ memory_region_add_subregion(&s->mem, OPREGBASE, &s->mem_opreg); ++ memory_region_add_subregion(&s->mem, PORTSC_BEGIN, &s->mem_ports); ++ + pci_register_bar(&s->dev, 0, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->mem); + + return 0; +diff --git a/trace-events b/trace-events +index c83d65e..cf05414 100644 +--- a/trace-events ++++ b/trace-events +@@ -243,9 +243,12 @@ usb_port_release(int bus, const char *port) "bus %d, port %s" + + # hw/usb/hcd-ehci.c + usb_ehci_reset(void) "=== RESET ===" +-usb_ehci_mmio_readl(uint32_t addr, const char *str, uint32_t val) "rd mmio %04x [%s] = %x" +-usb_ehci_mmio_writel(uint32_t addr, const char *str, uint32_t val) "wr mmio %04x [%s] = %x" +-usb_ehci_mmio_change(uint32_t addr, const char *str, uint32_t new, uint32_t old) "ch mmio %04x [%s] = %x (old: %x)" ++usb_ehci_opreg_read(uint32_t addr, const char *str, uint32_t val) "rd mmio %04x [%s] = %x" ++usb_ehci_opreg_write(uint32_t addr, const char *str, uint32_t val) "wr mmio %04x [%s] = %x" ++usb_ehci_opreg_change(uint32_t addr, const char *str, uint32_t new, uint32_t old) "ch mmio %04x [%s] = %x (old: %x)" ++usb_ehci_portsc_read(uint32_t addr, uint32_t port, uint32_t val) "rd mmio %04x [port %d] = %x" ++usb_ehci_portsc_write(uint32_t addr, uint32_t port, uint32_t val) "wr mmio %04x [port %d] = %x" ++usb_ehci_portsc_change(uint32_t addr, uint32_t port, uint32_t new, uint32_t old) "ch mmio %04x [port %d] = %x (old: %x)" + usb_ehci_usbsts(const char *sts, int state) "usbsts %s %d" + usb_ehci_state(const char *schedule, const char *state) "%s schedule %s" + usb_ehci_qh_ptrs(void *q, uint32_t addr, uint32_t nxt, uint32_t c_qtd, uint32_t n_qtd, uint32_t a_qtd) "q %p - QH @ %08x: next %08x qtds %08x,%08x,%08x" +-- +1.7.12.1 + diff --git a/0159-ehci-Fix-interrupts-stopping-when-Interrupt-Threshol.patch b/0159-ehci-Fix-interrupts-stopping-when-Interrupt-Threshol.patch new file mode 100644 index 0000000..bd8d88b --- /dev/null +++ b/0159-ehci-Fix-interrupts-stopping-when-Interrupt-Threshol.patch @@ -0,0 +1,38 @@ +From c84ed39e601ff69d93e0ad81d92cb7234ad5d4cd Mon Sep 17 00:00:00 2001 +From: Hans de Goede +Date: Mon, 10 Sep 2012 12:44:10 +0200 +Subject: [PATCH] ehci: Fix interrupts stopping when Interrupt Threshold + Control is 8 + +If Interrupt Threshold Control is 8 or a multiple of 8, then +s->usbsts_frindex can become exactly 0x4000, at which point +(s->usbsts_frindex > s->frindex) will never become true, as +s->usbsts_frindex will not be lowered / reset in this case. + +This patch fixes this. + +Signed-off-by: Hans de Goede +Signed-off-by: Gerd Hoffmann +(cherry picked from commit ffa1f2e088eb7e3d57f2fc35f21e7bdb23e592c5) + +Signed-off-by: Michael Roth +--- + hw/usb/hcd-ehci.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/hw/usb/hcd-ehci.c b/hw/usb/hcd-ehci.c +index f5ba8e1..54273d7 100644 +--- a/hw/usb/hcd-ehci.c ++++ b/hw/usb/hcd-ehci.c +@@ -2413,7 +2413,7 @@ static void ehci_update_frindex(EHCIState *ehci, int frames) + if (ehci->frindex == 0x00004000) { + ehci_raise_irq(ehci, USBSTS_FLR); + ehci->frindex = 0; +- if (ehci->usbsts_frindex > 0x00004000) { ++ if (ehci->usbsts_frindex >= 0x00004000) { + ehci->usbsts_frindex -= 0x00004000; + } else { + ehci->usbsts_frindex = 0; +-- +1.7.12.1 + diff --git a/0160-ehci-Don-t-process-too-much-frames-in-1-timer-tick-v.patch b/0160-ehci-Don-t-process-too-much-frames-in-1-timer-tick-v.patch new file mode 100644 index 0000000..f0a4b00 --- /dev/null +++ b/0160-ehci-Don-t-process-too-much-frames-in-1-timer-tick-v.patch @@ -0,0 +1,60 @@ +From a5022829821b27e00790f8fe2fd9cd8090a47e36 Mon Sep 17 00:00:00 2001 +From: Hans de Goede +Date: Mon, 10 Sep 2012 12:44:11 +0200 +Subject: [PATCH] ehci: Don't process too much frames in 1 timer tick (v2) + +The Linux ehci isoc scheduling code fills the entire schedule ahead of +time minus 80 frames. If we make a large jump in where we are in the +schedule, ie 40 frames, then the scheduler all of a sudden will only have +40 frames left to work in, causing it to fail packet submissions +with error -27 (-EFBIG). + +Changes in v2: +-Don't hardcode a maximum number of frames to process in one tick, instead: + -Process a minimum number of frames to ensure we do eventually catch up + -Stop (after the minimum number) when the guest has requested an irq + +Signed-off-by: Hans de Goede +Signed-off-by: Gerd Hoffmann +(cherry picked from commit 8f74ed1e43263293301031a10e440549bab19a6e) + +Signed-off-by: Michael Roth +--- + hw/usb/hcd-ehci.c | 14 ++++++++++++++ + 1 file changed, 14 insertions(+) + +diff --git a/hw/usb/hcd-ehci.c b/hw/usb/hcd-ehci.c +index 54273d7..017a01d 100644 +--- a/hw/usb/hcd-ehci.c ++++ b/hw/usb/hcd-ehci.c +@@ -139,6 +139,7 @@ + #define NB_PORTS 6 // Number of downstream ports + #define BUFF_SIZE 5*4096 // Max bytes to transfer per transaction + #define MAX_QH 100 // Max allowable queue heads in a chain ++#define MIN_FR_PER_TICK 3 // Min frames to process when catching up + + /* Internal periodic / asynchronous schedule state machine states + */ +@@ -2448,6 +2449,19 @@ static void ehci_frame_timer(void *opaque) + } + + for (i = 0; i < frames; i++) { ++ /* ++ * If we're running behind schedule, we should not catch up ++ * too fast, as that will make some guests unhappy: ++ * 1) We must process a minimum of MIN_FR_PER_TICK frames, ++ * otherwise we will never catch up ++ * 2) Process frames until the guest has requested an irq (IOC) ++ */ ++ if (i >= MIN_FR_PER_TICK) { ++ ehci_commit_irq(ehci); ++ if ((ehci->usbsts & USBINTR_MASK) & ehci->usbintr) { ++ break; ++ } ++ } + ehci_update_frindex(ehci, 1); + ehci_advance_periodic_state(ehci); + ehci->last_run_ns += FRAME_TIMER_NS; +-- +1.7.12.1 + diff --git a/0161-sheepdog-fix-savevm-and-loadvm.patch b/0161-sheepdog-fix-savevm-and-loadvm.patch new file mode 100644 index 0000000..f85cc0b --- /dev/null +++ b/0161-sheepdog-fix-savevm-and-loadvm.patch @@ -0,0 +1,41 @@ +From f065553b45322bb0ba14a4c9d1fb65554ae3e325 Mon Sep 17 00:00:00 2001 +From: MORITA Kazutaka +Date: Thu, 30 Aug 2012 03:39:45 +0900 +Subject: [PATCH] sheepdog: fix savevm and loadvm + +This patch sets data to be sent to Sheepdog correctly and fixes savevm +and loadvm operations on a Sheepdog image. + +Signed-off-by: MORITA Kazutaka +Signed-off-by: Kevin Wolf +(cherry picked from commit 1f7a48de4467f31afc51169122453318efdb0f33) + +Signed-off-by: Michael Roth +--- + block/sheepdog.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/block/sheepdog.c b/block/sheepdog.c +index df4f441..e0753ee 100644 +--- a/block/sheepdog.c ++++ b/block/sheepdog.c +@@ -1986,7 +1986,7 @@ static int do_load_save_vmstate(BDRVSheepdogState *s, uint8_t *data, + vdi_index = pos / SD_DATA_OBJ_SIZE; + offset = pos % SD_DATA_OBJ_SIZE; + +- data_len = MIN(remaining, SD_DATA_OBJ_SIZE); ++ data_len = MIN(remaining, SD_DATA_OBJ_SIZE - offset); + + vmstate_oid = vid_to_vmstate_oid(s->inode.vdi_id, vdi_index); + +@@ -2007,6 +2007,7 @@ static int do_load_save_vmstate(BDRVSheepdogState *s, uint8_t *data, + } + + pos += data_len; ++ data += data_len; + remaining -= data_len; + } + ret = size; +-- +1.7.12.1 + diff --git a/0162-ide-Fix-error-messages-from-static-code-analysis-no-.patch b/0162-ide-Fix-error-messages-from-static-code-analysis-no-.patch new file mode 100644 index 0000000..62a21ce --- /dev/null +++ b/0162-ide-Fix-error-messages-from-static-code-analysis-no-.patch @@ -0,0 +1,67 @@ +From 8557d38b8d660d07c7b6fd1bfa62182cc6c52400 Mon Sep 17 00:00:00 2001 +From: Stefan Weil +Date: Mon, 3 Sep 2012 22:13:56 +0200 +Subject: [PATCH] ide: Fix error messages from static code analysis (no real + error) + +Report from smatch: +hw/ide/core.c:1472 ide_exec_cmd(423) error: buffer overflow 'smart_attributes' 8 <= 29 +hw/ide/core.c:1474 ide_exec_cmd(425) error: buffer overflow 'smart_attributes' 8 <= 29 +hw/ide/core.c:1475 ide_exec_cmd(426) error: buffer overflow 'smart_attributes' 8 <= 29 +... + +The upper limit of 30 was never reached because both for loops terminated +when 'smart_attributes' reached end of list, so there was no real buffer +overflow. + +Nevertheless, changing the code not only fixes the error report, but also +reduces the size of smart_attributes and simplifies the for loops. + +Signed-off-by: Stefan Weil +Signed-off-by: Kevin Wolf +(cherry picked from commit 1e53537fdaa4657d11f130a0f2673fcfb1956381) + +Signed-off-by: Michael Roth +--- + hw/ide/core.c | 11 ++--------- + 1 file changed, 2 insertions(+), 9 deletions(-) + +diff --git a/hw/ide/core.c b/hw/ide/core.c +index d65ef3d..d6fb69c 100644 +--- a/hw/ide/core.c ++++ b/hw/ide/core.c +@@ -53,8 +53,6 @@ static const int smart_attributes[][12] = { + { 0x0c, 0x03, 0x00, 0x64, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + /* airflow-temperature-celsius */ + { 190, 0x03, 0x00, 0x45, 0x45, 0x1f, 0x00, 0x1f, 0x1f, 0x00, 0x00, 0x32}, +- /* end of list */ +- { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} + }; + + static int ide_handle_rw_error(IDEState *s, int error, int op); +@@ -1468,9 +1466,7 @@ void ide_exec_cmd(IDEBus *bus, uint32_t val) + case SMART_READ_THRESH: + memset(s->io_buffer, 0, 0x200); + s->io_buffer[0] = 0x01; /* smart struct version */ +- for (n=0; n<30; n++) { +- if (smart_attributes[n][0] == 0) +- break; ++ for (n = 0; n < ARRAY_SIZE(smart_attributes); n++) { + s->io_buffer[2+0+(n*12)] = smart_attributes[n][0]; + s->io_buffer[2+1+(n*12)] = smart_attributes[n][11]; + } +@@ -1484,10 +1480,7 @@ void ide_exec_cmd(IDEBus *bus, uint32_t val) + case SMART_READ_DATA: + memset(s->io_buffer, 0, 0x200); + s->io_buffer[0] = 0x01; /* smart struct version */ +- for (n=0; n<30; n++) { +- if (smart_attributes[n][0] == 0) { +- break; +- } ++ for (n = 0; n < ARRAY_SIZE(smart_attributes); n++) { + int i; + for(i = 0; i < 11; i++) { + s->io_buffer[2+i+(n*12)] = smart_attributes[n][i]; +-- +1.7.12.1 + diff --git a/0163-block-curl-Fix-wrong-free-statement.patch b/0163-block-curl-Fix-wrong-free-statement.patch new file mode 100644 index 0000000..a37ad7f --- /dev/null +++ b/0163-block-curl-Fix-wrong-free-statement.patch @@ -0,0 +1,37 @@ +From a29b7f5390e33d089dcdbf75d6e92c20bbedc562 Mon Sep 17 00:00:00 2001 +From: Stefan Weil +Date: Sat, 1 Sep 2012 11:06:45 +0200 +Subject: [PATCH] block/curl: Fix wrong free statement + +Report from smatch: +block/curl.c:546 curl_close(21) info: redundant null check on s->url calling free() + +The check was redundant, and free was also wrong because the memory +was allocated using g_strdup. + +Signed-off-by: Stefan Weil +Signed-off-by: Kevin Wolf +(cherry picked from commit 45724d6d02383b0d7d4a90e05787fca7c55cb070) + +Signed-off-by: Michael Roth +--- + block/curl.c | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +diff --git a/block/curl.c b/block/curl.c +index e7c3634..c1074cd 100644 +--- a/block/curl.c ++++ b/block/curl.c +@@ -542,8 +542,7 @@ static void curl_close(BlockDriverState *bs) + } + if (s->multi) + curl_multi_cleanup(s->multi); +- if (s->url) +- free(s->url); ++ g_free(s->url); + } + + static int64_t curl_getlength(BlockDriverState *bs) +-- +1.7.12.1 + diff --git a/0164-vdi-Fix-warning-from-clang.patch b/0164-vdi-Fix-warning-from-clang.patch new file mode 100644 index 0000000..c8e751d --- /dev/null +++ b/0164-vdi-Fix-warning-from-clang.patch @@ -0,0 +1,75 @@ +From 928865de80da6a23e6f0d4d86187c52f6c940255 Mon Sep 17 00:00:00 2001 +From: Stefan Weil +Date: Fri, 17 Aug 2012 15:23:24 +0200 +Subject: [PATCH] vdi: Fix warning from clang + +ccc-analyzer reports these warnings: + +block/vdi.c:704:13: warning: Dereference of null pointer + bmap[i] = VDI_UNALLOCATED; + ^ +block/vdi.c:702:13: warning: Dereference of null pointer + bmap[i] = i; + ^ + +Moving some code into the if block fixes this. +It also avoids calling function write with 0 bytes of data. + +Signed-off-by: Stefan Weil +Signed-off-by: Kevin Wolf +(cherry picked from commit 514f21a5d4613e495adc2e2dd48f18091454efb8) + +Signed-off-by: Michael Roth +--- + block/vdi.c | 25 ++++++++++++------------- + 1 file changed, 12 insertions(+), 13 deletions(-) + +diff --git a/block/vdi.c b/block/vdi.c +index c4f1529..550cf58 100644 +--- a/block/vdi.c ++++ b/block/vdi.c +@@ -628,7 +628,6 @@ static int vdi_create(const char *filename, QEMUOptionParameter *options) + VdiHeader header; + size_t i; + size_t bmap_size; +- uint32_t *bmap; + + logout("\n"); + +@@ -693,21 +692,21 @@ static int vdi_create(const char *filename, QEMUOptionParameter *options) + result = -errno; + } + +- bmap = NULL; + if (bmap_size > 0) { +- bmap = (uint32_t *)g_malloc0(bmap_size); +- } +- for (i = 0; i < blocks; i++) { +- if (image_type == VDI_TYPE_STATIC) { +- bmap[i] = i; +- } else { +- bmap[i] = VDI_UNALLOCATED; ++ uint32_t *bmap = g_malloc0(bmap_size); ++ for (i = 0; i < blocks; i++) { ++ if (image_type == VDI_TYPE_STATIC) { ++ bmap[i] = i; ++ } else { ++ bmap[i] = VDI_UNALLOCATED; ++ } + } ++ if (write(fd, bmap, bmap_size) < 0) { ++ result = -errno; ++ } ++ g_free(bmap); + } +- if (write(fd, bmap, bmap_size) < 0) { +- result = -errno; +- } +- g_free(bmap); ++ + if (image_type == VDI_TYPE_STATIC) { + if (ftruncate(fd, sizeof(header) + bmap_size + blocks * block_size)) { + result = -errno; +-- +1.7.12.1 + diff --git a/0165-block-fix-block-tray-status.patch b/0165-block-fix-block-tray-status.patch new file mode 100644 index 0000000..6db09b8 --- /dev/null +++ b/0165-block-fix-block-tray-status.patch @@ -0,0 +1,36 @@ +From 8794685f3ebb2d0001ab01bc8692d99242aedb4f Mon Sep 17 00:00:00 2001 +From: Pavel Hrdina +Date: Thu, 9 Aug 2012 12:44:48 +0200 +Subject: [PATCH] block: fix block tray status + +The tray status should change also if you eject empty block device. + +Signed-off-by: Pavel Hrdina +Signed-off-by: Kevin Wolf +(cherry picked from commit 9ca111544c64b5abed2e79cf52e19a8f227b347b) + +Signed-off-by: Michael Roth +--- + block.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/block.c b/block.c +index 470bdcc..c754353 100644 +--- a/block.c ++++ b/block.c +@@ -897,10 +897,10 @@ void bdrv_close(BlockDriverState *bs) + bdrv_delete(bs->file); + bs->file = NULL; + } +- +- bdrv_dev_change_media_cb(bs, false); + } + ++ bdrv_dev_change_media_cb(bs, false); ++ + /*throttling disk I/O limits*/ + if (bs->io_limits_enabled) { + bdrv_io_limits_disable(bs); +-- +1.7.12.1 + diff --git a/0166-ahci-properly-reset-PxCMD-on-HBA-reset.patch b/0166-ahci-properly-reset-PxCMD-on-HBA-reset.patch new file mode 100644 index 0000000..ad2d6b5 --- /dev/null +++ b/0166-ahci-properly-reset-PxCMD-on-HBA-reset.patch @@ -0,0 +1,64 @@ +From 3248d5fbbf9c0fbfd8d42af08aa81fe1e3fe2841 Mon Sep 17 00:00:00 2001 +From: Jason Baron +Date: Tue, 4 Sep 2012 16:08:08 -0400 +Subject: [PATCH] ahci: properly reset PxCMD on HBA reset + +While testing q35, I found that windows 7 (specifically, windows 7 ultimate +with sp1 x64), wouldn't install because it can't find the cdrom or disk drive. +The failure message is: 'A required cd/dvd device driver is missing. If you +have a driver floppy disk, CD, DVD, or USB flash drive, please insert it now.' +This can also be reproduced on piix by adding an ahci controller, and +observing that windows 7 does not see any devices behind it. + +The problem is that when windows issues a HBA reset, qemu does not reset the +individual ports' PxCMD register. Windows 7 then reads back the PxCMD register +and presumably assumes that the ahci controller has already been initialized. +Windows then never sets up the PxIE register to enable interrupts, and thus it +never gets irqs back when it sends ata device inquiry commands. + +This change brings qemu into ahci 1.3 specification compliance. + +Section 10.4.3 HBA Reset: + +" +When GHC.HR is set to '1', GHC.AE, GHC.IE, the IS register, and all port +register fields (except PxFB/PxFBU/PxCLB/PxCLBU) that are not HwInit in the +HBA's register memory space are reset. +" + +I've also re-tested Fedora 16 and 17 to verify that they continue to work with +this change. + +Signed-off-by: Jason Baron +Acked-by: Alexander Graf +Signed-off-by: Kevin Wolf +(cherry picked from commit 2a4f4f34e6fe55f4c82507c3e7ec9b58c2e24ad4) + +Signed-off-by: Michael Roth +--- + hw/ide/ahci.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/hw/ide/ahci.c b/hw/ide/ahci.c +index 5ea3cad..68671bc 100644 +--- a/hw/ide/ahci.c ++++ b/hw/ide/ahci.c +@@ -1175,7 +1175,6 @@ void ahci_init(AHCIState *s, DeviceState *qdev, DMAContext *dma, int ports) + ad->port_no = i; + ad->port.dma = &ad->dma; + ad->port.dma->ops = &ahci_dma_ops; +- ad->port_regs.cmd = PORT_CMD_SPIN_UP | PORT_CMD_POWER_ON; + } + } + +@@ -1199,6 +1198,7 @@ void ahci_reset(AHCIState *s) + pr->irq_stat = 0; + pr->irq_mask = 0; + pr->scr_ctl = 0; ++ pr->cmd = PORT_CMD_SPIN_UP | PORT_CMD_POWER_ON; + ahci_reset_port(s, i); + } + } +-- +1.7.12.1 + diff --git a/0167-Don-t-require-encryption-password-for-qemu-img-info-.patch b/0167-Don-t-require-encryption-password-for-qemu-img-info-.patch new file mode 100644 index 0000000..6b9d67f --- /dev/null +++ b/0167-Don-t-require-encryption-password-for-qemu-img-info-.patch @@ -0,0 +1,121 @@ +From 4812a358ff2d7442c33a517a6c80d7d3c301ec56 Mon Sep 17 00:00:00 2001 +From: "Daniel P. Berrange" +Date: Mon, 10 Sep 2012 12:11:31 +0100 +Subject: [PATCH] Don't require encryption password for 'qemu-img info' + command + +The encryption password is only required if I/O is going to be +performed on a disk image. The 'qemu-img info' command merely +reports metadata, so it should not ask for a decryption password + +Signed-off-by: Daniel P. Berrange +Signed-off-by: Kevin Wolf +(cherry picked from commit f0536bb848ad6eb2709a7dc675f261bd160c751b) + +Conflicts: + + qemu-img.c + +Signed-off-by: Michael Roth +--- + qemu-img.c | 21 +++++++++++---------- + 1 file changed, 11 insertions(+), 10 deletions(-) + +diff --git a/qemu-img.c b/qemu-img.c +index b41e670..0d208e8 100644 +--- a/qemu-img.c ++++ b/qemu-img.c +@@ -221,7 +221,8 @@ static int print_block_option_help(const char *filename, const char *fmt) + + static BlockDriverState *bdrv_new_open(const char *filename, + const char *fmt, +- int flags) ++ int flags, ++ bool require_io) + { + BlockDriverState *bs; + BlockDriver *drv; +@@ -246,7 +247,7 @@ static BlockDriverState *bdrv_new_open(const char *filename, + goto fail; + } + +- if (bdrv_is_encrypted(bs)) { ++ if (bdrv_is_encrypted(bs) && require_io) { + printf("Disk image '%s' is encrypted.\n", filename); + if (read_password(password, sizeof(password)) < 0) { + error_report("No password given"); +@@ -413,7 +414,7 @@ static int img_check(int argc, char **argv) + } + filename = argv[optind++]; + +- bs = bdrv_new_open(filename, fmt, flags); ++ bs = bdrv_new_open(filename, fmt, flags, true); + if (!bs) { + return 1; + } +@@ -520,7 +521,7 @@ static int img_commit(int argc, char **argv) + return -1; + } + +- bs = bdrv_new_open(filename, fmt, flags); ++ bs = bdrv_new_open(filename, fmt, flags, true); + if (!bs) { + return 1; + } +@@ -762,7 +763,7 @@ static int img_convert(int argc, char **argv) + + total_sectors = 0; + for (bs_i = 0; bs_i < bs_n; bs_i++) { +- bs[bs_i] = bdrv_new_open(argv[optind + bs_i], fmt, BDRV_O_FLAGS); ++ bs[bs_i] = bdrv_new_open(argv[optind + bs_i], fmt, BDRV_O_FLAGS, true); + if (!bs[bs_i]) { + error_report("Could not open '%s'", argv[optind + bs_i]); + ret = -1; +@@ -881,7 +882,7 @@ static int img_convert(int argc, char **argv) + return -1; + } + +- out_bs = bdrv_new_open(out_filename, out_fmt, flags); ++ out_bs = bdrv_new_open(out_filename, out_fmt, flags, true); + if (!out_bs) { + ret = -1; + goto out; +@@ -1135,7 +1136,7 @@ static int img_info(int argc, char **argv) + } + filename = argv[optind++]; + +- bs = bdrv_new_open(filename, fmt, BDRV_O_FLAGS | BDRV_O_NO_BACKING); ++ bs = bdrv_new_open(filename, fmt, BDRV_O_FLAGS | BDRV_O_NO_BACKING, false); + if (!bs) { + return 1; + } +@@ -1248,7 +1249,7 @@ static int img_snapshot(int argc, char **argv) + filename = argv[optind++]; + + /* Open the image */ +- bs = bdrv_new_open(filename, NULL, bdrv_oflags); ++ bs = bdrv_new_open(filename, NULL, bdrv_oflags, true); + if (!bs) { + return 1; + } +@@ -1366,7 +1367,7 @@ static int img_rebase(int argc, char **argv) + * Ignore the old backing file for unsafe rebase in case we want to correct + * the reference to a renamed or moved backing file. + */ +- bs = bdrv_new_open(filename, fmt, flags); ++ bs = bdrv_new_open(filename, fmt, flags, true); + if (!bs) { + return 1; + } +@@ -1639,7 +1640,7 @@ static int img_resize(int argc, char **argv) + n = qemu_opt_get_size(param, BLOCK_OPT_SIZE, 0); + qemu_opts_del(param); + +- bs = bdrv_new_open(filename, fmt, BDRV_O_FLAGS | BDRV_O_RDWR); ++ bs = bdrv_new_open(filename, fmt, BDRV_O_FLAGS | BDRV_O_RDWR, true); + if (!bs) { + ret = -1; + goto out; +-- +1.7.12.1 + diff --git a/0168-block-Don-t-forget-to-delete-temporary-file.patch b/0168-block-Don-t-forget-to-delete-temporary-file.patch new file mode 100644 index 0000000..90d07b9 --- /dev/null +++ b/0168-block-Don-t-forget-to-delete-temporary-file.patch @@ -0,0 +1,36 @@ +From 3306981d5631182fb1384b05d66be26918521511 Mon Sep 17 00:00:00 2001 +From: Dunrong Huang +Date: Wed, 5 Sep 2012 21:26:22 +0800 +Subject: [PATCH] block: Don't forget to delete temporary file + +The caller would not delete temporary file after failed get_tmp_filename(). + +Signed-off-by: Dunrong Huang +Signed-off-by: Kevin Wolf +(cherry picked from commit fe235a06e1e008dedd2ac3cc0a3a655169ce9b33) + +Signed-off-by: Michael Roth +--- + block.c | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +diff --git a/block.c b/block.c +index c754353..e78039b 100644 +--- a/block.c ++++ b/block.c +@@ -433,7 +433,11 @@ int get_tmp_filename(char *filename, int size) + return -EOVERFLOW; + } + fd = mkstemp(filename); +- if (fd < 0 || close(fd)) { ++ if (fd < 0) { ++ return -errno; ++ } ++ if (close(fd) != 0) { ++ unlink(filename); + return -errno; + } + return 0; +-- +1.7.12.1 + diff --git a/0169-hw-qxl-tracing-fixes.patch b/0169-hw-qxl-tracing-fixes.patch new file mode 100644 index 0000000..74c400f --- /dev/null +++ b/0169-hw-qxl-tracing-fixes.patch @@ -0,0 +1,99 @@ +From e4a803d8ebd69719f4d997052e5bc3a5a7d91124 Mon Sep 17 00:00:00 2001 +From: Alon Levy +Date: Wed, 12 Sep 2012 16:13:26 +0300 +Subject: [PATCH] hw/qxl: tracing fixes + +Add two new trace events: +qxl_send_events(int qid, uint32_t events) "%d %d" +qxl_set_guest_bug(int qid) "%d" + +Change qxl_io_unexpected_vga_mode parameters to be equivalent to those +of qxl_io_write for easier grouping under a single systemtap probe. + +Change d to qxl in one place. + +Signed-off-by: Alon Levy +Signed-off-by: Gerd Hoffmann +(cherry picked from commit 917ae08ca1565aab2d10c8b6269cd905d6c5c05b) + +Signed-off-by: Michael Roth +--- + hw/qxl.c | 8 +++++--- + trace-events | 6 ++++-- + 2 files changed, 9 insertions(+), 5 deletions(-) + +diff --git a/hw/qxl.c b/hw/qxl.c +index 67f7100..59bf822 100644 +--- a/hw/qxl.c ++++ b/hw/qxl.c +@@ -141,6 +141,7 @@ static void qxl_ring_set_dirty(PCIQXLDevice *qxl); + + void qxl_set_guest_bug(PCIQXLDevice *qxl, const char *msg, ...) + { ++ trace_qxl_set_guest_bug(qxl->id); + qxl_send_events(qxl, QXL_INTERRUPT_ERROR); + qxl->guest_bug = 1; + if (qxl->guestdebug) { +@@ -1381,7 +1382,7 @@ static void ioport_write(void *opaque, target_phys_addr_t addr, + break; + } + trace_qxl_io_unexpected_vga_mode(d->id, +- io_port, io_port_to_string(io_port)); ++ addr, val, io_port_to_string(io_port)); + /* be nice to buggy guest drivers */ + if (io_port >= QXL_IO_UPDATE_AREA_ASYNC && + io_port < QXL_IO_RANGE_SIZE) { +@@ -1580,9 +1581,9 @@ cancel_async: + static uint64_t ioport_read(void *opaque, target_phys_addr_t addr, + unsigned size) + { +- PCIQXLDevice *d = opaque; ++ PCIQXLDevice *qxl = opaque; + +- trace_qxl_io_read_unexpected(d->id); ++ trace_qxl_io_read_unexpected(qxl->id); + return 0xff; + } + +@@ -1612,6 +1613,7 @@ static void qxl_send_events(PCIQXLDevice *d, uint32_t events) + uint32_t old_pending; + uint32_t le_events = cpu_to_le32(events); + ++ trace_qxl_send_events(d->id, events); + assert(qemu_spice_display_is_running(&d->ssd)); + old_pending = __sync_fetch_and_or(&d->ram->int_pending, le_events); + if ((old_pending & le_events) == le_events) { +diff --git a/trace-events b/trace-events +index cf05414..aa79836 100644 +--- a/trace-events ++++ b/trace-events +@@ -931,7 +931,7 @@ qxl_interface_update_area_complete_overflow(int qid, int max) "%d max=%d" + qxl_interface_update_area_complete_schedule_bh(int qid, uint32_t num_dirty) "%d #dirty=%d" + qxl_io_destroy_primary_ignored(int qid, const char *mode) "%d %s" + qxl_io_read_unexpected(int qid) "%d" +-qxl_io_unexpected_vga_mode(int qid, uint32_t io_port, const char *desc) "%d 0x%x (%s)" ++qxl_io_unexpected_vga_mode(int qid, uint64_t addr, uint64_t val, const char *desc) "%d 0x%"PRIx64"=%"PRIu64" (%s)" + qxl_io_write(int qid, const char *mode, uint64_t addr, uint64_t val, unsigned size, int async) "%d %s addr=%"PRIu64 " val=%"PRIu64" size=%u async=%d" + qxl_memslot_add_guest(int qid, uint32_t slot_id, uint64_t guest_start, uint64_t guest_end) "%d %u: guest phys 0x%"PRIx64 " - 0x%" PRIx64 + qxl_post_load(int qid, const char *mode) "%d %s" +@@ -962,7 +962,7 @@ qxl_spice_destroy_surfaces(int qid, int async) "%d async=%d" + qxl_spice_destroy_surface_wait_complete(int qid, uint32_t id) "%d sid=%d" + qxl_spice_destroy_surface_wait(int qid, uint32_t id, int async) "%d sid=%d async=%d" + qxl_spice_flush_surfaces_async(int qid, uint32_t surface_count, uint32_t num_free_res) "%d s#=%d, res#=%d" +-qxl_spice_monitors_config(int id) "%d" ++qxl_spice_monitors_config(int qid) "%d" + qxl_spice_loadvm_commands(int qid, void *ext, uint32_t count) "%d ext=%p count=%d" + qxl_spice_oom(int qid) "%d" + qxl_spice_reset_cursor(int qid) "%d" +@@ -971,6 +971,8 @@ qxl_spice_reset_memslots(int qid) "%d" + qxl_spice_update_area(int qid, uint32_t surface_id, uint32_t left, uint32_t right, uint32_t top, uint32_t bottom) "%d sid=%d [%d,%d,%d,%d]" + qxl_spice_update_area_rest(int qid, uint32_t num_dirty_rects, uint32_t clear_dirty_region) "%d #d=%d clear=%d" + qxl_surfaces_dirty(int qid, int surface, int offset, int size) "%d surface=%d offset=%d size=%d" ++qxl_send_events(int qid, uint32_t events) "%d %d" ++qxl_set_guest_bug(int qid) "%d" + + # hw/qxl-render.c + qxl_render_blit_guest_primary_initialized(void) "" +-- +1.7.12.1 + diff --git a/0170-configure-usbredir-fixes.patch b/0170-configure-usbredir-fixes.patch new file mode 100644 index 0000000..cf87afa --- /dev/null +++ b/0170-configure-usbredir-fixes.patch @@ -0,0 +1,36 @@ +From 00d9118be03020d3a905bd0a61f74eccd76edee9 Mon Sep 17 00:00:00 2001 +From: Aurelien Jarno +Date: Tue, 11 Sep 2012 20:57:58 +0200 +Subject: [PATCH] configure: usbredir fixes + +usbredir is only used by system emulation, so add the libraries to +libs_softmmu instead of LIBS. + +Cc: Michael Tokarev +Cc: Gerd Hoffmann +Signed-off-by: Aurelien Jarno +Signed-off-by: Hans de Goede +Signed-off-by: Gerd Hoffmann +(cherry picked from commit 56ab2ad177dc43d474dc0a0bd84e81ef00f31e11) + +Signed-off-by: Michael Roth +--- + configure | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/configure b/configure +index a8061c1..dcd8e7b 100755 +--- a/configure ++++ b/configure +@@ -2737,7 +2737,7 @@ if test "$usb_redir" != "no" ; then + usb_redir_cflags=$($pkg_config --cflags libusbredirparser 2>/dev/null) + usb_redir_libs=$($pkg_config --libs libusbredirparser 2>/dev/null) + QEMU_CFLAGS="$QEMU_CFLAGS $usb_redir_cflags" +- LIBS="$LIBS $usb_redir_libs" ++ libs_softmmu="$libs_softmmu $usb_redir_libs" + else + if test "$usb_redir" = "yes"; then + feature_not_found "usb-redir" +-- +1.7.12.1 + diff --git a/0171-ehci-Don-t-set-seen-to-0-when-removing-unseen-queue-.patch b/0171-ehci-Don-t-set-seen-to-0-when-removing-unseen-queue-.patch new file mode 100644 index 0000000..de9f4ac --- /dev/null +++ b/0171-ehci-Don-t-set-seen-to-0-when-removing-unseen-queue-.patch @@ -0,0 +1,104 @@ +From ade9c6dfbbf573c22800d7ff6df7f0de933e7c96 Mon Sep 17 00:00:00 2001 +From: Hans de Goede +Date: Wed, 12 Sep 2012 15:08:32 +0200 +Subject: [PATCH] ehci: Don't set seen to 0 when removing unseen queue-heads + +When removing unseen queue-heads from the async queue list, we should not +set the seen flag to 0, as this may cause them to be removed by +ehci_queues_rip_unused() during the next call to ehci_advance_async_state() +if the timer is late or running at a low frequency. + +Note: +1) This *may* have caused the instant unlink / relinks described in commit + 9bc3a3a216e2689bfcdd36c3e079333bbdbf3ba0 + +2) Rather then putting more if-s inside ehci_queues_rip_unused, this patch + instead introduces a new ehci_queues_rip_unseen function. + +3) This patch also makes it save to call ehci_queues_rip_unseen() multiple + times, which gets used in the folluw up patch titled: + "ehci: Walk async schedule before and after migration" + +Signed-off-by: Hans de Goede +Signed-off-by: Gerd Hoffmann +(cherry picked from commit 8f5457eb04140714eaf57a99bc08dc661d83fa87) + +Signed-off-by: Michael Roth +--- + hw/usb/hcd-ehci.c | 24 ++++++++++++++++++------ + 1 file changed, 18 insertions(+), 6 deletions(-) + +diff --git a/hw/usb/hcd-ehci.c b/hw/usb/hcd-ehci.c +index 017a01d..bc86460 100644 +--- a/hw/usb/hcd-ehci.c ++++ b/hw/usb/hcd-ehci.c +@@ -848,10 +848,10 @@ static EHCIQueue *ehci_find_queue_by_qh(EHCIState *ehci, uint32_t addr, + return NULL; + } + +-static void ehci_queues_rip_unused(EHCIState *ehci, int async, int flush) ++static void ehci_queues_rip_unused(EHCIState *ehci, int async) + { + EHCIQueueHead *head = async ? &ehci->aqueues : &ehci->pqueues; +- const char *warn = (async && !flush) ? "guest unlinked busy QH" : NULL; ++ const char *warn = async ? "guest unlinked busy QH" : NULL; + uint64_t maxage = FRAME_TIMER_NS * ehci->maxframes * 4; + EHCIQueue *q, *tmp; + +@@ -861,13 +861,25 @@ static void ehci_queues_rip_unused(EHCIState *ehci, int async, int flush) + q->ts = ehci->last_run_ns; + continue; + } +- if (!flush && ehci->last_run_ns < q->ts + maxage) { ++ if (ehci->last_run_ns < q->ts + maxage) { + continue; + } + ehci_free_queue(q, warn); + } + } + ++static void ehci_queues_rip_unseen(EHCIState *ehci, int async) ++{ ++ EHCIQueueHead *head = async ? &ehci->aqueues : &ehci->pqueues; ++ EHCIQueue *q, *tmp; ++ ++ QTAILQ_FOREACH_SAFE(q, head, next, tmp) { ++ if (!q->seen) { ++ ehci_free_queue(q, NULL); ++ } ++ } ++} ++ + static void ehci_queues_rip_device(EHCIState *ehci, USBDevice *dev, int async) + { + EHCIQueueHead *head = async ? &ehci->aqueues : &ehci->pqueues; +@@ -1700,7 +1712,7 @@ static int ehci_state_waitlisthead(EHCIState *ehci, int async) + ehci_set_usbsts(ehci, USBSTS_REC); + } + +- ehci_queues_rip_unused(ehci, async, 0); ++ ehci_queues_rip_unused(ehci, async); + + /* Find the head of the list (4.9.1.1) */ + for(i = 0; i < MAX_QH; i++) { +@@ -2332,7 +2344,7 @@ static void ehci_advance_async_state(EHCIState *ehci) + */ + if (ehci->usbcmd & USBCMD_IAAD) { + /* Remove all unseen qhs from the async qhs queue */ +- ehci_queues_rip_unused(ehci, async, 1); ++ ehci_queues_rip_unseen(ehci, async); + trace_usb_ehci_doorbell_ack(); + ehci->usbcmd &= ~USBCMD_IAAD; + ehci_raise_irq(ehci, USBSTS_IAA); +@@ -2385,7 +2397,7 @@ static void ehci_advance_periodic_state(EHCIState *ehci) + ehci_set_fetch_addr(ehci, async,entry); + ehci_set_state(ehci, async, EST_FETCHENTRY); + ehci_advance_state(ehci, async); +- ehci_queues_rip_unused(ehci, async, 0); ++ ehci_queues_rip_unused(ehci, async); + break; + + default: +-- +1.7.12.1 + diff --git a/0172-ehci-Walk-async-schedule-before-and-after-migration.patch b/0172-ehci-Walk-async-schedule-before-and-after-migration.patch new file mode 100644 index 0000000..476e41e --- /dev/null +++ b/0172-ehci-Walk-async-schedule-before-and-after-migration.patch @@ -0,0 +1,70 @@ +From 6b145e32e9e219c723b4911aac0a96ea2aa70e77 Mon Sep 17 00:00:00 2001 +From: Hans de Goede +Date: Wed, 12 Sep 2012 15:08:33 +0200 +Subject: [PATCH] ehci: Walk async schedule before and after migration + +Signed-off-by: Hans de Goede +Signed-off-by: Gerd Hoffmann +(cherry picked from commit ceab6f96454fe6589d1b09ce64403c041d79f9d9) + +Signed-off-by: Michael Roth +--- + hw/usb/hcd-ehci.c | 28 ++++++++++++++++++++++++++++ + 1 file changed, 28 insertions(+) + +diff --git a/hw/usb/hcd-ehci.c b/hw/usb/hcd-ehci.c +index bc86460..6a5da84 100644 +--- a/hw/usb/hcd-ehci.c ++++ b/hw/usb/hcd-ehci.c +@@ -34,6 +34,7 @@ + #include "monitor.h" + #include "trace.h" + #include "dma.h" ++#include "sysemu.h" + + #define EHCI_DEBUG 0 + +@@ -2572,6 +2573,32 @@ static int usb_ehci_post_load(void *opaque, int version_id) + return 0; + } + ++static void usb_ehci_vm_state_change(void *opaque, int running, RunState state) ++{ ++ EHCIState *ehci = opaque; ++ ++ /* ++ * We don't migrate the EHCIQueue-s, instead we rebuild them for the ++ * schedule in guest memory. We must do the rebuilt ASAP, so that ++ * USB-devices which have async handled packages have a packet in the ++ * ep queue to match the completion with. ++ */ ++ if (state == RUN_STATE_RUNNING) { ++ ehci_advance_async_state(ehci); ++ } ++ ++ /* ++ * The schedule rebuilt from guest memory could cause the migration dest ++ * to miss a QH unlink, and fail to cancel packets, since the unlinked QH ++ * will never have existed on the destination. Therefor we must flush the ++ * async schedule on savevm to catch any not yet noticed unlinks. ++ */ ++ if (state == RUN_STATE_SAVE_VM) { ++ ehci_advance_async_state(ehci); ++ ehci_queues_rip_unseen(ehci, 1); ++ } ++} ++ + static const VMStateDescription vmstate_ehci = { + .name = "ehci", + .version_id = 2, +@@ -2721,6 +2748,7 @@ static int usb_ehci_initfn(PCIDevice *dev) + usb_packet_init(&s->ipacket); + + qemu_register_reset(ehci_reset, s); ++ qemu_add_vm_change_state_handler(usb_ehci_vm_state_change, s); + + memory_region_init(&s->mem, "ehci", MMIO_SIZE); + memory_region_init_io(&s->mem_caps, &ehci_mmio_caps_ops, s, +-- +1.7.12.1 + diff --git a/0173-usb-redir-Revert-usb-redir-part-of-commit-93bfef4c.patch b/0173-usb-redir-Revert-usb-redir-part-of-commit-93bfef4c.patch new file mode 100644 index 0000000..11125f2 --- /dev/null +++ b/0173-usb-redir-Revert-usb-redir-part-of-commit-93bfef4c.patch @@ -0,0 +1,63 @@ +From 9f6674cd9bf6e0e3bafa8b8ec8388576756a6d13 Mon Sep 17 00:00:00 2001 +From: Hans de Goede +Date: Wed, 12 Sep 2012 15:08:39 +0200 +Subject: [PATCH] usb-redir: Revert usb-redir part of commit 93bfef4c + +Commit 93bfef4c6e4b23caea9d51e1099d06433d8835a4 makes qemu-devices +which report the qemu version string to the guest in some way use a +qemu_get_version function which reports a machine-specific version string. + +However usb-redir does not expose the qemu version to the guest, only to +the usbredir-host as part of the initial handshake. This can then be logged +on the usbredir-host side for debugging purposes and is otherwise completely +unused! For debugging purposes it is important to have the real qemu version +in there, rather then the machine-specific version. + +Signed-off-by: Hans de Goede +Signed-off-by: Gerd Hoffmann +(cherry picked from commit 35efba2cc6812dc980c336d7b9bf81dbfb5daf00) + +Conflicts: + + hw/usb/redirect.c + +Signed-off-by: Michael Roth +--- + hw/usb/redirect.c | 7 +++---- + 1 file changed, 3 insertions(+), 4 deletions(-) + +diff --git a/hw/usb/redirect.c b/hw/usb/redirect.c +index ee75217..ab8d79a 100644 +--- a/hw/usb/redirect.c ++++ b/hw/usb/redirect.c +@@ -134,6 +134,8 @@ static void usbredir_interrupt_packet(void *priv, uint32_t id, + static int usbredir_handle_status(USBRedirDevice *dev, + int status, int actual_len); + ++#define VERSION "qemu usb-redir guest " QEMU_VERSION ++ + /* + * Logging stuff + */ +@@ -777,9 +779,6 @@ static void usbredir_chardev_open(USBRedirDevice *dev) + usbredir_chardev_close_bh(dev); + qemu_bh_cancel(dev->chardev_close_bh); + +- strcpy(version, "qemu usb-redir guest "); +- pstrcat(version, sizeof(version), qemu_get_version()); +- + dev->parser = qemu_oom_check(usbredirparser_create()); + dev->parser->priv = dev; + dev->parser->log_func = usbredir_log; +@@ -805,7 +804,7 @@ static void usbredir_chardev_open(USBRedirDevice *dev) + + usbredirparser_caps_set_cap(caps, usb_redir_cap_connect_device_version); + usbredirparser_caps_set_cap(caps, usb_redir_cap_filter); +- usbredirparser_init(dev->parser, version, caps, USB_REDIR_CAPS_SIZE, 0); ++ usbredirparser_init(dev->parser, VERSION, caps, USB_REDIR_CAPS_SIZE, 0); + usbredirparser_do_write(dev->parser); + } + +-- +1.7.12.1 + diff --git a/0174-uhci-Don-t-queue-up-packets-after-one-with-the-SPD-f.patch b/0174-uhci-Don-t-queue-up-packets-after-one-with-the-SPD-f.patch new file mode 100644 index 0000000..a135563 --- /dev/null +++ b/0174-uhci-Don-t-queue-up-packets-after-one-with-the-SPD-f.patch @@ -0,0 +1,47 @@ +From 48dbbecb0b010ff1c6a64a3a18a7272cce314bf8 Mon Sep 17 00:00:00 2001 +From: Hans de Goede +Date: Wed, 12 Sep 2012 15:08:40 +0200 +Subject: [PATCH] uhci: Don't queue up packets after one with the SPD flag set + +Don't queue up packets after a packet with the SPD (short packet detect) +flag set. Since we won't know if the packet will actually be short until it +has completed, and if it is short we should stop the queue. + +This fixes a miniature photoframe emulating a USB cdrom with the windows +software for it not working. + +Signed-off-by: Hans de Goede +Signed-off-by: Gerd Hoffmann +(cherry picked from commit 72a04d0c178f01908d74539230d9de64ffc6da19) + +Signed-off-by: Michael Roth +--- + hw/usb/hcd-uhci.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/hw/usb/hcd-uhci.c b/hw/usb/hcd-uhci.c +index c7c8786..cdc8bc3 100644 +--- a/hw/usb/hcd-uhci.c ++++ b/hw/usb/hcd-uhci.c +@@ -1000,6 +1000,9 @@ static void uhci_fill_queue(UHCIState *s, UHCI_TD *td) + } + assert(ret == TD_RESULT_ASYNC_START); + assert(int_mask == 0); ++ if (ptd.ctrl & TD_CTRL_SPD) { ++ break; ++ } + plink = ptd.link; + } + } +@@ -1097,7 +1100,7 @@ static void uhci_process_frame(UHCIState *s) + + case TD_RESULT_ASYNC_START: + trace_usb_uhci_td_async(curr_qh & ~0xf, link & ~0xf); +- if (is_valid(td.link)) { ++ if (is_valid(td.link) && !(td.ctrl & TD_CTRL_SPD)) { + uhci_fill_queue(s, &td); + } + link = curr_qh ? qh.link : td.link; +-- +1.7.12.1 + diff --git a/0175-slirp-Remove-wrong-type-casts-ins-debug-statements.patch b/0175-slirp-Remove-wrong-type-casts-ins-debug-statements.patch new file mode 100644 index 0000000..365d586 --- /dev/null +++ b/0175-slirp-Remove-wrong-type-casts-ins-debug-statements.patch @@ -0,0 +1,37 @@ +From 3196332dd2ca39a9b06562856b80b825217e3c96 Mon Sep 17 00:00:00 2001 +From: Stefan Weil +Date: Tue, 4 Sep 2012 23:20:35 +0200 +Subject: [PATCH] slirp: Remove wrong type casts ins debug statements + +The type casts of pointers to long are not allowed +when sizeof(pointer) != sizeof(long). + +Signed-off-by: Stefan Weil +Signed-off-by: Jan Kiszka +(cherry picked from commit c4d12a743c73a5b88a8705ca68ff620ce0f8bba7) + +Signed-off-by: Michael Roth +--- + slirp/tcp_subr.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/slirp/tcp_subr.c b/slirp/tcp_subr.c +index 025b374..5890d7a 100644 +--- a/slirp/tcp_subr.c ++++ b/slirp/tcp_subr.c +@@ -114,9 +114,9 @@ tcp_respond(struct tcpcb *tp, struct tcpiphdr *ti, struct mbuf *m, + int win = 0; + + DEBUG_CALL("tcp_respond"); +- DEBUG_ARG("tp = %lx", (long)tp); +- DEBUG_ARG("ti = %lx", (long)ti); +- DEBUG_ARG("m = %lx", (long)m); ++ DEBUG_ARG("tp = %p", tp); ++ DEBUG_ARG("ti = %p", ti); ++ DEBUG_ARG("m = %p", m); + DEBUG_ARG("ack = %u", ack); + DEBUG_ARG("seq = %u", seq); + DEBUG_ARG("flags = %x", flags); +-- +1.7.12.1 + diff --git a/0176-slirp-Fix-error-reported-by-static-code-analysis.patch b/0176-slirp-Fix-error-reported-by-static-code-analysis.patch new file mode 100644 index 0000000..7f2a90a --- /dev/null +++ b/0176-slirp-Fix-error-reported-by-static-code-analysis.patch @@ -0,0 +1,37 @@ +From b88c1cb2b263de9ffc3dcaa2822ef7b1fbd8575a Mon Sep 17 00:00:00 2001 +From: Stefan Weil +Date: Tue, 4 Sep 2012 23:20:36 +0200 +Subject: [PATCH] slirp: Fix error reported by static code analysis + +Report from smatch: + +slirp/tcp_subr.c:127 tcp_respond(17) error: + we previously assumed 'tp' could be null (see line 124) + +Return if 'tp' is NULL. + +Signed-off-by: Stefan Weil +Signed-off-by: Jan Kiszka +(cherry picked from commit e56afbc54a2132c56931f44bae1992c28119944f) + +Signed-off-by: Michael Roth +--- + slirp/tcp_subr.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/slirp/tcp_subr.c b/slirp/tcp_subr.c +index 5890d7a..1542e43 100644 +--- a/slirp/tcp_subr.c ++++ b/slirp/tcp_subr.c +@@ -124,7 +124,7 @@ tcp_respond(struct tcpcb *tp, struct tcpiphdr *ti, struct mbuf *m, + if (tp) + win = sbspace(&tp->t_socket->so_rcv); + if (m == NULL) { +- if ((m = m_get(tp->t_socket->slirp)) == NULL) ++ if (!tp || (m = m_get(tp->t_socket->slirp)) == NULL) + return; + tlen = 0; + m->m_data += IF_MAXLINKHDR; +-- +1.7.12.1 + diff --git a/0177-slirp-improve-TFTP-performance.patch b/0177-slirp-improve-TFTP-performance.patch new file mode 100644 index 0000000..65dce5d --- /dev/null +++ b/0177-slirp-improve-TFTP-performance.patch @@ -0,0 +1,106 @@ +From c1b408d0c9d836e0a95d1e0695c0c6c605ceb368 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Herv=C3=A9=20Poussineau?= +Date: Mon, 10 Sep 2012 20:52:25 +0200 +Subject: [PATCH] slirp: improve TFTP performance +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +When transferring a file, keep it open during the whole transfer, +instead of opening/closing it for each block. + +Signed-off-by: Hervé Poussineau +Reviewed-by: Aurelien Jarno +Signed-off-by: Jan Kiszka +(cherry picked from commit 78be056628c76ff73eedeade86fde44b97343c79) + +Signed-off-by: Michael Roth +--- + slirp/tftp.c | 32 ++++++++++++++++++-------------- + slirp/tftp.h | 1 + + 2 files changed, 19 insertions(+), 14 deletions(-) + +diff --git a/slirp/tftp.c b/slirp/tftp.c +index b78765f..520dbd6 100644 +--- a/slirp/tftp.c ++++ b/slirp/tftp.c +@@ -37,6 +37,10 @@ static inline void tftp_session_update(struct tftp_session *spt) + + static void tftp_session_terminate(struct tftp_session *spt) + { ++ if (spt->fd >= 0) { ++ close(spt->fd); ++ spt->fd = -1; ++ } + g_free(spt->filename); + spt->slirp = NULL; + } +@@ -54,7 +58,7 @@ static int tftp_session_allocate(Slirp *slirp, struct tftp_t *tp) + + /* sessions time out after 5 inactive seconds */ + if ((int)(curtime - spt->timestamp) > 5000) { +- g_free(spt->filename); ++ tftp_session_terminate(spt); + goto found; + } + } +@@ -64,6 +68,7 @@ static int tftp_session_allocate(Slirp *slirp, struct tftp_t *tp) + found: + memset(spt, 0, sizeof(*spt)); + memcpy(&spt->client_ip, &tp->ip.ip_src, sizeof(spt->client_ip)); ++ spt->fd = -1; + spt->client_port = tp->udp.uh_sport; + spt->slirp = slirp; + +@@ -95,24 +100,23 @@ static int tftp_session_find(Slirp *slirp, struct tftp_t *tp) + static int tftp_read_data(struct tftp_session *spt, uint16_t block_nr, + uint8_t *buf, int len) + { +- int fd; +- int bytes_read = 0; +- +- fd = open(spt->filename, O_RDONLY | O_BINARY); ++ int bytes_read = 0; + +- if (fd < 0) { +- return -1; +- } ++ if (spt->fd < 0) { ++ spt->fd = open(spt->filename, O_RDONLY | O_BINARY); ++ } + +- if (len) { +- lseek(fd, block_nr * 512, SEEK_SET); ++ if (spt->fd < 0) { ++ return -1; ++ } + +- bytes_read = read(fd, buf, len); +- } ++ if (len) { ++ lseek(spt->fd, block_nr * 512, SEEK_SET); + +- close(fd); ++ bytes_read = read(spt->fd, buf, len); ++ } + +- return bytes_read; ++ return bytes_read; + } + + static int tftp_send_oack(struct tftp_session *spt, +diff --git a/slirp/tftp.h b/slirp/tftp.h +index 72e5e91..9c364ea 100644 +--- a/slirp/tftp.h ++++ b/slirp/tftp.h +@@ -33,6 +33,7 @@ struct tftp_t { + struct tftp_session { + Slirp *slirp; + char *filename; ++ int fd; + + struct in_addr client_ip; + uint16_t client_port; +-- +1.7.12.1 + diff --git a/0178-slirp-Handle-more-than-65535-blocks-in-TFTP-transfer.patch b/0178-slirp-Handle-more-than-65535-blocks-in-TFTP-transfer.patch new file mode 100644 index 0000000..0a87572 --- /dev/null +++ b/0178-slirp-Handle-more-than-65535-blocks-in-TFTP-transfer.patch @@ -0,0 +1,121 @@ +From 5579c7740b29be4766ace824af36acb9ab254ecb Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Herv=C3=A9=20Poussineau?= +Date: Thu, 13 Sep 2012 12:39:36 +0200 +Subject: [PATCH] slirp: Handle more than 65535 blocks in TFTP transfers +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +RFC 1350 does not mention block count roll-over. However, a lot of TFTP servers +implement it to be able to transmit big files, so do it also. + +Current block size is 512 bytes, so TFTP files were limited to 32 MB. + +Signed-off-by: Hervé Poussineau +Signed-off-by: Jan Kiszka +(cherry picked from commit 4aa401f39e048e71020cceb59f126ab941095a42) + +Signed-off-by: Michael Roth +--- + slirp/tftp.c | 24 ++++++++++-------------- + slirp/tftp.h | 1 + + 2 files changed, 11 insertions(+), 14 deletions(-) + +diff --git a/slirp/tftp.c b/slirp/tftp.c +index 520dbd6..c6a5df2 100644 +--- a/slirp/tftp.c ++++ b/slirp/tftp.c +@@ -97,7 +97,7 @@ static int tftp_session_find(Slirp *slirp, struct tftp_t *tp) + return -1; + } + +-static int tftp_read_data(struct tftp_session *spt, uint16_t block_nr, ++static int tftp_read_data(struct tftp_session *spt, uint32_t block_nr, + uint8_t *buf, int len) + { + int bytes_read = 0; +@@ -197,19 +197,14 @@ out: + tftp_session_terminate(spt); + } + +-static int tftp_send_data(struct tftp_session *spt, +- uint16_t block_nr, +- struct tftp_t *recv_tp) ++static int tftp_send_next_block(struct tftp_session *spt, ++ struct tftp_t *recv_tp) + { + struct sockaddr_in saddr, daddr; + struct mbuf *m; + struct tftp_t *tp; + int nobytes; + +- if (block_nr < 1) { +- return -1; +- } +- + m = m_get(spt->slirp); + + if (!m) { +@@ -223,7 +218,7 @@ static int tftp_send_data(struct tftp_session *spt, + m->m_data += sizeof(struct udpiphdr); + + tp->tp_op = htons(TFTP_DATA); +- tp->x.tp_data.tp_block_nr = htons(block_nr); ++ tp->x.tp_data.tp_block_nr = htons((spt->block_nr + 1) & 0xffff); + + saddr.sin_addr = recv_tp->ip.ip_dst; + saddr.sin_port = recv_tp->udp.uh_dport; +@@ -231,7 +226,7 @@ static int tftp_send_data(struct tftp_session *spt, + daddr.sin_addr = spt->client_ip; + daddr.sin_port = spt->client_port; + +- nobytes = tftp_read_data(spt, block_nr - 1, tp->x.tp_data.tp_buf, 512); ++ nobytes = tftp_read_data(spt, spt->block_nr, tp->x.tp_data.tp_buf, 512); + + if (nobytes < 0) { + m_free(m); +@@ -255,6 +250,7 @@ static int tftp_send_data(struct tftp_session *spt, + tftp_session_terminate(spt); + } + ++ spt->block_nr++; + return 0; + } + +@@ -373,7 +369,8 @@ static void tftp_handle_rrq(Slirp *slirp, struct tftp_t *tp, int pktlen) + } + } + +- tftp_send_data(spt, 1, tp); ++ spt->block_nr = 0; ++ tftp_send_next_block(spt, tp); + } + + static void tftp_handle_ack(Slirp *slirp, struct tftp_t *tp, int pktlen) +@@ -386,9 +383,8 @@ static void tftp_handle_ack(Slirp *slirp, struct tftp_t *tp, int pktlen) + return; + } + +- if (tftp_send_data(&slirp->tftp_sessions[s], +- ntohs(tp->x.tp_data.tp_block_nr) + 1, +- tp) < 0) { ++ if (tftp_send_next_block(&slirp->tftp_sessions[s], ++ tp) < 0) { + return; + } + } +diff --git a/slirp/tftp.h b/slirp/tftp.h +index 9c364ea..51704e4 100644 +--- a/slirp/tftp.h ++++ b/slirp/tftp.h +@@ -37,6 +37,7 @@ struct tftp_session { + + struct in_addr client_ip; + uint16_t client_port; ++ uint32_t block_nr; + + int timestamp; + }; +-- +1.7.12.1 + diff --git a/0179-slirp-Implement-TFTP-Blocksize-option.patch b/0179-slirp-Implement-TFTP-Blocksize-option.patch new file mode 100644 index 0000000..38ebba3 --- /dev/null +++ b/0179-slirp-Implement-TFTP-Blocksize-option.patch @@ -0,0 +1,123 @@ +From e070dc7276c7958c322ca0fbf5ac10e639502b4d Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Herv=C3=A9=20Poussineau?= +Date: Thu, 13 Sep 2012 07:55:01 +0200 +Subject: [PATCH] slirp: Implement TFTP Blocksize option +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This option is described in RFC 1783. As this is only an optional field, +we may ignore it in some situations and handle it in some others. + +However, MS Windows 2003 PXE boot client requests a block size of the MTU +(most of the times 1472 bytes), and doesn't work if the option is not +acknowledged (with whatever value). + +According to the RFC 1783, we cannot acknowledge the option with a bigger +value than the requested one. + +As current implementation is using 512 bytes by block, accept the option +with a value of 512 if the option was specified, and don't acknowledge it +if it is not present or less than 512 bytes. + +Signed-off-by: Hervé Poussineau +Signed-off-by: Jan Kiszka +(cherry picked from commit 95b1ad7ad86793c27ab8e9987be69571937900d1) + +Signed-off-by: Michael Roth +--- + slirp/tftp.c | 42 +++++++++++++++++++++++++++++++++--------- + 1 file changed, 33 insertions(+), 9 deletions(-) + +diff --git a/slirp/tftp.c b/slirp/tftp.c +index c6a5df2..37b0387 100644 +--- a/slirp/tftp.c ++++ b/slirp/tftp.c +@@ -120,13 +120,13 @@ static int tftp_read_data(struct tftp_session *spt, uint32_t block_nr, + } + + static int tftp_send_oack(struct tftp_session *spt, +- const char *key, uint32_t value, ++ const char *keys[], uint32_t values[], int nb, + struct tftp_t *recv_tp) + { + struct sockaddr_in saddr, daddr; + struct mbuf *m; + struct tftp_t *tp; +- int n = 0; ++ int i, n = 0; + + m = m_get(spt->slirp); + +@@ -140,10 +140,12 @@ static int tftp_send_oack(struct tftp_session *spt, + m->m_data += sizeof(struct udpiphdr); + + tp->tp_op = htons(TFTP_OACK); +- n += snprintf(tp->x.tp_buf + n, sizeof(tp->x.tp_buf) - n, "%s", +- key) + 1; +- n += snprintf(tp->x.tp_buf + n, sizeof(tp->x.tp_buf) - n, "%u", +- value) + 1; ++ for (i = 0; i < nb; i++) { ++ n += snprintf(tp->x.tp_buf + n, sizeof(tp->x.tp_buf) - n, "%s", ++ keys[i]) + 1; ++ n += snprintf(tp->x.tp_buf + n, sizeof(tp->x.tp_buf) - n, "%u", ++ values[i]) + 1; ++ } + + saddr.sin_addr = recv_tp->ip.ip_dst; + saddr.sin_port = recv_tp->udp.uh_dport; +@@ -260,6 +262,9 @@ static void tftp_handle_rrq(Slirp *slirp, struct tftp_t *tp, int pktlen) + int s, k; + size_t prefix_len; + char *req_fname; ++ const char *option_name[2]; ++ uint32_t option_value[2]; ++ int nb_options = 0; + + /* check if a session already exists and if so terminate it */ + s = tftp_session_find(slirp, tp); +@@ -337,7 +342,7 @@ static void tftp_handle_rrq(Slirp *slirp, struct tftp_t *tp, int pktlen) + return; + } + +- while (k < pktlen) { ++ while (k < pktlen && nb_options < ARRAY_SIZE(option_name)) { + const char *key, *value; + + key = &tp->x.tp_buf[k]; +@@ -364,11 +369,30 @@ static void tftp_handle_rrq(Slirp *slirp, struct tftp_t *tp, int pktlen) + } + } + +- tftp_send_oack(spt, "tsize", tsize, tp); +- return; ++ option_name[nb_options] = "tsize"; ++ option_value[nb_options] = tsize; ++ nb_options++; ++ } else if (strcasecmp(key, "blksize") == 0) { ++ int blksize = atoi(value); ++ ++ /* If blksize option is bigger than what we will ++ * emit, accept the option with our packet size. ++ * Otherwise, simply do as we didn't see the option. ++ */ ++ if (blksize >= 512) { ++ option_name[nb_options] = "blksize"; ++ option_value[nb_options] = 512; ++ nb_options++; ++ } + } + } + ++ if (nb_options > 0) { ++ assert(nb_options <= ARRAY_SIZE(option_name)); ++ tftp_send_oack(spt, option_name, option_value, nb_options, tp); ++ return; ++ } ++ + spt->block_nr = 0; + tftp_send_next_block(spt, tp); + } +-- +1.7.12.1 + diff --git a/0180-srp-Don-t-use-QEMU_PACKED-for-single-elements-of-a-s.patch b/0180-srp-Don-t-use-QEMU_PACKED-for-single-elements-of-a-s.patch new file mode 100644 index 0000000..00cb718 --- /dev/null +++ b/0180-srp-Don-t-use-QEMU_PACKED-for-single-elements-of-a-s.patch @@ -0,0 +1,63 @@ +From 66cbaa761bc0f6d528957f9e3bc5762acb7f5f1c Mon Sep 17 00:00:00 2001 +From: Stefan Weil +Date: Fri, 10 Aug 2012 22:03:27 +0200 +Subject: [PATCH] srp: Don't use QEMU_PACKED for single elements of a + structured type + +QEMU_PACKED results in a MinGW compiler warning when it is +used for single structure elements: + +warning: 'gcc_struct' attribute ignored + +Using QEMU_PACKED for the whole structure avoids the compiler warning +without changing the memory layout. + +Signed-off-by: Stefan Weil +Signed-off-by: Stefan Hajnoczi +(cherry picked from commit 93d3ad2a8048469d2b2bb157697425b66b2a37aa) + +Signed-off-by: Michael Roth +--- + hw/srp.h | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/hw/srp.h b/hw/srp.h +index 3009bd5..5e0cad5 100644 +--- a/hw/srp.h ++++ b/hw/srp.h +@@ -177,13 +177,13 @@ struct srp_tsk_mgmt { + uint8_t reserved1[6]; + uint64_t tag; + uint8_t reserved2[4]; +- uint64_t lun QEMU_PACKED; ++ uint64_t lun; + uint8_t reserved3[2]; + uint8_t tsk_mgmt_func; + uint8_t reserved4; + uint64_t task_tag; + uint8_t reserved5[8]; +-}; ++} QEMU_PACKED; + + /* + * We need the packed attribute because the SRP spec only aligns the +@@ -198,14 +198,14 @@ struct srp_cmd { + uint8_t data_in_desc_cnt; + uint64_t tag; + uint8_t reserved2[4]; +- uint64_t lun QEMU_PACKED; ++ uint64_t lun; + uint8_t reserved3; + uint8_t task_attr; + uint8_t reserved4; + uint8_t add_cdb_len; + uint8_t cdb[16]; + uint8_t add_data[0]; +-}; ++} QEMU_PACKED; + + enum { + SRP_RSP_FLAG_RSPVALID = 1 << 0, +-- +1.7.12.1 + diff --git a/0181-Spelling-fixes-in-comments-and-documentation.patch b/0181-Spelling-fixes-in-comments-and-documentation.patch new file mode 100644 index 0000000..5b696ed --- /dev/null +++ b/0181-Spelling-fixes-in-comments-and-documentation.patch @@ -0,0 +1,183 @@ +From ca94ceccca88d284e5d638961b21bd83eac944db Mon Sep 17 00:00:00 2001 +From: Stefan Weil +Date: Fri, 10 Aug 2012 22:03:25 +0200 +Subject: [PATCH] Spelling fixes in comments and documentation + +These wrong spellings were detected by codespell: + +* successully -> successfully + +* alot -> a lot + +* wanna -> want to + +* infomation -> information + +* occured -> occurred + +["also is" -> "is also" and "ressources" -> "resources" suggested by +Peter Maydell ] + +Signed-off-by: Stefan Weil +Signed-off-by: Stefan Hajnoczi +(cherry picked from commit 0546b8c2f089867cd7606ff47e026e8931157828) + +Signed-off-by: Michael Roth +--- + docs/specs/ppc-spapr-hcalls.txt | 2 +- + docs/usb2.txt | 4 ++-- + hw/xen_pt.h | 4 ++-- + hw/xen_pt_config_init.c | 14 +++++++------- + qemu-img.c | 2 +- + qemu-img.texi | 2 +- + 6 files changed, 14 insertions(+), 14 deletions(-) + +diff --git a/docs/specs/ppc-spapr-hcalls.txt b/docs/specs/ppc-spapr-hcalls.txt +index 52ba8d4..667b3fa 100644 +--- a/docs/specs/ppc-spapr-hcalls.txt ++++ b/docs/specs/ppc-spapr-hcalls.txt +@@ -31,7 +31,7 @@ Arguments: + + Returns: + +- H_SUCCESS : Successully called the RTAS function (RTAS result ++ H_SUCCESS : Successfully called the RTAS function (RTAS result + will have been stored in the parameter block) + H_PARAMETER : Unknown token + +diff --git a/docs/usb2.txt b/docs/usb2.txt +index d17e3c0..43dacde 100644 +--- a/docs/usb2.txt ++++ b/docs/usb2.txt +@@ -58,11 +58,11 @@ try ... + xhci controller support + ----------------------- + +-There also is xhci host controller support available. It got alot ++There is also xhci host controller support available. It got a lot + less testing than ehci and there are a bunch of known limitations, so + ehci may work better for you. On the other hand the xhci hardware + design is much more virtualization-friendly, thus xhci emulation uses +-less ressources (especially cpu). If you wanna give xhci a try ++less resources (especially cpu). If you want to give xhci a try + use this to add the host controller ... + + qemu -device nec-usb-xhci,id=xhci +diff --git a/hw/xen_pt.h b/hw/xen_pt.h +index 41904ec..112477a 100644 +--- a/hw/xen_pt.h ++++ b/hw/xen_pt.h +@@ -96,7 +96,7 @@ typedef struct XenPTRegion { + * - do NOT use ALL F for init_val, otherwise the tbl will not be registered. + */ + +-/* emulated register infomation */ ++/* emulated register information */ + struct XenPTRegInfo { + uint32_t offset; + uint32_t size; +@@ -140,7 +140,7 @@ typedef int (*xen_pt_reg_size_init_fn) + (XenPCIPassthroughState *, const XenPTRegGroupInfo *, + uint32_t base_offset, uint8_t *size); + +-/* emulated register group infomation */ ++/* emulated register group information */ + struct XenPTRegGroupInfo { + uint8_t grp_id; + XenPTRegisterGroupType grp_type; +diff --git a/hw/xen_pt_config_init.c b/hw/xen_pt_config_init.c +index 00eb3d9..e524a40 100644 +--- a/hw/xen_pt_config_init.c ++++ b/hw/xen_pt_config_init.c +@@ -562,7 +562,7 @@ static int xen_pt_exp_rom_bar_reg_write(XenPCIPassthroughState *s, + return 0; + } + +-/* Header Type0 reg static infomation table */ ++/* Header Type0 reg static information table */ + static XenPTRegInfo xen_pt_emu_reg_header0[] = { + /* Vendor ID reg */ + { +@@ -753,7 +753,7 @@ static XenPTRegInfo xen_pt_emu_reg_header0[] = { + * Vital Product Data Capability + */ + +-/* Vital Product Data Capability Structure reg static infomation table */ ++/* Vital Product Data Capability Structure reg static information table */ + static XenPTRegInfo xen_pt_emu_reg_vpd[] = { + { + .offset = PCI_CAP_LIST_NEXT, +@@ -775,7 +775,7 @@ static XenPTRegInfo xen_pt_emu_reg_vpd[] = { + * Vendor Specific Capability + */ + +-/* Vendor Specific Capability Structure reg static infomation table */ ++/* Vendor Specific Capability Structure reg static information table */ + static XenPTRegInfo xen_pt_emu_reg_vendor[] = { + { + .offset = PCI_CAP_LIST_NEXT, +@@ -866,7 +866,7 @@ static int xen_pt_linkctrl2_reg_init(XenPCIPassthroughState *s, + return 0; + } + +-/* PCI Express Capability Structure reg static infomation table */ ++/* PCI Express Capability Structure reg static information table */ + static XenPTRegInfo xen_pt_emu_reg_pcie[] = { + /* Next Pointer reg */ + { +@@ -981,7 +981,7 @@ static int xen_pt_pmcsr_reg_write(XenPCIPassthroughState *s, + return 0; + } + +-/* Power Management Capability reg static infomation table */ ++/* Power Management Capability reg static information table */ + static XenPTRegInfo xen_pt_emu_reg_pm[] = { + /* Next Pointer reg */ + { +@@ -1259,7 +1259,7 @@ static int xen_pt_msgdata_reg_write(XenPCIPassthroughState *s, + return 0; + } + +-/* MSI Capability Structure reg static infomation table */ ++/* MSI Capability Structure reg static information table */ + static XenPTRegInfo xen_pt_emu_reg_msi[] = { + /* Next Pointer reg */ + { +@@ -1396,7 +1396,7 @@ static int xen_pt_msixctrl_reg_write(XenPCIPassthroughState *s, + return 0; + } + +-/* MSI-X Capability Structure reg static infomation table */ ++/* MSI-X Capability Structure reg static information table */ + static XenPTRegInfo xen_pt_emu_reg_msix[] = { + /* Next Pointer reg */ + { +diff --git a/qemu-img.c b/qemu-img.c +index 0d208e8..7615e91 100644 +--- a/qemu-img.c ++++ b/qemu-img.c +@@ -89,7 +89,7 @@ static void help(void) + " '-r' tries to repair any inconsistencies that are found during the check.\n" + " '-r leaks' repairs only cluster leaks, whereas '-r all' fixes all\n" + " kinds of errors, with a higher risk of choosing the wrong fix or\n" +- " hiding corruption that has already occured.\n" ++ " hiding corruption that has already occurred.\n" + "\n" + "Parameters to snapshot subcommand:\n" + " 'snapshot' is the name of the snapshot to create, apply or delete\n" +diff --git a/qemu-img.texi b/qemu-img.texi +index 6b42e35..360543b 100644 +--- a/qemu-img.texi ++++ b/qemu-img.texi +@@ -87,7 +87,7 @@ Perform a consistency check on the disk image @var{filename}. + If @code{-r} is specified, qemu-img tries to repair any inconsistencies found + during the check. @code{-r leaks} repairs only cluster leaks, whereas + @code{-r all} fixes all kinds of errors, with a higher risk of choosing the +-wrong fix or hiding corruption that has already occured. ++wrong fix or hiding corruption that has already occurred. + + Only the formats @code{qcow2}, @code{qed} and @code{vdi} support + consistency checks. +-- +1.7.12.1 + diff --git a/0182-console-Clean-up-bytes-per-pixel-calculation.patch b/0182-console-Clean-up-bytes-per-pixel-calculation.patch new file mode 100644 index 0000000..7815a2d --- /dev/null +++ b/0182-console-Clean-up-bytes-per-pixel-calculation.patch @@ -0,0 +1,51 @@ +From 9c6751bf2b2c817c3f52a638566b99125a0ba0f1 Mon Sep 17 00:00:00 2001 +From: BALATON Zoltan +Date: Wed, 22 Aug 2012 17:19:42 +0200 +Subject: [PATCH] console: Clean up bytes per pixel calculation + +Division with round up is the correct way to compute this even if the +only case where division with round down gives incorrect result is +probably 15 bpp. This case was explicitely patched up in one of these +functions but was unhandled in the other. (I'm not sure about setting +16 bpp for the 15bpp case either but I left that there for now.) + +Signed-off-by: BALATON Zoltan +Signed-off-by: Stefan Hajnoczi +(cherry picked from commit feadf1a4de0d7468ffb671a2b9f681925469fa58) + +Signed-off-by: Michael Roth +--- + console.c | 5 ++--- + 1 file changed, 2 insertions(+), 3 deletions(-) + +diff --git a/console.c b/console.c +index 3b5cabb..8b5e21d 100644 +--- a/console.c ++++ b/console.c +@@ -1611,7 +1611,7 @@ PixelFormat qemu_different_endianness_pixelformat(int bpp) + memset(&pf, 0x00, sizeof(PixelFormat)); + + pf.bits_per_pixel = bpp; +- pf.bytes_per_pixel = bpp / 8; ++ pf.bytes_per_pixel = DIV_ROUND_UP(bpp, 8); + pf.depth = bpp == 32 ? 24 : bpp; + + switch (bpp) { +@@ -1660,13 +1660,12 @@ PixelFormat qemu_default_pixelformat(int bpp) + memset(&pf, 0x00, sizeof(PixelFormat)); + + pf.bits_per_pixel = bpp; +- pf.bytes_per_pixel = bpp / 8; ++ pf.bytes_per_pixel = DIV_ROUND_UP(bpp, 8); + pf.depth = bpp == 32 ? 24 : bpp; + + switch (bpp) { + case 15: + pf.bits_per_pixel = 16; +- pf.bytes_per_pixel = 2; + pf.rmask = 0x00007c00; + pf.gmask = 0x000003E0; + pf.bmask = 0x0000001F; +-- +1.7.12.1 + diff --git a/0183-qapi-Fix-enumeration-typo-error.patch b/0183-qapi-Fix-enumeration-typo-error.patch new file mode 100644 index 0000000..8fc3e9f --- /dev/null +++ b/0183-qapi-Fix-enumeration-typo-error.patch @@ -0,0 +1,54 @@ +From 0ac82308def3b77162f0d9cecb11e6ffd2bd7939 Mon Sep 17 00:00:00 2001 +From: Lei Li +Date: Thu, 23 Aug 2012 13:14:25 +0800 +Subject: [PATCH] qapi: Fix enumeration typo error + +Signed-off-by: Lei Li +Reviewed-by: Luiz Capitulino +Signed-off-by: Stefan Hajnoczi +(cherry picked from commit 6932a69b20a88428c531805cdd20eec8acf05b27) + +Signed-off-by: Michael Roth +--- + qapi-schema-guest.json | 2 +- + qapi-schema.json | 4 ++-- + 2 files changed, 3 insertions(+), 3 deletions(-) + +diff --git a/qapi-schema-guest.json b/qapi-schema-guest.json +index d955cf1..ed0eb69 100644 +--- a/qapi-schema-guest.json ++++ b/qapi-schema-guest.json +@@ -293,7 +293,7 @@ + ## + # @GuestFsFreezeStatus + # +-# An enumation of filesystem freeze states ++# An enumeration of filesystem freeze states + # + # @thawed: filesystems thawed/unfrozen + # +diff --git a/qapi-schema.json b/qapi-schema.json +index 8ddde12..29dacb5 100644 +--- a/qapi-schema.json ++++ b/qapi-schema.json +@@ -118,7 +118,7 @@ + ## + # @RunState + # +-# An enumation of VM run states. ++# An enumeration of VM run states. + # + # @debug: QEMU is running on a debugger + # +@@ -785,7 +785,7 @@ + ## + # @SpiceQueryMouseMode + # +-# An enumation of Spice mouse states. ++# An enumeration of Spice mouse states. + # + # @client: Mouse cursor position is determined by the client. + # +-- +1.7.12.1 + diff --git a/0184-kvm-Fix-warning-from-static-code-analysis.patch b/0184-kvm-Fix-warning-from-static-code-analysis.patch new file mode 100644 index 0000000..87ad81d --- /dev/null +++ b/0184-kvm-Fix-warning-from-static-code-analysis.patch @@ -0,0 +1,49 @@ +From 0a8b8d39763f05c7862dceec9d4f44e902a9d192 Mon Sep 17 00:00:00 2001 +From: Stefan Weil +Date: Mon, 3 Sep 2012 22:40:40 +0200 +Subject: [PATCH] kvm: Fix warning from static code analysis + +Report from smatch: + +kvm-all.c:1373 kvm_init(135) warn: + variable dereferenced before check 's' (see line 1360) + +'s' cannot by NULL (it was alloced using g_malloc0), so there is no need +to check it here. + +Signed-off-by: Stefan Weil +Reviewed-by: Peter Maydell +Signed-off-by: Stefan Hajnoczi +(cherry picked from commit 6d1cc3210ccc4372ffa337c187da9db68314c0c4) + +Signed-off-by: Michael Roth +--- + kvm-all.c | 12 +++++------- + 1 file changed, 5 insertions(+), 7 deletions(-) + +diff --git a/kvm-all.c b/kvm-all.c +index 90c71f9..08d6051 100644 +--- a/kvm-all.c ++++ b/kvm-all.c +@@ -1419,13 +1419,11 @@ int kvm_init(void) + return 0; + + err: +- if (s) { +- if (s->vmfd >= 0) { +- close(s->vmfd); +- } +- if (s->fd != -1) { +- close(s->fd); +- } ++ if (s->vmfd >= 0) { ++ close(s->vmfd); ++ } ++ if (s->fd != -1) { ++ close(s->fd); + } + g_free(s); + +-- +1.7.12.1 + diff --git a/0185-arch_init.c-add-missing-symbols-before-PRIu64-in-deb.patch b/0185-arch_init.c-add-missing-symbols-before-PRIu64-in-deb.patch new file mode 100644 index 0000000..7fcc366 --- /dev/null +++ b/0185-arch_init.c-add-missing-symbols-before-PRIu64-in-deb.patch @@ -0,0 +1,54 @@ +From df075bd97f2d88969e3178ec9cb302f955d31737 Mon Sep 17 00:00:00 2001 +From: Igor Mitsyanko +Date: Wed, 5 Sep 2012 13:04:56 +0400 +Subject: [PATCH] arch_init.c: add missing '%' symbols before PRIu64 in debug + printfs + +'%' symbols were missing in front of PRIu64 macros in DPRINTF() messages in +arch_init.c, this caused compilation warnings when compiled with DEBUG_ARCH_INIT defined. + +Signed-off-by: Igor Mitsyanko +Signed-off-by: Stefan Hajnoczi +(cherry picked from commit ef37a699a06f96e098ee00683b7052b5fbb6ad7d) + +Signed-off-by: Michael Roth +--- + arch_init.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/arch_init.c b/arch_init.c +index 5a1173e..47977de 100644 +--- a/arch_init.c ++++ b/arch_init.c +@@ -562,7 +562,7 @@ static int ram_save_iterate(QEMUFile *f, void *opaque) + if ((i & 63) == 0) { + uint64_t t1 = (qemu_get_clock_ns(rt_clock) - bwidth) / 1000000; + if (t1 > MAX_WAIT) { +- DPRINTF("big wait: " PRIu64 " milliseconds, %d iterations\n", ++ DPRINTF("big wait: %" PRIu64 " milliseconds, %d iterations\n", + t1, i); + break; + } +@@ -587,7 +587,7 @@ static int ram_save_iterate(QEMUFile *f, void *opaque) + + expected_time = ram_save_remaining() * TARGET_PAGE_SIZE / bwidth; + +- DPRINTF("ram_save_live: expected(" PRIu64 ") <= max(" PRIu64 ")?\n", ++ DPRINTF("ram_save_live: expected(%" PRIu64 ") <= max(%" PRIu64 ")?\n", + expected_time, migrate_max_downtime()); + + if (expected_time <= migrate_max_downtime()) { +@@ -799,8 +799,8 @@ static int ram_load(QEMUFile *f, void *opaque, int version_id) + } while (!(flags & RAM_SAVE_FLAG_EOS)); + + done: +- DPRINTF("Completed load of VM with exit code %d seq iteration " PRIu64 "\n", +- ret, seq_iter); ++ DPRINTF("Completed load of VM with exit code %d seq iteration " ++ "%" PRIu64 "\n", ret, seq_iter); + return ret; + } + +-- +1.7.12.1 + diff --git a/0186-net-notify-iothread-after-flushing-queue.patch b/0186-net-notify-iothread-after-flushing-queue.patch new file mode 100644 index 0000000..b6a9f65 --- /dev/null +++ b/0186-net-notify-iothread-after-flushing-queue.patch @@ -0,0 +1,105 @@ +From 7d797af90c5293b518a072da9b23ec14a1a917f7 Mon Sep 17 00:00:00 2001 +From: Paolo Bonzini +Date: Thu, 9 Aug 2012 16:45:55 +0200 +Subject: [PATCH] net: notify iothread after flushing queue + +virtio-net has code to flush the queue and notify the iothread +whenever new receive buffers are added by the guest. That is +fine, and indeed we need to do the same in all other drivers. +However, notifying the iothread should be work for the network +subsystem. And since we are at it we can add a little smartness: +if some of the queued packets already could not be delivered, +there is no need to notify the iothread. + +Reported-by: Luigi Rizzo +Cc: Stefan Hajnoczi +Cc: Jan Kiszka +Signed-off-by: Paolo Bonzini +Reviewed-by: Amos Kong +Signed-off-by: Stefan Hajnoczi +(cherry picked from commit 987a9b4800003567b1a47a379255e886a77d57ea) + +Signed-off-by: Michael Roth +--- + hw/virtio-net.c | 4 ---- + net.c | 7 ++++++- + net/queue.c | 5 +++-- + net/queue.h | 2 +- + 4 files changed, 10 insertions(+), 8 deletions(-) + +diff --git a/hw/virtio-net.c b/hw/virtio-net.c +index b1998b2..6490743 100644 +--- a/hw/virtio-net.c ++++ b/hw/virtio-net.c +@@ -447,10 +447,6 @@ static void virtio_net_handle_rx(VirtIODevice *vdev, VirtQueue *vq) + VirtIONet *n = to_virtio_net(vdev); + + qemu_flush_queued_packets(&n->nic->nc); +- +- /* We now have RX buffers, signal to the IO thread to break out of the +- * select to re-poll the tap file descriptor */ +- qemu_notify_event(); + } + + static int virtio_net_can_receive(NetClientState *nc) +diff --git a/net.c b/net.c +index 60043dd..76a8336 100644 +--- a/net.c ++++ b/net.c +@@ -357,7 +357,12 @@ void qemu_flush_queued_packets(NetClientState *nc) + { + nc->receive_disabled = 0; + +- qemu_net_queue_flush(nc->send_queue); ++ if (qemu_net_queue_flush(nc->send_queue)) { ++ /* We emptied the queue successfully, signal to the IO thread to repoll ++ * the file descriptor (for tap, for example). ++ */ ++ qemu_notify_event(); ++ } + } + + static ssize_t qemu_send_packet_async_with_flags(NetClientState *sender, +diff --git a/net/queue.c b/net/queue.c +index e8030aa..6e64091 100644 +--- a/net/queue.c ++++ b/net/queue.c +@@ -228,7 +228,7 @@ void qemu_net_queue_purge(NetQueue *queue, NetClientState *from) + } + } + +-void qemu_net_queue_flush(NetQueue *queue) ++bool qemu_net_queue_flush(NetQueue *queue) + { + while (!QTAILQ_EMPTY(&queue->packets)) { + NetPacket *packet; +@@ -244,7 +244,7 @@ void qemu_net_queue_flush(NetQueue *queue) + packet->size); + if (ret == 0) { + QTAILQ_INSERT_HEAD(&queue->packets, packet, entry); +- break; ++ return false; + } + + if (packet->sent_cb) { +@@ -253,4 +253,5 @@ void qemu_net_queue_flush(NetQueue *queue) + + g_free(packet); + } ++ return true; + } +diff --git a/net/queue.h b/net/queue.h +index 9d44a9b..fc02b33 100644 +--- a/net/queue.h ++++ b/net/queue.h +@@ -53,6 +53,6 @@ ssize_t qemu_net_queue_send_iov(NetQueue *queue, + NetPacketSent *sent_cb); + + void qemu_net_queue_purge(NetQueue *queue, NetClientState *from); +-void qemu_net_queue_flush(NetQueue *queue); ++bool qemu_net_queue_flush(NetQueue *queue); + + #endif /* QEMU_NET_QUEUE_H */ +-- +1.7.12.1 + diff --git a/0187-e1000-flush-queue-whenever-can_receive-can-go-from-f.patch b/0187-e1000-flush-queue-whenever-can_receive-can-go-from-f.patch new file mode 100644 index 0000000..9d61ff8 --- /dev/null +++ b/0187-e1000-flush-queue-whenever-can_receive-can-go-from-f.patch @@ -0,0 +1,51 @@ +From a71b6050a88402c3f388b8f13afed51e6ba6f41a Mon Sep 17 00:00:00 2001 +From: Paolo Bonzini +Date: Thu, 9 Aug 2012 16:45:56 +0200 +Subject: [PATCH] e1000: flush queue whenever can_receive can go from false to + true + +When the guests replenish the receive ring buffer, the network device +should flush its queue of pending packets. This is done with +qemu_flush_queued_packets. + +e1000's can_receive can go from false to true when RCTL or RDT are +modified. + +Reported-by: Luigi Rizzo +Cc: Stefan Hajnoczi +Cc: Jan Kiszka +Signed-off-by: Paolo Bonzini +Reviewed-by: Amos Kong +Signed-off-by: Stefan Hajnoczi +(cherry picked from commit e8b4c680b41bd960ecccd9ff076b7b058e0afcd4) + +Signed-off-by: Michael Roth +--- + hw/e1000.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/hw/e1000.c b/hw/e1000.c +index ae8a6c5..ec3a7c4 100644 +--- a/hw/e1000.c ++++ b/hw/e1000.c +@@ -295,6 +295,7 @@ set_rx_control(E1000State *s, int index, uint32_t val) + s->rxbuf_min_shift = ((val / E1000_RCTL_RDMTS_QUAT) & 3) + 1; + DBGOUT(RX, "RCTL: %d, mac_reg[RCTL] = 0x%x\n", s->mac_reg[RDT], + s->mac_reg[RCTL]); ++ qemu_flush_queued_packets(&s->nic->nc); + } + + static void +@@ -926,6 +927,9 @@ set_rdt(E1000State *s, int index, uint32_t val) + { + s->check_rxov = 0; + s->mac_reg[index] = val & 0xffff; ++ if (e1000_has_rxbufs(s, 1)) { ++ qemu_flush_queued_packets(&s->nic->nc); ++ } + } + + static void +-- +1.7.12.1 + diff --git a/0188-xen-flush-queue-when-getting-an-event.patch b/0188-xen-flush-queue-when-getting-an-event.patch new file mode 100644 index 0000000..6c52eb4 --- /dev/null +++ b/0188-xen-flush-queue-when-getting-an-event.patch @@ -0,0 +1,37 @@ +From 7fc16be815b8ff85f174fc93d67f82400da08120 Mon Sep 17 00:00:00 2001 +From: Paolo Bonzini +Date: Thu, 9 Aug 2012 16:45:57 +0200 +Subject: [PATCH] xen: flush queue when getting an event + +xen does not have a register that, when written, will cause can_receive +to go from false to true. However, flushing the queue can be attempted +whenever the front-end raises its side of the Xen event channel. There +is a single event channel for tx and rx. + +Cc: Stefano Stabellini +Cc: Stefan Hajnoczi +Signed-off-by: Paolo Bonzini +Reviewed-by: Amos Kong +Signed-off-by: Stefan Hajnoczi +(cherry picked from commit a98b140223d3a627eab7ee3ddec645bab630d756) + +Signed-off-by: Michael Roth +--- + hw/xen_nic.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/hw/xen_nic.c b/hw/xen_nic.c +index 8b79bfb..cf7d559 100644 +--- a/hw/xen_nic.c ++++ b/hw/xen_nic.c +@@ -415,6 +415,7 @@ static void net_event(struct XenDevice *xendev) + { + struct XenNetDev *netdev = container_of(xendev, struct XenNetDev, xendev); + net_tx_packets(netdev); ++ qemu_flush_queued_packets(&netdev->nic->nc); + } + + static int net_free(struct XenDevice *xendev) +-- +1.7.12.1 + diff --git a/0189-eepro100-Fix-network-hang-when-rx-buffers-run-out.patch b/0189-eepro100-Fix-network-hang-when-rx-buffers-run-out.patch new file mode 100644 index 0000000..4e2df82 --- /dev/null +++ b/0189-eepro100-Fix-network-hang-when-rx-buffers-run-out.patch @@ -0,0 +1,72 @@ +From 154f1e30c09d261b12937c385632c05474989b02 Mon Sep 17 00:00:00 2001 +From: Bo Yang +Date: Wed, 29 Aug 2012 19:26:11 +0800 +Subject: [PATCH] eepro100: Fix network hang when rx buffers run out + +This is reported by QA. When installing os with pxe, after the initial +kernel and initrd are loaded, the procedure tries to copy files from install +server to local harddisk, the network becomes stall because of running out of +receive descriptor. + +[Whitespace fixes and removed qemu_notify_event() because Paolo's +earlier net patches have moved it into qemu_flush_queued_packets(). + +Additional info: + +I can reproduce the network hang with a tap device doing a iPXE HTTP +boot as follows: + + $ qemu -enable-kvm -m 1024 \ + -netdev tap,id=netdev0,script=no,downscript=no \ + -device i82559er,netdev=netdev0,romfile=80861209.rom \ + -drive if=virtio,cache=none,file=test.img + iPXE> ifopen net0 + iPXE> config # set static network configuration + iPXE> kernel http://mirror.bytemark.co.uk/fedora/linux/releases/17/Fedora/x86_64/os/images/pxeboot/vmlinuz + +I needed a vanilla iPXE ROM to get to the iPXE prompt. I think the boot +prompt has been disabled in the ROMs that ship with QEMU to reduce boot +time. + +During the vmlinuz HTTP download there is a network hang. hw/eepro100.c +has reached the end of the rx descriptor list. When the iPXE driver +replenishes the rx descriptor list we don't kick the QEMU net subsystem +and event loop, thereby leaving the tap netdev without its file +descriptor in select(2). + +Stefan Hajnoczi ] + +Signed-off-by: Bo Yang +Signed-off-by: Stefan Hajnoczi +(cherry picked from commit 1069985fb132cd4324fc02d371f1e61492a1823f) + +Signed-off-by: Michael Roth +--- + hw/eepro100.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/hw/eepro100.c b/hw/eepro100.c +index 50d117e..5b23116 100644 +--- a/hw/eepro100.c ++++ b/hw/eepro100.c +@@ -1036,6 +1036,7 @@ static void eepro100_ru_command(EEPRO100State * s, uint8_t val) + } + set_ru_state(s, ru_ready); + s->ru_offset = e100_read_reg4(s, SCBPointer); ++ qemu_flush_queued_packets(&s->nic->nc); + TRACE(OTHER, logout("val=0x%02x (rx start)\n", val)); + break; + case RX_RESUME: +@@ -1770,7 +1771,8 @@ static ssize_t nic_receive(NetClientState *nc, const uint8_t * buf, size_t size) + if (rfd_command & COMMAND_EL) { + /* EL bit is set, so this was the last frame. */ + logout("receive: Running out of frames\n"); +- set_ru_state(s, ru_suspended); ++ set_ru_state(s, ru_no_resources); ++ eepro100_rnr_interrupt(s); + } + if (rfd_command & COMMAND_S) { + /* S bit is set. */ +-- +1.7.12.1 + diff --git a/0190-net-add-receive_disabled-logic-to-iov-delivery-path.patch b/0190-net-add-receive_disabled-logic-to-iov-delivery-path.patch new file mode 100644 index 0000000..f94a29e --- /dev/null +++ b/0190-net-add-receive_disabled-logic-to-iov-delivery-path.patch @@ -0,0 +1,65 @@ +From eccdc01e744cf3a389a527406f4d529420133e89 Mon Sep 17 00:00:00 2001 +From: Stefan Hajnoczi +Date: Fri, 17 Aug 2012 21:16:42 +0100 +Subject: [PATCH] net: add receive_disabled logic to iov delivery path + +This patch adds the missing NetClient->receive_disabled logic in the +sendv delivery code path. It seems that commit +893379efd0e1b84ceb0c42a713293f3dbd27b1bd ("net: disable receiving if +client returns zero") only added the logic to qemu_deliver_packet() and +not qemu_deliver_packet_iov(). + +The receive_disabled flag should be automatically set when .receive(), +.receive_raw(), or .receive_iov() return 0. No further packets will be +delivered to the NetClient until the receive_disabled flag is cleared +again by calling qemu_flush_queued_packets(). + +Typically the NetClient will wait until its file descriptor becomes +writable and then invoke qemu_flush_queued_packets() to resume +transmission. + +Signed-off-by: Stefan Hajnoczi +(cherry picked from commit c67f5dc10573687497f0f5c3aec19b15c35c63d7) + +Signed-off-by: Michael Roth +--- + net.c | 15 +++++++++++++-- + 1 file changed, 13 insertions(+), 2 deletions(-) + +diff --git a/net.c b/net.c +index 76a8336..1303819 100644 +--- a/net.c ++++ b/net.c +@@ -423,16 +423,27 @@ ssize_t qemu_deliver_packet_iov(NetClientState *sender, + void *opaque) + { + NetClientState *nc = opaque; ++ int ret; + + if (nc->link_down) { + return iov_size(iov, iovcnt); + } + ++ if (nc->receive_disabled) { ++ return 0; ++ } ++ + if (nc->info->receive_iov) { +- return nc->info->receive_iov(nc, iov, iovcnt); ++ ret = nc->info->receive_iov(nc, iov, iovcnt); + } else { +- return nc_sendv_compat(nc, iov, iovcnt); ++ ret = nc_sendv_compat(nc, iov, iovcnt); + } ++ ++ if (ret == 0) { ++ nc->receive_disabled = 1; ++ } ++ ++ return ret; + } + + ssize_t qemu_sendv_packet_async(NetClientState *sender, +-- +1.7.12.1 + diff --git a/0191-net-do-not-report-queued-packets-as-sent.patch b/0191-net-do-not-report-queued-packets-as-sent.patch new file mode 100644 index 0000000..b6deca0 --- /dev/null +++ b/0191-net-do-not-report-queued-packets-as-sent.patch @@ -0,0 +1,103 @@ +From 17df2130cd8be0cd6892b86103947746f95efc2c Mon Sep 17 00:00:00 2001 +From: Stefan Hajnoczi +Date: Mon, 20 Aug 2012 13:35:23 +0100 +Subject: [PATCH] net: do not report queued packets as sent + +Net send functions have a return value where 0 means the packet has not +been sent and will be queued. A non-zero value means the packet was +sent or an error caused the packet to be dropped. + +This patch fixes two instances where packets are queued but we return +their size. This causes callers to believe the packets were sent. When +the caller uses the async send interface this creates a real problem +because the callback will be invoked for a packet that the caller +believed to be already sent. This bug can cause double-frees in the +caller. + +Signed-off-by: Stefan Hajnoczi +(cherry picked from commit 06b5f36d052b540a59b52150582d65674199b2ce) + +Signed-off-by: Michael Roth +--- + net/queue.c | 35 ++++++++++++++++------------------- + 1 file changed, 16 insertions(+), 19 deletions(-) + +diff --git a/net/queue.c b/net/queue.c +index 6e64091..254f280 100644 +--- a/net/queue.c ++++ b/net/queue.c +@@ -83,12 +83,12 @@ void qemu_del_net_queue(NetQueue *queue) + g_free(queue); + } + +-static ssize_t qemu_net_queue_append(NetQueue *queue, +- NetClientState *sender, +- unsigned flags, +- const uint8_t *buf, +- size_t size, +- NetPacketSent *sent_cb) ++static void qemu_net_queue_append(NetQueue *queue, ++ NetClientState *sender, ++ unsigned flags, ++ const uint8_t *buf, ++ size_t size, ++ NetPacketSent *sent_cb) + { + NetPacket *packet; + +@@ -100,16 +100,14 @@ static ssize_t qemu_net_queue_append(NetQueue *queue, + memcpy(packet->data, buf, size); + + QTAILQ_INSERT_TAIL(&queue->packets, packet, entry); +- +- return size; + } + +-static ssize_t qemu_net_queue_append_iov(NetQueue *queue, +- NetClientState *sender, +- unsigned flags, +- const struct iovec *iov, +- int iovcnt, +- NetPacketSent *sent_cb) ++static void qemu_net_queue_append_iov(NetQueue *queue, ++ NetClientState *sender, ++ unsigned flags, ++ const struct iovec *iov, ++ int iovcnt, ++ NetPacketSent *sent_cb) + { + NetPacket *packet; + size_t max_len = 0; +@@ -133,8 +131,6 @@ static ssize_t qemu_net_queue_append_iov(NetQueue *queue, + } + + QTAILQ_INSERT_TAIL(&queue->packets, packet, entry); +- +- return packet->size; + } + + static ssize_t qemu_net_queue_deliver(NetQueue *queue, +@@ -177,7 +173,8 @@ ssize_t qemu_net_queue_send(NetQueue *queue, + ssize_t ret; + + if (queue->delivering || !qemu_can_send_packet(sender)) { +- return qemu_net_queue_append(queue, sender, flags, data, size, sent_cb); ++ qemu_net_queue_append(queue, sender, flags, data, size, sent_cb); ++ return 0; + } + + ret = qemu_net_queue_deliver(queue, sender, flags, data, size); +@@ -201,8 +198,8 @@ ssize_t qemu_net_queue_send_iov(NetQueue *queue, + ssize_t ret; + + if (queue->delivering || !qemu_can_send_packet(sender)) { +- return qemu_net_queue_append_iov(queue, sender, flags, +- iov, iovcnt, sent_cb); ++ qemu_net_queue_append_iov(queue, sender, flags, iov, iovcnt, sent_cb); ++ return 0; + } + + ret = qemu_net_queue_deliver_iov(queue, sender, flags, iov, iovcnt); +-- +1.7.12.1 + diff --git a/0192-net-add-netdev-options-to-man-page.patch b/0192-net-add-netdev-options-to-man-page.patch new file mode 100644 index 0000000..b0272da --- /dev/null +++ b/0192-net-add-netdev-options-to-man-page.patch @@ -0,0 +1,81 @@ +From 773b0a456b236ccdcf1e5329992c0d4669f0af26 Mon Sep 17 00:00:00 2001 +From: Stefan Hajnoczi +Date: Tue, 14 Aug 2012 14:14:27 +0100 +Subject: [PATCH] net: add -netdev options to man page + +Document the -netdev syntax which supercedes the older -net syntax. +This patch is a first step to making -netdev prominent in the QEMU +manual. + +Reported-by: Anatoly Techtonik +Signed-off-by: Stefan Hajnoczi +(cherry picked from commit 08d12022c7f1aba6acccc75150659c6e4c9dff23) + +Signed-off-by: Michael Roth +--- + qemu-options.hx | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/qemu-options.hx b/qemu-options.hx +index 1af4fec..1021ab7 100644 +--- a/qemu-options.hx ++++ b/qemu-options.hx +@@ -1357,6 +1357,7 @@ Valid values for @var{type} are + Not all devices are supported on all targets. Use -net nic,model=? + for a list of available devices for your target. + ++@item -netdev user,id=@var{id}[,@var{option}][,@var{option}][,...] + @item -net user[,@var{option}][,@var{option}][,...] + Use the user mode network stack which requires no administrator + privilege to run. Valid options are: +@@ -1365,6 +1366,7 @@ privilege to run. Valid options are: + @item vlan=@var{n} + Connect user mode stack to VLAN @var{n} (@var{n} = 0 is the default). + ++@item id=@var{id} + @item name=@var{name} + Assign symbolic name for use in monitor commands. + +@@ -1490,6 +1492,7 @@ processed and applied to -net user. Mixing them with the new configuration + syntax gives undefined results. Their use for new applications is discouraged + as they will be removed from future versions. + ++@item -netdev tap,id=@var{id}[,fd=@var{h}][,ifname=@var{name}][,script=@var{file}][,downscript=@var{dfile}][,helper=@var{helper}] + @item -net tap[,vlan=@var{n}][,name=@var{name}][,fd=@var{h}][,ifname=@var{name}][,script=@var{file}][,downscript=@var{dfile}][,helper=@var{helper}] + Connect the host TAP network interface @var{name} to VLAN @var{n}. + +@@ -1529,6 +1532,7 @@ qemu-system-i386 linux.img \ + -net nic -net tap,"helper=/usr/local/libexec/qemu-bridge-helper" + @end example + ++@item -netdev bridge,id=@var{id}[,br=@var{bridge}][,helper=@var{helper}] + @item -net bridge[,vlan=@var{n}][,name=@var{name}][,br=@var{bridge}][,helper=@var{helper}] + Connect a host TAP network interface to a host bridge device. + +@@ -1551,6 +1555,7 @@ qemu-system-i386 linux.img -net bridge -net nic,model=virtio + qemu-system-i386 linux.img -net bridge,br=qemubr0 -net nic,model=virtio + @end example + ++@item -netdev socket,id=@var{id}[,fd=@var{h}][,listen=[@var{host}]:@var{port}][,connect=@var{host}:@var{port}] + @item -net socket[,vlan=@var{n}][,name=@var{name}][,fd=@var{h}] [,listen=[@var{host}]:@var{port}][,connect=@var{host}:@var{port}] + + Connect the VLAN @var{n} to a remote VLAN in another QEMU virtual +@@ -1573,6 +1578,7 @@ qemu-system-i386 linux.img \ + -net socket,connect=127.0.0.1:1234 + @end example + ++@item -netdev socket,id=@var{id}[,fd=@var{h}][,mcast=@var{maddr}:@var{port}[,localaddr=@var{addr}]] + @item -net socket[,vlan=@var{n}][,name=@var{name}][,fd=@var{h}][,mcast=@var{maddr}:@var{port}[,localaddr=@var{addr}]] + + Create a VLAN @var{n} shared with another QEMU virtual +@@ -1624,6 +1630,7 @@ qemu-system-i386 linux.img \ + -net socket,mcast=239.192.168.1:1102,localaddr=1.2.3.4 + @end example + ++@item -netdev vde,id=@var{id}[,sock=@var{socketpath}][,port=@var{n}][,group=@var{groupname}][,mode=@var{octalmode}] + @item -net vde[,vlan=@var{n}][,name=@var{name}][,sock=@var{socketpath}] [,port=@var{n}][,group=@var{groupname}][,mode=@var{octalmode}] + Connect VLAN @var{n} to PORT @var{n} of a vde switch running on host and + listening for incoming connections on @var{socketpath}. Use GROUP @var{groupname} +-- +1.7.12.1 + diff --git a/0193-net-clean-up-usbnet_receive.patch b/0193-net-clean-up-usbnet_receive.patch new file mode 100644 index 0000000..c92890e --- /dev/null +++ b/0193-net-clean-up-usbnet_receive.patch @@ -0,0 +1,80 @@ +From f3f975860db11101ccef2f75238032328de00ce0 Mon Sep 17 00:00:00 2001 +From: Stefan Hajnoczi +Date: Fri, 24 Aug 2012 13:32:16 +0100 +Subject: [PATCH] net: clean up usbnet_receive() + +The USB network interface has two code paths depending on whether or not +RNDIS mode is enabled. Refactor usbnet_receive() so that there is a +common path throughout the function instead of duplicating everything +across if (is_rndis(s)) ... else ... code paths. + +Clean up coding style and 80 character line wrap along the way. + +Signed-off-by: Stefan Hajnoczi +(cherry picked from commit f237ddbb89142c6948a2257c459e49dee7500a7c) + +Signed-off-by: Michael Roth +--- + hw/usb/dev-network.c | 30 +++++++++++++++++------------- + 1 file changed, 17 insertions(+), 13 deletions(-) + +diff --git a/hw/usb/dev-network.c b/hw/usb/dev-network.c +index c84892c..0b5cb71 100644 +--- a/hw/usb/dev-network.c ++++ b/hw/usb/dev-network.c +@@ -1250,20 +1250,27 @@ static int usb_net_handle_data(USBDevice *dev, USBPacket *p) + static ssize_t usbnet_receive(NetClientState *nc, const uint8_t *buf, size_t size) + { + USBNetState *s = DO_UPCAST(NICState, nc, nc)->opaque; +- struct rndis_packet_msg_type *msg; ++ uint8_t *in_buf = s->in_buf; ++ size_t total_size = size; + + if (is_rndis(s)) { +- msg = (struct rndis_packet_msg_type *) s->in_buf; + if (s->rndis_state != RNDIS_DATA_INITIALIZED) { + return -1; + } +- if (size + sizeof(struct rndis_packet_msg_type) > sizeof(s->in_buf)) +- return -1; ++ total_size += sizeof(struct rndis_packet_msg_type); ++ } ++ if (total_size > sizeof(s->in_buf)) { ++ return -1; ++ } + ++ if (is_rndis(s)) { ++ struct rndis_packet_msg_type *msg; ++ ++ msg = (struct rndis_packet_msg_type *)in_buf; + memset(msg, 0, sizeof(struct rndis_packet_msg_type)); + msg->MessageType = cpu_to_le32(RNDIS_PACKET_MSG); +- msg->MessageLength = cpu_to_le32(size + sizeof(struct rndis_packet_msg_type)); +- msg->DataOffset = cpu_to_le32(sizeof(struct rndis_packet_msg_type) - 8); ++ msg->MessageLength = cpu_to_le32(size + sizeof(*msg)); ++ msg->DataOffset = cpu_to_le32(sizeof(*msg) - 8); + msg->DataLength = cpu_to_le32(size); + /* msg->OOBDataOffset; + * msg->OOBDataLength; +@@ -1273,14 +1280,11 @@ static ssize_t usbnet_receive(NetClientState *nc, const uint8_t *buf, size_t siz + * msg->VcHandle; + * msg->Reserved; + */ +- memcpy(msg + 1, buf, size); +- s->in_len = size + sizeof(struct rndis_packet_msg_type); +- } else { +- if (size > sizeof(s->in_buf)) +- return -1; +- memcpy(s->in_buf, buf, size); +- s->in_len = size; ++ in_buf += sizeof(*msg); + } ++ ++ memcpy(in_buf, buf, size); ++ s->in_len = total_size; + s->in_ptr = 0; + return size; + } +-- +1.7.12.1 + diff --git a/0194-net-fix-usbnet_receive-packet-drops.patch b/0194-net-fix-usbnet_receive-packet-drops.patch new file mode 100644 index 0000000..bbe1c76 --- /dev/null +++ b/0194-net-fix-usbnet_receive-packet-drops.patch @@ -0,0 +1,81 @@ +From 14294fa1c903ab239bce3d2839e9e1883141b4f1 Mon Sep 17 00:00:00 2001 +From: Stefan Hajnoczi +Date: Fri, 24 Aug 2012 13:37:29 +0100 +Subject: [PATCH] net: fix usbnet_receive() packet drops + +The USB network interface has a single buffer which the guest reads +from. This patch prevents multiple calls to usbnet_receive() from +clobbering the input buffer. Instead we queue packets until buffer +space becomes available again. + +This is inspired by virtio-net and e1000 rxbuf handling. + +Signed-off-by: Stefan Hajnoczi +(cherry picked from commit 190563f9a90c9df8ad32fc7f3e4b166deda949a6) + +Signed-off-by: Michael Roth +--- + hw/usb/dev-network.c | 19 ++++++++++++++++--- + 1 file changed, 16 insertions(+), 3 deletions(-) + +diff --git a/hw/usb/dev-network.c b/hw/usb/dev-network.c +index 0b5cb71..e4a4359 100644 +--- a/hw/usb/dev-network.c ++++ b/hw/usb/dev-network.c +@@ -1001,6 +1001,13 @@ static int rndis_keepalive_response(USBNetState *s, + return 0; + } + ++/* Prepare to receive the next packet */ ++static void usb_net_reset_in_buf(USBNetState *s) ++{ ++ s->in_ptr = s->in_len = 0; ++ qemu_flush_queued_packets(&s->nic->nc); ++} ++ + static int rndis_parse(USBNetState *s, uint8_t *data, int length) + { + uint32_t msg_type; +@@ -1025,7 +1032,8 @@ static int rndis_parse(USBNetState *s, uint8_t *data, int length) + + case RNDIS_RESET_MSG: + rndis_clear_responsequeue(s); +- s->out_ptr = s->in_ptr = s->in_len = 0; ++ s->out_ptr = 0; ++ usb_net_reset_in_buf(s); + return rndis_reset_response(s, (rndis_reset_msg_type *) data); + + case RNDIS_KEEPALIVE_MSG: +@@ -1135,7 +1143,7 @@ static int usb_net_handle_datain(USBNetState *s, USBPacket *p) + int ret = USB_RET_NAK; + + if (s->in_ptr > s->in_len) { +- s->in_ptr = s->in_len = 0; ++ usb_net_reset_in_buf(s); + ret = USB_RET_NAK; + return ret; + } +@@ -1152,7 +1160,7 @@ static int usb_net_handle_datain(USBNetState *s, USBPacket *p) + if (s->in_ptr >= s->in_len && + (is_rndis(s) || (s->in_len & (64 - 1)) || !ret)) { + /* no short packet necessary */ +- s->in_ptr = s->in_len = 0; ++ usb_net_reset_in_buf(s); + } + + #ifdef TRAFFIC_DEBUG +@@ -1263,6 +1271,11 @@ static ssize_t usbnet_receive(NetClientState *nc, const uint8_t *buf, size_t siz + return -1; + } + ++ /* Only accept packet if input buffer is empty */ ++ if (s->in_len > 0) { ++ return 0; ++ } ++ + if (is_rndis(s)) { + struct rndis_packet_msg_type *msg; + +-- +1.7.12.1 + diff --git a/0195-net-broadcast-hub-packets-if-at-least-one-port-can-r.patch b/0195-net-broadcast-hub-packets-if-at-least-one-port-can-r.patch new file mode 100644 index 0000000..5cb7e1c --- /dev/null +++ b/0195-net-broadcast-hub-packets-if-at-least-one-port-can-r.patch @@ -0,0 +1,51 @@ +From 25ade2154673396e432de2b3c413865d1552c9b3 Mon Sep 17 00:00:00 2001 +From: Stefan Hajnoczi +Date: Fri, 24 Aug 2012 13:50:30 +0100 +Subject: [PATCH] net: broadcast hub packets if at least one port can receive + +In commit 60c07d933c66c4b30a83b7ccbc8a0cb3df1b2d0e ("net: fix +qemu_can_send_packet logic") the "VLAN" broadcast behavior was changed +to queue packets if any net client cannot receive. It turns out that +this was not actually the right fix and just hides the real bug that +hw/usb/dev-network.c:usbnet_receive() clobbers its receive buffer when +called multiple times in a row. The commit also introduced a new bug +that "VLAN" packets would not be sent if one of multiple net clients was +down. + +The hw/usb/dev-network.c bug has since been fixed, so this patch reverts +broadcast behavior to send packets as long as one net client can +receive. Packets simply get queued for the net clients that are +temporarily unable to receive. + +Reported-by: Roy.Li +Signed-off-by: Stefan Hajnoczi +(cherry picked from commit 61518a74ca98870e8ff132f91dd5dda252e31f58) + +Signed-off-by: Michael Roth +--- + net/hub.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/net/hub.c b/net/hub.c +index ac157e3..650a8b4 100644 +--- a/net/hub.c ++++ b/net/hub.c +@@ -97,12 +97,12 @@ static int net_hub_port_can_receive(NetClientState *nc) + continue; + } + +- if (!qemu_can_send_packet(&port->nc)) { +- return 0; ++ if (qemu_can_send_packet(&port->nc)) { ++ return 1; + } + } + +- return 1; ++ return 0; + } + + static ssize_t net_hub_port_receive(NetClientState *nc, +-- +1.7.12.1 + diff --git a/0196-net-asynchronous-send-receive-infrastructure-for-net.patch b/0196-net-asynchronous-send-receive-infrastructure-for-net.patch new file mode 100644 index 0000000..53f0722 --- /dev/null +++ b/0196-net-asynchronous-send-receive-infrastructure-for-net.patch @@ -0,0 +1,133 @@ +From 176b159d70cb26b24ce928497ae269b294e503d8 Mon Sep 17 00:00:00 2001 +From: Stefan Hajnoczi +Date: Mon, 20 Aug 2012 10:21:54 +0100 +Subject: [PATCH] net: asynchronous send/receive infrastructure for + net/socket.c + +The net/socket.c net client is not truly asynchronous. This patch +borrows the qemu_set_fd_handler2() code from net/tap.c as the basis for +proper asynchronous send/receive. + +Only read packets from the socket when the peer is able to receive. +This avoids needless queuing. + +Later patches implement asynchronous send. + +Signed-off-by: Stefan Hajnoczi +(cherry picked from commit 863f678fba4191f3b695620f41056cb7c124425d) + +Signed-off-by: Michael Roth +--- + net/socket.c | 58 ++++++++++++++++++++++++++++++++++++++++++++++++++++------ + 1 file changed, 52 insertions(+), 6 deletions(-) + +diff --git a/net/socket.c b/net/socket.c +index c172c24..54e32f0 100644 +--- a/net/socket.c ++++ b/net/socket.c +@@ -42,9 +42,51 @@ typedef struct NetSocketState { + unsigned int packet_len; + uint8_t buf[4096]; + struct sockaddr_in dgram_dst; /* contains inet host and port destination iff connectionless (SOCK_DGRAM) */ ++ IOHandler *send_fn; /* differs between SOCK_STREAM/SOCK_DGRAM */ ++ bool read_poll; /* waiting to receive data? */ ++ bool write_poll; /* waiting to transmit data? */ + } NetSocketState; + + static void net_socket_accept(void *opaque); ++static void net_socket_writable(void *opaque); ++ ++/* Only read packets from socket when peer can receive them */ ++static int net_socket_can_send(void *opaque) ++{ ++ NetSocketState *s = opaque; ++ ++ return qemu_can_send_packet(&s->nc); ++} ++ ++static void net_socket_update_fd_handler(NetSocketState *s) ++{ ++ qemu_set_fd_handler2(s->fd, ++ s->read_poll ? net_socket_can_send : NULL, ++ s->read_poll ? s->send_fn : NULL, ++ s->write_poll ? net_socket_writable : NULL, ++ s); ++} ++ ++static void net_socket_read_poll(NetSocketState *s, bool enable) ++{ ++ s->read_poll = enable; ++ net_socket_update_fd_handler(s); ++} ++ ++static void net_socket_write_poll(NetSocketState *s, bool enable) ++{ ++ s->write_poll = enable; ++ net_socket_update_fd_handler(s); ++} ++ ++static void net_socket_writable(void *opaque) ++{ ++ NetSocketState *s = opaque; ++ ++ net_socket_write_poll(s, false); ++ ++ qemu_flush_queued_packets(&s->nc); ++} + + /* XXX: we consider we can send the whole packet without blocking */ + static ssize_t net_socket_receive(NetClientState *nc, const uint8_t *buf, size_t size) +@@ -81,7 +123,8 @@ static void net_socket_send(void *opaque) + } else if (size == 0) { + /* end of connection */ + eoc: +- qemu_set_fd_handler(s->fd, NULL, NULL, NULL); ++ net_socket_read_poll(s, false); ++ net_socket_write_poll(s, false); + if (s->listen_fd != -1) { + qemu_set_fd_handler(s->listen_fd, net_socket_accept, NULL, s); + } +@@ -152,7 +195,8 @@ static void net_socket_send_dgram(void *opaque) + return; + if (size == 0) { + /* end of connection */ +- qemu_set_fd_handler(s->fd, NULL, NULL, NULL); ++ net_socket_read_poll(s, false); ++ net_socket_write_poll(s, false); + return; + } + qemu_send_packet(&s->nc, s->buf, size); +@@ -243,7 +287,8 @@ static void net_socket_cleanup(NetClientState *nc) + { + NetSocketState *s = DO_UPCAST(NetSocketState, nc, nc); + if (s->fd != -1) { +- qemu_set_fd_handler(s->fd, NULL, NULL, NULL); ++ net_socket_read_poll(s, false); ++ net_socket_write_poll(s, false); + close(s->fd); + s->fd = -1; + } +@@ -314,8 +359,8 @@ static NetSocketState *net_socket_fd_init_dgram(NetClientState *peer, + + s->fd = fd; + s->listen_fd = -1; +- +- qemu_set_fd_handler(s->fd, net_socket_send_dgram, NULL, s); ++ s->send_fn = net_socket_send_dgram; ++ net_socket_read_poll(s, true); + + /* mcast: save bound address as dst */ + if (is_connected) { +@@ -332,7 +377,8 @@ err: + static void net_socket_connect(void *opaque) + { + NetSocketState *s = opaque; +- qemu_set_fd_handler(s->fd, net_socket_send, NULL, s); ++ s->send_fn = net_socket_send; ++ net_socket_read_poll(s, true); + } + + static NetClientInfo net_socket_info = { +-- +1.7.12.1 + diff --git a/0197-net-EAGAIN-handling-for-net-socket.c-UDP.patch b/0197-net-EAGAIN-handling-for-net-socket.c-UDP.patch new file mode 100644 index 0000000..9745eaa --- /dev/null +++ b/0197-net-EAGAIN-handling-for-net-socket.c-UDP.patch @@ -0,0 +1,45 @@ +From a2374b78f298d5755e96468bb97e4d7b660ff9d6 Mon Sep 17 00:00:00 2001 +From: Stefan Hajnoczi +Date: Mon, 20 Aug 2012 10:28:53 +0100 +Subject: [PATCH] net: EAGAIN handling for net/socket.c UDP + +Implement asynchronous send for UDP (or other SOCK_DGRAM) sockets. If +send fails with EAGAIN we wait for the socket to become writable again. + +Signed-off-by: Stefan Hajnoczi +(cherry picked from commit 213fd5087e2e4e2da10ad266df0ba950cf7618bf) + +Signed-off-by: Michael Roth +--- + net/socket.c | 14 ++++++++++++-- + 1 file changed, 12 insertions(+), 2 deletions(-) + +diff --git a/net/socket.c b/net/socket.c +index 54e32f0..e5e4e8d 100644 +--- a/net/socket.c ++++ b/net/socket.c +@@ -102,9 +102,19 @@ static ssize_t net_socket_receive(NetClientState *nc, const uint8_t *buf, size_t + static ssize_t net_socket_receive_dgram(NetClientState *nc, const uint8_t *buf, size_t size) + { + NetSocketState *s = DO_UPCAST(NetSocketState, nc, nc); ++ ssize_t ret; + +- return sendto(s->fd, (const void *)buf, size, 0, +- (struct sockaddr *)&s->dgram_dst, sizeof(s->dgram_dst)); ++ do { ++ ret = sendto(s->fd, buf, size, 0, ++ (struct sockaddr *)&s->dgram_dst, ++ sizeof(s->dgram_dst)); ++ } while (ret == -1 && errno == EINTR); ++ ++ if (ret == -1 && errno == EAGAIN) { ++ net_socket_write_poll(s, true); ++ return 0; ++ } ++ return ret; + } + + static void net_socket_send(void *opaque) +-- +1.7.12.1 + diff --git a/0198-net-EAGAIN-handling-for-net-socket.c-TCP.patch b/0198-net-EAGAIN-handling-for-net-socket.c-TCP.patch new file mode 100644 index 0000000..d318bf1 --- /dev/null +++ b/0198-net-EAGAIN-handling-for-net-socket.c-TCP.patch @@ -0,0 +1,97 @@ +From 52d73aa49799848042c09be1c64c1bff2159a5e1 Mon Sep 17 00:00:00 2001 +From: Stefan Hajnoczi +Date: Mon, 20 Aug 2012 10:14:35 +0100 +Subject: [PATCH] net: EAGAIN handling for net/socket.c TCP + +Replace spinning send_all() with a proper non-blocking send. When the +socket write buffer limit is reached, we should stop trying to send and +wait for the socket to become writable again. + +Non-blocking TCP sockets can return in two different ways when the write +buffer limit is reached: + +1. ret = -1 and errno = EAGAIN/EWOULDBLOCK. No data has been written. + +2. ret < total_size. Short write, only part of the message was + transmitted. + +Handle both cases and keep track of how many bytes have been written in +s->send_index. (This includes the 'length' header before the actual +payload buffer.) + +Signed-off-by: Stefan Hajnoczi +(cherry picked from commit 45a7f54a8bb3928ffa58d522e0d61acaee8277bb) + +Signed-off-by: Michael Roth +--- + net/socket.c | 36 +++++++++++++++++++++++++++++++----- + 1 file changed, 31 insertions(+), 5 deletions(-) + +diff --git a/net/socket.c b/net/socket.c +index e5e4e8d..c3e55b8 100644 +--- a/net/socket.c ++++ b/net/socket.c +@@ -32,6 +32,7 @@ + #include "qemu-error.h" + #include "qemu-option.h" + #include "qemu_socket.h" ++#include "iov.h" + + typedef struct NetSocketState { + NetClientState nc; +@@ -40,6 +41,7 @@ typedef struct NetSocketState { + int state; /* 0 = getting length, 1 = getting data */ + unsigned int index; + unsigned int packet_len; ++ unsigned int send_index; /* number of bytes sent (only SOCK_STREAM) */ + uint8_t buf[4096]; + struct sockaddr_in dgram_dst; /* contains inet host and port destination iff connectionless (SOCK_DGRAM) */ + IOHandler *send_fn; /* differs between SOCK_STREAM/SOCK_DGRAM */ +@@ -88,15 +90,39 @@ static void net_socket_writable(void *opaque) + qemu_flush_queued_packets(&s->nc); + } + +-/* XXX: we consider we can send the whole packet without blocking */ + static ssize_t net_socket_receive(NetClientState *nc, const uint8_t *buf, size_t size) + { + NetSocketState *s = DO_UPCAST(NetSocketState, nc, nc); +- uint32_t len; +- len = htonl(size); ++ uint32_t len = htonl(size); ++ struct iovec iov[] = { ++ { ++ .iov_base = &len, ++ .iov_len = sizeof(len), ++ }, { ++ .iov_base = (void *)buf, ++ .iov_len = size, ++ }, ++ }; ++ size_t remaining; ++ ssize_t ret; ++ ++ remaining = iov_size(iov, 2) - s->send_index; ++ ret = iov_send(s->fd, iov, 2, s->send_index, remaining); + +- send_all(s->fd, (const uint8_t *)&len, sizeof(len)); +- return send_all(s->fd, buf, size); ++ if (ret == -1 && errno == EAGAIN) { ++ ret = 0; /* handled further down */ ++ } ++ if (ret == -1) { ++ s->send_index = 0; ++ return -errno; ++ } ++ if (ret < (ssize_t)remaining) { ++ s->send_index += ret; ++ net_socket_write_poll(s, true); ++ return 0; ++ } ++ s->send_index = 0; ++ return size; + } + + static ssize_t net_socket_receive_dgram(NetClientState *nc, const uint8_t *buf, size_t size) +-- +1.7.12.1 + diff --git a/0199-configure-fix-seccomp-check.patch b/0199-configure-fix-seccomp-check.patch new file mode 100644 index 0000000..bf742c6 --- /dev/null +++ b/0199-configure-fix-seccomp-check.patch @@ -0,0 +1,45 @@ +From 4a151cbe99766a8da4582234a93d4292f064108f Mon Sep 17 00:00:00 2001 +From: "Yann E. MORIN" +Date: Thu, 6 Sep 2012 22:40:30 +0200 +Subject: [PATCH] configure: fix seccomp check +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Currently, if libseccomp is missing but the user explicitly requested +seccomp support using --enable-seccomp, configure silently ignores the +situation and disables seccomp support. + +This is unlike all other tests that explicitly fail in such situation. + +Fix that. + +Signed-off-by: "Yann E. MORIN" +Reviewed-by: Andreas Färber +Signed-off-by: Stefan Hajnoczi +(cherry picked from commit e84d5956cc6215d2f098e7b6090fc5ec4cba1be3) + +Signed-off-by: Michael Roth +--- + configure | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/configure b/configure +index dcd8e7b..9e53cc2 100755 +--- a/configure ++++ b/configure +@@ -1405,10 +1405,10 @@ if test "$seccomp" != "no" ; then + LIBS=`$pkg_config --libs libseccomp` + seccomp="yes" + else +- seccomp="no" + if test "$seccomp" = "yes"; then + feature_not_found "libseccomp" + fi ++ seccomp="no" + fi + fi + ########################################## +-- +1.7.12.1 + diff --git a/0200-configure-properly-check-if-lrt-and-lm-is-needed.patch b/0200-configure-properly-check-if-lrt-and-lm-is-needed.patch new file mode 100644 index 0000000..2e9a949 --- /dev/null +++ b/0200-configure-properly-check-if-lrt-and-lm-is-needed.patch @@ -0,0 +1,80 @@ +From 39b2ed0e73ac5b220accf7116bdaecb71ce759af Mon Sep 17 00:00:00 2001 +From: Natanael Copa +Date: Wed, 12 Sep 2012 09:06:51 +0000 +Subject: [PATCH] configure: properly check if -lrt and -lm is needed + +Fixes build against uClibc. + +uClibc provides 2 versions of clock_gettime(), one with realtime +support and one without (this is so you can avoid linking in -lrt +unless actually needed). This means that the clock_gettime() don't +need -lrt. We still need it for timer_create() so we check for this +function in addition. + +We also need check if -lm is needed for isnan(). + +Both -lm and -lrt are needed for libs_qga. + +Signed-off-by: Natanael Copa +Signed-off-by: Blue Swirl +(cherry picked from commit 8bacde8d86a09699207d85d4bab06162aed18dc4) + +Signed-off-by: Michael Roth +--- + configure | 31 +++++++++++++++++++++++++++++-- + 1 file changed, 29 insertions(+), 2 deletions(-) + +diff --git a/configure b/configure +index 9e53cc2..a1f256c 100755 +--- a/configure ++++ b/configure +@@ -2645,17 +2645,44 @@ fi + + + ########################################## ++# Do we need libm ++cat > $TMPC << EOF ++#include ++int main(void) { return isnan(sin(0.0)); } ++EOF ++if compile_prog "" "" ; then ++ : ++elif compile_prog "" "-lm" ; then ++ LIBS="-lm $LIBS" ++ libs_qga="-lm $libs_qga" ++else ++ echo ++ echo "Error: libm check failed" ++ echo ++ exit 1 ++fi ++ ++########################################## + # Do we need librt ++# uClibc provides 2 versions of clock_gettime(), one with realtime ++# support and one without. This means that the clock_gettime() don't ++# need -lrt. We still need it for timer_create() so we check for this ++# function in addition. + cat > $TMPC < + #include +-int main(void) { return clock_gettime(CLOCK_REALTIME, NULL); } ++int main(void) { ++ timer_create(CLOCK_REALTIME, NULL, NULL); ++ return clock_gettime(CLOCK_REALTIME, NULL); ++} + EOF + + if compile_prog "" "" ; then + : +-elif compile_prog "" "-lrt" ; then ++# we need pthread for static linking. use previous pthread test result ++elif compile_prog "" "-lrt $pthread_lib" ; then + LIBS="-lrt $LIBS" ++ libs_qga="-lrt $libs_qga" + fi + + if test "$darwin" != "yes" -a "$mingw32" != "yes" -a "$solaris" != yes -a \ +-- +1.7.12.1 + diff --git a/0201-Revert-455aa1e08-and-c3767ed0eb.patch b/0201-Revert-455aa1e08-and-c3767ed0eb.patch new file mode 100644 index 0000000..5466652 --- /dev/null +++ b/0201-Revert-455aa1e08-and-c3767ed0eb.patch @@ -0,0 +1,51 @@ +From 423df48a1277f20511f21f4d249ea977aa4fa721 Mon Sep 17 00:00:00 2001 +From: Anthony Liguori +Date: Wed, 12 Sep 2012 14:34:07 -0500 +Subject: [PATCH] Revert 455aa1e08 and c3767ed0eb + + commit c3767ed0eb5d0bb25fe409ae5dec06e3411ff1b6 + qemu-char: (Re-)connect for tcp_chr_write() unconnected writing + +Has no hope of working because tcp_chr_connect() does not actually connect. + +455aa1e08 just fixes the SEGV with server() but the attempt to connect a client +socket is still completely broken. + +This patch reverts both. + +Reported-by: Richard W.M. Jones +Signed-off-by: Anthony Liguori +(cherry picked from commit 6db0fdce02d72546a4c47100a9b2cd0090cf464d) + +Signed-off-by: Michael Roth +--- + qemu-char.c | 7 +------ + 1 file changed, 1 insertion(+), 6 deletions(-) + +diff --git a/qemu-char.c b/qemu-char.c +index 767da93..10d1504 100644 +--- a/qemu-char.c ++++ b/qemu-char.c +@@ -2141,18 +2141,13 @@ typedef struct { + + static void tcp_chr_accept(void *opaque); + +-static void tcp_chr_connect(void *opaque); +- + static int tcp_chr_write(CharDriverState *chr, const uint8_t *buf, int len) + { + TCPCharDriver *s = chr->opaque; + if (s->connected) { + return send_all(s->fd, buf, len); +- } else if (s->listen_fd == -1) { +- /* (Re-)connect for unconnected writing */ +- tcp_chr_connect(chr); +- return 0; + } else { ++ /* XXX: indicate an error ? */ + return len; + } + } +-- +1.7.12.1 + diff --git a/0201-spice-abort-on-invalid-streaming-cmdline-params.patch b/0201-spice-abort-on-invalid-streaming-cmdline-params.patch deleted file mode 100644 index fa5c5b1..0000000 --- a/0201-spice-abort-on-invalid-streaming-cmdline-params.patch +++ /dev/null @@ -1,38 +0,0 @@ -From 46851363e2aed89fc535803c8a23f6bed9934312 Mon Sep 17 00:00:00 2001 -From: Christophe Fergeau -Date: Mon, 13 Aug 2012 10:32:32 +0200 -Subject: [PATCH 201/215] spice: abort on invalid streaming cmdline params - -When parsing its command line parameters, spice aborts when it -finds unexpected values, except for the 'streaming-video' option. -This happens because the parsing of the parameters for this option -is done using the 'name2enum' helper, which does not error out -on unknown values. Using the 'parse_name' helper makes sure we -error out in this case. Looking at git history, the use of -'name2enum' instead of 'parse_name' seems to have been an oversight, -so let's change to that now. - -Fixes rhbz#831708 - -Signed-off-by: Gerd Hoffmann ---- - ui/spice-core.c | 3 ++- - 1 file changed, 2 insertions(+), 1 deletion(-) - -diff --git a/ui/spice-core.c b/ui/spice-core.c -index 4fc48f8..bb4f585 100644 ---- a/ui/spice-core.c -+++ b/ui/spice-core.c -@@ -344,7 +344,8 @@ static const char *stream_video_names[] = { - [ SPICE_STREAM_VIDEO_FILTER ] = "filter", - }; - #define parse_stream_video(_name) \ -- name2enum(_name, stream_video_names, ARRAY_SIZE(stream_video_names)) -+ parse_name(_name, "stream video control", \ -+ stream_video_names, ARRAY_SIZE(stream_video_names)) - - static const char *compression_names[] = { - [ SPICE_IMAGE_COMPRESS_OFF ] = "off", --- -1.7.12 - diff --git a/0202-qemu-char-BUGFIX-don-t-call-FD_ISSET-with-negative-f.patch b/0202-qemu-char-BUGFIX-don-t-call-FD_ISSET-with-negative-f.patch new file mode 100644 index 0000000..74f8f39 --- /dev/null +++ b/0202-qemu-char-BUGFIX-don-t-call-FD_ISSET-with-negative-f.patch @@ -0,0 +1,59 @@ +From 04eefabaae59ad624f0baf3b97a1d1d15cf2a23d Mon Sep 17 00:00:00 2001 +From: David Gibson +Date: Mon, 10 Sep 2012 12:30:56 +1000 +Subject: [PATCH] qemu-char: BUGFIX, don't call FD_ISSET with negative fd + +tcp_chr_connect(), unlike for example udp_chr_update_read_handler() does +not check if the fd it is using is valid (>= 0) before passing it to +qemu_set_fd_handler2(). If using e.g. a TCP serial port, which is not +initially connected, this can result in -1 being passed to FD_ISSET, which +has undefined behaviour. On x86 it seems to harmlessly return 0, but on +PowerPC, it causes a fortify buffer overflow error to be thrown. + +This patch fixes this by putting an extra test in tcp_chr_connect(), and +also adds an assert qemu_set_fd_handler2() to catch other such errors on +all platforms, rather than just some. + +Signed-off-by: David Gibson +Signed-off-by: Anthony Liguori +(cherry picked from commit bbdd2ad0814ea0911076419ea21b7957505cf1cc) + +Signed-off-by: Michael Roth +--- + iohandler.c | 2 ++ + qemu-char.c | 6 ++++-- + 2 files changed, 6 insertions(+), 2 deletions(-) + +diff --git a/iohandler.c b/iohandler.c +index dea4355..a2d871b 100644 +--- a/iohandler.c ++++ b/iohandler.c +@@ -56,6 +56,8 @@ int qemu_set_fd_handler2(int fd, + { + IOHandlerRecord *ioh; + ++ assert(fd >= 0); ++ + if (!fd_read && !fd_write) { + QLIST_FOREACH(ioh, &io_handlers, next) { + if (ioh->fd == fd) { +diff --git a/qemu-char.c b/qemu-char.c +index 10d1504..7f0f895 100644 +--- a/qemu-char.c ++++ b/qemu-char.c +@@ -2329,8 +2329,10 @@ static void tcp_chr_connect(void *opaque) + TCPCharDriver *s = chr->opaque; + + s->connected = 1; +- qemu_set_fd_handler2(s->fd, tcp_chr_read_poll, +- tcp_chr_read, NULL, chr); ++ if (s->fd >= 0) { ++ qemu_set_fd_handler2(s->fd, tcp_chr_read_poll, ++ tcp_chr_read, NULL, chr); ++ } + qemu_chr_generic_open(chr); + } + +-- +1.7.12.1 + diff --git a/0202-spice-notify-spice-server-on-vm-start-stop.patch b/0202-spice-notify-spice-server-on-vm-start-stop.patch deleted file mode 100644 index 150bb5c..0000000 --- a/0202-spice-notify-spice-server-on-vm-start-stop.patch +++ /dev/null @@ -1,52 +0,0 @@ -From 2d2ccb50223c16fbf08140b9dd59275657de2a61 Mon Sep 17 00:00:00 2001 -From: Yonit Halperin -Date: Tue, 21 Aug 2012 11:51:55 +0300 -Subject: [PATCH 202/215] spice: notify spice server on vm start/stop - -Spice server needs to know about the vm state in order to prevent -attempts to write to devices when they are stopped, mainly during -the non-live stage of migration. -Instead, spice will take care of restoring this writes, on the migration -target side, after migration completes. - -Signed-off-by: Yonit Halperin -Signed-off-by: Gerd Hoffmann ---- - ui/spice-core.c | 14 ++++++++++++++ - 1 file changed, 14 insertions(+) - -diff --git a/ui/spice-core.c b/ui/spice-core.c -index bb4f585..a515c94 100644 ---- a/ui/spice-core.c -+++ b/ui/spice-core.c -@@ -546,6 +546,18 @@ static int add_channel(const char *name, const char *value, void *opaque) - return 0; - } - -+static void vm_change_state_handler(void *opaque, int running, -+ RunState state) -+{ -+#if SPICE_SERVER_VERSION >= 0x000b02 /* 0.11.2 */ -+ if (running) { -+ spice_server_vm_start(spice_server); -+ } else { -+ spice_server_vm_stop(spice_server); -+ } -+#endif -+} -+ - void qemu_spice_init(void) - { - QemuOpts *opts = QTAILQ_FIRST(&qemu_spice_opts.head); -@@ -719,6 +731,8 @@ void qemu_spice_init(void) - qemu_spice_input_init(); - qemu_spice_audio_init(); - -+ qemu_add_vm_change_state_handler(vm_change_state_handler, &spice_server); -+ - g_free(x509_key_file); - g_free(x509_cert_file); - g_free(x509_cacert_file); --- -1.7.12 - diff --git a/0203-cpu_physical_memory_write_rom-needs-to-do-TB-invalid.patch b/0203-cpu_physical_memory_write_rom-needs-to-do-TB-invalid.patch new file mode 100644 index 0000000..cceb39c --- /dev/null +++ b/0203-cpu_physical_memory_write_rom-needs-to-do-TB-invalid.patch @@ -0,0 +1,52 @@ +From 897815f54c446671cae0f202c54e9548e969d427 Mon Sep 17 00:00:00 2001 +From: David Gibson +Date: Mon, 10 Sep 2012 12:30:57 +1000 +Subject: [PATCH] cpu_physical_memory_write_rom() needs to do TB invalidates + +cpu_physical_memory_write_rom(), despite the name, can also be used to +write images into RAM - and will often be used that way if the machine +uses load_image_targphys() into RAM addresses. + +However, cpu_physical_memory_write_rom(), unlike cpu_physical_memory_rw() +doesn't invalidate any cached TBs which might be affected by the region +written. + +This was breaking reset (under full emu) on the pseries machine - we loaded +our firmware image into RAM, and while executing it rewrite the code at +the entry point (correctly causing a TB invalidate/refresh). When we +reset the firmware image was reloaded, but the TB from the rewrite was +still active and caused us to get an illegal instruction trap. + +This patch fixes the bug by duplicating the tb invalidate code from +cpu_physical_memory_rw() in cpu_physical_memory_write_rom(). + +Signed-off-by: David Gibson +Signed-off-by: Anthony Liguori +(cherry picked from commit 0b57e287138728f72d88b06e69b970c5d745c44a) + +Signed-off-by: Michael Roth +--- + exec.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/exec.c b/exec.c +index ad175db..3fdbbde 100644 +--- a/exec.c ++++ b/exec.c +@@ -3521,6 +3521,13 @@ void cpu_physical_memory_write_rom(target_phys_addr_t addr, + /* ROM/RAM case */ + ptr = qemu_get_ram_ptr(addr1); + memcpy(ptr, buf, l); ++ if (!cpu_physical_memory_is_dirty(addr1)) { ++ /* invalidate code */ ++ tb_invalidate_phys_page_range(addr1, addr1 + l, 0); ++ /* set dirty bit */ ++ cpu_physical_memory_set_dirty_flags( ++ addr1, (0xff & ~CODE_DIRTY_FLAG)); ++ } + qemu_put_ram_ptr(ptr); + } + len -= l; +-- +1.7.12.1 + diff --git a/0203-spice-notify-on-vm-state-change-only-via-spice_serve.patch b/0203-spice-notify-on-vm-state-change-only-via-spice_serve.patch deleted file mode 100644 index e0b42d0..0000000 --- a/0203-spice-notify-on-vm-state-change-only-via-spice_serve.patch +++ /dev/null @@ -1,170 +0,0 @@ -From f7d481b35b63f2df58aaef5afcac5ca1e67ce233 Mon Sep 17 00:00:00 2001 -From: Yonit Halperin -Date: Tue, 21 Aug 2012 11:51:56 +0300 -Subject: [PATCH 203/215] spice: notify on vm state change only via - spice_server_vm_start/stop - -QXLWorker->start/stop are deprecated since spice-server 0.11.2 - -Signed-off-by: Yonit Halperin -Signed-off-by: Gerd Hoffmann ---- - hw/qxl.c | 7 ++++--- - ui/spice-core.c | 4 ++++ - ui/spice-display.c | 32 ++++++++++++++++++++++++++++++-- - ui/spice-display.h | 9 +++++++-- - 4 files changed, 45 insertions(+), 7 deletions(-) - -diff --git a/hw/qxl.c b/hw/qxl.c -index c2dd3b4..95bbc03 100644 ---- a/hw/qxl.c -+++ b/hw/qxl.c -@@ -958,9 +958,10 @@ static void qxl_update_irq(PCIQXLDevice *d) - static void qxl_check_state(PCIQXLDevice *d) - { - QXLRam *ram = d->ram; -+ int spice_display_running = qemu_spice_display_is_running(&d->ssd); - -- assert(!d->ssd.running || SPICE_RING_IS_EMPTY(&ram->cmd_ring)); -- assert(!d->ssd.running || SPICE_RING_IS_EMPTY(&ram->cursor_ring)); -+ assert(!spice_display_running || SPICE_RING_IS_EMPTY(&ram->cmd_ring)); -+ assert(!spice_display_running || SPICE_RING_IS_EMPTY(&ram->cursor_ring)); - } - - static void qxl_reset_state(PCIQXLDevice *d) -@@ -1538,7 +1539,7 @@ static void qxl_send_events(PCIQXLDevice *d, uint32_t events) - uint32_t old_pending; - uint32_t le_events = cpu_to_le32(events); - -- assert(d->ssd.running); -+ assert(qemu_spice_display_is_running(&d->ssd)); - old_pending = __sync_fetch_and_or(&d->ram->int_pending, le_events); - if ((old_pending & le_events) == le_events) { - return; -diff --git a/ui/spice-core.c b/ui/spice-core.c -index a515c94..1a7a773 100644 ---- a/ui/spice-core.c -+++ b/ui/spice-core.c -@@ -37,6 +37,7 @@ - #include "migration.h" - #include "monitor.h" - #include "hw/hw.h" -+#include "spice-display.h" - - /* core bits */ - -@@ -551,9 +552,11 @@ static void vm_change_state_handler(void *opaque, int running, - { - #if SPICE_SERVER_VERSION >= 0x000b02 /* 0.11.2 */ - if (running) { -+ qemu_spice_display_start(); - spice_server_vm_start(spice_server); - } else { - spice_server_vm_stop(spice_server); -+ qemu_spice_display_stop(); - } - #endif - } -@@ -755,6 +758,7 @@ int qemu_spice_add_interface(SpiceBaseInstance *sin) - spice_server = spice_server_new(); - spice_server_init(spice_server, &core_interface); - } -+ - return spice_server_add_interface(spice_server, sin); - } - -diff --git a/ui/spice-display.c b/ui/spice-display.c -index 3e8f0b3..1c31418 100644 ---- a/ui/spice-display.c -+++ b/ui/spice-display.c -@@ -126,18 +126,44 @@ void qemu_spice_wakeup(SimpleSpiceDisplay *ssd) - ssd->worker->wakeup(ssd->worker); - } - --void qemu_spice_start(SimpleSpiceDisplay *ssd) -+#if SPICE_SERVER_VERSION < 0x000b02 /* before 0.11.2 */ -+static void qemu_spice_start(SimpleSpiceDisplay *ssd) - { - trace_qemu_spice_start(ssd->qxl.id); - ssd->worker->start(ssd->worker); - } - --void qemu_spice_stop(SimpleSpiceDisplay *ssd) -+static void qemu_spice_stop(SimpleSpiceDisplay *ssd) - { - trace_qemu_spice_stop(ssd->qxl.id); - ssd->worker->stop(ssd->worker); - } - -+#else -+ -+static int spice_display_is_running; -+ -+void qemu_spice_display_start(void) -+{ -+ spice_display_is_running = true; -+} -+ -+void qemu_spice_display_stop(void) -+{ -+ spice_display_is_running = false; -+} -+ -+#endif -+ -+int qemu_spice_display_is_running(SimpleSpiceDisplay *ssd) -+{ -+#if SPICE_SERVER_VERSION < 0x000b02 /* before 0.11.2 */ -+ return ssd->running; -+#else -+ return spice_display_is_running; -+#endif -+} -+ - static SimpleSpiceUpdate *qemu_spice_create_update(SimpleSpiceDisplay *ssd) - { - SimpleSpiceUpdate *update; -@@ -272,6 +298,7 @@ void qemu_spice_destroy_host_primary(SimpleSpiceDisplay *ssd) - void qemu_spice_vm_change_state_handler(void *opaque, int running, - RunState state) - { -+#if SPICE_SERVER_VERSION < 0x000b02 /* before 0.11.2 */ - SimpleSpiceDisplay *ssd = opaque; - - if (running) { -@@ -281,6 +308,7 @@ void qemu_spice_vm_change_state_handler(void *opaque, int running, - qemu_spice_stop(ssd); - ssd->running = false; - } -+#endif - } - - void qemu_spice_display_init_common(SimpleSpiceDisplay *ssd, DisplayState *ds) -diff --git a/ui/spice-display.h b/ui/spice-display.h -index 12e50b6..672d65e 100644 ---- a/ui/spice-display.h -+++ b/ui/spice-display.h -@@ -82,7 +82,9 @@ struct SimpleSpiceDisplay { - - QXLRect dirty; - int notify; -+#if SPICE_SERVER_VERSION < 0x000b02 /* before 0.11.2 */ - int running; -+#endif - - /* - * All struct members below this comment can be accessed from -@@ -129,5 +131,8 @@ void qemu_spice_create_primary_surface(SimpleSpiceDisplay *ssd, uint32_t id, - void qemu_spice_destroy_primary_surface(SimpleSpiceDisplay *ssd, - uint32_t id, qxl_async_io async); - void qemu_spice_wakeup(SimpleSpiceDisplay *ssd); --void qemu_spice_start(SimpleSpiceDisplay *ssd); --void qemu_spice_stop(SimpleSpiceDisplay *ssd); -+#if SPICE_SERVER_VERSION >= 0x000b02 /* before 0.11.2 */ -+void qemu_spice_display_start(void); -+void qemu_spice_display_stop(void); -+#endif -+int qemu_spice_display_is_running(SimpleSpiceDisplay *ssd); --- -1.7.12 - diff --git a/0204-arch_init.c-Improve-soundhw-help-for-non-HAS_AUDIO_C.patch b/0204-arch_init.c-Improve-soundhw-help-for-non-HAS_AUDIO_C.patch new file mode 100644 index 0000000..d9001a5 --- /dev/null +++ b/0204-arch_init.c-Improve-soundhw-help-for-non-HAS_AUDIO_C.patch @@ -0,0 +1,43 @@ +From 8daf993d3d75acea92ef5054c924c7d825ae812e Mon Sep 17 00:00:00 2001 +From: Peter Maydell +Date: Wed, 19 Sep 2012 14:51:38 +0100 +Subject: [PATCH] arch_init.c: Improve '-soundhw help' for + non-HAS_AUDIO_CHOICE archs + +For architectures which don't set HAS_AUDIO_CHOICE, improve the +'-soundhw help' message so that it doesn't simply print an empty +list, implying no sound support at all. + +Signed-off-by: Peter Maydell +Signed-off-by: malc +(cherry picked from commit 55d4fd3c24bd253bd96270c7fdf1bb862f3a3400) + +Signed-off-by: Michael Roth +--- + arch_init.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/arch_init.c b/arch_init.c +index 47977de..f849f9b 100644 +--- a/arch_init.c ++++ b/arch_init.c +@@ -922,11 +922,16 @@ void select_soundhw(const char *optarg) + if (is_help_option(optarg)) { + show_valid_cards: + ++#ifdef HAS_AUDIO_CHOICE + printf("Valid sound card names (comma separated):\n"); + for (c = soundhw; c->name; ++c) { + printf ("%-11s %s\n", c->name, c->descr); + } + printf("\n-soundhw all will enable all of the above\n"); ++#else ++ printf("Machine has no user-selectable audio hardware " ++ "(it may or may not have always-present audio hardware).\n"); ++#endif + exit(!is_help_option(optarg)); + } + else { +-- +1.7.12.1 + diff --git a/0204-spice-migration-add-QEVENT_SPICE_MIGRATE_COMPLETED.patch b/0204-spice-migration-add-QEVENT_SPICE_MIGRATE_COMPLETED.patch deleted file mode 100644 index 631271a..0000000 --- a/0204-spice-migration-add-QEVENT_SPICE_MIGRATE_COMPLETED.patch +++ /dev/null @@ -1,90 +0,0 @@ -From d8543fcc36b38c76a638d15ed95d8b5acf27d93a Mon Sep 17 00:00:00 2001 -From: Yonit Halperin -Date: Tue, 21 Aug 2012 11:51:57 +0300 -Subject: [PATCH 204/215] spice migration: add QEVENT_SPICE_MIGRATE_COMPLETED - -When migrating, libvirt queries the migration status, and upon migration -completions, it closes the migration src. On the other hand, when -migration is completed, spice transfers data from the src to destination -via the client. This data is required for keeping the spice session -after migration, without suffering from data loss and inconsistencies. -In order to allow this data transfer, we add QEVENT for signaling -libvirt that spice migration has completed, and libvirt needs to wait -for this event before quitting the src process. - -Signed-off-by: Yonit Halperin -Signed-off-by: Gerd Hoffmann ---- - monitor.c | 1 + - monitor.h | 1 + - ui/spice-core.c | 9 ++++++++- - 3 files changed, 10 insertions(+), 1 deletion(-) - -diff --git a/monitor.c b/monitor.c -index c14698d..99eee98 100644 ---- a/monitor.c -+++ b/monitor.c -@@ -455,6 +455,7 @@ static const char *monitor_event_names[] = { - [QEVENT_SUSPEND_DISK] = "SUSPEND_DISK", - [QEVENT_WAKEUP] = "WAKEUP", - [QEVENT_BALLOON_CHANGE] = "BALLOON_CHANGE", -+ [QEVENT_SPICE_MIGRATE_COMPLETED] = "SPICE_MIGRATE_COMPLETED", - }; - QEMU_BUILD_BUG_ON(ARRAY_SIZE(monitor_event_names) != QEVENT_MAX) - -diff --git a/monitor.h b/monitor.h -index 47d556b..5fc2983 100644 ---- a/monitor.h -+++ b/monitor.h -@@ -43,6 +43,7 @@ typedef enum MonitorEvent { - QEVENT_SUSPEND_DISK, - QEVENT_WAKEUP, - QEVENT_BALLOON_CHANGE, -+ QEVENT_SPICE_MIGRATE_COMPLETED, - - /* Add to 'monitor_event_names' array in monitor.c when - * defining new events here */ -diff --git a/ui/spice-core.c b/ui/spice-core.c -index 1a7a773..851e869 100644 ---- a/ui/spice-core.c -+++ b/ui/spice-core.c -@@ -285,6 +285,7 @@ typedef struct SpiceMigration { - } SpiceMigration; - - static void migrate_connect_complete_cb(SpiceMigrateInstance *sin); -+static void migrate_end_complete_cb(SpiceMigrateInstance *sin); - - static const SpiceMigrateInterface migrate_interface = { - .base.type = SPICE_INTERFACE_MIGRATION, -@@ -292,7 +293,7 @@ static const SpiceMigrateInterface migrate_interface = { - .base.major_version = SPICE_INTERFACE_MIGRATION_MAJOR, - .base.minor_version = SPICE_INTERFACE_MIGRATION_MINOR, - .migrate_connect_complete = migrate_connect_complete_cb, -- .migrate_end_complete = NULL, -+ .migrate_end_complete = migrate_end_complete_cb, - }; - - static SpiceMigration spice_migrate; -@@ -305,6 +306,11 @@ static void migrate_connect_complete_cb(SpiceMigrateInstance *sin) - } - sm->connect_complete.cb = NULL; - } -+ -+static void migrate_end_complete_cb(SpiceMigrateInstance *sin) -+{ -+ monitor_protocol_event(QEVENT_SPICE_MIGRATE_COMPLETED, NULL); -+} - #endif - - /* config string parsing */ -@@ -489,6 +495,7 @@ static void migration_state_notifier(Notifier *notifier, void *data) - } else if (migration_has_finished(s)) { - #ifndef SPICE_INTERFACE_MIGRATION - spice_server_migrate_switch(spice_server); -+ monitor_protocol_event(QEVENT_SPICE_MIGRATE_COMPLETED, NULL); - #else - spice_server_migrate_end(spice_server, true); - } else if (migration_has_failed(s)) { --- -1.7.12 - diff --git a/0205-spice-add-migrated-flag-to-spice-info.patch b/0205-spice-add-migrated-flag-to-spice-info.patch deleted file mode 100644 index 0e63c64..0000000 --- a/0205-spice-add-migrated-flag-to-spice-info.patch +++ /dev/null @@ -1,94 +0,0 @@ -From ad7734d7a3cb4560dcc0bef2794adeddc793af75 Mon Sep 17 00:00:00 2001 -From: Yonit Halperin -Date: Tue, 21 Aug 2012 11:51:58 +0300 -Subject: [PATCH 205/215] spice: add 'migrated' flag to spice info - -The flag is 'true' when spice migration has completed on the src side. -It is needed for a case where libvirt dies before migration completes -and it misses the event QEVENT_SPICE_MIGRATE_COMPLETED. -When libvirt is restored and queries the migration status, it also needs -to query spice and check if its migration has completed. - -Signed-off-by: Yonit Halperin -Signed-off-by: Gerd Hoffmann ---- - hmp.c | 2 ++ - qapi-schema.json | 5 ++++- - ui/spice-core.c | 4 ++++ - 3 files changed, 10 insertions(+), 1 deletion(-) - -diff --git a/hmp.c b/hmp.c -index 81c8acb..ec4274b 100644 ---- a/hmp.c -+++ b/hmp.c -@@ -413,6 +413,8 @@ void hmp_info_spice(Monitor *mon) - monitor_printf(mon, " address: %s:%" PRId64 " [tls]\n", - info->host, info->tls_port); - } -+ monitor_printf(mon, " migrated: %s\n", -+ info->migrated ? "true" : "false"); - monitor_printf(mon, " auth: %s\n", info->auth); - monitor_printf(mon, " compiled: %s\n", info->compiled_version); - monitor_printf(mon, " mouse-mode: %s\n", -diff --git a/qapi-schema.json b/qapi-schema.json -index bd8ad74..8ddde12 100644 ---- a/qapi-schema.json -+++ b/qapi-schema.json -@@ -808,6 +808,9 @@ - # - # @enabled: true if the SPICE server is enabled, false otherwise - # -+# @migrated: true if the last guest migration completed and spice -+# migration had completed as well. false otherwise. -+# - # @host: #optional The hostname the SPICE server is bound to. This depends on - # the name resolution on the host and may be an IP address. - # -@@ -833,7 +836,7 @@ - # Since: 0.14.0 - ## - { 'type': 'SpiceInfo', -- 'data': {'enabled': 'bool', '*host': 'str', '*port': 'int', -+ 'data': {'enabled': 'bool', 'migrated': 'bool', '*host': 'str', '*port': 'int', - '*tls-port': 'int', '*auth': 'str', '*compiled-version': 'str', - 'mouse-mode': 'SpiceQueryMouseMode', '*channels': ['SpiceChannel']} } - -diff --git a/ui/spice-core.c b/ui/spice-core.c -index 851e869..ab069c5 100644 ---- a/ui/spice-core.c -+++ b/ui/spice-core.c -@@ -46,6 +46,7 @@ static Notifier migration_state; - static const char *auth = "spice"; - static char *auth_passwd; - static time_t auth_expires = TIME_MAX; -+static int spice_migration_completed; - int using_spice = 0; - - static QemuThread me; -@@ -310,6 +311,7 @@ static void migrate_connect_complete_cb(SpiceMigrateInstance *sin) - static void migrate_end_complete_cb(SpiceMigrateInstance *sin) - { - monitor_protocol_event(QEVENT_SPICE_MIGRATE_COMPLETED, NULL); -+ spice_migration_completed = true; - } - #endif - -@@ -443,6 +445,7 @@ SpiceInfo *qmp_query_spice(Error **errp) - } - - info->enabled = true; -+ info->migrated = spice_migration_completed; - - addr = qemu_opt_get(opts, "addr"); - port = qemu_opt_get_number(opts, "port", 0); -@@ -496,6 +499,7 @@ static void migration_state_notifier(Notifier *notifier, void *data) - #ifndef SPICE_INTERFACE_MIGRATION - spice_server_migrate_switch(spice_server); - monitor_protocol_event(QEVENT_SPICE_MIGRATE_COMPLETED, NULL); -+ spice_migration_completed = true; - #else - spice_server_migrate_end(spice_server, true); - } else if (migration_has_failed(s)) { --- -1.7.12 - diff --git a/0205-xilinx_timer-Removed-comma-in-device-name.patch b/0205-xilinx_timer-Removed-comma-in-device-name.patch new file mode 100644 index 0000000..26b5d66 --- /dev/null +++ b/0205-xilinx_timer-Removed-comma-in-device-name.patch @@ -0,0 +1,54 @@ +From 030d44c473036d44abc76562860a89b21220ca2f Mon Sep 17 00:00:00 2001 +From: "Peter A. G. Crosthwaite" +Date: Thu, 28 Jun 2012 12:52:23 +1000 +Subject: [PATCH] xilinx_timer: Removed comma in device name + +Fixes an error in a61e4b07a30c062260d2d01771773f14820d1eb7 + +Signed-off-by: Peter A. G. Crosthwaite +(cherry picked from commit c0a1dcb9f0baf9269f8baeb02cbcca8dad75454c) + +Signed-off-by: Michael Roth +--- + hw/xilinx.h | 2 +- + hw/xilinx_timer.c | 4 ++-- + 2 files changed, 3 insertions(+), 3 deletions(-) + +diff --git a/hw/xilinx.h b/hw/xilinx.h +index 556c5aa..df06a00 100644 +--- a/hw/xilinx.h ++++ b/hw/xilinx.h +@@ -21,7 +21,7 @@ xilinx_timer_create(target_phys_addr_t base, qemu_irq irq, int oto, int freq) + { + DeviceState *dev; + +- dev = qdev_create(NULL, "xlnx,xps-timer"); ++ dev = qdev_create(NULL, "xlnx.xps-timer"); + qdev_prop_set_uint32(dev, "one-timer-only", oto); + qdev_prop_set_uint32(dev, "frequency", freq); + qdev_init_nofail(dev); +diff --git a/hw/xilinx_timer.c b/hw/xilinx_timer.c +index b562bd0..053ba02 100644 +--- a/hw/xilinx_timer.c ++++ b/hw/xilinx_timer.c +@@ -217,7 +217,7 @@ static int xilinx_timer_init(SysBusDevice *dev) + ptimer_set_freq(xt->ptimer, t->freq_hz); + } + +- memory_region_init_io(&t->mmio, &timer_ops, t, "xlnx,xps-timer", ++ memory_region_init_io(&t->mmio, &timer_ops, t, "xlnx.xps-timer", + R_MAX * 4 * num_timers(t)); + sysbus_init_mmio(dev, &t->mmio); + return 0; +@@ -239,7 +239,7 @@ static void xilinx_timer_class_init(ObjectClass *klass, void *data) + } + + static TypeInfo xilinx_timer_info = { +- .name = "xlnx,xps-timer", ++ .name = "xlnx.xps-timer", + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(struct timerblock), + .class_init = xilinx_timer_class_init, +-- +1.7.12.1 + diff --git a/0206-spice-adding-seamless-migration-option-to-the-comman.patch b/0206-spice-adding-seamless-migration-option-to-the-comman.patch deleted file mode 100644 index ac0e9a7..0000000 --- a/0206-spice-adding-seamless-migration-option-to-the-comman.patch +++ /dev/null @@ -1,77 +0,0 @@ -From 978a72a62c36e932a4b7ae18a5cf23d2d30e9755 Mon Sep 17 00:00:00 2001 -From: Yonit Halperin -Date: Tue, 21 Aug 2012 11:51:59 +0300 -Subject: [PATCH 206/215] spice: adding seamless-migration option to the - command line - -The seamless-migration flag is required in order to identify -whether libvirt supports the new QEVENT_SPICE_MIGRATE_COMPLETED or not -(by default the flag is off). -New libvirt versions that wait for QEVENT_SPICE_MIGRATE_COMPLETED should turn on this flag. -When this flag is off, spice fallbacks to its old migration method, which -can result in data loss. - -Signed-off-by: Yonit Halperin -Signed-off-by: Gerd Hoffmann ---- - qemu-config.c | 3 +++ - qemu-options.hx | 3 +++ - ui/spice-core.c | 7 +++++++ - 3 files changed, 13 insertions(+) - -diff --git a/qemu-config.c b/qemu-config.c -index 238390e..3eaee48 100644 ---- a/qemu-config.c -+++ b/qemu-config.c -@@ -541,6 +541,9 @@ QemuOptsList qemu_spice_opts = { - },{ - .name = "playback-compression", - .type = QEMU_OPT_BOOL, -+ }, { -+ .name = "seamless-migration", -+ .type = QEMU_OPT_BOOL, - }, - { /* end of list */ } - }, -diff --git a/qemu-options.hx b/qemu-options.hx -index ea06324..dd7aa63 100644 ---- a/qemu-options.hx -+++ b/qemu-options.hx -@@ -920,6 +920,9 @@ Enable/disable passing mouse events via vdagent. Default is on. - @item playback-compression=[on|off] - Enable/disable audio stream compression (using celt 0.5.1). Default is on. - -+@item seamless-migration=[on|off] -+Enable/disable spice seamless migration. Default is off. -+ - @end table - ETEXI - -diff --git a/ui/spice-core.c b/ui/spice-core.c -index ab069c5..ba0d0bd 100644 ---- a/ui/spice-core.c -+++ b/ui/spice-core.c -@@ -585,6 +585,9 @@ void qemu_spice_init(void) - int port, tls_port, len, addr_flags; - spice_image_compression_t compression; - spice_wan_compression_t wan_compr; -+#if SPICE_SERVER_VERSION >= 0x000b02 /* 0.11.2 */ -+ bool seamless_migration; -+#endif - - qemu_thread_get_self(&me); - -@@ -728,6 +731,10 @@ void qemu_spice_init(void) - spice_server_set_uuid(spice_server, qemu_uuid); - #endif - -+#if SPICE_SERVER_VERSION >= 0x000b02 /* 0.11.2 */ -+ seamless_migration = qemu_opt_get_bool(opts, "seamless-migration", 0); -+ spice_server_set_seamless_migration(spice_server, seamless_migration); -+#endif - if (0 != spice_server_init(spice_server, &core_interface)) { - error_report("failed to initialize spice server"); - exit(1); --- -1.7.12 - diff --git a/0206-xilinx_timer-Send-dbg-msgs-to-stderr-not-stdout.patch b/0206-xilinx_timer-Send-dbg-msgs-to-stderr-not-stdout.patch new file mode 100644 index 0000000..e7b8ea1 --- /dev/null +++ b/0206-xilinx_timer-Send-dbg-msgs-to-stderr-not-stdout.patch @@ -0,0 +1,56 @@ +From c03bf619fe8eb416aaea1f8b75b313a4b314ffeb Mon Sep 17 00:00:00 2001 +From: "Peter A. G. Crosthwaite" +Date: Thu, 28 Jun 2012 16:28:03 +1000 +Subject: [PATCH] xilinx_timer: Send dbg msgs to stderr not stdout + +Signed-off-by: Peter A. G. Crosthwaite +(cherry picked from commit e03377ae75808d33d0a7afc803b37bcda9f796b3) + +Signed-off-by: Michael Roth +--- + hw/xilinx_timer.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/hw/xilinx_timer.c b/hw/xilinx_timer.c +index 053ba02..c02e6ca 100644 +--- a/hw/xilinx_timer.c ++++ b/hw/xilinx_timer.c +@@ -119,7 +119,7 @@ timer_read(void *opaque, target_phys_addr_t addr, unsigned int size) + break; + + } +- D(printf("%s timer=%d %x=%x\n", __func__, timer, addr * 4, r)); ++ D(fprintf(stderr, "%s timer=%d %x=%x\n", __func__, timer, addr * 4, r)); + return r; + } + +@@ -127,7 +127,7 @@ static void timer_enable(struct xlx_timer *xt) + { + uint64_t count; + +- D(printf("%s timer=%d down=%d\n", __func__, ++ D(fprintf(stderr, "%s timer=%d down=%d\n", __func__, + xt->nr, xt->regs[R_TCSR] & TCSR_UDT)); + + ptimer_stop(xt->ptimer); +@@ -152,7 +152,7 @@ timer_write(void *opaque, target_phys_addr_t addr, + addr >>= 2; + timer = timer_from_addr(addr); + xt = &t->timers[timer]; +- D(printf("%s addr=%x val=%x (timer=%d off=%d)\n", ++ D(fprintf(stderr, "%s addr=%x val=%x (timer=%d off=%d)\n", + __func__, addr * 4, value, timer, addr & 3)); + /* Further decoding to address a specific timers reg. */ + addr &= 3; +@@ -189,7 +189,7 @@ static void timer_hit(void *opaque) + { + struct xlx_timer *xt = opaque; + struct timerblock *t = xt->parent; +- D(printf("%s %d\n", __func__, timer)); ++ D(fprintf(stderr, "%s %d\n", __func__, timer)); + xt->regs[R_TCSR] |= TCSR_TINT; + + if (xt->regs[R_TCSR] & TCSR_ARHT) +-- +1.7.12.1 + diff --git a/0207-spice-increase-the-verbosity-of-spice-section-in-qem.patch b/0207-spice-increase-the-verbosity-of-spice-section-in-qem.patch deleted file mode 100644 index 6440642..0000000 --- a/0207-spice-increase-the-verbosity-of-spice-section-in-qem.patch +++ /dev/null @@ -1,47 +0,0 @@ -From 54704702dbbb1d55f2aaecf5c837a583d9e209a5 Mon Sep 17 00:00:00 2001 -From: Yonit Halperin -Date: Tue, 21 Aug 2012 13:54:20 +0300 -Subject: [PATCH 207/215] spice: increase the verbosity of spice section in - "qemu --help" - -Added all spice options to the help string. This can be used by libvirt -to determine which spice related features are supported by qemu. - -Signed-off-by: Yonit Halperin -Signed-off-by: Gerd Hoffmann ---- - qemu-options.hx | 18 +++++++++++++++++- - 1 file changed, 17 insertions(+), 1 deletion(-) - -diff --git a/qemu-options.hx b/qemu-options.hx -index dd7aa63..1af4fec 100644 ---- a/qemu-options.hx -+++ b/qemu-options.hx -@@ -838,7 +838,23 @@ Enable SDL. - ETEXI - - DEF("spice", HAS_ARG, QEMU_OPTION_spice, -- "-spice enable spice\n", QEMU_ARCH_ALL) -+ "-spice [port=port][,tls-port=secured-port][,x509-dir=]\n" -+ " [,x509-key-file=][,x509-key-password=]\n" -+ " [,x509-cert-file=][,x509-cacert-file=]\n" -+ " [,x509-dh-key-file=][,addr=addr][,ipv4|ipv6]\n" -+ " [,tls-ciphers=]\n" -+ " [,tls-channel=[main|display|cursor|inputs|record|playback]]\n" -+ " [,plaintext-channel=[main|display|cursor|inputs|record|playback]]\n" -+ " [,sasl][,password=][,disable-ticketing]\n" -+ " [,image-compression=[auto_glz|auto_lz|quic|glz|lz|off]]\n" -+ " [,jpeg-wan-compression=[auto|never|always]]\n" -+ " [,zlib-glz-wan-compression=[auto|never|always]]\n" -+ " [,streaming-video=[off|all|filter]][,disable-copy-paste]\n" -+ " [,agent-mouse=[on|off]][,playback-compression=[on|off]]\n" -+ " [,seamless-migration=[on|off]]\n" -+ " enable spice\n" -+ " at least one of {port, tls-port} is mandatory\n", -+ QEMU_ARCH_ALL) - STEXI - @item -spice @var{option}[,@var{option}[,...]] - @findex -spice --- -1.7.12 - diff --git a/0207-xilinx.h-Error-check-when-setting-links.patch b/0207-xilinx.h-Error-check-when-setting-links.patch new file mode 100644 index 0000000..924d91f --- /dev/null +++ b/0207-xilinx.h-Error-check-when-setting-links.patch @@ -0,0 +1,54 @@ +From bfec52da020f35304f4e059bf4725fe01dbdd154 Mon Sep 17 00:00:00 2001 +From: "Peter A. G. Crosthwaite" +Date: Mon, 17 Sep 2012 13:41:39 +1000 +Subject: [PATCH] xilinx.h: Error check when setting links + +Assert that the ethernet and dma controller are sucessfully linked to their +peers. + +Signed-off-by: Peter A. G. Crosthwaite +(cherry picked from commit 4b5e52101f9ad077d1c016f2b7130e2fdae6d2da) + +Signed-off-by: Michael Roth +--- + hw/xilinx.h | 10 ++++++++-- + 1 file changed, 8 insertions(+), 2 deletions(-) + +diff --git a/hw/xilinx.h b/hw/xilinx.h +index df06a00..35d6681 100644 +--- a/hw/xilinx.h ++++ b/hw/xilinx.h +@@ -55,13 +55,16 @@ xilinx_axiethernet_create(NICInfo *nd, StreamSlave *peer, + int txmem, int rxmem) + { + DeviceState *dev; ++ Error *errp = NULL; ++ + qemu_check_nic_model(nd, "xlnx.axi-ethernet"); + + dev = qdev_create(NULL, "xlnx.axi-ethernet"); + qdev_set_nic_properties(dev, nd); + qdev_prop_set_uint32(dev, "rxmem", rxmem); + qdev_prop_set_uint32(dev, "txmem", txmem); +- object_property_set_link(OBJECT(dev), OBJECT(peer), "tx_dev", NULL); ++ object_property_set_link(OBJECT(dev), OBJECT(peer), "tx_dev", &errp); ++ assert_no_error(errp); + qdev_init_nofail(dev); + sysbus_mmio_map(sysbus_from_qdev(dev), 0, base); + sysbus_connect_irq(sysbus_from_qdev(dev), 0, irq); +@@ -74,8 +77,11 @@ xilinx_axiethernetdma_init(DeviceState *dev, StreamSlave *peer, + target_phys_addr_t base, qemu_irq irq, + qemu_irq irq2, int freqhz) + { ++ Error *errp = NULL; ++ + qdev_prop_set_uint32(dev, "freqhz", freqhz); +- object_property_set_link(OBJECT(dev), OBJECT(peer), "tx_dev", NULL); ++ object_property_set_link(OBJECT(dev), OBJECT(peer), "tx_dev", &errp); ++ assert_no_error(errp); + qdev_init_nofail(dev); + + sysbus_mmio_map(sysbus_from_qdev(dev), 0, base); +-- +1.7.12.1 + diff --git a/0208-qxl-update_area_io-guest_bug-on-invalid-parameters.patch b/0208-qxl-update_area_io-guest_bug-on-invalid-parameters.patch deleted file mode 100644 index beefe40..0000000 --- a/0208-qxl-update_area_io-guest_bug-on-invalid-parameters.patch +++ /dev/null @@ -1,37 +0,0 @@ -From c3236169b390617d13ede20ff0aed5d0bc1aba66 Mon Sep 17 00:00:00 2001 -From: Alon Levy -Date: Tue, 21 Aug 2012 13:51:31 +0300 -Subject: [PATCH 208/215] qxl/update_area_io: guest_bug on invalid parameters - -Signed-off-by: Alon Levy -Signed-off-by: Gerd Hoffmann ---- - hw/qxl.c | 12 ++++++++++++ - 1 file changed, 12 insertions(+) - -diff --git a/hw/qxl.c b/hw/qxl.c -index 95bbc03..baf9bb4 100644 ---- a/hw/qxl.c -+++ b/hw/qxl.c -@@ -1386,6 +1386,18 @@ async_common: - QXLCookie *cookie = NULL; - QXLRect update = d->ram->update_area; - -+ if (d->ram->update_surface > NUM_SURFACES) { -+ qxl_set_guest_bug(d, "QXL_IO_UPDATE_AREA: invalid surface id %d\n", -+ d->ram->update_surface); -+ return; -+ } -+ if (update.left >= update.right || update.top >= update.bottom) { -+ qxl_set_guest_bug(d, -+ "QXL_IO_UPDATE_AREA: invalid area (%ux%u)x(%ux%u)\n", -+ update.left, update.top, update.right, update.bottom); -+ return; -+ } -+ - if (async == QXL_ASYNC) { - cookie = qxl_cookie_new(QXL_COOKIE_TYPE_IO, - QXL_IO_UPDATE_AREA_ASYNC); --- -1.7.12 - diff --git a/0208-xilinx_timer-Fix-a-compile-error-if-debug-enabled.patch b/0208-xilinx_timer-Fix-a-compile-error-if-debug-enabled.patch new file mode 100644 index 0000000..7c084bf --- /dev/null +++ b/0208-xilinx_timer-Fix-a-compile-error-if-debug-enabled.patch @@ -0,0 +1,41 @@ +From 593883a749b0659ab4a2f2d96e65c34a3bd0fcca Mon Sep 17 00:00:00 2001 +From: Chris Wulff +Date: Sun, 9 Sep 2012 20:20:07 -0400 +Subject: [PATCH] xilinx_timer: Fix a compile error if debug enabled + +There was a missing include of qemu-log and a variable name in a printf was out +of date. + +Signed-off-by: Chris Wulff +Signed-off-by: Peter A. G. Crosthwaite +(cherry picked from commit 8354cd722e0afae63bee3e4cb21c8f0ddb6874c2) + +Signed-off-by: Michael Roth +--- + hw/xilinx_timer.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/hw/xilinx_timer.c b/hw/xilinx_timer.c +index c02e6ca..f410487 100644 +--- a/hw/xilinx_timer.c ++++ b/hw/xilinx_timer.c +@@ -24,6 +24,7 @@ + + #include "sysbus.h" + #include "ptimer.h" ++#include "qemu-log.h" + + #define D(x) + +@@ -189,7 +190,7 @@ static void timer_hit(void *opaque) + { + struct xlx_timer *xt = opaque; + struct timerblock *t = xt->parent; +- D(fprintf(stderr, "%s %d\n", __func__, timer)); ++ D(fprintf(stderr, "%s %d\n", __func__, xt->nr)); + xt->regs[R_TCSR] |= TCSR_TINT; + + if (xt->regs[R_TCSR] & TCSR_ARHT) +-- +1.7.12.1 + diff --git a/0209-pflash_cfi01-fix-vendor-specific-extended-query.patch b/0209-pflash_cfi01-fix-vendor-specific-extended-query.patch new file mode 100644 index 0000000..40c0e51 --- /dev/null +++ b/0209-pflash_cfi01-fix-vendor-specific-extended-query.patch @@ -0,0 +1,49 @@ +From a53ed08e1f8ee2a235213e802f3d5bb3342adaf3 Mon Sep 17 00:00:00 2001 +From: Aurelien Jarno +Date: Mon, 3 Sep 2012 22:47:03 +0200 +Subject: [PATCH] pflash_cfi01: fix vendor specific extended query + +pflash_cfi01 announces a version number of 1.1, which implies +"Protection Register Information" and "Burst Read information" +sections, which are not provided. + +Decrease the version number to 1.0 so that only the "Protection +Register Information" section is needed. + +Set the number of protection fields (0x3f) to 0x01, as 0x00 means 256 +protections field, which makes the CFI table bigger than the current +implementation, causing some kernels to fail to read it. + +Signed-off-by: Aurelien Jarno +(cherry picked from commit 262e1eaafabf32d33a9fa0b03b3c8ea426c5ae1b) + +Signed-off-by: Michael Roth +--- + hw/pflash_cfi01.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/hw/pflash_cfi01.c b/hw/pflash_cfi01.c +index d1c7423..d56b51a 100644 +--- a/hw/pflash_cfi01.c ++++ b/hw/pflash_cfi01.c +@@ -711,7 +711,7 @@ pflash_t *pflash_cfi01_register(target_phys_addr_t base, + pfl->cfi_table[0x33] = 'I'; + + pfl->cfi_table[0x34] = '1'; +- pfl->cfi_table[0x35] = '1'; ++ pfl->cfi_table[0x35] = '0'; + + pfl->cfi_table[0x36] = 0x00; + pfl->cfi_table[0x37] = 0x00; +@@ -723,6 +723,8 @@ pflash_t *pflash_cfi01_register(target_phys_addr_t base, + pfl->cfi_table[0x3b] = 0x00; + pfl->cfi_table[0x3c] = 0x00; + ++ pfl->cfi_table[0x3f] = 0x01; /* Number of protection fields */ ++ + return pfl; + } + +-- +1.7.12.1 + diff --git a/0209-qxl-disallow-unknown-revisions.patch b/0209-qxl-disallow-unknown-revisions.patch deleted file mode 100644 index 630be61..0000000 --- a/0209-qxl-disallow-unknown-revisions.patch +++ /dev/null @@ -1,33 +0,0 @@ -From 31052a357ad124c9ed17fbc39a0db5c8d6d0d9c5 Mon Sep 17 00:00:00 2001 -From: Alon Levy -Date: Tue, 21 Aug 2012 13:51:32 +0300 -Subject: [PATCH 209/215] qxl: disallow unknown revisions - -Signed-off-by: Alon Levy -Signed-off-by: Gerd Hoffmann ---- - hw/qxl.c | 5 ++++- - 1 file changed, 4 insertions(+), 1 deletion(-) - -diff --git a/hw/qxl.c b/hw/qxl.c -index baf9bb4..d134a70 100644 ---- a/hw/qxl.c -+++ b/hw/qxl.c -@@ -1798,10 +1798,13 @@ static int qxl_init_common(PCIQXLDevice *qxl) - io_size = 16; - break; - case 3: /* qxl-3 */ -- default: - pci_device_rev = QXL_DEFAULT_REVISION; - io_size = msb_mask(QXL_IO_RANGE_SIZE * 2 - 1); - break; -+ default: -+ error_report("Invalid revision %d for qxl device (max %d)", -+ qxl->revision, QXL_DEFAULT_REVISION); -+ return -1; - } - - pci_set_byte(&config[PCI_REVISION_ID], pci_device_rev); --- -1.7.12 - diff --git a/0210-MAINTAINERS-Add-entry-for-QOM-CPU.patch b/0210-MAINTAINERS-Add-entry-for-QOM-CPU.patch new file mode 100644 index 0000000..17385e6 --- /dev/null +++ b/0210-MAINTAINERS-Add-entry-for-QOM-CPU.patch @@ -0,0 +1,36 @@ +From a003aac48bda87a443bb312f478fb651e34998e5 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Andreas=20F=C3=A4rber?= +Date: Mon, 17 Sep 2012 19:10:32 +0200 +Subject: [PATCH] MAINTAINERS: Add entry for QOM CPU +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Signed-off-by: Andreas Färber +(cherry picked from commit f2ca052414d7eddc10517e98a5a27ba8099b19b1) + +Signed-off-by: Michael Roth +--- + MAINTAINERS | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/MAINTAINERS b/MAINTAINERS +index 61f8b45..25733fc 100644 +--- a/MAINTAINERS ++++ b/MAINTAINERS +@@ -531,6 +531,12 @@ M: Anthony Liguori + S: Maintained + F: qemu-char.c + ++CPU ++M: Andreas Färber ++S: Supported ++F: qom/cpu.c ++F: include/qemu/cpu.h ++ + Device Tree + M: Peter Crosthwaite + M: Alexander Graf +-- +1.7.12.1 + diff --git a/0210-qxl-add-QXL_IO_MONITORS_CONFIG_ASYNC.patch b/0210-qxl-add-QXL_IO_MONITORS_CONFIG_ASYNC.patch deleted file mode 100644 index a628f52..0000000 --- a/0210-qxl-add-QXL_IO_MONITORS_CONFIG_ASYNC.patch +++ /dev/null @@ -1,321 +0,0 @@ -From cc8b6a27e848cb88a4df98d48517c5b658d70efc Mon Sep 17 00:00:00 2001 -From: Alon Levy -Date: Wed, 22 Aug 2012 11:16:25 +0300 -Subject: [PATCH 210/215] qxl: add QXL_IO_MONITORS_CONFIG_ASYNC - -Revision bumped to 4 for new IO support, enabled for spice-server >= -0.11.1. New io enabled if revision is 4. Revision can be set to 4. - -[ kraxel: 3 continues to be the default revision. Once we have a new - stable spice-server release and the qemu patches to enable - the new bits merged we'll go flip the switch and make rev4 - the default ] - -This io calls the corresponding new spice api -spice_qxl_monitors_config_async to let spice-server read a new guest set -monitors config and notify the client. - -On migration reissue spice_qxl_monitors_config_async. - -RHBZ: 770842 - -Signed-off-by: Alon Levy -Signed-off-by: Gerd Hoffmann - -fixup - -Signed-off-by: Gerd Hoffmann ---- - configure | 7 ++++ - hw/qxl.c | 97 +++++++++++++++++++++++++++++++++++++++++++++++++++--- - hw/qxl.h | 7 ++++ - trace-events | 1 + - ui/spice-display.h | 1 + - 5 files changed, 109 insertions(+), 4 deletions(-) - -diff --git a/configure b/configure -index 9fc4fb5..c57d1c1 100755 ---- a/configure -+++ b/configure -@@ -2711,6 +2711,9 @@ EOF - spice="yes" - libs_softmmu="$libs_softmmu $spice_libs" - QEMU_CFLAGS="$QEMU_CFLAGS $spice_cflags" -+ if $pkg_config --atleast-version=0.12.0 spice-protocol >/dev/null 2>&1; then -+ spice_qxl_io_monitors_config_async="yes" -+ fi - else - if test "$spice" = "yes" ; then - feature_not_found "spice" -@@ -3448,6 +3451,10 @@ if test "$spice" = "yes" ; then - echo "CONFIG_SPICE=y" >> $config_host_mak - fi - -+if test "$spice_qxl_io_monitors_config_async" = "yes" ; then -+ echo "CONFIG_QXL_IO_MONITORS_CONFIG_ASYNC=y" >> $config_host_mak -+fi -+ - if test "$smartcard" = "yes" ; then - echo "CONFIG_SMARTCARD=y" >> $config_host_mak - fi -diff --git a/hw/qxl.c b/hw/qxl.c -index d134a70..adf17fd 100644 ---- a/hw/qxl.c -+++ b/hw/qxl.c -@@ -27,6 +27,11 @@ - - #include "qxl.h" - -+#ifndef CONFIG_QXL_IO_MONITORS_CONFIG_ASYNC -+/* spice-protocol is too old, add missing definitions */ -+#define QXL_IO_MONITORS_CONFIG_ASYNC (QXL_IO_FLUSH_RELEASE + 1) -+#endif -+ - /* - * NOTE: SPICE_RING_PROD_ITEM accesses memory on the pci bar and as - * such can be changed by the guest, so to avoid a guest trigerrable -@@ -249,6 +254,39 @@ static void qxl_spice_destroy_surfaces(PCIQXLDevice *qxl, qxl_async_io async) - } - } - -+static void qxl_spice_monitors_config_async(PCIQXLDevice *qxl, int replay) -+{ -+ trace_qxl_spice_monitors_config(qxl->id); -+/* 0x000b01 == 0.11.1 */ -+#if SPICE_SERVER_VERSION >= 0x000b01 && \ -+ defined(CONFIG_QXL_IO_MONITORS_CONFIG_ASYNC) -+ if (replay) { -+ /* -+ * don't use QXL_COOKIE_TYPE_IO: -+ * - we are not running yet (post_load), we will assert -+ * in send_events -+ * - this is not a guest io, but a reply, so async_io isn't set. -+ */ -+ spice_qxl_monitors_config_async(&qxl->ssd.qxl, -+ qxl->guest_monitors_config, -+ MEMSLOT_GROUP_GUEST, -+ (uintptr_t)qxl_cookie_new( -+ QXL_COOKIE_TYPE_POST_LOAD_MONITORS_CONFIG, -+ 0)); -+ } else { -+ qxl->guest_monitors_config = qxl->ram->monitors_config; -+ spice_qxl_monitors_config_async(&qxl->ssd.qxl, -+ qxl->ram->monitors_config, -+ MEMSLOT_GROUP_GUEST, -+ (uintptr_t)qxl_cookie_new(QXL_COOKIE_TYPE_IO, -+ QXL_IO_MONITORS_CONFIG_ASYNC)); -+ } -+#else -+ fprintf(stderr, "qxl: too old spice-protocol/spice-server for " -+ "QXL_IO_MONITORS_CONFIG_ASYNC\n"); -+#endif -+} -+ - void qxl_spice_reset_image_cache(PCIQXLDevice *qxl) - { - trace_qxl_spice_reset_image_cache(qxl->id); -@@ -538,6 +576,7 @@ static const char *io_port_to_string(uint32_t io_port) - = "QXL_IO_DESTROY_ALL_SURFACES_ASYNC", - [QXL_IO_FLUSH_SURFACES_ASYNC] = "QXL_IO_FLUSH_SURFACES_ASYNC", - [QXL_IO_FLUSH_RELEASE] = "QXL_IO_FLUSH_RELEASE", -+ [QXL_IO_MONITORS_CONFIG_ASYNC] = "QXL_IO_MONITORS_CONFIG_ASYNC", - }; - return io_port_to_string[io_port]; - } -@@ -819,6 +858,7 @@ static void interface_async_complete_io(PCIQXLDevice *qxl, QXLCookie *cookie) - case QXL_IO_DESTROY_PRIMARY_ASYNC: - case QXL_IO_UPDATE_AREA_ASYNC: - case QXL_IO_FLUSH_SURFACES_ASYNC: -+ case QXL_IO_MONITORS_CONFIG_ASYNC: - break; - case QXL_IO_CREATE_PRIMARY_ASYNC: - qxl_create_guest_primary_complete(qxl); -@@ -894,6 +934,8 @@ static void interface_async_complete(QXLInstance *sin, uint64_t cookie_token) - case QXL_COOKIE_TYPE_RENDER_UPDATE_AREA: - qxl_render_update_area_done(qxl, cookie); - break; -+ case QXL_COOKIE_TYPE_POST_LOAD_MONITORS_CONFIG: -+ break; - default: - fprintf(stderr, "qxl: %s: unexpected cookie type %d\n", - __func__, cookie->type); -@@ -1315,6 +1357,13 @@ static void ioport_write(void *opaque, target_phys_addr_t addr, - return; - } - -+ if (d->revision <= QXL_REVISION_STABLE_V10 && -+ io_port >= QXL_IO_FLUSH_SURFACES_ASYNC) { -+ qxl_set_guest_bug(d, "unsupported io %d for revision %d\n", -+ io_port, d->revision); -+ return; -+ } -+ - switch (io_port) { - case QXL_IO_RESET: - case QXL_IO_SET_MODE: -@@ -1334,7 +1383,7 @@ static void ioport_write(void *opaque, target_phys_addr_t addr, - io_port, io_port_to_string(io_port)); - /* be nice to buggy guest drivers */ - if (io_port >= QXL_IO_UPDATE_AREA_ASYNC && -- io_port <= QXL_IO_DESTROY_ALL_SURFACES_ASYNC) { -+ io_port < QXL_IO_RANGE_SIZE) { - qxl_send_events(d, QXL_INTERRUPT_IO_CMD); - } - return; -@@ -1362,6 +1411,7 @@ static void ioport_write(void *opaque, target_phys_addr_t addr, - io_port = QXL_IO_DESTROY_ALL_SURFACES; - goto async_common; - case QXL_IO_FLUSH_SURFACES_ASYNC: -+ case QXL_IO_MONITORS_CONFIG_ASYNC: - async_common: - async = QXL_ASYNC; - qemu_mutex_lock(&d->async_lock); -@@ -1503,6 +1553,9 @@ async_common: - d->mode = QXL_MODE_UNDEFINED; - qxl_spice_destroy_surfaces(d, async); - break; -+ case QXL_IO_MONITORS_CONFIG_ASYNC: -+ qxl_spice_monitors_config_async(d, 0); -+ break; - default: - qxl_set_guest_bug(d, "%s: unexpected ioport=0x%x\n", __func__, io_port); - } -@@ -1798,9 +1851,17 @@ static int qxl_init_common(PCIQXLDevice *qxl) - io_size = 16; - break; - case 3: /* qxl-3 */ -- pci_device_rev = QXL_DEFAULT_REVISION; -+ pci_device_rev = QXL_REVISION_STABLE_V10; -+ io_size = 32; /* PCI region size must be pow2 */ -+ break; -+/* 0x000b01 == 0.11.1 */ -+#if SPICE_SERVER_VERSION >= 0x000b01 && \ -+ defined(CONFIG_QXL_IO_MONITORS_CONFIG_ASYNC) -+ case 4: /* qxl-4 */ -+ pci_device_rev = QXL_REVISION_STABLE_V12; - io_size = msb_mask(QXL_IO_RANGE_SIZE * 2 - 1); - break; -+#endif - default: - error_report("Invalid revision %d for qxl device (max %d)", - qxl->revision, QXL_DEFAULT_REVISION); -@@ -1999,7 +2060,9 @@ static int qxl_post_load(void *opaque, int version) - } - qxl_spice_loadvm_commands(d, cmds, out); - g_free(cmds); -- -+ if (d->guest_monitors_config) { -+ qxl_spice_monitors_config_async(d, 1); -+ } - break; - case QXL_MODE_COMPAT: - /* note: no need to call qxl_create_memslots, qxl_set_mode -@@ -2012,6 +2075,14 @@ static int qxl_post_load(void *opaque, int version) - - #define QXL_SAVE_VERSION 21 - -+static bool qxl_monitors_config_needed(void *opaque) -+{ -+ PCIQXLDevice *qxl = opaque; -+ -+ return qxl->guest_monitors_config != 0; -+} -+ -+ - static VMStateDescription qxl_memslot = { - .name = "qxl-memslot", - .version_id = QXL_SAVE_VERSION, -@@ -2042,6 +2113,16 @@ static VMStateDescription qxl_surface = { - } - }; - -+static VMStateDescription qxl_vmstate_monitors_config = { -+ .name = "qxl/monitors-config", -+ .version_id = 1, -+ .minimum_version_id = 1, -+ .fields = (VMStateField[]) { -+ VMSTATE_UINT64(guest_monitors_config, PCIQXLDevice), -+ VMSTATE_END_OF_LIST() -+ }, -+}; -+ - static VMStateDescription qxl_vmstate = { - .name = "qxl", - .version_id = QXL_SAVE_VERSION, -@@ -2049,7 +2130,7 @@ static VMStateDescription qxl_vmstate = { - .pre_save = qxl_pre_save, - .pre_load = qxl_pre_load, - .post_load = qxl_post_load, -- .fields = (VMStateField []) { -+ .fields = (VMStateField[]) { - VMSTATE_PCI_DEVICE(pci, PCIQXLDevice), - VMSTATE_STRUCT(vga, PCIQXLDevice, 0, vmstate_vga_common, VGACommonState), - VMSTATE_UINT32(shadow_rom.mode, PCIQXLDevice), -@@ -2068,6 +2149,14 @@ static VMStateDescription qxl_vmstate = { - VMSTATE_UINT64(guest_cursor, PCIQXLDevice), - VMSTATE_END_OF_LIST() - }, -+ .subsections = (VMStateSubsection[]) { -+ { -+ .vmsd = &qxl_vmstate_monitors_config, -+ .needed = qxl_monitors_config_needed, -+ }, { -+ /* empty */ -+ } -+ } - }; - - static Property qxl_properties[] = { -diff --git a/hw/qxl.h b/hw/qxl.h -index 172baf6..9cfedb7 100644 ---- a/hw/qxl.h -+++ b/hw/qxl.h -@@ -71,6 +71,8 @@ typedef struct PCIQXLDevice { - } guest_surfaces; - QXLPHYSICAL guest_cursor; - -+ QXLPHYSICAL guest_monitors_config; -+ - QemuMutex track_lock; - - /* thread signaling */ -@@ -128,7 +130,12 @@ typedef struct PCIQXLDevice { - } \ - } while (0) - -+#if 0 -+/* spice-server 0.12 is still in development */ -+#define QXL_DEFAULT_REVISION QXL_REVISION_STABLE_V12 -+#else - #define QXL_DEFAULT_REVISION QXL_REVISION_STABLE_V10 -+#endif - - /* qxl.c */ - void *qxl_phys2virt(PCIQXLDevice *qxl, QXLPHYSICAL phys, int group_id); -diff --git a/trace-events b/trace-events -index 0de70d9..a58b0b7 100644 ---- a/trace-events -+++ b/trace-events -@@ -967,6 +967,7 @@ qxl_spice_destroy_surfaces(int qid, int async) "%d async=%d" - qxl_spice_destroy_surface_wait_complete(int qid, uint32_t id) "%d sid=%d" - qxl_spice_destroy_surface_wait(int qid, uint32_t id, int async) "%d sid=%d async=%d" - qxl_spice_flush_surfaces_async(int qid, uint32_t surface_count, uint32_t num_free_res) "%d s#=%d, res#=%d" -+qxl_spice_monitors_config(int id) "%d" - qxl_spice_loadvm_commands(int qid, void *ext, uint32_t count) "%d ext=%p count=%d" - qxl_spice_oom(int qid) "%d" - qxl_spice_reset_cursor(int qid) "%d" -diff --git a/ui/spice-display.h b/ui/spice-display.h -index 672d65e..bcff114 100644 ---- a/ui/spice-display.h -+++ b/ui/spice-display.h -@@ -51,6 +51,7 @@ typedef enum qxl_async_io { - enum { - QXL_COOKIE_TYPE_IO, - QXL_COOKIE_TYPE_RENDER_UPDATE_AREA, -+ QXL_COOKIE_TYPE_POST_LOAD_MONITORS_CONFIG, - }; - - typedef struct QXLCookie { --- -1.7.12 - diff --git a/0211-configure-print-spice-protocol-and-spice-server-vers.patch b/0211-configure-print-spice-protocol-and-spice-server-vers.patch deleted file mode 100644 index 711256c..0000000 --- a/0211-configure-print-spice-protocol-and-spice-server-vers.patch +++ /dev/null @@ -1,37 +0,0 @@ -From 1d2790682dfac06c2358ac99f5e0bad6a065702d Mon Sep 17 00:00:00 2001 -From: Alon Levy -Date: Wed, 22 Aug 2012 11:16:26 +0300 -Subject: [PATCH 211/215] configure: print spice-protocol and spice-server - versions - -Signed-off-by: Alon Levy -Signed-off-by: Gerd Hoffmann ---- - configure | 4 +++- - 1 file changed, 3 insertions(+), 1 deletion(-) - -diff --git a/configure b/configure -index c57d1c1..25c406f 100755 ---- a/configure -+++ b/configure -@@ -2711,6 +2711,8 @@ EOF - spice="yes" - libs_softmmu="$libs_softmmu $spice_libs" - QEMU_CFLAGS="$QEMU_CFLAGS $spice_cflags" -+ spice_protocol_version=$($pkg_config --modversion spice-protocol) -+ spice_server_version=$($pkg_config --modversion spice-server) - if $pkg_config --atleast-version=0.12.0 spice-protocol >/dev/null 2>&1; then - spice_qxl_io_monitors_config_async="yes" - fi -@@ -3169,7 +3171,7 @@ echo "libcap-ng support $cap_ng" - echo "vhost-net support $vhost_net" - echo "Trace backend $trace_backend" - echo "Trace output file $trace_file-" --echo "spice support $spice" -+echo "spice support $spice ($spice_protocol_version/$spice_server_version)" - echo "rbd support $rbd" - echo "xfsctl support $xfs" - echo "nss used $smartcard_nss" --- -1.7.12 - diff --git a/0211-iSCSI-We-need-to-support-SG_IO-also-from-iscsi_ioctl.patch b/0211-iSCSI-We-need-to-support-SG_IO-also-from-iscsi_ioctl.patch new file mode 100644 index 0000000..856ed96 --- /dev/null +++ b/0211-iSCSI-We-need-to-support-SG_IO-also-from-iscsi_ioctl.patch @@ -0,0 +1,59 @@ +From 76fcbe46a52b467cd2cd96a671bfccd26871153e Mon Sep 17 00:00:00 2001 +From: Ronnie Sahlberg +Date: Thu, 30 Aug 2012 17:28:40 -0700 +Subject: [PATCH] iSCSI: We need to support SG_IO also from iscsi_ioctl() + +We need to support SG_IO from the synchronous iscsi_ioctl() since +scsi-block uses this to do an INQ to the device to discover its properties +This patch makes scsi-block work with iscsi. + +Signed-off-by: Ronnie Sahlberg +Signed-off-by: Paolo Bonzini +(cherry picked from commit f1a12821d7df2e4d21be4f2206f84b4640533e53) + +Signed-off-by: Michael Roth +--- + block/iscsi.c | 17 +++++++++++++++++ + 1 file changed, 17 insertions(+) + +diff --git a/block/iscsi.c b/block/iscsi.c +index 0b96165..ea16609 100644 +--- a/block/iscsi.c ++++ b/block/iscsi.c +@@ -628,9 +628,17 @@ static BlockDriverAIOCB *iscsi_aio_ioctl(BlockDriverState *bs, + return &acb->common; + } + ++ ++static void ioctl_cb(void *opaque, int status) ++{ ++ int *p_status = opaque; ++ *p_status = status; ++} ++ + static int iscsi_ioctl(BlockDriverState *bs, unsigned long int req, void *buf) + { + IscsiLun *iscsilun = bs->opaque; ++ int status; + + switch (req) { + case SG_GET_VERSION_NUM: +@@ -639,6 +647,15 @@ static int iscsi_ioctl(BlockDriverState *bs, unsigned long int req, void *buf) + case SG_GET_SCSI_ID: + ((struct sg_scsi_id *)buf)->scsi_type = iscsilun->type; + break; ++ case SG_IO: ++ status = -EINPROGRESS; ++ iscsi_aio_ioctl(bs, req, buf, ioctl_cb, &status); ++ ++ while (status == -EINPROGRESS) { ++ qemu_aio_wait(); ++ } ++ ++ return 0; + default: + return -1; + } +-- +1.7.12.1 + diff --git a/0212-iSCSI-We-dont-need-to-explicitely-call-qemu_notify_e.patch b/0212-iSCSI-We-dont-need-to-explicitely-call-qemu_notify_e.patch new file mode 100644 index 0000000..d2d4b2d --- /dev/null +++ b/0212-iSCSI-We-dont-need-to-explicitely-call-qemu_notify_e.patch @@ -0,0 +1,39 @@ +From 05bfce1ee580c715dc3d220297b05097bdd007d2 Mon Sep 17 00:00:00 2001 +From: Ronnie Sahlberg +Date: Thu, 30 Aug 2012 16:56:36 -0700 +Subject: [PATCH] iSCSI: We dont need to explicitely call qemu_notify_event() + any more + +We no longer need to explicitely call qemu_notify_event() any more +since this is now done automatically any time the filehandles we listen +to change. + +Signed-off-by: Ronnie Sahlberg +Signed-off-by: Paolo Bonzini +(cherry picked from commit 40a13ca8d28c21062e35b10d9b80e76b92405bdf) + +Signed-off-by: Michael Roth +--- + block/iscsi.c | 6 ------ + 1 file changed, 6 deletions(-) + +diff --git a/block/iscsi.c b/block/iscsi.c +index ea16609..fb001b9 100644 +--- a/block/iscsi.c ++++ b/block/iscsi.c +@@ -167,12 +167,6 @@ iscsi_set_events(IscsiLun *iscsilun) + + } + +- /* If we just added an event, the callback might be delayed +- * unless we call qemu_notify_event(). +- */ +- if (ev & ~iscsilun->events) { +- qemu_notify_event(); +- } + iscsilun->events = ev; + } + +-- +1.7.12.1 + diff --git a/0212-spice-make-number-of-surfaces-runtime-configurable.patch b/0212-spice-make-number-of-surfaces-runtime-configurable.patch deleted file mode 100644 index 0101a20..0000000 --- a/0212-spice-make-number-of-surfaces-runtime-configurable.patch +++ /dev/null @@ -1,201 +0,0 @@ -From 72e437d9b775cb92f93c3acd0109239f1bb3e6e2 Mon Sep 17 00:00:00 2001 -From: Gerd Hoffmann -Date: Tue, 4 Sep 2012 11:39:41 +0200 -Subject: [PATCH 212/215] spice: make number of surfaces runtime-configurable. - -Signed-off-by: Gerd Hoffmann ---- - hw/qxl.c | 31 +++++++++++++++++-------------- - hw/qxl.h | 3 +-- - ui/spice-display.c | 5 ++++- - ui/spice-display.h | 3 +-- - 4 files changed, 23 insertions(+), 19 deletions(-) - -diff --git a/hw/qxl.c b/hw/qxl.c -index adf17fd..8725f67 100644 ---- a/hw/qxl.c -+++ b/hw/qxl.c -@@ -236,7 +236,8 @@ static void qxl_spice_destroy_surfaces_complete(PCIQXLDevice *qxl) - { - trace_qxl_spice_destroy_surfaces_complete(qxl->id); - qemu_mutex_lock(&qxl->track_lock); -- memset(&qxl->guest_surfaces.cmds, 0, sizeof(qxl->guest_surfaces.cmds)); -+ memset(qxl->guest_surfaces.cmds, 0, -+ sizeof(qxl->guest_surfaces.cmds) * qxl->ssd.num_surfaces); - qxl->guest_surfaces.count = 0; - qemu_mutex_unlock(&qxl->track_lock); - } -@@ -345,7 +346,7 @@ static void init_qxl_rom(PCIQXLDevice *d) - rom->slot_id_bits = MEMSLOT_SLOT_BITS; - rom->slots_start = 1; - rom->slots_end = NUM_MEMSLOTS - 1; -- rom->n_surfaces = cpu_to_le32(NUM_SURFACES); -+ rom->n_surfaces = cpu_to_le32(d->ssd.num_surfaces); - - for (i = 0, n = 0; i < ARRAY_SIZE(qxl_modes); i++) { - fb = qxl_modes[i].y_res * qxl_modes[i].stride; -@@ -449,9 +450,9 @@ static int qxl_track_command(PCIQXLDevice *qxl, struct QXLCommandExt *ext) - } - uint32_t id = le32_to_cpu(cmd->surface_id); - -- if (id >= NUM_SURFACES) { -+ if (id >= qxl->ssd.num_surfaces) { - qxl_set_guest_bug(qxl, "QXL_CMD_SURFACE id %d >= %d", id, -- NUM_SURFACES); -+ qxl->ssd.num_surfaces); - return 1; - } - qemu_mutex_lock(&qxl->track_lock); -@@ -527,7 +528,7 @@ static void interface_get_init_info(QXLInstance *sin, QXLDevInitInfo *info) - info->num_memslots_groups = NUM_MEMSLOTS_GROUPS; - info->internal_groupslot_id = 0; - info->qxl_ram_size = le32_to_cpu(qxl->shadow_rom.num_pages) << TARGET_PAGE_BITS; -- info->n_surfaces = NUM_SURFACES; -+ info->n_surfaces = qxl->ssd.num_surfaces; - } - - static const char *qxl_mode_to_string(int mode) -@@ -1436,7 +1437,7 @@ async_common: - QXLCookie *cookie = NULL; - QXLRect update = d->ram->update_area; - -- if (d->ram->update_surface > NUM_SURFACES) { -+ if (d->ram->update_surface > d->ssd.num_surfaces) { - qxl_set_guest_bug(d, "QXL_IO_UPDATE_AREA: invalid surface id %d\n", - d->ram->update_surface); - return; -@@ -1529,7 +1530,7 @@ async_common: - } - break; - case QXL_IO_DESTROY_SURFACE_WAIT: -- if (val >= NUM_SURFACES) { -+ if (val >= d->ssd.num_surfaces) { - qxl_set_guest_bug(d, "QXL_IO_DESTROY_SURFACE (async=%d):" - "%" PRIu64 " >= NUM_SURFACES", async, val); - goto cancel_async; -@@ -1707,7 +1708,7 @@ static void qxl_dirty_surfaces(PCIQXLDevice *qxl) - vram_start = (intptr_t)memory_region_get_ram_ptr(&qxl->vram_bar); - - /* dirty the off-screen surfaces */ -- for (i = 0; i < NUM_SURFACES; i++) { -+ for (i = 0; i < qxl->ssd.num_surfaces; i++) { - QXLSurfaceCmd *cmd; - intptr_t surface_offset; - int surface_size; -@@ -1835,7 +1836,6 @@ static int qxl_init_common(PCIQXLDevice *qxl) - qxl->mode = QXL_MODE_UNDEFINED; - qxl->generation = 1; - qxl->num_memslots = NUM_MEMSLOTS; -- qxl->num_surfaces = NUM_SURFACES; - qemu_mutex_init(&qxl->track_lock); - qemu_mutex_init(&qxl->async_lock); - qxl->current_async = QXL_UNDEFINED_IO; -@@ -1877,6 +1877,7 @@ static int qxl_init_common(PCIQXLDevice *qxl) - init_qxl_rom(qxl); - init_qxl_ram(qxl); - -+ qxl->guest_surfaces.cmds = g_new0(QXLPHYSICAL, qxl->ssd.num_surfaces); - memory_region_init_ram(&qxl->vram_bar, "qxl.vram", qxl->vram_size); - vmstate_register_ram(&qxl->vram_bar, &qxl->pci.qdev); - memory_region_init_alias(&qxl->vram32_bar, "qxl.vram32", &qxl->vram_bar, -@@ -2042,8 +2043,8 @@ static int qxl_post_load(void *opaque, int version) - qxl_create_guest_primary(d, 1, QXL_SYNC); - - /* replay surface-create and cursor-set commands */ -- cmds = g_malloc0(sizeof(QXLCommandExt) * (NUM_SURFACES + 1)); -- for (in = 0, out = 0; in < NUM_SURFACES; in++) { -+ cmds = g_malloc0(sizeof(QXLCommandExt) * (d->ssd.num_surfaces + 1)); -+ for (in = 0, out = 0; in < d->ssd.num_surfaces; in++) { - if (d->guest_surfaces.cmds[in] == 0) { - continue; - } -@@ -2143,9 +2144,10 @@ static VMStateDescription qxl_vmstate = { - qxl_memslot, struct guest_slots), - VMSTATE_STRUCT(guest_primary.surface, PCIQXLDevice, 0, - qxl_surface, QXLSurfaceCreate), -- VMSTATE_INT32_EQUAL(num_surfaces, PCIQXLDevice), -- VMSTATE_ARRAY(guest_surfaces.cmds, PCIQXLDevice, NUM_SURFACES, 0, -- vmstate_info_uint64, uint64_t), -+ VMSTATE_INT32_EQUAL(ssd.num_surfaces, PCIQXLDevice), -+ VMSTATE_VARRAY_INT32(guest_surfaces.cmds, PCIQXLDevice, -+ ssd.num_surfaces, 0, -+ vmstate_info_uint64, uint64_t), - VMSTATE_UINT64(guest_cursor, PCIQXLDevice), - VMSTATE_END_OF_LIST() - }, -@@ -2173,6 +2175,7 @@ static Property qxl_properties[] = { - DEFINE_PROP_UINT32("vram_size_mb", PCIQXLDevice, vram32_size_mb, -1), - DEFINE_PROP_UINT32("vram64_size_mb", PCIQXLDevice, vram_size_mb, -1), - DEFINE_PROP_UINT32("vgamem_mb", PCIQXLDevice, vgamem_size_mb, 16), -+ DEFINE_PROP_INT32("surfaces", PCIQXLDevice, ssd.num_surfaces, 1024), - DEFINE_PROP_END_OF_LIST(), - }; - -diff --git a/hw/qxl.h b/hw/qxl.h -index 9cfedb7..5553824 100644 ---- a/hw/qxl.h -+++ b/hw/qxl.h -@@ -40,7 +40,6 @@ typedef struct PCIQXLDevice { - uint32_t revision; - - int32_t num_memslots; -- int32_t num_surfaces; - - uint32_t current_async; - QemuMutex async_lock; -@@ -65,7 +64,7 @@ typedef struct PCIQXLDevice { - } guest_primary; - - struct surfaces { -- QXLPHYSICAL cmds[NUM_SURFACES]; -+ QXLPHYSICAL *cmds; - uint32_t count; - uint32_t max; - } guest_surfaces; -diff --git a/ui/spice-display.c b/ui/spice-display.c -index 1c31418..99bc665 100644 ---- a/ui/spice-display.c -+++ b/ui/spice-display.c -@@ -317,6 +317,9 @@ void qemu_spice_display_init_common(SimpleSpiceDisplay *ssd, DisplayState *ds) - qemu_mutex_init(&ssd->lock); - ssd->mouse_x = -1; - ssd->mouse_y = -1; -+ if (ssd->num_surfaces == 0) { -+ ssd->num_surfaces = 1024; -+ } - ssd->bufsize = (16 * 1024 * 1024); - ssd->buf = g_malloc(ssd->bufsize); - } -@@ -427,7 +430,7 @@ static void interface_get_init_info(QXLInstance *sin, QXLDevInitInfo *info) - info->num_memslots_groups = NUM_MEMSLOTS_GROUPS; - info->internal_groupslot_id = 0; - info->qxl_ram_size = ssd->bufsize; -- info->n_surfaces = NUM_SURFACES; -+ info->n_surfaces = ssd->num_surfaces; - } - - static int interface_get_command(QXLInstance *sin, struct QXLCommandExt *ext) -diff --git a/ui/spice-display.h b/ui/spice-display.h -index bcff114..512ab78 100644 ---- a/ui/spice-display.h -+++ b/ui/spice-display.h -@@ -32,8 +32,6 @@ - #define MEMSLOT_GROUP_GUEST 1 - #define NUM_MEMSLOTS_GROUPS 2 - --#define NUM_SURFACES 1024 -- - /* - * Internal enum to differenciate between options for - * io calls that have a sync (old) version and an _async (new) -@@ -80,6 +78,7 @@ struct SimpleSpiceDisplay { - QXLInstance qxl; - uint32_t unique; - QemuPfConv *conv; -+ int32_t num_surfaces; - - QXLRect dirty; - int notify; --- -1.7.12 - diff --git a/0213-qxl-Add-set_client_capabilities-interface-to-QXLInte.patch b/0213-qxl-Add-set_client_capabilities-interface-to-QXLInte.patch deleted file mode 100644 index 4427f78..0000000 --- a/0213-qxl-Add-set_client_capabilities-interface-to-QXLInte.patch +++ /dev/null @@ -1,65 +0,0 @@ -From 44eab2c48c8b090fff8b7ded39b40dae6c6ce003 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?S=C3=B8ren=20Sandmann=20Pedersen?= -Date: Tue, 4 Sep 2012 10:14:48 -0400 -Subject: [PATCH 213/215] qxl: Add set_client_capabilities() interface to - QXLInterface - -This new interface lets spice server inform the guest whether - -(a) a client is connected -(b) what capabilities the client has - -There is a fixed number (464) of bits reserved for capabilities, and -when the capabilities bits change, the QXL_INTERRUPT_CLIENT interrupt -is generated. - -Signed-off-by: Soren Sandmann -Signed-off-by: Gerd Hoffmann ---- - hw/qxl.c | 23 +++++++++++++++++++++++ - 1 file changed, 23 insertions(+) - -diff --git a/hw/qxl.c b/hw/qxl.c -index 8725f67..2aa5848 100644 ---- a/hw/qxl.c -+++ b/hw/qxl.c -@@ -944,6 +944,26 @@ static void interface_async_complete(QXLInstance *sin, uint64_t cookie_token) - } - } - -+#if SPICE_SERVER_VERSION >= 0x000b04 -+ -+/* called from spice server thread context only */ -+static void interface_set_client_capabilities(QXLInstance *sin, -+ uint8_t client_present, -+ uint8_t caps[58]) -+{ -+ PCIQXLDevice *qxl = container_of(sin, PCIQXLDevice, ssd.qxl); -+ -+ qxl->shadow_rom.client_present = client_present; -+ memcpy(qxl->shadow_rom.client_capabilities, caps, sizeof(caps)); -+ qxl->rom->client_present = client_present; -+ memcpy(qxl->rom->client_capabilities, caps, sizeof(caps)); -+ qxl_rom_set_dirty(qxl); -+ -+ qxl_send_events(qxl, QXL_INTERRUPT_CLIENT); -+} -+ -+#endif -+ - static const QXLInterface qxl_interface = { - .base.type = SPICE_INTERFACE_QXL, - .base.description = "qxl gpu", -@@ -965,6 +985,9 @@ static const QXLInterface qxl_interface = { - .flush_resources = interface_flush_resources, - .async_complete = interface_async_complete, - .update_area_complete = interface_update_area_complete, -+#if SPICE_SERVER_VERSION >= 0x000b04 -+ .set_client_capabilities = interface_set_client_capabilities, -+#endif - }; - - static void qxl_enter_vga_mode(PCIQXLDevice *d) --- -1.7.12 - diff --git a/0213-scsi-disk-introduce-check_lba_range.patch b/0213-scsi-disk-introduce-check_lba_range.patch new file mode 100644 index 0000000..567728d --- /dev/null +++ b/0213-scsi-disk-introduce-check_lba_range.patch @@ -0,0 +1,82 @@ +From dd43bce420668dcde639c55bc792cedb1bb8c950 Mon Sep 17 00:00:00 2001 +From: Paolo Bonzini +Date: Wed, 5 Sep 2012 17:46:18 +0200 +Subject: [PATCH] scsi-disk: introduce check_lba_range + +Abstract the test for an out-of-range (starting block, block count) +pair. + +Signed-off-by: Paolo Bonzini +(cherry picked from commit 444bc908611ccaf4512dc37c33ac3b54d873a62b) + +Signed-off-by: Michael Roth +--- + hw/scsi-disk.c | 24 ++++++++++++++++-------- + 1 file changed, 16 insertions(+), 8 deletions(-) + +diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c +index 1585683..3959603 100644 +--- a/hw/scsi-disk.c ++++ b/hw/scsi-disk.c +@@ -1449,6 +1449,18 @@ invalid_field: + return; + } + ++static inline bool check_lba_range(SCSIDiskState *s, ++ uint64_t sector_num, uint32_t nb_sectors) ++{ ++ /* ++ * The first line tests that no overflow happens when computing the last ++ * sector. The second line tests that the last accessed sector is in ++ * range. ++ */ ++ return (sector_num <= sector_num + nb_sectors && ++ sector_num + nb_sectors - 1 <= s->qdev.max_lba); ++} ++ + typedef struct UnmapCBData { + SCSIDiskReq *r; + uint8_t *inbuf; +@@ -1473,8 +1485,7 @@ static void scsi_unmap_complete(void *opaque, int ret) + if (data->count > 0 && !r->req.io_canceled) { + sector_num = ldq_be_p(&data->inbuf[0]); + nb_sectors = ldl_be_p(&data->inbuf[8]) & 0xffffffffULL; +- if (sector_num > sector_num + nb_sectors || +- sector_num + nb_sectors - 1 > s->qdev.max_lba) { ++ if (!check_lba_range(s, sector_num, nb_sectors)) { + scsi_check_condition(r, SENSE_CODE(LBA_OUT_OF_RANGE)); + goto done; + } +@@ -1802,8 +1813,7 @@ static int32_t scsi_disk_emulate_command(SCSIRequest *req, uint8_t *buf) + scsi_check_condition(r, SENSE_CODE(WRITE_PROTECTED)); + return 0; + } +- if (r->req.cmd.lba > r->req.cmd.lba + nb_sectors || +- r->req.cmd.lba + nb_sectors - 1 > s->qdev.max_lba) { ++ if (!check_lba_range(s, r->req.cmd.lba, nb_sectors)) { + goto illegal_lba; + } + +@@ -1878,8 +1888,7 @@ static int32_t scsi_disk_dma_command(SCSIRequest *req, uint8_t *buf) + if (r->req.cmd.buf[1] & 0xe0) { + goto illegal_request; + } +- if (r->req.cmd.lba > r->req.cmd.lba + len || +- r->req.cmd.lba + len - 1 > s->qdev.max_lba) { ++ if (!check_lba_range(s, r->req.cmd.lba, len)) { + goto illegal_lba; + } + r->sector = r->req.cmd.lba * (s->qdev.blocksize / 512); +@@ -1907,8 +1916,7 @@ static int32_t scsi_disk_dma_command(SCSIRequest *req, uint8_t *buf) + if (r->req.cmd.buf[1] & 0xe0) { + goto illegal_request; + } +- if (r->req.cmd.lba > r->req.cmd.lba + len || +- r->req.cmd.lba + len - 1 > s->qdev.max_lba) { ++ if (!check_lba_range(s, r->req.cmd.lba, len)) { + goto illegal_lba; + } + r->sector = r->req.cmd.lba * (s->qdev.blocksize / 512); +-- +1.7.12.1 + diff --git a/0214-Remove-ifdef-QXL_COMMAND_FLAG_COMPAT_16BPP.patch b/0214-Remove-ifdef-QXL_COMMAND_FLAG_COMPAT_16BPP.patch deleted file mode 100644 index cfae0f3..0000000 --- a/0214-Remove-ifdef-QXL_COMMAND_FLAG_COMPAT_16BPP.patch +++ /dev/null @@ -1,32 +0,0 @@ -From 666f88952fe1bcf84ba857f417a5d25f86bbf38b Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?S=C3=B8ren=20Sandmann=20Pedersen?= -Date: Tue, 4 Sep 2012 10:14:49 -0400 -Subject: [PATCH 214/215] Remove #ifdef QXL_COMMAND_FLAG_COMPAT_16BPP - -We require spice >= 0.8 now, so this flag is always present. - -Signed-off-by: Soren Sandmann -Signed-off-by: Gerd Hoffmann ---- - hw/qxl.c | 2 -- - 1 file changed, 2 deletions(-) - -diff --git a/hw/qxl.c b/hw/qxl.c -index 2aa5848..b726c19 100644 ---- a/hw/qxl.c -+++ b/hw/qxl.c -@@ -1359,11 +1359,9 @@ static void qxl_set_mode(PCIQXLDevice *d, int modenr, int loadvm) - - d->mode = QXL_MODE_COMPAT; - d->cmdflags = QXL_COMMAND_FLAG_COMPAT; --#ifdef QXL_COMMAND_FLAG_COMPAT_16BPP /* new in spice 0.6.1 */ - if (mode->bits == 16) { - d->cmdflags |= QXL_COMMAND_FLAG_COMPAT_16BPP; - } --#endif - d->shadow_rom.mode = cpu_to_le32(modenr); - d->rom->mode = cpu_to_le32(modenr); - qxl_rom_set_dirty(d); --- -1.7.12 - diff --git a/0214-scsi-disk-fix-check-for-out-of-range-LBA.patch b/0214-scsi-disk-fix-check-for-out-of-range-LBA.patch new file mode 100644 index 0000000..9deef86 --- /dev/null +++ b/0214-scsi-disk-fix-check-for-out-of-range-LBA.patch @@ -0,0 +1,38 @@ +From 2fd88dcb7fdb90508a85c30a32516ff57f081cba Mon Sep 17 00:00:00 2001 +From: Paolo Bonzini +Date: Wed, 5 Sep 2012 17:54:36 +0200 +Subject: [PATCH] scsi-disk: fix check for out-of-range LBA + +This fix is needed to correctly handle 0-block read and writes. +Without it, a 0-block access at LBA 0 would underflow. + +Signed-off-by: Paolo Bonzini +(cherry picked from commit 12ca76fc48081b3a0ad1a70546abfcf198aedfc4) + +Signed-off-by: Michael Roth +--- + hw/scsi-disk.c | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c +index 3959603..d621852 100644 +--- a/hw/scsi-disk.c ++++ b/hw/scsi-disk.c +@@ -1456,9 +1456,13 @@ static inline bool check_lba_range(SCSIDiskState *s, + * The first line tests that no overflow happens when computing the last + * sector. The second line tests that the last accessed sector is in + * range. ++ * ++ * Careful, the computations should not underflow for nb_sectors == 0, ++ * and a 0-block read to the first LBA beyond the end of device is ++ * valid. + */ + return (sector_num <= sector_num + nb_sectors && +- sector_num + nb_sectors - 1 <= s->qdev.max_lba); ++ sector_num + nb_sectors <= s->qdev.max_lba + 1); + } + + typedef struct UnmapCBData { +-- +1.7.12.1 + diff --git a/0215-SCSI-Standard-INQUIRY-data-should-report-HiSup-flag-.patch b/0215-SCSI-Standard-INQUIRY-data-should-report-HiSup-flag-.patch new file mode 100644 index 0000000..840be83 --- /dev/null +++ b/0215-SCSI-Standard-INQUIRY-data-should-report-HiSup-flag-.patch @@ -0,0 +1,43 @@ +From 8444d4c996120a2fc21547a784c258e639f1e8fb Mon Sep 17 00:00:00 2001 +From: Ronnie Sahlberg +Date: Fri, 14 Sep 2012 18:13:29 -0700 +Subject: [PATCH] SCSI: Standard INQUIRY data should report HiSup flag as set. + +QEMU as far as I know only reports LUN numbers using the modes that +are described in SAM4. +As such, since all LUN numbers generated by the SCSI emulation in QEMU +follow SAM4, we should set the HiSup bit in the standard INQUIRY data +to indicate such. + +From SAM4: + 4.6.3 LUNs overview + All LUN formats described in this standard are hierarchical in + structure even when only a single level in that hierarchy is used. + The HISUP bit shall be set to one in the standard INQUIRY data + (see SPC-4) when any LUN format described in this standard is used. + Non-hierarchical formats are outside the scope of this standard. + +Signed-off-by: Ronnie Sahlberg +(cherry picked from commit 1109c894052751df99962c009fd7dbae397721f5) + +Signed-off-by: Michael Roth +--- + hw/scsi-disk.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c +index d621852..7ed1bde 100644 +--- a/hw/scsi-disk.c ++++ b/hw/scsi-disk.c +@@ -678,7 +678,7 @@ static int scsi_disk_emulate_inquiry(SCSIRequest *req, uint8_t *outbuf) + * is actually implemented, but we're good enough. + */ + outbuf[2] = 5; +- outbuf[3] = 2; /* Format 2 */ ++ outbuf[3] = 2 | 0x10; /* Format 2, HiSup */ + + if (buflen > 36) { + outbuf[4] = buflen - 5; /* Additional Length = (Len - 1) - 4 */ +-- +1.7.12.1 + diff --git a/0215-spice-switch-to-queue-for-vga-mode-updates.patch b/0215-spice-switch-to-queue-for-vga-mode-updates.patch deleted file mode 100644 index 9bd3562..0000000 --- a/0215-spice-switch-to-queue-for-vga-mode-updates.patch +++ /dev/null @@ -1,138 +0,0 @@ -From 20b7c4b95c7f0c93000a68779e9cb9e63cff68da Mon Sep 17 00:00:00 2001 -From: Gerd Hoffmann -Date: Wed, 5 Sep 2012 08:25:08 +0200 -Subject: [PATCH 215/293] spice: switch to queue for vga mode updates - -Signed-off-by: Gerd Hoffmann ---- - hw/qxl.c | 6 +++--- - ui/spice-display.c | 25 ++++++++++++++----------- - ui/spice-display.h | 3 ++- - 3 files changed, 19 insertions(+), 15 deletions(-) - -diff --git a/hw/qxl.c b/hw/qxl.c -index b726c19..833cd77 100644 ---- a/hw/qxl.c -+++ b/hw/qxl.c -@@ -597,9 +597,9 @@ static int interface_get_command(QXLInstance *sin, struct QXLCommandExt *ext) - case QXL_MODE_VGA: - ret = false; - qemu_mutex_lock(&qxl->ssd.lock); -- if (qxl->ssd.update != NULL) { -- update = qxl->ssd.update; -- qxl->ssd.update = NULL; -+ update = QTAILQ_FIRST(&qxl->ssd.updates); -+ if (update != NULL) { -+ QTAILQ_REMOVE(&qxl->ssd.updates, update, next); - *ext = update->ext; - ret = true; - } -diff --git a/ui/spice-display.c b/ui/spice-display.c -index 99bc665..59c5fd7 100644 ---- a/ui/spice-display.c -+++ b/ui/spice-display.c -@@ -164,7 +164,7 @@ int qemu_spice_display_is_running(SimpleSpiceDisplay *ssd) - #endif - } - --static SimpleSpiceUpdate *qemu_spice_create_update(SimpleSpiceDisplay *ssd) -+static void qemu_spice_create_update(SimpleSpiceDisplay *ssd) - { - SimpleSpiceUpdate *update; - QXLDrawable *drawable; -@@ -175,7 +175,7 @@ static SimpleSpiceUpdate *qemu_spice_create_update(SimpleSpiceDisplay *ssd) - struct timespec time_space; - - if (qemu_spice_rect_is_empty(&ssd->dirty)) { -- return NULL; -+ return; - }; - - trace_qemu_spice_create_update( -@@ -239,7 +239,7 @@ static SimpleSpiceUpdate *qemu_spice_create_update(SimpleSpiceDisplay *ssd) - cmd->data = (uintptr_t)drawable; - - memset(&ssd->dirty, 0, sizeof(ssd->dirty)); -- return update; -+ QTAILQ_INSERT_TAIL(&ssd->updates, update, next); - } - - /* -@@ -315,6 +315,7 @@ void qemu_spice_display_init_common(SimpleSpiceDisplay *ssd, DisplayState *ds) - { - ssd->ds = ds; - qemu_mutex_init(&ssd->lock); -+ QTAILQ_INIT(&ssd->updates); - ssd->mouse_x = -1; - ssd->mouse_y = -1; - if (ssd->num_surfaces == 0) { -@@ -345,6 +346,8 @@ void qemu_spice_display_update(SimpleSpiceDisplay *ssd, - - void qemu_spice_display_resize(SimpleSpiceDisplay *ssd) - { -+ SimpleSpiceUpdate *update; -+ - dprint(1, "%s:\n", __FUNCTION__); - - memset(&ssd->dirty, 0, sizeof(ssd->dirty)); -@@ -352,9 +355,9 @@ void qemu_spice_display_resize(SimpleSpiceDisplay *ssd) - ssd->conv = NULL; - - qemu_mutex_lock(&ssd->lock); -- if (ssd->update != NULL) { -- qemu_spice_destroy_update(ssd, ssd->update); -- ssd->update = NULL; -+ while ((update = QTAILQ_FIRST(&ssd->updates)) != NULL) { -+ QTAILQ_REMOVE(&ssd->updates, update, next); -+ qemu_spice_destroy_update(ssd, update); - } - qemu_mutex_unlock(&ssd->lock); - qemu_spice_destroy_host_primary(ssd); -@@ -384,8 +387,8 @@ void qemu_spice_display_refresh(SimpleSpiceDisplay *ssd) - vga_hw_update(); - - qemu_mutex_lock(&ssd->lock); -- if (ssd->update == NULL) { -- ssd->update = qemu_spice_create_update(ssd); -+ if (QTAILQ_EMPTY(&ssd->updates)) { -+ qemu_spice_create_update(ssd); - ssd->notify++; - } - qemu_spice_cursor_refresh_unlocked(ssd); -@@ -442,9 +445,9 @@ static int interface_get_command(QXLInstance *sin, struct QXLCommandExt *ext) - dprint(3, "%s:\n", __FUNCTION__); - - qemu_mutex_lock(&ssd->lock); -- if (ssd->update != NULL) { -- update = ssd->update; -- ssd->update = NULL; -+ update = QTAILQ_FIRST(&ssd->updates); -+ if (update != NULL) { -+ QTAILQ_REMOVE(&ssd->updates, update, next); - *ext = update->ext; - ret = true; - } -diff --git a/ui/spice-display.h b/ui/spice-display.h -index 512ab78..3fcb6fe 100644 ---- a/ui/spice-display.h -+++ b/ui/spice-display.h -@@ -92,7 +92,7 @@ struct SimpleSpiceDisplay { - * to them must be protected by the lock. - */ - QemuMutex lock; -- SimpleSpiceUpdate *update; -+ QTAILQ_HEAD(, SimpleSpiceUpdate) updates; - QEMUCursor *cursor; - int mouse_x, mouse_y; - }; -@@ -102,6 +102,7 @@ struct SimpleSpiceUpdate { - QXLImage image; - QXLCommandExt ext; - uint8_t *bitmap; -+ QTAILQ_ENTRY(SimpleSpiceUpdate) next; - }; - - int qemu_spice_rect_is_empty(const QXLRect* r); --- -1.7.12 - diff --git a/0216-audio-Fix-warning-from-static-code-analysis.patch b/0216-audio-Fix-warning-from-static-code-analysis.patch new file mode 100644 index 0000000..d25383c --- /dev/null +++ b/0216-audio-Fix-warning-from-static-code-analysis.patch @@ -0,0 +1,47 @@ +From eb26fee60bcc7b1191395c21f41c22e5e4f24182 Mon Sep 17 00:00:00 2001 +From: Stefan Weil +Date: Mon, 3 Sep 2012 09:25:16 +0000 +Subject: [PATCH] audio: Fix warning from static code analysis + +smatch report: +audio/audio_template.h:416 AUD_open_out(18) warn: + variable dereferenced before check 'as' (see line 414) + +Moving the ldebug statement after the statement which checks 'as' +fixes that warning. + +Signed-off-by: Stefan Weil +Signed-off-by: malc +(cherry picked from commit 93b6599734f81328ee3d608f57667742cafeea72) + +Signed-off-by: Michael Roth +--- + audio/audio_template.h | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/audio/audio_template.h b/audio/audio_template.h +index 519432a..16f7880 100644 +--- a/audio/audio_template.h ++++ b/audio/audio_template.h +@@ -410,15 +410,15 @@ SW *glue (AUD_open_, TYPE) ( + SW *old_sw = NULL; + #endif + +- ldebug ("open %s, freq %d, nchannels %d, fmt %d\n", +- name, as->freq, as->nchannels, as->fmt); +- + if (audio_bug (AUDIO_FUNC, !card || !name || !callback_fn || !as)) { + dolog ("card=%p name=%p callback_fn=%p as=%p\n", + card, name, callback_fn, as); + goto fail; + } + ++ ldebug ("open %s, freq %d, nchannels %d, fmt %d\n", ++ name, as->freq, as->nchannels, as->fmt); ++ + if (audio_bug (AUDIO_FUNC, audio_validate_settings (as))) { + audio_print_settings (as); + goto fail; +-- +1.7.12.1 + diff --git a/0216-spice-split-qemu_spice_create_update.patch b/0216-spice-split-qemu_spice_create_update.patch deleted file mode 100644 index 711382c..0000000 --- a/0216-spice-split-qemu_spice_create_update.patch +++ /dev/null @@ -1,94 +0,0 @@ -From a754b60d7602dae18120ab014735927058e89983 Mon Sep 17 00:00:00 2001 -From: Gerd Hoffmann -Date: Wed, 5 Sep 2012 08:52:23 +0200 -Subject: [PATCH 216/293] spice: split qemu_spice_create_update - -Creating one function which creates a single update for a given -rectangle. And one (for now) pretty simple wrapper around it to -queue up screen updates for the dirty region. - -[ v2: also update bounding box ] - -Signed-off-by: Gerd Hoffmann ---- - ui/spice-display.c | 31 ++++++++++++++++++------------- - 1 file changed, 18 insertions(+), 13 deletions(-) - -diff --git a/ui/spice-display.c b/ui/spice-display.c -index 59c5fd7..6f68f28 100644 ---- a/ui/spice-display.c -+++ b/ui/spice-display.c -@@ -164,7 +164,8 @@ int qemu_spice_display_is_running(SimpleSpiceDisplay *ssd) - #endif - } - --static void qemu_spice_create_update(SimpleSpiceDisplay *ssd) -+static void qemu_spice_create_one_update(SimpleSpiceDisplay *ssd, -+ QXLRect *rect) - { - SimpleSpiceUpdate *update; - QXLDrawable *drawable; -@@ -174,24 +175,20 @@ static void qemu_spice_create_update(SimpleSpiceDisplay *ssd) - int by, bw, bh; - struct timespec time_space; - -- if (qemu_spice_rect_is_empty(&ssd->dirty)) { -- return; -- }; -- - trace_qemu_spice_create_update( -- ssd->dirty.left, ssd->dirty.right, -- ssd->dirty.top, ssd->dirty.bottom); -+ rect->left, rect->right, -+ rect->top, rect->bottom); - - update = g_malloc0(sizeof(*update)); - drawable = &update->drawable; - image = &update->image; - cmd = &update->ext.cmd; - -- bw = ssd->dirty.right - ssd->dirty.left; -- bh = ssd->dirty.bottom - ssd->dirty.top; -+ bw = rect->right - rect->left; -+ bh = rect->bottom - rect->top; - update->bitmap = g_malloc(bw * bh * 4); - -- drawable->bbox = ssd->dirty; -+ drawable->bbox = *rect; - drawable->clip.type = SPICE_CLIP_TYPE_NONE; - drawable->effect = QXL_EFFECT_OPAQUE; - drawable->release_info.id = (uintptr_t)update; -@@ -226,8 +223,8 @@ static void qemu_spice_create_update(SimpleSpiceDisplay *ssd) - } - - src = ds_get_data(ssd->ds) + -- ssd->dirty.top * ds_get_linesize(ssd->ds) + -- ssd->dirty.left * ds_get_bytes_per_pixel(ssd->ds); -+ rect->top * ds_get_linesize(ssd->ds) + -+ rect->left * ds_get_bytes_per_pixel(ssd->ds); - dst = update->bitmap; - for (by = 0; by < bh; by++) { - qemu_pf_conv_run(ssd->conv, dst, src, bw); -@@ -238,10 +235,18 @@ static void qemu_spice_create_update(SimpleSpiceDisplay *ssd) - cmd->type = QXL_CMD_DRAW; - cmd->data = (uintptr_t)drawable; - -- memset(&ssd->dirty, 0, sizeof(ssd->dirty)); - QTAILQ_INSERT_TAIL(&ssd->updates, update, next); - } - -+static void qemu_spice_create_update(SimpleSpiceDisplay *ssd) -+{ -+ if (qemu_spice_rect_is_empty(&ssd->dirty)) { -+ return; -+ }; -+ qemu_spice_create_one_update(ssd, &ssd->dirty); -+ memset(&ssd->dirty, 0, sizeof(ssd->dirty)); -+} -+ - /* - * Called from spice server thread context (via interface_release_ressource) - * We do *not* hold the global qemu mutex here, so extra care is needed --- -1.7.12 - diff --git a/0217-qemu-ga-Remove-unreachable-code-after-g_error.patch b/0217-qemu-ga-Remove-unreachable-code-after-g_error.patch new file mode 100644 index 0000000..5b64003 --- /dev/null +++ b/0217-qemu-ga-Remove-unreachable-code-after-g_error.patch @@ -0,0 +1,40 @@ +From 631ea4153ed0e1dc8688c463e0924b0dd8dc7ea5 Mon Sep 17 00:00:00 2001 +From: Stefan Weil +Date: Sat, 1 Sep 2012 09:34:15 +0200 +Subject: [PATCH] qemu-ga: Remove unreachable code after g_error + +Report from smatch: +qemu-ga.c:117 register_signal_handlers(11) info: ignoring unreachable code. +qemu-ga.c:122 register_signal_handlers(16) info: ignoring unreachable code. + +g_error calls abort which terminates the program. + +Signed-off-by: Stefan Weil +Signed-off-by: Stefan Hajnoczi +(cherry picked from commit b548828862d3bf7214b7ef9cb361356b153b89c9) + +Signed-off-by: Michael Roth +--- + qemu-ga.c | 2 -- + 1 file changed, 2 deletions(-) + +diff --git a/qemu-ga.c b/qemu-ga.c +index 7623079..b747470 100644 +--- a/qemu-ga.c ++++ b/qemu-ga.c +@@ -114,12 +114,10 @@ static gboolean register_signal_handlers(void) + ret = sigaction(SIGINT, &sigact, NULL); + if (ret == -1) { + g_error("error configuring signal handler: %s", strerror(errno)); +- return false; + } + ret = sigaction(SIGTERM, &sigact, NULL); + if (ret == -1) { + g_error("error configuring signal handler: %s", strerror(errno)); +- return false; + } + + return true; +-- +1.7.12.1 + diff --git a/0217-spice-add-screen-mirror.patch b/0217-spice-add-screen-mirror.patch deleted file mode 100644 index 5898ba8..0000000 --- a/0217-spice-add-screen-mirror.patch +++ /dev/null @@ -1,98 +0,0 @@ -From d7080640a03a1c7739eb730eaec0c63e7e12cdb6 Mon Sep 17 00:00:00 2001 -From: Gerd Hoffmann -Date: Wed, 5 Sep 2012 09:35:57 +0200 -Subject: [PATCH 217/293] spice: add screen mirror - -Create a screen mirror, keep there a copy of the most recent update -passed on to spice-server. - -Signed-off-by: Gerd Hoffmann ---- - ui/spice-display.c | 32 ++++++++++++++++++++++---------- - ui/spice-display.h | 1 + - 2 files changed, 23 insertions(+), 10 deletions(-) - -diff --git a/ui/spice-display.c b/ui/spice-display.c -index 6f68f28..973cd53 100644 ---- a/ui/spice-display.c -+++ b/ui/spice-display.c -@@ -171,8 +171,8 @@ static void qemu_spice_create_one_update(SimpleSpiceDisplay *ssd, - QXLDrawable *drawable; - QXLImage *image; - QXLCommand *cmd; -- uint8_t *src, *dst; -- int by, bw, bh; -+ uint8_t *src, *mirror, *dst; -+ int by, bw, bh, offset, bytes; - struct timespec time_space; - - trace_qemu_spice_create_update( -@@ -216,19 +216,18 @@ static void qemu_spice_create_one_update(SimpleSpiceDisplay *ssd, - image->bitmap.palette = 0; - image->bitmap.format = SPICE_BITMAP_FMT_32BIT; - -- if (ssd->conv == NULL) { -- PixelFormat dst = qemu_default_pixelformat(32); -- ssd->conv = qemu_pf_conv_get(&dst, &ssd->ds->surface->pf); -- assert(ssd->conv); -- } -- -- src = ds_get_data(ssd->ds) + -+ offset = - rect->top * ds_get_linesize(ssd->ds) + - rect->left * ds_get_bytes_per_pixel(ssd->ds); -+ bytes = ds_get_bytes_per_pixel(ssd->ds) * bw; -+ src = ds_get_data(ssd->ds) + offset; -+ mirror = ssd->ds_mirror + offset; - dst = update->bitmap; - for (by = 0; by < bh; by++) { -- qemu_pf_conv_run(ssd->conv, dst, src, bw); -+ memcpy(mirror, src, bytes); -+ qemu_pf_conv_run(ssd->conv, dst, mirror, bw); - src += ds_get_linesize(ssd->ds); -+ mirror += ds_get_linesize(ssd->ds); - dst += image->bitmap.stride; - } - -@@ -243,6 +242,17 @@ static void qemu_spice_create_update(SimpleSpiceDisplay *ssd) - if (qemu_spice_rect_is_empty(&ssd->dirty)) { - return; - }; -+ -+ if (ssd->conv == NULL) { -+ PixelFormat dst = qemu_default_pixelformat(32); -+ ssd->conv = qemu_pf_conv_get(&dst, &ssd->ds->surface->pf); -+ assert(ssd->conv); -+ } -+ if (ssd->ds_mirror == NULL) { -+ int size = ds_get_height(ssd->ds) * ds_get_linesize(ssd->ds); -+ ssd->ds_mirror = g_malloc0(size); -+ } -+ - qemu_spice_create_one_update(ssd, &ssd->dirty); - memset(&ssd->dirty, 0, sizeof(ssd->dirty)); - } -@@ -358,6 +368,8 @@ void qemu_spice_display_resize(SimpleSpiceDisplay *ssd) - memset(&ssd->dirty, 0, sizeof(ssd->dirty)); - qemu_pf_conv_put(ssd->conv); - ssd->conv = NULL; -+ g_free(ssd->ds_mirror); -+ ssd->ds_mirror = NULL; - - qemu_mutex_lock(&ssd->lock); - while ((update = QTAILQ_FIRST(&ssd->updates)) != NULL) { -diff --git a/ui/spice-display.h b/ui/spice-display.h -index 3fcb6fe..dea41c1 100644 ---- a/ui/spice-display.h -+++ b/ui/spice-display.h -@@ -72,6 +72,7 @@ typedef struct SimpleSpiceUpdate SimpleSpiceUpdate; - - struct SimpleSpiceDisplay { - DisplayState *ds; -+ uint8_t *ds_mirror; - void *buf; - int bufsize; - QXLWorker *worker; --- -1.7.12 - diff --git a/0218-qemu-sockets-Fix-potential-memory-leak.patch b/0218-qemu-sockets-Fix-potential-memory-leak.patch new file mode 100644 index 0000000..35d9a44 --- /dev/null +++ b/0218-qemu-sockets-Fix-potential-memory-leak.patch @@ -0,0 +1,32 @@ +From 46193407875faf8a8be20dabc4ecfee4ceb6f1a3 Mon Sep 17 00:00:00 2001 +From: Stefan Weil +Date: Sat, 1 Sep 2012 09:40:26 +0200 +Subject: [PATCH] qemu-sockets: Fix potential memory leak + +The old code leaks variable 'peer'. + +Signed-off-by: Stefan Weil +Signed-off-by: Stefan Hajnoczi +(cherry picked from commit 39b384591fda27d6e1213cea0b11b1ebe0ed4b74) + +Signed-off-by: Michael Roth +--- + qemu-sockets.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/qemu-sockets.c b/qemu-sockets.c +index 361d890..037775b 100644 +--- a/qemu-sockets.c ++++ b/qemu-sockets.c +@@ -353,7 +353,7 @@ int inet_dgram_opts(QemuOpts *opts) + if (0 != (rc = getaddrinfo(addr, port, &ai, &local))) { + fprintf(stderr,"getaddrinfo(%s,%s): %s\n", addr, port, + gai_strerror(rc)); +- return -1; ++ goto err; + } + + /* create socket */ +-- +1.7.12.1 + diff --git a/0218-spice-send-updates-only-for-changed-screen-content.patch b/0218-spice-send-updates-only-for-changed-screen-content.patch deleted file mode 100644 index 5b63fec..0000000 --- a/0218-spice-send-updates-only-for-changed-screen-content.patch +++ /dev/null @@ -1,93 +0,0 @@ -From e503ba260e585c9ee56f44ae5b8da51643776369 Mon Sep 17 00:00:00 2001 -From: Gerd Hoffmann -Date: Wed, 5 Sep 2012 10:41:42 +0200 -Subject: [PATCH 218/293] spice: send updates only for changed screen content - -when creating screen updates go compare the current guest screen -against the mirror (which holds the most recent update sent), then -only create updates for the screen areas which did actually change. - -[ v2: drop redundant qemu_spice_create_one_update call ] - -Signed-off-by: Gerd Hoffmann ---- - ui/spice-display.c | 56 +++++++++++++++++++++++++++++++++++++++++++++++++++++- - 1 file changed, 55 insertions(+), 1 deletion(-) - -diff --git a/ui/spice-display.c b/ui/spice-display.c -index 973cd53..d062765 100644 ---- a/ui/spice-display.c -+++ b/ui/spice-display.c -@@ -239,6 +239,13 @@ static void qemu_spice_create_one_update(SimpleSpiceDisplay *ssd, - - static void qemu_spice_create_update(SimpleSpiceDisplay *ssd) - { -+ static const int blksize = 32; -+ int blocks = (ds_get_width(ssd->ds) + blksize - 1) / blksize; -+ int dirty_top[blocks]; -+ int y, yoff, x, xoff, blk, bw; -+ int bpp = ds_get_bytes_per_pixel(ssd->ds); -+ uint8_t *guest, *mirror; -+ - if (qemu_spice_rect_is_empty(&ssd->dirty)) { - return; - }; -@@ -253,7 +260,54 @@ static void qemu_spice_create_update(SimpleSpiceDisplay *ssd) - ssd->ds_mirror = g_malloc0(size); - } - -- qemu_spice_create_one_update(ssd, &ssd->dirty); -+ for (blk = 0; blk < blocks; blk++) { -+ dirty_top[blk] = -1; -+ } -+ -+ guest = ds_get_data(ssd->ds); -+ mirror = ssd->ds_mirror; -+ for (y = ssd->dirty.top; y < ssd->dirty.bottom; y++) { -+ yoff = y * ds_get_linesize(ssd->ds); -+ for (x = ssd->dirty.left; x < ssd->dirty.right; x += blksize) { -+ xoff = x * bpp; -+ blk = x / blksize; -+ bw = MIN(blksize, ssd->dirty.right - x); -+ if (memcmp(guest + yoff + xoff, -+ mirror + yoff + xoff, -+ bw * bpp) == 0) { -+ if (dirty_top[blk] != -1) { -+ QXLRect update = { -+ .top = dirty_top[blk], -+ .bottom = y, -+ .left = x, -+ .right = x + bw, -+ }; -+ qemu_spice_create_one_update(ssd, &update); -+ dirty_top[blk] = -1; -+ } -+ } else { -+ if (dirty_top[blk] == -1) { -+ dirty_top[blk] = y; -+ } -+ } -+ } -+ } -+ -+ for (x = ssd->dirty.left; x < ssd->dirty.right; x += blksize) { -+ blk = x / blksize; -+ bw = MIN(blksize, ssd->dirty.right - x); -+ if (dirty_top[blk] != -1) { -+ QXLRect update = { -+ .top = dirty_top[blk], -+ .bottom = ssd->dirty.bottom, -+ .left = x, -+ .right = x + bw, -+ }; -+ qemu_spice_create_one_update(ssd, &update); -+ dirty_top[blk] = -1; -+ } -+ } -+ - memset(&ssd->dirty, 0, sizeof(ssd->dirty)); - } - --- -1.7.12 - diff --git a/0219-cadence_uart-Fix-buffer-overflow.patch b/0219-cadence_uart-Fix-buffer-overflow.patch new file mode 100644 index 0000000..3dbf127 --- /dev/null +++ b/0219-cadence_uart-Fix-buffer-overflow.patch @@ -0,0 +1,35 @@ +From d563cd7529186355aa8dc11e2cc7d16342dca1c9 Mon Sep 17 00:00:00 2001 +From: Stefan Weil +Date: Sat, 1 Sep 2012 11:12:23 +0200 +Subject: [PATCH] cadence_uart: Fix buffer overflow + +Report from smatch: +hw/cadence_uart.c:413 uart_read(13) error: buffer overflow 's->r' 18 <= 18 + +This fixes read access to s->r[R_MAX] which is behind the limits of s->r. + +Signed-off-by: Stefan Weil +Signed-off-by: Stefan Hajnoczi +(cherry picked from commit 5d40097fc09fe5d34cf316a411dc27d455ac2cd0) + +Signed-off-by: Michael Roth +--- + hw/cadence_uart.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/hw/cadence_uart.c b/hw/cadence_uart.c +index d98e531..f8afc4e 100644 +--- a/hw/cadence_uart.c ++++ b/hw/cadence_uart.c +@@ -404,7 +404,7 @@ static uint64_t uart_read(void *opaque, target_phys_addr_t offset, + uint32_t c = 0; + + offset >>= 2; +- if (offset > R_MAX) { ++ if (offset >= R_MAX) { + return 0; + } else if (offset == R_TX_RX) { + uart_read_rx_fifo(s, &c); +-- +1.7.12.1 + diff --git a/0219-qxl-dont-update-invalid-area.patch b/0219-qxl-dont-update-invalid-area.patch deleted file mode 100644 index 8739272..0000000 --- a/0219-qxl-dont-update-invalid-area.patch +++ /dev/null @@ -1,41 +0,0 @@ -From 6f1652c4412ab60c7f456100143c519d124a895c Mon Sep 17 00:00:00 2001 -From: Dunrong Huang -Date: Fri, 31 Aug 2012 00:44:44 +0800 -Subject: [PATCH 215/215] qxl: dont update invalid area - -This patch fixes the following error: - -$ ~/usr/bin/qemu-system-x86_64 -enable-kvm -m 1024 -spice port=5900,disable-ticketing -vga qxl -cdrom ~/Images/linuxmint-13-mate-dvd-32bit.iso -(/home/mathslinux/usr/bin/qemu-system-x86_64:10068): SpiceWorker-CRITICAL **: red_worker.c:4599:red_update_area: condition `area->left >= 0 && area->top >= 0 && area->left < area->right && area->top < area->bottom' failed -Aborted - -spice server terminates QEMU process if we pass invalid area to it, -so dont update those invalid areas. - -Signed-off-by: Dunrong Huang -Signed-off-by: Gerd Hoffmann ---- - hw/qxl.c | 7 +++++++ - 1 file changed, 7 insertions(+) - -diff --git a/hw/qxl.c b/hw/qxl.c -index b726c19..045432e 100644 ---- a/hw/qxl.c -+++ b/hw/qxl.c -@@ -1470,6 +1470,13 @@ async_common: - return; - } - -+ if (update.left < 0 || update.top < 0 || update.left >= update.right || -+ update.top >= update.bottom) { -+ qxl_set_guest_bug(d, "QXL_IO_UPDATE_AREA: " -+ "invalid area(%d,%d,%d,%d)\n", update.left, -+ update.right, update.top, update.bottom); -+ break; -+ } - if (async == QXL_ASYNC) { - cookie = qxl_cookie_new(QXL_COOKIE_TYPE_IO, - QXL_IO_UPDATE_AREA_ASYNC); --- -1.7.12 - diff --git a/0220-lm4549-Fix-buffer-overflow.patch b/0220-lm4549-Fix-buffer-overflow.patch new file mode 100644 index 0000000..656c9aa --- /dev/null +++ b/0220-lm4549-Fix-buffer-overflow.patch @@ -0,0 +1,47 @@ +From 00338325c4a2c5b0010462b21a4373cbb4341c9d Mon Sep 17 00:00:00 2001 +From: Stefan Weil +Date: Sat, 1 Sep 2012 12:43:41 +0200 +Subject: [PATCH] lm4549: Fix buffer overflow + +Report from smatch: +lm4549.c:234 lm4549_write_samples(14) error: + buffer overflow 's->buffer' 1024 <= 1024 + +There must be enough space to add two entries starting with index +s->buffer_level, therefore the old check was wrong. + +[Peter Maydell clarifies the nature of the +analyser warning: + +I don't object to making the change to placate the analyser, +but I don't think this is actually a buffer overrun. We always +add and remove samples from the buffer two at a time, so it's +not possible to get here with s->buffer_level == BUFFER_SIZE-1 +(which is the only case where the old and new conditions +give different answers).] + +Signed-off-by: Stefan Weil +Signed-off-by: Stefan Hajnoczi +(cherry picked from commit 8139626643cbe8dc07bd9acc88057effeedf8064) + +Signed-off-by: Michael Roth +--- + hw/lm4549.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/hw/lm4549.c b/hw/lm4549.c +index 80b3ec4..e0137d5 100644 +--- a/hw/lm4549.c ++++ b/hw/lm4549.c +@@ -224,7 +224,7 @@ uint32_t lm4549_write_samples(lm4549_state *s, uint32_t left, uint32_t right) + This model supports 16-bit playback. + */ + +- if (s->buffer_level >= LM4549_BUFFER_SIZE) { ++ if (s->buffer_level > LM4549_BUFFER_SIZE - 2) { + DPRINTF("write_sample Buffer full\n"); + return 0; + } +-- +1.7.12.1 + diff --git a/0220-qxl-Ignore-set_client_capabilities-pre-post-migrate.patch b/0220-qxl-Ignore-set_client_capabilities-pre-post-migrate.patch deleted file mode 100644 index 3391970..0000000 --- a/0220-qxl-Ignore-set_client_capabilities-pre-post-migrate.patch +++ /dev/null @@ -1,41 +0,0 @@ -From 68d246d6a904e0a851c521a08a18187598e1c696 Mon Sep 17 00:00:00 2001 -From: Hans de Goede -Date: Fri, 7 Sep 2012 21:29:22 +0200 -Subject: [PATCH] qxl: Ignore set_client_capabilities pre/post migrate - -The recent introduction of set_client_capabilities has broken -(seamless) migration by trying to call qxl_send_events pre (seamless -incoming) and post (*) migration, triggering the following assert: -qxl_send_events: Assertion `qemu_spice_display_is_running(&d->ssd)' failed. - -The solution is easy, pre migration the guest will have already received -the client caps on the migration source side, and post migration there no -longer is a guest, so we can simply ignore the set_client_capabilities call -in both those scenarios. - -*) Post migration, so not fatal for to the migration itself, but still a crash - -Signed-off-by: Hans de Goede ---- - hw/qxl.c | 5 +++++ - 1 file changed, 5 insertions(+) - -diff --git a/hw/qxl.c b/hw/qxl.c -index 045432e..1b400f1 100644 ---- a/hw/qxl.c -+++ b/hw/qxl.c -@@ -953,6 +953,11 @@ static void interface_set_client_capabilities(QXLInstance *sin, - { - PCIQXLDevice *qxl = container_of(sin, PCIQXLDevice, ssd.qxl); - -+ if (runstate_check(RUN_STATE_INMIGRATE) || -+ runstate_check(RUN_STATE_POSTMIGRATE)) { -+ return; -+ } -+ - qxl->shadow_rom.client_present = client_present; - memcpy(qxl->shadow_rom.client_capabilities, caps, sizeof(caps)); - qxl->rom->client_present = client_present; --- -1.7.12 - diff --git a/0221-ioh3420-Remove-unreachable-code.patch b/0221-ioh3420-Remove-unreachable-code.patch new file mode 100644 index 0000000..e465486 --- /dev/null +++ b/0221-ioh3420-Remove-unreachable-code.patch @@ -0,0 +1,33 @@ +From abb7dc3467f809d3d3dfc0aef70fce7ee542c550 Mon Sep 17 00:00:00 2001 +From: Stefan Weil +Date: Sat, 1 Sep 2012 12:56:03 +0200 +Subject: [PATCH] ioh3420: Remove unreachable code + +Report from smatch: +hw/ioh3420.c:128 ioh3420_initfn(35) info: ignoring unreachable code. + +Signed-off-by: Stefan Weil +Reviewed-by: Juan Quintela +Signed-off-by: Stefan Hajnoczi +(cherry picked from commit 997f15672a5ca7714cf310d92f475d2c5fe40970) + +Signed-off-by: Michael Roth +--- + hw/ioh3420.c | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/hw/ioh3420.c b/hw/ioh3420.c +index 94a537c..4d31473 100644 +--- a/hw/ioh3420.c ++++ b/hw/ioh3420.c +@@ -125,7 +125,6 @@ static int ioh3420_initfn(PCIDevice *d) + rc = pcie_chassis_add_slot(s); + if (rc < 0) { + goto err_pcie_cap; +- return rc; + } + pcie_cap_root_init(d); + rc = pcie_aer_init(d, IOH_EP_AER_OFFSET); +-- +1.7.12.1 + diff --git a/0221-qxl-better-cleanup-for-surface-destroy.patch b/0221-qxl-better-cleanup-for-surface-destroy.patch deleted file mode 100644 index d24e093..0000000 --- a/0221-qxl-better-cleanup-for-surface-destroy.patch +++ /dev/null @@ -1,32 +0,0 @@ -From 2315ba0b57785d788828e6871e528c9ab368068f Mon Sep 17 00:00:00 2001 -From: Uri Lublin -Date: Tue, 11 Sep 2012 10:09:58 +0300 -Subject: [PATCH 221/293] qxl: better cleanup for surface destroy - -Add back a call to qxl_spice_destroy_surface_wait_complete() in qxl_spice_destroy_surface_wait(), -that was removed by commit c480bb7da465186b84d8427e068ef7502e47ffbf - -It is needed to complete surface-removal cleanup, for non async. -For async, qxl_spice_destroy_surface_wait_complete is called upon operation completion. - -Signed-off-by: Uri Lublin -Signed-off-by: Gerd Hoffmann ---- - hw/qxl.c | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/hw/qxl.c b/hw/qxl.c -index 144a002..9f06f5e 100644 ---- a/hw/qxl.c -+++ b/hw/qxl.c -@@ -201,6 +201,7 @@ static void qxl_spice_destroy_surface_wait(PCIQXLDevice *qxl, uint32_t id, - spice_qxl_destroy_surface_async(&qxl->ssd.qxl, id, (uintptr_t)cookie); - } else { - qxl->ssd.worker->destroy_surface_wait(qxl->ssd.worker, id); -+ qxl_spice_destroy_surface_wait_complete(qxl, id); - } - } - --- -1.7.12 - diff --git a/0222-hw-qxl-tracing-fixes.patch b/0222-hw-qxl-tracing-fixes.patch deleted file mode 100644 index 2feba9d..0000000 --- a/0222-hw-qxl-tracing-fixes.patch +++ /dev/null @@ -1,96 +0,0 @@ -From b1b9a04abd4cc461e507091fadea866788d4a60a Mon Sep 17 00:00:00 2001 -From: Alon Levy -Date: Wed, 12 Sep 2012 16:13:26 +0300 -Subject: [PATCH 222/293] hw/qxl: tracing fixes - -Add two new trace events: -qxl_send_events(int qid, uint32_t events) "%d %d" -qxl_set_guest_bug(int qid) "%d" - -Change qxl_io_unexpected_vga_mode parameters to be equivalent to those -of qxl_io_write for easier grouping under a single systemtap probe. - -Change d to qxl in one place. - -Signed-off-by: Alon Levy -Signed-off-by: Gerd Hoffmann ---- - hw/qxl.c | 8 +++++--- - trace-events | 6 ++++-- - 2 files changed, 9 insertions(+), 5 deletions(-) - -diff --git a/hw/qxl.c b/hw/qxl.c -index 9f06f5e..360f4f6 100644 ---- a/hw/qxl.c -+++ b/hw/qxl.c -@@ -141,6 +141,7 @@ static void qxl_ring_set_dirty(PCIQXLDevice *qxl); - - void qxl_set_guest_bug(PCIQXLDevice *qxl, const char *msg, ...) - { -+ trace_qxl_set_guest_bug(qxl->id); - qxl_send_events(qxl, QXL_INTERRUPT_ERROR); - qxl->guest_bug = 1; - if (qxl->guestdebug) { -@@ -1408,7 +1409,7 @@ static void ioport_write(void *opaque, target_phys_addr_t addr, - break; - } - trace_qxl_io_unexpected_vga_mode(d->id, -- io_port, io_port_to_string(io_port)); -+ addr, val, io_port_to_string(io_port)); - /* be nice to buggy guest drivers */ - if (io_port >= QXL_IO_UPDATE_AREA_ASYNC && - io_port < QXL_IO_RANGE_SIZE) { -@@ -1607,9 +1608,9 @@ cancel_async: - static uint64_t ioport_read(void *opaque, target_phys_addr_t addr, - unsigned size) - { -- PCIQXLDevice *d = opaque; -+ PCIQXLDevice *qxl = opaque; - -- trace_qxl_io_read_unexpected(d->id); -+ trace_qxl_io_read_unexpected(qxl->id); - return 0xff; - } - -@@ -1639,6 +1640,7 @@ static void qxl_send_events(PCIQXLDevice *d, uint32_t events) - uint32_t old_pending; - uint32_t le_events = cpu_to_le32(events); - -+ trace_qxl_send_events(d->id, events); - assert(qemu_spice_display_is_running(&d->ssd)); - old_pending = __sync_fetch_and_or(&d->ram->int_pending, le_events); - if ((old_pending & le_events) == le_events) { -diff --git a/trace-events b/trace-events -index 8fcbc50..42dfb93 100644 ---- a/trace-events -+++ b/trace-events -@@ -925,7 +925,7 @@ qxl_interface_update_area_complete_overflow(int qid, int max) "%d max=%d" - qxl_interface_update_area_complete_schedule_bh(int qid, uint32_t num_dirty) "%d #dirty=%d" - qxl_io_destroy_primary_ignored(int qid, const char *mode) "%d %s" - qxl_io_read_unexpected(int qid) "%d" --qxl_io_unexpected_vga_mode(int qid, uint32_t io_port, const char *desc) "%d 0x%x (%s)" -+qxl_io_unexpected_vga_mode(int qid, uint64_t addr, uint64_t val, const char *desc) "%d 0x%"PRIx64"=%"PRIu64" (%s)" - qxl_io_write(int qid, const char *mode, uint64_t addr, uint64_t val, unsigned size, int async) "%d %s addr=%"PRIu64 " val=%"PRIu64" size=%u async=%d" - qxl_memslot_add_guest(int qid, uint32_t slot_id, uint64_t guest_start, uint64_t guest_end) "%d %u: guest phys 0x%"PRIx64 " - 0x%" PRIx64 - qxl_post_load(int qid, const char *mode) "%d %s" -@@ -956,7 +956,7 @@ qxl_spice_destroy_surfaces(int qid, int async) "%d async=%d" - qxl_spice_destroy_surface_wait_complete(int qid, uint32_t id) "%d sid=%d" - qxl_spice_destroy_surface_wait(int qid, uint32_t id, int async) "%d sid=%d async=%d" - qxl_spice_flush_surfaces_async(int qid, uint32_t surface_count, uint32_t num_free_res) "%d s#=%d, res#=%d" --qxl_spice_monitors_config(int id) "%d" -+qxl_spice_monitors_config(int qid) "%d" - qxl_spice_loadvm_commands(int qid, void *ext, uint32_t count) "%d ext=%p count=%d" - qxl_spice_oom(int qid) "%d" - qxl_spice_reset_cursor(int qid) "%d" -@@ -965,6 +965,8 @@ qxl_spice_reset_memslots(int qid) "%d" - qxl_spice_update_area(int qid, uint32_t surface_id, uint32_t left, uint32_t right, uint32_t top, uint32_t bottom) "%d sid=%d [%d,%d,%d,%d]" - qxl_spice_update_area_rest(int qid, uint32_t num_dirty_rects, uint32_t clear_dirty_region) "%d #d=%d clear=%d" - qxl_surfaces_dirty(int qid, int surface, int offset, int size) "%d surface=%d offset=%d size=%d" -+qxl_send_events(int qid, uint32_t events) "%d %d" -+qxl_set_guest_bug(int qid) "%d" - - # hw/qxl-render.c - qxl_render_blit_guest_primary_initialized(void) "" --- -1.7.12 - diff --git a/0222-pflash_cfi01-Fix-warning-caused-by-unreachable-code.patch b/0222-pflash_cfi01-Fix-warning-caused-by-unreachable-code.patch new file mode 100644 index 0000000..ef3cecd --- /dev/null +++ b/0222-pflash_cfi01-Fix-warning-caused-by-unreachable-code.patch @@ -0,0 +1,65 @@ +From 4377b521568c8dca87cfb8fad5629b3203c08032 Mon Sep 17 00:00:00 2001 +From: Stefan Weil +Date: Sat, 1 Sep 2012 13:00:48 +0200 +Subject: [PATCH] pflash_cfi01: Fix warning caused by unreachable code + +Report from smatch: +hw/pflash_cfi01.c:431 pflash_write(180) info: ignoring unreachable code. + +Instead of removing the return statement after the switch statement, +the patch replaces the return statements in the switch statement by +break statements. Other switch statements in the same code do it also +like that. + +Signed-off-by: Stefan Weil +Signed-off-by: Stefan Hajnoczi +(cherry picked from commit 12dabc79f976d66755025272f7e2e8e4da31715a) + +Signed-off-by: Michael Roth +--- + hw/pflash_cfi01.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/hw/pflash_cfi01.c b/hw/pflash_cfi01.c +index d56b51a..ac503cf 100644 +--- a/hw/pflash_cfi01.c ++++ b/hw/pflash_cfi01.c +@@ -320,7 +320,7 @@ static void pflash_write(pflash_t *pfl, target_phys_addr_t offset, + } + pfl->wcycle++; + pfl->cmd = cmd; +- return; ++ break; + case 1: + switch (pfl->cmd) { + case 0x10: /* Single Byte Program */ +@@ -375,7 +375,7 @@ static void pflash_write(pflash_t *pfl, target_phys_addr_t offset, + default: + goto error_flash; + } +- return; ++ break; + case 2: + switch (pfl->cmd) { + case 0xe8: /* Block write */ +@@ -406,7 +406,7 @@ static void pflash_write(pflash_t *pfl, target_phys_addr_t offset, + default: + goto error_flash; + } +- return; ++ break; + case 3: /* Confirm mode */ + switch (pfl->cmd) { + case 0xe8: /* Block write */ +@@ -422,7 +422,7 @@ static void pflash_write(pflash_t *pfl, target_phys_addr_t offset, + default: + goto error_flash; + } +- return; ++ break; + default: + /* Should never happen */ + DPRINTF("%s: invalid write state\n", __func__); +-- +1.7.12.1 + diff --git a/0223-curses-don-t-initialize-curses-when-qemu-is-daemoniz.patch b/0223-curses-don-t-initialize-curses-when-qemu-is-daemoniz.patch new file mode 100644 index 0000000..9f29c5e --- /dev/null +++ b/0223-curses-don-t-initialize-curses-when-qemu-is-daemoniz.patch @@ -0,0 +1,90 @@ +From 949f263f90b97dadae23ad205c4c5a3671ecb3aa Mon Sep 17 00:00:00 2001 +From: Hitoshi Mitake +Date: Sat, 15 Sep 2012 01:15:41 +0900 +Subject: [PATCH] curses: don't initialize curses when qemu is daemonized + +Current qemu initializes curses even if -daemonize option is +passed. This cause problem because shell prompt appears without +calling endwin(). + +This patch adds new function, is_daemonized(), to OS dependent +code. With this function, curses_display_init() can check that qemu is +daemonized or not. If daemonized, curses_display_init() isn't called +and the problem is avoided. + +Of course, -daemonize && -curses doesn't make sense. Users shouldn't +pass the arguments at the same time. But the problem is very painful +because Ctrl-C cannot be delivered to the terminal. + +Cc: Andrzej Zaborowski +Cc: Stefan Hajnoczi +Cc: Anthony Liguori +Cc: Michael Roth +Signed-off-by: Hitoshi Mitake +Signed-off-by: Stefan Hajnoczi +(cherry picked from commit 995ee2bf469de6bbe5ce133ec853392b2a4ce34c) + +Signed-off-by: Michael Roth +--- + os-posix.c | 5 +++++ + qemu-os-posix.h | 2 ++ + qemu-os-win32.h | 5 +++++ + vl.c | 4 +++- + 4 files changed, 15 insertions(+), 1 deletion(-) + +diff --git a/os-posix.c b/os-posix.c +index 79fa228..eabccb8 100644 +--- a/os-posix.c ++++ b/os-posix.c +@@ -360,3 +360,8 @@ int qemu_create_pidfile(const char *filename) + /* keep pidfile open & locked forever */ + return 0; + } ++ ++bool is_daemonized(void) ++{ ++ return daemonize; ++} +diff --git a/qemu-os-posix.h b/qemu-os-posix.h +index 8e1149d..7f198e4 100644 +--- a/qemu-os-posix.h ++++ b/qemu-os-posix.h +@@ -46,4 +46,6 @@ typedef struct timeval qemu_timeval; + typedef struct timespec qemu_timespec; + int qemu_utimens(const char *path, const qemu_timespec *times); + ++bool is_daemonized(void); ++ + #endif +diff --git a/qemu-os-win32.h b/qemu-os-win32.h +index 753679b..b3e451b 100644 +--- a/qemu-os-win32.h ++++ b/qemu-os-win32.h +@@ -86,4 +86,9 @@ typedef struct { + } qemu_timeval; + int qemu_gettimeofday(qemu_timeval *tp); + ++static inline bool is_daemonized(void) ++{ ++ return false; ++} ++ + #endif +diff --git a/vl.c b/vl.c +index c681c33..49d7a52 100644 +--- a/vl.c ++++ b/vl.c +@@ -3692,7 +3692,9 @@ int main(int argc, char **argv, char **envp) + break; + #if defined(CONFIG_CURSES) + case DT_CURSES: +- curses_display_init(ds, full_screen); ++ if (!is_daemonized()) { ++ curses_display_init(ds, full_screen); ++ } + break; + #endif + #if defined(CONFIG_SDL) +-- +1.7.12.1 + diff --git a/0223-qxl-add-trace-event-for-QXL_IO_LOG.patch b/0223-qxl-add-trace-event-for-QXL_IO_LOG.patch deleted file mode 100644 index 84982fa..0000000 --- a/0223-qxl-add-trace-event-for-QXL_IO_LOG.patch +++ /dev/null @@ -1,39 +0,0 @@ -From f4cebc3d7a15ecccf61809c35242427e2c2e6713 Mon Sep 17 00:00:00 2001 -From: Alon Levy -Date: Wed, 12 Sep 2012 16:13:27 +0300 -Subject: [PATCH 223/293] qxl: add trace-event for QXL_IO_LOG - -Signed-off-by: Alon Levy -Signed-off-by: Gerd Hoffmann ---- - hw/qxl.c | 1 + - trace-events | 1 + - 2 files changed, 2 insertions(+) - -diff --git a/hw/qxl.c b/hw/qxl.c -index 360f4f6..1ef117a 100644 ---- a/hw/qxl.c -+++ b/hw/qxl.c -@@ -1515,6 +1515,7 @@ async_common: - qxl_set_mode(d, val, 0); - break; - case QXL_IO_LOG: -+ trace_qxl_io_log(d->id, d->ram->log_buf); - if (d->guestdebug) { - fprintf(stderr, "qxl/guest-%d: %" PRId64 ": %s", d->id, - qemu_get_clock_ns(vm_clock), d->ram->log_buf); -diff --git a/trace-events b/trace-events -index 42dfb93..0ce69d6 100644 ---- a/trace-events -+++ b/trace-events -@@ -924,6 +924,7 @@ qxl_interface_update_area_complete_rest(int qid, uint32_t num_updated_rects) "%d - qxl_interface_update_area_complete_overflow(int qid, int max) "%d max=%d" - qxl_interface_update_area_complete_schedule_bh(int qid, uint32_t num_dirty) "%d #dirty=%d" - qxl_io_destroy_primary_ignored(int qid, const char *mode) "%d %s" -+qxl_io_log(int qid, const uint8_t *str) "%d %s" - qxl_io_read_unexpected(int qid) "%d" - qxl_io_unexpected_vga_mode(int qid, uint64_t addr, uint64_t val, const char *desc) "%d 0x%"PRIx64"=%"PRIu64" (%s)" - qxl_io_write(int qid, const char *mode, uint64_t addr, uint64_t val, unsigned size, int async) "%d %s addr=%"PRIu64 " val=%"PRIu64" size=%u async=%d" --- -1.7.12 - diff --git a/0224-TextConsole-saturate-escape-parameter-in-TTY_STATE_C.patch b/0224-TextConsole-saturate-escape-parameter-in-TTY_STATE_C.patch new file mode 100644 index 0000000..523d5f4 --- /dev/null +++ b/0224-TextConsole-saturate-escape-parameter-in-TTY_STATE_C.patch @@ -0,0 +1,36 @@ +From 93eaa3c8e14988fb38dfa9ae35067472bfd089b8 Mon Sep 17 00:00:00 2001 +From: Laszlo Ersek +Date: Mon, 17 Sep 2012 11:10:03 +0200 +Subject: [PATCH] TextConsole: saturate escape parameter in TTY_STATE_CSI + +Signed-off-by: Laszlo Ersek +Reviewed-by: Markus Armbruster +Signed-off-by: Stefan Hajnoczi +(cherry picked from commit c10600af60865ba6c60987be313102ebb5fcee57) + +Signed-off-by: Michael Roth +--- + console.c | 7 +++++-- + 1 file changed, 5 insertions(+), 2 deletions(-) + +diff --git a/console.c b/console.c +index 8b5e21d..314f5a5 100644 +--- a/console.c ++++ b/console.c +@@ -937,8 +937,11 @@ static void console_putchar(TextConsole *s, int ch) + case TTY_STATE_CSI: /* handle escape sequence parameters */ + if (ch >= '0' && ch <= '9') { + if (s->nb_esc_params < MAX_ESC_PARAMS) { +- s->esc_params[s->nb_esc_params] = +- s->esc_params[s->nb_esc_params] * 10 + ch - '0'; ++ int *param = &s->esc_params[s->nb_esc_params]; ++ int digit = (ch - '0'); ++ ++ *param = (*param <= (INT_MAX - digit) / 10) ? ++ *param * 10 + digit : INT_MAX; + } + } else { + if (s->nb_esc_params < MAX_ESC_PARAMS) +-- +1.7.12.1 + diff --git a/0224-hw-qxl-support-client-monitor-configuration-via-devi.patch b/0224-hw-qxl-support-client-monitor-configuration-via-devi.patch deleted file mode 100644 index 56cd1e1..0000000 --- a/0224-hw-qxl-support-client-monitor-configuration-via-devi.patch +++ /dev/null @@ -1,182 +0,0 @@ -From 3ad6b56cb328a01150fc9a61ee7f4300af2a0912 Mon Sep 17 00:00:00 2001 -From: Alon Levy -Date: Wed, 12 Sep 2012 16:13:28 +0300 -Subject: [PATCH 224/293] hw/qxl: support client monitor configuration via - device - -Until now we used only the agent to change the monitor count and each -monitor resolution. This patch introduces the qemu part of using the -device as the mediator instead of the agent via virtio-serial. - -Spice (>=0.11.5) calls the new QXLInterface::client_monitors_config, -which returns wether the interrupt is enabled, and if so and given a non -NULL monitors config will -generate an interrupt QXL_INTERRUPT_CLIENT_MONITORS_CONFIG with crc -checksum for the guest to verify a second call hasn't interfered. - -The maximal number of monitors is limited on the QXLRom to 64. - -Signed-off-by: Alon Levy -Signed-off-by: Gerd Hoffmann ---- - configure | 7 ++++++ - hw/qxl.c | 79 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - trace-events | 6 ++++- - 3 files changed, 91 insertions(+), 1 deletion(-) - -diff --git a/configure b/configure -index 0bfef84..ebe8b1c 100755 ---- a/configure -+++ b/configure -@@ -2716,6 +2716,9 @@ EOF - if $pkg_config --atleast-version=0.12.0 spice-protocol >/dev/null 2>&1; then - spice_qxl_io_monitors_config_async="yes" - fi -+ if $pkg_config --atleast-version=0.12.2 spice-protocol > /dev/null 2>&1; then -+ spice_qxl_client_monitors_config="yes" -+ fi - else - if test "$spice" = "yes" ; then - feature_not_found "spice" -@@ -3457,6 +3460,10 @@ if test "$spice_qxl_io_monitors_config_async" = "yes" ; then - echo "CONFIG_QXL_IO_MONITORS_CONFIG_ASYNC=y" >> $config_host_mak - fi - -+if test "$spice_qxl_client_monitors_config" = "yes" ; then -+ echo "CONFIG_QXL_CLIENT_MONITORS_CONFIG=y" >> $config_host_mak -+fi -+ - if test "$smartcard" = "yes" ; then - echo "CONFIG_SMARTCARD=y" >> $config_host_mak - fi -diff --git a/hw/qxl.c b/hw/qxl.c -index 1ef117a..0695872 100644 ---- a/hw/qxl.c -+++ b/hw/qxl.c -@@ -18,6 +18,8 @@ - * along with this program; if not, see . - */ - -+#include -+ - #include "qemu-common.h" - #include "qemu-timer.h" - #include "qemu-queue.h" -@@ -971,6 +973,79 @@ static void interface_set_client_capabilities(QXLInstance *sin, - - #endif - -+#if defined(CONFIG_QXL_CLIENT_MONITORS_CONFIG) \ -+ && SPICE_SERVER_VERSION >= 0x000b05 -+ -+static uint32_t qxl_crc32(const uint8_t *p, unsigned len) -+{ -+ /* -+ * zlib xors the seed with 0xffffffff, and xors the result -+ * again with 0xffffffff; Both are not done with linux's crc32, -+ * which we want to be compatible with, so undo that. -+ */ -+ return crc32(0xffffffff, p, len) ^ 0xffffffff; -+} -+ -+/* called from main context only */ -+static int interface_client_monitors_config(QXLInstance *sin, -+ VDAgentMonitorsConfig *monitors_config) -+{ -+ PCIQXLDevice *qxl = container_of(sin, PCIQXLDevice, ssd.qxl); -+ QXLRom *rom = memory_region_get_ram_ptr(&qxl->rom_bar); -+ int i; -+ -+ /* -+ * Older windows drivers set int_mask to 0 when their ISR is called, -+ * then later set it to ~0. So it doesn't relate to the actual interrupts -+ * handled. However, they are old, so clearly they don't support this -+ * interrupt -+ */ -+ if (qxl->ram->int_mask == 0 || qxl->ram->int_mask == ~0 || -+ !(qxl->ram->int_mask & QXL_INTERRUPT_CLIENT_MONITORS_CONFIG)) { -+ trace_qxl_client_monitors_config_unsupported_by_guest(qxl->id, -+ qxl->ram->int_mask, -+ monitors_config); -+ return 0; -+ } -+ if (!monitors_config) { -+ return 1; -+ } -+ memset(&rom->client_monitors_config, 0, -+ sizeof(rom->client_monitors_config)); -+ rom->client_monitors_config.count = monitors_config->num_of_monitors; -+ /* monitors_config->flags ignored */ -+ if (rom->client_monitors_config.count >= -+ ARRAY_SIZE(rom->client_monitors_config.heads)) { -+ trace_qxl_client_monitors_config_capped(qxl->id, -+ monitors_config->num_of_monitors, -+ ARRAY_SIZE(rom->client_monitors_config.heads)); -+ rom->client_monitors_config.count = -+ ARRAY_SIZE(rom->client_monitors_config.heads); -+ } -+ for (i = 0 ; i < rom->client_monitors_config.count ; ++i) { -+ VDAgentMonConfig *monitor = &monitors_config->monitors[i]; -+ QXLURect *rect = &rom->client_monitors_config.heads[i]; -+ /* monitor->depth ignored */ -+ rect->left = monitor->x; -+ rect->top = monitor->y; -+ rect->right = monitor->x + monitor->width; -+ rect->bottom = monitor->y + monitor->height; -+ } -+ rom->client_monitors_config_crc = qxl_crc32( -+ (const uint8_t *)&rom->client_monitors_config, -+ sizeof(rom->client_monitors_config)); -+ trace_qxl_client_monitors_config_crc(qxl->id, -+ sizeof(rom->client_monitors_config), -+ rom->client_monitors_config_crc); -+ -+ trace_qxl_interrupt_client_monitors_config(qxl->id, -+ rom->client_monitors_config.count, -+ rom->client_monitors_config.heads); -+ qxl_send_events(qxl, QXL_INTERRUPT_CLIENT_MONITORS_CONFIG); -+ return 1; -+} -+#endif -+ - static const QXLInterface qxl_interface = { - .base.type = SPICE_INTERFACE_QXL, - .base.description = "qxl gpu", -@@ -995,6 +1070,10 @@ static const QXLInterface qxl_interface = { - #if SPICE_SERVER_VERSION >= 0x000b04 - .set_client_capabilities = interface_set_client_capabilities, - #endif -+#if SPICE_SERVER_VERSION >= 0x000b05 && \ -+ defined(CONFIG_QXL_CLIENT_MONITORS_CONFIG) -+ .client_monitors_config = interface_client_monitors_config, -+#endif - }; - - static void qxl_enter_vga_mode(PCIQXLDevice *d) -diff --git a/trace-events b/trace-events -index 0ce69d6..1b19988 100644 ---- a/trace-events -+++ b/trace-events -@@ -924,7 +924,7 @@ qxl_interface_update_area_complete_rest(int qid, uint32_t num_updated_rects) "%d - qxl_interface_update_area_complete_overflow(int qid, int max) "%d max=%d" - qxl_interface_update_area_complete_schedule_bh(int qid, uint32_t num_dirty) "%d #dirty=%d" - qxl_io_destroy_primary_ignored(int qid, const char *mode) "%d %s" --qxl_io_log(int qid, const uint8_t *str) "%d %s" -+qxl_io_log(int qid, const uint8_t *log_buf) "%d %s" - qxl_io_read_unexpected(int qid) "%d" - qxl_io_unexpected_vga_mode(int qid, uint64_t addr, uint64_t val, const char *desc) "%d 0x%"PRIx64"=%"PRIu64" (%s)" - qxl_io_write(int qid, const char *mode, uint64_t addr, uint64_t val, unsigned size, int async) "%d %s addr=%"PRIu64 " val=%"PRIu64" size=%u async=%d" -@@ -968,6 +968,10 @@ qxl_spice_update_area_rest(int qid, uint32_t num_dirty_rects, uint32_t clear_dir - qxl_surfaces_dirty(int qid, int surface, int offset, int size) "%d surface=%d offset=%d size=%d" - qxl_send_events(int qid, uint32_t events) "%d %d" - qxl_set_guest_bug(int qid) "%d" -+qxl_interrupt_client_monitors_config(int qid, int num_heads, void *heads) "%d %d %p" -+qxl_client_monitors_config_unsupported_by_guest(int qid, uint32_t int_mask, void *client_monitors_config) "%d %X %p" -+qxl_client_monitors_config_capped(int qid, int requested, int limit) "%d %d %d" -+qxl_client_monitors_config_crc(int qid, unsigned size, uint32_t crc32) "%d %u %u" - - # hw/qxl-render.c - qxl_render_blit_guest_primary_initialized(void) "" --- -1.7.12 - diff --git a/0225-linux-user-Remove-redundant-null-check-and-replace-f.patch b/0225-linux-user-Remove-redundant-null-check-and-replace-f.patch new file mode 100644 index 0000000..acb18c0 --- /dev/null +++ b/0225-linux-user-Remove-redundant-null-check-and-replace-f.patch @@ -0,0 +1,42 @@ +From 755055c908ccda2dd9410bb1bde1f3621017fb0c Mon Sep 17 00:00:00 2001 +From: Stefan Weil +Date: Tue, 4 Sep 2012 22:14:19 +0200 +Subject: [PATCH] linux-user: Remove redundant null check and replace free by + g_free + +Report from smatch: + +linux-user/syscall.c:3632 do_ioctl_dm(220) info: + redundant null check on big_buf calling free() + +'big_buf' was allocated by g_malloc0, therefore free was also +replaced by g_free. + +Signed-off-by: Stefan Weil +Reviewed-by: Peter Maydell +Signed-off-by: Stefan Hajnoczi +(cherry picked from commit ad11ad77748bdd8016370db210751683dc038dd6) + +Signed-off-by: Michael Roth +--- + linux-user/syscall.c | 4 +--- + 1 file changed, 1 insertion(+), 3 deletions(-) + +diff --git a/linux-user/syscall.c b/linux-user/syscall.c +index 6257a04..471d060 100644 +--- a/linux-user/syscall.c ++++ b/linux-user/syscall.c +@@ -3628,9 +3628,7 @@ static abi_long do_ioctl_dm(const IOCTLEntry *ie, uint8_t *buf_temp, int fd, + unlock_user(argptr, arg, target_size); + } + out: +- if (big_buf) { +- free(big_buf); +- } ++ g_free(big_buf); + return ret; + } + +-- +1.7.12.1 + diff --git a/0225-qxl-always-update-displaysurface-on-resize.patch b/0225-qxl-always-update-displaysurface-on-resize.patch deleted file mode 100644 index ec92f32..0000000 --- a/0225-qxl-always-update-displaysurface-on-resize.patch +++ /dev/null @@ -1,44 +0,0 @@ -From 8046044514de3ef6a37bb982c8e239b9dc34208d Mon Sep 17 00:00:00 2001 -From: Gerd Hoffmann -Date: Fri, 14 Sep 2012 22:09:23 +0200 -Subject: [PATCH 225/228] qxl: always update displaysurface on resize - -Don't try to be clever and skip displaysurface reinitialization in case -the size hasn't changed. Other parameters might have changed -nevertheless, for example depth or stride, resulting in rendering being -broken then. - -Trigger: boot linux guest with vesafb, start X11, make sure both vesafb -and X11 use the display same resolution. Then watch X11 screen being -upside down. - -Signed-off-by: Gerd Hoffmann ---- - hw/qxl-render.c | 4 ---- - 1 file changed, 4 deletions(-) - -diff --git a/hw/qxl-render.c b/hw/qxl-render.c -index e2e3fe2..b66c168 100644 ---- a/hw/qxl-render.c -+++ b/hw/qxl-render.c -@@ -99,7 +99,6 @@ static void qxl_render_update_area_unlocked(PCIQXLDevice *qxl) - { - VGACommonState *vga = &qxl->vga; - int i; -- DisplaySurface *surface = vga->ds->surface; - - if (qxl->guest_primary.resized) { - qxl->guest_primary.resized = 0; -@@ -112,9 +111,6 @@ static void qxl_render_update_area_unlocked(PCIQXLDevice *qxl) - qxl->guest_primary.qxl_stride, - qxl->guest_primary.bytes_pp, - qxl->guest_primary.bits_pp); -- } -- if (surface->width != qxl->guest_primary.surface.width || -- surface->height != qxl->guest_primary.surface.height) { - if (qxl->guest_primary.qxl_stride > 0) { - qemu_free_displaysurface(vga->ds); - qemu_create_displaysurface_from(qxl->guest_primary.surface.width, --- -1.7.12 - diff --git a/0226-net-socket-Fix-compiler-warning-regression-for-MinGW.patch b/0226-net-socket-Fix-compiler-warning-regression-for-MinGW.patch new file mode 100644 index 0000000..e3cb65f --- /dev/null +++ b/0226-net-socket-Fix-compiler-warning-regression-for-MinGW.patch @@ -0,0 +1,68 @@ +From 96f47b0d2c307173e0a545ea230e21f1ce8d3fa2 Mon Sep 17 00:00:00 2001 +From: Stefan Weil +Date: Sat, 22 Sep 2012 21:13:28 +0200 +Subject: [PATCH] net/socket: Fix compiler warning (regression for MinGW) +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Commit 213fd5087e2e4e2da10ad266df0ba950cf7618bf removed a type cast +which is needed for MinGW: + +net/socket.c:136: warning: + pointer targets in passing argument 2 of ‘sendto’ differ in signedness +/usr/lib/gcc/amd64-mingw32msvc/4.4.4/../../../../amd64-mingw32msvc/include/winsock2.h:1313: note: + expected ‘const char *’ but argument is of type ‘const uint8_t *’ + +Add a 'qemu_sendto' macro which provides that type cast where needed +and use the new macro instead of 'sendto'. + +Signed-off-by: Stefan Weil +Signed-off-by: Stefan Hajnoczi +(cherry picked from commit 73062dfe6be0050dbd43ce3516e935ebb2545add) + +Signed-off-by: Michael Roth +--- + net/socket.c | 6 +++--- + qemu-common.h | 5 +++++ + 2 files changed, 8 insertions(+), 3 deletions(-) + +diff --git a/net/socket.c b/net/socket.c +index c3e55b8..83f21b5 100644 +--- a/net/socket.c ++++ b/net/socket.c +@@ -131,9 +131,9 @@ static ssize_t net_socket_receive_dgram(NetClientState *nc, const uint8_t *buf, + ssize_t ret; + + do { +- ret = sendto(s->fd, buf, size, 0, +- (struct sockaddr *)&s->dgram_dst, +- sizeof(s->dgram_dst)); ++ ret = qemu_sendto(s->fd, buf, size, 0, ++ (struct sockaddr *)&s->dgram_dst, ++ sizeof(s->dgram_dst)); + } while (ret == -1 && errno == EINTR); + + if (ret == -1 && errno == EAGAIN) { +diff --git a/qemu-common.h b/qemu-common.h +index e5c2bcd..15d9e4e 100644 +--- a/qemu-common.h ++++ b/qemu-common.h +@@ -223,9 +223,14 @@ int qemu_pipe(int pipefd[2]); + #endif + + #ifdef _WIN32 ++/* MinGW needs a type cast for the 'buf' argument. */ + #define qemu_recv(sockfd, buf, len, flags) recv(sockfd, (void *)buf, len, flags) ++#define qemu_sendto(sockfd, buf, len, flags, destaddr, addrlen) \ ++ sendto(sockfd, (const void *)buf, len, flags, destaddr, addrlen) + #else + #define qemu_recv(sockfd, buf, len, flags) recv(sockfd, buf, len, flags) ++#define qemu_sendto(sockfd, buf, len, flags, destaddr, addrlen) \ ++ sendto(sockfd, buf, len, flags, destaddr, addrlen) + #endif + + /* Error handling. */ +-- +1.7.12.1 + diff --git a/0226-qxl-update_area_io-cleanup-invalid-parameters-handli.patch b/0226-qxl-update_area_io-cleanup-invalid-parameters-handli.patch deleted file mode 100644 index 9082549..0000000 --- a/0226-qxl-update_area_io-cleanup-invalid-parameters-handli.patch +++ /dev/null @@ -1,49 +0,0 @@ -From 286f37492e7e3f746aba6fb5df4579a7fc1301da Mon Sep 17 00:00:00 2001 -From: Michael Tokarev -Date: Wed, 19 Sep 2012 17:41:26 +0400 -Subject: [PATCH 227/228] qxl/update_area_io: cleanup invalid parameters - handling - -This cleans up two additions of almost the same code in commits -511b13e2c9 and ccc2960d654. While at it, make error paths -consistent (always use 'break' instead of 'return'). - -Signed-off-by: Michael Tokarev -Cc: Dunrong Huang -Cc: Alon Levy -Signed-off-by: Gerd Hoffmann ---- - hw/qxl.c | 13 +++---------- - 1 file changed, 3 insertions(+), 10 deletions(-) - -diff --git a/hw/qxl.c b/hw/qxl.c -index bb0b5e1..1f0f4e7 100644 ---- a/hw/qxl.c -+++ b/hw/qxl.c -@@ -1551,20 +1551,13 @@ async_common: - if (d->ram->update_surface > d->ssd.num_surfaces) { - qxl_set_guest_bug(d, "QXL_IO_UPDATE_AREA: invalid surface id %d\n", - d->ram->update_surface); -- return; -+ break; - } -- if (update.left >= update.right || update.top >= update.bottom) { -+ if (update.left >= update.right || update.top >= update.bottom || -+ update.left < 0 || update.top < 0) { - qxl_set_guest_bug(d, - "QXL_IO_UPDATE_AREA: invalid area (%ux%u)x(%ux%u)\n", - update.left, update.top, update.right, update.bottom); -- return; -- } -- -- if (update.left < 0 || update.top < 0 || update.left >= update.right || -- update.top >= update.bottom) { -- qxl_set_guest_bug(d, "QXL_IO_UPDATE_AREA: " -- "invalid area(%d,%d,%d,%d)\n", update.left, -- update.right, update.top, update.bottom); - break; - } - if (async == QXL_ASYNC) { --- -1.7.12 - diff --git a/0227-qxl-fix-range-check-for-rev3-io-commands.patch b/0227-qxl-fix-range-check-for-rev3-io-commands.patch deleted file mode 100644 index 95df3f9..0000000 --- a/0227-qxl-fix-range-check-for-rev3-io-commands.patch +++ /dev/null @@ -1,29 +0,0 @@ -From 3133cf6b440dab301639ff979714bb08cab68eec Mon Sep 17 00:00:00 2001 -From: Gerd Hoffmann -Date: Tue, 25 Sep 2012 13:56:40 +0200 -Subject: [PATCH 228/228] qxl: fix range check for rev3 io commands. - -Enables QXL_IO_FLUSH_SURFACES_ASYNC and QXL_IO_FLUSH_RELEASE -which are part of the qxl rev3 feature set. - -Signed-off-by: Gerd Hoffmann ---- - hw/qxl.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/hw/qxl.c b/hw/qxl.c -index 1f0f4e7..ad5ebd5 100644 ---- a/hw/qxl.c -+++ b/hw/qxl.c -@@ -1470,7 +1470,7 @@ static void ioport_write(void *opaque, target_phys_addr_t addr, - } - - if (d->revision <= QXL_REVISION_STABLE_V10 && -- io_port >= QXL_IO_FLUSH_SURFACES_ASYNC) { -+ io_port > QXL_IO_FLUSH_RELEASE) { - qxl_set_guest_bug(d, "unsupported io %d for revision %d\n", - io_port, d->revision); - return; --- -1.7.12 - diff --git a/0227-w32-Always-use-standard-instead-of-native-format-str.patch b/0227-w32-Always-use-standard-instead-of-native-format-str.patch new file mode 100644 index 0000000..91b7bba --- /dev/null +++ b/0227-w32-Always-use-standard-instead-of-native-format-str.patch @@ -0,0 +1,52 @@ +From 675a9bdcd5bf5bd663ee58cf5e4be4acf12d34ce Mon Sep 17 00:00:00 2001 +From: Stefan Weil +Date: Wed, 22 Aug 2012 21:42:32 +0200 +Subject: [PATCH] w32: Always use standard instead of native format strings +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +GLib 2.0 include files use __printf__ for the format attribute +which resolves to native format strings on w32 hosts. + +QEMU wants standard format strings instead of native format +strings, so we simply change any declaration with __printf__ +to use __gnu_printf__. + +This works because all basic printf functions support both +kinds of format strings. + +This fixes a compiler warning: + +qapi/string-output-visitor.c: In function ‘print_type_int’: +qapi/string-output-visitor.c:34:5: warning: unknown conversion type character ‘l’ in format [-Wformat] +qapi/string-output-visitor.c:34:5: warning: too many arguments for format [-Wformat-extra-args] + +Signed-off-by: Stefan Weil +Signed-off-by: Stefan Hajnoczi +(cherry picked from commit 95df51a4a02a853af8828c281bce2d4f2a41d6fd) + +Signed-off-by: Michael Roth +--- + compiler.h | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/compiler.h b/compiler.h +index 07ba1f8..c734a71 100644 +--- a/compiler.h ++++ b/compiler.h +@@ -44,6 +44,11 @@ + /* Use gnu_printf when supported (qemu uses standard format strings). */ + # define GCC_ATTR __attribute__((__unused__, format(gnu_printf, 1, 2))) + # define GCC_FMT_ATTR(n, m) __attribute__((format(gnu_printf, n, m))) ++# if defined(_WIN32) ++ /* Map __printf__ to __gnu_printf__ because we want standard format strings ++ * even when MinGW or GLib include files use __printf__. */ ++# define __printf__ __gnu_printf__ ++# endif + # endif + #if defined(_WIN32) + #define GCC_WEAK __attribute__((weak)) +-- +1.7.12.1 + diff --git a/0228-w32-Add-implementation-of-gmtime_r-localtime_r.patch b/0228-w32-Add-implementation-of-gmtime_r-localtime_r.patch new file mode 100644 index 0000000..16473ea --- /dev/null +++ b/0228-w32-Add-implementation-of-gmtime_r-localtime_r.patch @@ -0,0 +1,81 @@ +From 27ca56812d2140c774f9d2b67a2919ef47c69758 Mon Sep 17 00:00:00 2001 +From: Stefan Weil +Date: Sat, 22 Sep 2012 22:26:19 +0200 +Subject: [PATCH] w32: Add implementation of gmtime_r, localtime_r + +Those functions are missing in MinGW. + +Some versions of MinGW-w64 include defines for gmtime_r and localtime_r. +Older versions of these macros are buggy (they return a pointer to a +static variable), therefore we don't want them. Newer versions are +similar to the code used here, but without the memset. + +The implementation which is used here is not strictly reentrant, +but sufficiently good for QEMU on w32 or w64. + +Signed-off-by: Stefan Weil +[blauwirbel@gmail.com: added comment about locking] +Signed-off-by: Blue Swirl +(cherry picked from commit d3e8f95753114a827f9cd8e819b1d5cc8333f76b) + +Signed-off-by: Michael Roth +--- + oslib-win32.c | 24 ++++++++++++++++++++++++ + qemu-os-win32.h | 6 ++++++ + 2 files changed, 30 insertions(+) + +diff --git a/oslib-win32.c b/oslib-win32.c +index ffbc6d0..51b33e8 100644 +--- a/oslib-win32.c ++++ b/oslib-win32.c +@@ -74,6 +74,30 @@ void qemu_vfree(void *ptr) + VirtualFree(ptr, 0, MEM_RELEASE); + } + ++/* FIXME: add proper locking */ ++struct tm *gmtime_r(const time_t *timep, struct tm *result) ++{ ++ struct tm *p = gmtime(timep); ++ memset(result, 0, sizeof(*result)); ++ if (p) { ++ *result = *p; ++ p = result; ++ } ++ return p; ++} ++ ++/* FIXME: add proper locking */ ++struct tm *localtime_r(const time_t *timep, struct tm *result) ++{ ++ struct tm *p = localtime(timep); ++ memset(result, 0, sizeof(*result)); ++ if (p) { ++ *result = *p; ++ p = result; ++ } ++ return p; ++} ++ + void socket_set_block(int fd) + { + unsigned long opt = 0; +diff --git a/qemu-os-win32.h b/qemu-os-win32.h +index b3e451b..8ba466d 100644 +--- a/qemu-os-win32.h ++++ b/qemu-os-win32.h +@@ -68,6 +68,12 @@ + /* Declaration of ffs() is missing in MinGW's strings.h. */ + int ffs(int i); + ++/* Missing POSIX functions. Don't use MinGW-w64 macros. */ ++#undef gmtime_r ++struct tm *gmtime_r(const time_t *timep, struct tm *result); ++#undef localtime_r ++struct tm *localtime_r(const time_t *timep, struct tm *result); ++ + static inline void os_setup_signal_handling(void) {} + static inline void os_daemonize(void) {} + static inline void os_setup_post(void) {} +-- +1.7.12.1 + diff --git a/0229-blockdev-preserve-readonly-and-snapshot-states-acros.patch b/0229-blockdev-preserve-readonly-and-snapshot-states-acros.patch new file mode 100644 index 0000000..19bbd20 --- /dev/null +++ b/0229-blockdev-preserve-readonly-and-snapshot-states-acros.patch @@ -0,0 +1,37 @@ +From 2afae8c7d44a043e36038d5f6f600034ad2b2aca Mon Sep 17 00:00:00 2001 +From: Kevin Shanahan +Date: Fri, 21 Sep 2012 08:50:22 +0930 +Subject: [PATCH] blockdev: preserve readonly and snapshot states across media + changes + +If readonly=on is given at device creation time, the ->readonly flag +needs to be set in the block driver state for this device so that +readonly-ness is preserved across media changes (qmp change command). +Similarly, to preserve the snapshot property requires ->open_flags to +be correct. + +Signed-off-by: Kevin Shanahan +Signed-off-by: Kevin Wolf +(cherry picked from commit 80dd1aae3657a902d262f5d20a7a3c655b23705e) + +Signed-off-by: Michael Roth +--- + blockdev.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/blockdev.c b/blockdev.c +index 4a5266e..9ba3503 100644 +--- a/blockdev.c ++++ b/blockdev.c +@@ -533,6 +533,8 @@ DriveInfo *drive_init(QemuOpts *opts, int default_to_scsi) + if_name[type], mediastr, unit_id); + } + dinfo->bdrv = bdrv_new(dinfo->id); ++ dinfo->bdrv->open_flags = snapshot ? BDRV_O_SNAPSHOT : 0; ++ dinfo->bdrv->read_only = ro; + dinfo->devaddr = devaddr; + dinfo->type = type; + dinfo->bus = bus_id; +-- +1.7.12.1 + diff --git a/0230-block-correctly-set-the-keep_read_only-flag.patch b/0230-block-correctly-set-the-keep_read_only-flag.patch new file mode 100644 index 0000000..ec1affa --- /dev/null +++ b/0230-block-correctly-set-the-keep_read_only-flag.patch @@ -0,0 +1,104 @@ +From 48f550221420bd90ddca06c6c7492ea3aca9b644 Mon Sep 17 00:00:00 2001 +From: Jeff Cody +Date: Thu, 20 Sep 2012 15:13:17 -0400 +Subject: [PATCH] block: correctly set the keep_read_only flag + +I believe the bs->keep_read_only flag is supposed to reflect +the initial open state of the device. If the device is initially +opened R/O, then commit operations, or reopen operations changing +to R/W, are prohibited. + +Currently, the keep_read_only flag is only accurate for the active +layer, and its backing file. Subsequent images end up always having +the keep_read_only flag set. + +For instance, what happens now: + +[ base ] kro = 1, ro = 1 + | + v +[ snap-1 ] kro = 1, ro = 1 + | + v +[ snap-2 ] kro = 0, ro = 1 + | + v +[ active ] kro = 0, ro = 0 + +What we want: + +[ base ] kro = 0, ro = 1 + | + v +[ snap-1 ] kro = 0, ro = 1 + | + v +[ snap-2 ] kro = 0, ro = 1 + | + v +[ active ] kro = 0, ro = 0 + +Signed-off-by: Jeff Cody +Signed-off-by: Kevin Wolf +(cherry picked from commit be028adcedd68ca4d78fdc43e7e2fa4f1cdbc653) + +Signed-off-by: Michael Roth +--- + block.c | 14 +++++++------- + block.h | 1 + + 2 files changed, 8 insertions(+), 7 deletions(-) + +diff --git a/block.c b/block.c +index e78039b..4c0e7f5 100644 +--- a/block.c ++++ b/block.c +@@ -668,7 +668,7 @@ static int bdrv_open_common(BlockDriverState *bs, const char *filename, + open_flags |= BDRV_O_RDWR; + } + +- bs->keep_read_only = bs->read_only = !(open_flags & BDRV_O_RDWR); ++ bs->read_only = !(open_flags & BDRV_O_RDWR); + + /* Open the image, either directly or using a protocol */ + if (drv->bdrv_file_open) { +@@ -808,6 +808,12 @@ int bdrv_open(BlockDriverState *bs, const char *filename, int flags, + goto unlink_and_fail; + } + ++ if (flags & BDRV_O_RDWR) { ++ flags |= BDRV_O_ALLOW_RDWR; ++ } ++ ++ bs->keep_read_only = !(flags & BDRV_O_ALLOW_RDWR); ++ + /* Open the image */ + ret = bdrv_open_common(bs, filename, flags, drv); + if (ret < 0) { +@@ -837,12 +843,6 @@ int bdrv_open(BlockDriverState *bs, const char *filename, int flags, + bdrv_close(bs); + return ret; + } +- if (bs->is_temporary) { +- bs->backing_hd->keep_read_only = !(flags & BDRV_O_RDWR); +- } else { +- /* base image inherits from "parent" */ +- bs->backing_hd->keep_read_only = bs->keep_read_only; +- } + } + + if (!bdrv_key_required(bs)) { +diff --git a/block.h b/block.h +index 2e2be11..4d919c2 100644 +--- a/block.h ++++ b/block.h +@@ -80,6 +80,7 @@ typedef struct BlockDevOps { + #define BDRV_O_COPY_ON_READ 0x0400 /* copy read backing sectors into image */ + #define BDRV_O_INCOMING 0x0800 /* consistency hint for incoming migration */ + #define BDRV_O_CHECK 0x1000 /* open solely for consistency check */ ++#define BDRV_O_ALLOW_RDWR 0x2000 /* allow reopen to change from r/o to r/w */ + + #define BDRV_O_CACHE_MASK (BDRV_O_NOCACHE | BDRV_O_CACHE_WB | BDRV_O_NO_FLUSH) + +-- +1.7.12.1 + diff --git a/0231-configure-Allow-builds-without-any-system-or-user-em.patch b/0231-configure-Allow-builds-without-any-system-or-user-em.patch new file mode 100644 index 0000000..d40c6dc --- /dev/null +++ b/0231-configure-Allow-builds-without-any-system-or-user-em.patch @@ -0,0 +1,59 @@ +From 20936a5a29113b32aeb319ca5ebe2a754cd3e014 Mon Sep 17 00:00:00 2001 +From: Stefan Weil +Date: Fri, 14 Sep 2012 19:02:30 +0200 +Subject: [PATCH] configure: Allow builds without any system or user emulation + +The old code aborted configure when no emulation target was selected. +Even after removing the 'exit 1', it tried to read from STDIN +when QEMU was configured with + + configure' '--disable-user' '--disable-system' + +This is fixed here. + +Signed-off-by: Stefan Weil +Signed-off-by: Anthony Liguori +(cherry picked from commit 8bdd3d499fe0ddffa9901c56ab3bc8911d5b8be0) + +Signed-off-by: Michael Roth +--- + Makefile | 5 +++++ + configure | 4 ---- + 2 files changed, 5 insertions(+), 4 deletions(-) + +diff --git a/Makefile b/Makefile +index 1cd5bc8..dd11e3c 100644 +--- a/Makefile ++++ b/Makefile +@@ -52,8 +52,13 @@ SUBDIR_MAKEFLAGS=$(if $(V),,--no-print-directory) BUILD_DIR=$(BUILD_DIR) + SUBDIR_DEVICES_MAK=$(patsubst %, %/config-devices.mak, $(TARGET_DIRS)) + SUBDIR_DEVICES_MAK_DEP=$(patsubst %, %/config-devices.mak.d, $(TARGET_DIRS)) + ++ifeq ($(SUBDIR_DEVICES_MAK),) ++config-all-devices.mak: ++ $(call quiet-command,echo '# no devices' > $@," GEN $@") ++else + config-all-devices.mak: $(SUBDIR_DEVICES_MAK) + $(call quiet-command,cat $(SUBDIR_DEVICES_MAK) | grep =y | sort -u > $@," GEN $@") ++endif + + -include $(SUBDIR_DEVICES_MAK_DEP) + +diff --git a/configure b/configure +index a1f256c..f528146 100755 +--- a/configure ++++ b/configure +@@ -1296,10 +1296,6 @@ if test -z "$target_list" ; then + else + target_list=`echo "$target_list" | sed -e 's/,/ /g'` + fi +-if test -z "$target_list" ; then +- echo "No targets enabled" +- exit 1 +-fi + # see if system emulation was really requested + case " $target_list " in + *"-softmmu "*) softmmu=yes +-- +1.7.12.1 + diff --git a/0232-Refactor-inet_connect_opts-function.patch b/0232-Refactor-inet_connect_opts-function.patch new file mode 100644 index 0000000..bd8702f --- /dev/null +++ b/0232-Refactor-inet_connect_opts-function.patch @@ -0,0 +1,207 @@ +From 2f56ee52ed70bed32de06ba1c9ef22e4d4d504f0 Mon Sep 17 00:00:00 2001 +From: "Michael S. Tsirkin" +Date: Mon, 24 Sep 2012 13:11:07 +0200 +Subject: [PATCH] Refactor inet_connect_opts function + +refactor address resolution code to fix nonblocking connect +remove getnameinfo call + +Signed-off-by: Michael S. Tsirkin +Signed-off-by: Amos Kong +Signed-off-by: Orit Wasserman +Signed-off-by: Anthony Liguori +(cherry picked from commit 05bc1d8a4b2f77df8cc9880a552047e30c16f1f8) + +Signed-off-by: Michael Roth +--- + qemu-sockets.c | 148 +++++++++++++++++++++++++++++++++------------------------ + 1 file changed, 85 insertions(+), 63 deletions(-) + +diff --git a/qemu-sockets.c b/qemu-sockets.c +index 037775b..22797bf 100644 +--- a/qemu-sockets.c ++++ b/qemu-sockets.c +@@ -209,95 +209,117 @@ listen: + return slisten; + } + +-int inet_connect_opts(QemuOpts *opts, bool *in_progress, Error **errp) ++#ifdef _WIN32 ++#define QEMU_SOCKET_RC_INPROGRESS(rc) \ ++ ((rc) == -EINPROGRESS || (rc) == -EWOULDBLOCK || (rc) == -WSAEALREADY) ++#else ++#define QEMU_SOCKET_RC_INPROGRESS(rc) \ ++ ((rc) == -EINPROGRESS) ++#endif ++ ++static int inet_connect_addr(struct addrinfo *addr, bool block, ++ bool *in_progress) + { +- struct addrinfo ai,*res,*e; ++ int sock, rc; ++ ++ if (in_progress) { ++ *in_progress = false; ++ } ++ ++ sock = qemu_socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol); ++ if (sock < 0) { ++ fprintf(stderr, "%s: socket(%s): %s\n", __func__, ++ inet_strfamily(addr->ai_family), strerror(errno)); ++ return -1; ++ } ++ setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)); ++ if (!block) { ++ socket_set_nonblock(sock); ++ } ++ /* connect to peer */ ++ do { ++ rc = 0; ++ if (connect(sock, addr->ai_addr, addr->ai_addrlen) < 0) { ++ rc = -socket_error(); ++ } ++ } while (rc == -EINTR); ++ ++ if (!block && QEMU_SOCKET_RC_INPROGRESS(rc)) { ++ if (in_progress) { ++ *in_progress = true; ++ } ++ } else if (rc < 0) { ++ closesocket(sock); ++ return -1; ++ } ++ return sock; ++} ++ ++static struct addrinfo *inet_parse_connect_opts(QemuOpts *opts, Error **errp) ++{ ++ struct addrinfo ai, *res; ++ int rc; + const char *addr; + const char *port; +- char uaddr[INET6_ADDRSTRLEN+1]; +- char uport[33]; +- int sock,rc; +- bool block; + +- memset(&ai,0, sizeof(ai)); ++ memset(&ai, 0, sizeof(ai)); + ai.ai_flags = AI_CANONNAME | AI_ADDRCONFIG; + ai.ai_family = PF_UNSPEC; + ai.ai_socktype = SOCK_STREAM; + +- if (in_progress) { +- *in_progress = false; +- } +- + addr = qemu_opt_get(opts, "host"); + port = qemu_opt_get(opts, "port"); +- block = qemu_opt_get_bool(opts, "block", 0); + if (addr == NULL || port == NULL) { +- fprintf(stderr, "inet_connect: host and/or port not specified\n"); ++ fprintf(stderr, ++ "inet_parse_connect_opts: host and/or port not specified\n"); + error_set(errp, QERR_SOCKET_CREATE_FAILED); +- return -1; ++ return NULL; + } + +- if (qemu_opt_get_bool(opts, "ipv4", 0)) ++ if (qemu_opt_get_bool(opts, "ipv4", 0)) { + ai.ai_family = PF_INET; +- if (qemu_opt_get_bool(opts, "ipv6", 0)) ++ } ++ if (qemu_opt_get_bool(opts, "ipv6", 0)) { + ai.ai_family = PF_INET6; ++ } + + /* lookup */ +- if (0 != (rc = getaddrinfo(addr, port, &ai, &res))) { +- fprintf(stderr,"getaddrinfo(%s,%s): %s\n", addr, port, ++ rc = getaddrinfo(addr, port, &ai, &res); ++ if (rc != 0) { ++ fprintf(stderr, "getaddrinfo(%s,%s): %s\n", addr, port, + gai_strerror(rc)); + error_set(errp, QERR_SOCKET_CREATE_FAILED); +- return -1; ++ return NULL; ++ } ++ return res; ++} ++ ++int inet_connect_opts(QemuOpts *opts, bool *in_progress, Error **errp) ++{ ++ struct addrinfo *res, *e; ++ int sock = -1; ++ bool block = qemu_opt_get_bool(opts, "block", 0); ++ ++ res = inet_parse_connect_opts(opts, errp); ++ if (!res) { ++ return -1; ++ } ++ ++ if (in_progress) { ++ *in_progress = false; + } + + for (e = res; e != NULL; e = e->ai_next) { +- if (getnameinfo((struct sockaddr*)e->ai_addr,e->ai_addrlen, +- uaddr,INET6_ADDRSTRLEN,uport,32, +- NI_NUMERICHOST | NI_NUMERICSERV) != 0) { +- fprintf(stderr,"%s: getnameinfo: oops\n", __FUNCTION__); +- continue; +- } +- sock = qemu_socket(e->ai_family, e->ai_socktype, e->ai_protocol); +- if (sock < 0) { +- fprintf(stderr,"%s: socket(%s): %s\n", __FUNCTION__, +- inet_strfamily(e->ai_family), strerror(errno)); +- continue; +- } +- setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,(void*)&on,sizeof(on)); +- if (!block) { +- socket_set_nonblock(sock); +- } +- /* connect to peer */ +- do { +- rc = 0; +- if (connect(sock, e->ai_addr, e->ai_addrlen) < 0) { +- rc = -socket_error(); +- } +- } while (rc == -EINTR); +- +- #ifdef _WIN32 +- if (!block && (rc == -EINPROGRESS || rc == -EWOULDBLOCK +- || rc == -WSAEALREADY)) { +- #else +- if (!block && (rc == -EINPROGRESS)) { +- #endif +- if (in_progress) { +- *in_progress = true; +- } +- } else if (rc < 0) { +- if (NULL == e->ai_next) +- fprintf(stderr, "%s: connect(%s,%s,%s,%s): %s\n", __FUNCTION__, +- inet_strfamily(e->ai_family), +- e->ai_canonname, uaddr, uport, strerror(errno)); +- closesocket(sock); +- continue; ++ sock = inet_connect_addr(e, block, in_progress); ++ if (sock >= 0) { ++ break; + } +- freeaddrinfo(res); +- return sock; + } +- error_set(errp, QERR_SOCKET_CONNECT_FAILED); ++ if (sock < 0) { ++ error_set(errp, QERR_SOCKET_CONNECT_FAILED); ++ } + freeaddrinfo(res); +- return -1; ++ return sock; + } + + int inet_dgram_opts(QemuOpts *opts) +-- +1.7.12.1 + diff --git a/0233-Separate-inet_connect-into-inet_connect-blocking-and.patch b/0233-Separate-inet_connect-into-inet_connect-blocking-and.patch new file mode 100644 index 0000000..e017ef0 --- /dev/null +++ b/0233-Separate-inet_connect-into-inet_connect-blocking-and.patch @@ -0,0 +1,188 @@ +From 36f7af3f8bfd2c16f2e6c4b61d9564d5cfdd2394 Mon Sep 17 00:00:00 2001 +From: Orit Wasserman +Date: Mon, 24 Sep 2012 13:11:08 +0200 +Subject: [PATCH] Separate inet_connect into inet_connect (blocking) and + inet_nonblocking_connect + +No need to add non blocking parameters to the blocking inet_connect +add block parameter for inet_connect_opts instead of using QemuOpt "block". + +Signed-off-by: Orit Wasserman +Signed-off-by: Anthony Liguori +(cherry picked from commit 5db5f44cb4b7f24b9e0efdefc9015e36b7c34881) + +Signed-off-by: Michael Roth +--- + migration-tcp.c | 2 +- + nbd.c | 2 +- + qemu-char.c | 2 +- + qemu-sockets.c | 58 +++++++++++++++++++++++++++++++++++++++++++++++---------- + qemu_socket.h | 7 +++++-- + ui/vnc.c | 2 +- + 6 files changed, 57 insertions(+), 16 deletions(-) + +diff --git a/migration-tcp.c b/migration-tcp.c +index ac891c3..7f6ad98 100644 +--- a/migration-tcp.c ++++ b/migration-tcp.c +@@ -88,7 +88,7 @@ int tcp_start_outgoing_migration(MigrationState *s, const char *host_port, + s->write = socket_write; + s->close = tcp_close; + +- s->fd = inet_connect(host_port, false, &in_progress, errp); ++ s->fd = inet_nonblocking_connect(host_port, &in_progress, errp); + if (error_is_set(errp)) { + migrate_fd_error(s); + return -1; +diff --git a/nbd.c b/nbd.c +index 0dd60c5..206f75c 100644 +--- a/nbd.c ++++ b/nbd.c +@@ -162,7 +162,7 @@ int tcp_socket_outgoing(const char *address, uint16_t port) + + int tcp_socket_outgoing_spec(const char *address_and_port) + { +- return inet_connect(address_and_port, true, NULL, NULL); ++ return inet_connect(address_and_port, NULL); + } + + int tcp_socket_incoming(const char *address, uint16_t port) +diff --git a/qemu-char.c b/qemu-char.c +index 7f0f895..13b87b5 100644 +--- a/qemu-char.c ++++ b/qemu-char.c +@@ -2456,7 +2456,7 @@ static CharDriverState *qemu_chr_open_socket(QemuOpts *opts) + if (is_listen) { + fd = inet_listen_opts(opts, 0, NULL); + } else { +- fd = inet_connect_opts(opts, NULL, NULL); ++ fd = inet_connect_opts(opts, true, NULL, NULL); + } + } + if (fd < 0) { +diff --git a/qemu-sockets.c b/qemu-sockets.c +index 22797bf..0883a66 100644 +--- a/qemu-sockets.c ++++ b/qemu-sockets.c +@@ -54,9 +54,6 @@ static QemuOptsList dummy_opts = { + },{ + .name = "ipv6", + .type = QEMU_OPT_BOOL, +- },{ +- .name = "block", +- .type = QEMU_OPT_BOOL, + }, + { /* end if list */ } + }, +@@ -294,11 +291,22 @@ static struct addrinfo *inet_parse_connect_opts(QemuOpts *opts, Error **errp) + return res; + } + +-int inet_connect_opts(QemuOpts *opts, bool *in_progress, Error **errp) ++/** ++ * Create a socket and connect it to an address. ++ * ++ * @opts: QEMU options, recognized parameters strings "host" and "port", ++ * bools "ipv4" and "ipv6". ++ * @block: set true for blocking socket ++ * @in_progress: set to true in case of ongoing connect ++ * @errp: set on error ++ * ++ * Returns: -1 on error, file descriptor on success. ++ */ ++int inet_connect_opts(QemuOpts *opts, bool block, bool *in_progress, ++ Error **errp) + { + struct addrinfo *res, *e; + int sock = -1; +- bool block = qemu_opt_get_bool(opts, "block", 0); + + res = inet_parse_connect_opts(opts, errp); + if (!res) { +@@ -515,17 +523,47 @@ int inet_listen(const char *str, char *ostr, int olen, + return sock; + } + +-int inet_connect(const char *str, bool block, bool *in_progress, Error **errp) ++/** ++ * Create a blocking socket and connect it to an address. ++ * ++ * @str: address string ++ * @errp: set in case of an error ++ * ++ * Returns -1 in case of error, file descriptor on success ++ **/ ++int inet_connect(const char *str, Error **errp) + { + QemuOpts *opts; + int sock = -1; + + opts = qemu_opts_create(&dummy_opts, NULL, 0, NULL); + if (inet_parse(opts, str) == 0) { +- if (block) { +- qemu_opt_set(opts, "block", "on"); +- } +- sock = inet_connect_opts(opts, in_progress, errp); ++ sock = inet_connect_opts(opts, true, NULL, errp); ++ } else { ++ error_set(errp, QERR_SOCKET_CREATE_FAILED); ++ } ++ qemu_opts_del(opts); ++ return sock; ++} ++ ++/** ++ * Create a non-blocking socket and connect it to an address. ++ * ++ * @str: address string ++ * @in_progress: set to true in case of ongoing connect ++ * @errp: set in case of an error ++ * ++ * Returns: -1 on error, file descriptor on success. ++ **/ ++int inet_nonblocking_connect(const char *str, bool *in_progress, ++ Error **errp) ++{ ++ QemuOpts *opts; ++ int sock = -1; ++ ++ opts = qemu_opts_create(&dummy_opts, NULL, 0, NULL); ++ if (inet_parse(opts, str) == 0) { ++ sock = inet_connect_opts(opts, false, in_progress, errp); + } else { + error_set(errp, QERR_SOCKET_CREATE_FAILED); + } +diff --git a/qemu_socket.h b/qemu_socket.h +index 30ae6af..80696aa 100644 +--- a/qemu_socket.h ++++ b/qemu_socket.h +@@ -42,8 +42,11 @@ int send_all(int fd, const void *buf, int len1); + int inet_listen_opts(QemuOpts *opts, int port_offset, Error **errp); + int inet_listen(const char *str, char *ostr, int olen, + int socktype, int port_offset, Error **errp); +-int inet_connect_opts(QemuOpts *opts, bool *in_progress, Error **errp); +-int inet_connect(const char *str, bool block, bool *in_progress, Error **errp); ++int inet_connect_opts(QemuOpts *opts, bool block, bool *in_progress, ++ Error **errp); ++int inet_connect(const char *str, Error **errp); ++int inet_nonblocking_connect(const char *str, bool *in_progress, ++ Error **errp); + int inet_dgram_opts(QemuOpts *opts); + const char *inet_strfamily(int family); + +diff --git a/ui/vnc.c b/ui/vnc.c +index 385e345..01b2daf 100644 +--- a/ui/vnc.c ++++ b/ui/vnc.c +@@ -3061,7 +3061,7 @@ int vnc_display_open(DisplayState *ds, const char *display) + if (strncmp(display, "unix:", 5) == 0) + vs->lsock = unix_connect(display+5); + else +- vs->lsock = inet_connect(display, true, NULL, NULL); ++ vs->lsock = inet_connect(display, NULL); + if (-1 == vs->lsock) { + g_free(vs->display); + vs->display = NULL; +-- +1.7.12.1 + diff --git a/0234-Fix-address-handling-in-inet_nonblocking_connect.patch b/0234-Fix-address-handling-in-inet_nonblocking_connect.patch new file mode 100644 index 0000000..9e64c16 --- /dev/null +++ b/0234-Fix-address-handling-in-inet_nonblocking_connect.patch @@ -0,0 +1,369 @@ +From b3db72271ead92daae43b1534fdfdbe750555b0a Mon Sep 17 00:00:00 2001 +From: Orit Wasserman +Date: Mon, 24 Sep 2012 13:11:09 +0200 +Subject: [PATCH] Fix address handling in inet_nonblocking_connect + +getaddrinfo can give us a list of addresses, but we only try to +connect to the first one. If that fails we never proceed to +the next one. This is common on desktop setups that often have ipv6 +configured but not actually working. + +To fix this make inet_connect_nonblocking retry connection with a different +address. +callers on inet_nonblocking_connect register a callback function that will +be called when connect opertion completes, in case of failure the fd will have +a negative value + +Signed-off-by: Orit Wasserman +Signed-off-by: Michael S. Tsirkin +Signed-off-by: Anthony Liguori +(cherry picked from commit 233aa5c2d1cf4655ffe335025a68cf5454f87dad) + +Signed-off-by: Michael Roth +--- + migration-tcp.c | 37 ++++------------ + qemu-char.c | 2 +- + qemu-sockets.c | 129 +++++++++++++++++++++++++++++++++++++++++++++----------- + qemu_socket.h | 16 ++++--- + 4 files changed, 126 insertions(+), 58 deletions(-) + +diff --git a/migration-tcp.c b/migration-tcp.c +index 7f6ad98..a15c2b8 100644 +--- a/migration-tcp.c ++++ b/migration-tcp.c +@@ -53,54 +53,35 @@ static int tcp_close(MigrationState *s) + return r; + } + +-static void tcp_wait_for_connect(void *opaque) ++static void tcp_wait_for_connect(int fd, void *opaque) + { + MigrationState *s = opaque; +- int val, ret; +- socklen_t valsize = sizeof(val); + +- DPRINTF("connect completed\n"); +- do { +- ret = getsockopt(s->fd, SOL_SOCKET, SO_ERROR, (void *) &val, &valsize); +- } while (ret == -1 && (socket_error()) == EINTR); +- +- if (ret < 0) { ++ if (fd < 0) { ++ DPRINTF("migrate connect error\n"); ++ s->fd = -1; + migrate_fd_error(s); +- return; +- } +- +- qemu_set_fd_handler2(s->fd, NULL, NULL, NULL, NULL); +- +- if (val == 0) ++ } else { ++ DPRINTF("migrate connect success\n"); ++ s->fd = fd; + migrate_fd_connect(s); +- else { +- DPRINTF("error connecting %d\n", val); +- migrate_fd_error(s); + } + } + + int tcp_start_outgoing_migration(MigrationState *s, const char *host_port, + Error **errp) + { +- bool in_progress; +- + s->get_error = socket_errno; + s->write = socket_write; + s->close = tcp_close; + +- s->fd = inet_nonblocking_connect(host_port, &in_progress, errp); ++ s->fd = inet_nonblocking_connect(host_port, tcp_wait_for_connect, s, ++ errp); + if (error_is_set(errp)) { + migrate_fd_error(s); + return -1; + } + +- if (in_progress) { +- DPRINTF("connect in progress\n"); +- qemu_set_fd_handler2(s->fd, NULL, NULL, tcp_wait_for_connect, s); +- } else { +- migrate_fd_connect(s); +- } +- + return 0; + } + +diff --git a/qemu-char.c b/qemu-char.c +index 13b87b5..b082bae 100644 +--- a/qemu-char.c ++++ b/qemu-char.c +@@ -2456,7 +2456,7 @@ static CharDriverState *qemu_chr_open_socket(QemuOpts *opts) + if (is_listen) { + fd = inet_listen_opts(opts, 0, NULL); + } else { +- fd = inet_connect_opts(opts, true, NULL, NULL); ++ fd = inet_connect_opts(opts, NULL, NULL, NULL); + } + } + if (fd < 0) { +diff --git a/qemu-sockets.c b/qemu-sockets.c +index 0883a66..1f14e8b 100644 +--- a/qemu-sockets.c ++++ b/qemu-sockets.c +@@ -24,6 +24,7 @@ + + #include "qemu_socket.h" + #include "qemu-common.h" /* for qemu_isdigit */ ++#include "main-loop.h" + + #ifndef AI_ADDRCONFIG + # define AI_ADDRCONFIG 0 +@@ -214,14 +215,66 @@ listen: + ((rc) == -EINPROGRESS) + #endif + +-static int inet_connect_addr(struct addrinfo *addr, bool block, +- bool *in_progress) ++/* Struct to store connect state for non blocking connect */ ++typedef struct ConnectState { ++ int fd; ++ struct addrinfo *addr_list; ++ struct addrinfo *current_addr; ++ NonBlockingConnectHandler *callback; ++ void *opaque; ++} ConnectState; ++ ++static int inet_connect_addr(struct addrinfo *addr, bool *in_progress, ++ ConnectState *connect_state); ++ ++static void wait_for_connect(void *opaque) + { +- int sock, rc; ++ ConnectState *s = opaque; ++ int val = 0, rc = 0; ++ socklen_t valsize = sizeof(val); ++ bool in_progress; ++ ++ qemu_set_fd_handler2(s->fd, NULL, NULL, NULL, NULL); ++ ++ do { ++ rc = getsockopt(s->fd, SOL_SOCKET, SO_ERROR, (void *) &val, &valsize); ++ } while (rc == -1 && socket_error() == EINTR); ++ ++ /* update rc to contain error */ ++ if (!rc && val) { ++ rc = -1; ++ } ++ ++ /* connect error */ ++ if (rc < 0) { ++ closesocket(s->fd); ++ s->fd = rc; ++ } ++ ++ /* try to connect to the next address on the list */ ++ while (s->current_addr->ai_next != NULL && s->fd < 0) { ++ s->current_addr = s->current_addr->ai_next; ++ s->fd = inet_connect_addr(s->current_addr, &in_progress, s); ++ /* connect in progress */ ++ if (in_progress) { ++ return; ++ } ++ } + +- if (in_progress) { +- *in_progress = false; ++ freeaddrinfo(s->addr_list); ++ if (s->callback) { ++ s->callback(s->fd, s->opaque); + } ++ g_free(s); ++ return; ++} ++ ++static int inet_connect_addr(struct addrinfo *addr, bool *in_progress, ++ ConnectState *connect_state) ++{ ++ int sock, rc; ++ ++ *in_progress = false; + + sock = qemu_socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol); + if (sock < 0) { +@@ -230,7 +283,7 @@ static int inet_connect_addr(struct addrinfo *addr, bool block, + return -1; + } + setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)); +- if (!block) { ++ if (connect_state != NULL) { + socket_set_nonblock(sock); + } + /* connect to peer */ +@@ -241,10 +294,11 @@ static int inet_connect_addr(struct addrinfo *addr, bool block, + } + } while (rc == -EINTR); + +- if (!block && QEMU_SOCKET_RC_INPROGRESS(rc)) { +- if (in_progress) { +- *in_progress = true; +- } ++ if (connect_state != NULL && QEMU_SOCKET_RC_INPROGRESS(rc)) { ++ connect_state->fd = sock; ++ qemu_set_fd_handler2(sock, NULL, NULL, wait_for_connect, ++ connect_state); ++ *in_progress = true; + } else if (rc < 0) { + closesocket(sock); + return -1; +@@ -260,6 +314,7 @@ static struct addrinfo *inet_parse_connect_opts(QemuOpts *opts, Error **errp) + const char *port; + + memset(&ai, 0, sizeof(ai)); ++ + ai.ai_flags = AI_CANONNAME | AI_ADDRCONFIG; + ai.ai_family = PF_UNSPEC; + ai.ai_socktype = SOCK_STREAM; +@@ -296,36 +351,55 @@ static struct addrinfo *inet_parse_connect_opts(QemuOpts *opts, Error **errp) + * + * @opts: QEMU options, recognized parameters strings "host" and "port", + * bools "ipv4" and "ipv6". +- * @block: set true for blocking socket +- * @in_progress: set to true in case of ongoing connect + * @errp: set on error ++ * @callback: callback function for non-blocking connect ++ * @opaque: opaque for callback function + * + * Returns: -1 on error, file descriptor on success. ++ * ++ * If @callback is non-null, the connect is non-blocking. If this ++ * function succeeds, callback will be called when the connection ++ * completes, with the file descriptor on success, or -1 on error. + */ +-int inet_connect_opts(QemuOpts *opts, bool block, bool *in_progress, +- Error **errp) ++int inet_connect_opts(QemuOpts *opts, Error **errp, ++ NonBlockingConnectHandler *callback, void *opaque) + { + struct addrinfo *res, *e; + int sock = -1; ++ bool in_progress; ++ ConnectState *connect_state = NULL; + + res = inet_parse_connect_opts(opts, errp); + if (!res) { + return -1; + } + +- if (in_progress) { +- *in_progress = false; ++ if (callback != NULL) { ++ connect_state = g_malloc0(sizeof(*connect_state)); ++ connect_state->addr_list = res; ++ connect_state->callback = callback; ++ connect_state->opaque = opaque; + } + + for (e = res; e != NULL; e = e->ai_next) { +- sock = inet_connect_addr(e, block, in_progress); +- if (sock >= 0) { ++ if (connect_state != NULL) { ++ connect_state->current_addr = e; ++ } ++ sock = inet_connect_addr(e, &in_progress, connect_state); ++ if (in_progress) { ++ return sock; ++ } else if (sock >= 0) { ++ /* non blocking socket immediate success, call callback */ ++ if (callback != NULL) { ++ callback(sock, opaque); ++ } + break; + } + } + if (sock < 0) { + error_set(errp, QERR_SOCKET_CONNECT_FAILED); + } ++ g_free(connect_state); + freeaddrinfo(res); + return sock; + } +@@ -538,7 +612,7 @@ int inet_connect(const char *str, Error **errp) + + opts = qemu_opts_create(&dummy_opts, NULL, 0, NULL); + if (inet_parse(opts, str) == 0) { +- sock = inet_connect_opts(opts, true, NULL, errp); ++ sock = inet_connect_opts(opts, errp, NULL, NULL); + } else { + error_set(errp, QERR_SOCKET_CREATE_FAILED); + } +@@ -548,22 +622,29 @@ int inet_connect(const char *str, Error **errp) + + /** + * Create a non-blocking socket and connect it to an address. ++ * Calls the callback function with fd in case of success or -1 in case of ++ * error. + * + * @str: address string +- * @in_progress: set to true in case of ongoing connect ++ * @callback: callback function that is called when connect completes, ++ * cannot be NULL. ++ * @opaque: opaque for callback function + * @errp: set in case of an error + * +- * Returns: -1 on error, file descriptor on success. ++ * Returns: -1 on immediate error, file descriptor on success. + **/ +-int inet_nonblocking_connect(const char *str, bool *in_progress, +- Error **errp) ++int inet_nonblocking_connect(const char *str, ++ NonBlockingConnectHandler *callback, ++ void *opaque, Error **errp) + { + QemuOpts *opts; + int sock = -1; + ++ g_assert(callback != NULL); ++ + opts = qemu_opts_create(&dummy_opts, NULL, 0, NULL); + if (inet_parse(opts, str) == 0) { +- sock = inet_connect_opts(opts, false, in_progress, errp); ++ sock = inet_connect_opts(opts, errp, callback, opaque); + } else { + error_set(errp, QERR_SOCKET_CREATE_FAILED); + } +diff --git a/qemu_socket.h b/qemu_socket.h +index 80696aa..3e8aee9 100644 +--- a/qemu_socket.h ++++ b/qemu_socket.h +@@ -38,15 +38,21 @@ void socket_set_block(int fd); + void socket_set_nonblock(int fd); + int send_all(int fd, const void *buf, int len1); + +-/* New, ipv6-ready socket helper functions, see qemu-sockets.c */ ++/* callback function for nonblocking connect ++ * valid fd on success, negative error code on failure ++ */ ++typedef void NonBlockingConnectHandler(int fd, void *opaque); ++ + int inet_listen_opts(QemuOpts *opts, int port_offset, Error **errp); + int inet_listen(const char *str, char *ostr, int olen, + int socktype, int port_offset, Error **errp); +-int inet_connect_opts(QemuOpts *opts, bool block, bool *in_progress, +- Error **errp); ++int inet_connect_opts(QemuOpts *opts, Error **errp, ++ NonBlockingConnectHandler *callback, void *opaque); + int inet_connect(const char *str, Error **errp); +-int inet_nonblocking_connect(const char *str, bool *in_progress, +- Error **errp); ++int inet_nonblocking_connect(const char *str, ++ NonBlockingConnectHandler *callback, ++ void *opaque, Error **errp); ++ + int inet_dgram_opts(QemuOpts *opts); + const char *inet_strfamily(int family); + +-- +1.7.12.1 + diff --git a/0235-Clear-handler-only-for-valid-fd.patch b/0235-Clear-handler-only-for-valid-fd.patch new file mode 100644 index 0000000..3ddcd80 --- /dev/null +++ b/0235-Clear-handler-only-for-valid-fd.patch @@ -0,0 +1,32 @@ +From b7b94b6016b89bf698d661ce4fd22139e771a835 Mon Sep 17 00:00:00 2001 +From: Orit Wasserman +Date: Mon, 24 Sep 2012 13:11:10 +0200 +Subject: [PATCH] Clear handler only for valid fd + +Signed-off-by: Orit Wasserman +Signed-off-by: Anthony Liguori +(cherry picked from commit 3202becaa2b805497ce9e6faa6edfb83665f91b1) + +Signed-off-by: Michael Roth +--- + migration.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/migration.c b/migration.c +index 1edeec5..22a05c4 100644 +--- a/migration.c ++++ b/migration.c +@@ -240,7 +240,9 @@ static int migrate_fd_cleanup(MigrationState *s) + { + int ret = 0; + +- qemu_set_fd_handler2(s->fd, NULL, NULL, NULL, NULL); ++ if (s->fd != -1) { ++ qemu_set_fd_handler2(s->fd, NULL, NULL, NULL, NULL); ++ } + + if (s->file) { + DPRINTF("closing file\n"); +-- +1.7.12.1 + diff --git a/0236-pl190-fix-read-of-VECTADDR.patch b/0236-pl190-fix-read-of-VECTADDR.patch new file mode 100644 index 0000000..c306cb5 --- /dev/null +++ b/0236-pl190-fix-read-of-VECTADDR.patch @@ -0,0 +1,51 @@ +From 12d4393d0830a2a63828d302f177a9b8e31f433a Mon Sep 17 00:00:00 2001 +From: Brendan Fennell +Date: Wed, 26 Sep 2012 16:46:28 +0100 +Subject: [PATCH] pl190: fix read of VECTADDR + +Reading VECTADDR was causing us to set the current priority to +the wrong value, the most obvious effect of which was that we +would return the vector for the wrong interrupt as the result +of the read. + +Signed-off-by: Brendan Fennell +Signed-off-by: Peter Maydell +(cherry picked from commit 14c126baf1c38607c5bd988878de85a06cefd8cf) + +Signed-off-by: Michael Roth +--- + hw/pl190.c | 18 ++++++++++++------ + 1 file changed, 12 insertions(+), 6 deletions(-) + +diff --git a/hw/pl190.c b/hw/pl190.c +index cb50afb..7332f4d 100644 +--- a/hw/pl190.c ++++ b/hw/pl190.c +@@ -117,12 +117,18 @@ static uint64_t pl190_read(void *opaque, target_phys_addr_t offset, + return s->protected; + case 12: /* VECTADDR */ + /* Read vector address at the start of an ISR. Increases the +- current priority level to that of the current interrupt. */ +- for (i = 0; i < s->priority; i++) +- { +- if ((s->level | s->soft_level) & s->prio_mask[i]) +- break; +- } ++ * current priority level to that of the current interrupt. ++ * ++ * Since an enabled interrupt X at priority P causes prio_mask[Y] ++ * to have bit X set for all Y > P, this loop will stop with ++ * i == the priority of the highest priority set interrupt. ++ */ ++ for (i = 0; i < s->priority; i++) { ++ if ((s->level | s->soft_level) & s->prio_mask[i + 1]) { ++ break; ++ } ++ } ++ + /* Reading this value with no pending interrupts is undefined. + We return the default address. */ + if (i == PL190_NUM_PRIO) +-- +1.7.12.1 + diff --git a/0237-hw-armv7m_nvic-Correctly-register-GIC-region-when-se.patch b/0237-hw-armv7m_nvic-Correctly-register-GIC-region-when-se.patch new file mode 100644 index 0000000..2f3f36d --- /dev/null +++ b/0237-hw-armv7m_nvic-Correctly-register-GIC-region-when-se.patch @@ -0,0 +1,40 @@ +From f4a5b8185d067430cd605a740af654cd1cd2e2aa Mon Sep 17 00:00:00 2001 +From: Meador Inge +Date: Wed, 26 Sep 2012 16:46:28 +0100 +Subject: [PATCH] hw/armv7m_nvic: Correctly register GIC region when setting + up NVIC + +When setting up the NVIC memory regions the memory range +0x100..0xcff is aliased to an IO memory region that belongs +to the ARM GIC. This aliased region should be added to the +NVIC memory container, but the actual GIC IO memory region +was being added instead. This mixup was causing the wrong +IO memory access functions to be called when accessing parts +of the NVIC memory. + +Signed-off-by: Meador Inge +Signed-off-by: Peter Maydell +(cherry picked from commit 9892cae39562d2e6c00ccc5966302c00f23be6d4) + +Signed-off-by: Michael Roth +--- + hw/armv7m_nvic.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/hw/armv7m_nvic.c b/hw/armv7m_nvic.c +index 6a0832e..5c09116 100644 +--- a/hw/armv7m_nvic.c ++++ b/hw/armv7m_nvic.c +@@ -489,7 +489,8 @@ static int armv7m_nvic_init(SysBusDevice *dev) + */ + memory_region_init_alias(&s->gic_iomem_alias, "nvic-gic", &s->gic.iomem, + 0x100, 0xc00); +- memory_region_add_subregion_overlap(&s->container, 0x100, &s->gic.iomem, 1); ++ memory_region_add_subregion_overlap(&s->container, 0x100, ++ &s->gic_iomem_alias, 1); + /* Map the whole thing into system memory at the location required + * by the v7M architecture. + */ +-- +1.7.12.1 + diff --git a/0238-Versatile-Express-Fix-NOR-flash-0-address-and-remove.patch b/0238-Versatile-Express-Fix-NOR-flash-0-address-and-remove.patch new file mode 100644 index 0000000..4fd2f11 --- /dev/null +++ b/0238-Versatile-Express-Fix-NOR-flash-0-address-and-remove.patch @@ -0,0 +1,56 @@ +From cb97f34eca351d150574c724047709b76d00d08a Mon Sep 17 00:00:00 2001 +From: Francesco Lavra +Date: Wed, 19 Sep 2012 05:51:58 +0000 +Subject: [PATCH] Versatile Express: Fix NOR flash 0 address and remove flash + alias + +In the A series memory map (implemented in the Cortex A15 CoreTile), the +first NOR flash bank (flash 0) is mapped to address 0x08000000, while +address 0x00000000 can be configured as alias to either the first or the +second flash bank. This patch fixes the definition of flash 0 address, +and for simplicity removes the alias definition. + +Signed-off-by: Francesco Lavra +Signed-off-by: Peter Maydell +(cherry picked from commit 661bafb3e14bfffcb0a7c7910534c7944608ca45) + +Signed-off-by: Michael Roth +--- + hw/vexpress.c | 7 ++----- + 1 file changed, 2 insertions(+), 5 deletions(-) + +diff --git a/hw/vexpress.c b/hw/vexpress.c +index b615844..454c2bb 100644 +--- a/hw/vexpress.c ++++ b/hw/vexpress.c +@@ -62,7 +62,6 @@ enum { + VE_COMPACTFLASH, + VE_CLCD, + VE_NORFLASH0, +- VE_NORFLASH0ALIAS, + VE_NORFLASH1, + VE_SRAM, + VE_VIDEORAM, +@@ -104,9 +103,8 @@ static target_phys_addr_t motherboard_legacy_map[] = { + }; + + static target_phys_addr_t motherboard_aseries_map[] = { +- /* CS0: 0x00000000 .. 0x0c000000 */ +- [VE_NORFLASH0] = 0x00000000, +- [VE_NORFLASH0ALIAS] = 0x08000000, ++ /* CS0: 0x08000000 .. 0x0c000000 */ ++ [VE_NORFLASH0] = 0x08000000, + /* CS4: 0x0c000000 .. 0x10000000 */ + [VE_NORFLASH1] = 0x0c000000, + /* CS5: 0x10000000 .. 0x14000000 */ +@@ -413,7 +411,6 @@ static void vexpress_common_init(const VEDBoardInfo *daughterboard, + sysbus_create_simple("pl111", map[VE_CLCD], pic[14]); + + /* VE_NORFLASH0: not modelled */ +- /* VE_NORFLASH0ALIAS: not modelled */ + /* VE_NORFLASH1: not modelled */ + + sram_size = 0x2000000; +-- +1.7.12.1 + diff --git a/0239-i386-kvm-bit-10-of-CPUID-8000_0001-.EDX-is-reserved.patch b/0239-i386-kvm-bit-10-of-CPUID-8000_0001-.EDX-is-reserved.patch new file mode 100644 index 0000000..772314f --- /dev/null +++ b/0239-i386-kvm-bit-10-of-CPUID-8000_0001-.EDX-is-reserved.patch @@ -0,0 +1,36 @@ +From b82c558c781a79e6facf06e7cddf4771b8abf962 Mon Sep 17 00:00:00 2001 +From: Eduardo Habkost +Date: Thu, 6 Sep 2012 10:05:35 +0000 +Subject: [PATCH] i386: kvm: bit 10 of CPUID[8000_0001].EDX is reserved + +Bit 10 of CPUID[8000_0001].EDX is not defined as an alias of +CPUID[1].EDX[10], so do not duplicate it on +kvm_arch_get_supported_cpuid(). + +Signed-off-by: Eduardo Habkost +Reviewed-By: Igor Mammedov +Reviewed-by: Don Slutz +Signed-off-by: Blue Swirl +(cherry picked from commit b1f4679392a03f2b26a37bfa52e95d6cc4f73d82) + +Signed-off-by: Michael Roth +--- + target-i386/kvm.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/target-i386/kvm.c b/target-i386/kvm.c +index 6790180..acb9369 100644 +--- a/target-i386/kvm.c ++++ b/target-i386/kvm.c +@@ -165,7 +165,7 @@ uint32_t kvm_arch_get_supported_cpuid(KVMState *s, uint32_t function, + * so add missing bits according to the AMD spec: + */ + cpuid_1_edx = kvm_arch_get_supported_cpuid(s, 1, 0, R_EDX); +- ret |= cpuid_1_edx & 0x183f7ff; ++ ret |= cpuid_1_edx & 0x183f3ff; + break; + } + break; +-- +1.7.12.1 + diff --git a/0240-fpu-softfloat.c-Return-correctly-signed-values-from-.patch b/0240-fpu-softfloat.c-Return-correctly-signed-values-from-.patch new file mode 100644 index 0000000..37e5c3a --- /dev/null +++ b/0240-fpu-softfloat.c-Return-correctly-signed-values-from-.patch @@ -0,0 +1,44 @@ +From 41e7a1710ee9787900713a769b7d07677857260a Mon Sep 17 00:00:00 2001 +From: Peter Maydell +Date: Fri, 28 Sep 2012 16:17:03 +0100 +Subject: [PATCH] fpu/softfloat.c: Return correctly signed values from + uint64_to_float32 + +The uint64_to_float32() conversion function was incorrectly always +returning numbers with the sign bit set (ie negative numbers). Correct +this so we return positive numbers instead. + +Signed-off-by: Peter Maydell +Signed-off-by: Aurelien Jarno +(cherry picked from commit e744c06fca438dc08271e626034e632a270c91c8) + +Signed-off-by: Michael Roth +--- + fpu/softfloat.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/fpu/softfloat.c b/fpu/softfloat.c +index b29256a..91497e8 100644 +--- a/fpu/softfloat.c ++++ b/fpu/softfloat.c +@@ -1238,7 +1238,7 @@ float32 uint64_to_float32( uint64 a STATUS_PARAM ) + if ( a == 0 ) return float32_zero; + shiftCount = countLeadingZeros64( a ) - 40; + if ( 0 <= shiftCount ) { +- return packFloat32( 1 > 0, 0x95 - shiftCount, a< 0, 0x9C - shiftCount, a STATUS_VAR ); ++ return roundAndPackFloat32(0, 0x9C - shiftCount, a STATUS_VAR); + } + } + +-- +1.7.12.1 + diff --git a/0241-pseries-Don-t-test-for-MSR_PR-for-hypercalls-under-K.patch b/0241-pseries-Don-t-test-for-MSR_PR-for-hypercalls-under-K.patch new file mode 100644 index 0000000..7edb0b2 --- /dev/null +++ b/0241-pseries-Don-t-test-for-MSR_PR-for-hypercalls-under-K.patch @@ -0,0 +1,66 @@ +From 45af32e160bf339974a74bb8a38384b95aa2f555 Mon Sep 17 00:00:00 2001 +From: David Gibson +Date: Tue, 25 Sep 2012 17:12:20 +0000 +Subject: [PATCH] pseries: Don't test for MSR_PR for hypercalls under KVM + +PAPR hypercalls should only be invoked from the guest kernel, not guest +user programs, that is, with MSR[PR]=0. Currently we check this in +spapr_hypercall, returning H_PRIVILEGE if MSR[PR]=1. + +However, under KVM the state of MSR[PR] is already checked by the host +kernel before passing the hypercall to qemu, making this check redundant. +Worse, however, we don't generally synchronize KVM and qemu state on the +hypercall path, meaning that qemu could incorrectly reject a hypercall +because it has a stale MSR value. + +This patch fixes the problem by moving the privilege test exclusively to +the TCG hypercall path. + +Signed-off-by: David Gibson +CC: qemu-stable@nongnu.org +Signed-off-by: Alexander Graf +(cherry picked from commit efcb9383b974114e5f682e531346006f8f2466c0) + +Signed-off-by: Michael Roth +--- + hw/spapr.c | 7 ++++++- + hw/spapr_hcall.c | 5 ----- + 2 files changed, 6 insertions(+), 6 deletions(-) + +diff --git a/hw/spapr.c b/hw/spapr.c +index c34b767..5e55430 100644 +--- a/hw/spapr.c ++++ b/hw/spapr.c +@@ -556,7 +556,12 @@ static uint64_t translate_kernel_address(void *opaque, uint64_t addr) + + static void emulate_spapr_hypercall(CPUPPCState *env) + { +- env->gpr[3] = spapr_hypercall(env, env->gpr[3], &env->gpr[4]); ++ if (msr_pr) { ++ hcall_dprintf("Hypercall made with MSR[PR]=1\n"); ++ env->gpr[3] = H_PRIVILEGE; ++ } else { ++ env->gpr[3] = spapr_hypercall(env, env->gpr[3], &env->gpr[4]); ++ } + } + + static void spapr_reset(void *opaque) +diff --git a/hw/spapr_hcall.c b/hw/spapr_hcall.c +index abd847f..38098f7 100644 +--- a/hw/spapr_hcall.c ++++ b/hw/spapr_hcall.c +@@ -713,11 +713,6 @@ void spapr_register_hypercall(target_ulong opcode, spapr_hcall_fn fn) + target_ulong spapr_hypercall(CPUPPCState *env, target_ulong opcode, + target_ulong *args) + { +- if (msr_pr) { +- hcall_dprintf("Hypercall made with MSR[PR]=1\n"); +- return H_PRIVILEGE; +- } +- + if ((opcode <= MAX_HCALL_OPCODE) + && ((opcode & 0x3) == 0)) { + spapr_hcall_fn fn = papr_hypercall_table[opcode / 4]; +-- +1.7.12.1 + diff --git a/0242-update-VERSION-for-v1.2.1.patch b/0242-update-VERSION-for-v1.2.1.patch new file mode 100644 index 0000000..5a2045d --- /dev/null +++ b/0242-update-VERSION-for-v1.2.1.patch @@ -0,0 +1,20 @@ +From 8a0e0b51b5df80c891d264f0492697f26a790cab Mon Sep 17 00:00:00 2001 +From: Michael Roth +Date: Thu, 11 Oct 2012 21:46:55 -0500 +Subject: [PATCH] update VERSION for v1.2.1 + +Signed-off-by: Michael Roth +--- + VERSION | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/VERSION b/VERSION +index 26aaba0..6085e94 100644 +--- a/VERSION ++++ b/VERSION +@@ -1 +1 @@ +-1.2.0 ++1.2.1 +-- +1.7.12.1 + diff --git a/0301-usb-controllers-do-not-need-to-check-for-babble-them.patch b/0301-usb-controllers-do-not-need-to-check-for-babble-them.patch deleted file mode 100644 index a1cfa08..0000000 --- a/0301-usb-controllers-do-not-need-to-check-for-babble-them.patch +++ /dev/null @@ -1,56 +0,0 @@ -From d69c3f589874de55e2eae03110a0c696485b8fa7 Mon Sep 17 00:00:00 2001 -From: Hans de Goede -Date: Fri, 17 Aug 2012 11:39:16 +0200 -Subject: [PATCH 301/366] usb: controllers do not need to check for babble - themselves - -If an (emulated) usb-device tries to write more data to a packet then -its iov len, this will trigger an assert in usb_packet_copy(), and if -a driver somehow circumvents that check and writes more data to the -iov then there is space, we have a much bigger problem then not correctly -reporting babble to the guest. - -In practice babble will only happen with (real) redirected devices, and there -both the usb-host os and the qemu usb-device code already check for it. - -Signed-off-by: Hans de Goede -Signed-off-by: Gerd Hoffmann ---- - hw/usb/hcd-ehci.c | 4 ---- - hw/usb/hcd-uhci.c | 5 ----- - 2 files changed, 9 deletions(-) - -diff --git a/hw/usb/hcd-ehci.c b/hw/usb/hcd-ehci.c -index 017342b..9523247 100644 ---- a/hw/usb/hcd-ehci.c -+++ b/hw/usb/hcd-ehci.c -@@ -1481,10 +1481,6 @@ static void ehci_execute_complete(EHCIQueue *q) - assert(0); - break; - } -- } else if ((p->usb_status > p->tbytes) && (p->pid == USB_TOKEN_IN)) { -- p->usb_status = USB_RET_BABBLE; -- q->qh.token |= (QTD_TOKEN_HALT | QTD_TOKEN_BABBLE); -- ehci_raise_irq(q->ehci, USBSTS_ERRINT); - } else { - // TODO check 4.12 for splits - -diff --git a/hw/usb/hcd-uhci.c b/hw/usb/hcd-uhci.c -index b0db921..c7c8786 100644 ---- a/hw/usb/hcd-uhci.c -+++ b/hw/usb/hcd-uhci.c -@@ -729,11 +729,6 @@ static int uhci_complete_td(UHCIState *s, UHCI_TD *td, UHCIAsync *async, uint32_ - *int_mask |= 0x01; - - if (pid == USB_TOKEN_IN) { -- if (len > max_len) { -- ret = USB_RET_BABBLE; -- goto out; -- } -- - if ((td->ctrl & TD_CTRL_SPD) && len < max_len) { - *int_mask |= 0x02; - /* short packet: do not update QH */ --- -1.7.12 - diff --git a/0302-usb-core-Don-t-set-packet-state-to-complete-on-a-nak.patch b/0302-usb-core-Don-t-set-packet-state-to-complete-on-a-nak.patch deleted file mode 100644 index e40f57d..0000000 --- a/0302-usb-core-Don-t-set-packet-state-to-complete-on-a-nak.patch +++ /dev/null @@ -1,35 +0,0 @@ -From ae5b888748b713d018ca7b339262b32bf88ec1be Mon Sep 17 00:00:00 2001 -From: Hans de Goede -Date: Mon, 3 Sep 2012 12:33:44 +0200 -Subject: [PATCH 302/366] usb-core: Don't set packet state to complete on a - nak - -This way the hcd can re-use the same packet to retry without needing -to re-init it. - -Signed-off-by: Hans de Goede -Signed-off-by: Gerd Hoffmann ---- - hw/usb/core.c | 6 ++++-- - 1 file changed, 4 insertions(+), 2 deletions(-) - -diff --git a/hw/usb/core.c b/hw/usb/core.c -index 2da38e7..be6d936 100644 ---- a/hw/usb/core.c -+++ b/hw/usb/core.c -@@ -399,8 +399,10 @@ int usb_handle_packet(USBDevice *dev, USBPacket *p) - * otherwise packets can complete out of order! - */ - assert(!p->ep->pipeline); -- p->result = ret; -- usb_packet_set_state(p, USB_PACKET_COMPLETE); -+ if (ret != USB_RET_NAK) { -+ p->result = ret; -+ usb_packet_set_state(p, USB_PACKET_COMPLETE); -+ } - } - } else { - ret = USB_RET_ASYNC; --- -1.7.12 - diff --git a/0303-usb-core-Add-a-usb_ep_find_packet_by_id-helper-funct.patch b/0303-usb-core-Add-a-usb_ep_find_packet_by_id-helper-funct.patch deleted file mode 100644 index c3ed784..0000000 --- a/0303-usb-core-Add-a-usb_ep_find_packet_by_id-helper-funct.patch +++ /dev/null @@ -1,52 +0,0 @@ -From d42de93ca42a6d3b5101ec3db474f52a87a07a63 Mon Sep 17 00:00:00 2001 -From: Hans de Goede -Date: Tue, 28 Aug 2012 09:43:18 +0200 -Subject: [PATCH 303/366] usb-core: Add a usb_ep_find_packet_by_id() helper - function - -Signed-off-by: Hans de Goede -Signed-off-by: Gerd Hoffmann ---- - hw/usb.h | 2 ++ - hw/usb/core.c | 15 +++++++++++++++ - 2 files changed, 17 insertions(+) - -diff --git a/hw/usb.h b/hw/usb.h -index b8fceec..684e3f4 100644 ---- a/hw/usb.h -+++ b/hw/usb.h -@@ -377,6 +377,8 @@ void usb_ep_set_max_packet_size(USBDevice *dev, int pid, int ep, - uint16_t raw); - int usb_ep_get_max_packet_size(USBDevice *dev, int pid, int ep); - void usb_ep_set_pipeline(USBDevice *dev, int pid, int ep, bool enabled); -+USBPacket *usb_ep_find_packet_by_id(USBDevice *dev, int pid, int ep, -+ uint64_t id); - - void usb_attach(USBPort *port); - void usb_detach(USBPort *port); -diff --git a/hw/usb/core.c b/hw/usb/core.c -index be6d936..fe431d0 100644 ---- a/hw/usb/core.c -+++ b/hw/usb/core.c -@@ -726,3 +726,18 @@ void usb_ep_set_pipeline(USBDevice *dev, int pid, int ep, bool enabled) - struct USBEndpoint *uep = usb_ep_get(dev, pid, ep); - uep->pipeline = enabled; - } -+ -+USBPacket *usb_ep_find_packet_by_id(USBDevice *dev, int pid, int ep, -+ uint64_t id) -+{ -+ struct USBEndpoint *uep = usb_ep_get(dev, pid, ep); -+ USBPacket *p; -+ -+ while ((p = QTAILQ_FIRST(&uep->queue)) != NULL) { -+ if (p->id == id) { -+ return p; -+ } -+ } -+ -+ return NULL; -+} --- -1.7.12 - diff --git a/0304-usb-core-Allow-the-first-packet-of-a-pipelined-ep-to.patch b/0304-usb-core-Allow-the-first-packet-of-a-pipelined-ep-to.patch deleted file mode 100644 index ffcd31a..0000000 --- a/0304-usb-core-Allow-the-first-packet-of-a-pipelined-ep-to.patch +++ /dev/null @@ -1,32 +0,0 @@ -From d0c16c3cd8dc1f2dc5ca6dae0d09e5f066332531 Mon Sep 17 00:00:00 2001 -From: Hans de Goede -Date: Mon, 3 Sep 2012 12:48:49 +0200 -Subject: [PATCH 304/366] usb-core: Allow the first packet of a pipelined ep - to complete immediately - -This can happen with usb-redir live-migration when the packet gets re-queued -after the migration and the original queuing from the migration source side -has already finished. - -Signed-off-by: Hans de Goede -Signed-off-by: Gerd Hoffmann ---- - hw/usb/core.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/hw/usb/core.c b/hw/usb/core.c -index fe431d0..b9f1f7a 100644 ---- a/hw/usb/core.c -+++ b/hw/usb/core.c -@@ -398,7 +398,7 @@ int usb_handle_packet(USBDevice *dev, USBPacket *p) - * When pipelining is enabled usb-devices must always return async, - * otherwise packets can complete out of order! - */ -- assert(!p->ep->pipeline); -+ assert(!p->ep->pipeline || QTAILQ_EMPTY(&p->ep->queue)); - if (ret != USB_RET_NAK) { - p->result = ret; - usb_packet_set_state(p, USB_PACKET_COMPLETE); --- -1.7.12 - diff --git a/0305-Revert-ehci-don-t-flush-cache-on-doorbell-rings.patch b/0305-Revert-ehci-don-t-flush-cache-on-doorbell-rings.patch deleted file mode 100644 index 6d8c7e9..0000000 --- a/0305-Revert-ehci-don-t-flush-cache-on-doorbell-rings.patch +++ /dev/null @@ -1,121 +0,0 @@ -From eccc0da01324939a52a74c763ade93e4a38d7328 Mon Sep 17 00:00:00 2001 -From: Hans de Goede -Date: Wed, 29 Aug 2012 10:12:52 +0200 -Subject: [PATCH 305/366] Revert "ehci: don't flush cache on doorbell rings." - -This reverts commit 9bc3a3a216e2689bfcdd36c3e079333bbdbf3ba0, which got -added to fix an issue where the real, underlying cause was not stopping -the ep queue on an error. - -Now that the underlying cause is fixed by the "usb: Halt ep queue and -cancel pending packets on a packet error" patch, the "don't flush" fix -is no longer needed. - -Not only is it not needed, it causes us to see cancellations (unlinks) -done by the Linux EHCI driver too late, which in combination with the new -usb-core packet-id generation where qtd addresses are used as ids, causes -duplicate ids for in flight packets. - -Signed-off-by: Hans de Goede ---- - hw/usb/hcd-ehci.c | 35 ++++++----------------------------- - 1 file changed, 6 insertions(+), 29 deletions(-) - -diff --git a/hw/usb/hcd-ehci.c b/hw/usb/hcd-ehci.c -index 9523247..e7c36f4 100644 ---- a/hw/usb/hcd-ehci.c -+++ b/hw/usb/hcd-ehci.c -@@ -365,7 +365,6 @@ struct EHCIQueue { - uint32_t seen; - uint64_t ts; - int async; -- int revalidate; - - /* cached data from guest - needs to be flushed - * when guest removes an entry (doorbell, handshake sequence) -@@ -805,18 +804,7 @@ static EHCIQueue *ehci_find_queue_by_qh(EHCIState *ehci, uint32_t addr, - return NULL; - } - --static void ehci_queues_tag_unused_async(EHCIState *ehci) --{ -- EHCIQueue *q; -- -- QTAILQ_FOREACH(q, &ehci->aqueues, next) { -- if (!q->seen) { -- q->revalidate = 1; -- } -- } --} -- --static void ehci_queues_rip_unused(EHCIState *ehci, int async) -+static void ehci_queues_rip_unused(EHCIState *ehci, int async, int flush) - { - EHCIQueueHead *head = async ? &ehci->aqueues : &ehci->pqueues; - uint64_t maxage = FRAME_TIMER_NS * ehci->maxframes * 4; -@@ -828,7 +816,7 @@ static void ehci_queues_rip_unused(EHCIState *ehci, int async) - q->ts = ehci->last_run_ns; - continue; - } -- if (ehci->last_run_ns < q->ts + maxage) { -+ if (!flush && ehci->last_run_ns < q->ts + maxage) { - continue; - } - ehci_free_queue(q); -@@ -1684,7 +1672,7 @@ static int ehci_state_waitlisthead(EHCIState *ehci, int async) - ehci_set_usbsts(ehci, USBSTS_REC); - } - -- ehci_queues_rip_unused(ehci, async); -+ ehci_queues_rip_unused(ehci, async, 0); - - /* Find the head of the list (4.9.1.1) */ - for(i = 0; i < MAX_QH; i++) { -@@ -1769,7 +1757,6 @@ static EHCIQueue *ehci_state_fetchqh(EHCIState *ehci, int async) - EHCIPacket *p; - uint32_t entry, devaddr; - EHCIQueue *q; -- EHCIqh qh; - - entry = ehci_get_fetch_addr(ehci, async); - q = ehci_find_queue_by_qh(ehci, entry, async); -@@ -1787,17 +1774,7 @@ static EHCIQueue *ehci_state_fetchqh(EHCIState *ehci, int async) - } - - get_dwords(ehci, NLPTR_GET(q->qhaddr), -- (uint32_t *) &qh, sizeof(EHCIqh) >> 2); -- if (q->revalidate && (q->qh.epchar != qh.epchar || -- q->qh.epcap != qh.epcap || -- q->qh.current_qtd != qh.current_qtd)) { -- ehci_free_queue(q); -- q = ehci_alloc_queue(ehci, entry, async); -- q->seen++; -- p = NULL; -- } -- q->qh = qh; -- q->revalidate = 0; -+ (uint32_t *) &q->qh, sizeof(EHCIqh) >> 2); - ehci_trace_qh(q, NLPTR_GET(q->qhaddr), &q->qh); - - devaddr = get_field(q->qh.epchar, QH_EPCHAR_DEVADDR); -@@ -2306,7 +2283,7 @@ static void ehci_advance_async_state(EHCIState *ehci) - */ - if (ehci->usbcmd & USBCMD_IAAD) { - /* Remove all unseen qhs from the async qhs queue */ -- ehci_queues_tag_unused_async(ehci); -+ ehci_queues_rip_unused(ehci, async, 1); - DPRINTF("ASYNC: doorbell request acknowledged\n"); - ehci->usbcmd &= ~USBCMD_IAAD; - ehci_raise_irq(ehci, USBSTS_IAA); -@@ -2359,7 +2336,7 @@ static void ehci_advance_periodic_state(EHCIState *ehci) - ehci_set_fetch_addr(ehci, async,entry); - ehci_set_state(ehci, async, EST_FETCHENTRY); - ehci_advance_state(ehci, async); -- ehci_queues_rip_unused(ehci, async); -+ ehci_queues_rip_unused(ehci, async, 0); - break; - - default: --- -1.7.12 - diff --git a/0306-ehci-Validate-qh-is-not-changed-unexpectedly-by-the-.patch b/0306-ehci-Validate-qh-is-not-changed-unexpectedly-by-the-.patch deleted file mode 100644 index 7af3a27..0000000 --- a/0306-ehci-Validate-qh-is-not-changed-unexpectedly-by-the-.patch +++ /dev/null @@ -1,84 +0,0 @@ -From 1ee48073d05a8a0dfe08ad2853be125a87f176de Mon Sep 17 00:00:00 2001 -From: Hans de Goede -Date: Wed, 29 Aug 2012 10:37:37 +0200 -Subject: [PATCH 306/366] ehci: Validate qh is not changed unexpectedly by the - guest - --combine the qh check with the check for devaddr changes --also ensure that p gets set to NULL when the queue gets cancelled on - devaddr change, which was not done properly before this patch - -Signed-off-by: Hans de Goede ---- - hw/usb/hcd-ehci.c | 39 ++++++++++++++++++++++++++++----------- - 1 file changed, 28 insertions(+), 11 deletions(-) - -diff --git a/hw/usb/hcd-ehci.c b/hw/usb/hcd-ehci.c -index e7c36f4..35eb441 100644 ---- a/hw/usb/hcd-ehci.c -+++ b/hw/usb/hcd-ehci.c -@@ -780,6 +780,14 @@ static void ehci_cancel_queue(EHCIQueue *q) - } while ((p = QTAILQ_FIRST(&q->packets)) != NULL); - } - -+static void ehci_reset_queue(EHCIQueue *q) -+{ -+ trace_usb_ehci_queue_action(q, "reset"); -+ ehci_cancel_queue(q); -+ q->dev = NULL; -+ q->qtdaddr = 0; -+} -+ - static void ehci_free_queue(EHCIQueue *q) - { - EHCIQueueHead *head = q->async ? &q->ehci->aqueues : &q->ehci->pqueues; -@@ -1755,8 +1763,9 @@ out: - static EHCIQueue *ehci_state_fetchqh(EHCIState *ehci, int async) - { - EHCIPacket *p; -- uint32_t entry, devaddr; -+ uint32_t entry, devaddr, endp; - EHCIQueue *q; -+ EHCIqh qh; - - entry = ehci_get_fetch_addr(ehci, async); - q = ehci_find_queue_by_qh(ehci, entry, async); -@@ -1774,17 +1783,25 @@ static EHCIQueue *ehci_state_fetchqh(EHCIState *ehci, int async) - } - - get_dwords(ehci, NLPTR_GET(q->qhaddr), -- (uint32_t *) &q->qh, sizeof(EHCIqh) >> 2); -- ehci_trace_qh(q, NLPTR_GET(q->qhaddr), &q->qh); -+ (uint32_t *) &qh, sizeof(EHCIqh) >> 2); -+ ehci_trace_qh(q, NLPTR_GET(q->qhaddr), &qh); -+ -+ /* -+ * The overlay area of the qh should never be changed by the guest, -+ * except when idle, in which case the reset is a nop. -+ */ -+ devaddr = get_field(qh.epchar, QH_EPCHAR_DEVADDR); -+ endp = get_field(qh.epchar, QH_EPCHAR_EP); -+ if ((devaddr != get_field(q->qh.epchar, QH_EPCHAR_DEVADDR)) || -+ (endp != get_field(q->qh.epchar, QH_EPCHAR_EP)) || -+ (memcmp(&qh.current_qtd, &q->qh.current_qtd, -+ 9 * sizeof(uint32_t)) != 0) || -+ (q->dev != NULL && q->dev->addr != devaddr)) { -+ ehci_reset_queue(q); -+ p = NULL; -+ } -+ q->qh = qh; - -- devaddr = get_field(q->qh.epchar, QH_EPCHAR_DEVADDR); -- if (q->dev != NULL && q->dev->addr != devaddr) { -- if (!QTAILQ_EMPTY(&q->packets)) { -- /* should not happen (guest bug) */ -- ehci_cancel_queue(q); -- } -- q->dev = NULL; -- } - if (q->dev == NULL) { - q->dev = ehci_find_device(q->ehci, devaddr); - } --- -1.7.12 - diff --git a/0307-ehci-Update-copyright-headers-to-reflect-recent-work.patch b/0307-ehci-Update-copyright-headers-to-reflect-recent-work.patch deleted file mode 100644 index edfb6e0..0000000 --- a/0307-ehci-Update-copyright-headers-to-reflect-recent-work.patch +++ /dev/null @@ -1,33 +0,0 @@ -From faeefe2a1fdb5895bffb1380b318f3cc396cb057 Mon Sep 17 00:00:00 2001 -From: Hans de Goede -Date: Tue, 28 Aug 2012 16:21:12 +0200 -Subject: [PATCH 307/366] ehci: Update copyright headers to reflect recent - work - -Update copyright headers to reflect all the work Gerd and I have been doing -on the EHCI emulation. - -Signed-off-by: Hans de Goede ---- - hw/usb/hcd-ehci.c | 5 +++++ - 1 file changed, 5 insertions(+) - -diff --git a/hw/usb/hcd-ehci.c b/hw/usb/hcd-ehci.c -index 35eb441..78a248f 100644 ---- a/hw/usb/hcd-ehci.c -+++ b/hw/usb/hcd-ehci.c -@@ -2,6 +2,11 @@ - * QEMU USB EHCI Emulation - * - * Copyright(c) 2008 Emutex Ltd. (address@hidden) -+ * Copyright(c) 2011-2012 Red Hat, Inc. -+ * -+ * Red Hat Authors: -+ * Gerd Hoffmann -+ * Hans de Goede - * - * EHCI project was started by Mark Burkley, with contributions by - * Niels de Vos. David S. Ahern continued working on it. Kevin Wolf, --- -1.7.12 - diff --git a/0308-ehci-Properly-cleanup-packets-on-cancel.patch b/0308-ehci-Properly-cleanup-packets-on-cancel.patch deleted file mode 100644 index 03b9ce4..0000000 --- a/0308-ehci-Properly-cleanup-packets-on-cancel.patch +++ /dev/null @@ -1,26 +0,0 @@ -From 95a792a46e8daae4bfb0997f6340bcd8dddea06c Mon Sep 17 00:00:00 2001 -From: Hans de Goede -Date: Thu, 30 Aug 2012 15:00:33 +0200 -Subject: [PATCH 308/366] ehci: Properly cleanup packets on cancel - -Signed-off-by: Hans de Goede ---- - hw/usb/hcd-ehci.c | 2 ++ - 1 file changed, 2 insertions(+) - -diff --git a/hw/usb/hcd-ehci.c b/hw/usb/hcd-ehci.c -index 78a248f..4fe85c8 100644 ---- a/hw/usb/hcd-ehci.c -+++ b/hw/usb/hcd-ehci.c -@@ -747,6 +747,8 @@ static void ehci_free_packet(EHCIPacket *p) - trace_usb_ehci_packet_action(p->queue, p, "free"); - if (p->async == EHCI_ASYNC_INFLIGHT) { - usb_cancel_packet(&p->packet); -+ usb_packet_unmap(&p->packet, &p->sgl); -+ qemu_sglist_destroy(&p->sgl); - } - QTAILQ_REMOVE(&p->queue->packets, p, next); - usb_packet_cleanup(&p->packet); --- -1.7.12 - diff --git a/0309-ehci-Properly-report-completed-but-not-yet-processed.patch b/0309-ehci-Properly-report-completed-but-not-yet-processed.patch deleted file mode 100644 index 445b322..0000000 --- a/0309-ehci-Properly-report-completed-but-not-yet-processed.patch +++ /dev/null @@ -1,49 +0,0 @@ -From 584606864261092041b46806030e4889b747ad41 Mon Sep 17 00:00:00 2001 -From: Hans de Goede -Date: Thu, 30 Aug 2012 15:18:24 +0200 -Subject: [PATCH 309/366] ehci: Properly report completed but not yet - processed packets to the guest - -Reported packets which have completed before being cancelled as such to the -host. Note that the new code path this patch adds is untested since it I've -been unable to actually trigger the race which needs this code path. - -Signed-off-by: Hans de Goede ---- - hw/usb/hcd-ehci.c | 13 +++++++++++++ - 1 file changed, 13 insertions(+) - -diff --git a/hw/usb/hcd-ehci.c b/hw/usb/hcd-ehci.c -index 4fe85c8..0a6c9ef 100644 ---- a/hw/usb/hcd-ehci.c -+++ b/hw/usb/hcd-ehci.c -@@ -489,6 +489,9 @@ static const char *ehci_mmio_names[] = { - [CONFIGFLAG] = "CONFIGFLAG", - }; - -+static int ehci_state_executing(EHCIQueue *q); -+static int ehci_state_writeback(EHCIQueue *q); -+ - static const char *nr2str(const char **n, size_t len, uint32_t nr) - { - if (nr < len && n[nr] != NULL) { -@@ -750,6 +753,16 @@ static void ehci_free_packet(EHCIPacket *p) - usb_packet_unmap(&p->packet, &p->sgl); - qemu_sglist_destroy(&p->sgl); - } -+ if (p->async == EHCI_ASYNC_FINISHED) { -+ int state = ehci_get_state(p->queue->ehci, p->queue->async); -+ /* This is a normal, but rare condition (cancel racing completion) */ -+ fprintf(stderr, "EHCI: Warning packet completed but not processed\n"); -+ ehci_state_executing(p->queue); -+ ehci_state_writeback(p->queue); -+ ehci_set_state(p->queue->ehci, p->queue->async, state); -+ /* state_writeback recurses into us with async == EHCI_ASYNC_NONE!! */ -+ return; -+ } - QTAILQ_REMOVE(&p->queue->packets, p, next); - usb_packet_cleanup(&p->packet); - g_free(p); --- -1.7.12 - diff --git a/0310-ehci-check-for-EHCI_ASYNC_FINISHED-first-in-ehci_fre.patch b/0310-ehci-check-for-EHCI_ASYNC_FINISHED-first-in-ehci_fre.patch deleted file mode 100644 index bcb596c..0000000 --- a/0310-ehci-check-for-EHCI_ASYNC_FINISHED-first-in-ehci_fre.patch +++ /dev/null @@ -1,47 +0,0 @@ -From 6f009493144d09e417997caa13b62a38798dc206 Mon Sep 17 00:00:00 2001 -From: Gerd Hoffmann -Date: Fri, 31 Aug 2012 10:31:54 +0200 -Subject: [PATCH 310/366] ehci: check for EHCI_ASYNC_FINISHED first in - ehci_free_packet - -Otherwise we'll see the packet free twice in the trace log even though -it actually happens only once. - -Signed-off-by: Gerd Hoffmann ---- - hw/usb/hcd-ehci.c | 12 ++++++------ - 1 file changed, 6 insertions(+), 6 deletions(-) - -diff --git a/hw/usb/hcd-ehci.c b/hw/usb/hcd-ehci.c -index 0a6c9ef..23221d0 100644 ---- a/hw/usb/hcd-ehci.c -+++ b/hw/usb/hcd-ehci.c -@@ -747,12 +747,6 @@ static EHCIPacket *ehci_alloc_packet(EHCIQueue *q) - - static void ehci_free_packet(EHCIPacket *p) - { -- trace_usb_ehci_packet_action(p->queue, p, "free"); -- if (p->async == EHCI_ASYNC_INFLIGHT) { -- usb_cancel_packet(&p->packet); -- usb_packet_unmap(&p->packet, &p->sgl); -- qemu_sglist_destroy(&p->sgl); -- } - if (p->async == EHCI_ASYNC_FINISHED) { - int state = ehci_get_state(p->queue->ehci, p->queue->async); - /* This is a normal, but rare condition (cancel racing completion) */ -@@ -763,6 +757,12 @@ static void ehci_free_packet(EHCIPacket *p) - /* state_writeback recurses into us with async == EHCI_ASYNC_NONE!! */ - return; - } -+ trace_usb_ehci_packet_action(p->queue, p, "free"); -+ if (p->async == EHCI_ASYNC_INFLIGHT) { -+ usb_cancel_packet(&p->packet); -+ usb_packet_unmap(&p->packet, &p->sgl); -+ qemu_sglist_destroy(&p->sgl); -+ } - QTAILQ_REMOVE(&p->queue->packets, p, next); - usb_packet_cleanup(&p->packet); - g_free(p); --- -1.7.12 - diff --git a/0311-ehci-trace-guest-bugs.patch b/0311-ehci-trace-guest-bugs.patch deleted file mode 100644 index 0abd96e..0000000 --- a/0311-ehci-trace-guest-bugs.patch +++ /dev/null @@ -1,106 +0,0 @@ -From 044dcae94243d03739c309935a68b646424a4d4e Mon Sep 17 00:00:00 2001 -From: Gerd Hoffmann -Date: Fri, 31 Aug 2012 10:44:21 +0200 -Subject: [PATCH 311/366] ehci: trace guest bugs - -make qemu_queue_{cancel,reset} return the number of packets released, -so the caller can figure whenever there have been active packets even -though there shouldn't have been any. Add tracepoint to log this. - -Signed-off-by: Gerd Hoffmann ---- - hw/usb/hcd-ehci.c | 26 ++++++++++++++++++++------ - trace-events | 1 + - 2 files changed, 21 insertions(+), 6 deletions(-) - -diff --git a/hw/usb/hcd-ehci.c b/hw/usb/hcd-ehci.c -index 23221d0..4564615 100644 ---- a/hw/usb/hcd-ehci.c -+++ b/hw/usb/hcd-ehci.c -@@ -716,6 +716,12 @@ static void ehci_trace_sitd(EHCIState *s, target_phys_addr_t addr, - (bool)(sitd->results & SITD_RESULTS_ACTIVE)); - } - -+static void ehci_trace_guest_bug(EHCIState *s, const char *message) -+{ -+ trace_usb_ehci_guest_bug(message); -+ fprintf(stderr, "ehci warning: %s\n", message); -+} -+ - static inline bool ehci_enabled(EHCIState *s) - { - return s->usbcmd & USBCMD_RUNSTOP; -@@ -785,27 +791,33 @@ static EHCIQueue *ehci_alloc_queue(EHCIState *ehci, uint32_t addr, int async) - return q; - } - --static void ehci_cancel_queue(EHCIQueue *q) -+static int ehci_cancel_queue(EHCIQueue *q) - { - EHCIPacket *p; -+ int packets = 0; - - p = QTAILQ_FIRST(&q->packets); - if (p == NULL) { -- return; -+ return 0; - } - - trace_usb_ehci_queue_action(q, "cancel"); - do { - ehci_free_packet(p); -+ packets++; - } while ((p = QTAILQ_FIRST(&q->packets)) != NULL); -+ return packets; - } - --static void ehci_reset_queue(EHCIQueue *q) -+static int ehci_reset_queue(EHCIQueue *q) - { -+ int packets; -+ - trace_usb_ehci_queue_action(q, "reset"); -- ehci_cancel_queue(q); -+ packets = ehci_cancel_queue(q); - q->dev = NULL; - q->qtdaddr = 0; -+ return packets; - } - - static void ehci_free_queue(EHCIQueue *q) -@@ -1817,7 +1829,9 @@ static EHCIQueue *ehci_state_fetchqh(EHCIState *ehci, int async) - (memcmp(&qh.current_qtd, &q->qh.current_qtd, - 9 * sizeof(uint32_t)) != 0) || - (q->dev != NULL && q->dev->addr != devaddr)) { -- ehci_reset_queue(q); -+ if (ehci_reset_queue(q) > 0) { -+ ehci_trace_guest_bug(ehci, "guest updated active QH"); -+ } - p = NULL; - } - q->qh = qh; -@@ -1979,8 +1993,8 @@ static int ehci_state_fetchqtd(EHCIQueue *q) - (!NLPTR_TBIT(p->qtd.next) && (p->qtd.next != qtd.next)) || - (!NLPTR_TBIT(p->qtd.altnext) && (p->qtd.altnext != qtd.altnext)) || - p->qtd.bufptr[0] != qtd.bufptr[0]) { -- /* guest bug: guest updated active QH or qTD underneath us */ - ehci_cancel_queue(q); -+ ehci_trace_guest_bug(q->ehci, "guest updated active QH or qTD"); - p = NULL; - } else { - p->qtd = qtd; -diff --git a/trace-events b/trace-events -index 8fcbc50..5112a47 100644 ---- a/trace-events -+++ b/trace-events -@@ -263,6 +263,7 @@ usb_ehci_data(int rw, uint32_t cpage, uint32_t offset, uint32_t addr, uint32_t l - usb_ehci_queue_action(void *q, const char *action) "q %p: %s" - usb_ehci_packet_action(void *q, void *p, const char *action) "q %p p %p: %s" - usb_ehci_irq(uint32_t level, uint32_t frindex, uint32_t sts, uint32_t mask) "level %d, frindex 0x%04x, sts 0x%x, mask 0x%x" -+usb_ehci_guest_bug(const char *reason) "%s" - - # hw/usb/hcd-uhci.c - usb_uhci_reset(void) "=== RESET ===" --- -1.7.12 - diff --git a/0312-ehci-add-doorbell-trace-events.patch b/0312-ehci-add-doorbell-trace-events.patch deleted file mode 100644 index 817132d..0000000 --- a/0312-ehci-add-doorbell-trace-events.patch +++ /dev/null @@ -1,48 +0,0 @@ -From 77e3a7e6bf15a85040101e7c0990dd82abdc9e9c Mon Sep 17 00:00:00 2001 -From: Gerd Hoffmann -Date: Fri, 31 Aug 2012 12:41:43 +0200 -Subject: [PATCH 312/366] ehci: add doorbell trace events - -Signed-off-by: Gerd Hoffmann ---- - hw/usb/hcd-ehci.c | 3 ++- - trace-events | 2 ++ - 2 files changed, 4 insertions(+), 1 deletion(-) - -diff --git a/hw/usb/hcd-ehci.c b/hw/usb/hcd-ehci.c -index 4564615..398f5e0 100644 ---- a/hw/usb/hcd-ehci.c -+++ b/hw/usb/hcd-ehci.c -@@ -1241,6 +1241,7 @@ static void ehci_mem_writel(void *ptr, target_phys_addr_t addr, uint32_t val) - */ - s->async_stepdown = 0; - qemu_bh_schedule(s->async_bh); -+ trace_usb_ehci_doorbell_ring(); - } - - if (((USBCMD_RUNSTOP | USBCMD_PSE | USBCMD_ASE) & val) != -@@ -2335,7 +2336,7 @@ static void ehci_advance_async_state(EHCIState *ehci) - if (ehci->usbcmd & USBCMD_IAAD) { - /* Remove all unseen qhs from the async qhs queue */ - ehci_queues_rip_unused(ehci, async, 1); -- DPRINTF("ASYNC: doorbell request acknowledged\n"); -+ trace_usb_ehci_doorbell_ack(); - ehci->usbcmd &= ~USBCMD_IAAD; - ehci_raise_irq(ehci, USBSTS_IAA); - } -diff --git a/trace-events b/trace-events -index 5112a47..10bc04e 100644 ---- a/trace-events -+++ b/trace-events -@@ -264,6 +264,8 @@ usb_ehci_queue_action(void *q, const char *action) "q %p: %s" - usb_ehci_packet_action(void *q, void *p, const char *action) "q %p p %p: %s" - usb_ehci_irq(uint32_t level, uint32_t frindex, uint32_t sts, uint32_t mask) "level %d, frindex 0x%04x, sts 0x%x, mask 0x%x" - usb_ehci_guest_bug(const char *reason) "%s" -+usb_ehci_doorbell_ring(void) "" -+usb_ehci_doorbell_ack(void) "" - - # hw/usb/hcd-uhci.c - usb_uhci_reset(void) "=== RESET ===" --- -1.7.12 - diff --git a/0313-ehci-Add-some-additional-ehci_trace_guest_bug-calls.patch b/0313-ehci-Add-some-additional-ehci_trace_guest_bug-calls.patch deleted file mode 100644 index 0587c98..0000000 --- a/0313-ehci-Add-some-additional-ehci_trace_guest_bug-calls.patch +++ /dev/null @@ -1,86 +0,0 @@ -From cbbfcc647e26708cdd78c8ddf28d99f8a1e1e6b0 Mon Sep 17 00:00:00 2001 -From: Hans de Goede -Date: Mon, 3 Sep 2012 10:22:16 +0200 -Subject: [PATCH 313/366] ehci: Add some additional ehci_trace_guest_bug() - calls - -Signed-off-by: Hans de Goede -Signed-off-by: Gerd Hoffmann ---- - hw/usb/hcd-ehci.c | 19 +++++++++++++------ - 1 file changed, 13 insertions(+), 6 deletions(-) - -diff --git a/hw/usb/hcd-ehci.c b/hw/usb/hcd-ehci.c -index 398f5e0..5a88268 100644 ---- a/hw/usb/hcd-ehci.c -+++ b/hw/usb/hcd-ehci.c -@@ -820,12 +820,16 @@ static int ehci_reset_queue(EHCIQueue *q) - return packets; - } - --static void ehci_free_queue(EHCIQueue *q) -+static void ehci_free_queue(EHCIQueue *q, const char *warn) - { - EHCIQueueHead *head = q->async ? &q->ehci->aqueues : &q->ehci->pqueues; -+ int cancelled; - - trace_usb_ehci_queue_action(q, "free"); -- ehci_cancel_queue(q); -+ cancelled = ehci_cancel_queue(q); -+ if (warn && cancelled > 0) { -+ ehci_trace_guest_bug(q->ehci, warn); -+ } - QTAILQ_REMOVE(head, q, next); - g_free(q); - } -@@ -847,6 +851,7 @@ static EHCIQueue *ehci_find_queue_by_qh(EHCIState *ehci, uint32_t addr, - static void ehci_queues_rip_unused(EHCIState *ehci, int async, int flush) - { - EHCIQueueHead *head = async ? &ehci->aqueues : &ehci->pqueues; -+ const char *warn = (async && !flush) ? "guest unlinked busy QH" : NULL; - uint64_t maxage = FRAME_TIMER_NS * ehci->maxframes * 4; - EHCIQueue *q, *tmp; - -@@ -859,7 +864,7 @@ static void ehci_queues_rip_unused(EHCIState *ehci, int async, int flush) - if (!flush && ehci->last_run_ns < q->ts + maxage) { - continue; - } -- ehci_free_queue(q); -+ ehci_free_queue(q, warn); - } - } - -@@ -872,17 +877,18 @@ static void ehci_queues_rip_device(EHCIState *ehci, USBDevice *dev, int async) - if (q->dev != dev) { - continue; - } -- ehci_free_queue(q); -+ ehci_free_queue(q, NULL); - } - } - - static void ehci_queues_rip_all(EHCIState *ehci, int async) - { - EHCIQueueHead *head = async ? &ehci->aqueues : &ehci->pqueues; -+ const char *warn = async ? "guest stopped busy async schedule" : NULL; - EHCIQueue *q, *tmp; - - QTAILQ_FOREACH_SAFE(q, head, next, tmp) { -- ehci_free_queue(q); -+ ehci_free_queue(q, warn); - } - } - -@@ -1549,7 +1555,8 @@ static int ehci_execute(EHCIPacket *p, const char *action) - - p->tbytes = (p->qtd.token & QTD_TOKEN_TBYTES_MASK) >> QTD_TOKEN_TBYTES_SH; - if (p->tbytes > BUFF_SIZE) { -- fprintf(stderr, "Request for more bytes than allowed\n"); -+ ehci_trace_guest_bug(p->queue->ehci, -+ "guest requested more bytes than allowed"); - return USB_RET_PROCERR; - } - --- -1.7.12 - diff --git a/0314-ehci-Fix-memory-leak-in-handling-of-NAK-ed-packets.patch b/0314-ehci-Fix-memory-leak-in-handling-of-NAK-ed-packets.patch deleted file mode 100644 index 3c82869..0000000 --- a/0314-ehci-Fix-memory-leak-in-handling-of-NAK-ed-packets.patch +++ /dev/null @@ -1,117 +0,0 @@ -From 68851693ee59d3f17c14983902076a5ef49e2e80 Mon Sep 17 00:00:00 2001 -From: Hans de Goede -Date: Mon, 3 Sep 2012 11:01:13 +0200 -Subject: [PATCH 314/366] ehci: Fix memory leak in handling of NAK-ed packets - -Currently each time we try to execute a NAK-ed packet we redo -ehci_init_transfer, and usb_packet_map, re-allocing (without freeing) the -sg list every time. - -This patch fixes this, it does this by introducing another async state, so -that we also properly cleanup a NAK-ed packet on cancel. - -Signed-off-by: Hans de Goede -Signed-off-by: Gerd Hoffmann ---- - hw/usb/hcd-ehci.c | 38 +++++++++++++++++++++++++++----------- - 1 file changed, 27 insertions(+), 11 deletions(-) - -diff --git a/hw/usb/hcd-ehci.c b/hw/usb/hcd-ehci.c -index 5a88268..d87aca8 100644 ---- a/hw/usb/hcd-ehci.c -+++ b/hw/usb/hcd-ehci.c -@@ -345,6 +345,7 @@ typedef struct EHCIState EHCIState; - - enum async_state { - EHCI_ASYNC_NONE = 0, -+ EHCI_ASYNC_INITIALIZED, - EHCI_ASYNC_INFLIGHT, - EHCI_ASYNC_FINISHED, - }; -@@ -764,6 +765,10 @@ static void ehci_free_packet(EHCIPacket *p) - return; - } - trace_usb_ehci_packet_action(p->queue, p, "free"); -+ if (p->async == EHCI_ASYNC_INITIALIZED) { -+ usb_packet_unmap(&p->packet, &p->sgl); -+ qemu_sglist_destroy(&p->sgl); -+ } - if (p->async == EHCI_ASYNC_INFLIGHT) { - usb_cancel_packet(&p->packet); - usb_packet_unmap(&p->packet, &p->sgl); -@@ -1485,8 +1490,8 @@ static void ehci_execute_complete(EHCIQueue *q) - - assert(p != NULL); - assert(p->qtdaddr == q->qtdaddr); -- assert(p->async != EHCI_ASYNC_INFLIGHT); -- p->async = EHCI_ASYNC_NONE; -+ assert(p->async == EHCI_ASYNC_INITIALIZED || -+ p->async == EHCI_ASYNC_FINISHED); - - DPRINTF("execute_complete: qhaddr 0x%x, next %x, qtdaddr 0x%x, status %d\n", - q->qhaddr, q->qh.next, q->qtdaddr, q->usb_status); -@@ -1531,6 +1536,7 @@ static void ehci_execute_complete(EHCIQueue *q) - ehci_finish_transfer(q, p->usb_status); - usb_packet_unmap(&p->packet, &p->sgl); - qemu_sglist_destroy(&p->sgl); -+ p->async = EHCI_ASYNC_NONE; - - q->qh.token ^= QTD_TOKEN_DTOGGLE; - q->qh.token &= ~QTD_TOKEN_ACTIVE; -@@ -1548,6 +1554,9 @@ static int ehci_execute(EHCIPacket *p, const char *action) - int ret; - int endp; - -+ assert(p->async == EHCI_ASYNC_NONE || -+ p->async == EHCI_ASYNC_INITIALIZED); -+ - if (!(p->qtd.token & QTD_TOKEN_ACTIVE)) { - fprintf(stderr, "Attempting to execute inactive qtd\n"); - return USB_RET_PROCERR; -@@ -1576,15 +1585,18 @@ static int ehci_execute(EHCIPacket *p, const char *action) - break; - } - -- if (ehci_init_transfer(p) != 0) { -- return USB_RET_PROCERR; -- } -- - endp = get_field(p->queue->qh.epchar, QH_EPCHAR_EP); - ep = usb_ep_get(p->queue->dev, p->pid, endp); - -- usb_packet_setup(&p->packet, p->pid, ep, p->qtdaddr); -- usb_packet_map(&p->packet, &p->sgl); -+ if (p->async == EHCI_ASYNC_NONE) { -+ if (ehci_init_transfer(p) != 0) { -+ return USB_RET_PROCERR; -+ } -+ -+ usb_packet_setup(&p->packet, p->pid, ep, p->qtdaddr); -+ usb_packet_map(&p->packet, &p->sgl); -+ p->async = EHCI_ASYNC_INITIALIZED; -+ } - - trace_usb_ehci_packet_action(p->queue, p, action); - ret = usb_handle_packet(p->queue->dev, &p->packet); -@@ -2021,11 +2033,15 @@ static int ehci_state_fetchqtd(EHCIQueue *q) - } else if (p != NULL) { - switch (p->async) { - case EHCI_ASYNC_NONE: -+ /* Should never happen packet should at least be initialized */ -+ assert(0); -+ break; -+ case EHCI_ASYNC_INITIALIZED: - /* Previously nacked packet (likely interrupt ep) */ -- ehci_set_state(q->ehci, q->async, EST_EXECUTE); -- break; -+ ehci_set_state(q->ehci, q->async, EST_EXECUTE); -+ break; - case EHCI_ASYNC_INFLIGHT: -- /* Unfinyshed async handled packet, go horizontal */ -+ /* Unfinished async handled packet, go horizontal */ - ehci_set_state(q->ehci, q->async, EST_HORIZONTALQH); - break; - case EHCI_ASYNC_FINISHED: --- -1.7.12 - diff --git a/0315-ehci-Handle-USB_RET_PROCERR-in-ehci_fill_queue.patch b/0315-ehci-Handle-USB_RET_PROCERR-in-ehci_fill_queue.patch deleted file mode 100644 index a52d3db..0000000 --- a/0315-ehci-Handle-USB_RET_PROCERR-in-ehci_fill_queue.patch +++ /dev/null @@ -1,54 +0,0 @@ -From 1599d0b01712fb16c3ad291b653a31f768f7f5ef Mon Sep 17 00:00:00 2001 -From: Hans de Goede -Date: Mon, 3 Sep 2012 11:35:58 +0200 -Subject: [PATCH 315/366] ehci: Handle USB_RET_PROCERR in ehci_fill_queue - -USB_RET_PROCERR can be triggered by the guest (by for example requesting more -then BUFFSIZE bytes), so don't assert on it. - -Signed-off-by: Hans de Goede -Signed-off-by: Gerd Hoffmann ---- - hw/usb/hcd-ehci.c | 9 ++++++--- - 1 file changed, 6 insertions(+), 3 deletions(-) - -diff --git a/hw/usb/hcd-ehci.c b/hw/usb/hcd-ehci.c -index d87aca8..2534394 100644 ---- a/hw/usb/hcd-ehci.c -+++ b/hw/usb/hcd-ehci.c -@@ -2076,7 +2076,7 @@ static int ehci_state_horizqh(EHCIQueue *q) - return again; - } - --static void ehci_fill_queue(EHCIPacket *p) -+static int ehci_fill_queue(EHCIPacket *p) - { - EHCIQueue *q = p->queue; - EHCIqtd qtd = p->qtd; -@@ -2100,9 +2100,13 @@ static void ehci_fill_queue(EHCIPacket *p) - p->qtdaddr = qtdaddr; - p->qtd = qtd; - p->usb_status = ehci_execute(p, "queue"); -+ if (p->usb_status == USB_RET_PROCERR) { -+ break; -+ } - assert(p->usb_status == USB_RET_ASYNC); - p->async = EHCI_ASYNC_INFLIGHT; - } -+ return p->usb_status; - } - - static int ehci_state_execute(EHCIQueue *q) -@@ -2144,8 +2148,7 @@ static int ehci_state_execute(EHCIQueue *q) - trace_usb_ehci_packet_action(p->queue, p, "async"); - p->async = EHCI_ASYNC_INFLIGHT; - ehci_set_state(q->ehci, q->async, EST_HORIZONTALQH); -- again = 1; -- ehci_fill_queue(p); -+ again = (ehci_fill_queue(p) == USB_RET_PROCERR) ? -1 : 1; - goto out; - } - --- -1.7.12 - diff --git a/0316-ehci-Correct-a-comment-in-fetchqtd-packet-processing.patch b/0316-ehci-Correct-a-comment-in-fetchqtd-packet-processing.patch deleted file mode 100644 index 8bd379d..0000000 --- a/0316-ehci-Correct-a-comment-in-fetchqtd-packet-processing.patch +++ /dev/null @@ -1,35 +0,0 @@ -From d17b1ad80cba3354b3eca5b8464bf7bb3f8e95c1 Mon Sep 17 00:00:00 2001 -From: Hans de Goede -Date: Mon, 3 Sep 2012 12:17:48 +0200 -Subject: [PATCH 316/366] ehci: Correct a comment in fetchqtd packet - processing - -Since my previous comment said "Should never happen", I tried changing the -next line to an assert(0), which did not go well, which as the new comments -explains is logical if you think about it for a moment. - -Signed-off-by: Hans de Goede -Signed-off-by: Gerd Hoffmann ---- - hw/usb/hcd-ehci.c | 5 ++++- - 1 file changed, 4 insertions(+), 1 deletion(-) - -diff --git a/hw/usb/hcd-ehci.c b/hw/usb/hcd-ehci.c -index 2534394..2f3e9c0 100644 ---- a/hw/usb/hcd-ehci.c -+++ b/hw/usb/hcd-ehci.c -@@ -2045,7 +2045,10 @@ static int ehci_state_fetchqtd(EHCIQueue *q) - ehci_set_state(q->ehci, q->async, EST_HORIZONTALQH); - break; - case EHCI_ASYNC_FINISHED: -- /* Should never happen, as this case is caught by fetchqh */ -+ /* -+ * We get here when advqueue moves to a packet which is already -+ * finished, which can happen with packets queued up by fill_queue -+ */ - ehci_set_state(q->ehci, q->async, EST_EXECUTING); - break; - } --- -1.7.12 - diff --git a/0317-usb-redir-Never-return-USB_RET_NAK-for-async-handled.patch b/0317-usb-redir-Never-return-USB_RET_NAK-for-async-handled.patch deleted file mode 100644 index 01ce1e1..0000000 --- a/0317-usb-redir-Never-return-USB_RET_NAK-for-async-handled.patch +++ /dev/null @@ -1,44 +0,0 @@ -From a15db9c6d428a756f6ad4055334e476cd90b31f6 Mon Sep 17 00:00:00 2001 -From: Hans de Goede -Date: Fri, 17 Aug 2012 17:27:08 +0200 -Subject: [PATCH 317/366] usb-redir: Never return USB_RET_NAK for async - handled packets - -USB_RET_NAK is not a valid response for async handled packets (and will -trigger an assert as such). - -Also drop the warning when receiving a status of cancelled for packets not -cancelled by qemu itself, this can happen when a device gets unredirected -by the usbredir-host while transfers are pending. - -Signed-off-by: Hans de Goede -Signed-off-by: Gerd Hoffmann ---- - hw/usb/redirect.c | 9 ++++++--- - 1 file changed, 6 insertions(+), 3 deletions(-) - -diff --git a/hw/usb/redirect.c b/hw/usb/redirect.c -index 1460515..9ba964e 100644 ---- a/hw/usb/redirect.c -+++ b/hw/usb/redirect.c -@@ -1055,11 +1055,14 @@ static int usbredir_handle_status(USBRedirDevice *dev, - case usb_redir_stall: - return USB_RET_STALL; - case usb_redir_cancelled: -- WARNING("returning cancelled packet to HC?\n"); -- return USB_RET_NAK; -+ /* -+ * When the usbredir-host unredirects a device, it will report a status -+ * of cancelled for all pending packets, followed by a disconnect msg. -+ */ -+ return USB_RET_IOERROR; - case usb_redir_inval: - WARNING("got invalid param error from usb-host?\n"); -- return USB_RET_NAK; -+ return USB_RET_IOERROR; - case usb_redir_babble: - return USB_RET_BABBLE; - case usb_redir_ioerror: --- -1.7.12 - diff --git a/0318-usb-redir-Don-t-delay-handling-of-open-events-to-a-b.patch b/0318-usb-redir-Don-t-delay-handling-of-open-events-to-a-b.patch deleted file mode 100644 index 4994684..0000000 --- a/0318-usb-redir-Don-t-delay-handling-of-open-events-to-a-b.patch +++ /dev/null @@ -1,181 +0,0 @@ -From acf269a7bbed7c969eb9be02943f7e4b52196a8f Mon Sep 17 00:00:00 2001 -From: Hans de Goede -Date: Thu, 23 Aug 2012 16:37:19 +0200 -Subject: [PATCH 318/366] usb-redir: Don't delay handling of open events to a - bottom half - -There is no need for this, and doing so means that a backend trying to -write immediately after an open event will see qemu_chr_be_can_write -returning 0, which not all backends handle well as there is no wakeup -mechanism to detect when the frontend does become writable. - -Signed-off-by: Hans de Goede -Signed-off-by: Gerd Hoffmann ---- - hw/usb/redirect.c | 100 +++++++++++++++++++++++++++++------------------------- - 1 file changed, 53 insertions(+), 47 deletions(-) - -diff --git a/hw/usb/redirect.c b/hw/usb/redirect.c -index 9ba964e..8ac8637 100644 ---- a/hw/usb/redirect.c -+++ b/hw/usb/redirect.c -@@ -79,8 +79,8 @@ struct USBRedirDevice { - /* Data passed from chardev the fd_read cb to the usbredirparser read cb */ - const uint8_t *read_buf; - int read_buf_size; -- /* For async handling of open/close */ -- QEMUBH *open_close_bh; -+ /* For async handling of close */ -+ QEMUBH *chardev_close_bh; - /* To delay the usb attach in case of quick chardev close + open */ - QEMUTimer *attach_timer; - int64_t next_attach_time; -@@ -794,18 +794,11 @@ static int usbredir_handle_control(USBDevice *udev, USBPacket *p, - * from within the USBDevice data / control packet callbacks and doing a - * usb_detach from within these callbacks is not a good idea. - * -- * So we use a bh handler to take care of close events. We also handle -- * open events from this callback to make sure that a close directly followed -- * by an open gets handled in the right order. -+ * So we use a bh handler to take care of close events. - */ --static void usbredir_open_close_bh(void *opaque) -+static void usbredir_chardev_close_bh(void *opaque) - { - USBRedirDevice *dev = opaque; -- uint32_t caps[USB_REDIR_CAPS_SIZE] = { 0, }; -- char version[32]; -- -- strcpy(version, "qemu usb-redir guest "); -- pstrcat(version, sizeof(version), qemu_get_version()); - - usbredir_device_disconnect(dev); - -@@ -813,36 +806,47 @@ static void usbredir_open_close_bh(void *opaque) - usbredirparser_destroy(dev->parser); - dev->parser = NULL; - } -+} - -- if (dev->cs->opened) { -- dev->parser = qemu_oom_check(usbredirparser_create()); -- dev->parser->priv = dev; -- dev->parser->log_func = usbredir_log; -- dev->parser->read_func = usbredir_read; -- dev->parser->write_func = usbredir_write; -- dev->parser->hello_func = usbredir_hello; -- dev->parser->device_connect_func = usbredir_device_connect; -- dev->parser->device_disconnect_func = usbredir_device_disconnect; -- dev->parser->interface_info_func = usbredir_interface_info; -- dev->parser->ep_info_func = usbredir_ep_info; -- dev->parser->configuration_status_func = usbredir_configuration_status; -- dev->parser->alt_setting_status_func = usbredir_alt_setting_status; -- dev->parser->iso_stream_status_func = usbredir_iso_stream_status; -- dev->parser->interrupt_receiving_status_func = -- usbredir_interrupt_receiving_status; -- dev->parser->bulk_streams_status_func = usbredir_bulk_streams_status; -- dev->parser->control_packet_func = usbredir_control_packet; -- dev->parser->bulk_packet_func = usbredir_bulk_packet; -- dev->parser->iso_packet_func = usbredir_iso_packet; -- dev->parser->interrupt_packet_func = usbredir_interrupt_packet; -- dev->read_buf = NULL; -- dev->read_buf_size = 0; -+static void usbredir_chardev_open(USBRedirDevice *dev) -+{ -+ uint32_t caps[USB_REDIR_CAPS_SIZE] = { 0, }; -+ char version[32]; - -- usbredirparser_caps_set_cap(caps, usb_redir_cap_connect_device_version); -- usbredirparser_caps_set_cap(caps, usb_redir_cap_filter); -- usbredirparser_init(dev->parser, version, caps, USB_REDIR_CAPS_SIZE, 0); -- usbredirparser_do_write(dev->parser); -- } -+ /* Make sure any pending closes are handled (no-op if none pending) */ -+ usbredir_chardev_close_bh(dev); -+ qemu_bh_cancel(dev->chardev_close_bh); -+ -+ strcpy(version, "qemu usb-redir guest "); -+ pstrcat(version, sizeof(version), qemu_get_version()); -+ -+ dev->parser = qemu_oom_check(usbredirparser_create()); -+ dev->parser->priv = dev; -+ dev->parser->log_func = usbredir_log; -+ dev->parser->read_func = usbredir_read; -+ dev->parser->write_func = usbredir_write; -+ dev->parser->hello_func = usbredir_hello; -+ dev->parser->device_connect_func = usbredir_device_connect; -+ dev->parser->device_disconnect_func = usbredir_device_disconnect; -+ dev->parser->interface_info_func = usbredir_interface_info; -+ dev->parser->ep_info_func = usbredir_ep_info; -+ dev->parser->configuration_status_func = usbredir_configuration_status; -+ dev->parser->alt_setting_status_func = usbredir_alt_setting_status; -+ dev->parser->iso_stream_status_func = usbredir_iso_stream_status; -+ dev->parser->interrupt_receiving_status_func = -+ usbredir_interrupt_receiving_status; -+ dev->parser->bulk_streams_status_func = usbredir_bulk_streams_status; -+ dev->parser->control_packet_func = usbredir_control_packet; -+ dev->parser->bulk_packet_func = usbredir_bulk_packet; -+ dev->parser->iso_packet_func = usbredir_iso_packet; -+ dev->parser->interrupt_packet_func = usbredir_interrupt_packet; -+ dev->read_buf = NULL; -+ dev->read_buf_size = 0; -+ -+ usbredirparser_caps_set_cap(caps, usb_redir_cap_connect_device_version); -+ usbredirparser_caps_set_cap(caps, usb_redir_cap_filter); -+ usbredirparser_init(dev->parser, version, caps, USB_REDIR_CAPS_SIZE, 0); -+ usbredirparser_do_write(dev->parser); - } - - static void usbredir_do_attach(void *opaque) -@@ -866,13 +870,13 @@ static int usbredir_chardev_can_read(void *opaque) - { - USBRedirDevice *dev = opaque; - -- if (dev->parser) { -- /* usbredir_parser_do_read will consume *all* data we give it */ -- return 1024 * 1024; -- } else { -- /* usbredir_open_close_bh hasn't handled the open event yet */ -+ if (!dev->parser) { -+ WARNING("chardev_can_read called on non open chardev!\n"); - return 0; - } -+ -+ /* usbredir_parser_do_read will consume *all* data we give it */ -+ return 1024 * 1024; - } - - static void usbredir_chardev_read(void *opaque, const uint8_t *buf, int size) -@@ -896,8 +900,10 @@ static void usbredir_chardev_event(void *opaque, int event) - - switch (event) { - case CHR_EVENT_OPENED: -+ usbredir_chardev_open(dev); -+ break; - case CHR_EVENT_CLOSED: -- qemu_bh_schedule(dev->open_close_bh); -+ qemu_bh_schedule(dev->chardev_close_bh); - break; - } - } -@@ -945,7 +951,7 @@ static int usbredir_initfn(USBDevice *udev) - } - } - -- dev->open_close_bh = qemu_bh_new(usbredir_open_close_bh, dev); -+ dev->chardev_close_bh = qemu_bh_new(usbredir_chardev_close_bh, dev); - dev->attach_timer = qemu_new_timer_ms(vm_clock, usbredir_do_attach, dev); - - QTAILQ_INIT(&dev->asyncq); -@@ -984,7 +990,7 @@ static void usbredir_handle_destroy(USBDevice *udev) - qemu_chr_fe_close(dev->cs); - qemu_chr_delete(dev->cs); - /* Note must be done after qemu_chr_close, as that causes a close event */ -- qemu_bh_delete(dev->open_close_bh); -+ qemu_bh_delete(dev->chardev_close_bh); - - qemu_del_timer(dev->attach_timer); - qemu_free_timer(dev->attach_timer); --- -1.7.12 - diff --git a/0319-usb-redir-Get-rid-of-async-struct-get-member.patch b/0319-usb-redir-Get-rid-of-async-struct-get-member.patch deleted file mode 100644 index daf27ed..0000000 --- a/0319-usb-redir-Get-rid-of-async-struct-get-member.patch +++ /dev/null @@ -1,73 +0,0 @@ -From 5f83bc6b7bf54271bc1e3460b2e6f790407964e0 Mon Sep 17 00:00:00 2001 -From: Hans de Goede -Date: Mon, 27 Aug 2012 16:33:08 +0200 -Subject: [PATCH 319/366] usb-redir: Get rid of async-struct get member - -This is a preparation patch for completely getting rid of the async-packet -struct in usb-redir, instead relying on the (new) per ep queues in the -qemu usb core. - -Signed-off-by: Hans de Goede -Signed-off-by: Gerd Hoffmann ---- - hw/usb/redirect.c | 9 +++------ - 1 file changed, 3 insertions(+), 6 deletions(-) - -diff --git a/hw/usb/redirect.c b/hw/usb/redirect.c -index 8ac8637..4121983 100644 ---- a/hw/usb/redirect.c -+++ b/hw/usb/redirect.c -@@ -1,7 +1,7 @@ - /* - * USB redirector usb-guest - * -- * Copyright (c) 2011 Red Hat, Inc. -+ * Copyright (c) 2011-2012 Red Hat, Inc. - * - * Red Hat Authors: - * Hans de Goede -@@ -99,7 +99,6 @@ struct AsyncURB { - USBRedirDevice *dev; - USBPacket *packet; - uint32_t packet_id; -- int get; - union { - struct usb_redir_control_packet_header control_packet; - struct usb_redir_bulk_packet_header bulk_packet; -@@ -682,7 +681,6 @@ static int usbredir_get_config(USBRedirDevice *dev, USBPacket *p) - - DPRINTF("get config id %u\n", aurb->packet_id); - -- aurb->get = 1; - usbredirparser_send_get_configuration(dev->parser, aurb->packet_id); - usbredirparser_do_write(dev->parser); - return USB_RET_ASYNC; -@@ -731,7 +729,6 @@ static int usbredir_get_interface(USBRedirDevice *dev, USBPacket *p, - DPRINTF("get interface %d id %u\n", interface, aurb->packet_id); - - get_alt.interface = interface; -- aurb->get = 1; - usbredirparser_send_get_alt_setting(dev->parser, aurb->packet_id, - &get_alt); - usbredirparser_do_write(dev->parser); -@@ -1253,7 +1250,7 @@ static void usbredir_configuration_status(void *priv, uint32_t id, - return; - } - if (aurb->packet) { -- if (aurb->get) { -+ if (dev->dev.setup_buf[0] & USB_DIR_IN) { - dev->dev.data_buf[0] = config_status->configuration; - len = 1; - } -@@ -1281,7 +1278,7 @@ static void usbredir_alt_setting_status(void *priv, uint32_t id, - return; - } - if (aurb->packet) { -- if (aurb->get) { -+ if (dev->dev.setup_buf[0] & USB_DIR_IN) { - dev->dev.data_buf[0] = alt_setting_status->alt; - len = 1; - } --- -1.7.12 - diff --git a/0320-usb-redir-Get-rid-of-local-shadow-copy-of-packet-hea.patch b/0320-usb-redir-Get-rid-of-local-shadow-copy-of-packet-hea.patch deleted file mode 100644 index ea5b5ed..0000000 --- a/0320-usb-redir-Get-rid-of-local-shadow-copy-of-packet-hea.patch +++ /dev/null @@ -1,107 +0,0 @@ -From 3240adfcb041efcb11b4cbf4b08dc86be52b8ffc Mon Sep 17 00:00:00 2001 -From: Hans de Goede -Date: Tue, 28 Aug 2012 09:05:38 +0200 -Subject: [PATCH 320/366] usb-redir: Get rid of local shadow copy of packet - headers - -The shadow copy only serves as an extra check (besides the packet-id) to -ensure the packet we get back is a reply to the packet we think it is. - -This check has never triggered in all the time usb-redir is in use now, -and since the verified data in the returned packet-header is not used -otherwise, removing the check does not open any possibilities for the -usbredirhost to confuse us. - -This is a preparation patch for completely getting rid of the async-packet -struct in usb-redir, instead relying on the (new) per ep queues in the -qemu usb core. - -Signed-off-by: Hans de Goede -Signed-off-by: Gerd Hoffmann ---- - hw/usb/redirect.c | 27 --------------------------- - 1 file changed, 27 deletions(-) - -diff --git a/hw/usb/redirect.c b/hw/usb/redirect.c -index 4121983..816a19a 100644 ---- a/hw/usb/redirect.c -+++ b/hw/usb/redirect.c -@@ -99,11 +99,6 @@ struct AsyncURB { - USBRedirDevice *dev; - USBPacket *packet; - uint32_t packet_id; -- union { -- struct usb_redir_control_packet_header control_packet; -- struct usb_redir_bulk_packet_header bulk_packet; -- struct usb_redir_interrupt_packet_header interrupt_packet; -- }; - QTAILQ_ENTRY(AsyncURB)next; - }; - -@@ -510,7 +505,6 @@ static int usbredir_handle_bulk_data(USBRedirDevice *dev, USBPacket *p, - bulk_packet.endpoint = ep; - bulk_packet.length = p->iov.size; - bulk_packet.stream_id = 0; -- aurb->bulk_packet = bulk_packet; - - if (ep & USB_DIR_IN) { - usbredirparser_send_bulk_packet(dev->parser, aurb->packet_id, -@@ -591,7 +585,6 @@ static int usbredir_handle_interrupt_data(USBRedirDevice *dev, - - interrupt_packet.endpoint = ep; - interrupt_packet.length = p->iov.size; -- aurb->interrupt_packet = interrupt_packet; - - usb_packet_copy(p, buf, p->iov.size); - usbredir_log_data(dev, "interrupt data out:", buf, p->iov.size); -@@ -772,7 +765,6 @@ static int usbredir_handle_control(USBDevice *udev, USBPacket *p, - control_packet.value = value; - control_packet.index = index; - control_packet.length = length; -- aurb->control_packet = control_packet; - - if (control_packet.requesttype & USB_DIR_IN) { - usbredirparser_send_control_packet(dev->parser, aurb->packet_id, -@@ -1353,14 +1345,6 @@ static void usbredir_control_packet(void *priv, uint32_t id, - return; - } - -- aurb->control_packet.status = control_packet->status; -- aurb->control_packet.length = control_packet->length; -- if (memcmp(&aurb->control_packet, control_packet, -- sizeof(*control_packet))) { -- ERROR("return control packet mismatch, please report this!\n"); -- len = USB_RET_NAK; -- } -- - if (aurb->packet) { - len = usbredir_handle_status(dev, control_packet->status, len); - if (len > 0) { -@@ -1398,12 +1382,6 @@ static void usbredir_bulk_packet(void *priv, uint32_t id, - return; - } - -- if (aurb->bulk_packet.endpoint != bulk_packet->endpoint || -- aurb->bulk_packet.stream_id != bulk_packet->stream_id) { -- ERROR("return bulk packet mismatch, please report this!\n"); -- len = USB_RET_NAK; -- } -- - if (aurb->packet) { - len = usbredir_handle_status(dev, bulk_packet->status, len); - if (len > 0) { -@@ -1482,11 +1460,6 @@ static void usbredir_interrupt_packet(void *priv, uint32_t id, - return; - } - -- if (aurb->interrupt_packet.endpoint != interrupt_packet->endpoint) { -- ERROR("return int packet mismatch, please report this!\n"); -- len = USB_RET_NAK; -- } -- - if (aurb->packet) { - aurb->packet->result = usbredir_handle_status(dev, - interrupt_packet->status, len); --- -1.7.12 - diff --git a/0321-usb-redir-Get-rid-of-unused-async-struct-dev-member.patch b/0321-usb-redir-Get-rid-of-unused-async-struct-dev-member.patch deleted file mode 100644 index 3852c31..0000000 --- a/0321-usb-redir-Get-rid-of-unused-async-struct-dev-member.patch +++ /dev/null @@ -1,38 +0,0 @@ -From 1b1c99626404328b571e1f6c18b50f9bed9c2e2c Mon Sep 17 00:00:00 2001 -From: Hans de Goede -Date: Tue, 28 Aug 2012 09:08:45 +0200 -Subject: [PATCH 321/366] usb-redir: Get rid of unused async-struct dev member - -This is a preparation patch for completely getting rid of the async-packet -struct in usb-redir, instead relying on the (new) per ep queues in the -qemu usb core. - -Signed-off-by: Hans de Goede -Signed-off-by: Gerd Hoffmann ---- - hw/usb/redirect.c | 2 -- - 1 file changed, 2 deletions(-) - -diff --git a/hw/usb/redirect.c b/hw/usb/redirect.c -index 816a19a..4a23b82 100644 ---- a/hw/usb/redirect.c -+++ b/hw/usb/redirect.c -@@ -96,7 +96,6 @@ struct USBRedirDevice { - }; - - struct AsyncURB { -- USBRedirDevice *dev; - USBPacket *packet; - uint32_t packet_id; - QTAILQ_ENTRY(AsyncURB)next; -@@ -255,7 +254,6 @@ static int usbredir_write(void *priv, uint8_t *data, int count) - static AsyncURB *async_alloc(USBRedirDevice *dev, USBPacket *p) - { - AsyncURB *aurb = (AsyncURB *) g_malloc0(sizeof(AsyncURB)); -- aurb->dev = dev; - aurb->packet = p; - aurb->packet_id = dev->packet_id; - QTAILQ_INSERT_TAIL(&dev->asyncq, aurb, next); --- -1.7.12 - diff --git a/0322-usb-redir-Move-to-core-packet-id-and-queue-handling.patch b/0322-usb-redir-Move-to-core-packet-id-and-queue-handling.patch deleted file mode 100644 index 0bf0d67..0000000 --- a/0322-usb-redir-Move-to-core-packet-id-and-queue-handling.patch +++ /dev/null @@ -1,499 +0,0 @@ -From 69642884acc4f5d5b92e16d94fdae50765d1eba7 Mon Sep 17 00:00:00 2001 -From: Hans de Goede -Date: Tue, 28 Aug 2012 11:30:13 +0200 -Subject: [PATCH 322/366] usb-redir: Move to core packet id and queue handling - -Signed-off-by: Hans de Goede -Signed-off-by: Gerd Hoffmann ---- - hw/usb/redirect.c | 226 ++++++++++++++++++++++-------------------------------- - 1 file changed, 92 insertions(+), 134 deletions(-) - -diff --git a/hw/usb/redirect.c b/hw/usb/redirect.c -index 4a23b82..1ce994c 100644 ---- a/hw/usb/redirect.c -+++ b/hw/usb/redirect.c -@@ -43,7 +43,7 @@ - #define EP2I(ep_address) (((ep_address & 0x80) >> 3) | (ep_address & 0x0f)) - #define I2EP(i) (((i & 0x10) << 3) | (i & 0x0f)) - --typedef struct AsyncURB AsyncURB; -+typedef struct Cancelled Cancelled; - typedef struct USBRedirDevice USBRedirDevice; - - /* Struct to hold buffered packets (iso or int input packets) */ -@@ -86,8 +86,7 @@ struct USBRedirDevice { - int64_t next_attach_time; - struct usbredirparser *parser; - struct endp_data endpoint[MAX_ENDPOINTS]; -- uint32_t packet_id; -- QTAILQ_HEAD(, AsyncURB) asyncq; -+ QTAILQ_HEAD(, Cancelled) cancelled; - /* Data for device filtering */ - struct usb_redir_device_connect_header device_info; - struct usb_redir_interface_info_header interface_info; -@@ -95,10 +94,9 @@ struct USBRedirDevice { - int filter_rules_count; - }; - --struct AsyncURB { -- USBPacket *packet; -- uint32_t packet_id; -- QTAILQ_ENTRY(AsyncURB)next; -+struct Cancelled { -+ uint64_t id; -+ QTAILQ_ENTRY(Cancelled)next; - }; - - static void usbredir_hello(void *priv, struct usb_redir_hello_header *h); -@@ -248,57 +246,58 @@ static int usbredir_write(void *priv, uint8_t *data, int count) - } - - /* -- * Async and buffered packets helpers -+ * Cancelled and buffered packets helpers - */ - --static AsyncURB *async_alloc(USBRedirDevice *dev, USBPacket *p) -+static void usbredir_cancel_packet(USBDevice *udev, USBPacket *p) - { -- AsyncURB *aurb = (AsyncURB *) g_malloc0(sizeof(AsyncURB)); -- aurb->packet = p; -- aurb->packet_id = dev->packet_id; -- QTAILQ_INSERT_TAIL(&dev->asyncq, aurb, next); -- dev->packet_id++; -+ USBRedirDevice *dev = DO_UPCAST(USBRedirDevice, dev, udev); -+ Cancelled *c; - -- return aurb; --} -+ DPRINTF("cancel packet id %"PRIu64"\n", p->id); - --static void async_free(USBRedirDevice *dev, AsyncURB *aurb) --{ -- QTAILQ_REMOVE(&dev->asyncq, aurb, next); -- g_free(aurb); -+ c = g_malloc0(sizeof(Cancelled)); -+ c->id = p->id; -+ QTAILQ_INSERT_TAIL(&dev->cancelled, c, next); -+ -+ usbredirparser_send_cancel_data_packet(dev->parser, p->id); -+ usbredirparser_do_write(dev->parser); - } - --static AsyncURB *async_find(USBRedirDevice *dev, uint32_t packet_id) -+static int usbredir_is_cancelled(USBRedirDevice *dev, uint64_t id) - { -- AsyncURB *aurb; -+ Cancelled *c; -+ -+ if (!dev->dev.attached) { -+ return 1; /* Treat everything as cancelled after a disconnect */ -+ } - -- QTAILQ_FOREACH(aurb, &dev->asyncq, next) { -- if (aurb->packet_id == packet_id) { -- return aurb; -+ QTAILQ_FOREACH(c, &dev->cancelled, next) { -+ if (c->id == id) { -+ QTAILQ_REMOVE(&dev->cancelled, c, next); -+ g_free(c); -+ return 1; - } - } -- DPRINTF("could not find async urb for packet_id %u\n", packet_id); -- return NULL; -+ return 0; - } - --static void usbredir_cancel_packet(USBDevice *udev, USBPacket *p) -+static USBPacket *usbredir_find_packet_by_id(USBRedirDevice *dev, -+ uint8_t ep, uint64_t id) - { -- USBRedirDevice *dev = DO_UPCAST(USBRedirDevice, dev, udev); -- AsyncURB *aurb; -- -- QTAILQ_FOREACH(aurb, &dev->asyncq, next) { -- if (p != aurb->packet) { -- continue; -- } -+ USBPacket *p; - -- DPRINTF("async cancel id %u\n", aurb->packet_id); -- usbredirparser_send_cancel_data_packet(dev->parser, aurb->packet_id); -- usbredirparser_do_write(dev->parser); -+ if (usbredir_is_cancelled(dev, id)) { -+ return NULL; -+ } - -- /* Mark it as dead */ -- aurb->packet = NULL; -- break; -+ p = usb_ep_find_packet_by_id(&dev->dev, -+ (ep & USB_DIR_IN) ? USB_TOKEN_IN : USB_TOKEN_OUT, -+ ep & 0x0f, id); -+ if (p == NULL) { -+ ERROR("could not find packet with id %"PRIu64"\n", id); - } -+ return p; - } - - static void bufp_alloc(USBRedirDevice *dev, -@@ -494,24 +493,22 @@ static void usbredir_stop_iso_stream(USBRedirDevice *dev, uint8_t ep) - static int usbredir_handle_bulk_data(USBRedirDevice *dev, USBPacket *p, - uint8_t ep) - { -- AsyncURB *aurb = async_alloc(dev, p); - struct usb_redir_bulk_packet_header bulk_packet; - -- DPRINTF("bulk-out ep %02X len %zd id %u\n", ep, -- p->iov.size, aurb->packet_id); -+ DPRINTF("bulk-out ep %02X len %zd id %"PRIu64"\n", ep, p->iov.size, p->id); - - bulk_packet.endpoint = ep; - bulk_packet.length = p->iov.size; - bulk_packet.stream_id = 0; - - if (ep & USB_DIR_IN) { -- usbredirparser_send_bulk_packet(dev->parser, aurb->packet_id, -+ usbredirparser_send_bulk_packet(dev->parser, p->id, - &bulk_packet, NULL, 0); - } else { - uint8_t buf[p->iov.size]; - usb_packet_copy(p, buf, p->iov.size); - usbredir_log_data(dev, "bulk data out:", buf, p->iov.size); -- usbredirparser_send_bulk_packet(dev->parser, aurb->packet_id, -+ usbredirparser_send_bulk_packet(dev->parser, p->id, - &bulk_packet, buf, p->iov.size); - } - usbredirparser_do_write(dev->parser); -@@ -574,19 +571,18 @@ static int usbredir_handle_interrupt_data(USBRedirDevice *dev, - return len; - } else { - /* Output interrupt endpoint, normal async operation */ -- AsyncURB *aurb = async_alloc(dev, p); - struct usb_redir_interrupt_packet_header interrupt_packet; - uint8_t buf[p->iov.size]; - -- DPRINTF("interrupt-out ep %02X len %zd id %u\n", ep, p->iov.size, -- aurb->packet_id); -+ DPRINTF("interrupt-out ep %02X len %zd id %"PRIu64"\n", ep, -+ p->iov.size, p->id); - - interrupt_packet.endpoint = ep; - interrupt_packet.length = p->iov.size; - - usb_packet_copy(p, buf, p->iov.size); - usbredir_log_data(dev, "interrupt data out:", buf, p->iov.size); -- usbredirparser_send_interrupt_packet(dev->parser, aurb->packet_id, -+ usbredirparser_send_interrupt_packet(dev->parser, p->id, - &interrupt_packet, buf, p->iov.size); - usbredirparser_do_write(dev->parser); - return USB_RET_ASYNC; -@@ -640,10 +636,9 @@ static int usbredir_set_config(USBRedirDevice *dev, USBPacket *p, - int config) - { - struct usb_redir_set_configuration_header set_config; -- AsyncURB *aurb = async_alloc(dev, p); - int i; - -- DPRINTF("set config %d id %u\n", config, aurb->packet_id); -+ DPRINTF("set config %d id %"PRIu64"\n", config, p->id); - - for (i = 0; i < MAX_ENDPOINTS; i++) { - switch (dev->endpoint[i].type) { -@@ -660,19 +655,16 @@ static int usbredir_set_config(USBRedirDevice *dev, USBPacket *p, - } - - set_config.configuration = config; -- usbredirparser_send_set_configuration(dev->parser, aurb->packet_id, -- &set_config); -+ usbredirparser_send_set_configuration(dev->parser, p->id, &set_config); - usbredirparser_do_write(dev->parser); - return USB_RET_ASYNC; - } - - static int usbredir_get_config(USBRedirDevice *dev, USBPacket *p) - { -- AsyncURB *aurb = async_alloc(dev, p); -- -- DPRINTF("get config id %u\n", aurb->packet_id); -+ DPRINTF("get config id %"PRIu64"\n", p->id); - -- usbredirparser_send_get_configuration(dev->parser, aurb->packet_id); -+ usbredirparser_send_get_configuration(dev->parser, p->id); - usbredirparser_do_write(dev->parser); - return USB_RET_ASYNC; - } -@@ -681,11 +673,9 @@ static int usbredir_set_interface(USBRedirDevice *dev, USBPacket *p, - int interface, int alt) - { - struct usb_redir_set_alt_setting_header set_alt; -- AsyncURB *aurb = async_alloc(dev, p); - int i; - -- DPRINTF("set interface %d alt %d id %u\n", interface, alt, -- aurb->packet_id); -+ DPRINTF("set interface %d alt %d id %"PRIu64"\n", interface, alt, p->id); - - for (i = 0; i < MAX_ENDPOINTS; i++) { - if (dev->endpoint[i].interface == interface) { -@@ -705,8 +695,7 @@ static int usbredir_set_interface(USBRedirDevice *dev, USBPacket *p, - - set_alt.interface = interface; - set_alt.alt = alt; -- usbredirparser_send_set_alt_setting(dev->parser, aurb->packet_id, -- &set_alt); -+ usbredirparser_send_set_alt_setting(dev->parser, p->id, &set_alt); - usbredirparser_do_write(dev->parser); - return USB_RET_ASYNC; - } -@@ -715,13 +704,11 @@ static int usbredir_get_interface(USBRedirDevice *dev, USBPacket *p, - int interface) - { - struct usb_redir_get_alt_setting_header get_alt; -- AsyncURB *aurb = async_alloc(dev, p); - -- DPRINTF("get interface %d id %u\n", interface, aurb->packet_id); -+ DPRINTF("get interface %d id %"PRIu64"\n", interface, p->id); - - get_alt.interface = interface; -- usbredirparser_send_get_alt_setting(dev->parser, aurb->packet_id, -- &get_alt); -+ usbredirparser_send_get_alt_setting(dev->parser, p->id, &get_alt); - usbredirparser_do_write(dev->parser); - return USB_RET_ASYNC; - } -@@ -731,7 +718,6 @@ static int usbredir_handle_control(USBDevice *udev, USBPacket *p, - { - USBRedirDevice *dev = DO_UPCAST(USBRedirDevice, dev, udev); - struct usb_redir_control_packet_header control_packet; -- AsyncURB *aurb; - - /* Special cases for certain standard device requests */ - switch (request) { -@@ -749,13 +735,10 @@ static int usbredir_handle_control(USBDevice *udev, USBPacket *p, - return usbredir_get_interface(dev, p, index); - } - -- /* "Normal" ctrl requests */ -- aurb = async_alloc(dev, p); -- -- /* Note request is (bRequestType << 8) | bRequest */ -- DPRINTF("ctrl-out type 0x%x req 0x%x val 0x%x index %d len %d id %u\n", -- request >> 8, request & 0xff, value, index, length, -- aurb->packet_id); -+ /* Normal ctrl requests, note request is (bRequestType << 8) | bRequest */ -+ DPRINTF( -+ "ctrl-out type 0x%x req 0x%x val 0x%x index %d len %d id %"PRIu64"\n", -+ request >> 8, request & 0xff, value, index, length, p->id); - - control_packet.request = request & 0xFF; - control_packet.requesttype = request >> 8; -@@ -765,11 +748,11 @@ static int usbredir_handle_control(USBDevice *udev, USBPacket *p, - control_packet.length = length; - - if (control_packet.requesttype & USB_DIR_IN) { -- usbredirparser_send_control_packet(dev->parser, aurb->packet_id, -+ usbredirparser_send_control_packet(dev->parser, p->id, - &control_packet, NULL, 0); - } else { - usbredir_log_data(dev, "ctrl data out:", data, length); -- usbredirparser_send_control_packet(dev->parser, aurb->packet_id, -+ usbredirparser_send_control_packet(dev->parser, p->id, - &control_packet, data, length); - } - usbredirparser_do_write(dev->parser); -@@ -941,7 +924,7 @@ static int usbredir_initfn(USBDevice *udev) - dev->chardev_close_bh = qemu_bh_new(usbredir_chardev_close_bh, dev); - dev->attach_timer = qemu_new_timer_ms(vm_clock, usbredir_do_attach, dev); - -- QTAILQ_INIT(&dev->asyncq); -+ QTAILQ_INIT(&dev->cancelled); - for (i = 0; i < MAX_ENDPOINTS; i++) { - QTAILQ_INIT(&dev->endpoint[i].bufpq); - } -@@ -959,11 +942,12 @@ static int usbredir_initfn(USBDevice *udev) - - static void usbredir_cleanup_device_queues(USBRedirDevice *dev) - { -- AsyncURB *aurb, *next_aurb; -+ Cancelled *c, *next_c; - int i; - -- QTAILQ_FOREACH_SAFE(aurb, &dev->asyncq, next, next_aurb) { -- async_free(dev, aurb); -+ QTAILQ_FOREACH_SAFE(c, &dev->cancelled, next, next_c) { -+ QTAILQ_REMOVE(&dev->cancelled, c, next); -+ g_free(c); - } - for (i = 0; i < MAX_ENDPOINTS; i++) { - usbredir_free_bufpq(dev, I2EP(i)); -@@ -1229,33 +1213,28 @@ static void usbredir_configuration_status(void *priv, uint32_t id, - struct usb_redir_configuration_status_header *config_status) - { - USBRedirDevice *dev = priv; -- AsyncURB *aurb; -+ USBPacket *p; - int len = 0; - - DPRINTF("set config status %d config %d id %u\n", config_status->status, - config_status->configuration, id); - -- aurb = async_find(dev, id); -- if (!aurb) { -- return; -- } -- if (aurb->packet) { -+ p = usbredir_find_packet_by_id(dev, 0, id); -+ if (p) { - if (dev->dev.setup_buf[0] & USB_DIR_IN) { - dev->dev.data_buf[0] = config_status->configuration; - len = 1; - } -- aurb->packet->result = -- usbredir_handle_status(dev, config_status->status, len); -- usb_generic_async_ctrl_complete(&dev->dev, aurb->packet); -+ p->result = usbredir_handle_status(dev, config_status->status, len); -+ usb_generic_async_ctrl_complete(&dev->dev, p); - } -- async_free(dev, aurb); - } - - static void usbredir_alt_setting_status(void *priv, uint32_t id, - struct usb_redir_alt_setting_status_header *alt_setting_status) - { - USBRedirDevice *dev = priv; -- AsyncURB *aurb; -+ USBPacket *p; - int len = 0; - - DPRINTF("alt status %d intf %d alt %d id: %u\n", -@@ -1263,20 +1242,16 @@ static void usbredir_alt_setting_status(void *priv, uint32_t id, - alt_setting_status->interface, - alt_setting_status->alt, id); - -- aurb = async_find(dev, id); -- if (!aurb) { -- return; -- } -- if (aurb->packet) { -+ p = usbredir_find_packet_by_id(dev, 0, id); -+ if (p) { - if (dev->dev.setup_buf[0] & USB_DIR_IN) { - dev->dev.data_buf[0] = alt_setting_status->alt; - len = 1; - } -- aurb->packet->result = -+ p->result = - usbredir_handle_status(dev, alt_setting_status->status, len); -- usb_generic_async_ctrl_complete(&dev->dev, aurb->packet); -+ usb_generic_async_ctrl_complete(&dev->dev, p); - } -- async_free(dev, aurb); - } - - static void usbredir_iso_stream_status(void *priv, uint32_t id, -@@ -1331,19 +1306,14 @@ static void usbredir_control_packet(void *priv, uint32_t id, - uint8_t *data, int data_len) - { - USBRedirDevice *dev = priv; -+ USBPacket *p; - int len = control_packet->length; -- AsyncURB *aurb; - - DPRINTF("ctrl-in status %d len %d id %u\n", control_packet->status, - len, id); - -- aurb = async_find(dev, id); -- if (!aurb) { -- free(data); -- return; -- } -- -- if (aurb->packet) { -+ p = usbredir_find_packet_by_id(dev, 0, id); -+ if (p) { - len = usbredir_handle_status(dev, control_packet->status, len); - if (len > 0) { - usbredir_log_data(dev, "ctrl data in:", data, data_len); -@@ -1355,10 +1325,9 @@ static void usbredir_control_packet(void *priv, uint32_t id, - len = USB_RET_STALL; - } - } -- aurb->packet->result = len; -- usb_generic_async_ctrl_complete(&dev->dev, aurb->packet); -+ p->result = len; -+ usb_generic_async_ctrl_complete(&dev->dev, p); - } -- async_free(dev, aurb); - free(data); - } - -@@ -1369,33 +1338,27 @@ static void usbredir_bulk_packet(void *priv, uint32_t id, - USBRedirDevice *dev = priv; - uint8_t ep = bulk_packet->endpoint; - int len = bulk_packet->length; -- AsyncURB *aurb; -+ USBPacket *p; - - DPRINTF("bulk-in status %d ep %02X len %d id %u\n", bulk_packet->status, - ep, len, id); - -- aurb = async_find(dev, id); -- if (!aurb) { -- free(data); -- return; -- } -- -- if (aurb->packet) { -+ p = usbredir_find_packet_by_id(dev, ep, id); -+ if (p) { - len = usbredir_handle_status(dev, bulk_packet->status, len); - if (len > 0) { - usbredir_log_data(dev, "bulk data in:", data, data_len); -- if (data_len <= aurb->packet->iov.size) { -- usb_packet_copy(aurb->packet, data, data_len); -+ if (data_len <= p->iov.size) { -+ usb_packet_copy(p, data, data_len); - } else { - ERROR("bulk buffer too small (%d > %zd)\n", data_len, -- aurb->packet->iov.size); -+ p->iov.size); - len = USB_RET_STALL; - } - } -- aurb->packet->result = len; -- usb_packet_complete(&dev->dev, aurb->packet); -+ p->result = len; -+ usb_packet_complete(&dev->dev, p); - } -- async_free(dev, aurb); - free(data); - } - -@@ -1453,17 +1416,12 @@ static void usbredir_interrupt_packet(void *priv, uint32_t id, - } else { - int len = interrupt_packet->length; - -- AsyncURB *aurb = async_find(dev, id); -- if (!aurb) { -- return; -- } -- -- if (aurb->packet) { -- aurb->packet->result = usbredir_handle_status(dev, -+ USBPacket *p = usbredir_find_packet_by_id(dev, ep, id); -+ if (p) { -+ p->result = usbredir_handle_status(dev, - interrupt_packet->status, len); -- usb_packet_complete(&dev->dev, aurb->packet); -+ usb_packet_complete(&dev->dev, p); - } -- async_free(dev, aurb); - } - } - --- -1.7.12 - diff --git a/0323-usb-redir-Return-babble-when-getting-more-bulk-data-.patch b/0323-usb-redir-Return-babble-when-getting-more-bulk-data-.patch deleted file mode 100644 index 20a9db2..0000000 --- a/0323-usb-redir-Return-babble-when-getting-more-bulk-data-.patch +++ /dev/null @@ -1,34 +0,0 @@ -From bd0bc4416beb7ecef0baf2424250c07b9ef15fb6 Mon Sep 17 00:00:00 2001 -From: Hans de Goede -Date: Tue, 28 Aug 2012 11:33:47 +0200 -Subject: [PATCH 323/366] usb-redir: Return babble when getting more bulk data - then requested - -Babble is the appropriate error in this case (rather then signalling a stall). - -Signed-off-by: Hans de Goede -Signed-off-by: Gerd Hoffmann ---- - hw/usb/redirect.c | 6 +++--- - 1 file changed, 3 insertions(+), 3 deletions(-) - -diff --git a/hw/usb/redirect.c b/hw/usb/redirect.c -index 1ce994c..60b8f3e 100644 ---- a/hw/usb/redirect.c -+++ b/hw/usb/redirect.c -@@ -1351,9 +1351,9 @@ static void usbredir_bulk_packet(void *priv, uint32_t id, - if (data_len <= p->iov.size) { - usb_packet_copy(p, data, data_len); - } else { -- ERROR("bulk buffer too small (%d > %zd)\n", data_len, -- p->iov.size); -- len = USB_RET_STALL; -+ ERROR("bulk got more data then requested (%d > %zd)\n", -+ data_len, p->iov.size); -+ len = USB_RET_BABBLE; - } - } - p->result = len; --- -1.7.12 - diff --git a/0324-usb-redir-Convert-to-new-libusbredirparser-0.5-API.patch b/0324-usb-redir-Convert-to-new-libusbredirparser-0.5-API.patch deleted file mode 100644 index e6296ec..0000000 --- a/0324-usb-redir-Convert-to-new-libusbredirparser-0.5-API.patch +++ /dev/null @@ -1,232 +0,0 @@ -From 5ea5581f88d2e4bba876c2ee2544cf3641a64eca Mon Sep 17 00:00:00 2001 -From: Hans de Goede -Date: Fri, 31 Aug 2012 13:41:38 +0200 -Subject: [PATCH 324/366] usb-redir: Convert to new libusbredirparser 0.5 API - -This gives us support for 64 bit ids which is needed for using XHCI with -the new hcd generated ids. - -Signed-off-by: Hans de Goede -Signed-off-by: Gerd Hoffmann ---- - configure | 2 +- - hw/usb/redirect.c | 62 +++++++++++++++++++++++++++---------------------------- - 2 files changed, 32 insertions(+), 32 deletions(-) - -diff --git a/configure b/configure -index 0bfef84..25c406f 100755 ---- a/configure -+++ b/configure -@@ -2765,7 +2765,7 @@ fi - - # check for usbredirparser for usb network redirection support - if test "$usb_redir" != "no" ; then -- if $pkg_config --atleast-version=0.3.4 libusbredirparser >/dev/null 2>&1 ; then -+ if $pkg_config --atleast-version=0.5 libusbredirparser >/dev/null 2>&1 ; then - usb_redir="yes" - usb_redir_cflags=$($pkg_config --cflags libusbredirparser 2>/dev/null) - usb_redir_libs=$($pkg_config --libs libusbredirparser 2>/dev/null) -diff --git a/hw/usb/redirect.c b/hw/usb/redirect.c -index 60b8f3e..789ef51 100644 ---- a/hw/usb/redirect.c -+++ b/hw/usb/redirect.c -@@ -107,27 +107,27 @@ static void usbredir_interface_info(void *priv, - struct usb_redir_interface_info_header *interface_info); - static void usbredir_ep_info(void *priv, - struct usb_redir_ep_info_header *ep_info); --static void usbredir_configuration_status(void *priv, uint32_t id, -+static void usbredir_configuration_status(void *priv, uint64_t id, - struct usb_redir_configuration_status_header *configuration_status); --static void usbredir_alt_setting_status(void *priv, uint32_t id, -+static void usbredir_alt_setting_status(void *priv, uint64_t id, - struct usb_redir_alt_setting_status_header *alt_setting_status); --static void usbredir_iso_stream_status(void *priv, uint32_t id, -+static void usbredir_iso_stream_status(void *priv, uint64_t id, - struct usb_redir_iso_stream_status_header *iso_stream_status); --static void usbredir_interrupt_receiving_status(void *priv, uint32_t id, -+static void usbredir_interrupt_receiving_status(void *priv, uint64_t id, - struct usb_redir_interrupt_receiving_status_header - *interrupt_receiving_status); --static void usbredir_bulk_streams_status(void *priv, uint32_t id, -+static void usbredir_bulk_streams_status(void *priv, uint64_t id, - struct usb_redir_bulk_streams_status_header *bulk_streams_status); --static void usbredir_control_packet(void *priv, uint32_t id, -+static void usbredir_control_packet(void *priv, uint64_t id, - struct usb_redir_control_packet_header *control_packet, - uint8_t *data, int data_len); --static void usbredir_bulk_packet(void *priv, uint32_t id, -+static void usbredir_bulk_packet(void *priv, uint64_t id, - struct usb_redir_bulk_packet_header *bulk_packet, - uint8_t *data, int data_len); --static void usbredir_iso_packet(void *priv, uint32_t id, -+static void usbredir_iso_packet(void *priv, uint64_t id, - struct usb_redir_iso_packet_header *iso_packet, - uint8_t *data, int data_len); --static void usbredir_interrupt_packet(void *priv, uint32_t id, -+static void usbredir_interrupt_packet(void *priv, uint64_t id, - struct usb_redir_interrupt_packet_header *interrupt_header, - uint8_t *data, int data_len); - -@@ -815,6 +815,7 @@ static void usbredir_chardev_open(USBRedirDevice *dev) - - usbredirparser_caps_set_cap(caps, usb_redir_cap_connect_device_version); - usbredirparser_caps_set_cap(caps, usb_redir_cap_filter); -+ usbredirparser_caps_set_cap(caps, usb_redir_cap_64bits_ids); - usbredirparser_init(dev->parser, version, caps, USB_REDIR_CAPS_SIZE, 0); - usbredirparser_do_write(dev->parser); - } -@@ -1209,15 +1210,15 @@ static void usbredir_ep_info(void *priv, - } - } - --static void usbredir_configuration_status(void *priv, uint32_t id, -+static void usbredir_configuration_status(void *priv, uint64_t id, - struct usb_redir_configuration_status_header *config_status) - { - USBRedirDevice *dev = priv; - USBPacket *p; - int len = 0; - -- DPRINTF("set config status %d config %d id %u\n", config_status->status, -- config_status->configuration, id); -+ DPRINTF("set config status %d config %d id %"PRIu64"\n", -+ config_status->status, config_status->configuration, id); - - p = usbredir_find_packet_by_id(dev, 0, id); - if (p) { -@@ -1230,16 +1231,15 @@ static void usbredir_configuration_status(void *priv, uint32_t id, - } - } - --static void usbredir_alt_setting_status(void *priv, uint32_t id, -+static void usbredir_alt_setting_status(void *priv, uint64_t id, - struct usb_redir_alt_setting_status_header *alt_setting_status) - { - USBRedirDevice *dev = priv; - USBPacket *p; - int len = 0; - -- DPRINTF("alt status %d intf %d alt %d id: %u\n", -- alt_setting_status->status, -- alt_setting_status->interface, -+ DPRINTF("alt status %d intf %d alt %d id: %"PRIu64"\n", -+ alt_setting_status->status, alt_setting_status->interface, - alt_setting_status->alt, id); - - p = usbredir_find_packet_by_id(dev, 0, id); -@@ -1254,13 +1254,13 @@ static void usbredir_alt_setting_status(void *priv, uint32_t id, - } - } - --static void usbredir_iso_stream_status(void *priv, uint32_t id, -+static void usbredir_iso_stream_status(void *priv, uint64_t id, - struct usb_redir_iso_stream_status_header *iso_stream_status) - { - USBRedirDevice *dev = priv; - uint8_t ep = iso_stream_status->endpoint; - -- DPRINTF("iso status %d ep %02X id %u\n", iso_stream_status->status, -+ DPRINTF("iso status %d ep %02X id %"PRIu64"\n", iso_stream_status->status, - ep, id); - - if (!dev->dev.attached || !dev->endpoint[EP2I(ep)].iso_started) { -@@ -1274,14 +1274,14 @@ static void usbredir_iso_stream_status(void *priv, uint32_t id, - } - } - --static void usbredir_interrupt_receiving_status(void *priv, uint32_t id, -+static void usbredir_interrupt_receiving_status(void *priv, uint64_t id, - struct usb_redir_interrupt_receiving_status_header - *interrupt_receiving_status) - { - USBRedirDevice *dev = priv; - uint8_t ep = interrupt_receiving_status->endpoint; - -- DPRINTF("interrupt recv status %d ep %02X id %u\n", -+ DPRINTF("interrupt recv status %d ep %02X id %"PRIu64"\n", - interrupt_receiving_status->status, ep, id); - - if (!dev->dev.attached || !dev->endpoint[EP2I(ep)].interrupt_started) { -@@ -1296,12 +1296,12 @@ static void usbredir_interrupt_receiving_status(void *priv, uint32_t id, - } - } - --static void usbredir_bulk_streams_status(void *priv, uint32_t id, -+static void usbredir_bulk_streams_status(void *priv, uint64_t id, - struct usb_redir_bulk_streams_status_header *bulk_streams_status) - { - } - --static void usbredir_control_packet(void *priv, uint32_t id, -+static void usbredir_control_packet(void *priv, uint64_t id, - struct usb_redir_control_packet_header *control_packet, - uint8_t *data, int data_len) - { -@@ -1309,7 +1309,7 @@ static void usbredir_control_packet(void *priv, uint32_t id, - USBPacket *p; - int len = control_packet->length; - -- DPRINTF("ctrl-in status %d len %d id %u\n", control_packet->status, -+ DPRINTF("ctrl-in status %d len %d id %"PRIu64"\n", control_packet->status, - len, id); - - p = usbredir_find_packet_by_id(dev, 0, id); -@@ -1331,7 +1331,7 @@ static void usbredir_control_packet(void *priv, uint32_t id, - free(data); - } - --static void usbredir_bulk_packet(void *priv, uint32_t id, -+static void usbredir_bulk_packet(void *priv, uint64_t id, - struct usb_redir_bulk_packet_header *bulk_packet, - uint8_t *data, int data_len) - { -@@ -1340,8 +1340,8 @@ static void usbredir_bulk_packet(void *priv, uint32_t id, - int len = bulk_packet->length; - USBPacket *p; - -- DPRINTF("bulk-in status %d ep %02X len %d id %u\n", bulk_packet->status, -- ep, len, id); -+ DPRINTF("bulk-in status %d ep %02X len %d id %"PRIu64"\n", -+ bulk_packet->status, ep, len, id); - - p = usbredir_find_packet_by_id(dev, ep, id); - if (p) { -@@ -1362,15 +1362,15 @@ static void usbredir_bulk_packet(void *priv, uint32_t id, - free(data); - } - --static void usbredir_iso_packet(void *priv, uint32_t id, -+static void usbredir_iso_packet(void *priv, uint64_t id, - struct usb_redir_iso_packet_header *iso_packet, - uint8_t *data, int data_len) - { - USBRedirDevice *dev = priv; - uint8_t ep = iso_packet->endpoint; - -- DPRINTF2("iso-in status %d ep %02X len %d id %u\n", iso_packet->status, ep, -- data_len, id); -+ DPRINTF2("iso-in status %d ep %02X len %d id %"PRIu64"\n", -+ iso_packet->status, ep, data_len, id); - - if (dev->endpoint[EP2I(ep)].type != USB_ENDPOINT_XFER_ISOC) { - ERROR("received iso packet for non iso endpoint %02X\n", ep); -@@ -1388,14 +1388,14 @@ static void usbredir_iso_packet(void *priv, uint32_t id, - bufp_alloc(dev, data, data_len, iso_packet->status, ep); - } - --static void usbredir_interrupt_packet(void *priv, uint32_t id, -+static void usbredir_interrupt_packet(void *priv, uint64_t id, - struct usb_redir_interrupt_packet_header *interrupt_packet, - uint8_t *data, int data_len) - { - USBRedirDevice *dev = priv; - uint8_t ep = interrupt_packet->endpoint; - -- DPRINTF("interrupt-in status %d ep %02X len %d id %u\n", -+ DPRINTF("interrupt-in status %d ep %02X len %d id %"PRIu64"\n", - interrupt_packet->status, ep, data_len, id); - - if (dev->endpoint[EP2I(ep)].type != USB_ENDPOINT_XFER_INT) { --- -1.7.12 - diff --git a/0325-usb-redir-Set-ep-max_packet_size-if-available.patch b/0325-usb-redir-Set-ep-max_packet_size-if-available.patch deleted file mode 100644 index d9e15a5..0000000 --- a/0325-usb-redir-Set-ep-max_packet_size-if-available.patch +++ /dev/null @@ -1,39 +0,0 @@ -From 7c936f9e6b07f4468f49886b4e785e4120a08e11 Mon Sep 17 00:00:00 2001 -From: Hans de Goede -Date: Mon, 3 Sep 2012 11:49:07 +0200 -Subject: [PATCH 325/366] usb-redir: Set ep max_packet_size if available - -This is needed for usb-redir to work properly with the xhci emulation. - -Signed-off-by: Hans de Goede -Signed-off-by: Gerd Hoffmann ---- - hw/usb/redirect.c | 5 +++++ - 1 file changed, 5 insertions(+) - -diff --git a/hw/usb/redirect.c b/hw/usb/redirect.c -index 789ef51..ac8bfd2 100644 ---- a/hw/usb/redirect.c -+++ b/hw/usb/redirect.c -@@ -815,6 +815,7 @@ static void usbredir_chardev_open(USBRedirDevice *dev) - - usbredirparser_caps_set_cap(caps, usb_redir_cap_connect_device_version); - usbredirparser_caps_set_cap(caps, usb_redir_cap_filter); -+ usbredirparser_caps_set_cap(caps, usb_redir_cap_ep_info_max_packet_size); - usbredirparser_caps_set_cap(caps, usb_redir_cap_64bits_ids); - usbredirparser_init(dev->parser, version, caps, USB_REDIR_CAPS_SIZE, 0); - usbredirparser_do_write(dev->parser); -@@ -1207,6 +1208,10 @@ static void usbredir_ep_info(void *priv, - i & 0x0f); - usb_ep->type = dev->endpoint[i].type; - usb_ep->ifnum = dev->endpoint[i].interface; -+ if (usbredirparser_peer_has_cap(dev->parser, -+ usb_redir_cap_ep_info_max_packet_size)) { -+ usb_ep->max_packet_size = ep_info->max_packet_size[i]; -+ } - } - } - --- -1.7.12 - diff --git a/0326-usb-redir-Add-a-usbredir_reject_device-helper-functi.patch b/0326-usb-redir-Add-a-usbredir_reject_device-helper-functi.patch deleted file mode 100644 index d4cde52..0000000 --- a/0326-usb-redir-Add-a-usbredir_reject_device-helper-functi.patch +++ /dev/null @@ -1,59 +0,0 @@ -From 4ba71f5871be4d92f36097bc431fc303e1e42a7a Mon Sep 17 00:00:00 2001 -From: Hans de Goede -Date: Mon, 3 Sep 2012 11:53:28 +0200 -Subject: [PATCH 326/366] usb-redir: Add a usbredir_reject_device helper - function - -Signed-off-by: Hans de Goede -Signed-off-by: Gerd Hoffmann ---- - hw/usb/redirect.c | 21 +++++++++++---------- - 1 file changed, 11 insertions(+), 10 deletions(-) - -diff --git a/hw/usb/redirect.c b/hw/usb/redirect.c -index ac8bfd2..357f307 100644 ---- a/hw/usb/redirect.c -+++ b/hw/usb/redirect.c -@@ -821,16 +821,21 @@ static void usbredir_chardev_open(USBRedirDevice *dev) - usbredirparser_do_write(dev->parser); - } - -+static void usbredir_reject_device(USBRedirDevice *dev) -+{ -+ usbredir_device_disconnect(dev); -+ if (usbredirparser_peer_has_cap(dev->parser, usb_redir_cap_filter)) { -+ usbredirparser_send_filter_reject(dev->parser); -+ usbredirparser_do_write(dev->parser); -+ } -+} -+ - static void usbredir_do_attach(void *opaque) - { - USBRedirDevice *dev = opaque; - - if (usb_device_attach(&dev->dev) != 0) { -- usbredir_device_disconnect(dev); -- if (usbredirparser_peer_has_cap(dev->parser, usb_redir_cap_filter)) { -- usbredirparser_send_filter_reject(dev->parser); -- usbredirparser_do_write(dev->parser); -- } -+ usbredir_reject_device(dev); - } - } - -@@ -1013,11 +1018,7 @@ static int usbredir_check_filter(USBRedirDevice *dev) - return 0; - - error: -- usbredir_device_disconnect(dev); -- if (usbredirparser_peer_has_cap(dev->parser, usb_redir_cap_filter)) { -- usbredirparser_send_filter_reject(dev->parser); -- usbredirparser_do_write(dev->parser); -- } -+ usbredir_reject_device(dev); - return -1; - } - --- -1.7.12 - diff --git a/0327-usb-redir-Ensure-our-peer-has-the-necessary-caps-whe.patch b/0327-usb-redir-Ensure-our-peer-has-the-necessary-caps-whe.patch deleted file mode 100644 index f3ea67a..0000000 --- a/0327-usb-redir-Ensure-our-peer-has-the-necessary-caps-whe.patch +++ /dev/null @@ -1,43 +0,0 @@ -From af1ecda005c043dd8186725ae7a93ea66ebfe96f Mon Sep 17 00:00:00 2001 -From: Hans de Goede -Date: Mon, 3 Sep 2012 12:04:49 +0200 -Subject: [PATCH 327/366] usb-redir: Ensure our peer has the necessary caps - when redirecting to XHCI - -In order for redirection to work properly when redirecting to an emulated -XHCI controller, the usb-redir-host must support both -usb_redir_cap_ep_info_max_packet_size and usb_redir_cap_64bits_ids, -reject any devices redirected to an XHCI controller when these are not -supported. - -Signed-off-by: Hans de Goede -Signed-off-by: Gerd Hoffmann ---- - hw/usb/redirect.c | 11 +++++++++++ - 1 file changed, 11 insertions(+) - -diff --git a/hw/usb/redirect.c b/hw/usb/redirect.c -index 357f307..5b0f834 100644 ---- a/hw/usb/redirect.c -+++ b/hw/usb/redirect.c -@@ -834,6 +834,17 @@ static void usbredir_do_attach(void *opaque) - { - USBRedirDevice *dev = opaque; - -+ /* In order to work properly with XHCI controllers we need these caps */ -+ if ((dev->dev.port->speedmask & USB_SPEED_MASK_SUPER) && !( -+ usbredirparser_peer_has_cap(dev->parser, -+ usb_redir_cap_ep_info_max_packet_size) && -+ usbredirparser_peer_has_cap(dev->parser, -+ usb_redir_cap_64bits_ids))) { -+ ERROR("usb-redir-host lacks capabilities needed for use with XHCI\n"); -+ usbredir_reject_device(dev); -+ return; -+ } -+ - if (usb_device_attach(&dev->dev) != 0) { - usbredir_reject_device(dev); - } --- -1.7.12 - diff --git a/0328-usb-redir-Enable-pipelining-for-bulk-endpoints.patch b/0328-usb-redir-Enable-pipelining-for-bulk-endpoints.patch deleted file mode 100644 index 48de611..0000000 --- a/0328-usb-redir-Enable-pipelining-for-bulk-endpoints.patch +++ /dev/null @@ -1,28 +0,0 @@ -From 30b6793253b39f347e1f74791118403451b9886c Mon Sep 17 00:00:00 2001 -From: Hans de Goede -Date: Mon, 3 Sep 2012 13:44:04 +0200 -Subject: [PATCH 328/366] usb-redir: Enable pipelining for bulk endpoints - -Signed-off-by: Hans de Goede -Signed-off-by: Gerd Hoffmann ---- - hw/usb/redirect.c | 3 +++ - 1 file changed, 3 insertions(+) - -diff --git a/hw/usb/redirect.c b/hw/usb/redirect.c -index 5b0f834..9cbcddb 100644 ---- a/hw/usb/redirect.c -+++ b/hw/usb/redirect.c -@@ -1224,6 +1224,9 @@ static void usbredir_ep_info(void *priv, - usb_redir_cap_ep_info_max_packet_size)) { - usb_ep->max_packet_size = ep_info->max_packet_size[i]; - } -+ if (ep_info->type[i] == usb_redir_type_bulk) { -+ usb_ep->pipeline = true; -+ } - } - } - --- -1.7.12 - diff --git a/0329-Better-name-usb-braille-device.patch b/0329-Better-name-usb-braille-device.patch deleted file mode 100644 index b9cf4e6..0000000 --- a/0329-Better-name-usb-braille-device.patch +++ /dev/null @@ -1,30 +0,0 @@ -From f83e26f01f1489af484f69bdeb2d01d4896de6ec Mon Sep 17 00:00:00 2001 -From: Samuel Thibault -Date: Thu, 23 Aug 2012 09:59:27 +0200 -Subject: [PATCH 329/366] Better name usb braille device - -Windows users need to know that they have to use the Baum driver to make -the qemu braille device work. - -Signed-off-by: Samuel Thibault -Signed-off-by: Gerd Hoffmann ---- - 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 8fc9bdd..0ddfab6 100644 ---- a/hw/usb/dev-serial.c -+++ b/hw/usb/dev-serial.c -@@ -113,7 +113,7 @@ enum { - static const USBDescStrings desc_strings = { - [STR_MANUFACTURER] = "QEMU", - [STR_PRODUCT_SERIAL] = "QEMU USB SERIAL", -- [STR_PRODUCT_BRAILLE] = "QEMU USB BRAILLE", -+ [STR_PRODUCT_BRAILLE] = "QEMU USB BAUM BRAILLE", - [STR_SERIALNUMBER] = "1", - }; - --- -1.7.12 - diff --git a/0330-usb-audio-fix-usb-version.patch b/0330-usb-audio-fix-usb-version.patch deleted file mode 100644 index c79c18f..0000000 --- a/0330-usb-audio-fix-usb-version.patch +++ /dev/null @@ -1,29 +0,0 @@ -From 77824f2b7aba75a3f31a996634dc836fe26ee2c5 Mon Sep 17 00:00:00 2001 -From: Gerd Hoffmann -Date: Tue, 28 Aug 2012 16:43:34 +0200 -Subject: [PATCH 330/366] usb-audio: fix usb version - -usb-audio is a full speed (1.1) device, -but bcdUSB claims it is usb 2.0. Fix it. - -Signed-off-by: Gerd Hoffmann ---- - hw/usb/dev-audio.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/hw/usb/dev-audio.c b/hw/usb/dev-audio.c -index 79b75fb..2594c78 100644 ---- a/hw/usb/dev-audio.c -+++ b/hw/usb/dev-audio.c -@@ -217,7 +217,7 @@ static const USBDescIface desc_iface[] = { - }; - - static const USBDescDevice desc_device = { -- .bcdUSB = 0x0200, -+ .bcdUSB = 0x0100, - .bMaxPacketSize0 = 64, - .bNumConfigurations = 1, - .confs = (USBDescConfig[]) { --- -1.7.12 - diff --git a/0331-xhci-rip-out-background-transfer-code.patch b/0331-xhci-rip-out-background-transfer-code.patch deleted file mode 100644 index 4ccdfd5..0000000 --- a/0331-xhci-rip-out-background-transfer-code.patch +++ /dev/null @@ -1,324 +0,0 @@ -From f019cdb4b17a0615e897ddac37f2ffa8866a4979 Mon Sep 17 00:00:00 2001 -From: Gerd Hoffmann -Date: Fri, 17 Aug 2012 14:05:21 +0200 -Subject: [PATCH 331/366] xhci: rip out background transfer code - -original xhci code (the one which used libusb directly) used to use -'background transfers' for iso streams. In upstream qemu the iso -stream buffering is handled by usb-host & usb-redir, so we will -never ever need this. It has been left in as reference, but is dead -code anyway. Rip it out. - -Signed-off-by: Gerd Hoffmann ---- - hw/usb/hcd-xhci.c | 223 +----------------------------------------------------- - 1 file changed, 4 insertions(+), 219 deletions(-) - -diff --git a/hw/usb/hcd-xhci.c b/hw/usb/hcd-xhci.c -index 3eb27fa..c0a2476 100644 ---- a/hw/usb/hcd-xhci.c -+++ b/hw/usb/hcd-xhci.c -@@ -45,8 +45,6 @@ - #define MAXPORTS (USB2_PORTS+USB3_PORTS) - - #define TD_QUEUE 24 --#define BG_XFERS 8 --#define BG_PKTS 8 - - /* Very pessimistic, let's hope it's enough for all cases */ - #define EV_QUEUE (((3*TD_QUEUE)+16)*MAXSLOTS) -@@ -311,13 +309,11 @@ typedef struct XHCITransfer { - bool running_retry; - bool cancelled; - bool complete; -- bool backgrounded; - unsigned int iso_pkts; - unsigned int slotid; - unsigned int epid; - bool in_xfer; - bool iso_xfer; -- bool bg_xfer; - - unsigned int trb_count; - unsigned int trb_alloced; -@@ -340,14 +336,9 @@ typedef struct XHCIEPContext { - unsigned int comp_xfer; - XHCITransfer transfers[TD_QUEUE]; - XHCITransfer *retry; -- bool bg_running; -- bool bg_updating; -- unsigned int next_bg; -- XHCITransfer bg_transfers[BG_XFERS]; - EPType type; - dma_addr_t pctx; - unsigned int max_psize; -- bool has_bg; - uint32_t state; - } XHCIEPContext; - -@@ -866,10 +857,6 @@ static TRBCCode xhci_enable_ep(XHCIState *xhci, unsigned int slotid, - epctx->pctx = pctx; - epctx->max_psize = ctx[1]>>16; - epctx->max_psize *= 1+((ctx[1]>>8)&0xff); -- epctx->has_bg = false; -- if (epctx->type == ET_ISO_IN) { -- epctx->has_bg = true; -- } - DPRINTF("xhci: endpoint %d.%d max transaction (burst) size is %d\n", - epid/2, epid%2, epctx->max_psize); - for (i = 0; i < ARRAY_SIZE(epctx->transfers); i++) { -@@ -916,9 +903,6 @@ static int xhci_ep_nuke_xfers(XHCIState *xhci, unsigned int slotid, - t->running_retry = 0; - epctx->retry = NULL; - } -- if (t->backgrounded) { -- t->backgrounded = 0; -- } - if (t->trbs) { - g_free(t->trbs); - } -@@ -932,25 +916,6 @@ static int xhci_ep_nuke_xfers(XHCIState *xhci, unsigned int slotid, - t->data_length = t->data_alloced = 0; - xferi = (xferi + 1) % TD_QUEUE; - } -- if (epctx->has_bg) { -- xferi = epctx->next_bg; -- for (i = 0; i < BG_XFERS; i++) { -- XHCITransfer *t = &epctx->bg_transfers[xferi]; -- if (t->running_async) { -- usb_cancel_packet(&t->packet); -- t->running_async = 0; -- t->cancelled = 1; -- DPRINTF("xhci: cancelling bg transfer %d, waiting for it to complete...\n", i); -- killed++; -- } -- if (t->data) { -- g_free(t->data); -- } -- -- t->data = NULL; -- xferi = (xferi + 1) % BG_XFERS; -- } -- } - return killed; - } - -@@ -1231,160 +1196,6 @@ static void xhci_stall_ep(XHCITransfer *xfer) - static int xhci_submit(XHCIState *xhci, XHCITransfer *xfer, - XHCIEPContext *epctx); - --static void xhci_bg_update(XHCIState *xhci, XHCIEPContext *epctx) --{ -- if (epctx->bg_updating) { -- return; -- } -- DPRINTF("xhci_bg_update(%p, %p)\n", xhci, epctx); -- assert(epctx->has_bg); -- DPRINTF("xhci: fg=%d bg=%d\n", epctx->comp_xfer, epctx->next_bg); -- epctx->bg_updating = 1; -- while (epctx->transfers[epctx->comp_xfer].backgrounded && -- epctx->bg_transfers[epctx->next_bg].complete) { -- XHCITransfer *fg = &epctx->transfers[epctx->comp_xfer]; -- XHCITransfer *bg = &epctx->bg_transfers[epctx->next_bg]; --#if 0 -- DPRINTF("xhci: completing fg %d from bg %d.%d (stat: %d)\n", -- epctx->comp_xfer, epctx->next_bg, bg->cur_pkt, -- bg->usbxfer->iso_packet_desc[bg->cur_pkt].status -- ); --#endif -- assert(epctx->type == ET_ISO_IN); -- assert(bg->iso_xfer); -- assert(bg->in_xfer); -- uint8_t *p = bg->data + bg->cur_pkt * bg->pktsize; --#if 0 -- int len = bg->usbxfer->iso_packet_desc[bg->cur_pkt].actual_length; -- fg->status = libusb_to_ccode(bg->usbxfer->iso_packet_desc[bg->cur_pkt].status); --#else -- int len = 0; -- FIXME(); --#endif -- fg->complete = 1; -- fg->backgrounded = 0; -- -- if (fg->status == CC_STALL_ERROR) { -- xhci_stall_ep(fg); -- } -- -- xhci_xfer_data(fg, p, len, 1, 0, 1); -- -- epctx->comp_xfer++; -- if (epctx->comp_xfer == TD_QUEUE) { -- epctx->comp_xfer = 0; -- } -- DPRINTF("next fg xfer: %d\n", epctx->comp_xfer); -- bg->cur_pkt++; -- if (bg->cur_pkt == bg->pkts) { -- bg->complete = 0; -- if (xhci_submit(xhci, bg, epctx) < 0) { -- fprintf(stderr, "xhci: bg resubmit failed\n"); -- } -- epctx->next_bg++; -- if (epctx->next_bg == BG_XFERS) { -- epctx->next_bg = 0; -- } -- DPRINTF("next bg xfer: %d\n", epctx->next_bg); -- -- xhci_kick_ep(xhci, fg->slotid, fg->epid); -- } -- } -- epctx->bg_updating = 0; --} -- --#if 0 --static void xhci_xfer_cb(struct libusb_transfer *transfer) --{ -- XHCIState *xhci; -- XHCITransfer *xfer; -- -- xfer = (XHCITransfer *)transfer->user_data; -- xhci = xfer->xhci; -- -- DPRINTF("xhci_xfer_cb(slot=%d, ep=%d, status=%d)\n", xfer->slotid, -- xfer->epid, transfer->status); -- -- assert(xfer->slotid >= 1 && xfer->slotid <= MAXSLOTS); -- assert(xfer->epid >= 1 && xfer->epid <= 31); -- -- if (xfer->cancelled) { -- DPRINTF("xhci: transfer cancelled, not reporting anything\n"); -- xfer->running = 0; -- return; -- } -- -- XHCIEPContext *epctx; -- XHCISlot *slot; -- slot = &xhci->slots[xfer->slotid-1]; -- assert(slot->eps[xfer->epid-1]); -- epctx = slot->eps[xfer->epid-1]; -- -- if (xfer->bg_xfer) { -- DPRINTF("xhci: background transfer, updating\n"); -- xfer->complete = 1; -- xfer->running = 0; -- xhci_bg_update(xhci, epctx); -- return; -- } -- -- if (xfer->iso_xfer) { -- transfer->status = transfer->iso_packet_desc[0].status; -- transfer->actual_length = transfer->iso_packet_desc[0].actual_length; -- } -- -- xfer->status = libusb_to_ccode(transfer->status); -- -- xfer->complete = 1; -- xfer->running = 0; -- -- if (transfer->status == LIBUSB_TRANSFER_STALL) -- xhci_stall_ep(xhci, epctx, xfer); -- -- DPRINTF("xhci: transfer actual length = %d\n", transfer->actual_length); -- -- if (xfer->in_xfer) { -- if (xfer->epid == 1) { -- xhci_xfer_data(xhci, xfer, xfer->data + 8, -- transfer->actual_length, 1, 0, 1); -- } else { -- xhci_xfer_data(xhci, xfer, xfer->data, -- transfer->actual_length, 1, 0, 1); -- } -- } else { -- xhci_xfer_data(xhci, xfer, NULL, transfer->actual_length, 0, 0, 1); -- } -- -- xhci_kick_ep(xhci, xfer->slotid, xfer->epid); --} -- --static int xhci_hle_control(XHCIState *xhci, XHCITransfer *xfer, -- uint8_t bmRequestType, uint8_t bRequest, -- uint16_t wValue, uint16_t wIndex, uint16_t wLength) --{ -- uint16_t type_req = (bmRequestType << 8) | bRequest; -- -- switch (type_req) { -- case 0x0000 | USB_REQ_SET_CONFIGURATION: -- DPRINTF("xhci: HLE switch configuration\n"); -- return xhci_switch_config(xhci, xfer->slotid, wValue) == 0; -- case 0x0100 | USB_REQ_SET_INTERFACE: -- DPRINTF("xhci: HLE set interface altsetting\n"); -- return xhci_set_iface_alt(xhci, xfer->slotid, wIndex, wValue) == 0; -- case 0x0200 | USB_REQ_CLEAR_FEATURE: -- if (wValue == 0) { // endpoint halt -- DPRINTF("xhci: HLE clear halt\n"); -- return xhci_clear_halt(xhci, xfer->slotid, wIndex); -- } -- case 0x0000 | USB_REQ_SET_ADDRESS: -- fprintf(stderr, "xhci: warn: illegal SET_ADDRESS request\n"); -- return 0; -- default: -- return 0; -- } --} --#endif -- - static int xhci_setup_packet(XHCITransfer *xfer, USBDevice *dev) - { - USBEndpoint *ep; -@@ -1559,9 +1370,7 @@ static int xhci_submit(XHCIState *xhci, XHCITransfer *xfer, XHCIEPContext *epctx - xfer->data_alloced = xfer->data_length; - } - if (epctx->type == ET_ISO_IN || epctx->type == ET_ISO_OUT) { -- if (!xfer->bg_xfer) { -- xfer->pkts = 1; -- } -+ xfer->pkts = 1; - } else { - xfer->pkts = 0; - } -@@ -1620,32 +1429,8 @@ static int xhci_fire_transfer(XHCIState *xhci, XHCITransfer *xfer, XHCIEPContext - - trace_usb_xhci_xfer_start(xfer, xfer->slotid, xfer->epid, length); - -- if (!epctx->has_bg) { -- xfer->data_length = length; -- xfer->backgrounded = 0; -- return xhci_submit(xhci, xfer, epctx); -- } else { -- if (!epctx->bg_running) { -- for (i = 0; i < BG_XFERS; i++) { -- XHCITransfer *t = &epctx->bg_transfers[i]; -- t->xhci = xhci; -- t->epid = xfer->epid; -- t->slotid = xfer->slotid; -- t->pkts = BG_PKTS; -- t->pktsize = epctx->max_psize; -- t->data_length = t->pkts * t->pktsize; -- t->bg_xfer = 1; -- if (xhci_submit(xhci, t, epctx) < 0) { -- fprintf(stderr, "xhci: bg submit failed\n"); -- return -1; -- } -- } -- epctx->bg_running = 1; -- } -- xfer->backgrounded = 1; -- xhci_bg_update(xhci, epctx); -- return 0; -- } -+ xfer->data_length = length; -+ return xhci_submit(xhci, xfer, epctx); - } - - static void xhci_kick_ep(XHCIState *xhci, unsigned int slotid, unsigned int epid) -@@ -1695,7 +1480,7 @@ static void xhci_kick_ep(XHCIState *xhci, unsigned int slotid, unsigned int epid - - while (1) { - XHCITransfer *xfer = &epctx->transfers[epctx->next_xfer]; -- if (xfer->running_async || xfer->running_retry || xfer->backgrounded) { -+ if (xfer->running_async || xfer->running_retry) { - break; - } - length = xhci_ring_chain_length(xhci, &epctx->ring); --- -1.7.12 - diff --git a/0332-xhci-drop-buffering.patch b/0332-xhci-drop-buffering.patch deleted file mode 100644 index 67de840..0000000 --- a/0332-xhci-drop-buffering.patch +++ /dev/null @@ -1,383 +0,0 @@ -From ba184fe5a0e63bd40956b456d85a01da13d6183d Mon Sep 17 00:00:00 2001 -From: Gerd Hoffmann -Date: Fri, 17 Aug 2012 11:04:36 +0200 -Subject: [PATCH 332/369] xhci: drop buffering - -This patch splits the xhci_xfer_data function into three. -The xhci_xfer_data function used to do does two things: - - (1) copy transfer data between guest memory and a temporary buffer. - (2) report transfer results to the guest using events. - -Now we three functions to handle this: - - (1) xhci_xfer_map creates a scatter list for the transfer and - uses that (instead of the temporary buffer) to build a - USBPacket. - (2) xhci_xfer_unmap undoes the mapping. - (3) xhci_xfer_report sends out events. - -The patch also fixes reporting of transaction errors which must be -reported unconditinally, not only in case the guest asks for it -using the ISP flag. - -[ v2: fix warning ] - -Signed-off-by: Gerd Hoffmann ---- - hw/usb/hcd-xhci.c | 185 +++++++++++++++++++++--------------------------------- - trace-events | 2 +- - 2 files changed, 72 insertions(+), 115 deletions(-) - -diff --git a/hw/usb/hcd-xhci.c b/hw/usb/hcd-xhci.c -index c0a2476..446d692 100644 ---- a/hw/usb/hcd-xhci.c -+++ b/hw/usb/hcd-xhci.c -@@ -305,6 +305,7 @@ typedef struct XHCIState XHCIState; - typedef struct XHCITransfer { - XHCIState *xhci; - USBPacket packet; -+ QEMUSGList sgl; - bool running_async; - bool running_retry; - bool cancelled; -@@ -319,10 +320,6 @@ typedef struct XHCITransfer { - unsigned int trb_alloced; - XHCITRB *trbs; - -- unsigned int data_length; -- unsigned int data_alloced; -- uint8_t *data; -- - TRBCCode status; - - unsigned int pkts; -@@ -906,14 +903,9 @@ static int xhci_ep_nuke_xfers(XHCIState *xhci, unsigned int slotid, - if (t->trbs) { - g_free(t->trbs); - } -- if (t->data) { -- g_free(t->data); -- } - - t->trbs = NULL; -- t->data = NULL; - t->trb_count = t->trb_alloced = 0; -- t->data_length = t->data_alloced = 0; - xferi = (xferi + 1) % TD_QUEUE; - } - return killed; -@@ -1072,24 +1064,13 @@ static TRBCCode xhci_set_ep_dequeue(XHCIState *xhci, unsigned int slotid, - return CC_SUCCESS; - } - --static int xhci_xfer_data(XHCITransfer *xfer, uint8_t *data, -- unsigned int length, bool in_xfer, bool out_xfer, -- bool report) -+static int xhci_xfer_map(XHCITransfer *xfer) - { -- int i; -- uint32_t edtla = 0; -- unsigned int transferred = 0; -- unsigned int left = length; -- bool reported = 0; -- bool shortpkt = 0; -- XHCIEvent event = {ER_TRANSFER, CC_SUCCESS}; -+ int in_xfer = (xfer->packet.pid == USB_TOKEN_IN); - XHCIState *xhci = xfer->xhci; -+ int i; - -- DPRINTF("xhci_xfer_data(len=%d, in_xfer=%d, out_xfer=%d, report=%d)\n", -- length, in_xfer, out_xfer, report); -- -- assert(!(in_xfer && out_xfer)); -- -+ pci_dma_sglist_init(&xfer->sgl, &xhci->pci_dev, xfer->trb_count); - for (i = 0; i < xfer->trb_count; i++) { - XHCITRB *trb = &xfer->trbs[i]; - dma_addr_t addr; -@@ -1099,54 +1080,70 @@ static int xhci_xfer_data(XHCITransfer *xfer, uint8_t *data, - case TR_DATA: - if ((!(trb->control & TRB_TR_DIR)) != (!in_xfer)) { - fprintf(stderr, "xhci: data direction mismatch for TR_DATA\n"); -- xhci_die(xhci); -- return transferred; -+ goto err; - } - /* fallthrough */ - case TR_NORMAL: - case TR_ISOCH: - addr = xhci_mask64(trb->parameter); - chunk = trb->status & 0x1ffff; -+ if (trb->control & TRB_TR_IDT) { -+ if (chunk > 8 || in_xfer) { -+ fprintf(stderr, "xhci: invalid immediate data TRB\n"); -+ goto err; -+ } -+ qemu_sglist_add(&xfer->sgl, trb->addr, chunk); -+ } else { -+ qemu_sglist_add(&xfer->sgl, addr, chunk); -+ } -+ break; -+ } -+ } -+ -+ usb_packet_map(&xfer->packet, &xfer->sgl); -+ return 0; -+ -+err: -+ qemu_sglist_destroy(&xfer->sgl); -+ xhci_die(xhci); -+ return -1; -+} -+ -+static void xhci_xfer_unmap(XHCITransfer *xfer) -+{ -+ usb_packet_unmap(&xfer->packet, &xfer->sgl); -+ qemu_sglist_destroy(&xfer->sgl); -+} -+ -+static void xhci_xfer_report(XHCITransfer *xfer) -+{ -+ uint32_t edtla = 0; -+ unsigned int left; -+ bool reported = 0; -+ bool shortpkt = 0; -+ XHCIEvent event = {ER_TRANSFER, CC_SUCCESS}; -+ XHCIState *xhci = xfer->xhci; -+ int i; -+ -+ left = xfer->packet.result < 0 ? 0 : xfer->packet.result; -+ -+ for (i = 0; i < xfer->trb_count; i++) { -+ XHCITRB *trb = &xfer->trbs[i]; -+ unsigned int chunk = 0; -+ -+ switch (TRB_TYPE(*trb)) { -+ case TR_DATA: -+ case TR_NORMAL: -+ case TR_ISOCH: -+ chunk = trb->status & 0x1ffff; - if (chunk > left) { - chunk = left; -- shortpkt = 1; -- } -- if (in_xfer || out_xfer) { -- if (trb->control & TRB_TR_IDT) { -- uint64_t idata; -- if (chunk > 8 || in_xfer) { -- fprintf(stderr, "xhci: invalid immediate data TRB\n"); -- xhci_die(xhci); -- return transferred; -- } -- idata = le64_to_cpu(trb->parameter); -- memcpy(data, &idata, chunk); -- } else { -- DPRINTF("xhci_xfer_data: r/w(%d) %d bytes at " -- DMA_ADDR_FMT "\n", in_xfer, chunk, addr); -- if (in_xfer) { -- pci_dma_write(&xhci->pci_dev, addr, data, chunk); -- } else { -- pci_dma_read(&xhci->pci_dev, addr, data, chunk); -- } --#ifdef DEBUG_DATA -- unsigned int count = chunk; -- int i; -- if (count > 16) { -- count = 16; -- } -- DPRINTF(" ::"); -- for (i = 0; i < count; i++) { -- DPRINTF(" %02x", data[i]); -- } -- DPRINTF("\n"); --#endif -+ if (xfer->status == CC_SUCCESS) { -+ shortpkt = 1; - } - } - left -= chunk; -- data += chunk; - edtla += chunk; -- transferred += chunk; - break; - case TR_STATUS: - reported = 0; -@@ -1154,8 +1151,9 @@ static int xhci_xfer_data(XHCITransfer *xfer, uint8_t *data, - break; - } - -- if (report && !reported && (trb->control & TRB_TR_IOC || -- (shortpkt && (trb->control & TRB_TR_ISP)))) { -+ if (!reported && ((trb->control & TRB_TR_IOC) || -+ (shortpkt && (trb->control & TRB_TR_ISP)) || -+ (xfer->status != CC_SUCCESS))) { - event.slotid = xfer->slotid; - event.epid = xfer->epid; - event.length = (trb->status & 0x1ffff) - chunk; -@@ -1175,9 +1173,11 @@ static int xhci_xfer_data(XHCITransfer *xfer, uint8_t *data, - } - xhci_event(xhci, &event); - reported = 1; -+ if (xfer->status != CC_SUCCESS) { -+ return; -+ } - } - } -- return transferred; - } - - static void xhci_stall_ep(XHCITransfer *xfer) -@@ -1204,7 +1204,7 @@ static int xhci_setup_packet(XHCITransfer *xfer, USBDevice *dev) - dir = xfer->in_xfer ? USB_TOKEN_IN : USB_TOKEN_OUT; - ep = usb_ep_get(dev, dir, xfer->epid >> 1); - usb_packet_setup(&xfer->packet, dir, ep, xfer->trbs[0].addr); -- usb_packet_addbuf(&xfer->packet, xfer->data, xfer->data_length); -+ xhci_xfer_map(xfer); - DPRINTF("xhci: setup packet pid 0x%x addr %d ep %d\n", - xfer->packet.pid, dev->addr, ep->nr); - return 0; -@@ -1230,12 +1230,13 @@ static int xhci_complete_packet(XHCITransfer *xfer, int ret) - xfer->running_async = 0; - xfer->running_retry = 0; - xfer->complete = 1; -+ xhci_xfer_unmap(xfer); - } - - if (ret >= 0) { -- xfer->status = CC_SUCCESS; -- xhci_xfer_data(xfer, xfer->data, ret, xfer->in_xfer, 0, 1); - trace_usb_xhci_xfer_success(xfer, ret); -+ xfer->status = CC_SUCCESS; -+ xhci_xfer_report(xfer); - return 0; - } - -@@ -1244,12 +1245,12 @@ static int xhci_complete_packet(XHCITransfer *xfer, int ret) - switch (ret) { - case USB_RET_NODEV: - xfer->status = CC_USB_TRANSACTION_ERROR; -- xhci_xfer_data(xfer, xfer->data, 0, xfer->in_xfer, 0, 1); -+ xhci_xfer_report(xfer); - xhci_stall_ep(xfer); - break; - case USB_RET_STALL: - xfer->status = CC_STALL_ERROR; -- xhci_xfer_data(xfer, xfer->data, 0, xfer->in_xfer, 0, 1); -+ xhci_xfer_report(xfer); - xhci_stall_ep(xfer); - break; - default: -@@ -1271,7 +1272,6 @@ static int xhci_fire_ctl_transfer(XHCIState *xhci, XHCITransfer *xfer) - { - XHCITRB *trb_setup, *trb_status; - uint8_t bmRequestType; -- uint16_t wLength; - XHCIPort *port; - USBDevice *dev; - int ret; -@@ -1279,8 +1279,7 @@ static int xhci_fire_ctl_transfer(XHCIState *xhci, XHCITransfer *xfer) - trb_setup = &xfer->trbs[0]; - trb_status = &xfer->trbs[xfer->trb_count-1]; - -- trace_usb_xhci_xfer_start(xfer, xfer->slotid, xfer->epid, -- trb_setup->parameter >> 48); -+ trace_usb_xhci_xfer_start(xfer, xfer->slotid, xfer->epid); - - /* at most one Event Data TRB allowed after STATUS */ - if (TRB_TYPE(*trb_status) == TR_EVDATA && xfer->trb_count > 2) { -@@ -1309,19 +1308,6 @@ static int xhci_fire_ctl_transfer(XHCIState *xhci, XHCITransfer *xfer) - } - - bmRequestType = trb_setup->parameter; -- wLength = trb_setup->parameter >> 48; -- -- if (xfer->data && xfer->data_alloced < wLength) { -- xfer->data_alloced = 0; -- g_free(xfer->data); -- xfer->data = NULL; -- } -- if (!xfer->data) { -- DPRINTF("xhci: alloc %d bytes data\n", wLength); -- xfer->data = g_malloc(wLength+1); -- xfer->data_alloced = wLength; -- } -- xfer->data_length = wLength; - - port = &xhci->ports[xhci->slots[xfer->slotid-1].port-1]; - dev = xhci_find_device(port, xhci->slots[xfer->slotid-1].devaddr); -@@ -1336,9 +1322,6 @@ static int xhci_fire_ctl_transfer(XHCIState *xhci, XHCITransfer *xfer) - - xhci_setup_packet(xfer, dev); - xfer->packet.parameter = trb_setup->parameter; -- if (!xfer->in_xfer) { -- xhci_xfer_data(xfer, xfer->data, wLength, 0, 1, 0); -- } - - ret = usb_handle_packet(dev, &xfer->packet); - -@@ -1359,16 +1342,6 @@ static int xhci_submit(XHCIState *xhci, XHCITransfer *xfer, XHCIEPContext *epctx - - xfer->in_xfer = epctx->type>>2; - -- if (xfer->data && xfer->data_alloced < xfer->data_length) { -- xfer->data_alloced = 0; -- g_free(xfer->data); -- xfer->data = NULL; -- } -- if (!xfer->data && xfer->data_length) { -- DPRINTF("xhci: alloc %d bytes data\n", xfer->data_length); -- xfer->data = g_malloc(xfer->data_length); -- xfer->data_alloced = xfer->data_length; -- } - if (epctx->type == ET_ISO_IN || epctx->type == ET_ISO_OUT) { - xfer->pkts = 1; - } else { -@@ -1402,9 +1375,6 @@ static int xhci_submit(XHCIState *xhci, XHCITransfer *xfer, XHCIEPContext *epctx - return -1; - } - -- if (!xfer->in_xfer) { -- xhci_xfer_data(xfer, xfer->data, xfer->data_length, 0, 1, 0); -- } - ret = usb_handle_packet(dev, &xfer->packet); - - xhci_complete_packet(xfer, ret); -@@ -1416,20 +1386,7 @@ static int xhci_submit(XHCIState *xhci, XHCITransfer *xfer, XHCIEPContext *epctx - - static int xhci_fire_transfer(XHCIState *xhci, XHCITransfer *xfer, XHCIEPContext *epctx) - { -- int i; -- unsigned int length = 0; -- XHCITRB *trb; -- -- for (i = 0; i < xfer->trb_count; i++) { -- trb = &xfer->trbs[i]; -- if (TRB_TYPE(*trb) == TR_NORMAL || TRB_TYPE(*trb) == TR_ISOCH) { -- length += trb->status & 0x1ffff; -- } -- } -- -- trace_usb_xhci_xfer_start(xfer, xfer->slotid, xfer->epid, length); -- -- xfer->data_length = length; -+ trace_usb_xhci_xfer_start(xfer, xfer->slotid, xfer->epid); - return xhci_submit(xhci, xfer, epctx); - } - -diff --git a/trace-events b/trace-events -index 10bc04e..c83d65e 100644 ---- a/trace-events -+++ b/trace-events -@@ -326,7 +326,7 @@ usb_xhci_ep_disable(uint32_t slotid, uint32_t epid) "slotid %d, epid %d" - usb_xhci_ep_kick(uint32_t slotid, uint32_t epid) "slotid %d, epid %d" - usb_xhci_ep_stop(uint32_t slotid, uint32_t epid) "slotid %d, epid %d" - usb_xhci_ep_reset(uint32_t slotid, uint32_t epid) "slotid %d, epid %d" --usb_xhci_xfer_start(void *xfer, uint32_t slotid, uint32_t epid, uint32_t length) "%p: slotid %d, epid %d, length %d" -+usb_xhci_xfer_start(void *xfer, uint32_t slotid, uint32_t epid) "%p: slotid %d, epid %d" - usb_xhci_xfer_async(void *xfer) "%p" - usb_xhci_xfer_nak(void *xfer) "%p" - usb_xhci_xfer_retry(void *xfer) "%p" --- -1.7.12 - diff --git a/0333-xhci-move-device-lookup-into-xhci_setup_packet.patch b/0333-xhci-move-device-lookup-into-xhci_setup_packet.patch deleted file mode 100644 index 2ac0629..0000000 --- a/0333-xhci-move-device-lookup-into-xhci_setup_packet.patch +++ /dev/null @@ -1,154 +0,0 @@ -From e144accdeb05222cf671c3bad142c81c40dbacdb Mon Sep 17 00:00:00 2001 -From: Gerd Hoffmann -Date: Fri, 24 Aug 2012 14:21:39 +0200 -Subject: [PATCH 333/369] xhci: move device lookup into xhci_setup_packet - -Signed-off-by: Gerd Hoffmann ---- - hw/usb/hcd-xhci.c | 74 ++++++++++++++++++++++++++++--------------------------- - 1 file changed, 38 insertions(+), 36 deletions(-) - -diff --git a/hw/usb/hcd-xhci.c b/hw/usb/hcd-xhci.c -index 446d692..c108c9d 100644 ---- a/hw/usb/hcd-xhci.c -+++ b/hw/usb/hcd-xhci.c -@@ -1196,13 +1196,38 @@ static void xhci_stall_ep(XHCITransfer *xfer) - static int xhci_submit(XHCIState *xhci, XHCITransfer *xfer, - XHCIEPContext *epctx); - --static int xhci_setup_packet(XHCITransfer *xfer, USBDevice *dev) -+static USBDevice *xhci_find_device(XHCIPort *port, uint8_t addr) - { -+ if (!(port->portsc & PORTSC_PED)) { -+ return NULL; -+ } -+ return usb_find_device(&port->port, addr); -+} -+ -+static int xhci_setup_packet(XHCITransfer *xfer) -+{ -+ XHCIState *xhci = xfer->xhci; -+ XHCIPort *port; -+ USBDevice *dev; - USBEndpoint *ep; - int dir; - - dir = xfer->in_xfer ? USB_TOKEN_IN : USB_TOKEN_OUT; -- ep = usb_ep_get(dev, dir, xfer->epid >> 1); -+ -+ if (xfer->packet.ep) { -+ ep = xfer->packet.ep; -+ dev = ep->dev; -+ } else { -+ port = &xhci->ports[xhci->slots[xfer->slotid-1].port-1]; -+ dev = xhci_find_device(port, xhci->slots[xfer->slotid-1].devaddr); -+ if (!dev) { -+ fprintf(stderr, "xhci: slot %d port %d has no device\n", -+ xfer->slotid, xhci->slots[xfer->slotid-1].port); -+ return -1; -+ } -+ ep = usb_ep_get(dev, dir, xfer->epid >> 1); -+ } -+ - usb_packet_setup(&xfer->packet, dir, ep, xfer->trbs[0].addr); - xhci_xfer_map(xfer); - DPRINTF("xhci: setup packet pid 0x%x addr %d ep %d\n", -@@ -1260,20 +1285,10 @@ static int xhci_complete_packet(XHCITransfer *xfer, int ret) - return 0; - } - --static USBDevice *xhci_find_device(XHCIPort *port, uint8_t addr) --{ -- if (!(port->portsc & PORTSC_PED)) { -- return NULL; -- } -- return usb_find_device(&port->port, addr); --} -- - static int xhci_fire_ctl_transfer(XHCIState *xhci, XHCITransfer *xfer) - { - XHCITRB *trb_setup, *trb_status; - uint8_t bmRequestType; -- XHCIPort *port; -- USBDevice *dev; - int ret; - - trb_setup = &xfer->trbs[0]; -@@ -1309,21 +1324,15 @@ static int xhci_fire_ctl_transfer(XHCIState *xhci, XHCITransfer *xfer) - - bmRequestType = trb_setup->parameter; - -- port = &xhci->ports[xhci->slots[xfer->slotid-1].port-1]; -- dev = xhci_find_device(port, xhci->slots[xfer->slotid-1].devaddr); -- if (!dev) { -- fprintf(stderr, "xhci: slot %d port %d has no device\n", xfer->slotid, -- xhci->slots[xfer->slotid-1].port); -- return -1; -- } -- - xfer->in_xfer = bmRequestType & USB_DIR_IN; - xfer->iso_xfer = false; - -- xhci_setup_packet(xfer, dev); -+ if (xhci_setup_packet(xfer) < 0) { -+ return -1; -+ } - xfer->packet.parameter = trb_setup->parameter; - -- ret = usb_handle_packet(dev, &xfer->packet); -+ ret = usb_handle_packet(xfer->packet.ep->dev, &xfer->packet); - - xhci_complete_packet(xfer, ret); - if (!xfer->running_async && !xfer->running_retry) { -@@ -1334,8 +1343,6 @@ static int xhci_fire_ctl_transfer(XHCIState *xhci, XHCITransfer *xfer) - - static int xhci_submit(XHCIState *xhci, XHCITransfer *xfer, XHCIEPContext *epctx) - { -- XHCIPort *port; -- USBDevice *dev; - int ret; - - DPRINTF("xhci_submit(slotid=%d,epid=%d)\n", xfer->slotid, xfer->epid); -@@ -1348,16 +1355,6 @@ static int xhci_submit(XHCIState *xhci, XHCITransfer *xfer, XHCIEPContext *epctx - xfer->pkts = 0; - } - -- port = &xhci->ports[xhci->slots[xfer->slotid-1].port-1]; -- dev = xhci_find_device(port, xhci->slots[xfer->slotid-1].devaddr); -- if (!dev) { -- fprintf(stderr, "xhci: slot %d port %d has no device\n", xfer->slotid, -- xhci->slots[xfer->slotid-1].port); -- return -1; -- } -- -- xhci_setup_packet(xfer, dev); -- - switch(epctx->type) { - case ET_INTR_OUT: - case ET_INTR_IN: -@@ -1375,7 +1372,10 @@ static int xhci_submit(XHCIState *xhci, XHCITransfer *xfer, XHCIEPContext *epctx - return -1; - } - -- ret = usb_handle_packet(dev, &xfer->packet); -+ if (xhci_setup_packet(xfer) < 0) { -+ return -1; -+ } -+ ret = usb_handle_packet(xfer->packet.ep->dev, &xfer->packet); - - xhci_complete_packet(xfer, ret); - if (!xfer->running_async && !xfer->running_retry) { -@@ -1418,7 +1418,9 @@ static void xhci_kick_ep(XHCIState *xhci, unsigned int slotid, unsigned int epid - - trace_usb_xhci_xfer_retry(xfer); - assert(xfer->running_retry); -- xhci_setup_packet(xfer, xfer->packet.ep->dev); -+ if (xhci_setup_packet(xfer) < 0) { -+ return; -+ } - result = usb_handle_packet(xfer->packet.ep->dev, &xfer->packet); - if (result == USB_RET_NAK) { - return; --- -1.7.12 - diff --git a/0334-xhci-implement-mfindex.patch b/0334-xhci-implement-mfindex.patch deleted file mode 100644 index 9f00140..0000000 --- a/0334-xhci-implement-mfindex.patch +++ /dev/null @@ -1,142 +0,0 @@ -From 6a1c694cd009fb7e4656e1c9a18756da6f89be14 Mon Sep 17 00:00:00 2001 -From: Gerd Hoffmann -Date: Tue, 21 Aug 2012 12:32:58 +0200 -Subject: [PATCH 334/366] xhci: implement mfindex - -Implement mfindex register and mfindex wrap event. - -Signed-off-by: Gerd Hoffmann ---- - hw/usb/hcd-xhci.c | 53 ++++++++++++++++++++++++++++++++++++++++++++++------- - 1 file changed, 46 insertions(+), 7 deletions(-) - -diff --git a/hw/usb/hcd-xhci.c b/hw/usb/hcd-xhci.c -index 303e1ac..9077cb3 100644 ---- a/hw/usb/hcd-xhci.c -+++ b/hw/usb/hcd-xhci.c -@@ -380,8 +380,6 @@ struct XHCIState { - XHCISlot slots[MAXSLOTS]; - - /* Runtime Registers */ -- uint32_t mfindex; -- /* note: we only support one interrupter */ - uint32_t iman; - uint32_t imod; - uint32_t erstsz; -@@ -390,6 +388,9 @@ struct XHCIState { - uint32_t erdp_low; - uint32_t erdp_high; - -+ int64_t mfindex_start; -+ QEMUTimer *mfwrap_timer; -+ - dma_addr_t er_start; - uint32_t er_size; - bool er_pcs; -@@ -410,6 +411,11 @@ typedef struct XHCIEvRingSeg { - uint32_t rsvd; - } XHCIEvRingSeg; - -+static void xhci_kick_ep(XHCIState *xhci, unsigned int slotid, -+ unsigned int epid); -+static void xhci_event(XHCIState *xhci, XHCIEvent *event); -+static void xhci_write_event(XHCIState *xhci, XHCIEvent *event); -+ - static const char *TRBType_names[] = { - [TRB_RESERVED] = "TRB_RESERVED", - [TR_NORMAL] = "TR_NORMAL", -@@ -462,8 +468,36 @@ static const char *trb_name(XHCITRB *trb) - ARRAY_SIZE(TRBType_names)); - } - --static void xhci_kick_ep(XHCIState *xhci, unsigned int slotid, -- unsigned int epid); -+static uint64_t xhci_mfindex_get(XHCIState *xhci) -+{ -+ int64_t now = qemu_get_clock_ns(vm_clock); -+ return (now - xhci->mfindex_start) / 125000; -+} -+ -+static void xhci_mfwrap_update(XHCIState *xhci) -+{ -+ const uint32_t bits = USBCMD_RS | USBCMD_EWE; -+ uint32_t mfindex, left; -+ int64_t now; -+ -+ if ((xhci->usbcmd & bits) == bits) { -+ now = qemu_get_clock_ns(vm_clock); -+ mfindex = ((now - xhci->mfindex_start) / 125000) & 0x3fff; -+ left = 0x4000 - mfindex; -+ qemu_mod_timer(xhci->mfwrap_timer, now + left * 125000); -+ } else { -+ qemu_del_timer(xhci->mfwrap_timer); -+ } -+} -+ -+static void xhci_mfwrap_timer(void *opaque) -+{ -+ XHCIState *xhci = opaque; -+ XHCIEvent wrap = { ER_MFINDEX_WRAP, CC_SUCCESS }; -+ -+ xhci_event(xhci, &wrap); -+ xhci_mfwrap_update(xhci); -+} - - static inline dma_addr_t xhci_addr64(uint32_t low, uint32_t high) - { -@@ -793,6 +827,7 @@ static void xhci_run(XHCIState *xhci) - { - trace_usb_xhci_run(); - xhci->usbsts &= ~USBSTS_HCH; -+ xhci->mfindex_start = qemu_get_clock_ns(vm_clock); - } - - static void xhci_stop(XHCIState *xhci) -@@ -2050,7 +2085,6 @@ static void xhci_reset(DeviceState *dev) - xhci_update_port(xhci, xhci->ports + i, 0); - } - -- xhci->mfindex = 0; - xhci->iman = 0; - xhci->imod = 0; - xhci->erstsz = 0; -@@ -2064,6 +2098,9 @@ static void xhci_reset(DeviceState *dev) - xhci->er_full = 0; - xhci->ev_buffer_put = 0; - xhci->ev_buffer_get = 0; -+ -+ xhci->mfindex_start = qemu_get_clock_ns(vm_clock); -+ xhci_mfwrap_update(xhci); - } - - static uint32_t xhci_cap_read(XHCIState *xhci, uint32_t reg) -@@ -2266,6 +2303,7 @@ static void xhci_oper_write(XHCIState *xhci, uint32_t reg, uint32_t val) - xhci_stop(xhci); - } - xhci->usbcmd = val & 0xc0f; -+ xhci_mfwrap_update(xhci); - if (val & USBCMD_HCRST) { - xhci_reset(&xhci->pci_dev.qdev); - } -@@ -2317,8 +2355,7 @@ static uint32_t xhci_runtime_read(XHCIState *xhci, uint32_t reg) - - switch (reg) { - case 0x00: /* MFINDEX */ -- fprintf(stderr, "xhci_runtime_read: MFINDEX not yet implemented\n"); -- ret = xhci->mfindex; -+ ret = xhci_mfindex_get(xhci) & 0x3fff; - break; - case 0x20: /* IMAN */ - ret = xhci->iman; -@@ -2618,6 +2655,8 @@ static int usb_xhci_initfn(struct PCIDevice *dev) - - usb_xhci_init(xhci, &dev->qdev); - -+ xhci->mfwrap_timer = qemu_new_timer_ns(vm_clock, xhci_mfwrap_timer, xhci); -+ - xhci->irq = xhci->pci_dev.irq[0]; - - memory_region_init_io(&xhci->mem, &xhci_mem_ops, xhci, --- -1.7.12 - diff --git a/0335-xhci-iso-xfer-support.patch b/0335-xhci-iso-xfer-support.patch deleted file mode 100644 index ae88244..0000000 --- a/0335-xhci-iso-xfer-support.patch +++ /dev/null @@ -1,238 +0,0 @@ -From 9f7a9361a816479ca109e1747e45d40135fad3b0 Mon Sep 17 00:00:00 2001 -From: Gerd Hoffmann -Date: Fri, 24 Aug 2012 14:13:08 +0200 -Subject: [PATCH 335/366] xhci: iso xfer support - -Add support for iso transfers. - -Signed-off-by: Gerd Hoffmann ---- - hw/usb/hcd-xhci.c | 117 ++++++++++++++++++++++++++++++++++++++++++++++-------- - 1 file changed, 101 insertions(+), 16 deletions(-) - -diff --git a/hw/usb/hcd-xhci.c b/hw/usb/hcd-xhci.c -index 9077cb3..3c61bb8 100644 ---- a/hw/usb/hcd-xhci.c -+++ b/hw/usb/hcd-xhci.c -@@ -325,9 +325,15 @@ typedef struct XHCITransfer { - unsigned int pkts; - unsigned int pktsize; - unsigned int cur_pkt; -+ -+ uint64_t mfindex_kick; - } XHCITransfer; - - typedef struct XHCIEPContext { -+ XHCIState *xhci; -+ unsigned int slotid; -+ unsigned int epid; -+ - XHCIRing ring; - unsigned int next_xfer; - unsigned int comp_xfer; -@@ -337,6 +343,11 @@ typedef struct XHCIEPContext { - dma_addr_t pctx; - unsigned int max_psize; - uint32_t state; -+ -+ /* iso xfer scheduling */ -+ unsigned int interval; -+ int64_t mfindex_last; -+ QEMUTimer *kick_timer; - } XHCIEPContext; - - typedef struct XHCISlot { -@@ -856,6 +867,12 @@ static void xhci_set_ep_state(XHCIState *xhci, XHCIEPContext *epctx, - epctx->state = state; - } - -+static void xhci_ep_kick_timer(void *opaque) -+{ -+ XHCIEPContext *epctx = opaque; -+ xhci_kick_ep(epctx->xhci, epctx->slotid, epctx->epid); -+} -+ - static TRBCCode xhci_enable_ep(XHCIState *xhci, unsigned int slotid, - unsigned int epid, dma_addr_t pctx, - uint32_t *ctx) -@@ -877,6 +894,9 @@ static TRBCCode xhci_enable_ep(XHCIState *xhci, unsigned int slotid, - - epctx = g_malloc(sizeof(XHCIEPContext)); - memset(epctx, 0, sizeof(XHCIEPContext)); -+ epctx->xhci = xhci; -+ epctx->slotid = slotid; -+ epctx->epid = epid; - - slot->eps[epid-1] = epctx; - -@@ -895,6 +915,10 @@ static TRBCCode xhci_enable_ep(XHCIState *xhci, unsigned int slotid, - usb_packet_init(&epctx->transfers[i].packet); - } - -+ epctx->interval = 1 << (ctx[0] >> 16) & 0xff; -+ epctx->mfindex_last = 0; -+ epctx->kick_timer = qemu_new_timer_ns(vm_clock, xhci_ep_kick_timer, epctx); -+ - epctx->state = EP_RUNNING; - ctx[0] &= ~EP_STATE_MASK; - ctx[0] |= EP_RUNNING; -@@ -934,6 +958,7 @@ static int xhci_ep_nuke_xfers(XHCIState *xhci, unsigned int slotid, - if (t->running_retry) { - t->running_retry = 0; - epctx->retry = NULL; -+ qemu_del_timer(epctx->kick_timer); - } - if (t->trbs) { - g_free(t->trbs); -@@ -969,6 +994,7 @@ static TRBCCode xhci_disable_ep(XHCIState *xhci, unsigned int slotid, - - xhci_set_ep_state(xhci, epctx, EP_DISABLED); - -+ qemu_free_timer(epctx->kick_timer); - g_free(epctx); - slot->eps[epid-1] = NULL; - -@@ -1378,29 +1404,70 @@ static int xhci_fire_ctl_transfer(XHCIState *xhci, XHCITransfer *xfer) - return 0; - } - -+static void xhci_calc_iso_kick(XHCIState *xhci, XHCITransfer *xfer, -+ XHCIEPContext *epctx, uint64_t mfindex) -+{ -+ if (xfer->trbs[0].control & TRB_TR_SIA) { -+ uint64_t asap = ((mfindex + epctx->interval - 1) & -+ ~(epctx->interval-1)); -+ if (asap >= epctx->mfindex_last && -+ asap <= epctx->mfindex_last + epctx->interval * 4) { -+ xfer->mfindex_kick = epctx->mfindex_last + epctx->interval; -+ } else { -+ xfer->mfindex_kick = asap; -+ } -+ } else { -+ xfer->mfindex_kick = (xfer->trbs[0].control >> TRB_TR_FRAMEID_SHIFT) -+ & TRB_TR_FRAMEID_MASK; -+ xfer->mfindex_kick |= mfindex & ~0x3fff; -+ if (xfer->mfindex_kick < mfindex) { -+ xfer->mfindex_kick += 0x4000; -+ } -+ } -+} -+ -+static void xhci_check_iso_kick(XHCIState *xhci, XHCITransfer *xfer, -+ XHCIEPContext *epctx, uint64_t mfindex) -+{ -+ if (xfer->mfindex_kick > mfindex) { -+ qemu_mod_timer(epctx->kick_timer, qemu_get_clock_ns(vm_clock) + -+ (xfer->mfindex_kick - mfindex) * 125000); -+ xfer->running_retry = 1; -+ } else { -+ epctx->mfindex_last = xfer->mfindex_kick; -+ qemu_del_timer(epctx->kick_timer); -+ xfer->running_retry = 0; -+ } -+} -+ -+ - static int xhci_submit(XHCIState *xhci, XHCITransfer *xfer, XHCIEPContext *epctx) - { -+ uint64_t mfindex; - int ret; - - DPRINTF("xhci_submit(slotid=%d,epid=%d)\n", xfer->slotid, xfer->epid); - - xfer->in_xfer = epctx->type>>2; - -- if (epctx->type == ET_ISO_IN || epctx->type == ET_ISO_OUT) { -- xfer->pkts = 1; -- } else { -- xfer->pkts = 0; -- } -- - switch(epctx->type) { - case ET_INTR_OUT: - case ET_INTR_IN: - case ET_BULK_OUT: - case ET_BULK_IN: -+ xfer->pkts = 0; -+ xfer->iso_xfer = false; - break; - case ET_ISO_OUT: - case ET_ISO_IN: -- FIXME(); -+ xfer->pkts = 1; -+ xfer->iso_xfer = true; -+ mfindex = xhci_mfindex_get(xhci); -+ xhci_calc_iso_kick(xhci, xfer, epctx, mfindex); -+ xhci_check_iso_kick(xhci, xfer, epctx, mfindex); -+ if (xfer->running_retry) { -+ return -1; -+ } - break; - default: - fprintf(stderr, "xhci: unknown or unhandled EP " -@@ -1430,6 +1497,7 @@ static int xhci_fire_transfer(XHCIState *xhci, XHCITransfer *xfer, XHCIEPContext - static void xhci_kick_ep(XHCIState *xhci, unsigned int slotid, unsigned int epid) - { - XHCIEPContext *epctx; -+ uint64_t mfindex; - int length; - int i; - -@@ -1449,20 +1517,35 @@ static void xhci_kick_ep(XHCIState *xhci, unsigned int slotid, unsigned int epid - } - - if (epctx->retry) { -- /* retry nak'ed transfer */ - XHCITransfer *xfer = epctx->retry; - int result; - - trace_usb_xhci_xfer_retry(xfer); - assert(xfer->running_retry); -- if (xhci_setup_packet(xfer) < 0) { -- return; -- } -- result = usb_handle_packet(xfer->packet.ep->dev, &xfer->packet); -- if (result == USB_RET_NAK) { -- return; -+ if (xfer->iso_xfer) { -+ /* retry delayed iso transfer */ -+ mfindex = xhci_mfindex_get(xhci); -+ xhci_check_iso_kick(xhci, xfer, epctx, mfindex); -+ if (xfer->running_retry) { -+ return; -+ } -+ if (xhci_setup_packet(xfer) < 0) { -+ return; -+ } -+ result = usb_handle_packet(xfer->packet.ep->dev, &xfer->packet); -+ assert(result != USB_RET_NAK); -+ xhci_complete_packet(xfer, result); -+ } else { -+ /* retry nak'ed transfer */ -+ if (xhci_setup_packet(xfer) < 0) { -+ return; -+ } -+ result = usb_handle_packet(xfer->packet.ep->dev, &xfer->packet); -+ if (result == USB_RET_NAK) { -+ return; -+ } -+ xhci_complete_packet(xfer, result); - } -- xhci_complete_packet(xfer, result); - assert(!xfer->running_retry); - epctx->retry = NULL; - } -@@ -1514,7 +1597,9 @@ static void xhci_kick_ep(XHCIState *xhci, unsigned int slotid, unsigned int epid - if (xhci_fire_transfer(xhci, xfer, epctx) >= 0) { - epctx->next_xfer = (epctx->next_xfer + 1) % TD_QUEUE; - } else { -- fprintf(stderr, "xhci: error firing data transfer\n"); -+ if (!xfer->iso_xfer) { -+ fprintf(stderr, "xhci: error firing data transfer\n"); -+ } - } - } - --- -1.7.12 - diff --git a/0336-xhci-trace-cc-codes-in-cleartext.patch b/0336-xhci-trace-cc-codes-in-cleartext.patch deleted file mode 100644 index 096d194..0000000 --- a/0336-xhci-trace-cc-codes-in-cleartext.patch +++ /dev/null @@ -1,100 +0,0 @@ -From 530efbfebc3b33f6b109e52d57a25e9b7fe2b588 Mon Sep 17 00:00:00 2001 -From: Gerd Hoffmann -Date: Mon, 27 Aug 2012 16:09:20 +0200 -Subject: [PATCH 336/366] xhci: trace cc codes in cleartext - -Signed-off-by: Gerd Hoffmann ---- - hw/usb/hcd-xhci.c | 48 +++++++++++++++++++++++++++++++++++++++++++++++- - trace-events | 2 +- - 2 files changed, 48 insertions(+), 2 deletions(-) - -diff --git a/hw/usb/hcd-xhci.c b/hw/usb/hcd-xhci.c -index 3c61bb8..ab32a7b 100644 ---- a/hw/usb/hcd-xhci.c -+++ b/hw/usb/hcd-xhci.c -@@ -465,6 +465,45 @@ static const char *TRBType_names[] = { - [CR_VENDOR_NEC_CHALLENGE_RESPONSE] = "CR_VENDOR_NEC_CHALLENGE_RESPONSE", - }; - -+static const char *TRBCCode_names[] = { -+ [CC_INVALID] = "CC_INVALID", -+ [CC_SUCCESS] = "CC_SUCCESS", -+ [CC_DATA_BUFFER_ERROR] = "CC_DATA_BUFFER_ERROR", -+ [CC_BABBLE_DETECTED] = "CC_BABBLE_DETECTED", -+ [CC_USB_TRANSACTION_ERROR] = "CC_USB_TRANSACTION_ERROR", -+ [CC_TRB_ERROR] = "CC_TRB_ERROR", -+ [CC_STALL_ERROR] = "CC_STALL_ERROR", -+ [CC_RESOURCE_ERROR] = "CC_RESOURCE_ERROR", -+ [CC_BANDWIDTH_ERROR] = "CC_BANDWIDTH_ERROR", -+ [CC_NO_SLOTS_ERROR] = "CC_NO_SLOTS_ERROR", -+ [CC_INVALID_STREAM_TYPE_ERROR] = "CC_INVALID_STREAM_TYPE_ERROR", -+ [CC_SLOT_NOT_ENABLED_ERROR] = "CC_SLOT_NOT_ENABLED_ERROR", -+ [CC_EP_NOT_ENABLED_ERROR] = "CC_EP_NOT_ENABLED_ERROR", -+ [CC_SHORT_PACKET] = "CC_SHORT_PACKET", -+ [CC_RING_UNDERRUN] = "CC_RING_UNDERRUN", -+ [CC_RING_OVERRUN] = "CC_RING_OVERRUN", -+ [CC_VF_ER_FULL] = "CC_VF_ER_FULL", -+ [CC_PARAMETER_ERROR] = "CC_PARAMETER_ERROR", -+ [CC_BANDWIDTH_OVERRUN] = "CC_BANDWIDTH_OVERRUN", -+ [CC_CONTEXT_STATE_ERROR] = "CC_CONTEXT_STATE_ERROR", -+ [CC_NO_PING_RESPONSE_ERROR] = "CC_NO_PING_RESPONSE_ERROR", -+ [CC_EVENT_RING_FULL_ERROR] = "CC_EVENT_RING_FULL_ERROR", -+ [CC_INCOMPATIBLE_DEVICE_ERROR] = "CC_INCOMPATIBLE_DEVICE_ERROR", -+ [CC_MISSED_SERVICE_ERROR] = "CC_MISSED_SERVICE_ERROR", -+ [CC_COMMAND_RING_STOPPED] = "CC_COMMAND_RING_STOPPED", -+ [CC_COMMAND_ABORTED] = "CC_COMMAND_ABORTED", -+ [CC_STOPPED] = "CC_STOPPED", -+ [CC_STOPPED_LENGTH_INVALID] = "CC_STOPPED_LENGTH_INVALID", -+ [CC_MAX_EXIT_LATENCY_TOO_LARGE_ERROR] -+ = "CC_MAX_EXIT_LATENCY_TOO_LARGE_ERROR", -+ [CC_ISOCH_BUFFER_OVERRUN] = "CC_ISOCH_BUFFER_OVERRUN", -+ [CC_EVENT_LOST_ERROR] = "CC_EVENT_LOST_ERROR", -+ [CC_UNDEFINED_ERROR] = "CC_UNDEFINED_ERROR", -+ [CC_INVALID_STREAM_ID_ERROR] = "CC_INVALID_STREAM_ID_ERROR", -+ [CC_SECONDARY_BANDWIDTH_ERROR] = "CC_SECONDARY_BANDWIDTH_ERROR", -+ [CC_SPLIT_TRANSACTION_ERROR] = "CC_SPLIT_TRANSACTION_ERROR", -+}; -+ - static const char *lookup_name(uint32_t index, const char **list, uint32_t llen) - { - if (index >= llen || list[index] == NULL) { -@@ -479,6 +518,12 @@ static const char *trb_name(XHCITRB *trb) - ARRAY_SIZE(TRBType_names)); - } - -+static const char *event_name(XHCIEvent *event) -+{ -+ return lookup_name(event->ccode, TRBCCode_names, -+ ARRAY_SIZE(TRBCCode_names)); -+} -+ - static uint64_t xhci_mfindex_get(XHCIState *xhci) - { - int64_t now = qemu_get_clock_ns(vm_clock); -@@ -574,7 +619,8 @@ static void xhci_write_event(XHCIState *xhci, XHCIEvent *event) - ev_trb.control = cpu_to_le32(ev_trb.control); - - trace_usb_xhci_queue_event(xhci->er_ep_idx, trb_name(&ev_trb), -- ev_trb.parameter, ev_trb.status, ev_trb.control); -+ event_name(event), ev_trb.parameter, -+ ev_trb.status, ev_trb.control); - - addr = xhci->er_start + TRB_SIZE*xhci->er_ep_idx; - pci_dma_write(&xhci->pci_dev, addr, &ev_trb, TRB_SIZE); -diff --git a/trace-events b/trace-events -index c83d65e..27d59cd 100644 ---- a/trace-events -+++ b/trace-events -@@ -313,7 +313,7 @@ usb_xhci_runtime_write(uint32_t off, uint32_t val) "off 0x%04x, val 0x%08x" - usb_xhci_doorbell_write(uint32_t off, uint32_t val) "off 0x%04x, val 0x%08x" - usb_xhci_irq_intx(uint32_t level) "level %d" - usb_xhci_irq_msi(uint32_t nr) "nr %d" --usb_xhci_queue_event(uint32_t idx, const char *name, uint64_t param, uint32_t status, uint32_t control) "idx %d, %s, p %016" PRIx64 ", s %08x, c 0x%08x" -+usb_xhci_queue_event(uint32_t idx, const char *trb, const char *evt, uint64_t param, uint32_t status, uint32_t control) "idx %d, %s, %s, p %016" PRIx64 ", s %08x, c 0x%08x" - usb_xhci_fetch_trb(uint64_t addr, const char *name, uint64_t param, uint32_t status, uint32_t control) "addr %016" PRIx64 ", %s, p %016" PRIx64 ", s %08x, c 0x%08x" - usb_xhci_slot_enable(uint32_t slotid) "slotid %d" - usb_xhci_slot_disable(uint32_t slotid) "slotid %d" --- -1.7.12 - diff --git a/0337-xhci-add-trace_usb_xhci_ep_set_dequeue.patch b/0337-xhci-add-trace_usb_xhci_ep_set_dequeue.patch deleted file mode 100644 index c36d7d8..0000000 --- a/0337-xhci-add-trace_usb_xhci_ep_set_dequeue.patch +++ /dev/null @@ -1,39 +0,0 @@ -From 53adf697ca70ee8298b6abeb05ebf5a0ebebdc1c Mon Sep 17 00:00:00 2001 -From: Gerd Hoffmann -Date: Wed, 29 Aug 2012 12:54:59 +0200 -Subject: [PATCH 337/366] xhci: add trace_usb_xhci_ep_set_dequeue - -Signed-off-by: Gerd Hoffmann ---- - hw/usb/hcd-xhci.c | 2 +- - trace-events | 1 + - 2 files changed, 2 insertions(+), 1 deletion(-) - -diff --git a/hw/usb/hcd-xhci.c b/hw/usb/hcd-xhci.c -index ab32a7b..5cdaf76 100644 ---- a/hw/usb/hcd-xhci.c -+++ b/hw/usb/hcd-xhci.c -@@ -1145,7 +1145,7 @@ static TRBCCode xhci_set_ep_dequeue(XHCIState *xhci, unsigned int slotid, - return CC_TRB_ERROR; - } - -- DPRINTF("xhci_set_ep_dequeue(%d, %d, %016"PRIx64")\n", slotid, epid, pdequeue); -+ trace_usb_xhci_ep_set_dequeue(slotid, epid, pdequeue); - dequeue = xhci_mask64(pdequeue); - - slot = &xhci->slots[slotid-1]; -diff --git a/trace-events b/trace-events -index 27d59cd..a894689 100644 ---- a/trace-events -+++ b/trace-events -@@ -323,6 +323,7 @@ usb_xhci_slot_evaluate(uint32_t slotid) "slotid %d" - usb_xhci_slot_reset(uint32_t slotid) "slotid %d" - usb_xhci_ep_enable(uint32_t slotid, uint32_t epid) "slotid %d, epid %d" - usb_xhci_ep_disable(uint32_t slotid, uint32_t epid) "slotid %d, epid %d" -+usb_xhci_ep_set_dequeue(uint32_t slotid, uint32_t epid, uint64_t param) "slotid %d, epid %d, ptr %016" PRIx64 - usb_xhci_ep_kick(uint32_t slotid, uint32_t epid) "slotid %d, epid %d" - usb_xhci_ep_stop(uint32_t slotid, uint32_t epid) "slotid %d, epid %d" - usb_xhci_ep_reset(uint32_t slotid, uint32_t epid) "slotid %d, epid %d" --- -1.7.12 - diff --git a/0338-xhci-fix-runtime-write-tracepoint.patch b/0338-xhci-fix-runtime-write-tracepoint.patch deleted file mode 100644 index a2eebfd..0000000 --- a/0338-xhci-fix-runtime-write-tracepoint.patch +++ /dev/null @@ -1,26 +0,0 @@ -From 9c1e6303c5c86f20ed083a0ed9c829c08fd2ac06 Mon Sep 17 00:00:00 2001 -From: Gerd Hoffmann -Date: Thu, 30 Aug 2012 12:42:32 +0200 -Subject: [PATCH 338/366] xhci: fix runtime write tracepoint - -Signed-off-by: Gerd Hoffmann ---- - hw/usb/hcd-xhci.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/hw/usb/hcd-xhci.c b/hw/usb/hcd-xhci.c -index 5cdaf76..e8d2372 100644 ---- a/hw/usb/hcd-xhci.c -+++ b/hw/usb/hcd-xhci.c -@@ -2520,7 +2520,7 @@ static uint32_t xhci_runtime_read(XHCIState *xhci, uint32_t reg) - - static void xhci_runtime_write(XHCIState *xhci, uint32_t reg, uint32_t val) - { -- trace_usb_xhci_runtime_read(reg, val); -+ trace_usb_xhci_runtime_write(reg, val); - - switch (reg) { - case 0x20: /* IMAN */ --- -1.7.12 - diff --git a/0339-xhci-update-register-layout.patch b/0339-xhci-update-register-layout.patch deleted file mode 100644 index 7fc8af1..0000000 --- a/0339-xhci-update-register-layout.patch +++ /dev/null @@ -1,63 +0,0 @@ -From 56a4ea65ecc929a355b0cc243099d2e3a9862843 Mon Sep 17 00:00:00 2001 -From: Gerd Hoffmann -Date: Thu, 23 Aug 2012 13:26:25 +0200 -Subject: [PATCH 339/366] xhci: update register layout - -Change the register layout to be a bit more sparse and also not depend -on the number of ports. Useful when for making the number of ports -runtime-configurable. ---- - hw/usb/hcd-xhci.c | 21 +++++++++++++-------- - 1 file changed, 13 insertions(+), 8 deletions(-) - -diff --git a/hw/usb/hcd-xhci.c b/hw/usb/hcd-xhci.c -index e8d2372..414b633 100644 ---- a/hw/usb/hcd-xhci.c -+++ b/hw/usb/hcd-xhci.c -@@ -36,13 +36,12 @@ - #define FIXME() do { fprintf(stderr, "FIXME %s:%d\n", \ - __func__, __LINE__); abort(); } while (0) - --#define MAXSLOTS 8 --#define MAXINTRS 1 -- - #define USB2_PORTS 4 - #define USB3_PORTS 4 - - #define MAXPORTS (USB2_PORTS+USB3_PORTS) -+#define MAXSLOTS MAXPORTS -+#define MAXINTRS 1 /* MAXPORTS */ - - #define TD_QUEUE 24 - -@@ -53,16 +52,22 @@ - #define ER_FULL_HACK - - #define LEN_CAP 0x40 --#define OFF_OPER LEN_CAP - #define LEN_OPER (0x400 + 0x10 * MAXPORTS) --#define OFF_RUNTIME ((OFF_OPER + LEN_OPER + 0x20) & ~0x1f) --#define LEN_RUNTIME (0x20 + MAXINTRS * 0x20) --#define OFF_DOORBELL (OFF_RUNTIME + LEN_RUNTIME) -+#define LEN_RUNTIME ((MAXINTRS + 1) * 0x20) - #define LEN_DOORBELL ((MAXSLOTS + 1) * 0x20) - -+#define OFF_OPER LEN_CAP -+#define OFF_RUNTIME 0x1000 -+#define OFF_DOORBELL 0x2000 - /* must be power of 2 */ --#define LEN_REGS 0x2000 -+#define LEN_REGS 0x4000 - -+#if (OFF_OPER + LEN_OPER) > OFF_RUNTIME -+#error Increase OFF_RUNTIME -+#endif -+#if (OFF_RUNTIME + LEN_RUNTIME) > OFF_DOORBELL -+#error Increase OFF_DOORBELL -+#endif - #if (OFF_DOORBELL + LEN_DOORBELL) > LEN_REGS - # error Increase LEN_REGS - #endif --- -1.7.12 - diff --git a/0340-xhci-update-port-handling.patch b/0340-xhci-update-port-handling.patch deleted file mode 100644 index 289fa52..0000000 --- a/0340-xhci-update-port-handling.patch +++ /dev/null @@ -1,352 +0,0 @@ -From ed16ece865cb40c9ad8ddf28905c0af3ad80e118 Mon Sep 17 00:00:00 2001 -From: Gerd Hoffmann -Date: Tue, 28 Aug 2012 13:38:01 +0200 -Subject: [PATCH 340/366] xhci: update port handling - -This patch changes the way xhci ports are linked to USBPorts. The fixed -1:1 relationship between xhci ports and USBPorts is gone. Now each -USBPort represents a physical plug which has usually two xhci ports -assigned: one usb2 and ond usb3 port. usb devices show up at one or the -other, depending on whenever they support superspeed or not. - -This patch also makes the number of usb2 and usb3 ports runtime -configurable by adding 'p2' and 'p3' properties. It is allowed to -have different numbers of usb2 and usb3 ports. Specifying p2=4,p3=2 -will give you an xhci adapter which supports all speeds on physical -ports 1+2 and usb2 only on ports 3+4. ---- - hw/usb/hcd-xhci.c | 137 ++++++++++++++++++++++++++++++++++++++---------------- - 1 file changed, 97 insertions(+), 40 deletions(-) - -diff --git a/hw/usb/hcd-xhci.c b/hw/usb/hcd-xhci.c -index 414b633..e08312e 100644 ---- a/hw/usb/hcd-xhci.c -+++ b/hw/usb/hcd-xhci.c -@@ -36,10 +36,10 @@ - #define FIXME() do { fprintf(stderr, "FIXME %s:%d\n", \ - __func__, __LINE__); abort(); } while (0) - --#define USB2_PORTS 4 --#define USB3_PORTS 4 -+#define MAXPORTS_2 8 -+#define MAXPORTS_3 8 - --#define MAXPORTS (USB2_PORTS+USB3_PORTS) -+#define MAXPORTS (MAXPORTS_2+MAXPORTS_3) - #define MAXSLOTS MAXPORTS - #define MAXINTRS 1 /* MAXPORTS */ - -@@ -300,8 +300,10 @@ typedef struct XHCIRing { - } XHCIRing; - - typedef struct XHCIPort { -- USBPort port; - uint32_t portsc; -+ uint32_t portnr; -+ USBPort *uport; -+ uint32_t speedmask; - } XHCIPort; - - struct XHCIState; -@@ -379,9 +381,13 @@ struct XHCIState { - qemu_irq irq; - MemoryRegion mem; - const char *name; -- uint32_t msi; - unsigned int devaddr; - -+ /* properties */ -+ uint32_t numports_2; -+ uint32_t numports_3; -+ uint32_t msi; -+ - /* Operational Registers */ - uint32_t usbcmd; - uint32_t usbsts; -@@ -392,8 +398,10 @@ struct XHCIState { - uint32_t dcbaap_high; - uint32_t config; - -+ USBPort uports[MAX(MAXPORTS_2, MAXPORTS_3)]; - XHCIPort ports[MAXPORTS]; - XHCISlot slots[MAXSLOTS]; -+ uint32_t numports; - - /* Runtime Registers */ - uint32_t iman; -@@ -578,6 +586,28 @@ static inline dma_addr_t xhci_mask64(uint64_t addr) - } - } - -+static XHCIPort *xhci_lookup_port(XHCIState *xhci, struct USBPort *uport) -+{ -+ int index; -+ -+ if (!uport->dev) { -+ return NULL; -+ } -+ switch (uport->dev->speed) { -+ case USB_SPEED_LOW: -+ case USB_SPEED_FULL: -+ case USB_SPEED_HIGH: -+ index = uport->index; -+ break; -+ case USB_SPEED_SUPER: -+ index = uport->index + xhci->numports_2; -+ break; -+ default: -+ return NULL; -+ } -+ return &xhci->ports[index]; -+} -+ - static void xhci_irq_update(XHCIState *xhci) - { - int level = 0; -@@ -1126,7 +1156,7 @@ static TRBCCode xhci_reset_ep(XHCIState *xhci, unsigned int slotid, - ep |= 0x80; - } - -- dev = xhci->ports[xhci->slots[slotid-1].port-1].port.dev; -+ dev = xhci->ports[xhci->slots[slotid-1].port-1].uport->dev; - if (!dev) { - return CC_USB_TRANSACTION_ERROR; - } -@@ -1313,7 +1343,7 @@ static USBDevice *xhci_find_device(XHCIPort *port, uint8_t addr) - if (!(port->portsc & PORTSC_PED)) { - return NULL; - } -- return usb_find_device(&port->port, addr); -+ return usb_find_device(port->uport, addr); - } - - static int xhci_setup_packet(XHCITransfer *xfer) -@@ -1736,9 +1766,9 @@ static TRBCCode xhci_address_slot(XHCIState *xhci, unsigned int slotid, - ep0_ctx[0], ep0_ctx[1], ep0_ctx[2], ep0_ctx[3], ep0_ctx[4]); - - port = (slot_ctx[1]>>16) & 0xFF; -- dev = xhci->ports[port-1].port.dev; -+ dev = xhci->ports[port-1].uport->dev; - -- if (port < 1 || port > MAXPORTS) { -+ if (port < 1 || port > xhci->numports) { - fprintf(stderr, "xhci: bad port %d\n", port); - return CC_TRB_ERROR; - } else if (!dev) { -@@ -1987,7 +2017,7 @@ static unsigned int xhci_get_slot(XHCIState *xhci, XHCIEvent *event, XHCITRB *tr - static TRBCCode xhci_get_port_bandwidth(XHCIState *xhci, uint64_t pctx) - { - dma_addr_t ctx; -- uint8_t bw_ctx[MAXPORTS+1]; -+ uint8_t bw_ctx[xhci->numports+1]; - - DPRINTF("xhci_get_port_bandwidth()\n"); - -@@ -1997,7 +2027,7 @@ static TRBCCode xhci_get_port_bandwidth(XHCIState *xhci, uint64_t pctx) - - /* TODO: actually implement real values here */ - bw_ctx[0] = 0; -- memset(&bw_ctx[1], 80, MAXPORTS); /* 80% */ -+ memset(&bw_ctx[1], 80, xhci->numports); /* 80% */ - pci_dma_write(&xhci->pci_dev, ctx, bw_ctx, sizeof(bw_ctx)); - - return CC_SUCCESS; -@@ -2167,12 +2197,11 @@ static void xhci_process_commands(XHCIState *xhci) - - static void xhci_update_port(XHCIState *xhci, XHCIPort *port, int is_detach) - { -- int nr = port->port.index + 1; -- - port->portsc = PORTSC_PP; -- if (port->port.dev && port->port.dev->attached && !is_detach) { -+ if (port->uport->dev && port->uport->dev->attached && !is_detach && -+ (1 << port->uport->dev->speed) & port->speedmask) { - port->portsc |= PORTSC_CCS; -- switch (port->port.dev->speed) { -+ switch (port->uport->dev->speed) { - case USB_SPEED_LOW: - port->portsc |= PORTSC_SPEED_LOW; - break; -@@ -2182,14 +2211,18 @@ static void xhci_update_port(XHCIState *xhci, XHCIPort *port, int is_detach) - case USB_SPEED_HIGH: - port->portsc |= PORTSC_SPEED_HIGH; - break; -+ case USB_SPEED_SUPER: -+ port->portsc |= PORTSC_SPEED_SUPER; -+ break; - } - } - - if (xhci_running(xhci)) { - port->portsc |= PORTSC_CSC; -- XHCIEvent ev = { ER_PORT_STATUS_CHANGE, CC_SUCCESS, nr << 24}; -+ XHCIEvent ev = { ER_PORT_STATUS_CHANGE, CC_SUCCESS, -+ port->portnr << 24}; - xhci_event(xhci, &ev); -- DPRINTF("xhci: port change event for port %d\n", nr); -+ DPRINTF("xhci: port change event for port %d\n", port->portnr); - } - } - -@@ -2217,7 +2250,7 @@ static void xhci_reset(DeviceState *dev) - xhci_disable_slot(xhci, i+1); - } - -- for (i = 0; i < MAXPORTS; i++) { -+ for (i = 0; i < xhci->numports; i++) { - xhci_update_port(xhci, xhci->ports + i, 0); - } - -@@ -2248,7 +2281,8 @@ static uint32_t xhci_cap_read(XHCIState *xhci, uint32_t reg) - ret = 0x01000000 | LEN_CAP; - break; - case 0x04: /* HCSPARAMS 1 */ -- ret = (MAXPORTS<<24) | (MAXINTRS<<8) | MAXSLOTS; -+ ret = ((xhci->numports_2+xhci->numports_3)<<24) -+ | (MAXINTRS<<8) | MAXSLOTS; - break; - case 0x08: /* HCSPARAMS 2 */ - ret = 0x0000000f; -@@ -2278,7 +2312,7 @@ static uint32_t xhci_cap_read(XHCIState *xhci, uint32_t reg) - ret = 0x20425455; /* "USB " */ - break; - case 0x28: /* Supported Protocol:08 */ -- ret = 0x00000001 | (USB2_PORTS<<8); -+ ret = 0x00000001 | (xhci->numports_2<<8); - break; - case 0x2c: /* Supported Protocol:0c */ - ret = 0x00000000; /* reserved */ -@@ -2290,7 +2324,7 @@ static uint32_t xhci_cap_read(XHCIState *xhci, uint32_t reg) - ret = 0x20425455; /* "USB " */ - break; - case 0x38: /* Supported Protocol:08 */ -- ret = 0x00000000 | (USB2_PORTS+1) | (USB3_PORTS<<8); -+ ret = 0x00000000 | (xhci->numports_2+1) | (xhci->numports_3<<8); - break; - case 0x3c: /* Supported Protocol:0c */ - ret = 0x00000000; /* reserved */ -@@ -2309,7 +2343,7 @@ static uint32_t xhci_port_read(XHCIState *xhci, uint32_t reg) - uint32_t port = reg >> 4; - uint32_t ret; - -- if (port >= MAXPORTS) { -+ if (port >= xhci->numports) { - fprintf(stderr, "xhci_port_read: port %d out of bounds\n", port); - ret = 0; - goto out; -@@ -2342,7 +2376,7 @@ static void xhci_port_write(XHCIState *xhci, uint32_t reg, uint32_t val) - - trace_usb_xhci_port_write(port, reg & 0x0f, val); - -- if (port >= MAXPORTS) { -+ if (port >= xhci->numports) { - fprintf(stderr, "xhci_port_read: port %d out of bounds\n", port); - return; - } -@@ -2364,7 +2398,7 @@ static void xhci_port_write(XHCIState *xhci, uint32_t reg, uint32_t val) - /* write-1-to-start bits */ - if (val & PORTSC_PR) { - DPRINTF("xhci: port %d reset\n", port); -- usb_device_reset(xhci->ports[port].port.dev); -+ usb_device_reset(xhci->ports[port].uport->dev); - portsc |= PORTSC_PRC | PORTSC_PED; - } - xhci->ports[port].portsc = portsc; -@@ -2659,7 +2693,7 @@ static const MemoryRegionOps xhci_mem_ops = { - static void xhci_attach(USBPort *usbport) - { - XHCIState *xhci = usbport->opaque; -- XHCIPort *port = &xhci->ports[usbport->index]; -+ XHCIPort *port = xhci_lookup_port(xhci, usbport); - - xhci_update_port(xhci, port, 0); - } -@@ -2667,7 +2701,7 @@ static void xhci_attach(USBPort *usbport) - static void xhci_detach(USBPort *usbport) - { - XHCIState *xhci = usbport->opaque; -- XHCIPort *port = &xhci->ports[usbport->index]; -+ XHCIPort *port = xhci_lookup_port(xhci, usbport); - - xhci_update_port(xhci, port, 1); - } -@@ -2675,9 +2709,9 @@ static void xhci_detach(USBPort *usbport) - static void xhci_wakeup(USBPort *usbport) - { - XHCIState *xhci = usbport->opaque; -- XHCIPort *port = &xhci->ports[usbport->index]; -- int nr = port->port.index + 1; -- XHCIEvent ev = { ER_PORT_STATUS_CHANGE, CC_SUCCESS, nr << 24}; -+ XHCIPort *port = xhci_lookup_port(xhci, usbport); -+ XHCIEvent ev = { ER_PORT_STATUS_CHANGE, CC_SUCCESS, -+ port->portnr << 24}; - uint32_t pls; - - pls = (port->portsc >> PORTSC_PLS_SHIFT) & PORTSC_PLS_MASK; -@@ -2759,22 +2793,43 @@ static USBBusOps xhci_bus_ops = { - - static void usb_xhci_init(XHCIState *xhci, DeviceState *dev) - { -- int i; -+ XHCIPort *port; -+ int i, usbports, speedmask; - - xhci->usbsts = USBSTS_HCH; - -+ if (xhci->numports_2 > MAXPORTS_2) { -+ xhci->numports_2 = MAXPORTS_2; -+ } -+ if (xhci->numports_3 > MAXPORTS_3) { -+ xhci->numports_3 = MAXPORTS_3; -+ } -+ usbports = MAX(xhci->numports_2, xhci->numports_3); -+ xhci->numports = xhci->numports_2 + xhci->numports_3; -+ - usb_bus_new(&xhci->bus, &xhci_bus_ops, &xhci->pci_dev.qdev); - -- for (i = 0; i < MAXPORTS; i++) { -- memset(&xhci->ports[i], 0, sizeof(xhci->ports[i])); -- usb_register_port(&xhci->bus, &xhci->ports[i].port, xhci, i, -- &xhci_port_ops, -- USB_SPEED_MASK_LOW | -- USB_SPEED_MASK_FULL | -- USB_SPEED_MASK_HIGH); -- } -- for (i = 0; i < MAXSLOTS; i++) { -- xhci->slots[i].enabled = 0; -+ for (i = 0; i < usbports; i++) { -+ speedmask = 0; -+ if (i < xhci->numports_2) { -+ port = &xhci->ports[i]; -+ port->portnr = i + 1; -+ port->uport = &xhci->uports[i]; -+ port->speedmask = -+ USB_SPEED_MASK_LOW | -+ USB_SPEED_MASK_FULL | -+ USB_SPEED_MASK_HIGH; -+ speedmask |= port->speedmask; -+ } -+ if (i < xhci->numports_3) { -+ port = &xhci->ports[i + xhci->numports_2]; -+ port->portnr = i + 1 + xhci->numports_2; -+ port->uport = &xhci->uports[i]; -+ port->speedmask = USB_SPEED_MASK_SUPER; -+ speedmask |= port->speedmask; -+ } -+ usb_register_port(&xhci->bus, &xhci->uports[i], xhci, i, -+ &xhci_port_ops, speedmask); - } - } - -@@ -2830,6 +2885,8 @@ static const VMStateDescription vmstate_xhci = { - - static Property xhci_properties[] = { - DEFINE_PROP_UINT32("msi", XHCIState, msi, 0), -+ DEFINE_PROP_UINT32("p2", XHCIState, numports_2, 4), -+ DEFINE_PROP_UINT32("p3", XHCIState, numports_3, 4), - DEFINE_PROP_END_OF_LIST(), - }; - --- -1.7.12 - diff --git a/0341-usb3-superspeed-descriptors.patch b/0341-usb3-superspeed-descriptors.patch deleted file mode 100644 index 05591fe..0000000 --- a/0341-usb3-superspeed-descriptors.patch +++ /dev/null @@ -1,64 +0,0 @@ -From f25f31e864756f27f6a94ab7e66b20061291ffa5 Mon Sep 17 00:00:00 2001 -From: Gerd Hoffmann -Date: Tue, 28 Aug 2012 17:28:50 +0200 -Subject: [PATCH 341/366] usb3: superspeed descriptors - -Add superspeed descriptor entry to USBDesc, -advertise superspeed support when present. - -Signed-off-by: Gerd Hoffmann ---- - hw/usb/desc.c | 10 +++++++++- - hw/usb/desc.h | 1 + - 2 files changed, 10 insertions(+), 1 deletion(-) - -diff --git a/hw/usb/desc.c b/hw/usb/desc.c -index 0a9d3c9..3e8c6cb 100644 ---- a/hw/usb/desc.c -+++ b/hw/usb/desc.c -@@ -359,6 +359,9 @@ static void usb_desc_setdefaults(USBDevice *dev) - case USB_SPEED_HIGH: - dev->device = desc->high; - break; -+ case USB_SPEED_SUPER: -+ dev->device = desc->super; -+ break; - } - usb_desc_set_config(dev, 0); - } -@@ -376,6 +379,9 @@ void usb_desc_init(USBDevice *dev) - if (desc->high) { - dev->speedmask |= USB_SPEED_MASK_HIGH; - } -+ if (desc->super) { -+ dev->speedmask |= USB_SPEED_MASK_SUPER; -+ } - usb_desc_setdefaults(dev); - } - -@@ -384,7 +390,9 @@ void usb_desc_attach(USBDevice *dev) - const USBDesc *desc = usb_device_get_usb_desc(dev); - - assert(desc != NULL); -- if (desc->high && (dev->port->speedmask & USB_SPEED_MASK_HIGH)) { -+ if (desc->super && (dev->port->speedmask & USB_SPEED_MASK_SUPER)) { -+ dev->speed = USB_SPEED_SUPER; -+ } else if (desc->high && (dev->port->speedmask & USB_SPEED_MASK_HIGH)) { - dev->speed = USB_SPEED_HIGH; - } else if (desc->full && (dev->port->speedmask & USB_SPEED_MASK_FULL)) { - dev->speed = USB_SPEED_FULL; -diff --git a/hw/usb/desc.h b/hw/usb/desc.h -index 7cf5442..d89fa41 100644 ---- a/hw/usb/desc.h -+++ b/hw/usb/desc.h -@@ -152,6 +152,7 @@ struct USBDesc { - USBDescID id; - const USBDescDevice *full; - const USBDescDevice *high; -+ const USBDescDevice *super; - const char* const *str; - }; - --- -1.7.12 - diff --git a/0342-usb3-superspeed-endpoint-companion.patch b/0342-usb3-superspeed-endpoint-companion.patch deleted file mode 100644 index 7949f8f..0000000 --- a/0342-usb3-superspeed-endpoint-companion.patch +++ /dev/null @@ -1,248 +0,0 @@ -From 5a02a74430f4628a78f43242afbb1377deea4c80 Mon Sep 17 00:00:00 2001 -From: Gerd Hoffmann -Date: Tue, 28 Aug 2012 17:28:03 +0200 -Subject: [PATCH 342/366] usb3: superspeed endpoint companion - -Add support for building superspeed endpoint companion descriptors, -create them for superspeed usb devices. - -Signed-off-by: Gerd Hoffmann ---- - hw/usb.h | 1 + - hw/usb/desc.c | 55 ++++++++++++++++++++++++++++++++++++++++--------------- - hw/usb/desc.h | 26 +++++++++++++++++++++----- - 3 files changed, 62 insertions(+), 20 deletions(-) - -diff --git a/hw/usb.h b/hw/usb.h -index 684e3f4..78ffdf4 100644 ---- a/hw/usb.h -+++ b/hw/usb.h -@@ -137,6 +137,7 @@ - #define USB_DT_INTERFACE_ASSOC 0x0B - #define USB_DT_CS_INTERFACE 0x24 - #define USB_DT_CS_ENDPOINT 0x25 -+#define USB_DT_ENDPOINT_COMPANION 0x30 - - #define USB_ENDPOINT_XFER_CONTROL 0 - #define USB_ENDPOINT_XFER_ISOC 1 -diff --git a/hw/usb/desc.c b/hw/usb/desc.c -index 3e8c6cb..8f5a8e5 100644 ---- a/hw/usb/desc.c -+++ b/hw/usb/desc.c -@@ -76,7 +76,8 @@ int usb_desc_device_qualifier(const USBDescDevice *dev, - return bLength; - } - --int usb_desc_config(const USBDescConfig *conf, uint8_t *dest, size_t len) -+int usb_desc_config(const USBDescConfig *conf, int flags, -+ uint8_t *dest, size_t len) - { - uint8_t bLength = 0x09; - uint16_t wTotalLength = 0; -@@ -99,7 +100,7 @@ int usb_desc_config(const USBDescConfig *conf, uint8_t *dest, size_t len) - - /* handle grouped interfaces if any */ - for (i = 0; i < conf->nif_groups; i++) { -- rc = usb_desc_iface_group(&(conf->if_groups[i]), -+ rc = usb_desc_iface_group(&(conf->if_groups[i]), flags, - dest + wTotalLength, - len - wTotalLength); - if (rc < 0) { -@@ -110,7 +111,8 @@ int usb_desc_config(const USBDescConfig *conf, uint8_t *dest, size_t len) - - /* handle normal (ungrouped / no IAD) interfaces if any */ - for (i = 0; i < conf->nif; i++) { -- rc = usb_desc_iface(conf->ifs + i, dest + wTotalLength, len - wTotalLength); -+ rc = usb_desc_iface(conf->ifs + i, flags, -+ dest + wTotalLength, len - wTotalLength); - if (rc < 0) { - return rc; - } -@@ -122,8 +124,8 @@ int usb_desc_config(const USBDescConfig *conf, uint8_t *dest, size_t len) - return wTotalLength; - } - --int usb_desc_iface_group(const USBDescIfaceAssoc *iad, uint8_t *dest, -- size_t len) -+int usb_desc_iface_group(const USBDescIfaceAssoc *iad, int flags, -+ uint8_t *dest, size_t len) - { - int pos = 0; - int i = 0; -@@ -147,7 +149,7 @@ int usb_desc_iface_group(const USBDescIfaceAssoc *iad, uint8_t *dest, - - /* handle associated interfaces in this group */ - for (i = 0; i < iad->nif; i++) { -- int rc = usb_desc_iface(&(iad->ifs[i]), dest + pos, len - pos); -+ int rc = usb_desc_iface(&(iad->ifs[i]), flags, dest + pos, len - pos); - if (rc < 0) { - return rc; - } -@@ -157,7 +159,8 @@ int usb_desc_iface_group(const USBDescIfaceAssoc *iad, uint8_t *dest, - return pos; - } - --int usb_desc_iface(const USBDescIface *iface, uint8_t *dest, size_t len) -+int usb_desc_iface(const USBDescIface *iface, int flags, -+ uint8_t *dest, size_t len) - { - uint8_t bLength = 0x09; - int i, rc, pos = 0; -@@ -188,7 +191,7 @@ int usb_desc_iface(const USBDescIface *iface, uint8_t *dest, size_t len) - } - - for (i = 0; i < iface->bNumEndpoints; i++) { -- rc = usb_desc_endpoint(iface->eps + i, dest + pos, len - pos); -+ rc = usb_desc_endpoint(iface->eps + i, flags, dest + pos, len - pos); - if (rc < 0) { - return rc; - } -@@ -198,13 +201,15 @@ int usb_desc_iface(const USBDescIface *iface, uint8_t *dest, size_t len) - return pos; - } - --int usb_desc_endpoint(const USBDescEndpoint *ep, uint8_t *dest, size_t len) -+int usb_desc_endpoint(const USBDescEndpoint *ep, int flags, -+ uint8_t *dest, size_t len) - { - uint8_t bLength = ep->is_audio ? 0x09 : 0x07; - uint8_t extralen = ep->extra ? ep->extra[0] : 0; -+ uint8_t superlen = (flags & USB_DESC_FLAG_SUPER) ? 0x06 : 0; - USBDescriptor *d = (void *)dest; - -- if (len < bLength + extralen) { -+ if (len < bLength + extralen + superlen) { - return -1; - } - -@@ -224,7 +229,21 @@ int usb_desc_endpoint(const USBDescEndpoint *ep, uint8_t *dest, size_t len) - memcpy(dest + bLength, ep->extra, extralen); - } - -- return bLength + extralen; -+ if (superlen) { -+ USBDescriptor *d = (void *)(dest + bLength + extralen); -+ -+ d->bLength = 0x06; -+ d->bDescriptorType = USB_DT_ENDPOINT_COMPANION; -+ -+ d->u.super_endpoint.bMaxBurst = ep->bMaxBurst; -+ d->u.super_endpoint.bmAttributes = ep->bmAttributes_super; -+ d->u.super_endpoint.wBytesPerInterval_lo = -+ usb_lo(ep->wBytesPerInterval); -+ d->u.super_endpoint.wBytesPerInterval_hi = -+ usb_hi(ep->wBytesPerInterval); -+ } -+ -+ return bLength + extralen + superlen; - } - - int usb_desc_other(const USBDescOther *desc, uint8_t *dest, size_t len) -@@ -509,7 +528,7 @@ int usb_desc_get_descriptor(USBDevice *dev, int value, uint8_t *dest, size_t len - uint8_t buf[256]; - uint8_t type = value >> 8; - uint8_t index = value & 0xff; -- int ret = -1; -+ int flags, ret = -1; - - if (dev->speed == USB_SPEED_HIGH) { - other_dev = usb_device_get_usb_desc(dev)->full; -@@ -517,6 +536,11 @@ int usb_desc_get_descriptor(USBDevice *dev, int value, uint8_t *dest, size_t len - other_dev = usb_device_get_usb_desc(dev)->high; - } - -+ flags = 0; -+ if (dev->device->bcdUSB >= 0x0300) { -+ flags |= USB_DESC_FLAG_SUPER; -+ } -+ - switch(type) { - case USB_DT_DEVICE: - ret = usb_desc_device(&desc->id, dev->device, buf, sizeof(buf)); -@@ -524,7 +548,8 @@ int usb_desc_get_descriptor(USBDevice *dev, int value, uint8_t *dest, size_t len - break; - case USB_DT_CONFIG: - if (index < dev->device->bNumConfigurations) { -- ret = usb_desc_config(dev->device->confs + index, buf, sizeof(buf)); -+ ret = usb_desc_config(dev->device->confs + index, flags, -+ buf, sizeof(buf)); - } - trace_usb_desc_config(dev->addr, index, len, ret); - break; -@@ -532,7 +557,6 @@ int usb_desc_get_descriptor(USBDevice *dev, int value, uint8_t *dest, size_t len - ret = usb_desc_string(dev, index, buf, sizeof(buf)); - trace_usb_desc_string(dev->addr, index, len, ret); - break; -- - case USB_DT_DEVICE_QUALIFIER: - if (other_dev != NULL) { - ret = usb_desc_device_qualifier(other_dev, buf, sizeof(buf)); -@@ -541,7 +565,8 @@ int usb_desc_get_descriptor(USBDevice *dev, int value, uint8_t *dest, size_t len - break; - case USB_DT_OTHER_SPEED_CONFIG: - if (other_dev != NULL && index < other_dev->bNumConfigurations) { -- ret = usb_desc_config(other_dev->confs + index, buf, sizeof(buf)); -+ ret = usb_desc_config(other_dev->confs + index, flags, -+ buf, sizeof(buf)); - buf[0x01] = USB_DT_OTHER_SPEED_CONFIG; - } - trace_usb_desc_other_speed_config(dev->addr, index, len, ret); -diff --git a/hw/usb/desc.h b/hw/usb/desc.h -index d89fa41..4b5e88d 100644 ---- a/hw/usb/desc.h -+++ b/hw/usb/desc.h -@@ -63,6 +63,12 @@ typedef struct USBDescriptor { - uint8_t bRefresh; /* only audio ep */ - uint8_t bSynchAddress; /* only audio ep */ - } endpoint; -+ struct { -+ uint8_t bMaxBurst; -+ uint8_t bmAttributes; -+ uint8_t wBytesPerInterval_lo; -+ uint8_t wBytesPerInterval_hi; -+ } super_endpoint; - } u; - } QEMU_PACKED USBDescriptor; - -@@ -139,6 +145,11 @@ struct USBDescEndpoint { - - uint8_t is_audio; /* has bRefresh + bSynchAddress */ - uint8_t *extra; -+ -+ /* superspeed endpoint companion */ -+ uint8_t bMaxBurst; -+ uint8_t bmAttributes_super; -+ uint16_t wBytesPerInterval; - }; - - struct USBDescOther { -@@ -156,16 +167,21 @@ struct USBDesc { - const char* const *str; - }; - -+#define USB_DESC_FLAG_SUPER (1 << 1) -+ - /* generate usb packages from structs */ - int usb_desc_device(const USBDescID *id, const USBDescDevice *dev, - uint8_t *dest, size_t len); - int usb_desc_device_qualifier(const USBDescDevice *dev, - uint8_t *dest, size_t len); --int usb_desc_config(const USBDescConfig *conf, uint8_t *dest, size_t len); --int usb_desc_iface_group(const USBDescIfaceAssoc *iad, uint8_t *dest, -- size_t len); --int usb_desc_iface(const USBDescIface *iface, uint8_t *dest, size_t len); --int usb_desc_endpoint(const USBDescEndpoint *ep, uint8_t *dest, size_t len); -+int usb_desc_config(const USBDescConfig *conf, int flags, -+ uint8_t *dest, size_t len); -+int usb_desc_iface_group(const USBDescIfaceAssoc *iad, int flags, -+ uint8_t *dest, size_t len); -+int usb_desc_iface(const USBDescIface *iface, int flags, -+ uint8_t *dest, size_t len); -+int usb_desc_endpoint(const USBDescEndpoint *ep, int flags, -+ uint8_t *dest, size_t len); - int usb_desc_other(const USBDescOther *desc, uint8_t *dest, size_t len); - - /* control message emulation helpers */ --- -1.7.12 - diff --git a/0343-usb3-bos-decriptor.patch b/0343-usb3-bos-decriptor.patch deleted file mode 100644 index 3158fd0..0000000 --- a/0343-usb3-bos-decriptor.patch +++ /dev/null @@ -1,215 +0,0 @@ -From 52666569c1aa34531c101e005feccec0899c14e2 Mon Sep 17 00:00:00 2001 -From: Gerd Hoffmann -Date: Tue, 28 Aug 2012 17:46:29 +0200 -Subject: [PATCH 343/366] usb3: bos decriptor - -Add support for creating BOS descriptor and -device cappability descriptors. - -Signed-off-by: Gerd Hoffmann ---- - hw/usb.h | 6 ++++ - hw/usb/desc.c | 109 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - hw/usb/desc.h | 25 ++++++++++++++ - trace-events | 1 + - 4 files changed, 141 insertions(+) - -diff --git a/hw/usb.h b/hw/usb.h -index 78ffdf4..48c8926 100644 ---- a/hw/usb.h -+++ b/hw/usb.h -@@ -135,10 +135,16 @@ - #define USB_DT_OTHER_SPEED_CONFIG 0x07 - #define USB_DT_DEBUG 0x0A - #define USB_DT_INTERFACE_ASSOC 0x0B -+#define USB_DT_BOS 0x0F -+#define USB_DT_DEVICE_CAPABILITY 0x10 - #define USB_DT_CS_INTERFACE 0x24 - #define USB_DT_CS_ENDPOINT 0x25 - #define USB_DT_ENDPOINT_COMPANION 0x30 - -+#define USB_DEV_CAP_WIRELESS 0x01 -+#define USB_DEV_CAP_USB2_EXT 0x02 -+#define USB_DEV_CAP_SUPERSPEED 0x03 -+ - #define USB_ENDPOINT_XFER_CONTROL 0 - #define USB_ENDPOINT_XFER_ISOC 1 - #define USB_ENDPOINT_XFER_BULK 2 -diff --git a/hw/usb/desc.c b/hw/usb/desc.c -index 8f5a8e5..1f12eae 100644 ---- a/hw/usb/desc.c -+++ b/hw/usb/desc.c -@@ -258,6 +258,111 @@ int usb_desc_other(const USBDescOther *desc, uint8_t *dest, size_t len) - return bLength; - } - -+static int usb_desc_cap_usb2_ext(const USBDesc *desc, uint8_t *dest, size_t len) -+{ -+ uint8_t bLength = 0x07; -+ USBDescriptor *d = (void *)dest; -+ -+ if (len < bLength) { -+ return -1; -+ } -+ -+ d->bLength = bLength; -+ d->bDescriptorType = USB_DT_DEVICE_CAPABILITY; -+ d->u.cap.bDevCapabilityType = USB_DEV_CAP_USB2_EXT; -+ -+ d->u.cap.u.usb2_ext.bmAttributes_1 = (1 << 1); /* LPM */ -+ d->u.cap.u.usb2_ext.bmAttributes_2 = 0; -+ d->u.cap.u.usb2_ext.bmAttributes_3 = 0; -+ d->u.cap.u.usb2_ext.bmAttributes_4 = 0; -+ -+ return bLength; -+} -+ -+static int usb_desc_cap_super(const USBDesc *desc, uint8_t *dest, size_t len) -+{ -+ uint8_t bLength = 0x0a; -+ USBDescriptor *d = (void *)dest; -+ -+ if (len < bLength) { -+ return -1; -+ } -+ -+ d->bLength = bLength; -+ d->bDescriptorType = USB_DT_DEVICE_CAPABILITY; -+ d->u.cap.bDevCapabilityType = USB_DEV_CAP_SUPERSPEED; -+ -+ d->u.cap.u.super.bmAttributes = 0; -+ d->u.cap.u.super.wSpeedsSupported_lo = 0; -+ d->u.cap.u.super.wSpeedsSupported_hi = 0; -+ d->u.cap.u.super.bFunctionalitySupport = 0; -+ d->u.cap.u.super.bU1DevExitLat = 0x0a; -+ d->u.cap.u.super.wU2DevExitLat_lo = 0x20; -+ d->u.cap.u.super.wU2DevExitLat_hi = 0; -+ -+ if (desc->full) { -+ d->u.cap.u.super.wSpeedsSupported_lo |= (1 << 1); -+ d->u.cap.u.super.bFunctionalitySupport = 1; -+ } -+ if (desc->high) { -+ d->u.cap.u.super.wSpeedsSupported_lo |= (1 << 2); -+ if (!d->u.cap.u.super.bFunctionalitySupport) { -+ d->u.cap.u.super.bFunctionalitySupport = 2; -+ } -+ } -+ if (desc->super) { -+ d->u.cap.u.super.wSpeedsSupported_lo |= (1 << 3); -+ if (!d->u.cap.u.super.bFunctionalitySupport) { -+ d->u.cap.u.super.bFunctionalitySupport = 3; -+ } -+ } -+ -+ return bLength; -+} -+ -+static int usb_desc_bos(const USBDesc *desc, uint8_t *dest, size_t len) -+{ -+ uint8_t bLength = 0x05; -+ uint16_t wTotalLength = 0; -+ uint8_t bNumDeviceCaps = 0; -+ USBDescriptor *d = (void *)dest; -+ int rc; -+ -+ if (len < bLength) { -+ return -1; -+ } -+ -+ d->bLength = bLength; -+ d->bDescriptorType = USB_DT_BOS; -+ -+ wTotalLength += bLength; -+ -+ if (desc->high != NULL) { -+ rc = usb_desc_cap_usb2_ext(desc, dest + wTotalLength, -+ len - wTotalLength); -+ if (rc < 0) { -+ return rc; -+ } -+ wTotalLength += rc; -+ bNumDeviceCaps++; -+ } -+ -+ if (desc->super != NULL) { -+ rc = usb_desc_cap_super(desc, dest + wTotalLength, -+ len - wTotalLength); -+ if (rc < 0) { -+ return rc; -+ } -+ wTotalLength += rc; -+ bNumDeviceCaps++; -+ } -+ -+ d->u.bos.wTotalLength_lo = usb_lo(wTotalLength); -+ d->u.bos.wTotalLength_hi = usb_hi(wTotalLength); -+ d->u.bos.bNumDeviceCaps = bNumDeviceCaps; -+ return wTotalLength; -+} -+ - /* ------------------------------------------------------------------ */ - - static void usb_desc_ep_init(USBDevice *dev) -@@ -571,6 +676,10 @@ int usb_desc_get_descriptor(USBDevice *dev, int value, uint8_t *dest, size_t len - } - trace_usb_desc_other_speed_config(dev->addr, index, len, ret); - break; -+ case USB_DT_BOS: -+ ret = usb_desc_bos(desc, buf, sizeof(buf)); -+ trace_usb_desc_bos(dev->addr, len, ret); -+ break; - - case USB_DT_DEBUG: - /* ignore silently */ -diff --git a/hw/usb/desc.h b/hw/usb/desc.h -index 4b5e88d..68bb570 100644 ---- a/hw/usb/desc.h -+++ b/hw/usb/desc.h -@@ -69,6 +69,31 @@ typedef struct USBDescriptor { - uint8_t wBytesPerInterval_lo; - uint8_t wBytesPerInterval_hi; - } super_endpoint; -+ struct { -+ uint8_t wTotalLength_lo; -+ uint8_t wTotalLength_hi; -+ uint8_t bNumDeviceCaps; -+ } bos; -+ struct { -+ uint8_t bDevCapabilityType; -+ union { -+ struct { -+ uint8_t bmAttributes_1; -+ uint8_t bmAttributes_2; -+ uint8_t bmAttributes_3; -+ uint8_t bmAttributes_4; -+ } usb2_ext; -+ struct { -+ uint8_t bmAttributes; -+ uint8_t wSpeedsSupported_lo; -+ uint8_t wSpeedsSupported_hi; -+ uint8_t bFunctionalitySupport; -+ uint8_t bU1DevExitLat; -+ uint8_t wU2DevExitLat_lo; -+ uint8_t wU2DevExitLat_hi; -+ } super; -+ } u; -+ } cap; - } u; - } QEMU_PACKED USBDescriptor; - -diff --git a/trace-events b/trace-events -index a894689..5bc591a 100644 ---- a/trace-events -+++ b/trace-events -@@ -340,6 +340,7 @@ usb_desc_device_qualifier(int addr, int len, int ret) "dev %d query device quali - usb_desc_config(int addr, int index, int len, int ret) "dev %d query config %d, len %d, ret %d" - usb_desc_other_speed_config(int addr, int index, int len, int ret) "dev %d query config %d, len %d, ret %d" - usb_desc_string(int addr, int index, int len, int ret) "dev %d query string %d, len %d, ret %d" -+usb_desc_bos(int addr, int len, int ret) "dev %d bos, len %d, ret %d" - usb_set_addr(int addr) "dev %d" - usb_set_config(int addr, int config, int ret) "dev %d, config %d, ret %d" - usb_set_interface(int addr, int iface, int alt, int ret) "dev %d, interface %d, altsetting %d, ret %d" --- -1.7.12 - diff --git a/0344-usb-storage-usb3-support.patch b/0344-usb-storage-usb3-support.patch deleted file mode 100644 index b50fcdd..0000000 --- a/0344-usb-storage-usb3-support.patch +++ /dev/null @@ -1,94 +0,0 @@ -From 4a6f1fdf12d8b03633dad54dadc12781a77fbf6b Mon Sep 17 00:00:00 2001 -From: Gerd Hoffmann -Date: Tue, 28 Aug 2012 17:29:15 +0200 -Subject: [PATCH 344/366] usb-storage: usb3 support - -Add usb3 descriptors to usb-storage, so it shows up as superspeed -device when connected to xhci. - -Signed-off-by: Gerd Hoffmann ---- - hw/usb/dev-storage.c | 46 +++++++++++++++++++++++++++++++++++++++++++--- - 1 file changed, 43 insertions(+), 3 deletions(-) - -diff --git a/hw/usb/dev-storage.c b/hw/usb/dev-storage.c -index ff48d91..e732191 100644 ---- a/hw/usb/dev-storage.c -+++ b/hw/usb/dev-storage.c -@@ -78,6 +78,7 @@ enum { - STR_SERIALNUMBER, - STR_CONFIG_FULL, - STR_CONFIG_HIGH, -+ STR_CONFIG_SUPER, - }; - - static const USBDescStrings desc_strings = { -@@ -86,6 +87,7 @@ static const USBDescStrings desc_strings = { - [STR_SERIALNUMBER] = "1", - [STR_CONFIG_FULL] = "Full speed config (usb 1.1)", - [STR_CONFIG_HIGH] = "High speed config (usb 2.0)", -+ [STR_CONFIG_SUPER] = "Super speed config (usb 3.0)", - }; - - static const USBDescIface desc_iface_full = { -@@ -158,6 +160,43 @@ static const USBDescDevice desc_device_high = { - }, - }; - -+static const USBDescIface desc_iface_super = { -+ .bInterfaceNumber = 0, -+ .bNumEndpoints = 2, -+ .bInterfaceClass = USB_CLASS_MASS_STORAGE, -+ .bInterfaceSubClass = 0x06, /* SCSI */ -+ .bInterfaceProtocol = 0x50, /* Bulk */ -+ .eps = (USBDescEndpoint[]) { -+ { -+ .bEndpointAddress = USB_DIR_IN | 0x01, -+ .bmAttributes = USB_ENDPOINT_XFER_BULK, -+ .wMaxPacketSize = 1024, -+ .bMaxBurst = 15, -+ },{ -+ .bEndpointAddress = USB_DIR_OUT | 0x02, -+ .bmAttributes = USB_ENDPOINT_XFER_BULK, -+ .wMaxPacketSize = 1024, -+ .bMaxBurst = 15, -+ }, -+ } -+}; -+ -+static const USBDescDevice desc_device_super = { -+ .bcdUSB = 0x0300, -+ .bMaxPacketSize0 = 9, -+ .bNumConfigurations = 1, -+ .confs = (USBDescConfig[]) { -+ { -+ .bNumInterfaces = 1, -+ .bConfigurationValue = 1, -+ .iConfiguration = STR_CONFIG_SUPER, -+ .bmAttributes = 0xc0, -+ .nif = 1, -+ .ifs = &desc_iface_super, -+ }, -+ }, -+}; -+ - static const USBDesc desc = { - .id = { - .idVendor = 0x46f4, /* CRC16() of "QEMU" */ -@@ -167,9 +206,10 @@ static const USBDesc desc = { - .iProduct = STR_PRODUCT, - .iSerialNumber = STR_SERIALNUMBER, - }, -- .full = &desc_device_full, -- .high = &desc_device_high, -- .str = desc_strings, -+ .full = &desc_device_full, -+ .high = &desc_device_high, -+ .super = &desc_device_super, -+ .str = desc_strings, - }; - - static void usb_msd_copy_data(MSDState *s, USBPacket *p) --- -1.7.12 - diff --git a/0345-xhci-fix-cleanup-msi.patch b/0345-xhci-fix-cleanup-msi.patch deleted file mode 100644 index 5f25cbd..0000000 --- a/0345-xhci-fix-cleanup-msi.patch +++ /dev/null @@ -1,96 +0,0 @@ -From 3ed11ea2c3b6d5db29246b4da105902aa0346d65 Mon Sep 17 00:00:00 2001 -From: Gerd Hoffmann -Date: Thu, 30 Aug 2012 10:57:12 +0200 -Subject: [PATCH 345/366] xhci: fix & cleanup msi. - -Drop custom write_config function which isn't needed any more. -Make the msi property a bit property so it accepts 'on' & 'off'. -Enable MSI by default. - -TODO: add compat property to disable on old machine types. - -Signed-off-by: Gerd Hoffmann ---- - hw/usb/hcd-xhci.c | 27 +++++++++------------------ - 1 file changed, 9 insertions(+), 18 deletions(-) - -diff --git a/hw/usb/hcd-xhci.c b/hw/usb/hcd-xhci.c -index e08312e..e1d5d2a 100644 ---- a/hw/usb/hcd-xhci.c -+++ b/hw/usb/hcd-xhci.c -@@ -386,7 +386,7 @@ struct XHCIState { - /* properties */ - uint32_t numports_2; - uint32_t numports_3; -- uint32_t msi; -+ uint32_t flags; - - /* Operational Registers */ - uint32_t usbcmd; -@@ -435,6 +435,10 @@ typedef struct XHCIEvRingSeg { - uint32_t rsvd; - } XHCIEvRingSeg; - -+enum xhci_flags { -+ XHCI_FLAG_USE_MSI = 1, -+}; -+ - static void xhci_kick_ep(XHCIState *xhci, unsigned int slotid, - unsigned int epid); - static void xhci_event(XHCIState *xhci, XHCIEvent *event); -@@ -617,7 +621,7 @@ static void xhci_irq_update(XHCIState *xhci) - level = 1; - } - -- if (xhci->msi && msi_enabled(&xhci->pci_dev)) { -+ if (msi_enabled(&xhci->pci_dev)) { - if (level) { - trace_usb_xhci_irq_msi(0); - msi_notify(&xhci->pci_dev, 0); -@@ -2859,32 +2863,20 @@ static int usb_xhci_initfn(struct PCIDevice *dev) - ret = pcie_cap_init(&xhci->pci_dev, 0xa0, PCI_EXP_TYPE_ENDPOINT, 0); - assert(ret >= 0); - -- if (xhci->msi) { -- ret = msi_init(&xhci->pci_dev, 0x70, 1, true, false); -- assert(ret >= 0); -+ if (xhci->flags & (1 << XHCI_FLAG_USE_MSI)) { -+ msi_init(&xhci->pci_dev, 0x70, MAXINTRS, true, false); - } - - return 0; - } - --static void xhci_write_config(PCIDevice *dev, uint32_t addr, uint32_t val, -- int len) --{ -- XHCIState *xhci = DO_UPCAST(XHCIState, pci_dev, dev); -- -- pci_default_write_config(dev, addr, val, len); -- if (xhci->msi) { -- msi_write_config(dev, addr, val, len); -- } --} -- - static const VMStateDescription vmstate_xhci = { - .name = "xhci", - .unmigratable = 1, - }; - - static Property xhci_properties[] = { -- DEFINE_PROP_UINT32("msi", XHCIState, msi, 0), -+ DEFINE_PROP_BIT("msi", XHCIState, flags, XHCI_FLAG_USE_MSI, true), - DEFINE_PROP_UINT32("p2", XHCIState, numports_2, 4), - DEFINE_PROP_UINT32("p3", XHCIState, numports_3, 4), - DEFINE_PROP_END_OF_LIST(), -@@ -2904,7 +2896,6 @@ static void xhci_class_init(ObjectClass *klass, void *data) - k->class_id = PCI_CLASS_SERIAL_USB; - k->revision = 0x03; - k->is_express = 1; -- k->config_write = xhci_write_config; - } - - static TypeInfo xhci_info = { --- -1.7.12 - diff --git a/0346-xhci-rework-interrupt-handling.patch b/0346-xhci-rework-interrupt-handling.patch deleted file mode 100644 index b0ea1df..0000000 --- a/0346-xhci-rework-interrupt-handling.patch +++ /dev/null @@ -1,117 +0,0 @@ -From da881a3422ae525f1d0a24f61117a47473261037 Mon Sep 17 00:00:00 2001 -From: Gerd Hoffmann -Date: Thu, 30 Aug 2012 13:05:10 +0200 -Subject: [PATCH 346/366] xhci: rework interrupt handling - -Split xhci_irq_update into a function which handles intx updates -(including lowering the irq line once the guests acks the interrupt) -and one which is used for raising an irq only. - -Signed-off-by: Gerd Hoffmann ---- - hw/usb/hcd-xhci.c | 47 +++++++++++++++++++++++++++++++++-------------- - 1 file changed, 33 insertions(+), 14 deletions(-) - -diff --git a/hw/usb/hcd-xhci.c b/hw/usb/hcd-xhci.c -index e1d5d2a..5eae32e 100644 ---- a/hw/usb/hcd-xhci.c -+++ b/hw/usb/hcd-xhci.c -@@ -612,24 +612,43 @@ static XHCIPort *xhci_lookup_port(XHCIState *xhci, struct USBPort *uport) - return &xhci->ports[index]; - } - --static void xhci_irq_update(XHCIState *xhci) -+static void xhci_intx_update(XHCIState *xhci) - { - int level = 0; - -- if (xhci->iman & IMAN_IP && xhci->iman & IMAN_IE && -+ if (msi_enabled(&xhci->pci_dev)) { -+ return; -+ } -+ -+ if (xhci->iman & IMAN_IP && -+ xhci->iman & IMAN_IE && - xhci->usbcmd & USBCMD_INTE) { - level = 1; - } - -+ trace_usb_xhci_irq_intx(level); -+ qemu_set_irq(xhci->irq, level); -+} -+ -+static void xhci_intr_raise(XHCIState *xhci) -+{ -+ if (!(xhci->iman & IMAN_IP) || -+ !(xhci->iman & IMAN_IE)) { -+ return; -+ } -+ -+ if (!(xhci->usbcmd & USBCMD_INTE)) { -+ return; -+ } -+ - if (msi_enabled(&xhci->pci_dev)) { -- if (level) { -- trace_usb_xhci_irq_msi(0); -- msi_notify(&xhci->pci_dev, 0); -- } -- } else { -- trace_usb_xhci_irq_intx(level); -- qemu_set_irq(xhci->irq, level); -+ trace_usb_xhci_irq_msi(0); -+ msi_notify(&xhci->pci_dev, 0); -+ return; - } -+ -+ trace_usb_xhci_irq_intx(1); -+ qemu_set_irq(xhci->irq, 1); - } - - static inline int xhci_running(XHCIState *xhci) -@@ -732,7 +751,7 @@ static void xhci_events_update(XHCIState *xhci) - xhci->erdp_low |= ERDP_EHB; - xhci->iman |= IMAN_IP; - xhci->usbsts |= USBSTS_EINT; -- xhci_irq_update(xhci); -+ xhci_intr_raise(xhci); - } - - if (xhci->er_full && xhci->ev_buffer_put == xhci->ev_buffer_get) { -@@ -796,7 +815,7 @@ static void xhci_event(XHCIState *xhci, XHCIEvent *event) - xhci->iman |= IMAN_IP; - xhci->usbsts |= USBSTS_EINT; - -- xhci_irq_update(xhci); -+ xhci_intr_raise(xhci); - } - - static void xhci_ring_init(XHCIState *xhci, XHCIRing *ring, -@@ -2481,13 +2500,13 @@ static void xhci_oper_write(XHCIState *xhci, uint32_t reg, uint32_t val) - if (val & USBCMD_HCRST) { - xhci_reset(&xhci->pci_dev.qdev); - } -- xhci_irq_update(xhci); -+ xhci_intx_update(xhci); - break; - - case 0x04: /* USBSTS */ - /* these bits are write-1-to-clear */ - xhci->usbsts &= ~(val & (USBSTS_HSE|USBSTS_EINT|USBSTS_PCD|USBSTS_SRE)); -- xhci_irq_update(xhci); -+ xhci_intx_update(xhci); - break; - - case 0x14: /* DNCTRL */ -@@ -2572,7 +2591,7 @@ static void xhci_runtime_write(XHCIState *xhci, uint32_t reg, uint32_t val) - } - xhci->iman &= ~IMAN_IE; - xhci->iman |= val & IMAN_IE; -- xhci_irq_update(xhci); -+ xhci_intx_update(xhci); - break; - case 0x24: /* IMOD */ - xhci->imod = val; --- -1.7.12 - diff --git a/0347-xhci-add-msix-support.patch b/0347-xhci-add-msix-support.patch deleted file mode 100644 index 5110aaa..0000000 --- a/0347-xhci-add-msix-support.patch +++ /dev/null @@ -1,156 +0,0 @@ -From 03ab86ecf677d777864a3643ec8479037d3f41cd Mon Sep 17 00:00:00 2001 -From: Gerd Hoffmann -Date: Thu, 30 Aug 2012 12:06:59 +0200 -Subject: [PATCH 347/366] xhci: add msix support - -Signed-off-by: Gerd Hoffmann ---- - hw/usb/hcd-xhci.c | 47 ++++++++++++++++++++++++++++++++++++++++++++++- - trace-events | 3 +++ - 2 files changed, 49 insertions(+), 1 deletion(-) - -diff --git a/hw/usb/hcd-xhci.c b/hw/usb/hcd-xhci.c -index 5eae32e..3bac99a 100644 ---- a/hw/usb/hcd-xhci.c -+++ b/hw/usb/hcd-xhci.c -@@ -23,6 +23,7 @@ - #include "hw/usb.h" - #include "hw/pci.h" - #include "hw/msi.h" -+#include "hw/msix.h" - #include "trace.h" - - //#define DEBUG_XHCI -@@ -59,6 +60,8 @@ - #define OFF_OPER LEN_CAP - #define OFF_RUNTIME 0x1000 - #define OFF_DOORBELL 0x2000 -+#define OFF_MSIX_TABLE 0x3000 -+#define OFF_MSIX_PBA 0x3800 - /* must be power of 2 */ - #define LEN_REGS 0x4000 - -@@ -411,6 +414,7 @@ struct XHCIState { - uint32_t erstba_high; - uint32_t erdp_low; - uint32_t erdp_high; -+ bool msix_used; - - int64_t mfindex_start; - QEMUTimer *mfwrap_timer; -@@ -437,6 +441,7 @@ typedef struct XHCIEvRingSeg { - - enum xhci_flags { - XHCI_FLAG_USE_MSI = 1, -+ XHCI_FLAG_USE_MSI_X, - }; - - static void xhci_kick_ep(XHCIState *xhci, unsigned int slotid, -@@ -616,7 +621,8 @@ static void xhci_intx_update(XHCIState *xhci) - { - int level = 0; - -- if (msi_enabled(&xhci->pci_dev)) { -+ if (msix_enabled(&xhci->pci_dev) || -+ msi_enabled(&xhci->pci_dev)) { - return; - } - -@@ -630,6 +636,30 @@ static void xhci_intx_update(XHCIState *xhci) - qemu_set_irq(xhci->irq, level); - } - -+static void xhci_msix_update(XHCIState *xhci) -+{ -+ bool enabled; -+ -+ if (!msix_enabled(&xhci->pci_dev)) { -+ return; -+ } -+ -+ enabled = xhci->iman & IMAN_IE; -+ if (enabled == xhci->msix_used) { -+ return; -+ } -+ -+ if (enabled) { -+ trace_usb_xhci_irq_msix_use(0); -+ msix_vector_use(&xhci->pci_dev, 0); -+ xhci->msix_used = true; -+ } else { -+ trace_usb_xhci_irq_msix_unuse(0); -+ msix_vector_unuse(&xhci->pci_dev, 0); -+ xhci->msix_used = false; -+ } -+} -+ - static void xhci_intr_raise(XHCIState *xhci) - { - if (!(xhci->iman & IMAN_IP) || -@@ -641,6 +671,12 @@ static void xhci_intr_raise(XHCIState *xhci) - return; - } - -+ if (msix_enabled(&xhci->pci_dev)) { -+ trace_usb_xhci_irq_msix(0); -+ msix_notify(&xhci->pci_dev, 0); -+ return; -+ } -+ - if (msi_enabled(&xhci->pci_dev)) { - trace_usb_xhci_irq_msi(0); - msi_notify(&xhci->pci_dev, 0); -@@ -2284,6 +2320,7 @@ static void xhci_reset(DeviceState *dev) - xhci->erstba_high = 0; - xhci->erdp_low = 0; - xhci->erdp_high = 0; -+ xhci->msix_used = 0; - - xhci->er_ep_idx = 0; - xhci->er_pcs = 1; -@@ -2592,6 +2629,7 @@ static void xhci_runtime_write(XHCIState *xhci, uint32_t reg, uint32_t val) - xhci->iman &= ~IMAN_IE; - xhci->iman |= val & IMAN_IE; - xhci_intx_update(xhci); -+ xhci_msix_update(xhci); - break; - case 0x24: /* IMOD */ - xhci->imod = val; -@@ -2885,6 +2923,12 @@ static int usb_xhci_initfn(struct PCIDevice *dev) - if (xhci->flags & (1 << XHCI_FLAG_USE_MSI)) { - msi_init(&xhci->pci_dev, 0x70, MAXINTRS, true, false); - } -+ if (xhci->flags & (1 << XHCI_FLAG_USE_MSI_X)) { -+ msix_init(&xhci->pci_dev, MAXINTRS, -+ &xhci->mem, 0, OFF_MSIX_TABLE, -+ &xhci->mem, 0, OFF_MSIX_PBA, -+ 0x90); -+ } - - return 0; - } -@@ -2896,6 +2940,7 @@ static const VMStateDescription vmstate_xhci = { - - static Property xhci_properties[] = { - DEFINE_PROP_BIT("msi", XHCIState, flags, XHCI_FLAG_USE_MSI, true), -+ DEFINE_PROP_BIT("msix", XHCIState, flags, XHCI_FLAG_USE_MSI_X, true), - DEFINE_PROP_UINT32("p2", XHCIState, numports_2, 4), - DEFINE_PROP_UINT32("p3", XHCIState, numports_3, 4), - DEFINE_PROP_END_OF_LIST(), -diff --git a/trace-events b/trace-events -index 5bc591a..8589ca4 100644 ---- a/trace-events -+++ b/trace-events -@@ -313,6 +313,9 @@ usb_xhci_runtime_write(uint32_t off, uint32_t val) "off 0x%04x, val 0x%08x" - usb_xhci_doorbell_write(uint32_t off, uint32_t val) "off 0x%04x, val 0x%08x" - usb_xhci_irq_intx(uint32_t level) "level %d" - usb_xhci_irq_msi(uint32_t nr) "nr %d" -+usb_xhci_irq_msix(uint32_t nr) "nr %d" -+usb_xhci_irq_msix_use(uint32_t nr) "nr %d" -+usb_xhci_irq_msix_unuse(uint32_t nr) "nr %d" - usb_xhci_queue_event(uint32_t idx, const char *trb, const char *evt, uint64_t param, uint32_t status, uint32_t control) "idx %d, %s, %s, p %016" PRIx64 ", s %08x, c 0x%08x" - usb_xhci_fetch_trb(uint64_t addr, const char *name, uint64_t param, uint32_t status, uint32_t control) "addr %016" PRIx64 ", %s, p %016" PRIx64 ", s %08x, c 0x%08x" - usb_xhci_slot_enable(uint32_t slotid) "slotid %d" --- -1.7.12 - diff --git a/0348-xhci-move-register-update-into-xhci_intr_raise.patch b/0348-xhci-move-register-update-into-xhci_intr_raise.patch deleted file mode 100644 index 60537da..0000000 --- a/0348-xhci-move-register-update-into-xhci_intr_raise.patch +++ /dev/null @@ -1,55 +0,0 @@ -From c7ca31b2f54b945ba4babf8ad329c938462c75f5 Mon Sep 17 00:00:00 2001 -From: Gerd Hoffmann -Date: Thu, 30 Aug 2012 14:04:04 +0200 -Subject: [PATCH 348/366] xhci: move register update into xhci_intr_raise - -Now that we have a separate function to raise an IRQ we can move -some comon code into the function. - -Signed-off-by: Gerd Hoffmann ---- - hw/usb/hcd-xhci.c | 14 +++++--------- - 1 file changed, 5 insertions(+), 9 deletions(-) - -diff --git a/hw/usb/hcd-xhci.c b/hw/usb/hcd-xhci.c -index 3bac99a..e39fe04 100644 ---- a/hw/usb/hcd-xhci.c -+++ b/hw/usb/hcd-xhci.c -@@ -662,8 +662,11 @@ static void xhci_msix_update(XHCIState *xhci) - - static void xhci_intr_raise(XHCIState *xhci) - { -- if (!(xhci->iman & IMAN_IP) || -- !(xhci->iman & IMAN_IE)) { -+ xhci->erdp_low |= ERDP_EHB; -+ xhci->iman |= IMAN_IP; -+ xhci->usbsts |= USBSTS_EINT; -+ -+ if (!(xhci->iman & IMAN_IE)) { - return; - } - -@@ -784,9 +787,6 @@ static void xhci_events_update(XHCIState *xhci) - } - - if (do_irq) { -- xhci->erdp_low |= ERDP_EHB; -- xhci->iman |= IMAN_IP; -- xhci->usbsts |= USBSTS_EINT; - xhci_intr_raise(xhci); - } - -@@ -847,10 +847,6 @@ static void xhci_event(XHCIState *xhci, XHCIEvent *event) - xhci_write_event(xhci, event); - } - -- xhci->erdp_low |= ERDP_EHB; -- xhci->iman |= IMAN_IP; -- xhci->usbsts |= USBSTS_EINT; -- - xhci_intr_raise(xhci); - } - --- -1.7.12 - diff --git a/0349-xhci-add-XHCIInterrupter.patch b/0349-xhci-add-XHCIInterrupter.patch deleted file mode 100644 index 3ad7de3..0000000 --- a/0349-xhci-add-XHCIInterrupter.patch +++ /dev/null @@ -1,642 +0,0 @@ -From 84ce3d5155c984ad131ba7153b9c3646c88b8636 Mon Sep 17 00:00:00 2001 -From: Gerd Hoffmann -Date: Thu, 30 Aug 2012 15:49:03 +0200 -Subject: [PATCH 349/366] xhci: add XHCIInterrupter - -Move all state belonging to the (single) interrupter into a separate -struct. First step in adding support for multiple interrupters. - -Signed-off-by: Gerd Hoffmann ---- - hw/usb/hcd-xhci.c | 307 ++++++++++++++++++++++++++++-------------------------- - trace-events | 2 +- - 2 files changed, 161 insertions(+), 148 deletions(-) - -diff --git a/hw/usb/hcd-xhci.c b/hw/usb/hcd-xhci.c -index e39fe04..ddc3825 100644 ---- a/hw/usb/hcd-xhci.c -+++ b/hw/usb/hcd-xhci.c -@@ -378,6 +378,27 @@ typedef struct XHCIEvent { - uint8_t epid; - } XHCIEvent; - -+typedef struct XHCIInterrupter { -+ uint32_t iman; -+ uint32_t imod; -+ uint32_t erstsz; -+ uint32_t erstba_low; -+ uint32_t erstba_high; -+ uint32_t erdp_low; -+ uint32_t erdp_high; -+ -+ bool msix_used, er_pcs, er_full; -+ -+ dma_addr_t er_start; -+ uint32_t er_size; -+ unsigned int er_ep_idx; -+ -+ XHCIEvent ev_buffer[EV_QUEUE]; -+ unsigned int ev_buffer_put; -+ unsigned int ev_buffer_get; -+ -+} XHCIInterrupter; -+ - struct XHCIState { - PCIDevice pci_dev; - USBBus bus; -@@ -407,27 +428,9 @@ struct XHCIState { - uint32_t numports; - - /* Runtime Registers */ -- uint32_t iman; -- uint32_t imod; -- uint32_t erstsz; -- uint32_t erstba_low; -- uint32_t erstba_high; -- uint32_t erdp_low; -- uint32_t erdp_high; -- bool msix_used; -- - int64_t mfindex_start; - QEMUTimer *mfwrap_timer; -- -- dma_addr_t er_start; -- uint32_t er_size; -- bool er_pcs; -- unsigned int er_ep_idx; -- bool er_full; -- -- XHCIEvent ev_buffer[EV_QUEUE]; -- unsigned int ev_buffer_put; -- unsigned int ev_buffer_get; -+ XHCIInterrupter intr[MAXINTRS]; - - XHCIRing cmd_ring; - }; -@@ -446,8 +449,8 @@ enum xhci_flags { - - static void xhci_kick_ep(XHCIState *xhci, unsigned int slotid, - unsigned int epid); --static void xhci_event(XHCIState *xhci, XHCIEvent *event); --static void xhci_write_event(XHCIState *xhci, XHCIEvent *event); -+static void xhci_event(XHCIState *xhci, XHCIEvent *event, int v); -+static void xhci_write_event(XHCIState *xhci, XHCIEvent *event, int v); - - static const char *TRBType_names[] = { - [TRB_RESERVED] = "TRB_RESERVED", -@@ -573,7 +576,7 @@ static void xhci_mfwrap_timer(void *opaque) - XHCIState *xhci = opaque; - XHCIEvent wrap = { ER_MFINDEX_WRAP, CC_SUCCESS }; - -- xhci_event(xhci, &wrap); -+ xhci_event(xhci, &wrap, 0); - xhci_mfwrap_update(xhci); - } - -@@ -626,8 +629,8 @@ static void xhci_intx_update(XHCIState *xhci) - return; - } - -- if (xhci->iman & IMAN_IP && -- xhci->iman & IMAN_IE && -+ if (xhci->intr[0].iman & IMAN_IP && -+ xhci->intr[0].iman & IMAN_IE && - xhci->usbcmd & USBCMD_INTE) { - level = 1; - } -@@ -636,7 +639,7 @@ static void xhci_intx_update(XHCIState *xhci) - qemu_set_irq(xhci->irq, level); - } - --static void xhci_msix_update(XHCIState *xhci) -+static void xhci_msix_update(XHCIState *xhci, int v) - { - bool enabled; - -@@ -644,29 +647,29 @@ static void xhci_msix_update(XHCIState *xhci) - return; - } - -- enabled = xhci->iman & IMAN_IE; -- if (enabled == xhci->msix_used) { -+ enabled = xhci->intr[v].iman & IMAN_IE; -+ if (enabled == xhci->intr[v].msix_used) { - return; - } - - if (enabled) { -- trace_usb_xhci_irq_msix_use(0); -- msix_vector_use(&xhci->pci_dev, 0); -- xhci->msix_used = true; -+ trace_usb_xhci_irq_msix_use(v); -+ msix_vector_use(&xhci->pci_dev, v); -+ xhci->intr[v].msix_used = true; - } else { -- trace_usb_xhci_irq_msix_unuse(0); -- msix_vector_unuse(&xhci->pci_dev, 0); -- xhci->msix_used = false; -+ trace_usb_xhci_irq_msix_unuse(v); -+ msix_vector_unuse(&xhci->pci_dev, v); -+ xhci->intr[v].msix_used = false; - } - } - --static void xhci_intr_raise(XHCIState *xhci) -+static void xhci_intr_raise(XHCIState *xhci, int v) - { -- xhci->erdp_low |= ERDP_EHB; -- xhci->iman |= IMAN_IP; -+ xhci->intr[v].erdp_low |= ERDP_EHB; -+ xhci->intr[v].iman |= IMAN_IP; - xhci->usbsts |= USBSTS_EINT; - -- if (!(xhci->iman & IMAN_IE)) { -+ if (!(xhci->intr[v].iman & IMAN_IE)) { - return; - } - -@@ -675,24 +678,26 @@ static void xhci_intr_raise(XHCIState *xhci) - } - - if (msix_enabled(&xhci->pci_dev)) { -- trace_usb_xhci_irq_msix(0); -- msix_notify(&xhci->pci_dev, 0); -+ trace_usb_xhci_irq_msix(v); -+ msix_notify(&xhci->pci_dev, v); - return; - } - - if (msi_enabled(&xhci->pci_dev)) { -- trace_usb_xhci_irq_msi(0); -- msi_notify(&xhci->pci_dev, 0); -+ trace_usb_xhci_irq_msi(v); -+ msi_notify(&xhci->pci_dev, v); - return; - } - -- trace_usb_xhci_irq_intx(1); -- qemu_set_irq(xhci->irq, 1); -+ if (v == 0) { -+ trace_usb_xhci_irq_intx(1); -+ qemu_set_irq(xhci->irq, 1); -+ } - } - - static inline int xhci_running(XHCIState *xhci) - { -- return !(xhci->usbsts & USBSTS_HCH) && !xhci->er_full; -+ return !(xhci->usbsts & USBSTS_HCH) && !xhci->intr[0].er_full; - } - - static void xhci_die(XHCIState *xhci) -@@ -701,8 +706,9 @@ static void xhci_die(XHCIState *xhci) - fprintf(stderr, "xhci: asserted controller error\n"); - } - --static void xhci_write_event(XHCIState *xhci, XHCIEvent *event) -+static void xhci_write_event(XHCIState *xhci, XHCIEvent *event, int v) - { -+ XHCIInterrupter *intr = &xhci->intr[v]; - XHCITRB ev_trb; - dma_addr_t addr; - -@@ -710,27 +716,28 @@ static void xhci_write_event(XHCIState *xhci, XHCIEvent *event) - ev_trb.status = cpu_to_le32(event->length | (event->ccode << 24)); - ev_trb.control = (event->slotid << 24) | (event->epid << 16) | - event->flags | (event->type << TRB_TYPE_SHIFT); -- if (xhci->er_pcs) { -+ if (intr->er_pcs) { - ev_trb.control |= TRB_C; - } - ev_trb.control = cpu_to_le32(ev_trb.control); - -- trace_usb_xhci_queue_event(xhci->er_ep_idx, trb_name(&ev_trb), -+ trace_usb_xhci_queue_event(v, intr->er_ep_idx, trb_name(&ev_trb), - event_name(event), ev_trb.parameter, - ev_trb.status, ev_trb.control); - -- addr = xhci->er_start + TRB_SIZE*xhci->er_ep_idx; -+ addr = intr->er_start + TRB_SIZE*intr->er_ep_idx; - pci_dma_write(&xhci->pci_dev, addr, &ev_trb, TRB_SIZE); - -- xhci->er_ep_idx++; -- if (xhci->er_ep_idx >= xhci->er_size) { -- xhci->er_ep_idx = 0; -- xhci->er_pcs = !xhci->er_pcs; -+ intr->er_ep_idx++; -+ if (intr->er_ep_idx >= intr->er_size) { -+ intr->er_ep_idx = 0; -+ intr->er_pcs = !intr->er_pcs; - } - } - --static void xhci_events_update(XHCIState *xhci) -+static void xhci_events_update(XHCIState *xhci, int v) - { -+ XHCIInterrupter *intr = &xhci->intr[v]; - dma_addr_t erdp; - unsigned int dp_idx; - bool do_irq = 0; -@@ -739,115 +746,116 @@ static void xhci_events_update(XHCIState *xhci) - return; - } - -- erdp = xhci_addr64(xhci->erdp_low, xhci->erdp_high); -- if (erdp < xhci->er_start || -- erdp >= (xhci->er_start + TRB_SIZE*xhci->er_size)) { -+ erdp = xhci_addr64(intr->erdp_low, intr->erdp_high); -+ if (erdp < intr->er_start || -+ erdp >= (intr->er_start + TRB_SIZE*intr->er_size)) { - fprintf(stderr, "xhci: ERDP out of bounds: "DMA_ADDR_FMT"\n", erdp); -- fprintf(stderr, "xhci: ER at "DMA_ADDR_FMT" len %d\n", -- xhci->er_start, xhci->er_size); -+ fprintf(stderr, "xhci: ER[%d] at "DMA_ADDR_FMT" len %d\n", -+ v, intr->er_start, intr->er_size); - xhci_die(xhci); - return; - } -- dp_idx = (erdp - xhci->er_start) / TRB_SIZE; -- assert(dp_idx < xhci->er_size); -+ dp_idx = (erdp - intr->er_start) / TRB_SIZE; -+ assert(dp_idx < intr->er_size); - - /* NEC didn't read section 4.9.4 of the spec (v1.0 p139 top Note) and thus - * deadlocks when the ER is full. Hack it by holding off events until - * the driver decides to free at least half of the ring */ -- if (xhci->er_full) { -- int er_free = dp_idx - xhci->er_ep_idx; -+ if (intr->er_full) { -+ int er_free = dp_idx - intr->er_ep_idx; - if (er_free <= 0) { -- er_free += xhci->er_size; -+ er_free += intr->er_size; - } -- if (er_free < (xhci->er_size/2)) { -+ if (er_free < (intr->er_size/2)) { - DPRINTF("xhci_events_update(): event ring still " - "more than half full (hack)\n"); - return; - } - } - -- while (xhci->ev_buffer_put != xhci->ev_buffer_get) { -- assert(xhci->er_full); -- if (((xhci->er_ep_idx+1) % xhci->er_size) == dp_idx) { -+ while (intr->ev_buffer_put != intr->ev_buffer_get) { -+ assert(intr->er_full); -+ if (((intr->er_ep_idx+1) % intr->er_size) == dp_idx) { - DPRINTF("xhci_events_update(): event ring full again\n"); - #ifndef ER_FULL_HACK - XHCIEvent full = {ER_HOST_CONTROLLER, CC_EVENT_RING_FULL_ERROR}; -- xhci_write_event(xhci, &full); -+ xhci_write_event(xhci, &full, v); - #endif - do_irq = 1; - break; - } -- XHCIEvent *event = &xhci->ev_buffer[xhci->ev_buffer_get]; -- xhci_write_event(xhci, event); -- xhci->ev_buffer_get++; -+ XHCIEvent *event = &intr->ev_buffer[intr->ev_buffer_get]; -+ xhci_write_event(xhci, event, v); -+ intr->ev_buffer_get++; - do_irq = 1; -- if (xhci->ev_buffer_get == EV_QUEUE) { -- xhci->ev_buffer_get = 0; -+ if (intr->ev_buffer_get == EV_QUEUE) { -+ intr->ev_buffer_get = 0; - } - } - - if (do_irq) { -- xhci_intr_raise(xhci); -+ xhci_intr_raise(xhci, v); - } - -- if (xhci->er_full && xhci->ev_buffer_put == xhci->ev_buffer_get) { -+ if (intr->er_full && intr->ev_buffer_put == intr->ev_buffer_get) { - DPRINTF("xhci_events_update(): event ring no longer full\n"); -- xhci->er_full = 0; -+ intr->er_full = 0; - } - return; - } - --static void xhci_event(XHCIState *xhci, XHCIEvent *event) -+static void xhci_event(XHCIState *xhci, XHCIEvent *event, int v) - { -+ XHCIInterrupter *intr = &xhci->intr[v]; - dma_addr_t erdp; - unsigned int dp_idx; - -- if (xhci->er_full) { -+ if (intr->er_full) { - DPRINTF("xhci_event(): ER full, queueing\n"); -- if (((xhci->ev_buffer_put+1) % EV_QUEUE) == xhci->ev_buffer_get) { -+ if (((intr->ev_buffer_put+1) % EV_QUEUE) == intr->ev_buffer_get) { - fprintf(stderr, "xhci: event queue full, dropping event!\n"); - return; - } -- xhci->ev_buffer[xhci->ev_buffer_put++] = *event; -- if (xhci->ev_buffer_put == EV_QUEUE) { -- xhci->ev_buffer_put = 0; -+ intr->ev_buffer[intr->ev_buffer_put++] = *event; -+ if (intr->ev_buffer_put == EV_QUEUE) { -+ intr->ev_buffer_put = 0; - } - return; - } - -- erdp = xhci_addr64(xhci->erdp_low, xhci->erdp_high); -- if (erdp < xhci->er_start || -- erdp >= (xhci->er_start + TRB_SIZE*xhci->er_size)) { -+ erdp = xhci_addr64(intr->erdp_low, intr->erdp_high); -+ if (erdp < intr->er_start || -+ erdp >= (intr->er_start + TRB_SIZE*intr->er_size)) { - fprintf(stderr, "xhci: ERDP out of bounds: "DMA_ADDR_FMT"\n", erdp); -- fprintf(stderr, "xhci: ER at "DMA_ADDR_FMT" len %d\n", -- xhci->er_start, xhci->er_size); -+ fprintf(stderr, "xhci: ER[%d] at "DMA_ADDR_FMT" len %d\n", -+ v, intr->er_start, intr->er_size); - xhci_die(xhci); - return; - } - -- dp_idx = (erdp - xhci->er_start) / TRB_SIZE; -- assert(dp_idx < xhci->er_size); -+ dp_idx = (erdp - intr->er_start) / TRB_SIZE; -+ assert(dp_idx < intr->er_size); - -- if ((xhci->er_ep_idx+1) % xhci->er_size == dp_idx) { -+ if ((intr->er_ep_idx+1) % intr->er_size == dp_idx) { - DPRINTF("xhci_event(): ER full, queueing\n"); - #ifndef ER_FULL_HACK - XHCIEvent full = {ER_HOST_CONTROLLER, CC_EVENT_RING_FULL_ERROR}; - xhci_write_event(xhci, &full); - #endif -- xhci->er_full = 1; -- if (((xhci->ev_buffer_put+1) % EV_QUEUE) == xhci->ev_buffer_get) { -+ intr->er_full = 1; -+ if (((intr->ev_buffer_put+1) % EV_QUEUE) == intr->ev_buffer_get) { - fprintf(stderr, "xhci: event queue full, dropping event!\n"); - return; - } -- xhci->ev_buffer[xhci->ev_buffer_put++] = *event; -- if (xhci->ev_buffer_put == EV_QUEUE) { -- xhci->ev_buffer_put = 0; -+ intr->ev_buffer[intr->ev_buffer_put++] = *event; -+ if (intr->ev_buffer_put == EV_QUEUE) { -+ intr->ev_buffer_put = 0; - } - } else { -- xhci_write_event(xhci, event); -+ xhci_write_event(xhci, event, v); - } - -- xhci_intr_raise(xhci); -+ xhci_intr_raise(xhci, v); - } - - static void xhci_ring_init(XHCIState *xhci, XHCIRing *ring, -@@ -939,17 +947,18 @@ static int xhci_ring_chain_length(XHCIState *xhci, const XHCIRing *ring) - } - } - --static void xhci_er_reset(XHCIState *xhci) -+static void xhci_er_reset(XHCIState *xhci, int v) - { -+ XHCIInterrupter *intr = &xhci->intr[v]; - XHCIEvRingSeg seg; - - /* cache the (sole) event ring segment location */ -- if (xhci->erstsz != 1) { -- fprintf(stderr, "xhci: invalid value for ERSTSZ: %d\n", xhci->erstsz); -+ if (intr->erstsz != 1) { -+ fprintf(stderr, "xhci: invalid value for ERSTSZ: %d\n", intr->erstsz); - xhci_die(xhci); - return; - } -- dma_addr_t erstba = xhci_addr64(xhci->erstba_low, xhci->erstba_high); -+ dma_addr_t erstba = xhci_addr64(intr->erstba_low, intr->erstba_high); - pci_dma_read(&xhci->pci_dev, erstba, &seg, sizeof(seg)); - le32_to_cpus(&seg.addr_low); - le32_to_cpus(&seg.addr_high); -@@ -959,15 +968,15 @@ static void xhci_er_reset(XHCIState *xhci) - xhci_die(xhci); - return; - } -- xhci->er_start = xhci_addr64(seg.addr_low, seg.addr_high); -- xhci->er_size = seg.size; -+ intr->er_start = xhci_addr64(seg.addr_low, seg.addr_high); -+ intr->er_size = seg.size; - -- xhci->er_ep_idx = 0; -- xhci->er_pcs = 1; -- xhci->er_full = 0; -+ intr->er_ep_idx = 0; -+ intr->er_pcs = 1; -+ intr->er_full = 0; - -- DPRINTF("xhci: event ring:" DMA_ADDR_FMT " [%d]\n", -- xhci->er_start, xhci->er_size); -+ DPRINTF("xhci: event ring[%d]:" DMA_ADDR_FMT " [%d]\n", -+ v, intr->er_start, intr->er_size); - } - - static void xhci_run(XHCIState *xhci) -@@ -1368,7 +1377,7 @@ static void xhci_xfer_report(XHCITransfer *xfer) - DPRINTF("xhci_xfer_data: EDTLA=%d\n", event.length); - edtla = 0; - } -- xhci_event(xhci, &event); -+ xhci_event(xhci, &event, 0 /* FIXME */); - reported = 1; - if (xfer->status != CC_SUCCESS) { - return; -@@ -2246,7 +2255,7 @@ static void xhci_process_commands(XHCIState *xhci) - break; - } - event.slotid = slotid; -- xhci_event(xhci, &event); -+ xhci_event(xhci, &event, 0 /* FIXME */); - } - } - -@@ -2276,7 +2285,7 @@ static void xhci_update_port(XHCIState *xhci, XHCIPort *port, int is_detach) - port->portsc |= PORTSC_CSC; - XHCIEvent ev = { ER_PORT_STATUS_CHANGE, CC_SUCCESS, - port->portnr << 24}; -- xhci_event(xhci, &ev); -+ xhci_event(xhci, &ev, 0 /* FIXME */); - DPRINTF("xhci: port change event for port %d\n", port->portnr); - } - } -@@ -2309,20 +2318,22 @@ static void xhci_reset(DeviceState *dev) - xhci_update_port(xhci, xhci->ports + i, 0); - } - -- xhci->iman = 0; -- xhci->imod = 0; -- xhci->erstsz = 0; -- xhci->erstba_low = 0; -- xhci->erstba_high = 0; -- xhci->erdp_low = 0; -- xhci->erdp_high = 0; -- xhci->msix_used = 0; -+ for (i = 0; i < MAXINTRS; i++) { -+ xhci->intr[i].iman = 0; -+ xhci->intr[i].imod = 0; -+ xhci->intr[i].erstsz = 0; -+ xhci->intr[i].erstba_low = 0; -+ xhci->intr[i].erstba_high = 0; -+ xhci->intr[i].erdp_low = 0; -+ xhci->intr[i].erdp_high = 0; -+ xhci->intr[i].msix_used = 0; - -- xhci->er_ep_idx = 0; -- xhci->er_pcs = 1; -- xhci->er_full = 0; -- xhci->ev_buffer_put = 0; -- xhci->ev_buffer_get = 0; -+ xhci->intr[i].er_ep_idx = 0; -+ xhci->intr[i].er_pcs = 1; -+ xhci->intr[i].er_full = 0; -+ xhci->intr[i].ev_buffer_put = 0; -+ xhci->intr[i].ev_buffer_get = 0; -+ } - - xhci->mfindex_start = qemu_get_clock_ns(vm_clock); - xhci_mfwrap_update(xhci); -@@ -2553,7 +2564,7 @@ static void xhci_oper_write(XHCIState *xhci, uint32_t reg, uint32_t val) - if (xhci->crcr_low & (CRCR_CA|CRCR_CS) && (xhci->crcr_low & CRCR_CRR)) { - XHCIEvent event = {ER_COMMAND_COMPLETE, CC_COMMAND_RING_STOPPED}; - xhci->crcr_low &= ~CRCR_CRR; -- xhci_event(xhci, &event); -+ xhci_event(xhci, &event, 0 /* FIXME */); - DPRINTF("xhci: command ring stopped (CRCR=%08x)\n", xhci->crcr_low); - } else { - dma_addr_t base = xhci_addr64(xhci->crcr_low & ~0x3f, val); -@@ -2577,6 +2588,7 @@ static void xhci_oper_write(XHCIState *xhci, uint32_t reg, uint32_t val) - - static uint32_t xhci_runtime_read(XHCIState *xhci, uint32_t reg) - { -+ XHCIInterrupter *intr = &xhci->intr[0]; - uint32_t ret; - - switch (reg) { -@@ -2584,25 +2596,25 @@ static uint32_t xhci_runtime_read(XHCIState *xhci, uint32_t reg) - ret = xhci_mfindex_get(xhci) & 0x3fff; - break; - case 0x20: /* IMAN */ -- ret = xhci->iman; -+ ret = intr->iman; - break; - case 0x24: /* IMOD */ -- ret = xhci->imod; -+ ret = intr->imod; - break; - case 0x28: /* ERSTSZ */ -- ret = xhci->erstsz; -+ ret = intr->erstsz; - break; - case 0x30: /* ERSTBA low */ -- ret = xhci->erstba_low; -+ ret = intr->erstba_low; - break; - case 0x34: /* ERSTBA high */ -- ret = xhci->erstba_high; -+ ret = intr->erstba_high; - break; - case 0x38: /* ERDP low */ -- ret = xhci->erdp_low; -+ ret = intr->erdp_low; - break; - case 0x3c: /* ERDP high */ -- ret = xhci->erdp_high; -+ ret = intr->erdp_high; - break; - default: - fprintf(stderr, "xhci_runtime_read: reg 0x%x unimplemented\n", reg); -@@ -2615,42 +2627,43 @@ static uint32_t xhci_runtime_read(XHCIState *xhci, uint32_t reg) - - static void xhci_runtime_write(XHCIState *xhci, uint32_t reg, uint32_t val) - { -+ XHCIInterrupter *intr = &xhci->intr[0]; - trace_usb_xhci_runtime_write(reg, val); - - switch (reg) { - case 0x20: /* IMAN */ - if (val & IMAN_IP) { -- xhci->iman &= ~IMAN_IP; -+ intr->iman &= ~IMAN_IP; - } -- xhci->iman &= ~IMAN_IE; -- xhci->iman |= val & IMAN_IE; -+ intr->iman &= ~IMAN_IE; -+ intr->iman |= val & IMAN_IE; - xhci_intx_update(xhci); -- xhci_msix_update(xhci); -+ xhci_msix_update(xhci, 0); - break; - case 0x24: /* IMOD */ -- xhci->imod = val; -+ intr->imod = val; - break; - case 0x28: /* ERSTSZ */ -- xhci->erstsz = val & 0xffff; -+ intr->erstsz = val & 0xffff; - break; - case 0x30: /* ERSTBA low */ - /* XXX NEC driver bug: it doesn't align this to 64 bytes -- xhci->erstba_low = val & 0xffffffc0; */ -- xhci->erstba_low = val & 0xfffffff0; -+ intr->erstba_low = val & 0xffffffc0; */ -+ intr->erstba_low = val & 0xfffffff0; - break; - case 0x34: /* ERSTBA high */ -- xhci->erstba_high = val; -- xhci_er_reset(xhci); -+ intr->erstba_high = val; -+ xhci_er_reset(xhci, 0); - break; - case 0x38: /* ERDP low */ - if (val & ERDP_EHB) { -- xhci->erdp_low &= ~ERDP_EHB; -+ intr->erdp_low &= ~ERDP_EHB; - } -- xhci->erdp_low = (val & ~ERDP_EHB) | (xhci->erdp_low & ERDP_EHB); -+ intr->erdp_low = (val & ~ERDP_EHB) | (intr->erdp_low & ERDP_EHB); - break; - case 0x3c: /* ERDP high */ -- xhci->erdp_high = val; -- xhci_events_update(xhci); -+ intr->erdp_high = val; -+ xhci_events_update(xhci, 0); - break; - default: - fprintf(stderr, "xhci_oper_write: reg 0x%x unimplemented\n", reg); -@@ -2780,7 +2793,7 @@ static void xhci_wakeup(USBPort *usbport) - return; - } - port->portsc |= PORTSC_PLC; -- xhci_event(xhci, &ev); -+ xhci_event(xhci, &ev, 0 /* FIXME */); - } - - static void xhci_complete(USBPort *port, USBPacket *packet) -diff --git a/trace-events b/trace-events -index 8589ca4..b25ae1c 100644 ---- a/trace-events -+++ b/trace-events -@@ -316,7 +316,7 @@ usb_xhci_irq_msi(uint32_t nr) "nr %d" - usb_xhci_irq_msix(uint32_t nr) "nr %d" - usb_xhci_irq_msix_use(uint32_t nr) "nr %d" - usb_xhci_irq_msix_unuse(uint32_t nr) "nr %d" --usb_xhci_queue_event(uint32_t idx, const char *trb, const char *evt, uint64_t param, uint32_t status, uint32_t control) "idx %d, %s, %s, p %016" PRIx64 ", s %08x, c 0x%08x" -+usb_xhci_queue_event(uint32_t vector, uint32_t idx, const char *trb, const char *evt, uint64_t param, uint32_t status, uint32_t control) "v %d, idx %d, %s, %s, p %016" PRIx64 ", s %08x, c 0x%08x" - usb_xhci_fetch_trb(uint64_t addr, const char *name, uint64_t param, uint32_t status, uint32_t control) "addr %016" PRIx64 ", %s, p %016" PRIx64 ", s %08x, c 0x%08x" - usb_xhci_slot_enable(uint32_t slotid) "slotid %d" - usb_xhci_slot_disable(uint32_t slotid) "slotid %d" --- -1.7.12 - diff --git a/0350-xhci-prepare-xhci_runtime_-read-write-for-multiple-i.patch b/0350-xhci-prepare-xhci_runtime_-read-write-for-multiple-i.patch deleted file mode 100644 index 305b321..0000000 --- a/0350-xhci-prepare-xhci_runtime_-read-write-for-multiple-i.patch +++ /dev/null @@ -1,159 +0,0 @@ -From 8bbd489bb885f5799ebbc108022eee3b2d5a1682 Mon Sep 17 00:00:00 2001 -From: Gerd Hoffmann -Date: Thu, 30 Aug 2012 17:15:12 +0200 -Subject: [PATCH 350/366] xhci: prepare xhci_runtime_{read,write} for multiple - interrupters - -Prepare xhci runtime register access function for multiple interrupters. - -Signed-off-by: Gerd Hoffmann ---- - hw/usb/hcd-xhci.c | 100 +++++++++++++++++++++++++++++++----------------------- - 1 file changed, 57 insertions(+), 43 deletions(-) - -diff --git a/hw/usb/hcd-xhci.c b/hw/usb/hcd-xhci.c -index ddc3825..68a19ab 100644 ---- a/hw/usb/hcd-xhci.c -+++ b/hw/usb/hcd-xhci.c -@@ -2588,37 +2588,43 @@ static void xhci_oper_write(XHCIState *xhci, uint32_t reg, uint32_t val) - - static uint32_t xhci_runtime_read(XHCIState *xhci, uint32_t reg) - { -- XHCIInterrupter *intr = &xhci->intr[0]; -- uint32_t ret; -+ uint32_t ret = 0; - -- switch (reg) { -- case 0x00: /* MFINDEX */ -- ret = xhci_mfindex_get(xhci) & 0x3fff; -- break; -- case 0x20: /* IMAN */ -- ret = intr->iman; -- break; -- case 0x24: /* IMOD */ -- ret = intr->imod; -- break; -- case 0x28: /* ERSTSZ */ -- ret = intr->erstsz; -- break; -- case 0x30: /* ERSTBA low */ -- ret = intr->erstba_low; -- break; -- case 0x34: /* ERSTBA high */ -- ret = intr->erstba_high; -- break; -- case 0x38: /* ERDP low */ -- ret = intr->erdp_low; -- break; -- case 0x3c: /* ERDP high */ -- ret = intr->erdp_high; -- break; -- default: -- fprintf(stderr, "xhci_runtime_read: reg 0x%x unimplemented\n", reg); -- ret = 0; -+ if (reg < 0x20) { -+ switch (reg) { -+ case 0x00: /* MFINDEX */ -+ ret = xhci_mfindex_get(xhci) & 0x3fff; -+ break; -+ default: -+ fprintf(stderr, "xhci_runtime_read: reg 0x%x unimplemented\n", reg); -+ break; -+ } -+ } else { -+ int v = (reg - 0x20) / 0x20; -+ XHCIInterrupter *intr = &xhci->intr[v]; -+ switch (reg & 0x1f) { -+ case 0x00: /* IMAN */ -+ ret = intr->iman; -+ break; -+ case 0x04: /* IMOD */ -+ ret = intr->imod; -+ break; -+ case 0x08: /* ERSTSZ */ -+ ret = intr->erstsz; -+ break; -+ case 0x10: /* ERSTBA low */ -+ ret = intr->erstba_low; -+ break; -+ case 0x14: /* ERSTBA high */ -+ ret = intr->erstba_high; -+ break; -+ case 0x18: /* ERDP low */ -+ ret = intr->erdp_low; -+ break; -+ case 0x1c: /* ERDP high */ -+ ret = intr->erdp_high; -+ break; -+ } - } - - trace_usb_xhci_runtime_read(reg, ret); -@@ -2627,43 +2633,51 @@ static uint32_t xhci_runtime_read(XHCIState *xhci, uint32_t reg) - - static void xhci_runtime_write(XHCIState *xhci, uint32_t reg, uint32_t val) - { -- XHCIInterrupter *intr = &xhci->intr[0]; -+ int v = (reg - 0x20) / 0x20; -+ XHCIInterrupter *intr = &xhci->intr[v]; - trace_usb_xhci_runtime_write(reg, val); - -- switch (reg) { -- case 0x20: /* IMAN */ -+ if (reg < 0x20) { -+ fprintf(stderr, "xhci_oper_write: reg 0x%x unimplemented\n", reg); -+ return; -+ } -+ -+ switch (reg & 0x1f) { -+ case 0x00: /* IMAN */ - if (val & IMAN_IP) { - intr->iman &= ~IMAN_IP; - } - intr->iman &= ~IMAN_IE; - intr->iman |= val & IMAN_IE; -- xhci_intx_update(xhci); -- xhci_msix_update(xhci, 0); -+ if (v == 0) { -+ xhci_intx_update(xhci); -+ } -+ xhci_msix_update(xhci, v); - break; -- case 0x24: /* IMOD */ -+ case 0x04: /* IMOD */ - intr->imod = val; - break; -- case 0x28: /* ERSTSZ */ -+ case 0x08: /* ERSTSZ */ - intr->erstsz = val & 0xffff; - break; -- case 0x30: /* ERSTBA low */ -+ case 0x10: /* ERSTBA low */ - /* XXX NEC driver bug: it doesn't align this to 64 bytes - intr->erstba_low = val & 0xffffffc0; */ - intr->erstba_low = val & 0xfffffff0; - break; -- case 0x34: /* ERSTBA high */ -+ case 0x14: /* ERSTBA high */ - intr->erstba_high = val; -- xhci_er_reset(xhci, 0); -+ xhci_er_reset(xhci, v); - break; -- case 0x38: /* ERDP low */ -+ case 0x18: /* ERDP low */ - if (val & ERDP_EHB) { - intr->erdp_low &= ~ERDP_EHB; - } - intr->erdp_low = (val & ~ERDP_EHB) | (intr->erdp_low & ERDP_EHB); - break; -- case 0x3c: /* ERDP high */ -+ case 0x1c: /* ERDP high */ - intr->erdp_high = val; -- xhci_events_update(xhci, 0); -+ xhci_events_update(xhci, v); - break; - default: - fprintf(stderr, "xhci_oper_write: reg 0x%x unimplemented\n", reg); --- -1.7.12 - diff --git a/0351-xhci-pick-target-interrupter.patch b/0351-xhci-pick-target-interrupter.patch deleted file mode 100644 index bf95359..0000000 --- a/0351-xhci-pick-target-interrupter.patch +++ /dev/null @@ -1,93 +0,0 @@ -From 11ba203517cc28be513ac31c12762c4519e98ee5 Mon Sep 17 00:00:00 2001 -From: Gerd Hoffmann -Date: Fri, 31 Aug 2012 15:30:51 +0200 -Subject: [PATCH 351/366] xhci: pick target interrupter - -Pick the correct interrupter when queuing an event. - -Signed-off-by: Gerd Hoffmann ---- - hw/usb/hcd-xhci.c | 22 ++++++++++++++++------ - 1 file changed, 16 insertions(+), 6 deletions(-) - -diff --git a/hw/usb/hcd-xhci.c b/hw/usb/hcd-xhci.c -index 68a19ab..d6ab0c6 100644 ---- a/hw/usb/hcd-xhci.c -+++ b/hw/usb/hcd-xhci.c -@@ -264,6 +264,10 @@ typedef enum TRBCCode { - - #define TRB_LK_TC (1<<1) - -+#define TRB_INTR_SHIFT 22 -+#define TRB_INTR_MASK 0x3ff -+#define TRB_INTR(t) (((t).status >> TRB_INTR_SHIFT) & TRB_INTR_MASK) -+ - #define EP_TYPE_MASK 0x7 - #define EP_TYPE_SHIFT 3 - -@@ -806,10 +810,16 @@ static void xhci_events_update(XHCIState *xhci, int v) - - static void xhci_event(XHCIState *xhci, XHCIEvent *event, int v) - { -- XHCIInterrupter *intr = &xhci->intr[v]; -+ XHCIInterrupter *intr; - dma_addr_t erdp; - unsigned int dp_idx; - -+ if (v >= MAXINTRS) { -+ DPRINTF("intr nr out of range (%d >= %d)\n", v, MAXINTRS); -+ return; -+ } -+ intr = &xhci->intr[v]; -+ - if (intr->er_full) { - DPRINTF("xhci_event(): ER full, queueing\n"); - if (((intr->ev_buffer_put+1) % EV_QUEUE) == intr->ev_buffer_get) { -@@ -1377,7 +1387,7 @@ static void xhci_xfer_report(XHCITransfer *xfer) - DPRINTF("xhci_xfer_data: EDTLA=%d\n", event.length); - edtla = 0; - } -- xhci_event(xhci, &event, 0 /* FIXME */); -+ xhci_event(xhci, &event, TRB_INTR(*trb)); - reported = 1; - if (xfer->status != CC_SUCCESS) { - return; -@@ -2255,7 +2265,7 @@ static void xhci_process_commands(XHCIState *xhci) - break; - } - event.slotid = slotid; -- xhci_event(xhci, &event, 0 /* FIXME */); -+ xhci_event(xhci, &event, 0); - } - } - -@@ -2285,7 +2295,7 @@ static void xhci_update_port(XHCIState *xhci, XHCIPort *port, int is_detach) - port->portsc |= PORTSC_CSC; - XHCIEvent ev = { ER_PORT_STATUS_CHANGE, CC_SUCCESS, - port->portnr << 24}; -- xhci_event(xhci, &ev, 0 /* FIXME */); -+ xhci_event(xhci, &ev, 0); - DPRINTF("xhci: port change event for port %d\n", port->portnr); - } - } -@@ -2564,7 +2574,7 @@ static void xhci_oper_write(XHCIState *xhci, uint32_t reg, uint32_t val) - if (xhci->crcr_low & (CRCR_CA|CRCR_CS) && (xhci->crcr_low & CRCR_CRR)) { - XHCIEvent event = {ER_COMMAND_COMPLETE, CC_COMMAND_RING_STOPPED}; - xhci->crcr_low &= ~CRCR_CRR; -- xhci_event(xhci, &event, 0 /* FIXME */); -+ xhci_event(xhci, &event, 0); - DPRINTF("xhci: command ring stopped (CRCR=%08x)\n", xhci->crcr_low); - } else { - dma_addr_t base = xhci_addr64(xhci->crcr_low & ~0x3f, val); -@@ -2807,7 +2817,7 @@ static void xhci_wakeup(USBPort *usbport) - return; - } - port->portsc |= PORTSC_PLC; -- xhci_event(xhci, &ev, 0 /* FIXME */); -+ xhci_event(xhci, &ev, 0); - } - - static void xhci_complete(USBPort *port, USBPacket *packet) --- -1.7.12 - diff --git a/0352-xhci-support-multiple-interrupters.patch b/0352-xhci-support-multiple-interrupters.patch deleted file mode 100644 index 08b1d44..0000000 --- a/0352-xhci-support-multiple-interrupters.patch +++ /dev/null @@ -1,40 +0,0 @@ -From d6d045365af5cef5bc98ad48dcf4172cbe35c7c4 Mon Sep 17 00:00:00 2001 -From: Gerd Hoffmann -Date: Tue, 4 Sep 2012 12:56:55 +0200 -Subject: [PATCH 352/366] xhci: support multiple interrupters - -Everything is in place, flip the big switch now -and enable support for multiple interrupters. - -Signed-off-by: Gerd Hoffmann ---- - hw/usb/hcd-xhci.c | 6 +----- - 1 file changed, 1 insertion(+), 5 deletions(-) - -diff --git a/hw/usb/hcd-xhci.c b/hw/usb/hcd-xhci.c -index d6ab0c6..55e31ec 100644 ---- a/hw/usb/hcd-xhci.c -+++ b/hw/usb/hcd-xhci.c -@@ -42,7 +42,7 @@ - - #define MAXPORTS (MAXPORTS_2+MAXPORTS_3) - #define MAXSLOTS MAXPORTS --#define MAXINTRS 1 /* MAXPORTS */ -+#define MAXINTRS MAXPORTS - - #define TD_QUEUE 24 - -@@ -75,10 +75,6 @@ - # error Increase LEN_REGS - #endif - --#if MAXINTRS > 1 --# error TODO: only one interrupter supported --#endif -- - /* bit definitions */ - #define USBCMD_RS (1<<0) - #define USBCMD_HCRST (1<<1) --- -1.7.12 - diff --git a/0353-xhci-kill-xhci_mem_-read-write-dispatcher-functions.patch b/0353-xhci-kill-xhci_mem_-read-write-dispatcher-functions.patch deleted file mode 100644 index 04a2dbf..0000000 --- a/0353-xhci-kill-xhci_mem_-read-write-dispatcher-functions.patch +++ /dev/null @@ -1,281 +0,0 @@ -From e5295db184d2b78a6a779aac019acbf58ed3da5e Mon Sep 17 00:00:00 2001 -From: Gerd Hoffmann -Date: Tue, 4 Sep 2012 14:42:20 +0200 -Subject: [PATCH 353/366] xhci: kill xhci_mem_{read,write} dispatcher - functions - -... and register subregions instead, so we offload the dispatching -to the the memory subsystem which is designed to handle it. - -Signed-off-by: Gerd Hoffmann ---- - hw/usb/hcd-xhci.c | 140 +++++++++++++++++++++++++++++------------------------- - 1 file changed, 75 insertions(+), 65 deletions(-) - -diff --git a/hw/usb/hcd-xhci.c b/hw/usb/hcd-xhci.c -index 55e31ec..500892d 100644 ---- a/hw/usb/hcd-xhci.c -+++ b/hw/usb/hcd-xhci.c -@@ -404,6 +404,10 @@ struct XHCIState { - USBBus bus; - qemu_irq irq; - MemoryRegion mem; -+ MemoryRegion mem_cap; -+ MemoryRegion mem_oper; -+ MemoryRegion mem_runtime; -+ MemoryRegion mem_doorbell; - const char *name; - unsigned int devaddr; - -@@ -2345,8 +2349,9 @@ static void xhci_reset(DeviceState *dev) - xhci_mfwrap_update(xhci); - } - --static uint32_t xhci_cap_read(XHCIState *xhci, uint32_t reg) -+static uint64_t xhci_cap_read(void *ptr, target_phys_addr_t reg, unsigned size) - { -+ XHCIState *xhci = ptr; - uint32_t ret; - - switch (reg) { -@@ -2403,7 +2408,7 @@ static uint32_t xhci_cap_read(XHCIState *xhci, uint32_t reg) - ret = 0x00000000; /* reserved */ - break; - default: -- fprintf(stderr, "xhci_cap_read: reg %d unimplemented\n", reg); -+ fprintf(stderr, "xhci_cap_read: reg %d unimplemented\n", (int)reg); - ret = 0; - } - -@@ -2484,8 +2489,9 @@ static void xhci_port_write(XHCIState *xhci, uint32_t reg, uint32_t val) - } - } - --static uint32_t xhci_oper_read(XHCIState *xhci, uint32_t reg) -+static uint64_t xhci_oper_read(void *ptr, target_phys_addr_t reg, unsigned size) - { -+ XHCIState *xhci = ptr; - uint32_t ret; - - if (reg >= 0x400) { -@@ -2521,7 +2527,7 @@ static uint32_t xhci_oper_read(XHCIState *xhci, uint32_t reg) - ret = xhci->config; - break; - default: -- fprintf(stderr, "xhci_oper_read: reg 0x%x unimplemented\n", reg); -+ fprintf(stderr, "xhci_oper_read: reg 0x%x unimplemented\n", (int)reg); - ret = 0; - } - -@@ -2529,8 +2535,11 @@ static uint32_t xhci_oper_read(XHCIState *xhci, uint32_t reg) - return ret; - } - --static void xhci_oper_write(XHCIState *xhci, uint32_t reg, uint32_t val) -+static void xhci_oper_write(void *ptr, target_phys_addr_t reg, -+ uint64_t val, unsigned size) - { -+ XHCIState *xhci = ptr; -+ - if (reg >= 0x400) { - xhci_port_write(xhci, reg - 0x400, val); - return; -@@ -2588,12 +2597,14 @@ static void xhci_oper_write(XHCIState *xhci, uint32_t reg, uint32_t val) - xhci->config = val & 0xff; - break; - default: -- fprintf(stderr, "xhci_oper_write: reg 0x%x unimplemented\n", reg); -+ fprintf(stderr, "xhci_oper_write: reg 0x%x unimplemented\n", (int)reg); - } - } - --static uint32_t xhci_runtime_read(XHCIState *xhci, uint32_t reg) -+static uint64_t xhci_runtime_read(void *ptr, target_phys_addr_t reg, -+ unsigned size) - { -+ XHCIState *xhci = ptr; - uint32_t ret = 0; - - if (reg < 0x20) { -@@ -2602,7 +2613,8 @@ static uint32_t xhci_runtime_read(XHCIState *xhci, uint32_t reg) - ret = xhci_mfindex_get(xhci) & 0x3fff; - break; - default: -- fprintf(stderr, "xhci_runtime_read: reg 0x%x unimplemented\n", reg); -+ fprintf(stderr, "xhci_runtime_read: reg 0x%x unimplemented\n", -+ (int)reg); - break; - } - } else { -@@ -2637,14 +2649,16 @@ static uint32_t xhci_runtime_read(XHCIState *xhci, uint32_t reg) - return ret; - } - --static void xhci_runtime_write(XHCIState *xhci, uint32_t reg, uint32_t val) -+static void xhci_runtime_write(void *ptr, target_phys_addr_t reg, -+ uint64_t val, unsigned size) - { -+ XHCIState *xhci = ptr; - int v = (reg - 0x20) / 0x20; - XHCIInterrupter *intr = &xhci->intr[v]; - trace_usb_xhci_runtime_write(reg, val); - - if (reg < 0x20) { -- fprintf(stderr, "xhci_oper_write: reg 0x%x unimplemented\n", reg); -+ fprintf(stderr, "xhci_oper_write: reg 0x%x unimplemented\n", (int)reg); - return; - } - -@@ -2686,19 +2700,24 @@ static void xhci_runtime_write(XHCIState *xhci, uint32_t reg, uint32_t val) - xhci_events_update(xhci, v); - break; - default: -- fprintf(stderr, "xhci_oper_write: reg 0x%x unimplemented\n", reg); -+ fprintf(stderr, "xhci_oper_write: reg 0x%x unimplemented\n", -+ (int)reg); - } - } - --static uint32_t xhci_doorbell_read(XHCIState *xhci, uint32_t reg) -+static uint64_t xhci_doorbell_read(void *ptr, target_phys_addr_t reg, -+ unsigned size) - { - /* doorbells always read as 0 */ - trace_usb_xhci_doorbell_read(reg, 0); - return 0; - } - --static void xhci_doorbell_write(XHCIState *xhci, uint32_t reg, uint32_t val) -+static void xhci_doorbell_write(void *ptr, target_phys_addr_t reg, -+ uint64_t val, unsigned size) - { -+ XHCIState *xhci = ptr; -+ - trace_usb_xhci_doorbell_write(reg, val); - - if (!xhci_running(xhci)) { -@@ -2712,69 +2731,47 @@ static void xhci_doorbell_write(XHCIState *xhci, uint32_t reg, uint32_t val) - if (val == 0) { - xhci_process_commands(xhci); - } else { -- fprintf(stderr, "xhci: bad doorbell 0 write: 0x%x\n", val); -+ fprintf(stderr, "xhci: bad doorbell 0 write: 0x%x\n", -+ (uint32_t)val); - } - } else { - if (reg > MAXSLOTS) { -- fprintf(stderr, "xhci: bad doorbell %d\n", reg); -+ fprintf(stderr, "xhci: bad doorbell %d\n", (int)reg); - } else if (val > 31) { -- fprintf(stderr, "xhci: bad doorbell %d write: 0x%x\n", reg, val); -+ fprintf(stderr, "xhci: bad doorbell %d write: 0x%x\n", -+ (int)reg, (uint32_t)val); - } else { - xhci_kick_ep(xhci, reg, val); - } - } - } - --static uint64_t xhci_mem_read(void *ptr, target_phys_addr_t addr, -- unsigned size) --{ -- XHCIState *xhci = ptr; -- -- /* Only aligned reads are allowed on xHCI */ -- if (addr & 3) { -- fprintf(stderr, "xhci_mem_read: Mis-aligned read\n"); -- return 0; -- } -- -- if (addr < LEN_CAP) { -- return xhci_cap_read(xhci, addr); -- } else if (addr >= OFF_OPER && addr < (OFF_OPER + LEN_OPER)) { -- return xhci_oper_read(xhci, addr - OFF_OPER); -- } else if (addr >= OFF_RUNTIME && addr < (OFF_RUNTIME + LEN_RUNTIME)) { -- return xhci_runtime_read(xhci, addr - OFF_RUNTIME); -- } else if (addr >= OFF_DOORBELL && addr < (OFF_DOORBELL + LEN_DOORBELL)) { -- return xhci_doorbell_read(xhci, addr - OFF_DOORBELL); -- } else { -- fprintf(stderr, "xhci_mem_read: Bad offset %x\n", (int)addr); -- return 0; -- } --} -- --static void xhci_mem_write(void *ptr, target_phys_addr_t addr, -- uint64_t val, unsigned size) --{ -- XHCIState *xhci = ptr; -+static const MemoryRegionOps xhci_cap_ops = { -+ .read = xhci_cap_read, -+ .valid.min_access_size = 4, -+ .valid.max_access_size = 4, -+ .endianness = DEVICE_LITTLE_ENDIAN, -+}; - -- /* Only aligned writes are allowed on xHCI */ -- if (addr & 3) { -- fprintf(stderr, "xhci_mem_write: Mis-aligned write\n"); -- return; -- } -+static const MemoryRegionOps xhci_oper_ops = { -+ .read = xhci_oper_read, -+ .write = xhci_oper_write, -+ .valid.min_access_size = 4, -+ .valid.max_access_size = 4, -+ .endianness = DEVICE_LITTLE_ENDIAN, -+}; - -- if (addr >= OFF_OPER && addr < (OFF_OPER + LEN_OPER)) { -- xhci_oper_write(xhci, addr - OFF_OPER, val); -- } else if (addr >= OFF_RUNTIME && addr < (OFF_RUNTIME + LEN_RUNTIME)) { -- xhci_runtime_write(xhci, addr - OFF_RUNTIME, val); -- } else if (addr >= OFF_DOORBELL && addr < (OFF_DOORBELL + LEN_DOORBELL)) { -- xhci_doorbell_write(xhci, addr - OFF_DOORBELL, val); -- } else { -- fprintf(stderr, "xhci_mem_write: Bad offset %x\n", (int)addr); -- } --} -+static const MemoryRegionOps xhci_runtime_ops = { -+ .read = xhci_runtime_read, -+ .write = xhci_runtime_write, -+ .valid.min_access_size = 4, -+ .valid.max_access_size = 4, -+ .endianness = DEVICE_LITTLE_ENDIAN, -+}; - --static const MemoryRegionOps xhci_mem_ops = { -- .read = xhci_mem_read, -- .write = xhci_mem_write, -+static const MemoryRegionOps xhci_doorbell_ops = { -+ .read = xhci_doorbell_read, -+ .write = xhci_doorbell_write, - .valid.min_access_size = 4, - .valid.max_access_size = 4, - .endianness = DEVICE_LITTLE_ENDIAN, -@@ -2940,8 +2937,21 @@ static int usb_xhci_initfn(struct PCIDevice *dev) - - xhci->irq = xhci->pci_dev.irq[0]; - -- memory_region_init_io(&xhci->mem, &xhci_mem_ops, xhci, -- "xhci", LEN_REGS); -+ memory_region_init(&xhci->mem, "xhci", LEN_REGS); -+ memory_region_init_io(&xhci->mem_cap, &xhci_cap_ops, xhci, -+ "capabilities", LEN_CAP); -+ memory_region_init_io(&xhci->mem_oper, &xhci_oper_ops, xhci, -+ "operational", 0x400 + 0x10 * xhci->numports); -+ memory_region_init_io(&xhci->mem_runtime, &xhci_runtime_ops, xhci, -+ "runtime", LEN_RUNTIME); -+ memory_region_init_io(&xhci->mem_doorbell, &xhci_doorbell_ops, xhci, -+ "doorbell", LEN_DOORBELL); -+ -+ memory_region_add_subregion(&xhci->mem, 0, &xhci->mem_cap); -+ memory_region_add_subregion(&xhci->mem, OFF_OPER, &xhci->mem_oper); -+ memory_region_add_subregion(&xhci->mem, OFF_RUNTIME, &xhci->mem_runtime); -+ memory_region_add_subregion(&xhci->mem, OFF_DOORBELL, &xhci->mem_doorbell); -+ - pci_register_bar(&xhci->pci_dev, 0, - PCI_BASE_ADDRESS_SPACE_MEMORY|PCI_BASE_ADDRESS_MEM_TYPE_64, - &xhci->mem); --- -1.7.12 - diff --git a/0354-xhci-allow-bytewise-capability-register-reads.patch b/0354-xhci-allow-bytewise-capability-register-reads.patch deleted file mode 100644 index 12b4338..0000000 --- a/0354-xhci-allow-bytewise-capability-register-reads.patch +++ /dev/null @@ -1,32 +0,0 @@ -From 25968a7c7947b7e215e351b159a5f4ebf4609aab Mon Sep 17 00:00:00 2001 -From: Gerd Hoffmann -Date: Tue, 4 Sep 2012 14:48:03 +0200 -Subject: [PATCH 354/366] xhci: allow bytewise capability register reads - -Some guests need this according to -Alejandro Martinez Ruiz - -Signed-off-by: Gerd Hoffmann ---- - hw/usb/hcd-xhci.c | 4 +++- - 1 file changed, 3 insertions(+), 1 deletion(-) - -diff --git a/hw/usb/hcd-xhci.c b/hw/usb/hcd-xhci.c -index 500892d..2918e64 100644 ---- a/hw/usb/hcd-xhci.c -+++ b/hw/usb/hcd-xhci.c -@@ -2748,8 +2748,10 @@ static void xhci_doorbell_write(void *ptr, target_phys_addr_t reg, - - static const MemoryRegionOps xhci_cap_ops = { - .read = xhci_cap_read, -- .valid.min_access_size = 4, -+ .valid.min_access_size = 1, - .valid.max_access_size = 4, -+ .impl.min_access_size = 4, -+ .impl.max_access_size = 4, - .endianness = DEVICE_LITTLE_ENDIAN, - }; - --- -1.7.12 - diff --git a/0355-usb-host-allow-emulated-non-async-control-requests-w.patch b/0355-usb-host-allow-emulated-non-async-control-requests-w.patch deleted file mode 100644 index 752582f..0000000 --- a/0355-usb-host-allow-emulated-non-async-control-requests-w.patch +++ /dev/null @@ -1,37 +0,0 @@ -From 487e24442148aa659a53f69db394642a7d93c3c6 Mon Sep 17 00:00:00 2001 -From: Gerd Hoffmann -Date: Thu, 6 Sep 2012 12:03:41 +0200 -Subject: [PATCH 357/366] usb-host: allow emulated (non-async) control - requests without USBPacket - -xhci needs this for USB_REQ_SET_ADDRESS due to the way -usb addressing is handled by the xhci hardware. - -Signed-off-by: Gerd Hoffmann ---- - hw/usb/host-linux.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/hw/usb/host-linux.c b/hw/usb/host-linux.c -index 8df9207..44f1a64 100644 ---- a/hw/usb/host-linux.c -+++ b/hw/usb/host-linux.c -@@ -1045,7 +1045,6 @@ static int usb_host_handle_control(USBDevice *dev, USBPacket *p, - - /* Note request is (bRequestType << 8) | bRequest */ - trace_usb_host_req_control(s->bus_num, s->addr, p, request, value, index); -- assert(p->result == 0); - - switch (request) { - case DeviceOutRequest | USB_REQ_SET_ADDRESS: -@@ -1074,6 +1073,7 @@ static int usb_host_handle_control(USBDevice *dev, USBPacket *p, - } - - /* The rest are asynchronous */ -+ assert(p && p->result == 0); - - if (length > sizeof(dev->data_buf)) { - fprintf(stderr, "husb: ctrl buffer too small (%d > %zu)\n", --- -1.7.12 - diff --git a/0356-ehci-switch-to-new-style-memory-ops.patch b/0356-ehci-switch-to-new-style-memory-ops.patch deleted file mode 100644 index 78e6b4f..0000000 --- a/0356-ehci-switch-to-new-style-memory-ops.patch +++ /dev/null @@ -1,367 +0,0 @@ -From 538ee859ae415782e5be3b4a07e7db655cf70aa2 Mon Sep 17 00:00:00 2001 -From: Gerd Hoffmann -Date: Thu, 6 Sep 2012 11:24:51 +0200 -Subject: [PATCH 355/366] ehci: switch to new-style memory ops - -Also register different memory regions for capabilities, -operational registers and port status registers. Create -separate tracepoints for operational regs and port status -regs. Ditch a bunch of sanity checks because the memory -core will do this for us now. - -Offloading the byte, word and dword access handling to the -memory core also has the side effect of fixing ehci register -access on bigendian hosts. - -Cc: David Gibson -Signed-off-by: Gerd Hoffmann ---- - hw/usb/hcd-ehci.c | 173 ++++++++++++++++++++++++++---------------------------- - trace-events | 9 ++- - 2 files changed, 90 insertions(+), 92 deletions(-) - -diff --git a/hw/usb/hcd-ehci.c b/hw/usb/hcd-ehci.c -index 2f3e9c0..f5ba8e1 100644 ---- a/hw/usb/hcd-ehci.c -+++ b/hw/usb/hcd-ehci.c -@@ -389,6 +389,9 @@ struct EHCIState { - USBBus bus; - qemu_irq irq; - MemoryRegion mem; -+ MemoryRegion mem_caps; -+ MemoryRegion mem_opreg; -+ MemoryRegion mem_ports; - int companion_count; - - /* properties */ -@@ -398,10 +401,10 @@ struct EHCIState { - * EHCI spec version 1.0 Section 2.3 - * Host Controller Operational Registers - */ -+ uint8_t caps[OPREGBASE]; - union { -- uint8_t mmio[MMIO_SIZE]; -+ uint32_t opreg[(PORTSC_BEGIN-OPREGBASE)/sizeof(uint32_t)]; - struct { -- uint8_t cap[OPREGBASE]; - uint32_t usbcmd; - uint32_t usbsts; - uint32_t usbintr; -@@ -411,9 +414,9 @@ struct EHCIState { - uint32_t asynclistaddr; - uint32_t notused[9]; - uint32_t configflag; -- uint32_t portsc[NB_PORTS]; - }; - }; -+ uint32_t portsc[NB_PORTS]; - - /* - * Internal states, shadow registers, etc -@@ -471,22 +474,12 @@ static const char *ehci_state_names[] = { - }; - - static const char *ehci_mmio_names[] = { -- [CAPLENGTH] = "CAPLENGTH", -- [HCIVERSION] = "HCIVERSION", -- [HCSPARAMS] = "HCSPARAMS", -- [HCCPARAMS] = "HCCPARAMS", - [USBCMD] = "USBCMD", - [USBSTS] = "USBSTS", - [USBINTR] = "USBINTR", - [FRINDEX] = "FRINDEX", - [PERIODICLISTBASE] = "P-LIST BASE", - [ASYNCLISTADDR] = "A-LIST ADDR", -- [PORTSC_BEGIN] = "PORTSC #0", -- [PORTSC_BEGIN + 4] = "PORTSC #1", -- [PORTSC_BEGIN + 8] = "PORTSC #2", -- [PORTSC_BEGIN + 12] = "PORTSC #3", -- [PORTSC_BEGIN + 16] = "PORTSC #4", -- [PORTSC_BEGIN + 20] = "PORTSC #5", - [CONFIGFLAG] = "CONFIGFLAG", - }; - -@@ -509,7 +502,8 @@ static const char *state2str(uint32_t state) - - static const char *addr2str(target_phys_addr_t addr) - { -- return nr2str(ehci_mmio_names, ARRAY_SIZE(ehci_mmio_names), addr); -+ return nr2str(ehci_mmio_names, ARRAY_SIZE(ehci_mmio_names), -+ addr + OPREGBASE); - } - - static void ehci_trace_usbsts(uint32_t mask, int state) -@@ -1018,7 +1012,7 @@ static int ehci_register_companion(USBBus *bus, USBPort *ports[], - } - - s->companion_count++; -- s->mmio[0x05] = (s->companion_count << 4) | portcount; -+ s->caps[0x05] = (s->companion_count << 4) | portcount; - - return 0; - } -@@ -1063,7 +1057,8 @@ static void ehci_reset(void *opaque) - } - } - -- memset(&s->mmio[OPREGBASE], 0x00, MMIO_SIZE - OPREGBASE); -+ memset(&s->opreg, 0x00, sizeof(s->opreg)); -+ memset(&s->portsc, 0x00, sizeof(s->portsc)); - - s->usbcmd = NB_MAXINTRATE << USBCMD_ITC_SH; - s->usbsts = USBSTS_HALT; -@@ -1090,50 +1085,35 @@ static void ehci_reset(void *opaque) - qemu_bh_cancel(s->async_bh); - } - --static uint32_t ehci_mem_readb(void *ptr, target_phys_addr_t addr) -+static uint64_t ehci_caps_read(void *ptr, target_phys_addr_t addr, -+ unsigned size) - { - EHCIState *s = ptr; -- uint32_t val; -- -- val = s->mmio[addr]; -- -- return val; -+ return s->caps[addr]; - } - --static uint32_t ehci_mem_readw(void *ptr, target_phys_addr_t addr) -+static uint64_t ehci_opreg_read(void *ptr, target_phys_addr_t addr, -+ unsigned size) - { - EHCIState *s = ptr; - uint32_t val; - -- val = s->mmio[addr] | (s->mmio[addr+1] << 8); -- -+ val = s->opreg[addr >> 2]; -+ trace_usb_ehci_opreg_read(addr + OPREGBASE, addr2str(addr), val); - return val; - } - --static uint32_t ehci_mem_readl(void *ptr, target_phys_addr_t addr) -+static uint64_t ehci_port_read(void *ptr, target_phys_addr_t addr, -+ unsigned size) - { - EHCIState *s = ptr; - uint32_t val; - -- val = s->mmio[addr] | (s->mmio[addr+1] << 8) | -- (s->mmio[addr+2] << 16) | (s->mmio[addr+3] << 24); -- -- trace_usb_ehci_mmio_readl(addr, addr2str(addr), val); -+ val = s->portsc[addr >> 2]; -+ trace_usb_ehci_portsc_read(addr + PORTSC_BEGIN, addr >> 2, val); - return val; - } - --static void ehci_mem_writeb(void *ptr, target_phys_addr_t addr, uint32_t val) --{ -- fprintf(stderr, "EHCI doesn't handle byte writes to MMIO\n"); -- exit(1); --} -- --static void ehci_mem_writew(void *ptr, target_phys_addr_t addr, uint32_t val) --{ -- fprintf(stderr, "EHCI doesn't handle 16-bit writes to MMIO\n"); -- exit(1); --} -- - static void handle_port_owner_write(EHCIState *s, int port, uint32_t owner) - { - USBDevice *dev = s->ports[port].dev; -@@ -1162,11 +1142,17 @@ static void handle_port_owner_write(EHCIState *s, int port, uint32_t owner) - } - } - --static void handle_port_status_write(EHCIState *s, int port, uint32_t val) -+static void ehci_port_write(void *ptr, target_phys_addr_t addr, -+ uint64_t val, unsigned size) - { -+ EHCIState *s = ptr; -+ int port = addr >> 2; - uint32_t *portsc = &s->portsc[port]; -+ uint32_t old = *portsc; - USBDevice *dev = s->ports[port].dev; - -+ trace_usb_ehci_portsc_write(addr + PORTSC_BEGIN, addr >> 2, val); -+ - /* Clear rwc bits */ - *portsc &= ~(val & PORTSC_RWC_MASK); - /* The guest may clear, but not set the PED bit */ -@@ -1198,39 +1184,20 @@ static void handle_port_status_write(EHCIState *s, int port, uint32_t val) - - *portsc &= ~PORTSC_RO_MASK; - *portsc |= val; -+ trace_usb_ehci_portsc_change(addr + PORTSC_BEGIN, addr >> 2, *portsc, old); - } - --static void ehci_mem_writel(void *ptr, target_phys_addr_t addr, uint32_t val) -+static void ehci_opreg_write(void *ptr, target_phys_addr_t addr, -+ uint64_t val, unsigned size) - { - EHCIState *s = ptr; -- uint32_t *mmio = (uint32_t *)(&s->mmio[addr]); -+ uint32_t *mmio = s->opreg + (addr >> 2); - uint32_t old = *mmio; - int i; - -- trace_usb_ehci_mmio_writel(addr, addr2str(addr), val); -- -- /* Only aligned reads are allowed on OHCI */ -- if (addr & 3) { -- fprintf(stderr, "usb-ehci: Mis-aligned write to addr 0x" -- TARGET_FMT_plx "\n", addr); -- return; -- } -- -- if (addr >= PORTSC && addr < PORTSC + 4 * NB_PORTS) { -- handle_port_status_write(s, (addr-PORTSC)/4, val); -- trace_usb_ehci_mmio_change(addr, addr2str(addr), *mmio, old); -- return; -- } -- -- if (addr < OPREGBASE) { -- fprintf(stderr, "usb-ehci: write attempt to read-only register" -- TARGET_FMT_plx "\n", addr); -- return; -- } -- -+ trace_usb_ehci_opreg_write(addr + OPREGBASE, addr2str(addr), val); - -- /* Do any register specific pre-write processing here. */ -- switch(addr) { -+ switch (addr + OPREGBASE) { - case USBCMD: - if (val & USBCMD_HCRESET) { - ehci_reset(s); -@@ -1241,7 +1208,7 @@ static void ehci_mem_writel(void *ptr, target_phys_addr_t addr, uint32_t val) - /* not supporting dynamic frame list size at the moment */ - if ((val & USBCMD_FLS) && !(s->usbcmd & USBCMD_FLS)) { - fprintf(stderr, "attempt to set frame list size -- value %d\n", -- val & USBCMD_FLS); -+ (int)val & USBCMD_FLS); - val &= ~USBCMD_FLS; - } - -@@ -1308,7 +1275,7 @@ static void ehci_mem_writel(void *ptr, target_phys_addr_t addr, uint32_t val) - } - - *mmio = val; -- trace_usb_ehci_mmio_change(addr, addr2str(addr), *mmio, old); -+ trace_usb_ehci_opreg_change(addr + OPREGBASE, addr2str(addr), *mmio, old); - } - - -@@ -2520,11 +2487,28 @@ static void ehci_async_bh(void *opaque) - ehci_advance_async_state(ehci); - } - --static const MemoryRegionOps ehci_mem_ops = { -- .old_mmio = { -- .read = { ehci_mem_readb, ehci_mem_readw, ehci_mem_readl }, -- .write = { ehci_mem_writeb, ehci_mem_writew, ehci_mem_writel }, -- }, -+static const MemoryRegionOps ehci_mmio_caps_ops = { -+ .read = ehci_caps_read, -+ .valid.min_access_size = 1, -+ .valid.max_access_size = 4, -+ .impl.min_access_size = 1, -+ .impl.max_access_size = 1, -+ .endianness = DEVICE_LITTLE_ENDIAN, -+}; -+ -+static const MemoryRegionOps ehci_mmio_opreg_ops = { -+ .read = ehci_opreg_read, -+ .write = ehci_opreg_write, -+ .valid.min_access_size = 4, -+ .valid.max_access_size = 4, -+ .endianness = DEVICE_LITTLE_ENDIAN, -+}; -+ -+static const MemoryRegionOps ehci_mmio_port_ops = { -+ .read = ehci_port_read, -+ .write = ehci_port_write, -+ .valid.min_access_size = 4, -+ .valid.max_access_size = 4, - .endianness = DEVICE_LITTLE_ENDIAN, - }; - -@@ -2681,19 +2665,19 @@ static int usb_ehci_initfn(PCIDevice *dev) - pci_conf[0x6e] = 0x00; - pci_conf[0x6f] = 0xc0; // USBLEFCTLSTS - -- // 2.2 host controller interface version -- s->mmio[0x00] = (uint8_t) OPREGBASE; -- s->mmio[0x01] = 0x00; -- s->mmio[0x02] = 0x00; -- s->mmio[0x03] = 0x01; // HC version -- s->mmio[0x04] = NB_PORTS; // Number of downstream ports -- s->mmio[0x05] = 0x00; // No companion ports at present -- s->mmio[0x06] = 0x00; -- s->mmio[0x07] = 0x00; -- s->mmio[0x08] = 0x80; // We can cache whole frame, not 64-bit capable -- s->mmio[0x09] = 0x68; // EECP -- s->mmio[0x0a] = 0x00; -- s->mmio[0x0b] = 0x00; -+ /* 2.2 host controller interface version */ -+ s->caps[0x00] = (uint8_t) OPREGBASE; -+ s->caps[0x01] = 0x00; -+ s->caps[0x02] = 0x00; -+ s->caps[0x03] = 0x01; /* HC version */ -+ s->caps[0x04] = NB_PORTS; /* Number of downstream ports */ -+ s->caps[0x05] = 0x00; /* No companion ports at present */ -+ s->caps[0x06] = 0x00; -+ s->caps[0x07] = 0x00; -+ s->caps[0x08] = 0x80; /* We can cache whole frame, no 64-bit */ -+ s->caps[0x09] = 0x68; /* EECP */ -+ s->caps[0x0a] = 0x00; -+ s->caps[0x0b] = 0x00; - - s->irq = s->dev.irq[3]; - -@@ -2712,7 +2696,18 @@ static int usb_ehci_initfn(PCIDevice *dev) - - qemu_register_reset(ehci_reset, s); - -- memory_region_init_io(&s->mem, &ehci_mem_ops, s, "ehci", MMIO_SIZE); -+ memory_region_init(&s->mem, "ehci", MMIO_SIZE); -+ memory_region_init_io(&s->mem_caps, &ehci_mmio_caps_ops, s, -+ "capabilities", OPREGBASE); -+ memory_region_init_io(&s->mem_opreg, &ehci_mmio_opreg_ops, s, -+ "operational", PORTSC_BEGIN - OPREGBASE); -+ memory_region_init_io(&s->mem_ports, &ehci_mmio_port_ops, s, -+ "ports", PORTSC_END - PORTSC_BEGIN); -+ -+ memory_region_add_subregion(&s->mem, 0, &s->mem_caps); -+ memory_region_add_subregion(&s->mem, OPREGBASE, &s->mem_opreg); -+ memory_region_add_subregion(&s->mem, PORTSC_BEGIN, &s->mem_ports); -+ - pci_register_bar(&s->dev, 0, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->mem); - - return 0; -diff --git a/trace-events b/trace-events -index b25ae1c..a58b0b7 100644 ---- a/trace-events -+++ b/trace-events -@@ -243,9 +243,12 @@ usb_port_release(int bus, const char *port) "bus %d, port %s" - - # hw/usb/hcd-ehci.c - usb_ehci_reset(void) "=== RESET ===" --usb_ehci_mmio_readl(uint32_t addr, const char *str, uint32_t val) "rd mmio %04x [%s] = %x" --usb_ehci_mmio_writel(uint32_t addr, const char *str, uint32_t val) "wr mmio %04x [%s] = %x" --usb_ehci_mmio_change(uint32_t addr, const char *str, uint32_t new, uint32_t old) "ch mmio %04x [%s] = %x (old: %x)" -+usb_ehci_opreg_read(uint32_t addr, const char *str, uint32_t val) "rd mmio %04x [%s] = %x" -+usb_ehci_opreg_write(uint32_t addr, const char *str, uint32_t val) "wr mmio %04x [%s] = %x" -+usb_ehci_opreg_change(uint32_t addr, const char *str, uint32_t new, uint32_t old) "ch mmio %04x [%s] = %x (old: %x)" -+usb_ehci_portsc_read(uint32_t addr, uint32_t port, uint32_t val) "rd mmio %04x [port %d] = %x" -+usb_ehci_portsc_write(uint32_t addr, uint32_t port, uint32_t val) "wr mmio %04x [port %d] = %x" -+usb_ehci_portsc_change(uint32_t addr, uint32_t port, uint32_t new, uint32_t old) "ch mmio %04x [port %d] = %x (old: %x)" - usb_ehci_usbsts(const char *sts, int state) "usbsts %s %d" - usb_ehci_state(const char *schedule, const char *state) "%s schedule %s" - usb_ehci_qh_ptrs(void *q, uint32_t addr, uint32_t nxt, uint32_t c_qtd, uint32_t n_qtd, uint32_t a_qtd) "q %p - QH @ %08x: next %08x qtds %08x,%08x,%08x" --- -1.7.12 - diff --git a/0357-ehci-Fix-interrupts-stopping-when-Interrupt-Threshol.patch b/0357-ehci-Fix-interrupts-stopping-when-Interrupt-Threshol.patch deleted file mode 100644 index 803ab11..0000000 --- a/0357-ehci-Fix-interrupts-stopping-when-Interrupt-Threshol.patch +++ /dev/null @@ -1,34 +0,0 @@ -From 2ebb3309738501fcc9e8da807866fa4225bb5e91 Mon Sep 17 00:00:00 2001 -From: Hans de Goede -Date: Mon, 10 Sep 2012 11:44:08 +0200 -Subject: [PATCH 357/369] ehci: Fix interrupts stopping when Interrupt - Threshold Control is 8 - -If Interrupt Threshold Control is 8 or a multiple of 8, then -s->usbsts_frindex can become exactly 0x4000, at which point -(s->usbsts_frindex > s->frindex) will never become true, as -s->usbsts_frindex will not be lowered / reset in this case. - -This patch fixes this. - -Signed-off-by: Hans de Goede ---- - hw/usb/hcd-ehci.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/hw/usb/hcd-ehci.c b/hw/usb/hcd-ehci.c -index f5ba8e1..54273d7 100644 ---- a/hw/usb/hcd-ehci.c -+++ b/hw/usb/hcd-ehci.c -@@ -2413,7 +2413,7 @@ static void ehci_update_frindex(EHCIState *ehci, int frames) - if (ehci->frindex == 0x00004000) { - ehci_raise_irq(ehci, USBSTS_FLR); - ehci->frindex = 0; -- if (ehci->usbsts_frindex > 0x00004000) { -+ if (ehci->usbsts_frindex >= 0x00004000) { - ehci->usbsts_frindex -= 0x00004000; - } else { - ehci->usbsts_frindex = 0; --- -1.7.12 - diff --git a/0358-ehci-Don-t-process-too-much-frames-in-1-timer-tick-v.patch b/0358-ehci-Don-t-process-too-much-frames-in-1-timer-tick-v.patch deleted file mode 100644 index 9608c63..0000000 --- a/0358-ehci-Don-t-process-too-much-frames-in-1-timer-tick-v.patch +++ /dev/null @@ -1,57 +0,0 @@ -From d1034a88fdd8ad693a5cc2cb75af946e1562ff09 Mon Sep 17 00:00:00 2001 -From: Hans de Goede -Date: Mon, 10 Sep 2012 12:38:21 +0200 -Subject: [PATCH 358/369] ehci: Don't process too much frames in 1 timer tick - (v2) - -The Linux ehci isoc scheduling code fills the entire schedule ahead of -time minus 80 frames. If we make a large jump in where we are in the -schedule, ie 40 frames, then the scheduler all of a sudden will only have -40 frames left to work in, causing it to fail packet submissions -with error -27 (-EFBIG). - -Changes in v2: --Don't hardcode a maximum number of frames to process in one tick, instead: - -Process a minimum number of frames to ensure we do eventually catch up - -Stop (after the minimum number) when the guest has requested an irq - -Signed-off-by: Hans de Goede ---- - hw/usb/hcd-ehci.c | 14 ++++++++++++++ - 1 file changed, 14 insertions(+) - -diff --git a/hw/usb/hcd-ehci.c b/hw/usb/hcd-ehci.c -index 54273d7..6ce727c 100644 ---- a/hw/usb/hcd-ehci.c -+++ b/hw/usb/hcd-ehci.c -@@ -139,6 +139,7 @@ - #define NB_PORTS 6 // Number of downstream ports - #define BUFF_SIZE 5*4096 // Max bytes to transfer per transaction - #define MAX_QH 100 // Max allowable queue heads in a chain -+#define MIN_FR_PER_TICK 3 // Min frames to process when catching up - - /* Internal periodic / asynchronous schedule state machine states - */ -@@ -2448,6 +2449,19 @@ static void ehci_frame_timer(void *opaque) - } - - for (i = 0; i < frames; i++) { -+ /* -+ * If we're running behind schedule, we should not catch up -+ * too fast, as that will make some guests unhappy: -+ * 1) We must process a minimum of MIN_FR_PER_TICK frames, -+ * otherwise we will never catch up -+ * 2) Process frames until the guest has requested an irq (IOC) -+ */ -+ if (i >= MIN_FR_PER_TICK) { -+ ehci_commit_irq(ehci); -+ if ((ehci->usbsts & USBINTR_MASK) & ehci->usbintr) { -+ break; -+ } -+ } - ehci_update_frindex(ehci, 1); - ehci_advance_periodic_state(ehci); - ehci->last_run_ns += FRAME_TIMER_NS; --- -1.7.12 - diff --git a/0359-configure-usbredir-fixes.patch b/0359-configure-usbredir-fixes.patch deleted file mode 100644 index ff0454b..0000000 --- a/0359-configure-usbredir-fixes.patch +++ /dev/null @@ -1,33 +0,0 @@ -From 31bb27a1393168657cb53deff12d4b58601e4d72 Mon Sep 17 00:00:00 2001 -From: Aurelien Jarno -Date: Tue, 11 Sep 2012 18:57:58 +0000 -Subject: [PATCH 359/369] configure: usbredir fixes - -usbredir is only used by system emulation, so add the libraries to -libs_softmmu instead of LIBS. - -Cc: Michael Tokarev -Cc: Gerd Hoffmann -Signed-off-by: Aurelien Jarno -Signed-off-by: Hans de Goede -Signed-off-by: Gerd Hoffmann ---- - configure | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/configure b/configure -index 25c406f..d63530a 100755 ---- a/configure -+++ b/configure -@@ -2770,7 +2770,7 @@ if test "$usb_redir" != "no" ; then - usb_redir_cflags=$($pkg_config --cflags libusbredirparser 2>/dev/null) - usb_redir_libs=$($pkg_config --libs libusbredirparser 2>/dev/null) - QEMU_CFLAGS="$QEMU_CFLAGS $usb_redir_cflags" -- LIBS="$LIBS $usb_redir_libs" -+ libs_softmmu="$libs_softmmu $usb_redir_libs" - else - if test "$usb_redir" = "yes"; then - feature_not_found "usb-redir" --- -1.7.12 - diff --git a/0360-ehci-Don-t-set-seen-to-0-when-removing-unseen-queue-.patch b/0360-ehci-Don-t-set-seen-to-0-when-removing-unseen-queue-.patch deleted file mode 100644 index f40d17b..0000000 --- a/0360-ehci-Don-t-set-seen-to-0-when-removing-unseen-queue-.patch +++ /dev/null @@ -1,101 +0,0 @@ -From 833eeda8129b2cf4955a34600b60c01e00652526 Mon Sep 17 00:00:00 2001 -From: Hans de Goede -Date: Wed, 5 Sep 2012 12:13:41 +0200 -Subject: [PATCH 358/366] ehci: Don't set seen to 0 when removing unseen - queue-heads - -When removing unseen queue-heads from the async queue list, we should not -set the seen flag to 0, as this may cause them to be removed by -ehci_queues_rip_unused() during the next call to ehci_advance_async_state() -if the timer is late or running at a low frequency. - -Note: -1) This *may* have caused the instant unlink / relinks described in commit - 9bc3a3a216e2689bfcdd36c3e079333bbdbf3ba0 - -2) Rather then putting more if-s inside ehci_queues_rip_unused, this patch - instead introduces a new ehci_queues_rip_unseen function. - -3) This patch also makes it save to call ehci_queues_rip_unseen() multiple - times, which gets used in the folluw up patch titled: - "ehci: Walk async schedule before and after migration" - -Signed-off-by: Hans de Goede ---- - hw/usb/hcd-ehci.c | 24 ++++++++++++++++++------ - 1 file changed, 18 insertions(+), 6 deletions(-) - -diff --git a/hw/usb/hcd-ehci.c b/hw/usb/hcd-ehci.c -index f5ba8e1..6f48132 100644 ---- a/hw/usb/hcd-ehci.c -+++ b/hw/usb/hcd-ehci.c -@@ -847,10 +847,10 @@ static EHCIQueue *ehci_find_queue_by_qh(EHCIState *ehci, uint32_t addr, - return NULL; - } - --static void ehci_queues_rip_unused(EHCIState *ehci, int async, int flush) -+static void ehci_queues_rip_unused(EHCIState *ehci, int async) - { - EHCIQueueHead *head = async ? &ehci->aqueues : &ehci->pqueues; -- const char *warn = (async && !flush) ? "guest unlinked busy QH" : NULL; -+ const char *warn = async ? "guest unlinked busy QH" : NULL; - uint64_t maxage = FRAME_TIMER_NS * ehci->maxframes * 4; - EHCIQueue *q, *tmp; - -@@ -860,13 +860,25 @@ static void ehci_queues_rip_unused(EHCIState *ehci, int async, int flush) - q->ts = ehci->last_run_ns; - continue; - } -- if (!flush && ehci->last_run_ns < q->ts + maxage) { -+ if (ehci->last_run_ns < q->ts + maxage) { - continue; - } - ehci_free_queue(q, warn); - } - } - -+static void ehci_queues_rip_unseen(EHCIState *ehci, int async) -+{ -+ EHCIQueueHead *head = async ? &ehci->aqueues : &ehci->pqueues; -+ EHCIQueue *q, *tmp; -+ -+ QTAILQ_FOREACH_SAFE(q, head, next, tmp) { -+ if (!q->seen) { -+ ehci_free_queue(q, NULL); -+ } -+ } -+} -+ - static void ehci_queues_rip_device(EHCIState *ehci, USBDevice *dev, int async) - { - EHCIQueueHead *head = async ? &ehci->aqueues : &ehci->pqueues; -@@ -1699,7 +1711,7 @@ static int ehci_state_waitlisthead(EHCIState *ehci, int async) - ehci_set_usbsts(ehci, USBSTS_REC); - } - -- ehci_queues_rip_unused(ehci, async, 0); -+ ehci_queues_rip_unused(ehci, async); - - /* Find the head of the list (4.9.1.1) */ - for(i = 0; i < MAX_QH; i++) { -@@ -2331,7 +2343,7 @@ static void ehci_advance_async_state(EHCIState *ehci) - */ - if (ehci->usbcmd & USBCMD_IAAD) { - /* Remove all unseen qhs from the async qhs queue */ -- ehci_queues_rip_unused(ehci, async, 1); -+ ehci_queues_rip_unseen(ehci, async); - trace_usb_ehci_doorbell_ack(); - ehci->usbcmd &= ~USBCMD_IAAD; - ehci_raise_irq(ehci, USBSTS_IAA); -@@ -2384,7 +2396,7 @@ static void ehci_advance_periodic_state(EHCIState *ehci) - ehci_set_fetch_addr(ehci, async,entry); - ehci_set_state(ehci, async, EST_FETCHENTRY); - ehci_advance_state(ehci, async); -- ehci_queues_rip_unused(ehci, async, 0); -+ ehci_queues_rip_unused(ehci, async); - break; - - default: --- -1.7.12 - diff --git a/0361-ehci-Walk-async-schedule-before-and-after-migration.patch b/0361-ehci-Walk-async-schedule-before-and-after-migration.patch deleted file mode 100644 index 3c2bf54..0000000 --- a/0361-ehci-Walk-async-schedule-before-and-after-migration.patch +++ /dev/null @@ -1,66 +0,0 @@ -From fec70ddafe1632f40608ef6917760a7f946f278a Mon Sep 17 00:00:00 2001 -From: Hans de Goede -Date: Wed, 5 Sep 2012 12:07:10 +0200 -Subject: [PATCH 359/366] ehci: Walk async schedule before and after migration - -Signed-off-by: Hans de Goede ---- - hw/usb/hcd-ehci.c | 28 ++++++++++++++++++++++++++++ - 1 file changed, 28 insertions(+) - -diff --git a/hw/usb/hcd-ehci.c b/hw/usb/hcd-ehci.c -index 6f48132..30d2b56 100644 ---- a/hw/usb/hcd-ehci.c -+++ b/hw/usb/hcd-ehci.c -@@ -34,6 +34,7 @@ - #include "monitor.h" - #include "trace.h" - #include "dma.h" -+#include "sysemu.h" - - #define EHCI_DEBUG 0 - -@@ -2558,6 +2559,32 @@ static int usb_ehci_post_load(void *opaque, int version_id) - return 0; - } - -+static void usb_ehci_vm_state_change(void *opaque, int running, RunState state) -+{ -+ EHCIState *ehci = opaque; -+ -+ /* -+ * We don't migrate the EHCIQueue-s, instead we rebuild them for the -+ * schedule in guest memory. We must do the rebuilt ASAP, so that -+ * USB-devices which have async handled packages have a packet in the -+ * ep queue to match the completion with. -+ */ -+ if (state == RUN_STATE_RUNNING) { -+ ehci_advance_async_state(ehci); -+ } -+ -+ /* -+ * The schedule rebuilt from guest memory could cause the migration dest -+ * to miss a QH unlink, and fail to cancel packets, since the unlinked QH -+ * will never have existed on the destination. Therefor we must flush the -+ * async schedule on savevm to catch any not yet noticed unlinks. -+ */ -+ if (state == RUN_STATE_SAVE_VM) { -+ ehci_advance_async_state(ehci); -+ ehci_queues_rip_unseen(ehci, 1); -+ } -+} -+ - static const VMStateDescription vmstate_ehci = { - .name = "ehci", - .version_id = 2, -@@ -2707,6 +2734,7 @@ static int usb_ehci_initfn(PCIDevice *dev) - usb_packet_init(&s->ipacket); - - qemu_register_reset(ehci_reset, s); -+ qemu_add_vm_change_state_handler(usb_ehci_vm_state_change, s); - - memory_region_init(&s->mem, "ehci", MMIO_SIZE); - memory_region_init_io(&s->mem_caps, &ehci_mmio_caps_ops, s, --- -1.7.12 - diff --git a/0362-usb-redir-Change-cancelled-packet-code-into-a-generi.patch b/0362-usb-redir-Change-cancelled-packet-code-into-a-generi.patch deleted file mode 100644 index 2efd733..0000000 --- a/0362-usb-redir-Change-cancelled-packet-code-into-a-generi.patch +++ /dev/null @@ -1,184 +0,0 @@ -From efbf5d06a89ec7b329d2aa15d3a6ea023b63c646 Mon Sep 17 00:00:00 2001 -From: Hans de Goede -Date: Tue, 4 Sep 2012 14:18:34 +0200 -Subject: [PATCH 361/365] usb-redir: Change cancelled packet code into a - generic packet-id queue - -Signed-off-by: Hans de Goede ---- - hw/usb/redirect.c | 102 +++++++++++++++++++++++++++++++++++++----------------- - 1 file changed, 71 insertions(+), 31 deletions(-) - -diff --git a/hw/usb/redirect.c b/hw/usb/redirect.c -index 9cbcddb..08776d9 100644 ---- a/hw/usb/redirect.c -+++ b/hw/usb/redirect.c -@@ -43,7 +43,6 @@ - #define EP2I(ep_address) (((ep_address & 0x80) >> 3) | (ep_address & 0x0f)) - #define I2EP(i) (((i & 0x10) << 3) | (i & 0x0f)) - --typedef struct Cancelled Cancelled; - typedef struct USBRedirDevice USBRedirDevice; - - /* Struct to hold buffered packets (iso or int input packets) */ -@@ -69,6 +68,18 @@ struct endp_data { - int bufpq_target_size; - }; - -+struct PacketIdQueueEntry { -+ uint64_t id; -+ QTAILQ_ENTRY(PacketIdQueueEntry)next; -+}; -+ -+struct PacketIdQueue { -+ USBRedirDevice *dev; -+ const char *name; -+ QTAILQ_HEAD(, PacketIdQueueEntry) head; -+ int size; -+}; -+ - struct USBRedirDevice { - USBDevice dev; - /* Properties */ -@@ -86,7 +97,7 @@ struct USBRedirDevice { - int64_t next_attach_time; - struct usbredirparser *parser; - struct endp_data endpoint[MAX_ENDPOINTS]; -- QTAILQ_HEAD(, Cancelled) cancelled; -+ struct PacketIdQueue cancelled; - /* Data for device filtering */ - struct usb_redir_device_connect_header device_info; - struct usb_redir_interface_info_header interface_info; -@@ -94,11 +105,6 @@ struct USBRedirDevice { - int filter_rules_count; - }; - --struct Cancelled { -- uint64_t id; -- QTAILQ_ENTRY(Cancelled)next; --}; -- - static void usbredir_hello(void *priv, struct usb_redir_hello_header *h); - static void usbredir_device_connect(void *priv, - struct usb_redir_device_connect_header *device_connect); -@@ -249,37 +255,75 @@ static int usbredir_write(void *priv, uint8_t *data, int count) - * Cancelled and buffered packets helpers - */ - --static void usbredir_cancel_packet(USBDevice *udev, USBPacket *p) -+static void packet_id_queue_init(struct PacketIdQueue *q, -+ USBRedirDevice *dev, const char *name) - { -- USBRedirDevice *dev = DO_UPCAST(USBRedirDevice, dev, udev); -- Cancelled *c; -+ q->dev = dev; -+ q->name = name; -+ QTAILQ_INIT(&q->head); -+ q->size = 0; -+} -+ -+static void packet_id_queue_add(struct PacketIdQueue *q, uint64_t id) -+{ -+ USBRedirDevice *dev = q->dev; -+ struct PacketIdQueueEntry *e; -+ -+ DPRINTF("adding packet id %"PRIu64" to %s queue\n", id, q->name); -+ -+ e = g_malloc0(sizeof(struct PacketIdQueueEntry)); -+ e->id = id; -+ QTAILQ_INSERT_TAIL(&q->head, e, next); -+ q->size++; -+} -+ -+static int packet_id_queue_remove(struct PacketIdQueue *q, uint64_t id) -+{ -+ USBRedirDevice *dev = q->dev; -+ struct PacketIdQueueEntry *e; -+ -+ QTAILQ_FOREACH(e, &q->head, next) { -+ if (e->id == id) { -+ DPRINTF("removing packet id %"PRIu64" from %s queue\n", -+ id, q->name); -+ QTAILQ_REMOVE(&q->head, e, next); -+ q->size--; -+ g_free(e); -+ return 1; -+ } -+ } -+ return 0; -+} -+ -+static void packet_id_queue_empty(struct PacketIdQueue *q) -+{ -+ USBRedirDevice *dev = q->dev; -+ struct PacketIdQueueEntry *e, *next_e; - -- DPRINTF("cancel packet id %"PRIu64"\n", p->id); -+ DPRINTF("removing %d packet-ids from %s queue\n", q->size, q->name); - -- c = g_malloc0(sizeof(Cancelled)); -- c->id = p->id; -- QTAILQ_INSERT_TAIL(&dev->cancelled, c, next); -+ QTAILQ_FOREACH_SAFE(e, &q->head, next, next_e) { -+ QTAILQ_REMOVE(&q->head, e, next); -+ g_free(e); -+ } -+ q->size = 0; -+} - -+static void usbredir_cancel_packet(USBDevice *udev, USBPacket *p) -+{ -+ USBRedirDevice *dev = DO_UPCAST(USBRedirDevice, dev, udev); -+ -+ packet_id_queue_add(&dev->cancelled, p->id); - usbredirparser_send_cancel_data_packet(dev->parser, p->id); - usbredirparser_do_write(dev->parser); - } - - static int usbredir_is_cancelled(USBRedirDevice *dev, uint64_t id) - { -- Cancelled *c; -- - if (!dev->dev.attached) { - return 1; /* Treat everything as cancelled after a disconnect */ - } -- -- QTAILQ_FOREACH(c, &dev->cancelled, next) { -- if (c->id == id) { -- QTAILQ_REMOVE(&dev->cancelled, c, next); -- g_free(c); -- return 1; -- } -- } -- return 0; -+ return packet_id_queue_remove(&dev->cancelled, id); - } - - static USBPacket *usbredir_find_packet_by_id(USBRedirDevice *dev, -@@ -942,7 +986,7 @@ static int usbredir_initfn(USBDevice *udev) - dev->chardev_close_bh = qemu_bh_new(usbredir_chardev_close_bh, dev); - dev->attach_timer = qemu_new_timer_ms(vm_clock, usbredir_do_attach, dev); - -- QTAILQ_INIT(&dev->cancelled); -+ packet_id_queue_init(&dev->cancelled, dev, "cancelled"); - for (i = 0; i < MAX_ENDPOINTS; i++) { - QTAILQ_INIT(&dev->endpoint[i].bufpq); - } -@@ -960,13 +1004,9 @@ static int usbredir_initfn(USBDevice *udev) - - static void usbredir_cleanup_device_queues(USBRedirDevice *dev) - { -- Cancelled *c, *next_c; - int i; - -- QTAILQ_FOREACH_SAFE(c, &dev->cancelled, next, next_c) { -- QTAILQ_REMOVE(&dev->cancelled, c, next); -- g_free(c); -- } -+ packet_id_queue_empty(&dev->cancelled); - for (i = 0; i < MAX_ENDPOINTS; i++) { - usbredir_free_bufpq(dev, I2EP(i)); - } --- -1.7.12 - diff --git a/0363-usb-redir-Add-an-already_in_flight-packet-id-queue.patch b/0363-usb-redir-Add-an-already_in_flight-packet-id-queue.patch deleted file mode 100644 index 10c9aa3..0000000 --- a/0363-usb-redir-Add-an-already_in_flight-packet-id-queue.patch +++ /dev/null @@ -1,119 +0,0 @@ -From b422d151d0861ed346bed7cddb410a6b4c67711b Mon Sep 17 00:00:00 2001 -From: Hans de Goede -Date: Tue, 4 Sep 2012 17:03:54 +0200 -Subject: [PATCH 362/365] usb-redir: Add an already_in_flight packet-id queue - -After a live migration, the usb-hcd will re-queue all packets by -walking over the schedule in the guest memory again, but requests which -were encountered on the migration source before will already be in flight, -so these should *not* be re-send to the usbredir-host. - -This patch adds an already in flight packet ud queue, which will be filled by -the source before migration and then moved over to the migration dest, any -async handled packets are then checked against this queue to avoid sending -the same packet to the usbredir-host twice. - -Signed-off-by: Hans de Goede ---- - hw/usb/redirect.c | 43 +++++++++++++++++++++++++++++++++++++++++++ - 1 file changed, 43 insertions(+) - -diff --git a/hw/usb/redirect.c b/hw/usb/redirect.c -index 08776d9..1c8edd3 100644 ---- a/hw/usb/redirect.c -+++ b/hw/usb/redirect.c -@@ -98,6 +98,7 @@ struct USBRedirDevice { - struct usbredirparser *parser; - struct endp_data endpoint[MAX_ENDPOINTS]; - struct PacketIdQueue cancelled; -+ struct PacketIdQueue already_in_flight; - /* Data for device filtering */ - struct usb_redir_device_connect_header device_info; - struct usb_redir_interface_info_header interface_info; -@@ -326,6 +327,34 @@ static int usbredir_is_cancelled(USBRedirDevice *dev, uint64_t id) - return packet_id_queue_remove(&dev->cancelled, id); - } - -+static void usbredir_fill_already_in_flight_from_ep(USBRedirDevice *dev, -+ struct USBEndpoint *ep) -+{ -+ static USBPacket *p; -+ -+ QTAILQ_FOREACH(p, &ep->queue, queue) { -+ packet_id_queue_add(&dev->already_in_flight, p->id); -+ } -+} -+ -+static void usbredir_fill_already_in_flight(USBRedirDevice *dev) -+{ -+ int ep; -+ struct USBDevice *udev = &dev->dev; -+ -+ usbredir_fill_already_in_flight_from_ep(dev, &udev->ep_ctl); -+ -+ for (ep = 0; ep < USB_MAX_ENDPOINTS; ep++) { -+ usbredir_fill_already_in_flight_from_ep(dev, &udev->ep_in[ep]); -+ usbredir_fill_already_in_flight_from_ep(dev, &udev->ep_out[ep]); -+ } -+} -+ -+static int usbredir_already_in_flight(USBRedirDevice *dev, uint64_t id) -+{ -+ return packet_id_queue_remove(&dev->already_in_flight, id); -+} -+ - static USBPacket *usbredir_find_packet_by_id(USBRedirDevice *dev, - uint8_t ep, uint64_t id) - { -@@ -541,6 +570,10 @@ static int usbredir_handle_bulk_data(USBRedirDevice *dev, USBPacket *p, - - DPRINTF("bulk-out ep %02X len %zd id %"PRIu64"\n", ep, p->iov.size, p->id); - -+ if (usbredir_already_in_flight(dev, p->id)) { -+ return USB_RET_ASYNC; -+ } -+ - bulk_packet.endpoint = ep; - bulk_packet.length = p->iov.size; - bulk_packet.stream_id = 0; -@@ -621,6 +654,10 @@ static int usbredir_handle_interrupt_data(USBRedirDevice *dev, - DPRINTF("interrupt-out ep %02X len %zd id %"PRIu64"\n", ep, - p->iov.size, p->id); - -+ if (usbredir_already_in_flight(dev, p->id)) { -+ return USB_RET_ASYNC; -+ } -+ - interrupt_packet.endpoint = ep; - interrupt_packet.length = p->iov.size; - -@@ -763,6 +800,10 @@ static int usbredir_handle_control(USBDevice *udev, USBPacket *p, - USBRedirDevice *dev = DO_UPCAST(USBRedirDevice, dev, udev); - struct usb_redir_control_packet_header control_packet; - -+ if (usbredir_already_in_flight(dev, p->id)) { -+ return USB_RET_ASYNC; -+ } -+ - /* Special cases for certain standard device requests */ - switch (request) { - case DeviceOutRequest | USB_REQ_SET_ADDRESS: -@@ -987,6 +1028,7 @@ static int usbredir_initfn(USBDevice *udev) - dev->attach_timer = qemu_new_timer_ms(vm_clock, usbredir_do_attach, dev); - - packet_id_queue_init(&dev->cancelled, dev, "cancelled"); -+ packet_id_queue_init(&dev->already_in_flight, dev, "already-in-flight"); - for (i = 0; i < MAX_ENDPOINTS; i++) { - QTAILQ_INIT(&dev->endpoint[i].bufpq); - } -@@ -1007,6 +1049,7 @@ static void usbredir_cleanup_device_queues(USBRedirDevice *dev) - int i; - - packet_id_queue_empty(&dev->cancelled); -+ packet_id_queue_empty(&dev->already_in_flight); - for (i = 0; i < MAX_ENDPOINTS; i++) { - usbredir_free_bufpq(dev, I2EP(i)); - } --- -1.7.12 - diff --git a/0364-usb-redir-Store-max_packet_size-in-endp_data.patch b/0364-usb-redir-Store-max_packet_size-in-endp_data.patch deleted file mode 100644 index 16f05d3..0000000 --- a/0364-usb-redir-Store-max_packet_size-in-endp_data.patch +++ /dev/null @@ -1,38 +0,0 @@ -From c9917c910cf59e2407bbf51770724c5ec17d9cd1 Mon Sep 17 00:00:00 2001 -From: Hans de Goede -Date: Thu, 6 Sep 2012 20:52:36 +0200 -Subject: [PATCH 363/365] usb-redir: Store max_packet_size in endp_data - -So that we've a place to migrate it to / from to allow restoring it after -migration. - -Signed-off-by: Hans de Goede ---- - hw/usb/redirect.c | 4 +++- - 1 file changed, 3 insertions(+), 1 deletion(-) - -diff --git a/hw/usb/redirect.c b/hw/usb/redirect.c -index 1c8edd3..d8568ae 100644 ---- a/hw/usb/redirect.c -+++ b/hw/usb/redirect.c -@@ -57,6 +57,7 @@ struct endp_data { - uint8_t type; - uint8_t interval; - uint8_t interface; /* bInterfaceNumber this ep belongs to */ -+ uint16_t max_packet_size; /* In bytes, not wMaxPacketSize format !! */ - uint8_t iso_started; - uint8_t iso_error; /* For reporting iso errors to the HC */ - uint8_t interrupt_started; -@@ -1305,7 +1306,8 @@ static void usbredir_ep_info(void *priv, - usb_ep->ifnum = dev->endpoint[i].interface; - if (usbredirparser_peer_has_cap(dev->parser, - usb_redir_cap_ep_info_max_packet_size)) { -- usb_ep->max_packet_size = ep_info->max_packet_size[i]; -+ dev->endpoint[i].max_packet_size = -+ usb_ep->max_packet_size = ep_info->max_packet_size[i]; - } - if (ep_info->type[i] == usb_redir_type_bulk) { - usb_ep->pipeline = true; --- -1.7.12 - diff --git a/0365-usb-redir-Add-support-for-migration.patch b/0365-usb-redir-Add-support-for-migration.patch deleted file mode 100644 index bcbbaab..0000000 --- a/0365-usb-redir-Add-support-for-migration.patch +++ /dev/null @@ -1,429 +0,0 @@ -From 0d733a1280bdaba402c6efbfae116408d7c81bb0 Mon Sep 17 00:00:00 2001 -From: Hans de Goede -Date: Wed, 5 Sep 2012 09:21:44 +0200 -Subject: [PATCH 364/365] usb-redir: Add support for migration - -Signed-off-by: Hans de Goede ---- - hw/usb/redirect.c | 349 +++++++++++++++++++++++++++++++++++++++++++++++++++++- - 1 file changed, 346 insertions(+), 3 deletions(-) - -diff --git a/hw/usb/redirect.c b/hw/usb/redirect.c -index d8568ae..812096e 100644 ---- a/hw/usb/redirect.c -+++ b/hw/usb/redirect.c -@@ -65,8 +65,8 @@ struct endp_data { - uint8_t bufpq_prefilled; - uint8_t bufpq_dropping_packets; - QTAILQ_HEAD(, buf_packet) bufpq; -- int bufpq_size; -- int bufpq_target_size; -+ int32_t bufpq_size; -+ int32_t bufpq_target_size; - }; - - struct PacketIdQueueEntry { -@@ -241,6 +241,11 @@ static int usbredir_write(void *priv, uint8_t *data, int count) - return 0; - } - -+ /* Don't send new data to the chardev until our state is fully synced */ -+ if (!runstate_check(RUN_STATE_RUNNING)) { -+ return 0; -+ } -+ - r = qemu_chr_fe_write(dev->cs, data, count); - - if (r < 0) { -@@ -868,6 +873,7 @@ static void usbredir_chardev_open(USBRedirDevice *dev) - { - uint32_t caps[USB_REDIR_CAPS_SIZE] = { 0, }; - char version[32]; -+ int flags = 0; - - /* Make sure any pending closes are handled (no-op if none pending) */ - usbredir_chardev_close_bh(dev); -@@ -903,7 +909,12 @@ static void usbredir_chardev_open(USBRedirDevice *dev) - usbredirparser_caps_set_cap(caps, usb_redir_cap_filter); - usbredirparser_caps_set_cap(caps, usb_redir_cap_ep_info_max_packet_size); - usbredirparser_caps_set_cap(caps, usb_redir_cap_64bits_ids); -- usbredirparser_init(dev->parser, version, caps, USB_REDIR_CAPS_SIZE, 0); -+ -+ if (runstate_check(RUN_STATE_INMIGRATE)) { -+ flags |= usbredirparser_fl_no_hello; -+ } -+ usbredirparser_init(dev->parser, version, caps, USB_REDIR_CAPS_SIZE, -+ flags); - usbredirparser_do_write(dev->parser); - } - -@@ -949,6 +960,11 @@ static int usbredir_chardev_can_read(void *opaque) - return 0; - } - -+ /* Don't read new data from the chardev until our state is fully synced */ -+ if (!runstate_check(RUN_STATE_RUNNING)) { -+ return 0; -+ } -+ - /* usbredir_parser_do_read will consume *all* data we give it */ - return 1024 * 1024; - } -@@ -1004,6 +1020,15 @@ static const QemuChrHandlers usbredir_chr_handlers = { - * init + destroy - */ - -+static void usbredir_vm_state_change(void *priv, int running, RunState state) -+{ -+ USBRedirDevice *dev = priv; -+ -+ if (state == RUN_STATE_RUNNING && dev->parser != NULL) { -+ usbredirparser_do_write(dev->parser); /* Flush any pending writes */ -+ } -+} -+ - static int usbredir_initfn(USBDevice *udev) - { - USBRedirDevice *dev = DO_UPCAST(USBRedirDevice, dev, udev); -@@ -1041,6 +1066,7 @@ static int usbredir_initfn(USBDevice *udev) - qemu_chr_fe_open(dev->cs); - qemu_chr_add_handlers(dev->cs, &usbredir_chr_handlers, dev); - -+ qemu_add_vm_change_state_handler(usbredir_vm_state_change, dev); - add_boot_device_path(dev->bootindex, &udev->qdev, NULL); - return 0; - } -@@ -1530,6 +1556,322 @@ static void usbredir_interrupt_packet(void *priv, uint64_t id, - } - } - -+/* -+ * Migration code -+ */ -+ -+static void usbredir_pre_save(void *priv) -+{ -+ USBRedirDevice *dev = priv; -+ -+ usbredir_fill_already_in_flight(dev); -+} -+ -+static int usbredir_post_load(void *priv, int version_id) -+{ -+ USBRedirDevice *dev = priv; -+ struct USBEndpoint *usb_ep; -+ int i; -+ -+ switch (dev->device_info.speed) { -+ case usb_redir_speed_low: -+ dev->dev.speed = USB_SPEED_LOW; -+ break; -+ case usb_redir_speed_full: -+ dev->dev.speed = USB_SPEED_FULL; -+ break; -+ case usb_redir_speed_high: -+ dev->dev.speed = USB_SPEED_HIGH; -+ break; -+ case usb_redir_speed_super: -+ dev->dev.speed = USB_SPEED_SUPER; -+ break; -+ default: -+ dev->dev.speed = USB_SPEED_FULL; -+ } -+ dev->dev.speedmask = (1 << dev->dev.speed); -+ -+ for (i = 0; i < MAX_ENDPOINTS; i++) { -+ usb_ep = usb_ep_get(&dev->dev, -+ (i & 0x10) ? USB_TOKEN_IN : USB_TOKEN_OUT, -+ i & 0x0f); -+ usb_ep->type = dev->endpoint[i].type; -+ usb_ep->ifnum = dev->endpoint[i].interface; -+ usb_ep->max_packet_size = dev->endpoint[i].max_packet_size; -+ if (dev->endpoint[i].type == usb_redir_type_bulk) { -+ usb_ep->pipeline = true; -+ } -+ } -+ return 0; -+} -+ -+/* For usbredirparser migration */ -+static void usbredir_put_parser(QEMUFile *f, void *priv, size_t unused) -+{ -+ USBRedirDevice *dev = priv; -+ uint8_t *data; -+ int len; -+ -+ if (dev->parser == NULL) { -+ qemu_put_be32(f, 0); -+ return; -+ } -+ -+ usbredirparser_serialize(dev->parser, &data, &len); -+ qemu_oom_check(data); -+ -+ qemu_put_be32(f, len); -+ qemu_put_buffer(f, data, len); -+ -+ free(data); -+} -+ -+static int usbredir_get_parser(QEMUFile *f, void *priv, size_t unused) -+{ -+ USBRedirDevice *dev = priv; -+ uint8_t *data; -+ int len, ret; -+ -+ len = qemu_get_be32(f); -+ if (len == 0) { -+ return 0; -+ } -+ -+ /* -+ * Our chardev should be open already at this point, otherwise -+ * the usbredir channel will be broken (ie spice without seamless) -+ */ -+ if (dev->parser == NULL) { -+ ERROR("get_parser called with closed chardev, failing migration\n"); -+ return -1; -+ } -+ -+ data = g_malloc(len); -+ qemu_get_buffer(f, data, len); -+ -+ ret = usbredirparser_unserialize(dev->parser, data, len); -+ -+ g_free(data); -+ -+ return ret; -+} -+ -+static const VMStateInfo usbredir_parser_vmstate_info = { -+ .name = "usb-redir-parser", -+ .put = usbredir_put_parser, -+ .get = usbredir_get_parser, -+}; -+ -+ -+/* For buffered packets (iso/irq) queue migration */ -+static void usbredir_put_bufpq(QEMUFile *f, void *priv, size_t unused) -+{ -+ struct endp_data *endp = priv; -+ struct buf_packet *bufp; -+ int remain = endp->bufpq_size; -+ -+ qemu_put_be32(f, endp->bufpq_size); -+ QTAILQ_FOREACH(bufp, &endp->bufpq, next) { -+ qemu_put_be32(f, bufp->len); -+ qemu_put_be32(f, bufp->status); -+ qemu_put_buffer(f, bufp->data, bufp->len); -+ remain--; -+ } -+ assert(remain == 0); -+} -+ -+static int usbredir_get_bufpq(QEMUFile *f, void *priv, size_t unused) -+{ -+ struct endp_data *endp = priv; -+ struct buf_packet *bufp; -+ int i; -+ -+ endp->bufpq_size = qemu_get_be32(f); -+ for (i = 0; i < endp->bufpq_size; i++) { -+ bufp = g_malloc(sizeof(struct buf_packet)); -+ bufp->len = qemu_get_be32(f); -+ bufp->status = qemu_get_be32(f); -+ bufp->data = qemu_oom_check(malloc(bufp->len)); /* regular malloc! */ -+ qemu_get_buffer(f, bufp->data, bufp->len); -+ QTAILQ_INSERT_TAIL(&endp->bufpq, bufp, next); -+ } -+ return 0; -+} -+ -+static const VMStateInfo usbredir_ep_bufpq_vmstate_info = { -+ .name = "usb-redir-bufpq", -+ .put = usbredir_put_bufpq, -+ .get = usbredir_get_bufpq, -+}; -+ -+ -+/* For endp_data migration */ -+static const VMStateDescription usbredir_ep_vmstate = { -+ .name = "usb-redir-ep", -+ .version_id = 1, -+ .minimum_version_id = 1, -+ .fields = (VMStateField []) { -+ VMSTATE_UINT8(type, struct endp_data), -+ VMSTATE_UINT8(interval, struct endp_data), -+ VMSTATE_UINT8(interface, struct endp_data), -+ VMSTATE_UINT16(max_packet_size, struct endp_data), -+ VMSTATE_UINT8(iso_started, struct endp_data), -+ VMSTATE_UINT8(iso_error, struct endp_data), -+ VMSTATE_UINT8(interrupt_started, struct endp_data), -+ VMSTATE_UINT8(interrupt_error, struct endp_data), -+ VMSTATE_UINT8(bufpq_prefilled, struct endp_data), -+ VMSTATE_UINT8(bufpq_dropping_packets, struct endp_data), -+ { -+ .name = "bufpq", -+ .version_id = 0, -+ .field_exists = NULL, -+ .size = 0, -+ .info = &usbredir_ep_bufpq_vmstate_info, -+ .flags = VMS_SINGLE, -+ .offset = 0, -+ }, -+ VMSTATE_INT32(bufpq_target_size, struct endp_data), -+ VMSTATE_END_OF_LIST() -+ } -+}; -+ -+ -+/* For PacketIdQueue migration */ -+static void usbredir_put_packet_id_q(QEMUFile *f, void *priv, size_t unused) -+{ -+ struct PacketIdQueue *q = priv; -+ USBRedirDevice *dev = q->dev; -+ struct PacketIdQueueEntry *e; -+ int remain = q->size; -+ -+ DPRINTF("put_packet_id_q %s size %d\n", q->name, q->size); -+ qemu_put_be32(f, q->size); -+ QTAILQ_FOREACH(e, &q->head, next) { -+ qemu_put_be64(f, e->id); -+ remain--; -+ } -+ assert(remain == 0); -+} -+ -+static int usbredir_get_packet_id_q(QEMUFile *f, void *priv, size_t unused) -+{ -+ struct PacketIdQueue *q = priv; -+ USBRedirDevice *dev = q->dev; -+ int i, size; -+ uint64_t id; -+ -+ size = qemu_get_be32(f); -+ DPRINTF("get_packet_id_q %s size %d\n", q->name, size); -+ for (i = 0; i < size; i++) { -+ id = qemu_get_be64(f); -+ packet_id_queue_add(q, id); -+ } -+ assert(q->size == size); -+ return 0; -+} -+ -+static const VMStateInfo usbredir_ep_packet_id_q_vmstate_info = { -+ .name = "usb-redir-packet-id-q", -+ .put = usbredir_put_packet_id_q, -+ .get = usbredir_get_packet_id_q, -+}; -+ -+static const VMStateDescription usbredir_ep_packet_id_queue_vmstate = { -+ .name = "usb-redir-packet-id-queue", -+ .version_id = 1, -+ .minimum_version_id = 1, -+ .fields = (VMStateField []) { -+ { -+ .name = "queue", -+ .version_id = 0, -+ .field_exists = NULL, -+ .size = 0, -+ .info = &usbredir_ep_packet_id_q_vmstate_info, -+ .flags = VMS_SINGLE, -+ .offset = 0, -+ }, -+ VMSTATE_END_OF_LIST() -+ } -+}; -+ -+ -+/* For usb_redir_device_connect_header migration */ -+static const VMStateDescription usbredir_device_info_vmstate = { -+ .name = "usb-redir-device-info", -+ .version_id = 1, -+ .minimum_version_id = 1, -+ .fields = (VMStateField []) { -+ VMSTATE_UINT8(speed, struct usb_redir_device_connect_header), -+ VMSTATE_UINT8(device_class, struct usb_redir_device_connect_header), -+ VMSTATE_UINT8(device_subclass, struct usb_redir_device_connect_header), -+ VMSTATE_UINT8(device_protocol, struct usb_redir_device_connect_header), -+ VMSTATE_UINT16(vendor_id, struct usb_redir_device_connect_header), -+ VMSTATE_UINT16(product_id, struct usb_redir_device_connect_header), -+ VMSTATE_UINT16(device_version_bcd, -+ struct usb_redir_device_connect_header), -+ VMSTATE_END_OF_LIST() -+ } -+}; -+ -+ -+/* For usb_redir_interface_info_header migration */ -+static const VMStateDescription usbredir_interface_info_vmstate = { -+ .name = "usb-redir-interface-info", -+ .version_id = 1, -+ .minimum_version_id = 1, -+ .fields = (VMStateField []) { -+ VMSTATE_UINT32(interface_count, -+ struct usb_redir_interface_info_header), -+ VMSTATE_UINT8_ARRAY(interface, -+ struct usb_redir_interface_info_header, 32), -+ VMSTATE_UINT8_ARRAY(interface_class, -+ struct usb_redir_interface_info_header, 32), -+ VMSTATE_UINT8_ARRAY(interface_subclass, -+ struct usb_redir_interface_info_header, 32), -+ VMSTATE_UINT8_ARRAY(interface_protocol, -+ struct usb_redir_interface_info_header, 32), -+ VMSTATE_END_OF_LIST() -+ } -+}; -+ -+ -+/* And finally the USBRedirDevice vmstate itself */ -+static const VMStateDescription usbredir_vmstate = { -+ .name = "usb-redir", -+ .version_id = 1, -+ .minimum_version_id = 1, -+ .pre_save = usbredir_pre_save, -+ .post_load = usbredir_post_load, -+ .fields = (VMStateField []) { -+ VMSTATE_USB_DEVICE(dev, USBRedirDevice), -+ VMSTATE_TIMER(attach_timer, USBRedirDevice), -+ { -+ .name = "parser", -+ .version_id = 0, -+ .field_exists = NULL, -+ .size = 0, -+ .info = &usbredir_parser_vmstate_info, -+ .flags = VMS_SINGLE, -+ .offset = 0, -+ }, -+ VMSTATE_STRUCT_ARRAY(endpoint, USBRedirDevice, MAX_ENDPOINTS, 1, -+ usbredir_ep_vmstate, struct endp_data), -+ VMSTATE_STRUCT(cancelled, USBRedirDevice, 1, -+ usbredir_ep_packet_id_queue_vmstate, -+ struct PacketIdQueue), -+ VMSTATE_STRUCT(already_in_flight, USBRedirDevice, 1, -+ usbredir_ep_packet_id_queue_vmstate, -+ struct PacketIdQueue), -+ VMSTATE_STRUCT(device_info, USBRedirDevice, 1, -+ usbredir_device_info_vmstate, -+ struct usb_redir_device_connect_header), -+ VMSTATE_STRUCT(interface_info, USBRedirDevice, 1, -+ usbredir_interface_info_vmstate, -+ struct usb_redir_interface_info_header), -+ VMSTATE_END_OF_LIST() -+ } -+}; -+ - static Property usbredir_properties[] = { - DEFINE_PROP_CHR("chardev", USBRedirDevice, cs), - DEFINE_PROP_UINT8("debug", USBRedirDevice, debug, 0), -@@ -1550,6 +1892,7 @@ static void usbredir_class_initfn(ObjectClass *klass, void *data) - uc->handle_reset = usbredir_handle_reset; - uc->handle_data = usbredir_handle_data; - uc->handle_control = usbredir_handle_control; -+ dc->vmsd = &usbredir_vmstate; - dc->props = usbredir_properties; - } - --- -1.7.12 - diff --git a/0366-usb-redir-Add-chardev-open-close-debug-logging.patch b/0366-usb-redir-Add-chardev-open-close-debug-logging.patch deleted file mode 100644 index 4e2f75d..0000000 --- a/0366-usb-redir-Add-chardev-open-close-debug-logging.patch +++ /dev/null @@ -1,54 +0,0 @@ -From 3efd9345ea643cf6f15776425213a92a442dd217 Mon Sep 17 00:00:00 2001 -From: Hans de Goede -Date: Wed, 5 Sep 2012 15:56:57 +0200 -Subject: [PATCH 365/365] usb-redir: Add chardev open / close debug logging - -Signed-off-by: Hans de Goede ---- - hw/usb/redirect.c | 6 ++++++ - 1 file changed, 6 insertions(+) - -diff --git a/hw/usb/redirect.c b/hw/usb/redirect.c -index 812096e..b03c412 100644 ---- a/hw/usb/redirect.c -+++ b/hw/usb/redirect.c -@@ -864,6 +864,7 @@ static void usbredir_chardev_close_bh(void *opaque) - usbredir_device_disconnect(dev); - - if (dev->parser) { -+ DPRINTF("destroying usbredirparser\n"); - usbredirparser_destroy(dev->parser); - dev->parser = NULL; - } -@@ -879,6 +880,8 @@ static void usbredir_chardev_open(USBRedirDevice *dev) - usbredir_chardev_close_bh(dev); - qemu_bh_cancel(dev->chardev_close_bh); - -+ DPRINTF("creating usbredirparser\n"); -+ - strcpy(version, "qemu usb-redir guest "); - pstrcat(version, sizeof(version), qemu_get_version()); - -@@ -990,9 +993,11 @@ static void usbredir_chardev_event(void *opaque, int event) - - switch (event) { - case CHR_EVENT_OPENED: -+ DPRINTF("chardev open\n"); - usbredir_chardev_open(dev); - break; - case CHR_EVENT_CLOSED: -+ DPRINTF("chardev close\n"); - qemu_bh_schedule(dev->chardev_close_bh); - break; - } -@@ -1255,6 +1260,7 @@ static void usbredir_device_disconnect(void *priv) - qemu_del_timer(dev->attach_timer); - - if (dev->dev.attached) { -+ DPRINTF("detaching device\n"); - usb_device_detach(&dev->dev); - /* - * Delay next usb device attach to give the guest a chance to see --- -1.7.12 - diff --git a/0367-usb-redir-Revert-usb-redir-part-of-commit-93bfef4c.patch b/0367-usb-redir-Revert-usb-redir-part-of-commit-93bfef4c.patch deleted file mode 100644 index 8a1b518..0000000 --- a/0367-usb-redir-Revert-usb-redir-part-of-commit-93bfef4c.patch +++ /dev/null @@ -1,63 +0,0 @@ -From 786657ed32cb68ae5cd4d099e6ea3f36290bcbcb Mon Sep 17 00:00:00 2001 -From: Hans de Goede -Date: Mon, 10 Sep 2012 13:49:46 +0200 -Subject: [PATCH 367/369] usb-redir: Revert usb-redir part of commit 93bfef4c - -Commit 93bfef4c6e4b23caea9d51e1099d06433d8835a4 makes qemu-devices -which report the qemu version string to the guest in some way use a -qemu_get_version function which reports a machine-specific version string. - -However usb-redir does not expose the qemu version to the guest, only to -the usbredir-host as part of the initial handshake. This can then be logged -on the usbredir-host side for debugging purposes and is otherwise completely -unused! For debugging purposes it is important to have the real qemu version -in there, rather then the machine-specific version. - -Signed-off-by: Hans de Goede ---- - hw/usb/redirect.c | 8 +++----- - 1 file changed, 3 insertions(+), 5 deletions(-) - -diff --git a/hw/usb/redirect.c b/hw/usb/redirect.c -index 86c0398..78e93a7 100644 ---- a/hw/usb/redirect.c -+++ b/hw/usb/redirect.c -@@ -142,6 +142,8 @@ static void usbredir_interrupt_packet(void *priv, uint64_t id, - static int usbredir_handle_status(USBRedirDevice *dev, - int status, int actual_len); - -+#define VERSION "qemu usb-redir guest " QEMU_VERSION -+ - /* - * Logging stuff - */ -@@ -873,7 +875,6 @@ static void usbredir_chardev_close_bh(void *opaque) - static void usbredir_chardev_open(USBRedirDevice *dev) - { - uint32_t caps[USB_REDIR_CAPS_SIZE] = { 0, }; -- char version[32]; - int flags = 0; - - /* Make sure any pending closes are handled (no-op if none pending) */ -@@ -882,9 +883,6 @@ static void usbredir_chardev_open(USBRedirDevice *dev) - - DPRINTF("creating usbredirparser\n"); - -- strcpy(version, "qemu usb-redir guest "); -- pstrcat(version, sizeof(version), qemu_get_version()); -- - dev->parser = qemu_oom_check(usbredirparser_create()); - dev->parser->priv = dev; - dev->parser->log_func = usbredir_log; -@@ -916,7 +914,7 @@ static void usbredir_chardev_open(USBRedirDevice *dev) - if (runstate_check(RUN_STATE_INMIGRATE)) { - flags |= usbredirparser_fl_no_hello; - } -- usbredirparser_init(dev->parser, version, caps, USB_REDIR_CAPS_SIZE, -+ usbredirparser_init(dev->parser, VERSION, caps, USB_REDIR_CAPS_SIZE, - flags); - usbredirparser_do_write(dev->parser); - } --- -1.7.12 - diff --git a/0368-uhci-Don-t-queue-up-packets-after-one-with-the-SPD-f.patch b/0368-uhci-Don-t-queue-up-packets-after-one-with-the-SPD-f.patch deleted file mode 100644 index af350d9..0000000 --- a/0368-uhci-Don-t-queue-up-packets-after-one-with-the-SPD-f.patch +++ /dev/null @@ -1,44 +0,0 @@ -From 41f5d67c0649d74b505edc2a874c91148355eb25 Mon Sep 17 00:00:00 2001 -From: Hans de Goede -Date: Wed, 12 Sep 2012 13:30:51 +0200 -Subject: [PATCH 368/369] uhci: Don't queue up packets after one with the SPD - flag set - -Don't queue up packets after a packet with the SPD (short packet detect) -flag set. Since we won't know if the packet will actually be short until it -has completed, and if it is short we should stop the queue. - -This fixes a miniature photoframe emulating a USB cdrom with the windows -software for it not working. - -Signed-off-by: Hans de Goede ---- - hw/usb/hcd-uhci.c | 5 ++++- - 1 file changed, 4 insertions(+), 1 deletion(-) - -diff --git a/hw/usb/hcd-uhci.c b/hw/usb/hcd-uhci.c -index c7c8786..cdc8bc3 100644 ---- a/hw/usb/hcd-uhci.c -+++ b/hw/usb/hcd-uhci.c -@@ -1000,6 +1000,9 @@ static void uhci_fill_queue(UHCIState *s, UHCI_TD *td) - } - assert(ret == TD_RESULT_ASYNC_START); - assert(int_mask == 0); -+ if (ptd.ctrl & TD_CTRL_SPD) { -+ break; -+ } - plink = ptd.link; - } - } -@@ -1097,7 +1100,7 @@ static void uhci_process_frame(UHCIState *s) - - case TD_RESULT_ASYNC_START: - trace_usb_uhci_td_async(curr_qh & ~0xf, link & ~0xf); -- if (is_valid(td.link)) { -+ if (is_valid(td.link) && !(td.ctrl & TD_CTRL_SPD)) { - uhci_fill_queue(s, &td); - } - link = curr_qh ? qh.link : td.link; --- -1.7.12 - diff --git a/0369-ehci-Fix-interrupt-packet-MULT-handling.patch b/0369-ehci-Fix-interrupt-packet-MULT-handling.patch deleted file mode 100644 index 3105ad9..0000000 --- a/0369-ehci-Fix-interrupt-packet-MULT-handling.patch +++ /dev/null @@ -1,131 +0,0 @@ -From 074e4dddddec4456026e211163e0d8d5c9bfaf0c Mon Sep 17 00:00:00 2001 -From: Hans de Goede -Date: Thu, 20 Sep 2012 16:55:02 +0200 -Subject: [PATCH 369/369] ehci: Fix interrupt packet MULT handling - -There are several issues with our handling of the MULT epcap field -of interrupt qhs, which this patch fixes. - -1) When we don't execute a transaction because of the transaction counter -being 0, p->async stays EHCI_ASYNC_NONE, and the next time we process the -same qtd we hit an assert in ehci_state_fetchqtd because of this. Even though -I believe that this is caused by 3 below, this patch still removes the assert, -as that can still happen without 3, when multiple packets are queued for the -same interrupt ep. - -2) We only *check* the transaction counter from ehci_state_execute, any -packets queued up by fill_queue bypass this check. This is fixed by not calling -fill_queue for interrupt packets. - -3) Some versions of Windows set the MULT field of the qh to 0, which is a -clear violation of the EHCI spec, but still they do it. This means that we -will never execute a qtd for these, making interrupt ep-s on USB-2 devices -not work, and after recent changes, triggering 1). - -So far we've stored the transaction counter in our copy of the mult field, -but with this beginnig at 0 already when dealing with these version of windows -this won't work. So this patch adds a transact_ctr field to our qh struct, -and sets this to the MULT field value on fetchqh. When the MULT field value -is 0, we set it to 4. Assuming that windows gets way with setting it to 0, -by the actual hardware going horizontal on a 1 -> 0 transition, which will -give it 4 transactions (MULT goes from 0 - 3). - -Note that we cannot stop on detecting the 1 -> 0 transition, as our decrement -of the transaction counter, and checking for it are done in 2 different places. - -Reported-by: Shawn Starr -Signed-off-by: Hans de Goede ---- - hw/usb/hcd-ehci.c | 39 +++++++++++++++++++-------------------- - 1 file changed, 19 insertions(+), 20 deletions(-) - -diff --git a/hw/usb/hcd-ehci.c b/hw/usb/hcd-ehci.c -index 48a1b09..3acd881a 100644 ---- a/hw/usb/hcd-ehci.c -+++ b/hw/usb/hcd-ehci.c -@@ -373,6 +373,7 @@ struct EHCIQueue { - uint32_t seen; - uint64_t ts; - int async; -+ int transact_ctr; - - /* cached data from guest - needs to be flushed - * when guest removes an entry (doorbell, handshake sequence) -@@ -1837,6 +1838,10 @@ static EHCIQueue *ehci_state_fetchqh(EHCIState *ehci, int async) - } - q->qh = qh; - -+ q->transact_ctr = get_field(q->qh.epcap, QH_EPCAP_MULT); -+ if (q->transact_ctr == 0) /* Guest bug in some versions of windows */ -+ q->transact_ctr = 4; -+ - if (q->dev == NULL) { - q->dev = ehci_find_device(q->ehci, devaddr); - } -@@ -2014,11 +2019,8 @@ static int ehci_state_fetchqtd(EHCIQueue *q) - } else if (p != NULL) { - switch (p->async) { - case EHCI_ASYNC_NONE: -- /* Should never happen packet should at least be initialized */ -- assert(0); -- break; - case EHCI_ASYNC_INITIALIZED: -- /* Previously nacked packet (likely interrupt ep) */ -+ /* Not yet executed (MULT), or previously nacked (int) packet */ - ehci_set_state(q->ehci, q->async, EST_EXECUTE); - break; - case EHCI_ASYNC_INFLIGHT: -@@ -2107,15 +2109,12 @@ static int ehci_state_execute(EHCIQueue *q) - - // TODO verify enough time remains in the uframe as in 4.4.1.1 - // TODO write back ptr to async list when done or out of time -- // TODO Windows does not seem to ever set the MULT field - -- if (!q->async) { -- int transactCtr = get_field(q->qh.epcap, QH_EPCAP_MULT); -- if (!transactCtr) { -- ehci_set_state(q->ehci, q->async, EST_HORIZONTALQH); -- again = 1; -- goto out; -- } -+ /* 4.10.3, bottom of page 82, go horizontal on transaction counter == 0 */ -+ if (!q->async && q->transact_ctr == 0) { -+ ehci_set_state(q->ehci, q->async, EST_HORIZONTALQH); -+ again = 1; -+ goto out; - } - - if (q->async) { -@@ -2132,7 +2131,11 @@ static int ehci_state_execute(EHCIQueue *q) - trace_usb_ehci_packet_action(p->queue, p, "async"); - p->async = EHCI_ASYNC_INFLIGHT; - ehci_set_state(q->ehci, q->async, EST_HORIZONTALQH); -- again = (ehci_fill_queue(p) == USB_RET_PROCERR) ? -1 : 1; -+ if (q->async) { -+ again = (ehci_fill_queue(p) == USB_RET_PROCERR) ? -1 : 1; -+ } else { -+ again = 1; -+ } - goto out; - } - -@@ -2152,13 +2155,9 @@ static int ehci_state_executing(EHCIQueue *q) - - ehci_execute_complete(q); - -- // 4.10.3 -- if (!q->async) { -- int transactCtr = get_field(q->qh.epcap, QH_EPCAP_MULT); -- transactCtr--; -- set_field(&q->qh.epcap, transactCtr, QH_EPCAP_MULT); -- // 4.10.3, bottom of page 82, should exit this state when transaction -- // counter decrements to 0 -+ /* 4.10.3 */ -+ if (!q->async && q->transact_ctr > 0) { -+ q->transact_ctr--; - } - - /* 4.10.5 */ --- -1.7.12 - diff --git a/0370-usb-redir-Adjust-pkg-config-check-for-usbredirparser.patch b/0370-usb-redir-Adjust-pkg-config-check-for-usbredirparser.patch deleted file mode 100644 index f38d08e..0000000 --- a/0370-usb-redir-Adjust-pkg-config-check-for-usbredirparser.patch +++ /dev/null @@ -1,49 +0,0 @@ -From a873076925e599afe3852f87546e479f23c279ba Mon Sep 17 00:00:00 2001 -From: Hans de Goede -Date: Tue, 25 Sep 2012 13:22:21 +0200 -Subject: [PATCH 370/382] usb-redir: Adjust pkg-config check for - usbredirparser .pc file rename (v2) - -The usbredir 0.5 release introduced the new API for 64 bit packet ids, but -it kept the libusbredirparser.pc name as is, meaning that older versions of -qemu will still have their pkg-config check for usbredirparser fulfilled, -and build with the usb-redir device. Due to the API change there will be -some compiler warnings, but the build will succeed, however the usb-redir -device will be broken on 32 bit machines. - -To solve this a new usbredir-0.5.2 release is coming, which renames the -libusbredirparser.pc file to libusbredirparser-0.5.pc, so that it will no -longer fulfill the pkg-config check of the qemu-1.2 and older releases, -stopping the (silent) breakage. This patch adjusts qemu master's configure -to properly detect the new usbredir release. - -Changes in v2: --Not only use the new .pc name in the check but also when getting cflags - and libs! - -Signed-off-by: Hans de Goede ---- - configure | 6 +++--- - 1 file changed, 3 insertions(+), 3 deletions(-) - -diff --git a/configure b/configure -index d63530a..6c8b8c9 100755 ---- a/configure -+++ b/configure -@@ -2765,10 +2765,10 @@ fi - - # check for usbredirparser for usb network redirection support - if test "$usb_redir" != "no" ; then -- if $pkg_config --atleast-version=0.5 libusbredirparser >/dev/null 2>&1 ; then -+ if $pkg_config --atleast-version=0.5 libusbredirparser-0.5 >/dev/null 2>&1 ; then - usb_redir="yes" -- usb_redir_cflags=$($pkg_config --cflags libusbredirparser 2>/dev/null) -- usb_redir_libs=$($pkg_config --libs libusbredirparser 2>/dev/null) -+ usb_redir_cflags=$($pkg_config --cflags libusbredirparser-0.5 2>/dev/null) -+ usb_redir_libs=$($pkg_config --libs libusbredirparser-0.5 2>/dev/null) - QEMU_CFLAGS="$QEMU_CFLAGS $usb_redir_cflags" - libs_softmmu="$libs_softmmu $usb_redir_libs" - else --- -1.7.12 - diff --git a/0371-usb-redir-Change-usbredir_open_chardev-into-usbredir.patch b/0371-usb-redir-Change-usbredir_open_chardev-into-usbredir.patch deleted file mode 100644 index 2d7b66c..0000000 --- a/0371-usb-redir-Change-usbredir_open_chardev-into-usbredir.patch +++ /dev/null @@ -1,49 +0,0 @@ -From 0ef8cdced724a03efea3523410ffd51cf1ec308d Mon Sep 17 00:00:00 2001 -From: Hans de Goede -Date: Thu, 27 Sep 2012 16:59:50 +0200 -Subject: [PATCH 371/372] usb-redir: Change usbredir_open_chardev into - usbredir_create_parser - -As we need to create the parser at more places. - -Signed-off-by: Hans de Goede ---- - hw/usb/redirect.c | 11 +++++------ - 1 file changed, 5 insertions(+), 6 deletions(-) - -diff --git a/hw/usb/redirect.c b/hw/usb/redirect.c -index 78e93a7..5d16aff 100644 ---- a/hw/usb/redirect.c -+++ b/hw/usb/redirect.c -@@ -872,15 +872,11 @@ static void usbredir_chardev_close_bh(void *opaque) - } - } - --static void usbredir_chardev_open(USBRedirDevice *dev) -+static void usbredir_create_parser(USBRedirDevice *dev) - { - uint32_t caps[USB_REDIR_CAPS_SIZE] = { 0, }; - int flags = 0; - -- /* Make sure any pending closes are handled (no-op if none pending) */ -- usbredir_chardev_close_bh(dev); -- qemu_bh_cancel(dev->chardev_close_bh); -- - DPRINTF("creating usbredirparser\n"); - - dev->parser = qemu_oom_check(usbredirparser_create()); -@@ -992,7 +988,10 @@ static void usbredir_chardev_event(void *opaque, int event) - switch (event) { - case CHR_EVENT_OPENED: - DPRINTF("chardev open\n"); -- usbredir_chardev_open(dev); -+ /* Make sure any pending closes are handled (no-op if none pending) */ -+ usbredir_chardev_close_bh(dev); -+ qemu_bh_cancel(dev->chardev_close_bh); -+ usbredir_create_parser(dev); - break; - case CHR_EVENT_CLOSED: - DPRINTF("chardev close\n"); --- -1.7.12 - diff --git a/0372-usb-redir-Don-t-make-migration-fail-in-none-seamless.patch b/0372-usb-redir-Don-t-make-migration-fail-in-none-seamless.patch deleted file mode 100644 index 109a3f3..0000000 --- a/0372-usb-redir-Don-t-make-migration-fail-in-none-seamless.patch +++ /dev/null @@ -1,43 +0,0 @@ -From adbc805b1f775ef8565bf8d074b45813daa2e779 Mon Sep 17 00:00:00 2001 -From: Hans de Goede -Date: Thu, 27 Sep 2012 16:57:41 +0200 -Subject: [PATCH 372/372] usb-redir: Don't make migration fail in none - seamless case - -Instead simple disconnect the device like host redirection does on -migration. - -Signed-off-by: Hans de Goede ---- - hw/usb/redirect.c | 13 +++++++++---- - 1 file changed, 9 insertions(+), 4 deletions(-) - -diff --git a/hw/usb/redirect.c b/hw/usb/redirect.c -index 5d16aff..022ba42 100644 ---- a/hw/usb/redirect.c -+++ b/hw/usb/redirect.c -@@ -1637,12 +1637,17 @@ static int usbredir_get_parser(QEMUFile *f, void *priv, size_t unused) - } - - /* -- * Our chardev should be open already at this point, otherwise -- * the usbredir channel will be broken (ie spice without seamless) -+ * If our chardev is not open already at this point the usbredir connection -+ * has been broken (non seamless migration, or restore from disk). -+ * -+ * In this case create a temporary parser to receive the migration data, -+ * and schedule the close_bh to report the device as disconnected to the -+ * guest and to destroy the parser again. - */ - if (dev->parser == NULL) { -- ERROR("get_parser called with closed chardev, failing migration\n"); -- return -1; -+ WARNING("usb-redir connection broken during migration\n"); -+ usbredir_create_parser(dev); -+ qemu_bh_schedule(dev->chardev_close_bh); - } - - data = g_malloc(len); --- -1.7.12 - diff --git a/0400-char-Split-out-tcp-socket-close-code-in-a-separate-f.patch b/0400-char-Split-out-tcp-socket-close-code-in-a-separate-f.patch new file mode 100644 index 0000000..0df1449 --- /dev/null +++ b/0400-char-Split-out-tcp-socket-close-code-in-a-separate-f.patch @@ -0,0 +1,57 @@ +From e999fe6e315c5d6f6e8b5d4c689787fc46f10575 Mon Sep 17 00:00:00 2001 +From: Amit Shah +Date: Mon, 21 Mar 2011 21:57:47 +0100 +Subject: [PATCH] char: Split out tcp socket close code in a separate function + +Signed-off-by: Amit Shah +Signed-off-by: Cole Robinson +--- + qemu-char.c | 25 ++++++++++++++++--------- + 1 file changed, 16 insertions(+), 9 deletions(-) + +diff --git a/qemu-char.c b/qemu-char.c +index b082bae..a1fdf88 100644 +--- a/qemu-char.c ++++ b/qemu-char.c +@@ -2141,6 +2141,21 @@ typedef struct { + + static void tcp_chr_accept(void *opaque); + ++static void tcp_closed(void *opaque) ++{ ++ CharDriverState *chr = opaque; ++ TCPCharDriver *s = chr->opaque; ++ ++ s->connected = 0; ++ if (s->listen_fd >= 0) { ++ qemu_set_fd_handler2(s->listen_fd, NULL, tcp_chr_accept, NULL, chr); ++ } ++ qemu_set_fd_handler2(s->fd, NULL, NULL, NULL, NULL); ++ closesocket(s->fd); ++ s->fd = -1; ++ qemu_chr_be_event(chr, CHR_EVENT_CLOSED); ++} ++ + static int tcp_chr_write(CharDriverState *chr, const uint8_t *buf, int len) + { + TCPCharDriver *s = chr->opaque; +@@ -2299,15 +2314,7 @@ static void tcp_chr_read(void *opaque) + len = s->max_size; + size = tcp_chr_recv(chr, (void *)buf, len); + if (size == 0) { +- /* connection closed */ +- s->connected = 0; +- if (s->listen_fd >= 0) { +- qemu_set_fd_handler2(s->listen_fd, NULL, tcp_chr_accept, NULL, chr); +- } +- qemu_set_fd_handler2(s->fd, NULL, NULL, NULL, NULL); +- closesocket(s->fd); +- s->fd = -1; +- qemu_chr_be_event(chr, CHR_EVENT_CLOSED); ++ tcp_closed(chr); + } else if (size > 0) { + if (s->do_telnetopt) + tcp_chr_process_IAC_bytes(chr, s, buf, &size); +-- +1.7.12.1 + diff --git a/0401-char-Add-a-QemuChrHandlers-struct-to-initialise-char.patch b/0401-char-Add-a-QemuChrHandlers-struct-to-initialise-char.patch new file mode 100644 index 0000000..58d0b4a --- /dev/null +++ b/0401-char-Add-a-QemuChrHandlers-struct-to-initialise-char.patch @@ -0,0 +1,962 @@ +From 5f3ba69a09688b40a4648e8818e4878ae20fc2f6 Mon Sep 17 00:00:00 2001 +From: Amit Shah +Date: Mon, 21 Mar 2011 20:31:45 +0100 +Subject: [PATCH] char: Add a QemuChrHandlers struct to initialise chardev + handlers + +Instead of passing each handler in the qemu_add_handlers() function, +create a struct of handlers that can be passed to the function instead. + +Signed-off-by: Amit Shah +Signed-off-by: Cole Robinson +--- + gdbstub.c | 9 +++++++-- + hw/cadence_uart.c | 9 +++++++-- + hw/ccid-card-passthru.c | 11 +++++++---- + hw/debugcon.c | 2 +- + hw/escc.c | 9 +++++++-- + hw/etraxfs_ser.c | 13 +++++++++---- + hw/exynos4210_uart.c | 9 +++++++-- + hw/grlib_apbuart.c | 12 +++++++----- + hw/imx_serial.c | 9 +++++++-- + hw/ivshmem.c | 28 ++++++++++++++++++++++------ + hw/lm32_juart.c | 8 +++++++- + hw/lm32_uart.c | 8 +++++++- + hw/mcf_uart.c | 9 +++++++-- + hw/milkymist-uart.c | 8 +++++++- + hw/pl011.c | 9 +++++++-- + hw/pxa2xx.c | 13 +++++++++---- + hw/qdev-properties.c | 2 +- + hw/serial.c | 9 +++++++-- + hw/sh_serial.c | 12 +++++++++--- + hw/spapr_vty.c | 8 ++++++-- + hw/strongarm.c | 12 +++++++----- + hw/usb/dev-serial.c | 9 +++++++-- + hw/usb/redirect.c | 9 +++++++-- + hw/virtio-console.c | 9 +++++++-- + hw/xen_console.c | 16 +++++++++++----- + hw/xilinx_uartlite.c | 11 +++++++++-- + monitor.c | 18 ++++++++++++++---- + net/slirp.c | 8 ++++++-- + qemu-char.c | 32 ++++++++++++++++++++++---------- + qemu-char.h | 13 +++++++++---- + qtest.c | 9 ++++++++- + 31 files changed, 255 insertions(+), 88 deletions(-) + +diff --git a/gdbstub.c b/gdbstub.c +index a91709f..b905c15 100644 +--- a/gdbstub.c ++++ b/gdbstub.c +@@ -2965,6 +2965,12 @@ static void gdb_sigterm_handler(int signal) + } + #endif + ++static const QemuChrHandlers gdb_handlers = { ++ .fd_can_read = gdb_chr_can_receive, ++ .fd_read = gdb_chr_receive, ++ .fd_event = gdb_chr_event, ++}; ++ + int gdbserver_start(const char *device) + { + GDBState *s; +@@ -2994,8 +3000,7 @@ int gdbserver_start(const char *device) + if (!chr) + return -1; + +- qemu_chr_add_handlers(chr, gdb_chr_can_receive, gdb_chr_receive, +- gdb_chr_event, NULL); ++ qemu_chr_add_handlers(chr, &gdb_handlers, NULL); + } + + s = gdbserver_state; +diff --git a/hw/cadence_uart.c b/hw/cadence_uart.c +index f8afc4e..c9d3b21 100644 +--- a/hw/cadence_uart.c ++++ b/hw/cadence_uart.c +@@ -435,6 +435,12 @@ static void cadence_uart_reset(UartState *s) + s->rx_wpos = 0; + } + ++static const QemuChrHandlers cadence_uart_handlers = { ++ .fd_can_read = uart_can_receive, ++ .fd_read = uart_receive, ++ .fd_event = uart_event, ++}; ++ + static int cadence_uart_init(SysBusDevice *dev) + { + UartState *s = FROM_SYSBUS(UartState, dev); +@@ -456,8 +462,7 @@ static int cadence_uart_init(SysBusDevice *dev) + cadence_uart_reset(s); + + if (s->chr) { +- qemu_chr_add_handlers(s->chr, uart_can_receive, uart_receive, +- uart_event, s); ++ qemu_chr_add_handlers(s->chr, &cadence_uart_handlers, s); + } + + return 0; +diff --git a/hw/ccid-card-passthru.c b/hw/ccid-card-passthru.c +index bd6c777..fb32107 100644 +--- a/hw/ccid-card-passthru.c ++++ b/hw/ccid-card-passthru.c +@@ -274,6 +274,12 @@ static const uint8_t *passthru_get_atr(CCIDCardState *base, uint32_t *len) + return card->atr; + } + ++static const QemuChrHandlers passthru_handlers = { ++ .fd_can_read = ccid_card_vscard_can_read, ++ .fd_read = ccid_card_vscard_read, ++ .fd_event = ccid_card_vscard_event, ++}; ++ + static int passthru_initfn(CCIDCardState *base) + { + PassthruState *card = DO_UPCAST(PassthruState, base, base); +@@ -282,10 +288,7 @@ static int passthru_initfn(CCIDCardState *base) + card->vscard_in_hdr = 0; + if (card->cs) { + DPRINTF(card, D_INFO, "initing chardev\n"); +- qemu_chr_add_handlers(card->cs, +- ccid_card_vscard_can_read, +- ccid_card_vscard_read, +- ccid_card_vscard_event, card); ++ qemu_chr_add_handlers(card->cs, &passthru_handlers, card); + ccid_card_vscard_send_init(card); + } else { + error_report("missing chardev"); +diff --git a/hw/debugcon.c b/hw/debugcon.c +index 14ab326..7887fd2 100644 +--- a/hw/debugcon.c ++++ b/hw/debugcon.c +@@ -73,7 +73,7 @@ static void debugcon_init_core(DebugconState *s) + exit(1); + } + +- qemu_chr_add_handlers(s->chr, NULL, NULL, NULL, s); ++ qemu_chr_add_handlers(s->chr, NULL, s); + } + + static int debugcon_isa_initfn(ISADevice *dev) +diff --git a/hw/escc.c b/hw/escc.c +index e1f5e73..ff9d8b1 100644 +--- a/hw/escc.c ++++ b/hw/escc.c +@@ -867,6 +867,12 @@ void slavio_serial_ms_kbd_init(target_phys_addr_t base, qemu_irq irq, + sysbus_mmio_map(s, 0, base); + } + ++static const QemuChrHandlers serial_handlers = { ++ .fd_can_read = serial_can_receive, ++ .fd_read = serial_receive1, ++ .fd_event = serial_event, ++}; ++ + static int escc_init1(SysBusDevice *dev) + { + SerialState *s = FROM_SYSBUS(SerialState, dev); +@@ -879,8 +885,7 @@ static int escc_init1(SysBusDevice *dev) + s->chn[i].chn = 1 - i; + s->chn[i].clock = s->frequency / 2; + if (s->chn[i].chr) { +- qemu_chr_add_handlers(s->chn[i].chr, serial_can_receive, +- serial_receive1, serial_event, &s->chn[i]); ++ qemu_chr_add_handlers(s->chn[i].chr, &serial_handlers, &s->chn[i]); + } + } + s->chn[0].otherchn = &s->chn[1]; +diff --git a/hw/etraxfs_ser.c b/hw/etraxfs_ser.c +index 5f16b17..f2571c2 100644 +--- a/hw/etraxfs_ser.c ++++ b/hw/etraxfs_ser.c +@@ -208,6 +208,12 @@ static void etraxfs_ser_reset(DeviceState *d) + + } + ++static const QemuChrHandlers serial_handlers = { ++ .fd_can_read = serial_can_receive, ++ .fd_read = serial_receive, ++ .fd_event = serial_event, ++}; ++ + static int etraxfs_ser_init(SysBusDevice *dev) + { + struct etrax_serial *s = FROM_SYSBUS(typeof (*s), dev); +@@ -217,10 +223,9 @@ static int etraxfs_ser_init(SysBusDevice *dev) + sysbus_init_mmio(dev, &s->mmio); + + s->chr = qemu_char_get_next_serial(); +- if (s->chr) +- qemu_chr_add_handlers(s->chr, +- serial_can_receive, serial_receive, +- serial_event, s); ++ if (s->chr) { ++ qemu_chr_add_handlers(s->chr, &serial_handlers, s); ++ } + return 0; + } + +diff --git a/hw/exynos4210_uart.c b/hw/exynos4210_uart.c +index ccc4780..fefe400 100644 +--- a/hw/exynos4210_uart.c ++++ b/hw/exynos4210_uart.c +@@ -625,6 +625,12 @@ DeviceState *exynos4210_uart_create(target_phys_addr_t addr, + return dev; + } + ++static const QemuChrHandlers exynos4210_handlers = { ++ .fd_can_read = exynos4210_uart_can_receive, ++ .fd_read = exynos4210_uart_receive, ++ .fd_event = exynos4210_uart_event, ++}; ++ + static int exynos4210_uart_init(SysBusDevice *dev) + { + Exynos4210UartState *s = FROM_SYSBUS(Exynos4210UartState, dev); +@@ -636,8 +642,7 @@ static int exynos4210_uart_init(SysBusDevice *dev) + + sysbus_init_irq(dev, &s->irq); + +- qemu_chr_add_handlers(s->chr, exynos4210_uart_can_receive, +- exynos4210_uart_receive, exynos4210_uart_event, s); ++ qemu_chr_add_handlers(s->chr, &exynos4210_handlers, s); + + return 0; + } +diff --git a/hw/grlib_apbuart.c b/hw/grlib_apbuart.c +index 73fc989..fd77d52 100644 +--- a/hw/grlib_apbuart.c ++++ b/hw/grlib_apbuart.c +@@ -222,15 +222,17 @@ static const MemoryRegionOps grlib_apbuart_ops = { + .endianness = DEVICE_NATIVE_ENDIAN, + }; + ++static const QemuChrHandlers grlib_handlers = { ++ .fd_can_read = grlib_apbuart_can_receive, ++ .fd_read = grlib_apbuart_receive, ++ .fd_event = grlib_apbuart_event, ++}; ++ + static int grlib_apbuart_init(SysBusDevice *dev) + { + UART *uart = FROM_SYSBUS(typeof(*uart), dev); + +- qemu_chr_add_handlers(uart->chr, +- grlib_apbuart_can_receive, +- grlib_apbuart_receive, +- grlib_apbuart_event, +- uart); ++ qemu_chr_add_handlers(uart->chr, &grlib_handlers, uart); + + sysbus_init_irq(dev, &uart->irq); + +diff --git a/hw/imx_serial.c b/hw/imx_serial.c +index d4eae43..f2304d2 100644 +--- a/hw/imx_serial.c ++++ b/hw/imx_serial.c +@@ -381,6 +381,12 @@ static const struct MemoryRegionOps imx_serial_ops = { + .endianness = DEVICE_NATIVE_ENDIAN, + }; + ++static const QemuChrHandlers imx_handlers = { ++ .fd_can_read = imx_can_receive, ++ .fd_read = imx_receive, ++ .fd_event = imx_event, ++}; ++ + static int imx_serial_init(SysBusDevice *dev) + { + IMXSerialState *s = FROM_SYSBUS(IMXSerialState, dev); +@@ -391,8 +397,7 @@ static int imx_serial_init(SysBusDevice *dev) + sysbus_init_irq(dev, &s->irq); + + if (s->chr) { +- qemu_chr_add_handlers(s->chr, imx_can_receive, imx_receive, +- imx_event, s); ++ qemu_chr_add_handlers(s->chr, &imx_handlers, s); + } else { + DPRINTF("No char dev for uart at 0x%lx\n", + (unsigned long)s->iomem.ram_addr); +diff --git a/hw/ivshmem.c b/hw/ivshmem.c +index 62fe53a..e90f691 100644 +--- a/hw/ivshmem.c ++++ b/hw/ivshmem.c +@@ -273,6 +273,18 @@ static void fake_irqfd(void *opaque, const uint8_t *buf, int size) { + msix_notify(pdev, entry->vector); + } + ++static const QemuChrHandlers ivshmem_handlers = { ++ .fd_can_read = ivshmem_can_receive, ++ .fd_read = ivshmem_receive, ++ .fd_event = ivshmem_event, ++}; ++ ++static const QemuChrHandlers ivshmem_msi_handlers = { ++ .fd_can_read = ivshmem_can_receive, ++ .fd_read = fake_irqfd, ++ .fd_event = ivshmem_event, ++}; ++ + static CharDriverState* create_eventfd_chr_device(void * opaque, EventNotifier *n, + int vector) + { +@@ -293,11 +305,10 @@ static CharDriverState* create_eventfd_chr_device(void * opaque, EventNotifier * + s->eventfd_table[vector].pdev = &s->dev; + s->eventfd_table[vector].vector = vector; + +- qemu_chr_add_handlers(chr, ivshmem_can_receive, fake_irqfd, +- ivshmem_event, &s->eventfd_table[vector]); ++ qemu_chr_add_handlers(chr, &ivshmem_msi_handlers, ++ &s->eventfd_table[vector]); + } else { +- qemu_chr_add_handlers(chr, ivshmem_can_receive, ivshmem_receive, +- ivshmem_event, s); ++ qemu_chr_add_handlers(chr, &ivshmem_handlers, s); + } + + return chr; +@@ -634,6 +645,12 @@ static void ivshmem_write_config(PCIDevice *pci_dev, uint32_t address, + msix_write_config(pci_dev, address, val, len); + } + ++static const QemuChrHandlers ivshmem_server_handlers = { ++ .fd_can_read = ivshmem_can_receive, ++ .fd_read = ivshmem_read, ++ .fd_event = ivshmem_event, ++}; ++ + static int pci_ivshmem_init(PCIDevice *dev) + { + IVShmemState *s = DO_UPCAST(IVShmemState, dev, dev); +@@ -720,8 +737,7 @@ static int pci_ivshmem_init(PCIDevice *dev) + + s->eventfd_chr = g_malloc0(s->vectors * sizeof(CharDriverState *)); + +- qemu_chr_add_handlers(s->server_chr, ivshmem_can_receive, ivshmem_read, +- ivshmem_event, s); ++ qemu_chr_add_handlers(s->server_chr, &ivshmem_server_handlers, s); + } else { + /* just map the file immediately, we're not using a server */ + int fd; +diff --git a/hw/lm32_juart.c b/hw/lm32_juart.c +index f07ed39..d4daeb8 100644 +--- a/hw/lm32_juart.c ++++ b/hw/lm32_juart.c +@@ -110,13 +110,19 @@ static void juart_reset(DeviceState *d) + s->jrx = 0; + } + ++static const QemuChrHandlers juart_handlers = { ++ .fd_can_read = juart_can_rx, ++ .fd_read = juart_rx, ++ .fd_event = juart_event, ++}; ++ + static int lm32_juart_init(SysBusDevice *dev) + { + LM32JuartState *s = FROM_SYSBUS(typeof(*s), dev); + + s->chr = qemu_char_get_next_serial(); + if (s->chr) { +- qemu_chr_add_handlers(s->chr, juart_can_rx, juart_rx, juart_event, s); ++ qemu_chr_add_handlers(s->chr, &juart_handlers, s); + } + + return 0; +diff --git a/hw/lm32_uart.c b/hw/lm32_uart.c +index 57066e2..4ea130b 100644 +--- a/hw/lm32_uart.c ++++ b/hw/lm32_uart.c +@@ -243,6 +243,12 @@ static void uart_reset(DeviceState *d) + s->regs[R_LSR] = LSR_THRE | LSR_TEMT; + } + ++static const QemuChrHandlers uart_handlers = { ++ .fd_can_read = uart_can_rx, ++ .fd_read = uart_rx, ++ .fd_event = uart_event, ++}; ++ + static int lm32_uart_init(SysBusDevice *dev) + { + LM32UartState *s = FROM_SYSBUS(typeof(*s), dev); +@@ -254,7 +260,7 @@ static int lm32_uart_init(SysBusDevice *dev) + + s->chr = qemu_char_get_next_serial(); + if (s->chr) { +- qemu_chr_add_handlers(s->chr, uart_can_rx, uart_rx, uart_event, s); ++ qemu_chr_add_handlers(s->chr, &uart_handlers, s); + } + + return 0; +diff --git a/hw/mcf_uart.c b/hw/mcf_uart.c +index ec6a87f..f52fb96 100644 +--- a/hw/mcf_uart.c ++++ b/hw/mcf_uart.c +@@ -272,6 +272,12 @@ static void mcf_uart_receive(void *opaque, const uint8_t *buf, int size) + mcf_uart_push_byte(s, buf[0]); + } + ++static const QemuChrHandlers mcf_uart_handlers = { ++ .fd_can_read = mcf_uart_can_receive, ++ .fd_read = mcf_uart_receive, ++ .fd_event = mcf_uart_event, ++}; ++ + void *mcf_uart_init(qemu_irq irq, CharDriverState *chr) + { + mcf_uart_state *s; +@@ -280,8 +286,7 @@ void *mcf_uart_init(qemu_irq irq, CharDriverState *chr) + s->chr = chr; + s->irq = irq; + if (chr) { +- qemu_chr_add_handlers(chr, mcf_uart_can_receive, mcf_uart_receive, +- mcf_uart_event, s); ++ qemu_chr_add_handlers(chr, &mcf_uart_handlers, s); + } + mcf_uart_reset(s); + return s; +diff --git a/hw/milkymist-uart.c b/hw/milkymist-uart.c +index 291fe3c..2dcb41c 100644 +--- a/hw/milkymist-uart.c ++++ b/hw/milkymist-uart.c +@@ -189,6 +189,12 @@ static void milkymist_uart_reset(DeviceState *d) + s->regs[R_STAT] = STAT_THRE; + } + ++static const QemuChrHandlers uart_handlers = { ++ .fd_can_read = uart_can_rx, ++ .fd_read = uart_rx, ++ .fd_event = uart_event, ++}; ++ + static int milkymist_uart_init(SysBusDevice *dev) + { + MilkymistUartState *s = FROM_SYSBUS(typeof(*s), dev); +@@ -201,7 +207,7 @@ static int milkymist_uart_init(SysBusDevice *dev) + + s->chr = qemu_char_get_next_serial(); + if (s->chr) { +- qemu_chr_add_handlers(s->chr, uart_can_rx, uart_rx, uart_event, s); ++ qemu_chr_add_handlers(s->chr, &uart_handlers, s); + } + + return 0; +diff --git a/hw/pl011.c b/hw/pl011.c +index 3245702..0d620f8 100644 +--- a/hw/pl011.c ++++ b/hw/pl011.c +@@ -258,6 +258,12 @@ static const VMStateDescription vmstate_pl011 = { + } + }; + ++static const QemuChrHandlers pl011_handlers = { ++ .fd_can_read = pl011_can_receive, ++ .fd_read = pl011_receive, ++ .fd_event = pl011_event, ++}; ++ + static int pl011_init(SysBusDevice *dev, const unsigned char *id) + { + pl011_state *s = FROM_SYSBUS(pl011_state, dev); +@@ -273,8 +279,7 @@ static int pl011_init(SysBusDevice *dev, const unsigned char *id) + s->cr = 0x300; + s->flags = 0x90; + if (s->chr) { +- qemu_chr_add_handlers(s->chr, pl011_can_receive, pl011_receive, +- pl011_event, s); ++ qemu_chr_add_handlers(s->chr, &pl011_handlers, s); + } + vmstate_register(&dev->qdev, -1, &vmstate_pl011, s); + return 0; +diff --git a/hw/pxa2xx.c b/hw/pxa2xx.c +index d5f1420..0b308cf 100644 +--- a/hw/pxa2xx.c ++++ b/hw/pxa2xx.c +@@ -1962,6 +1962,12 @@ static int pxa2xx_fir_load(QEMUFile *f, void *opaque, int version_id) + return 0; + } + ++static const QemuChrHandlers pxa2xx_handlers = { ++ .fd_can_read = pxa2xx_fir_is_empty, ++ .fd_read = pxa2xx_fir_rx, ++ .fd_event = pxa2xx_fir_event, ++}; ++ + static PXA2xxFIrState *pxa2xx_fir_init(MemoryRegion *sysmem, + target_phys_addr_t base, + qemu_irq irq, qemu_irq rx_dma, qemu_irq tx_dma, +@@ -1980,10 +1986,9 @@ static PXA2xxFIrState *pxa2xx_fir_init(MemoryRegion *sysmem, + memory_region_init_io(&s->iomem, &pxa2xx_fir_ops, s, "pxa2xx-fir", 0x1000); + memory_region_add_subregion(sysmem, base, &s->iomem); + +- if (chr) +- qemu_chr_add_handlers(chr, pxa2xx_fir_is_empty, +- pxa2xx_fir_rx, pxa2xx_fir_event, s); +- ++ if (chr) { ++ qemu_chr_add_handlers(chr, &pxa2xx_handlers, s); ++ } + register_savevm(NULL, "pxa2xx_fir", 0, 0, pxa2xx_fir_save, + pxa2xx_fir_load, s); + +diff --git a/hw/qdev-properties.c b/hw/qdev-properties.c +index 8aca0d4..677c665 100644 +--- a/hw/qdev-properties.c ++++ b/hw/qdev-properties.c +@@ -549,7 +549,7 @@ static void release_chr(Object *obj, const char *name, void *opaque) + CharDriverState **ptr = qdev_get_prop_ptr(dev, prop); + + if (*ptr) { +- qemu_chr_add_handlers(*ptr, NULL, NULL, NULL, NULL); ++ qemu_chr_add_handlers(*ptr, NULL, NULL); + } + } + +diff --git a/hw/serial.c b/hw/serial.c +index a421d1e..056d823 100644 +--- a/hw/serial.c ++++ b/hw/serial.c +@@ -736,6 +736,12 @@ static void serial_reset(void *opaque) + qemu_irq_lower(s->irq); + } + ++static const QemuChrHandlers serial_handlers = { ++ .fd_can_read = serial_can_receive1, ++ .fd_read = serial_receive1, ++ .fd_event = serial_event, ++}; ++ + static void serial_init_core(SerialState *s) + { + if (!s->chr) { +@@ -750,8 +756,7 @@ static void serial_init_core(SerialState *s) + + qemu_register_reset(serial_reset, s); + +- qemu_chr_add_handlers(s->chr, serial_can_receive1, serial_receive1, +- serial_event, s); ++ qemu_chr_add_handlers(s->chr, &serial_handlers, s); + } + + /* Change the main reference oscillator frequency. */ +diff --git a/hw/sh_serial.c b/hw/sh_serial.c +index 1d1883d..ce1c765 100644 +--- a/hw/sh_serial.c ++++ b/hw/sh_serial.c +@@ -352,6 +352,12 @@ static const MemoryRegionOps sh_serial_ops = { + .endianness = DEVICE_NATIVE_ENDIAN, + }; + ++static const QemuChrHandlers sh_serial_handlers = { ++ .fd_can_read = sh_serial_can_receive1, ++ .fd_read = sh_serial_receive1, ++ .fd_event = sh_serial_event, ++}; ++ + void sh_serial_init(MemoryRegion *sysmem, + target_phys_addr_t base, int feat, + uint32_t freq, CharDriverState *chr, +@@ -396,9 +402,9 @@ void sh_serial_init(MemoryRegion *sysmem, + + s->chr = chr; + +- if (chr) +- qemu_chr_add_handlers(chr, sh_serial_can_receive1, sh_serial_receive1, +- sh_serial_event, s); ++ if (chr) { ++ qemu_chr_add_handlers(chr, &sh_serial_handlers, s); ++ } + + s->eri = eri_source; + s->rxi = rxi_source; +diff --git a/hw/spapr_vty.c b/hw/spapr_vty.c +index 5da17a3..6c2ada1 100644 +--- a/hw/spapr_vty.c ++++ b/hw/spapr_vty.c +@@ -54,6 +54,11 @@ void vty_putchars(VIOsPAPRDevice *sdev, uint8_t *buf, int len) + qemu_chr_fe_write(dev->chardev, buf, len); + } + ++static const QemuChrHandlers vty_handlers = { ++ .fd_can_read = vty_can_receive, ++ .fd_read = vty_receive, ++}; ++ + static int spapr_vty_init(VIOsPAPRDevice *sdev) + { + VIOsPAPRVTYDevice *dev = (VIOsPAPRVTYDevice *)sdev; +@@ -63,8 +68,7 @@ static int spapr_vty_init(VIOsPAPRDevice *sdev) + exit(1); + } + +- qemu_chr_add_handlers(dev->chardev, vty_can_receive, +- vty_receive, NULL, dev); ++ qemu_chr_add_handlers(dev->chardev, &vty_handlers, dev); + + return 0; + } +diff --git a/hw/strongarm.c b/hw/strongarm.c +index 7150eeb..594cf31 100644 +--- a/hw/strongarm.c ++++ b/hw/strongarm.c +@@ -1199,6 +1199,12 @@ static const MemoryRegionOps strongarm_uart_ops = { + .endianness = DEVICE_NATIVE_ENDIAN, + }; + ++static const QemuChrHandlers strongarm_uart_handlers = { ++ .fd_can_read = strongarm_uart_can_receive, ++ .fd_read = strongarm_uart_receive, ++ .fd_event = strongarm_uart_event, ++}; ++ + static int strongarm_uart_init(SysBusDevice *dev) + { + StrongARMUARTState *s = FROM_SYSBUS(StrongARMUARTState, dev); +@@ -1211,11 +1217,7 @@ static int strongarm_uart_init(SysBusDevice *dev) + s->tx_timer = qemu_new_timer_ns(vm_clock, strongarm_uart_tx, s); + + if (s->chr) { +- qemu_chr_add_handlers(s->chr, +- strongarm_uart_can_receive, +- strongarm_uart_receive, +- strongarm_uart_event, +- s); ++ qemu_chr_add_handlers(s->chr, &strongarm_uart_handlers, s); + } + + return 0; +diff --git a/hw/usb/dev-serial.c b/hw/usb/dev-serial.c +index 69b6e48..0ddfab6 100644 +--- a/hw/usb/dev-serial.c ++++ b/hw/usb/dev-serial.c +@@ -475,6 +475,12 @@ static void usb_serial_event(void *opaque, int event) + } + } + ++static const QemuChrHandlers usb_serial_handlers = { ++ .fd_can_read = usb_serial_can_read, ++ .fd_read = usb_serial_read, ++ .fd_event = usb_serial_event, ++}; ++ + static int usb_serial_initfn(USBDevice *dev) + { + USBSerialState *s = DO_UPCAST(USBSerialState, dev, dev); +@@ -487,8 +493,7 @@ static int usb_serial_initfn(USBDevice *dev) + return -1; + } + +- qemu_chr_add_handlers(s->cs, usb_serial_can_read, usb_serial_read, +- usb_serial_event, s); ++ qemu_chr_add_handlers(s->cs, &usb_serial_handlers, s); + usb_serial_handle_reset(dev); + return 0; + } +diff --git a/hw/usb/redirect.c b/hw/usb/redirect.c +index ab8d79a..8b22c80 100644 +--- a/hw/usb/redirect.c ++++ b/hw/usb/redirect.c +@@ -867,6 +867,12 @@ static void usbredir_chardev_event(void *opaque, int event) + } + } + ++static const QemuChrHandlers usbredir_chr_handlers = { ++ .fd_can_read = usbredir_chardev_can_read, ++ .fd_read = usbredir_chardev_read, ++ .fd_event = usbredir_chardev_event, ++}; ++ + /* + * init + destroy + */ +@@ -905,8 +911,7 @@ static int usbredir_initfn(USBDevice *udev) + + /* Let the backend know we are ready */ + qemu_chr_fe_open(dev->cs); +- qemu_chr_add_handlers(dev->cs, usbredir_chardev_can_read, +- usbredir_chardev_read, usbredir_chardev_event, dev); ++ qemu_chr_add_handlers(dev->cs, &usbredir_chr_handlers, dev); + + add_boot_device_path(dev->bootindex, &udev->qdev, NULL); + return 0; +diff --git a/hw/virtio-console.c b/hw/virtio-console.c +index cffee3d..066590c 100644 +--- a/hw/virtio-console.c ++++ b/hw/virtio-console.c +@@ -106,6 +106,12 @@ static void chr_event(void *opaque, int event) + } + } + ++static const QemuChrHandlers chr_handlers = { ++ .fd_can_read = chr_can_read, ++ .fd_read = chr_read, ++ .fd_event = chr_event, ++}; ++ + static int virtconsole_initfn(VirtIOSerialPort *port) + { + VirtConsole *vcon = DO_UPCAST(VirtConsole, port, port); +@@ -117,8 +123,7 @@ static int virtconsole_initfn(VirtIOSerialPort *port) + } + + if (vcon->chr) { +- qemu_chr_add_handlers(vcon->chr, chr_can_read, chr_read, chr_event, +- vcon); ++ qemu_chr_add_handlers(vcon->chr, &chr_handlers, vcon); + } + + return 0; +diff --git a/hw/xen_console.c b/hw/xen_console.c +index 9426d73..e9fcadc 100644 +--- a/hw/xen_console.c ++++ b/hw/xen_console.c +@@ -211,6 +211,11 @@ out: + return ret; + } + ++static const QemuChrHandlers xencons_handlers = { ++ .fd_can_read = xencons_can_receive, ++ .fd_read = xencons_receive, ++}; ++ + static int con_initialise(struct XenDevice *xendev) + { + struct XenConsole *con = container_of(xendev, struct XenConsole, xendev); +@@ -231,9 +236,9 @@ static int con_initialise(struct XenDevice *xendev) + return -1; + + xen_be_bind_evtchn(&con->xendev); +- if (con->chr) +- qemu_chr_add_handlers(con->chr, xencons_can_receive, xencons_receive, +- NULL, con); ++ if (con->chr) { ++ qemu_chr_add_handlers(con->chr, &xencons_handlers, con); ++ } + + xen_be_printf(xendev, 1, "ring mfn %d, remote port %d, local port %d, limit %zd\n", + con->ring_ref, +@@ -250,8 +255,9 @@ static void con_disconnect(struct XenDevice *xendev) + if (!xendev->dev) { + return; + } +- if (con->chr) +- qemu_chr_add_handlers(con->chr, NULL, NULL, NULL, NULL); ++ if (con->chr) { ++ qemu_chr_add_handlers(con->chr, NULL, NULL); ++ } + xen_be_unbind_evtchn(&con->xendev); + + if (con->sring) { +diff --git a/hw/xilinx_uartlite.c b/hw/xilinx_uartlite.c +index d0f32db..33f0cd5 100644 +--- a/hw/xilinx_uartlite.c ++++ b/hw/xilinx_uartlite.c +@@ -195,6 +195,12 @@ static void uart_event(void *opaque, int event) + + } + ++static const QemuChrHandlers uart_handlers = { ++ .fd_can_read = uart_can_rx, ++ .fd_read = uart_rx, ++ .fd_event = uart_event, ++}; ++ + static int xilinx_uartlite_init(SysBusDevice *dev) + { + struct xlx_uartlite *s = FROM_SYSBUS(typeof (*s), dev); +@@ -207,8 +213,9 @@ static int xilinx_uartlite_init(SysBusDevice *dev) + sysbus_init_mmio(dev, &s->mmio); + + s->chr = qemu_char_get_next_serial(); +- if (s->chr) +- qemu_chr_add_handlers(s->chr, uart_can_rx, uart_rx, uart_event, s); ++ if (s->chr) { ++ qemu_chr_add_handlers(s->chr, &uart_handlers, s); ++ } + return 0; + } + +diff --git a/monitor.c b/monitor.c +index f45cf92..99eee98 100644 +--- a/monitor.c ++++ b/monitor.c +@@ -4942,6 +4942,18 @@ static void sortcmdlist(void) + * End: + */ + ++static const QemuChrHandlers monitor_handlers = { ++ .fd_can_read = monitor_can_read, ++ .fd_read = monitor_read, ++ .fd_event = monitor_event, ++}; ++ ++static const QemuChrHandlers monitor_control_handlers = { ++ .fd_can_read = monitor_can_read, ++ .fd_read = monitor_control_read, ++ .fd_event = monitor_control_event, ++}; ++ + void monitor_init(CharDriverState *chr, int flags) + { + static int is_first_init = 1; +@@ -4965,14 +4977,12 @@ void monitor_init(CharDriverState *chr, int flags) + if (monitor_ctrl_mode(mon)) { + mon->mc = g_malloc0(sizeof(MonitorControl)); + /* Control mode requires special handlers */ +- qemu_chr_add_handlers(chr, monitor_can_read, monitor_control_read, +- monitor_control_event, mon); ++ qemu_chr_add_handlers(chr, &monitor_control_handlers, mon); + qemu_chr_fe_set_echo(chr, true); + + json_message_parser_init(&mon->mc->parser, handle_qmp_command); + } else { +- qemu_chr_add_handlers(chr, monitor_can_read, monitor_read, +- monitor_event, mon); ++ qemu_chr_add_handlers(chr, &monitor_handlers, mon); + } + + QLIST_INSERT_HEAD(&mon_list, mon, entry); +diff --git a/net/slirp.c b/net/slirp.c +index 8db66ea..63542cb 100644 +--- a/net/slirp.c ++++ b/net/slirp.c +@@ -593,6 +593,11 @@ static void guestfwd_read(void *opaque, const uint8_t *buf, int size) + slirp_socket_recv(fwd->slirp, fwd->server, fwd->port, buf, size); + } + ++static const QemuChrHandlers guestfwd_handlers = { ++ .fd_can_read = guestfwd_can_read, ++ .fd_read = guestfwd_read, ++}; ++ + static int slirp_guestfwd(SlirpState *s, const char *config_str, + int legacy_format) + { +@@ -658,8 +663,7 @@ static int slirp_guestfwd(SlirpState *s, const char *config_str, + fwd->port = port; + fwd->slirp = s->slirp; + +- qemu_chr_add_handlers(fwd->hd, guestfwd_can_read, guestfwd_read, +- NULL, fwd); ++ qemu_chr_add_handlers(fwd->hd, &guestfwd_handlers, fwd); + } + return 0; + +diff --git a/qemu-char.c b/qemu-char.c +index a1fdf88..bd443db 100644 +--- a/qemu-char.c ++++ b/qemu-char.c +@@ -192,19 +192,26 @@ void qemu_chr_fe_printf(CharDriverState *s, const char *fmt, ...) + va_end(ap); + } + ++static const QemuChrHandlers null_handlers = { ++ /* All handlers are initialised to NULL */ ++}; ++ + void qemu_chr_add_handlers(CharDriverState *s, +- IOCanReadHandler *fd_can_read, +- IOReadHandler *fd_read, +- IOEventHandler *fd_event, +- void *opaque) ++ const QemuChrHandlers *handlers, void *opaque) + { +- if (!opaque && !fd_can_read && !fd_read && !fd_event) { ++ if (!s) { ++ return; ++ } ++ if (!opaque && !handlers) { + /* chr driver being released. */ + ++s->avail_connections; + } +- s->chr_can_read = fd_can_read; +- s->chr_read = fd_read; +- s->chr_event = fd_event; ++ if (!handlers) { ++ handlers = &null_handlers; ++ } ++ s->chr_can_read = handlers->fd_can_read; ++ s->chr_read = handlers->fd_read; ++ s->chr_event = handlers->fd_event; + s->handler_opaque = opaque; + if (s->chr_update_read_handler) + s->chr_update_read_handler(s); +@@ -442,6 +449,12 @@ static void mux_chr_event(void *opaque, int event) + mux_chr_send_event(d, i, event); + } + ++static const QemuChrHandlers mux_chr_handlers = { ++ .fd_can_read = mux_chr_can_read, ++ .fd_read = mux_chr_read, ++ .fd_event = mux_chr_event, ++}; ++ + static void mux_chr_update_read_handler(CharDriverState *chr) + { + MuxDriver *d = chr->opaque; +@@ -456,8 +469,7 @@ static void mux_chr_update_read_handler(CharDriverState *chr) + d->chr_event[d->mux_cnt] = chr->chr_event; + /* Fix up the real driver with mux routines */ + if (d->mux_cnt == 0) { +- qemu_chr_add_handlers(d->drv, mux_chr_can_read, mux_chr_read, +- mux_chr_event, chr); ++ qemu_chr_add_handlers(d->drv, &mux_chr_handlers, chr); + } + if (d->focus != -1) { + mux_chr_send_event(d, d->focus, CHR_EVENT_MUX_OUT); +diff --git a/qemu-char.h b/qemu-char.h +index 486644b..dfa8c2d 100644 +--- a/qemu-char.h ++++ b/qemu-char.h +@@ -222,10 +222,15 @@ void qemu_chr_be_write(CharDriverState *s, uint8_t *buf, int len); + */ + void qemu_chr_be_event(CharDriverState *s, int event); + +-void qemu_chr_add_handlers(CharDriverState *s, +- IOCanReadHandler *fd_can_read, +- IOReadHandler *fd_read, +- IOEventHandler *fd_event, ++ ++typedef struct QemuChrHandlers { ++ IOCanReadHandler *fd_can_read; ++ IOReadHandler *fd_read; ++ IOHandler *fd_write_unblocked; ++ IOEventHandler *fd_event; ++} QemuChrHandlers; ++ ++void qemu_chr_add_handlers(CharDriverState *s, const QemuChrHandlers *handlers, + void *opaque); + + void qemu_chr_generic_open(CharDriverState *s); +diff --git a/qtest.c b/qtest.c +index fbfab4e..4ab5b69 100644 +--- a/qtest.c ++++ b/qtest.c +@@ -416,6 +416,13 @@ static void qtest_event(void *opaque, int event) + } + } + ++static const QemuChrHandlers test_handlers = { ++ .fd_can_read = qtest_can_read, ++ .fd_read = qtest_read, ++ .fd_event = qtest_event, ++}; ++ ++ + int qtest_init(void) + { + CharDriverState *chr; +@@ -425,7 +432,7 @@ int qtest_init(void) + configure_icount("0"); + chr = qemu_chr_new("qtest", qtest_chrdev, NULL); + +- qemu_chr_add_handlers(chr, qtest_can_read, qtest_read, qtest_event, chr); ++ qemu_chr_add_handlers(chr, &test_handlers, chr); + qemu_chr_fe_set_echo(chr, true); + + inbuf = g_string_new(""); +-- +1.7.12.1 + diff --git a/0402-iohandlers-Add-enable-disable_write_fd_handler-funct.patch b/0402-iohandlers-Add-enable-disable_write_fd_handler-funct.patch new file mode 100644 index 0000000..cfc7cd2 --- /dev/null +++ b/0402-iohandlers-Add-enable-disable_write_fd_handler-funct.patch @@ -0,0 +1,77 @@ +From 2ac23d2134611b4e5b0fb389911bd03baa685df3 Mon Sep 17 00:00:00 2001 +From: Amit Shah +Date: Mon, 21 Mar 2011 20:32:58 +0100 +Subject: [PATCH] iohandlers: Add enable/disable_write_fd_handler() functions + +These will be used to provide a cleaner API for the nonblocking case. + +Signed-off-by: Amit Shah +Signed-off-by: Cole Robinson +--- + iohandler.c | 35 +++++++++++++++++++++++++++++++++++ + main-loop.h | 3 +++ + 2 files changed, 38 insertions(+) + +diff --git a/iohandler.c b/iohandler.c +index a2d871b..c00fecd 100644 +--- a/iohandler.c ++++ b/iohandler.c +@@ -45,6 +45,41 @@ typedef struct IOHandlerRecord { + static QLIST_HEAD(, IOHandlerRecord) io_handlers = + QLIST_HEAD_INITIALIZER(io_handlers); + ++static IOHandlerRecord *find_iohandler(int fd) ++{ ++ IOHandlerRecord *ioh; ++ ++ QLIST_FOREACH(ioh, &io_handlers, next) { ++ if (ioh->fd == fd) { ++ return ioh; ++ } ++ } ++ return NULL; ++} ++ ++void enable_write_fd_handler(int fd, IOHandler *fd_write) ++{ ++ IOHandlerRecord *ioh; ++ ++ ioh = find_iohandler(fd); ++ if (!ioh) { ++ return; ++ } ++ ++ ioh->fd_write = fd_write; ++} ++ ++void disable_write_fd_handler(int fd) ++{ ++ IOHandlerRecord *ioh; ++ ++ ioh = find_iohandler(fd); ++ if (!ioh) { ++ return; ++ } ++ ++ ioh->fd_write = NULL; ++} + + /* XXX: fd_read_poll should be suppressed, but an API change is + necessary in the character devices to suppress fd_can_read(). */ +diff --git a/main-loop.h b/main-loop.h +index dce1cd9..eb31273 100644 +--- a/main-loop.h ++++ b/main-loop.h +@@ -175,6 +175,9 @@ typedef void IOReadHandler(void *opaque, const uint8_t *buf, int size); + typedef int IOCanReadHandler(void *opaque); + typedef void IOHandler(void *opaque); + ++void enable_write_fd_handler(int fd, IOHandler *fd_write); ++void disable_write_fd_handler(int fd); ++ + /** + * qemu_set_fd_handler2: Register a file descriptor with the main loop + * +-- +1.7.12.1 + diff --git a/0403-char-Add-framework-for-a-write-unblocked-callback.patch b/0403-char-Add-framework-for-a-write-unblocked-callback.patch new file mode 100644 index 0000000..67f83f6 --- /dev/null +++ b/0403-char-Add-framework-for-a-write-unblocked-callback.patch @@ -0,0 +1,62 @@ +From 8ca97117074b5eb12bf9cb0b25548116174601a8 Mon Sep 17 00:00:00 2001 +From: Amit Shah +Date: Mon, 21 Mar 2011 21:41:42 +0100 +Subject: [PATCH] char: Add framework for a 'write unblocked' callback + +The char layer can let users know that the driver will block on further +input. For users interested in not blocking, they can assign a function +pointer that will be called back when the driver becomes writable. This +patch just adds the function pointers to the CharDriverState structure, +future patches will enable the nonblocking and callback functionality. + +Signed-off-by: Amit Shah +Signed-off-by: Cole Robinson +--- + qemu-char.c | 3 +++ + qemu-char.h | 4 ++++ + 2 files changed, 7 insertions(+) + +diff --git a/qemu-char.c b/qemu-char.c +index bd443db..b5266d1 100644 +--- a/qemu-char.c ++++ b/qemu-char.c +@@ -211,11 +211,14 @@ void qemu_chr_add_handlers(CharDriverState *s, + } + s->chr_can_read = handlers->fd_can_read; + s->chr_read = handlers->fd_read; ++ s->chr_write_unblocked = handlers->fd_write_unblocked; + s->chr_event = handlers->fd_event; + s->handler_opaque = opaque; + if (s->chr_update_read_handler) + s->chr_update_read_handler(s); + ++ s->write_blocked = false; ++ + /* We're connecting to an already opened device, so let's make sure we + also get the open event */ + if (s->opened) { +diff --git a/qemu-char.h b/qemu-char.h +index dfa8c2d..b5e23a4 100644 +--- a/qemu-char.h ++++ b/qemu-char.h +@@ -62,6 +62,9 @@ struct CharDriverState { + IOEventHandler *chr_event; + IOCanReadHandler *chr_can_read; + IOReadHandler *chr_read; ++ IOHandler *chr_write_unblocked; ++ void (*chr_enable_write_fd_handler)(struct CharDriverState *chr); ++ void (*chr_disable_write_fd_handler)(struct CharDriverState *chr); + void *handler_opaque; + void (*chr_close)(struct CharDriverState *chr); + void (*chr_accept_input)(struct CharDriverState *chr); +@@ -74,6 +77,7 @@ struct CharDriverState { + char *filename; + int opened; + int avail_connections; ++ bool write_blocked; /* Are we in a blocked state? */ + QTAILQ_ENTRY(CharDriverState) next; + }; + +-- +1.7.12.1 + diff --git a/0404-char-Update-send_all-to-handle-nonblocking-chardev-w.patch b/0404-char-Update-send_all-to-handle-nonblocking-chardev-w.patch new file mode 100644 index 0000000..b53d594 --- /dev/null +++ b/0404-char-Update-send_all-to-handle-nonblocking-chardev-w.patch @@ -0,0 +1,173 @@ +From dd7b138971deb72c7e37c4b79665df6ff5c1130b Mon Sep 17 00:00:00 2001 +From: Amit Shah +Date: Mon, 21 Mar 2011 22:00:27 +0100 +Subject: [PATCH] char: Update send_all() to handle nonblocking chardev write + requests + +The send_all function is modified to return to the caller in case the +driver cannot handle any more data. It returns -EAGAIN or +WSAEWOULDBLOCK on non-Windows and Windows platforms respectively. This +is only done when the caller sets a callback function handler indicating +it's not interested in blocking till the driver has written out all the +data. + +Currently there's no driver or caller that supports this. Future +commits will add such capability. + +Signed-off-by: Amit Shah +Signed-off-by: Cole Robinson +--- + qemu-char.c | 69 +++++++++++++++++++++++++++++++++++++++++++++++++++++------ + qemu_socket.h | 2 +- + 2 files changed, 64 insertions(+), 7 deletions(-) + +diff --git a/qemu-char.c b/qemu-char.c +index b5266d1..b46cc97 100644 +--- a/qemu-char.c ++++ b/qemu-char.c +@@ -508,7 +508,7 @@ static CharDriverState *qemu_chr_open_mux(CharDriverState *drv) + + + #ifdef _WIN32 +-int send_all(int fd, const void *buf, int len1) ++static int do_send(int fd, const void *buf, int len1, bool nonblock) + { + int ret, len; + +@@ -516,9 +516,14 @@ int send_all(int fd, const void *buf, int len1) + while (len > 0) { + ret = send(fd, buf, len, 0); + if (ret < 0) { ++ if (nonblock && len1 - len) { ++ return len1 - len; ++ } + errno = WSAGetLastError(); + if (errno != WSAEWOULDBLOCK) { + return -1; ++ } else if (errno == WSAEWOULDBLOCK && nonblock) { ++ return WSAEWOULDBLOCK; + } + } else if (ret == 0) { + break; +@@ -532,7 +537,7 @@ int send_all(int fd, const void *buf, int len1) + + #else + +-int send_all(int fd, const void *_buf, int len1) ++static int do_send(int fd, const void *_buf, int len1, bool nonblock) + { + int ret, len; + const uint8_t *buf = _buf; +@@ -541,8 +546,15 @@ int send_all(int fd, const void *_buf, int len1) + while (len > 0) { + ret = write(fd, buf, len); + if (ret < 0) { +- if (errno != EINTR && errno != EAGAIN) ++ if (nonblock && len1 - len) { ++ return len1 - len; ++ } ++ if (errno == EAGAIN && nonblock) { ++ return -EAGAIN; ++ } ++ if (errno != EINTR && errno != EAGAIN) { + return -1; ++ } + } else if (ret == 0) { + break; + } else { +@@ -557,6 +569,44 @@ int send_all(int fd, const void *_buf, int len1) + #define STDIO_MAX_CLIENTS 1 + static int stdio_nb_clients; + ++int send_all(CharDriverState *chr, int fd, const void *_buf, int len1) ++{ ++ int ret, eagain_errno; ++ bool nonblock; ++ ++ if (chr && chr->write_blocked) { ++ /* ++ * The caller should not send us data while we're blocked, ++ * but this can happen when multiple writers are woken at once, ++ * so simply return -EAGAIN. ++ */ ++ return -EAGAIN; ++ } ++ ++ nonblock = false; ++ /* ++ * Ensure the char backend is able to receive and handle the ++ * 'write unblocked' event before we turn on nonblock support. ++ */ ++ if (chr && chr->chr_enable_write_fd_handler && chr->chr_write_unblocked) { ++ nonblock = true; ++ } ++ ret = do_send(fd, _buf, len1, nonblock); ++ ++#ifdef _WIN32 ++ eagain_errno = WSAEWOULDBLOCK; ++#else ++ eagain_errno = -EAGAIN; ++#endif ++ ++ if (nonblock && (ret == eagain_errno || (ret >= 0 && ret < len1))) { ++ /* Update fd handler to wake up when chr becomes writable */ ++ chr->chr_enable_write_fd_handler(chr); ++ chr->write_blocked = true; ++ } ++ return ret; ++} ++ + #ifndef _WIN32 + + typedef struct { +@@ -568,7 +618,7 @@ typedef struct { + static int fd_chr_write(CharDriverState *chr, const uint8_t *buf, int len) + { + FDCharDriver *s = chr->opaque; +- return send_all(s->fd_out, buf, len); ++ return send_all(chr, s->fd_out, buf, len); + } + + static int fd_chr_read_poll(void *opaque) +@@ -887,7 +937,7 @@ static int pty_chr_write(CharDriverState *chr, const uint8_t *buf, int len) + pty_chr_update_read_handler(chr); + return 0; + } +- return send_all(s->fd, buf, len); ++ return send_all(chr, s->fd, buf, len); + } + + static int pty_chr_read_poll(void *opaque) +@@ -2174,8 +2224,15 @@ static void tcp_closed(void *opaque) + static int tcp_chr_write(CharDriverState *chr, const uint8_t *buf, int len) + { + TCPCharDriver *s = chr->opaque; ++ + if (s->connected) { +- return send_all(s->fd, buf, len); ++ int ret; ++ ++ ret = send_all(chr, s->fd, buf, len); ++ if (ret == -1 && errno == EPIPE) { ++ tcp_closed(chr); ++ } ++ return ret; + } else { + /* XXX: indicate an error ? */ + return len; +diff --git a/qemu_socket.h b/qemu_socket.h +index 3e8aee9..a537d86 100644 +--- a/qemu_socket.h ++++ b/qemu_socket.h +@@ -36,7 +36,7 @@ int qemu_accept(int s, struct sockaddr *addr, socklen_t *addrlen); + int socket_set_cork(int fd, int v); + void socket_set_block(int fd); + void socket_set_nonblock(int fd); +-int send_all(int fd, const void *buf, int len1); ++int send_all(CharDriverState *chr, int fd, const void *buf, int len1); + + /* callback function for nonblocking connect + * valid fd on success, negative error code on failure +-- +1.7.12.1 + diff --git a/0405-char-Equip-the-unix-tcp-backend-to-handle-nonblockin.patch b/0405-char-Equip-the-unix-tcp-backend-to-handle-nonblockin.patch new file mode 100644 index 0000000..830ed84 --- /dev/null +++ b/0405-char-Equip-the-unix-tcp-backend-to-handle-nonblockin.patch @@ -0,0 +1,82 @@ +From 625915146f56f77c275be1aee160f40183008b8d Mon Sep 17 00:00:00 2001 +From: Amit Shah +Date: Mon, 21 Mar 2011 22:02:47 +0100 +Subject: [PATCH] char: Equip the unix/tcp backend to handle nonblocking + writes# + +Now that the infrastructure is in place to return -EAGAIN to callers, +individual char drivers can set their update_fd_handlers() function to +set or remove an fd's write handler. This handler checks if the driver +became writable. + +A generic callback routine is used for unblocking writes and letting +users of chardevs know that a driver became writable again. + +Signed-off-by: Amit Shah +Signed-off-by: Cole Robinson +--- + qemu-char.c | 34 ++++++++++++++++++++++++++++++++++ + 1 file changed, 34 insertions(+) + +diff --git a/qemu-char.c b/qemu-char.c +index b46cc97..9f8608a 100644 +--- a/qemu-char.c ++++ b/qemu-char.c +@@ -106,6 +106,19 @@ + static QTAILQ_HEAD(CharDriverStateHead, CharDriverState) chardevs = + QTAILQ_HEAD_INITIALIZER(chardevs); + ++/* ++ * Generic routine that gets called when chardev becomes writable. ++ * Lets chardev user know it's OK to send more data. ++ */ ++static void char_write_unblocked(void *opaque) ++{ ++ CharDriverState *chr = opaque; ++ ++ chr->write_blocked = false; ++ chr->chr_disable_write_fd_handler(chr); ++ chr->chr_write_unblocked(chr->handler_opaque); ++} ++ + void qemu_chr_be_event(CharDriverState *s, int event) + { + /* Keep track if the char device is open */ +@@ -2503,6 +2516,25 @@ static void tcp_chr_close(CharDriverState *chr) + qemu_chr_be_event(chr, CHR_EVENT_CLOSED); + } + ++static void tcp_enable_write_fd_handler(CharDriverState *chr) ++{ ++ TCPCharDriver *s = chr->opaque; ++ ++ /* ++ * This function is called only after tcp_chr_connect() is called ++ * (either in 'server' mode or client mode. So we're sure of ++ * s->fd being initialised. ++ */ ++ enable_write_fd_handler(s->fd, char_write_unblocked); ++} ++ ++static void tcp_disable_write_fd_handler(CharDriverState *chr) ++{ ++ TCPCharDriver *s = chr->opaque; ++ ++ disable_write_fd_handler(s->fd); ++} ++ + static CharDriverState *qemu_chr_open_socket(QemuOpts *opts) + { + CharDriverState *chr = NULL; +@@ -2557,6 +2589,8 @@ static CharDriverState *qemu_chr_open_socket(QemuOpts *opts) + chr->chr_close = tcp_chr_close; + chr->get_msgfd = tcp_get_msgfd; + chr->chr_add_client = tcp_chr_add_client; ++ chr->chr_enable_write_fd_handler = tcp_enable_write_fd_handler; ++ chr->chr_disable_write_fd_handler = tcp_disable_write_fd_handler; + + if (is_listen) { + s->listen_fd = fd; +-- +1.7.12.1 + diff --git a/0406-char-Throttle-when-host-connection-is-down.patch b/0406-char-Throttle-when-host-connection-is-down.patch new file mode 100644 index 0000000..2190637 --- /dev/null +++ b/0406-char-Throttle-when-host-connection-is-down.patch @@ -0,0 +1,57 @@ +From 542fa14530022044ab577c543fba83202d52b703 Mon Sep 17 00:00:00 2001 +From: Amit Shah +Date: Mon, 21 Mar 2011 22:05:10 +0100 +Subject: [PATCH] char: Throttle when host connection is down# + +When the host-side connection goes down, throttle the virtio-serial bus +and later unthrottle when a connection gets established. This helps +prevent any lost IO (guest->host) while the host connection was down. + +Bugzilla: 621484 + +This commit actually helps the bug mentioned above as no writes will now +get lost because of the throttling done here. With just the patches +sent earlier for that bug, one write will end up getting lost in the +worst case (host d/c, guest write, host connect). + +Signed-off-by: Amit Shah +Signed-off-by: Cole Robinson +--- + qemu-char.c | 14 ++++++++++++++ + 1 file changed, 14 insertions(+) + +diff --git a/qemu-char.c b/qemu-char.c +index 9f8608a..bfc94a5 100644 +--- a/qemu-char.c ++++ b/qemu-char.c +@@ -140,6 +140,9 @@ static void qemu_chr_generic_open_bh(void *opaque) + { + CharDriverState *s = opaque; + qemu_chr_be_event(s, CHR_EVENT_OPENED); ++ if (s->write_blocked) { ++ char_write_unblocked(s); ++ } + qemu_bh_delete(s->bh); + s->bh = NULL; + } +@@ -2244,6 +2247,17 @@ static int tcp_chr_write(CharDriverState *chr, const uint8_t *buf, int len) + ret = send_all(chr, s->fd, buf, len); + if (ret == -1 && errno == EPIPE) { + tcp_closed(chr); ++ ++ if (chr->chr_enable_write_fd_handler && chr->chr_write_unblocked) { ++ /* ++ * Since we haven't written out anything, let's say ++ * we're throttled. This will prevent any output from ++ * the guest getting lost if host-side chardev goes ++ * down. Unthrottle when we re-connect. ++ */ ++ chr->write_blocked = true; ++ return 0; ++ } + } + return ret; + } else { +-- +1.7.12.1 + diff --git a/0407-virtio-console-Enable-port-throttling-when-chardev-i.patch b/0407-virtio-console-Enable-port-throttling-when-chardev-i.patch new file mode 100644 index 0000000..85630c0 --- /dev/null +++ b/0407-virtio-console-Enable-port-throttling-when-chardev-i.patch @@ -0,0 +1,50 @@ +From feeea13d5eac9c0dd5da1ee7639a57ca519f4c91 Mon Sep 17 00:00:00 2001 +From: Amit Shah +Date: Mon, 21 Mar 2011 22:06:41 +0100 +Subject: [PATCH] virtio-console: Enable port throttling when chardev is slow + to consume data + +When a chardev indicates it can't accept more data, we tell the +virtio-serial code to stop sending us any more data till we tell +otherwise. This helps in guests continuing to run normally while the vq +keeps getting full and eventually the guest stops queueing more data. +As soon as the chardev indicates it can accept more data, start pushing! + +Signed-off-by: Amit Shah +Signed-off-by: Cole Robinson +--- + hw/virtio-console.c | 11 +++++++++++ + 1 file changed, 11 insertions(+) + +diff --git a/hw/virtio-console.c b/hw/virtio-console.c +index 066590c..2b5e515 100644 +--- a/hw/virtio-console.c ++++ b/hw/virtio-console.c +@@ -20,6 +20,16 @@ typedef struct VirtConsole { + CharDriverState *chr; + } VirtConsole; + ++/* ++ * Callback function that's called from chardevs when backend becomes ++ * writable. ++ */ ++static void chr_write_unblocked(void *opaque) ++{ ++ VirtConsole *vcon = opaque; ++ ++ virtio_serial_throttle_port(&vcon->port, false); ++} + + /* Callback function that's called when the guest sends us data */ + static ssize_t flush_buf(VirtIOSerialPort *port, const uint8_t *buf, size_t len) +@@ -110,6 +120,7 @@ static const QemuChrHandlers chr_handlers = { + .fd_can_read = chr_can_read, + .fd_read = chr_read, + .fd_event = chr_event, ++ .fd_write_unblocked = chr_write_unblocked, + }; + + static int virtconsole_initfn(VirtIOSerialPort *port) +-- +1.7.12.1 + diff --git a/0408-spice-qemu-char.c-add-throttling.patch b/0408-spice-qemu-char.c-add-throttling.patch new file mode 100644 index 0000000..23018ec --- /dev/null +++ b/0408-spice-qemu-char.c-add-throttling.patch @@ -0,0 +1,135 @@ +From 2d1cf5b1be8cbd9c5a8c5f96ca699676fc1b23a7 Mon Sep 17 00:00:00 2001 +From: Alon Levy +Date: Tue, 22 Mar 2011 12:27:59 +0200 +Subject: [PATCH] spice-qemu-char.c: add throttling + +BZ: 672191 + +upstream: not submitted (explained below) + +Adds throttling support to spicevmc chardev. Uses a timer to avoid recursing: +1. spice-server: reds.c: read_from_vdi_port +2. qemu: spice-qemu-char.c: vmc_read +3. chr_write_unblocked + (calls virtio_serial_throttle_port(port, false)) +4. qemu: virtio ... +5. qemu: spice-qemu-char.c: spice_chr_write +6. qemu: spice-qemu-char.c: wakeup (calls into spice-server) +7. spice-server: ... +8. qemu: spice-qemu-char.c: vmc_read + +Instead, in vmc_read if we were throttled and we are just about to return +all the bytes we will set a timer to be triggered immediately to call +chr_write_unblocked. Then we return after 2 above, and 3 is called from the +timer callback. This also means we can later remove some ugly recursion protection +from spice-server. + +The other tricky point in this patch is not returning the leftover chunk twice. +When we throttle, by definition we have data that spice server didn't consume. +It is being kept by virtio-serial, and by us. The next vmc_read callback needs +to not return it, but just do unthrottling. Then virtio will give us the remaining +chunk as usual in spice_chr_write, and we will pass it to spice server in the +next vmc_read. + +This patch relies on Amit's series to expose throttling to chardev's, which +was not accepted upstream, and will not be accepted upstream until the mainloop +is reworked to use glib. + +Signed-off-by: Cole Robinson +--- + spice-qemu-char.c | 39 +++++++++++++++++++++++++++++++++++---- + 1 file changed, 35 insertions(+), 4 deletions(-) + +diff --git a/spice-qemu-char.c b/spice-qemu-char.c +index 09aa22d..fba2bfb 100644 +--- a/spice-qemu-char.c ++++ b/spice-qemu-char.c +@@ -1,4 +1,6 @@ + #include "config-host.h" ++#include "qemu-common.h" ++#include "qemu-timer.h" + #include "trace.h" + #include "ui/qemu-spice.h" + #include +@@ -25,6 +27,7 @@ typedef struct SpiceCharDriver { + uint8_t *datapos; + ssize_t bufsize, datalen; + uint32_t debug; ++ QEMUTimer *unblock_timer; + } SpiceCharDriver; + + static int vmc_write(SpiceCharDeviceInstance *sin, const uint8_t *buf, int len) +@@ -50,6 +53,17 @@ static int vmc_write(SpiceCharDeviceInstance *sin, const uint8_t *buf, int len) + return out; + } + ++static void spice_chr_unblock(void *opaque) ++{ ++ SpiceCharDriver *scd = opaque; ++ ++ if (scd->chr->chr_write_unblocked == NULL) { ++ dprintf(scd, 1, "%s: backend doesn't support unthrottling.\n", __func__); ++ return; ++ } ++ scd->chr->chr_write_unblocked(scd->chr->handler_opaque); ++} ++ + static int vmc_read(SpiceCharDeviceInstance *sin, uint8_t *buf, int len) + { + SpiceCharDriver *scd = container_of(sin, SpiceCharDriver, sin); +@@ -61,9 +75,16 @@ static int vmc_read(SpiceCharDeviceInstance *sin, uint8_t *buf, int len) + scd->datapos += bytes; + scd->datalen -= bytes; + assert(scd->datalen >= 0); +- if (scd->datalen == 0) { +- scd->datapos = 0; +- } ++ } ++ if (scd->datalen == 0 && scd->chr->write_blocked) { ++ dprintf(scd, 1, "%s: unthrottling (%d)\n", __func__, bytes); ++ scd->chr->write_blocked = false; ++ /* ++ * set a timer instead of calling scd->chr->chr_write_unblocked directly, ++ * because that will call back into spice_chr_write (see ++ * virtio-console.c:chr_write_unblocked), which is unwanted. ++ */ ++ qemu_mod_timer(scd->unblock_timer, 0); + } + trace_spice_vmc_read(bytes, len); + return bytes; +@@ -135,6 +156,7 @@ static void vmc_unregister_interface(SpiceCharDriver *scd) + static int spice_chr_write(CharDriverState *chr, const uint8_t *buf, int len) + { + SpiceCharDriver *s = chr->opaque; ++ int read_bytes; + + dprintf(s, 2, "%s: %d\n", __func__, len); + vmc_register_interface(s); +@@ -147,7 +169,15 @@ static int spice_chr_write(CharDriverState *chr, const uint8_t *buf, int len) + s->datapos = s->buffer; + s->datalen = len; + spice_server_char_device_wakeup(&s->sin); +- return len; ++ read_bytes = len - s->datalen; ++ if (read_bytes != len) { ++ dprintf(s, 1, "%s: throttling: %d < %d (%zd)\n", __func__, ++ read_bytes, len, s->bufsize); ++ s->chr->write_blocked = true; ++ /* We'll get passed in the unconsumed data with the next call */ ++ s->datalen = 0; ++ } ++ return read_bytes; + } + + static void spice_chr_close(struct CharDriverState *chr) +@@ -225,6 +255,7 @@ CharDriverState *qemu_chr_open_spice(QemuOpts *opts) + chr->chr_close = spice_chr_close; + chr->chr_guest_open = spice_chr_guest_open; + chr->chr_guest_close = spice_chr_guest_close; ++ s->unblock_timer = qemu_new_timer_ms(vm_clock, spice_chr_unblock, s); + + #if SPICE_SERVER_VERSION < 0x000901 + /* See comment in vmc_state() */ +-- +1.7.12.1 + diff --git a/0409-spice-qemu-char.c-remove-intermediate-buffer.patch b/0409-spice-qemu-char.c-remove-intermediate-buffer.patch new file mode 100644 index 0000000..e1c6f0a --- /dev/null +++ b/0409-spice-qemu-char.c-remove-intermediate-buffer.patch @@ -0,0 +1,73 @@ +From fb481324641fc36e6f58aca8d8e5ada0536332f2 Mon Sep 17 00:00:00 2001 +From: Alon Levy +Date: Tue, 22 Mar 2011 12:28:00 +0200 +Subject: [PATCH] spice-qemu-char.c: remove intermediate buffer + +BZ: 672191 +upstream: not submitted (explained below) + +virtio-serial's buffer is valid when it calls us, and we don't +access it otherwise: vmc_read is only called in response to wakeup, +or else we set datalen=0 and throttle. Then vmc_read is called back, +we return 0 (not accessing the buffer) and set the timer to unthrottle. + +Also make datalen int and not ssize_t (to fit spice_chr_write signature). + +This relied on the previous patch that introduces throttling, which +can't go upstream right now as explained in that patch. + +Signed-off-by: Cole Robinson +--- + spice-qemu-char.c | 18 ++++++------------ + 1 file changed, 6 insertions(+), 12 deletions(-) + +diff --git a/spice-qemu-char.c b/spice-qemu-char.c +index fba2bfb..ef44bc0 100644 +--- a/spice-qemu-char.c ++++ b/spice-qemu-char.c +@@ -23,9 +23,8 @@ typedef struct SpiceCharDriver { + SpiceCharDeviceInstance sin; + char *subtype; + bool active; +- uint8_t *buffer; +- uint8_t *datapos; +- ssize_t bufsize, datalen; ++ const uint8_t *datapos; ++ int datalen; + uint32_t debug; + QEMUTimer *unblock_timer; + } SpiceCharDriver; +@@ -69,7 +68,7 @@ static int vmc_read(SpiceCharDeviceInstance *sin, uint8_t *buf, int len) + SpiceCharDriver *scd = container_of(sin, SpiceCharDriver, sin); + int bytes = MIN(len, scd->datalen); + +- dprintf(scd, 2, "%s: %p %d/%d/%zd\n", __func__, scd->datapos, len, bytes, scd->datalen); ++ dprintf(scd, 2, "%s: %p %d/%d/%d\n", __func__, scd->datapos, len, bytes, scd->datalen); + if (bytes > 0) { + memcpy(buf, scd->datapos, bytes); + scd->datapos += bytes; +@@ -161,18 +160,13 @@ static int spice_chr_write(CharDriverState *chr, const uint8_t *buf, int len) + dprintf(s, 2, "%s: %d\n", __func__, len); + vmc_register_interface(s); + assert(s->datalen == 0); +- if (s->bufsize < len) { +- s->bufsize = len; +- s->buffer = g_realloc(s->buffer, s->bufsize); +- } +- memcpy(s->buffer, buf, len); +- s->datapos = s->buffer; ++ s->datapos = buf; + s->datalen = len; + spice_server_char_device_wakeup(&s->sin); + read_bytes = len - s->datalen; + if (read_bytes != len) { +- dprintf(s, 1, "%s: throttling: %d < %d (%zd)\n", __func__, +- read_bytes, len, s->bufsize); ++ dprintf(s, 1, "%s: throttling: %d < %d\n", __func__, ++ read_bytes, len); + s->chr->write_blocked = true; + /* We'll get passed in the unconsumed data with the next call */ + s->datalen = 0; +-- +1.7.12.1 + diff --git a/0410-usb-redir-Add-flow-control-support.patch b/0410-usb-redir-Add-flow-control-support.patch new file mode 100644 index 0000000..8506b22 --- /dev/null +++ b/0410-usb-redir-Add-flow-control-support.patch @@ -0,0 +1,62 @@ +From 539b42dbeefbf2fc7dc40ab7c1b5d9592a87d9b8 Mon Sep 17 00:00:00 2001 +From: Hans de Goede +Date: Tue, 19 Jul 2011 10:56:19 +0200 +Subject: [PATCH] usb-redir: Add flow control support + +Signed-off-by: Hans de Goede +Signed-off-by: Cole Robinson +--- + hw/usb/redirect.c | 22 ++++++++++++++++++++-- + 1 file changed, 20 insertions(+), 2 deletions(-) + +diff --git a/hw/usb/redirect.c b/hw/usb/redirect.c +index 8b22c80..b7c7f1e 100644 +--- a/hw/usb/redirect.c ++++ b/hw/usb/redirect.c +@@ -229,12 +229,22 @@ static int usbredir_read(void *priv, uint8_t *data, int count) + static int usbredir_write(void *priv, uint8_t *data, int count) + { + USBRedirDevice *dev = priv; ++ int r; + +- if (!dev->cs->opened) { ++ if (!dev->cs->opened || dev->cs->write_blocked) { + return 0; + } + +- return qemu_chr_fe_write(dev->cs, data, count); ++ r = qemu_chr_fe_write(dev->cs, data, count); ++ ++ if (r < 0) { ++ if (dev->cs->write_blocked) { ++ return 0; ++ } ++ return -1; ++ } ++ ++ return r; + } + + /* +@@ -867,10 +877,18 @@ static void usbredir_chardev_event(void *opaque, int event) + } + } + ++static void usbredir_chardev_write_unblocked(void *opaque) ++{ ++ USBRedirDevice *dev = opaque; ++ ++ usbredirparser_do_write(dev->parser); ++} ++ + static const QemuChrHandlers usbredir_chr_handlers = { + .fd_can_read = usbredir_chardev_can_read, + .fd_read = usbredir_chardev_read, + .fd_event = usbredir_chardev_event, ++ .fd_write_unblocked = usbredir_chardev_write_unblocked, + }; + + /* +-- +1.7.12.1 + diff --git a/0411-virtio-serial-bus-replay-guest_open-on-migration.patch b/0411-virtio-serial-bus-replay-guest_open-on-migration.patch new file mode 100644 index 0000000..7cdc9bb --- /dev/null +++ b/0411-virtio-serial-bus-replay-guest_open-on-migration.patch @@ -0,0 +1,51 @@ +From a9bc20afc1f0604ee81c23b7c67d627e51d2e8d4 Mon Sep 17 00:00:00 2001 +From: Alon Levy +Date: Thu, 28 Jul 2011 15:08:48 +0300 +Subject: [PATCH] virtio-serial-bus: replay guest_open on migration + +When migrating a host with with a spice agent running the mouse becomes +non operational after the migration. This is rhbz #725965. + +The problem is that after migration spice doesn't know the guest agent is open. +Spice is just a char dev here. And a chardev cannot query it's device, the +device has to let the chardev know when it is open. Right now after migration +the chardev which is recreated is in it's default state, which assumes the +guest is disconnected. + +Char devices carry no information across migration, but the virtio-serial does +already carry the guest_connected state. This patch passes that bit to the +chardev. + +Signed-off-by: Alon Levy +Signed-off-by: Cole Robinson +--- + hw/virtio-serial-bus.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/hw/virtio-serial-bus.c b/hw/virtio-serial-bus.c +index 82073f5..18c2ed3 100644 +--- a/hw/virtio-serial-bus.c ++++ b/hw/virtio-serial-bus.c +@@ -682,6 +682,7 @@ static int virtio_serial_load(QEMUFile *f, void *opaque, int version_id) + for (i = 0; i < nr_active_ports; i++) { + uint32_t id; + bool host_connected; ++ VirtIOSerialPortClass *vsc; + + id = qemu_get_be32(f); + port = find_port_by_id(s, id); +@@ -690,6 +691,11 @@ static int virtio_serial_load(QEMUFile *f, void *opaque, int version_id) + } + + port->guest_connected = qemu_get_byte(f); ++ vsc = VIRTIO_SERIAL_PORT_GET_CLASS(port); ++ if (port->guest_connected && vsc->guest_open) { ++ /* replay guest open */ ++ vsc->guest_open(port); ++ } + host_connected = qemu_get_byte(f); + if (host_connected != port->host_connected) { + /* +-- +1.7.12.1 + diff --git a/0412-char-Disable-write-callback-if-throttled-chardev-is-.patch b/0412-char-Disable-write-callback-if-throttled-chardev-is-.patch new file mode 100644 index 0000000..ae0be6f --- /dev/null +++ b/0412-char-Disable-write-callback-if-throttled-chardev-is-.patch @@ -0,0 +1,37 @@ +From f3551d3640f3436b0e5505fd208cbd7bbfef411f Mon Sep 17 00:00:00 2001 +From: Amit Shah +Date: Fri, 2 Dec 2011 15:42:55 +0530 +Subject: [PATCH] char: Disable write callback if throttled chardev is + detached + +If a throttled chardev is detached from the frontend device, all future +callbacks should be suppressed. Not doing this results in a segfault. + +Bugzilla: 745758 +Upstream: Not applicable, since throttling is a RHEL6-only feature. + +Signed-off-by: Amit Shah +Signed-off-by: Cole Robinson +--- + qemu-char.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/qemu-char.c b/qemu-char.c +index bfc94a5..67a6d73 100644 +--- a/qemu-char.c ++++ b/qemu-char.c +@@ -223,6 +223,11 @@ void qemu_chr_add_handlers(CharDriverState *s, + ++s->avail_connections; + } + if (!handlers) { ++ if (s->write_blocked) { ++ /* Ensure we disable the callback if we were throttled */ ++ s->chr_disable_write_fd_handler(s); ++ /* s->write_blocked is cleared below */ ++ } + handlers = &null_handlers; + } + s->chr_can_read = handlers->fd_can_read; +-- +1.7.12.1 + diff --git a/0500-qxl-disallow-unknown-revisions.patch b/0500-qxl-disallow-unknown-revisions.patch new file mode 100644 index 0000000..331ca45 --- /dev/null +++ b/0500-qxl-disallow-unknown-revisions.patch @@ -0,0 +1,31 @@ +From 4b9d4103e5ff91b022ee8e9522040829f009543a Mon Sep 17 00:00:00 2001 +From: Alon Levy +Date: Tue, 21 Aug 2012 13:51:32 +0300 +Subject: [PATCH] qxl: disallow unknown revisions + +Signed-off-by: Alon Levy +Signed-off-by: Gerd Hoffmann +--- + hw/qxl.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/hw/qxl.c b/hw/qxl.c +index 59bf822..71879fe 100644 +--- a/hw/qxl.c ++++ b/hw/qxl.c +@@ -1873,9 +1873,9 @@ static int qxl_init_common(PCIQXLDevice *qxl) + break; + #endif + default: +- pci_device_rev = QXL_DEFAULT_REVISION; +- io_size = msb_mask(QXL_IO_RANGE_SIZE * 2 - 1); +- break; ++ error_report("Invalid revision %d for qxl device (max %d)", ++ qxl->revision, QXL_DEFAULT_REVISION); ++ return -1; + } + + pci_set_byte(&config[PCI_REVISION_ID], pci_device_rev); +-- +1.7.12.1 + diff --git a/0501-spice-make-number-of-surfaces-runtime-configurable.patch b/0501-spice-make-number-of-surfaces-runtime-configurable.patch new file mode 100644 index 0000000..b55c3df --- /dev/null +++ b/0501-spice-make-number-of-surfaces-runtime-configurable.patch @@ -0,0 +1,201 @@ +From 1c74b60fa972c9489f9cf8fa59165dedd0c23de2 Mon Sep 17 00:00:00 2001 +From: Gerd Hoffmann +Date: Tue, 4 Sep 2012 11:39:41 +0200 +Subject: [PATCH] spice: make number of surfaces runtime-configurable. + +Signed-off-by: Gerd Hoffmann +--- + hw/qxl.c | 31 +++++++++++++++++-------------- + hw/qxl.h | 3 +-- + ui/spice-display.c | 5 ++++- + ui/spice-display.h | 3 +-- + 4 files changed, 23 insertions(+), 19 deletions(-) + +diff --git a/hw/qxl.c b/hw/qxl.c +index 71879fe..83df499 100644 +--- a/hw/qxl.c ++++ b/hw/qxl.c +@@ -238,7 +238,8 @@ static void qxl_spice_destroy_surfaces_complete(PCIQXLDevice *qxl) + { + trace_qxl_spice_destroy_surfaces_complete(qxl->id); + qemu_mutex_lock(&qxl->track_lock); +- memset(&qxl->guest_surfaces.cmds, 0, sizeof(qxl->guest_surfaces.cmds)); ++ memset(qxl->guest_surfaces.cmds, 0, ++ sizeof(qxl->guest_surfaces.cmds) * qxl->ssd.num_surfaces); + qxl->guest_surfaces.count = 0; + qemu_mutex_unlock(&qxl->track_lock); + } +@@ -347,7 +348,7 @@ static void init_qxl_rom(PCIQXLDevice *d) + rom->slot_id_bits = MEMSLOT_SLOT_BITS; + rom->slots_start = 1; + rom->slots_end = NUM_MEMSLOTS - 1; +- rom->n_surfaces = cpu_to_le32(NUM_SURFACES); ++ rom->n_surfaces = cpu_to_le32(d->ssd.num_surfaces); + + for (i = 0, n = 0; i < ARRAY_SIZE(qxl_modes); i++) { + fb = qxl_modes[i].y_res * qxl_modes[i].stride; +@@ -451,9 +452,9 @@ static int qxl_track_command(PCIQXLDevice *qxl, struct QXLCommandExt *ext) + } + uint32_t id = le32_to_cpu(cmd->surface_id); + +- if (id >= NUM_SURFACES) { ++ if (id >= qxl->ssd.num_surfaces) { + qxl_set_guest_bug(qxl, "QXL_CMD_SURFACE id %d >= %d", id, +- NUM_SURFACES); ++ qxl->ssd.num_surfaces); + return 1; + } + qemu_mutex_lock(&qxl->track_lock); +@@ -529,7 +530,7 @@ static void interface_get_init_info(QXLInstance *sin, QXLDevInitInfo *info) + info->num_memslots_groups = NUM_MEMSLOTS_GROUPS; + info->internal_groupslot_id = 0; + info->qxl_ram_size = le32_to_cpu(qxl->shadow_rom.num_pages) << TARGET_PAGE_BITS; +- info->n_surfaces = NUM_SURFACES; ++ info->n_surfaces = qxl->ssd.num_surfaces; + } + + static const char *qxl_mode_to_string(int mode) +@@ -1438,7 +1439,7 @@ async_common: + QXLCookie *cookie = NULL; + QXLRect update = d->ram->update_area; + +- if (d->ram->update_surface > NUM_SURFACES) { ++ if (d->ram->update_surface > d->ssd.num_surfaces) { + qxl_set_guest_bug(d, "QXL_IO_UPDATE_AREA: invalid surface id %d\n", + d->ram->update_surface); + return; +@@ -1538,7 +1539,7 @@ async_common: + } + break; + case QXL_IO_DESTROY_SURFACE_WAIT: +- if (val >= NUM_SURFACES) { ++ if (val >= d->ssd.num_surfaces) { + qxl_set_guest_bug(d, "QXL_IO_DESTROY_SURFACE (async=%d):" + "%" PRIu64 " >= NUM_SURFACES", async, val); + goto cancel_async; +@@ -1717,7 +1718,7 @@ static void qxl_dirty_surfaces(PCIQXLDevice *qxl) + vram_start = (intptr_t)memory_region_get_ram_ptr(&qxl->vram_bar); + + /* dirty the off-screen surfaces */ +- for (i = 0; i < NUM_SURFACES; i++) { ++ for (i = 0; i < qxl->ssd.num_surfaces; i++) { + QXLSurfaceCmd *cmd; + intptr_t surface_offset; + int surface_size; +@@ -1845,7 +1846,6 @@ static int qxl_init_common(PCIQXLDevice *qxl) + qxl->mode = QXL_MODE_UNDEFINED; + qxl->generation = 1; + qxl->num_memslots = NUM_MEMSLOTS; +- qxl->num_surfaces = NUM_SURFACES; + qemu_mutex_init(&qxl->track_lock); + qemu_mutex_init(&qxl->async_lock); + qxl->current_async = QXL_UNDEFINED_IO; +@@ -1887,6 +1887,7 @@ static int qxl_init_common(PCIQXLDevice *qxl) + init_qxl_rom(qxl); + init_qxl_ram(qxl); + ++ qxl->guest_surfaces.cmds = g_new0(QXLPHYSICAL, qxl->ssd.num_surfaces); + memory_region_init_ram(&qxl->vram_bar, "qxl.vram", qxl->vram_size); + vmstate_register_ram(&qxl->vram_bar, &qxl->pci.qdev); + memory_region_init_alias(&qxl->vram32_bar, "qxl.vram32", &qxl->vram_bar, +@@ -2052,8 +2053,8 @@ static int qxl_post_load(void *opaque, int version) + qxl_create_guest_primary(d, 1, QXL_SYNC); + + /* replay surface-create and cursor-set commands */ +- cmds = g_malloc0(sizeof(QXLCommandExt) * (NUM_SURFACES + 1)); +- for (in = 0, out = 0; in < NUM_SURFACES; in++) { ++ cmds = g_malloc0(sizeof(QXLCommandExt) * (d->ssd.num_surfaces + 1)); ++ for (in = 0, out = 0; in < d->ssd.num_surfaces; in++) { + if (d->guest_surfaces.cmds[in] == 0) { + continue; + } +@@ -2153,9 +2154,10 @@ static VMStateDescription qxl_vmstate = { + qxl_memslot, struct guest_slots), + VMSTATE_STRUCT(guest_primary.surface, PCIQXLDevice, 0, + qxl_surface, QXLSurfaceCreate), +- VMSTATE_INT32_EQUAL(num_surfaces, PCIQXLDevice), +- VMSTATE_ARRAY(guest_surfaces.cmds, PCIQXLDevice, NUM_SURFACES, 0, +- vmstate_info_uint64, uint64_t), ++ VMSTATE_INT32_EQUAL(ssd.num_surfaces, PCIQXLDevice), ++ VMSTATE_VARRAY_INT32(guest_surfaces.cmds, PCIQXLDevice, ++ ssd.num_surfaces, 0, ++ vmstate_info_uint64, uint64_t), + VMSTATE_UINT64(guest_cursor, PCIQXLDevice), + VMSTATE_END_OF_LIST() + }, +@@ -2183,6 +2185,7 @@ static Property qxl_properties[] = { + DEFINE_PROP_UINT32("vram_size_mb", PCIQXLDevice, vram32_size_mb, -1), + DEFINE_PROP_UINT32("vram64_size_mb", PCIQXLDevice, vram_size_mb, -1), + DEFINE_PROP_UINT32("vgamem_mb", PCIQXLDevice, vgamem_size_mb, 16), ++ DEFINE_PROP_INT32("surfaces", PCIQXLDevice, ssd.num_surfaces, 1024), + DEFINE_PROP_END_OF_LIST(), + }; + +diff --git a/hw/qxl.h b/hw/qxl.h +index 9cfedb7..5553824 100644 +--- a/hw/qxl.h ++++ b/hw/qxl.h +@@ -40,7 +40,6 @@ typedef struct PCIQXLDevice { + uint32_t revision; + + int32_t num_memslots; +- int32_t num_surfaces; + + uint32_t current_async; + QemuMutex async_lock; +@@ -65,7 +64,7 @@ typedef struct PCIQXLDevice { + } guest_primary; + + struct surfaces { +- QXLPHYSICAL cmds[NUM_SURFACES]; ++ QXLPHYSICAL *cmds; + uint32_t count; + uint32_t max; + } guest_surfaces; +diff --git a/ui/spice-display.c b/ui/spice-display.c +index 1c31418..99bc665 100644 +--- a/ui/spice-display.c ++++ b/ui/spice-display.c +@@ -317,6 +317,9 @@ void qemu_spice_display_init_common(SimpleSpiceDisplay *ssd, DisplayState *ds) + qemu_mutex_init(&ssd->lock); + ssd->mouse_x = -1; + ssd->mouse_y = -1; ++ if (ssd->num_surfaces == 0) { ++ ssd->num_surfaces = 1024; ++ } + ssd->bufsize = (16 * 1024 * 1024); + ssd->buf = g_malloc(ssd->bufsize); + } +@@ -427,7 +430,7 @@ static void interface_get_init_info(QXLInstance *sin, QXLDevInitInfo *info) + info->num_memslots_groups = NUM_MEMSLOTS_GROUPS; + info->internal_groupslot_id = 0; + info->qxl_ram_size = ssd->bufsize; +- info->n_surfaces = NUM_SURFACES; ++ info->n_surfaces = ssd->num_surfaces; + } + + static int interface_get_command(QXLInstance *sin, struct QXLCommandExt *ext) +diff --git a/ui/spice-display.h b/ui/spice-display.h +index bcff114..512ab78 100644 +--- a/ui/spice-display.h ++++ b/ui/spice-display.h +@@ -32,8 +32,6 @@ + #define MEMSLOT_GROUP_GUEST 1 + #define NUM_MEMSLOTS_GROUPS 2 + +-#define NUM_SURFACES 1024 +- + /* + * Internal enum to differenciate between options for + * io calls that have a sync (old) version and an _async (new) +@@ -80,6 +78,7 @@ struct SimpleSpiceDisplay { + QXLInstance qxl; + uint32_t unique; + QemuPfConv *conv; ++ int32_t num_surfaces; + + QXLRect dirty; + int notify; +-- +1.7.12.1 + diff --git a/0502-qxl-Add-set_client_capabilities-interface-to-QXLInte.patch b/0502-qxl-Add-set_client_capabilities-interface-to-QXLInte.patch new file mode 100644 index 0000000..41c05f5 --- /dev/null +++ b/0502-qxl-Add-set_client_capabilities-interface-to-QXLInte.patch @@ -0,0 +1,64 @@ +From 0fe78ffd13555bed86a41acf96cdc15ece961b0d Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?S=C3=B8ren=20Sandmann=20Pedersen?= +Date: Tue, 4 Sep 2012 10:14:48 -0400 +Subject: [PATCH] qxl: Add set_client_capabilities() interface to QXLInterface + +This new interface lets spice server inform the guest whether + +(a) a client is connected +(b) what capabilities the client has + +There is a fixed number (464) of bits reserved for capabilities, and +when the capabilities bits change, the QXL_INTERRUPT_CLIENT interrupt +is generated. + +Signed-off-by: Soren Sandmann +Signed-off-by: Gerd Hoffmann +--- + hw/qxl.c | 23 +++++++++++++++++++++++ + 1 file changed, 23 insertions(+) + +diff --git a/hw/qxl.c b/hw/qxl.c +index 83df499..d8b67b2 100644 +--- a/hw/qxl.c ++++ b/hw/qxl.c +@@ -946,6 +946,26 @@ static void interface_async_complete(QXLInstance *sin, uint64_t cookie_token) + } + } + ++#if SPICE_SERVER_VERSION >= 0x000b04 ++ ++/* called from spice server thread context only */ ++static void interface_set_client_capabilities(QXLInstance *sin, ++ uint8_t client_present, ++ uint8_t caps[58]) ++{ ++ PCIQXLDevice *qxl = container_of(sin, PCIQXLDevice, ssd.qxl); ++ ++ qxl->shadow_rom.client_present = client_present; ++ memcpy(qxl->shadow_rom.client_capabilities, caps, sizeof(caps)); ++ qxl->rom->client_present = client_present; ++ memcpy(qxl->rom->client_capabilities, caps, sizeof(caps)); ++ qxl_rom_set_dirty(qxl); ++ ++ qxl_send_events(qxl, QXL_INTERRUPT_CLIENT); ++} ++ ++#endif ++ + static const QXLInterface qxl_interface = { + .base.type = SPICE_INTERFACE_QXL, + .base.description = "qxl gpu", +@@ -967,6 +987,9 @@ static const QXLInterface qxl_interface = { + .flush_resources = interface_flush_resources, + .async_complete = interface_async_complete, + .update_area_complete = interface_update_area_complete, ++#if SPICE_SERVER_VERSION >= 0x000b04 ++ .set_client_capabilities = interface_set_client_capabilities, ++#endif + }; + + static void qxl_enter_vga_mode(PCIQXLDevice *d) +-- +1.7.12.1 + diff --git a/0503-Remove-ifdef-QXL_COMMAND_FLAG_COMPAT_16BPP.patch b/0503-Remove-ifdef-QXL_COMMAND_FLAG_COMPAT_16BPP.patch new file mode 100644 index 0000000..899e280 --- /dev/null +++ b/0503-Remove-ifdef-QXL_COMMAND_FLAG_COMPAT_16BPP.patch @@ -0,0 +1,32 @@ +From 0dcef831a875505fdaffb824de9e4450273ea53d Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?S=C3=B8ren=20Sandmann=20Pedersen?= +Date: Tue, 4 Sep 2012 10:14:49 -0400 +Subject: [PATCH] Remove #ifdef QXL_COMMAND_FLAG_COMPAT_16BPP + +We require spice >= 0.8 now, so this flag is always present. + +Signed-off-by: Soren Sandmann +Signed-off-by: Gerd Hoffmann +--- + hw/qxl.c | 2 -- + 1 file changed, 2 deletions(-) + +diff --git a/hw/qxl.c b/hw/qxl.c +index d8b67b2..a6e6cf1 100644 +--- a/hw/qxl.c ++++ b/hw/qxl.c +@@ -1361,11 +1361,9 @@ static void qxl_set_mode(PCIQXLDevice *d, int modenr, int loadvm) + + d->mode = QXL_MODE_COMPAT; + d->cmdflags = QXL_COMMAND_FLAG_COMPAT; +-#ifdef QXL_COMMAND_FLAG_COMPAT_16BPP /* new in spice 0.6.1 */ + if (mode->bits == 16) { + d->cmdflags |= QXL_COMMAND_FLAG_COMPAT_16BPP; + } +-#endif + d->shadow_rom.mode = cpu_to_le32(modenr); + d->rom->mode = cpu_to_le32(modenr); + qxl_rom_set_dirty(d); +-- +1.7.12.1 + diff --git a/0504-spice-switch-to-queue-for-vga-mode-updates.patch b/0504-spice-switch-to-queue-for-vga-mode-updates.patch new file mode 100644 index 0000000..b9726e8 --- /dev/null +++ b/0504-spice-switch-to-queue-for-vga-mode-updates.patch @@ -0,0 +1,138 @@ +From 244ff52221b4c4181422861a930d8f755a1a5c08 Mon Sep 17 00:00:00 2001 +From: Gerd Hoffmann +Date: Wed, 5 Sep 2012 08:25:08 +0200 +Subject: [PATCH] spice: switch to queue for vga mode updates + +Signed-off-by: Gerd Hoffmann +--- + hw/qxl.c | 6 +++--- + ui/spice-display.c | 25 ++++++++++++++----------- + ui/spice-display.h | 3 ++- + 3 files changed, 19 insertions(+), 15 deletions(-) + +diff --git a/hw/qxl.c b/hw/qxl.c +index a6e6cf1..2ec4341 100644 +--- a/hw/qxl.c ++++ b/hw/qxl.c +@@ -599,9 +599,9 @@ static int interface_get_command(QXLInstance *sin, struct QXLCommandExt *ext) + case QXL_MODE_VGA: + ret = false; + qemu_mutex_lock(&qxl->ssd.lock); +- if (qxl->ssd.update != NULL) { +- update = qxl->ssd.update; +- qxl->ssd.update = NULL; ++ update = QTAILQ_FIRST(&qxl->ssd.updates); ++ if (update != NULL) { ++ QTAILQ_REMOVE(&qxl->ssd.updates, update, next); + *ext = update->ext; + ret = true; + } +diff --git a/ui/spice-display.c b/ui/spice-display.c +index 99bc665..59c5fd7 100644 +--- a/ui/spice-display.c ++++ b/ui/spice-display.c +@@ -164,7 +164,7 @@ int qemu_spice_display_is_running(SimpleSpiceDisplay *ssd) + #endif + } + +-static SimpleSpiceUpdate *qemu_spice_create_update(SimpleSpiceDisplay *ssd) ++static void qemu_spice_create_update(SimpleSpiceDisplay *ssd) + { + SimpleSpiceUpdate *update; + QXLDrawable *drawable; +@@ -175,7 +175,7 @@ static SimpleSpiceUpdate *qemu_spice_create_update(SimpleSpiceDisplay *ssd) + struct timespec time_space; + + if (qemu_spice_rect_is_empty(&ssd->dirty)) { +- return NULL; ++ return; + }; + + trace_qemu_spice_create_update( +@@ -239,7 +239,7 @@ static SimpleSpiceUpdate *qemu_spice_create_update(SimpleSpiceDisplay *ssd) + cmd->data = (uintptr_t)drawable; + + memset(&ssd->dirty, 0, sizeof(ssd->dirty)); +- return update; ++ QTAILQ_INSERT_TAIL(&ssd->updates, update, next); + } + + /* +@@ -315,6 +315,7 @@ void qemu_spice_display_init_common(SimpleSpiceDisplay *ssd, DisplayState *ds) + { + ssd->ds = ds; + qemu_mutex_init(&ssd->lock); ++ QTAILQ_INIT(&ssd->updates); + ssd->mouse_x = -1; + ssd->mouse_y = -1; + if (ssd->num_surfaces == 0) { +@@ -345,6 +346,8 @@ void qemu_spice_display_update(SimpleSpiceDisplay *ssd, + + void qemu_spice_display_resize(SimpleSpiceDisplay *ssd) + { ++ SimpleSpiceUpdate *update; ++ + dprint(1, "%s:\n", __FUNCTION__); + + memset(&ssd->dirty, 0, sizeof(ssd->dirty)); +@@ -352,9 +355,9 @@ void qemu_spice_display_resize(SimpleSpiceDisplay *ssd) + ssd->conv = NULL; + + qemu_mutex_lock(&ssd->lock); +- if (ssd->update != NULL) { +- qemu_spice_destroy_update(ssd, ssd->update); +- ssd->update = NULL; ++ while ((update = QTAILQ_FIRST(&ssd->updates)) != NULL) { ++ QTAILQ_REMOVE(&ssd->updates, update, next); ++ qemu_spice_destroy_update(ssd, update); + } + qemu_mutex_unlock(&ssd->lock); + qemu_spice_destroy_host_primary(ssd); +@@ -384,8 +387,8 @@ void qemu_spice_display_refresh(SimpleSpiceDisplay *ssd) + vga_hw_update(); + + qemu_mutex_lock(&ssd->lock); +- if (ssd->update == NULL) { +- ssd->update = qemu_spice_create_update(ssd); ++ if (QTAILQ_EMPTY(&ssd->updates)) { ++ qemu_spice_create_update(ssd); + ssd->notify++; + } + qemu_spice_cursor_refresh_unlocked(ssd); +@@ -442,9 +445,9 @@ static int interface_get_command(QXLInstance *sin, struct QXLCommandExt *ext) + dprint(3, "%s:\n", __FUNCTION__); + + qemu_mutex_lock(&ssd->lock); +- if (ssd->update != NULL) { +- update = ssd->update; +- ssd->update = NULL; ++ update = QTAILQ_FIRST(&ssd->updates); ++ if (update != NULL) { ++ QTAILQ_REMOVE(&ssd->updates, update, next); + *ext = update->ext; + ret = true; + } +diff --git a/ui/spice-display.h b/ui/spice-display.h +index 512ab78..3fcb6fe 100644 +--- a/ui/spice-display.h ++++ b/ui/spice-display.h +@@ -92,7 +92,7 @@ struct SimpleSpiceDisplay { + * to them must be protected by the lock. + */ + QemuMutex lock; +- SimpleSpiceUpdate *update; ++ QTAILQ_HEAD(, SimpleSpiceUpdate) updates; + QEMUCursor *cursor; + int mouse_x, mouse_y; + }; +@@ -102,6 +102,7 @@ struct SimpleSpiceUpdate { + QXLImage image; + QXLCommandExt ext; + uint8_t *bitmap; ++ QTAILQ_ENTRY(SimpleSpiceUpdate) next; + }; + + int qemu_spice_rect_is_empty(const QXLRect* r); +-- +1.7.12.1 + diff --git a/0505-spice-split-qemu_spice_create_update.patch b/0505-spice-split-qemu_spice_create_update.patch new file mode 100644 index 0000000..d761fcf --- /dev/null +++ b/0505-spice-split-qemu_spice_create_update.patch @@ -0,0 +1,94 @@ +From 6d196973a9adba583cf9bbc5a4196a58f2cb0eb3 Mon Sep 17 00:00:00 2001 +From: Gerd Hoffmann +Date: Wed, 5 Sep 2012 08:52:23 +0200 +Subject: [PATCH] spice: split qemu_spice_create_update + +Creating one function which creates a single update for a given +rectangle. And one (for now) pretty simple wrapper around it to +queue up screen updates for the dirty region. + +[ v2: also update bounding box ] + +Signed-off-by: Gerd Hoffmann +--- + ui/spice-display.c | 31 ++++++++++++++++++------------- + 1 file changed, 18 insertions(+), 13 deletions(-) + +diff --git a/ui/spice-display.c b/ui/spice-display.c +index 59c5fd7..6f68f28 100644 +--- a/ui/spice-display.c ++++ b/ui/spice-display.c +@@ -164,7 +164,8 @@ int qemu_spice_display_is_running(SimpleSpiceDisplay *ssd) + #endif + } + +-static void qemu_spice_create_update(SimpleSpiceDisplay *ssd) ++static void qemu_spice_create_one_update(SimpleSpiceDisplay *ssd, ++ QXLRect *rect) + { + SimpleSpiceUpdate *update; + QXLDrawable *drawable; +@@ -174,24 +175,20 @@ static void qemu_spice_create_update(SimpleSpiceDisplay *ssd) + int by, bw, bh; + struct timespec time_space; + +- if (qemu_spice_rect_is_empty(&ssd->dirty)) { +- return; +- }; +- + trace_qemu_spice_create_update( +- ssd->dirty.left, ssd->dirty.right, +- ssd->dirty.top, ssd->dirty.bottom); ++ rect->left, rect->right, ++ rect->top, rect->bottom); + + update = g_malloc0(sizeof(*update)); + drawable = &update->drawable; + image = &update->image; + cmd = &update->ext.cmd; + +- bw = ssd->dirty.right - ssd->dirty.left; +- bh = ssd->dirty.bottom - ssd->dirty.top; ++ bw = rect->right - rect->left; ++ bh = rect->bottom - rect->top; + update->bitmap = g_malloc(bw * bh * 4); + +- drawable->bbox = ssd->dirty; ++ drawable->bbox = *rect; + drawable->clip.type = SPICE_CLIP_TYPE_NONE; + drawable->effect = QXL_EFFECT_OPAQUE; + drawable->release_info.id = (uintptr_t)update; +@@ -226,8 +223,8 @@ static void qemu_spice_create_update(SimpleSpiceDisplay *ssd) + } + + src = ds_get_data(ssd->ds) + +- ssd->dirty.top * ds_get_linesize(ssd->ds) + +- ssd->dirty.left * ds_get_bytes_per_pixel(ssd->ds); ++ rect->top * ds_get_linesize(ssd->ds) + ++ rect->left * ds_get_bytes_per_pixel(ssd->ds); + dst = update->bitmap; + for (by = 0; by < bh; by++) { + qemu_pf_conv_run(ssd->conv, dst, src, bw); +@@ -238,10 +235,18 @@ static void qemu_spice_create_update(SimpleSpiceDisplay *ssd) + cmd->type = QXL_CMD_DRAW; + cmd->data = (uintptr_t)drawable; + +- memset(&ssd->dirty, 0, sizeof(ssd->dirty)); + QTAILQ_INSERT_TAIL(&ssd->updates, update, next); + } + ++static void qemu_spice_create_update(SimpleSpiceDisplay *ssd) ++{ ++ if (qemu_spice_rect_is_empty(&ssd->dirty)) { ++ return; ++ }; ++ qemu_spice_create_one_update(ssd, &ssd->dirty); ++ memset(&ssd->dirty, 0, sizeof(ssd->dirty)); ++} ++ + /* + * Called from spice server thread context (via interface_release_ressource) + * We do *not* hold the global qemu mutex here, so extra care is needed +-- +1.7.12.1 + diff --git a/0506-spice-add-screen-mirror.patch b/0506-spice-add-screen-mirror.patch new file mode 100644 index 0000000..6ee91d1 --- /dev/null +++ b/0506-spice-add-screen-mirror.patch @@ -0,0 +1,98 @@ +From 9f4c601032d7a27e8856517a1a020c9988667ed3 Mon Sep 17 00:00:00 2001 +From: Gerd Hoffmann +Date: Wed, 5 Sep 2012 09:35:57 +0200 +Subject: [PATCH] spice: add screen mirror + +Create a screen mirror, keep there a copy of the most recent update +passed on to spice-server. + +Signed-off-by: Gerd Hoffmann +--- + ui/spice-display.c | 32 ++++++++++++++++++++++---------- + ui/spice-display.h | 1 + + 2 files changed, 23 insertions(+), 10 deletions(-) + +diff --git a/ui/spice-display.c b/ui/spice-display.c +index 6f68f28..973cd53 100644 +--- a/ui/spice-display.c ++++ b/ui/spice-display.c +@@ -171,8 +171,8 @@ static void qemu_spice_create_one_update(SimpleSpiceDisplay *ssd, + QXLDrawable *drawable; + QXLImage *image; + QXLCommand *cmd; +- uint8_t *src, *dst; +- int by, bw, bh; ++ uint8_t *src, *mirror, *dst; ++ int by, bw, bh, offset, bytes; + struct timespec time_space; + + trace_qemu_spice_create_update( +@@ -216,19 +216,18 @@ static void qemu_spice_create_one_update(SimpleSpiceDisplay *ssd, + image->bitmap.palette = 0; + image->bitmap.format = SPICE_BITMAP_FMT_32BIT; + +- if (ssd->conv == NULL) { +- PixelFormat dst = qemu_default_pixelformat(32); +- ssd->conv = qemu_pf_conv_get(&dst, &ssd->ds->surface->pf); +- assert(ssd->conv); +- } +- +- src = ds_get_data(ssd->ds) + ++ offset = + rect->top * ds_get_linesize(ssd->ds) + + rect->left * ds_get_bytes_per_pixel(ssd->ds); ++ bytes = ds_get_bytes_per_pixel(ssd->ds) * bw; ++ src = ds_get_data(ssd->ds) + offset; ++ mirror = ssd->ds_mirror + offset; + dst = update->bitmap; + for (by = 0; by < bh; by++) { +- qemu_pf_conv_run(ssd->conv, dst, src, bw); ++ memcpy(mirror, src, bytes); ++ qemu_pf_conv_run(ssd->conv, dst, mirror, bw); + src += ds_get_linesize(ssd->ds); ++ mirror += ds_get_linesize(ssd->ds); + dst += image->bitmap.stride; + } + +@@ -243,6 +242,17 @@ static void qemu_spice_create_update(SimpleSpiceDisplay *ssd) + if (qemu_spice_rect_is_empty(&ssd->dirty)) { + return; + }; ++ ++ if (ssd->conv == NULL) { ++ PixelFormat dst = qemu_default_pixelformat(32); ++ ssd->conv = qemu_pf_conv_get(&dst, &ssd->ds->surface->pf); ++ assert(ssd->conv); ++ } ++ if (ssd->ds_mirror == NULL) { ++ int size = ds_get_height(ssd->ds) * ds_get_linesize(ssd->ds); ++ ssd->ds_mirror = g_malloc0(size); ++ } ++ + qemu_spice_create_one_update(ssd, &ssd->dirty); + memset(&ssd->dirty, 0, sizeof(ssd->dirty)); + } +@@ -358,6 +368,8 @@ void qemu_spice_display_resize(SimpleSpiceDisplay *ssd) + memset(&ssd->dirty, 0, sizeof(ssd->dirty)); + qemu_pf_conv_put(ssd->conv); + ssd->conv = NULL; ++ g_free(ssd->ds_mirror); ++ ssd->ds_mirror = NULL; + + qemu_mutex_lock(&ssd->lock); + while ((update = QTAILQ_FIRST(&ssd->updates)) != NULL) { +diff --git a/ui/spice-display.h b/ui/spice-display.h +index 3fcb6fe..dea41c1 100644 +--- a/ui/spice-display.h ++++ b/ui/spice-display.h +@@ -72,6 +72,7 @@ typedef struct SimpleSpiceUpdate SimpleSpiceUpdate; + + struct SimpleSpiceDisplay { + DisplayState *ds; ++ uint8_t *ds_mirror; + void *buf; + int bufsize; + QXLWorker *worker; +-- +1.7.12.1 + diff --git a/0507-spice-send-updates-only-for-changed-screen-content.patch b/0507-spice-send-updates-only-for-changed-screen-content.patch new file mode 100644 index 0000000..b575091 --- /dev/null +++ b/0507-spice-send-updates-only-for-changed-screen-content.patch @@ -0,0 +1,93 @@ +From e2da4b3f683ae63a55b8e50903a164f704be9e1d Mon Sep 17 00:00:00 2001 +From: Gerd Hoffmann +Date: Wed, 5 Sep 2012 10:41:42 +0200 +Subject: [PATCH] spice: send updates only for changed screen content + +when creating screen updates go compare the current guest screen +against the mirror (which holds the most recent update sent), then +only create updates for the screen areas which did actually change. + +[ v2: drop redundant qemu_spice_create_one_update call ] + +Signed-off-by: Gerd Hoffmann +--- + ui/spice-display.c | 56 +++++++++++++++++++++++++++++++++++++++++++++++++++++- + 1 file changed, 55 insertions(+), 1 deletion(-) + +diff --git a/ui/spice-display.c b/ui/spice-display.c +index 973cd53..d062765 100644 +--- a/ui/spice-display.c ++++ b/ui/spice-display.c +@@ -239,6 +239,13 @@ static void qemu_spice_create_one_update(SimpleSpiceDisplay *ssd, + + static void qemu_spice_create_update(SimpleSpiceDisplay *ssd) + { ++ static const int blksize = 32; ++ int blocks = (ds_get_width(ssd->ds) + blksize - 1) / blksize; ++ int dirty_top[blocks]; ++ int y, yoff, x, xoff, blk, bw; ++ int bpp = ds_get_bytes_per_pixel(ssd->ds); ++ uint8_t *guest, *mirror; ++ + if (qemu_spice_rect_is_empty(&ssd->dirty)) { + return; + }; +@@ -253,7 +260,54 @@ static void qemu_spice_create_update(SimpleSpiceDisplay *ssd) + ssd->ds_mirror = g_malloc0(size); + } + +- qemu_spice_create_one_update(ssd, &ssd->dirty); ++ for (blk = 0; blk < blocks; blk++) { ++ dirty_top[blk] = -1; ++ } ++ ++ guest = ds_get_data(ssd->ds); ++ mirror = ssd->ds_mirror; ++ for (y = ssd->dirty.top; y < ssd->dirty.bottom; y++) { ++ yoff = y * ds_get_linesize(ssd->ds); ++ for (x = ssd->dirty.left; x < ssd->dirty.right; x += blksize) { ++ xoff = x * bpp; ++ blk = x / blksize; ++ bw = MIN(blksize, ssd->dirty.right - x); ++ if (memcmp(guest + yoff + xoff, ++ mirror + yoff + xoff, ++ bw * bpp) == 0) { ++ if (dirty_top[blk] != -1) { ++ QXLRect update = { ++ .top = dirty_top[blk], ++ .bottom = y, ++ .left = x, ++ .right = x + bw, ++ }; ++ qemu_spice_create_one_update(ssd, &update); ++ dirty_top[blk] = -1; ++ } ++ } else { ++ if (dirty_top[blk] == -1) { ++ dirty_top[blk] = y; ++ } ++ } ++ } ++ } ++ ++ for (x = ssd->dirty.left; x < ssd->dirty.right; x += blksize) { ++ blk = x / blksize; ++ bw = MIN(blksize, ssd->dirty.right - x); ++ if (dirty_top[blk] != -1) { ++ QXLRect update = { ++ .top = dirty_top[blk], ++ .bottom = ssd->dirty.bottom, ++ .left = x, ++ .right = x + bw, ++ }; ++ qemu_spice_create_one_update(ssd, &update); ++ dirty_top[blk] = -1; ++ } ++ } ++ + memset(&ssd->dirty, 0, sizeof(ssd->dirty)); + } + +-- +1.7.12.1 + diff --git a/0508-qxl-Ignore-set_client_capabilities-pre-post-migrate.patch b/0508-qxl-Ignore-set_client_capabilities-pre-post-migrate.patch new file mode 100644 index 0000000..78845b8 --- /dev/null +++ b/0508-qxl-Ignore-set_client_capabilities-pre-post-migrate.patch @@ -0,0 +1,41 @@ +From 984e5c7aee378a8de44ff54891695115b92fe585 Mon Sep 17 00:00:00 2001 +From: Hans de Goede +Date: Fri, 7 Sep 2012 21:29:22 +0200 +Subject: [PATCH] qxl: Ignore set_client_capabilities pre/post migrate + +The recent introduction of set_client_capabilities has broken +(seamless) migration by trying to call qxl_send_events pre (seamless +incoming) and post (*) migration, triggering the following assert: +qxl_send_events: Assertion `qemu_spice_display_is_running(&d->ssd)' failed. + +The solution is easy, pre migration the guest will have already received +the client caps on the migration source side, and post migration there no +longer is a guest, so we can simply ignore the set_client_capabilities call +in both those scenarios. + +*) Post migration, so not fatal for to the migration itself, but still a crash + +Signed-off-by: Hans de Goede +--- + hw/qxl.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/hw/qxl.c b/hw/qxl.c +index 2ec4341..360f4f6 100644 +--- a/hw/qxl.c ++++ b/hw/qxl.c +@@ -955,6 +955,11 @@ static void interface_set_client_capabilities(QXLInstance *sin, + { + PCIQXLDevice *qxl = container_of(sin, PCIQXLDevice, ssd.qxl); + ++ if (runstate_check(RUN_STATE_INMIGRATE) || ++ runstate_check(RUN_STATE_POSTMIGRATE)) { ++ return; ++ } ++ + qxl->shadow_rom.client_present = client_present; + memcpy(qxl->shadow_rom.client_capabilities, caps, sizeof(caps)); + qxl->rom->client_present = client_present; +-- +1.7.12.1 + diff --git a/0509-qxl-add-trace-event-for-QXL_IO_LOG.patch b/0509-qxl-add-trace-event-for-QXL_IO_LOG.patch new file mode 100644 index 0000000..d5093de --- /dev/null +++ b/0509-qxl-add-trace-event-for-QXL_IO_LOG.patch @@ -0,0 +1,39 @@ +From 720192d056402f47a8f71d9ac9bc4b0cf37902ed Mon Sep 17 00:00:00 2001 +From: Alon Levy +Date: Wed, 12 Sep 2012 16:13:27 +0300 +Subject: [PATCH] qxl: add trace-event for QXL_IO_LOG + +Signed-off-by: Alon Levy +Signed-off-by: Gerd Hoffmann +--- + hw/qxl.c | 1 + + trace-events | 1 + + 2 files changed, 2 insertions(+) + +diff --git a/hw/qxl.c b/hw/qxl.c +index 360f4f6..1ef117a 100644 +--- a/hw/qxl.c ++++ b/hw/qxl.c +@@ -1515,6 +1515,7 @@ async_common: + qxl_set_mode(d, val, 0); + break; + case QXL_IO_LOG: ++ trace_qxl_io_log(d->id, d->ram->log_buf); + if (d->guestdebug) { + fprintf(stderr, "qxl/guest-%d: %" PRId64 ": %s", d->id, + qemu_get_clock_ns(vm_clock), d->ram->log_buf); +diff --git a/trace-events b/trace-events +index aa79836..80a52d9 100644 +--- a/trace-events ++++ b/trace-events +@@ -930,6 +930,7 @@ qxl_interface_update_area_complete_rest(int qid, uint32_t num_updated_rects) "%d + qxl_interface_update_area_complete_overflow(int qid, int max) "%d max=%d" + qxl_interface_update_area_complete_schedule_bh(int qid, uint32_t num_dirty) "%d #dirty=%d" + qxl_io_destroy_primary_ignored(int qid, const char *mode) "%d %s" ++qxl_io_log(int qid, const uint8_t *str) "%d %s" + qxl_io_read_unexpected(int qid) "%d" + qxl_io_unexpected_vga_mode(int qid, uint64_t addr, uint64_t val, const char *desc) "%d 0x%"PRIx64"=%"PRIu64" (%s)" + qxl_io_write(int qid, const char *mode, uint64_t addr, uint64_t val, unsigned size, int async) "%d %s addr=%"PRIu64 " val=%"PRIu64" size=%u async=%d" +-- +1.7.12.1 + diff --git a/0510-hw-qxl-support-client-monitor-configuration-via-devi.patch b/0510-hw-qxl-support-client-monitor-configuration-via-devi.patch new file mode 100644 index 0000000..4a00940 --- /dev/null +++ b/0510-hw-qxl-support-client-monitor-configuration-via-devi.patch @@ -0,0 +1,181 @@ +From f5c2bd00890dc32e940e8b2fae09f62f758317eb Mon Sep 17 00:00:00 2001 +From: Alon Levy +Date: Wed, 12 Sep 2012 16:13:28 +0300 +Subject: [PATCH] hw/qxl: support client monitor configuration via device + +Until now we used only the agent to change the monitor count and each +monitor resolution. This patch introduces the qemu part of using the +device as the mediator instead of the agent via virtio-serial. + +Spice (>=0.11.5) calls the new QXLInterface::client_monitors_config, +which returns wether the interrupt is enabled, and if so and given a non +NULL monitors config will +generate an interrupt QXL_INTERRUPT_CLIENT_MONITORS_CONFIG with crc +checksum for the guest to verify a second call hasn't interfered. + +The maximal number of monitors is limited on the QXLRom to 64. + +Signed-off-by: Alon Levy +Signed-off-by: Gerd Hoffmann +--- + configure | 7 ++++++ + hw/qxl.c | 79 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + trace-events | 6 ++++- + 3 files changed, 91 insertions(+), 1 deletion(-) + +diff --git a/configure b/configure +index f528146..83c478c 100755 +--- a/configure ++++ b/configure +@@ -2706,6 +2706,9 @@ EOF + if $pkg_config --atleast-version=0.12.0 spice-protocol >/dev/null 2>&1; then + spice_qxl_io_monitors_config_async="yes" + fi ++ if $pkg_config --atleast-version=0.12.2 spice-protocol > /dev/null 2>&1; then ++ spice_qxl_client_monitors_config="yes" ++ fi + else + if test "$spice" = "yes" ; then + feature_not_found "spice" +@@ -3453,6 +3456,10 @@ if test "$spice_qxl_io_monitors_config_async" = "yes" ; then + echo "CONFIG_QXL_IO_MONITORS_CONFIG_ASYNC=y" >> $config_host_mak + fi + ++if test "$spice_qxl_client_monitors_config" = "yes" ; then ++ echo "CONFIG_QXL_CLIENT_MONITORS_CONFIG=y" >> $config_host_mak ++fi ++ + if test "$smartcard" = "yes" ; then + echo "CONFIG_SMARTCARD=y" >> $config_host_mak + fi +diff --git a/hw/qxl.c b/hw/qxl.c +index 1ef117a..0695872 100644 +--- a/hw/qxl.c ++++ b/hw/qxl.c +@@ -18,6 +18,8 @@ + * along with this program; if not, see . + */ + ++#include ++ + #include "qemu-common.h" + #include "qemu-timer.h" + #include "qemu-queue.h" +@@ -971,6 +973,79 @@ static void interface_set_client_capabilities(QXLInstance *sin, + + #endif + ++#if defined(CONFIG_QXL_CLIENT_MONITORS_CONFIG) \ ++ && SPICE_SERVER_VERSION >= 0x000b05 ++ ++static uint32_t qxl_crc32(const uint8_t *p, unsigned len) ++{ ++ /* ++ * zlib xors the seed with 0xffffffff, and xors the result ++ * again with 0xffffffff; Both are not done with linux's crc32, ++ * which we want to be compatible with, so undo that. ++ */ ++ return crc32(0xffffffff, p, len) ^ 0xffffffff; ++} ++ ++/* called from main context only */ ++static int interface_client_monitors_config(QXLInstance *sin, ++ VDAgentMonitorsConfig *monitors_config) ++{ ++ PCIQXLDevice *qxl = container_of(sin, PCIQXLDevice, ssd.qxl); ++ QXLRom *rom = memory_region_get_ram_ptr(&qxl->rom_bar); ++ int i; ++ ++ /* ++ * Older windows drivers set int_mask to 0 when their ISR is called, ++ * then later set it to ~0. So it doesn't relate to the actual interrupts ++ * handled. However, they are old, so clearly they don't support this ++ * interrupt ++ */ ++ if (qxl->ram->int_mask == 0 || qxl->ram->int_mask == ~0 || ++ !(qxl->ram->int_mask & QXL_INTERRUPT_CLIENT_MONITORS_CONFIG)) { ++ trace_qxl_client_monitors_config_unsupported_by_guest(qxl->id, ++ qxl->ram->int_mask, ++ monitors_config); ++ return 0; ++ } ++ if (!monitors_config) { ++ return 1; ++ } ++ memset(&rom->client_monitors_config, 0, ++ sizeof(rom->client_monitors_config)); ++ rom->client_monitors_config.count = monitors_config->num_of_monitors; ++ /* monitors_config->flags ignored */ ++ if (rom->client_monitors_config.count >= ++ ARRAY_SIZE(rom->client_monitors_config.heads)) { ++ trace_qxl_client_monitors_config_capped(qxl->id, ++ monitors_config->num_of_monitors, ++ ARRAY_SIZE(rom->client_monitors_config.heads)); ++ rom->client_monitors_config.count = ++ ARRAY_SIZE(rom->client_monitors_config.heads); ++ } ++ for (i = 0 ; i < rom->client_monitors_config.count ; ++i) { ++ VDAgentMonConfig *monitor = &monitors_config->monitors[i]; ++ QXLURect *rect = &rom->client_monitors_config.heads[i]; ++ /* monitor->depth ignored */ ++ rect->left = monitor->x; ++ rect->top = monitor->y; ++ rect->right = monitor->x + monitor->width; ++ rect->bottom = monitor->y + monitor->height; ++ } ++ rom->client_monitors_config_crc = qxl_crc32( ++ (const uint8_t *)&rom->client_monitors_config, ++ sizeof(rom->client_monitors_config)); ++ trace_qxl_client_monitors_config_crc(qxl->id, ++ sizeof(rom->client_monitors_config), ++ rom->client_monitors_config_crc); ++ ++ trace_qxl_interrupt_client_monitors_config(qxl->id, ++ rom->client_monitors_config.count, ++ rom->client_monitors_config.heads); ++ qxl_send_events(qxl, QXL_INTERRUPT_CLIENT_MONITORS_CONFIG); ++ return 1; ++} ++#endif ++ + static const QXLInterface qxl_interface = { + .base.type = SPICE_INTERFACE_QXL, + .base.description = "qxl gpu", +@@ -995,6 +1070,10 @@ static const QXLInterface qxl_interface = { + #if SPICE_SERVER_VERSION >= 0x000b04 + .set_client_capabilities = interface_set_client_capabilities, + #endif ++#if SPICE_SERVER_VERSION >= 0x000b05 && \ ++ defined(CONFIG_QXL_CLIENT_MONITORS_CONFIG) ++ .client_monitors_config = interface_client_monitors_config, ++#endif + }; + + static void qxl_enter_vga_mode(PCIQXLDevice *d) +diff --git a/trace-events b/trace-events +index 80a52d9..07b63f1 100644 +--- a/trace-events ++++ b/trace-events +@@ -930,7 +930,7 @@ qxl_interface_update_area_complete_rest(int qid, uint32_t num_updated_rects) "%d + qxl_interface_update_area_complete_overflow(int qid, int max) "%d max=%d" + qxl_interface_update_area_complete_schedule_bh(int qid, uint32_t num_dirty) "%d #dirty=%d" + qxl_io_destroy_primary_ignored(int qid, const char *mode) "%d %s" +-qxl_io_log(int qid, const uint8_t *str) "%d %s" ++qxl_io_log(int qid, const uint8_t *log_buf) "%d %s" + qxl_io_read_unexpected(int qid) "%d" + qxl_io_unexpected_vga_mode(int qid, uint64_t addr, uint64_t val, const char *desc) "%d 0x%"PRIx64"=%"PRIu64" (%s)" + qxl_io_write(int qid, const char *mode, uint64_t addr, uint64_t val, unsigned size, int async) "%d %s addr=%"PRIu64 " val=%"PRIu64" size=%u async=%d" +@@ -974,6 +974,10 @@ qxl_spice_update_area_rest(int qid, uint32_t num_dirty_rects, uint32_t clear_dir + qxl_surfaces_dirty(int qid, int surface, int offset, int size) "%d surface=%d offset=%d size=%d" + qxl_send_events(int qid, uint32_t events) "%d %d" + qxl_set_guest_bug(int qid) "%d" ++qxl_interrupt_client_monitors_config(int qid, int num_heads, void *heads) "%d %d %p" ++qxl_client_monitors_config_unsupported_by_guest(int qid, uint32_t int_mask, void *client_monitors_config) "%d %X %p" ++qxl_client_monitors_config_capped(int qid, int requested, int limit) "%d %d %d" ++qxl_client_monitors_config_crc(int qid, unsigned size, uint32_t crc32) "%d %u %u" + + # hw/qxl-render.c + qxl_render_blit_guest_primary_initialized(void) "" +-- +1.7.12.1 + diff --git a/0511-qxl-always-update-displaysurface-on-resize.patch b/0511-qxl-always-update-displaysurface-on-resize.patch new file mode 100644 index 0000000..4b556c7 --- /dev/null +++ b/0511-qxl-always-update-displaysurface-on-resize.patch @@ -0,0 +1,44 @@ +From d0b5c82d532ef14bbbc770b06a6ae68f6ec3c1a8 Mon Sep 17 00:00:00 2001 +From: Gerd Hoffmann +Date: Fri, 14 Sep 2012 22:09:23 +0200 +Subject: [PATCH] qxl: always update displaysurface on resize + +Don't try to be clever and skip displaysurface reinitialization in case +the size hasn't changed. Other parameters might have changed +nevertheless, for example depth or stride, resulting in rendering being +broken then. + +Trigger: boot linux guest with vesafb, start X11, make sure both vesafb +and X11 use the display same resolution. Then watch X11 screen being +upside down. + +Signed-off-by: Gerd Hoffmann +--- + hw/qxl-render.c | 4 ---- + 1 file changed, 4 deletions(-) + +diff --git a/hw/qxl-render.c b/hw/qxl-render.c +index e2e3fe2..b66c168 100644 +--- a/hw/qxl-render.c ++++ b/hw/qxl-render.c +@@ -99,7 +99,6 @@ static void qxl_render_update_area_unlocked(PCIQXLDevice *qxl) + { + VGACommonState *vga = &qxl->vga; + int i; +- DisplaySurface *surface = vga->ds->surface; + + if (qxl->guest_primary.resized) { + qxl->guest_primary.resized = 0; +@@ -112,9 +111,6 @@ static void qxl_render_update_area_unlocked(PCIQXLDevice *qxl) + qxl->guest_primary.qxl_stride, + qxl->guest_primary.bytes_pp, + qxl->guest_primary.bits_pp); +- } +- if (surface->width != qxl->guest_primary.surface.width || +- surface->height != qxl->guest_primary.surface.height) { + if (qxl->guest_primary.qxl_stride > 0) { + qemu_free_displaysurface(vga->ds); + qemu_create_displaysurface_from(qxl->guest_primary.surface.width, +-- +1.7.12.1 + diff --git a/0512-qxl-update_area_io-cleanup-invalid-parameters-handli.patch b/0512-qxl-update_area_io-cleanup-invalid-parameters-handli.patch new file mode 100644 index 0000000..e742f65 --- /dev/null +++ b/0512-qxl-update_area_io-cleanup-invalid-parameters-handli.patch @@ -0,0 +1,48 @@ +From 2bbe4bb8c12976312c9421489f7568a70e5ffae3 Mon Sep 17 00:00:00 2001 +From: Michael Tokarev +Date: Wed, 19 Sep 2012 17:41:26 +0400 +Subject: [PATCH] qxl/update_area_io: cleanup invalid parameters handling + +This cleans up two additions of almost the same code in commits +511b13e2c9 and ccc2960d654. While at it, make error paths +consistent (always use 'break' instead of 'return'). + +Signed-off-by: Michael Tokarev +Cc: Dunrong Huang +Cc: Alon Levy +Signed-off-by: Gerd Hoffmann +--- + hw/qxl.c | 13 +++---------- + 1 file changed, 3 insertions(+), 10 deletions(-) + +diff --git a/hw/qxl.c b/hw/qxl.c +index 0695872..720363f 100644 +--- a/hw/qxl.c ++++ b/hw/qxl.c +@@ -1547,20 +1547,13 @@ async_common: + if (d->ram->update_surface > d->ssd.num_surfaces) { + qxl_set_guest_bug(d, "QXL_IO_UPDATE_AREA: invalid surface id %d\n", + d->ram->update_surface); +- return; ++ break; + } +- if (update.left >= update.right || update.top >= update.bottom) { ++ if (update.left >= update.right || update.top >= update.bottom || ++ update.left < 0 || update.top < 0) { + qxl_set_guest_bug(d, + "QXL_IO_UPDATE_AREA: invalid area (%ux%u)x(%ux%u)\n", + update.left, update.top, update.right, update.bottom); +- return; +- } +- +- if (update.left < 0 || update.top < 0 || update.left >= update.right || +- update.top >= update.bottom) { +- qxl_set_guest_bug(d, "QXL_IO_UPDATE_AREA: " +- "invalid area(%d,%d,%d,%d)\n", update.left, +- update.right, update.top, update.bottom); + break; + } + if (async == QXL_ASYNC) { +-- +1.7.12.1 + diff --git a/0513-qxl-fix-range-check-for-rev3-io-commands.patch b/0513-qxl-fix-range-check-for-rev3-io-commands.patch new file mode 100644 index 0000000..65f8763 --- /dev/null +++ b/0513-qxl-fix-range-check-for-rev3-io-commands.patch @@ -0,0 +1,29 @@ +From 0e0d8cfb93813c0d693b14e3d433d36ee9bc6bab Mon Sep 17 00:00:00 2001 +From: Gerd Hoffmann +Date: Tue, 25 Sep 2012 13:56:40 +0200 +Subject: [PATCH] qxl: fix range check for rev3 io commands. + +Enables QXL_IO_FLUSH_SURFACES_ASYNC and QXL_IO_FLUSH_RELEASE +which are part of the qxl rev3 feature set. + +Signed-off-by: Gerd Hoffmann +--- + hw/qxl.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/hw/qxl.c b/hw/qxl.c +index 720363f..9389752 100644 +--- a/hw/qxl.c ++++ b/hw/qxl.c +@@ -1466,7 +1466,7 @@ static void ioport_write(void *opaque, target_phys_addr_t addr, + } + + if (d->revision <= QXL_REVISION_STABLE_V10 && +- io_port >= QXL_IO_FLUSH_SURFACES_ASYNC) { ++ io_port > QXL_IO_FLUSH_RELEASE) { + qxl_set_guest_bug(d, "unsupported io %d for revision %d\n", + io_port, d->revision); + return; +-- +1.7.12.1 + diff --git a/0600-usb-redir-Convert-to-new-libusbredirparser-0.5-API.patch b/0600-usb-redir-Convert-to-new-libusbredirparser-0.5-API.patch new file mode 100644 index 0000000..3651fda --- /dev/null +++ b/0600-usb-redir-Convert-to-new-libusbredirparser-0.5-API.patch @@ -0,0 +1,232 @@ +From a6400ff20f4e32eecce44931e33939cdf04e2a3e Mon Sep 17 00:00:00 2001 +From: Hans de Goede +Date: Fri, 31 Aug 2012 13:41:38 +0200 +Subject: [PATCH] usb-redir: Convert to new libusbredirparser 0.5 API + +This gives us support for 64 bit ids which is needed for using XHCI with +the new hcd generated ids. + +Signed-off-by: Hans de Goede +Signed-off-by: Gerd Hoffmann +--- + configure | 2 +- + hw/usb/redirect.c | 62 +++++++++++++++++++++++++++---------------------------- + 2 files changed, 32 insertions(+), 32 deletions(-) + +diff --git a/configure b/configure +index 83c478c..2c4469f 100755 +--- a/configure ++++ b/configure +@@ -2758,7 +2758,7 @@ fi + + # check for usbredirparser for usb network redirection support + if test "$usb_redir" != "no" ; then +- if $pkg_config --atleast-version=0.3.4 libusbredirparser >/dev/null 2>&1 ; then ++ if $pkg_config --atleast-version=0.5 libusbredirparser >/dev/null 2>&1 ; then + usb_redir="yes" + usb_redir_cflags=$($pkg_config --cflags libusbredirparser 2>/dev/null) + usb_redir_libs=$($pkg_config --libs libusbredirparser 2>/dev/null) +diff --git a/hw/usb/redirect.c b/hw/usb/redirect.c +index b7c7f1e..321f5be 100644 +--- a/hw/usb/redirect.c ++++ b/hw/usb/redirect.c +@@ -107,27 +107,27 @@ static void usbredir_interface_info(void *priv, + struct usb_redir_interface_info_header *interface_info); + static void usbredir_ep_info(void *priv, + struct usb_redir_ep_info_header *ep_info); +-static void usbredir_configuration_status(void *priv, uint32_t id, ++static void usbredir_configuration_status(void *priv, uint64_t id, + struct usb_redir_configuration_status_header *configuration_status); +-static void usbredir_alt_setting_status(void *priv, uint32_t id, ++static void usbredir_alt_setting_status(void *priv, uint64_t id, + struct usb_redir_alt_setting_status_header *alt_setting_status); +-static void usbredir_iso_stream_status(void *priv, uint32_t id, ++static void usbredir_iso_stream_status(void *priv, uint64_t id, + struct usb_redir_iso_stream_status_header *iso_stream_status); +-static void usbredir_interrupt_receiving_status(void *priv, uint32_t id, ++static void usbredir_interrupt_receiving_status(void *priv, uint64_t id, + struct usb_redir_interrupt_receiving_status_header + *interrupt_receiving_status); +-static void usbredir_bulk_streams_status(void *priv, uint32_t id, ++static void usbredir_bulk_streams_status(void *priv, uint64_t id, + struct usb_redir_bulk_streams_status_header *bulk_streams_status); +-static void usbredir_control_packet(void *priv, uint32_t id, ++static void usbredir_control_packet(void *priv, uint64_t id, + struct usb_redir_control_packet_header *control_packet, + uint8_t *data, int data_len); +-static void usbredir_bulk_packet(void *priv, uint32_t id, ++static void usbredir_bulk_packet(void *priv, uint64_t id, + struct usb_redir_bulk_packet_header *bulk_packet, + uint8_t *data, int data_len); +-static void usbredir_iso_packet(void *priv, uint32_t id, ++static void usbredir_iso_packet(void *priv, uint64_t id, + struct usb_redir_iso_packet_header *iso_packet, + uint8_t *data, int data_len); +-static void usbredir_interrupt_packet(void *priv, uint32_t id, ++static void usbredir_interrupt_packet(void *priv, uint64_t id, + struct usb_redir_interrupt_packet_header *interrupt_header, + uint8_t *data, int data_len); + +@@ -814,6 +814,7 @@ static void usbredir_chardev_open(USBRedirDevice *dev) + + usbredirparser_caps_set_cap(caps, usb_redir_cap_connect_device_version); + usbredirparser_caps_set_cap(caps, usb_redir_cap_filter); ++ usbredirparser_caps_set_cap(caps, usb_redir_cap_64bits_ids); + usbredirparser_init(dev->parser, VERSION, caps, USB_REDIR_CAPS_SIZE, 0); + usbredirparser_do_write(dev->parser); + } +@@ -1204,15 +1205,15 @@ static void usbredir_ep_info(void *priv, + } + } + +-static void usbredir_configuration_status(void *priv, uint32_t id, ++static void usbredir_configuration_status(void *priv, uint64_t id, + struct usb_redir_configuration_status_header *config_status) + { + USBRedirDevice *dev = priv; + USBPacket *p; + int len = 0; + +- DPRINTF("set config status %d config %d id %u\n", config_status->status, +- config_status->configuration, id); ++ DPRINTF("set config status %d config %d id %"PRIu64"\n", ++ config_status->status, config_status->configuration, id); + + p = usbredir_find_packet_by_id(dev, 0, id); + if (p) { +@@ -1225,16 +1226,15 @@ static void usbredir_configuration_status(void *priv, uint32_t id, + } + } + +-static void usbredir_alt_setting_status(void *priv, uint32_t id, ++static void usbredir_alt_setting_status(void *priv, uint64_t id, + struct usb_redir_alt_setting_status_header *alt_setting_status) + { + USBRedirDevice *dev = priv; + USBPacket *p; + int len = 0; + +- DPRINTF("alt status %d intf %d alt %d id: %u\n", +- alt_setting_status->status, +- alt_setting_status->interface, ++ DPRINTF("alt status %d intf %d alt %d id: %"PRIu64"\n", ++ alt_setting_status->status, alt_setting_status->interface, + alt_setting_status->alt, id); + + p = usbredir_find_packet_by_id(dev, 0, id); +@@ -1249,13 +1249,13 @@ static void usbredir_alt_setting_status(void *priv, uint32_t id, + } + } + +-static void usbredir_iso_stream_status(void *priv, uint32_t id, ++static void usbredir_iso_stream_status(void *priv, uint64_t id, + struct usb_redir_iso_stream_status_header *iso_stream_status) + { + USBRedirDevice *dev = priv; + uint8_t ep = iso_stream_status->endpoint; + +- DPRINTF("iso status %d ep %02X id %u\n", iso_stream_status->status, ++ DPRINTF("iso status %d ep %02X id %"PRIu64"\n", iso_stream_status->status, + ep, id); + + if (!dev->dev.attached || !dev->endpoint[EP2I(ep)].iso_started) { +@@ -1269,14 +1269,14 @@ static void usbredir_iso_stream_status(void *priv, uint32_t id, + } + } + +-static void usbredir_interrupt_receiving_status(void *priv, uint32_t id, ++static void usbredir_interrupt_receiving_status(void *priv, uint64_t id, + struct usb_redir_interrupt_receiving_status_header + *interrupt_receiving_status) + { + USBRedirDevice *dev = priv; + uint8_t ep = interrupt_receiving_status->endpoint; + +- DPRINTF("interrupt recv status %d ep %02X id %u\n", ++ DPRINTF("interrupt recv status %d ep %02X id %"PRIu64"\n", + interrupt_receiving_status->status, ep, id); + + if (!dev->dev.attached || !dev->endpoint[EP2I(ep)].interrupt_started) { +@@ -1291,12 +1291,12 @@ static void usbredir_interrupt_receiving_status(void *priv, uint32_t id, + } + } + +-static void usbredir_bulk_streams_status(void *priv, uint32_t id, ++static void usbredir_bulk_streams_status(void *priv, uint64_t id, + struct usb_redir_bulk_streams_status_header *bulk_streams_status) + { + } + +-static void usbredir_control_packet(void *priv, uint32_t id, ++static void usbredir_control_packet(void *priv, uint64_t id, + struct usb_redir_control_packet_header *control_packet, + uint8_t *data, int data_len) + { +@@ -1304,7 +1304,7 @@ static void usbredir_control_packet(void *priv, uint32_t id, + USBPacket *p; + int len = control_packet->length; + +- DPRINTF("ctrl-in status %d len %d id %u\n", control_packet->status, ++ DPRINTF("ctrl-in status %d len %d id %"PRIu64"\n", control_packet->status, + len, id); + + p = usbredir_find_packet_by_id(dev, 0, id); +@@ -1326,7 +1326,7 @@ static void usbredir_control_packet(void *priv, uint32_t id, + free(data); + } + +-static void usbredir_bulk_packet(void *priv, uint32_t id, ++static void usbredir_bulk_packet(void *priv, uint64_t id, + struct usb_redir_bulk_packet_header *bulk_packet, + uint8_t *data, int data_len) + { +@@ -1335,8 +1335,8 @@ static void usbredir_bulk_packet(void *priv, uint32_t id, + int len = bulk_packet->length; + USBPacket *p; + +- DPRINTF("bulk-in status %d ep %02X len %d id %u\n", bulk_packet->status, +- ep, len, id); ++ DPRINTF("bulk-in status %d ep %02X len %d id %"PRIu64"\n", ++ bulk_packet->status, ep, len, id); + + p = usbredir_find_packet_by_id(dev, ep, id); + if (p) { +@@ -1357,15 +1357,15 @@ static void usbredir_bulk_packet(void *priv, uint32_t id, + free(data); + } + +-static void usbredir_iso_packet(void *priv, uint32_t id, ++static void usbredir_iso_packet(void *priv, uint64_t id, + struct usb_redir_iso_packet_header *iso_packet, + uint8_t *data, int data_len) + { + USBRedirDevice *dev = priv; + uint8_t ep = iso_packet->endpoint; + +- DPRINTF2("iso-in status %d ep %02X len %d id %u\n", iso_packet->status, ep, +- data_len, id); ++ DPRINTF2("iso-in status %d ep %02X len %d id %"PRIu64"\n", ++ iso_packet->status, ep, data_len, id); + + if (dev->endpoint[EP2I(ep)].type != USB_ENDPOINT_XFER_ISOC) { + ERROR("received iso packet for non iso endpoint %02X\n", ep); +@@ -1383,14 +1383,14 @@ static void usbredir_iso_packet(void *priv, uint32_t id, + bufp_alloc(dev, data, data_len, iso_packet->status, ep); + } + +-static void usbredir_interrupt_packet(void *priv, uint32_t id, ++static void usbredir_interrupt_packet(void *priv, uint64_t id, + struct usb_redir_interrupt_packet_header *interrupt_packet, + uint8_t *data, int data_len) + { + USBRedirDevice *dev = priv; + uint8_t ep = interrupt_packet->endpoint; + +- DPRINTF("interrupt-in status %d ep %02X len %d id %u\n", ++ DPRINTF("interrupt-in status %d ep %02X len %d id %"PRIu64"\n", + interrupt_packet->status, ep, data_len, id); + + if (dev->endpoint[EP2I(ep)].type != USB_ENDPOINT_XFER_INT) { +-- +1.7.12.1 + diff --git a/0601-usb-redir-Set-ep-max_packet_size-if-available.patch b/0601-usb-redir-Set-ep-max_packet_size-if-available.patch new file mode 100644 index 0000000..8dacdb4 --- /dev/null +++ b/0601-usb-redir-Set-ep-max_packet_size-if-available.patch @@ -0,0 +1,39 @@ +From 0995eaeb06c4810cd133e710170a7b181caf04cd Mon Sep 17 00:00:00 2001 +From: Hans de Goede +Date: Mon, 3 Sep 2012 11:49:07 +0200 +Subject: [PATCH] usb-redir: Set ep max_packet_size if available + +This is needed for usb-redir to work properly with the xhci emulation. + +Signed-off-by: Hans de Goede +Signed-off-by: Gerd Hoffmann +--- + hw/usb/redirect.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/hw/usb/redirect.c b/hw/usb/redirect.c +index 321f5be..b9a3633 100644 +--- a/hw/usb/redirect.c ++++ b/hw/usb/redirect.c +@@ -814,6 +814,7 @@ static void usbredir_chardev_open(USBRedirDevice *dev) + + usbredirparser_caps_set_cap(caps, usb_redir_cap_connect_device_version); + usbredirparser_caps_set_cap(caps, usb_redir_cap_filter); ++ usbredirparser_caps_set_cap(caps, usb_redir_cap_ep_info_max_packet_size); + usbredirparser_caps_set_cap(caps, usb_redir_cap_64bits_ids); + usbredirparser_init(dev->parser, VERSION, caps, USB_REDIR_CAPS_SIZE, 0); + usbredirparser_do_write(dev->parser); +@@ -1202,6 +1203,10 @@ static void usbredir_ep_info(void *priv, + i & 0x0f); + usb_ep->type = dev->endpoint[i].type; + usb_ep->ifnum = dev->endpoint[i].interface; ++ if (usbredirparser_peer_has_cap(dev->parser, ++ usb_redir_cap_ep_info_max_packet_size)) { ++ usb_ep->max_packet_size = ep_info->max_packet_size[i]; ++ } + } + } + +-- +1.7.12.1 + diff --git a/0602-usb-redir-Add-a-usbredir_reject_device-helper-functi.patch b/0602-usb-redir-Add-a-usbredir_reject_device-helper-functi.patch new file mode 100644 index 0000000..cfe0fa1 --- /dev/null +++ b/0602-usb-redir-Add-a-usbredir_reject_device-helper-functi.patch @@ -0,0 +1,58 @@ +From 596013354fd1d5b102cdb54449b10e11346f9fda Mon Sep 17 00:00:00 2001 +From: Hans de Goede +Date: Mon, 3 Sep 2012 11:53:28 +0200 +Subject: [PATCH] usb-redir: Add a usbredir_reject_device helper function + +Signed-off-by: Hans de Goede +Signed-off-by: Gerd Hoffmann +--- + hw/usb/redirect.c | 21 +++++++++++---------- + 1 file changed, 11 insertions(+), 10 deletions(-) + +diff --git a/hw/usb/redirect.c b/hw/usb/redirect.c +index b9a3633..a590cb2 100644 +--- a/hw/usb/redirect.c ++++ b/hw/usb/redirect.c +@@ -820,16 +820,21 @@ static void usbredir_chardev_open(USBRedirDevice *dev) + usbredirparser_do_write(dev->parser); + } + ++static void usbredir_reject_device(USBRedirDevice *dev) ++{ ++ usbredir_device_disconnect(dev); ++ if (usbredirparser_peer_has_cap(dev->parser, usb_redir_cap_filter)) { ++ usbredirparser_send_filter_reject(dev->parser); ++ usbredirparser_do_write(dev->parser); ++ } ++} ++ + static void usbredir_do_attach(void *opaque) + { + USBRedirDevice *dev = opaque; + + if (usb_device_attach(&dev->dev) != 0) { +- usbredir_device_disconnect(dev); +- if (usbredirparser_peer_has_cap(dev->parser, usb_redir_cap_filter)) { +- usbredirparser_send_filter_reject(dev->parser); +- usbredirparser_do_write(dev->parser); +- } ++ usbredir_reject_device(dev); + } + } + +@@ -1008,11 +1013,7 @@ static int usbredir_check_filter(USBRedirDevice *dev) + return 0; + + error: +- usbredir_device_disconnect(dev); +- if (usbredirparser_peer_has_cap(dev->parser, usb_redir_cap_filter)) { +- usbredirparser_send_filter_reject(dev->parser); +- usbredirparser_do_write(dev->parser); +- } ++ usbredir_reject_device(dev); + return -1; + } + +-- +1.7.12.1 + diff --git a/0603-usb-redir-Ensure-our-peer-has-the-necessary-caps-whe.patch b/0603-usb-redir-Ensure-our-peer-has-the-necessary-caps-whe.patch new file mode 100644 index 0000000..ef6b4a2 --- /dev/null +++ b/0603-usb-redir-Ensure-our-peer-has-the-necessary-caps-whe.patch @@ -0,0 +1,43 @@ +From 87317670541ed043a21964c29e0e613aab375224 Mon Sep 17 00:00:00 2001 +From: Hans de Goede +Date: Mon, 3 Sep 2012 12:04:49 +0200 +Subject: [PATCH] usb-redir: Ensure our peer has the necessary caps when + redirecting to XHCI + +In order for redirection to work properly when redirecting to an emulated +XHCI controller, the usb-redir-host must support both +usb_redir_cap_ep_info_max_packet_size and usb_redir_cap_64bits_ids, +reject any devices redirected to an XHCI controller when these are not +supported. + +Signed-off-by: Hans de Goede +Signed-off-by: Gerd Hoffmann +--- + hw/usb/redirect.c | 11 +++++++++++ + 1 file changed, 11 insertions(+) + +diff --git a/hw/usb/redirect.c b/hw/usb/redirect.c +index a590cb2..f1bb692 100644 +--- a/hw/usb/redirect.c ++++ b/hw/usb/redirect.c +@@ -833,6 +833,17 @@ static void usbredir_do_attach(void *opaque) + { + USBRedirDevice *dev = opaque; + ++ /* In order to work properly with XHCI controllers we need these caps */ ++ if ((dev->dev.port->speedmask & USB_SPEED_MASK_SUPER) && !( ++ usbredirparser_peer_has_cap(dev->parser, ++ usb_redir_cap_ep_info_max_packet_size) && ++ usbredirparser_peer_has_cap(dev->parser, ++ usb_redir_cap_64bits_ids))) { ++ ERROR("usb-redir-host lacks capabilities needed for use with XHCI\n"); ++ usbredir_reject_device(dev); ++ return; ++ } ++ + if (usb_device_attach(&dev->dev) != 0) { + usbredir_reject_device(dev); + } +-- +1.7.12.1 + diff --git a/0604-usb-redir-Enable-pipelining-for-bulk-endpoints.patch b/0604-usb-redir-Enable-pipelining-for-bulk-endpoints.patch new file mode 100644 index 0000000..cfb988e --- /dev/null +++ b/0604-usb-redir-Enable-pipelining-for-bulk-endpoints.patch @@ -0,0 +1,28 @@ +From c12ef3d896e426505ea3ca4fb2f1d9017f9cf828 Mon Sep 17 00:00:00 2001 +From: Hans de Goede +Date: Mon, 3 Sep 2012 13:44:04 +0200 +Subject: [PATCH] usb-redir: Enable pipelining for bulk endpoints + +Signed-off-by: Hans de Goede +Signed-off-by: Gerd Hoffmann +--- + hw/usb/redirect.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/hw/usb/redirect.c b/hw/usb/redirect.c +index f1bb692..f183263 100644 +--- a/hw/usb/redirect.c ++++ b/hw/usb/redirect.c +@@ -1219,6 +1219,9 @@ static void usbredir_ep_info(void *priv, + usb_redir_cap_ep_info_max_packet_size)) { + usb_ep->max_packet_size = ep_info->max_packet_size[i]; + } ++ if (ep_info->type[i] == usb_redir_type_bulk) { ++ usb_ep->pipeline = true; ++ } + } + } + +-- +1.7.12.1 + diff --git a/0605-xhci-move-device-lookup-into-xhci_setup_packet.patch b/0605-xhci-move-device-lookup-into-xhci_setup_packet.patch new file mode 100644 index 0000000..3a2ad62 --- /dev/null +++ b/0605-xhci-move-device-lookup-into-xhci_setup_packet.patch @@ -0,0 +1,154 @@ +From 2255facbc338e73aa2442e2a1dc13b3474b35f98 Mon Sep 17 00:00:00 2001 +From: Gerd Hoffmann +Date: Fri, 24 Aug 2012 14:21:39 +0200 +Subject: [PATCH] xhci: move device lookup into xhci_setup_packet + +Signed-off-by: Gerd Hoffmann +--- + hw/usb/hcd-xhci.c | 74 ++++++++++++++++++++++++++++--------------------------- + 1 file changed, 38 insertions(+), 36 deletions(-) + +diff --git a/hw/usb/hcd-xhci.c b/hw/usb/hcd-xhci.c +index 333df59..316a303 100644 +--- a/hw/usb/hcd-xhci.c ++++ b/hw/usb/hcd-xhci.c +@@ -1196,13 +1196,38 @@ static void xhci_stall_ep(XHCITransfer *xfer) + static int xhci_submit(XHCIState *xhci, XHCITransfer *xfer, + XHCIEPContext *epctx); + +-static int xhci_setup_packet(XHCITransfer *xfer, USBDevice *dev) ++static USBDevice *xhci_find_device(XHCIPort *port, uint8_t addr) + { ++ if (!(port->portsc & PORTSC_PED)) { ++ return NULL; ++ } ++ return usb_find_device(&port->port, addr); ++} ++ ++static int xhci_setup_packet(XHCITransfer *xfer) ++{ ++ XHCIState *xhci = xfer->xhci; ++ XHCIPort *port; ++ USBDevice *dev; + USBEndpoint *ep; + int dir; + + dir = xfer->in_xfer ? USB_TOKEN_IN : USB_TOKEN_OUT; +- ep = usb_ep_get(dev, dir, xfer->epid >> 1); ++ ++ if (xfer->packet.ep) { ++ ep = xfer->packet.ep; ++ dev = ep->dev; ++ } else { ++ port = &xhci->ports[xhci->slots[xfer->slotid-1].port-1]; ++ dev = xhci_find_device(port, xhci->slots[xfer->slotid-1].devaddr); ++ if (!dev) { ++ fprintf(stderr, "xhci: slot %d port %d has no device\n", ++ xfer->slotid, xhci->slots[xfer->slotid-1].port); ++ return -1; ++ } ++ ep = usb_ep_get(dev, dir, xfer->epid >> 1); ++ } ++ + usb_packet_setup(&xfer->packet, dir, ep, xfer->trbs[0].addr); + xhci_xfer_map(xfer); + DPRINTF("xhci: setup packet pid 0x%x addr %d ep %d\n", +@@ -1260,20 +1285,10 @@ static int xhci_complete_packet(XHCITransfer *xfer, int ret) + return 0; + } + +-static USBDevice *xhci_find_device(XHCIPort *port, uint8_t addr) +-{ +- if (!(port->portsc & PORTSC_PED)) { +- return NULL; +- } +- return usb_find_device(&port->port, addr); +-} +- + static int xhci_fire_ctl_transfer(XHCIState *xhci, XHCITransfer *xfer) + { + XHCITRB *trb_setup, *trb_status; + uint8_t bmRequestType; +- XHCIPort *port; +- USBDevice *dev; + int ret; + + trb_setup = &xfer->trbs[0]; +@@ -1309,21 +1324,15 @@ static int xhci_fire_ctl_transfer(XHCIState *xhci, XHCITransfer *xfer) + + bmRequestType = trb_setup->parameter; + +- port = &xhci->ports[xhci->slots[xfer->slotid-1].port-1]; +- dev = xhci_find_device(port, xhci->slots[xfer->slotid-1].devaddr); +- if (!dev) { +- fprintf(stderr, "xhci: slot %d port %d has no device\n", xfer->slotid, +- xhci->slots[xfer->slotid-1].port); +- return -1; +- } +- + xfer->in_xfer = bmRequestType & USB_DIR_IN; + xfer->iso_xfer = false; + +- xhci_setup_packet(xfer, dev); ++ if (xhci_setup_packet(xfer) < 0) { ++ return -1; ++ } + xfer->packet.parameter = trb_setup->parameter; + +- ret = usb_handle_packet(dev, &xfer->packet); ++ ret = usb_handle_packet(xfer->packet.ep->dev, &xfer->packet); + + xhci_complete_packet(xfer, ret); + if (!xfer->running_async && !xfer->running_retry) { +@@ -1334,8 +1343,6 @@ static int xhci_fire_ctl_transfer(XHCIState *xhci, XHCITransfer *xfer) + + static int xhci_submit(XHCIState *xhci, XHCITransfer *xfer, XHCIEPContext *epctx) + { +- XHCIPort *port; +- USBDevice *dev; + int ret; + + DPRINTF("xhci_submit(slotid=%d,epid=%d)\n", xfer->slotid, xfer->epid); +@@ -1348,16 +1355,6 @@ static int xhci_submit(XHCIState *xhci, XHCITransfer *xfer, XHCIEPContext *epctx + xfer->pkts = 0; + } + +- port = &xhci->ports[xhci->slots[xfer->slotid-1].port-1]; +- dev = xhci_find_device(port, xhci->slots[xfer->slotid-1].devaddr); +- if (!dev) { +- fprintf(stderr, "xhci: slot %d port %d has no device\n", xfer->slotid, +- xhci->slots[xfer->slotid-1].port); +- return -1; +- } +- +- xhci_setup_packet(xfer, dev); +- + switch(epctx->type) { + case ET_INTR_OUT: + case ET_INTR_IN: +@@ -1375,7 +1372,10 @@ static int xhci_submit(XHCIState *xhci, XHCITransfer *xfer, XHCIEPContext *epctx + return -1; + } + +- ret = usb_handle_packet(dev, &xfer->packet); ++ if (xhci_setup_packet(xfer) < 0) { ++ return -1; ++ } ++ ret = usb_handle_packet(xfer->packet.ep->dev, &xfer->packet); + + xhci_complete_packet(xfer, ret); + if (!xfer->running_async && !xfer->running_retry) { +@@ -1418,7 +1418,9 @@ static void xhci_kick_ep(XHCIState *xhci, unsigned int slotid, unsigned int epid + + trace_usb_xhci_xfer_retry(xfer); + assert(xfer->running_retry); +- xhci_setup_packet(xfer, xfer->packet.ep->dev); ++ if (xhci_setup_packet(xfer) < 0) { ++ return; ++ } + result = usb_handle_packet(xfer->packet.ep->dev, &xfer->packet); + if (result == USB_RET_NAK) { + return; +-- +1.7.12.1 + diff --git a/0606-xhci-implement-mfindex.patch b/0606-xhci-implement-mfindex.patch new file mode 100644 index 0000000..4e4d268 --- /dev/null +++ b/0606-xhci-implement-mfindex.patch @@ -0,0 +1,142 @@ +From 1f98b775c9f02caece1df5813edbb9c0a509bd58 Mon Sep 17 00:00:00 2001 +From: Gerd Hoffmann +Date: Tue, 21 Aug 2012 12:32:58 +0200 +Subject: [PATCH] xhci: implement mfindex + +Implement mfindex register and mfindex wrap event. + +Signed-off-by: Gerd Hoffmann +--- + hw/usb/hcd-xhci.c | 53 ++++++++++++++++++++++++++++++++++++++++++++++------- + 1 file changed, 46 insertions(+), 7 deletions(-) + +diff --git a/hw/usb/hcd-xhci.c b/hw/usb/hcd-xhci.c +index 316a303..f5ba6a4 100644 +--- a/hw/usb/hcd-xhci.c ++++ b/hw/usb/hcd-xhci.c +@@ -380,8 +380,6 @@ struct XHCIState { + XHCISlot slots[MAXSLOTS]; + + /* Runtime Registers */ +- uint32_t mfindex; +- /* note: we only support one interrupter */ + uint32_t iman; + uint32_t imod; + uint32_t erstsz; +@@ -390,6 +388,9 @@ struct XHCIState { + uint32_t erdp_low; + uint32_t erdp_high; + ++ int64_t mfindex_start; ++ QEMUTimer *mfwrap_timer; ++ + dma_addr_t er_start; + uint32_t er_size; + bool er_pcs; +@@ -410,6 +411,11 @@ typedef struct XHCIEvRingSeg { + uint32_t rsvd; + } XHCIEvRingSeg; + ++static void xhci_kick_ep(XHCIState *xhci, unsigned int slotid, ++ unsigned int epid); ++static void xhci_event(XHCIState *xhci, XHCIEvent *event); ++static void xhci_write_event(XHCIState *xhci, XHCIEvent *event); ++ + static const char *TRBType_names[] = { + [TRB_RESERVED] = "TRB_RESERVED", + [TR_NORMAL] = "TR_NORMAL", +@@ -462,8 +468,36 @@ static const char *trb_name(XHCITRB *trb) + ARRAY_SIZE(TRBType_names)); + } + +-static void xhci_kick_ep(XHCIState *xhci, unsigned int slotid, +- unsigned int epid); ++static uint64_t xhci_mfindex_get(XHCIState *xhci) ++{ ++ int64_t now = qemu_get_clock_ns(vm_clock); ++ return (now - xhci->mfindex_start) / 125000; ++} ++ ++static void xhci_mfwrap_update(XHCIState *xhci) ++{ ++ const uint32_t bits = USBCMD_RS | USBCMD_EWE; ++ uint32_t mfindex, left; ++ int64_t now; ++ ++ if ((xhci->usbcmd & bits) == bits) { ++ now = qemu_get_clock_ns(vm_clock); ++ mfindex = ((now - xhci->mfindex_start) / 125000) & 0x3fff; ++ left = 0x4000 - mfindex; ++ qemu_mod_timer(xhci->mfwrap_timer, now + left * 125000); ++ } else { ++ qemu_del_timer(xhci->mfwrap_timer); ++ } ++} ++ ++static void xhci_mfwrap_timer(void *opaque) ++{ ++ XHCIState *xhci = opaque; ++ XHCIEvent wrap = { ER_MFINDEX_WRAP, CC_SUCCESS }; ++ ++ xhci_event(xhci, &wrap); ++ xhci_mfwrap_update(xhci); ++} + + static inline dma_addr_t xhci_addr64(uint32_t low, uint32_t high) + { +@@ -793,6 +827,7 @@ static void xhci_run(XHCIState *xhci) + { + trace_usb_xhci_run(); + xhci->usbsts &= ~USBSTS_HCH; ++ xhci->mfindex_start = qemu_get_clock_ns(vm_clock); + } + + static void xhci_stop(XHCIState *xhci) +@@ -2048,7 +2083,6 @@ static void xhci_reset(DeviceState *dev) + xhci_update_port(xhci, xhci->ports + i, 0); + } + +- xhci->mfindex = 0; + xhci->iman = 0; + xhci->imod = 0; + xhci->erstsz = 0; +@@ -2062,6 +2096,9 @@ static void xhci_reset(DeviceState *dev) + xhci->er_full = 0; + xhci->ev_buffer_put = 0; + xhci->ev_buffer_get = 0; ++ ++ xhci->mfindex_start = qemu_get_clock_ns(vm_clock); ++ xhci_mfwrap_update(xhci); + } + + static uint32_t xhci_cap_read(XHCIState *xhci, uint32_t reg) +@@ -2264,6 +2301,7 @@ static void xhci_oper_write(XHCIState *xhci, uint32_t reg, uint32_t val) + xhci_stop(xhci); + } + xhci->usbcmd = val & 0xc0f; ++ xhci_mfwrap_update(xhci); + if (val & USBCMD_HCRST) { + xhci_reset(&xhci->pci_dev.qdev); + } +@@ -2315,8 +2353,7 @@ static uint32_t xhci_runtime_read(XHCIState *xhci, uint32_t reg) + + switch (reg) { + case 0x00: /* MFINDEX */ +- fprintf(stderr, "xhci_runtime_read: MFINDEX not yet implemented\n"); +- ret = xhci->mfindex; ++ ret = xhci_mfindex_get(xhci) & 0x3fff; + break; + case 0x20: /* IMAN */ + ret = xhci->iman; +@@ -2618,6 +2655,8 @@ static int usb_xhci_initfn(struct PCIDevice *dev) + + usb_xhci_init(xhci, &dev->qdev); + ++ xhci->mfwrap_timer = qemu_new_timer_ns(vm_clock, xhci_mfwrap_timer, xhci); ++ + xhci->irq = xhci->pci_dev.irq[0]; + + memory_region_init_io(&xhci->mem, &xhci_mem_ops, xhci, +-- +1.7.12.1 + diff --git a/0607-xhci-iso-xfer-support.patch b/0607-xhci-iso-xfer-support.patch new file mode 100644 index 0000000..acaee96 --- /dev/null +++ b/0607-xhci-iso-xfer-support.patch @@ -0,0 +1,238 @@ +From 82508212e19333e527b64fb76cd1bc016afacc8a Mon Sep 17 00:00:00 2001 +From: Gerd Hoffmann +Date: Fri, 24 Aug 2012 14:13:08 +0200 +Subject: [PATCH] xhci: iso xfer support + +Add support for iso transfers. + +Signed-off-by: Gerd Hoffmann +--- + hw/usb/hcd-xhci.c | 117 ++++++++++++++++++++++++++++++++++++++++++++++-------- + 1 file changed, 101 insertions(+), 16 deletions(-) + +diff --git a/hw/usb/hcd-xhci.c b/hw/usb/hcd-xhci.c +index f5ba6a4..b313330 100644 +--- a/hw/usb/hcd-xhci.c ++++ b/hw/usb/hcd-xhci.c +@@ -325,9 +325,15 @@ typedef struct XHCITransfer { + unsigned int pkts; + unsigned int pktsize; + unsigned int cur_pkt; ++ ++ uint64_t mfindex_kick; + } XHCITransfer; + + typedef struct XHCIEPContext { ++ XHCIState *xhci; ++ unsigned int slotid; ++ unsigned int epid; ++ + XHCIRing ring; + unsigned int next_xfer; + unsigned int comp_xfer; +@@ -337,6 +343,11 @@ typedef struct XHCIEPContext { + dma_addr_t pctx; + unsigned int max_psize; + uint32_t state; ++ ++ /* iso xfer scheduling */ ++ unsigned int interval; ++ int64_t mfindex_last; ++ QEMUTimer *kick_timer; + } XHCIEPContext; + + typedef struct XHCISlot { +@@ -856,6 +867,12 @@ static void xhci_set_ep_state(XHCIState *xhci, XHCIEPContext *epctx, + epctx->state = state; + } + ++static void xhci_ep_kick_timer(void *opaque) ++{ ++ XHCIEPContext *epctx = opaque; ++ xhci_kick_ep(epctx->xhci, epctx->slotid, epctx->epid); ++} ++ + static TRBCCode xhci_enable_ep(XHCIState *xhci, unsigned int slotid, + unsigned int epid, dma_addr_t pctx, + uint32_t *ctx) +@@ -877,6 +894,9 @@ static TRBCCode xhci_enable_ep(XHCIState *xhci, unsigned int slotid, + + epctx = g_malloc(sizeof(XHCIEPContext)); + memset(epctx, 0, sizeof(XHCIEPContext)); ++ epctx->xhci = xhci; ++ epctx->slotid = slotid; ++ epctx->epid = epid; + + slot->eps[epid-1] = epctx; + +@@ -895,6 +915,10 @@ static TRBCCode xhci_enable_ep(XHCIState *xhci, unsigned int slotid, + usb_packet_init(&epctx->transfers[i].packet); + } + ++ epctx->interval = 1 << (ctx[0] >> 16) & 0xff; ++ epctx->mfindex_last = 0; ++ epctx->kick_timer = qemu_new_timer_ns(vm_clock, xhci_ep_kick_timer, epctx); ++ + epctx->state = EP_RUNNING; + ctx[0] &= ~EP_STATE_MASK; + ctx[0] |= EP_RUNNING; +@@ -934,6 +958,7 @@ static int xhci_ep_nuke_xfers(XHCIState *xhci, unsigned int slotid, + if (t->running_retry) { + t->running_retry = 0; + epctx->retry = NULL; ++ qemu_del_timer(epctx->kick_timer); + } + if (t->trbs) { + g_free(t->trbs); +@@ -969,6 +994,7 @@ static TRBCCode xhci_disable_ep(XHCIState *xhci, unsigned int slotid, + + xhci_set_ep_state(xhci, epctx, EP_DISABLED); + ++ qemu_free_timer(epctx->kick_timer); + g_free(epctx); + slot->eps[epid-1] = NULL; + +@@ -1376,29 +1402,70 @@ static int xhci_fire_ctl_transfer(XHCIState *xhci, XHCITransfer *xfer) + return 0; + } + ++static void xhci_calc_iso_kick(XHCIState *xhci, XHCITransfer *xfer, ++ XHCIEPContext *epctx, uint64_t mfindex) ++{ ++ if (xfer->trbs[0].control & TRB_TR_SIA) { ++ uint64_t asap = ((mfindex + epctx->interval - 1) & ++ ~(epctx->interval-1)); ++ if (asap >= epctx->mfindex_last && ++ asap <= epctx->mfindex_last + epctx->interval * 4) { ++ xfer->mfindex_kick = epctx->mfindex_last + epctx->interval; ++ } else { ++ xfer->mfindex_kick = asap; ++ } ++ } else { ++ xfer->mfindex_kick = (xfer->trbs[0].control >> TRB_TR_FRAMEID_SHIFT) ++ & TRB_TR_FRAMEID_MASK; ++ xfer->mfindex_kick |= mfindex & ~0x3fff; ++ if (xfer->mfindex_kick < mfindex) { ++ xfer->mfindex_kick += 0x4000; ++ } ++ } ++} ++ ++static void xhci_check_iso_kick(XHCIState *xhci, XHCITransfer *xfer, ++ XHCIEPContext *epctx, uint64_t mfindex) ++{ ++ if (xfer->mfindex_kick > mfindex) { ++ qemu_mod_timer(epctx->kick_timer, qemu_get_clock_ns(vm_clock) + ++ (xfer->mfindex_kick - mfindex) * 125000); ++ xfer->running_retry = 1; ++ } else { ++ epctx->mfindex_last = xfer->mfindex_kick; ++ qemu_del_timer(epctx->kick_timer); ++ xfer->running_retry = 0; ++ } ++} ++ ++ + static int xhci_submit(XHCIState *xhci, XHCITransfer *xfer, XHCIEPContext *epctx) + { ++ uint64_t mfindex; + int ret; + + DPRINTF("xhci_submit(slotid=%d,epid=%d)\n", xfer->slotid, xfer->epid); + + xfer->in_xfer = epctx->type>>2; + +- if (epctx->type == ET_ISO_IN || epctx->type == ET_ISO_OUT) { +- xfer->pkts = 1; +- } else { +- xfer->pkts = 0; +- } +- + switch(epctx->type) { + case ET_INTR_OUT: + case ET_INTR_IN: + case ET_BULK_OUT: + case ET_BULK_IN: ++ xfer->pkts = 0; ++ xfer->iso_xfer = false; + break; + case ET_ISO_OUT: + case ET_ISO_IN: +- FIXME(); ++ xfer->pkts = 1; ++ xfer->iso_xfer = true; ++ mfindex = xhci_mfindex_get(xhci); ++ xhci_calc_iso_kick(xhci, xfer, epctx, mfindex); ++ xhci_check_iso_kick(xhci, xfer, epctx, mfindex); ++ if (xfer->running_retry) { ++ return -1; ++ } + break; + default: + fprintf(stderr, "xhci: unknown or unhandled EP " +@@ -1428,6 +1495,7 @@ static int xhci_fire_transfer(XHCIState *xhci, XHCITransfer *xfer, XHCIEPContext + static void xhci_kick_ep(XHCIState *xhci, unsigned int slotid, unsigned int epid) + { + XHCIEPContext *epctx; ++ uint64_t mfindex; + int length; + int i; + +@@ -1447,20 +1515,35 @@ static void xhci_kick_ep(XHCIState *xhci, unsigned int slotid, unsigned int epid + } + + if (epctx->retry) { +- /* retry nak'ed transfer */ + XHCITransfer *xfer = epctx->retry; + int result; + + trace_usb_xhci_xfer_retry(xfer); + assert(xfer->running_retry); +- if (xhci_setup_packet(xfer) < 0) { +- return; +- } +- result = usb_handle_packet(xfer->packet.ep->dev, &xfer->packet); +- if (result == USB_RET_NAK) { +- return; ++ if (xfer->iso_xfer) { ++ /* retry delayed iso transfer */ ++ mfindex = xhci_mfindex_get(xhci); ++ xhci_check_iso_kick(xhci, xfer, epctx, mfindex); ++ if (xfer->running_retry) { ++ return; ++ } ++ if (xhci_setup_packet(xfer) < 0) { ++ return; ++ } ++ result = usb_handle_packet(xfer->packet.ep->dev, &xfer->packet); ++ assert(result != USB_RET_NAK); ++ xhci_complete_packet(xfer, result); ++ } else { ++ /* retry nak'ed transfer */ ++ if (xhci_setup_packet(xfer) < 0) { ++ return; ++ } ++ result = usb_handle_packet(xfer->packet.ep->dev, &xfer->packet); ++ if (result == USB_RET_NAK) { ++ return; ++ } ++ xhci_complete_packet(xfer, result); + } +- xhci_complete_packet(xfer, result); + assert(!xfer->running_retry); + epctx->retry = NULL; + } +@@ -1512,7 +1595,9 @@ static void xhci_kick_ep(XHCIState *xhci, unsigned int slotid, unsigned int epid + if (xhci_fire_transfer(xhci, xfer, epctx) >= 0) { + epctx->next_xfer = (epctx->next_xfer + 1) % TD_QUEUE; + } else { +- fprintf(stderr, "xhci: error firing data transfer\n"); ++ if (!xfer->iso_xfer) { ++ fprintf(stderr, "xhci: error firing data transfer\n"); ++ } + } + } + +-- +1.7.12.1 + diff --git a/0608-xhci-trace-cc-codes-in-cleartext.patch b/0608-xhci-trace-cc-codes-in-cleartext.patch new file mode 100644 index 0000000..b2b70f6 --- /dev/null +++ b/0608-xhci-trace-cc-codes-in-cleartext.patch @@ -0,0 +1,100 @@ +From 188fbd363df2e7f23ea37fb1b179e984bbce39e5 Mon Sep 17 00:00:00 2001 +From: Gerd Hoffmann +Date: Mon, 27 Aug 2012 16:09:20 +0200 +Subject: [PATCH] xhci: trace cc codes in cleartext + +Signed-off-by: Gerd Hoffmann +--- + hw/usb/hcd-xhci.c | 48 +++++++++++++++++++++++++++++++++++++++++++++++- + trace-events | 2 +- + 2 files changed, 48 insertions(+), 2 deletions(-) + +diff --git a/hw/usb/hcd-xhci.c b/hw/usb/hcd-xhci.c +index b313330..ab352c0 100644 +--- a/hw/usb/hcd-xhci.c ++++ b/hw/usb/hcd-xhci.c +@@ -465,6 +465,45 @@ static const char *TRBType_names[] = { + [CR_VENDOR_NEC_CHALLENGE_RESPONSE] = "CR_VENDOR_NEC_CHALLENGE_RESPONSE", + }; + ++static const char *TRBCCode_names[] = { ++ [CC_INVALID] = "CC_INVALID", ++ [CC_SUCCESS] = "CC_SUCCESS", ++ [CC_DATA_BUFFER_ERROR] = "CC_DATA_BUFFER_ERROR", ++ [CC_BABBLE_DETECTED] = "CC_BABBLE_DETECTED", ++ [CC_USB_TRANSACTION_ERROR] = "CC_USB_TRANSACTION_ERROR", ++ [CC_TRB_ERROR] = "CC_TRB_ERROR", ++ [CC_STALL_ERROR] = "CC_STALL_ERROR", ++ [CC_RESOURCE_ERROR] = "CC_RESOURCE_ERROR", ++ [CC_BANDWIDTH_ERROR] = "CC_BANDWIDTH_ERROR", ++ [CC_NO_SLOTS_ERROR] = "CC_NO_SLOTS_ERROR", ++ [CC_INVALID_STREAM_TYPE_ERROR] = "CC_INVALID_STREAM_TYPE_ERROR", ++ [CC_SLOT_NOT_ENABLED_ERROR] = "CC_SLOT_NOT_ENABLED_ERROR", ++ [CC_EP_NOT_ENABLED_ERROR] = "CC_EP_NOT_ENABLED_ERROR", ++ [CC_SHORT_PACKET] = "CC_SHORT_PACKET", ++ [CC_RING_UNDERRUN] = "CC_RING_UNDERRUN", ++ [CC_RING_OVERRUN] = "CC_RING_OVERRUN", ++ [CC_VF_ER_FULL] = "CC_VF_ER_FULL", ++ [CC_PARAMETER_ERROR] = "CC_PARAMETER_ERROR", ++ [CC_BANDWIDTH_OVERRUN] = "CC_BANDWIDTH_OVERRUN", ++ [CC_CONTEXT_STATE_ERROR] = "CC_CONTEXT_STATE_ERROR", ++ [CC_NO_PING_RESPONSE_ERROR] = "CC_NO_PING_RESPONSE_ERROR", ++ [CC_EVENT_RING_FULL_ERROR] = "CC_EVENT_RING_FULL_ERROR", ++ [CC_INCOMPATIBLE_DEVICE_ERROR] = "CC_INCOMPATIBLE_DEVICE_ERROR", ++ [CC_MISSED_SERVICE_ERROR] = "CC_MISSED_SERVICE_ERROR", ++ [CC_COMMAND_RING_STOPPED] = "CC_COMMAND_RING_STOPPED", ++ [CC_COMMAND_ABORTED] = "CC_COMMAND_ABORTED", ++ [CC_STOPPED] = "CC_STOPPED", ++ [CC_STOPPED_LENGTH_INVALID] = "CC_STOPPED_LENGTH_INVALID", ++ [CC_MAX_EXIT_LATENCY_TOO_LARGE_ERROR] ++ = "CC_MAX_EXIT_LATENCY_TOO_LARGE_ERROR", ++ [CC_ISOCH_BUFFER_OVERRUN] = "CC_ISOCH_BUFFER_OVERRUN", ++ [CC_EVENT_LOST_ERROR] = "CC_EVENT_LOST_ERROR", ++ [CC_UNDEFINED_ERROR] = "CC_UNDEFINED_ERROR", ++ [CC_INVALID_STREAM_ID_ERROR] = "CC_INVALID_STREAM_ID_ERROR", ++ [CC_SECONDARY_BANDWIDTH_ERROR] = "CC_SECONDARY_BANDWIDTH_ERROR", ++ [CC_SPLIT_TRANSACTION_ERROR] = "CC_SPLIT_TRANSACTION_ERROR", ++}; ++ + static const char *lookup_name(uint32_t index, const char **list, uint32_t llen) + { + if (index >= llen || list[index] == NULL) { +@@ -479,6 +518,12 @@ static const char *trb_name(XHCITRB *trb) + ARRAY_SIZE(TRBType_names)); + } + ++static const char *event_name(XHCIEvent *event) ++{ ++ return lookup_name(event->ccode, TRBCCode_names, ++ ARRAY_SIZE(TRBCCode_names)); ++} ++ + static uint64_t xhci_mfindex_get(XHCIState *xhci) + { + int64_t now = qemu_get_clock_ns(vm_clock); +@@ -574,7 +619,8 @@ static void xhci_write_event(XHCIState *xhci, XHCIEvent *event) + ev_trb.control = cpu_to_le32(ev_trb.control); + + trace_usb_xhci_queue_event(xhci->er_ep_idx, trb_name(&ev_trb), +- ev_trb.parameter, ev_trb.status, ev_trb.control); ++ event_name(event), ev_trb.parameter, ++ ev_trb.status, ev_trb.control); + + addr = xhci->er_start + TRB_SIZE*xhci->er_ep_idx; + pci_dma_write(&xhci->pci_dev, addr, &ev_trb, TRB_SIZE); +diff --git a/trace-events b/trace-events +index 07b63f1..b38e32a 100644 +--- a/trace-events ++++ b/trace-events +@@ -316,7 +316,7 @@ usb_xhci_runtime_write(uint32_t off, uint32_t val) "off 0x%04x, val 0x%08x" + usb_xhci_doorbell_write(uint32_t off, uint32_t val) "off 0x%04x, val 0x%08x" + usb_xhci_irq_intx(uint32_t level) "level %d" + usb_xhci_irq_msi(uint32_t nr) "nr %d" +-usb_xhci_queue_event(uint32_t idx, const char *name, uint64_t param, uint32_t status, uint32_t control) "idx %d, %s, p %016" PRIx64 ", s %08x, c 0x%08x" ++usb_xhci_queue_event(uint32_t idx, const char *trb, const char *evt, uint64_t param, uint32_t status, uint32_t control) "idx %d, %s, %s, p %016" PRIx64 ", s %08x, c 0x%08x" + usb_xhci_fetch_trb(uint64_t addr, const char *name, uint64_t param, uint32_t status, uint32_t control) "addr %016" PRIx64 ", %s, p %016" PRIx64 ", s %08x, c 0x%08x" + usb_xhci_slot_enable(uint32_t slotid) "slotid %d" + usb_xhci_slot_disable(uint32_t slotid) "slotid %d" +-- +1.7.12.1 + diff --git a/0609-xhci-add-trace_usb_xhci_ep_set_dequeue.patch b/0609-xhci-add-trace_usb_xhci_ep_set_dequeue.patch new file mode 100644 index 0000000..7a07da9 --- /dev/null +++ b/0609-xhci-add-trace_usb_xhci_ep_set_dequeue.patch @@ -0,0 +1,39 @@ +From 10a1380a50e33f98d5030d75d9d356f7ce024556 Mon Sep 17 00:00:00 2001 +From: Gerd Hoffmann +Date: Wed, 29 Aug 2012 12:54:59 +0200 +Subject: [PATCH] xhci: add trace_usb_xhci_ep_set_dequeue + +Signed-off-by: Gerd Hoffmann +--- + hw/usb/hcd-xhci.c | 2 +- + trace-events | 1 + + 2 files changed, 2 insertions(+), 1 deletion(-) + +diff --git a/hw/usb/hcd-xhci.c b/hw/usb/hcd-xhci.c +index ab352c0..c6ab4a1 100644 +--- a/hw/usb/hcd-xhci.c ++++ b/hw/usb/hcd-xhci.c +@@ -1145,7 +1145,7 @@ static TRBCCode xhci_set_ep_dequeue(XHCIState *xhci, unsigned int slotid, + return CC_TRB_ERROR; + } + +- DPRINTF("xhci_set_ep_dequeue(%d, %d, %016"PRIx64")\n", slotid, epid, pdequeue); ++ trace_usb_xhci_ep_set_dequeue(slotid, epid, pdequeue); + dequeue = xhci_mask64(pdequeue); + + slot = &xhci->slots[slotid-1]; +diff --git a/trace-events b/trace-events +index b38e32a..2db1deb 100644 +--- a/trace-events ++++ b/trace-events +@@ -326,6 +326,7 @@ usb_xhci_slot_evaluate(uint32_t slotid) "slotid %d" + usb_xhci_slot_reset(uint32_t slotid) "slotid %d" + usb_xhci_ep_enable(uint32_t slotid, uint32_t epid) "slotid %d, epid %d" + usb_xhci_ep_disable(uint32_t slotid, uint32_t epid) "slotid %d, epid %d" ++usb_xhci_ep_set_dequeue(uint32_t slotid, uint32_t epid, uint64_t param) "slotid %d, epid %d, ptr %016" PRIx64 + usb_xhci_ep_kick(uint32_t slotid, uint32_t epid) "slotid %d, epid %d" + usb_xhci_ep_stop(uint32_t slotid, uint32_t epid) "slotid %d, epid %d" + usb_xhci_ep_reset(uint32_t slotid, uint32_t epid) "slotid %d, epid %d" +-- +1.7.12.1 + diff --git a/0610-xhci-update-register-layout.patch b/0610-xhci-update-register-layout.patch new file mode 100644 index 0000000..6052e50 --- /dev/null +++ b/0610-xhci-update-register-layout.patch @@ -0,0 +1,63 @@ +From 79e9a5ca778bfcb67073bfecd3f7cea7d93781ce Mon Sep 17 00:00:00 2001 +From: Gerd Hoffmann +Date: Thu, 23 Aug 2012 13:26:25 +0200 +Subject: [PATCH] xhci: update register layout + +Change the register layout to be a bit more sparse and also not depend +on the number of ports. Useful when for making the number of ports +runtime-configurable. +--- + hw/usb/hcd-xhci.c | 21 +++++++++++++-------- + 1 file changed, 13 insertions(+), 8 deletions(-) + +diff --git a/hw/usb/hcd-xhci.c b/hw/usb/hcd-xhci.c +index c6ab4a1..d47539d 100644 +--- a/hw/usb/hcd-xhci.c ++++ b/hw/usb/hcd-xhci.c +@@ -36,13 +36,12 @@ + #define FIXME() do { fprintf(stderr, "FIXME %s:%d\n", \ + __func__, __LINE__); abort(); } while (0) + +-#define MAXSLOTS 8 +-#define MAXINTRS 1 +- + #define USB2_PORTS 4 + #define USB3_PORTS 4 + + #define MAXPORTS (USB2_PORTS+USB3_PORTS) ++#define MAXSLOTS MAXPORTS ++#define MAXINTRS 1 /* MAXPORTS */ + + #define TD_QUEUE 24 + +@@ -53,16 +52,22 @@ + #define ER_FULL_HACK + + #define LEN_CAP 0x40 +-#define OFF_OPER LEN_CAP + #define LEN_OPER (0x400 + 0x10 * MAXPORTS) +-#define OFF_RUNTIME ((OFF_OPER + LEN_OPER + 0x20) & ~0x1f) +-#define LEN_RUNTIME (0x20 + MAXINTRS * 0x20) +-#define OFF_DOORBELL (OFF_RUNTIME + LEN_RUNTIME) ++#define LEN_RUNTIME ((MAXINTRS + 1) * 0x20) + #define LEN_DOORBELL ((MAXSLOTS + 1) * 0x20) + ++#define OFF_OPER LEN_CAP ++#define OFF_RUNTIME 0x1000 ++#define OFF_DOORBELL 0x2000 + /* must be power of 2 */ +-#define LEN_REGS 0x2000 ++#define LEN_REGS 0x4000 + ++#if (OFF_OPER + LEN_OPER) > OFF_RUNTIME ++#error Increase OFF_RUNTIME ++#endif ++#if (OFF_RUNTIME + LEN_RUNTIME) > OFF_DOORBELL ++#error Increase OFF_DOORBELL ++#endif + #if (OFF_DOORBELL + LEN_DOORBELL) > LEN_REGS + # error Increase LEN_REGS + #endif +-- +1.7.12.1 + diff --git a/0611-xhci-update-port-handling.patch b/0611-xhci-update-port-handling.patch new file mode 100644 index 0000000..d47740a --- /dev/null +++ b/0611-xhci-update-port-handling.patch @@ -0,0 +1,352 @@ +From 0b1ccd39faa8d1ea71f2d02dbab5dfd13f54ac98 Mon Sep 17 00:00:00 2001 +From: Gerd Hoffmann +Date: Tue, 28 Aug 2012 13:38:01 +0200 +Subject: [PATCH] xhci: update port handling + +This patch changes the way xhci ports are linked to USBPorts. The fixed +1:1 relationship between xhci ports and USBPorts is gone. Now each +USBPort represents a physical plug which has usually two xhci ports +assigned: one usb2 and ond usb3 port. usb devices show up at one or the +other, depending on whenever they support superspeed or not. + +This patch also makes the number of usb2 and usb3 ports runtime +configurable by adding 'p2' and 'p3' properties. It is allowed to +have different numbers of usb2 and usb3 ports. Specifying p2=4,p3=2 +will give you an xhci adapter which supports all speeds on physical +ports 1+2 and usb2 only on ports 3+4. +--- + hw/usb/hcd-xhci.c | 137 ++++++++++++++++++++++++++++++++++++++---------------- + 1 file changed, 97 insertions(+), 40 deletions(-) + +diff --git a/hw/usb/hcd-xhci.c b/hw/usb/hcd-xhci.c +index d47539d..5813b4a 100644 +--- a/hw/usb/hcd-xhci.c ++++ b/hw/usb/hcd-xhci.c +@@ -36,10 +36,10 @@ + #define FIXME() do { fprintf(stderr, "FIXME %s:%d\n", \ + __func__, __LINE__); abort(); } while (0) + +-#define USB2_PORTS 4 +-#define USB3_PORTS 4 ++#define MAXPORTS_2 8 ++#define MAXPORTS_3 8 + +-#define MAXPORTS (USB2_PORTS+USB3_PORTS) ++#define MAXPORTS (MAXPORTS_2+MAXPORTS_3) + #define MAXSLOTS MAXPORTS + #define MAXINTRS 1 /* MAXPORTS */ + +@@ -300,8 +300,10 @@ typedef struct XHCIRing { + } XHCIRing; + + typedef struct XHCIPort { +- USBPort port; + uint32_t portsc; ++ uint32_t portnr; ++ USBPort *uport; ++ uint32_t speedmask; + } XHCIPort; + + struct XHCIState; +@@ -379,9 +381,13 @@ struct XHCIState { + qemu_irq irq; + MemoryRegion mem; + const char *name; +- uint32_t msi; + unsigned int devaddr; + ++ /* properties */ ++ uint32_t numports_2; ++ uint32_t numports_3; ++ uint32_t msi; ++ + /* Operational Registers */ + uint32_t usbcmd; + uint32_t usbsts; +@@ -392,8 +398,10 @@ struct XHCIState { + uint32_t dcbaap_high; + uint32_t config; + ++ USBPort uports[MAX(MAXPORTS_2, MAXPORTS_3)]; + XHCIPort ports[MAXPORTS]; + XHCISlot slots[MAXSLOTS]; ++ uint32_t numports; + + /* Runtime Registers */ + uint32_t iman; +@@ -578,6 +586,28 @@ static inline dma_addr_t xhci_mask64(uint64_t addr) + } + } + ++static XHCIPort *xhci_lookup_port(XHCIState *xhci, struct USBPort *uport) ++{ ++ int index; ++ ++ if (!uport->dev) { ++ return NULL; ++ } ++ switch (uport->dev->speed) { ++ case USB_SPEED_LOW: ++ case USB_SPEED_FULL: ++ case USB_SPEED_HIGH: ++ index = uport->index; ++ break; ++ case USB_SPEED_SUPER: ++ index = uport->index + xhci->numports_2; ++ break; ++ default: ++ return NULL; ++ } ++ return &xhci->ports[index]; ++} ++ + static void xhci_irq_update(XHCIState *xhci) + { + int level = 0; +@@ -1126,7 +1156,7 @@ static TRBCCode xhci_reset_ep(XHCIState *xhci, unsigned int slotid, + ep |= 0x80; + } + +- dev = xhci->ports[xhci->slots[slotid-1].port-1].port.dev; ++ dev = xhci->ports[xhci->slots[slotid-1].port-1].uport->dev; + if (!dev) { + return CC_USB_TRANSACTION_ERROR; + } +@@ -1313,7 +1343,7 @@ static USBDevice *xhci_find_device(XHCIPort *port, uint8_t addr) + if (!(port->portsc & PORTSC_PED)) { + return NULL; + } +- return usb_find_device(&port->port, addr); ++ return usb_find_device(port->uport, addr); + } + + static int xhci_setup_packet(XHCITransfer *xfer) +@@ -1734,9 +1764,9 @@ static TRBCCode xhci_address_slot(XHCIState *xhci, unsigned int slotid, + ep0_ctx[0], ep0_ctx[1], ep0_ctx[2], ep0_ctx[3], ep0_ctx[4]); + + port = (slot_ctx[1]>>16) & 0xFF; +- dev = xhci->ports[port-1].port.dev; ++ dev = xhci->ports[port-1].uport->dev; + +- if (port < 1 || port > MAXPORTS) { ++ if (port < 1 || port > xhci->numports) { + fprintf(stderr, "xhci: bad port %d\n", port); + return CC_TRB_ERROR; + } else if (!dev) { +@@ -1985,7 +2015,7 @@ static unsigned int xhci_get_slot(XHCIState *xhci, XHCIEvent *event, XHCITRB *tr + static TRBCCode xhci_get_port_bandwidth(XHCIState *xhci, uint64_t pctx) + { + dma_addr_t ctx; +- uint8_t bw_ctx[MAXPORTS+1]; ++ uint8_t bw_ctx[xhci->numports+1]; + + DPRINTF("xhci_get_port_bandwidth()\n"); + +@@ -1995,7 +2025,7 @@ static TRBCCode xhci_get_port_bandwidth(XHCIState *xhci, uint64_t pctx) + + /* TODO: actually implement real values here */ + bw_ctx[0] = 0; +- memset(&bw_ctx[1], 80, MAXPORTS); /* 80% */ ++ memset(&bw_ctx[1], 80, xhci->numports); /* 80% */ + pci_dma_write(&xhci->pci_dev, ctx, bw_ctx, sizeof(bw_ctx)); + + return CC_SUCCESS; +@@ -2165,12 +2195,11 @@ static void xhci_process_commands(XHCIState *xhci) + + static void xhci_update_port(XHCIState *xhci, XHCIPort *port, int is_detach) + { +- int nr = port->port.index + 1; +- + port->portsc = PORTSC_PP; +- if (port->port.dev && port->port.dev->attached && !is_detach) { ++ if (port->uport->dev && port->uport->dev->attached && !is_detach && ++ (1 << port->uport->dev->speed) & port->speedmask) { + port->portsc |= PORTSC_CCS; +- switch (port->port.dev->speed) { ++ switch (port->uport->dev->speed) { + case USB_SPEED_LOW: + port->portsc |= PORTSC_SPEED_LOW; + break; +@@ -2180,14 +2209,18 @@ static void xhci_update_port(XHCIState *xhci, XHCIPort *port, int is_detach) + case USB_SPEED_HIGH: + port->portsc |= PORTSC_SPEED_HIGH; + break; ++ case USB_SPEED_SUPER: ++ port->portsc |= PORTSC_SPEED_SUPER; ++ break; + } + } + + if (xhci_running(xhci)) { + port->portsc |= PORTSC_CSC; +- XHCIEvent ev = { ER_PORT_STATUS_CHANGE, CC_SUCCESS, nr << 24}; ++ XHCIEvent ev = { ER_PORT_STATUS_CHANGE, CC_SUCCESS, ++ port->portnr << 24}; + xhci_event(xhci, &ev); +- DPRINTF("xhci: port change event for port %d\n", nr); ++ DPRINTF("xhci: port change event for port %d\n", port->portnr); + } + } + +@@ -2215,7 +2248,7 @@ static void xhci_reset(DeviceState *dev) + xhci_disable_slot(xhci, i+1); + } + +- for (i = 0; i < MAXPORTS; i++) { ++ for (i = 0; i < xhci->numports; i++) { + xhci_update_port(xhci, xhci->ports + i, 0); + } + +@@ -2246,7 +2279,8 @@ static uint32_t xhci_cap_read(XHCIState *xhci, uint32_t reg) + ret = 0x01000000 | LEN_CAP; + break; + case 0x04: /* HCSPARAMS 1 */ +- ret = (MAXPORTS<<24) | (MAXINTRS<<8) | MAXSLOTS; ++ ret = ((xhci->numports_2+xhci->numports_3)<<24) ++ | (MAXINTRS<<8) | MAXSLOTS; + break; + case 0x08: /* HCSPARAMS 2 */ + ret = 0x0000000f; +@@ -2276,7 +2310,7 @@ static uint32_t xhci_cap_read(XHCIState *xhci, uint32_t reg) + ret = 0x20425455; /* "USB " */ + break; + case 0x28: /* Supported Protocol:08 */ +- ret = 0x00000001 | (USB2_PORTS<<8); ++ ret = 0x00000001 | (xhci->numports_2<<8); + break; + case 0x2c: /* Supported Protocol:0c */ + ret = 0x00000000; /* reserved */ +@@ -2288,7 +2322,7 @@ static uint32_t xhci_cap_read(XHCIState *xhci, uint32_t reg) + ret = 0x20425455; /* "USB " */ + break; + case 0x38: /* Supported Protocol:08 */ +- ret = 0x00000000 | (USB2_PORTS+1) | (USB3_PORTS<<8); ++ ret = 0x00000000 | (xhci->numports_2+1) | (xhci->numports_3<<8); + break; + case 0x3c: /* Supported Protocol:0c */ + ret = 0x00000000; /* reserved */ +@@ -2307,7 +2341,7 @@ static uint32_t xhci_port_read(XHCIState *xhci, uint32_t reg) + uint32_t port = reg >> 4; + uint32_t ret; + +- if (port >= MAXPORTS) { ++ if (port >= xhci->numports) { + fprintf(stderr, "xhci_port_read: port %d out of bounds\n", port); + ret = 0; + goto out; +@@ -2340,7 +2374,7 @@ static void xhci_port_write(XHCIState *xhci, uint32_t reg, uint32_t val) + + trace_usb_xhci_port_write(port, reg & 0x0f, val); + +- if (port >= MAXPORTS) { ++ if (port >= xhci->numports) { + fprintf(stderr, "xhci_port_read: port %d out of bounds\n", port); + return; + } +@@ -2362,7 +2396,7 @@ static void xhci_port_write(XHCIState *xhci, uint32_t reg, uint32_t val) + /* write-1-to-start bits */ + if (val & PORTSC_PR) { + DPRINTF("xhci: port %d reset\n", port); +- usb_device_reset(xhci->ports[port].port.dev); ++ usb_device_reset(xhci->ports[port].uport->dev); + portsc |= PORTSC_PRC | PORTSC_PED; + } + xhci->ports[port].portsc = portsc; +@@ -2659,7 +2693,7 @@ static const MemoryRegionOps xhci_mem_ops = { + static void xhci_attach(USBPort *usbport) + { + XHCIState *xhci = usbport->opaque; +- XHCIPort *port = &xhci->ports[usbport->index]; ++ XHCIPort *port = xhci_lookup_port(xhci, usbport); + + xhci_update_port(xhci, port, 0); + } +@@ -2667,7 +2701,7 @@ static void xhci_attach(USBPort *usbport) + static void xhci_detach(USBPort *usbport) + { + XHCIState *xhci = usbport->opaque; +- XHCIPort *port = &xhci->ports[usbport->index]; ++ XHCIPort *port = xhci_lookup_port(xhci, usbport); + + xhci_update_port(xhci, port, 1); + } +@@ -2675,9 +2709,9 @@ static void xhci_detach(USBPort *usbport) + static void xhci_wakeup(USBPort *usbport) + { + XHCIState *xhci = usbport->opaque; +- XHCIPort *port = &xhci->ports[usbport->index]; +- int nr = port->port.index + 1; +- XHCIEvent ev = { ER_PORT_STATUS_CHANGE, CC_SUCCESS, nr << 24}; ++ XHCIPort *port = xhci_lookup_port(xhci, usbport); ++ XHCIEvent ev = { ER_PORT_STATUS_CHANGE, CC_SUCCESS, ++ port->portnr << 24}; + uint32_t pls; + + pls = (port->portsc >> PORTSC_PLS_SHIFT) & PORTSC_PLS_MASK; +@@ -2759,22 +2793,43 @@ static USBBusOps xhci_bus_ops = { + + static void usb_xhci_init(XHCIState *xhci, DeviceState *dev) + { +- int i; ++ XHCIPort *port; ++ int i, usbports, speedmask; + + xhci->usbsts = USBSTS_HCH; + ++ if (xhci->numports_2 > MAXPORTS_2) { ++ xhci->numports_2 = MAXPORTS_2; ++ } ++ if (xhci->numports_3 > MAXPORTS_3) { ++ xhci->numports_3 = MAXPORTS_3; ++ } ++ usbports = MAX(xhci->numports_2, xhci->numports_3); ++ xhci->numports = xhci->numports_2 + xhci->numports_3; ++ + usb_bus_new(&xhci->bus, &xhci_bus_ops, &xhci->pci_dev.qdev); + +- for (i = 0; i < MAXPORTS; i++) { +- memset(&xhci->ports[i], 0, sizeof(xhci->ports[i])); +- usb_register_port(&xhci->bus, &xhci->ports[i].port, xhci, i, +- &xhci_port_ops, +- USB_SPEED_MASK_LOW | +- USB_SPEED_MASK_FULL | +- USB_SPEED_MASK_HIGH); +- } +- for (i = 0; i < MAXSLOTS; i++) { +- xhci->slots[i].enabled = 0; ++ for (i = 0; i < usbports; i++) { ++ speedmask = 0; ++ if (i < xhci->numports_2) { ++ port = &xhci->ports[i]; ++ port->portnr = i + 1; ++ port->uport = &xhci->uports[i]; ++ port->speedmask = ++ USB_SPEED_MASK_LOW | ++ USB_SPEED_MASK_FULL | ++ USB_SPEED_MASK_HIGH; ++ speedmask |= port->speedmask; ++ } ++ if (i < xhci->numports_3) { ++ port = &xhci->ports[i + xhci->numports_2]; ++ port->portnr = i + 1 + xhci->numports_2; ++ port->uport = &xhci->uports[i]; ++ port->speedmask = USB_SPEED_MASK_SUPER; ++ speedmask |= port->speedmask; ++ } ++ usb_register_port(&xhci->bus, &xhci->uports[i], xhci, i, ++ &xhci_port_ops, speedmask); + } + } + +@@ -2830,6 +2885,8 @@ static const VMStateDescription vmstate_xhci = { + + static Property xhci_properties[] = { + DEFINE_PROP_UINT32("msi", XHCIState, msi, 0), ++ DEFINE_PROP_UINT32("p2", XHCIState, numports_2, 4), ++ DEFINE_PROP_UINT32("p3", XHCIState, numports_3, 4), + DEFINE_PROP_END_OF_LIST(), + }; + +-- +1.7.12.1 + diff --git a/0612-usb3-superspeed-descriptors.patch b/0612-usb3-superspeed-descriptors.patch new file mode 100644 index 0000000..4c60573 --- /dev/null +++ b/0612-usb3-superspeed-descriptors.patch @@ -0,0 +1,64 @@ +From 81e37421158a28277c9857ba733da4371cb06129 Mon Sep 17 00:00:00 2001 +From: Gerd Hoffmann +Date: Tue, 28 Aug 2012 17:28:50 +0200 +Subject: [PATCH] usb3: superspeed descriptors + +Add superspeed descriptor entry to USBDesc, +advertise superspeed support when present. + +Signed-off-by: Gerd Hoffmann +--- + hw/usb/desc.c | 10 +++++++++- + hw/usb/desc.h | 1 + + 2 files changed, 10 insertions(+), 1 deletion(-) + +diff --git a/hw/usb/desc.c b/hw/usb/desc.c +index 0a9d3c9..3e8c6cb 100644 +--- a/hw/usb/desc.c ++++ b/hw/usb/desc.c +@@ -359,6 +359,9 @@ static void usb_desc_setdefaults(USBDevice *dev) + case USB_SPEED_HIGH: + dev->device = desc->high; + break; ++ case USB_SPEED_SUPER: ++ dev->device = desc->super; ++ break; + } + usb_desc_set_config(dev, 0); + } +@@ -376,6 +379,9 @@ void usb_desc_init(USBDevice *dev) + if (desc->high) { + dev->speedmask |= USB_SPEED_MASK_HIGH; + } ++ if (desc->super) { ++ dev->speedmask |= USB_SPEED_MASK_SUPER; ++ } + usb_desc_setdefaults(dev); + } + +@@ -384,7 +390,9 @@ void usb_desc_attach(USBDevice *dev) + const USBDesc *desc = usb_device_get_usb_desc(dev); + + assert(desc != NULL); +- if (desc->high && (dev->port->speedmask & USB_SPEED_MASK_HIGH)) { ++ if (desc->super && (dev->port->speedmask & USB_SPEED_MASK_SUPER)) { ++ dev->speed = USB_SPEED_SUPER; ++ } else if (desc->high && (dev->port->speedmask & USB_SPEED_MASK_HIGH)) { + dev->speed = USB_SPEED_HIGH; + } else if (desc->full && (dev->port->speedmask & USB_SPEED_MASK_FULL)) { + dev->speed = USB_SPEED_FULL; +diff --git a/hw/usb/desc.h b/hw/usb/desc.h +index 7cf5442..d89fa41 100644 +--- a/hw/usb/desc.h ++++ b/hw/usb/desc.h +@@ -152,6 +152,7 @@ struct USBDesc { + USBDescID id; + const USBDescDevice *full; + const USBDescDevice *high; ++ const USBDescDevice *super; + const char* const *str; + }; + +-- +1.7.12.1 + diff --git a/0613-usb3-superspeed-endpoint-companion.patch b/0613-usb3-superspeed-endpoint-companion.patch new file mode 100644 index 0000000..40983e4 --- /dev/null +++ b/0613-usb3-superspeed-endpoint-companion.patch @@ -0,0 +1,248 @@ +From e0354b4f91dd198b5bfe1ddf649588d6af84ea9c Mon Sep 17 00:00:00 2001 +From: Gerd Hoffmann +Date: Tue, 28 Aug 2012 17:28:03 +0200 +Subject: [PATCH] usb3: superspeed endpoint companion + +Add support for building superspeed endpoint companion descriptors, +create them for superspeed usb devices. + +Signed-off-by: Gerd Hoffmann +--- + hw/usb.h | 1 + + hw/usb/desc.c | 55 ++++++++++++++++++++++++++++++++++++++++--------------- + hw/usb/desc.h | 26 +++++++++++++++++++++----- + 3 files changed, 62 insertions(+), 20 deletions(-) + +diff --git a/hw/usb.h b/hw/usb.h +index 684e3f4..78ffdf4 100644 +--- a/hw/usb.h ++++ b/hw/usb.h +@@ -137,6 +137,7 @@ + #define USB_DT_INTERFACE_ASSOC 0x0B + #define USB_DT_CS_INTERFACE 0x24 + #define USB_DT_CS_ENDPOINT 0x25 ++#define USB_DT_ENDPOINT_COMPANION 0x30 + + #define USB_ENDPOINT_XFER_CONTROL 0 + #define USB_ENDPOINT_XFER_ISOC 1 +diff --git a/hw/usb/desc.c b/hw/usb/desc.c +index 3e8c6cb..8f5a8e5 100644 +--- a/hw/usb/desc.c ++++ b/hw/usb/desc.c +@@ -76,7 +76,8 @@ int usb_desc_device_qualifier(const USBDescDevice *dev, + return bLength; + } + +-int usb_desc_config(const USBDescConfig *conf, uint8_t *dest, size_t len) ++int usb_desc_config(const USBDescConfig *conf, int flags, ++ uint8_t *dest, size_t len) + { + uint8_t bLength = 0x09; + uint16_t wTotalLength = 0; +@@ -99,7 +100,7 @@ int usb_desc_config(const USBDescConfig *conf, uint8_t *dest, size_t len) + + /* handle grouped interfaces if any */ + for (i = 0; i < conf->nif_groups; i++) { +- rc = usb_desc_iface_group(&(conf->if_groups[i]), ++ rc = usb_desc_iface_group(&(conf->if_groups[i]), flags, + dest + wTotalLength, + len - wTotalLength); + if (rc < 0) { +@@ -110,7 +111,8 @@ int usb_desc_config(const USBDescConfig *conf, uint8_t *dest, size_t len) + + /* handle normal (ungrouped / no IAD) interfaces if any */ + for (i = 0; i < conf->nif; i++) { +- rc = usb_desc_iface(conf->ifs + i, dest + wTotalLength, len - wTotalLength); ++ rc = usb_desc_iface(conf->ifs + i, flags, ++ dest + wTotalLength, len - wTotalLength); + if (rc < 0) { + return rc; + } +@@ -122,8 +124,8 @@ int usb_desc_config(const USBDescConfig *conf, uint8_t *dest, size_t len) + return wTotalLength; + } + +-int usb_desc_iface_group(const USBDescIfaceAssoc *iad, uint8_t *dest, +- size_t len) ++int usb_desc_iface_group(const USBDescIfaceAssoc *iad, int flags, ++ uint8_t *dest, size_t len) + { + int pos = 0; + int i = 0; +@@ -147,7 +149,7 @@ int usb_desc_iface_group(const USBDescIfaceAssoc *iad, uint8_t *dest, + + /* handle associated interfaces in this group */ + for (i = 0; i < iad->nif; i++) { +- int rc = usb_desc_iface(&(iad->ifs[i]), dest + pos, len - pos); ++ int rc = usb_desc_iface(&(iad->ifs[i]), flags, dest + pos, len - pos); + if (rc < 0) { + return rc; + } +@@ -157,7 +159,8 @@ int usb_desc_iface_group(const USBDescIfaceAssoc *iad, uint8_t *dest, + return pos; + } + +-int usb_desc_iface(const USBDescIface *iface, uint8_t *dest, size_t len) ++int usb_desc_iface(const USBDescIface *iface, int flags, ++ uint8_t *dest, size_t len) + { + uint8_t bLength = 0x09; + int i, rc, pos = 0; +@@ -188,7 +191,7 @@ int usb_desc_iface(const USBDescIface *iface, uint8_t *dest, size_t len) + } + + for (i = 0; i < iface->bNumEndpoints; i++) { +- rc = usb_desc_endpoint(iface->eps + i, dest + pos, len - pos); ++ rc = usb_desc_endpoint(iface->eps + i, flags, dest + pos, len - pos); + if (rc < 0) { + return rc; + } +@@ -198,13 +201,15 @@ int usb_desc_iface(const USBDescIface *iface, uint8_t *dest, size_t len) + return pos; + } + +-int usb_desc_endpoint(const USBDescEndpoint *ep, uint8_t *dest, size_t len) ++int usb_desc_endpoint(const USBDescEndpoint *ep, int flags, ++ uint8_t *dest, size_t len) + { + uint8_t bLength = ep->is_audio ? 0x09 : 0x07; + uint8_t extralen = ep->extra ? ep->extra[0] : 0; ++ uint8_t superlen = (flags & USB_DESC_FLAG_SUPER) ? 0x06 : 0; + USBDescriptor *d = (void *)dest; + +- if (len < bLength + extralen) { ++ if (len < bLength + extralen + superlen) { + return -1; + } + +@@ -224,7 +229,21 @@ int usb_desc_endpoint(const USBDescEndpoint *ep, uint8_t *dest, size_t len) + memcpy(dest + bLength, ep->extra, extralen); + } + +- return bLength + extralen; ++ if (superlen) { ++ USBDescriptor *d = (void *)(dest + bLength + extralen); ++ ++ d->bLength = 0x06; ++ d->bDescriptorType = USB_DT_ENDPOINT_COMPANION; ++ ++ d->u.super_endpoint.bMaxBurst = ep->bMaxBurst; ++ d->u.super_endpoint.bmAttributes = ep->bmAttributes_super; ++ d->u.super_endpoint.wBytesPerInterval_lo = ++ usb_lo(ep->wBytesPerInterval); ++ d->u.super_endpoint.wBytesPerInterval_hi = ++ usb_hi(ep->wBytesPerInterval); ++ } ++ ++ return bLength + extralen + superlen; + } + + int usb_desc_other(const USBDescOther *desc, uint8_t *dest, size_t len) +@@ -509,7 +528,7 @@ int usb_desc_get_descriptor(USBDevice *dev, int value, uint8_t *dest, size_t len + uint8_t buf[256]; + uint8_t type = value >> 8; + uint8_t index = value & 0xff; +- int ret = -1; ++ int flags, ret = -1; + + if (dev->speed == USB_SPEED_HIGH) { + other_dev = usb_device_get_usb_desc(dev)->full; +@@ -517,6 +536,11 @@ int usb_desc_get_descriptor(USBDevice *dev, int value, uint8_t *dest, size_t len + other_dev = usb_device_get_usb_desc(dev)->high; + } + ++ flags = 0; ++ if (dev->device->bcdUSB >= 0x0300) { ++ flags |= USB_DESC_FLAG_SUPER; ++ } ++ + switch(type) { + case USB_DT_DEVICE: + ret = usb_desc_device(&desc->id, dev->device, buf, sizeof(buf)); +@@ -524,7 +548,8 @@ int usb_desc_get_descriptor(USBDevice *dev, int value, uint8_t *dest, size_t len + break; + case USB_DT_CONFIG: + if (index < dev->device->bNumConfigurations) { +- ret = usb_desc_config(dev->device->confs + index, buf, sizeof(buf)); ++ ret = usb_desc_config(dev->device->confs + index, flags, ++ buf, sizeof(buf)); + } + trace_usb_desc_config(dev->addr, index, len, ret); + break; +@@ -532,7 +557,6 @@ int usb_desc_get_descriptor(USBDevice *dev, int value, uint8_t *dest, size_t len + ret = usb_desc_string(dev, index, buf, sizeof(buf)); + trace_usb_desc_string(dev->addr, index, len, ret); + break; +- + case USB_DT_DEVICE_QUALIFIER: + if (other_dev != NULL) { + ret = usb_desc_device_qualifier(other_dev, buf, sizeof(buf)); +@@ -541,7 +565,8 @@ int usb_desc_get_descriptor(USBDevice *dev, int value, uint8_t *dest, size_t len + break; + case USB_DT_OTHER_SPEED_CONFIG: + if (other_dev != NULL && index < other_dev->bNumConfigurations) { +- ret = usb_desc_config(other_dev->confs + index, buf, sizeof(buf)); ++ ret = usb_desc_config(other_dev->confs + index, flags, ++ buf, sizeof(buf)); + buf[0x01] = USB_DT_OTHER_SPEED_CONFIG; + } + trace_usb_desc_other_speed_config(dev->addr, index, len, ret); +diff --git a/hw/usb/desc.h b/hw/usb/desc.h +index d89fa41..4b5e88d 100644 +--- a/hw/usb/desc.h ++++ b/hw/usb/desc.h +@@ -63,6 +63,12 @@ typedef struct USBDescriptor { + uint8_t bRefresh; /* only audio ep */ + uint8_t bSynchAddress; /* only audio ep */ + } endpoint; ++ struct { ++ uint8_t bMaxBurst; ++ uint8_t bmAttributes; ++ uint8_t wBytesPerInterval_lo; ++ uint8_t wBytesPerInterval_hi; ++ } super_endpoint; + } u; + } QEMU_PACKED USBDescriptor; + +@@ -139,6 +145,11 @@ struct USBDescEndpoint { + + uint8_t is_audio; /* has bRefresh + bSynchAddress */ + uint8_t *extra; ++ ++ /* superspeed endpoint companion */ ++ uint8_t bMaxBurst; ++ uint8_t bmAttributes_super; ++ uint16_t wBytesPerInterval; + }; + + struct USBDescOther { +@@ -156,16 +167,21 @@ struct USBDesc { + const char* const *str; + }; + ++#define USB_DESC_FLAG_SUPER (1 << 1) ++ + /* generate usb packages from structs */ + int usb_desc_device(const USBDescID *id, const USBDescDevice *dev, + uint8_t *dest, size_t len); + int usb_desc_device_qualifier(const USBDescDevice *dev, + uint8_t *dest, size_t len); +-int usb_desc_config(const USBDescConfig *conf, uint8_t *dest, size_t len); +-int usb_desc_iface_group(const USBDescIfaceAssoc *iad, uint8_t *dest, +- size_t len); +-int usb_desc_iface(const USBDescIface *iface, uint8_t *dest, size_t len); +-int usb_desc_endpoint(const USBDescEndpoint *ep, uint8_t *dest, size_t len); ++int usb_desc_config(const USBDescConfig *conf, int flags, ++ uint8_t *dest, size_t len); ++int usb_desc_iface_group(const USBDescIfaceAssoc *iad, int flags, ++ uint8_t *dest, size_t len); ++int usb_desc_iface(const USBDescIface *iface, int flags, ++ uint8_t *dest, size_t len); ++int usb_desc_endpoint(const USBDescEndpoint *ep, int flags, ++ uint8_t *dest, size_t len); + int usb_desc_other(const USBDescOther *desc, uint8_t *dest, size_t len); + + /* control message emulation helpers */ +-- +1.7.12.1 + diff --git a/0614-usb3-bos-decriptor.patch b/0614-usb3-bos-decriptor.patch new file mode 100644 index 0000000..99d4f81 --- /dev/null +++ b/0614-usb3-bos-decriptor.patch @@ -0,0 +1,215 @@ +From 2014680cdc2834fef9b4cee5e1239f22d8dbdba3 Mon Sep 17 00:00:00 2001 +From: Gerd Hoffmann +Date: Tue, 28 Aug 2012 17:46:29 +0200 +Subject: [PATCH] usb3: bos decriptor + +Add support for creating BOS descriptor and +device cappability descriptors. + +Signed-off-by: Gerd Hoffmann +--- + hw/usb.h | 6 ++++ + hw/usb/desc.c | 109 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + hw/usb/desc.h | 25 ++++++++++++++ + trace-events | 1 + + 4 files changed, 141 insertions(+) + +diff --git a/hw/usb.h b/hw/usb.h +index 78ffdf4..48c8926 100644 +--- a/hw/usb.h ++++ b/hw/usb.h +@@ -135,10 +135,16 @@ + #define USB_DT_OTHER_SPEED_CONFIG 0x07 + #define USB_DT_DEBUG 0x0A + #define USB_DT_INTERFACE_ASSOC 0x0B ++#define USB_DT_BOS 0x0F ++#define USB_DT_DEVICE_CAPABILITY 0x10 + #define USB_DT_CS_INTERFACE 0x24 + #define USB_DT_CS_ENDPOINT 0x25 + #define USB_DT_ENDPOINT_COMPANION 0x30 + ++#define USB_DEV_CAP_WIRELESS 0x01 ++#define USB_DEV_CAP_USB2_EXT 0x02 ++#define USB_DEV_CAP_SUPERSPEED 0x03 ++ + #define USB_ENDPOINT_XFER_CONTROL 0 + #define USB_ENDPOINT_XFER_ISOC 1 + #define USB_ENDPOINT_XFER_BULK 2 +diff --git a/hw/usb/desc.c b/hw/usb/desc.c +index 8f5a8e5..1f12eae 100644 +--- a/hw/usb/desc.c ++++ b/hw/usb/desc.c +@@ -258,6 +258,111 @@ int usb_desc_other(const USBDescOther *desc, uint8_t *dest, size_t len) + return bLength; + } + ++static int usb_desc_cap_usb2_ext(const USBDesc *desc, uint8_t *dest, size_t len) ++{ ++ uint8_t bLength = 0x07; ++ USBDescriptor *d = (void *)dest; ++ ++ if (len < bLength) { ++ return -1; ++ } ++ ++ d->bLength = bLength; ++ d->bDescriptorType = USB_DT_DEVICE_CAPABILITY; ++ d->u.cap.bDevCapabilityType = USB_DEV_CAP_USB2_EXT; ++ ++ d->u.cap.u.usb2_ext.bmAttributes_1 = (1 << 1); /* LPM */ ++ d->u.cap.u.usb2_ext.bmAttributes_2 = 0; ++ d->u.cap.u.usb2_ext.bmAttributes_3 = 0; ++ d->u.cap.u.usb2_ext.bmAttributes_4 = 0; ++ ++ return bLength; ++} ++ ++static int usb_desc_cap_super(const USBDesc *desc, uint8_t *dest, size_t len) ++{ ++ uint8_t bLength = 0x0a; ++ USBDescriptor *d = (void *)dest; ++ ++ if (len < bLength) { ++ return -1; ++ } ++ ++ d->bLength = bLength; ++ d->bDescriptorType = USB_DT_DEVICE_CAPABILITY; ++ d->u.cap.bDevCapabilityType = USB_DEV_CAP_SUPERSPEED; ++ ++ d->u.cap.u.super.bmAttributes = 0; ++ d->u.cap.u.super.wSpeedsSupported_lo = 0; ++ d->u.cap.u.super.wSpeedsSupported_hi = 0; ++ d->u.cap.u.super.bFunctionalitySupport = 0; ++ d->u.cap.u.super.bU1DevExitLat = 0x0a; ++ d->u.cap.u.super.wU2DevExitLat_lo = 0x20; ++ d->u.cap.u.super.wU2DevExitLat_hi = 0; ++ ++ if (desc->full) { ++ d->u.cap.u.super.wSpeedsSupported_lo |= (1 << 1); ++ d->u.cap.u.super.bFunctionalitySupport = 1; ++ } ++ if (desc->high) { ++ d->u.cap.u.super.wSpeedsSupported_lo |= (1 << 2); ++ if (!d->u.cap.u.super.bFunctionalitySupport) { ++ d->u.cap.u.super.bFunctionalitySupport = 2; ++ } ++ } ++ if (desc->super) { ++ d->u.cap.u.super.wSpeedsSupported_lo |= (1 << 3); ++ if (!d->u.cap.u.super.bFunctionalitySupport) { ++ d->u.cap.u.super.bFunctionalitySupport = 3; ++ } ++ } ++ ++ return bLength; ++} ++ ++static int usb_desc_bos(const USBDesc *desc, uint8_t *dest, size_t len) ++{ ++ uint8_t bLength = 0x05; ++ uint16_t wTotalLength = 0; ++ uint8_t bNumDeviceCaps = 0; ++ USBDescriptor *d = (void *)dest; ++ int rc; ++ ++ if (len < bLength) { ++ return -1; ++ } ++ ++ d->bLength = bLength; ++ d->bDescriptorType = USB_DT_BOS; ++ ++ wTotalLength += bLength; ++ ++ if (desc->high != NULL) { ++ rc = usb_desc_cap_usb2_ext(desc, dest + wTotalLength, ++ len - wTotalLength); ++ if (rc < 0) { ++ return rc; ++ } ++ wTotalLength += rc; ++ bNumDeviceCaps++; ++ } ++ ++ if (desc->super != NULL) { ++ rc = usb_desc_cap_super(desc, dest + wTotalLength, ++ len - wTotalLength); ++ if (rc < 0) { ++ return rc; ++ } ++ wTotalLength += rc; ++ bNumDeviceCaps++; ++ } ++ ++ d->u.bos.wTotalLength_lo = usb_lo(wTotalLength); ++ d->u.bos.wTotalLength_hi = usb_hi(wTotalLength); ++ d->u.bos.bNumDeviceCaps = bNumDeviceCaps; ++ return wTotalLength; ++} ++ + /* ------------------------------------------------------------------ */ + + static void usb_desc_ep_init(USBDevice *dev) +@@ -571,6 +676,10 @@ int usb_desc_get_descriptor(USBDevice *dev, int value, uint8_t *dest, size_t len + } + trace_usb_desc_other_speed_config(dev->addr, index, len, ret); + break; ++ case USB_DT_BOS: ++ ret = usb_desc_bos(desc, buf, sizeof(buf)); ++ trace_usb_desc_bos(dev->addr, len, ret); ++ break; + + case USB_DT_DEBUG: + /* ignore silently */ +diff --git a/hw/usb/desc.h b/hw/usb/desc.h +index 4b5e88d..68bb570 100644 +--- a/hw/usb/desc.h ++++ b/hw/usb/desc.h +@@ -69,6 +69,31 @@ typedef struct USBDescriptor { + uint8_t wBytesPerInterval_lo; + uint8_t wBytesPerInterval_hi; + } super_endpoint; ++ struct { ++ uint8_t wTotalLength_lo; ++ uint8_t wTotalLength_hi; ++ uint8_t bNumDeviceCaps; ++ } bos; ++ struct { ++ uint8_t bDevCapabilityType; ++ union { ++ struct { ++ uint8_t bmAttributes_1; ++ uint8_t bmAttributes_2; ++ uint8_t bmAttributes_3; ++ uint8_t bmAttributes_4; ++ } usb2_ext; ++ struct { ++ uint8_t bmAttributes; ++ uint8_t wSpeedsSupported_lo; ++ uint8_t wSpeedsSupported_hi; ++ uint8_t bFunctionalitySupport; ++ uint8_t bU1DevExitLat; ++ uint8_t wU2DevExitLat_lo; ++ uint8_t wU2DevExitLat_hi; ++ } super; ++ } u; ++ } cap; + } u; + } QEMU_PACKED USBDescriptor; + +diff --git a/trace-events b/trace-events +index 2db1deb..d941e78 100644 +--- a/trace-events ++++ b/trace-events +@@ -343,6 +343,7 @@ usb_desc_device_qualifier(int addr, int len, int ret) "dev %d query device quali + usb_desc_config(int addr, int index, int len, int ret) "dev %d query config %d, len %d, ret %d" + usb_desc_other_speed_config(int addr, int index, int len, int ret) "dev %d query config %d, len %d, ret %d" + usb_desc_string(int addr, int index, int len, int ret) "dev %d query string %d, len %d, ret %d" ++usb_desc_bos(int addr, int len, int ret) "dev %d bos, len %d, ret %d" + usb_set_addr(int addr) "dev %d" + usb_set_config(int addr, int config, int ret) "dev %d, config %d, ret %d" + usb_set_interface(int addr, int iface, int alt, int ret) "dev %d, interface %d, altsetting %d, ret %d" +-- +1.7.12.1 + diff --git a/0615-usb-storage-usb3-support.patch b/0615-usb-storage-usb3-support.patch new file mode 100644 index 0000000..7caeb42 --- /dev/null +++ b/0615-usb-storage-usb3-support.patch @@ -0,0 +1,94 @@ +From 9a6fd10bf6a85c4df63a7ba1cf7d6203220d722e Mon Sep 17 00:00:00 2001 +From: Gerd Hoffmann +Date: Tue, 28 Aug 2012 17:29:15 +0200 +Subject: [PATCH] usb-storage: usb3 support + +Add usb3 descriptors to usb-storage, so it shows up as superspeed +device when connected to xhci. + +Signed-off-by: Gerd Hoffmann +--- + hw/usb/dev-storage.c | 46 +++++++++++++++++++++++++++++++++++++++++++--- + 1 file changed, 43 insertions(+), 3 deletions(-) + +diff --git a/hw/usb/dev-storage.c b/hw/usb/dev-storage.c +index ff48d91..e732191 100644 +--- a/hw/usb/dev-storage.c ++++ b/hw/usb/dev-storage.c +@@ -78,6 +78,7 @@ enum { + STR_SERIALNUMBER, + STR_CONFIG_FULL, + STR_CONFIG_HIGH, ++ STR_CONFIG_SUPER, + }; + + static const USBDescStrings desc_strings = { +@@ -86,6 +87,7 @@ static const USBDescStrings desc_strings = { + [STR_SERIALNUMBER] = "1", + [STR_CONFIG_FULL] = "Full speed config (usb 1.1)", + [STR_CONFIG_HIGH] = "High speed config (usb 2.0)", ++ [STR_CONFIG_SUPER] = "Super speed config (usb 3.0)", + }; + + static const USBDescIface desc_iface_full = { +@@ -158,6 +160,43 @@ static const USBDescDevice desc_device_high = { + }, + }; + ++static const USBDescIface desc_iface_super = { ++ .bInterfaceNumber = 0, ++ .bNumEndpoints = 2, ++ .bInterfaceClass = USB_CLASS_MASS_STORAGE, ++ .bInterfaceSubClass = 0x06, /* SCSI */ ++ .bInterfaceProtocol = 0x50, /* Bulk */ ++ .eps = (USBDescEndpoint[]) { ++ { ++ .bEndpointAddress = USB_DIR_IN | 0x01, ++ .bmAttributes = USB_ENDPOINT_XFER_BULK, ++ .wMaxPacketSize = 1024, ++ .bMaxBurst = 15, ++ },{ ++ .bEndpointAddress = USB_DIR_OUT | 0x02, ++ .bmAttributes = USB_ENDPOINT_XFER_BULK, ++ .wMaxPacketSize = 1024, ++ .bMaxBurst = 15, ++ }, ++ } ++}; ++ ++static const USBDescDevice desc_device_super = { ++ .bcdUSB = 0x0300, ++ .bMaxPacketSize0 = 9, ++ .bNumConfigurations = 1, ++ .confs = (USBDescConfig[]) { ++ { ++ .bNumInterfaces = 1, ++ .bConfigurationValue = 1, ++ .iConfiguration = STR_CONFIG_SUPER, ++ .bmAttributes = 0xc0, ++ .nif = 1, ++ .ifs = &desc_iface_super, ++ }, ++ }, ++}; ++ + static const USBDesc desc = { + .id = { + .idVendor = 0x46f4, /* CRC16() of "QEMU" */ +@@ -167,9 +206,10 @@ static const USBDesc desc = { + .iProduct = STR_PRODUCT, + .iSerialNumber = STR_SERIALNUMBER, + }, +- .full = &desc_device_full, +- .high = &desc_device_high, +- .str = desc_strings, ++ .full = &desc_device_full, ++ .high = &desc_device_high, ++ .super = &desc_device_super, ++ .str = desc_strings, + }; + + static void usb_msd_copy_data(MSDState *s, USBPacket *p) +-- +1.7.12.1 + diff --git a/0616-xhci-fix-cleanup-msi.patch b/0616-xhci-fix-cleanup-msi.patch new file mode 100644 index 0000000..33fca14 --- /dev/null +++ b/0616-xhci-fix-cleanup-msi.patch @@ -0,0 +1,96 @@ +From e97e63460859a74cf53c85e97a6d60633a92cc64 Mon Sep 17 00:00:00 2001 +From: Gerd Hoffmann +Date: Thu, 30 Aug 2012 10:57:12 +0200 +Subject: [PATCH] xhci: fix & cleanup msi. + +Drop custom write_config function which isn't needed any more. +Make the msi property a bit property so it accepts 'on' & 'off'. +Enable MSI by default. + +TODO: add compat property to disable on old machine types. + +Signed-off-by: Gerd Hoffmann +--- + hw/usb/hcd-xhci.c | 27 +++++++++------------------ + 1 file changed, 9 insertions(+), 18 deletions(-) + +diff --git a/hw/usb/hcd-xhci.c b/hw/usb/hcd-xhci.c +index 5813b4a..d2e6ee6 100644 +--- a/hw/usb/hcd-xhci.c ++++ b/hw/usb/hcd-xhci.c +@@ -386,7 +386,7 @@ struct XHCIState { + /* properties */ + uint32_t numports_2; + uint32_t numports_3; +- uint32_t msi; ++ uint32_t flags; + + /* Operational Registers */ + uint32_t usbcmd; +@@ -435,6 +435,10 @@ typedef struct XHCIEvRingSeg { + uint32_t rsvd; + } XHCIEvRingSeg; + ++enum xhci_flags { ++ XHCI_FLAG_USE_MSI = 1, ++}; ++ + static void xhci_kick_ep(XHCIState *xhci, unsigned int slotid, + unsigned int epid); + static void xhci_event(XHCIState *xhci, XHCIEvent *event); +@@ -617,7 +621,7 @@ static void xhci_irq_update(XHCIState *xhci) + level = 1; + } + +- if (xhci->msi && msi_enabled(&xhci->pci_dev)) { ++ if (msi_enabled(&xhci->pci_dev)) { + if (level) { + trace_usb_xhci_irq_msi(0); + msi_notify(&xhci->pci_dev, 0); +@@ -2859,32 +2863,20 @@ static int usb_xhci_initfn(struct PCIDevice *dev) + ret = pcie_cap_init(&xhci->pci_dev, 0xa0, PCI_EXP_TYPE_ENDPOINT, 0); + assert(ret >= 0); + +- if (xhci->msi) { +- ret = msi_init(&xhci->pci_dev, 0x70, 1, true, false); +- assert(ret >= 0); ++ if (xhci->flags & (1 << XHCI_FLAG_USE_MSI)) { ++ msi_init(&xhci->pci_dev, 0x70, MAXINTRS, true, false); + } + + return 0; + } + +-static void xhci_write_config(PCIDevice *dev, uint32_t addr, uint32_t val, +- int len) +-{ +- XHCIState *xhci = DO_UPCAST(XHCIState, pci_dev, dev); +- +- pci_default_write_config(dev, addr, val, len); +- if (xhci->msi) { +- msi_write_config(dev, addr, val, len); +- } +-} +- + static const VMStateDescription vmstate_xhci = { + .name = "xhci", + .unmigratable = 1, + }; + + static Property xhci_properties[] = { +- DEFINE_PROP_UINT32("msi", XHCIState, msi, 0), ++ DEFINE_PROP_BIT("msi", XHCIState, flags, XHCI_FLAG_USE_MSI, true), + DEFINE_PROP_UINT32("p2", XHCIState, numports_2, 4), + DEFINE_PROP_UINT32("p3", XHCIState, numports_3, 4), + DEFINE_PROP_END_OF_LIST(), +@@ -2904,7 +2896,6 @@ static void xhci_class_init(ObjectClass *klass, void *data) + k->class_id = PCI_CLASS_SERIAL_USB; + k->revision = 0x03; + k->is_express = 1; +- k->config_write = xhci_write_config; + } + + static TypeInfo xhci_info = { +-- +1.7.12.1 + diff --git a/0617-xhci-rework-interrupt-handling.patch b/0617-xhci-rework-interrupt-handling.patch new file mode 100644 index 0000000..3ac4ccc --- /dev/null +++ b/0617-xhci-rework-interrupt-handling.patch @@ -0,0 +1,117 @@ +From 3bf435b656390f75ce8b8990f7484efb162472c9 Mon Sep 17 00:00:00 2001 +From: Gerd Hoffmann +Date: Thu, 30 Aug 2012 13:05:10 +0200 +Subject: [PATCH] xhci: rework interrupt handling + +Split xhci_irq_update into a function which handles intx updates +(including lowering the irq line once the guests acks the interrupt) +and one which is used for raising an irq only. + +Signed-off-by: Gerd Hoffmann +--- + hw/usb/hcd-xhci.c | 47 +++++++++++++++++++++++++++++++++-------------- + 1 file changed, 33 insertions(+), 14 deletions(-) + +diff --git a/hw/usb/hcd-xhci.c b/hw/usb/hcd-xhci.c +index d2e6ee6..1857f42 100644 +--- a/hw/usb/hcd-xhci.c ++++ b/hw/usb/hcd-xhci.c +@@ -612,24 +612,43 @@ static XHCIPort *xhci_lookup_port(XHCIState *xhci, struct USBPort *uport) + return &xhci->ports[index]; + } + +-static void xhci_irq_update(XHCIState *xhci) ++static void xhci_intx_update(XHCIState *xhci) + { + int level = 0; + +- if (xhci->iman & IMAN_IP && xhci->iman & IMAN_IE && ++ if (msi_enabled(&xhci->pci_dev)) { ++ return; ++ } ++ ++ if (xhci->iman & IMAN_IP && ++ xhci->iman & IMAN_IE && + xhci->usbcmd & USBCMD_INTE) { + level = 1; + } + ++ trace_usb_xhci_irq_intx(level); ++ qemu_set_irq(xhci->irq, level); ++} ++ ++static void xhci_intr_raise(XHCIState *xhci) ++{ ++ if (!(xhci->iman & IMAN_IP) || ++ !(xhci->iman & IMAN_IE)) { ++ return; ++ } ++ ++ if (!(xhci->usbcmd & USBCMD_INTE)) { ++ return; ++ } ++ + if (msi_enabled(&xhci->pci_dev)) { +- if (level) { +- trace_usb_xhci_irq_msi(0); +- msi_notify(&xhci->pci_dev, 0); +- } +- } else { +- trace_usb_xhci_irq_intx(level); +- qemu_set_irq(xhci->irq, level); ++ trace_usb_xhci_irq_msi(0); ++ msi_notify(&xhci->pci_dev, 0); ++ return; + } ++ ++ trace_usb_xhci_irq_intx(1); ++ qemu_set_irq(xhci->irq, 1); + } + + static inline int xhci_running(XHCIState *xhci) +@@ -732,7 +751,7 @@ static void xhci_events_update(XHCIState *xhci) + xhci->erdp_low |= ERDP_EHB; + xhci->iman |= IMAN_IP; + xhci->usbsts |= USBSTS_EINT; +- xhci_irq_update(xhci); ++ xhci_intr_raise(xhci); + } + + if (xhci->er_full && xhci->ev_buffer_put == xhci->ev_buffer_get) { +@@ -796,7 +815,7 @@ static void xhci_event(XHCIState *xhci, XHCIEvent *event) + xhci->iman |= IMAN_IP; + xhci->usbsts |= USBSTS_EINT; + +- xhci_irq_update(xhci); ++ xhci_intr_raise(xhci); + } + + static void xhci_ring_init(XHCIState *xhci, XHCIRing *ring, +@@ -2479,13 +2498,13 @@ static void xhci_oper_write(XHCIState *xhci, uint32_t reg, uint32_t val) + if (val & USBCMD_HCRST) { + xhci_reset(&xhci->pci_dev.qdev); + } +- xhci_irq_update(xhci); ++ xhci_intx_update(xhci); + break; + + case 0x04: /* USBSTS */ + /* these bits are write-1-to-clear */ + xhci->usbsts &= ~(val & (USBSTS_HSE|USBSTS_EINT|USBSTS_PCD|USBSTS_SRE)); +- xhci_irq_update(xhci); ++ xhci_intx_update(xhci); + break; + + case 0x14: /* DNCTRL */ +@@ -2570,7 +2589,7 @@ static void xhci_runtime_write(XHCIState *xhci, uint32_t reg, uint32_t val) + } + xhci->iman &= ~IMAN_IE; + xhci->iman |= val & IMAN_IE; +- xhci_irq_update(xhci); ++ xhci_intx_update(xhci); + break; + case 0x24: /* IMOD */ + xhci->imod = val; +-- +1.7.12.1 + diff --git a/0618-xhci-add-msix-support.patch b/0618-xhci-add-msix-support.patch new file mode 100644 index 0000000..ab0abab --- /dev/null +++ b/0618-xhci-add-msix-support.patch @@ -0,0 +1,156 @@ +From b04ba21e22b2df805af8236bc462c5c403fc6ee4 Mon Sep 17 00:00:00 2001 +From: Gerd Hoffmann +Date: Thu, 30 Aug 2012 12:06:59 +0200 +Subject: [PATCH] xhci: add msix support + +Signed-off-by: Gerd Hoffmann +--- + hw/usb/hcd-xhci.c | 47 ++++++++++++++++++++++++++++++++++++++++++++++- + trace-events | 3 +++ + 2 files changed, 49 insertions(+), 1 deletion(-) + +diff --git a/hw/usb/hcd-xhci.c b/hw/usb/hcd-xhci.c +index 1857f42..777f903 100644 +--- a/hw/usb/hcd-xhci.c ++++ b/hw/usb/hcd-xhci.c +@@ -23,6 +23,7 @@ + #include "hw/usb.h" + #include "hw/pci.h" + #include "hw/msi.h" ++#include "hw/msix.h" + #include "trace.h" + + //#define DEBUG_XHCI +@@ -59,6 +60,8 @@ + #define OFF_OPER LEN_CAP + #define OFF_RUNTIME 0x1000 + #define OFF_DOORBELL 0x2000 ++#define OFF_MSIX_TABLE 0x3000 ++#define OFF_MSIX_PBA 0x3800 + /* must be power of 2 */ + #define LEN_REGS 0x4000 + +@@ -411,6 +414,7 @@ struct XHCIState { + uint32_t erstba_high; + uint32_t erdp_low; + uint32_t erdp_high; ++ bool msix_used; + + int64_t mfindex_start; + QEMUTimer *mfwrap_timer; +@@ -437,6 +441,7 @@ typedef struct XHCIEvRingSeg { + + enum xhci_flags { + XHCI_FLAG_USE_MSI = 1, ++ XHCI_FLAG_USE_MSI_X, + }; + + static void xhci_kick_ep(XHCIState *xhci, unsigned int slotid, +@@ -616,7 +621,8 @@ static void xhci_intx_update(XHCIState *xhci) + { + int level = 0; + +- if (msi_enabled(&xhci->pci_dev)) { ++ if (msix_enabled(&xhci->pci_dev) || ++ msi_enabled(&xhci->pci_dev)) { + return; + } + +@@ -630,6 +636,30 @@ static void xhci_intx_update(XHCIState *xhci) + qemu_set_irq(xhci->irq, level); + } + ++static void xhci_msix_update(XHCIState *xhci) ++{ ++ bool enabled; ++ ++ if (!msix_enabled(&xhci->pci_dev)) { ++ return; ++ } ++ ++ enabled = xhci->iman & IMAN_IE; ++ if (enabled == xhci->msix_used) { ++ return; ++ } ++ ++ if (enabled) { ++ trace_usb_xhci_irq_msix_use(0); ++ msix_vector_use(&xhci->pci_dev, 0); ++ xhci->msix_used = true; ++ } else { ++ trace_usb_xhci_irq_msix_unuse(0); ++ msix_vector_unuse(&xhci->pci_dev, 0); ++ xhci->msix_used = false; ++ } ++} ++ + static void xhci_intr_raise(XHCIState *xhci) + { + if (!(xhci->iman & IMAN_IP) || +@@ -641,6 +671,12 @@ static void xhci_intr_raise(XHCIState *xhci) + return; + } + ++ if (msix_enabled(&xhci->pci_dev)) { ++ trace_usb_xhci_irq_msix(0); ++ msix_notify(&xhci->pci_dev, 0); ++ return; ++ } ++ + if (msi_enabled(&xhci->pci_dev)) { + trace_usb_xhci_irq_msi(0); + msi_notify(&xhci->pci_dev, 0); +@@ -2282,6 +2318,7 @@ static void xhci_reset(DeviceState *dev) + xhci->erstba_high = 0; + xhci->erdp_low = 0; + xhci->erdp_high = 0; ++ xhci->msix_used = 0; + + xhci->er_ep_idx = 0; + xhci->er_pcs = 1; +@@ -2590,6 +2627,7 @@ static void xhci_runtime_write(XHCIState *xhci, uint32_t reg, uint32_t val) + xhci->iman &= ~IMAN_IE; + xhci->iman |= val & IMAN_IE; + xhci_intx_update(xhci); ++ xhci_msix_update(xhci); + break; + case 0x24: /* IMOD */ + xhci->imod = val; +@@ -2885,6 +2923,12 @@ static int usb_xhci_initfn(struct PCIDevice *dev) + if (xhci->flags & (1 << XHCI_FLAG_USE_MSI)) { + msi_init(&xhci->pci_dev, 0x70, MAXINTRS, true, false); + } ++ if (xhci->flags & (1 << XHCI_FLAG_USE_MSI_X)) { ++ msix_init(&xhci->pci_dev, MAXINTRS, ++ &xhci->mem, 0, OFF_MSIX_TABLE, ++ &xhci->mem, 0, OFF_MSIX_PBA, ++ 0x90); ++ } + + return 0; + } +@@ -2896,6 +2940,7 @@ static const VMStateDescription vmstate_xhci = { + + static Property xhci_properties[] = { + DEFINE_PROP_BIT("msi", XHCIState, flags, XHCI_FLAG_USE_MSI, true), ++ DEFINE_PROP_BIT("msix", XHCIState, flags, XHCI_FLAG_USE_MSI_X, true), + DEFINE_PROP_UINT32("p2", XHCIState, numports_2, 4), + DEFINE_PROP_UINT32("p3", XHCIState, numports_3, 4), + DEFINE_PROP_END_OF_LIST(), +diff --git a/trace-events b/trace-events +index d941e78..f86bbda 100644 +--- a/trace-events ++++ b/trace-events +@@ -316,6 +316,9 @@ usb_xhci_runtime_write(uint32_t off, uint32_t val) "off 0x%04x, val 0x%08x" + usb_xhci_doorbell_write(uint32_t off, uint32_t val) "off 0x%04x, val 0x%08x" + usb_xhci_irq_intx(uint32_t level) "level %d" + usb_xhci_irq_msi(uint32_t nr) "nr %d" ++usb_xhci_irq_msix(uint32_t nr) "nr %d" ++usb_xhci_irq_msix_use(uint32_t nr) "nr %d" ++usb_xhci_irq_msix_unuse(uint32_t nr) "nr %d" + usb_xhci_queue_event(uint32_t idx, const char *trb, const char *evt, uint64_t param, uint32_t status, uint32_t control) "idx %d, %s, %s, p %016" PRIx64 ", s %08x, c 0x%08x" + usb_xhci_fetch_trb(uint64_t addr, const char *name, uint64_t param, uint32_t status, uint32_t control) "addr %016" PRIx64 ", %s, p %016" PRIx64 ", s %08x, c 0x%08x" + usb_xhci_slot_enable(uint32_t slotid) "slotid %d" +-- +1.7.12.1 + diff --git a/0619-xhci-move-register-update-into-xhci_intr_raise.patch b/0619-xhci-move-register-update-into-xhci_intr_raise.patch new file mode 100644 index 0000000..f89d2a2 --- /dev/null +++ b/0619-xhci-move-register-update-into-xhci_intr_raise.patch @@ -0,0 +1,55 @@ +From be996e1a852397f4009d08ac803081e1dfbc7326 Mon Sep 17 00:00:00 2001 +From: Gerd Hoffmann +Date: Thu, 30 Aug 2012 14:04:04 +0200 +Subject: [PATCH] xhci: move register update into xhci_intr_raise + +Now that we have a separate function to raise an IRQ we can move +some comon code into the function. + +Signed-off-by: Gerd Hoffmann +--- + hw/usb/hcd-xhci.c | 14 +++++--------- + 1 file changed, 5 insertions(+), 9 deletions(-) + +diff --git a/hw/usb/hcd-xhci.c b/hw/usb/hcd-xhci.c +index 777f903..32d22f7 100644 +--- a/hw/usb/hcd-xhci.c ++++ b/hw/usb/hcd-xhci.c +@@ -662,8 +662,11 @@ static void xhci_msix_update(XHCIState *xhci) + + static void xhci_intr_raise(XHCIState *xhci) + { +- if (!(xhci->iman & IMAN_IP) || +- !(xhci->iman & IMAN_IE)) { ++ xhci->erdp_low |= ERDP_EHB; ++ xhci->iman |= IMAN_IP; ++ xhci->usbsts |= USBSTS_EINT; ++ ++ if (!(xhci->iman & IMAN_IE)) { + return; + } + +@@ -784,9 +787,6 @@ static void xhci_events_update(XHCIState *xhci) + } + + if (do_irq) { +- xhci->erdp_low |= ERDP_EHB; +- xhci->iman |= IMAN_IP; +- xhci->usbsts |= USBSTS_EINT; + xhci_intr_raise(xhci); + } + +@@ -847,10 +847,6 @@ static void xhci_event(XHCIState *xhci, XHCIEvent *event) + xhci_write_event(xhci, event); + } + +- xhci->erdp_low |= ERDP_EHB; +- xhci->iman |= IMAN_IP; +- xhci->usbsts |= USBSTS_EINT; +- + xhci_intr_raise(xhci); + } + +-- +1.7.12.1 + diff --git a/0620-xhci-add-XHCIInterrupter.patch b/0620-xhci-add-XHCIInterrupter.patch new file mode 100644 index 0000000..2992970 --- /dev/null +++ b/0620-xhci-add-XHCIInterrupter.patch @@ -0,0 +1,642 @@ +From 40ddf0dafd6a8171d2a0f960a21d7d99bdf73cd6 Mon Sep 17 00:00:00 2001 +From: Gerd Hoffmann +Date: Thu, 30 Aug 2012 15:49:03 +0200 +Subject: [PATCH] xhci: add XHCIInterrupter + +Move all state belonging to the (single) interrupter into a separate +struct. First step in adding support for multiple interrupters. + +Signed-off-by: Gerd Hoffmann +--- + hw/usb/hcd-xhci.c | 307 ++++++++++++++++++++++++++++-------------------------- + trace-events | 2 +- + 2 files changed, 161 insertions(+), 148 deletions(-) + +diff --git a/hw/usb/hcd-xhci.c b/hw/usb/hcd-xhci.c +index 32d22f7..8a14ee8 100644 +--- a/hw/usb/hcd-xhci.c ++++ b/hw/usb/hcd-xhci.c +@@ -378,6 +378,27 @@ typedef struct XHCIEvent { + uint8_t epid; + } XHCIEvent; + ++typedef struct XHCIInterrupter { ++ uint32_t iman; ++ uint32_t imod; ++ uint32_t erstsz; ++ uint32_t erstba_low; ++ uint32_t erstba_high; ++ uint32_t erdp_low; ++ uint32_t erdp_high; ++ ++ bool msix_used, er_pcs, er_full; ++ ++ dma_addr_t er_start; ++ uint32_t er_size; ++ unsigned int er_ep_idx; ++ ++ XHCIEvent ev_buffer[EV_QUEUE]; ++ unsigned int ev_buffer_put; ++ unsigned int ev_buffer_get; ++ ++} XHCIInterrupter; ++ + struct XHCIState { + PCIDevice pci_dev; + USBBus bus; +@@ -407,27 +428,9 @@ struct XHCIState { + uint32_t numports; + + /* Runtime Registers */ +- uint32_t iman; +- uint32_t imod; +- uint32_t erstsz; +- uint32_t erstba_low; +- uint32_t erstba_high; +- uint32_t erdp_low; +- uint32_t erdp_high; +- bool msix_used; +- + int64_t mfindex_start; + QEMUTimer *mfwrap_timer; +- +- dma_addr_t er_start; +- uint32_t er_size; +- bool er_pcs; +- unsigned int er_ep_idx; +- bool er_full; +- +- XHCIEvent ev_buffer[EV_QUEUE]; +- unsigned int ev_buffer_put; +- unsigned int ev_buffer_get; ++ XHCIInterrupter intr[MAXINTRS]; + + XHCIRing cmd_ring; + }; +@@ -446,8 +449,8 @@ enum xhci_flags { + + static void xhci_kick_ep(XHCIState *xhci, unsigned int slotid, + unsigned int epid); +-static void xhci_event(XHCIState *xhci, XHCIEvent *event); +-static void xhci_write_event(XHCIState *xhci, XHCIEvent *event); ++static void xhci_event(XHCIState *xhci, XHCIEvent *event, int v); ++static void xhci_write_event(XHCIState *xhci, XHCIEvent *event, int v); + + static const char *TRBType_names[] = { + [TRB_RESERVED] = "TRB_RESERVED", +@@ -573,7 +576,7 @@ static void xhci_mfwrap_timer(void *opaque) + XHCIState *xhci = opaque; + XHCIEvent wrap = { ER_MFINDEX_WRAP, CC_SUCCESS }; + +- xhci_event(xhci, &wrap); ++ xhci_event(xhci, &wrap, 0); + xhci_mfwrap_update(xhci); + } + +@@ -626,8 +629,8 @@ static void xhci_intx_update(XHCIState *xhci) + return; + } + +- if (xhci->iman & IMAN_IP && +- xhci->iman & IMAN_IE && ++ if (xhci->intr[0].iman & IMAN_IP && ++ xhci->intr[0].iman & IMAN_IE && + xhci->usbcmd & USBCMD_INTE) { + level = 1; + } +@@ -636,7 +639,7 @@ static void xhci_intx_update(XHCIState *xhci) + qemu_set_irq(xhci->irq, level); + } + +-static void xhci_msix_update(XHCIState *xhci) ++static void xhci_msix_update(XHCIState *xhci, int v) + { + bool enabled; + +@@ -644,29 +647,29 @@ static void xhci_msix_update(XHCIState *xhci) + return; + } + +- enabled = xhci->iman & IMAN_IE; +- if (enabled == xhci->msix_used) { ++ enabled = xhci->intr[v].iman & IMAN_IE; ++ if (enabled == xhci->intr[v].msix_used) { + return; + } + + if (enabled) { +- trace_usb_xhci_irq_msix_use(0); +- msix_vector_use(&xhci->pci_dev, 0); +- xhci->msix_used = true; ++ trace_usb_xhci_irq_msix_use(v); ++ msix_vector_use(&xhci->pci_dev, v); ++ xhci->intr[v].msix_used = true; + } else { +- trace_usb_xhci_irq_msix_unuse(0); +- msix_vector_unuse(&xhci->pci_dev, 0); +- xhci->msix_used = false; ++ trace_usb_xhci_irq_msix_unuse(v); ++ msix_vector_unuse(&xhci->pci_dev, v); ++ xhci->intr[v].msix_used = false; + } + } + +-static void xhci_intr_raise(XHCIState *xhci) ++static void xhci_intr_raise(XHCIState *xhci, int v) + { +- xhci->erdp_low |= ERDP_EHB; +- xhci->iman |= IMAN_IP; ++ xhci->intr[v].erdp_low |= ERDP_EHB; ++ xhci->intr[v].iman |= IMAN_IP; + xhci->usbsts |= USBSTS_EINT; + +- if (!(xhci->iman & IMAN_IE)) { ++ if (!(xhci->intr[v].iman & IMAN_IE)) { + return; + } + +@@ -675,24 +678,26 @@ static void xhci_intr_raise(XHCIState *xhci) + } + + if (msix_enabled(&xhci->pci_dev)) { +- trace_usb_xhci_irq_msix(0); +- msix_notify(&xhci->pci_dev, 0); ++ trace_usb_xhci_irq_msix(v); ++ msix_notify(&xhci->pci_dev, v); + return; + } + + if (msi_enabled(&xhci->pci_dev)) { +- trace_usb_xhci_irq_msi(0); +- msi_notify(&xhci->pci_dev, 0); ++ trace_usb_xhci_irq_msi(v); ++ msi_notify(&xhci->pci_dev, v); + return; + } + +- trace_usb_xhci_irq_intx(1); +- qemu_set_irq(xhci->irq, 1); ++ if (v == 0) { ++ trace_usb_xhci_irq_intx(1); ++ qemu_set_irq(xhci->irq, 1); ++ } + } + + static inline int xhci_running(XHCIState *xhci) + { +- return !(xhci->usbsts & USBSTS_HCH) && !xhci->er_full; ++ return !(xhci->usbsts & USBSTS_HCH) && !xhci->intr[0].er_full; + } + + static void xhci_die(XHCIState *xhci) +@@ -701,8 +706,9 @@ static void xhci_die(XHCIState *xhci) + fprintf(stderr, "xhci: asserted controller error\n"); + } + +-static void xhci_write_event(XHCIState *xhci, XHCIEvent *event) ++static void xhci_write_event(XHCIState *xhci, XHCIEvent *event, int v) + { ++ XHCIInterrupter *intr = &xhci->intr[v]; + XHCITRB ev_trb; + dma_addr_t addr; + +@@ -710,27 +716,28 @@ static void xhci_write_event(XHCIState *xhci, XHCIEvent *event) + ev_trb.status = cpu_to_le32(event->length | (event->ccode << 24)); + ev_trb.control = (event->slotid << 24) | (event->epid << 16) | + event->flags | (event->type << TRB_TYPE_SHIFT); +- if (xhci->er_pcs) { ++ if (intr->er_pcs) { + ev_trb.control |= TRB_C; + } + ev_trb.control = cpu_to_le32(ev_trb.control); + +- trace_usb_xhci_queue_event(xhci->er_ep_idx, trb_name(&ev_trb), ++ trace_usb_xhci_queue_event(v, intr->er_ep_idx, trb_name(&ev_trb), + event_name(event), ev_trb.parameter, + ev_trb.status, ev_trb.control); + +- addr = xhci->er_start + TRB_SIZE*xhci->er_ep_idx; ++ addr = intr->er_start + TRB_SIZE*intr->er_ep_idx; + pci_dma_write(&xhci->pci_dev, addr, &ev_trb, TRB_SIZE); + +- xhci->er_ep_idx++; +- if (xhci->er_ep_idx >= xhci->er_size) { +- xhci->er_ep_idx = 0; +- xhci->er_pcs = !xhci->er_pcs; ++ intr->er_ep_idx++; ++ if (intr->er_ep_idx >= intr->er_size) { ++ intr->er_ep_idx = 0; ++ intr->er_pcs = !intr->er_pcs; + } + } + +-static void xhci_events_update(XHCIState *xhci) ++static void xhci_events_update(XHCIState *xhci, int v) + { ++ XHCIInterrupter *intr = &xhci->intr[v]; + dma_addr_t erdp; + unsigned int dp_idx; + bool do_irq = 0; +@@ -739,115 +746,116 @@ static void xhci_events_update(XHCIState *xhci) + return; + } + +- erdp = xhci_addr64(xhci->erdp_low, xhci->erdp_high); +- if (erdp < xhci->er_start || +- erdp >= (xhci->er_start + TRB_SIZE*xhci->er_size)) { ++ erdp = xhci_addr64(intr->erdp_low, intr->erdp_high); ++ if (erdp < intr->er_start || ++ erdp >= (intr->er_start + TRB_SIZE*intr->er_size)) { + fprintf(stderr, "xhci: ERDP out of bounds: "DMA_ADDR_FMT"\n", erdp); +- fprintf(stderr, "xhci: ER at "DMA_ADDR_FMT" len %d\n", +- xhci->er_start, xhci->er_size); ++ fprintf(stderr, "xhci: ER[%d] at "DMA_ADDR_FMT" len %d\n", ++ v, intr->er_start, intr->er_size); + xhci_die(xhci); + return; + } +- dp_idx = (erdp - xhci->er_start) / TRB_SIZE; +- assert(dp_idx < xhci->er_size); ++ dp_idx = (erdp - intr->er_start) / TRB_SIZE; ++ assert(dp_idx < intr->er_size); + + /* NEC didn't read section 4.9.4 of the spec (v1.0 p139 top Note) and thus + * deadlocks when the ER is full. Hack it by holding off events until + * the driver decides to free at least half of the ring */ +- if (xhci->er_full) { +- int er_free = dp_idx - xhci->er_ep_idx; ++ if (intr->er_full) { ++ int er_free = dp_idx - intr->er_ep_idx; + if (er_free <= 0) { +- er_free += xhci->er_size; ++ er_free += intr->er_size; + } +- if (er_free < (xhci->er_size/2)) { ++ if (er_free < (intr->er_size/2)) { + DPRINTF("xhci_events_update(): event ring still " + "more than half full (hack)\n"); + return; + } + } + +- while (xhci->ev_buffer_put != xhci->ev_buffer_get) { +- assert(xhci->er_full); +- if (((xhci->er_ep_idx+1) % xhci->er_size) == dp_idx) { ++ while (intr->ev_buffer_put != intr->ev_buffer_get) { ++ assert(intr->er_full); ++ if (((intr->er_ep_idx+1) % intr->er_size) == dp_idx) { + DPRINTF("xhci_events_update(): event ring full again\n"); + #ifndef ER_FULL_HACK + XHCIEvent full = {ER_HOST_CONTROLLER, CC_EVENT_RING_FULL_ERROR}; +- xhci_write_event(xhci, &full); ++ xhci_write_event(xhci, &full, v); + #endif + do_irq = 1; + break; + } +- XHCIEvent *event = &xhci->ev_buffer[xhci->ev_buffer_get]; +- xhci_write_event(xhci, event); +- xhci->ev_buffer_get++; ++ XHCIEvent *event = &intr->ev_buffer[intr->ev_buffer_get]; ++ xhci_write_event(xhci, event, v); ++ intr->ev_buffer_get++; + do_irq = 1; +- if (xhci->ev_buffer_get == EV_QUEUE) { +- xhci->ev_buffer_get = 0; ++ if (intr->ev_buffer_get == EV_QUEUE) { ++ intr->ev_buffer_get = 0; + } + } + + if (do_irq) { +- xhci_intr_raise(xhci); ++ xhci_intr_raise(xhci, v); + } + +- if (xhci->er_full && xhci->ev_buffer_put == xhci->ev_buffer_get) { ++ if (intr->er_full && intr->ev_buffer_put == intr->ev_buffer_get) { + DPRINTF("xhci_events_update(): event ring no longer full\n"); +- xhci->er_full = 0; ++ intr->er_full = 0; + } + return; + } + +-static void xhci_event(XHCIState *xhci, XHCIEvent *event) ++static void xhci_event(XHCIState *xhci, XHCIEvent *event, int v) + { ++ XHCIInterrupter *intr = &xhci->intr[v]; + dma_addr_t erdp; + unsigned int dp_idx; + +- if (xhci->er_full) { ++ if (intr->er_full) { + DPRINTF("xhci_event(): ER full, queueing\n"); +- if (((xhci->ev_buffer_put+1) % EV_QUEUE) == xhci->ev_buffer_get) { ++ if (((intr->ev_buffer_put+1) % EV_QUEUE) == intr->ev_buffer_get) { + fprintf(stderr, "xhci: event queue full, dropping event!\n"); + return; + } +- xhci->ev_buffer[xhci->ev_buffer_put++] = *event; +- if (xhci->ev_buffer_put == EV_QUEUE) { +- xhci->ev_buffer_put = 0; ++ intr->ev_buffer[intr->ev_buffer_put++] = *event; ++ if (intr->ev_buffer_put == EV_QUEUE) { ++ intr->ev_buffer_put = 0; + } + return; + } + +- erdp = xhci_addr64(xhci->erdp_low, xhci->erdp_high); +- if (erdp < xhci->er_start || +- erdp >= (xhci->er_start + TRB_SIZE*xhci->er_size)) { ++ erdp = xhci_addr64(intr->erdp_low, intr->erdp_high); ++ if (erdp < intr->er_start || ++ erdp >= (intr->er_start + TRB_SIZE*intr->er_size)) { + fprintf(stderr, "xhci: ERDP out of bounds: "DMA_ADDR_FMT"\n", erdp); +- fprintf(stderr, "xhci: ER at "DMA_ADDR_FMT" len %d\n", +- xhci->er_start, xhci->er_size); ++ fprintf(stderr, "xhci: ER[%d] at "DMA_ADDR_FMT" len %d\n", ++ v, intr->er_start, intr->er_size); + xhci_die(xhci); + return; + } + +- dp_idx = (erdp - xhci->er_start) / TRB_SIZE; +- assert(dp_idx < xhci->er_size); ++ dp_idx = (erdp - intr->er_start) / TRB_SIZE; ++ assert(dp_idx < intr->er_size); + +- if ((xhci->er_ep_idx+1) % xhci->er_size == dp_idx) { ++ if ((intr->er_ep_idx+1) % intr->er_size == dp_idx) { + DPRINTF("xhci_event(): ER full, queueing\n"); + #ifndef ER_FULL_HACK + XHCIEvent full = {ER_HOST_CONTROLLER, CC_EVENT_RING_FULL_ERROR}; + xhci_write_event(xhci, &full); + #endif +- xhci->er_full = 1; +- if (((xhci->ev_buffer_put+1) % EV_QUEUE) == xhci->ev_buffer_get) { ++ intr->er_full = 1; ++ if (((intr->ev_buffer_put+1) % EV_QUEUE) == intr->ev_buffer_get) { + fprintf(stderr, "xhci: event queue full, dropping event!\n"); + return; + } +- xhci->ev_buffer[xhci->ev_buffer_put++] = *event; +- if (xhci->ev_buffer_put == EV_QUEUE) { +- xhci->ev_buffer_put = 0; ++ intr->ev_buffer[intr->ev_buffer_put++] = *event; ++ if (intr->ev_buffer_put == EV_QUEUE) { ++ intr->ev_buffer_put = 0; + } + } else { +- xhci_write_event(xhci, event); ++ xhci_write_event(xhci, event, v); + } + +- xhci_intr_raise(xhci); ++ xhci_intr_raise(xhci, v); + } + + static void xhci_ring_init(XHCIState *xhci, XHCIRing *ring, +@@ -939,17 +947,18 @@ static int xhci_ring_chain_length(XHCIState *xhci, const XHCIRing *ring) + } + } + +-static void xhci_er_reset(XHCIState *xhci) ++static void xhci_er_reset(XHCIState *xhci, int v) + { ++ XHCIInterrupter *intr = &xhci->intr[v]; + XHCIEvRingSeg seg; + + /* cache the (sole) event ring segment location */ +- if (xhci->erstsz != 1) { +- fprintf(stderr, "xhci: invalid value for ERSTSZ: %d\n", xhci->erstsz); ++ if (intr->erstsz != 1) { ++ fprintf(stderr, "xhci: invalid value for ERSTSZ: %d\n", intr->erstsz); + xhci_die(xhci); + return; + } +- dma_addr_t erstba = xhci_addr64(xhci->erstba_low, xhci->erstba_high); ++ dma_addr_t erstba = xhci_addr64(intr->erstba_low, intr->erstba_high); + pci_dma_read(&xhci->pci_dev, erstba, &seg, sizeof(seg)); + le32_to_cpus(&seg.addr_low); + le32_to_cpus(&seg.addr_high); +@@ -959,15 +968,15 @@ static void xhci_er_reset(XHCIState *xhci) + xhci_die(xhci); + return; + } +- xhci->er_start = xhci_addr64(seg.addr_low, seg.addr_high); +- xhci->er_size = seg.size; ++ intr->er_start = xhci_addr64(seg.addr_low, seg.addr_high); ++ intr->er_size = seg.size; + +- xhci->er_ep_idx = 0; +- xhci->er_pcs = 1; +- xhci->er_full = 0; ++ intr->er_ep_idx = 0; ++ intr->er_pcs = 1; ++ intr->er_full = 0; + +- DPRINTF("xhci: event ring:" DMA_ADDR_FMT " [%d]\n", +- xhci->er_start, xhci->er_size); ++ DPRINTF("xhci: event ring[%d]:" DMA_ADDR_FMT " [%d]\n", ++ v, intr->er_start, intr->er_size); + } + + static void xhci_run(XHCIState *xhci) +@@ -1368,7 +1377,7 @@ static void xhci_xfer_report(XHCITransfer *xfer) + DPRINTF("xhci_xfer_data: EDTLA=%d\n", event.length); + edtla = 0; + } +- xhci_event(xhci, &event); ++ xhci_event(xhci, &event, 0 /* FIXME */); + reported = 1; + if (xfer->status != CC_SUCCESS) { + return; +@@ -2244,7 +2253,7 @@ static void xhci_process_commands(XHCIState *xhci) + break; + } + event.slotid = slotid; +- xhci_event(xhci, &event); ++ xhci_event(xhci, &event, 0 /* FIXME */); + } + } + +@@ -2274,7 +2283,7 @@ static void xhci_update_port(XHCIState *xhci, XHCIPort *port, int is_detach) + port->portsc |= PORTSC_CSC; + XHCIEvent ev = { ER_PORT_STATUS_CHANGE, CC_SUCCESS, + port->portnr << 24}; +- xhci_event(xhci, &ev); ++ xhci_event(xhci, &ev, 0 /* FIXME */); + DPRINTF("xhci: port change event for port %d\n", port->portnr); + } + } +@@ -2307,20 +2316,22 @@ static void xhci_reset(DeviceState *dev) + xhci_update_port(xhci, xhci->ports + i, 0); + } + +- xhci->iman = 0; +- xhci->imod = 0; +- xhci->erstsz = 0; +- xhci->erstba_low = 0; +- xhci->erstba_high = 0; +- xhci->erdp_low = 0; +- xhci->erdp_high = 0; +- xhci->msix_used = 0; ++ for (i = 0; i < MAXINTRS; i++) { ++ xhci->intr[i].iman = 0; ++ xhci->intr[i].imod = 0; ++ xhci->intr[i].erstsz = 0; ++ xhci->intr[i].erstba_low = 0; ++ xhci->intr[i].erstba_high = 0; ++ xhci->intr[i].erdp_low = 0; ++ xhci->intr[i].erdp_high = 0; ++ xhci->intr[i].msix_used = 0; + +- xhci->er_ep_idx = 0; +- xhci->er_pcs = 1; +- xhci->er_full = 0; +- xhci->ev_buffer_put = 0; +- xhci->ev_buffer_get = 0; ++ xhci->intr[i].er_ep_idx = 0; ++ xhci->intr[i].er_pcs = 1; ++ xhci->intr[i].er_full = 0; ++ xhci->intr[i].ev_buffer_put = 0; ++ xhci->intr[i].ev_buffer_get = 0; ++ } + + xhci->mfindex_start = qemu_get_clock_ns(vm_clock); + xhci_mfwrap_update(xhci); +@@ -2551,7 +2562,7 @@ static void xhci_oper_write(XHCIState *xhci, uint32_t reg, uint32_t val) + if (xhci->crcr_low & (CRCR_CA|CRCR_CS) && (xhci->crcr_low & CRCR_CRR)) { + XHCIEvent event = {ER_COMMAND_COMPLETE, CC_COMMAND_RING_STOPPED}; + xhci->crcr_low &= ~CRCR_CRR; +- xhci_event(xhci, &event); ++ xhci_event(xhci, &event, 0 /* FIXME */); + DPRINTF("xhci: command ring stopped (CRCR=%08x)\n", xhci->crcr_low); + } else { + dma_addr_t base = xhci_addr64(xhci->crcr_low & ~0x3f, val); +@@ -2575,6 +2586,7 @@ static void xhci_oper_write(XHCIState *xhci, uint32_t reg, uint32_t val) + + static uint32_t xhci_runtime_read(XHCIState *xhci, uint32_t reg) + { ++ XHCIInterrupter *intr = &xhci->intr[0]; + uint32_t ret; + + switch (reg) { +@@ -2582,25 +2594,25 @@ static uint32_t xhci_runtime_read(XHCIState *xhci, uint32_t reg) + ret = xhci_mfindex_get(xhci) & 0x3fff; + break; + case 0x20: /* IMAN */ +- ret = xhci->iman; ++ ret = intr->iman; + break; + case 0x24: /* IMOD */ +- ret = xhci->imod; ++ ret = intr->imod; + break; + case 0x28: /* ERSTSZ */ +- ret = xhci->erstsz; ++ ret = intr->erstsz; + break; + case 0x30: /* ERSTBA low */ +- ret = xhci->erstba_low; ++ ret = intr->erstba_low; + break; + case 0x34: /* ERSTBA high */ +- ret = xhci->erstba_high; ++ ret = intr->erstba_high; + break; + case 0x38: /* ERDP low */ +- ret = xhci->erdp_low; ++ ret = intr->erdp_low; + break; + case 0x3c: /* ERDP high */ +- ret = xhci->erdp_high; ++ ret = intr->erdp_high; + break; + default: + fprintf(stderr, "xhci_runtime_read: reg 0x%x unimplemented\n", reg); +@@ -2613,42 +2625,43 @@ static uint32_t xhci_runtime_read(XHCIState *xhci, uint32_t reg) + + static void xhci_runtime_write(XHCIState *xhci, uint32_t reg, uint32_t val) + { ++ XHCIInterrupter *intr = &xhci->intr[0]; + trace_usb_xhci_runtime_write(reg, val); + + switch (reg) { + case 0x20: /* IMAN */ + if (val & IMAN_IP) { +- xhci->iman &= ~IMAN_IP; ++ intr->iman &= ~IMAN_IP; + } +- xhci->iman &= ~IMAN_IE; +- xhci->iman |= val & IMAN_IE; ++ intr->iman &= ~IMAN_IE; ++ intr->iman |= val & IMAN_IE; + xhci_intx_update(xhci); +- xhci_msix_update(xhci); ++ xhci_msix_update(xhci, 0); + break; + case 0x24: /* IMOD */ +- xhci->imod = val; ++ intr->imod = val; + break; + case 0x28: /* ERSTSZ */ +- xhci->erstsz = val & 0xffff; ++ intr->erstsz = val & 0xffff; + break; + case 0x30: /* ERSTBA low */ + /* XXX NEC driver bug: it doesn't align this to 64 bytes +- xhci->erstba_low = val & 0xffffffc0; */ +- xhci->erstba_low = val & 0xfffffff0; ++ intr->erstba_low = val & 0xffffffc0; */ ++ intr->erstba_low = val & 0xfffffff0; + break; + case 0x34: /* ERSTBA high */ +- xhci->erstba_high = val; +- xhci_er_reset(xhci); ++ intr->erstba_high = val; ++ xhci_er_reset(xhci, 0); + break; + case 0x38: /* ERDP low */ + if (val & ERDP_EHB) { +- xhci->erdp_low &= ~ERDP_EHB; ++ intr->erdp_low &= ~ERDP_EHB; + } +- xhci->erdp_low = (val & ~ERDP_EHB) | (xhci->erdp_low & ERDP_EHB); ++ intr->erdp_low = (val & ~ERDP_EHB) | (intr->erdp_low & ERDP_EHB); + break; + case 0x3c: /* ERDP high */ +- xhci->erdp_high = val; +- xhci_events_update(xhci); ++ intr->erdp_high = val; ++ xhci_events_update(xhci, 0); + break; + default: + fprintf(stderr, "xhci_oper_write: reg 0x%x unimplemented\n", reg); +@@ -2780,7 +2793,7 @@ static void xhci_wakeup(USBPort *usbport) + return; + } + port->portsc |= PORTSC_PLC; +- xhci_event(xhci, &ev); ++ xhci_event(xhci, &ev, 0 /* FIXME */); + } + + static void xhci_complete(USBPort *port, USBPacket *packet) +diff --git a/trace-events b/trace-events +index f86bbda..f5b5097 100644 +--- a/trace-events ++++ b/trace-events +@@ -319,7 +319,7 @@ usb_xhci_irq_msi(uint32_t nr) "nr %d" + usb_xhci_irq_msix(uint32_t nr) "nr %d" + usb_xhci_irq_msix_use(uint32_t nr) "nr %d" + usb_xhci_irq_msix_unuse(uint32_t nr) "nr %d" +-usb_xhci_queue_event(uint32_t idx, const char *trb, const char *evt, uint64_t param, uint32_t status, uint32_t control) "idx %d, %s, %s, p %016" PRIx64 ", s %08x, c 0x%08x" ++usb_xhci_queue_event(uint32_t vector, uint32_t idx, const char *trb, const char *evt, uint64_t param, uint32_t status, uint32_t control) "v %d, idx %d, %s, %s, p %016" PRIx64 ", s %08x, c 0x%08x" + usb_xhci_fetch_trb(uint64_t addr, const char *name, uint64_t param, uint32_t status, uint32_t control) "addr %016" PRIx64 ", %s, p %016" PRIx64 ", s %08x, c 0x%08x" + usb_xhci_slot_enable(uint32_t slotid) "slotid %d" + usb_xhci_slot_disable(uint32_t slotid) "slotid %d" +-- +1.7.12.1 + diff --git a/0621-xhci-prepare-xhci_runtime_-read-write-for-multiple-i.patch b/0621-xhci-prepare-xhci_runtime_-read-write-for-multiple-i.patch new file mode 100644 index 0000000..d753d08 --- /dev/null +++ b/0621-xhci-prepare-xhci_runtime_-read-write-for-multiple-i.patch @@ -0,0 +1,159 @@ +From 670eba790c368e9c37b0c964d94e0ff7f0d0c443 Mon Sep 17 00:00:00 2001 +From: Gerd Hoffmann +Date: Thu, 30 Aug 2012 17:15:12 +0200 +Subject: [PATCH] xhci: prepare xhci_runtime_{read,write} for multiple + interrupters + +Prepare xhci runtime register access function for multiple interrupters. + +Signed-off-by: Gerd Hoffmann +--- + hw/usb/hcd-xhci.c | 100 +++++++++++++++++++++++++++++++----------------------- + 1 file changed, 57 insertions(+), 43 deletions(-) + +diff --git a/hw/usb/hcd-xhci.c b/hw/usb/hcd-xhci.c +index 8a14ee8..6b3ff16 100644 +--- a/hw/usb/hcd-xhci.c ++++ b/hw/usb/hcd-xhci.c +@@ -2586,37 +2586,43 @@ static void xhci_oper_write(XHCIState *xhci, uint32_t reg, uint32_t val) + + static uint32_t xhci_runtime_read(XHCIState *xhci, uint32_t reg) + { +- XHCIInterrupter *intr = &xhci->intr[0]; +- uint32_t ret; ++ uint32_t ret = 0; + +- switch (reg) { +- case 0x00: /* MFINDEX */ +- ret = xhci_mfindex_get(xhci) & 0x3fff; +- break; +- case 0x20: /* IMAN */ +- ret = intr->iman; +- break; +- case 0x24: /* IMOD */ +- ret = intr->imod; +- break; +- case 0x28: /* ERSTSZ */ +- ret = intr->erstsz; +- break; +- case 0x30: /* ERSTBA low */ +- ret = intr->erstba_low; +- break; +- case 0x34: /* ERSTBA high */ +- ret = intr->erstba_high; +- break; +- case 0x38: /* ERDP low */ +- ret = intr->erdp_low; +- break; +- case 0x3c: /* ERDP high */ +- ret = intr->erdp_high; +- break; +- default: +- fprintf(stderr, "xhci_runtime_read: reg 0x%x unimplemented\n", reg); +- ret = 0; ++ if (reg < 0x20) { ++ switch (reg) { ++ case 0x00: /* MFINDEX */ ++ ret = xhci_mfindex_get(xhci) & 0x3fff; ++ break; ++ default: ++ fprintf(stderr, "xhci_runtime_read: reg 0x%x unimplemented\n", reg); ++ break; ++ } ++ } else { ++ int v = (reg - 0x20) / 0x20; ++ XHCIInterrupter *intr = &xhci->intr[v]; ++ switch (reg & 0x1f) { ++ case 0x00: /* IMAN */ ++ ret = intr->iman; ++ break; ++ case 0x04: /* IMOD */ ++ ret = intr->imod; ++ break; ++ case 0x08: /* ERSTSZ */ ++ ret = intr->erstsz; ++ break; ++ case 0x10: /* ERSTBA low */ ++ ret = intr->erstba_low; ++ break; ++ case 0x14: /* ERSTBA high */ ++ ret = intr->erstba_high; ++ break; ++ case 0x18: /* ERDP low */ ++ ret = intr->erdp_low; ++ break; ++ case 0x1c: /* ERDP high */ ++ ret = intr->erdp_high; ++ break; ++ } + } + + trace_usb_xhci_runtime_read(reg, ret); +@@ -2625,43 +2631,51 @@ static uint32_t xhci_runtime_read(XHCIState *xhci, uint32_t reg) + + static void xhci_runtime_write(XHCIState *xhci, uint32_t reg, uint32_t val) + { +- XHCIInterrupter *intr = &xhci->intr[0]; ++ int v = (reg - 0x20) / 0x20; ++ XHCIInterrupter *intr = &xhci->intr[v]; + trace_usb_xhci_runtime_write(reg, val); + +- switch (reg) { +- case 0x20: /* IMAN */ ++ if (reg < 0x20) { ++ fprintf(stderr, "xhci_oper_write: reg 0x%x unimplemented\n", reg); ++ return; ++ } ++ ++ switch (reg & 0x1f) { ++ case 0x00: /* IMAN */ + if (val & IMAN_IP) { + intr->iman &= ~IMAN_IP; + } + intr->iman &= ~IMAN_IE; + intr->iman |= val & IMAN_IE; +- xhci_intx_update(xhci); +- xhci_msix_update(xhci, 0); ++ if (v == 0) { ++ xhci_intx_update(xhci); ++ } ++ xhci_msix_update(xhci, v); + break; +- case 0x24: /* IMOD */ ++ case 0x04: /* IMOD */ + intr->imod = val; + break; +- case 0x28: /* ERSTSZ */ ++ case 0x08: /* ERSTSZ */ + intr->erstsz = val & 0xffff; + break; +- case 0x30: /* ERSTBA low */ ++ case 0x10: /* ERSTBA low */ + /* XXX NEC driver bug: it doesn't align this to 64 bytes + intr->erstba_low = val & 0xffffffc0; */ + intr->erstba_low = val & 0xfffffff0; + break; +- case 0x34: /* ERSTBA high */ ++ case 0x14: /* ERSTBA high */ + intr->erstba_high = val; +- xhci_er_reset(xhci, 0); ++ xhci_er_reset(xhci, v); + break; +- case 0x38: /* ERDP low */ ++ case 0x18: /* ERDP low */ + if (val & ERDP_EHB) { + intr->erdp_low &= ~ERDP_EHB; + } + intr->erdp_low = (val & ~ERDP_EHB) | (intr->erdp_low & ERDP_EHB); + break; +- case 0x3c: /* ERDP high */ ++ case 0x1c: /* ERDP high */ + intr->erdp_high = val; +- xhci_events_update(xhci, 0); ++ xhci_events_update(xhci, v); + break; + default: + fprintf(stderr, "xhci_oper_write: reg 0x%x unimplemented\n", reg); +-- +1.7.12.1 + diff --git a/0622-xhci-pick-target-interrupter.patch b/0622-xhci-pick-target-interrupter.patch new file mode 100644 index 0000000..e336b49 --- /dev/null +++ b/0622-xhci-pick-target-interrupter.patch @@ -0,0 +1,93 @@ +From d6968ced27f697b26d7a1d5b44f15eeb300a9fd6 Mon Sep 17 00:00:00 2001 +From: Gerd Hoffmann +Date: Fri, 31 Aug 2012 15:30:51 +0200 +Subject: [PATCH] xhci: pick target interrupter + +Pick the correct interrupter when queuing an event. + +Signed-off-by: Gerd Hoffmann +--- + hw/usb/hcd-xhci.c | 22 ++++++++++++++++------ + 1 file changed, 16 insertions(+), 6 deletions(-) + +diff --git a/hw/usb/hcd-xhci.c b/hw/usb/hcd-xhci.c +index 6b3ff16..3b03c6c 100644 +--- a/hw/usb/hcd-xhci.c ++++ b/hw/usb/hcd-xhci.c +@@ -264,6 +264,10 @@ typedef enum TRBCCode { + + #define TRB_LK_TC (1<<1) + ++#define TRB_INTR_SHIFT 22 ++#define TRB_INTR_MASK 0x3ff ++#define TRB_INTR(t) (((t).status >> TRB_INTR_SHIFT) & TRB_INTR_MASK) ++ + #define EP_TYPE_MASK 0x7 + #define EP_TYPE_SHIFT 3 + +@@ -806,10 +810,16 @@ static void xhci_events_update(XHCIState *xhci, int v) + + static void xhci_event(XHCIState *xhci, XHCIEvent *event, int v) + { +- XHCIInterrupter *intr = &xhci->intr[v]; ++ XHCIInterrupter *intr; + dma_addr_t erdp; + unsigned int dp_idx; + ++ if (v >= MAXINTRS) { ++ DPRINTF("intr nr out of range (%d >= %d)\n", v, MAXINTRS); ++ return; ++ } ++ intr = &xhci->intr[v]; ++ + if (intr->er_full) { + DPRINTF("xhci_event(): ER full, queueing\n"); + if (((intr->ev_buffer_put+1) % EV_QUEUE) == intr->ev_buffer_get) { +@@ -1377,7 +1387,7 @@ static void xhci_xfer_report(XHCITransfer *xfer) + DPRINTF("xhci_xfer_data: EDTLA=%d\n", event.length); + edtla = 0; + } +- xhci_event(xhci, &event, 0 /* FIXME */); ++ xhci_event(xhci, &event, TRB_INTR(*trb)); + reported = 1; + if (xfer->status != CC_SUCCESS) { + return; +@@ -2253,7 +2263,7 @@ static void xhci_process_commands(XHCIState *xhci) + break; + } + event.slotid = slotid; +- xhci_event(xhci, &event, 0 /* FIXME */); ++ xhci_event(xhci, &event, 0); + } + } + +@@ -2283,7 +2293,7 @@ static void xhci_update_port(XHCIState *xhci, XHCIPort *port, int is_detach) + port->portsc |= PORTSC_CSC; + XHCIEvent ev = { ER_PORT_STATUS_CHANGE, CC_SUCCESS, + port->portnr << 24}; +- xhci_event(xhci, &ev, 0 /* FIXME */); ++ xhci_event(xhci, &ev, 0); + DPRINTF("xhci: port change event for port %d\n", port->portnr); + } + } +@@ -2562,7 +2572,7 @@ static void xhci_oper_write(XHCIState *xhci, uint32_t reg, uint32_t val) + if (xhci->crcr_low & (CRCR_CA|CRCR_CS) && (xhci->crcr_low & CRCR_CRR)) { + XHCIEvent event = {ER_COMMAND_COMPLETE, CC_COMMAND_RING_STOPPED}; + xhci->crcr_low &= ~CRCR_CRR; +- xhci_event(xhci, &event, 0 /* FIXME */); ++ xhci_event(xhci, &event, 0); + DPRINTF("xhci: command ring stopped (CRCR=%08x)\n", xhci->crcr_low); + } else { + dma_addr_t base = xhci_addr64(xhci->crcr_low & ~0x3f, val); +@@ -2807,7 +2817,7 @@ static void xhci_wakeup(USBPort *usbport) + return; + } + port->portsc |= PORTSC_PLC; +- xhci_event(xhci, &ev, 0 /* FIXME */); ++ xhci_event(xhci, &ev, 0); + } + + static void xhci_complete(USBPort *port, USBPacket *packet) +-- +1.7.12.1 + diff --git a/0623-xhci-support-multiple-interrupters.patch b/0623-xhci-support-multiple-interrupters.patch new file mode 100644 index 0000000..0d8ffbd --- /dev/null +++ b/0623-xhci-support-multiple-interrupters.patch @@ -0,0 +1,40 @@ +From 4e4d4191a40b5cbcd6f967ed105eea559104cd8a Mon Sep 17 00:00:00 2001 +From: Gerd Hoffmann +Date: Tue, 4 Sep 2012 12:56:55 +0200 +Subject: [PATCH] xhci: support multiple interrupters + +Everything is in place, flip the big switch now +and enable support for multiple interrupters. + +Signed-off-by: Gerd Hoffmann +--- + hw/usb/hcd-xhci.c | 6 +----- + 1 file changed, 1 insertion(+), 5 deletions(-) + +diff --git a/hw/usb/hcd-xhci.c b/hw/usb/hcd-xhci.c +index 3b03c6c..4992705 100644 +--- a/hw/usb/hcd-xhci.c ++++ b/hw/usb/hcd-xhci.c +@@ -42,7 +42,7 @@ + + #define MAXPORTS (MAXPORTS_2+MAXPORTS_3) + #define MAXSLOTS MAXPORTS +-#define MAXINTRS 1 /* MAXPORTS */ ++#define MAXINTRS MAXPORTS + + #define TD_QUEUE 24 + +@@ -75,10 +75,6 @@ + # error Increase LEN_REGS + #endif + +-#if MAXINTRS > 1 +-# error TODO: only one interrupter supported +-#endif +- + /* bit definitions */ + #define USBCMD_RS (1<<0) + #define USBCMD_HCRST (1<<1) +-- +1.7.12.1 + diff --git a/0624-xhci-kill-xhci_mem_-read-write-dispatcher-functions.patch b/0624-xhci-kill-xhci_mem_-read-write-dispatcher-functions.patch new file mode 100644 index 0000000..ec23202 --- /dev/null +++ b/0624-xhci-kill-xhci_mem_-read-write-dispatcher-functions.patch @@ -0,0 +1,280 @@ +From d2efc9f3dc62810ef6075f8759c9856016447c14 Mon Sep 17 00:00:00 2001 +From: Gerd Hoffmann +Date: Tue, 4 Sep 2012 14:42:20 +0200 +Subject: [PATCH] xhci: kill xhci_mem_{read,write} dispatcher functions + +... and register subregions instead, so we offload the dispatching +to the the memory subsystem which is designed to handle it. + +Signed-off-by: Gerd Hoffmann +--- + hw/usb/hcd-xhci.c | 140 +++++++++++++++++++++++++++++------------------------- + 1 file changed, 75 insertions(+), 65 deletions(-) + +diff --git a/hw/usb/hcd-xhci.c b/hw/usb/hcd-xhci.c +index 4992705..4ba9464 100644 +--- a/hw/usb/hcd-xhci.c ++++ b/hw/usb/hcd-xhci.c +@@ -404,6 +404,10 @@ struct XHCIState { + USBBus bus; + qemu_irq irq; + MemoryRegion mem; ++ MemoryRegion mem_cap; ++ MemoryRegion mem_oper; ++ MemoryRegion mem_runtime; ++ MemoryRegion mem_doorbell; + const char *name; + unsigned int devaddr; + +@@ -2343,8 +2347,9 @@ static void xhci_reset(DeviceState *dev) + xhci_mfwrap_update(xhci); + } + +-static uint32_t xhci_cap_read(XHCIState *xhci, uint32_t reg) ++static uint64_t xhci_cap_read(void *ptr, target_phys_addr_t reg, unsigned size) + { ++ XHCIState *xhci = ptr; + uint32_t ret; + + switch (reg) { +@@ -2401,7 +2406,7 @@ static uint32_t xhci_cap_read(XHCIState *xhci, uint32_t reg) + ret = 0x00000000; /* reserved */ + break; + default: +- fprintf(stderr, "xhci_cap_read: reg %d unimplemented\n", reg); ++ fprintf(stderr, "xhci_cap_read: reg %d unimplemented\n", (int)reg); + ret = 0; + } + +@@ -2482,8 +2487,9 @@ static void xhci_port_write(XHCIState *xhci, uint32_t reg, uint32_t val) + } + } + +-static uint32_t xhci_oper_read(XHCIState *xhci, uint32_t reg) ++static uint64_t xhci_oper_read(void *ptr, target_phys_addr_t reg, unsigned size) + { ++ XHCIState *xhci = ptr; + uint32_t ret; + + if (reg >= 0x400) { +@@ -2519,7 +2525,7 @@ static uint32_t xhci_oper_read(XHCIState *xhci, uint32_t reg) + ret = xhci->config; + break; + default: +- fprintf(stderr, "xhci_oper_read: reg 0x%x unimplemented\n", reg); ++ fprintf(stderr, "xhci_oper_read: reg 0x%x unimplemented\n", (int)reg); + ret = 0; + } + +@@ -2527,8 +2533,11 @@ static uint32_t xhci_oper_read(XHCIState *xhci, uint32_t reg) + return ret; + } + +-static void xhci_oper_write(XHCIState *xhci, uint32_t reg, uint32_t val) ++static void xhci_oper_write(void *ptr, target_phys_addr_t reg, ++ uint64_t val, unsigned size) + { ++ XHCIState *xhci = ptr; ++ + if (reg >= 0x400) { + xhci_port_write(xhci, reg - 0x400, val); + return; +@@ -2586,12 +2595,14 @@ static void xhci_oper_write(XHCIState *xhci, uint32_t reg, uint32_t val) + xhci->config = val & 0xff; + break; + default: +- fprintf(stderr, "xhci_oper_write: reg 0x%x unimplemented\n", reg); ++ fprintf(stderr, "xhci_oper_write: reg 0x%x unimplemented\n", (int)reg); + } + } + +-static uint32_t xhci_runtime_read(XHCIState *xhci, uint32_t reg) ++static uint64_t xhci_runtime_read(void *ptr, target_phys_addr_t reg, ++ unsigned size) + { ++ XHCIState *xhci = ptr; + uint32_t ret = 0; + + if (reg < 0x20) { +@@ -2600,7 +2611,8 @@ static uint32_t xhci_runtime_read(XHCIState *xhci, uint32_t reg) + ret = xhci_mfindex_get(xhci) & 0x3fff; + break; + default: +- fprintf(stderr, "xhci_runtime_read: reg 0x%x unimplemented\n", reg); ++ fprintf(stderr, "xhci_runtime_read: reg 0x%x unimplemented\n", ++ (int)reg); + break; + } + } else { +@@ -2635,14 +2647,16 @@ static uint32_t xhci_runtime_read(XHCIState *xhci, uint32_t reg) + return ret; + } + +-static void xhci_runtime_write(XHCIState *xhci, uint32_t reg, uint32_t val) ++static void xhci_runtime_write(void *ptr, target_phys_addr_t reg, ++ uint64_t val, unsigned size) + { ++ XHCIState *xhci = ptr; + int v = (reg - 0x20) / 0x20; + XHCIInterrupter *intr = &xhci->intr[v]; + trace_usb_xhci_runtime_write(reg, val); + + if (reg < 0x20) { +- fprintf(stderr, "xhci_oper_write: reg 0x%x unimplemented\n", reg); ++ fprintf(stderr, "xhci_oper_write: reg 0x%x unimplemented\n", (int)reg); + return; + } + +@@ -2684,19 +2698,24 @@ static void xhci_runtime_write(XHCIState *xhci, uint32_t reg, uint32_t val) + xhci_events_update(xhci, v); + break; + default: +- fprintf(stderr, "xhci_oper_write: reg 0x%x unimplemented\n", reg); ++ fprintf(stderr, "xhci_oper_write: reg 0x%x unimplemented\n", ++ (int)reg); + } + } + +-static uint32_t xhci_doorbell_read(XHCIState *xhci, uint32_t reg) ++static uint64_t xhci_doorbell_read(void *ptr, target_phys_addr_t reg, ++ unsigned size) + { + /* doorbells always read as 0 */ + trace_usb_xhci_doorbell_read(reg, 0); + return 0; + } + +-static void xhci_doorbell_write(XHCIState *xhci, uint32_t reg, uint32_t val) ++static void xhci_doorbell_write(void *ptr, target_phys_addr_t reg, ++ uint64_t val, unsigned size) + { ++ XHCIState *xhci = ptr; ++ + trace_usb_xhci_doorbell_write(reg, val); + + if (!xhci_running(xhci)) { +@@ -2710,69 +2729,47 @@ static void xhci_doorbell_write(XHCIState *xhci, uint32_t reg, uint32_t val) + if (val == 0) { + xhci_process_commands(xhci); + } else { +- fprintf(stderr, "xhci: bad doorbell 0 write: 0x%x\n", val); ++ fprintf(stderr, "xhci: bad doorbell 0 write: 0x%x\n", ++ (uint32_t)val); + } + } else { + if (reg > MAXSLOTS) { +- fprintf(stderr, "xhci: bad doorbell %d\n", reg); ++ fprintf(stderr, "xhci: bad doorbell %d\n", (int)reg); + } else if (val > 31) { +- fprintf(stderr, "xhci: bad doorbell %d write: 0x%x\n", reg, val); ++ fprintf(stderr, "xhci: bad doorbell %d write: 0x%x\n", ++ (int)reg, (uint32_t)val); + } else { + xhci_kick_ep(xhci, reg, val); + } + } + } + +-static uint64_t xhci_mem_read(void *ptr, target_phys_addr_t addr, +- unsigned size) +-{ +- XHCIState *xhci = ptr; +- +- /* Only aligned reads are allowed on xHCI */ +- if (addr & 3) { +- fprintf(stderr, "xhci_mem_read: Mis-aligned read\n"); +- return 0; +- } +- +- if (addr < LEN_CAP) { +- return xhci_cap_read(xhci, addr); +- } else if (addr >= OFF_OPER && addr < (OFF_OPER + LEN_OPER)) { +- return xhci_oper_read(xhci, addr - OFF_OPER); +- } else if (addr >= OFF_RUNTIME && addr < (OFF_RUNTIME + LEN_RUNTIME)) { +- return xhci_runtime_read(xhci, addr - OFF_RUNTIME); +- } else if (addr >= OFF_DOORBELL && addr < (OFF_DOORBELL + LEN_DOORBELL)) { +- return xhci_doorbell_read(xhci, addr - OFF_DOORBELL); +- } else { +- fprintf(stderr, "xhci_mem_read: Bad offset %x\n", (int)addr); +- return 0; +- } +-} +- +-static void xhci_mem_write(void *ptr, target_phys_addr_t addr, +- uint64_t val, unsigned size) +-{ +- XHCIState *xhci = ptr; ++static const MemoryRegionOps xhci_cap_ops = { ++ .read = xhci_cap_read, ++ .valid.min_access_size = 4, ++ .valid.max_access_size = 4, ++ .endianness = DEVICE_LITTLE_ENDIAN, ++}; + +- /* Only aligned writes are allowed on xHCI */ +- if (addr & 3) { +- fprintf(stderr, "xhci_mem_write: Mis-aligned write\n"); +- return; +- } ++static const MemoryRegionOps xhci_oper_ops = { ++ .read = xhci_oper_read, ++ .write = xhci_oper_write, ++ .valid.min_access_size = 4, ++ .valid.max_access_size = 4, ++ .endianness = DEVICE_LITTLE_ENDIAN, ++}; + +- if (addr >= OFF_OPER && addr < (OFF_OPER + LEN_OPER)) { +- xhci_oper_write(xhci, addr - OFF_OPER, val); +- } else if (addr >= OFF_RUNTIME && addr < (OFF_RUNTIME + LEN_RUNTIME)) { +- xhci_runtime_write(xhci, addr - OFF_RUNTIME, val); +- } else if (addr >= OFF_DOORBELL && addr < (OFF_DOORBELL + LEN_DOORBELL)) { +- xhci_doorbell_write(xhci, addr - OFF_DOORBELL, val); +- } else { +- fprintf(stderr, "xhci_mem_write: Bad offset %x\n", (int)addr); +- } +-} ++static const MemoryRegionOps xhci_runtime_ops = { ++ .read = xhci_runtime_read, ++ .write = xhci_runtime_write, ++ .valid.min_access_size = 4, ++ .valid.max_access_size = 4, ++ .endianness = DEVICE_LITTLE_ENDIAN, ++}; + +-static const MemoryRegionOps xhci_mem_ops = { +- .read = xhci_mem_read, +- .write = xhci_mem_write, ++static const MemoryRegionOps xhci_doorbell_ops = { ++ .read = xhci_doorbell_read, ++ .write = xhci_doorbell_write, + .valid.min_access_size = 1, + .valid.max_access_size = 4, + .impl.min_access_size = 4, +@@ -2940,8 +2937,21 @@ static int usb_xhci_initfn(struct PCIDevice *dev) + + xhci->irq = xhci->pci_dev.irq[0]; + +- memory_region_init_io(&xhci->mem, &xhci_mem_ops, xhci, +- "xhci", LEN_REGS); ++ memory_region_init(&xhci->mem, "xhci", LEN_REGS); ++ memory_region_init_io(&xhci->mem_cap, &xhci_cap_ops, xhci, ++ "capabilities", LEN_CAP); ++ memory_region_init_io(&xhci->mem_oper, &xhci_oper_ops, xhci, ++ "operational", 0x400 + 0x10 * xhci->numports); ++ memory_region_init_io(&xhci->mem_runtime, &xhci_runtime_ops, xhci, ++ "runtime", LEN_RUNTIME); ++ memory_region_init_io(&xhci->mem_doorbell, &xhci_doorbell_ops, xhci, ++ "doorbell", LEN_DOORBELL); ++ ++ memory_region_add_subregion(&xhci->mem, 0, &xhci->mem_cap); ++ memory_region_add_subregion(&xhci->mem, OFF_OPER, &xhci->mem_oper); ++ memory_region_add_subregion(&xhci->mem, OFF_RUNTIME, &xhci->mem_runtime); ++ memory_region_add_subregion(&xhci->mem, OFF_DOORBELL, &xhci->mem_doorbell); ++ + pci_register_bar(&xhci->pci_dev, 0, + PCI_BASE_ADDRESS_SPACE_MEMORY|PCI_BASE_ADDRESS_MEM_TYPE_64, + &xhci->mem); +-- +1.7.12.1 + diff --git a/0625-usb-redir-Change-cancelled-packet-code-into-a-generi.patch b/0625-usb-redir-Change-cancelled-packet-code-into-a-generi.patch new file mode 100644 index 0000000..1f0e575 --- /dev/null +++ b/0625-usb-redir-Change-cancelled-packet-code-into-a-generi.patch @@ -0,0 +1,184 @@ +From 5b44a6c9c102b69690adcc2c5be886857ea35ebd Mon Sep 17 00:00:00 2001 +From: Hans de Goede +Date: Tue, 4 Sep 2012 14:18:34 +0200 +Subject: [PATCH] usb-redir: Change cancelled packet code into a generic + packet-id queue + +Signed-off-by: Hans de Goede +--- + hw/usb/redirect.c | 102 +++++++++++++++++++++++++++++++++++++----------------- + 1 file changed, 71 insertions(+), 31 deletions(-) + +diff --git a/hw/usb/redirect.c b/hw/usb/redirect.c +index f183263..e2b8159 100644 +--- a/hw/usb/redirect.c ++++ b/hw/usb/redirect.c +@@ -43,7 +43,6 @@ + #define EP2I(ep_address) (((ep_address & 0x80) >> 3) | (ep_address & 0x0f)) + #define I2EP(i) (((i & 0x10) << 3) | (i & 0x0f)) + +-typedef struct Cancelled Cancelled; + typedef struct USBRedirDevice USBRedirDevice; + + /* Struct to hold buffered packets (iso or int input packets) */ +@@ -69,6 +68,18 @@ struct endp_data { + int bufpq_target_size; + }; + ++struct PacketIdQueueEntry { ++ uint64_t id; ++ QTAILQ_ENTRY(PacketIdQueueEntry)next; ++}; ++ ++struct PacketIdQueue { ++ USBRedirDevice *dev; ++ const char *name; ++ QTAILQ_HEAD(, PacketIdQueueEntry) head; ++ int size; ++}; ++ + struct USBRedirDevice { + USBDevice dev; + /* Properties */ +@@ -86,7 +97,7 @@ struct USBRedirDevice { + int64_t next_attach_time; + struct usbredirparser *parser; + struct endp_data endpoint[MAX_ENDPOINTS]; +- QTAILQ_HEAD(, Cancelled) cancelled; ++ struct PacketIdQueue cancelled; + /* Data for device filtering */ + struct usb_redir_device_connect_header device_info; + struct usb_redir_interface_info_header interface_info; +@@ -94,11 +105,6 @@ struct USBRedirDevice { + int filter_rules_count; + }; + +-struct Cancelled { +- uint64_t id; +- QTAILQ_ENTRY(Cancelled)next; +-}; +- + static void usbredir_hello(void *priv, struct usb_redir_hello_header *h); + static void usbredir_device_connect(void *priv, + struct usb_redir_device_connect_header *device_connect); +@@ -251,37 +257,75 @@ static int usbredir_write(void *priv, uint8_t *data, int count) + * Cancelled and buffered packets helpers + */ + +-static void usbredir_cancel_packet(USBDevice *udev, USBPacket *p) ++static void packet_id_queue_init(struct PacketIdQueue *q, ++ USBRedirDevice *dev, const char *name) + { +- USBRedirDevice *dev = DO_UPCAST(USBRedirDevice, dev, udev); +- Cancelled *c; ++ q->dev = dev; ++ q->name = name; ++ QTAILQ_INIT(&q->head); ++ q->size = 0; ++} ++ ++static void packet_id_queue_add(struct PacketIdQueue *q, uint64_t id) ++{ ++ USBRedirDevice *dev = q->dev; ++ struct PacketIdQueueEntry *e; ++ ++ DPRINTF("adding packet id %"PRIu64" to %s queue\n", id, q->name); ++ ++ e = g_malloc0(sizeof(struct PacketIdQueueEntry)); ++ e->id = id; ++ QTAILQ_INSERT_TAIL(&q->head, e, next); ++ q->size++; ++} ++ ++static int packet_id_queue_remove(struct PacketIdQueue *q, uint64_t id) ++{ ++ USBRedirDevice *dev = q->dev; ++ struct PacketIdQueueEntry *e; ++ ++ QTAILQ_FOREACH(e, &q->head, next) { ++ if (e->id == id) { ++ DPRINTF("removing packet id %"PRIu64" from %s queue\n", ++ id, q->name); ++ QTAILQ_REMOVE(&q->head, e, next); ++ q->size--; ++ g_free(e); ++ return 1; ++ } ++ } ++ return 0; ++} ++ ++static void packet_id_queue_empty(struct PacketIdQueue *q) ++{ ++ USBRedirDevice *dev = q->dev; ++ struct PacketIdQueueEntry *e, *next_e; + +- DPRINTF("cancel packet id %"PRIu64"\n", p->id); ++ DPRINTF("removing %d packet-ids from %s queue\n", q->size, q->name); + +- c = g_malloc0(sizeof(Cancelled)); +- c->id = p->id; +- QTAILQ_INSERT_TAIL(&dev->cancelled, c, next); ++ QTAILQ_FOREACH_SAFE(e, &q->head, next, next_e) { ++ QTAILQ_REMOVE(&q->head, e, next); ++ g_free(e); ++ } ++ q->size = 0; ++} + ++static void usbredir_cancel_packet(USBDevice *udev, USBPacket *p) ++{ ++ USBRedirDevice *dev = DO_UPCAST(USBRedirDevice, dev, udev); ++ ++ packet_id_queue_add(&dev->cancelled, p->id); + usbredirparser_send_cancel_data_packet(dev->parser, p->id); + usbredirparser_do_write(dev->parser); + } + + static int usbredir_is_cancelled(USBRedirDevice *dev, uint64_t id) + { +- Cancelled *c; +- + if (!dev->dev.attached) { + return 1; /* Treat everything as cancelled after a disconnect */ + } +- +- QTAILQ_FOREACH(c, &dev->cancelled, next) { +- if (c->id == id) { +- QTAILQ_REMOVE(&dev->cancelled, c, next); +- g_free(c); +- return 1; +- } +- } +- return 0; ++ return packet_id_queue_remove(&dev->cancelled, id); + } + + static USBPacket *usbredir_find_packet_by_id(USBRedirDevice *dev, +@@ -937,7 +981,7 @@ static int usbredir_initfn(USBDevice *udev) + dev->chardev_close_bh = qemu_bh_new(usbredir_chardev_close_bh, dev); + dev->attach_timer = qemu_new_timer_ms(vm_clock, usbredir_do_attach, dev); + +- QTAILQ_INIT(&dev->cancelled); ++ packet_id_queue_init(&dev->cancelled, dev, "cancelled"); + for (i = 0; i < MAX_ENDPOINTS; i++) { + QTAILQ_INIT(&dev->endpoint[i].bufpq); + } +@@ -955,13 +999,9 @@ static int usbredir_initfn(USBDevice *udev) + + static void usbredir_cleanup_device_queues(USBRedirDevice *dev) + { +- Cancelled *c, *next_c; + int i; + +- QTAILQ_FOREACH_SAFE(c, &dev->cancelled, next, next_c) { +- QTAILQ_REMOVE(&dev->cancelled, c, next); +- g_free(c); +- } ++ packet_id_queue_empty(&dev->cancelled); + for (i = 0; i < MAX_ENDPOINTS; i++) { + usbredir_free_bufpq(dev, I2EP(i)); + } +-- +1.7.12.1 + diff --git a/0626-usb-redir-Add-an-already_in_flight-packet-id-queue.patch b/0626-usb-redir-Add-an-already_in_flight-packet-id-queue.patch new file mode 100644 index 0000000..e0e58c1 --- /dev/null +++ b/0626-usb-redir-Add-an-already_in_flight-packet-id-queue.patch @@ -0,0 +1,119 @@ +From 9a38bd644b97a4a3ae92c9246bdcdd09ba937ae8 Mon Sep 17 00:00:00 2001 +From: Hans de Goede +Date: Tue, 4 Sep 2012 17:03:54 +0200 +Subject: [PATCH] usb-redir: Add an already_in_flight packet-id queue + +After a live migration, the usb-hcd will re-queue all packets by +walking over the schedule in the guest memory again, but requests which +were encountered on the migration source before will already be in flight, +so these should *not* be re-send to the usbredir-host. + +This patch adds an already in flight packet ud queue, which will be filled by +the source before migration and then moved over to the migration dest, any +async handled packets are then checked against this queue to avoid sending +the same packet to the usbredir-host twice. + +Signed-off-by: Hans de Goede +--- + hw/usb/redirect.c | 43 +++++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 43 insertions(+) + +diff --git a/hw/usb/redirect.c b/hw/usb/redirect.c +index e2b8159..cdd705f 100644 +--- a/hw/usb/redirect.c ++++ b/hw/usb/redirect.c +@@ -98,6 +98,7 @@ struct USBRedirDevice { + struct usbredirparser *parser; + struct endp_data endpoint[MAX_ENDPOINTS]; + struct PacketIdQueue cancelled; ++ struct PacketIdQueue already_in_flight; + /* Data for device filtering */ + struct usb_redir_device_connect_header device_info; + struct usb_redir_interface_info_header interface_info; +@@ -328,6 +329,34 @@ static int usbredir_is_cancelled(USBRedirDevice *dev, uint64_t id) + return packet_id_queue_remove(&dev->cancelled, id); + } + ++static void usbredir_fill_already_in_flight_from_ep(USBRedirDevice *dev, ++ struct USBEndpoint *ep) ++{ ++ static USBPacket *p; ++ ++ QTAILQ_FOREACH(p, &ep->queue, queue) { ++ packet_id_queue_add(&dev->already_in_flight, p->id); ++ } ++} ++ ++static void usbredir_fill_already_in_flight(USBRedirDevice *dev) ++{ ++ int ep; ++ struct USBDevice *udev = &dev->dev; ++ ++ usbredir_fill_already_in_flight_from_ep(dev, &udev->ep_ctl); ++ ++ for (ep = 0; ep < USB_MAX_ENDPOINTS; ep++) { ++ usbredir_fill_already_in_flight_from_ep(dev, &udev->ep_in[ep]); ++ usbredir_fill_already_in_flight_from_ep(dev, &udev->ep_out[ep]); ++ } ++} ++ ++static int usbredir_already_in_flight(USBRedirDevice *dev, uint64_t id) ++{ ++ return packet_id_queue_remove(&dev->already_in_flight, id); ++} ++ + static USBPacket *usbredir_find_packet_by_id(USBRedirDevice *dev, + uint8_t ep, uint64_t id) + { +@@ -543,6 +572,10 @@ static int usbredir_handle_bulk_data(USBRedirDevice *dev, USBPacket *p, + + DPRINTF("bulk-out ep %02X len %zd id %"PRIu64"\n", ep, p->iov.size, p->id); + ++ if (usbredir_already_in_flight(dev, p->id)) { ++ return USB_RET_ASYNC; ++ } ++ + bulk_packet.endpoint = ep; + bulk_packet.length = p->iov.size; + bulk_packet.stream_id = 0; +@@ -623,6 +656,10 @@ static int usbredir_handle_interrupt_data(USBRedirDevice *dev, + DPRINTF("interrupt-out ep %02X len %zd id %"PRIu64"\n", ep, + p->iov.size, p->id); + ++ if (usbredir_already_in_flight(dev, p->id)) { ++ return USB_RET_ASYNC; ++ } ++ + interrupt_packet.endpoint = ep; + interrupt_packet.length = p->iov.size; + +@@ -765,6 +802,10 @@ static int usbredir_handle_control(USBDevice *udev, USBPacket *p, + USBRedirDevice *dev = DO_UPCAST(USBRedirDevice, dev, udev); + struct usb_redir_control_packet_header control_packet; + ++ if (usbredir_already_in_flight(dev, p->id)) { ++ return USB_RET_ASYNC; ++ } ++ + /* Special cases for certain standard device requests */ + switch (request) { + case DeviceOutRequest | USB_REQ_SET_ADDRESS: +@@ -982,6 +1023,7 @@ static int usbredir_initfn(USBDevice *udev) + dev->attach_timer = qemu_new_timer_ms(vm_clock, usbredir_do_attach, dev); + + packet_id_queue_init(&dev->cancelled, dev, "cancelled"); ++ packet_id_queue_init(&dev->already_in_flight, dev, "already-in-flight"); + for (i = 0; i < MAX_ENDPOINTS; i++) { + QTAILQ_INIT(&dev->endpoint[i].bufpq); + } +@@ -1002,6 +1044,7 @@ static void usbredir_cleanup_device_queues(USBRedirDevice *dev) + int i; + + packet_id_queue_empty(&dev->cancelled); ++ packet_id_queue_empty(&dev->already_in_flight); + for (i = 0; i < MAX_ENDPOINTS; i++) { + usbredir_free_bufpq(dev, I2EP(i)); + } +-- +1.7.12.1 + diff --git a/0627-usb-redir-Store-max_packet_size-in-endp_data.patch b/0627-usb-redir-Store-max_packet_size-in-endp_data.patch new file mode 100644 index 0000000..2c44744 --- /dev/null +++ b/0627-usb-redir-Store-max_packet_size-in-endp_data.patch @@ -0,0 +1,38 @@ +From c41be182adcd7026fcf76250fc3a64cec8a2c903 Mon Sep 17 00:00:00 2001 +From: Hans de Goede +Date: Thu, 6 Sep 2012 20:52:36 +0200 +Subject: [PATCH] usb-redir: Store max_packet_size in endp_data + +So that we've a place to migrate it to / from to allow restoring it after +migration. + +Signed-off-by: Hans de Goede +--- + hw/usb/redirect.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/hw/usb/redirect.c b/hw/usb/redirect.c +index cdd705f..6eb3c6d 100644 +--- a/hw/usb/redirect.c ++++ b/hw/usb/redirect.c +@@ -57,6 +57,7 @@ struct endp_data { + uint8_t type; + uint8_t interval; + uint8_t interface; /* bInterfaceNumber this ep belongs to */ ++ uint16_t max_packet_size; /* In bytes, not wMaxPacketSize format !! */ + uint8_t iso_started; + uint8_t iso_error; /* For reporting iso errors to the HC */ + uint8_t interrupt_started; +@@ -1300,7 +1301,8 @@ static void usbredir_ep_info(void *priv, + usb_ep->ifnum = dev->endpoint[i].interface; + if (usbredirparser_peer_has_cap(dev->parser, + usb_redir_cap_ep_info_max_packet_size)) { +- usb_ep->max_packet_size = ep_info->max_packet_size[i]; ++ dev->endpoint[i].max_packet_size = ++ usb_ep->max_packet_size = ep_info->max_packet_size[i]; + } + if (ep_info->type[i] == usb_redir_type_bulk) { + usb_ep->pipeline = true; +-- +1.7.12.1 + diff --git a/0628-usb-redir-Add-support-for-migration.patch b/0628-usb-redir-Add-support-for-migration.patch new file mode 100644 index 0000000..52d9002 --- /dev/null +++ b/0628-usb-redir-Add-support-for-migration.patch @@ -0,0 +1,429 @@ +From a056ffda5a57d7169268e49a3e42c7d79c8f7c48 Mon Sep 17 00:00:00 2001 +From: Hans de Goede +Date: Wed, 5 Sep 2012 09:21:44 +0200 +Subject: [PATCH] usb-redir: Add support for migration + +Signed-off-by: Hans de Goede +--- + hw/usb/redirect.c | 349 +++++++++++++++++++++++++++++++++++++++++++++++++++++- + 1 file changed, 346 insertions(+), 3 deletions(-) + +diff --git a/hw/usb/redirect.c b/hw/usb/redirect.c +index 6eb3c6d..b7387b6 100644 +--- a/hw/usb/redirect.c ++++ b/hw/usb/redirect.c +@@ -65,8 +65,8 @@ struct endp_data { + uint8_t bufpq_prefilled; + uint8_t bufpq_dropping_packets; + QTAILQ_HEAD(, buf_packet) bufpq; +- int bufpq_size; +- int bufpq_target_size; ++ int32_t bufpq_size; ++ int32_t bufpq_target_size; + }; + + struct PacketIdQueueEntry { +@@ -243,6 +243,11 @@ static int usbredir_write(void *priv, uint8_t *data, int count) + return 0; + } + ++ /* Don't send new data to the chardev until our state is fully synced */ ++ if (!runstate_check(RUN_STATE_RUNNING)) { ++ return 0; ++ } ++ + r = qemu_chr_fe_write(dev->cs, data, count); + + if (r < 0) { +@@ -870,6 +875,7 @@ static void usbredir_chardev_open(USBRedirDevice *dev) + { + uint32_t caps[USB_REDIR_CAPS_SIZE] = { 0, }; + char version[32]; ++ int flags = 0; + + /* Make sure any pending closes are handled (no-op if none pending) */ + usbredir_chardev_close_bh(dev); +@@ -902,7 +908,12 @@ static void usbredir_chardev_open(USBRedirDevice *dev) + usbredirparser_caps_set_cap(caps, usb_redir_cap_filter); + usbredirparser_caps_set_cap(caps, usb_redir_cap_ep_info_max_packet_size); + usbredirparser_caps_set_cap(caps, usb_redir_cap_64bits_ids); +- usbredirparser_init(dev->parser, VERSION, caps, USB_REDIR_CAPS_SIZE, 0); ++ ++ if (runstate_check(RUN_STATE_INMIGRATE)) { ++ flags |= usbredirparser_fl_no_hello; ++ } ++ usbredirparser_init(dev->parser, VERSION, caps, USB_REDIR_CAPS_SIZE, ++ flags); + usbredirparser_do_write(dev->parser); + } + +@@ -948,6 +959,11 @@ static int usbredir_chardev_can_read(void *opaque) + return 0; + } + ++ /* Don't read new data from the chardev until our state is fully synced */ ++ if (!runstate_check(RUN_STATE_RUNNING)) { ++ return 0; ++ } ++ + /* usbredir_parser_do_read will consume *all* data we give it */ + return 1024 * 1024; + } +@@ -999,6 +1015,15 @@ static const QemuChrHandlers usbredir_chr_handlers = { + * init + destroy + */ + ++static void usbredir_vm_state_change(void *priv, int running, RunState state) ++{ ++ USBRedirDevice *dev = priv; ++ ++ if (state == RUN_STATE_RUNNING && dev->parser != NULL) { ++ usbredirparser_do_write(dev->parser); /* Flush any pending writes */ ++ } ++} ++ + static int usbredir_initfn(USBDevice *udev) + { + USBRedirDevice *dev = DO_UPCAST(USBRedirDevice, dev, udev); +@@ -1036,6 +1061,7 @@ static int usbredir_initfn(USBDevice *udev) + qemu_chr_fe_open(dev->cs); + qemu_chr_add_handlers(dev->cs, &usbredir_chr_handlers, dev); + ++ qemu_add_vm_change_state_handler(usbredir_vm_state_change, dev); + add_boot_device_path(dev->bootindex, &udev->qdev, NULL); + return 0; + } +@@ -1525,6 +1551,322 @@ static void usbredir_interrupt_packet(void *priv, uint64_t id, + } + } + ++/* ++ * Migration code ++ */ ++ ++static void usbredir_pre_save(void *priv) ++{ ++ USBRedirDevice *dev = priv; ++ ++ usbredir_fill_already_in_flight(dev); ++} ++ ++static int usbredir_post_load(void *priv, int version_id) ++{ ++ USBRedirDevice *dev = priv; ++ struct USBEndpoint *usb_ep; ++ int i; ++ ++ switch (dev->device_info.speed) { ++ case usb_redir_speed_low: ++ dev->dev.speed = USB_SPEED_LOW; ++ break; ++ case usb_redir_speed_full: ++ dev->dev.speed = USB_SPEED_FULL; ++ break; ++ case usb_redir_speed_high: ++ dev->dev.speed = USB_SPEED_HIGH; ++ break; ++ case usb_redir_speed_super: ++ dev->dev.speed = USB_SPEED_SUPER; ++ break; ++ default: ++ dev->dev.speed = USB_SPEED_FULL; ++ } ++ dev->dev.speedmask = (1 << dev->dev.speed); ++ ++ for (i = 0; i < MAX_ENDPOINTS; i++) { ++ usb_ep = usb_ep_get(&dev->dev, ++ (i & 0x10) ? USB_TOKEN_IN : USB_TOKEN_OUT, ++ i & 0x0f); ++ usb_ep->type = dev->endpoint[i].type; ++ usb_ep->ifnum = dev->endpoint[i].interface; ++ usb_ep->max_packet_size = dev->endpoint[i].max_packet_size; ++ if (dev->endpoint[i].type == usb_redir_type_bulk) { ++ usb_ep->pipeline = true; ++ } ++ } ++ return 0; ++} ++ ++/* For usbredirparser migration */ ++static void usbredir_put_parser(QEMUFile *f, void *priv, size_t unused) ++{ ++ USBRedirDevice *dev = priv; ++ uint8_t *data; ++ int len; ++ ++ if (dev->parser == NULL) { ++ qemu_put_be32(f, 0); ++ return; ++ } ++ ++ usbredirparser_serialize(dev->parser, &data, &len); ++ qemu_oom_check(data); ++ ++ qemu_put_be32(f, len); ++ qemu_put_buffer(f, data, len); ++ ++ free(data); ++} ++ ++static int usbredir_get_parser(QEMUFile *f, void *priv, size_t unused) ++{ ++ USBRedirDevice *dev = priv; ++ uint8_t *data; ++ int len, ret; ++ ++ len = qemu_get_be32(f); ++ if (len == 0) { ++ return 0; ++ } ++ ++ /* ++ * Our chardev should be open already at this point, otherwise ++ * the usbredir channel will be broken (ie spice without seamless) ++ */ ++ if (dev->parser == NULL) { ++ ERROR("get_parser called with closed chardev, failing migration\n"); ++ return -1; ++ } ++ ++ data = g_malloc(len); ++ qemu_get_buffer(f, data, len); ++ ++ ret = usbredirparser_unserialize(dev->parser, data, len); ++ ++ g_free(data); ++ ++ return ret; ++} ++ ++static const VMStateInfo usbredir_parser_vmstate_info = { ++ .name = "usb-redir-parser", ++ .put = usbredir_put_parser, ++ .get = usbredir_get_parser, ++}; ++ ++ ++/* For buffered packets (iso/irq) queue migration */ ++static void usbredir_put_bufpq(QEMUFile *f, void *priv, size_t unused) ++{ ++ struct endp_data *endp = priv; ++ struct buf_packet *bufp; ++ int remain = endp->bufpq_size; ++ ++ qemu_put_be32(f, endp->bufpq_size); ++ QTAILQ_FOREACH(bufp, &endp->bufpq, next) { ++ qemu_put_be32(f, bufp->len); ++ qemu_put_be32(f, bufp->status); ++ qemu_put_buffer(f, bufp->data, bufp->len); ++ remain--; ++ } ++ assert(remain == 0); ++} ++ ++static int usbredir_get_bufpq(QEMUFile *f, void *priv, size_t unused) ++{ ++ struct endp_data *endp = priv; ++ struct buf_packet *bufp; ++ int i; ++ ++ endp->bufpq_size = qemu_get_be32(f); ++ for (i = 0; i < endp->bufpq_size; i++) { ++ bufp = g_malloc(sizeof(struct buf_packet)); ++ bufp->len = qemu_get_be32(f); ++ bufp->status = qemu_get_be32(f); ++ bufp->data = qemu_oom_check(malloc(bufp->len)); /* regular malloc! */ ++ qemu_get_buffer(f, bufp->data, bufp->len); ++ QTAILQ_INSERT_TAIL(&endp->bufpq, bufp, next); ++ } ++ return 0; ++} ++ ++static const VMStateInfo usbredir_ep_bufpq_vmstate_info = { ++ .name = "usb-redir-bufpq", ++ .put = usbredir_put_bufpq, ++ .get = usbredir_get_bufpq, ++}; ++ ++ ++/* For endp_data migration */ ++static const VMStateDescription usbredir_ep_vmstate = { ++ .name = "usb-redir-ep", ++ .version_id = 1, ++ .minimum_version_id = 1, ++ .fields = (VMStateField []) { ++ VMSTATE_UINT8(type, struct endp_data), ++ VMSTATE_UINT8(interval, struct endp_data), ++ VMSTATE_UINT8(interface, struct endp_data), ++ VMSTATE_UINT16(max_packet_size, struct endp_data), ++ VMSTATE_UINT8(iso_started, struct endp_data), ++ VMSTATE_UINT8(iso_error, struct endp_data), ++ VMSTATE_UINT8(interrupt_started, struct endp_data), ++ VMSTATE_UINT8(interrupt_error, struct endp_data), ++ VMSTATE_UINT8(bufpq_prefilled, struct endp_data), ++ VMSTATE_UINT8(bufpq_dropping_packets, struct endp_data), ++ { ++ .name = "bufpq", ++ .version_id = 0, ++ .field_exists = NULL, ++ .size = 0, ++ .info = &usbredir_ep_bufpq_vmstate_info, ++ .flags = VMS_SINGLE, ++ .offset = 0, ++ }, ++ VMSTATE_INT32(bufpq_target_size, struct endp_data), ++ VMSTATE_END_OF_LIST() ++ } ++}; ++ ++ ++/* For PacketIdQueue migration */ ++static void usbredir_put_packet_id_q(QEMUFile *f, void *priv, size_t unused) ++{ ++ struct PacketIdQueue *q = priv; ++ USBRedirDevice *dev = q->dev; ++ struct PacketIdQueueEntry *e; ++ int remain = q->size; ++ ++ DPRINTF("put_packet_id_q %s size %d\n", q->name, q->size); ++ qemu_put_be32(f, q->size); ++ QTAILQ_FOREACH(e, &q->head, next) { ++ qemu_put_be64(f, e->id); ++ remain--; ++ } ++ assert(remain == 0); ++} ++ ++static int usbredir_get_packet_id_q(QEMUFile *f, void *priv, size_t unused) ++{ ++ struct PacketIdQueue *q = priv; ++ USBRedirDevice *dev = q->dev; ++ int i, size; ++ uint64_t id; ++ ++ size = qemu_get_be32(f); ++ DPRINTF("get_packet_id_q %s size %d\n", q->name, size); ++ for (i = 0; i < size; i++) { ++ id = qemu_get_be64(f); ++ packet_id_queue_add(q, id); ++ } ++ assert(q->size == size); ++ return 0; ++} ++ ++static const VMStateInfo usbredir_ep_packet_id_q_vmstate_info = { ++ .name = "usb-redir-packet-id-q", ++ .put = usbredir_put_packet_id_q, ++ .get = usbredir_get_packet_id_q, ++}; ++ ++static const VMStateDescription usbredir_ep_packet_id_queue_vmstate = { ++ .name = "usb-redir-packet-id-queue", ++ .version_id = 1, ++ .minimum_version_id = 1, ++ .fields = (VMStateField []) { ++ { ++ .name = "queue", ++ .version_id = 0, ++ .field_exists = NULL, ++ .size = 0, ++ .info = &usbredir_ep_packet_id_q_vmstate_info, ++ .flags = VMS_SINGLE, ++ .offset = 0, ++ }, ++ VMSTATE_END_OF_LIST() ++ } ++}; ++ ++ ++/* For usb_redir_device_connect_header migration */ ++static const VMStateDescription usbredir_device_info_vmstate = { ++ .name = "usb-redir-device-info", ++ .version_id = 1, ++ .minimum_version_id = 1, ++ .fields = (VMStateField []) { ++ VMSTATE_UINT8(speed, struct usb_redir_device_connect_header), ++ VMSTATE_UINT8(device_class, struct usb_redir_device_connect_header), ++ VMSTATE_UINT8(device_subclass, struct usb_redir_device_connect_header), ++ VMSTATE_UINT8(device_protocol, struct usb_redir_device_connect_header), ++ VMSTATE_UINT16(vendor_id, struct usb_redir_device_connect_header), ++ VMSTATE_UINT16(product_id, struct usb_redir_device_connect_header), ++ VMSTATE_UINT16(device_version_bcd, ++ struct usb_redir_device_connect_header), ++ VMSTATE_END_OF_LIST() ++ } ++}; ++ ++ ++/* For usb_redir_interface_info_header migration */ ++static const VMStateDescription usbredir_interface_info_vmstate = { ++ .name = "usb-redir-interface-info", ++ .version_id = 1, ++ .minimum_version_id = 1, ++ .fields = (VMStateField []) { ++ VMSTATE_UINT32(interface_count, ++ struct usb_redir_interface_info_header), ++ VMSTATE_UINT8_ARRAY(interface, ++ struct usb_redir_interface_info_header, 32), ++ VMSTATE_UINT8_ARRAY(interface_class, ++ struct usb_redir_interface_info_header, 32), ++ VMSTATE_UINT8_ARRAY(interface_subclass, ++ struct usb_redir_interface_info_header, 32), ++ VMSTATE_UINT8_ARRAY(interface_protocol, ++ struct usb_redir_interface_info_header, 32), ++ VMSTATE_END_OF_LIST() ++ } ++}; ++ ++ ++/* And finally the USBRedirDevice vmstate itself */ ++static const VMStateDescription usbredir_vmstate = { ++ .name = "usb-redir", ++ .version_id = 1, ++ .minimum_version_id = 1, ++ .pre_save = usbredir_pre_save, ++ .post_load = usbredir_post_load, ++ .fields = (VMStateField []) { ++ VMSTATE_USB_DEVICE(dev, USBRedirDevice), ++ VMSTATE_TIMER(attach_timer, USBRedirDevice), ++ { ++ .name = "parser", ++ .version_id = 0, ++ .field_exists = NULL, ++ .size = 0, ++ .info = &usbredir_parser_vmstate_info, ++ .flags = VMS_SINGLE, ++ .offset = 0, ++ }, ++ VMSTATE_STRUCT_ARRAY(endpoint, USBRedirDevice, MAX_ENDPOINTS, 1, ++ usbredir_ep_vmstate, struct endp_data), ++ VMSTATE_STRUCT(cancelled, USBRedirDevice, 1, ++ usbredir_ep_packet_id_queue_vmstate, ++ struct PacketIdQueue), ++ VMSTATE_STRUCT(already_in_flight, USBRedirDevice, 1, ++ usbredir_ep_packet_id_queue_vmstate, ++ struct PacketIdQueue), ++ VMSTATE_STRUCT(device_info, USBRedirDevice, 1, ++ usbredir_device_info_vmstate, ++ struct usb_redir_device_connect_header), ++ VMSTATE_STRUCT(interface_info, USBRedirDevice, 1, ++ usbredir_interface_info_vmstate, ++ struct usb_redir_interface_info_header), ++ VMSTATE_END_OF_LIST() ++ } ++}; ++ + static Property usbredir_properties[] = { + DEFINE_PROP_CHR("chardev", USBRedirDevice, cs), + DEFINE_PROP_UINT8("debug", USBRedirDevice, debug, 0), +@@ -1545,6 +1887,7 @@ static void usbredir_class_initfn(ObjectClass *klass, void *data) + uc->handle_reset = usbredir_handle_reset; + uc->handle_data = usbredir_handle_data; + uc->handle_control = usbredir_handle_control; ++ dc->vmsd = &usbredir_vmstate; + dc->props = usbredir_properties; + } + +-- +1.7.12.1 + diff --git a/0629-usb-redir-Add-chardev-open-close-debug-logging.patch b/0629-usb-redir-Add-chardev-open-close-debug-logging.patch new file mode 100644 index 0000000..5e8305d --- /dev/null +++ b/0629-usb-redir-Add-chardev-open-close-debug-logging.patch @@ -0,0 +1,54 @@ +From 5a717110d859cbd989634e8acdcedd800ee2be74 Mon Sep 17 00:00:00 2001 +From: Hans de Goede +Date: Wed, 5 Sep 2012 15:56:57 +0200 +Subject: [PATCH] usb-redir: Add chardev open / close debug logging + +Signed-off-by: Hans de Goede +--- + hw/usb/redirect.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/hw/usb/redirect.c b/hw/usb/redirect.c +index b7387b6..57e6289 100644 +--- a/hw/usb/redirect.c ++++ b/hw/usb/redirect.c +@@ -866,6 +866,7 @@ static void usbredir_chardev_close_bh(void *opaque) + usbredir_device_disconnect(dev); + + if (dev->parser) { ++ DPRINTF("destroying usbredirparser\n"); + usbredirparser_destroy(dev->parser); + dev->parser = NULL; + } +@@ -881,6 +882,8 @@ static void usbredir_chardev_open(USBRedirDevice *dev) + usbredir_chardev_close_bh(dev); + qemu_bh_cancel(dev->chardev_close_bh); + ++ DPRINTF("creating usbredirparser\n"); ++ + dev->parser = qemu_oom_check(usbredirparser_create()); + dev->parser->priv = dev; + dev->parser->log_func = usbredir_log; +@@ -989,9 +992,11 @@ static void usbredir_chardev_event(void *opaque, int event) + + switch (event) { + case CHR_EVENT_OPENED: ++ DPRINTF("chardev open\n"); + usbredir_chardev_open(dev); + break; + case CHR_EVENT_CLOSED: ++ DPRINTF("chardev close\n"); + qemu_bh_schedule(dev->chardev_close_bh); + break; + } +@@ -1250,6 +1255,7 @@ static void usbredir_device_disconnect(void *priv) + qemu_del_timer(dev->attach_timer); + + if (dev->dev.attached) { ++ DPRINTF("detaching device\n"); + usb_device_detach(&dev->dev); + /* + * Delay next usb device attach to give the guest a chance to see +-- +1.7.12.1 + diff --git a/0630-usb-redir-Revert-usb-redir-part-of-commit-93bfef4c.patch b/0630-usb-redir-Revert-usb-redir-part-of-commit-93bfef4c.patch new file mode 100644 index 0000000..4ffc46b --- /dev/null +++ b/0630-usb-redir-Revert-usb-redir-part-of-commit-93bfef4c.patch @@ -0,0 +1,35 @@ +From b95fb22d2799ed07c55bccbd7ffa3cb19fb7feb3 Mon Sep 17 00:00:00 2001 +From: Hans de Goede +Date: Mon, 10 Sep 2012 13:49:46 +0200 +Subject: [PATCH] usb-redir: Revert usb-redir part of commit 93bfef4c + +Commit 93bfef4c6e4b23caea9d51e1099d06433d8835a4 makes qemu-devices +which report the qemu version string to the guest in some way use a +qemu_get_version function which reports a machine-specific version string. + +However usb-redir does not expose the qemu version to the guest, only to +the usbredir-host as part of the initial handshake. This can then be logged +on the usbredir-host side for debugging purposes and is otherwise completely +unused! For debugging purposes it is important to have the real qemu version +in there, rather then the machine-specific version. + +Signed-off-by: Hans de Goede +--- + hw/usb/redirect.c | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/hw/usb/redirect.c b/hw/usb/redirect.c +index 57e6289..78e93a7 100644 +--- a/hw/usb/redirect.c ++++ b/hw/usb/redirect.c +@@ -875,7 +875,6 @@ static void usbredir_chardev_close_bh(void *opaque) + static void usbredir_chardev_open(USBRedirDevice *dev) + { + uint32_t caps[USB_REDIR_CAPS_SIZE] = { 0, }; +- char version[32]; + int flags = 0; + + /* Make sure any pending closes are handled (no-op if none pending) */ +-- +1.7.12.1 + diff --git a/0631-ehci-Fix-interrupt-packet-MULT-handling.patch b/0631-ehci-Fix-interrupt-packet-MULT-handling.patch new file mode 100644 index 0000000..17abd7f --- /dev/null +++ b/0631-ehci-Fix-interrupt-packet-MULT-handling.patch @@ -0,0 +1,131 @@ +From d6fe9953a8277a54ae7f4cefa192b49d9bf99e3d Mon Sep 17 00:00:00 2001 +From: Hans de Goede +Date: Thu, 20 Sep 2012 16:55:02 +0200 +Subject: [PATCH] ehci: Fix interrupt packet MULT handling + +There are several issues with our handling of the MULT epcap field +of interrupt qhs, which this patch fixes. + +1) When we don't execute a transaction because of the transaction counter +being 0, p->async stays EHCI_ASYNC_NONE, and the next time we process the +same qtd we hit an assert in ehci_state_fetchqtd because of this. Even though +I believe that this is caused by 3 below, this patch still removes the assert, +as that can still happen without 3, when multiple packets are queued for the +same interrupt ep. + +2) We only *check* the transaction counter from ehci_state_execute, any +packets queued up by fill_queue bypass this check. This is fixed by not calling +fill_queue for interrupt packets. + +3) Some versions of Windows set the MULT field of the qh to 0, which is a +clear violation of the EHCI spec, but still they do it. This means that we +will never execute a qtd for these, making interrupt ep-s on USB-2 devices +not work, and after recent changes, triggering 1). + +So far we've stored the transaction counter in our copy of the mult field, +but with this beginnig at 0 already when dealing with these version of windows +this won't work. So this patch adds a transact_ctr field to our qh struct, +and sets this to the MULT field value on fetchqh. When the MULT field value +is 0, we set it to 4. Assuming that windows gets way with setting it to 0, +by the actual hardware going horizontal on a 1 -> 0 transition, which will +give it 4 transactions (MULT goes from 0 - 3). + +Note that we cannot stop on detecting the 1 -> 0 transition, as our decrement +of the transaction counter, and checking for it are done in 2 different places. + +Reported-by: Shawn Starr +Signed-off-by: Hans de Goede +--- + hw/usb/hcd-ehci.c | 39 +++++++++++++++++++-------------------- + 1 file changed, 19 insertions(+), 20 deletions(-) + +diff --git a/hw/usb/hcd-ehci.c b/hw/usb/hcd-ehci.c +index 6a5da84..46f6d99 100644 +--- a/hw/usb/hcd-ehci.c ++++ b/hw/usb/hcd-ehci.c +@@ -373,6 +373,7 @@ struct EHCIQueue { + uint32_t seen; + uint64_t ts; + int async; ++ int transact_ctr; + + /* cached data from guest - needs to be flushed + * when guest removes an entry (doorbell, handshake sequence) +@@ -1837,6 +1838,10 @@ static EHCIQueue *ehci_state_fetchqh(EHCIState *ehci, int async) + } + q->qh = qh; + ++ q->transact_ctr = get_field(q->qh.epcap, QH_EPCAP_MULT); ++ if (q->transact_ctr == 0) /* Guest bug in some versions of windows */ ++ q->transact_ctr = 4; ++ + if (q->dev == NULL) { + q->dev = ehci_find_device(q->ehci, devaddr); + } +@@ -2014,11 +2019,8 @@ static int ehci_state_fetchqtd(EHCIQueue *q) + } else if (p != NULL) { + switch (p->async) { + case EHCI_ASYNC_NONE: +- /* Should never happen packet should at least be initialized */ +- assert(0); +- break; + case EHCI_ASYNC_INITIALIZED: +- /* Previously nacked packet (likely interrupt ep) */ ++ /* Not yet executed (MULT), or previously nacked (int) packet */ + ehci_set_state(q->ehci, q->async, EST_EXECUTE); + break; + case EHCI_ASYNC_INFLIGHT: +@@ -2107,15 +2109,12 @@ static int ehci_state_execute(EHCIQueue *q) + + // TODO verify enough time remains in the uframe as in 4.4.1.1 + // TODO write back ptr to async list when done or out of time +- // TODO Windows does not seem to ever set the MULT field + +- if (!q->async) { +- int transactCtr = get_field(q->qh.epcap, QH_EPCAP_MULT); +- if (!transactCtr) { +- ehci_set_state(q->ehci, q->async, EST_HORIZONTALQH); +- again = 1; +- goto out; +- } ++ /* 4.10.3, bottom of page 82, go horizontal on transaction counter == 0 */ ++ if (!q->async && q->transact_ctr == 0) { ++ ehci_set_state(q->ehci, q->async, EST_HORIZONTALQH); ++ again = 1; ++ goto out; + } + + if (q->async) { +@@ -2132,7 +2131,11 @@ static int ehci_state_execute(EHCIQueue *q) + trace_usb_ehci_packet_action(p->queue, p, "async"); + p->async = EHCI_ASYNC_INFLIGHT; + ehci_set_state(q->ehci, q->async, EST_HORIZONTALQH); +- again = (ehci_fill_queue(p) == USB_RET_PROCERR) ? -1 : 1; ++ if (q->async) { ++ again = (ehci_fill_queue(p) == USB_RET_PROCERR) ? -1 : 1; ++ } else { ++ again = 1; ++ } + goto out; + } + +@@ -2152,13 +2155,9 @@ static int ehci_state_executing(EHCIQueue *q) + + ehci_execute_complete(q); + +- // 4.10.3 +- if (!q->async) { +- int transactCtr = get_field(q->qh.epcap, QH_EPCAP_MULT); +- transactCtr--; +- set_field(&q->qh.epcap, transactCtr, QH_EPCAP_MULT); +- // 4.10.3, bottom of page 82, should exit this state when transaction +- // counter decrements to 0 ++ /* 4.10.3 */ ++ if (!q->async && q->transact_ctr > 0) { ++ q->transact_ctr--; + } + + /* 4.10.5 */ +-- +1.7.12.1 + diff --git a/0632-usb-redir-Adjust-pkg-config-check-for-usbredirparser.patch b/0632-usb-redir-Adjust-pkg-config-check-for-usbredirparser.patch new file mode 100644 index 0000000..a8bebbd --- /dev/null +++ b/0632-usb-redir-Adjust-pkg-config-check-for-usbredirparser.patch @@ -0,0 +1,49 @@ +From 79467d7c3fe963b39b00c884a5624cb1e754db9d Mon Sep 17 00:00:00 2001 +From: Hans de Goede +Date: Tue, 25 Sep 2012 13:22:21 +0200 +Subject: [PATCH] usb-redir: Adjust pkg-config check for usbredirparser .pc + file rename (v2) + +The usbredir 0.5 release introduced the new API for 64 bit packet ids, but +it kept the libusbredirparser.pc name as is, meaning that older versions of +qemu will still have their pkg-config check for usbredirparser fulfilled, +and build with the usb-redir device. Due to the API change there will be +some compiler warnings, but the build will succeed, however the usb-redir +device will be broken on 32 bit machines. + +To solve this a new usbredir-0.5.2 release is coming, which renames the +libusbredirparser.pc file to libusbredirparser-0.5.pc, so that it will no +longer fulfill the pkg-config check of the qemu-1.2 and older releases, +stopping the (silent) breakage. This patch adjusts qemu master's configure +to properly detect the new usbredir release. + +Changes in v2: +-Not only use the new .pc name in the check but also when getting cflags + and libs! + +Signed-off-by: Hans de Goede +--- + configure | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/configure b/configure +index 2c4469f..f019526 100755 +--- a/configure ++++ b/configure +@@ -2758,10 +2758,10 @@ fi + + # check for usbredirparser for usb network redirection support + if test "$usb_redir" != "no" ; then +- if $pkg_config --atleast-version=0.5 libusbredirparser >/dev/null 2>&1 ; then ++ if $pkg_config --atleast-version=0.5 libusbredirparser-0.5 >/dev/null 2>&1 ; then + usb_redir="yes" +- usb_redir_cflags=$($pkg_config --cflags libusbredirparser 2>/dev/null) +- usb_redir_libs=$($pkg_config --libs libusbredirparser 2>/dev/null) ++ usb_redir_cflags=$($pkg_config --cflags libusbredirparser-0.5 2>/dev/null) ++ usb_redir_libs=$($pkg_config --libs libusbredirparser-0.5 2>/dev/null) + QEMU_CFLAGS="$QEMU_CFLAGS $usb_redir_cflags" + libs_softmmu="$libs_softmmu $usb_redir_libs" + else +-- +1.7.12.1 + diff --git a/0633-usb-redir-Change-usbredir_open_chardev-into-usbredir.patch b/0633-usb-redir-Change-usbredir_open_chardev-into-usbredir.patch new file mode 100644 index 0000000..f39bc12 --- /dev/null +++ b/0633-usb-redir-Change-usbredir_open_chardev-into-usbredir.patch @@ -0,0 +1,49 @@ +From 9ebfb490e04e1fe5466a4d31df17c5e6283236cb Mon Sep 17 00:00:00 2001 +From: Hans de Goede +Date: Thu, 27 Sep 2012 16:59:50 +0200 +Subject: [PATCH] usb-redir: Change usbredir_open_chardev into + usbredir_create_parser + +As we need to create the parser at more places. + +Signed-off-by: Hans de Goede +--- + hw/usb/redirect.c | 11 +++++------ + 1 file changed, 5 insertions(+), 6 deletions(-) + +diff --git a/hw/usb/redirect.c b/hw/usb/redirect.c +index 78e93a7..5d16aff 100644 +--- a/hw/usb/redirect.c ++++ b/hw/usb/redirect.c +@@ -872,15 +872,11 @@ static void usbredir_chardev_close_bh(void *opaque) + } + } + +-static void usbredir_chardev_open(USBRedirDevice *dev) ++static void usbredir_create_parser(USBRedirDevice *dev) + { + uint32_t caps[USB_REDIR_CAPS_SIZE] = { 0, }; + int flags = 0; + +- /* Make sure any pending closes are handled (no-op if none pending) */ +- usbredir_chardev_close_bh(dev); +- qemu_bh_cancel(dev->chardev_close_bh); +- + DPRINTF("creating usbredirparser\n"); + + dev->parser = qemu_oom_check(usbredirparser_create()); +@@ -992,7 +988,10 @@ static void usbredir_chardev_event(void *opaque, int event) + switch (event) { + case CHR_EVENT_OPENED: + DPRINTF("chardev open\n"); +- usbredir_chardev_open(dev); ++ /* Make sure any pending closes are handled (no-op if none pending) */ ++ usbredir_chardev_close_bh(dev); ++ qemu_bh_cancel(dev->chardev_close_bh); ++ usbredir_create_parser(dev); + break; + case CHR_EVENT_CLOSED: + DPRINTF("chardev close\n"); +-- +1.7.12.1 + diff --git a/0634-usb-redir-Don-t-make-migration-fail-in-none-seamless.patch b/0634-usb-redir-Don-t-make-migration-fail-in-none-seamless.patch new file mode 100644 index 0000000..a222747 --- /dev/null +++ b/0634-usb-redir-Don-t-make-migration-fail-in-none-seamless.patch @@ -0,0 +1,42 @@ +From c57b03073357e813ade4b3b34f6c1e3c0de394c2 Mon Sep 17 00:00:00 2001 +From: Hans de Goede +Date: Thu, 27 Sep 2012 16:57:41 +0200 +Subject: [PATCH] usb-redir: Don't make migration fail in none seamless case + +Instead simple disconnect the device like host redirection does on +migration. + +Signed-off-by: Hans de Goede +--- + hw/usb/redirect.c | 13 +++++++++---- + 1 file changed, 9 insertions(+), 4 deletions(-) + +diff --git a/hw/usb/redirect.c b/hw/usb/redirect.c +index 5d16aff..022ba42 100644 +--- a/hw/usb/redirect.c ++++ b/hw/usb/redirect.c +@@ -1637,12 +1637,17 @@ static int usbredir_get_parser(QEMUFile *f, void *priv, size_t unused) + } + + /* +- * Our chardev should be open already at this point, otherwise +- * the usbredir channel will be broken (ie spice without seamless) ++ * If our chardev is not open already at this point the usbredir connection ++ * has been broken (non seamless migration, or restore from disk). ++ * ++ * In this case create a temporary parser to receive the migration data, ++ * and schedule the close_bh to report the device as disconnected to the ++ * guest and to destroy the parser again. + */ + if (dev->parser == NULL) { +- ERROR("get_parser called with closed chardev, failing migration\n"); +- return -1; ++ WARNING("usb-redir connection broken during migration\n"); ++ usbredir_create_parser(dev); ++ qemu_bh_schedule(dev->chardev_close_bh); + } + + data = g_malloc(len); +-- +1.7.12.1 + diff --git a/0800-mips-Fix-link-error-with-piix4_pm_init.patch b/0800-mips-Fix-link-error-with-piix4_pm_init.patch new file mode 100644 index 0000000..3ceb891 --- /dev/null +++ b/0800-mips-Fix-link-error-with-piix4_pm_init.patch @@ -0,0 +1,30 @@ +From 5196eaa783b83110e6a8b99bfeb244b758b6e9c7 Mon Sep 17 00:00:00 2001 +From: Cole Robinson +Date: Mon, 6 Aug 2012 17:12:40 -0400 +Subject: [PATCH] mips: Fix link error with 'piix4_pm_init' + + LINK mips-softmmu/qemu-system-mips + LINK m68k-softmmu/qemu-system-m68k +hw/mips/../mips_malta.o: In function `mips_malta_init': +/home/crobinso/qemu-kvm/hw/mips/../mips_malta.c:961: undefined reference to `piix4_pm_init' + +Signed-off-by: Cole Robinson +--- + hw/mips/Makefile.objs | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/hw/mips/Makefile.objs b/hw/mips/Makefile.objs +index 29a5d0d..89af0e9 100644 +--- a/hw/mips/Makefile.objs ++++ b/hw/mips/Makefile.objs +@@ -1,6 +1,7 @@ + obj-y = mips_r4k.o mips_jazz.o mips_malta.o mips_mipssim.o + obj-y += mips_addr.o mips_timer.o mips_int.o + obj-y += gt64xxx.o mc146818rtc.o ++obj-y += acpi.o acpi_piix4.o + obj-$(CONFIG_FULONG) += bonito.o vt82c686.o mips_fulong2e.o + + obj-y := $(addprefix ../,$(obj-y)) +-- +1.7.12.1 + diff --git a/0801-configure-Add-disable-kvm-options.patch b/0801-configure-Add-disable-kvm-options.patch new file mode 100644 index 0000000..05021f1 --- /dev/null +++ b/0801-configure-Add-disable-kvm-options.patch @@ -0,0 +1,72 @@ +From b80fff00ed7f9baff808edb6c2c9f98f7e75e8ca Mon Sep 17 00:00:00 2001 +From: Cole Robinson +Date: Mon, 13 Aug 2012 18:39:54 -0400 +Subject: [PATCH] configure: Add --disable-kvm-options + +In Fedora, our qemu package is based on qemu-kvm, and we go to convoluted +lengths to provide a qemu-kvm binary with KVM on by default, but all +qemu-system-* with KVM off by default (using ./configure --disable-kvm) + +For qemu-system*, what we really want is upstream qemu symantics of TCG +by default, but the opt in option for KVM. CONFIG_KVM_OPTIONS fits the +bill, so let's expose it through ./configure. This will also simplify +our packaging for non-x86 KVM. + +Signed-off-by: Cole Robinson +--- + configure | 11 ++++++++++- + 1 file changed, 10 insertions(+), 1 deletion(-) + +diff --git a/configure b/configure +index f019526..933754d 100755 +--- a/configure ++++ b/configure +@@ -210,6 +210,7 @@ bsd_user="no" + guest_base="" + uname_release="" + mixemu="no" ++kvmoptions="yes" + aix="no" + blobs="yes" + pkgversion=" ($(kvm_version))" +@@ -732,6 +733,8 @@ for opt do + ;; + --enable-kvm) kvm="yes" + ;; ++ --disable-kvm-options) kvmoptions="no" ++ ;; + --disable-tcg-interpreter) tcg_interpreter="no" + ;; + --enable-tcg-interpreter) tcg_interpreter="yes" +@@ -1080,6 +1083,8 @@ echo " --enable-bluez enable bluez stack connectivity" + echo " --disable-slirp disable SLIRP userspace network connectivity" + echo " --disable-kvm disable KVM acceleration support" + echo " --enable-kvm enable KVM acceleration support" ++echo " --disable-kvm-options if KVM is enabled, default to KVM=off, and" ++echo " remove non-upstream cli options" + echo " --enable-tcg-interpreter enable TCG with bytecode interpreter (TCI)" + echo " --disable-nptl disable usermode NPTL support" + echo " --enable-nptl enable usermode NPTL support" +@@ -3160,6 +3165,7 @@ echo "ATTR/XATTR support $attr" + echo "Install blobs $blobs" + echo "KVM support $kvm" + echo "TCG interpreter $tcg_interpreter" ++echo "KVM CLI options $kvmoptions" + echo "fdt support $fdt" + echo "preadv support $preadv" + echo "fdatasync $fdatasync" +@@ -3893,7 +3899,10 @@ case "$target_arch2" in + \( "$target_arch2" = "x86_64" -a "$cpu" = "i386" \) -o \ + \( "$target_arch2" = "i386" -a "$cpu" = "x86_64" \) \) ; then + echo "CONFIG_KVM=y" >> $config_target_mak +- echo "CONFIG_KVM_OPTIONS=y" >> $config_host_mak ++ ++ if test "$kvmoptions" = "yes" ; then ++ echo "CONFIG_KVM_OPTIONS=y" >> $config_host_mak ++ fi + if test "$vhost_net" = "yes" ; then + echo "CONFIG_VHOST_NET=y" >> $config_target_mak + fi +-- +1.7.12.1 + diff --git a/qemu.spec b/qemu.spec index f06fa65..a596ecf 100644 --- a/qemu.spec +++ b/qemu.spec @@ -109,7 +109,7 @@ Summary: QEMU is a FAST! processor emulator Name: qemu Version: 1.2.0 -Release: 16%{?dist} +Release: 17%{?dist} # Epoch because we pushed a qemu-1.0 package. AIUI this can't ever be dropped Epoch: 2 License: GPLv2+ and LGPLv2+ and BSD @@ -149,141 +149,324 @@ Source9: ksmtuned.conf Source10: qemu-guest-agent.service Source11: 99-qemu-guest-agent.rules -# Non upstream build fix -Patch1: 0001-mips-Fix-link-error-with-piix4_pm_init.patch - -# Add ./configure --disable-kvm-options -# keep: Carrying locally until qemu-kvm is fully merged into qemu.git -Patch2: 0002-configure-Add-disable-kvm-options.patch +# Patches queued for 1.2.1 stable +Patch0001: 0001-target-xtensa-convert-host-errno-values-to-guest.patch +Patch0002: 0002-target-cris-Fix-buffer-overflow.patch +Patch0003: 0003-target-xtensa-fix-missing-errno-codes-for-mingw32.patch +Patch0004: 0004-target-sparc-fix-fcmp-s-d-q-instructions-wrt-excepti.patch +Patch0005: 0005-target-s390x-fix-style.patch +Patch0006: 0006-target-s390x-split-FPU-ops.patch +Patch0007: 0007-target-s390x-split-condition-code-helpers.patch +Patch0008: 0008-target-s390x-split-integer-helpers.patch +Patch0009: 0009-target-s390x-split-memory-access-helpers.patch +Patch0010: 0010-target-s390x-rename-op_helper.c-to-misc_helper.c.patch +Patch0011: 0011-target-s390x-avoid-AREG0-for-FPU-helpers.patch +Patch0012: 0012-target-s390x-avoid-AREG0-for-integer-helpers.patch +Patch0013: 0013-target-s390x-avoid-AREG0-for-condition-code-helpers.patch +Patch0014: 0014-target-s390x-avoid-AREG0-for-misc-helpers.patch +Patch0015: 0015-target-s390x-switch-to-AREG0-free-mode.patch +Patch0016: 0016-tcg-s390-fix-ld-st-with-CONFIG_TCG_PASS_AREG0.patch +Patch0017: 0017-target-arm-Fix-potential-buffer-overflow.patch +Patch0018: 0018-tcg-optimize-split-expression-simplification.patch +Patch0019: 0019-tcg-optimize-simplify-or-xor-r-a-0-cases.patch +Patch0020: 0020-tcg-optimize-simplify-and-r-a-0-cases.patch +Patch0021: 0021-tcg-optimize-simplify-shift-rot-r-0-a-movi-r-0-cases.patch +Patch0022: 0022-tcg-optimize-swap-brcond-setcond-arguments-when-poss.patch +Patch0023: 0023-tcg-optimize-add-constant-folding-for-setcond.patch +Patch0024: 0024-tcg-optimize-add-constant-folding-for-brcond.patch +Patch0025: 0025-tcg-optimize-fix-if-else-break-coding-style.patch +Patch0026: 0026-target-s390x-avoid-cpu_single_env.patch +Patch0027: 0027-target-lm32-switch-to-AREG0-free-mode.patch +Patch0028: 0028-target-m68k-switch-to-AREG0-free-mode.patch +Patch0029: 0029-target-m68k-avoid-using-cpu_single_env.patch +Patch0030: 0030-target-unicore32-switch-to-AREG0-free-mode.patch +Patch0031: 0031-target-arm-convert-void-helpers.patch +Patch0032: 0032-target-arm-convert-remaining-helpers.patch +Patch0033: 0033-target-arm-final-conversion-to-AREG0-free-mode.patch +Patch0034: 0034-target-microblaze-switch-to-AREG0-free-mode.patch +Patch0035: 0035-target-cris-Avoid-AREG0-for-helpers.patch +Patch0036: 0036-target-cris-Switch-to-AREG0-free-mode.patch +Patch0037: 0037-target-sh4-switch-to-AREG0-free-mode.patch +Patch0038: 0038-target-mips-switch-to-AREG0-free-mode.patch +Patch0039: 0039-Remove-unused-CONFIG_TCG_PASS_AREG0-and-dead-code.patch +Patch0040: 0040-tcg-i386-allow-constants-in-load-store-ops.patch +Patch0041: 0041-tcg-mark-set_label-with-TCG_OPF_BB_END-flag.patch +Patch0042: 0042-revert-TCG-fix-copy-propagation.patch +Patch0043: 0043-target-mips-Set-opn-in-gen_ldst_multiple.patch +Patch0044: 0044-target-mips-Fix-MIPS_DEBUG.patch +Patch0045: 0045-target-mips-Always-evaluate-debugging-macro-argument.patch +Patch0046: 0046-tcg-optimize-fix-end-of-basic-block-detection.patch +Patch0047: 0047-target-xtensa-fix-extui-shift-amount.patch +Patch0048: 0048-target-xtensa-don-t-emit-extra-tcg_gen_goto_tb.patch +Patch0049: 0049-tcg-Introduce-movcond.patch +Patch0050: 0050-target-alpha-Use-movcond.patch +Patch0051: 0051-tcg-i386-Implement-movcond.patch +Patch0052: 0052-tcg-Optimize-movcond-for-constant-comparisons.patch +Patch0053: 0053-tcg-Optimize-two-address-commutative-operations.patch +Patch0054: 0054-gdbstub-sh4-fix-build-with-USE_SOFTFLOAT_STRUCT_TYPE.patch +Patch0055: 0055-tcg-Fix-USE_DIRECT_JUMP.patch +Patch0056: 0056-tcg-hppa-Fix-brcond2-and-setcond2.patch +Patch0057: 0057-tcg-hppa-Fix-broken-load-store-helpers.patch +Patch0058: 0058-tcg-mips-fix-wrong-usage-of-Z-constraint.patch +Patch0059: 0059-tcg-mips-kill-warnings-in-user-mode.patch +Patch0060: 0060-tcg-mips-use-TCGArg-or-TCGReg-instead-of-int.patch +Patch0061: 0061-tcg-mips-don-t-use-global-pointer.patch +Patch0062: 0062-tcg-mips-use-stack-for-TCG-temps.patch +Patch0063: 0063-tcg-mips-optimize-brcond-arg-0.patch +Patch0064: 0064-tcg-mips-optimize-bswap-16-16s-32-on-MIPS32R2.patch +Patch0065: 0065-tcg-mips-implement-rotl-rotr-ops-on-MIPS32R2.patch +Patch0066: 0066-tcg-mips-implement-deposit-op-on-MIPS32R2.patch +Patch0067: 0067-tcg-mips-implement-movcond-op-on-MIPS32R2.patch +Patch0068: 0068-tcg-optimize-remove-TCG_TEMP_ANY.patch +Patch0069: 0069-tcg-optimize-check-types-in-copy-propagation.patch +Patch0070: 0070-tcg-optimize-rework-copy-progagation.patch +Patch0071: 0071-tcg-optimize-do-copy-propagation-for-all-operations.patch +Patch0072: 0072-tcg-optimize-optimize-op-r-a-a-mov-r-a.patch +Patch0073: 0073-tcg-optimize-optimize-op-r-a-a-movi-r-0.patch +Patch0074: 0074-tcg-optimize-further-optimize-brcond-movcond-setcond.patch +Patch0075: 0075-tcg-optimize-prefer-the-op-a-a-b-form-for-commutativ.patch +Patch0076: 0076-tcg-remove-ifdef-endif-around-TCGOpcode-tests.patch +Patch0077: 0077-tcg-optimize-add-constant-folding-for-deposit.patch +Patch0078: 0078-tcg-README-document-tcg_gen_goto_tb-restrictions.patch +Patch0079: 0079-w64-Fix-TCG-helper-functions-with-5-arguments.patch +Patch0080: 0080-tcg-ppc32-Implement-movcond32.patch +Patch0081: 0081-tcg-sparc-Hack-in-qemu_ld-st64-for-32-bit.patch +Patch0082: 0082-tcg-sparc-Fix-ADDX-opcode.patch +Patch0083: 0083-tcg-sparc-Don-t-MAP_FIXED-on-top-of-the-program.patch +Patch0084: 0084-tcg-sparc-Assume-v9-cpu-always-i.e.-force-v8plus-in-.patch +Patch0085: 0085-tcg-sparc-Fix-qemu_ld-st-to-handle-32-bit-host.patch +Patch0086: 0086-tcg-sparc-Support-GUEST_BASE.patch +Patch0087: 0087-tcg-sparc-Change-AREG0-in-generated-code-to-i0.patch +Patch0088: 0088-tcg-sparc-Clean-up-cruft-stemming-from-attempts-to-u.patch +Patch0089: 0089-tcg-sparc-Mask-shift-immediates-to-avoid-illegal-ins.patch +Patch0090: 0090-tcg-sparc-Use-defines-for-temporaries.patch +Patch0091: 0091-tcg-sparc-Add-g-o-registers-to-alloc_order.patch +Patch0092: 0092-tcg-sparc-Fix-and-enable-direct-TB-chaining.patch +Patch0093: 0093-tcg-sparc-Preserve-branch-destinations-during-retran.patch +Patch0094: 0094-target-alpha-Initialize-env-cpu_model_str.patch +Patch0095: 0095-tcg-mips-fix-MIPS32-R2-detection.patch +Patch0096: 0096-tcg-Adjust-descriptions-of-cond-opcodes.patch +Patch0097: 0097-tcg-i386-fix-build-with-march-i686.patch +Patch0098: 0098-tcg-Fix-MAX_OPC_PARAM_IARGS.patch +Patch0099: 0099-tci-Fix-for-AREG0-free-mode.patch +Patch0100: 0100-spice-abort-on-invalid-streaming-cmdline-params.patch +Patch0101: 0101-spice-notify-spice-server-on-vm-start-stop.patch +Patch0102: 0102-spice-notify-on-vm-state-change-only-via-spice_serve.patch +Patch0103: 0103-spice-migration-add-QEVENT_SPICE_MIGRATE_COMPLETED.patch +Patch0104: 0104-spice-add-migrated-flag-to-spice-info.patch +Patch0105: 0105-spice-adding-seamless-migration-option-to-the-comman.patch +Patch0106: 0106-spice-increase-the-verbosity-of-spice-section-in-qem.patch +Patch0107: 0107-qxl-update_area_io-guest_bug-on-invalid-parameters.patch +Patch0108: 0108-qxl-add-QXL_IO_MONITORS_CONFIG_ASYNC.patch +Patch0109: 0109-configure-print-spice-protocol-and-spice-server-vers.patch +Patch0110: 0110-fix-doc-of-using-raw-values-with-sendkey.patch +Patch0111: 0111-qapi-Fix-potential-NULL-pointer-segfault.patch +Patch0112: 0112-json-parser-Fix-potential-NULL-pointer-segfault.patch +Patch0113: 0113-pcie-drop-version_id-field-for-live-migration.patch +Patch0114: 0114-pcie_aer-clear-cmask-for-Advanced-Error-Interrupt-Me.patch +Patch0115: 0115-fix-entry-pointer-for-ELF-kernels-loaded-with-kernel.patch +Patch0116: 0116-lan9118-fix-multicast-filtering.patch +Patch0117: 0117-MIPS-user-Fix-reset-CPU-state-initialization.patch +Patch0118: 0118-Add-MAINTAINERS-entry-for-leon3.patch +Patch0119: 0119-musicpal-Fix-flash-mapping.patch +Patch0120: 0120-qemu-Use-valgrind-annotations-to-mark-kvm-guest-memo.patch +Patch0121: 0121-hw-wm8750-Fix-potential-buffer-overflow.patch +Patch0122: 0122-hw-mcf5206-Fix-buffer-overflow-for-MBAR-read-write.patch +Patch0123: 0123-use-libexecdir-instead-of-ignoring-it-first-and-rein.patch +Patch0124: 0124-socket-don-t-attempt-to-reconnect-a-TCP-socket-in-se.patch +Patch0125: 0125-Add-ability-to-force-enable-disable-of-tools-build.patch +Patch0126: 0126-usb-controllers-do-not-need-to-check-for-babble-them.patch +Patch0127: 0127-usb-core-Don-t-set-packet-state-to-complete-on-a-nak.patch +Patch0128: 0128-usb-core-Add-a-usb_ep_find_packet_by_id-helper-funct.patch +Patch0129: 0129-usb-core-Allow-the-first-packet-of-a-pipelined-ep-to.patch +Patch0130: 0130-Revert-ehci-don-t-flush-cache-on-doorbell-rings.patch +Patch0131: 0131-ehci-Validate-qh-is-not-changed-unexpectedly-by-the-.patch +Patch0132: 0132-ehci-Update-copyright-headers-to-reflect-recent-work.patch +Patch0133: 0133-ehci-Properly-cleanup-packets-on-cancel.patch +Patch0134: 0134-ehci-Properly-report-completed-but-not-yet-processed.patch +Patch0135: 0135-ehci-check-for-EHCI_ASYNC_FINISHED-first-in-ehci_fre.patch +Patch0136: 0136-ehci-trace-guest-bugs.patch +Patch0137: 0137-ehci-add-doorbell-trace-events.patch +Patch0138: 0138-ehci-Add-some-additional-ehci_trace_guest_bug-calls.patch +Patch0139: 0139-ehci-Fix-memory-leak-in-handling-of-NAK-ed-packets.patch +Patch0140: 0140-ehci-Handle-USB_RET_PROCERR-in-ehci_fill_queue.patch +Patch0141: 0141-ehci-Correct-a-comment-in-fetchqtd-packet-processing.patch +Patch0142: 0142-usb-redir-Never-return-USB_RET_NAK-for-async-handled.patch +Patch0143: 0143-usb-redir-Don-t-delay-handling-of-open-events-to-a-b.patch +Patch0144: 0144-usb-redir-Get-rid-of-async-struct-get-member.patch +Patch0145: 0145-usb-redir-Get-rid-of-local-shadow-copy-of-packet-hea.patch +Patch0146: 0146-usb-redir-Get-rid-of-unused-async-struct-dev-member.patch +Patch0147: 0147-usb-redir-Move-to-core-packet-id-and-queue-handling.patch +Patch0148: 0148-usb-redir-Return-babble-when-getting-more-bulk-data-.patch +Patch0149: 0149-Better-name-usb-braille-device.patch +Patch0150: 0150-usb-audio-fix-usb-version.patch +Patch0151: 0151-xhci-rip-out-background-transfer-code.patch +Patch0152: 0152-xhci-drop-buffering.patch +Patch0153: 0153-xhci-fix-runtime-write-tracepoint.patch +Patch0154: 0154-xhci-allow-bytewise-capability-register-reads.patch +Patch0155: 0155-qxl-dont-update-invalid-area.patch +Patch0156: 0156-usb-host-allow-emulated-non-async-control-requests-w.patch +Patch0157: 0157-qxl-better-cleanup-for-surface-destroy.patch +Patch0158: 0158-ehci-switch-to-new-style-memory-ops.patch +Patch0159: 0159-ehci-Fix-interrupts-stopping-when-Interrupt-Threshol.patch +Patch0160: 0160-ehci-Don-t-process-too-much-frames-in-1-timer-tick-v.patch +Patch0161: 0161-sheepdog-fix-savevm-and-loadvm.patch +Patch0162: 0162-ide-Fix-error-messages-from-static-code-analysis-no-.patch +Patch0163: 0163-block-curl-Fix-wrong-free-statement.patch +Patch0164: 0164-vdi-Fix-warning-from-clang.patch +Patch0165: 0165-block-fix-block-tray-status.patch +Patch0166: 0166-ahci-properly-reset-PxCMD-on-HBA-reset.patch +Patch0167: 0167-Don-t-require-encryption-password-for-qemu-img-info-.patch +Patch0168: 0168-block-Don-t-forget-to-delete-temporary-file.patch +Patch0169: 0169-hw-qxl-tracing-fixes.patch +Patch0170: 0170-configure-usbredir-fixes.patch +Patch0171: 0171-ehci-Don-t-set-seen-to-0-when-removing-unseen-queue-.patch +Patch0172: 0172-ehci-Walk-async-schedule-before-and-after-migration.patch +Patch0173: 0173-usb-redir-Revert-usb-redir-part-of-commit-93bfef4c.patch +Patch0174: 0174-uhci-Don-t-queue-up-packets-after-one-with-the-SPD-f.patch +Patch0175: 0175-slirp-Remove-wrong-type-casts-ins-debug-statements.patch +Patch0176: 0176-slirp-Fix-error-reported-by-static-code-analysis.patch +Patch0177: 0177-slirp-improve-TFTP-performance.patch +Patch0178: 0178-slirp-Handle-more-than-65535-blocks-in-TFTP-transfer.patch +Patch0179: 0179-slirp-Implement-TFTP-Blocksize-option.patch +Patch0180: 0180-srp-Don-t-use-QEMU_PACKED-for-single-elements-of-a-s.patch +Patch0181: 0181-Spelling-fixes-in-comments-and-documentation.patch +Patch0182: 0182-console-Clean-up-bytes-per-pixel-calculation.patch +Patch0183: 0183-qapi-Fix-enumeration-typo-error.patch +Patch0184: 0184-kvm-Fix-warning-from-static-code-analysis.patch +Patch0185: 0185-arch_init.c-add-missing-symbols-before-PRIu64-in-deb.patch +Patch0186: 0186-net-notify-iothread-after-flushing-queue.patch +Patch0187: 0187-e1000-flush-queue-whenever-can_receive-can-go-from-f.patch +Patch0188: 0188-xen-flush-queue-when-getting-an-event.patch +Patch0189: 0189-eepro100-Fix-network-hang-when-rx-buffers-run-out.patch +Patch0190: 0190-net-add-receive_disabled-logic-to-iov-delivery-path.patch +Patch0191: 0191-net-do-not-report-queued-packets-as-sent.patch +Patch0192: 0192-net-add-netdev-options-to-man-page.patch +Patch0193: 0193-net-clean-up-usbnet_receive.patch +Patch0194: 0194-net-fix-usbnet_receive-packet-drops.patch +Patch0195: 0195-net-broadcast-hub-packets-if-at-least-one-port-can-r.patch +Patch0196: 0196-net-asynchronous-send-receive-infrastructure-for-net.patch +Patch0197: 0197-net-EAGAIN-handling-for-net-socket.c-UDP.patch +Patch0198: 0198-net-EAGAIN-handling-for-net-socket.c-TCP.patch +Patch0199: 0199-configure-fix-seccomp-check.patch +Patch0200: 0200-configure-properly-check-if-lrt-and-lm-is-needed.patch +Patch0201: 0201-Revert-455aa1e08-and-c3767ed0eb.patch +Patch0202: 0202-qemu-char-BUGFIX-don-t-call-FD_ISSET-with-negative-f.patch +Patch0203: 0203-cpu_physical_memory_write_rom-needs-to-do-TB-invalid.patch +Patch0204: 0204-arch_init.c-Improve-soundhw-help-for-non-HAS_AUDIO_C.patch +Patch0205: 0205-xilinx_timer-Removed-comma-in-device-name.patch +Patch0206: 0206-xilinx_timer-Send-dbg-msgs-to-stderr-not-stdout.patch +Patch0207: 0207-xilinx.h-Error-check-when-setting-links.patch +Patch0208: 0208-xilinx_timer-Fix-a-compile-error-if-debug-enabled.patch +Patch0209: 0209-pflash_cfi01-fix-vendor-specific-extended-query.patch +Patch0210: 0210-MAINTAINERS-Add-entry-for-QOM-CPU.patch +Patch0211: 0211-iSCSI-We-need-to-support-SG_IO-also-from-iscsi_ioctl.patch +Patch0212: 0212-iSCSI-We-dont-need-to-explicitely-call-qemu_notify_e.patch +Patch0213: 0213-scsi-disk-introduce-check_lba_range.patch +Patch0214: 0214-scsi-disk-fix-check-for-out-of-range-LBA.patch +Patch0215: 0215-SCSI-Standard-INQUIRY-data-should-report-HiSup-flag-.patch +Patch0216: 0216-audio-Fix-warning-from-static-code-analysis.patch +Patch0217: 0217-qemu-ga-Remove-unreachable-code-after-g_error.patch +Patch0218: 0218-qemu-sockets-Fix-potential-memory-leak.patch +Patch0219: 0219-cadence_uart-Fix-buffer-overflow.patch +Patch0220: 0220-lm4549-Fix-buffer-overflow.patch +Patch0221: 0221-ioh3420-Remove-unreachable-code.patch +Patch0222: 0222-pflash_cfi01-Fix-warning-caused-by-unreachable-code.patch +Patch0223: 0223-curses-don-t-initialize-curses-when-qemu-is-daemoniz.patch +Patch0224: 0224-TextConsole-saturate-escape-parameter-in-TTY_STATE_C.patch +Patch0225: 0225-linux-user-Remove-redundant-null-check-and-replace-f.patch +Patch0226: 0226-net-socket-Fix-compiler-warning-regression-for-MinGW.patch +Patch0227: 0227-w32-Always-use-standard-instead-of-native-format-str.patch +Patch0228: 0228-w32-Add-implementation-of-gmtime_r-localtime_r.patch +Patch0229: 0229-blockdev-preserve-readonly-and-snapshot-states-acros.patch +Patch0230: 0230-block-correctly-set-the-keep_read_only-flag.patch +Patch0231: 0231-configure-Allow-builds-without-any-system-or-user-em.patch +Patch0232: 0232-Refactor-inet_connect_opts-function.patch +Patch0233: 0233-Separate-inet_connect-into-inet_connect-blocking-and.patch +Patch0234: 0234-Fix-address-handling-in-inet_nonblocking_connect.patch +Patch0235: 0235-Clear-handler-only-for-valid-fd.patch +Patch0236: 0236-pl190-fix-read-of-VECTADDR.patch +Patch0237: 0237-hw-armv7m_nvic-Correctly-register-GIC-region-when-se.patch +Patch0238: 0238-Versatile-Express-Fix-NOR-flash-0-address-and-remove.patch +Patch0239: 0239-i386-kvm-bit-10-of-CPUID-8000_0001-.EDX-is-reserved.patch +Patch0240: 0240-fpu-softfloat.c-Return-correctly-signed-values-from-.patch +Patch0241: 0241-pseries-Don-t-test-for-MSR_PR-for-hypercalls-under-K.patch +Patch0242: 0242-update-VERSION-for-v1.2.1.patch # The infamous chardev flow control patches -Patch101: 0101-char-Split-out-tcp-socket-close-code-in-a-separate-f.patch -Patch102: 0102-char-Add-a-QemuChrHandlers-struct-to-initialise-char.patch -Patch103: 0103-iohandlers-Add-enable-disable_write_fd_handler-funct.patch -Patch104: 0104-char-Add-framework-for-a-write-unblocked-callback.patch -Patch105: 0105-char-Update-send_all-to-handle-nonblocking-chardev-w.patch -Patch106: 0106-char-Equip-the-unix-tcp-backend-to-handle-nonblockin.patch -Patch107: 0107-char-Throttle-when-host-connection-is-down.patch -Patch108: 0108-virtio-console-Enable-port-throttling-when-chardev-i.patch -Patch109: 0109-spice-qemu-char.c-add-throttling.patch -Patch110: 0110-spice-qemu-char.c-remove-intermediate-buffer.patch -Patch111: 0111-usb-redir-Add-flow-control-support.patch -Patch112: 0112-virtio-serial-bus-replay-guest_open-on-migration.patch -Patch113: 0113-char-Disable-write-callback-if-throttled-chardev-is-.patch +Patch0400: 0400-char-Split-out-tcp-socket-close-code-in-a-separate-f.patch +Patch0401: 0401-char-Add-a-QemuChrHandlers-struct-to-initialise-char.patch +Patch0402: 0402-iohandlers-Add-enable-disable_write_fd_handler-funct.patch +Patch0403: 0403-char-Add-framework-for-a-write-unblocked-callback.patch +Patch0404: 0404-char-Update-send_all-to-handle-nonblocking-chardev-w.patch +Patch0405: 0405-char-Equip-the-unix-tcp-backend-to-handle-nonblockin.patch +Patch0406: 0406-char-Throttle-when-host-connection-is-down.patch +Patch0407: 0407-virtio-console-Enable-port-throttling-when-chardev-i.patch +Patch0408: 0408-spice-qemu-char.c-add-throttling.patch +Patch0409: 0409-spice-qemu-char.c-remove-intermediate-buffer.patch +Patch0410: 0410-usb-redir-Add-flow-control-support.patch +Patch0411: 0411-virtio-serial-bus-replay-guest_open-on-migration.patch +Patch0412: 0412-char-Disable-write-callback-if-throttled-chardev-is-.patch # Spice features from upstream master: seamless migration & dynamic monitors -Patch201: 0201-spice-abort-on-invalid-streaming-cmdline-params.patch -Patch202: 0202-spice-notify-spice-server-on-vm-start-stop.patch -Patch203: 0203-spice-notify-on-vm-state-change-only-via-spice_serve.patch -Patch204: 0204-spice-migration-add-QEVENT_SPICE_MIGRATE_COMPLETED.patch -Patch205: 0205-spice-add-migrated-flag-to-spice-info.patch -Patch206: 0206-spice-adding-seamless-migration-option-to-the-comman.patch -Patch207: 0207-spice-increase-the-verbosity-of-spice-section-in-qem.patch -Patch208: 0208-qxl-update_area_io-guest_bug-on-invalid-parameters.patch -Patch209: 0209-qxl-disallow-unknown-revisions.patch -Patch210: 0210-qxl-add-QXL_IO_MONITORS_CONFIG_ASYNC.patch -Patch211: 0211-configure-print-spice-protocol-and-spice-server-vers.patch -Patch212: 0212-spice-make-number-of-surfaces-runtime-configurable.patch -Patch213: 0213-qxl-Add-set_client_capabilities-interface-to-QXLInte.patch -Patch214: 0214-Remove-ifdef-QXL_COMMAND_FLAG_COMPAT_16BPP.patch -Patch215: 0215-spice-switch-to-queue-for-vga-mode-updates.patch -Patch216: 0216-spice-split-qemu_spice_create_update.patch -Patch217: 0217-spice-add-screen-mirror.patch -Patch218: 0218-spice-send-updates-only-for-changed-screen-content.patch -Patch219: 0219-qxl-dont-update-invalid-area.patch -Patch220: 0220-qxl-Ignore-set_client_capabilities-pre-post-migrate.patch -Patch221: 0221-qxl-better-cleanup-for-surface-destroy.patch -Patch222: 0222-hw-qxl-tracing-fixes.patch -Patch223: 0223-qxl-add-trace-event-for-QXL_IO_LOG.patch -Patch224: 0224-hw-qxl-support-client-monitor-configuration-via-devi.patch -Patch225: 0225-qxl-always-update-displaysurface-on-resize.patch -Patch226: 0226-qxl-update_area_io-cleanup-invalid-parameters-handli.patch -Patch227: 0227-qxl-fix-range-check-for-rev3-io-commands.patch - -# Ugh, ton of USB bugfixes / preparation patches for usb-redir -# live-migration which did not make 1.2.0 :| -# All are in upstream master so can be dropped next qemu release -Patch0301: 0301-usb-controllers-do-not-need-to-check-for-babble-them.patch -Patch0302: 0302-usb-core-Don-t-set-packet-state-to-complete-on-a-nak.patch -Patch0303: 0303-usb-core-Add-a-usb_ep_find_packet_by_id-helper-funct.patch -Patch0304: 0304-usb-core-Allow-the-first-packet-of-a-pipelined-ep-to.patch -Patch0305: 0305-Revert-ehci-don-t-flush-cache-on-doorbell-rings.patch -Patch0306: 0306-ehci-Validate-qh-is-not-changed-unexpectedly-by-the-.patch -Patch0307: 0307-ehci-Update-copyright-headers-to-reflect-recent-work.patch -Patch0308: 0308-ehci-Properly-cleanup-packets-on-cancel.patch -Patch0309: 0309-ehci-Properly-report-completed-but-not-yet-processed.patch -Patch0310: 0310-ehci-check-for-EHCI_ASYNC_FINISHED-first-in-ehci_fre.patch -Patch0311: 0311-ehci-trace-guest-bugs.patch -Patch0312: 0312-ehci-add-doorbell-trace-events.patch -Patch0313: 0313-ehci-Add-some-additional-ehci_trace_guest_bug-calls.patch -Patch0314: 0314-ehci-Fix-memory-leak-in-handling-of-NAK-ed-packets.patch -Patch0315: 0315-ehci-Handle-USB_RET_PROCERR-in-ehci_fill_queue.patch -Patch0316: 0316-ehci-Correct-a-comment-in-fetchqtd-packet-processing.patch -Patch0317: 0317-usb-redir-Never-return-USB_RET_NAK-for-async-handled.patch -Patch0318: 0318-usb-redir-Don-t-delay-handling-of-open-events-to-a-b.patch -Patch0319: 0319-usb-redir-Get-rid-of-async-struct-get-member.patch -Patch0320: 0320-usb-redir-Get-rid-of-local-shadow-copy-of-packet-hea.patch -Patch0321: 0321-usb-redir-Get-rid-of-unused-async-struct-dev-member.patch -Patch0322: 0322-usb-redir-Move-to-core-packet-id-and-queue-handling.patch -Patch0323: 0323-usb-redir-Return-babble-when-getting-more-bulk-data-.patch -Patch0324: 0324-usb-redir-Convert-to-new-libusbredirparser-0.5-API.patch -Patch0325: 0325-usb-redir-Set-ep-max_packet_size-if-available.patch -Patch0326: 0326-usb-redir-Add-a-usbredir_reject_device-helper-functi.patch -Patch0327: 0327-usb-redir-Ensure-our-peer-has-the-necessary-caps-whe.patch -Patch0328: 0328-usb-redir-Enable-pipelining-for-bulk-endpoints.patch -Patch0329: 0329-Better-name-usb-braille-device.patch -Patch0330: 0330-usb-audio-fix-usb-version.patch -Patch0331: 0331-xhci-rip-out-background-transfer-code.patch -Patch0332: 0332-xhci-drop-buffering.patch -Patch0333: 0333-xhci-move-device-lookup-into-xhci_setup_packet.patch -Patch0334: 0334-xhci-implement-mfindex.patch -Patch0335: 0335-xhci-iso-xfer-support.patch -Patch0336: 0336-xhci-trace-cc-codes-in-cleartext.patch -Patch0337: 0337-xhci-add-trace_usb_xhci_ep_set_dequeue.patch -Patch0338: 0338-xhci-fix-runtime-write-tracepoint.patch -Patch0339: 0339-xhci-update-register-layout.patch -Patch0340: 0340-xhci-update-port-handling.patch -Patch0341: 0341-usb3-superspeed-descriptors.patch -Patch0342: 0342-usb3-superspeed-endpoint-companion.patch -Patch0343: 0343-usb3-bos-decriptor.patch -Patch0344: 0344-usb-storage-usb3-support.patch -Patch0345: 0345-xhci-fix-cleanup-msi.patch -Patch0346: 0346-xhci-rework-interrupt-handling.patch -Patch0347: 0347-xhci-add-msix-support.patch -Patch0348: 0348-xhci-move-register-update-into-xhci_intr_raise.patch -Patch0349: 0349-xhci-add-XHCIInterrupter.patch -Patch0350: 0350-xhci-prepare-xhci_runtime_-read-write-for-multiple-i.patch -Patch0351: 0351-xhci-pick-target-interrupter.patch -Patch0352: 0352-xhci-support-multiple-interrupters.patch -Patch0353: 0353-xhci-kill-xhci_mem_-read-write-dispatcher-functions.patch -Patch0354: 0354-xhci-allow-bytewise-capability-register-reads.patch -Patch0355: 0355-usb-host-allow-emulated-non-async-control-requests-w.patch -Patch0356: 0356-ehci-switch-to-new-style-memory-ops.patch -Patch0357: 0357-ehci-Fix-interrupts-stopping-when-Interrupt-Threshol.patch -Patch0358: 0358-ehci-Don-t-process-too-much-frames-in-1-timer-tick-v.patch -Patch0359: 0359-configure-usbredir-fixes.patch -Patch0360: 0360-ehci-Don-t-set-seen-to-0-when-removing-unseen-queue-.patch -Patch0361: 0361-ehci-Walk-async-schedule-before-and-after-migration.patch -Patch0362: 0362-usb-redir-Change-cancelled-packet-code-into-a-generi.patch -Patch0363: 0363-usb-redir-Add-an-already_in_flight-packet-id-queue.patch -Patch0364: 0364-usb-redir-Store-max_packet_size-in-endp_data.patch -Patch0365: 0365-usb-redir-Add-support-for-migration.patch -Patch0366: 0366-usb-redir-Add-chardev-open-close-debug-logging.patch -Patch0367: 0367-usb-redir-Revert-usb-redir-part-of-commit-93bfef4c.patch -Patch0368: 0368-uhci-Don-t-queue-up-packets-after-one-with-the-SPD-f.patch -# And the last few ehci fixes + the actual usb-redir live migration code -# Not yet upstream but should get there real soon -Patch0369: 0369-ehci-Fix-interrupt-packet-MULT-handling.patch -Patch0370: 0370-usb-redir-Adjust-pkg-config-check-for-usbredirparser.patch -Patch0371: 0371-usb-redir-Change-usbredir_open_chardev-into-usbredir.patch -Patch0372: 0372-usb-redir-Don-t-make-migration-fail-in-none-seamless.patch - -# Revert c3767ed0eb5d0. -# NOT upstream (hopefully will be soon). -# See: https://bugzilla.redhat.com/show_bug.cgi?id=853408 -# and: https://lists.gnu.org/archive/html/qemu-devel/2012-09/msg00526.html -# plus followups. -Patch0900: 0001-Revert-qemu-char-Re-connect-for-tcp_chr_write-unconn.patch +Patch0500: 0500-qxl-disallow-unknown-revisions.patch +Patch0501: 0501-spice-make-number-of-surfaces-runtime-configurable.patch +Patch0502: 0502-qxl-Add-set_client_capabilities-interface-to-QXLInte.patch +Patch0503: 0503-Remove-ifdef-QXL_COMMAND_FLAG_COMPAT_16BPP.patch +Patch0504: 0504-spice-switch-to-queue-for-vga-mode-updates.patch +Patch0505: 0505-spice-split-qemu_spice_create_update.patch +Patch0506: 0506-spice-add-screen-mirror.patch +Patch0507: 0507-spice-send-updates-only-for-changed-screen-content.patch +Patch0508: 0508-qxl-Ignore-set_client_capabilities-pre-post-migrate.patch +Patch0509: 0509-qxl-add-trace-event-for-QXL_IO_LOG.patch +Patch0510: 0510-hw-qxl-support-client-monitor-configuration-via-devi.patch +Patch0511: 0511-qxl-always-update-displaysurface-on-resize.patch +Patch0512: 0512-qxl-update_area_io-cleanup-invalid-parameters-handli.patch +Patch0513: 0513-qxl-fix-range-check-for-rev3-io-commands.patch + +# usb-redir live-migration and misc bits, will be in before 1.3.0 +Patch0600: 0600-usb-redir-Convert-to-new-libusbredirparser-0.5-API.patch +Patch0601: 0601-usb-redir-Set-ep-max_packet_size-if-available.patch +Patch0602: 0602-usb-redir-Add-a-usbredir_reject_device-helper-functi.patch +Patch0603: 0603-usb-redir-Ensure-our-peer-has-the-necessary-caps-whe.patch +Patch0604: 0604-usb-redir-Enable-pipelining-for-bulk-endpoints.patch +Patch0605: 0605-xhci-move-device-lookup-into-xhci_setup_packet.patch +Patch0606: 0606-xhci-implement-mfindex.patch +Patch0607: 0607-xhci-iso-xfer-support.patch +Patch0608: 0608-xhci-trace-cc-codes-in-cleartext.patch +Patch0609: 0609-xhci-add-trace_usb_xhci_ep_set_dequeue.patch +Patch0610: 0610-xhci-update-register-layout.patch +Patch0611: 0611-xhci-update-port-handling.patch +Patch0612: 0612-usb3-superspeed-descriptors.patch +Patch0613: 0613-usb3-superspeed-endpoint-companion.patch +Patch0614: 0614-usb3-bos-decriptor.patch +Patch0615: 0615-usb-storage-usb3-support.patch +Patch0616: 0616-xhci-fix-cleanup-msi.patch +Patch0617: 0617-xhci-rework-interrupt-handling.patch +Patch0618: 0618-xhci-add-msix-support.patch +Patch0619: 0619-xhci-move-register-update-into-xhci_intr_raise.patch +Patch0620: 0620-xhci-add-XHCIInterrupter.patch +Patch0621: 0621-xhci-prepare-xhci_runtime_-read-write-for-multiple-i.patch +Patch0622: 0622-xhci-pick-target-interrupter.patch +Patch0623: 0623-xhci-support-multiple-interrupters.patch +Patch0624: 0624-xhci-kill-xhci_mem_-read-write-dispatcher-functions.patch +Patch0625: 0625-usb-redir-Change-cancelled-packet-code-into-a-generi.patch +Patch0626: 0626-usb-redir-Add-an-already_in_flight-packet-id-queue.patch +Patch0627: 0627-usb-redir-Store-max_packet_size-in-endp_data.patch +Patch0628: 0628-usb-redir-Add-support-for-migration.patch +Patch0629: 0629-usb-redir-Add-chardev-open-close-debug-logging.patch +Patch0630: 0630-usb-redir-Revert-usb-redir-part-of-commit-93bfef4c.patch +Patch0631: 0631-ehci-Fix-interrupt-packet-MULT-handling.patch +Patch0632: 0632-usb-redir-Adjust-pkg-config-check-for-usbredirparser.patch +Patch0633: 0633-usb-redir-Change-usbredir_open_chardev-into-usbredir.patch +Patch0634: 0634-usb-redir-Don-t-make-migration-fail-in-none-seamless.patch + +# Non upstream build fix, http://www.spinics.net/lists/kvm/msg80589.html +Patch0800: 0800-mips-Fix-link-error-with-piix4_pm_init.patch +# Add ./configure --disable-kvm-options +# keep: Carrying locally until qemu-kvm is fully merged into qemu.git +Patch0801: 0801-configure-Add-disable-kvm-options.patch + BuildRequires: SDL-devel BuildRequires: zlib-devel @@ -705,125 +888,316 @@ such as kvm_stat. %prep %setup -q -n qemu-kvm-%{version} -%patch1 -p1 -%patch2 -p1 - -%patch101 -p1 -%patch102 -p1 -%patch103 -p1 -%patch104 -p1 -%patch105 -p1 -%patch106 -p1 -%patch107 -p1 -%patch108 -p1 -%patch109 -p1 -%patch110 -p1 -%patch111 -p1 -%patch112 -p1 -%patch113 -p1 - -%patch201 -p1 -%patch202 -p1 -%patch203 -p1 -%patch204 -p1 -%patch205 -p1 -%patch206 -p1 -%patch207 -p1 -%patch208 -p1 -%patch209 -p1 -%patch210 -p1 -%patch211 -p1 -%patch212 -p1 -%patch213 -p1 -%patch214 -p1 -%patch215 -p1 -%patch216 -p1 -%patch217 -p1 -%patch218 -p1 -%patch219 -p1 -%patch220 -p1 -%patch221 -p1 -%patch222 -p1 -%patch223 -p1 -%patch224 -p1 -%patch225 -p1 -%patch226 -p1 -%patch227 -p1 - -%patch301 -p1 -%patch302 -p1 -%patch303 -p1 -%patch304 -p1 -%patch305 -p1 -%patch306 -p1 -%patch307 -p1 -%patch308 -p1 -%patch309 -p1 -%patch310 -p1 -%patch311 -p1 -%patch312 -p1 -%patch313 -p1 -%patch314 -p1 -%patch315 -p1 -%patch316 -p1 -%patch317 -p1 -%patch318 -p1 -%patch319 -p1 -%patch320 -p1 -%patch321 -p1 -%patch322 -p1 -%patch323 -p1 -%patch324 -p1 -%patch325 -p1 -%patch326 -p1 -%patch327 -p1 -%patch328 -p1 -%patch329 -p1 -%patch330 -p1 -%patch331 -p1 -%patch332 -p1 -%patch333 -p1 -%patch334 -p1 -%patch335 -p1 -%patch336 -p1 -%patch337 -p1 -%patch338 -p1 -%patch339 -p1 -%patch340 -p1 -%patch341 -p1 -%patch342 -p1 -%patch343 -p1 -%patch344 -p1 -%patch345 -p1 -%patch346 -p1 -%patch347 -p1 -%patch348 -p1 -%patch349 -p1 -%patch350 -p1 -%patch351 -p1 -%patch352 -p1 -%patch353 -p1 -%patch354 -p1 -%patch355 -p1 -%patch356 -p1 -%patch357 -p1 -%patch358 -p1 -%patch359 -p1 -%patch360 -p1 -%patch361 -p1 -%patch362 -p1 -%patch363 -p1 -%patch364 -p1 -%patch365 -p1 -%patch366 -p1 -%patch367 -p1 -%patch368 -p1 -%patch369 -p1 -%patch370 -p1 -%patch371 -p1 -%patch372 -p1 - -%patch900 -p1 +%patch0001 -p1 +%patch0002 -p1 +%patch0003 -p1 +%patch0004 -p1 +%patch0005 -p1 +%patch0006 -p1 +%patch0007 -p1 +%patch0008 -p1 +%patch0009 -p1 +%patch0010 -p1 +%patch0011 -p1 +%patch0012 -p1 +%patch0013 -p1 +%patch0014 -p1 +%patch0015 -p1 +%patch0016 -p1 +%patch0017 -p1 +%patch0018 -p1 +%patch0019 -p1 +%patch0020 -p1 +%patch0021 -p1 +%patch0022 -p1 +%patch0023 -p1 +%patch0024 -p1 +%patch0025 -p1 +%patch0026 -p1 +%patch0027 -p1 +%patch0028 -p1 +%patch0029 -p1 +%patch0030 -p1 +%patch0031 -p1 +%patch0032 -p1 +%patch0033 -p1 +%patch0034 -p1 +%patch0035 -p1 +%patch0036 -p1 +%patch0037 -p1 +%patch0038 -p1 +%patch0039 -p1 +%patch0040 -p1 +%patch0041 -p1 +%patch0042 -p1 +%patch0043 -p1 +%patch0044 -p1 +%patch0045 -p1 +%patch0046 -p1 +%patch0047 -p1 +%patch0048 -p1 +%patch0049 -p1 +%patch0050 -p1 +%patch0051 -p1 +%patch0052 -p1 +%patch0053 -p1 +%patch0054 -p1 +%patch0055 -p1 +%patch0056 -p1 +%patch0057 -p1 +%patch0058 -p1 +%patch0059 -p1 +%patch0060 -p1 +%patch0061 -p1 +%patch0062 -p1 +%patch0063 -p1 +%patch0064 -p1 +%patch0065 -p1 +%patch0066 -p1 +%patch0067 -p1 +%patch0068 -p1 +%patch0069 -p1 +%patch0070 -p1 +%patch0071 -p1 +%patch0072 -p1 +%patch0073 -p1 +%patch0074 -p1 +%patch0075 -p1 +%patch0076 -p1 +%patch0077 -p1 +%patch0078 -p1 +%patch0079 -p1 +%patch0080 -p1 +%patch0081 -p1 +%patch0082 -p1 +%patch0083 -p1 +%patch0084 -p1 +%patch0085 -p1 +%patch0086 -p1 +%patch0087 -p1 +%patch0088 -p1 +%patch0089 -p1 +%patch0090 -p1 +%patch0091 -p1 +%patch0092 -p1 +%patch0093 -p1 +%patch0094 -p1 +%patch0095 -p1 +%patch0096 -p1 +%patch0097 -p1 +%patch0098 -p1 +%patch0099 -p1 +%patch0100 -p1 +%patch0101 -p1 +%patch0102 -p1 +%patch0103 -p1 +%patch0104 -p1 +%patch0105 -p1 +%patch0106 -p1 +%patch0107 -p1 +%patch0108 -p1 +%patch0109 -p1 +%patch0110 -p1 +%patch0111 -p1 +%patch0112 -p1 +%patch0113 -p1 +%patch0114 -p1 +%patch0115 -p1 +%patch0116 -p1 +%patch0117 -p1 +%patch0118 -p1 +%patch0119 -p1 +%patch0120 -p1 +%patch0121 -p1 +%patch0122 -p1 +%patch0123 -p1 +%patch0124 -p1 +%patch0125 -p1 +%patch0126 -p1 +%patch0127 -p1 +%patch0128 -p1 +%patch0129 -p1 +%patch0130 -p1 +%patch0131 -p1 +%patch0132 -p1 +%patch0133 -p1 +%patch0134 -p1 +%patch0135 -p1 +%patch0136 -p1 +%patch0137 -p1 +%patch0138 -p1 +%patch0139 -p1 +%patch0140 -p1 +%patch0141 -p1 +%patch0142 -p1 +%patch0143 -p1 +%patch0144 -p1 +%patch0145 -p1 +%patch0146 -p1 +%patch0147 -p1 +%patch0148 -p1 +%patch0149 -p1 +%patch0150 -p1 +%patch0151 -p1 +%patch0152 -p1 +%patch0153 -p1 +%patch0154 -p1 +%patch0155 -p1 +%patch0156 -p1 +%patch0157 -p1 +%patch0158 -p1 +%patch0159 -p1 +%patch0160 -p1 +%patch0161 -p1 +%patch0162 -p1 +%patch0163 -p1 +%patch0164 -p1 +%patch0165 -p1 +%patch0166 -p1 +%patch0167 -p1 +%patch0168 -p1 +%patch0169 -p1 +%patch0170 -p1 +%patch0171 -p1 +%patch0172 -p1 +%patch0173 -p1 +%patch0174 -p1 +%patch0175 -p1 +%patch0176 -p1 +%patch0177 -p1 +%patch0178 -p1 +%patch0179 -p1 +%patch0180 -p1 +%patch0181 -p1 +%patch0182 -p1 +%patch0183 -p1 +%patch0184 -p1 +%patch0185 -p1 +%patch0186 -p1 +%patch0187 -p1 +%patch0188 -p1 +%patch0189 -p1 +%patch0190 -p1 +%patch0191 -p1 +%patch0192 -p1 +%patch0193 -p1 +%patch0194 -p1 +%patch0195 -p1 +%patch0196 -p1 +%patch0197 -p1 +%patch0198 -p1 +%patch0199 -p1 +%patch0200 -p1 +%patch0201 -p1 +%patch0202 -p1 +%patch0203 -p1 +%patch0204 -p1 +%patch0205 -p1 +%patch0206 -p1 +%patch0207 -p1 +%patch0208 -p1 +%patch0209 -p1 +%patch0210 -p1 +%patch0211 -p1 +%patch0212 -p1 +%patch0213 -p1 +%patch0214 -p1 +%patch0215 -p1 +%patch0216 -p1 +%patch0217 -p1 +%patch0218 -p1 +%patch0219 -p1 +%patch0220 -p1 +%patch0221 -p1 +%patch0222 -p1 +%patch0223 -p1 +%patch0224 -p1 +%patch0225 -p1 +%patch0226 -p1 +%patch0227 -p1 +%patch0228 -p1 +%patch0229 -p1 +%patch0230 -p1 +%patch0231 -p1 +%patch0232 -p1 +%patch0233 -p1 +%patch0234 -p1 +%patch0235 -p1 +%patch0236 -p1 +%patch0237 -p1 +%patch0238 -p1 +%patch0239 -p1 +%patch0240 -p1 +%patch0241 -p1 +%patch0242 -p1 + +%patch0400 -p1 +%patch0401 -p1 +%patch0402 -p1 +%patch0403 -p1 +%patch0404 -p1 +%patch0405 -p1 +%patch0406 -p1 +%patch0407 -p1 +%patch0408 -p1 +%patch0409 -p1 +%patch0410 -p1 +%patch0411 -p1 +%patch0412 -p1 + +%patch0500 -p1 +%patch0501 -p1 +%patch0502 -p1 +%patch0503 -p1 +%patch0504 -p1 +%patch0505 -p1 +%patch0506 -p1 +%patch0507 -p1 +%patch0508 -p1 +%patch0509 -p1 +%patch0510 -p1 +%patch0511 -p1 +%patch0512 -p1 +%patch0513 -p1 + +%patch0600 -p1 +%patch0601 -p1 +%patch0602 -p1 +%patch0603 -p1 +%patch0604 -p1 +%patch0605 -p1 +%patch0606 -p1 +%patch0607 -p1 +%patch0608 -p1 +%patch0609 -p1 +%patch0610 -p1 +%patch0611 -p1 +%patch0612 -p1 +%patch0613 -p1 +%patch0614 -p1 +%patch0615 -p1 +%patch0616 -p1 +%patch0617 -p1 +%patch0618 -p1 +%patch0619 -p1 +%patch0620 -p1 +%patch0621 -p1 +%patch0622 -p1 +%patch0623 -p1 +%patch0624 -p1 +%patch0625 -p1 +%patch0626 -p1 +%patch0627 -p1 +%patch0628 -p1 +%patch0629 -p1 +%patch0630 -p1 +%patch0631 -p1 +%patch0632 -p1 +%patch0633 -p1 +%patch0634 -p1 + +%patch0800 -p1 +%patch0801 -p1 %build @@ -1416,6 +1790,9 @@ fi %{_mandir}/man1/qemu-img.1* %changelog +* Sun Oct 28 2012 Cole Robinson - 2:1.2.0-17 +- Pull patches queued for qemu 1.2.1 + * Fri Oct 19 2012 Paolo Bonzini - 2:1.2.0-16 - add s390x KVM support - distribute pre-built firmware or device trees for Alpha, Microblaze, S390