diff options
author | 2011-02-09 12:05:42 +0200 | |
---|---|---|
committer | 2011-02-09 12:05:42 +0200 | |
commit | 71f62bd7770688f4404df19694f50204475e15a6 (patch) | |
tree | 2816e8866cf511f7c8357e27b740df2f171fd089 | |
parent | updated flush to 0.9.9, added patched qbittorrent (diff) | |
download | wish-71f62bd7770688f4404df19694f50204475e15a6.tar.gz wish-71f62bd7770688f4404df19694f50204475e15a6.tar.bz2 wish-71f62bd7770688f4404df19694f50204475e15a6.zip |
Removed obsolete playonlinux; added qemu-0.13 with Red Hat patches to support SPICE and QXL :)
-rw-r--r-- | app-emulation/playonlinux/Manifest | 2 | ||||
-rw-r--r-- | app-emulation/playonlinux/playonlinux-3.8.3.ebuild | 90 | ||||
-rw-r--r-- | app-emulation/qemu-kvm/ChangeLog | 301 | ||||
-rw-r--r-- | app-emulation/qemu-kvm/Manifest | 10 | ||||
-rw-r--r-- | app-emulation/qemu-kvm/files/qemu-0.11.0-mips64-user-fix.patch | 11 | ||||
-rw-r--r-- | app-emulation/qemu-kvm/files/qemu-kvm | 2 | ||||
-rw-r--r-- | app-emulation/qemu-kvm/files/qemu-kvm-0.12.3-fix-crash-with-sdl.patch | 145 | ||||
-rw-r--r-- | app-emulation/qemu-kvm/files/qemu-kvm-0.12.3-include-madvise-defines.patch | 12 | ||||
-rw-r--r-- | app-emulation/qemu-kvm/files/qemu-kvm-0.13.0-redhat-patches.patch | 11648 | ||||
-rw-r--r-- | app-emulation/qemu-kvm/files/qemu-kvm-guest-hang-on-usb-add.patch | 100 | ||||
-rw-r--r-- | app-emulation/qemu-kvm/metadata.xml | 26 | ||||
-rw-r--r-- | app-emulation/qemu-kvm/qemu-kvm-0.13.0-r99.ebuild | 261 |
12 files changed, 12516 insertions, 92 deletions
diff --git a/app-emulation/playonlinux/Manifest b/app-emulation/playonlinux/Manifest deleted file mode 100644 index b7036a4..0000000 --- a/app-emulation/playonlinux/Manifest +++ /dev/null @@ -1,2 +0,0 @@ -DIST PlayOnLinux_3.8.3.tar.gz 2309646 RMD160 1a23a219a96c81d3d1f12e42c4e583cb151575b7 SHA1 e2e89fdbaa6feafb956e4b5b02ce4ac0c95f739e SHA256 ca84d080e5d6f11c43c754543289125c56162c8c5a9d9b3f128ea71a7f378763 -EBUILD playonlinux-3.8.3.ebuild 2621 RMD160 3f7884d4667659d39ea45abb27f92aae403e69bb SHA1 3a2d96d5568b589920c57d4e0bcafe724baaa2a4 SHA256 210969b2f4d9d7648946e23f928c880b16e3f59bdf2ab709c4959f477ceb97f2 diff --git a/app-emulation/playonlinux/playonlinux-3.8.3.ebuild b/app-emulation/playonlinux/playonlinux-3.8.3.ebuild deleted file mode 100644 index 2531738..0000000 --- a/app-emulation/playonlinux/playonlinux-3.8.3.ebuild +++ /dev/null @@ -1,90 +0,0 @@ -# Copyright 1999-2010 Gentoo Foundation -# Distributed under the terms of the GNU General Public License v2 - -EAPI="2" - -inherit eutils python games - -MY_PN="PlayOnLinux" - -DESCRIPTION="Set of scripts to easily install and use Windows(tm) games and softwares" -HOMEPAGE="http://playonlinux.com/" -SRC_URI="http://www.playonlinux.com/script_files/${MY_PN}/${PV}/${MY_PN}_${PV}.tar.gz" - -LICENSE="GPL-3" -SLOT="0" -KEYWORDS="~amd64 ~x86" -IUSE="" - -DEPEND="" -RDEPEND="app-emulation/wine - app-arch/cabextract - app-arch/unzip - dev-python/wxpython:2.8 - || ( media-gfx/imagemagick media-gfx/graphicsmagick[imagemagick] ) - x11-apps/mesa-progs - x11-terms/xterm" - -S=${WORKDIR}/${PN} - -# TODO: -# Having a real install script and let playonlinux use standard filesystem -# architecture to prevent having everything installed into GAMES_DATADIR -# It will let using LANGUAGES easily -# How to deal with Microsoft Fonts installation asked every time ? -# How to deal with wine version installed ? (have a better mgmt of system one) -# Look at debian pkg: http://packages.debian.org/sid/playonlinux - -src_prepare() { - einfo "Removing temporary files..." - rm -f $(find . -name *.pyc) || die "rm -f doesn't die" - rm -f $(find . -name *~) || die "rm -f doesn't die" -} - -src_install() { - # all things without exec permissions - insinto "${GAMES_DATADIR}/${PN}" - doins -r themes lang lib etc || die "doins failed" - - # bash/ bash/terminals/ bash/expert/ python/ install - for dir in 'bash' 'bash/terminals' 'bash/expert' 'python' - do - exeinto "${GAMES_DATADIR}/${PN}/${dir}" - doexe ${dir}/* || die "doexe failed for ${dir}" - done - - # lib/ python/lib/ plugins/ install - for dir in 'lib' 'python/lib' 'plugins' - do - insinto "${GAMES_DATADIR}/${PN}/${dir}" - doins ${dir}/* || die "doexe failed for ${dir}" - done - - # main executable files - exeinto "${GAMES_DATADIR}/${PN}" - doexe ${PN}{,-pkg,-daemon,-cmd,-shell} || die "doexe failed" - - # making a script to run app from ${GAMES_BINDIR} - echo "#!/bin/bash" > ${PN}_launcher - echo "cd \"${GAMES_DATADIR}/${PN}\" && ./${PN}" >> ${PN}_launcher - newgamesbin playonlinux_launcher playonlinux || die "newgamesbin failed" - - dodoc CHANGELOG || die "dodoc failed" - - doicon etc/${PN}.png || die "doicon failed" - domenu etc/${MY_PN}.desktop || die "domenu failed" - prepgamesdirs -} - -pkg_postinst() { - games_pkg_postinst - python_mod_optimize "${GAMES_DATADIR}/${PN}" -} - -pkg_postrm() { - python_mod_cleanup "${GAMES_DATADIR}/${PN}" - - ewarn "Installed softwares and games with playonlinux have not been removed." - ewarn "To remove them, you can re-install playonlinux and remove them using it" - ewarn "or do it manually." -} diff --git a/app-emulation/qemu-kvm/ChangeLog b/app-emulation/qemu-kvm/ChangeLog new file mode 100644 index 0000000..c3c0b53 --- /dev/null +++ b/app-emulation/qemu-kvm/ChangeLog @@ -0,0 +1,301 @@ +# ChangeLog for app-emulation/qemu-kvm +# Copyright 1999-2011 Gentoo Foundation; Distributed under the GPL v2 +# $Header: /var/cvsroot/gentoo-x86/app-emulation/qemu-kvm/ChangeLog,v 1.50 2011/01/21 13:49:43 dev-zero Exp $ + + 21 Jan 2011; Tiziano Müller <dev-zero@gentoo.org> qemu-kvm-9999.ebuild, + metadata.xml: + spice (resp. the QXL graphics device) support has been finally merged at + qemu-upstream, added a USE flag for it. Added USE flags to toggle vhost-net + support (which requires newer kernel-headers) and rados block device storage + backend support. + + 17 Jan 2011; Jory A. Pratt <anarchy@gentoo.org> qemu-kvm-0.13.0-r1.ebuild, + qemu-kvm-0.13.0-r2.ebuild, qemu-kvm-9999.ebuild: + convert to virtual/jpeg instead of forcing media-libs/jpeg + + 05 Jan 2011; Markos Chandras <hwoarang@gentoo.org> qemu-kvm-0.13.0-r2.ebuild: + Stable on amd64 wrt bug #346681 + + 25 Nov 2010; Christian Faulhammer <fauli@gentoo.org> + qemu-kvm-0.13.0-r2.ebuild: + stable x86, bug 346681 + +*qemu-kvm-0.13.0-r2 (03 Nov 2010) + + 03 Nov 2010; Jorge Manuel B. S. Vicetto <jmbsvicetto@gentoo.org> + -qemu-kvm-0.11.1-r1.ebuild, + -files/qemu-kvm-0.12.2-virtio-large-iovecs.patch, + -qemu-kvm-0.12.3-r1.ebuild, -qemu-kvm-0.12.4-r1.ebuild, + -files/qemu-kvm-0.12.4-large-virtio-corruption.patch, + -qemu-kvm-0.13.0.ebuild, qemu-kvm-0.13.0-r1.ebuild, + +qemu-kvm-0.13.0-r2.ebuild, metadata.xml: + Fixed the non installation of binaries due to a bad variable declaration - + bug 343951. + Updated dtc dep to fix the build failures on amd64 - bug 339044. + Restricted parallel build until we fix it - bug 343175. + Dropped old ebuilds and files. + +*qemu-kvm-0.13.0-r1 (02 Nov 2010) + + 02 Nov 2010; Jorge Manuel B. S. Vicetto <jmbsvicetto@gentoo.org> + -files/qemu-kvm-0.12.1-kvm_save_mpstate-workaround.patch, + -qemu-kvm-0.12.5.ebuild, +qemu-kvm-0.13.0-r1.ebuild, qemu-kvm-9999.ebuild, + +files/qemu-kvm-guest-hang-on-usb-add.patch: + Synced the qemu-kvm-0.13.0-r1 ebuild with qemu-kvm-9999 ebuild. + Added missing jpeg and png use flags. Dropped the non-existent kvm-trace + use flag - fixes bug 343317. + Moved some checks from pkg_setup to src_configure. Applied the fix to the + $(prefix)/etc issue. + Dropped unused qemu-kvm-0.12.1-kvm_save_mpstate-workaround.patch file - + fixes bug 340727. + Included patch file to fix issues with usb, bug 337988 , but won't use it + until upstream commits it to the git tree or gives an ok. + Dropped old version. + +*qemu-kvm-0.13.0 (28 Oct 2010) + + 28 Oct 2010; Luca Barbato <lu_zero@gentoo.org> +qemu-kvm-0.13.0.ebuild: + New version, user targets support improved + + 06 Sep 2010; Jorge Manuel B. S. Vicetto <jmbsvicetto@gentoo.org> + qemu-kvm-9999.ebuild: + [app-emulation/qemu-kvm-9999] Synced to latest qemu-kvm-0.12.5-r1. + Sorted IUSE flags. + + 06 Sep 2010; Jorge Manuel B. S. Vicetto <jmbsvicetto@gentoo.org> + qemu-kvm-0.12.5-r1.ebuild, metadata.xml: + [app-emulation/qemu-kvm-0.12.5-r1] Synced the updates on qemu-kvm-9999. + Applied the gnutls to ssl use flag change - fixes bug 311627. + + 06 Sep 2010; Luca Barbato <lu_zero@gentoo.org> qemu-kvm-0.12.5-r1.ebuild: + Fix typo in brltty vs brlapi + + 06 Sep 2010; Patrick Lauer <patrick@gentoo.org> qemu-kvm-0.12.5-r1.ebuild: + Removing keywords from 0.12.5-r1 until it is fixed. See #336162 + + 06 Sep 2010; Jorge Manuel B. S. Vicetto <jmbsvicetto@gentoo.org> + qemu-kvm-9999.ebuild: + [app-emulation/qemu-kvm-9999] Updated ebuild to reflect changes in + upstream's build system. + Added use flags to enable jpeg and png compression on vnc. + Replaced gnu-tls with ssl use flag - bug 311627. + Added use flag to make accessbility support optional - bug 326491. + Currently it seems qemu-kvm won't build with -sasl - will check and + updated ebuild soon. + + 06 Sep 2010; Luca Barbato <lu_zero@gentoo.org> qemu-kvm-0.12.5-r1.ebuild, + qemu-kvm-9999.ebuild: + Add dep for brltty, see #326491 + +*qemu-kvm-0.12.5-r1 (26 Aug 2010) + + 26 Aug 2010; Doug Goldstein <cardoe@gentoo.org> + +qemu-kvm-0.12.5-r1.ebuild: + Fix a few IDE issues related to the -drive option. fixes #332993 + + 12 Aug 2010; Tiziano Müller <dev-zero@gentoo.org> + qemu-kvm-0.11.1-r1.ebuild, qemu-kvm-0.12.3-r1.ebuild, + qemu-kvm-0.12.4-r1.ebuild, qemu-kvm-0.12.5.ebuild, qemu-kvm-9999.ebuild: + Disallow parallel installation with qemu-kvm-spice. + + 05 Aug 2010; Doug Goldstein <cardoe@gentoo.org> -qemu-kvm-0.11.1.ebuild, + -qemu-kvm-0.12.3.ebuild, -qemu-kvm-0.12.4.ebuild, + -qemu-kvm-0.12.4-r2.ebuild, -qemu-kvm-0.12.4-r3.ebuild, + qemu-kvm-0.12.5.ebuild: + Remove older versions. Remove versions with broken epatch line. Fix epatch + line for future versions + +*qemu-kvm-0.12.5 (27 Jul 2010) + + 27 Jul 2010; Doug Goldstein <cardoe@gentoo.org> +qemu-kvm-0.12.5.ebuild: + bump for upstream release + +*qemu-kvm-0.12.4-r3 (20 Jul 2010) + + 20 Jul 2010; Doug Goldstein <cardoe@gentoo.org> + +qemu-kvm-0.12.4-r3.ebuild: + Missed an upstream patch for bug #325209 in the -r2 version + +*qemu-kvm-0.12.4-r2 (20 Jul 2010) + + 20 Jul 2010; Doug Goldstein <cardoe@gentoo.org> + +qemu-kvm-0.12.4-r2.ebuild: + Pull in a lot of stable patches from upstream stable repos. + + 30 Jun 2010; Harald van Dijk <truedfx@gentoo.org> qemu-kvm-0.11.1.ebuild, + qemu-kvm-0.11.1-r1.ebuild, qemu-kvm-0.12.3.ebuild, + qemu-kvm-0.12.3-r1.ebuild, qemu-kvm-0.12.4.ebuild, + qemu-kvm-0.12.4-r1.ebuild, qemu-kvm-9999.ebuild: + Fix quoting + +*qemu-kvm-0.12.4-r1 (15 Jun 2010) + + 15 Jun 2010; Doug Goldstein <cardoe@gentoo.org> + +qemu-kvm-0.12.4-r1.ebuild, + +files/qemu-kvm-0.12.4-large-virtio-corruption.patch: + Fix issue with large virtio disks getting corrupted. bug #321005 + + 12 Jun 2010; Jorge Manuel B. S. Vicetto <jmbsvicetto@gentoo.org> + qemu-kvm-9999.ebuild: + [app-emulation/qemu-kvm-9999] Restricted targets to x86_64-softmmu after + upstream informed that's the only supported target for qemu-kvm. + Should fix bug 317205 and bug 318413. + +*qemu-kvm-0.12.4 (18 May 2010) + + 18 May 2010; Thomas Sachau (Tommy[D]) <tommy@gentoo.org> + -qemu-kvm-0.12.2-r2.ebuild, +qemu-kvm-0.12.4.ebuild: + Version bump + +*qemu-kvm-0.12.3-r1 (03 Apr 2010) + + 03 Apr 2010; Thomas Sachau (Tommy[D]) <tommy@gentoo.org> + +qemu-kvm-0.12.3-r1.ebuild, + +files/qemu-kvm-0.12.3-fix-crash-with-sdl.patch, + +files/qemu-kvm-0.12.3-include-madvise-defines.patch: + Include madvise defines, fixes bug 305785, include virtio-large-iovecs + patch, fixes bug 308451, include upstream fix for crash with sdl as + default sound option, fixes sound issues of bug 294269 + + 28 Mar 2010; Jorge Manuel B. S. Vicetto <jmbsvicetto@gentoo.org> + qemu-kvm-9999.ebuild, -files/qemu-kvm-9999-sysconfigdir.patch: + Remove the sysconfigdir patch from qemu-kvm-9999 as the fix was applied + upstream. + Fixes bug 310979 - thanks to Jeff Kowalczyk <jtk@yahoo.com>. + + 19 Mar 2010; Thomas Sachau (Tommy[D]) <tommy@gentoo.org> + qemu-kvm-0.12.2-r2.ebuild, qemu-kvm-0.12.3.ebuild: + Also add warning and dont install useless files without + QEMU_SOFTMMU_TARGETS=x86_64 + + 19 Mar 2010; Thomas Sachau (Tommy[D]) <tommy@gentoo.org> + qemu-kvm-0.12.2-r2.ebuild, qemu-kvm-0.12.3.ebuild: + Die, when nothing from QEMU_SOFTMMU_TARGETS is defined, fixes bug 310243 + + 10 Mar 2010; Thomas Sachau (Tommy[D]) <tommy@gentoo.org> + qemu-kvm-0.12.2-r2.ebuild: + Also apply changes to 0.12.2-r2 + + 10 Mar 2010; Thomas Sachau (Tommy[D]) <tommy@gentoo.org> + -qemu-kvm-0.12.1.ebuild, -qemu-kvm-0.12.1.1.ebuild, + -qemu-kvm-0.12.1.2.ebuild, -qemu-kvm-0.12.2.ebuild, + -qemu-kvm-0.12.2-r1.ebuild, qemu-kvm-0.12.3.ebuild: + Add message, if no targets are defined (bug #298287), some cleanup, remove + older 0.12* versions + + 07 Mar 2010; Jorge Manuel B. S. Vicetto <jmbsvicetto@gentoo.org> + qemu-kvm-9999.ebuild, +files/qemu-kvm-9999-sysconfigdir.patch: + Added a patch to fix the support for --sysconfdir and updated + src_configure to prevent the default $prefix/etc. + +*qemu-kvm-0.12.3 (02 Mar 2010) + + 02 Mar 2010; Doug Goldstein <cardoe@gentoo.org> +qemu-kvm-0.12.3.ebuild, + qemu-kvm-9999.ebuild, metadata.xml: + version bump. fix bug #304097 in the process + +*qemu-kvm-0.12.2-r2 (15 Feb 2010) + + 15 Feb 2010; Doug Goldstein <cardoe@gentoo.org> + +qemu-kvm-0.12.2-r2.ebuild, qemu-kvm-9999.ebuild: + Correct building with the right compiler (tc-getBUILD_CC). Fix issue with + executable stacks by passing correct LDFLAGS option. Add support for + static builds. Fix issue with fdt being disabled, bug #297909 + + 12 Feb 2010; Doug Goldstein <cardoe@gentoo.org> qemu-kvm-0.11.1.ebuild, + qemu-kvm-0.11.1-r1.ebuild, qemu-kvm-0.12.1.ebuild, + qemu-kvm-0.12.1.1.ebuild, qemu-kvm-0.12.1.2.ebuild, + qemu-kvm-0.12.2.ebuild, qemu-kvm-0.12.2-r1.ebuild: + add missing depend on sys-apps/iproute2 and net-misc/bridge-utils for the + qemu/ifup script + +*qemu-kvm-0.11.1-r1 (08 Feb 2010) + + 08 Feb 2010; Lance Albertson <ramereth@gentoo.org> + +qemu-kvm-0.11.1-r1.ebuild: + Add 'kvm' symlink so that other applications can still use it for + portability + +*qemu-kvm-0.12.2-r1 (03 Feb 2010) + + 03 Feb 2010; Doug Goldstein <cardoe@gentoo.org> + +qemu-kvm-0.12.2-r1.ebuild, + +files/qemu-kvm-0.12.2-virtio-large-iovecs.patch: + upstream fix for virtio and certain use cases. Fixes issues people have + seen with Ubuntu 10.04 guests and other distros + +*qemu-kvm-0.12.2 (21 Jan 2010) + + 21 Jan 2010; Doug Goldstein <cardoe@gentoo.org> +qemu-kvm-0.12.2.ebuild, + -qemu-kvm-0.12.2.build: + fix awesome typo + + 20 Jan 2010; Doug Goldstein <cardoe@gentoo.org> +qemu-kvm-0.12.2.build: + version bump + +*qemu-kvm-0.12.1.2 (31 Dec 2009) + + 31 Dec 2009; Jorge Manuel B. S. Vicetto <jmbsvicetto@gentoo.org> + qemu-kvm-0.12.1.1.ebuild, +qemu-kvm-0.12.1.2.ebuild, qemu-kvm-9999.ebuild: + Version bump. + +*qemu-kvm-9999 (30 Dec 2009) + + 30 Dec 2009; Jorge Manuel B. S. Vicetto <jmbsvicetto@gentoo.org> + qemu-kvm-0.12.1.1.ebuild, +qemu-kvm-9999.ebuild: + Added live qemu-kvm ebuild and sorted 0.12.1.1 deps. + + 29 Dec 2009; Christian Faulhammer <fauli@gentoo.org> metadata.xml: + Write out acronym ftd, as requested on bug 298906 by Michael Orlitzky + <michael AT orlitzky DOT com> + + 23 Dec 2009; Doug Goldstein <cardoe@gentoo.org> qemu-kvm-0.12.1.ebuild, + qemu-kvm-0.12.1.1.ebuild: + Xen backend support is broken in this release. Upstream is looking into + it. + +*qemu-kvm-0.12.1.1 (22 Dec 2009) + + 22 Dec 2009; Thomas Sachau (Tommy[D]) <tommy@gentoo.org> + +qemu-kvm-0.12.1.1.ebuild: + Version bump + + 21 Dec 2009; Doug Goldstein <cardoe@gentoo.org> qemu-kvm-0.12.1.ebuild: + Add Linux Async IO support. Add curl support for live migrations. Add back + support for fdt. Add support for KVM trace. Enable experimental support + for Xen backend. Use libuuid to generate proper uuid's. Fix compile failure + when missing paxctl. No longer require kernel to be present to build. + +*qemu-kvm-0.12.1 (21 Dec 2009) + + 21 Dec 2009; Thomas Sachau (Tommy[D]) <tommy@gentoo.org> + -qemu-kvm-0.11.0.ebuild, +qemu-kvm-0.12.1.ebuild, + +files/qemu-kvm-0.12.1-kvm_save_mpstate-workaround.patch: + Version bump, drop old version + + 18 Dec 2009; Thomas Sachau (Tommy[D]) <tommy@gentoo.org> + qemu-kvm-0.11.1.ebuild: + Comment out pie and stack-protector filtering, remove with next version, + if there are no complains + + 15 Dec 2009; Doug Goldstein <cardoe@gentoo.org> metadata.xml: + change to qemu herd + +*qemu-kvm-0.11.1 (09 Dec 2009) + + 09 Dec 2009; Luca Barbato <lu_zero@gentoo.org> +qemu-kvm-0.11.1.ebuild: + Version Bump + + 22 Nov 2009; Doug Goldstein <cardoe@gentoo.org> qemu-kvm-0.11.0.ebuild: + fix bug #291007 and install the ifup and ifdown scripts in the correct + locations + + 22 Nov 2009; Doug Goldstein <cardoe@gentoo.org> qemu-kvm-0.11.0.ebuild: + fix auto-magical depend against sasl + +*qemu-kvm-0.11.0 (22 Nov 2009) + + 22 Nov 2009; Doug Goldstein <cardoe@gentoo.org> +qemu-kvm-0.11.0.ebuild, + +files/qemu-0.11.0-mips64-user-fix.patch, +metadata.xml: + add initial ebuild based on qemu-0.11.0 + diff --git a/app-emulation/qemu-kvm/Manifest b/app-emulation/qemu-kvm/Manifest new file mode 100644 index 0000000..52506b5 --- /dev/null +++ b/app-emulation/qemu-kvm/Manifest @@ -0,0 +1,10 @@ +AUX qemu-0.11.0-mips64-user-fix.patch 313 RMD160 db016e0a48990a435dd6cf6e807145b33ada4908 SHA1 2ea913b1bcd29734a6d4011794bdb4aa3599a184 SHA256 b4173fc177bd0d0ba67f5551a3512047a19a9b2c0a122f968e32fbd834848d2f +AUX qemu-kvm 61 RMD160 83882e881a067065258f562ad1e60440666c85d3 SHA1 a965f19031e303d583bd541c9d8fff2214262e6b SHA256 211d51f0a7d3d2ba8c53016c75e2b483feadbb65e383b1eec81d9cebf6a22c29 +AUX qemu-kvm-0.12.3-fix-crash-with-sdl.patch 4003 RMD160 1e8965e94537e24d0903a7a096c91e35f7013118 SHA1 a6a36da9613d90d45148aa133392bd342b83d1cd SHA256 aeca9f133c021726c0e3ce2a58843ee12d592669143d0b75e46b8e301b5cf102 +AUX qemu-kvm-0.12.3-include-madvise-defines.patch 274 RMD160 2b2b454fabc3b5362c0479d581e5fb038e02aa97 SHA1 c34b51b9c0b5a69ab2ab7a8a64c804f7cbbbebf5 SHA256 0d33d22a853e9b1d19786c9ac53a515587a9753ff69a2f53e61c4764590e7821 +AUX qemu-kvm-0.13.0-redhat-patches.patch 352789 RMD160 8c64efeefd64ed0ac214a4ce494ddf93f41589a9 SHA1 11b027b11dc1707fbaae3b8552bee90fdc31c77d SHA256 1858b6f6afdec4e487af20c78f420403982d92a972624a937de978bb551e0251 +AUX qemu-kvm-guest-hang-on-usb-add.patch 3491 RMD160 7bc186c283b0eb220a47895f7cab50e191f1a3ea SHA1 00f36fd0197fa9d359e28a9ef2f56a1ee860fddf SHA256 d3068a419d69dbe44758830509fc13460d1497b14a5a10ffad910552da0c86b3 +DIST qemu-kvm-0.13.0.tar.gz 5153895 RMD160 7b8f4d8cdbb9730bb9d7fbf4cec165a8703696c4 SHA1 b8cfb8e8dbd403281a98a41f7d3eeaecc0aac8f1 SHA256 6db2600d7e3c1ed12feb6dc7596c23324bc2036a72f101cf580cef252ea9be53 +EBUILD qemu-kvm-0.13.0-r99.ebuild 8016 RMD160 31eddf30b690f05fd4d7bf61a04d62ab2ece2c71 SHA1 81015d90b4757689127eed0818e025a18c2d943d SHA256 50e8ef47050e48ef5e63f65a4adc80e8642ddffc37eab867a59d5f63ba44dc71 +MISC ChangeLog 11813 RMD160 a0d94b7b78f7f95155b76d710256abc04c0433d8 SHA1 60f4e896a64057a78431895df414a30691032118 SHA256 190cc1ff57d22594397b23014442ac048203703747a105d3909bf0379334990b +MISC metadata.xml 1556 RMD160 8437c7ce85708abae6fa308da974a4bbf14e59fd SHA1 367e2957602139dc897a6379981537fb748a5f71 SHA256 a5675e07f50148cf3d8b76924d417fae0ed6d2d08a03133e4929659c98acd750 diff --git a/app-emulation/qemu-kvm/files/qemu-0.11.0-mips64-user-fix.patch b/app-emulation/qemu-kvm/files/qemu-0.11.0-mips64-user-fix.patch new file mode 100644 index 0000000..c069f89 --- /dev/null +++ b/app-emulation/qemu-kvm/files/qemu-0.11.0-mips64-user-fix.patch @@ -0,0 +1,11 @@ +--- qemu-0.11.0.orig/linux-user/main.c 2009-10-23 02:19:57.000000000 +0200 ++++ qemu-0.11.0/linux-user/main.c 2009-10-23 02:47:09.000000000 +0200 +@@ -1469,6 +1469,8 @@ + + #ifdef TARGET_MIPS + ++#define TARGET_QEMU_ESIGRETURN 255 ++ + #define MIPS_SYS(name, args) args, + + static const uint8_t mips_syscall_args[] = { diff --git a/app-emulation/qemu-kvm/files/qemu-kvm b/app-emulation/qemu-kvm/files/qemu-kvm new file mode 100644 index 0000000..844147d --- /dev/null +++ b/app-emulation/qemu-kvm/files/qemu-kvm @@ -0,0 +1,2 @@ +#!/bin/sh +exec /usr/bin/qemu-system-x86_64 --enable-kvm "$@" diff --git a/app-emulation/qemu-kvm/files/qemu-kvm-0.12.3-fix-crash-with-sdl.patch b/app-emulation/qemu-kvm/files/qemu-kvm-0.12.3-fix-crash-with-sdl.patch new file mode 100644 index 0000000..909dead --- /dev/null +++ b/app-emulation/qemu-kvm/files/qemu-kvm-0.12.3-fix-crash-with-sdl.patch @@ -0,0 +1,145 @@ +From ff5414990645653bf43bf64adfc1ca77ffb9edcb Mon Sep 17 00:00:00 2001 +From: malc <av1474@comtv.ru> +Date: Sun, 17 Jan 2010 00:25:29 +0300 +Subject: [PATCH] Revert "sdlaudio: make it suck less" + +This reverts commit 4839abe78fd466a3cf06faa7c362154afd5404f1. + +The commit was badly broken, Gentoo has sdl as the default driver, +consequently 5 gentoo users have hit the breakage and were kind enough +to report, so thank you: + +Claes Gyllenswrd +vekin +Chris + +But above all thanks to Toralf Foerster who actually provied enough +information to pinpoint the breakage to sdlaudio. + +http://bugs.gentoo.org/show_bug.cgi?id=294269 +--- + audio/sdlaudio.c | 80 +++++++++++++++++++++++++++++++++-------------------- + 1 files changed, 50 insertions(+), 30 deletions(-) + +diff --git a/audio/sdlaudio.c b/audio/sdlaudio.c +index aa39c33..8e7e5cb 100644 +--- a/audio/sdlaudio.c ++++ b/audio/sdlaudio.c +@@ -41,8 +41,8 @@ + typedef struct SDLVoiceOut { + HWVoiceOut hw; + int live; ++ int rpos; + int decr; +- int pending; + } SDLVoiceOut; + + static struct { +@@ -225,10 +225,6 @@ static void sdl_callback (void *opaque, Uint8 *buf, int len) + HWVoiceOut *hw = &sdl->hw; + int samples = len >> hw->info.shift; + +- if (sdl_lock (s, "sdl_callback")) { +- return; +- } +- + if (s->exit) { + return; + } +@@ -236,34 +232,49 @@ static void sdl_callback (void *opaque, Uint8 *buf, int len) + while (samples) { + int to_mix, decr; + +- while (!sdl->pending) { +- if (sdl_unlock (s, "sdl_callback")) { +- return; +- } +- +- sdl_wait (s, "sdl_callback"); +- if (s->exit) { +- return; +- } +- +- if (sdl_lock (s, "sdl_callback")) { +- return; +- } +- sdl->pending += sdl->live; +- sdl->live = 0; ++ /* dolog ("in callback samples=%d\n", samples); */ ++ sdl_wait (s, "sdl_callback"); ++ if (s->exit) { ++ return; ++ } ++ ++ if (sdl_lock (s, "sdl_callback")) { ++ return; ++ } ++ ++ if (audio_bug (AUDIO_FUNC, sdl->live < 0 || sdl->live > hw->samples)) { ++ dolog ("sdl->live=%d hw->samples=%d\n", ++ sdl->live, hw->samples); ++ return; ++ } ++ ++ if (!sdl->live) { ++ goto again; + } + +- to_mix = audio_MIN (samples, sdl->pending); +- decr = audio_pcm_hw_clip_out (hw, buf, to_mix, 0); +- buf += decr << hw->info.shift; ++ /* dolog ("in callback live=%d\n", live); */ ++ to_mix = audio_MIN (samples, sdl->live); ++ decr = to_mix; ++ while (to_mix) { ++ int chunk = audio_MIN (to_mix, hw->samples - hw->rpos); ++ struct st_sample *src = hw->mix_buf + hw->rpos; ++ ++ /* dolog ("in callback to_mix %d, chunk %d\n", to_mix, chunk); */ ++ hw->clip (buf, src, chunk); ++ sdl->rpos = (sdl->rpos + chunk) % hw->samples; ++ to_mix -= chunk; ++ buf += chunk << hw->info.shift; ++ } + samples -= decr; ++ sdl->live -= decr; + sdl->decr += decr; +- sdl->pending -= decr; +- } + +- if (sdl_unlock (s, "sdl_callback")) { +- return; ++ again: ++ if (sdl_unlock (s, "sdl_callback")) { ++ return; ++ } + } ++ /* dolog ("done len=%d\n", len); */ + } + + static int sdl_write_out (SWVoiceOut *sw, void *buf, int len) +@@ -281,9 +292,18 @@ static int sdl_run_out (HWVoiceOut *hw, int live) + return 0; + } + +- sdl->live = live; +- decr = sdl->decr; +- sdl->decr = 0; ++ if (sdl->decr > live) { ++ ldebug ("sdl->decr %d live %d sdl->live %d\n", ++ sdl->decr, ++ live, ++ sdl->live); ++ } ++ ++ decr = audio_MIN (sdl->decr, live); ++ sdl->decr -= decr; ++ ++ sdl->live = live - decr; ++ hw->rpos = sdl->rpos; + + if (sdl->live > 0) { + sdl_unlock_and_post (s, "sdl_run_out"); +-- +1.7.0.4 + diff --git a/app-emulation/qemu-kvm/files/qemu-kvm-0.12.3-include-madvise-defines.patch b/app-emulation/qemu-kvm/files/qemu-kvm-0.12.3-include-madvise-defines.patch new file mode 100644 index 0000000..c50c717 --- /dev/null +++ b/app-emulation/qemu-kvm/files/qemu-kvm-0.12.3-include-madvise-defines.patch @@ -0,0 +1,12 @@ +--- exec.c 2010-02-26 03:34:00.000000000 +0100 ++++ exec.c.new 2010-04-03 15:31:53.000000000 +0200 +@@ -22,6 +22,9 @@ + #else + #include <sys/types.h> + #include <sys/mman.h> ++#ifndef MADV_MERGEABLE ++#include <asm/mman.h> ++#endif + #endif + #include <stdlib.h> + #include <stdio.h> diff --git a/app-emulation/qemu-kvm/files/qemu-kvm-0.13.0-redhat-patches.patch b/app-emulation/qemu-kvm/files/qemu-kvm-0.13.0-redhat-patches.patch new file mode 100644 index 0000000..e63388d --- /dev/null +++ b/app-emulation/qemu-kvm/files/qemu-kvm-0.13.0-redhat-patches.patch @@ -0,0 +1,11648 @@ +diff -urN qemu-kvm-0.13.0.orig/audio/audio.c qemu-kvm-0.13.0/audio/audio.c +--- qemu-kvm-0.13.0.orig/audio/audio.c 2011-02-09 11:01:45.805000327 +0200 ++++ qemu-kvm-0.13.0/audio/audio.c 2011-02-09 11:08:02.779000327 +0200 +@@ -44,6 +44,9 @@ + that we generate the list. + */ + static struct audio_driver *drvtab[] = { ++#ifdef CONFIG_SPICE ++ &spice_audio_driver, ++#endif + CONFIG_AUDIO_DRIVERS + &no_audio_driver, + &wav_audio_driver +diff -urN qemu-kvm-0.13.0.orig/audio/audio_int.h qemu-kvm-0.13.0/audio/audio_int.h +--- qemu-kvm-0.13.0.orig/audio/audio_int.h 2011-02-09 11:01:45.806000327 +0200 ++++ qemu-kvm-0.13.0/audio/audio_int.h 2011-02-09 11:08:02.780000327 +0200 +@@ -209,6 +209,7 @@ + extern struct audio_driver dsound_audio_driver; + extern struct audio_driver esd_audio_driver; + extern struct audio_driver pa_audio_driver; ++extern struct audio_driver spice_audio_driver; + extern struct audio_driver winwave_audio_driver; + extern struct mixeng_volume nominal_volume; + +diff -urN qemu-kvm-0.13.0.orig/audio/spiceaudio.c qemu-kvm-0.13.0/audio/spiceaudio.c +--- qemu-kvm-0.13.0.orig/audio/spiceaudio.c 1970-01-01 02:00:00.000000000 +0200 ++++ qemu-kvm-0.13.0/audio/spiceaudio.c 2011-02-09 11:08:02.781000327 +0200 +@@ -0,0 +1,312 @@ ++#include "hw/hw.h" ++#include "qemu-timer.h" ++#include "qemu-spice.h" ++ ++#define AUDIO_CAP "spice" ++#include "audio.h" ++#include "audio_int.h" ++ ++#define LINE_IN_SAMPLES 1024 ++#define LINE_OUT_SAMPLES 1024 ++ ++typedef struct SpiceVoiceOut { ++ HWVoiceOut hw; ++ SpicePlaybackInstance sin; ++ int64_t prev_ticks; ++ int active; ++ uint32_t *frame; ++ uint32_t *fpos; ++ uint32_t fsize; ++} SpiceVoiceOut; ++ ++typedef struct SpiceVoiceIn { ++ HWVoiceIn hw; ++ SpiceRecordInstance sin; ++ int64_t prev_ticks; ++ int active; ++ uint32_t samples[LINE_IN_SAMPLES]; ++} SpiceVoiceIn; ++ ++static const SpicePlaybackInterface playback_sif = { ++ .base.type = SPICE_INTERFACE_PLAYBACK, ++ .base.description = "playback", ++ .base.major_version = SPICE_INTERFACE_PLAYBACK_MAJOR, ++ .base.minor_version = SPICE_INTERFACE_PLAYBACK_MINOR, ++}; ++ ++static const SpiceRecordInterface record_sif = { ++ .base.type = SPICE_INTERFACE_RECORD, ++ .base.description = "record", ++ .base.major_version = SPICE_INTERFACE_RECORD_MAJOR, ++ .base.minor_version = SPICE_INTERFACE_RECORD_MINOR, ++}; ++ ++static void *spice_audio_init(void) ++{ ++ if (!using_spice) { ++ return NULL; ++ } ++ return &spice_audio_init; ++} ++ ++static void spice_audio_fini(void *opaque) ++{ ++ /* nothing */ ++} ++ ++static int calculate_samples(struct audio_pcm_info *info, int64_t *old_ticks) ++{ ++ int64_t now; ++ int64_t ticks; ++ int64_t bytes; ++ int samples; ++ ++ now = qemu_get_clock (vm_clock); ++ ticks = now - *old_ticks; ++ *old_ticks = now; ++ bytes = muldiv64 (ticks, info->bytes_per_second, get_ticks_per_sec ()); ++ bytes = audio_MIN (bytes, INT_MAX); ++ samples = bytes >> info->shift; ++ return samples; ++} ++ ++/* playback */ ++ ++static int line_out_init(HWVoiceOut *hw, struct audsettings *as) ++{ ++ SpiceVoiceOut *out = container_of(hw, SpiceVoiceOut, hw); ++ struct audsettings settings; ++ ++ settings.freq = SPICE_INTERFACE_PLAYBACK_FREQ; ++ settings.nchannels = SPICE_INTERFACE_PLAYBACK_CHAN; ++ settings.fmt = AUD_FMT_S16; ++ settings.endianness = AUDIO_HOST_ENDIANNESS; ++ ++ audio_pcm_init_info(&hw->info, &settings); ++ hw->samples = LINE_OUT_SAMPLES; ++ out->active = 0; ++ ++ out->sin.base.sif = &playback_sif.base; ++ spice_server_add_interface(spice_server, &out->sin.base); ++ return 0; ++} ++ ++static void line_out_fini(HWVoiceOut *hw) ++{ ++ SpiceVoiceOut *out = container_of(hw, SpiceVoiceOut, hw); ++ ++ spice_server_remove_interface(&out->sin.base); ++} ++ ++static int line_out_run(HWVoiceOut *hw, int live) ++{ ++ SpiceVoiceOut *out = container_of(hw, SpiceVoiceOut, hw); ++ int rpos, decr; ++ int samples; ++ ++ if (!live) { ++ return 0; ++ } ++ ++ decr = calculate_samples(&hw->info, &out->prev_ticks); ++ decr = audio_MIN(live, decr); ++ ++ samples = decr; ++ rpos = hw->rpos; ++ while (samples) { ++ int left_till_end_samples = hw->samples - rpos; ++ int len = audio_MIN(samples, left_till_end_samples); ++ ++ if (!out->frame) { ++ spice_server_playback_get_buffer(&out->sin, &out->frame, &out->fsize); ++ out->fpos = out->frame; ++ } ++ if (out->frame) { ++ len = audio_MIN(len, out->fsize); ++ hw->clip(out->fpos, hw->mix_buf + rpos, len); ++ out->fsize -= len; ++ out->fpos += len; ++ if (out->fsize == 0) { ++ spice_server_playback_put_samples(&out->sin, out->frame); ++ out->frame = out->fpos = NULL; ++ } ++ } ++ rpos = (rpos + len) % hw->samples; ++ samples -= len; ++ } ++ hw->rpos = rpos; ++ return decr; ++} ++ ++static int line_out_write(SWVoiceOut *sw, void *buf, int len) ++{ ++ return audio_pcm_sw_write(sw, buf, len); ++} ++ ++static int line_out_ctl(HWVoiceOut *hw, int cmd, ...) ++{ ++ SpiceVoiceOut *out = container_of(hw, SpiceVoiceOut, hw); ++ ++ switch (cmd) { ++ case VOICE_ENABLE: ++ if (out->active) { ++ break; ++ } ++ out->active = 1; ++ out->prev_ticks = qemu_get_clock (vm_clock); ++ spice_server_playback_start(&out->sin); ++ break; ++ case VOICE_DISABLE: ++ if (!out->active) { ++ break; ++ } ++ out->active = 0; ++ if (out->frame) { ++ memset(out->fpos, 0, out->fsize << 2); ++ spice_server_playback_put_samples(&out->sin, out->frame); ++ out->frame = out->fpos = NULL; ++ } ++ spice_server_playback_stop(&out->sin); ++ break; ++ } ++ return 0; ++} ++ ++/* record */ ++ ++static int line_in_init(HWVoiceIn *hw, struct audsettings *as) ++{ ++ SpiceVoiceIn *in = container_of(hw, SpiceVoiceIn, hw); ++ struct audsettings settings; ++ ++ settings.freq = SPICE_INTERFACE_RECORD_FREQ; ++ settings.nchannels = SPICE_INTERFACE_RECORD_CHAN; ++ settings.fmt = AUD_FMT_S16; ++ settings.endianness = AUDIO_HOST_ENDIANNESS; ++ ++ audio_pcm_init_info(&hw->info, &settings); ++ hw->samples = LINE_IN_SAMPLES; ++ in->active = 0; ++ ++ in->sin.base.sif = &record_sif.base; ++ spice_server_add_interface(spice_server, &in->sin.base); ++ return 0; ++} ++ ++static void line_in_fini(HWVoiceIn *hw) ++{ ++ SpiceVoiceIn *in = container_of(hw, SpiceVoiceIn, hw); ++ ++ spice_server_remove_interface(&in->sin.base); ++} ++ ++static int line_in_run(HWVoiceIn *hw) ++{ ++ SpiceVoiceIn *in = container_of(hw, SpiceVoiceIn, hw); ++ int num_samples; ++ int ready; ++ int len[2]; ++ uint64_t delta_samp; ++ uint32_t *samples; ++ ++ if (!(num_samples = hw->samples - audio_pcm_hw_get_live_in(hw))) { ++ return 0; ++ } ++ ++ delta_samp = calculate_samples(&hw->info, &in->prev_ticks); ++ num_samples = audio_MIN(num_samples, delta_samp); ++ ++ ready = spice_server_record_get_samples(&in->sin, in->samples, num_samples); ++ samples = in->samples; ++ if (ready == 0) { ++ static uint32_t silence[LINE_IN_SAMPLES]; ++ samples = silence; ++ ready = LINE_IN_SAMPLES; ++ } ++ ++ num_samples = audio_MIN(ready, num_samples); ++ ++ if (hw->wpos + num_samples > hw->samples) { ++ len[0] = hw->samples - hw->wpos; ++ len[1] = num_samples - len[0]; ++ } else { ++ len[0] = num_samples; ++ len[1] = 0; ++ } ++ ++ hw->conv(hw->conv_buf + hw->wpos, samples, len[0], &nominal_volume); ++ ++ if (len[1]) { ++ hw->conv(hw->conv_buf, samples + len[0], len[1], ++ &nominal_volume); ++ } ++ ++ hw->wpos = (hw->wpos + num_samples) % hw->samples; ++ ++ return num_samples; ++} ++ ++static int line_in_read(SWVoiceIn *sw, void *buf, int size) ++{ ++ return audio_pcm_sw_read(sw, buf, size); ++} ++ ++static int line_in_ctl(HWVoiceIn *hw, int cmd, ...) ++{ ++ SpiceVoiceIn *in = container_of(hw, SpiceVoiceIn, hw); ++ ++ switch (cmd) { ++ case VOICE_ENABLE: ++ if (in->active) { ++ break; ++ } ++ in->active = 1; ++ in->prev_ticks = qemu_get_clock (vm_clock); ++ spice_server_record_start(&in->sin); ++ break; ++ case VOICE_DISABLE: ++ if (!in->active) { ++ break; ++ } ++ in->active = 0; ++ spice_server_record_stop(&in->sin); ++ break; ++ } ++ return 0; ++} ++ ++static struct audio_option audio_options[] = { ++ { /* end of list */ }, ++}; ++ ++static struct audio_pcm_ops audio_callbacks = { ++ .init_out = line_out_init, ++ .fini_out = line_out_fini, ++ .run_out = line_out_run, ++ .write = line_out_write, ++ .ctl_out = line_out_ctl, ++ ++ .init_in = line_in_init, ++ .fini_in = line_in_fini, ++ .run_in = line_in_run, ++ .read = line_in_read, ++ .ctl_in = line_in_ctl, ++}; ++ ++struct audio_driver spice_audio_driver = { ++ .name = "spice", ++ .descr = "spice audio driver", ++ .options = audio_options, ++ .init = spice_audio_init, ++ .fini = spice_audio_fini, ++ .pcm_ops = &audio_callbacks, ++ .max_voices_out = 1, ++ .max_voices_in = 1, ++ .voice_size_out = sizeof(SpiceVoiceOut), ++ .voice_size_in = sizeof(SpiceVoiceIn), ++}; ++ ++void qemu_spice_audio_init(void) ++{ ++ spice_audio_driver.can_be_default = 1; ++} +diff -urN qemu-kvm-0.13.0.orig/configure qemu-kvm-0.13.0/configure +--- qemu-kvm-0.13.0.orig/configure 2011-02-09 11:01:45.652000327 +0200 ++++ qemu-kvm-0.13.0/configure 2011-02-09 11:08:02.704000327 +0200 +@@ -16,15 +16,18 @@ + TMPE="${TMPDIR1}/qemu-conf-${RANDOM}-$$-${RANDOM}.exe" + + trap "rm -f $TMPC $TMPO $TMPE ; exit" EXIT INT QUIT TERM ++rm -f config.log + + compile_object() { +- $cc $QEMU_CFLAGS -c -o $TMPO $TMPC > /dev/null 2> /dev/null ++ echo $cc $QEMU_CFLAGS -c -o $TMPO $TMPC >> config.log ++ $cc $QEMU_CFLAGS -c -o $TMPO $TMPC >> config.log 2>&1 + } + + compile_prog() { + local_cflags="$1" + local_ldflags="$2" +- $cc $QEMU_CFLAGS $local_cflags -o $TMPE $TMPC $LDFLAGS $local_ldflags > /dev/null 2> /dev/null ++ echo $cc $QEMU_CFLAGS $local_cflags -o $TMPE $TMPC $LDFLAGS $local_ldflags >> config.log ++ $cc $QEMU_CFLAGS $local_cflags -o $TMPE $TMPC $LDFLAGS $local_ldflags >> config.log 2>&1 + } + + # check whether a command is available to this shell (may be either an +@@ -328,6 +331,7 @@ + check_utests="no" + user_pie="no" + zero_malloc="" ++spice="" + + # OS specific + if check_define __linux__ ; then +@@ -644,6 +648,10 @@ + ;; + --enable-kvm-device-assignment) kvm_cap_device_assignment="yes" + ;; ++ --disable-spice) spice="no" ++ ;; ++ --enable-spice) spice="yes" ++ ;; + --enable-profiler) profiler="yes" + ;; + --enable-cocoa) +@@ -930,6 +938,8 @@ + echo " --disable-docs disable documentation build" + echo " --disable-vhost-net disable vhost-net acceleration support" + echo " --enable-vhost-net enable vhost-net acceleration support" ++echo " --disable-spice disable spice" ++echo " --enable-spice enable spice" + echo "" + echo "NOTE: The object files are built at the place where configure is launched" + exit 1 +@@ -2181,6 +2191,30 @@ + gcc_attribute_warn_unused_result=yes + fi + ++# spice probe ++if test "$spice" != "no" ; then ++ cat > $TMPC << EOF ++#include <spice.h> ++int main(void) { spice_server_new(); return 0; } ++EOF ++ spice_proto_ver=$($pkgconfig --modversion spice-protocol 2>/dev/null) ++ spice_server_ver=$($pkgconfig --modversion spice-server 2>/dev/null) ++ spice_cflags=$($pkgconfig --cflags spice-protocol spice-server 2>/dev/null) ++ spice_libs=$($pkgconfig --libs spice-protocol spice-server 2>/dev/null) ++ if compile_prog "$spice_cflags" "$spice_libs" ; then ++ spice="yes" ++ libs_softmmu="$libs_softmmu $spice_libs" ++ QEMU_CFLAGS="$QEMU_CFLAGS $spice_cflags" ++ else ++ if test "$spice" = "yes" ; then ++ feature_not_found "spice" ++ fi ++ spice="no" ++ fi ++fi ++ ++########################################## ++ + ########################################## + # check if we have fdatasync + +@@ -2326,6 +2360,7 @@ + echo "fdatasync $fdatasync" + echo "uuid support $uuid" + echo "vhost-net support $vhost_net" ++echo "spice support $spice" + + if test $sdl_too_old = "yes"; then + echo "-> Your SDL version is too old - please upgrade to have SDL support" +@@ -2571,6 +2606,10 @@ + echo "CONFIG_NO_CPU_EMULATION=y" >> $config_host_mak + fi + ++if test "$spice" = "yes" ; then ++ echo "CONFIG_SPICE=y" >> $config_host_mak ++fi ++ + # XXX: suppress that + if [ "$bsd" = "yes" ] ; then + echo "CONFIG_BSD=y" >> $config_host_mak +diff -urN qemu-kvm-0.13.0.orig/hw/cirrus_vga.c qemu-kvm-0.13.0/hw/cirrus_vga.c +--- qemu-kvm-0.13.0.orig/hw/cirrus_vga.c 2011-02-09 11:01:45.879000328 +0200 ++++ qemu-kvm-0.13.0/hw/cirrus_vga.c 2011-02-09 11:08:02.752000327 +0200 +@@ -3206,6 +3206,10 @@ + uint8_t *pci_conf = d->dev.config; + int device_id = CIRRUS_ID_CLGD5446; + ++ if (dev->qdev.hotplugged) { ++ return -1; ++ } ++ + /* setup VGA */ + vga_common_init(&s->vga, VGA_RAM_SIZE); + cirrus_init_common(s, device_id, 1); +diff -urN qemu-kvm-0.13.0.orig/hw/hw.h qemu-kvm-0.13.0/hw/hw.h +--- qemu-kvm-0.13.0.orig/hw/hw.h 2011-02-09 11:01:45.837000328 +0200 ++++ qemu-kvm-0.13.0/hw/hw.h 2011-02-09 11:08:02.763000327 +0200 +@@ -530,6 +530,17 @@ + .start = (_start), \ + } + ++#define VMSTATE_VBUFFER_UINT32(_field, _state, _version, _test, _start, _field_size) { \ ++ .name = (stringify(_field)), \ ++ .version_id = (_version), \ ++ .field_exists = (_test), \ ++ .size_offset = vmstate_offset_value(_state, _field_size, uint32_t),\ ++ .info = &vmstate_info_buffer, \ ++ .flags = VMS_VBUFFER|VMS_POINTER, \ ++ .offset = offsetof(_state, _field), \ ++ .start = (_start), \ ++} ++ + #define VMSTATE_BUFFER_UNSAFE_INFO(_field, _state, _version, _info, _size) { \ + .name = (stringify(_field)), \ + .version_id = (_version), \ +@@ -744,6 +755,9 @@ + #define VMSTATE_PARTIAL_VBUFFER(_f, _s, _size) \ + VMSTATE_VBUFFER(_f, _s, 0, NULL, 0, _size) + ++#define VMSTATE_PARTIAL_VBUFFER_UINT32(_f, _s, _size) \ ++ VMSTATE_VBUFFER_UINT32(_f, _s, 0, NULL, 0, _size) ++ + #define VMSTATE_SUB_VBUFFER(_f, _s, _start, _size) \ + VMSTATE_VBUFFER(_f, _s, 0, NULL, _start, _size) + +diff -urN qemu-kvm-0.13.0.orig/hw/hw.h.orig qemu-kvm-0.13.0/hw/hw.h.orig +--- qemu-kvm-0.13.0.orig/hw/hw.h.orig 1970-01-01 02:00:00.000000000 +0200 ++++ qemu-kvm-0.13.0/hw/hw.h.orig 2011-02-09 11:07:32.609000328 +0200 +@@ -0,0 +1,800 @@ ++/* Declarations for use by hardware emulation. */ ++#ifndef QEMU_HW_H ++#define QEMU_HW_H ++ ++#include "qemu-common.h" ++ ++#if defined(TARGET_PHYS_ADDR_BITS) && !defined(NEED_CPU_H) ++#include "cpu-common.h" ++#endif ++ ++#include "ioport.h" ++#include "irq.h" ++ ++/* VM Load/Save */ ++ ++/* This function writes a chunk of data to a file at the given position. ++ * The pos argument can be ignored if the file is only being used for ++ * streaming. The handler should try to write all of the data it can. ++ */ ++typedef int (QEMUFilePutBufferFunc)(void *opaque, const uint8_t *buf, ++ int64_t pos, int size); ++ ++/* Read a chunk of data from a file at the given position. The pos argument ++ * can be ignored if the file is only be used for streaming. The number of ++ * bytes actually read should be returned. ++ */ ++typedef int (QEMUFileGetBufferFunc)(void *opaque, uint8_t *buf, ++ int64_t pos, int size); ++ ++/* Close a file and return an error code */ ++typedef int (QEMUFileCloseFunc)(void *opaque); ++ ++/* Called to determine if the file has exceeded it's bandwidth allocation. The ++ * bandwidth capping is a soft limit, not a hard limit. ++ */ ++typedef int (QEMUFileRateLimit)(void *opaque); ++ ++/* Called to change the current bandwidth allocation. This function must return ++ * the new actual bandwidth. It should be new_rate if everything goes ok, and ++ * the old rate otherwise ++ */ ++typedef size_t (QEMUFileSetRateLimit)(void *opaque, size_t new_rate); ++typedef size_t (QEMUFileGetRateLimit)(void *opaque); ++ ++QEMUFile *qemu_fopen_ops(void *opaque, QEMUFilePutBufferFunc *put_buffer, ++ QEMUFileGetBufferFunc *get_buffer, ++ QEMUFileCloseFunc *close, ++ QEMUFileRateLimit *rate_limit, ++ QEMUFileSetRateLimit *set_rate_limit, ++ QEMUFileGetRateLimit *get_rate_limit); ++QEMUFile *qemu_fopen(const char *filename, const char *mode); ++QEMUFile *qemu_fdopen(int fd, const char *mode); ++QEMUFile *qemu_fopen_socket(int fd); ++QEMUFile *qemu_popen(FILE *popen_file, const char *mode); ++QEMUFile *qemu_popen_cmd(const char *command, const char *mode); ++int qemu_stdio_fd(QEMUFile *f); ++void qemu_fflush(QEMUFile *f); ++int qemu_fclose(QEMUFile *f); ++void qemu_put_buffer(QEMUFile *f, const uint8_t *buf, int size); ++void qemu_put_byte(QEMUFile *f, int v); ++ ++static inline void qemu_put_ubyte(QEMUFile *f, unsigned int v) ++{ ++ qemu_put_byte(f, (int)v); ++} ++ ++#define qemu_put_sbyte qemu_put_byte ++ ++void qemu_put_be16(QEMUFile *f, unsigned int v); ++void qemu_put_be32(QEMUFile *f, unsigned int v); ++void qemu_put_be64(QEMUFile *f, uint64_t v); ++int qemu_get_buffer(QEMUFile *f, uint8_t *buf, int size); ++int qemu_get_byte(QEMUFile *f); ++ ++static inline unsigned int qemu_get_ubyte(QEMUFile *f) ++{ ++ return (unsigned int)qemu_get_byte(f); ++} ++ ++#define qemu_get_sbyte qemu_get_byte ++ ++unsigned int qemu_get_be16(QEMUFile *f); ++unsigned int qemu_get_be32(QEMUFile *f); ++uint64_t qemu_get_be64(QEMUFile *f); ++int qemu_file_rate_limit(QEMUFile *f); ++size_t qemu_file_set_rate_limit(QEMUFile *f, size_t new_rate); ++size_t qemu_file_get_rate_limit(QEMUFile *f); ++int qemu_file_has_error(QEMUFile *f); ++void qemu_file_set_error(QEMUFile *f); ++ ++/* Try to send any outstanding data. This function is useful when output is ++ * halted due to rate limiting or EAGAIN errors occur as it can be used to ++ * resume output. */ ++void qemu_file_put_notify(QEMUFile *f); ++ ++static inline void qemu_put_be64s(QEMUFile *f, const uint64_t *pv) ++{ ++ qemu_put_be64(f, *pv); ++} ++ ++static inline void qemu_put_be32s(QEMUFile *f, const uint32_t *pv) ++{ ++ qemu_put_be32(f, *pv); ++} ++ ++static inline void qemu_put_be16s(QEMUFile *f, const uint16_t *pv) ++{ ++ qemu_put_be16(f, *pv); ++} ++ ++static inline void qemu_put_8s(QEMUFile *f, const uint8_t *pv) ++{ ++ qemu_put_byte(f, *pv); ++} ++ ++static inline void qemu_get_be64s(QEMUFile *f, uint64_t *pv) ++{ ++ *pv = qemu_get_be64(f); ++} ++ ++static inline void qemu_get_be32s(QEMUFile *f, uint32_t *pv) ++{ ++ *pv = qemu_get_be32(f); ++} ++ ++static inline void qemu_get_be16s(QEMUFile *f, uint16_t *pv) ++{ ++ *pv = qemu_get_be16(f); ++} ++ ++static inline void qemu_get_8s(QEMUFile *f, uint8_t *pv) ++{ ++ *pv = qemu_get_byte(f); ++} ++ ++// Signed versions for type safety ++static inline void qemu_put_sbuffer(QEMUFile *f, const int8_t *buf, int size) ++{ ++ qemu_put_buffer(f, (const uint8_t *)buf, size); ++} ++ ++static inline void qemu_put_sbe16(QEMUFile *f, int v) ++{ ++ qemu_put_be16(f, (unsigned int)v); ++} ++ ++static inline void qemu_put_sbe32(QEMUFile *f, int v) ++{ ++ qemu_put_be32(f, (unsigned int)v); ++} ++ ++static inline void qemu_put_sbe64(QEMUFile *f, int64_t v) ++{ ++ qemu_put_be64(f, (uint64_t)v); ++} ++ ++static inline size_t qemu_get_sbuffer(QEMUFile *f, int8_t *buf, int size) ++{ ++ return qemu_get_buffer(f, (uint8_t *)buf, size); ++} ++ ++static inline int qemu_get_sbe16(QEMUFile *f) ++{ ++ return (int)qemu_get_be16(f); ++} ++ ++static inline int qemu_get_sbe32(QEMUFile *f) ++{ ++ return (int)qemu_get_be32(f); ++} ++ ++static inline int64_t qemu_get_sbe64(QEMUFile *f) ++{ ++ return (int64_t)qemu_get_be64(f); ++} ++ ++static inline void qemu_put_s8s(QEMUFile *f, const int8_t *pv) ++{ ++ qemu_put_8s(f, (const uint8_t *)pv); ++} ++ ++static inline void qemu_put_sbe16s(QEMUFile *f, const int16_t *pv) ++{ ++ qemu_put_be16s(f, (const uint16_t *)pv); ++} ++ ++static inline void qemu_put_sbe32s(QEMUFile *f, const int32_t *pv) ++{ ++ qemu_put_be32s(f, (const uint32_t *)pv); ++} ++ ++static inline void qemu_put_sbe64s(QEMUFile *f, const int64_t *pv) ++{ ++ qemu_put_be64s(f, (const uint64_t *)pv); ++} ++ ++static inline void qemu_get_s8s(QEMUFile *f, int8_t *pv) ++{ ++ qemu_get_8s(f, (uint8_t *)pv); ++} ++ ++static inline void qemu_get_sbe16s(QEMUFile *f, int16_t *pv) ++{ ++ qemu_get_be16s(f, (uint16_t *)pv); ++} ++ ++static inline void qemu_get_sbe32s(QEMUFile *f, int32_t *pv) ++{ ++ qemu_get_be32s(f, (uint32_t *)pv); ++} ++ ++static inline void qemu_get_sbe64s(QEMUFile *f, int64_t *pv) ++{ ++ qemu_get_be64s(f, (uint64_t *)pv); ++} ++ ++#ifdef NEED_CPU_H ++#if TARGET_LONG_BITS == 64 ++#define qemu_put_betl qemu_put_be64 ++#define qemu_get_betl qemu_get_be64 ++#define qemu_put_betls qemu_put_be64s ++#define qemu_get_betls qemu_get_be64s ++#define qemu_put_sbetl qemu_put_sbe64 ++#define qemu_get_sbetl qemu_get_sbe64 ++#define qemu_put_sbetls qemu_put_sbe64s ++#define qemu_get_sbetls qemu_get_sbe64s ++#else ++#define qemu_put_betl qemu_put_be32 ++#define qemu_get_betl qemu_get_be32 ++#define qemu_put_betls qemu_put_be32s ++#define qemu_get_betls qemu_get_be32s ++#define qemu_put_sbetl qemu_put_sbe32 ++#define qemu_get_sbetl qemu_get_sbe32 ++#define qemu_put_sbetls qemu_put_sbe32s ++#define qemu_get_sbetls qemu_get_sbe32s ++#endif ++#endif ++ ++int64_t qemu_ftell(QEMUFile *f); ++int64_t qemu_fseek(QEMUFile *f, int64_t pos, int whence); ++ ++typedef void SaveSetParamsHandler(int blk_enable, int shared, void * opaque); ++typedef void SaveStateHandler(QEMUFile *f, void *opaque); ++typedef int SaveLiveStateHandler(Monitor *mon, QEMUFile *f, int stage, ++ void *opaque); ++typedef int LoadStateHandler(QEMUFile *f, void *opaque, int version_id); ++ ++int register_savevm(DeviceState *dev, ++ const char *idstr, ++ int instance_id, ++ int version_id, ++ SaveStateHandler *save_state, ++ LoadStateHandler *load_state, ++ void *opaque); ++ ++int register_savevm_live(DeviceState *dev, ++ const char *idstr, ++ int instance_id, ++ int version_id, ++ SaveSetParamsHandler *set_params, ++ SaveLiveStateHandler *save_live_state, ++ SaveStateHandler *save_state, ++ LoadStateHandler *load_state, ++ void *opaque); ++ ++void unregister_savevm(DeviceState *dev, const char *idstr, void *opaque); ++void register_device_unmigratable(DeviceState *dev, const char *idstr, ++ void *opaque); ++ ++typedef void QEMUResetHandler(void *opaque); ++ ++void qemu_register_reset(QEMUResetHandler *func, void *opaque); ++void qemu_unregister_reset(QEMUResetHandler *func, void *opaque); ++ ++/* handler to set the boot_device order for a specific type of QEMUMachine */ ++/* return 0 if success */ ++typedef int QEMUBootSetHandler(void *opaque, const char *boot_devices); ++void qemu_register_boot_set(QEMUBootSetHandler *func, void *opaque); ++int qemu_boot_set(const char *boot_devices); ++ ++typedef struct VMStateInfo VMStateInfo; ++typedef struct VMStateDescription VMStateDescription; ++ ++struct VMStateInfo { ++ const char *name; ++ int (*get)(QEMUFile *f, void *pv, size_t size); ++ void (*put)(QEMUFile *f, void *pv, size_t size); ++}; ++ ++enum VMStateFlags { ++ VMS_SINGLE = 0x001, ++ VMS_POINTER = 0x002, ++ VMS_ARRAY = 0x004, ++ VMS_STRUCT = 0x008, ++ VMS_VARRAY_INT32 = 0x010, /* Array with size in int32_t field*/ ++ VMS_BUFFER = 0x020, /* static sized buffer */ ++ VMS_ARRAY_OF_POINTER = 0x040, ++ VMS_VARRAY_UINT16 = 0x080, /* Array with size in uint16_t field */ ++ VMS_VBUFFER = 0x100, /* Buffer with size in int32_t field */ ++ VMS_MULTIPLY = 0x200, /* multiply "size" field by field_size */ ++}; ++ ++typedef struct { ++ const char *name; ++ size_t offset; ++ size_t size; ++ size_t start; ++ int num; ++ size_t num_offset; ++ size_t size_offset; ++ const VMStateInfo *info; ++ enum VMStateFlags flags; ++ const VMStateDescription *vmsd; ++ int version_id; ++ bool (*field_exists)(void *opaque, int version_id); ++} VMStateField; ++ ++typedef struct VMStateSubsection { ++ const VMStateDescription *vmsd; ++ bool (*needed)(void *opaque); ++} VMStateSubsection; ++ ++struct VMStateDescription { ++ const char *name; ++ int version_id; ++ int minimum_version_id; ++ int minimum_version_id_old; ++ LoadStateHandler *load_state_old; ++ int (*pre_load)(void *opaque); ++ int (*post_load)(void *opaque, int version_id); ++ void (*pre_save)(void *opaque); ++ VMStateField *fields; ++ const VMStateSubsection *subsections; ++}; ++ ++extern const VMStateInfo vmstate_info_int8; ++extern const VMStateInfo vmstate_info_int16; ++extern const VMStateInfo vmstate_info_int32; ++extern const VMStateInfo vmstate_info_int64; ++ ++extern const VMStateInfo vmstate_info_uint8_equal; ++extern const VMStateInfo vmstate_info_uint16_equal; ++extern const VMStateInfo vmstate_info_int32_equal; ++extern const VMStateInfo vmstate_info_int32_le; ++ ++extern const VMStateInfo vmstate_info_uint8; ++extern const VMStateInfo vmstate_info_uint16; ++extern const VMStateInfo vmstate_info_uint32; ++extern const VMStateInfo vmstate_info_uint64; ++ ++#ifdef __linux__ ++extern const VMStateInfo vmstate_info_u64; ++#endif ++ ++extern const VMStateInfo vmstate_info_timer; ++extern const VMStateInfo vmstate_info_ptimer; ++extern const VMStateInfo vmstate_info_buffer; ++extern const VMStateInfo vmstate_info_unused_buffer; ++ ++#define type_check_array(t1,t2,n) ((t1(*)[n])0 - (t2*)0) ++#define type_check_pointer(t1,t2) ((t1**)0 - (t2*)0) ++ ++#define vmstate_offset_value(_state, _field, _type) \ ++ (offsetof(_state, _field) + \ ++ type_check(_type, typeof_field(_state, _field))) ++ ++#define vmstate_offset_pointer(_state, _field, _type) \ ++ (offsetof(_state, _field) + \ ++ type_check_pointer(_type, typeof_field(_state, _field))) ++ ++#define vmstate_offset_array(_state, _field, _type, _num) \ ++ (offsetof(_state, _field) + \ ++ type_check_array(_type, typeof_field(_state, _field), _num)) ++ ++#define vmstate_offset_sub_array(_state, _field, _type, _start) \ ++ (offsetof(_state, _field[_start])) ++ ++#define vmstate_offset_buffer(_state, _field) \ ++ vmstate_offset_array(_state, _field, uint8_t, \ ++ sizeof(typeof_field(_state, _field))) ++ ++#define VMSTATE_SINGLE_TEST(_field, _state, _test, _version, _info, _type) { \ ++ .name = (stringify(_field)), \ ++ .version_id = (_version), \ ++ .field_exists = (_test), \ ++ .size = sizeof(_type), \ ++ .info = &(_info), \ ++ .flags = VMS_SINGLE, \ ++ .offset = vmstate_offset_value(_state, _field, _type), \ ++} ++ ++#define VMSTATE_POINTER(_field, _state, _version, _info, _type) { \ ++ .name = (stringify(_field)), \ ++ .version_id = (_version), \ ++ .info = &(_info), \ ++ .size = sizeof(_type), \ ++ .flags = VMS_SINGLE|VMS_POINTER, \ ++ .offset = vmstate_offset_value(_state, _field, _type), \ ++} ++ ++#define VMSTATE_ARRAY(_field, _state, _num, _version, _info, _type) {\ ++ .name = (stringify(_field)), \ ++ .version_id = (_version), \ ++ .num = (_num), \ ++ .info = &(_info), \ ++ .size = sizeof(_type), \ ++ .flags = VMS_ARRAY, \ ++ .offset = vmstate_offset_array(_state, _field, _type, _num), \ ++} ++ ++#define VMSTATE_ARRAY_TEST(_field, _state, _num, _test, _info, _type) {\ ++ .name = (stringify(_field)), \ ++ .field_exists = (_test), \ ++ .num = (_num), \ ++ .info = &(_info), \ ++ .size = sizeof(_type), \ ++ .flags = VMS_ARRAY, \ ++ .offset = vmstate_offset_array(_state, _field, _type, _num),\ ++} ++ ++#define VMSTATE_SUB_ARRAY(_field, _state, _start, _num, _version, _info, _type) { \ ++ .name = (stringify(_field)), \ ++ .version_id = (_version), \ ++ .num = (_num), \ ++ .info = &(_info), \ ++ .size = sizeof(_type), \ ++ .flags = VMS_ARRAY, \ ++ .offset = vmstate_offset_sub_array(_state, _field, _type, _start), \ ++} ++ ++#define VMSTATE_VARRAY_INT32(_field, _state, _field_num, _version, _info, _type) {\ ++ .name = (stringify(_field)), \ ++ .version_id = (_version), \ ++ .num_offset = vmstate_offset_value(_state, _field_num, int32_t), \ ++ .info = &(_info), \ ++ .size = sizeof(_type), \ ++ .flags = VMS_VARRAY_INT32|VMS_POINTER, \ ++ .offset = vmstate_offset_pointer(_state, _field, _type), \ ++} ++ ++#define VMSTATE_VARRAY_UINT16_UNSAFE(_field, _state, _field_num, _version, _info, _type) {\ ++ .name = (stringify(_field)), \ ++ .version_id = (_version), \ ++ .num_offset = vmstate_offset_value(_state, _field_num, uint16_t),\ ++ .info = &(_info), \ ++ .size = sizeof(_type), \ ++ .flags = VMS_VARRAY_UINT16, \ ++ .offset = offsetof(_state, _field), \ ++} ++ ++#define VMSTATE_STRUCT_TEST(_field, _state, _test, _version, _vmsd, _type) { \ ++ .name = (stringify(_field)), \ ++ .version_id = (_version), \ ++ .field_exists = (_test), \ ++ .vmsd = &(_vmsd), \ ++ .size = sizeof(_type), \ ++ .flags = VMS_STRUCT, \ ++ .offset = vmstate_offset_value(_state, _field, _type), \ ++} ++ ++#define VMSTATE_STRUCT_POINTER_TEST(_field, _state, _test, _vmsd, _type) { \ ++ .name = (stringify(_field)), \ ++ .field_exists = (_test), \ ++ .vmsd = &(_vmsd), \ ++ .size = sizeof(_type), \ ++ .flags = VMS_STRUCT|VMS_POINTER, \ ++ .offset = vmstate_offset_value(_state, _field, _type), \ ++} ++ ++#define VMSTATE_ARRAY_OF_POINTER(_field, _state, _num, _version, _info, _type) {\ ++ .name = (stringify(_field)), \ ++ .version_id = (_version), \ ++ .num = (_num), \ ++ .info = &(_info), \ ++ .size = sizeof(_type), \ ++ .flags = VMS_ARRAY|VMS_ARRAY_OF_POINTER, \ ++ .offset = vmstate_offset_array(_state, _field, _type, _num), \ ++} ++ ++#define VMSTATE_STRUCT_ARRAY(_field, _state, _num, _version, _vmsd, _type) { \ ++ .name = (stringify(_field)), \ ++ .num = (_num), \ ++ .version_id = (_version), \ ++ .vmsd = &(_vmsd), \ ++ .size = sizeof(_type), \ ++ .flags = VMS_STRUCT|VMS_ARRAY, \ ++ .offset = vmstate_offset_array(_state, _field, _type, _num), \ ++} ++ ++#define VMSTATE_STRUCT_VARRAY_UINT8(_field, _state, _field_num, _version, _vmsd, _type) { \ ++ .name = (stringify(_field)), \ ++ .num_offset = vmstate_offset_value(_state, _field_num, uint8_t), \ ++ .version_id = (_version), \ ++ .vmsd = &(_vmsd), \ ++ .size = sizeof(_type), \ ++ .flags = VMS_STRUCT|VMS_VARRAY_INT32, \ ++ .offset = offsetof(_state, _field), \ ++} ++ ++#define VMSTATE_STATIC_BUFFER(_field, _state, _version, _test, _start, _size) { \ ++ .name = (stringify(_field)), \ ++ .version_id = (_version), \ ++ .field_exists = (_test), \ ++ .size = (_size - _start), \ ++ .info = &vmstate_info_buffer, \ ++ .flags = VMS_BUFFER, \ ++ .offset = vmstate_offset_buffer(_state, _field) + _start, \ ++} ++ ++#define VMSTATE_BUFFER_MULTIPLY(_field, _state, _version, _test, _start, _field_size, _multiply) { \ ++ .name = (stringify(_field)), \ ++ .version_id = (_version), \ ++ .field_exists = (_test), \ ++ .size_offset = vmstate_offset_value(_state, _field_size, uint32_t),\ ++ .size = (_multiply), \ ++ .info = &vmstate_info_buffer, \ ++ .flags = VMS_VBUFFER|VMS_MULTIPLY, \ ++ .offset = offsetof(_state, _field), \ ++ .start = (_start), \ ++} ++ ++#define VMSTATE_VBUFFER(_field, _state, _version, _test, _start, _field_size) { \ ++ .name = (stringify(_field)), \ ++ .version_id = (_version), \ ++ .field_exists = (_test), \ ++ .size_offset = vmstate_offset_value(_state, _field_size, int32_t),\ ++ .info = &vmstate_info_buffer, \ ++ .flags = VMS_VBUFFER|VMS_POINTER, \ ++ .offset = offsetof(_state, _field), \ ++ .start = (_start), \ ++} ++ ++#define VMSTATE_BUFFER_UNSAFE_INFO(_field, _state, _version, _info, _size) { \ ++ .name = (stringify(_field)), \ ++ .version_id = (_version), \ ++ .size = (_size), \ ++ .info = &(_info), \ ++ .flags = VMS_BUFFER, \ ++ .offset = offsetof(_state, _field), \ ++} ++ ++#define VMSTATE_UNUSED_BUFFER(_test, _version, _size) { \ ++ .name = "unused", \ ++ .field_exists = (_test), \ ++ .version_id = (_version), \ ++ .size = (_size), \ ++ .info = &vmstate_info_unused_buffer, \ ++ .flags = VMS_BUFFER, \ ++} ++extern const VMStateDescription vmstate_pci_device; ++ ++#define VMSTATE_PCI_DEVICE(_field, _state) { \ ++ .name = (stringify(_field)), \ ++ .size = sizeof(PCIDevice), \ ++ .vmsd = &vmstate_pci_device, \ ++ .flags = VMS_STRUCT, \ ++ .offset = vmstate_offset_value(_state, _field, PCIDevice), \ ++} ++ ++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, \ ++ .offset = vmstate_offset_value(_state, _field, PCIDevice), \ ++} ++ ++extern const VMStateDescription vmstate_i2c_slave; ++ ++#define VMSTATE_I2C_SLAVE(_field, _state) { \ ++ .name = (stringify(_field)), \ ++ .size = sizeof(i2c_slave), \ ++ .vmsd = &vmstate_i2c_slave, \ ++ .flags = VMS_STRUCT, \ ++ .offset = vmstate_offset_value(_state, _field, i2c_slave), \ ++} ++ ++#define vmstate_offset_macaddr(_state, _field) \ ++ vmstate_offset_array(_state, _field.a, uint8_t, \ ++ sizeof(typeof_field(_state, _field))) ++ ++#define VMSTATE_MACADDR(_field, _state) { \ ++ .name = (stringify(_field)), \ ++ .size = sizeof(MACAddr), \ ++ .info = &vmstate_info_buffer, \ ++ .flags = VMS_BUFFER, \ ++ .offset = vmstate_offset_macaddr(_state, _field), \ ++} ++ ++/* _f : field name ++ _f_n : num of elements field_name ++ _n : num of elements ++ _s : struct state name ++ _v : version ++*/ ++ ++#define VMSTATE_SINGLE(_field, _state, _version, _info, _type) \ ++ VMSTATE_SINGLE_TEST(_field, _state, NULL, _version, _info, _type) ++ ++#define VMSTATE_STRUCT(_field, _state, _version, _vmsd, _type) \ ++ VMSTATE_STRUCT_TEST(_field, _state, NULL, _version, _vmsd, _type) ++ ++#define VMSTATE_STRUCT_POINTER(_field, _state, _vmsd, _type) \ ++ VMSTATE_STRUCT_POINTER_TEST(_field, _state, NULL, _vmsd, _type) ++ ++#define VMSTATE_INT8_V(_f, _s, _v) \ ++ VMSTATE_SINGLE(_f, _s, _v, vmstate_info_int8, int8_t) ++#define VMSTATE_INT16_V(_f, _s, _v) \ ++ VMSTATE_SINGLE(_f, _s, _v, vmstate_info_int16, int16_t) ++#define VMSTATE_INT32_V(_f, _s, _v) \ ++ VMSTATE_SINGLE(_f, _s, _v, vmstate_info_int32, int32_t) ++#define VMSTATE_INT64_V(_f, _s, _v) \ ++ VMSTATE_SINGLE(_f, _s, _v, vmstate_info_int64, int64_t) ++ ++#define VMSTATE_UINT8_V(_f, _s, _v) \ ++ VMSTATE_SINGLE(_f, _s, _v, vmstate_info_uint8, uint8_t) ++#define VMSTATE_UINT16_V(_f, _s, _v) \ ++ VMSTATE_SINGLE(_f, _s, _v, vmstate_info_uint16, uint16_t) ++#define VMSTATE_UINT32_V(_f, _s, _v) \ ++ VMSTATE_SINGLE(_f, _s, _v, vmstate_info_uint32, uint32_t) ++#define VMSTATE_UINT64_V(_f, _s, _v) \ ++ VMSTATE_SINGLE(_f, _s, _v, vmstate_info_uint64, uint64_t) ++ ++#define VMSTATE_INT8(_f, _s) \ ++ VMSTATE_INT8_V(_f, _s, 0) ++#define VMSTATE_INT16(_f, _s) \ ++ VMSTATE_INT16_V(_f, _s, 0) ++#define VMSTATE_INT32(_f, _s) \ ++ VMSTATE_INT32_V(_f, _s, 0) ++#define VMSTATE_INT64(_f, _s) \ ++ VMSTATE_INT64_V(_f, _s, 0) ++ ++#define VMSTATE_UINT8(_f, _s) \ ++ VMSTATE_UINT8_V(_f, _s, 0) ++#define VMSTATE_UINT16(_f, _s) \ ++ VMSTATE_UINT16_V(_f, _s, 0) ++#define VMSTATE_UINT32(_f, _s) \ ++ VMSTATE_UINT32_V(_f, _s, 0) ++#define VMSTATE_UINT64(_f, _s) \ ++ VMSTATE_UINT64_V(_f, _s, 0) ++ ++/* This is needed because on linux __u64 is unsigned long long ++ and on glibc uint64_t is unsigned long on 64 bits */ ++#ifdef __linux__ ++#define VMSTATE_U64_V(_f, _s, _v) \ ++ VMSTATE_SINGLE(_f, _s, _v, vmstate_info_u64, __u64) ++#define VMSTATE_U64(_f, _s) \ ++ VMSTATE_U64_V(_f, _s, 0) ++#endif ++ ++#define VMSTATE_UINT8_EQUAL(_f, _s) \ ++ VMSTATE_SINGLE(_f, _s, 0, vmstate_info_uint8_equal, uint8_t) ++ ++#define VMSTATE_UINT16_EQUAL(_f, _s) \ ++ VMSTATE_SINGLE(_f, _s, 0, vmstate_info_uint16_equal, uint16_t) ++ ++#define VMSTATE_UINT16_EQUAL_V(_f, _s, _v) \ ++ VMSTATE_SINGLE(_f, _s, _v, vmstate_info_uint16_equal, uint16_t) ++ ++#define VMSTATE_INT32_EQUAL(_f, _s) \ ++ VMSTATE_SINGLE(_f, _s, 0, vmstate_info_int32_equal, int32_t) ++ ++#define VMSTATE_INT32_LE(_f, _s) \ ++ VMSTATE_SINGLE(_f, _s, 0, vmstate_info_int32_le, int32_t) ++ ++#define VMSTATE_UINT16_TEST(_f, _s, _t) \ ++ VMSTATE_SINGLE_TEST(_f, _s, _t, 0, vmstate_info_uint16, uint16_t) ++ ++#define VMSTATE_UINT32_TEST(_f, _s, _t) \ ++ VMSTATE_SINGLE_TEST(_f, _s, _t, 0, vmstate_info_uint32, uint32_t) ++ ++#define VMSTATE_TIMER_V(_f, _s, _v) \ ++ VMSTATE_POINTER(_f, _s, _v, vmstate_info_timer, QEMUTimer *) ++ ++#define VMSTATE_TIMER(_f, _s) \ ++ VMSTATE_TIMER_V(_f, _s, 0) ++ ++#define VMSTATE_TIMER_ARRAY(_f, _s, _n) \ ++ VMSTATE_ARRAY_OF_POINTER(_f, _s, _n, 0, vmstate_info_timer, QEMUTimer *) ++ ++#define VMSTATE_PTIMER_V(_f, _s, _v) \ ++ VMSTATE_POINTER(_f, _s, _v, vmstate_info_ptimer, ptimer_state *) ++ ++#define VMSTATE_PTIMER(_f, _s) \ ++ VMSTATE_PTIMER_V(_f, _s, 0) ++ ++#define VMSTATE_UINT16_ARRAY_V(_f, _s, _n, _v) \ ++ VMSTATE_ARRAY(_f, _s, _n, _v, vmstate_info_uint16, uint16_t) ++ ++#define VMSTATE_UINT16_ARRAY(_f, _s, _n) \ ++ VMSTATE_UINT16_ARRAY_V(_f, _s, _n, 0) ++ ++#define VMSTATE_UINT8_ARRAY_V(_f, _s, _n, _v) \ ++ VMSTATE_ARRAY(_f, _s, _n, _v, vmstate_info_uint8, uint8_t) ++ ++#define VMSTATE_UINT8_ARRAY(_f, _s, _n) \ ++ VMSTATE_UINT8_ARRAY_V(_f, _s, _n, 0) ++ ++#define VMSTATE_UINT32_ARRAY_V(_f, _s, _n, _v) \ ++ VMSTATE_ARRAY(_f, _s, _n, _v, vmstate_info_uint32, uint32_t) ++ ++#define VMSTATE_UINT32_ARRAY(_f, _s, _n) \ ++ VMSTATE_UINT32_ARRAY_V(_f, _s, _n, 0) ++ ++#define VMSTATE_UINT64_ARRAY_V(_f, _s, _n, _v) \ ++ VMSTATE_ARRAY(_f, _s, _n, _v, vmstate_info_uint64, uint64_t) ++ ++#define VMSTATE_UINT64_ARRAY(_f, _s, _n) \ ++ VMSTATE_UINT64_ARRAY_V(_f, _s, _n, 0) ++ ++#define VMSTATE_INT16_ARRAY_V(_f, _s, _n, _v) \ ++ VMSTATE_ARRAY(_f, _s, _n, _v, vmstate_info_int16, int16_t) ++ ++#define VMSTATE_INT16_ARRAY(_f, _s, _n) \ ++ VMSTATE_INT16_ARRAY_V(_f, _s, _n, 0) ++ ++#define VMSTATE_INT32_ARRAY_V(_f, _s, _n, _v) \ ++ VMSTATE_ARRAY(_f, _s, _n, _v, vmstate_info_int32, int32_t) ++ ++#define VMSTATE_INT32_ARRAY(_f, _s, _n) \ ++ VMSTATE_INT32_ARRAY_V(_f, _s, _n, 0) ++ ++#define VMSTATE_UINT32_SUB_ARRAY(_f, _s, _start, _num) \ ++ VMSTATE_SUB_ARRAY(_f, _s, _start, _num, 0, vmstate_info_uint32, uint32_t) ++ ++#define VMSTATE_UINT32_ARRAY(_f, _s, _n) \ ++ VMSTATE_UINT32_ARRAY_V(_f, _s, _n, 0) ++ ++#define VMSTATE_BUFFER_V(_f, _s, _v) \ ++ VMSTATE_STATIC_BUFFER(_f, _s, _v, NULL, 0, sizeof(typeof_field(_s, _f))) ++ ++#define VMSTATE_BUFFER(_f, _s) \ ++ VMSTATE_BUFFER_V(_f, _s, 0) ++ ++#define VMSTATE_PARTIAL_BUFFER(_f, _s, _size) \ ++ VMSTATE_STATIC_BUFFER(_f, _s, 0, NULL, 0, _size) ++ ++#define VMSTATE_BUFFER_START_MIDDLE(_f, _s, _start) \ ++ VMSTATE_STATIC_BUFFER(_f, _s, 0, NULL, _start, sizeof(typeof_field(_s, _f))) ++ ++#define VMSTATE_PARTIAL_VBUFFER(_f, _s, _size) \ ++ VMSTATE_VBUFFER(_f, _s, 0, NULL, 0, _size) ++ ++#define VMSTATE_SUB_VBUFFER(_f, _s, _start, _size) \ ++ VMSTATE_VBUFFER(_f, _s, 0, NULL, _start, _size) ++ ++#define VMSTATE_BUFFER_TEST(_f, _s, _test) \ ++ VMSTATE_STATIC_BUFFER(_f, _s, 0, _test, 0, sizeof(typeof_field(_s, _f))) ++ ++#define VMSTATE_BUFFER_UNSAFE(_field, _state, _version, _size) \ ++ VMSTATE_BUFFER_UNSAFE_INFO(_field, _state, _version, vmstate_info_buffer, _size) ++ ++#define VMSTATE_UNUSED_V(_v, _size) \ ++ VMSTATE_UNUSED_BUFFER(NULL, _v, _size) ++ ++#define VMSTATE_UNUSED(_size) \ ++ VMSTATE_UNUSED_V(0, _size) ++ ++#define VMSTATE_UNUSED_TEST(_test, _size) \ ++ VMSTATE_UNUSED_BUFFER(_test, 0, _size) ++ ++#ifdef NEED_CPU_H ++#if TARGET_LONG_BITS == 64 ++#define VMSTATE_UINTTL_V(_f, _s, _v) \ ++ VMSTATE_UINT64_V(_f, _s, _v) ++#define VMSTATE_UINTTL_ARRAY_V(_f, _s, _n, _v) \ ++ VMSTATE_UINT64_ARRAY_V(_f, _s, _n, _v) ++#else ++#define VMSTATE_UINTTL_V(_f, _s, _v) \ ++ VMSTATE_UINT32_V(_f, _s, _v) ++#define VMSTATE_UINTTL_ARRAY_V(_f, _s, _n, _v) \ ++ VMSTATE_UINT32_ARRAY_V(_f, _s, _n, _v) ++#endif ++#define VMSTATE_UINTTL(_f, _s) \ ++ VMSTATE_UINTTL_V(_f, _s, 0) ++#define VMSTATE_UINTTL_ARRAY(_f, _s, _n) \ ++ VMSTATE_UINTTL_ARRAY_V(_f, _s, _n, 0) ++ ++#endif ++ ++#define VMSTATE_END_OF_LIST() \ ++ {} ++ ++extern int vmstate_load_state(QEMUFile *f, const VMStateDescription *vmsd, ++ void *opaque, int version_id); ++extern void vmstate_save_state(QEMUFile *f, const VMStateDescription *vmsd, ++ void *opaque); ++extern int vmstate_register(DeviceState *dev, int instance_id, ++ const VMStateDescription *vmsd, void *base); ++extern int vmstate_register_with_alias_id(DeviceState *dev, ++ int instance_id, ++ const VMStateDescription *vmsd, ++ void *base, int alias_id, ++ int required_for_version); ++void vmstate_unregister(DeviceState *dev, const VMStateDescription *vmsd, ++ void *opaque); ++#endif +diff -urN qemu-kvm-0.13.0.orig/hw/msix.c qemu-kvm-0.13.0/hw/msix.c +--- qemu-kvm-0.13.0.orig/hw/msix.c 2011-02-09 11:01:45.882000328 +0200 ++++ qemu-kvm-0.13.0/hw/msix.c 2011-02-09 11:08:02.908000327 +0200 +@@ -300,10 +300,8 @@ + if (kvm_enabled() && kvm_irqchip_in_kernel()) { + kvm_msix_update(dev, vector, was_masked, msix_is_masked(dev, vector)); + } +- if (was_masked != msix_is_masked(dev, vector) && +- dev->msix_mask_notifier && dev->msix_mask_notifier_opaque[vector]) { ++ if (was_masked != msix_is_masked(dev, vector) && dev->msix_mask_notifier) { + int r = dev->msix_mask_notifier(dev, vector, +- dev->msix_mask_notifier_opaque[vector], + msix_is_masked(dev, vector)); + assert(r >= 0); + } +@@ -351,9 +349,8 @@ + int was_masked = msix_is_masked(dev, vector); + dev->msix_table_page[offset] |= MSIX_VECTOR_MASK; + if (was_masked != msix_is_masked(dev, vector) && +- dev->msix_mask_notifier && dev->msix_mask_notifier_opaque[vector]) { ++ dev->msix_mask_notifier) { + r = dev->msix_mask_notifier(dev, vector, +- dev->msix_mask_notifier_opaque[vector], + msix_is_masked(dev, vector)); + assert(r >= 0); + } +@@ -379,8 +376,6 @@ + sizeof *dev->msix_irq_entries); + } + #endif +- dev->msix_mask_notifier_opaque = +- qemu_mallocz(nentries * sizeof *dev->msix_mask_notifier_opaque); + dev->msix_mask_notifier = NULL; + dev->msix_entry_used = qemu_mallocz(MSIX_MAX_ENTRIES * + sizeof *dev->msix_entry_used); +@@ -444,8 +439,6 @@ + dev->msix_entry_used = NULL; + qemu_free(dev->msix_irq_entries); + dev->msix_irq_entries = NULL; +- qemu_free(dev->msix_mask_notifier_opaque); +- dev->msix_mask_notifier_opaque = NULL; + dev->cap_present &= ~QEMU_PCI_CAP_MSIX; + return 0; + } +@@ -590,46 +583,65 @@ + msix_free_irq_entries(dev); + } + +-int msix_set_mask_notifier(PCIDevice *dev, unsigned vector, void *opaque) ++/* Invoke the notifier if vector entry is used and unmasked. */ ++static int msix_notify_if_unmasked(PCIDevice *dev, unsigned vector, int masked) + { +- int r = 0; +- if (vector >= dev->msix_entries_nr || !dev->msix_entry_used[vector]) ++ assert(dev->msix_mask_notifier); ++ if (!dev->msix_entry_used[vector] || msix_is_masked(dev, vector)) { + return 0; ++ } ++ return dev->msix_mask_notifier(dev, vector, masked); ++} + +- assert(dev->msix_mask_notifier); +- assert(opaque); +- assert(!dev->msix_mask_notifier_opaque[vector]); ++static int msix_set_mask_notifier_for_vector(PCIDevice *dev, unsigned vector) ++{ ++ /* Notifier has been set. Invoke it on unmasked vectors. */ ++ return msix_notify_if_unmasked(dev, vector, 0); ++} ++ ++static int msix_unset_mask_notifier_for_vector(PCIDevice *dev, unsigned vector) ++{ ++ /* Notifier will be unset. Invoke it to mask unmasked entries. */ ++ return msix_notify_if_unmasked(dev, vector, 1); ++} + +- /* Unmask the new notifier unless vector is masked. */ +- if (!msix_is_masked(dev, vector)) { +- r = dev->msix_mask_notifier(dev, vector, opaque, false); ++int msix_set_mask_notifier(PCIDevice *dev, msix_mask_notifier_func f) ++{ ++ int r, n; ++ assert(!dev->msix_mask_notifier); ++ dev->msix_mask_notifier = f; ++ for (n = 0; n < dev->msix_entries_nr; ++n) { ++ r = msix_set_mask_notifier_for_vector(dev, n); + if (r < 0) { +- return r; ++ goto undo; + } + } +- dev->msix_mask_notifier_opaque[vector] = opaque; ++ return 0; ++ ++undo: ++ while (--n >= 0) { ++ msix_unset_mask_notifier_for_vector(dev, n); ++ } ++ dev->msix_mask_notifier = NULL; + return r; + } + +-int msix_unset_mask_notifier(PCIDevice *dev, unsigned vector) ++int msix_unset_mask_notifier(PCIDevice *dev) + { +- int r = 0; +- void *opaque; +- if (vector >= dev->msix_entries_nr || !dev->msix_entry_used[vector]) +- return 0; +- +- opaque = dev->msix_mask_notifier_opaque[vector]; +- ++ int r, n; + assert(dev->msix_mask_notifier); +- assert(opaque); +- +- /* Mask the old notifier unless it is already masked. */ +- if (!msix_is_masked(dev, vector)) { +- r = dev->msix_mask_notifier(dev, vector, opaque, true); ++ for (n = 0; n < dev->msix_entries_nr; ++n) { ++ r = msix_unset_mask_notifier_for_vector(dev, n); + if (r < 0) { +- return r; ++ goto undo; + } + } +- dev->msix_mask_notifier_opaque[vector] = NULL; ++ dev->msix_mask_notifier = NULL; ++ return 0; ++ ++undo: ++ while (--n >= 0) { ++ msix_set_mask_notifier_for_vector(dev, n); ++ } + return r; + } +diff -urN qemu-kvm-0.13.0.orig/hw/msix.h qemu-kvm-0.13.0/hw/msix.h +--- qemu-kvm-0.13.0.orig/hw/msix.h 2011-02-09 11:01:45.839000328 +0200 ++++ qemu-kvm-0.13.0/hw/msix.h 2011-02-09 11:08:02.908000327 +0200 +@@ -33,6 +33,6 @@ + + extern int msix_supported; + +-int msix_set_mask_notifier(PCIDevice *dev, unsigned vector, void *opaque); +-int msix_unset_mask_notifier(PCIDevice *dev, unsigned vector); ++int msix_set_mask_notifier(PCIDevice *dev, msix_mask_notifier_func); ++int msix_unset_mask_notifier(PCIDevice *dev); + #endif +diff -urN qemu-kvm-0.13.0.orig/hw/pc.c qemu-kvm-0.13.0/hw/pc.c +--- qemu-kvm-0.13.0.orig/hw/pc.c 2011-02-09 11:01:45.874000328 +0200 ++++ qemu-kvm-0.13.0/hw/pc.c 2011-02-09 11:08:02.765000327 +0200 +@@ -41,6 +41,7 @@ + #include "sysemu.h" + #include "device-assignment.h" + #include "kvm.h" ++#include "qemu-spice.h" + + /* output Bochs bios info messages */ + //#define DEBUG_BIOS +@@ -1002,6 +1003,13 @@ + pci_vmsvga_init(pci_bus); + else + fprintf(stderr, "%s: vmware_vga: no PCI bus\n", __FUNCTION__); ++#ifdef CONFIG_SPICE ++ } else if (qxl_enabled) { ++ if (pci_bus) ++ pci_create_simple(pci_bus, -1, "qxl"); ++ else ++ fprintf(stderr, "%s: qxl: no PCI bus\n", __FUNCTION__); ++#endif + } else if (std_vga_enabled) { + if (pci_bus) { + pci_vga_init(pci_bus, 0, 0); +diff -urN qemu-kvm-0.13.0.orig/hw/pci.h qemu-kvm-0.13.0/hw/pci.h +--- qemu-kvm-0.13.0.orig/hw/pci.h 2011-02-09 11:01:45.843000328 +0200 ++++ qemu-kvm-0.13.0/hw/pci.h 2011-02-09 11:08:02.909000327 +0200 +@@ -131,7 +131,7 @@ + #define PCI_CAPABILITY_CONFIG_MSIX_LENGTH 0x10 + + typedef int (*msix_mask_notifier_func)(PCIDevice *, unsigned vector, +- void *opaque, int masked); ++ int masked); + + struct PCIDevice { + DeviceState qdev; +@@ -198,7 +198,6 @@ + + struct kvm_irq_routing_entry *msix_irq_entries; + +- void **msix_mask_notifier_opaque; + msix_mask_notifier_func msix_mask_notifier; + + /* Device capability configuration space */ +diff -urN qemu-kvm-0.13.0.orig/hw/qxl.c qemu-kvm-0.13.0/hw/qxl.c +--- qemu-kvm-0.13.0.orig/hw/qxl.c 1970-01-01 02:00:00.000000000 +0200 ++++ qemu-kvm-0.13.0/hw/qxl.c 2011-02-09 11:08:02.900000327 +0200 +@@ -0,0 +1,1470 @@ ++#include <stdio.h> ++#include <stdlib.h> ++#include <stdbool.h> ++#include <stdint.h> ++#include <string.h> ++#include <pthread.h> ++ ++#include "qemu-common.h" ++#include "qemu-timer.h" ++#include "qemu-queue.h" ++#include "monitor.h" ++#include "sysemu.h" ++ ++#include "qxl.h" ++ ++#undef SPICE_RING_PROD_ITEM ++#define SPICE_RING_PROD_ITEM(r, ret) { \ ++ typeof(r) start = r; \ ++ typeof(r) end = r + 1; \ ++ uint32_t prod = (r)->prod & SPICE_RING_INDEX_MASK(r); \ ++ typeof(&(r)->items[prod]) m_item = &(r)->items[prod]; \ ++ if (!((uint8_t*)m_item >= (uint8_t*)(start) && (uint8_t*)(m_item + 1) <= (uint8_t*)(end))) { \ ++ abort(); \ ++ } \ ++ ret = &m_item->el; \ ++ } ++ ++#undef SPICE_RING_CONS_ITEM ++#define SPICE_RING_CONS_ITEM(r, ret) { \ ++ typeof(r) start = r; \ ++ typeof(r) end = r + 1; \ ++ uint32_t cons = (r)->cons & SPICE_RING_INDEX_MASK(r); \ ++ typeof(&(r)->items[cons]) m_item = &(r)->items[cons]; \ ++ if (!((uint8_t*)m_item >= (uint8_t*)(start) && (uint8_t*)(m_item + 1) <= (uint8_t*)(end))) { \ ++ abort(); \ ++ } \ ++ ret = &m_item->el; \ ++ } ++ ++#undef ALIGN ++#define ALIGN(a, b) (((a) + ((b) - 1)) & ~((b) - 1)) ++ ++#define PIXEL_SIZE 0.2936875 //1280x1024 is 14.8" x 11.9" ++ ++#define QXL_MODE(_x, _y, _b, _o) \ ++ { .x_res = _x, \ ++ .y_res = _y, \ ++ .bits = _b, \ ++ .stride = (_x) * (_b) / 8, \ ++ .x_mili = PIXEL_SIZE * (_x), \ ++ .y_mili = PIXEL_SIZE * (_y), \ ++ .orientation = _o, \ ++ } ++ ++#define QXL_MODE_16_32(x_res, y_res, orientation) \ ++ QXL_MODE(x_res, y_res, 16, orientation), \ ++ QXL_MODE(x_res, y_res, 32, orientation) ++ ++#define QXL_MODE_EX(x_res, y_res) \ ++ QXL_MODE_16_32(x_res, y_res, 0), \ ++ QXL_MODE_16_32(y_res, x_res, 1), \ ++ QXL_MODE_16_32(x_res, y_res, 2), \ ++ QXL_MODE_16_32(y_res, x_res, 3) ++ ++static QXLMode qxl_modes[] = { ++ QXL_MODE_EX(640, 480), ++ QXL_MODE_EX(800, 480), ++ QXL_MODE_EX(800, 600), ++ QXL_MODE_EX(832, 624), ++ QXL_MODE_EX(1024, 768), ++ QXL_MODE_EX(1152, 864), ++ QXL_MODE_EX(1152, 870), ++ QXL_MODE_EX(1280, 720), ++ QXL_MODE_EX(1280, 768), ++ QXL_MODE_EX(1280, 800), ++ QXL_MODE_EX(1280, 960), ++ QXL_MODE_EX(1280, 1024), ++ QXL_MODE_EX(1360, 768), ++ QXL_MODE_EX(1366, 768), ++ QXL_MODE_EX(1400, 1050), ++ QXL_MODE_EX(1440, 900), ++ QXL_MODE_EX(1600, 900), ++ QXL_MODE_EX(1600, 1200), ++ QXL_MODE_EX(1680, 1050), ++ QXL_MODE_EX(1920, 1080), ++#ifdef QXL_HIRES_MODES ++ QXL_MODE_EX(1920, 1200), ++ QXL_MODE_EX(1920, 1440), ++ QXL_MODE_EX(2048, 1536), ++ QXL_MODE_EX(2560, 1600), ++ QXL_MODE_EX(2560, 2048), ++ QXL_MODE_EX(2800, 2100), ++ QXL_MODE_EX(3200, 2400), ++#endif ++}; ++ ++static int device_id = 0; ++static PCIQXLDevice *qxl0; ++ ++static void qxl_send_events(PCIQXLDevice *d, uint32_t events); ++static void qxl_destroy_primary(PCIQXLDevice *d); ++static void qxl_reset_memslots(PCIQXLDevice *d); ++static void qxl_reset_surfaces(PCIQXLDevice *d); ++static void qxl_ring_set_dirty(PCIQXLDevice *qxl); ++ ++static inline uint32_t msb_mask(uint32_t val) ++{ ++ uint32_t mask; ++ ++ do { ++ mask = ~(val - 1) & val; ++ val &= ~mask; ++ } while (mask < val); ++ ++ return mask; ++} ++ ++static ram_addr_t qxl_rom_size(void) ++{ ++ uint32_t rom_size = sizeof(QXLRom) + sizeof(QXLModes) + sizeof(qxl_modes); ++ rom_size = MAX(rom_size, TARGET_PAGE_SIZE); ++ rom_size = msb_mask(rom_size * 2 - 1); ++ return rom_size; ++} ++ ++static void init_qxl_rom(PCIQXLDevice *d) ++{ ++ QXLRom *rom = qemu_get_ram_ptr(d->rom_offset); ++ QXLModes *modes = (QXLModes *)(rom + 1); ++ uint32_t ram_header_size; ++ uint32_t surface0_area_size; ++ uint32_t num_pages; ++ uint32_t fb, maxfb = 0; ++ int i; ++ ++ memset(rom, 0, d->rom_size); ++ ++ rom->magic = cpu_to_le32(QXL_ROM_MAGIC); ++ rom->id = cpu_to_le32(d->id); ++ rom->modes_offset = cpu_to_le32(sizeof(QXLRom)); ++ ++ rom->slot_gen_bits = MEMSLOT_GENERATION_BITS; ++ 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); ++ ++ modes->n_modes = cpu_to_le32(ARRAY_SIZE(qxl_modes)); ++ for (i = 0; i < modes->n_modes; i++) { ++ fb = qxl_modes[i].y_res * qxl_modes[i].stride; ++ if (maxfb < fb) ++ maxfb = fb; ++ modes->modes[i].id = cpu_to_le32(i); ++ modes->modes[i].x_res = cpu_to_le32(qxl_modes[i].x_res); ++ modes->modes[i].y_res = cpu_to_le32(qxl_modes[i].y_res); ++ modes->modes[i].bits = cpu_to_le32(qxl_modes[i].bits); ++ modes->modes[i].stride = cpu_to_le32(qxl_modes[i].stride); ++ modes->modes[i].x_mili = cpu_to_le32(qxl_modes[i].x_mili); ++ modes->modes[i].y_mili = cpu_to_le32(qxl_modes[i].y_mili); ++ modes->modes[i].orientation = cpu_to_le32(qxl_modes[i].orientation); ++ } ++ if (maxfb < VGA_RAM_SIZE && d->id == 0) ++ maxfb = VGA_RAM_SIZE; ++ ++ ram_header_size = ALIGN(sizeof(QXLRam), 4096); ++ surface0_area_size = ALIGN(maxfb, 4096); ++ num_pages = d->vga.vram_size; ++ num_pages -= ram_header_size; ++ num_pages -= surface0_area_size; ++ num_pages = num_pages / TARGET_PAGE_SIZE; ++ ++ rom->draw_area_offset = cpu_to_le32(0); ++ rom->surface0_area_size = cpu_to_le32(surface0_area_size); ++ rom->pages_offset = cpu_to_le32(surface0_area_size); ++ rom->num_pages = cpu_to_le32(num_pages); ++ rom->ram_header_offset = cpu_to_le32(d->vga.vram_size - ram_header_size); ++ ++ d->shadow_rom = *rom; ++ d->rom = rom; ++ d->modes = modes; ++} ++ ++static void init_qxl_ram(PCIQXLDevice *d) ++{ ++ uint8_t *buf; ++ uint64_t *item; ++ ++ buf = d->vga.vram_ptr; ++ d->ram = (QXLRam *)(buf + le32_to_cpu(d->shadow_rom.ram_header_offset)); ++ d->ram->magic = cpu_to_le32(QXL_RAM_MAGIC); ++ d->ram->int_pending = cpu_to_le32(0); ++ d->ram->int_mask = cpu_to_le32(0); ++ SPICE_RING_INIT(&d->ram->cmd_ring); ++ SPICE_RING_INIT(&d->ram->cursor_ring); ++ SPICE_RING_INIT(&d->ram->release_ring); ++ SPICE_RING_PROD_ITEM(&d->ram->release_ring, item); ++ *item = 0; ++ qxl_ring_set_dirty(d); ++} ++ ++static void qxl_set_dirty(ram_addr_t addr, ram_addr_t end) ++{ ++ while (addr < end) { ++ cpu_physical_memory_set_dirty(addr); ++ addr += TARGET_PAGE_SIZE; ++ } ++} ++ ++static void qxl_rom_set_dirty(PCIQXLDevice *qxl) ++{ ++ ram_addr_t addr = qxl->rom_offset; ++ qxl_set_dirty(addr, addr + qxl->rom_size); ++} ++ ++static void qxl_ram_set_dirty(PCIQXLDevice *qxl, void *ptr) ++{ ++ ram_addr_t addr = qxl->vga.vram_offset; ++ void *base = qxl->vga.vram_ptr; ++ intptr_t offset; ++ ++ offset = ptr - base; ++ offset &= ~(TARGET_PAGE_SIZE-1); ++ assert(offset < qxl->vga.vram_size); ++ qxl_set_dirty(addr + offset, addr + offset + TARGET_PAGE_SIZE); ++} ++ ++static void qxl_ring_set_dirty(PCIQXLDevice *qxl) ++{ ++ ram_addr_t addr = qxl->vga.vram_offset + qxl->shadow_rom.ram_header_offset; ++ ram_addr_t end = qxl->vga.vram_offset + qxl->vga.vram_size; ++ qxl_set_dirty(addr, end); ++} ++ ++/* ++ * keep track of some command state, for savevm/loadvm. ++ */ ++static void qxl_track_command(PCIQXLDevice *qxl, struct QXLCommandExt *ext) ++{ ++ switch (le32_to_cpu(ext->cmd.type)) { ++ case QXL_CMD_SURFACE: ++ { ++ QXLSurfaceCmd *cmd = qxl_phys2virt(qxl, ext->cmd.data, ext->group_id); ++ uint32_t id = le32_to_cpu(cmd->surface_id); ++ PANIC_ON(id >= NUM_SURFACES); ++ if (cmd->type == QXL_SURFACE_CMD_CREATE) { ++ qxl->guest_surfaces.cmds[id] = ext->cmd.data; ++ qxl->guest_surfaces.count++; ++ if (qxl->guest_surfaces.max < qxl->guest_surfaces.count) ++ qxl->guest_surfaces.max = qxl->guest_surfaces.count; ++ } ++ if (cmd->type == QXL_SURFACE_CMD_DESTROY) { ++ qxl->guest_surfaces.cmds[id] = 0; ++ qxl->guest_surfaces.count--; ++ } ++ break; ++ } ++ case QXL_CMD_CURSOR: ++ { ++ QXLCursorCmd *cmd = qxl_phys2virt(qxl, ext->cmd.data, ext->group_id); ++ if (cmd->type == QXL_CURSOR_SET) { ++ qxl->guest_cursor = ext->cmd.data; ++ } ++ break; ++ } ++ } ++} ++ ++/* spice display interface callbacks */ ++ ++static void interface_attach_worker(QXLInstance *sin, QXLWorker *qxl_worker) ++{ ++ PCIQXLDevice *qxl = container_of(sin, PCIQXLDevice, ssd.qxl); ++ ++ dprintf(qxl, 1, "%s:\n", __FUNCTION__); ++ qxl->ssd.worker = qxl_worker; ++} ++ ++static void interface_set_compression_level(QXLInstance *sin, int level) ++{ ++ PCIQXLDevice *qxl = container_of(sin, PCIQXLDevice, ssd.qxl); ++ ++ dprintf(qxl, 1, "%s: %d\n", __FUNCTION__, level); ++ qxl->shadow_rom.compression_level = cpu_to_le32(level); ++ qxl->rom->compression_level = cpu_to_le32(level); ++ qxl_rom_set_dirty(qxl); ++} ++ ++static void interface_set_mm_time(QXLInstance *sin, uint32_t mm_time) ++{ ++ PCIQXLDevice *qxl = container_of(sin, PCIQXLDevice, ssd.qxl); ++ ++ qxl->shadow_rom.mm_clock = cpu_to_le32(mm_time); ++ qxl->rom->mm_clock = cpu_to_le32(mm_time); ++ qxl_rom_set_dirty(qxl); ++} ++ ++static void interface_get_init_info(QXLInstance *sin, QXLDevInitInfo *info) ++{ ++ PCIQXLDevice *qxl = container_of(sin, PCIQXLDevice, ssd.qxl); ++ ++ dprintf(qxl, 1, "%s:\n", __FUNCTION__); ++ info->memslot_gen_bits = MEMSLOT_GENERATION_BITS; ++ info->memslot_id_bits = MEMSLOT_SLOT_BITS; ++ info->num_memslots = NUM_MEMSLOTS; ++ 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; ++} ++ ++static int interface_get_command(QXLInstance *sin, struct QXLCommandExt *ext) ++{ ++ PCIQXLDevice *qxl = container_of(sin, PCIQXLDevice, ssd.qxl); ++ SimpleSpiceUpdate *update; ++ QXLCommandRing *ring; ++ QXLCommand *cmd; ++ int notify; ++ ++ switch (qxl->mode) { ++ case QXL_MODE_VGA: ++ dprintf(qxl, 2, "%s: vga\n", __FUNCTION__); ++ update = qemu_spice_create_update(&qxl->ssd); ++ if (update == NULL) { ++ return false; ++ } ++ *ext = update->ext; ++ qxl_log_command(qxl, "vga", ext); ++ return true; ++ case QXL_MODE_COMPAT: ++ case QXL_MODE_NATIVE: ++ case QXL_MODE_UNDEFINED: ++ dprintf(qxl, 2, "%s: %s\n", __FUNCTION__, ++ qxl->cmdflags ? "compat" : "native"); ++ ring = &qxl->ram->cmd_ring; ++ if (SPICE_RING_IS_EMPTY(ring)) { ++ return false; ++ } ++ SPICE_RING_CONS_ITEM(ring, cmd); ++ ext->cmd = *cmd; ++ ext->group_id = MEMSLOT_GROUP_GUEST; ++ ext->flags = qxl->cmdflags; ++ SPICE_RING_POP(ring, notify); ++ qxl_ring_set_dirty(qxl); ++ if (notify) { ++ qxl_send_events(qxl, QXL_INTERRUPT_DISPLAY); ++ } ++ qxl->guest_primary.commands++; ++ qxl_track_command(qxl, ext); ++ qxl_log_command(qxl, "cmd", ext); ++ return true; ++ default: ++ return false; ++ } ++} ++ ++static int interface_req_cmd_notification(QXLInstance *sin) ++{ ++ PCIQXLDevice *qxl = container_of(sin, PCIQXLDevice, ssd.qxl); ++ int wait = 1; ++ ++ switch (qxl->mode) { ++ case QXL_MODE_COMPAT: ++ case QXL_MODE_NATIVE: ++ case QXL_MODE_UNDEFINED: ++ SPICE_RING_CONS_WAIT(&qxl->ram->cmd_ring, wait); ++ qxl_ring_set_dirty(qxl); ++ break; ++ default: ++ /* nothing */ ++ break; ++ } ++ return wait; ++} ++ ++static inline void qxl_push_free_res(PCIQXLDevice *d) ++{ ++ QXLReleaseRing *ring = &d->ram->release_ring; ++ uint64_t *item; ++ ++#define QXL_FREE_BUNCH_SIZE 32 ++ ++ if (SPICE_RING_IS_EMPTY(ring) || (d->num_free_res >= QXL_FREE_BUNCH_SIZE && ++ ring->prod - ring->cons + 2 != ring->num_items)) { ++ int notify; ++ ++ SPICE_RING_PUSH(ring, notify); ++ if (notify) { ++ qxl_send_events(d, QXL_INTERRUPT_DISPLAY); ++ } ++ SPICE_RING_PROD_ITEM(ring, item); ++ *item = 0; ++ d->num_free_res = 0; ++ d->last_release = NULL; ++ qxl_ring_set_dirty(d); ++ } ++} ++ ++static void interface_release_resource(QXLInstance *sin, ++ struct QXLReleaseInfoExt ext) ++{ ++ PCIQXLDevice *qxl = container_of(sin, PCIQXLDevice, ssd.qxl); ++ QXLReleaseRing *ring; ++ uint64_t *item, id; ++ ++ if (ext.group_id == MEMSLOT_GROUP_HOST) { ++ /* host group -> vga mode update request */ ++ qemu_spice_destroy_update(&qxl->ssd, (void*)ext.info->id); ++ return; ++ } ++ ++ /* ++ * ext->info points into guest-visible memory ++ * pci bar 0, $command.release_info ++ */ ++ ring = &qxl->ram->release_ring; ++ SPICE_RING_PROD_ITEM(ring, item); ++ if (*item == 0) { ++ /* stick head into the ring */ ++ id = ext.info->id; ++ ext.info->next = 0; ++ qxl_ram_set_dirty(qxl, &ext.info->next); ++ *item = id; ++ qxl_ring_set_dirty(qxl); ++ } else { ++ /* append item to the list */ ++ qxl->last_release->next = ext.info->id; ++ qxl_ram_set_dirty(qxl, &qxl->last_release->next); ++ ext.info->next = 0; ++ qxl_ram_set_dirty(qxl, &ext.info->next); ++ } ++ qxl->last_release = ext.info; ++ qxl->num_free_res++; ++ qxl_push_free_res(qxl); ++} ++ ++static int interface_get_cursor_command(QXLInstance *sin, struct QXLCommandExt *ext) ++{ ++ PCIQXLDevice *qxl = container_of(sin, PCIQXLDevice, ssd.qxl); ++ QXLCursorRing *ring; ++ QXLCommand *cmd; ++ int notify; ++ ++ switch (qxl->mode) { ++ case QXL_MODE_COMPAT: ++ case QXL_MODE_NATIVE: ++ case QXL_MODE_UNDEFINED: ++ ring = &qxl->ram->cursor_ring; ++ if (SPICE_RING_IS_EMPTY(ring)) { ++ return false; ++ } ++ SPICE_RING_CONS_ITEM(ring, cmd); ++ ext->cmd = *cmd; ++ ext->group_id = MEMSLOT_GROUP_GUEST; ++ ext->flags = qxl->cmdflags; ++ SPICE_RING_POP(ring, notify); ++ qxl_ring_set_dirty(qxl); ++ if (notify) { ++ qxl_send_events(qxl, QXL_INTERRUPT_CURSOR); ++ } ++ qxl->guest_primary.commands++; ++ qxl_track_command(qxl, ext); ++ qxl_log_command(qxl, "csr", ext); ++ if (qxl->id == 0) { ++ qxl_render_cursor(qxl, ext); ++ } ++ return true; ++ default: ++ return false; ++ } ++} ++ ++static int interface_req_cursor_notification(QXLInstance *sin) ++{ ++ PCIQXLDevice *qxl = container_of(sin, PCIQXLDevice, ssd.qxl); ++ int wait = 1; ++ ++ switch (qxl->mode) { ++ case QXL_MODE_COMPAT: ++ case QXL_MODE_NATIVE: ++ case QXL_MODE_UNDEFINED: ++ SPICE_RING_CONS_WAIT(&qxl->ram->cursor_ring, wait); ++ qxl_ring_set_dirty(qxl); ++ break; ++ default: ++ /* nothing */ ++ break; ++ } ++ return wait; ++} ++ ++static void interface_notify_update(QXLInstance *sin, uint32_t update_id) ++{ ++ fprintf(stderr, "%s: abort()\n", __FUNCTION__); ++ abort(); ++} ++ ++static int interface_flush_resources(QXLInstance *sin) ++{ ++ PCIQXLDevice *qxl = container_of(sin, PCIQXLDevice, ssd.qxl); ++ int ret; ++ ++ ret = qxl->num_free_res; ++ if (ret) { ++ qxl_push_free_res(qxl); ++ } ++ return ret; ++} ++ ++static const QXLInterface qxl_interface = { ++ .base.type = SPICE_INTERFACE_QXL, ++ .base.description = "qxl gpu", ++ .base.major_version = SPICE_INTERFACE_QXL_MAJOR, ++ .base.minor_version = SPICE_INTERFACE_QXL_MINOR, ++ ++ .attache_worker = interface_attach_worker, ++ .set_compression_level = interface_set_compression_level, ++ .set_mm_time = interface_set_mm_time, ++ ++ .get_init_info = interface_get_init_info, ++ .get_command = interface_get_command, ++ .req_cmd_notification = interface_req_cmd_notification, ++ .release_resource = interface_release_resource, ++ .get_cursor_command = interface_get_cursor_command, ++ .req_cursor_notification = interface_req_cursor_notification, ++ .notify_update = interface_notify_update, ++ .flush_resources = interface_flush_resources, ++}; ++ ++static void qxl_enter_vga_mode(PCIQXLDevice *d) ++{ ++ if (d->mode == QXL_MODE_VGA) { ++ return; ++ } ++ dprintf(d, 1, "%s\n", __FUNCTION__); ++ qemu_spice_create_host_primary(&d->ssd); ++ d->mode = QXL_MODE_VGA; ++ memset(&d->ssd.dirty, 0, sizeof(d->ssd.dirty)); ++} ++ ++static void qxl_exit_vga_mode(PCIQXLDevice *d) ++{ ++ if (d->mode != QXL_MODE_VGA) { ++ return; ++ } ++ dprintf(d, 1, "%s\n", __FUNCTION__); ++ qxl_destroy_primary(d); ++} ++ ++static void qxl_set_irq(PCIQXLDevice *d) ++{ ++ uint32_t pending = le32_to_cpu(d->ram->int_pending); ++ uint32_t mask = le32_to_cpu(d->ram->int_mask); ++ int level = !!(pending & mask); ++ qemu_set_irq(d->pci.irq[0], level); ++ qxl_ring_set_dirty(d); ++} ++ ++static void qxl_write_config(PCIDevice *d, uint32_t address, ++ uint32_t val, int len) ++{ ++ PCIQXLDevice *qxl = DO_UPCAST(PCIQXLDevice, pci, d); ++ VGACommonState *vga = &qxl->vga; ++ ++ if (qxl->id == 0) { ++ vga_dirty_log_stop(vga); ++ } ++ pci_default_write_config(d, address, val, len); ++ if (qxl->id == 0) { ++ if (vga->map_addr && qxl->pci.io_regions[0].addr == -1) ++ vga->map_addr = 0; ++ vga_dirty_log_start(vga); ++ } ++} ++ ++static void qxl_check_state(PCIQXLDevice *d) ++{ ++ QXLRam *ram = d->ram; ++ ++ assert(SPICE_RING_IS_EMPTY(&ram->cmd_ring)); ++ assert(SPICE_RING_IS_EMPTY(&ram->cursor_ring)); ++} ++ ++static void qxl_reset_state(PCIQXLDevice *d) ++{ ++ QXLRam *ram = d->ram; ++ QXLRom *rom = d->rom; ++ ++ assert(SPICE_RING_IS_EMPTY(&ram->cmd_ring)); ++ assert(SPICE_RING_IS_EMPTY(&ram->cursor_ring)); ++ d->shadow_rom.update_id = cpu_to_le32(0); ++ *rom = d->shadow_rom; ++ qxl_rom_set_dirty(d); ++ init_qxl_ram(d); ++ d->num_free_res = 0; ++ d->last_release = NULL; ++ memset(&d->ssd.dirty, 0, sizeof(d->ssd.dirty)); ++} ++ ++static void qxl_soft_reset(PCIQXLDevice *d) ++{ ++ dprintf(d, 1, "%s:\n", __FUNCTION__); ++ qxl_check_state(d); ++ ++ if (d->id == 0) { ++ qxl_enter_vga_mode(d); ++ } else { ++ d->mode = QXL_MODE_UNDEFINED; ++ } ++} ++ ++static void qxl_hard_reset(PCIQXLDevice *d, int loadvm) ++{ ++ dprintf(d, 1, "%s: start%s\n", __FUNCTION__, ++ loadvm ? " (loadvm)" : ""); ++ ++ d->ssd.worker->reset_cursor(d->ssd.worker); ++ d->ssd.worker->reset_image_cache(d->ssd.worker); ++ qxl_reset_surfaces(d); ++ qxl_reset_memslots(d); ++ ++ /* pre loadvm reset must not touch QXLRam. This lives in ++ * device memory, is migrated together with RAM and thus ++ * already loaded at this point */ ++ if (!loadvm) { ++ qxl_reset_state(d); ++ } ++ qemu_spice_create_host_memslot(&d->ssd); ++ qxl_soft_reset(d); ++ ++ dprintf(d, 1, "%s: done\n", __FUNCTION__); ++} ++ ++static void qxl_reset_handler(DeviceState *dev) ++{ ++ PCIQXLDevice *d = DO_UPCAST(PCIQXLDevice, pci.qdev, dev); ++ qxl_hard_reset(d, 0); ++} ++ ++static void qxl_vga_ioport_write(void *opaque, uint32_t addr, uint32_t val) ++{ ++ VGACommonState *vga = opaque; ++ PCIQXLDevice *qxl = container_of(vga, PCIQXLDevice, vga); ++ ++ if (qxl->mode != QXL_MODE_VGA) { ++ dprintf(qxl, 1, "%s\n", __FUNCTION__); ++ qxl_destroy_primary(qxl); ++ qxl_soft_reset(qxl); ++ } ++ vga_ioport_write(opaque, addr, val); ++} ++ ++static void qxl_add_memslot(PCIQXLDevice *d, uint32_t slot_id, uint64_t delta) ++{ ++ static const int regions[] = { ++ QXL_RAM_RANGE_INDEX, ++ QXL_VRAM_RANGE_INDEX, ++ }; ++ uint64_t guest_start; ++ uint64_t guest_end; ++ int pci_region; ++ pcibus_t pci_start; ++ pcibus_t pci_end; ++ intptr_t virt_start; ++ QXLDevMemSlot memslot; ++ int i; ++ ++ guest_start = le64_to_cpu(d->guest_slots[slot_id].slot.mem_start); ++ guest_end = le64_to_cpu(d->guest_slots[slot_id].slot.mem_end); ++ ++ dprintf(d, 1, "%s: slot %d: guest phys 0x%" PRIx64 " - 0x%" PRIx64 "\n", ++ __FUNCTION__, slot_id, ++ guest_start, guest_end); ++ ++ PANIC_ON(slot_id >= NUM_MEMSLOTS); ++ PANIC_ON(guest_start > guest_end); ++ ++ for (i = 0; i < ARRAY_SIZE(regions); i++) { ++ pci_region = regions[i]; ++ pci_start = d->pci.io_regions[pci_region].addr; ++ pci_end = pci_start + d->pci.io_regions[pci_region].size; ++ /* mapped? */ ++ if (pci_start == -1) { ++ continue; ++ } ++ /* start address in range ? */ ++ if (guest_start < pci_start || guest_start > pci_end) { ++ continue; ++ } ++ /* end address in range ? */ ++ if (guest_end > pci_end) { ++ continue; ++ } ++ /* passed */ ++ break; ++ } ++ PANIC_ON(i == ARRAY_SIZE(regions)); /* finished loop without match */ ++ ++ switch (pci_region) { ++ case QXL_RAM_RANGE_INDEX: ++ virt_start = (intptr_t)qemu_get_ram_ptr(d->vga.vram_offset); ++ break; ++ case QXL_VRAM_RANGE_INDEX: ++ virt_start = (intptr_t)qemu_get_ram_ptr(d->vram_offset); ++ break; ++ default: ++ /* should not happen */ ++ abort(); ++ } ++ ++ memslot.slot_id = slot_id; ++ memslot.slot_group_id = MEMSLOT_GROUP_GUEST; /* guest group */ ++ memslot.virt_start = virt_start + (guest_start - pci_start); ++ memslot.virt_end = virt_start + (guest_end - pci_start); ++ memslot.addr_delta = memslot.virt_start - delta; ++ memslot.generation = d->rom->slot_generation = 0; // FIXME d->generation++; ++ qxl_rom_set_dirty(d); ++ ++ dprintf(d, 1, "%s: slot %d: host virt 0x%" PRIx64 " - 0x%" PRIx64 "\n", ++ __FUNCTION__, memslot.slot_id, ++ memslot.virt_start, memslot.virt_end); ++ ++ d->ssd.worker->add_memslot(d->ssd.worker, &memslot); ++ d->guest_slots[slot_id].ptr = (void*)memslot.virt_start; ++ d->guest_slots[slot_id].size = memslot.virt_end - memslot.virt_start; ++ d->guest_slots[slot_id].delta = delta; ++ d->guest_slots[slot_id].active = 1; ++} ++ ++static void qxl_del_memslot(PCIQXLDevice *d, uint32_t slot_id) ++{ ++ dprintf(d, 1, "%s: slot %d\n", __FUNCTION__, slot_id); ++ d->ssd.worker->del_memslot(d->ssd.worker, MEMSLOT_GROUP_HOST, slot_id); ++ d->guest_slots[slot_id].active = 0; ++} ++ ++static void qxl_reset_memslots(PCIQXLDevice *d) ++{ ++ dprintf(d, 1, "%s:\n", __FUNCTION__); ++ d->ssd.worker->reset_memslots(d->ssd.worker); ++ memset(&d->guest_slots, 0, sizeof(d->guest_slots)); ++} ++ ++static void qxl_reset_surfaces(PCIQXLDevice *d) ++{ ++ dprintf(d, 1, "%s:\n", __FUNCTION__); ++ d->mode = QXL_MODE_UNDEFINED; ++ d->ssd.worker->destroy_surfaces(d->ssd.worker); ++ memset(&d->guest_surfaces.cmds, 0, sizeof(d->guest_surfaces.cmds)); ++} ++ ++void *qxl_phys2virt(PCIQXLDevice *qxl, QXLPHYSICAL pqxl, int group_id) ++{ ++ uint64_t phys = le64_to_cpu(pqxl); ++ uint32_t slot = (phys >> (64 - 8)) & 0xff; ++ uint64_t offset = phys & 0xffffffffffff; ++ ++ switch (group_id) { ++ case MEMSLOT_GROUP_HOST: ++ return (void*)offset; ++ case MEMSLOT_GROUP_GUEST: ++ PANIC_ON(slot > NUM_MEMSLOTS); ++ PANIC_ON(!qxl->guest_slots[slot].active); ++ PANIC_ON(offset < qxl->guest_slots[slot].delta); ++ offset -= qxl->guest_slots[slot].delta; ++ PANIC_ON(offset > qxl->guest_slots[slot].size) ++ return qxl->guest_slots[slot].ptr + offset; ++ default: ++ PANIC_ON(1); ++ } ++} ++ ++static void qxl_create_guest_primary(PCIQXLDevice *qxl, int loadvm) ++{ ++ QXLDevSurfaceCreate surface; ++ QXLSurfaceCreate *sc = &qxl->guest_primary.surface; ++ ++ assert(qxl->mode != QXL_MODE_NATIVE); ++ qxl_exit_vga_mode(qxl); ++ ++ dprintf(qxl, 1, "%s: %dx%d\n", __FUNCTION__, ++ le32_to_cpu(sc->width), le32_to_cpu(sc->height)); ++ ++ surface.format = le32_to_cpu(sc->format); ++ surface.height = le32_to_cpu(sc->height); ++ surface.mem = le64_to_cpu(sc->mem); ++ surface.position = le32_to_cpu(sc->position); ++ surface.stride = le32_to_cpu(sc->stride); ++ surface.width = le32_to_cpu(sc->width); ++ surface.type = le32_to_cpu(sc->type); ++ surface.flags = le32_to_cpu(sc->flags); ++ ++ surface.mouse_mode = true; ++ surface.group_id = MEMSLOT_GROUP_GUEST; ++ if (loadvm) { ++ surface.flags |= QXL_SURF_FLAG_KEEP_DATA; ++ } ++ ++ qxl->mode = QXL_MODE_NATIVE; ++ qxl->cmdflags = 0; ++ qxl->ssd.worker->create_primary_surface(qxl->ssd.worker, 0, &surface); ++ ++ /* for local rendering */ ++ qxl_render_resize(qxl); ++} ++ ++static void qxl_destroy_primary(PCIQXLDevice *d) ++{ ++ if (d->mode == QXL_MODE_UNDEFINED) { ++ return; ++ } ++ ++ dprintf(d, 1, "%s\n", __FUNCTION__); ++ ++ d->mode = QXL_MODE_UNDEFINED; ++ d->ssd.worker->destroy_primary_surface(d->ssd.worker, 0); ++} ++ ++static void qxl_set_mode(PCIQXLDevice *d, int modenr) ++{ ++ pcibus_t start = d->pci.io_regions[QXL_RAM_RANGE_INDEX].addr; ++ pcibus_t end = d->pci.io_regions[QXL_RAM_RANGE_INDEX].size + start; ++ QXLMode *mode = d->modes->modes + modenr; ++ uint64_t devmem = d->pci.io_regions[QXL_RAM_RANGE_INDEX].addr; ++ QXLMemSlot slot = { ++ .mem_start = start, ++ .mem_end = end ++ }; ++ QXLSurfaceCreate surface = { ++ .width = mode->x_res, ++ .height = mode->y_res, ++ .stride = -mode->x_res * 4, ++ .format = SPICE_SURFACE_FMT_32_xRGB, ++ .mouse_mode = true, ++ .mem = devmem, ++ }; ++ ++ dprintf(d, 1, "%s: mode %d [ %d x %d @ %d bpp devmem 0x%lx ]\n", __FUNCTION__, ++ modenr, mode->x_res, mode->y_res, mode->bits, devmem); ++ qxl_hard_reset(d, 0); ++ ++ d->guest_slots[0].slot = slot; ++ qxl_add_memslot(d, 0, devmem); ++ ++ d->guest_primary.surface = surface; ++ qxl_create_guest_primary(d, 0); ++ ++ d->mode = QXL_MODE_COMPAT; ++ d->cmdflags = QXL_COMMAND_FLAG_COMPAT; ++ d->shadow_rom.mode = cpu_to_le32(modenr); ++ d->rom->mode = cpu_to_le32(modenr); ++ qxl_rom_set_dirty(d); ++} ++ ++static void ioport_write(void *opaque, uint32_t addr, uint32_t val) ++{ ++ PCIQXLDevice *d = opaque; ++ uint32_t io_port = addr - d->io_base; ++ ++ switch (io_port) { ++ case QXL_IO_RESET: ++ case QXL_IO_SET_MODE: ++ case QXL_IO_MEMSLOT_ADD: ++ case QXL_IO_MEMSLOT_DEL: ++ case QXL_IO_CREATE_PRIMARY: ++ break; ++ default: ++ if (d->mode == QXL_MODE_NATIVE || d->mode == QXL_MODE_COMPAT) ++ break; ++ dprintf(d, 1, "%s: unexpected port 0x%x in vga mode\n", __FUNCTION__, io_port); ++ return; ++ } ++ ++ switch (io_port) { ++ case QXL_IO_UPDATE_AREA: ++ { ++ QXLRect update = d->ram->update_area; ++ d->ssd.worker->update_area(d->ssd.worker, d->ram->update_surface, ++ &update, NULL, 0, 0); ++ break; ++ } ++ case QXL_IO_NOTIFY_CMD: ++ d->ssd.worker->wakeup(d->ssd.worker); ++ break; ++ case QXL_IO_NOTIFY_CURSOR: ++ d->ssd.worker->wakeup(d->ssd.worker); ++ break; ++ case QXL_IO_UPDATE_IRQ: ++ qxl_set_irq(d); ++ break; ++ case QXL_IO_NOTIFY_OOM: ++ if (!SPICE_RING_IS_EMPTY(&d->ram->release_ring)) { ++ break; ++ } ++ pthread_yield(); ++ if (!SPICE_RING_IS_EMPTY(&d->ram->release_ring)) { ++ break; ++ } ++ d->ssd.worker->oom(d->ssd.worker); ++ break; ++ case QXL_IO_SET_MODE: ++ dprintf(d, 1, "QXL_SET_MODE %d\n", val); ++ qxl_set_mode(d, val); ++ break; ++ case QXL_IO_LOG: ++ dprintf(d, 1, "log %s", d->ram->log_buf); ++ break; ++ case QXL_IO_RESET: ++ dprintf(d, 1, "QXL_IO_RESET\n"); ++ qxl_hard_reset(d, 0); ++ break; ++ case QXL_IO_MEMSLOT_ADD: ++ PANIC_ON(val >= NUM_MEMSLOTS); ++ PANIC_ON(d->guest_slots[val].active); ++ d->guest_slots[val].slot = d->ram->mem_slot; ++ qxl_add_memslot(d, val, 0); ++ break; ++ case QXL_IO_MEMSLOT_DEL: ++ qxl_del_memslot(d, val); ++ break; ++ case QXL_IO_CREATE_PRIMARY: ++ PANIC_ON(val != 0); ++ dprintf(d, 1, "QXL_IO_CREATE_PRIMARY\n"); ++ d->guest_primary.surface = d->ram->create_surface; ++ qxl_create_guest_primary(d, 0); ++ break; ++ case QXL_IO_DESTROY_PRIMARY: ++ PANIC_ON(val != 0); ++ dprintf(d, 1, "QXL_IO_DESTROY_PRIMARY\n"); ++ qxl_destroy_primary(d); ++ break; ++ case QXL_IO_DESTROY_SURFACE_WAIT: ++ d->ssd.worker->destroy_surface_wait(d->ssd.worker, val); ++ break; ++ case QXL_IO_DESTROY_ALL_SURFACES: ++ d->ssd.worker->destroy_surfaces(d->ssd.worker); ++ break; ++ default: ++ fprintf(stderr, "%s: ioport=0x%x, abort()\n", __FUNCTION__, io_port); ++ abort(); ++ } ++} ++ ++static uint32_t ioport_read(void *opaque, uint32_t addr) ++{ ++ PCIQXLDevice *d = opaque; ++ ++ dprintf(d, 1, "%s: unexpected\n", __FUNCTION__); ++ return 0xff; ++} ++ ++static void qxl_map(PCIDevice *pci, int region_num, ++ pcibus_t addr, pcibus_t size, int type) ++{ ++ static const char *names[] = { ++ [ QXL_IO_RANGE_INDEX ] = "ioports", ++ [ QXL_RAM_RANGE_INDEX ] = "devram", ++ [ QXL_ROM_RANGE_INDEX ] = "rom", ++ [ QXL_VRAM_RANGE_INDEX ] = "vram", ++ }; ++ PCIQXLDevice *qxl = DO_UPCAST(PCIQXLDevice, pci, pci); ++ ++ dprintf(qxl, 1, "%s: bar %d [%s] addr 0x%lx size 0x%lx\n", __FUNCTION__, ++ region_num, names[region_num], addr, size); ++ ++ switch (region_num) { ++ case QXL_IO_RANGE_INDEX: ++ register_ioport_write(addr, size, 1, ioport_write, pci); ++ register_ioport_read(addr, size, 1, ioport_read, pci); ++ qxl->io_base = addr; ++ break; ++ case QXL_RAM_RANGE_INDEX: ++ cpu_register_physical_memory(addr, size, qxl->vga.vram_offset | IO_MEM_RAM); ++ qxl->vga.map_addr = addr; ++ qxl->vga.map_end = addr + size; ++ if (qxl->id == 0) { ++ vga_dirty_log_start(&qxl->vga); ++ } ++ break; ++ case QXL_ROM_RANGE_INDEX: ++ cpu_register_physical_memory(addr, size, qxl->rom_offset | IO_MEM_ROM); ++ break; ++ case QXL_VRAM_RANGE_INDEX: ++ cpu_register_physical_memory(addr, size, qxl->vram_offset | IO_MEM_RAM); ++ break; ++ } ++} ++ ++static void pipe_read(void *opaque) ++{ ++ PCIQXLDevice *d = opaque; ++ char dummy; ++ int len; ++ ++ do { ++ len = read(d->pipe[0], &dummy, sizeof(dummy)); ++ } while (len == sizeof(dummy)); ++ qxl_set_irq(d); ++} ++ ++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); ++ old_pending = __sync_fetch_and_or(&d->ram->int_pending, le_events); ++ if ((old_pending & le_events) == le_events) { ++ return; ++ } ++ if (pthread_self() == d->main) { ++ qxl_set_irq(d); ++ } else { ++ if (write(d->pipe[1], d, 1) != 1) { ++ dprintf(d, 1, "%s: write to pipe failed\n", __FUNCTION__); ++ } ++ } ++} ++ ++static void init_pipe_signaling(PCIQXLDevice *d) ++{ ++ if (pipe(d->pipe) < 0) { ++ dprintf(d, 1, "%s: pipe creation failed\n", __FUNCTION__); ++ return; ++ } ++#ifdef CONFIG_IOTHREAD ++ fcntl(d->pipe[0], F_SETFL, O_NONBLOCK); ++#else ++ fcntl(d->pipe[0], F_SETFL, O_NONBLOCK /* | O_ASYNC */); ++#endif ++ fcntl(d->pipe[1], F_SETFL, O_NONBLOCK); ++ fcntl(d->pipe[0], F_SETOWN, getpid()); ++ ++ d->main = pthread_self(); ++ qemu_set_fd_handler(d->pipe[0], pipe_read, NULL, d); ++} ++ ++/* graphics console */ ++ ++static void qxl_hw_update(void *opaque) ++{ ++ PCIQXLDevice *qxl = opaque; ++ VGACommonState *vga = &qxl->vga; ++ ++ switch (qxl->mode) { ++ case QXL_MODE_VGA: ++ vga->update(vga); ++ break; ++ case QXL_MODE_NATIVE: ++ qxl_render_update(qxl); ++ break; ++ default: ++ break; ++ } ++} ++ ++static void qxl_hw_invalidate(void *opaque) ++{ ++ PCIQXLDevice *qxl = opaque; ++ VGACommonState *vga = &qxl->vga; ++ ++ vga->invalidate(vga); ++} ++ ++static void qxl_hw_screen_dump(void *opaque, const char *filename) ++{ ++ PCIQXLDevice *qxl = opaque; ++ VGACommonState *vga = &qxl->vga; ++ ++ if (qxl->mode == QXL_MODE_VGA) { ++ vga->screen_dump(vga, filename); ++ return; ++ } ++} ++ ++static void qxl_hw_text_update(void *opaque, console_ch_t *chardata) ++{ ++ PCIQXLDevice *qxl = opaque; ++ VGACommonState *vga = &qxl->vga; ++ ++ if (qxl->mode == QXL_MODE_VGA) { ++ vga->text_update(vga, chardata); ++ return; ++ } ++} ++ ++static void qxl_vm_change_state_handler(void *opaque, int running, int reason) ++{ ++ PCIQXLDevice *qxl = opaque; ++ qemu_spice_vm_change_state_handler(&qxl->ssd, running, reason); ++ ++ if (!running && qxl->mode == QXL_MODE_NATIVE) { ++ /* dirty all vram (which holds surfaces) to make sure it is saved */ ++ /* FIXME #1: should go out during "live" stage */ ++ /* FIXME #2: we only need to save the areas which are actually used */ ++ ram_addr_t addr = qxl->vram_offset; ++ qxl_set_dirty(addr, addr + qxl->vram_size); ++ } ++} ++ ++/* display change listener */ ++ ++static void display_update(struct DisplayState *ds, int x, int y, int w, int h) ++{ ++ if (qxl0->mode == QXL_MODE_VGA) { ++ qemu_spice_display_update(&qxl0->ssd, x, y, w, h); ++ } ++} ++ ++static void display_resize(struct DisplayState *ds) ++{ ++ if (qxl0->mode == QXL_MODE_VGA) { ++ qemu_spice_display_resize(&qxl0->ssd); ++ } ++} ++ ++static void display_refresh(struct DisplayState *ds) ++{ ++ if (qxl0->mode == QXL_MODE_VGA) { ++ qemu_spice_display_refresh(&qxl0->ssd); ++ } ++} ++ ++static DisplayChangeListener display_listener = { ++ .dpy_update = display_update, ++ .dpy_resize = display_resize, ++ .dpy_refresh = display_refresh, ++}; ++ ++static int qxl_init(PCIDevice *dev) ++{ ++ PCIQXLDevice *qxl = DO_UPCAST(PCIQXLDevice, pci, dev); ++ VGACommonState *vga = &qxl->vga; ++ uint8_t* config = qxl->pci.config; ++ ram_addr_t ram_size = msb_mask(qxl->vga.vram_size * 2 - 1); ++ uint32_t pci_device_id; ++ uint32_t pci_device_rev; ++ ++ if (device_id == 0 && dev->qdev.hotplugged) { ++ device_id++; ++ } ++ ++ qxl->id = device_id; ++ qxl->mode = QXL_MODE_UNDEFINED; ++ qxl->generation = 1; ++ qxl->num_memslots = NUM_MEMSLOTS; ++ qxl->num_surfaces = NUM_SURFACES; ++ ++ switch (qxl->revision) { ++ case 1: /* spice 0.4 -- qxl-1 */ ++ pci_device_id = QXL_DEVICE_ID_STABLE; ++ pci_device_rev = QXL_REVISION_STABLE_V04; ++ break; ++ case 2: /* spice 0.6 -- qxl-2 */ ++ pci_device_id = QXL_DEVICE_ID_STABLE; ++ pci_device_rev = QXL_REVISION_STABLE_V06; ++ break; ++ default: /* experimental */ ++ pci_device_id = QXL_DEVICE_ID_DEVEL; ++ pci_device_rev = 1; ++ break; ++ } ++ ++ if (!qxl->id) { ++ if (ram_size < 32 * 1024 * 1024) ++ ram_size = 32 * 1024 * 1024; ++ vga_common_init(vga, ram_size); ++ vga_init(vga); ++ register_ioport_write(0x3c0, 16, 1, qxl_vga_ioport_write, vga); ++ register_ioport_write(0x3b4, 2, 1, qxl_vga_ioport_write, vga); ++ register_ioport_write(0x3d4, 2, 1, qxl_vga_ioport_write, vga); ++ register_ioport_write(0x3ba, 1, 1, qxl_vga_ioport_write, vga); ++ register_ioport_write(0x3da, 1, 1, qxl_vga_ioport_write, vga); ++ ++ vga->ds = graphic_console_init(qxl_hw_update, qxl_hw_invalidate, ++ qxl_hw_screen_dump, qxl_hw_text_update, qxl); ++ qxl->ssd.ds = vga->ds; ++ qxl->ssd.bufsize = (16 * 1024 * 1024); ++ qxl->ssd.buf = qemu_malloc(qxl->ssd.bufsize); ++ pthread_mutex_init(&qxl->ssd.lock, NULL); ++ ++ qxl0 = qxl; ++ register_displaychangelistener(vga->ds, &display_listener); ++ ++ if (qxl->pci.romfile == NULL) { ++ if (pci_device_id == 0x01ff) { ++ qxl->pci.romfile = qemu_strdup("vgabios-qxldev.bin"); ++ } else { ++ qxl->pci.romfile = qemu_strdup("vgabios-qxl.bin"); ++ } ++ } ++ pci_config_set_class(config, PCI_CLASS_DISPLAY_VGA); ++ } else { ++ if (ram_size < 16 * 1024 * 1024) ++ ram_size = 16 * 1024 * 1024; ++ qxl->vga.vram_size = ram_size; ++ qxl->vga.vram_offset = qemu_ram_alloc(&qxl->pci.qdev, "qxl.vgavram", ++ qxl->vga.vram_size); ++ qxl->vga.vram_ptr = qemu_get_ram_ptr(qxl->vga.vram_offset); ++ ++ pci_config_set_class(config, PCI_CLASS_DISPLAY_OTHER); ++ } ++ ++ pci_config_set_vendor_id(config, REDHAT_PCI_VENDOR_ID); ++ pci_config_set_device_id(config, pci_device_id); ++ pci_set_byte(&config[PCI_REVISION_ID], pci_device_rev); ++ pci_set_byte(&config[PCI_INTERRUPT_PIN], 1); ++ ++ qxl->rom_size = qxl_rom_size(); ++ qxl->rom_offset = qemu_ram_alloc(&qxl->pci.qdev, "qxl.vrom", qxl->rom_size); ++ init_qxl_rom(qxl); ++ init_qxl_ram(qxl); ++ ++ if (qxl->vram_size < 16 * 1024 * 1024) ++ qxl->vram_size = 16 * 1024 * 1024; ++ qxl->vram_size = msb_mask(qxl->vram_size * 2 - 1); ++ qxl->vram_offset = qemu_ram_alloc(&qxl->pci.qdev, "qxl.vram", qxl->vram_size); ++ ++ pci_register_bar(&qxl->pci, QXL_IO_RANGE_INDEX, ++ msb_mask(QXL_IO_RANGE_SIZE * 2 - 1), ++ PCI_BASE_ADDRESS_SPACE_IO, qxl_map); ++ ++ pci_register_bar(&qxl->pci, QXL_ROM_RANGE_INDEX, ++ qxl->rom_size, PCI_BASE_ADDRESS_SPACE_MEMORY, ++ qxl_map); ++ ++ pci_register_bar(&qxl->pci, QXL_RAM_RANGE_INDEX, ++ qxl->vga.vram_size, PCI_BASE_ADDRESS_SPACE_MEMORY, ++ qxl_map); ++ ++ pci_register_bar(&qxl->pci, QXL_VRAM_RANGE_INDEX, qxl->vram_size, ++ PCI_BASE_ADDRESS_SPACE_MEMORY, qxl_map); ++ ++ qxl->ssd.qxl.base.sif = &qxl_interface.base; ++ qxl->ssd.qxl.id = qxl->id; ++ spice_server_add_interface(spice_server, &qxl->ssd.qxl.base); ++ qemu_add_vm_change_state_handler(qxl_vm_change_state_handler, qxl); ++ ++ init_pipe_signaling(qxl); ++ qxl_reset_state(qxl); ++ ++ device_id++; ++ return 0; ++} ++ ++static void qxl_pre_save(void *opaque) ++{ ++ PCIQXLDevice* d = opaque; ++ uint8_t *ram_start = d->vga.vram_ptr; ++ ++ dprintf(d, 1, "%s:\n", __FUNCTION__); ++ if (d->last_release == NULL) { ++ d->last_release_offset = 0; ++ } else { ++ d->last_release_offset = (uint8_t *)d->last_release - ram_start; ++ } ++ assert(d->last_release_offset < d->vga.vram_size); ++} ++ ++static int qxl_pre_load(void *opaque) ++{ ++ PCIQXLDevice* d = opaque; ++ ++ dprintf(d, 1, "%s: start\n", __FUNCTION__); ++ qxl_hard_reset(d, 1); ++ qxl_exit_vga_mode(d); ++ dprintf(d, 1, "%s: done\n", __FUNCTION__); ++ return 0; ++} ++ ++static int qxl_post_load(void *opaque, int version) ++{ ++ PCIQXLDevice* d = opaque; ++ uint8_t *ram_start = d->vga.vram_ptr; ++ QXLCommandExt *cmds; ++ int in, out, i, newmode; ++ ++ dprintf(d, 1, "%s: start\n", __FUNCTION__); ++ newmode = d->mode; ++ d->mode = QXL_MODE_UNDEFINED; ++ switch (newmode) { ++ case QXL_MODE_UNDEFINED: ++ break; ++ case QXL_MODE_VGA: ++ qxl_enter_vga_mode(d); ++ break; ++ case QXL_MODE_NATIVE: ++ for (i = 0; i < NUM_MEMSLOTS; i++) { ++ if (!d->guest_slots[i].active) ++ continue; ++ qxl_add_memslot(d, i, 0); ++ } ++ qxl_create_guest_primary(d, 1); ++ ++ /* replay surface-create and cursor-set commands */ ++ cmds = qemu_mallocz(sizeof(QXLCommandExt) * (NUM_SURFACES + 1)); ++ for (in = 0, out = 0; in < NUM_SURFACES; in++) { ++ if (d->guest_surfaces.cmds[in] == 0) ++ continue; ++ cmds[out].cmd.data = d->guest_surfaces.cmds[in]; ++ cmds[out].cmd.type = QXL_CMD_SURFACE; ++ cmds[out].group_id = MEMSLOT_GROUP_GUEST; ++ out++; ++ } ++ cmds[out].cmd.data = d->guest_cursor; ++ cmds[out].cmd.type = QXL_CMD_CURSOR; ++ cmds[out].group_id = MEMSLOT_GROUP_GUEST; ++ out++; ++ d->ssd.worker->loadvm_commands(d->ssd.worker, cmds, out); ++ qemu_free(cmds); ++ ++ break; ++ case QXL_MODE_COMPAT: ++ qxl_set_mode(d, d->shadow_rom.mode); ++ break; ++ } ++ dprintf(d, 1, "%s: done\n", __FUNCTION__); ++ ++ assert(d->last_release_offset < d->vga.vram_size); ++ if (d->last_release_offset == 0) { ++ d->last_release = NULL; ++ } else { ++ d->last_release = (QXLReleaseInfo *)(ram_start + d->last_release_offset); ++ } ++ ++ /* spice 0.4 compatibility -- accept but ignore */ ++ free(d->worker_data); ++ d->worker_data = NULL; ++ d->worker_data_size = 0; ++ ++ return 0; ++} ++ ++#define QXL_SAVE_VERSION 20 ++ ++static bool qxl_test_worker_data(void *opaque, int version_id) ++{ ++ PCIQXLDevice* d = opaque; ++ ++ if (d->revision != 1) { ++ return false; ++ } ++ if (!d->worker_data_size) { ++ return false; ++ } ++ if (!d->worker_data) { ++ d->worker_data = qemu_malloc(d->worker_data_size); ++ } ++ return true; ++} ++ ++static bool qxl_test_spice04(void *opaque, int version_id) ++{ ++ PCIQXLDevice* d = opaque; ++ return d->revision == 1; ++} ++ ++static bool qxl_test_spice06(void *opaque) ++{ ++ PCIQXLDevice* d = opaque; ++ return d->revision > 1; ++} ++ ++static VMStateDescription qxl_memslot = { ++ .name = "qxl-memslot", ++ .version_id = QXL_SAVE_VERSION, ++ .minimum_version_id = QXL_SAVE_VERSION, ++ .fields = (VMStateField[]) { ++ VMSTATE_UINT64(slot.mem_start, struct guest_slots), ++ VMSTATE_UINT64(slot.mem_end, struct guest_slots), ++ VMSTATE_UINT32(active, struct guest_slots), ++ VMSTATE_END_OF_LIST() ++ } ++}; ++ ++static VMStateDescription qxl_surface = { ++ .name = "qxl-surface", ++ .version_id = QXL_SAVE_VERSION, ++ .minimum_version_id = QXL_SAVE_VERSION, ++ .fields = (VMStateField[]) { ++ VMSTATE_UINT32(width, QXLSurfaceCreate), ++ VMSTATE_UINT32(height, QXLSurfaceCreate), ++ VMSTATE_INT32(stride, QXLSurfaceCreate), ++ VMSTATE_UINT32(format, QXLSurfaceCreate), ++ VMSTATE_UINT32(position, QXLSurfaceCreate), ++ VMSTATE_UINT32(mouse_mode, QXLSurfaceCreate), ++ VMSTATE_UINT32(flags, QXLSurfaceCreate), ++ VMSTATE_UINT32(type, QXLSurfaceCreate), ++ VMSTATE_UINT64(mem, QXLSurfaceCreate), ++ VMSTATE_END_OF_LIST() ++ } ++}; ++ ++static VMStateDescription qxl_vmstate_spice06 = { ++ .name = "qxl/spice06", ++ .version_id = QXL_SAVE_VERSION, ++ .minimum_version_id = QXL_SAVE_VERSION, ++ .fields = (VMStateField []) { ++ VMSTATE_INT32_EQUAL(num_memslots, PCIQXLDevice), ++ VMSTATE_STRUCT_ARRAY(guest_slots, PCIQXLDevice, NUM_MEMSLOTS, 0, ++ 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_UINT64(guest_cursor, PCIQXLDevice), ++ VMSTATE_END_OF_LIST() ++ }, ++}; ++ ++static VMStateDescription qxl_vmstate = { ++ .name = "qxl", ++ .version_id = QXL_SAVE_VERSION, ++ .minimum_version_id = QXL_SAVE_VERSION, ++ .pre_save = qxl_pre_save, ++ .pre_load = qxl_pre_load, ++ .post_load = qxl_post_load, ++ .fields = (VMStateField []) { ++ VMSTATE_PCI_DEVICE(pci, PCIQXLDevice), ++ VMSTATE_STRUCT(vga, PCIQXLDevice, 0, vmstate_vga_common, VGACommonState), ++ VMSTATE_UINT32(shadow_rom.mode, PCIQXLDevice), ++ VMSTATE_UINT32(num_free_res, PCIQXLDevice), ++ VMSTATE_UINT32(last_release_offset, PCIQXLDevice), ++ VMSTATE_UINT32(mode, PCIQXLDevice), ++ VMSTATE_UINT32(ssd.unique, PCIQXLDevice), ++ ++ /* spice 0.4 sends/expects them */ ++ VMSTATE_VBUFFER_UINT32(vga.vram_ptr, PCIQXLDevice, 0, qxl_test_spice04, 0, ++ vga.vram_size), ++ VMSTATE_UINT32_TEST(worker_data_size, PCIQXLDevice, qxl_test_spice04), ++ VMSTATE_VBUFFER_UINT32(worker_data, PCIQXLDevice, 0, qxl_test_worker_data, 0, ++ worker_data_size), ++ ++ VMSTATE_END_OF_LIST() ++ }, ++ .subsections = (VMStateSubsection[]) { ++ { ++ /* additional spice 0.6 state */ ++ .vmsd = &qxl_vmstate_spice06, ++ .needed = qxl_test_spice06, ++ },{ ++ /* end of list */ ++ }, ++ }, ++}; ++ ++static PCIDeviceInfo qxl_info = { ++ .qdev.name = "qxl", ++ .qdev.desc = "Spice QXL GPU", ++ .qdev.size = sizeof(PCIQXLDevice), ++ .qdev.reset = qxl_reset_handler, ++ .qdev.vmsd = &qxl_vmstate, ++ .init = qxl_init, ++ .config_write = qxl_write_config, ++ .qdev.props = (Property[]) { ++ DEFINE_PROP_UINT32("ram_size", PCIQXLDevice, vga.vram_size, 64 * 1024 * 1024), ++ DEFINE_PROP_UINT32("vram_size", PCIQXLDevice, vram_size, 64 * 1024 * 1024), ++ DEFINE_PROP_UINT32("revision", PCIQXLDevice, revision, 2), ++ DEFINE_PROP_UINT32("debug", PCIQXLDevice, debug, 0), ++ DEFINE_PROP_UINT32("cmdlog", PCIQXLDevice, cmdlog, 0), ++ DEFINE_PROP_END_OF_LIST(), ++ } ++}; ++ ++static void qxl_register(void) ++{ ++ pci_qdev_register(&qxl_info); ++} ++ ++device_init(qxl_register); +diff -urN qemu-kvm-0.13.0.orig/hw/qxl.h qemu-kvm-0.13.0/hw/qxl.h +--- qemu-kvm-0.13.0.orig/hw/qxl.h 1970-01-01 02:00:00.000000000 +0200 ++++ qemu-kvm-0.13.0/hw/qxl.h 2011-02-09 11:08:02.854000327 +0200 +@@ -0,0 +1,108 @@ ++#include "console.h" ++#include "hw.h" ++#include "pci.h" ++#include "vga_int.h" ++ ++#include "qemu-spice.h" ++#include "spice-display.h" ++ ++enum qxl_mode { ++ QXL_MODE_UNDEFINED, ++ QXL_MODE_VGA, ++ QXL_MODE_COMPAT, /* spice 0.4.x */ ++ QXL_MODE_NATIVE, ++}; ++ ++typedef struct PCIQXLDevice { ++ PCIDevice pci; ++ SimpleSpiceDisplay ssd; ++ int id; ++ uint32_t debug; ++ uint32_t cmdlog; ++ enum qxl_mode mode; ++ uint32_t cmdflags; ++ int generation; ++ uint32_t revision; ++ ++ int32_t num_memslots; ++ int32_t num_surfaces; ++ ++ struct guest_slots { ++ QXLMemSlot slot; ++ void *ptr; ++ uint64_t size; ++ uint64_t delta; ++ uint32_t active; ++ } guest_slots[NUM_MEMSLOTS]; ++ ++ struct guest_primary { ++ QXLSurfaceCreate surface; ++ uint32_t commands; ++ uint32_t resized; ++ int32_t stride; ++ uint32_t bits_pp; ++ uint32_t bytes_pp; ++ uint8_t *data, *flipped; ++ } guest_primary; ++ ++ struct surfaces { ++ QXLPHYSICAL cmds[NUM_SURFACES]; ++ uint32_t count; ++ uint32_t max; ++ } guest_surfaces; ++ QXLPHYSICAL guest_cursor; ++ ++ /* thread signaling */ ++ pthread_t main; ++ int pipe[2]; ++ ++ /* ram pci bar */ ++ QXLRam *ram; ++ VGACommonState vga; ++ uint32_t num_free_res; ++ QXLReleaseInfo *last_release; ++ uint32_t last_release_offset; ++ ++ /* rom pci bar */ ++ QXLRom shadow_rom; ++ QXLRom *rom; ++ QXLModes *modes; ++ uint32_t rom_size; ++ uint64_t rom_offset; ++ ++ /* vram pci bar */ ++ uint32_t vram_size; ++ uint64_t vram_offset; ++ ++ /* io bar */ ++ uint32_t io_base; ++ ++ /* spice 0.4 loadvm compatibility */ ++ void *worker_data; ++ uint32_t worker_data_size; ++} PCIQXLDevice; ++ ++#define PANIC_ON(x) if ((x)) { \ ++ printf("%s: PANIC %s failed\n", __FUNCTION__, #x); \ ++ exit(-1); \ ++} ++ ++#define dprintf(_qxl, _level, _fmt, ...) \ ++ do { \ ++ if (_qxl->debug >= _level) { \ ++ fprintf(stderr, "qxl-%d: ", _qxl->id); \ ++ fprintf(stderr, _fmt, ## __VA_ARGS__); \ ++ } \ ++ } while (0) ++ ++/* qxl.c */ ++void *qxl_phys2virt(PCIQXLDevice *qxl, QXLPHYSICAL phys, int group_id); ++ ++/* qxl-logger.c */ ++void qxl_log_cmd_cursor(PCIQXLDevice *qxl, QXLCursorCmd *cmd, int group_id); ++void qxl_log_command(PCIQXLDevice *qxl, const char *ring, QXLCommandExt *ext); ++ ++/* qxl-render.c */ ++void qxl_render_resize(PCIQXLDevice *qxl); ++void qxl_render_update(PCIQXLDevice *qxl); ++void qxl_render_cursor(PCIQXLDevice *qxl, QXLCommandExt *ext); +diff -urN qemu-kvm-0.13.0.orig/hw/qxl-logger.c qemu-kvm-0.13.0/hw/qxl-logger.c +--- qemu-kvm-0.13.0.orig/hw/qxl-logger.c 1970-01-01 02:00:00.000000000 +0200 ++++ qemu-kvm-0.13.0/hw/qxl-logger.c 2011-02-09 11:08:02.766000327 +0200 +@@ -0,0 +1,179 @@ ++/* ++ * qxl command logging -- for debug purposes ++ */ ++ ++#include <stdio.h> ++#include <stdbool.h> ++#include <stdint.h> ++#include <string.h> ++ ++#include "qxl.h" ++ ++static const char *qxl_type[] = { ++ [ QXL_CMD_NOP ] = "nop", ++ [ QXL_CMD_DRAW ] = "draw", ++ [ QXL_CMD_UPDATE ] = "update", ++ [ QXL_CMD_CURSOR ] = "cursor", ++ [ QXL_CMD_MESSAGE ] = "message", ++ [ QXL_CMD_SURFACE ] = "surface", ++}; ++ ++static const char *qxl_draw_type[] = { ++ [ QXL_DRAW_NOP ] = "nop", ++ [ QXL_DRAW_FILL ] = "fill", ++ [ QXL_DRAW_OPAQUE ] = "opaque", ++ [ QXL_DRAW_COPY ] = "copy", ++ [ QXL_COPY_BITS ] = "copy-bits", ++ [ QXL_DRAW_BLEND ] = "blend", ++ [ QXL_DRAW_BLACKNESS ] = "blackness", ++ [ QXL_DRAW_WHITENESS ] = "whitemess", ++ [ QXL_DRAW_INVERS ] = "invers", ++ [ QXL_DRAW_ROP3 ] = "rop3", ++ [ QXL_DRAW_STROKE ] = "stroke", ++ [ QXL_DRAW_TEXT ] = "text", ++ [ QXL_DRAW_TRANSPARENT ] = "transparent", ++ [ QXL_DRAW_ALPHA_BLEND ] = "alpha-blend", ++}; ++ ++static const char *qxl_draw_effect[] = { ++ [ QXL_EFFECT_BLEND ] = "blend", ++ [ QXL_EFFECT_OPAQUE ] = "opaque", ++ [ QXL_EFFECT_REVERT_ON_DUP ] = "revert-on-dup", ++ [ QXL_EFFECT_BLACKNESS_ON_DUP ] = "blackness-on-dup", ++ [ QXL_EFFECT_WHITENESS_ON_DUP ] = "whiteness-on-dup", ++ [ QXL_EFFECT_NOP_ON_DUP ] = "nop-on-dup", ++ [ QXL_EFFECT_NOP ] = "nop", ++ [ QXL_EFFECT_OPAQUE_BRUSH ] = "opaque-brush", ++}; ++ ++static const char *qxl_surface_cmd[] = { ++ [ QXL_SURFACE_CMD_CREATE ] = "create", ++ [ QXL_SURFACE_CMD_DESTROY ] = "destroy", ++}; ++ ++static const char *spice_surface_fmt[] = { ++ [ SPICE_SURFACE_FMT_INVALID ] = "invalid", ++ [ SPICE_SURFACE_FMT_1_A ] = "alpha/1", ++ [ SPICE_SURFACE_FMT_8_A ] = "alpha/8", ++ [ SPICE_SURFACE_FMT_16_555 ] = "555/16", ++ [ SPICE_SURFACE_FMT_16_565 ] = "565/16", ++ [ SPICE_SURFACE_FMT_32_xRGB ] = "xRGB/32", ++ [ SPICE_SURFACE_FMT_32_ARGB ] = "ARGB/32", ++}; ++ ++static const char *qxl_cursor_cmd[] = { ++ [ QXL_CURSOR_SET ] = "set", ++ [ QXL_CURSOR_MOVE ] = "move", ++ [ QXL_CURSOR_HIDE ] = "hide", ++ [ QXL_CURSOR_TRAIL ] = "trail", ++}; ++ ++static const char *spice_cursor_type[] = { ++ [ SPICE_CURSOR_TYPE_ALPHA ] = "alpha", ++ [ SPICE_CURSOR_TYPE_MONO ] = "mono", ++ [ SPICE_CURSOR_TYPE_COLOR4 ] = "color4", ++ [ SPICE_CURSOR_TYPE_COLOR8 ] = "color8", ++ [ SPICE_CURSOR_TYPE_COLOR16 ] = "color16", ++ [ SPICE_CURSOR_TYPE_COLOR24 ] = "color24", ++ [ SPICE_CURSOR_TYPE_COLOR32 ] = "color32", ++}; ++ ++static const char *qxl_v2n(const char *n[], size_t l, int v) ++{ ++ if (v >= l || !n[v]) ++ return "???"; ++ return n[v]; ++} ++#define qxl_name(_list, _value) qxl_v2n(_list, ARRAY_SIZE(_list), _value) ++ ++static void qxl_log_cmd_draw(PCIQXLDevice *qxl, QXLDrawable *draw) ++{ ++ fprintf(stderr, ": surface_id %d type %s effect %s", ++ draw->surface_id, ++ qxl_name(qxl_draw_type, draw->type), ++ qxl_name(qxl_draw_effect, draw->effect)); ++} ++ ++static void qxl_log_cmd_draw_compat(PCIQXLDevice *qxl, QXLCompatDrawable *draw) ++{ ++ fprintf(stderr, ": type %s effect %s", ++ qxl_name(qxl_draw_type, draw->type), ++ qxl_name(qxl_draw_effect, draw->effect)); ++} ++ ++static void qxl_log_cmd_surface(PCIQXLDevice *qxl, QXLSurfaceCmd *cmd) ++{ ++ fprintf(stderr, ": %s id %d", ++ qxl_name(qxl_surface_cmd, cmd->type), ++ cmd->surface_id); ++ if (cmd->type == QXL_SURFACE_CMD_CREATE) { ++ fprintf(stderr, " size %dx%d stride %d format %s (count %d, max %d)", ++ cmd->u.surface_create.width, ++ cmd->u.surface_create.height, ++ cmd->u.surface_create.stride, ++ qxl_name(spice_surface_fmt, cmd->u.surface_create.format), ++ qxl->guest_surfaces.count, qxl->guest_surfaces.max); ++ } ++ if (cmd->type == QXL_SURFACE_CMD_DESTROY) { ++ fprintf(stderr, " (count %d)", qxl->guest_surfaces.count); ++ } ++} ++ ++void qxl_log_cmd_cursor(PCIQXLDevice *qxl, QXLCursorCmd *cmd, int group_id) ++{ ++ QXLCursor *cursor; ++ ++ fprintf(stderr, ": %s", ++ qxl_name(qxl_cursor_cmd, cmd->type)); ++ switch (cmd->type) { ++ case QXL_CURSOR_SET: ++ fprintf(stderr, " +%d+%d visible %s, shape @ 0x%" PRIx64, ++ cmd->u.set.position.x, ++ cmd->u.set.position.y, ++ cmd->u.set.visible ? "yes" : "no", ++ cmd->u.set.shape); ++ cursor = qxl_phys2virt(qxl, cmd->u.set.shape, group_id); ++ fprintf(stderr, " type %s size %dx%d hot-spot +%d+%d" ++ " unique 0x%" PRIx64 " data-size %d", ++ qxl_name(spice_cursor_type, cursor->header.type), ++ cursor->header.width, cursor->header.height, ++ cursor->header.hot_spot_x, cursor->header.hot_spot_y, ++ cursor->header.unique, cursor->data_size); ++ break; ++ case QXL_CURSOR_MOVE: ++ fprintf(stderr, " +%d+%d", cmd->u.position.x, cmd->u.position.y); ++ break; ++ } ++} ++ ++void qxl_log_command(PCIQXLDevice *qxl, const char *ring, QXLCommandExt *ext) ++{ ++ bool compat = ext->flags & QXL_COMMAND_FLAG_COMPAT; ++ void *data; ++ ++ if (!qxl->cmdlog) { ++ return; ++ } ++ fprintf(stderr, "qxl-%d/%s:", qxl->id, ring); ++ fprintf(stderr, " cmd @ 0x%" PRIx64 " %s%s", ext->cmd.data, ++ qxl_name(qxl_type, ext->cmd.type), ++ compat ? "(compat)" : ""); ++ ++ data = qxl_phys2virt(qxl, ext->cmd.data, ext->group_id); ++ switch (ext->cmd.type) { ++ case QXL_CMD_DRAW: ++ if (!compat) { ++ qxl_log_cmd_draw(qxl, data); ++ } else { ++ qxl_log_cmd_draw_compat(qxl, data); ++ } ++ break; ++ case QXL_CMD_SURFACE: ++ qxl_log_cmd_surface(qxl, data); ++ break; ++ case QXL_CMD_CURSOR: ++ qxl_log_cmd_cursor(qxl, data, ext->group_id); ++ break; ++ } ++ fprintf(stderr, "\n"); ++} +diff -urN qemu-kvm-0.13.0.orig/hw/qxl-render.c qemu-kvm-0.13.0/hw/qxl-render.c +--- qemu-kvm-0.13.0.orig/hw/qxl-render.c 1970-01-01 02:00:00.000000000 +0200 ++++ qemu-kvm-0.13.0/hw/qxl-render.c 2011-02-09 11:08:02.766000327 +0200 +@@ -0,0 +1,207 @@ ++/* ++ * qxl local rendering (aka display on sdl/vnc) ++ */ ++#include <stdio.h> ++#include <stdbool.h> ++#include <stdint.h> ++#include <string.h> ++ ++#include "qxl.h" ++ ++static void qxl_flip(PCIQXLDevice *qxl, QXLRect *rect) ++{ ++ uint8_t *src = qxl->guest_primary.data; ++ uint8_t *dst = qxl->guest_primary.flipped; ++ int len, i; ++ ++ src += (qxl->guest_primary.surface.height - rect->top - 1) * ++ qxl->guest_primary.stride; ++ dst += rect->top * qxl->guest_primary.stride; ++ src += rect->left * qxl->guest_primary.bytes_pp; ++ dst += rect->left * qxl->guest_primary.bytes_pp; ++ len = (rect->right - rect->left) * qxl->guest_primary.bytes_pp; ++ ++ for (i = rect->top; i < rect->bottom; i++) { ++ memcpy(dst, src, len); ++ dst += qxl->guest_primary.stride; ++ src -= qxl->guest_primary.stride; ++ } ++} ++ ++void qxl_render_resize(PCIQXLDevice *qxl) ++{ ++ QXLSurfaceCreate *sc = &qxl->guest_primary.surface; ++ ++ qxl->guest_primary.stride = sc->stride; ++ qxl->guest_primary.resized++; ++ switch (sc->format) { ++ case SPICE_SURFACE_FMT_16_555: ++ qxl->guest_primary.bytes_pp = 2; ++ qxl->guest_primary.bits_pp = 15; ++ break; ++ case SPICE_SURFACE_FMT_16_565: ++ qxl->guest_primary.bytes_pp = 2; ++ qxl->guest_primary.bits_pp = 16; ++ break; ++ case SPICE_SURFACE_FMT_32_xRGB: ++ case SPICE_SURFACE_FMT_32_ARGB: ++ qxl->guest_primary.bytes_pp = 4; ++ qxl->guest_primary.bits_pp = 32; ++ break; ++ default: ++ fprintf(stderr, "%s: unhandled format: %x\n", __FUNCTION__, ++ qxl->guest_primary.surface.format); ++ qxl->guest_primary.bytes_pp = 4; ++ qxl->guest_primary.bits_pp = 32; ++ break; ++ } ++} ++ ++void qxl_render_update(PCIQXLDevice *qxl) ++{ ++ VGACommonState *vga = &qxl->vga; ++ QXLRect dirty[32], update; ++ void *ptr; ++ int i; ++ ++ if (qxl->guest_primary.resized) { ++ qxl->guest_primary.resized = 0; ++ ++ if (qxl->guest_primary.flipped) { ++ qemu_free(qxl->guest_primary.flipped); ++ qxl->guest_primary.flipped = NULL; ++ } ++ qemu_free_displaysurface(vga->ds); ++ ++ qxl->guest_primary.data = qemu_get_ram_ptr(qxl->vga.vram_offset); ++ if (qxl->guest_primary.stride < 0) { ++ /* spice surface is upside down -> need extra buffer to flip */ ++ qxl->guest_primary.stride = -qxl->guest_primary.stride; ++ qxl->guest_primary.flipped = qemu_malloc(qxl->guest_primary.surface.width * ++ qxl->guest_primary.stride); ++ ptr = qxl->guest_primary.flipped; ++ } else { ++ ptr = qxl->guest_primary.data; ++ } ++ fprintf(stderr, "%s: %dx%d, stride %d, bpp %d, depth %d, flip %s\n", ++ __FUNCTION__, ++ qxl->guest_primary.surface.width, ++ qxl->guest_primary.surface.height, ++ qxl->guest_primary.stride, ++ qxl->guest_primary.bytes_pp, ++ qxl->guest_primary.bits_pp, ++ qxl->guest_primary.flipped ? "yes" : "no"); ++ vga->ds->surface = ++ qemu_create_displaysurface_from(qxl->guest_primary.surface.width, ++ qxl->guest_primary.surface.height, ++ qxl->guest_primary.bits_pp, ++ qxl->guest_primary.stride, ++ ptr); ++ dpy_resize(vga->ds); ++ } ++ ++ if (!qxl->guest_primary.commands) ++ return; ++ qxl->guest_primary.commands = 0; ++ ++ update.left = 0; ++ update.right = qxl->guest_primary.surface.width; ++ update.top = 0; ++ update.bottom = qxl->guest_primary.surface.height; ++ ++ memset(dirty, 0, sizeof(dirty)); ++ qxl->ssd.worker->update_area(qxl->ssd.worker, 0, &update, ++ dirty, ARRAY_SIZE(dirty), 1); ++ ++ for (i = 0; i < ARRAY_SIZE(dirty); i++) { ++ if (qemu_spice_rect_is_empty(dirty+i)) ++ break; ++ if (qxl->guest_primary.flipped) { ++ qxl_flip(qxl, dirty+i); ++ } ++ dpy_update(vga->ds, ++ dirty[i].left, dirty[i].top, ++ dirty[i].right - dirty[i].left, ++ dirty[i].bottom - dirty[i].top); ++ } ++} ++ ++static QEMUCursor *qxl_cursor(PCIQXLDevice *qxl, QXLCursor *cursor) ++{ ++ QEMUCursor *c; ++ uint8_t *image, *mask; ++ int size; ++ ++ c = cursor_alloc(cursor->header.width, cursor->header.height); ++ c->hot_x = cursor->header.hot_spot_x; ++ c->hot_y = cursor->header.hot_spot_y; ++ switch (cursor->header.type) { ++ case SPICE_CURSOR_TYPE_ALPHA: ++ size = cursor->header.width * cursor->header.height * sizeof(uint32_t); ++ memcpy(c->data, cursor->chunk.data, size); ++ if (qxl->debug > 1) ++ cursor_print_ascii_art(c, "qxl/alpha"); ++ break; ++ case SPICE_CURSOR_TYPE_MONO: ++ mask = cursor->chunk.data; ++ image = mask + cursor_get_mono_bpl(c) * c->width; ++ cursor_set_mono(c, 0xffffff, 0x000000, image, 1, mask); ++ if (qxl->debug > 1) ++ cursor_print_ascii_art(c, "qxl/mono"); ++ break; ++ default: ++ fprintf(stderr, "%s: not implemented: type %d\n", ++ __FUNCTION__, cursor->header.type); ++ goto fail; ++ } ++ return c; ++ ++fail: ++ cursor_put(c); ++ return NULL; ++} ++ ++ ++void qxl_render_cursor(PCIQXLDevice *qxl, QXLCommandExt *ext) ++{ ++ QXLCursorCmd *cmd = qxl_phys2virt(qxl, ext->cmd.data, ext->group_id); ++ QXLCursor *cursor; ++ QEMUCursor *c; ++ int x = -1, y = -1; ++ ++ if (!qxl->ssd.ds->mouse_set || ++ !qxl->ssd.ds->cursor_define) ++ return; ++ ++#if 1 ++ if (cmd->type != QXL_CURSOR_MOVE) { ++ fprintf(stderr, "%s", __FUNCTION__); ++ qxl_log_cmd_cursor(qxl, cmd, ext->group_id); ++ fprintf(stderr, "\n"); ++ } ++#endif ++ switch (cmd->type) { ++ case QXL_CURSOR_SET: ++ x = cmd->u.set.position.x; ++ y = cmd->u.set.position.y; ++ cursor = qxl_phys2virt(qxl, cmd->u.set.shape, ext->group_id); ++ if (cursor->chunk.data_size != cursor->data_size) { ++ fprintf(stderr, "%s: multiple chunks\n", __FUNCTION__); ++ return; ++ } ++ c = qxl_cursor(qxl, cursor); ++ if (c == NULL) { ++ c = cursor_builtin_left_ptr(); ++ } ++ qxl->ssd.ds->cursor_define(c); ++ cursor_put(c); ++ break; ++ case QXL_CURSOR_MOVE: ++ x = cmd->u.position.x; ++ y = cmd->u.position.y; ++ break; ++ } ++ if (x != -1 && y != -1) { ++ qxl->ssd.ds->mouse_set(x, y, 1); ++ } ++} +diff -urN qemu-kvm-0.13.0.orig/hw/spice-vmc.c qemu-kvm-0.13.0/hw/spice-vmc.c +--- qemu-kvm-0.13.0.orig/hw/spice-vmc.c 1970-01-01 02:00:00.000000000 +0200 ++++ qemu-kvm-0.13.0/hw/spice-vmc.c 2011-02-09 11:08:02.891000327 +0200 +@@ -0,0 +1,262 @@ ++/* ++ ++ Spice Virtual Machine Channel (VMC). ++ ++ A virtio-serial port used for spice to guest communication, over ++ which spice client and a daemon in the guest operating system ++ communicate. ++ ++ Replaces the old vdi_port PCI device. ++ ++*/ ++ ++#include <stdio.h> ++#include <stdbool.h> ++#include <spice.h> ++#include <spice-experimental.h> ++ ++#include "virtio-serial.h" ++#include "qemu-spice.h" ++ ++#define VMC_GUEST_DEVICE_NAME "com.redhat.spice.0" ++#define VMC_DEVICE_NAME "spicevmc" ++ ++/* windows guest driver bug workaround */ ++#define VMC_MAX_HOST_WRITE 2048 ++ ++#define dprintf(_svc, _level, _fmt, ...) \ ++ do { \ ++ static unsigned __dprintf_counter = 0; \ ++ if (_svc->debug >= _level) { \ ++ fprintf(stderr, "svc: %3d: " _fmt, ++__dprintf_counter, ## __VA_ARGS__);\ ++ } \ ++ } while (0) ++ ++typedef struct SpiceVirtualChannel { ++ VirtIOSerialPort port; ++ VMChangeStateEntry *vmstate; ++ SpiceCharDeviceInstance sin; ++ char *subtype; ++ bool active; ++ uint8_t *buffer; ++ uint8_t *datapos; ++ ssize_t bufsize, datalen; ++ uint32_t debug; ++} SpiceVirtualChannel; ++ ++static int vmc_write(SpiceCharDeviceInstance *sin, const uint8_t *buf, int len) ++{ ++ SpiceVirtualChannel *svc = container_of(sin, SpiceVirtualChannel, sin); ++ ssize_t out = 0; ++ ssize_t last_out; ++ uint8_t* p = (uint8_t*)buf; ++ ++ while (len > 0) { ++ last_out = virtio_serial_write(&svc->port, p, ++ MIN(len, VMC_MAX_HOST_WRITE)); ++ if (last_out > 0) { ++ out += last_out; ++ len -= last_out; ++ p += last_out; ++ } else { ++ break; ++ } ++ } ++ ++ dprintf(svc, 3, "%s: %lu/%zd\n", __func__, out, len + out); ++ return out; ++} ++ ++static int vmc_read(SpiceCharDeviceInstance *sin, uint8_t *buf, int len) ++{ ++ SpiceVirtualChannel *svc = container_of(sin, SpiceVirtualChannel, sin); ++ int bytes = MIN(len, svc->datalen); ++ ++ dprintf(svc, 2, "%s: %p %d/%d/%zd\n", __func__, svc->datapos, len, bytes, svc->datalen); ++ if (bytes > 0) { ++ memcpy(buf, svc->datapos, bytes); ++ svc->datapos += bytes; ++ svc->datalen -= bytes; ++ assert(svc->datalen >= 0); ++ if (svc->datalen == 0) { ++ svc->datapos = 0; ++ virtio_serial_throttle_port(&svc->port, false); ++ // ^^^ !!! may call vmc_have_data, so don't touch svc after it! ++ } ++ } ++ return bytes; ++} ++ ++static SpiceCharDeviceInterface vmc_interface = { ++ .base.type = SPICE_INTERFACE_CHAR_DEVICE, ++ .base.description = "spice virtual channel char device", ++ .base.major_version = SPICE_INTERFACE_CHAR_DEVICE_MAJOR, ++ .base.minor_version = SPICE_INTERFACE_CHAR_DEVICE_MINOR, ++ .write = vmc_write, ++ .read = vmc_read, ++}; ++ ++static void vmc_register_interface(SpiceVirtualChannel *svc) ++{ ++ if (svc->active) { ++ return; ++ } ++ dprintf(svc, 1, "%s\n", __func__); ++ svc->sin.base.sif = &vmc_interface.base; ++ spice_server_add_interface(spice_server, &svc->sin.base); ++ svc->active = true; ++} ++ ++static void vmc_unregister_interface(SpiceVirtualChannel *svc) ++{ ++ if (!svc->active) { ++ return; ++ } ++ dprintf(svc, 1, "%s\n", __func__); ++ spice_server_remove_interface(&svc->sin.base); ++ svc->active = false; ++} ++ ++ ++static void vmc_change_state_handler(void *opaque, int running, int reason) ++{ ++ SpiceVirtualChannel *svc = opaque; ++ ++ if (running && svc->active) { ++ spice_server_char_device_wakeup(&svc->sin); ++ } ++} ++ ++/* ++ * virtio-serial callbacks ++ */ ++ ++static void vmc_guest_open(VirtIOSerialPort *port) ++{ ++ SpiceVirtualChannel *svc = DO_UPCAST(SpiceVirtualChannel, port, port); ++ ++ dprintf(svc, 1, "%s\n", __func__); ++ vmc_register_interface(svc); ++} ++ ++static void vmc_guest_close(VirtIOSerialPort *port) ++{ ++ SpiceVirtualChannel *svc = DO_UPCAST(SpiceVirtualChannel, port, port); ++ ++ dprintf(svc, 1, "%s\n", __func__); ++ vmc_unregister_interface(svc); ++} ++ ++static void vmc_guest_ready(VirtIOSerialPort *port) ++{ ++ SpiceVirtualChannel *svc = DO_UPCAST(SpiceVirtualChannel, port, port); ++ ++ dprintf(svc, 1, "%s\n", __func__); ++ if (svc->active) { ++ spice_server_char_device_wakeup(&svc->sin); ++ } ++} ++ ++static void vmc_have_data(VirtIOSerialPort *port, const uint8_t *buf, size_t len) ++{ ++ SpiceVirtualChannel *svc = DO_UPCAST(SpiceVirtualChannel, port, port); ++ ++ dprintf(svc, 2, "%s: %zd\n", __func__, len); ++ assert(svc->datalen == 0); ++ if (svc->bufsize < len) { ++ svc->bufsize = len; ++ svc->buffer = qemu_realloc(svc->buffer, svc->bufsize); ++ } ++ memcpy(svc->buffer, buf, len); ++ svc->datapos = svc->buffer; ++ svc->datalen = len; ++ virtio_serial_throttle_port(&svc->port, true); ++ spice_server_char_device_wakeup(&svc->sin); ++} ++ ++static void vmc_print_optional_subtypes(void) ++{ ++ const char** psubtype = spice_server_char_device_recognized_subtypes(); ++ int i; ++ ++ fprintf(stderr, "supported subtypes: "); ++ for(i=0; *psubtype != NULL; ++psubtype, ++i) { ++ if (i == 0) { ++ fprintf(stderr, *psubtype); ++ } else { ++ fprintf(stderr, ", %s", *psubtype); ++ } ++ } ++ fprintf(stderr, "\n"); ++} ++ ++static int vmc_initfn(VirtIOSerialDevice *dev) ++{ ++ VirtIOSerialPort *port = DO_UPCAST(VirtIOSerialPort, dev, &dev->qdev); ++ SpiceVirtualChannel *svc = DO_UPCAST(SpiceVirtualChannel, port, port); ++ const char** psubtype = spice_server_char_device_recognized_subtypes(); ++ const char *subtype = NULL; ++ ++ if (!using_spice) { ++ return -1; ++ } ++ ++ dprintf(svc, 1, "%s\n", __func__); ++ ++ if (svc->subtype == NULL) { ++ svc->subtype = strdup("vdagent"); ++ } ++ ++ for(;*psubtype != NULL; ++psubtype) { ++ if (strcmp(svc->subtype, *psubtype) == 0) { ++ subtype = *psubtype; ++ break; ++ } ++ } ++ if (subtype == NULL) { ++ fprintf(stderr, "spice-vmc: unsupported subtype\n"); ++ vmc_print_optional_subtypes(); ++ return -1; ++ } ++ port->name = qemu_strdup(VMC_GUEST_DEVICE_NAME); ++ svc->vmstate = qemu_add_vm_change_state_handler ++ (vmc_change_state_handler, svc); ++ svc->sin.subtype = svc->subtype; ++ virtio_serial_open(port); ++ return 0; ++} ++ ++static int vmc_exitfn(VirtIOSerialDevice *dev) ++{ ++ VirtIOSerialPort *port = DO_UPCAST(VirtIOSerialPort, dev, &dev->qdev); ++ SpiceVirtualChannel *svc = DO_UPCAST(SpiceVirtualChannel, port, port); ++ ++ dprintf(svc, 1, "%s\n", __func__); ++ vmc_unregister_interface(svc); ++ qemu_del_vm_change_state_handler(svc->vmstate); ++ virtio_serial_close(port); ++ return 0; ++} ++ ++static VirtIOSerialPortInfo vmc_info = { ++ .qdev.name = VMC_DEVICE_NAME, ++ .qdev.size = sizeof(SpiceVirtualChannel), ++ .init = vmc_initfn, ++ .exit = vmc_exitfn, ++ .guest_open = vmc_guest_open, ++ .guest_close = vmc_guest_close, ++ .guest_ready = vmc_guest_ready, ++ .have_data = vmc_have_data, ++ .qdev.props = (Property[]) { ++ DEFINE_PROP_UINT32("nr", SpiceVirtualChannel, port.id, VIRTIO_CONSOLE_BAD_ID), ++ DEFINE_PROP_UINT32("debug", SpiceVirtualChannel, debug, 1), ++ DEFINE_PROP_STRING("subtype", SpiceVirtualChannel, subtype), ++ DEFINE_PROP_END_OF_LIST(), ++ } ++}; ++ ++static void vmc_register(void) ++{ ++ virtio_serial_port_qdev_register(&vmc_info); ++} ++device_init(vmc_register) +diff -urN qemu-kvm-0.13.0.orig/hw/vga_int.h qemu-kvm-0.13.0/hw/vga_int.h +--- qemu-kvm-0.13.0.orig/hw/vga_int.h 2011-02-09 11:01:45.856000328 +0200 ++++ qemu-kvm-0.13.0/hw/vga_int.h 2011-02-09 11:08:02.771000327 +0200 +@@ -106,7 +106,7 @@ + typedef struct VGACommonState { + uint8_t *vram_ptr; + ram_addr_t vram_offset; +- unsigned int vram_size; ++ uint32_t vram_size; + uint32_t lfb_addr; + uint32_t lfb_end; + uint32_t map_addr; +diff -urN qemu-kvm-0.13.0.orig/hw/vga-pci.c qemu-kvm-0.13.0/hw/vga-pci.c +--- qemu-kvm-0.13.0.orig/hw/vga-pci.c 2011-02-09 11:01:45.855000328 +0200 ++++ qemu-kvm-0.13.0/hw/vga-pci.c 2011-02-09 11:08:02.753000327 +0200 +@@ -81,6 +81,10 @@ + VGACommonState *s = &d->vga; + uint8_t *pci_conf = d->dev.config; + ++ if (dev->qdev.hotplugged) { ++ return -1; ++ } ++ + // vga + console init + vga_common_init(s, VGA_RAM_SIZE); + vga_init(s); +@@ -105,11 +109,10 @@ + bios_total_size <<= 1; + pci_register_bar(&d->dev, PCI_ROM_SLOT, bios_total_size, + PCI_BASE_ADDRESS_MEM_PREFETCH, vga_map); ++ } else { ++ if (dev->romfile == NULL) ++ dev->romfile = qemu_strdup("vgabios-stdvga.bin"); + } +- +- vga_init_vbe(s); +- /* ROM BIOS */ +- rom_add_vga(VGABIOS_FILENAME); + return 0; + } + +diff -urN qemu-kvm-0.13.0.orig/hw/virtio-pci.c qemu-kvm-0.13.0/hw/virtio-pci.c +--- qemu-kvm-0.13.0.orig/hw/virtio-pci.c 2011-02-09 11:01:45.879000328 +0200 ++++ qemu-kvm-0.13.0/hw/virtio-pci.c 2011-02-09 11:08:02.910000327 +0200 +@@ -427,11 +427,10 @@ + } + } + +-static int virtio_pci_mask_notifier(PCIDevice *dev, unsigned vector, +- void *opaque, int masked) ++static int virtio_pci_mask_vq(PCIDevice *dev, unsigned vector, ++ VirtQueue *vq, int masked) + { + #ifdef CONFIG_KVM +- VirtQueue *vq = opaque; + EventNotifier *notifier = virtio_queue_get_guest_notifier(vq); + int r = kvm_set_irqfd(dev->msix_irq_entries[vector].gsi, + event_notifier_get_fd(notifier), +@@ -452,6 +451,34 @@ + #endif + } + ++static int virtio_pci_mask_notifier(PCIDevice *dev, unsigned vector, ++ int masked) ++{ ++ VirtIOPCIProxy *proxy = container_of(dev, VirtIOPCIProxy, pci_dev); ++ VirtIODevice *vdev = proxy->vdev; ++ int r, n; ++ ++ for (n = 0; n < VIRTIO_PCI_QUEUE_MAX; n++) { ++ if (!virtio_queue_get_num(vdev, n)) { ++ break; ++ } ++ if (virtio_queue_vector(vdev, n) != vector) { ++ continue; ++ } ++ r = virtio_pci_mask_vq(dev, vector, virtio_get_queue(vdev, n), masked); ++ if (r < 0) { ++ goto undo; ++ } ++ } ++ return 0; ++undo: ++ while (--n >= 0) { ++ virtio_pci_mask_vq(dev, vector, virtio_get_queue(vdev, n), !masked); ++ } ++ return r; ++} ++ ++ + static int virtio_pci_set_guest_notifier(void *opaque, int n, bool assign) + { + VirtIOPCIProxy *proxy = opaque; +@@ -465,11 +492,7 @@ + } + qemu_set_fd_handler(event_notifier_get_fd(notifier), + virtio_pci_guest_notifier_read, NULL, vq); +- msix_set_mask_notifier(&proxy->pci_dev, +- virtio_queue_vector(proxy->vdev, n), vq); + } else { +- msix_unset_mask_notifier(&proxy->pci_dev, +- virtio_queue_vector(proxy->vdev, n)); + qemu_set_fd_handler(event_notifier_get_fd(notifier), + NULL, NULL, NULL); + /* Test and clear notifier before closing it, +@@ -487,6 +510,13 @@ + VirtIODevice *vdev = proxy->vdev; + int r, n; + ++ /* Must unset mask notifier while guest notifier ++ * is still assigned */ ++ if (!assign) { ++ r = msix_unset_mask_notifier(&proxy->pci_dev); ++ assert(r >= 0); ++ } ++ + for (n = 0; n < VIRTIO_PCI_QUEUE_MAX; n++) { + if (!virtio_queue_get_num(vdev, n)) { + break; +@@ -498,6 +528,16 @@ + } + } + ++ /* Must set mask notifier after guest notifier ++ * has been assigned */ ++ if (assign) { ++ r = msix_set_mask_notifier(&proxy->pci_dev, ++ virtio_pci_mask_notifier); ++ if (r < 0) { ++ goto assign_error; ++ } ++ } ++ + return 0; + + assign_error: +@@ -583,8 +623,6 @@ + + proxy->pci_dev.config_write = virtio_write_config; + +- proxy->pci_dev.msix_mask_notifier = virtio_pci_mask_notifier; +- + size = VIRTIO_PCI_REGION_SIZE(&proxy->pci_dev) + vdev->config_len; + if (size & (size-1)) + size = 1 << qemu_fls(size); +diff -urN qemu-kvm-0.13.0.orig/hw/vmmouse.c qemu-kvm-0.13.0/hw/vmmouse.c +--- qemu-kvm-0.13.0.orig/hw/vmmouse.c 2011-02-09 11:01:45.879000328 +0200 ++++ qemu-kvm-0.13.0/hw/vmmouse.c 2011-02-09 11:08:02.904000327 +0200 +@@ -100,16 +100,29 @@ + i8042_isa_mouse_fake_event(s->ps2_mouse); + } + +-static void vmmouse_update_handler(VMMouseState *s) ++static void vmmouse_remove_handler(VMMouseState *s) + { + if (s->entry) { + qemu_remove_mouse_event_handler(s->entry); + s->entry = NULL; + } +- if (s->status == 0) ++} ++ ++static void vmmouse_update_handler(VMMouseState *s, int absolute) ++{ ++ if (s->status != 0) { ++ return; ++ } ++ if (s->absolute != absolute) { ++ s->absolute = absolute; ++ vmmouse_remove_handler(s); ++ } ++ if (s->entry == NULL) { + s->entry = qemu_add_mouse_event_handler(vmmouse_mouse_event, + s, s->absolute, + "vmmouse"); ++ qemu_activate_mouse_event_handler(s->entry); ++ } + } + + static void vmmouse_read_id(VMMouseState *s) +@@ -121,28 +134,25 @@ + + s->queue[s->nb_queue++] = VMMOUSE_VERSION; + s->status = 0; +- vmmouse_update_handler(s); + } + + static void vmmouse_request_relative(VMMouseState *s) + { + DPRINTF("vmmouse_request_relative()\n"); +- s->absolute = 0; +- vmmouse_update_handler(s); ++ vmmouse_update_handler(s, 0); + } + + static void vmmouse_request_absolute(VMMouseState *s) + { + DPRINTF("vmmouse_request_absolute()\n"); +- s->absolute = 1; +- vmmouse_update_handler(s); ++ vmmouse_update_handler(s, 1); + } + + static void vmmouse_disable(VMMouseState *s) + { + DPRINTF("vmmouse_disable()\n"); + s->status = 0xffff; +- vmmouse_update_handler(s); ++ vmmouse_remove_handler(s); + } + + static void vmmouse_data(VMMouseState *s, uint32_t *data, uint32_t size) +@@ -154,7 +164,7 @@ + if (size == 0 || size > 6 || size > s->nb_queue) { + printf("vmmouse: driver requested too much data %d\n", size); + s->status = 0xffff; +- vmmouse_update_handler(s); ++ vmmouse_remove_handler(s); + return; + } + +@@ -239,7 +249,8 @@ + { + VMMouseState *s = opaque; + +- vmmouse_update_handler(s); ++ vmmouse_remove_handler(s); ++ vmmouse_update_handler(s, s->absolute); + return 0; + } + +diff -urN qemu-kvm-0.13.0.orig/hw/vmware_vga.c qemu-kvm-0.13.0/hw/vmware_vga.c +--- qemu-kvm-0.13.0.orig/hw/vmware_vga.c 2011-02-09 11:01:45.878000328 +0200 ++++ qemu-kvm-0.13.0/hw/vmware_vga.c 2011-02-09 11:08:02.754000327 +0200 +@@ -114,14 +114,12 @@ + # define SVGA_IO_BASE SVGA_LEGACY_BASE_PORT + # define SVGA_IO_MUL 1 + # define SVGA_FIFO_SIZE 0x10000 +-# define SVGA_MEM_BASE 0xe0000000 + # define SVGA_PCI_DEVICE_ID PCI_DEVICE_ID_VMWARE_SVGA2 + #else + # define SVGA_ID SVGA_ID_1 + # define SVGA_IO_BASE SVGA_LEGACY_BASE_PORT + # define SVGA_IO_MUL 4 + # define SVGA_FIFO_SIZE 0x10000 +-# define SVGA_MEM_BASE 0xe0000000 + # define SVGA_PCI_DEVICE_ID PCI_DEVICE_ID_VMWARE_SVGA + #endif + +@@ -1171,10 +1169,6 @@ + vga_init(&s->vga); + vmstate_register(NULL, 0, &vmstate_vga_common, &s->vga); + +- vga_init_vbe(&s->vga); +- +- rom_add_vga(VGABIOS_FILENAME); +- + vmsvga_reset(s); + } + +@@ -1238,6 +1232,10 @@ + struct pci_vmsvga_state_s *s = + DO_UPCAST(struct pci_vmsvga_state_s, card, dev); + ++ if (dev->qdev.hotplugged) { ++ return -1; ++ } ++ + pci_config_set_vendor_id(s->card.config, PCI_VENDOR_ID_VMWARE); + pci_config_set_device_id(s->card.config, SVGA_PCI_DEVICE_ID); + pci_config_set_class(s->card.config, PCI_CLASS_DISPLAY_VGA); +@@ -1272,6 +1270,7 @@ + .qdev.size = sizeof(struct pci_vmsvga_state_s), + .qdev.vmsd = &vmstate_vmware_vga, + .init = pci_vmsvga_initfn, ++ .romfile = "vgabios-vmware.bin", + }; + + static void vmsvga_register(void) +diff -urN qemu-kvm-0.13.0.orig/Makefile qemu-kvm-0.13.0/Makefile +--- qemu-kvm-0.13.0.orig/Makefile 2011-02-09 11:01:45.899000328 +0200 ++++ qemu-kvm-0.13.0/Makefile 2011-02-09 11:08:02.739000327 +0200 +@@ -154,8 +154,9 @@ + common de-ch es fo fr-ca hu ja mk nl-be pt sl tr + + ifdef INSTALL_BLOBS +-BLOBS=bios.bin vgabios.bin vgabios-cirrus.bin ppc_rom.bin \ +-video.x openbios-sparc32 openbios-sparc64 openbios-ppc \ ++BLOBS=bios.bin vgabios.bin vgabios-cirrus.bin \ ++vgabios-stdvga.bin vgabios-vmware.bin vgabios-qxl.bin vgabios-qxldev.bin \ ++ppc_rom.bin video.x openbios-sparc32 openbios-sparc64 openbios-ppc \ + gpxe-eepro100-80861209.rom \ + gpxe-eepro100-80861229.rom \ + pxe-e1000.bin \ +diff -urN qemu-kvm-0.13.0.orig/Makefile.objs qemu-kvm-0.13.0/Makefile.objs +--- qemu-kvm-0.13.0.orig/Makefile.objs 2011-02-09 11:01:45.720000328 +0200 ++++ qemu-kvm-0.13.0/Makefile.objs 2011-02-09 11:08:02.778000327 +0200 +@@ -84,13 +84,17 @@ + common-obj-y += msmouse.o ps2.o + common-obj-y += qdev.o qdev-properties.o + common-obj-y += block-migration.o ++common-obj-y += pflib.o + + common-obj-$(CONFIG_BRLAPI) += baum.o + common-obj-$(CONFIG_POSIX) += migration-exec.o migration-unix.o migration-fd.o + ++common-obj-$(CONFIG_SPICE) += spice.o spice-input.o spice-display.o ++ + audio-obj-y = audio.o noaudio.o wavaudio.o mixeng.o + audio-obj-$(CONFIG_SDL) += sdlaudio.o + audio-obj-$(CONFIG_OSS) += ossaudio.o ++audio-obj-$(CONFIG_SPICE) += spiceaudio.o + audio-obj-$(CONFIG_COREAUDIO) += coreaudio.o + audio-obj-$(CONFIG_ALSA) += alsaaudio.o + audio-obj-$(CONFIG_DSOUND) += dsoundaudio.o +diff -urN qemu-kvm-0.13.0.orig/Makefile.target qemu-kvm-0.13.0/Makefile.target +--- qemu-kvm-0.13.0.orig/Makefile.target 2011-02-09 11:01:45.776000327 +0200 ++++ qemu-kvm-0.13.0/Makefile.target 2011-02-09 11:08:02.889000327 +0200 +@@ -219,6 +219,8 @@ + obj-i386-y += pc_piix.o + obj-i386-y += testdev.o + obj-i386-y += acpi.o acpi_piix4.o ++obj-i386-$(CONFIG_SPICE) += qxl.o qxl-logger.o qxl-render.o ++obj-i386-$(CONFIG_SPICE) += spice-vmc.o + + obj-i386-y += pcspk.o i8254.o + obj-i386-$(CONFIG_KVM_PIT) += i8254-kvm.o +diff -urN qemu-kvm-0.13.0.orig/Makefile.target.orig qemu-kvm-0.13.0/Makefile.target.orig +--- qemu-kvm-0.13.0.orig/Makefile.target.orig 1970-01-01 02:00:00.000000000 +0200 ++++ qemu-kvm-0.13.0/Makefile.target.orig 2011-02-09 11:08:02.884000327 +0200 +@@ -0,0 +1,373 @@ ++# -*- Mode: makefile -*- ++ ++GENERATED_HEADERS = config-target.h ++CONFIG_NO_KVM = $(if $(subst n,,$(CONFIG_KVM)),n,y) ++ ++include ../config-host.mak ++include config-devices.mak ++include config-target.mak ++include $(SRC_PATH)/rules.mak ++ifneq ($(HWDIR),) ++include $(HWDIR)/config.mak ++endif ++ ++TARGET_PATH=$(SRC_PATH)/target-$(TARGET_BASE_ARCH) ++$(call set-vpath, $(SRC_PATH):$(TARGET_PATH):$(SRC_PATH)/hw) ++QEMU_CFLAGS+= -I.. -I$(TARGET_PATH) -DNEED_CPU_H ++ ++include $(SRC_PATH)/Makefile.objs ++ ++ifdef CONFIG_USER_ONLY ++# user emulator name ++QEMU_PROG=qemu-$(TARGET_ARCH2) ++else ++# system emulator name ++ifeq ($(TARGET_ARCH), i386) ++QEMU_PROG=qemu$(EXESUF) ++else ++QEMU_PROG=qemu-system-$(TARGET_ARCH2)$(EXESUF) ++endif ++endif ++ ++PROGS=$(QEMU_PROG) ++ ++LIBS+=-lm ++ ++kvm.o kvm-all.o vhost.o vhost_net.o: QEMU_CFLAGS+=$(KVM_CFLAGS) ++ ++CFLAGS += $(KVM_CFLAGS) ++ ++config-target.h: config-target.h-timestamp ++config-target.h-timestamp: config-target.mak ++ ++all: $(PROGS) ++ ++# Dummy command so that make thinks it has done something ++ @true ++ ++######################################################### ++# cpu emulator library ++libobj-y = exec.o cpu-exec.o ++libobj-$(CONFIG_NO_CPU_EMULATION) += fake-exec.o ++libobj-$(CONFIG_CPU_EMULATION) += translate-all.o translate.o ++libobj-$(CONFIG_CPU_EMULATION) += tcg/tcg.o ++libobj-$(CONFIG_SOFTFLOAT) += fpu/softfloat.o ++libobj-$(CONFIG_NOSOFTFLOAT) += fpu/softfloat-native.o ++libobj-y += op_helper.o helper.o ++ifeq ($(TARGET_BASE_ARCH), i386) ++libobj-y += cpuid.o ++endif ++libobj-$(CONFIG_NEED_MMU) += mmu.o ++ ++libobj-$(CONFIG_KVM) += kvm-tpr-opt.o ++libobj-$(CONFIG_KVM) += qemu-kvm-helper.o ++ ++libobj-$(TARGET_ARM) += neon_helper.o iwmmxt_helper.o ++ ++libobj-y += disas.o ++ ++$(libobj-y): $(GENERATED_HEADERS) ++ ++# libqemu ++ ++translate.o: translate.c cpu.h ++ ++translate-all.o: translate-all.c cpu.h ++ ++tcg/tcg.o: cpu.h ++ ++# HELPER_CFLAGS is used for all the code compiled with static register ++# variables ++op_helper.o cpu-exec.o: QEMU_CFLAGS += $(HELPER_CFLAGS) ++ ++# Note: this is a workaround. The real fix is to avoid compiling ++# cpu_signal_handler() in cpu-exec.c. ++signal.o: QEMU_CFLAGS += $(HELPER_CFLAGS) ++ ++qemu-kvm-helper.o: QEMU_CFLAGS += $(HELPER_CFLAGS) ++ ++######################################################### ++# Linux user emulator target ++ ++ifdef CONFIG_LINUX_USER ++ ++$(call set-vpath, $(SRC_PATH)/linux-user:$(SRC_PATH)/linux-user/$(TARGET_ABI_DIR)) ++ ++QEMU_CFLAGS+=-I$(SRC_PATH)/linux-user -I$(SRC_PATH)/linux-user/$(TARGET_ABI_DIR) ++obj-y = main.o syscall.o strace.o mmap.o signal.o thunk.o \ ++ elfload.o linuxload.o uaccess.o gdbstub.o cpu-uname.o \ ++ qemu-malloc.o ++ ++obj-$(TARGET_HAS_BFLT) += flatload.o ++ ++obj-$(TARGET_I386) += vm86.o ++ ++obj-i386-y += ioport-user.o ++ ++nwfpe-obj-y = fpa11.o fpa11_cpdo.o fpa11_cpdt.o fpa11_cprt.o fpopcode.o ++nwfpe-obj-y += single_cpdo.o double_cpdo.o extended_cpdo.o ++obj-arm-y += $(addprefix nwfpe/, $(nwfpe-obj-y)) ++obj-arm-y += arm-semi.o ++ ++obj-m68k-y += m68k-sim.o m68k-semi.o ++ ++$(obj-y) $(obj-$(TARGET_BASE_ARCH)-y): $(GENERATED_HEADERS) ++ ++obj-y += $(addprefix ../libuser/, $(user-obj-y)) ++obj-y += $(addprefix ../libdis-user/, $(libdis-y)) ++obj-y += $(libobj-y) ++ ++endif #CONFIG_LINUX_USER ++ ++######################################################### ++# Darwin user emulator target ++ ++ifdef CONFIG_DARWIN_USER ++ ++$(call set-vpath, $(SRC_PATH)/darwin-user) ++ ++QEMU_CFLAGS+=-I$(SRC_PATH)/darwin-user -I$(SRC_PATH)/darwin-user/$(TARGET_ARCH) ++ ++# Leave some space for the regular program loading zone ++LDFLAGS+=-Wl,-segaddr,__STD_PROG_ZONE,0x1000 -image_base 0x0e000000 ++ ++LIBS+=-lmx ++ ++obj-y = main.o commpage.o machload.o mmap.o signal.o syscall.o thunk.o \ ++ gdbstub.o ++ ++obj-i386-y += ioport-user.o ++ ++$(obj-y) $(obj-$(TARGET_BASE_ARCH)-y): $(GENERATED_HEADERS) ++ ++obj-y += $(addprefix ../libuser/, $(user-obj-y)) ++obj-y += $(addprefix ../libdis-user/, $(libdis-y)) ++obj-y += $(libobj-y) ++ ++endif #CONFIG_DARWIN_USER ++ ++######################################################### ++# BSD user emulator target ++ ++ifdef CONFIG_BSD_USER ++ ++$(call set-vpath, $(SRC_PATH)/bsd-user) ++ ++QEMU_CFLAGS+=-I$(SRC_PATH)/bsd-user -I$(SRC_PATH)/bsd-user/$(TARGET_ARCH) ++ ++obj-y = main.o bsdload.o elfload.o mmap.o signal.o strace.o syscall.o \ ++ gdbstub.o uaccess.o ++ ++obj-i386-y += ioport-user.o ++ ++$(obj-y) $(obj-$(TARGET_BASE_ARCH)-y): $(GENERATED_HEADERS) ++ ++obj-y += $(addprefix ../libuser/, $(user-obj-y)) ++obj-y += $(addprefix ../libdis-user/, $(libdis-y)) ++obj-y += $(libobj-y) ++ ++endif #CONFIG_BSD_USER ++ ++######################################################### ++# System emulator target ++ifdef CONFIG_SOFTMMU ++ ++obj-y = arch_init.o cpus.o monitor.o pci.o machine.o gdbstub.o vl.o balloon.o ++# virtio has to be here due to weird dependency between PCI and virtio-net. ++# need to fix this properly ++obj-y += virtio-blk.o virtio-balloon.o virtio-net.o virtio-serial-bus.o ++obj-$(CONFIG_VIRTIO_PCI) += virtio-pci.o ++obj-y += vhost_net.o ++obj-$(CONFIG_VHOST_NET) += vhost.o ++obj-$(CONFIG_VIRTFS) += virtio-9p.o ++obj-y += rwhandler.o ++obj-$(CONFIG_KVM) += kvm.o kvm-all.o ++obj-$(CONFIG_NO_KVM) += kvm-stub.o ++ ++# MSI-X depends on kvm for interrupt injection, ++# so moved it from Makefile.objs to Makefile.target for now ++obj-y += msix.o ++ ++LIBS+=-lz ++ ++QEMU_CFLAGS += $(VNC_TLS_CFLAGS) ++QEMU_CFLAGS += $(VNC_SASL_CFLAGS) ++QEMU_CFLAGS += $(VNC_JPEG_CFLAGS) ++QEMU_CFLAGS += $(VNC_PNG_CFLAGS) ++ ++# xen backend driver support ++obj-$(CONFIG_XEN) += xen_machine_pv.o xen_domainbuild.o ++ ++# USB layer ++obj-$(CONFIG_USB_OHCI) += usb-ohci.o ++ ++# PCI network cards ++obj-y += rtl8139.o ++obj-y += e1000.o ++ ++# Inter-VM PCI shared memory ++obj-$(CONFIG_KVM) += ivshmem.o ++ ++# Hardware support ++obj-i386-y += vga.o ++obj-i386-y += mc146818rtc.o i8259.o pc.o ++obj-i386-y += cirrus_vga.o apic.o ioapic.o piix_pci.o ++obj-i386-y += vmmouse.o vmport.o hpet.o applesmc.o ++obj-i386-y += device-hotplug.o pci-hotplug.o smbios.o wdt_ib700.o ++obj-i386-y += extboot.o ++obj-i386-y += debugcon.o multiboot.o ++obj-i386-y += pc_piix.o ++obj-i386-y += testdev.o ++obj-i386-y += acpi.o acpi_piix4.o ++obj-i386-$(CONFIG_SPICE) += qxl.o qxl-logger.o qxl-render.o ++ ++obj-i386-y += pcspk.o i8254.o ++obj-i386-$(CONFIG_KVM_PIT) += i8254-kvm.o ++obj-i386-$(CONFIG_KVM_DEVICE_ASSIGNMENT) += device-assignment.o ++ ++# Hardware support ++obj-ia64-y += ide.o pckbd.o vga.o $(SOUND_HW) dma.o $(AUDIODRV) ++obj-ia64-y += fdc.o mc146818rtc.o serial.o i8259.o ipf.o ++obj-ia64-y += cirrus_vga.o parallel.o acpi.o piix_pci.o ++obj-ia64-y += usb-uhci.o ++obj-ia64-$(CONFIG_KVM_DEVICE_ASSIGNMENT) += device-assignment.o ++ ++# shared objects ++obj-ppc-y = ppc.o ++obj-ppc-y += vga.o ++# PREP target ++obj-ppc-y += i8259.o mc146818rtc.o ++obj-ppc-y += ppc_prep.o ++# OldWorld PowerMac ++obj-ppc-y += ppc_oldworld.o ++# NewWorld PowerMac ++obj-ppc-y += ppc_newworld.o ++# PowerPC 4xx boards ++obj-ppc-y += ppc4xx_devs.o ppc4xx_pci.o ppc405_uc.o ppc405_boards.o ++obj-ppc-y += ppc440.o ppc440_bamboo.o ++# PowerPC E500 boards ++obj-ppc-y += ppce500_mpc8544ds.o ++obj-ppc-$(CONFIG_KVM) += kvm_ppc.o ++obj-ppc-$(CONFIG_FDT) += device_tree.o ++ ++obj-mips-y = mips_r4k.o mips_jazz.o mips_malta.o mips_mipssim.o ++obj-mips-y += pcspk.o i8254.o ++obj-mips-y += acpi.o acpi_piix4.o ++obj-mips-y += mips_addr.o mips_timer.o mips_int.o ++obj-mips-y += vga.o i8259.o ++obj-mips-y += g364fb.o jazz_led.o ++obj-mips-y += gt64xxx.o mc146818rtc.o ++obj-mips-y += cirrus_vga.o ++obj-mips-$(CONFIG_FULONG) += bonito.o vt82c686.o mips_fulong2e.o ++ ++obj-microblaze-y = petalogix_s3adsp1800_mmu.o ++ ++obj-microblaze-y += microblaze_pic_cpu.o ++obj-microblaze-y += xilinx_intc.o ++obj-microblaze-y += xilinx_timer.o ++obj-microblaze-y += xilinx_uartlite.o ++obj-microblaze-y += xilinx_ethlite.o ++ ++obj-microblaze-$(CONFIG_FDT) += device_tree.o ++ ++# Boards ++obj-cris-y = cris_pic_cpu.o ++obj-cris-y += cris-boot.o ++obj-cris-y += etraxfs.o axis_dev88.o ++obj-cris-y += axis_dev88.o ++ ++# IO blocks ++obj-cris-y += etraxfs_dma.o ++obj-cris-y += etraxfs_pic.o ++obj-cris-y += etraxfs_eth.o ++obj-cris-y += etraxfs_timer.o ++obj-cris-y += etraxfs_ser.o ++ ++ifeq ($(TARGET_ARCH), sparc64) ++obj-sparc-y = sun4u.o apb_pci.o ++obj-sparc-y += vga.o ++obj-sparc-y += mc146818rtc.o ++obj-sparc-y += cirrus_vga.o ++else ++obj-sparc-y = sun4m.o lance.o tcx.o sun4m_iommu.o slavio_intctl.o ++obj-sparc-y += slavio_timer.o slavio_misc.o sparc32_dma.o ++obj-sparc-y += cs4231.o eccmemctl.o sbi.o sun4c_intctl.o ++endif ++ ++obj-arm-y = integratorcp.o versatilepb.o arm_pic.o arm_timer.o ++obj-arm-y += arm_boot.o pl011.o pl031.o pl050.o pl080.o pl110.o pl181.o pl190.o ++obj-arm-y += versatile_pci.o ++obj-arm-y += realview_gic.o realview.o arm_sysctl.o arm11mpcore.o a9mpcore.o ++obj-arm-y += armv7m.o armv7m_nvic.o stellaris.o pl022.o stellaris_enet.o ++obj-arm-y += pl061.o ++obj-arm-y += arm-semi.o ++obj-arm-y += pxa2xx.o pxa2xx_pic.o pxa2xx_gpio.o pxa2xx_timer.o pxa2xx_dma.o ++obj-arm-y += pxa2xx_lcd.o pxa2xx_mmci.o pxa2xx_pcmcia.o pxa2xx_keypad.o ++obj-arm-y += gumstix.o ++obj-arm-y += zaurus.o ide/microdrive.o spitz.o tosa.o tc6393xb.o ++obj-arm-y += omap1.o omap_lcdc.o omap_dma.o omap_clk.o omap_mmc.o omap_i2c.o \ ++ omap_gpio.o omap_intc.o omap_uart.o ++obj-arm-y += omap2.o omap_dss.o soc_dma.o omap_gptimer.o omap_synctimer.o \ ++ omap_gpmc.o omap_sdrc.o omap_spi.o omap_tap.o omap_l4.o ++obj-arm-y += omap_sx1.o palm.o tsc210x.o ++obj-arm-y += nseries.o blizzard.o onenand.o vga.o cbus.o tusb6010.o usb-musb.o ++obj-arm-y += mst_fpga.o mainstone.o ++obj-arm-y += musicpal.o bitbang_i2c.o marvell_88w8618_audio.o ++obj-arm-y += framebuffer.o ++obj-arm-y += syborg.o syborg_fb.o syborg_interrupt.o syborg_keyboard.o ++obj-arm-y += syborg_serial.o syborg_timer.o syborg_pointer.o syborg_rtc.o ++obj-arm-y += syborg_virtio.o ++ ++obj-sh4-y = shix.o r2d.o sh7750.o sh7750_regnames.o tc58128.o ++obj-sh4-y += sh_timer.o sh_serial.o sh_intc.o sh_pci.o sm501.o ++obj-sh4-y += ide/mmio.o ++ ++obj-m68k-y = an5206.o mcf5206.o mcf_uart.o mcf_intc.o mcf5208.o mcf_fec.o ++obj-m68k-y += m68k-semi.o dummy_m68k.o ++ ++obj-s390x-y = s390-virtio-bus.o s390-virtio.o ++ ++obj-alpha-y = alpha_palcode.o ++ ++ifeq ($(TARGET_ARCH), ia64) ++firmware.o: firmware.c ++ $(CC) $(HELPER_CFLAGS) $(CPPFLAGS) $(BASE_CFLAGS) -c -o $@ $< ++endif ++ ++main.o: QEMU_CFLAGS+=$(GPROF_CFLAGS) ++ ++monitor.o: qemu-monitor.h ++ ++$(obj-y) $(obj-$(TARGET_BASE_ARCH)-y): $(GENERATED_HEADERS) ++ ++obj-y += $(addprefix ../, $(common-obj-y)) ++obj-y += $(addprefix ../libdis/, $(libdis-y)) ++obj-y += $(libobj-y) ++obj-y += $(addprefix $(HWDIR)/, $(hw-obj-y)) ++ ++endif # CONFIG_SOFTMMU ++ ++obj-$(CONFIG_GDBSTUB_XML) += gdbstub-xml.o ++ ++$(QEMU_PROG): $(obj-y) $(obj-$(TARGET_BASE_ARCH)-y) ++ $(call LINK,$(obj-y) $(obj-$(TARGET_BASE_ARCH)-y)) ++ ++ ++gdbstub-xml.c: $(TARGET_XML_FILES) $(SRC_PATH)/feature_to_c.sh ++ $(call quiet-command,rm -f $@ && $(SHELL) $(SRC_PATH)/feature_to_c.sh $@ $(TARGET_XML_FILES)," GEN $(TARGET_DIR)$@") ++ ++qemu-monitor.h: $(SRC_PATH)/qemu-monitor.hx ++ $(call quiet-command,sh $(SRC_PATH)/hxtool -h < $< > $@," GEN $(TARGET_DIR)$@") ++ ++clean: ++ rm -f *.o *.a *~ $(PROGS) nwfpe/*.o fpu/*.o ++ rm -f *.d */*.d tcg/*.o ide/*.o ++ rm -f qemu-monitor.h gdbstub-xml.c ++ ++install: all ++ifneq ($(PROGS),) ++ $(INSTALL) -m 755 $(STRIP_OPT) $(PROGS) "$(DESTDIR)$(bindir)" ++endif ++ ++# Include automatically generated dependency files ++-include $(wildcard *.d */*.d) +diff -urN qemu-kvm-0.13.0.orig/osdep.c qemu-kvm-0.13.0/osdep.c +--- qemu-kvm-0.13.0.orig/osdep.c 2011-02-09 11:01:45.737000327 +0200 ++++ qemu-kvm-0.13.0/osdep.c 2011-02-09 11:08:02.796000327 +0200 +@@ -100,7 +100,12 @@ + #if defined(_POSIX_C_SOURCE) && !defined(__sun__) + int ret; + void *ptr; ++#if 0 + ret = posix_memalign(&ptr, alignment, size); ++#else ++ ptr = memalign(alignment, size); ++ ret = (ptr == NULL) ? -1 : 0; ++#endif + if (ret != 0) { + fprintf(stderr, "Failed to allocate %zu B: %s\n", + size, strerror(ret)); +diff -urN qemu-kvm-0.13.0.orig/pflib.c qemu-kvm-0.13.0/pflib.c +--- qemu-kvm-0.13.0.orig/pflib.c 1970-01-01 02:00:00.000000000 +0200 ++++ qemu-kvm-0.13.0/pflib.c 2011-02-09 11:08:02.693000327 +0200 +@@ -0,0 +1,213 @@ ++/* ++ * PixelFormat conversion library. ++ * ++ * Author: Gerd Hoffmann <kraxel@redhat.com> ++ * ++ * This work is licensed under the terms of the GNU GPL, version 2. See ++ * the COPYING file in the top-level directory. ++ * ++ */ ++#include "qemu-common.h" ++#include "console.h" ++#include "pflib.h" ++ ++typedef struct QemuPixel QemuPixel; ++ ++typedef void (*pf_convert)(QemuPfConv *conv, ++ void *dst, void *src, uint32_t cnt); ++typedef void (*pf_convert_from)(PixelFormat *pf, ++ QemuPixel *dst, void *src, uint32_t cnt); ++typedef void (*pf_convert_to)(PixelFormat *pf, ++ void *dst, QemuPixel *src, uint32_t cnt); ++ ++struct QemuPfConv { ++ pf_convert convert; ++ PixelFormat src; ++ PixelFormat dst; ++ ++ /* for copy_generic() */ ++ pf_convert_from conv_from; ++ pf_convert_to conv_to; ++ QemuPixel *conv_buf; ++ uint32_t conv_cnt; ++}; ++ ++struct QemuPixel { ++ uint8_t red; ++ uint8_t green; ++ uint8_t blue; ++ uint8_t alpha; ++}; ++ ++/* ----------------------------------------------------------------------- */ ++/* PixelFormat -> QemuPixel conversions */ ++ ++static void conv_16_to_pixel(PixelFormat *pf, ++ QemuPixel *dst, void *src, uint32_t cnt) ++{ ++ uint16_t *src16 = src; ++ ++ while (cnt > 0) { ++ dst->red = ((*src16 & pf->rmask) >> pf->rshift) << (8 - pf->rbits); ++ dst->green = ((*src16 & pf->gmask) >> pf->gshift) << (8 - pf->gbits); ++ dst->blue = ((*src16 & pf->bmask) >> pf->bshift) << (8 - pf->bbits); ++ dst->alpha = ((*src16 & pf->amask) >> pf->ashift) << (8 - pf->abits); ++ dst++, src16++, cnt--; ++ } ++} ++ ++/* assumes pf->{r,g,b,a}bits == 8 */ ++static void conv_32_to_pixel_fast(PixelFormat *pf, ++ QemuPixel *dst, void *src, uint32_t cnt) ++{ ++ uint32_t *src32 = src; ++ ++ while (cnt > 0) { ++ dst->red = (*src32 & pf->rmask) >> pf->rshift; ++ dst->green = (*src32 & pf->gmask) >> pf->gshift; ++ dst->blue = (*src32 & pf->bmask) >> pf->bshift; ++ dst->alpha = (*src32 & pf->amask) >> pf->ashift; ++ dst++, src32++, cnt--; ++ } ++} ++ ++static void conv_32_to_pixel_generic(PixelFormat *pf, ++ QemuPixel *dst, void *src, uint32_t cnt) ++{ ++ uint32_t *src32 = src; ++ ++ while (cnt > 0) { ++ if (pf->rbits < 8) { ++ dst->red = ((*src32 & pf->rmask) >> pf->rshift) << (8 - pf->rbits); ++ } else { ++ dst->red = ((*src32 & pf->rmask) >> pf->rshift) >> (pf->rbits - 8); ++ } ++ if (pf->gbits < 8) { ++ dst->green = ((*src32 & pf->gmask) >> pf->gshift) << (8 - pf->gbits); ++ } else { ++ dst->green = ((*src32 & pf->gmask) >> pf->gshift) >> (pf->gbits - 8); ++ } ++ if (pf->bbits < 8) { ++ dst->blue = ((*src32 & pf->bmask) >> pf->bshift) << (8 - pf->bbits); ++ } else { ++ dst->blue = ((*src32 & pf->bmask) >> pf->bshift) >> (pf->bbits - 8); ++ } ++ if (pf->abits < 8) { ++ dst->alpha = ((*src32 & pf->amask) >> pf->ashift) << (8 - pf->abits); ++ } else { ++ dst->alpha = ((*src32 & pf->amask) >> pf->ashift) >> (pf->abits - 8); ++ } ++ dst++, src32++, cnt--; ++ } ++} ++ ++/* ----------------------------------------------------------------------- */ ++/* QemuPixel -> PixelFormat conversions */ ++ ++static void conv_pixel_to_16(PixelFormat *pf, ++ void *dst, QemuPixel *src, uint32_t cnt) ++{ ++ uint16_t *dst16 = dst; ++ ++ while (cnt > 0) { ++ *dst16 = ((uint16_t)src->red >> (8 - pf->rbits)) << pf->rshift; ++ *dst16 |= ((uint16_t)src->green >> (8 - pf->gbits)) << pf->gshift; ++ *dst16 |= ((uint16_t)src->blue >> (8 - pf->bbits)) << pf->bshift; ++ *dst16 |= ((uint16_t)src->alpha >> (8 - pf->abits)) << pf->ashift; ++ dst16++, src++, cnt--; ++ } ++} ++ ++static void conv_pixel_to_32(PixelFormat *pf, ++ void *dst, QemuPixel *src, uint32_t cnt) ++{ ++ uint32_t *dst32 = dst; ++ ++ while (cnt > 0) { ++ *dst32 = ((uint32_t)src->red >> (8 - pf->rbits)) << pf->rshift; ++ *dst32 |= ((uint32_t)src->green >> (8 - pf->gbits)) << pf->gshift; ++ *dst32 |= ((uint32_t)src->blue >> (8 - pf->bbits)) << pf->bshift; ++ *dst32 |= ((uint32_t)src->alpha >> (8 - pf->abits)) << pf->ashift; ++ dst32++, src++, cnt--; ++ } ++} ++ ++/* ----------------------------------------------------------------------- */ ++/* PixelFormat -> PixelFormat conversions */ ++ ++static void convert_copy(QemuPfConv *conv, void *dst, void *src, uint32_t cnt) ++{ ++ uint32_t bytes = cnt * conv->src.bytes_per_pixel; ++ memcpy(dst, src, bytes); ++} ++ ++static void convert_generic(QemuPfConv *conv, void *dst, void *src, uint32_t cnt) ++{ ++ if (conv->conv_cnt < cnt) { ++ conv->conv_cnt = cnt; ++ conv->conv_buf = qemu_realloc(conv->conv_buf, sizeof(QemuPixel) * conv->conv_cnt); ++ } ++ conv->conv_from(&conv->src, conv->conv_buf, src, cnt); ++ conv->conv_to(&conv->dst, dst, conv->conv_buf, cnt); ++} ++ ++/* ----------------------------------------------------------------------- */ ++/* public interface */ ++ ++QemuPfConv *qemu_pf_conv_get(PixelFormat *dst, PixelFormat *src) ++{ ++ QemuPfConv *conv = qemu_mallocz(sizeof(QemuPfConv)); ++ ++ conv->src = *src; ++ conv->dst = *dst; ++ ++ if (memcmp(&conv->src, &conv->dst, sizeof(PixelFormat)) == 0) { ++ /* formats identical, can simply copy */ ++ conv->convert = convert_copy; ++ } else { ++ /* generic two-step conversion: src -> QemuPixel -> dst */ ++ switch (conv->src.bytes_per_pixel) { ++ case 2: ++ conv->conv_from = conv_16_to_pixel; ++ break; ++ case 4: ++ if (conv->src.rbits == 8 && conv->src.gbits == 8 && conv->src.bbits == 8) { ++ conv->conv_from = conv_32_to_pixel_fast; ++ } else { ++ conv->conv_from = conv_32_to_pixel_generic; ++ } ++ break; ++ default: ++ goto err; ++ } ++ switch (conv->dst.bytes_per_pixel) { ++ case 2: ++ conv->conv_to = conv_pixel_to_16; ++ break; ++ case 4: ++ conv->conv_to = conv_pixel_to_32; ++ break; ++ default: ++ goto err; ++ } ++ conv->convert = convert_generic; ++ } ++ return conv; ++ ++err: ++ qemu_free(conv); ++ return NULL; ++} ++ ++void qemu_pf_conv_run(QemuPfConv *conv, void *dst, void *src, uint32_t cnt) ++{ ++ conv->convert(conv, dst, src, cnt); ++} ++ ++void qemu_pf_conv_put(QemuPfConv *conv) ++{ ++ if (conv) { ++ qemu_free(conv->conv_buf); ++ qemu_free(conv); ++ } ++} +diff -urN qemu-kvm-0.13.0.orig/pflib.h qemu-kvm-0.13.0/pflib.h +--- qemu-kvm-0.13.0.orig/pflib.h 1970-01-01 02:00:00.000000000 +0200 ++++ qemu-kvm-0.13.0/pflib.h 2011-02-09 11:08:02.693000327 +0200 +@@ -0,0 +1,6 @@ ++/* public */ ++typedef struct QemuPfConv QemuPfConv; ++ ++QemuPfConv *qemu_pf_conv_get(PixelFormat *dst, PixelFormat *src); ++void qemu_pf_conv_run(QemuPfConv *conv, void *dst, void *src, uint32_t cnt); ++void qemu_pf_conv_put(QemuPfConv *conv); +diff -urN qemu-kvm-0.13.0.orig/qemu-config.c qemu-kvm-0.13.0/qemu-config.c +--- qemu-kvm-0.13.0.orig/qemu-config.c 2011-02-09 11:01:45.719000328 +0200 ++++ qemu-kvm-0.13.0/qemu-config.c 2011-02-09 11:08:02.832000327 +0200 +@@ -346,6 +346,56 @@ + }, + }; + ++#ifdef CONFIG_SPICE ++QemuOptsList qemu_spice_opts = { ++ .name = "spice", ++ .head = QTAILQ_HEAD_INITIALIZER(qemu_spice_opts.head), ++ .desc = { ++ { ++ .name = "port", ++ .type = QEMU_OPT_NUMBER, ++ },{ ++ .name = "tls-port", ++ .type = QEMU_OPT_NUMBER, ++ },{ ++ .name = "password", ++ .type = QEMU_OPT_STRING, ++ },{ ++ .name = "disable-ticketing", ++ .type = QEMU_OPT_BOOL, ++ },{ ++ .name = "x509-dir", ++ .type = QEMU_OPT_STRING, ++ },{ ++ .name = "x509-key-file", ++ .type = QEMU_OPT_STRING, ++ },{ ++ .name = "x509-key-password", ++ .type = QEMU_OPT_STRING, ++ },{ ++ .name = "x509-cert-file", ++ .type = QEMU_OPT_STRING, ++ },{ ++ .name = "x509-cacert-file", ++ .type = QEMU_OPT_STRING, ++ },{ ++ .name = "x509-dh-key-file", ++ .type = QEMU_OPT_STRING, ++ },{ ++ .name = "tls-ciphers", ++ .type = QEMU_OPT_STRING, ++ },{ ++ .name = "jpeg", ++ .type = QEMU_OPT_STRING, ++ },{ ++ .name = "zlib-glz", ++ .type = QEMU_OPT_STRING, ++ }, ++ { /* end if list */ } ++ }, ++}; ++#endif ++ + static QemuOptsList *vm_config_groups[] = { + &qemu_drive_opts, + &qemu_chardev_opts, +@@ -356,6 +406,9 @@ + &qemu_global_opts, + &qemu_mon_opts, + &qemu_cpudef_opts, ++#ifdef CONFIG_SPICE ++ &qemu_spice_opts, ++#endif + NULL, + }; + +diff -urN qemu-kvm-0.13.0.orig/qemu-config.h qemu-kvm-0.13.0/qemu-config.h +--- qemu-kvm-0.13.0.orig/qemu-config.h 2011-02-09 11:01:45.735000327 +0200 ++++ qemu-kvm-0.13.0/qemu-config.h 2011-02-09 11:08:02.709000327 +0200 +@@ -14,6 +14,7 @@ + extern QemuOptsList qemu_global_opts; + extern QemuOptsList qemu_mon_opts; + extern QemuOptsList qemu_cpudef_opts; ++extern QemuOptsList qemu_spice_opts; + + QemuOptsList *qemu_find_opts(const char *group); + int qemu_set_option(const char *str); +diff -urN qemu-kvm-0.13.0.orig/qemu-monitor.hx.orig qemu-kvm-0.13.0/qemu-monitor.hx.orig +--- qemu-kvm-0.13.0.orig/qemu-monitor.hx.orig 1970-01-01 02:00:00.000000000 +0200 ++++ qemu-kvm-0.13.0/qemu-monitor.hx.orig 2011-02-09 11:08:02.803000327 +0200 +@@ -0,0 +1,2560 @@ ++HXCOMM Use DEFHEADING() to define headings in both help text and texi ++HXCOMM Text between STEXI and ETEXI are copied to texi version and ++HXCOMM discarded from C version ++HXCOMM Text between SQMP and EQMP is copied to the QMP documention file and ++HXCOMM does not show up in the other formats. ++HXCOMM DEF(command, args, callback, arg_string, help) is used to construct ++HXCOMM monitor commands ++HXCOMM HXCOMM can be used for comments, discarded from both texi and C ++ ++SQMP ++ QMP Supported Commands ++ ---------------------- ++ ++This document describes all commands currently supported by QMP. ++ ++Most of the time their usage is exactly the same as in the user Monitor, this ++means that any other document which also describe commands (the manpage, ++QEMU's manual, etc) can and should be consulted. ++ ++QMP has two types of commands: regular and query commands. Regular commands ++usually change the Virtual Machine's state someway, while query commands just ++return information. The sections below are divided accordingly. ++ ++It's important to observe that all communication examples are formatted in ++a reader-friendly way, so that they're easier to understand. However, in real ++protocol usage, they're emitted as a single line. ++ ++Also, the following notation is used to denote data flow: ++ ++-> data issued by the Client ++<- Server data response ++ ++Please, refer to the QMP specification (QMP/qmp-spec.txt) for detailed ++information on the Server command and response formats. ++ ++NOTE: This document is temporary and will be replaced soon. ++ ++1. Stability Considerations ++=========================== ++ ++The current QMP command set (described in this file) may be useful for a ++number of use cases, however it's limited and several commands have bad ++defined semantics, specially with regard to command completion. ++ ++These problems are going to be solved incrementally in the next QEMU releases ++and we're going to establish a deprecation policy for badly defined commands. ++ ++If you're planning to adopt QMP, please observe the following: ++ ++ 1. The deprecation policy will take efect and be documented soon, please ++ check the documentation of each used command as soon as a new release of ++ QEMU is available ++ ++ 2. DO NOT rely on anything which is not explicit documented ++ ++ 3. Errors, in special, are not documented. Applications should NOT check ++ for specific errors classes or data (it's strongly recommended to only ++ check for the "error" key) ++ ++2. Regular Commands ++=================== ++ ++Server's responses in the examples below are always a success response, please ++refer to the QMP specification for more details on error responses. ++ ++EQMP ++ ++STEXI ++@table @option ++ETEXI ++ ++ { ++ .name = "help|?", ++ .args_type = "name:s?", ++ .params = "[cmd]", ++ .help = "show the help", ++ .mhandler.cmd = do_help_cmd, ++ }, ++ ++STEXI ++@item help or ? [@var{cmd}] ++@findex help ++Show the help for all commands or just for command @var{cmd}. ++ETEXI ++ ++ { ++ .name = "commit", ++ .args_type = "device:B", ++ .params = "device|all", ++ .help = "commit changes to the disk images (if -snapshot is used) or backing files", ++ .mhandler.cmd = do_commit, ++ }, ++ ++STEXI ++@item commit ++@findex commit ++Commit changes to the disk images (if -snapshot is used) or backing files. ++ETEXI ++ ++ { ++ .name = "q|quit", ++ .args_type = "", ++ .params = "", ++ .help = "quit the emulator", ++ .user_print = monitor_user_noop, ++ .mhandler.cmd_new = do_quit, ++ }, ++ ++STEXI ++@item q or quit ++@findex quit ++Quit the emulator. ++ETEXI ++SQMP ++quit ++---- ++ ++Quit the emulator. ++ ++Arguments: None. ++ ++Example: ++ ++-> { "execute": "quit" } ++<- { "return": {} } ++ ++EQMP ++ ++ { ++ .name = "eject", ++ .args_type = "force:-f,device:B", ++ .params = "[-f] device", ++ .help = "eject a removable medium (use -f to force it)", ++ .user_print = monitor_user_noop, ++ .mhandler.cmd_new = do_eject, ++ }, ++ ++STEXI ++@item eject [-f] @var{device} ++@findex eject ++Eject a removable medium (use -f to force it). ++ETEXI ++SQMP ++eject ++----- ++ ++Eject a removable medium. ++ ++Arguments: ++ ++- force: force ejection (json-bool, optional) ++- device: device name (json-string) ++ ++Example: ++ ++-> { "execute": "eject", "arguments": { "device": "ide1-cd0" } } ++<- { "return": {} } ++ ++Note: The "force" argument defaults to false. ++ ++EQMP ++ ++ { ++ .name = "change", ++ .args_type = "device:B,target:F,arg:s?", ++ .params = "device filename [format]", ++ .help = "change a removable medium, optional format", ++ .user_print = monitor_user_noop, ++ .mhandler.cmd_new = do_change, ++ }, ++ ++STEXI ++@item change @var{device} @var{setting} ++@findex change ++ ++Change the configuration of a device. ++ ++@table @option ++@item change @var{diskdevice} @var{filename} [@var{format}] ++Change the medium for a removable disk device to point to @var{filename}. eg ++ ++@example ++(qemu) change ide1-cd0 /path/to/some.iso ++@end example ++ ++@var{format} is optional. ++ ++@item change vnc @var{display},@var{options} ++Change the configuration of the VNC server. The valid syntax for @var{display} ++and @var{options} are described at @ref{sec_invocation}. eg ++ ++@example ++(qemu) change vnc localhost:1 ++@end example ++ ++@item change vnc password [@var{password}] ++ ++Change the password associated with the VNC server. If the new password is not ++supplied, the monitor will prompt for it to be entered. VNC passwords are only ++significant up to 8 letters. eg ++ ++@example ++(qemu) change vnc password ++Password: ******** ++@end example ++ ++@end table ++ETEXI ++SQMP ++change ++------ ++ ++Change a removable medium or VNC configuration. ++ ++Arguments: ++ ++- "device": device name (json-string) ++- "target": filename or item (json-string) ++- "arg": additional argument (json-string, optional) ++ ++Examples: ++ ++1. Change a removable medium ++ ++-> { "execute": "change", ++ "arguments": { "device": "ide1-cd0", ++ "target": "/srv/images/Fedora-12-x86_64-DVD.iso" } } ++<- { "return": {} } ++ ++2. Change VNC password ++ ++-> { "execute": "change", ++ "arguments": { "device": "vnc", "target": "password", ++ "arg": "foobar1" } } ++<- { "return": {} } ++ ++EQMP ++ ++ { ++ .name = "screendump", ++ .args_type = "filename:F", ++ .params = "filename", ++ .help = "save screen into PPM image 'filename'", ++ .user_print = monitor_user_noop, ++ .mhandler.cmd_new = do_screen_dump, ++ }, ++ ++STEXI ++@item screendump @var{filename} ++@findex screendump ++Save screen into PPM image @var{filename}. ++ETEXI ++SQMP ++screendump ++---------- ++ ++Save screen into PPM image. ++ ++Arguments: ++ ++- "filename": file path (json-string) ++ ++Example: ++ ++-> { "execute": "screendump", "arguments": { "filename": "/tmp/image" } } ++<- { "return": {} } ++ ++EQMP ++ ++ { ++ .name = "logfile", ++ .args_type = "filename:F", ++ .params = "filename", ++ .help = "output logs to 'filename'", ++ .mhandler.cmd = do_logfile, ++ }, ++ ++STEXI ++@item logfile @var{filename} ++@findex logfile ++Output logs to @var{filename}. ++ETEXI ++ ++ { ++ .name = "log", ++ .args_type = "items:s", ++ .params = "item1[,...]", ++ .help = "activate logging of the specified items to '/tmp/qemu.log'", ++ .mhandler.cmd = do_log, ++ }, ++ ++STEXI ++@item log @var{item1}[,...] ++@findex log ++Activate logging of the specified items to @file{/tmp/qemu.log}. ++ETEXI ++ ++ { ++ .name = "savevm", ++ .args_type = "name:s?", ++ .params = "[tag|id]", ++ .help = "save a VM snapshot. If no tag or id are provided, a new snapshot is created", ++ .mhandler.cmd = do_savevm, ++ }, ++ ++STEXI ++@item savevm [@var{tag}|@var{id}] ++@findex savevm ++Create a snapshot of the whole virtual machine. If @var{tag} is ++provided, it is used as human readable identifier. If there is already ++a snapshot with the same tag or ID, it is replaced. More info at ++@ref{vm_snapshots}. ++ETEXI ++ ++ { ++ .name = "loadvm", ++ .args_type = "name:s", ++ .params = "tag|id", ++ .help = "restore a VM snapshot from its tag or id", ++ .mhandler.cmd = do_loadvm, ++ }, ++ ++STEXI ++@item loadvm @var{tag}|@var{id} ++@findex loadvm ++Set the whole virtual machine to the snapshot identified by the tag ++@var{tag} or the unique snapshot ID @var{id}. ++ETEXI ++ ++ { ++ .name = "delvm", ++ .args_type = "name:s", ++ .params = "tag|id", ++ .help = "delete a VM snapshot from its tag or id", ++ .mhandler.cmd = do_delvm, ++ }, ++ ++STEXI ++@item delvm @var{tag}|@var{id} ++@findex delvm ++Delete the snapshot identified by @var{tag} or @var{id}. ++ETEXI ++ ++ { ++ .name = "singlestep", ++ .args_type = "option:s?", ++ .params = "[on|off]", ++ .help = "run emulation in singlestep mode or switch to normal mode", ++ .mhandler.cmd = do_singlestep, ++ }, ++ ++STEXI ++@item singlestep [off] ++@findex singlestep ++Run the emulation in single step mode. ++If called with option off, the emulation returns to normal mode. ++ETEXI ++ ++ { ++ .name = "stop", ++ .args_type = "", ++ .params = "", ++ .help = "stop emulation", ++ .user_print = monitor_user_noop, ++ .mhandler.cmd_new = do_stop, ++ }, ++ ++STEXI ++@item stop ++@findex stop ++Stop emulation. ++ETEXI ++SQMP ++stop ++---- ++ ++Stop the emulator. ++ ++Arguments: None. ++ ++Example: ++ ++-> { "execute": "stop" } ++<- { "return": {} } ++ ++EQMP ++ ++ { ++ .name = "c|cont", ++ .args_type = "", ++ .params = "", ++ .help = "resume emulation", ++ .user_print = monitor_user_noop, ++ .mhandler.cmd_new = do_cont, ++ }, ++ ++STEXI ++@item c or cont ++@findex cont ++Resume emulation. ++ETEXI ++SQMP ++cont ++---- ++ ++Resume emulation. ++ ++Arguments: None. ++ ++Example: ++ ++-> { "execute": "cont" } ++<- { "return": {} } ++ ++EQMP ++ ++ { ++ .name = "gdbserver", ++ .args_type = "device:s?", ++ .params = "[device]", ++ .help = "start gdbserver on given device (default 'tcp::1234'), stop with 'none'", ++ .mhandler.cmd = do_gdbserver, ++ }, ++ ++STEXI ++@item gdbserver [@var{port}] ++@findex gdbserver ++Start gdbserver session (default @var{port}=1234) ++ETEXI ++ ++ { ++ .name = "x", ++ .args_type = "fmt:/,addr:l", ++ .params = "/fmt addr", ++ .help = "virtual memory dump starting at 'addr'", ++ .mhandler.cmd = do_memory_dump, ++ }, ++ ++STEXI ++@item x/fmt @var{addr} ++@findex x ++Virtual memory dump starting at @var{addr}. ++ETEXI ++ ++ { ++ .name = "xp", ++ .args_type = "fmt:/,addr:l", ++ .params = "/fmt addr", ++ .help = "physical memory dump starting at 'addr'", ++ .mhandler.cmd = do_physical_memory_dump, ++ }, ++ ++STEXI ++@item xp /@var{fmt} @var{addr} ++@findex xp ++Physical memory dump starting at @var{addr}. ++ ++@var{fmt} is a format which tells the command how to format the ++data. Its syntax is: @option{/@{count@}@{format@}@{size@}} ++ ++@table @var ++@item count ++is the number of items to be dumped. ++ ++@item format ++can be x (hex), d (signed decimal), u (unsigned decimal), o (octal), ++c (char) or i (asm instruction). ++ ++@item size ++can be b (8 bits), h (16 bits), w (32 bits) or g (64 bits). On x86, ++@code{h} or @code{w} can be specified with the @code{i} format to ++respectively select 16 or 32 bit code instruction size. ++ ++@end table ++ ++Examples: ++@itemize ++@item ++Dump 10 instructions at the current instruction pointer: ++@example ++(qemu) x/10i $eip ++0x90107063: ret ++0x90107064: sti ++0x90107065: lea 0x0(%esi,1),%esi ++0x90107069: lea 0x0(%edi,1),%edi ++0x90107070: ret ++0x90107071: jmp 0x90107080 ++0x90107073: nop ++0x90107074: nop ++0x90107075: nop ++0x90107076: nop ++@end example ++ ++@item ++Dump 80 16 bit values at the start of the video memory. ++@smallexample ++(qemu) xp/80hx 0xb8000 ++0x000b8000: 0x0b50 0x0b6c 0x0b65 0x0b78 0x0b38 0x0b36 0x0b2f 0x0b42 ++0x000b8010: 0x0b6f 0x0b63 0x0b68 0x0b73 0x0b20 0x0b56 0x0b47 0x0b41 ++0x000b8020: 0x0b42 0x0b69 0x0b6f 0x0b73 0x0b20 0x0b63 0x0b75 0x0b72 ++0x000b8030: 0x0b72 0x0b65 0x0b6e 0x0b74 0x0b2d 0x0b63 0x0b76 0x0b73 ++0x000b8040: 0x0b20 0x0b30 0x0b35 0x0b20 0x0b4e 0x0b6f 0x0b76 0x0b20 ++0x000b8050: 0x0b32 0x0b30 0x0b30 0x0b33 0x0720 0x0720 0x0720 0x0720 ++0x000b8060: 0x0720 0x0720 0x0720 0x0720 0x0720 0x0720 0x0720 0x0720 ++0x000b8070: 0x0720 0x0720 0x0720 0x0720 0x0720 0x0720 0x0720 0x0720 ++0x000b8080: 0x0720 0x0720 0x0720 0x0720 0x0720 0x0720 0x0720 0x0720 ++0x000b8090: 0x0720 0x0720 0x0720 0x0720 0x0720 0x0720 0x0720 0x0720 ++@end smallexample ++@end itemize ++ETEXI ++ ++ { ++ .name = "p|print", ++ .args_type = "fmt:/,val:l", ++ .params = "/fmt expr", ++ .help = "print expression value (use $reg for CPU register access)", ++ .mhandler.cmd = do_print, ++ }, ++ ++STEXI ++@item p or print/@var{fmt} @var{expr} ++@findex print ++ ++Print expression value. Only the @var{format} part of @var{fmt} is ++used. ++ETEXI ++ ++ { ++ .name = "i", ++ .args_type = "fmt:/,addr:i,index:i.", ++ .params = "/fmt addr", ++ .help = "I/O port read", ++ .mhandler.cmd = do_ioport_read, ++ }, ++ ++STEXI ++Read I/O port. ++ETEXI ++ ++ { ++ .name = "o", ++ .args_type = "fmt:/,addr:i,val:i", ++ .params = "/fmt addr value", ++ .help = "I/O port write", ++ .mhandler.cmd = do_ioport_write, ++ }, ++ ++STEXI ++Write to I/O port. ++ETEXI ++ ++ { ++ .name = "sendkey", ++ .args_type = "string:s,hold_time:i?", ++ .params = "keys [hold_ms]", ++ .help = "send keys to the VM (e.g. 'sendkey ctrl-alt-f1', default hold time=100 ms)", ++ .mhandler.cmd = do_sendkey, ++ }, ++ ++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: ++@example ++sendkey ctrl-alt-f1 ++@end example ++ ++This command is useful to send keys that your graphical user interface ++intercepts at low level, such as @code{ctrl-alt-f1} in X Window. ++ETEXI ++ ++ { ++ .name = "system_reset", ++ .args_type = "", ++ .params = "", ++ .help = "reset the system", ++ .user_print = monitor_user_noop, ++ .mhandler.cmd_new = do_system_reset, ++ }, ++ ++STEXI ++@item system_reset ++@findex system_reset ++ ++Reset the system. ++ETEXI ++SQMP ++system_reset ++------------ ++ ++Reset the system. ++ ++Arguments: None. ++ ++Example: ++ ++-> { "execute": "system_reset" } ++<- { "return": {} } ++ ++EQMP ++ ++ { ++ .name = "system_powerdown", ++ .args_type = "", ++ .params = "", ++ .help = "send system power down event", ++ .user_print = monitor_user_noop, ++ .mhandler.cmd_new = do_system_powerdown, ++ }, ++ ++STEXI ++@item system_powerdown ++@findex system_powerdown ++ ++Power down the system (if supported). ++ETEXI ++SQMP ++system_powerdown ++---------------- ++ ++Send system power down event. ++ ++Arguments: None. ++ ++Example: ++ ++-> { "execute": "system_powerdown" } ++<- { "return": {} } ++ ++EQMP ++ ++ { ++ .name = "sum", ++ .args_type = "start:i,size:i", ++ .params = "addr size", ++ .help = "compute the checksum of a memory region", ++ .mhandler.cmd = do_sum, ++ }, ++ ++STEXI ++@item sum @var{addr} @var{size} ++@findex sum ++ ++Compute the checksum of a memory region. ++ETEXI ++ ++ { ++ .name = "usb_add", ++ .args_type = "devname:s", ++ .params = "device", ++ .help = "add USB device (e.g. 'host:bus.addr' or 'host:vendor_id:product_id')", ++ .mhandler.cmd = do_usb_add, ++ }, ++ ++STEXI ++@item usb_add @var{devname} ++@findex usb_add ++ ++Add the USB device @var{devname}. For details of available devices see ++@ref{usb_devices} ++ETEXI ++ ++ { ++ .name = "usb_del", ++ .args_type = "devname:s", ++ .params = "device", ++ .help = "remove USB device 'bus.addr'", ++ .mhandler.cmd = do_usb_del, ++ }, ++ ++STEXI ++@item usb_del @var{devname} ++@findex usb_del ++ ++Remove the USB device @var{devname} from the QEMU virtual USB ++hub. @var{devname} has the syntax @code{bus.addr}. Use the monitor ++command @code{info usb} to see the devices you can remove. ++ETEXI ++ ++ { ++ .name = "device_add", ++ .args_type = "device:O", ++ .params = "driver[,prop=value][,...]", ++ .help = "add device, like -device on the command line", ++ .user_print = monitor_user_noop, ++ .mhandler.cmd_new = do_device_add, ++ }, ++ ++STEXI ++@item device_add @var{config} ++@findex device_add ++ ++Add device. ++ETEXI ++SQMP ++device_add ++---------- ++ ++Add a device. ++ ++Arguments: ++ ++- "driver": the name of the new device's driver (json-string) ++- "bus": the device's parent bus (device tree path, json-string, optional) ++- "id": the device's ID, must be unique (json-string) ++- device properties ++ ++Example: ++ ++-> { "execute": "device_add", "arguments": { "driver": "e1000", "id": "net1" } } ++<- { "return": {} } ++ ++Notes: ++ ++(1) For detailed information about this command, please refer to the ++ 'docs/qdev-device-use.txt' file. ++ ++(2) It's possible to list device properties by running QEMU with the ++ "-device DEVICE,\?" command-line argument, where DEVICE is the device's name ++ ++EQMP ++ ++ { ++ .name = "device_del", ++ .args_type = "id:s", ++ .params = "device", ++ .help = "remove device", ++ .user_print = monitor_user_noop, ++ .mhandler.cmd_new = do_device_del, ++ }, ++ ++STEXI ++@item device_del @var{id} ++@findex device_del ++ ++Remove device @var{id}. ++ETEXI ++SQMP ++device_del ++---------- ++ ++Remove a device. ++ ++Arguments: ++ ++- "id": the device's ID (json-string) ++ ++Example: ++ ++-> { "execute": "device_del", "arguments": { "id": "net1" } } ++<- { "return": {} } ++ ++EQMP ++ ++ { ++ .name = "cpu", ++ .args_type = "index:i", ++ .params = "index", ++ .help = "set the default CPU", ++ .user_print = monitor_user_noop, ++ .mhandler.cmd_new = do_cpu_set, ++ }, ++ ++STEXI ++@item cpu @var{index} ++@findex cpu ++Set the default CPU. ++ETEXI ++SQMP ++cpu ++--- ++ ++Set the default CPU. ++ ++Arguments: ++ ++- "index": the CPU's index (json-int) ++ ++Example: ++ ++-> { "execute": "cpu", "arguments": { "index": 0 } } ++<- { "return": {} } ++ ++Note: CPUs' indexes are obtained with the 'query-cpus' command. ++ ++EQMP ++ ++ { ++ .name = "mouse_move", ++ .args_type = "dx_str:s,dy_str:s,dz_str:s?", ++ .params = "dx dy [dz]", ++ .help = "send mouse move events", ++ .mhandler.cmd = do_mouse_move, ++ }, ++ ++STEXI ++@item mouse_move @var{dx} @var{dy} [@var{dz}] ++@findex mouse_move ++Move the active mouse to the specified coordinates @var{dx} @var{dy} ++with optional scroll axis @var{dz}. ++ETEXI ++ ++ { ++ .name = "mouse_button", ++ .args_type = "button_state:i", ++ .params = "state", ++ .help = "change mouse button state (1=L, 2=M, 4=R)", ++ .mhandler.cmd = do_mouse_button, ++ }, ++ ++STEXI ++@item mouse_button @var{val} ++@findex mouse_button ++Change the active mouse button state @var{val} (1=L, 2=M, 4=R). ++ETEXI ++ ++ { ++ .name = "mouse_set", ++ .args_type = "index:i", ++ .params = "index", ++ .help = "set which mouse device receives events", ++ .mhandler.cmd = do_mouse_set, ++ }, ++ ++STEXI ++@item mouse_set @var{index} ++@findex mouse_set ++Set which mouse device receives events at given @var{index}, index ++can be obtained with ++@example ++info mice ++@end example ++ETEXI ++ ++#ifdef HAS_AUDIO ++ { ++ .name = "wavcapture", ++ .args_type = "path:F,freq:i?,bits:i?,nchannels:i?", ++ .params = "path [frequency [bits [channels]]]", ++ .help = "capture audio to a wave file (default frequency=44100 bits=16 channels=2)", ++ .mhandler.cmd = do_wav_capture, ++ }, ++#endif ++STEXI ++@item wavcapture @var{filename} [@var{frequency} [@var{bits} [@var{channels}]]] ++@findex wavcapture ++Capture audio into @var{filename}. Using sample rate @var{frequency} ++bits per sample @var{bits} and number of channels @var{channels}. ++ ++Defaults: ++@itemize @minus ++@item Sample rate = 44100 Hz - CD quality ++@item Bits = 16 ++@item Number of channels = 2 - Stereo ++@end itemize ++ETEXI ++ ++#ifdef HAS_AUDIO ++ { ++ .name = "stopcapture", ++ .args_type = "n:i", ++ .params = "capture index", ++ .help = "stop capture", ++ .mhandler.cmd = do_stop_capture, ++ }, ++#endif ++STEXI ++@item stopcapture @var{index} ++@findex stopcapture ++Stop capture with a given @var{index}, index can be obtained with ++@example ++info capture ++@end example ++ETEXI ++ ++ { ++ .name = "memsave", ++ .args_type = "val:l,size:i,filename:s", ++ .params = "addr size file", ++ .help = "save to disk virtual memory dump starting at 'addr' of size 'size'", ++ .user_print = monitor_user_noop, ++ .mhandler.cmd_new = do_memory_save, ++ }, ++ ++STEXI ++@item memsave @var{addr} @var{size} @var{file} ++@findex memsave ++save to disk virtual memory dump starting at @var{addr} of size @var{size}. ++ETEXI ++SQMP ++memsave ++------- ++ ++Save to disk virtual memory dump starting at 'val' of size 'size'. ++ ++Arguments: ++ ++- "val": the starting address (json-int) ++- "size": the memory size, in bytes (json-int) ++- "filename": file path (json-string) ++ ++Example: ++ ++-> { "execute": "memsave", ++ "arguments": { "val": 10, ++ "size": 100, ++ "filename": "/tmp/virtual-mem-dump" } } ++<- { "return": {} } ++ ++Note: Depends on the current CPU. ++ ++EQMP ++ ++ { ++ .name = "pmemsave", ++ .args_type = "val:l,size:i,filename:s", ++ .params = "addr size file", ++ .help = "save to disk physical memory dump starting at 'addr' of size 'size'", ++ .user_print = monitor_user_noop, ++ .mhandler.cmd_new = do_physical_memory_save, ++ }, ++ ++STEXI ++@item pmemsave @var{addr} @var{size} @var{file} ++@findex pmemsave ++save to disk physical memory dump starting at @var{addr} of size @var{size}. ++ETEXI ++SQMP ++pmemsave ++-------- ++ ++Save to disk physical memory dump starting at 'val' of size 'size'. ++ ++Arguments: ++ ++- "val": the starting address (json-int) ++- "size": the memory size, in bytes (json-int) ++- "filename": file path (json-string) ++ ++Example: ++ ++-> { "execute": "pmemsave", ++ "arguments": { "val": 10, ++ "size": 100, ++ "filename": "/tmp/physical-mem-dump" } } ++<- { "return": {} } ++ ++EQMP ++ ++ { ++ .name = "boot_set", ++ .args_type = "bootdevice:s", ++ .params = "bootdevice", ++ .help = "define new values for the boot device list", ++ .mhandler.cmd = do_boot_set, ++ }, ++ ++STEXI ++@item boot_set @var{bootdevicelist} ++@findex boot_set ++ ++Define new values for the boot device list. Those values will override ++the values specified on the command line through the @code{-boot} option. ++ ++The values that can be specified here depend on the machine type, but are ++the same that can be specified in the @code{-boot} command line option. ++ETEXI ++ ++#if defined(TARGET_I386) ++ { ++ .name = "nmi", ++ .args_type = "cpu_index:i", ++ .params = "cpu", ++ .help = "inject an NMI on the given CPU", ++ .mhandler.cmd = do_inject_nmi, ++ }, ++#endif ++STEXI ++@item nmi @var{cpu} ++@findex nmi ++Inject an NMI on the given CPU (x86 only). ++ETEXI ++ ++ { ++ .name = "migrate", ++ .args_type = "detach:-d,blk:-b,inc:-i,uri:s", ++ .params = "[-d] [-b] [-i] uri", ++ .help = "migrate to URI (using -d to not wait for completion)" ++ "\n\t\t\t -b for migration without shared storage with" ++ " full copy of disk\n\t\t\t -i for migration without " ++ "shared storage with incremental copy of disk " ++ "(base image shared between src and destination)", ++ .user_print = monitor_user_noop, ++ .mhandler.cmd_new = do_migrate, ++ }, ++ ++ ++STEXI ++@item migrate [-d] [-b] [-i] @var{uri} ++@findex migrate ++Migrate to @var{uri} (using -d to not wait for completion). ++ -b for migration with full copy of disk ++ -i for migration with incremental copy of disk (base image is shared) ++ETEXI ++SQMP ++migrate ++------- ++ ++Migrate to URI. ++ ++Arguments: ++ ++- "blk": block migration, full disk copy (json-bool, optional) ++- "inc": incremental disk copy (json-bool, optional) ++- "uri": Destination URI (json-string) ++ ++Example: ++ ++-> { "execute": "migrate", "arguments": { "uri": "tcp:0:4446" } } ++<- { "return": {} } ++ ++Notes: ++ ++(1) The 'query-migrate' command should be used to check migration's progress ++ and final result (this information is provided by the 'status' member) ++(2) All boolean arguments default to false ++(3) The user Monitor's "detach" argument is invalid in QMP and should not ++ be used ++ ++EQMP ++ ++ { ++ .name = "migrate_cancel", ++ .args_type = "", ++ .params = "", ++ .help = "cancel the current VM migration", ++ .user_print = monitor_user_noop, ++ .mhandler.cmd_new = do_migrate_cancel, ++ }, ++ ++STEXI ++@item migrate_cancel ++@findex migrate_cancel ++Cancel the current VM migration. ++ETEXI ++SQMP ++migrate_cancel ++-------------- ++ ++Cancel the current migration. ++ ++Arguments: None. ++ ++Example: ++ ++-> { "execute": "migrate_cancel" } ++<- { "return": {} } ++ ++EQMP ++ ++ { ++ .name = "migrate_set_speed", ++ .args_type = "value:f", ++ .params = "value", ++ .help = "set maximum speed (in bytes) for migrations", ++ .user_print = monitor_user_noop, ++ .mhandler.cmd_new = do_migrate_set_speed, ++ }, ++ ++STEXI ++@item migrate_set_speed @var{value} ++@findex migrate_set_speed ++Set maximum speed to @var{value} (in bytes) for migrations. ++ETEXI ++SQMP ++migrate_set_speed ++----------------- ++ ++Set maximum speed for migrations. ++ ++Arguments: ++ ++- "value": maximum speed, in bytes per second (json-number) ++ ++Example: ++ ++-> { "execute": "migrate_set_speed", "arguments": { "value": 1024 } } ++<- { "return": {} } ++ ++EQMP ++ ++ { ++ .name = "migrate_set_downtime", ++ .args_type = "value:T", ++ .params = "value", ++ .help = "set maximum tolerated downtime (in seconds) for migrations", ++ .user_print = monitor_user_noop, ++ .mhandler.cmd_new = do_migrate_set_downtime, ++ }, ++ ++STEXI ++@item migrate_set_downtime @var{second} ++@findex migrate_set_downtime ++Set maximum tolerated downtime (in seconds) for migration. ++ETEXI ++SQMP ++migrate_set_downtime ++-------------------- ++ ++Set maximum tolerated downtime (in seconds) for migrations. ++ ++Arguments: ++ ++- "value": maximum downtime (json-number) ++ ++Example: ++ ++-> { "execute": "migrate_set_downtime", "arguments": { "value": 0.1 } } ++<- { "return": {} } ++ ++EQMP ++ ++#if defined(TARGET_I386) ++ { ++ .name = "drive_add", ++ .args_type = "pci_addr:s,opts:s", ++ .params = "[[<domain>:]<bus>:]<slot>\n" ++ "[file=file][,if=type][,bus=n]\n" ++ "[,unit=m][,media=d][index=i]\n" ++ "[,cyls=c,heads=h,secs=s[,trans=t]]\n" ++ "[snapshot=on|off][,cache=on|off]", ++ .help = "add drive to PCI storage controller", ++ .mhandler.cmd = drive_hot_add, ++ }, ++#endif ++ ++STEXI ++@item drive_add ++@findex drive_add ++Add drive to PCI storage controller. ++ETEXI ++ ++#if defined(TARGET_I386) ++ { ++ .name = "pci_add", ++ .args_type = "pci_addr:s,type:s,opts:s?", ++ .params = "auto|[[<domain>:]<bus>:]<slot> nic|storage|host [[vlan=n][,macaddr=addr][,model=type]] [file=file][,if=type][,bus=nr]... [host=02:00.0[,name=string][,dma=none]", ++ .help = "hot-add PCI device", ++ .mhandler.cmd = pci_device_hot_add, ++ }, ++#endif ++ ++STEXI ++@item pci_add ++@findex pci_add ++Hot-add PCI device. ++ETEXI ++ ++#if defined(TARGET_I386) ++ { ++ .name = "pci_del", ++ .args_type = "pci_addr:s", ++ .params = "[[<domain>:]<bus>:]<slot>", ++ .help = "hot remove PCI device", ++ .mhandler.cmd = do_pci_device_hot_remove, ++ }, ++#endif ++ ++STEXI ++@item pci_del ++@findex pci_del ++Hot remove PCI device. ++ETEXI ++ ++ { ++ .name = "host_net_add", ++ .args_type = "device:s,opts:s?", ++ .params = "tap|user|socket|vde|dump [options]", ++ .help = "add host VLAN client", ++ .mhandler.cmd = net_host_device_add, ++ }, ++ ++STEXI ++@item host_net_add ++@findex host_net_add ++Add host VLAN client. ++ETEXI ++ ++ { ++ .name = "host_net_remove", ++ .args_type = "vlan_id:i,device:s", ++ .params = "vlan_id name", ++ .help = "remove host VLAN client", ++ .mhandler.cmd = net_host_device_remove, ++ }, ++ ++STEXI ++@item host_net_remove ++@findex host_net_remove ++Remove host VLAN client. ++ETEXI ++ ++ { ++ .name = "netdev_add", ++ .args_type = "netdev:O", ++ .params = "[user|tap|socket],id=str[,prop=value][,...]", ++ .help = "add host network device", ++ .user_print = monitor_user_noop, ++ .mhandler.cmd_new = do_netdev_add, ++ }, ++ ++STEXI ++@item netdev_add ++@findex netdev_add ++Add host network device. ++ETEXI ++SQMP ++netdev_add ++---------- ++ ++Add host network device. ++ ++Arguments: ++ ++- "type": the device type, "tap", "user", ... (json-string) ++- "id": the device's ID, must be unique (json-string) ++- device options ++ ++Example: ++ ++-> { "execute": "netdev_add", "arguments": { "type": "user", "id": "netdev1" } } ++<- { "return": {} } ++ ++Note: The supported device options are the same ones supported by the '-net' ++ command-line argument, which are listed in the '-help' output or QEMU's ++ manual ++ ++EQMP ++ ++ { ++ .name = "netdev_del", ++ .args_type = "id:s", ++ .params = "id", ++ .help = "remove host network device", ++ .user_print = monitor_user_noop, ++ .mhandler.cmd_new = do_netdev_del, ++ }, ++ ++STEXI ++@item netdev_del ++@findex netdev_del ++Remove host network device. ++ETEXI ++SQMP ++netdev_del ++---------- ++ ++Remove host network device. ++ ++Arguments: ++ ++- "id": the device's ID, must be unique (json-string) ++ ++Example: ++ ++-> { "execute": "netdev_del", "arguments": { "id": "netdev1" } } ++<- { "return": {} } ++ ++EQMP ++ ++#ifdef CONFIG_SLIRP ++ { ++ .name = "hostfwd_add", ++ .args_type = "arg1:s,arg2:s?,arg3:s?", ++ .params = "[vlan_id name] [tcp|udp]:[hostaddr]:hostport-[guestaddr]:guestport", ++ .help = "redirect TCP or UDP connections from host to guest (requires -net user)", ++ .mhandler.cmd = net_slirp_hostfwd_add, ++ }, ++#endif ++STEXI ++@item hostfwd_add ++@findex hostfwd_add ++Redirect TCP or UDP connections from host to guest (requires -net user). ++ETEXI ++ ++#ifdef CONFIG_SLIRP ++ { ++ .name = "hostfwd_remove", ++ .args_type = "arg1:s,arg2:s?,arg3:s?", ++ .params = "[vlan_id name] [tcp|udp]:[hostaddr]:hostport", ++ .help = "remove host-to-guest TCP or UDP redirection", ++ .mhandler.cmd = net_slirp_hostfwd_remove, ++ }, ++ ++#endif ++STEXI ++@item hostfwd_remove ++@findex hostfwd_remove ++Remove host-to-guest TCP or UDP redirection. ++ETEXI ++ ++ { ++ .name = "balloon", ++ .args_type = "value:M", ++ .params = "target", ++ .help = "request VM to change its memory allocation (in MB)", ++ .user_print = monitor_user_noop, ++ .mhandler.cmd_async = do_balloon, ++ .flags = MONITOR_CMD_ASYNC, ++ }, ++ ++STEXI ++@item balloon @var{value} ++@findex balloon ++Request VM to change its memory allocation to @var{value} (in MB). ++ETEXI ++SQMP ++balloon ++------- ++ ++Request VM to change its memory allocation (in bytes). ++ ++Arguments: ++ ++- "value": New memory allocation (json-int) ++ ++Example: ++ ++-> { "execute": "balloon", "arguments": { "value": 536870912 } } ++<- { "return": {} } ++ ++EQMP ++ ++ { ++ .name = "set_link", ++ .args_type = "name:s,up:b", ++ .params = "name on|off", ++ .help = "change the link status of a network adapter", ++ .user_print = monitor_user_noop, ++ .mhandler.cmd_new = do_set_link, ++ }, ++ ++STEXI ++@item set_link @var{name} [on|off] ++@findex set_link ++Switch link @var{name} on (i.e. up) or off (i.e. down). ++ETEXI ++SQMP ++set_link ++-------- ++ ++Change the link status of a network adapter. ++ ++Arguments: ++ ++- "name": network device name (json-string) ++- "up": status is up (json-bool) ++ ++Example: ++ ++-> { "execute": "set_link", "arguments": { "name": "e1000.0", "up": false } } ++<- { "return": {} } ++ ++EQMP ++ ++ { ++ .name = "watchdog_action", ++ .args_type = "action:s", ++ .params = "[reset|shutdown|poweroff|pause|debug|none]", ++ .help = "change watchdog action", ++ .mhandler.cmd = do_watchdog_action, ++ }, ++ ++STEXI ++@item watchdog_action ++@findex watchdog_action ++Change watchdog action. ++ETEXI ++ ++ { ++ .name = "acl_show", ++ .args_type = "aclname:s", ++ .params = "aclname", ++ .help = "list rules in the access control list", ++ .mhandler.cmd = do_acl_show, ++ }, ++ ++STEXI ++@item acl_show @var{aclname} ++@findex acl_show ++List all the matching rules in the access control list, and the default ++policy. There are currently two named access control lists, ++@var{vnc.x509dname} and @var{vnc.username} matching on the x509 client ++certificate distinguished name, and SASL username respectively. ++ETEXI ++ ++ { ++ .name = "acl_policy", ++ .args_type = "aclname:s,policy:s", ++ .params = "aclname allow|deny", ++ .help = "set default access control list policy", ++ .mhandler.cmd = do_acl_policy, ++ }, ++ ++STEXI ++@item acl_policy @var{aclname} @code{allow|deny} ++@findex acl_policy ++Set the default access control list policy, used in the event that ++none of the explicit rules match. The default policy at startup is ++always @code{deny}. ++ETEXI ++ ++ { ++ .name = "acl_add", ++ .args_type = "aclname:s,match:s,policy:s,index:i?", ++ .params = "aclname match allow|deny [index]", ++ .help = "add a match rule to the access control list", ++ .mhandler.cmd = do_acl_add, ++ }, ++ ++STEXI ++@item acl_add @var{aclname} @var{match} @code{allow|deny} [@var{index}] ++@findex acl_add ++Add a match rule to the access control list, allowing or denying access. ++The match will normally be an exact username or x509 distinguished name, ++but can optionally include wildcard globs. eg @code{*@@EXAMPLE.COM} to ++allow all users in the @code{EXAMPLE.COM} kerberos realm. The match will ++normally be appended to the end of the ACL, but can be inserted ++earlier in the list if the optional @var{index} parameter is supplied. ++ETEXI ++ ++ { ++ .name = "acl_remove", ++ .args_type = "aclname:s,match:s", ++ .params = "aclname match", ++ .help = "remove a match rule from the access control list", ++ .mhandler.cmd = do_acl_remove, ++ }, ++ ++STEXI ++@item acl_remove @var{aclname} @var{match} ++@findex acl_remove ++Remove the specified match rule from the access control list. ++ETEXI ++ ++ { ++ .name = "acl_reset", ++ .args_type = "aclname:s", ++ .params = "aclname", ++ .help = "reset the access control list", ++ .mhandler.cmd = do_acl_reset, ++ }, ++ ++STEXI ++@item acl_reset @var{aclname} ++@findex acl_reset ++Remove all matches from the access control list, and set the default ++policy back to @code{deny}. ++ETEXI ++ ++#if defined(TARGET_I386) ++ ++ { ++ .name = "mce", ++ .args_type = "cpu_index:i,bank:i,status:l,mcg_status:l,addr:l,misc:l", ++ .params = "cpu bank status mcgstatus addr misc", ++ .help = "inject a MCE on the given CPU", ++ .mhandler.cmd = do_inject_mce, ++ }, ++ ++#endif ++STEXI ++@item mce @var{cpu} @var{bank} @var{status} @var{mcgstatus} @var{addr} @var{misc} ++@findex mce (x86) ++Inject an MCE on the given CPU (x86 only). ++ETEXI ++ ++ { ++ .name = "getfd", ++ .args_type = "fdname:s", ++ .params = "getfd name", ++ .help = "receive a file descriptor via SCM rights and assign it a name", ++ .user_print = monitor_user_noop, ++ .mhandler.cmd_new = do_getfd, ++ }, ++ ++STEXI ++@item getfd @var{fdname} ++@findex getfd ++If a file descriptor is passed alongside this command using the SCM_RIGHTS ++mechanism on unix sockets, it is stored using the name @var{fdname} for ++later use by other monitor commands. ++ETEXI ++SQMP ++getfd ++----- ++ ++Receive a file descriptor via SCM rights and assign it a name. ++ ++Arguments: ++ ++- "fdname": file descriptor name (json-string) ++ ++Example: ++ ++-> { "execute": "getfd", "arguments": { "fdname": "fd1" } } ++<- { "return": {} } ++ ++EQMP ++ ++ { ++ .name = "closefd", ++ .args_type = "fdname:s", ++ .params = "closefd name", ++ .help = "close a file descriptor previously passed via SCM rights", ++ .user_print = monitor_user_noop, ++ .mhandler.cmd_new = do_closefd, ++ }, ++ ++STEXI ++@item closefd @var{fdname} ++@findex closefd ++Close the file descriptor previously assigned to @var{fdname} using the ++@code{getfd} command. This is only needed if the file descriptor was never ++used by another monitor command. ++ETEXI ++SQMP ++closefd ++------- ++ ++Close a file descriptor previously passed via SCM rights. ++ ++Arguments: ++ ++- "fdname": file descriptor name (json-string) ++ ++Example: ++ ++-> { "execute": "closefd", "arguments": { "fdname": "fd1" } } ++<- { "return": {} } ++ ++EQMP ++ ++ { ++ .name = "block_passwd", ++ .args_type = "device:B,password:s", ++ .params = "block_passwd device password", ++ .help = "set the password of encrypted block devices", ++ .user_print = monitor_user_noop, ++ .mhandler.cmd_new = do_block_set_passwd, ++ }, ++ ++STEXI ++@item block_passwd @var{device} @var{password} ++@findex block_passwd ++Set the encrypted device @var{device} password to @var{password} ++ETEXI ++SQMP ++block_passwd ++------------ ++ ++Set the password of encrypted block devices. ++ ++Arguments: ++ ++- "device": device name (json-string) ++- "password": password (json-string) ++ ++Example: ++ ++-> { "execute": "block_passwd", "arguments": { "device": "ide0-hd0", ++ "password": "12345" } } ++<- { "return": {} } ++ ++EQMP ++ ++ { ++ .name = "cpu_set", ++ .args_type = "cpu:i,state:s", ++ .params = "cpu [online|offline]", ++ .help = "change cpu state", ++ .mhandler.cmd = do_cpu_set_nr, ++ }, ++ ++STEXI ++@item cpu_set @var{cpu} [online|offline] ++Set CPU @var{cpu} online or offline. ++ETEXI ++ ++ { ++ .name = "qmp_capabilities", ++ .args_type = "", ++ .params = "", ++ .help = "enable QMP capabilities", ++ .user_print = monitor_user_noop, ++ .mhandler.cmd_new = do_qmp_capabilities, ++ }, ++ ++STEXI ++@item qmp_capabilities ++@findex qmp_capabilities ++Enable the specified QMP capabilities ++ETEXI ++SQMP ++qmp_capabilities ++---------------- ++ ++Enable QMP capabilities. ++ ++Arguments: None. ++ ++Example: ++ ++-> { "execute": "qmp_capabilities" } ++<- { "return": {} } ++ ++Note: This command must be issued before issuing any other command. ++ ++EQMP ++ ++ ++HXCOMM Keep the 'info' command at the end! ++HXCOMM This is required for the QMP documentation layout. ++ ++SQMP ++ ++3. Query Commands ++================= ++ ++EQMP ++ ++ { ++ .name = "info", ++ .args_type = "item:s?", ++ .params = "[subcommand]", ++ .help = "show various information about the system state", ++ .user_print = monitor_user_noop, ++ .mhandler.cmd_new = do_info, ++ }, ++ ++STEXI ++@item info @var{subcommand} ++@findex info ++Show various information about the system state. ++ ++@table @option ++@item info version ++show the version of QEMU ++ETEXI ++SQMP ++query-version ++------------- ++ ++Show QEMU version. ++ ++Return a json-object with the following information: ++ ++- "qemu": A json-object containing three integer values: ++ - "major": QEMU's major version (json-int) ++ - "minor": QEMU's minor version (json-int) ++ - "micro": QEMU's micro version (json-int) ++- "package": package's version (json-string) ++ ++Example: ++ ++-> { "execute": "query-version" } ++<- { ++ "return":{ ++ "qemu":{ ++ "major":0, ++ "minor":11, ++ "micro":5 ++ }, ++ "package":"" ++ } ++ } ++ ++EQMP ++ ++STEXI ++@item info commands ++list QMP available commands ++ETEXI ++SQMP ++query-commands ++-------------- ++ ++List QMP available commands. ++ ++Each command is represented by a json-object, the returned value is a json-array ++of all commands. ++ ++Each json-object contain: ++ ++- "name": command's name (json-string) ++ ++Example: ++ ++-> { "execute": "query-commands" } ++<- { ++ "return":[ ++ { ++ "name":"query-balloon" ++ }, ++ { ++ "name":"system_powerdown" ++ } ++ ] ++ } ++ ++Note: This example has been shortened as the real response is too long. ++ ++EQMP ++ ++STEXI ++@item info network ++show the various VLANs and the associated devices ++ETEXI ++ ++STEXI ++@item info chardev ++show the character devices ++ETEXI ++SQMP ++query-chardev ++------------- ++ ++Each device is represented by a json-object. The returned value is a json-array ++of all devices. ++ ++Each json-object contain the following: ++ ++- "label": device's label (json-string) ++- "filename": device's file (json-string) ++ ++Example: ++ ++-> { "execute": "query-chardev" } ++<- { ++ "return":[ ++ { ++ "label":"monitor", ++ "filename":"stdio" ++ }, ++ { ++ "label":"serial0", ++ "filename":"vc" ++ } ++ ] ++ } ++ ++EQMP ++ ++STEXI ++@item info block ++show the block devices ++ETEXI ++SQMP ++query-block ++----------- ++ ++Show the block devices. ++ ++Each block device information is stored in a json-object and the returned value ++is a json-array of all devices. ++ ++Each json-object contain the following: ++ ++- "device": device name (json-string) ++- "type": device type (json-string) ++ - Possible values: "hd", "cdrom", "floppy", "unknown" ++- "removable": true if the device is removable, false otherwise (json-bool) ++- "locked": true if the device is locked, false otherwise (json-bool) ++- "inserted": only present if the device is inserted, it is a json-object ++ containing the following: ++ - "file": device file name (json-string) ++ - "ro": true if read-only, false otherwise (json-bool) ++ - "drv": driver format name (json-string) ++ - Possible values: "blkdebug", "bochs", "cloop", "cow", "dmg", ++ "file", "file", "ftp", "ftps", "host_cdrom", ++ "host_device", "host_floppy", "http", "https", ++ "nbd", "parallels", "qcow", "qcow2", "raw", ++ "tftp", "vdi", "vmdk", "vpc", "vvfat" ++ - "backing_file": backing file name (json-string, optional) ++ - "encrypted": true if encrypted, false otherwise (json-bool) ++ ++Example: ++ ++-> { "execute": "query-block" } ++<- { ++ "return":[ ++ { ++ "device":"ide0-hd0", ++ "locked":false, ++ "removable":false, ++ "inserted":{ ++ "ro":false, ++ "drv":"qcow2", ++ "encrypted":false, ++ "file":"disks/test.img" ++ }, ++ "type":"hd" ++ }, ++ { ++ "device":"ide1-cd0", ++ "locked":false, ++ "removable":true, ++ "type":"cdrom" ++ }, ++ { ++ "device":"floppy0", ++ "locked":false, ++ "removable":true, ++ "type": "floppy" ++ }, ++ { ++ "device":"sd0", ++ "locked":false, ++ "removable":true, ++ "type":"floppy" ++ } ++ ] ++ } ++ ++EQMP ++ ++STEXI ++@item info blockstats ++show block device statistics ++ETEXI ++SQMP ++query-blockstats ++---------------- ++ ++Show block device statistics. ++ ++Each device statistic information is stored in a json-object and the returned ++value is a json-array of all devices. ++ ++Each json-object contain the following: ++ ++- "device": device name (json-string) ++- "stats": A json-object with the statistics information, it contains: ++ - "rd_bytes": bytes read (json-int) ++ - "wr_bytes": bytes written (json-int) ++ - "rd_operations": read operations (json-int) ++ - "wr_operations": write operations (json-int) ++ - "wr_highest_offset": Highest offset of a sector written since the ++ BlockDriverState has been opened (json-int) ++- "parent": Contains recursively the statistics of the underlying ++ protocol (e.g. the host file for a qcow2 image). If there is ++ no underlying protocol, this field is omitted ++ (json-object, optional) ++ ++Example: ++ ++-> { "execute": "query-blockstats" } ++<- { ++ "return":[ ++ { ++ "device":"ide0-hd0", ++ "parent":{ ++ "stats":{ ++ "wr_highest_offset":3686448128, ++ "wr_bytes":9786368, ++ "wr_operations":751, ++ "rd_bytes":122567168, ++ "rd_operations":36772 ++ } ++ }, ++ "stats":{ ++ "wr_highest_offset":2821110784, ++ "wr_bytes":9786368, ++ "wr_operations":692, ++ "rd_bytes":122739200, ++ "rd_operations":36604 ++ } ++ }, ++ { ++ "device":"ide1-cd0", ++ "stats":{ ++ "wr_highest_offset":0, ++ "wr_bytes":0, ++ "wr_operations":0, ++ "rd_bytes":0, ++ "rd_operations":0 ++ } ++ }, ++ { ++ "device":"floppy0", ++ "stats":{ ++ "wr_highest_offset":0, ++ "wr_bytes":0, ++ "wr_operations":0, ++ "rd_bytes":0, ++ "rd_operations":0 ++ } ++ }, ++ { ++ "device":"sd0", ++ "stats":{ ++ "wr_highest_offset":0, ++ "wr_bytes":0, ++ "wr_operations":0, ++ "rd_bytes":0, ++ "rd_operations":0 ++ } ++ } ++ ] ++ } ++ ++EQMP ++ ++STEXI ++@item info registers ++show the cpu registers ++@item info cpus ++show infos for each CPU ++ETEXI ++SQMP ++query-cpus ++---------- ++ ++Show CPU information. ++ ++Return a json-array. Each CPU is represented by a json-object, which contains: ++ ++- "CPU": CPU index (json-int) ++- "current": true if this is the current CPU, false otherwise (json-bool) ++- "halted": true if the cpu is halted, false otherwise (json-bool) ++- Current program counter. The key's name depends on the architecture: ++ "pc": i386/x86_64 (json-int) ++ "nip": PPC (json-int) ++ "pc" and "npc": sparc (json-int) ++ "PC": mips (json-int) ++ ++Example: ++ ++-> { "execute": "query-cpus" } ++<- { ++ "return":[ ++ { ++ "CPU":0, ++ "current":true, ++ "halted":false, ++ "pc":3227107138 ++ }, ++ { ++ "CPU":1, ++ "current":false, ++ "halted":true, ++ "pc":7108165 ++ } ++ ] ++ } ++ ++EQMP ++ ++STEXI ++@item info history ++show the command line history ++@item info irq ++show the interrupts statistics (if available) ++@item info pic ++show i8259 (PIC) state ++ETEXI ++ ++STEXI ++@item info pci ++show emulated PCI device info ++ETEXI ++SQMP ++query-pci ++--------- ++ ++PCI buses and devices information. ++ ++The returned value is a json-array of all buses. Each bus is represented by ++a json-object, which has a key with a json-array of all PCI devices attached ++to it. Each device is represented by a json-object. ++ ++The bus json-object contains the following: ++ ++- "bus": bus number (json-int) ++- "devices": a json-array of json-objects, each json-object represents a ++ PCI device ++ ++The PCI device json-object contains the following: ++ ++- "bus": identical to the parent's bus number (json-int) ++- "slot": slot number (json-int) ++- "function": function number (json-int) ++- "class_info": a json-object containing: ++ - "desc": device class description (json-string, optional) ++ - "class": device class number (json-int) ++- "id": a json-object containing: ++ - "device": device ID (json-int) ++ - "vendor": vendor ID (json-int) ++- "irq": device's IRQ if assigned (json-int, optional) ++- "qdev_id": qdev id string (json-string) ++- "pci_bridge": It's a json-object, only present if this device is a ++ PCI bridge, contains: ++ - "bus": bus number (json-int) ++ - "secondary": secondary bus number (json-int) ++ - "subordinate": subordinate bus number (json-int) ++ - "io_range": I/O memory range information, a json-object with the ++ following members: ++ - "base": base address, in bytes (json-int) ++ - "limit": limit address, in bytes (json-int) ++ - "memory_range": memory range information, a json-object with the ++ following members: ++ - "base": base address, in bytes (json-int) ++ - "limit": limit address, in bytes (json-int) ++ - "prefetchable_range": Prefetchable memory range information, a ++ json-object with the following members: ++ - "base": base address, in bytes (json-int) ++ - "limit": limit address, in bytes (json-int) ++ - "devices": a json-array of PCI devices if there's any attached, each ++ each element is represented by a json-object, which contains ++ the same members of the 'PCI device json-object' described ++ above (optional) ++- "regions": a json-array of json-objects, each json-object represents a ++ memory region of this device ++ ++The memory range json-object contains the following: ++ ++- "base": base memory address (json-int) ++- "limit": limit value (json-int) ++ ++The region json-object can be an I/O region or a memory region, an I/O region ++json-object contains the following: ++ ++- "type": "io" (json-string, fixed) ++- "bar": BAR number (json-int) ++- "address": memory address (json-int) ++- "size": memory size (json-int) ++ ++A memory region json-object contains the following: ++ ++- "type": "memory" (json-string, fixed) ++- "bar": BAR number (json-int) ++- "address": memory address (json-int) ++- "size": memory size (json-int) ++- "mem_type_64": true or false (json-bool) ++- "prefetch": true or false (json-bool) ++ ++Example: ++ ++-> { "execute": "query-pci" } ++<- { ++ "return":[ ++ { ++ "bus":0, ++ "devices":[ ++ { ++ "bus":0, ++ "qdev_id":"", ++ "slot":0, ++ "class_info":{ ++ "class":1536, ++ "desc":"Host bridge" ++ }, ++ "id":{ ++ "device":32902, ++ "vendor":4663 ++ }, ++ "function":0, ++ "regions":[ ++ ++ ] ++ }, ++ { ++ "bus":0, ++ "qdev_id":"", ++ "slot":1, ++ "class_info":{ ++ "class":1537, ++ "desc":"ISA bridge" ++ }, ++ "id":{ ++ "device":32902, ++ "vendor":28672 ++ }, ++ "function":0, ++ "regions":[ ++ ++ ] ++ }, ++ { ++ "bus":0, ++ "qdev_id":"", ++ "slot":1, ++ "class_info":{ ++ "class":257, ++ "desc":"IDE controller" ++ }, ++ "id":{ ++ "device":32902, ++ "vendor":28688 ++ }, ++ "function":1, ++ "regions":[ ++ { ++ "bar":4, ++ "size":16, ++ "address":49152, ++ "type":"io" ++ } ++ ] ++ }, ++ { ++ "bus":0, ++ "qdev_id":"", ++ "slot":2, ++ "class_info":{ ++ "class":768, ++ "desc":"VGA controller" ++ }, ++ "id":{ ++ "device":4115, ++ "vendor":184 ++ }, ++ "function":0, ++ "regions":[ ++ { ++ "prefetch":true, ++ "mem_type_64":false, ++ "bar":0, ++ "size":33554432, ++ "address":4026531840, ++ "type":"memory" ++ }, ++ { ++ "prefetch":false, ++ "mem_type_64":false, ++ "bar":1, ++ "size":4096, ++ "address":4060086272, ++ "type":"memory" ++ }, ++ { ++ "prefetch":false, ++ "mem_type_64":false, ++ "bar":6, ++ "size":65536, ++ "address":-1, ++ "type":"memory" ++ } ++ ] ++ }, ++ { ++ "bus":0, ++ "qdev_id":"", ++ "irq":11, ++ "slot":4, ++ "class_info":{ ++ "class":1280, ++ "desc":"RAM controller" ++ }, ++ "id":{ ++ "device":6900, ++ "vendor":4098 ++ }, ++ "function":0, ++ "regions":[ ++ { ++ "bar":0, ++ "size":32, ++ "address":49280, ++ "type":"io" ++ } ++ ] ++ } ++ ] ++ } ++ ] ++ } ++ ++Note: This example has been shortened as the real response is too long. ++ ++EQMP ++ ++STEXI ++@item info tlb ++show virtual to physical memory mappings (i386 only) ++@item info mem ++show the active virtual memory mappings (i386 only) ++ETEXI ++ ++STEXI ++@item info jit ++show dynamic compiler info ++@item info kvm ++show KVM information ++@item info numa ++show NUMA information ++ETEXI ++ ++STEXI ++@item info kvm ++show KVM information ++ETEXI ++SQMP ++query-kvm ++--------- ++ ++Show KVM information. ++ ++Return a json-object with the following information: ++ ++- "enabled": true if KVM support is enabled, false otherwise (json-bool) ++- "present": true if QEMU has KVM support, false otherwise (json-bool) ++ ++Example: ++ ++-> { "execute": "query-kvm" } ++<- { "return": { "enabled": true, "present": true } } ++ ++EQMP ++ ++STEXI ++@item info usb ++show USB devices plugged on the virtual USB hub ++@item info usbhost ++show all USB host devices ++@item info profile ++show profiling information ++@item info capture ++show information about active capturing ++@item info snapshots ++show list of VM snapshots ++ETEXI ++ ++STEXI ++@item info status ++show the current VM status (running|paused) ++ETEXI ++SQMP ++query-status ++------------ ++ ++Return a json-object with the following information: ++ ++- "running": true if the VM is running, or false if it is paused (json-bool) ++- "singlestep": true if the VM is in single step mode, ++ false otherwise (json-bool) ++ ++Example: ++ ++-> { "execute": "query-status" } ++<- { "return": { "running": true, "singlestep": false } } ++ ++EQMP ++ ++STEXI ++@item info pcmcia ++show guest PCMCIA status ++ETEXI ++ ++STEXI ++@item info mice ++show which guest mouse is receiving events ++ETEXI ++SQMP ++query-mice ++---------- ++ ++Show VM mice information. ++ ++Each mouse is represented by a json-object, the returned value is a json-array ++of all mice. ++ ++The mouse json-object contains the following: ++ ++- "name": mouse's name (json-string) ++- "index": mouse's index (json-int) ++- "current": true if this mouse is receiving events, false otherwise (json-bool) ++- "absolute": true if the mouse generates absolute input events (json-bool) ++ ++Example: ++ ++-> { "execute": "query-mice" } ++<- { ++ "return":[ ++ { ++ "name":"QEMU Microsoft Mouse", ++ "index":0, ++ "current":false, ++ "absolute":false ++ }, ++ { ++ "name":"QEMU PS/2 Mouse", ++ "index":1, ++ "current":true, ++ "absolute":true ++ } ++ ] ++ } ++ ++EQMP ++ ++STEXI ++@item info vnc ++show the vnc server status ++ETEXI ++SQMP ++query-vnc ++--------- ++ ++Show VNC server information. ++ ++Return a json-object with server information. Connected clients are returned ++as a json-array of json-objects. ++ ++The main json-object contains the following: ++ ++- "enabled": true or false (json-bool) ++- "host": server's IP address (json-string) ++- "family": address family (json-string) ++ - Possible values: "ipv4", "ipv6", "unix", "unknown" ++- "service": server's port number (json-string) ++- "auth": authentication method (json-string) ++ - Possible values: "invalid", "none", "ra2", "ra2ne", "sasl", "tight", ++ "tls", "ultra", "unknown", "vencrypt", "vencrypt", ++ "vencrypt+plain", "vencrypt+tls+none", ++ "vencrypt+tls+plain", "vencrypt+tls+sasl", ++ "vencrypt+tls+vnc", "vencrypt+x509+none", ++ "vencrypt+x509+plain", "vencrypt+x509+sasl", ++ "vencrypt+x509+vnc", "vnc" ++- "clients": a json-array of all connected clients ++ ++Clients are described by a json-object, each one contain the following: ++ ++- "host": client's IP address (json-string) ++- "family": address family (json-string) ++ - Possible values: "ipv4", "ipv6", "unix", "unknown" ++- "service": client's port number (json-string) ++- "x509_dname": TLS dname (json-string, optional) ++- "sasl_username": SASL username (json-string, optional) ++ ++Example: ++ ++-> { "execute": "query-vnc" } ++<- { ++ "return":{ ++ "enabled":true, ++ "host":"0.0.0.0", ++ "service":"50402", ++ "auth":"vnc", ++ "family":"ipv4", ++ "clients":[ ++ { ++ "host":"127.0.0.1", ++ "service":"50401", ++ "family":"ipv4" ++ } ++ ] ++ } ++ } ++ ++EQMP ++ ++STEXI ++@item info name ++show the current VM name ++ETEXI ++SQMP ++query-name ++---------- ++ ++Show VM name. ++ ++Return a json-object with the following information: ++ ++- "name": VM's name (json-string, optional) ++ ++Example: ++ ++-> { "execute": "query-name" } ++<- { "return": { "name": "qemu-name" } } ++ ++EQMP ++ ++STEXI ++@item info uuid ++show the current VM UUID ++ETEXI ++SQMP ++query-uuid ++---------- ++ ++Show VM UUID. ++ ++Return a json-object with the following information: ++ ++- "UUID": Universally Unique Identifier (json-string) ++ ++Example: ++ ++-> { "execute": "query-uuid" } ++<- { "return": { "UUID": "550e8400-e29b-41d4-a716-446655440000" } } ++ ++EQMP ++ ++STEXI ++@item info cpustats ++show CPU statistics ++@item info usernet ++show user network stack connection states ++ETEXI ++ ++STEXI ++@item info migrate ++show migration status ++ETEXI ++SQMP ++query-migrate ++------------- ++ ++Migration status. ++ ++Return a json-object. If migration is active there will be another json-object ++with RAM migration status and if block migration is active another one with ++block migration status. ++ ++The main json-object contains the following: ++ ++- "status": migration status (json-string) ++ - Possible values: "active", "completed", "failed", "cancelled" ++- "ram": only present if "status" is "active", it is a json-object with the ++ following RAM information (in bytes): ++ - "transferred": amount transferred (json-int) ++ - "remaining": amount remaining (json-int) ++ - "total": total (json-int) ++- "disk": only present if "status" is "active" and it is a block migration, ++ it is a json-object with the following disk information (in bytes): ++ - "transferred": amount transferred (json-int) ++ - "remaining": amount remaining (json-int) ++ - "total": total (json-int) ++ ++Examples: ++ ++1. Before the first migration ++ ++-> { "execute": "query-migrate" } ++<- { "return": {} } ++ ++2. Migration is done and has succeeded ++ ++-> { "execute": "query-migrate" } ++<- { "return": { "status": "completed" } } ++ ++3. Migration is done and has failed ++ ++-> { "execute": "query-migrate" } ++<- { "return": { "status": "failed" } } ++ ++4. Migration is being performed and is not a block migration: ++ ++-> { "execute": "query-migrate" } ++<- { ++ "return":{ ++ "status":"active", ++ "ram":{ ++ "transferred":123, ++ "remaining":123, ++ "total":246 ++ } ++ } ++ } ++ ++5. Migration is being performed and is a block migration: ++ ++-> { "execute": "query-migrate" } ++<- { ++ "return":{ ++ "status":"active", ++ "ram":{ ++ "total":1057024, ++ "remaining":1053304, ++ "transferred":3720 ++ }, ++ "disk":{ ++ "total":20971520, ++ "remaining":20880384, ++ "transferred":91136 ++ } ++ } ++ } ++ ++EQMP ++ ++STEXI ++@item info balloon ++show balloon information ++ETEXI ++SQMP ++query-balloon ++------------- ++ ++Show balloon information. ++ ++Make an asynchronous request for balloon info. When the request completes a ++json-object will be returned containing the following data: ++ ++- "actual": current balloon value in bytes (json-int) ++- "mem_swapped_in": Amount of memory swapped in bytes (json-int, optional) ++- "mem_swapped_out": Amount of memory swapped out in bytes (json-int, optional) ++- "major_page_faults": Number of major faults (json-int, optional) ++- "minor_page_faults": Number of minor faults (json-int, optional) ++- "free_mem": Total amount of free and unused memory in ++ bytes (json-int, optional) ++- "total_mem": Total amount of available memory in bytes (json-int, optional) ++ ++Example: ++ ++-> { "execute": "query-balloon" } ++<- { ++ "return":{ ++ "actual":1073741824, ++ "mem_swapped_in":0, ++ "mem_swapped_out":0, ++ "major_page_faults":142, ++ "minor_page_faults":239245, ++ "free_mem":1014185984, ++ "total_mem":1044668416 ++ } ++ } ++ ++EQMP ++ ++STEXI ++@item info qtree ++show device tree ++@item info qdm ++show qdev device model list ++@item info roms ++show roms ++@end table ++ETEXI ++ ++HXCOMM DO NOT add new commands after 'info', move your addition before it! ++ ++#if defined(CONFIG_SPICE) ++ { ++ .name = "spice_migrate_info", ++ .args_type = "hostname:s,port:i?,tls-port:i?,cert-subject:s?", ++ .params = "hostname port tls-port cert-subject", ++ .help = "send migration info to spice client", ++ .user_print = monitor_user_noop, ++ .mhandler.cmd_new = mon_spice_migrate, ++ }, ++#endif ++ ++STEXI ++@end table ++ETEXI +diff -urN qemu-kvm-0.13.0.orig/qemu-options.hx qemu-kvm-0.13.0/qemu-options.hx +--- qemu-kvm-0.13.0.orig/qemu-options.hx 2011-02-09 11:01:45.887000328 +0200 ++++ qemu-kvm-0.13.0/qemu-options.hx 2011-02-09 11:08:02.915000327 +0200 +@@ -676,6 +676,14 @@ + Enable SDL. + ETEXI + ++#ifdef CONFIG_SPICE ++DEF("spice", HAS_ARG, QEMU_OPTION_spice, ++ "-spice <args> use spice\n", QEMU_ARCH_ALL) ++STEXI ++Use Spice. ++ETEXI ++#endif ++ + DEF("portrait", 0, QEMU_OPTION_portrait, + "-portrait rotate graphical output 90 deg left (only PXA LCD)\n", + QEMU_ARCH_ALL) +@@ -686,7 +694,7 @@ + ETEXI + + DEF("vga", HAS_ARG, QEMU_OPTION_vga, +- "-vga [std|cirrus|vmware|xenfb|none]\n" ++ "-vga [std|cirrus|vmware|xenfb|qxl|none]\n" + " select video card type\n", QEMU_ARCH_ALL) + STEXI + @item -vga @var{type} +diff -urN qemu-kvm-0.13.0.orig/qemu-spice.h qemu-kvm-0.13.0/qemu-spice.h +--- qemu-kvm-0.13.0.orig/qemu-spice.h 1970-01-01 02:00:00.000000000 +0200 ++++ qemu-kvm-0.13.0/qemu-spice.h 2011-02-09 11:08:02.873000327 +0200 +@@ -0,0 +1,25 @@ ++#ifndef QEMU_SPICE_H ++#define QEMU_SPICE_H ++ ++#ifdef CONFIG_SPICE ++ ++#include <spice.h> ++ ++#include "qemu-option.h" ++#include "qemu-config.h" ++ ++extern SpiceServer *spice_server; ++extern int using_spice; ++ ++void qemu_spice_init(void); ++void qemu_spice_input_init(void); ++void qemu_spice_audio_init(void); ++void qemu_spice_display_init(DisplayState *ds); ++ ++#else /* CONFIG_SPICE */ ++ ++#define using_spice 0 ++ ++#endif /* CONFIG_SPICE */ ++ ++#endif /* QEMU_SPICE_H */ +diff -urN qemu-kvm-0.13.0.orig/spice.c qemu-kvm-0.13.0/spice.c +--- qemu-kvm-0.13.0.orig/spice.c 1970-01-01 02:00:00.000000000 +0200 ++++ qemu-kvm-0.13.0/spice.c 2011-02-09 11:08:02.874000327 +0200 +@@ -0,0 +1,245 @@ ++#include <stdlib.h> ++#include <stdio.h> ++#include <string.h> ++ ++#include <spice.h> ++#include <spice-experimental.h> ++ ++#include "qemu-common.h" ++#include "qemu-spice.h" ++#include "qemu-timer.h" ++#include "qemu-queue.h" ++#include "qemu-x509.h" ++#include "monitor.h" ++ ++/* core bits */ ++ ++SpiceServer *spice_server; ++int using_spice = 0; ++ ++struct SpiceTimer { ++ QEMUTimer *timer; ++ QTAILQ_ENTRY(SpiceTimer) next; ++}; ++static QTAILQ_HEAD(, SpiceTimer) timers = QTAILQ_HEAD_INITIALIZER(timers); ++ ++static SpiceTimer *timer_add(SpiceTimerFunc func, void *opaque) ++{ ++ SpiceTimer *timer; ++ ++ timer = qemu_mallocz(sizeof(*timer)); ++ timer->timer = qemu_new_timer(rt_clock, func, opaque); ++ QTAILQ_INSERT_TAIL(&timers, timer, next); ++ return timer; ++} ++ ++static void timer_start(SpiceTimer *timer, uint32_t ms) ++{ ++ qemu_mod_timer(timer->timer, qemu_get_clock(rt_clock) + ms); ++} ++ ++static void timer_cancel(SpiceTimer *timer) ++{ ++ qemu_del_timer(timer->timer); ++} ++ ++static void timer_remove(SpiceTimer *timer) ++{ ++ qemu_del_timer(timer->timer); ++ qemu_free_timer(timer->timer); ++ QTAILQ_REMOVE(&timers, timer, next); ++ free(timer); ++} ++ ++struct SpiceWatch { ++ int fd; ++ int event_mask; ++ SpiceWatchFunc func; ++ void *opaque; ++ QTAILQ_ENTRY(SpiceWatch) next; ++}; ++static QTAILQ_HEAD(, SpiceWatch) watches = QTAILQ_HEAD_INITIALIZER(watches); ++ ++static void watch_read(void *opaque) ++{ ++ SpiceWatch *watch = opaque; ++ watch->func(watch->fd, SPICE_WATCH_EVENT_READ, watch->opaque); ++} ++ ++static void watch_write(void *opaque) ++{ ++ SpiceWatch *watch = opaque; ++ watch->func(watch->fd, SPICE_WATCH_EVENT_WRITE, watch->opaque); ++} ++ ++static void watch_update_mask(SpiceWatch *watch, int event_mask) ++{ ++ IOHandler *on_read = NULL; ++ IOHandler *on_write = NULL; ++ ++ watch->event_mask = event_mask; ++ if (watch->event_mask & SPICE_WATCH_EVENT_READ) ++ on_read = watch_read; ++ if (watch->event_mask & SPICE_WATCH_EVENT_WRITE) ++ on_read = watch_write; ++ qemu_set_fd_handler(watch->fd, on_read, on_write, watch); ++} ++ ++static SpiceWatch *watch_add(int fd, int event_mask, SpiceWatchFunc func, void *opaque) ++{ ++ SpiceWatch *watch; ++ ++ watch = qemu_mallocz(sizeof(*watch)); ++ watch->fd = fd; ++ watch->func = func; ++ watch->opaque = opaque; ++ QTAILQ_INSERT_TAIL(&watches, watch, next); ++ ++ watch_update_mask(watch, event_mask); ++ return watch; ++} ++ ++static void watch_remove(SpiceWatch *watch) ++{ ++ watch_update_mask(watch, 0); ++ QTAILQ_REMOVE(&watches, watch, next); ++ qemu_free(watch); ++} ++ ++static SpiceCoreInterface core_interface = { ++ .base.type = SPICE_INTERFACE_CORE, ++ .base.description = "qemu core services", ++ .base.major_version = SPICE_INTERFACE_CORE_MAJOR, ++ .base.minor_version = SPICE_INTERFACE_CORE_MINOR, ++ ++ .timer_add = timer_add, ++ .timer_start = timer_start, ++ .timer_cancel = timer_cancel, ++ .timer_remove = timer_remove, ++ ++ .watch_add = watch_add, ++ .watch_update_mask = watch_update_mask, ++ .watch_remove = watch_remove, ++}; ++ ++/* functions for the rest of qemu */ ++ ++#if defined(SPICE_SERVER_VERSION) && SPICE_SERVER_VERSION >= 0x000503 ++static inline spice_wan_compression_t get_wan_compression_value(const char *str) ++{ ++ if (!strcmp(str, "wan")) { ++ return SPICE_WAN_COMPRESSION_AUTO; ++ } ++ ++ if (!strcmp(str, "never")) { ++ return SPICE_WAN_COMPRESSION_NEVER; ++ } ++ ++ if (!strcmp(str, "always")) { ++ return SPICE_WAN_COMPRESSION_ALWAYS; ++ } ++ ++ return SPICE_WAN_COMPRESSION_INVALID; ++} ++#endif ++ ++void qemu_spice_init(void) ++{ ++ QemuOpts *opts = QTAILQ_FIRST(&qemu_spice_opts.head); ++ const char *password, *str, *x509_dir, ++ *x509_key_password = NULL, ++ *x509_dh_file = NULL, ++ *tls_ciphers = NULL; ++ char *x509_key_file = NULL, ++ *x509_cert_file = NULL, ++ *x509_cacert_file = NULL; ++ int port, tls_port, len; ++ ++ if (!opts) ++ return; ++ port = qemu_opt_get_number(opts, "port", 0); ++ tls_port = qemu_opt_get_number(opts, "tls-port", 0); ++ if (!port && !tls_port) ++ return; ++ password = qemu_opt_get(opts, "password"); ++ ++ if (tls_port) { ++ x509_dir = qemu_opt_get(opts, "x509-dir"); ++ if (NULL == x509_dir) ++ x509_dir = "."; ++ len = strlen(x509_dir) + 32; ++ ++ str = qemu_opt_get(opts, "x509-key-file"); ++ if (str) { ++ x509_key_file = qemu_strdup(str); ++ } else { ++ x509_key_file = qemu_malloc(len); ++ snprintf(x509_key_file, len, "%s/%s", x509_dir, X509_SERVER_KEY_FILE); ++ } ++ ++ str = qemu_opt_get(opts, "x509-cert-file"); ++ if (str) { ++ x509_cert_file = qemu_strdup(str); ++ } else { ++ x509_cert_file = qemu_malloc(len); ++ snprintf(x509_cert_file, len, "%s/%s", x509_dir, X509_SERVER_CERT_FILE); ++ } ++ ++ str = qemu_opt_get(opts, "x509-cacert-file"); ++ if (str) { ++ x509_cacert_file = qemu_strdup(str); ++ } else { ++ x509_cacert_file = qemu_malloc(len); ++ snprintf(x509_cacert_file, len, "%s/%s", x509_dir, X509_CA_CERT_FILE); ++ } ++ ++ x509_key_password = qemu_opt_get(opts, "x509-key-password"); ++ x509_dh_file = qemu_opt_get(opts, "x509-dh-file"); ++ tls_ciphers = qemu_opt_get(opts, "tls-ciphers"); ++ } ++ ++ spice_server = spice_server_new(); ++ if (port) { ++ spice_server_set_port(spice_server, port); ++ } ++ if (tls_port) { ++ spice_server_set_tls(spice_server, tls_port, ++ x509_cacert_file, ++ x509_cert_file, ++ x509_key_file, ++ x509_key_password, ++ x509_dh_file, ++ tls_ciphers); ++ } ++ if (password) ++ spice_server_set_ticket(spice_server, password, 0, 0, 0); ++ if (qemu_opt_get_bool(opts, "disable-ticketing", 0)) ++ spice_server_set_noauth(spice_server); ++ ++ /* TODO: make configurable via cmdline */ ++ spice_server_set_image_compression(spice_server, SPICE_IMAGE_COMPRESS_AUTO_GLZ); ++ ++#if defined(SPICE_SERVER_VERSION) && SPICE_SERVER_VERSION >= 0x000503 ++ const char *jpeg, *zlib_glz; ++ jpeg = qemu_opt_get(opts, "jpeg"); ++ zlib_glz = qemu_opt_get(opts, "zlib-glz"); ++ ++ if (jpeg) { ++ spice_server_set_jpeg_compression(spice_server, get_wan_compression_value(jpeg)); ++ } ++ ++ if (zlib_glz) { ++ spice_server_set_zlib_glz_compression(spice_server, get_wan_compression_value(zlib_glz)); ++ } ++#endif ++ ++ spice_server_init(spice_server, &core_interface); ++ using_spice = 1; ++ ++ qemu_spice_input_init(); ++ qemu_spice_audio_init(); ++ ++ qemu_free(x509_key_file); ++ qemu_free(x509_cert_file); ++ qemu_free(x509_cacert_file); ++} +diff -urN qemu-kvm-0.13.0.orig/spice-display.c qemu-kvm-0.13.0/spice-display.c +--- qemu-kvm-0.13.0.orig/spice-display.c 1970-01-01 02:00:00.000000000 +0200 ++++ qemu-kvm-0.13.0/spice-display.c 2011-02-09 11:08:02.816000327 +0200 +@@ -0,0 +1,390 @@ ++#include <stdio.h> ++#include <stdlib.h> ++#include <stdbool.h> ++#include <stdint.h> ++#include <string.h> ++#include <pthread.h> ++ ++#include "qemu-common.h" ++#include "qemu-spice.h" ++#include "qemu-timer.h" ++#include "qemu-queue.h" ++#include "monitor.h" ++#include "console.h" ++#include "sysemu.h" ++ ++#include "spice-display.h" ++ ++static int debug = 0; ++ ++int qemu_spice_rect_is_empty(const QXLRect* r) ++{ ++ return r->top == r->bottom || r->left == r->right; ++} ++ ++void qemu_spice_rect_union(QXLRect *dest, const QXLRect *r) ++{ ++ if (qemu_spice_rect_is_empty(r)) { ++ return; ++ } ++ ++ if (qemu_spice_rect_is_empty(dest)) { ++ *dest = *r; ++ return; ++ } ++ ++ dest->top = MIN(dest->top, r->top); ++ dest->left = MIN(dest->left, r->left); ++ dest->bottom = MAX(dest->bottom, r->bottom); ++ dest->right = MAX(dest->right, r->right); ++} ++ ++SimpleSpiceUpdate *qemu_spice_create_update(SimpleSpiceDisplay *ssd) ++{ ++ SimpleSpiceUpdate *update; ++ QXLDrawable *drawable; ++ QXLImage *image; ++ QXLCommand *cmd; ++ uint8_t *src, *dst; ++ int by, bw, bh; ++ ++ if (qemu_spice_rect_is_empty(&ssd->dirty)) { ++ return NULL; ++ }; ++ ++ pthread_mutex_lock(&ssd->lock); ++ if (debug > 1) ++ fprintf(stderr, "%s: lr %d -> %d, tb -> %d -> %d\n", __FUNCTION__, ++ ssd->dirty.left, ssd->dirty.right, ++ ssd->dirty.top, ssd->dirty.bottom); ++ ++ update = qemu_mallocz(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; ++ update->bitmap = qemu_malloc(bw * bh * 4); ++ ++ drawable->bbox = ssd->dirty; ++ drawable->clip.type = SPICE_CLIP_TYPE_NONE; ++ drawable->effect = QXL_EFFECT_OPAQUE; ++ drawable->release_info.id = (intptr_t)update; ++ drawable->type = QXL_DRAW_COPY; ++ ++ drawable->u.copy.rop_descriptor = SPICE_ROPD_OP_PUT; ++ drawable->u.copy.src_bitmap = (intptr_t)image; ++ drawable->u.copy.src_area.right = bw; ++ drawable->u.copy.src_area.bottom = bh; ++ ++ QXL_SET_IMAGE_ID(image, QXL_IMAGE_GROUP_DEVICE, ssd->unique++); ++ image->descriptor.type = SPICE_IMAGE_TYPE_BITMAP; ++ image->bitmap.flags = QXL_BITMAP_DIRECT | QXL_BITMAP_TOP_DOWN; ++ image->bitmap.stride = bw * 4; ++ image->descriptor.width = image->bitmap.x = bw; ++ image->descriptor.height = image->bitmap.y = bh; ++ image->bitmap.data = (intptr_t)(update->bitmap); ++ 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) + ++ ssd->dirty.top * ds_get_linesize(ssd->ds) + ++ ssd->dirty.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); ++ src += ds_get_linesize(ssd->ds); ++ dst += image->bitmap.stride; ++ } ++ ++ cmd->type = QXL_CMD_DRAW; ++ cmd->data = (intptr_t)drawable; ++ ++ memset(&ssd->dirty, 0, sizeof(ssd->dirty)); ++ pthread_mutex_unlock(&ssd->lock); ++ return update; ++} ++ ++void qemu_spice_destroy_update(SimpleSpiceDisplay *sdpy, SimpleSpiceUpdate *update) ++{ ++ qemu_free(update->bitmap); ++ qemu_free(update); ++} ++ ++void qemu_spice_create_host_memslot(SimpleSpiceDisplay *ssd) ++{ ++ QXLDevMemSlot memslot; ++ ++ if (debug) ++ fprintf(stderr, "%s:\n", __FUNCTION__); ++ ++ memset(&memslot, 0, sizeof(memslot)); ++ memslot.slot_group_id = MEMSLOT_GROUP_HOST; ++ memslot.virt_end = ~0; ++ ssd->worker->add_memslot(ssd->worker, &memslot); ++} ++ ++void qemu_spice_create_host_primary(SimpleSpiceDisplay *ssd) ++{ ++ QXLDevSurfaceCreate surface; ++ ++ if (debug) ++ fprintf(stderr, "%s: %dx%d\n", __FUNCTION__, ++ ds_get_width(ssd->ds), ds_get_height(ssd->ds)); ++ ++ surface.format = SPICE_SURFACE_FMT_32_xRGB; ++ surface.width = ds_get_width(ssd->ds); ++ surface.height = ds_get_height(ssd->ds); ++ surface.stride = -surface.width * 4; ++ surface.mouse_mode = true; ++ surface.flags = 0; ++ surface.type = 0; ++ surface.mem = (intptr_t)ssd->buf; ++ surface.group_id = MEMSLOT_GROUP_HOST; ++ ssd->worker->create_primary_surface(ssd->worker, 0, &surface); ++} ++ ++void qemu_spice_destroy_host_primary(SimpleSpiceDisplay *ssd) ++{ ++ if (debug) ++ fprintf(stderr, "%s:\n", __FUNCTION__); ++ ++ ssd->worker->destroy_primary_surface(ssd->worker, 0); ++} ++ ++void qemu_spice_vm_change_state_handler(void *opaque, int running, int reason) ++{ ++ SimpleSpiceDisplay *ssd = opaque; ++ ++ if (running) { ++ ssd->worker->start(ssd->worker); ++ } else { ++ ssd->worker->stop(ssd->worker); ++ } ++ ssd->running = running; ++} ++ ++/* display listener callbacks */ ++ ++void qemu_spice_display_update(SimpleSpiceDisplay *ssd, ++ int x, int y, int w, int h) ++{ ++ QXLRect update_area; ++ ++ if (debug > 1) ++ fprintf(stderr, "%s: x %d y %d w %d h %d\n", __FUNCTION__, x, y, w, h); ++ update_area.left = x, ++ update_area.right = x + w; ++ update_area.top = y; ++ update_area.bottom = y + h; ++ ++ pthread_mutex_lock(&ssd->lock); ++ if (qemu_spice_rect_is_empty(&ssd->dirty)) { ++ ssd->notify++; ++ } ++ qemu_spice_rect_union(&ssd->dirty, &update_area); ++ pthread_mutex_unlock(&ssd->lock); ++} ++ ++void qemu_spice_display_resize(SimpleSpiceDisplay *ssd) ++{ ++ if (debug) ++ fprintf(stderr, "%s:\n", __FUNCTION__); ++ ++ pthread_mutex_lock(&ssd->lock); ++ memset(&ssd->dirty, 0, sizeof(ssd->dirty)); ++ pthread_mutex_unlock(&ssd->lock); ++ ++ qemu_spice_destroy_host_primary(ssd); ++ qemu_spice_create_host_primary(ssd); ++ qemu_pf_conv_put(ssd->conv); ++ ssd->conv = NULL; ++ ++ pthread_mutex_lock(&ssd->lock); ++ ssd->dirty.left = 0; ++ ssd->dirty.right = ds_get_width(ssd->ds); ++ ssd->dirty.top = 0; ++ ssd->dirty.bottom = ds_get_height(ssd->ds); ++ ssd->notify++; ++ pthread_mutex_unlock(&ssd->lock); ++} ++ ++void qemu_spice_display_refresh(SimpleSpiceDisplay *ssd) ++{ ++ if (debug > 2) ++ fprintf(stderr, "%s:\n", __FUNCTION__); ++ vga_hw_update(); ++ if (ssd->notify) { ++ ssd->notify = 0; ++ ssd->worker->wakeup(ssd->worker); ++ if (debug > 1) ++ fprintf(stderr, "%s: notify\n", __FUNCTION__); ++ } ++} ++ ++/* spice display interface callbacks */ ++ ++static void interface_attach_worker(QXLInstance *sin, QXLWorker *qxl_worker) ++{ ++ SimpleSpiceDisplay *ssd = container_of(sin, SimpleSpiceDisplay, qxl); ++ ++ if (debug) ++ fprintf(stderr, "%s:\n", __FUNCTION__); ++ ssd->worker = qxl_worker; ++} ++ ++static void interface_set_compression_level(QXLInstance *sin, int level) ++{ ++ if (debug) ++ fprintf(stderr, "%s:\n", __FUNCTION__); ++ /* nothing to do */ ++} ++ ++static void interface_set_mm_time(QXLInstance *sin, uint32_t mm_time) ++{ ++ if (debug > 2) ++ fprintf(stderr, "%s:\n", __FUNCTION__); ++ /* nothing to do */ ++} ++ ++static void interface_get_init_info(QXLInstance *sin, QXLDevInitInfo *info) ++{ ++ SimpleSpiceDisplay *ssd = container_of(sin, SimpleSpiceDisplay, qxl); ++ ++ info->memslot_gen_bits = MEMSLOT_GENERATION_BITS; ++ info->memslot_id_bits = MEMSLOT_SLOT_BITS; ++ info->num_memslots = NUM_MEMSLOTS; ++ info->num_memslots_groups = NUM_MEMSLOTS_GROUPS; ++ info->internal_groupslot_id = 0; ++ info->qxl_ram_size = ssd->bufsize; ++ info->n_surfaces = NUM_SURFACES; ++} ++ ++static int interface_get_command(QXLInstance *sin, struct QXLCommandExt *ext) ++{ ++ SimpleSpiceDisplay *ssd = container_of(sin, SimpleSpiceDisplay, qxl); ++ SimpleSpiceUpdate *update; ++ ++ if (debug > 2) ++ fprintf(stderr, "%s:\n", __FUNCTION__); ++ update = qemu_spice_create_update(ssd); ++ if (update == NULL) { ++ return false; ++ } ++ *ext = update->ext; ++ return true; ++} ++ ++static int interface_req_cmd_notification(QXLInstance *sin) ++{ ++ if (debug) ++ fprintf(stderr, "%s:\n", __FUNCTION__); ++ return 1; ++} ++ ++static void interface_release_resource(QXLInstance *sin, ++ struct QXLReleaseInfoExt ext) ++{ ++ SimpleSpiceDisplay *ssd = container_of(sin, SimpleSpiceDisplay, qxl); ++ uintptr_t id; ++ ++ if (debug > 1) ++ fprintf(stderr, "%s:\n", __FUNCTION__); ++ id = ext.info->id; ++ qemu_spice_destroy_update(ssd, (void*)id); ++} ++ ++static int interface_get_cursor_command(QXLInstance *sin, struct QXLCommandExt *ext) ++{ ++ if (debug > 2) ++ fprintf(stderr, "%s:\n", __FUNCTION__); ++ return false; ++} ++ ++static int interface_req_cursor_notification(QXLInstance *sin) ++{ ++ if (debug) ++ fprintf(stderr, "%s:\n", __FUNCTION__); ++ return 1; ++} ++ ++static void interface_notify_update(QXLInstance *sin, uint32_t update_id) ++{ ++ fprintf(stderr, "%s: abort()\n", __FUNCTION__); ++ abort(); ++} ++ ++static int interface_flush_resources(QXLInstance *sin) ++{ ++ fprintf(stderr, "%s: abort()\n", __FUNCTION__); ++ abort(); ++ return 0; ++} ++ ++static const QXLInterface dpy_interface = { ++ .base.type = SPICE_INTERFACE_QXL, ++ .base.description = "qemu simple display", ++ .base.major_version = SPICE_INTERFACE_QXL_MAJOR, ++ .base.minor_version = SPICE_INTERFACE_QXL_MINOR, ++ ++ .attache_worker = interface_attach_worker, ++ .set_compression_level = interface_set_compression_level, ++ .set_mm_time = interface_set_mm_time, ++ ++ .get_init_info = interface_get_init_info, ++ .get_command = interface_get_command, ++ .req_cmd_notification = interface_req_cmd_notification, ++ .release_resource = interface_release_resource, ++ .get_cursor_command = interface_get_cursor_command, ++ .req_cursor_notification = interface_req_cursor_notification, ++ .notify_update = interface_notify_update, ++ .flush_resources = interface_flush_resources, ++}; ++ ++static SimpleSpiceDisplay sdpy; ++ ++static void display_update(struct DisplayState *ds, int x, int y, int w, int h) ++{ ++ qemu_spice_display_update(&sdpy, x, y, w, h); ++} ++ ++static void display_resize(struct DisplayState *ds) ++{ ++ qemu_spice_display_resize(&sdpy); ++} ++ ++static void display_refresh(struct DisplayState *ds) ++{ ++ qemu_spice_display_refresh(&sdpy); ++} ++ ++static DisplayChangeListener display_listener = { ++ .dpy_update = display_update, ++ .dpy_resize = display_resize, ++ .dpy_refresh = display_refresh, ++}; ++ ++void qemu_spice_display_init(DisplayState *ds) ++{ ++ assert(sdpy.ds == NULL); ++ sdpy.ds = ds; ++ sdpy.bufsize = (16 * 1024 * 1024); ++ sdpy.buf = qemu_malloc(sdpy.bufsize); ++ pthread_mutex_init(&sdpy.lock, NULL); ++ register_displaychangelistener(ds, &display_listener); ++ ++ sdpy.qxl.base.sif = &dpy_interface.base; ++ spice_server_add_interface(spice_server, &sdpy.qxl.base); ++ assert(sdpy.worker); ++ ++ qemu_add_vm_change_state_handler(qemu_spice_vm_change_state_handler, &sdpy); ++ qemu_spice_create_host_memslot(&sdpy); ++ qemu_spice_create_host_primary(&sdpy); ++} +diff -urN qemu-kvm-0.13.0.orig/spice-display.h qemu-kvm-0.13.0/spice-display.h +--- qemu-kvm-0.13.0.orig/spice-display.h 1970-01-01 02:00:00.000000000 +0200 ++++ qemu-kvm-0.13.0/spice-display.h 2011-02-09 11:08:02.809000327 +0200 +@@ -0,0 +1,52 @@ ++#include <spice/ipc_ring.h> ++#include <spice/enums.h> ++#include <spice/qxl_dev.h> ++ ++#include "pflib.h" ++ ++#define NUM_MEMSLOTS 8 ++#define MEMSLOT_GENERATION_BITS 8 ++#define MEMSLOT_SLOT_BITS 8 ++ ++#define MEMSLOT_GROUP_HOST 0 ++#define MEMSLOT_GROUP_GUEST 1 ++#define NUM_MEMSLOTS_GROUPS 2 ++ ++#define NUM_SURFACES 1024 ++ ++typedef struct SimpleSpiceDisplay { ++ DisplayState *ds; ++ void *buf; ++ int bufsize; ++ QXLWorker *worker; ++ QXLInstance qxl; ++ uint32_t unique; ++ QemuPfConv *conv; ++ ++ pthread_mutex_t lock; ++ QXLRect dirty; ++ int notify; ++ int running; ++} SimpleSpiceDisplay; ++ ++typedef struct SimpleSpiceUpdate { ++ QXLDrawable drawable; ++ QXLImage image; ++ QXLCommandExt ext; ++ uint8_t *bitmap; ++} SimpleSpiceUpdate; ++ ++int qemu_spice_rect_is_empty(const QXLRect* r); ++void qemu_spice_rect_union(QXLRect *dest, const QXLRect *r); ++ ++SimpleSpiceUpdate *qemu_spice_create_update(SimpleSpiceDisplay *sdpy); ++void qemu_spice_destroy_update(SimpleSpiceDisplay *sdpy, SimpleSpiceUpdate *update); ++void qemu_spice_create_host_memslot(SimpleSpiceDisplay *ssd); ++void qemu_spice_create_host_primary(SimpleSpiceDisplay *ssd); ++void qemu_spice_destroy_host_primary(SimpleSpiceDisplay *ssd); ++void qemu_spice_vm_change_state_handler(void *opaque, int running, int reason); ++ ++void qemu_spice_display_update(SimpleSpiceDisplay *ssd, ++ int x, int y, int w, int h); ++void qemu_spice_display_resize(SimpleSpiceDisplay *ssd); ++void qemu_spice_display_refresh(SimpleSpiceDisplay *ssd); +diff -urN qemu-kvm-0.13.0.orig/spice-input.c qemu-kvm-0.13.0/spice-input.c +--- qemu-kvm-0.13.0.orig/spice-input.c 1970-01-01 02:00:00.000000000 +0200 ++++ qemu-kvm-0.13.0/spice-input.c 2011-02-09 11:08:02.735000327 +0200 +@@ -0,0 +1,173 @@ ++#include <stdlib.h> ++#include <stdio.h> ++#include <stdbool.h> ++#include <string.h> ++ ++#include <spice.h> ++ ++#include "qemu-common.h" ++#include "qemu-spice.h" ++#include "console.h" ++ ++/* keyboard bits */ ++ ++typedef struct QemuSpiceKbd { ++ SpiceKbdInstance sin; ++ int ledstate; ++} QemuSpiceKbd; ++ ++static void kbd_push_key(SpiceKbdInstance *sin, uint8_t frag); ++static uint8_t kbd_get_leds(SpiceKbdInstance *sin); ++static void kbd_leds(void *opaque, int l); ++ ++static const SpiceKbdInterface kbd_interface = { ++ .base.type = SPICE_INTERFACE_KEYBOARD, ++ .base.description = "qemu keyboard", ++ .base.major_version = SPICE_INTERFACE_KEYBOARD_MAJOR, ++ .base.minor_version = SPICE_INTERFACE_KEYBOARD_MINOR, ++ .push_scan_freg = kbd_push_key, ++ .get_leds = kbd_get_leds, ++}; ++ ++static void kbd_push_key(SpiceKbdInstance *sin, uint8_t frag) ++{ ++ kbd_put_keycode(frag); ++} ++ ++static uint8_t kbd_get_leds(SpiceKbdInstance *sin) ++{ ++ QemuSpiceKbd *kbd = container_of(sin, QemuSpiceKbd, sin); ++ return kbd->ledstate; ++} ++ ++static void kbd_leds(void *opaque, int ledstate) ++{ ++ QemuSpiceKbd *kbd = opaque; ++ kbd->ledstate = ledstate; ++ spice_server_kbd_leds(&kbd->sin, ledstate); ++} ++ ++/* mouse bits */ ++ ++typedef struct QemuSpicePointer { ++ SpiceMouseInstance mouse; ++ SpiceTabletInstance tablet; ++ int width, height, x, y; ++ Notifier mouse_mode; ++ bool absolute; ++} QemuSpicePointer; ++ ++static void mouse_motion(SpiceMouseInstance *sin, int dx, int dy, int dz, ++ uint32_t buttons_state) ++{ ++ kbd_mouse_event(dx, dy, dz, buttons_state); ++} ++ ++static void mouse_buttons(SpiceMouseInstance *sin, uint32_t buttons_state) ++{ ++ kbd_mouse_event(0, 0, 0, buttons_state); ++} ++ ++static const SpiceMouseInterface mouse_interface = { ++ .base.type = SPICE_INTERFACE_MOUSE, ++ .base.description = "mouse", ++ .base.major_version = SPICE_INTERFACE_MOUSE_MAJOR, ++ .base.minor_version = SPICE_INTERFACE_MOUSE_MINOR, ++ .motion = mouse_motion, ++ .buttons = mouse_buttons, ++}; ++ ++static void tablet_set_logical_size(SpiceTabletInstance* sin, int width, int height) ++{ ++ QemuSpicePointer *pointer = container_of(sin, QemuSpicePointer, tablet); ++ ++ fprintf(stderr, "%s: %dx%d\n", __FUNCTION__, width, height); ++ if (height < 16) ++ height = 16; ++ if (width < 16) ++ width = 16; ++ pointer->width = width; ++ pointer->height = height; ++} ++ ++static void tablet_position(SpiceTabletInstance* sin, int x, int y, ++ uint32_t buttons_state) ++{ ++ QemuSpicePointer *pointer = container_of(sin, QemuSpicePointer, tablet); ++ ++ pointer->x = x * 0x7FFF / (pointer->width - 1); ++ pointer->y = y * 0x7FFF / (pointer->height - 1); ++ kbd_mouse_event(pointer->x, pointer->y, 0, buttons_state); ++} ++ ++ ++static void tablet_wheel(SpiceTabletInstance* sin, int wheel, ++ uint32_t buttons_state) ++{ ++ QemuSpicePointer *pointer = container_of(sin, QemuSpicePointer, tablet); ++ ++ kbd_mouse_event(pointer->x, pointer->y, wheel, buttons_state); ++} ++ ++static void tablet_buttons(SpiceTabletInstance *sin, ++ uint32_t buttons_state) ++{ ++ QemuSpicePointer *pointer = container_of(sin, QemuSpicePointer, tablet); ++ ++ kbd_mouse_event(pointer->x, pointer->y, 0, buttons_state); ++} ++ ++static const SpiceTabletInterface tablet_interface = { ++ .base.type = SPICE_INTERFACE_TABLET, ++ .base.description = "tablet", ++ .base.major_version = SPICE_INTERFACE_TABLET_MAJOR, ++ .base.minor_version = SPICE_INTERFACE_TABLET_MINOR, ++ .set_logical_size = tablet_set_logical_size, ++ .position = tablet_position, ++ .wheel = tablet_wheel, ++ .buttons = tablet_buttons, ++}; ++ ++static void mouse_mode_notifier(Notifier *notifier) ++{ ++ QemuSpicePointer *pointer = container_of(notifier, QemuSpicePointer, mouse_mode); ++ bool is_absolute = kbd_mouse_is_absolute(); ++ bool has_absolute = kbd_mouse_has_absolute(); ++ ++ fprintf(stderr, "%s: absolute pointer: %s%s\n", __FUNCTION__, ++ has_absolute ? "present" : "not available", ++ is_absolute ? "+active" : ""); ++ ++ if (pointer->absolute == is_absolute) ++ return; ++ ++ if (is_absolute) { ++ fprintf(stderr, "%s: using absolute pointer (client mode)\n", __FUNCTION__); ++ spice_server_add_interface(spice_server, &pointer->tablet.base); ++ } else { ++ fprintf(stderr, "%s: using relative pointer (server mode)\n", __FUNCTION__); ++ spice_server_remove_interface(&pointer->tablet.base); ++ } ++ pointer->absolute = is_absolute; ++} ++ ++void qemu_spice_input_init(void) ++{ ++ QemuSpiceKbd *kbd; ++ QemuSpicePointer *pointer; ++ ++ kbd = qemu_mallocz(sizeof(*kbd)); ++ kbd->sin.base.sif = &kbd_interface.base; ++ spice_server_add_interface(spice_server, &kbd->sin.base); ++ qemu_add_led_event_handler(kbd_leds, kbd); ++ ++ pointer = qemu_mallocz(sizeof(*pointer)); ++ pointer->mouse.base.sif = &mouse_interface.base; ++ pointer->tablet.base.sif = &tablet_interface.base; ++ spice_server_add_interface(spice_server, &pointer->mouse.base); ++ ++ pointer->absolute = false; ++ pointer->mouse_mode.notify = mouse_mode_notifier; ++ qemu_add_mouse_mode_change_notifier(&pointer->mouse_mode); ++ mouse_mode_notifier(&pointer->mouse_mode); ++} +diff -urN qemu-kvm-0.13.0.orig/sysemu.h qemu-kvm-0.13.0/sysemu.h +--- qemu-kvm-0.13.0.orig/sysemu.h 2011-02-09 11:01:45.776000327 +0200 ++++ qemu-kvm-0.13.0/sysemu.h 2011-02-09 11:08:02.771000327 +0200 +@@ -104,7 +104,7 @@ + extern int bios_size; + + typedef enum { +- VGA_NONE, VGA_STD, VGA_CIRRUS, VGA_VMWARE, VGA_XENFB ++ VGA_NONE, VGA_STD, VGA_CIRRUS, VGA_VMWARE, VGA_XENFB, VGA_QXL, + } VGAInterfaceType; + + extern int vga_interface_type; +@@ -112,6 +112,7 @@ + #define std_vga_enabled (vga_interface_type == VGA_STD) + #define xenfb_enabled (vga_interface_type == VGA_XENFB) + #define vmsvga_enabled (vga_interface_type == VGA_VMWARE) ++#define qxl_enabled (vga_interface_type == VGA_QXL) + + extern int graphic_width; + extern int graphic_height; +diff -urN qemu-kvm-0.13.0.orig/sysemu.h.orig qemu-kvm-0.13.0/sysemu.h.orig +--- qemu-kvm-0.13.0.orig/sysemu.h.orig 1970-01-01 02:00:00.000000000 +0200 ++++ qemu-kvm-0.13.0/sysemu.h.orig 2011-02-09 11:07:32.579000328 +0200 +@@ -0,0 +1,197 @@ ++#ifndef SYSEMU_H ++#define SYSEMU_H ++/* Misc. things related to the system emulator. */ ++ ++#include "qemu-common.h" ++#include "qemu-option.h" ++#include "qemu-queue.h" ++#include "qemu-timer.h" ++#include "notify.h" ++ ++#ifdef _WIN32 ++#include <windows.h> ++#include "qemu-os-win32.h" ++#endif ++ ++#ifdef CONFIG_POSIX ++#include "qemu-os-posix.h" ++#endif ++ ++/* vl.c */ ++extern const char *bios_name; ++ ++#define QEMU_FILE_TYPE_BIOS 0 ++#define QEMU_FILE_TYPE_KEYMAP 1 ++char *qemu_find_file(int type, const char *name); ++ ++extern int vm_running; ++extern const char *qemu_name; ++extern uint8_t qemu_uuid[]; ++int qemu_uuid_parse(const char *str, uint8_t *uuid); ++#define UUID_FMT "%02hhx%02hhx%02hhx%02hhx-%02hhx%02hhx-%02hhx%02hhx-%02hhx%02hhx-%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx" ++ ++typedef struct vm_change_state_entry VMChangeStateEntry; ++typedef void VMChangeStateHandler(void *opaque, int running, int reason); ++ ++VMChangeStateEntry *qemu_add_vm_change_state_handler(VMChangeStateHandler *cb, ++ void *opaque); ++void qemu_del_vm_change_state_handler(VMChangeStateEntry *e); ++ ++void vm_start(void); ++void vm_stop(int reason); ++ ++uint64_t ram_bytes_remaining(void); ++uint64_t ram_bytes_transferred(void); ++uint64_t ram_bytes_total(void); ++ ++int64_t cpu_get_ticks(void); ++void cpu_enable_ticks(void); ++void cpu_disable_ticks(void); ++ ++void qemu_system_reset_request(void); ++void qemu_system_shutdown_request(void); ++void qemu_system_powerdown_request(void); ++int qemu_no_shutdown(void); ++int qemu_shutdown_requested(void); ++int qemu_reset_requested(void); ++int qemu_powerdown_requested(void); ++extern qemu_irq qemu_system_powerdown; ++void qemu_system_reset(void); ++ ++void qemu_add_exit_notifier(Notifier *notify); ++void qemu_remove_exit_notifier(Notifier *notify); ++ ++void do_savevm(Monitor *mon, const QDict *qdict); ++int load_vmstate(const char *name); ++void do_delvm(Monitor *mon, const QDict *qdict); ++void do_info_snapshots(Monitor *mon); ++ ++void cpu_synchronize_all_states(void); ++void cpu_synchronize_all_post_reset(void); ++void cpu_synchronize_all_post_init(void); ++ ++void qemu_announce_self(void); ++ ++void main_loop_wait(int nonblocking); ++ ++int qemu_savevm_state_begin(Monitor *mon, QEMUFile *f, int blk_enable, ++ int shared); ++int qemu_savevm_state_iterate(Monitor *mon, QEMUFile *f); ++int qemu_savevm_state_complete(Monitor *mon, QEMUFile *f); ++void qemu_savevm_state_cancel(Monitor *mon, QEMUFile *f); ++int qemu_loadvm_state(QEMUFile *f); ++ ++/* SLIRP */ ++void do_info_slirp(Monitor *mon); ++ ++/* OS specific functions */ ++void os_setup_early_signal_handling(void); ++char *os_find_datadir(const char *argv0); ++void os_parse_cmd_args(int index, const char *optarg); ++void os_pidfile_error(void); ++ ++typedef enum DisplayType ++{ ++ DT_DEFAULT, ++ DT_CURSES, ++ DT_SDL, ++ DT_VNC, ++ DT_NOGRAPHIC, ++} DisplayType; ++ ++extern int autostart; ++extern int incoming_expected; ++extern int bios_size; ++ ++typedef enum { ++ VGA_NONE, VGA_STD, VGA_CIRRUS, VGA_VMWARE, VGA_XENFB ++} VGAInterfaceType; ++ ++extern int vga_interface_type; ++#define cirrus_vga_enabled (vga_interface_type == VGA_CIRRUS) ++#define std_vga_enabled (vga_interface_type == VGA_STD) ++#define xenfb_enabled (vga_interface_type == VGA_XENFB) ++#define vmsvga_enabled (vga_interface_type == VGA_VMWARE) ++ ++extern int graphic_width; ++extern int graphic_height; ++extern int graphic_depth; ++extern uint8_t irq0override; ++extern DisplayType display_type; ++extern const char *keyboard_layout; ++extern int win2k_install_hack; ++extern int rtc_td_hack; ++extern int alt_grab; ++extern int ctrl_grab; ++extern int usb_enabled; ++extern int smp_cpus; ++extern int max_cpus; ++extern int cursor_hide; ++extern int graphic_rotate; ++extern int no_quit; ++extern int no_shutdown; ++extern int semihosting_enabled; ++extern int old_param; ++extern int boot_menu; ++extern QEMUClock *rtc_clock; ++extern long hpagesize; ++ ++#define MAX_NODES 64 ++extern int nb_numa_nodes; ++extern uint64_t node_mem[MAX_NODES]; ++extern uint64_t node_cpumask[MAX_NODES]; ++ ++#define MAX_OPTION_ROMS 16 ++extern const char *option_rom[MAX_OPTION_ROMS]; ++extern int nb_option_roms; ++ ++#define MAX_PROM_ENVS 128 ++extern const char *prom_envs[MAX_PROM_ENVS]; ++extern unsigned int nb_prom_envs; ++ ++/* acpi */ ++void qemu_system_cpu_hot_add(int cpu, int state); ++ ++/* pci-hotplug */ ++void pci_device_hot_add(Monitor *mon, const QDict *qdict); ++void drive_hot_add(Monitor *mon, const QDict *qdict); ++void do_pci_device_hot_remove(Monitor *mon, const QDict *qdict); ++ ++/* serial ports */ ++ ++#define MAX_SERIAL_PORTS 4 ++ ++extern CharDriverState *serial_hds[MAX_SERIAL_PORTS]; ++ ++/* parallel ports */ ++ ++#define MAX_PARALLEL_PORTS 3 ++ ++extern CharDriverState *parallel_hds[MAX_PARALLEL_PORTS]; ++ ++#define TFR(expr) do { if ((expr) != -1) break; } while (errno == EINTR) ++ ++#ifdef HAS_AUDIO ++struct soundhw { ++ const char *name; ++ const char *descr; ++ int enabled; ++ int isa; ++ union { ++ int (*init_isa) (qemu_irq *pic); ++ int (*init_pci) (PCIBus *bus); ++ } init; ++}; ++ ++extern struct soundhw soundhw[]; ++#endif ++ ++void do_usb_add(Monitor *mon, const QDict *qdict); ++void do_usb_del(Monitor *mon, const QDict *qdict); ++void usb_info(Monitor *mon); ++ ++void rtc_change_mon_event(struct tm *tm); ++ ++void register_devices(void); ++ ++#endif +diff -urN qemu-kvm-0.13.0.orig/vl.c qemu-kvm-0.13.0/vl.c +--- qemu-kvm-0.13.0.orig/vl.c 2011-02-09 11:01:45.746000327 +0200 ++++ qemu-kvm-0.13.0/vl.c 2011-02-09 11:08:02.773000327 +0200 +@@ -162,6 +162,8 @@ + #include "cpus.h" + #include "arch_init.h" + ++#include "qemu-spice.h" ++ + //#define DEBUG_NET + //#define DEBUG_SLIRP + +@@ -1458,6 +1460,8 @@ + vga_interface_type = VGA_VMWARE; + } else if (strstart(p, "xenfb", &opts)) { + vga_interface_type = VGA_XENFB; ++ } else if (strstart(p, "qxl", &opts)) { ++ vga_interface_type = VGA_QXL; + } else if (!strstart(p, "none", &opts)) { + invalid_vga: + fprintf(stderr, "Unknown vga type: %s\n", p); +@@ -2679,6 +2683,15 @@ + } + break; + } ++#ifdef CONFIG_SPICE ++ case QEMU_OPTION_spice: ++ opts = qemu_opts_parse(&qemu_spice_opts, optarg, 0); ++ if (!opts) { ++ fprintf(stderr, "parse error: %s\n", optarg); ++ exit(1); ++ } ++ break; ++#endif + case QEMU_OPTION_writeconfig: + { + FILE *fp; +@@ -2953,6 +2966,10 @@ + } + qemu_add_globals(); + ++#ifdef CONFIG_SPICE ++ qemu_spice_init(); ++#endif ++ + machine->init(ram_size, boot_devices, + kernel_filename, kernel_cmdline, initrd_filename, cpu_model); + +@@ -2980,7 +2997,7 @@ + /* just use the first displaystate for the moment */ + ds = get_displaystate(); + +- if (display_type == DT_DEFAULT) { ++ if (display_type == DT_DEFAULT && !using_spice) { + #if defined(CONFIG_SDL) || defined(CONFIG_COCOA) + display_type = DT_SDL; + #else +@@ -3020,6 +3037,11 @@ + default: + break; + } ++#ifdef CONFIG_SPICE ++ if (using_spice && !qxl_enabled) { ++ qemu_spice_display_init(ds); ++ } ++#endif + dpy_resize(ds); + + dcl = ds->listeners; +diff -urN qemu-kvm-0.13.0.orig/vl.c.orig qemu-kvm-0.13.0/vl.c.orig +--- qemu-kvm-0.13.0.orig/vl.c.orig 1970-01-01 02:00:00.000000000 +0200 ++++ qemu-kvm-0.13.0/vl.c.orig 2011-02-09 11:08:02.730000327 +0200 +@@ -0,0 +1,3100 @@ ++/* ++ * QEMU System Emulator ++ * ++ * Copyright (c) 2003-2008 Fabrice Bellard ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a copy ++ * of this software and associated documentation files (the "Software"), to deal ++ * in the Software without restriction, including without limitation the rights ++ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell ++ * copies of the Software, and to permit persons to whom the Software is ++ * furnished to do so, subject to the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be included in ++ * all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ++ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, ++ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN ++ * THE SOFTWARE. ++ */ ++#include <unistd.h> ++#include <fcntl.h> ++#include <signal.h> ++#include <time.h> ++#include <errno.h> ++#include <sys/time.h> ++#include <zlib.h> ++ ++/* Needed early for CONFIG_BSD etc. */ ++#include "config-host.h" ++ ++#ifndef _WIN32 ++#include <libgen.h> ++#include <sys/times.h> ++#include <sys/wait.h> ++#include <termios.h> ++#include <sys/mman.h> ++#include <sys/ioctl.h> ++#include <sys/resource.h> ++#include <sys/socket.h> ++#include <netinet/in.h> ++#include <net/if.h> ++#include <arpa/inet.h> ++#include <dirent.h> ++#include <netdb.h> ++#include <sys/select.h> ++#ifdef CONFIG_BSD ++#include <sys/stat.h> ++#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__) ++#include <libutil.h> ++#include <sys/sysctl.h> ++#else ++#include <util.h> ++#endif ++#else ++#ifdef __linux__ ++#include <pty.h> ++#include <malloc.h> ++ ++#include <linux/ppdev.h> ++#include <linux/parport.h> ++#endif ++#ifdef __sun__ ++#include <sys/stat.h> ++#include <sys/ethernet.h> ++#include <sys/sockio.h> ++#include <netinet/arp.h> ++#include <netinet/in_systm.h> ++#include <netinet/ip.h> ++#include <netinet/ip_icmp.h> // must come after ip.h ++#include <netinet/udp.h> ++#include <netinet/tcp.h> ++#include <net/if.h> ++#include <syslog.h> ++#include <stropts.h> ++/* See MySQL bug #7156 (http://bugs.mysql.com/bug.php?id=7156) for ++ discussion about Solaris header problems */ ++extern int madvise(caddr_t, size_t, int); ++#endif ++#endif ++#endif ++ ++#if defined(__OpenBSD__) ++#include <util.h> ++#endif ++ ++#if defined(CONFIG_VDE) ++#include <libvdeplug.h> ++#endif ++ ++#ifdef _WIN32 ++#include <windows.h> ++#endif ++ ++#ifdef CONFIG_SDL ++#if defined(__APPLE__) || defined(main) ++#include <SDL.h> ++int qemu_main(int argc, char **argv, char **envp); ++int main(int argc, char **argv) ++{ ++ return qemu_main(argc, argv, NULL); ++} ++#undef main ++#define main qemu_main ++#endif ++#endif /* CONFIG_SDL */ ++ ++#ifdef CONFIG_COCOA ++#undef main ++#define main qemu_main ++#endif /* CONFIG_COCOA */ ++ ++#include "hw/hw.h" ++#include "hw/boards.h" ++#include "hw/usb.h" ++#include "hw/pcmcia.h" ++#include "hw/pc.h" ++#include "hw/isa.h" ++#include "hw/baum.h" ++#include "hw/bt.h" ++#include "hw/watchdog.h" ++#include "hw/smbios.h" ++#include "hw/xen.h" ++#include "hw/qdev.h" ++#include "hw/loader.h" ++#include "bt-host.h" ++#include "net.h" ++#include "net/slirp.h" ++#include "monitor.h" ++#include "console.h" ++#include "sysemu.h" ++#include "gdbstub.h" ++#include "qemu-timer.h" ++#include "qemu-char.h" ++#include "cache-utils.h" ++#include "block.h" ++#include "blockdev.h" ++#include "block-migration.h" ++#include "dma.h" ++#include "audio/audio.h" ++#include "migration.h" ++#include "kvm.h" ++#include "qemu-option.h" ++#include "qemu-config.h" ++#include "qemu-objects.h" ++#include "qemu-options.h" ++#include "hw/device-assignment.h" ++#ifdef CONFIG_VIRTFS ++#include "fsdev/qemu-fsdev.h" ++#endif ++ ++#include "disas.h" ++ ++#include "qemu_socket.h" ++ ++#include "slirp/libslirp.h" ++ ++#include "qemu-queue.h" ++#include "cpus.h" ++#include "arch_init.h" ++ ++#include "qemu-spice.h" ++ ++//#define DEBUG_NET ++//#define DEBUG_SLIRP ++ ++#define DEFAULT_RAM_SIZE 128 ++ ++#define MAX_VIRTIO_CONSOLES 1 ++ ++static const char *data_dir; ++const char *bios_name = NULL; ++enum vga_retrace_method vga_retrace_method = VGA_RETRACE_DUMB; ++DisplayType display_type = DT_DEFAULT; ++const char* keyboard_layout = NULL; ++ram_addr_t ram_size; ++const char *mem_path = NULL; ++#ifdef MAP_POPULATE ++int mem_prealloc = 0; /* force preallocation of physical target memory */ ++#endif ++int nb_nics; ++NICInfo nd_table[MAX_NICS]; ++int vm_running; ++int autostart; ++int incoming_expected; /* Started with -incoming and waiting for incoming */ ++static int rtc_utc = 1; ++static int rtc_date_offset = -1; /* -1 means no change */ ++QEMUClock *rtc_clock; ++int vga_interface_type = VGA_NONE; ++static int full_screen = 0; ++#ifdef CONFIG_SDL ++static int no_frame = 0; ++#endif ++int no_quit = 0; ++CharDriverState *serial_hds[MAX_SERIAL_PORTS]; ++CharDriverState *parallel_hds[MAX_PARALLEL_PORTS]; ++CharDriverState *virtcon_hds[MAX_VIRTIO_CONSOLES]; ++int win2k_install_hack = 0; ++int rtc_td_hack = 0; ++int usb_enabled = 0; ++int singlestep = 0; ++const char *assigned_devices[MAX_DEV_ASSIGN_CMDLINE]; ++int assigned_devices_index; ++int smp_cpus = 1; ++int max_cpus = 0; ++int smp_cores = 1; ++int smp_threads = 1; ++const char *vnc_display; ++int acpi_enabled = 1; ++int no_hpet = 0; ++int fd_bootchk = 1; ++int no_reboot = 0; ++int no_shutdown = 0; ++int cursor_hide = 1; ++int graphic_rotate = 0; ++uint8_t irq0override = 1; ++const char *watchdog; ++const char *option_rom[MAX_OPTION_ROMS]; ++int nb_option_roms; ++int semihosting_enabled = 0; ++int time_drift_fix = 0; ++unsigned int kvm_shadow_memory = 0; ++int old_param = 0; ++const char *qemu_name; ++int alt_grab = 0; ++int ctrl_grab = 0; ++unsigned int nb_prom_envs = 0; ++const char *prom_envs[MAX_PROM_ENVS]; ++const char *nvram = NULL; ++int boot_menu; ++ ++int nb_numa_nodes; ++uint64_t node_mem[MAX_NODES]; ++uint64_t node_cpumask[MAX_NODES]; ++ ++static QEMUTimer *nographic_timer; ++ ++uint8_t qemu_uuid[16]; ++ ++static QEMUBootSetHandler *boot_set_handler; ++static void *boot_set_opaque; ++ ++static NotifierList exit_notifiers = ++ NOTIFIER_LIST_INITIALIZER(exit_notifiers); ++ ++int kvm_allowed = 1; ++uint32_t xen_domid; ++enum xen_mode xen_mode = XEN_EMULATE; ++ ++static int default_serial = 1; ++static int default_parallel = 1; ++static int default_virtcon = 1; ++static int default_monitor = 1; ++static int default_vga = 1; ++static int default_floppy = 1; ++static int default_cdrom = 1; ++static int default_sdcard = 1; ++ ++static struct { ++ const char *driver; ++ int *flag; ++} default_list[] = { ++ { .driver = "isa-serial", .flag = &default_serial }, ++ { .driver = "isa-parallel", .flag = &default_parallel }, ++ { .driver = "isa-fdc", .flag = &default_floppy }, ++ { .driver = "ide-drive", .flag = &default_cdrom }, ++ { .driver = "virtio-serial-pci", .flag = &default_virtcon }, ++ { .driver = "virtio-serial-s390", .flag = &default_virtcon }, ++ { .driver = "virtio-serial", .flag = &default_virtcon }, ++ { .driver = "VGA", .flag = &default_vga }, ++ { .driver = "cirrus-vga", .flag = &default_vga }, ++ { .driver = "vmware-svga", .flag = &default_vga }, ++}; ++ ++static int default_driver_check(QemuOpts *opts, void *opaque) ++{ ++ const char *driver = qemu_opt_get(opts, "driver"); ++ int i; ++ ++ if (!driver) ++ return 0; ++ for (i = 0; i < ARRAY_SIZE(default_list); i++) { ++ if (strcmp(default_list[i].driver, driver) != 0) ++ continue; ++ *(default_list[i].flag) = 0; ++ } ++ return 0; ++} ++ ++/***********************************************************/ ++/* real time host monotonic timer */ ++ ++/* compute with 96 bit intermediate result: (a*b)/c */ ++uint64_t muldiv64(uint64_t a, uint32_t b, uint32_t c) ++{ ++ union { ++ uint64_t ll; ++ struct { ++#ifdef HOST_WORDS_BIGENDIAN ++ uint32_t high, low; ++#else ++ uint32_t low, high; ++#endif ++ } l; ++ } u, res; ++ uint64_t rl, rh; ++ ++ u.ll = a; ++ rl = (uint64_t)u.l.low * (uint64_t)b; ++ rh = (uint64_t)u.l.high * (uint64_t)b; ++ rh += (rl >> 32); ++ res.l.high = rh / c; ++ res.l.low = (((rh % c) << 32) + (rl & 0xffffffff)) / c; ++ return res.ll; ++} ++ ++/***********************************************************/ ++/* host time/date access */ ++void qemu_get_timedate(struct tm *tm, int offset) ++{ ++ time_t ti; ++ struct tm *ret; ++ ++ time(&ti); ++ ti += offset; ++ if (rtc_date_offset == -1) { ++ if (rtc_utc) ++ ret = gmtime(&ti); ++ else ++ ret = localtime(&ti); ++ } else { ++ ti -= rtc_date_offset; ++ ret = gmtime(&ti); ++ } ++ ++ memcpy(tm, ret, sizeof(struct tm)); ++} ++ ++int qemu_timedate_diff(struct tm *tm) ++{ ++ time_t seconds; ++ ++ if (rtc_date_offset == -1) ++ if (rtc_utc) ++ seconds = mktimegm(tm); ++ else ++ seconds = mktime(tm); ++ else ++ seconds = mktimegm(tm) + rtc_date_offset; ++ ++ return seconds - time(NULL); ++} ++ ++void rtc_change_mon_event(struct tm *tm) ++{ ++ QObject *data; ++ ++ data = qobject_from_jsonf("{ 'offset': %d }", qemu_timedate_diff(tm)); ++ monitor_protocol_event(QEVENT_RTC_CHANGE, data); ++ qobject_decref(data); ++} ++ ++static void configure_rtc_date_offset(const char *startdate, int legacy) ++{ ++ time_t rtc_start_date; ++ struct tm tm; ++ ++ if (!strcmp(startdate, "now") && legacy) { ++ rtc_date_offset = -1; ++ } else { ++ if (sscanf(startdate, "%d-%d-%dT%d:%d:%d", ++ &tm.tm_year, ++ &tm.tm_mon, ++ &tm.tm_mday, ++ &tm.tm_hour, ++ &tm.tm_min, ++ &tm.tm_sec) == 6) { ++ /* OK */ ++ } else if (sscanf(startdate, "%d-%d-%d", ++ &tm.tm_year, ++ &tm.tm_mon, ++ &tm.tm_mday) == 3) { ++ tm.tm_hour = 0; ++ tm.tm_min = 0; ++ tm.tm_sec = 0; ++ } else { ++ goto date_fail; ++ } ++ tm.tm_year -= 1900; ++ tm.tm_mon--; ++ rtc_start_date = mktimegm(&tm); ++ if (rtc_start_date == -1) { ++ date_fail: ++ fprintf(stderr, "Invalid date format. Valid formats are:\n" ++ "'2006-06-17T16:01:21' or '2006-06-17'\n"); ++ exit(1); ++ } ++ rtc_date_offset = time(NULL) - rtc_start_date; ++ } ++} ++ ++static void configure_rtc(QemuOpts *opts) ++{ ++ const char *value; ++ ++ value = qemu_opt_get(opts, "base"); ++ if (value) { ++ if (!strcmp(value, "utc")) { ++ rtc_utc = 1; ++ } else if (!strcmp(value, "localtime")) { ++ rtc_utc = 0; ++ } else { ++ configure_rtc_date_offset(value, 0); ++ } ++ } ++ value = qemu_opt_get(opts, "clock"); ++ if (value) { ++ if (!strcmp(value, "host")) { ++ rtc_clock = host_clock; ++ } else if (!strcmp(value, "vm")) { ++ rtc_clock = vm_clock; ++ } else { ++ fprintf(stderr, "qemu: invalid option value '%s'\n", value); ++ exit(1); ++ } ++ } ++ value = qemu_opt_get(opts, "driftfix"); ++ if (value) { ++ if (!strcmp(value, "slew")) { ++ rtc_td_hack = 1; ++ } else if (!strcmp(value, "none")) { ++ rtc_td_hack = 0; ++ } else { ++ fprintf(stderr, "qemu: invalid option value '%s'\n", value); ++ exit(1); ++ } ++ } ++} ++ ++/***********************************************************/ ++/* Bluetooth support */ ++static int nb_hcis; ++static int cur_hci; ++static struct HCIInfo *hci_table[MAX_NICS]; ++ ++static struct bt_vlan_s { ++ struct bt_scatternet_s net; ++ int id; ++ struct bt_vlan_s *next; ++} *first_bt_vlan; ++ ++/* find or alloc a new bluetooth "VLAN" */ ++static struct bt_scatternet_s *qemu_find_bt_vlan(int id) ++{ ++ struct bt_vlan_s **pvlan, *vlan; ++ for (vlan = first_bt_vlan; vlan != NULL; vlan = vlan->next) { ++ if (vlan->id == id) ++ return &vlan->net; ++ } ++ vlan = qemu_mallocz(sizeof(struct bt_vlan_s)); ++ vlan->id = id; ++ pvlan = &first_bt_vlan; ++ while (*pvlan != NULL) ++ pvlan = &(*pvlan)->next; ++ *pvlan = vlan; ++ return &vlan->net; ++} ++ ++static void null_hci_send(struct HCIInfo *hci, const uint8_t *data, int len) ++{ ++} ++ ++static int null_hci_addr_set(struct HCIInfo *hci, const uint8_t *bd_addr) ++{ ++ return -ENOTSUP; ++} ++ ++static struct HCIInfo null_hci = { ++ .cmd_send = null_hci_send, ++ .sco_send = null_hci_send, ++ .acl_send = null_hci_send, ++ .bdaddr_set = null_hci_addr_set, ++}; ++ ++struct HCIInfo *qemu_next_hci(void) ++{ ++ if (cur_hci == nb_hcis) ++ return &null_hci; ++ ++ return hci_table[cur_hci++]; ++} ++ ++static struct HCIInfo *hci_init(const char *str) ++{ ++ char *endp; ++ struct bt_scatternet_s *vlan = 0; ++ ++ if (!strcmp(str, "null")) ++ /* null */ ++ return &null_hci; ++ else if (!strncmp(str, "host", 4) && (str[4] == '\0' || str[4] == ':')) ++ /* host[:hciN] */ ++ return bt_host_hci(str[4] ? str + 5 : "hci0"); ++ else if (!strncmp(str, "hci", 3)) { ++ /* hci[,vlan=n] */ ++ if (str[3]) { ++ if (!strncmp(str + 3, ",vlan=", 6)) { ++ vlan = qemu_find_bt_vlan(strtol(str + 9, &endp, 0)); ++ if (*endp) ++ vlan = 0; ++ } ++ } else ++ vlan = qemu_find_bt_vlan(0); ++ if (vlan) ++ return bt_new_hci(vlan); ++ } ++ ++ fprintf(stderr, "qemu: Unknown bluetooth HCI `%s'.\n", str); ++ ++ return 0; ++} ++ ++static int bt_hci_parse(const char *str) ++{ ++ struct HCIInfo *hci; ++ bdaddr_t bdaddr; ++ ++ if (nb_hcis >= MAX_NICS) { ++ fprintf(stderr, "qemu: Too many bluetooth HCIs (max %i).\n", MAX_NICS); ++ return -1; ++ } ++ ++ hci = hci_init(str); ++ if (!hci) ++ return -1; ++ ++ bdaddr.b[0] = 0x52; ++ bdaddr.b[1] = 0x54; ++ bdaddr.b[2] = 0x00; ++ bdaddr.b[3] = 0x12; ++ bdaddr.b[4] = 0x34; ++ bdaddr.b[5] = 0x56 + nb_hcis; ++ hci->bdaddr_set(hci, bdaddr.b); ++ ++ hci_table[nb_hcis++] = hci; ++ ++ return 0; ++} ++ ++static void bt_vhci_add(int vlan_id) ++{ ++ struct bt_scatternet_s *vlan = qemu_find_bt_vlan(vlan_id); ++ ++ if (!vlan->slave) ++ fprintf(stderr, "qemu: warning: adding a VHCI to " ++ "an empty scatternet %i\n", vlan_id); ++ ++ bt_vhci_init(bt_new_hci(vlan)); ++} ++ ++static struct bt_device_s *bt_device_add(const char *opt) ++{ ++ struct bt_scatternet_s *vlan; ++ int vlan_id = 0; ++ char *endp = strstr(opt, ",vlan="); ++ int len = (endp ? endp - opt : strlen(opt)) + 1; ++ char devname[10]; ++ ++ pstrcpy(devname, MIN(sizeof(devname), len), opt); ++ ++ if (endp) { ++ vlan_id = strtol(endp + 6, &endp, 0); ++ if (*endp) { ++ fprintf(stderr, "qemu: unrecognised bluetooth vlan Id\n"); ++ return 0; ++ } ++ } ++ ++ vlan = qemu_find_bt_vlan(vlan_id); ++ ++ if (!vlan->slave) ++ fprintf(stderr, "qemu: warning: adding a slave device to " ++ "an empty scatternet %i\n", vlan_id); ++ ++ if (!strcmp(devname, "keyboard")) ++ return bt_keyboard_init(vlan); ++ ++ fprintf(stderr, "qemu: unsupported bluetooth device `%s'\n", devname); ++ return 0; ++} ++ ++static int bt_parse(const char *opt) ++{ ++ const char *endp, *p; ++ int vlan; ++ ++ if (strstart(opt, "hci", &endp)) { ++ if (!*endp || *endp == ',') { ++ if (*endp) ++ if (!strstart(endp, ",vlan=", 0)) ++ opt = endp + 1; ++ ++ return bt_hci_parse(opt); ++ } ++ } else if (strstart(opt, "vhci", &endp)) { ++ if (!*endp || *endp == ',') { ++ if (*endp) { ++ if (strstart(endp, ",vlan=", &p)) { ++ vlan = strtol(p, (char **) &endp, 0); ++ if (*endp) { ++ fprintf(stderr, "qemu: bad scatternet '%s'\n", p); ++ return 1; ++ } ++ } else { ++ fprintf(stderr, "qemu: bad parameter '%s'\n", endp + 1); ++ return 1; ++ } ++ } else ++ vlan = 0; ++ ++ bt_vhci_add(vlan); ++ return 0; ++ } ++ } else if (strstart(opt, "device:", &endp)) ++ return !bt_device_add(endp); ++ ++ fprintf(stderr, "qemu: bad bluetooth parameter '%s'\n", opt); ++ return 1; ++} ++ ++/***********************************************************/ ++/* QEMU Block devices */ ++ ++#define HD_ALIAS "index=%d,media=disk" ++#define CDROM_ALIAS "index=2,media=cdrom" ++#define FD_ALIAS "index=%d,if=floppy" ++#define PFLASH_ALIAS "if=pflash" ++#define MTD_ALIAS "if=mtd" ++#define SD_ALIAS "index=0,if=sd" ++ ++static int drive_init_func(QemuOpts *opts, void *opaque) ++{ ++ int *use_scsi = opaque; ++ int fatal_error = 0; ++ ++ if (drive_init(opts, *use_scsi, &fatal_error) == NULL) { ++ if (fatal_error) ++ return 1; ++ } ++ return 0; ++} ++ ++static int drive_enable_snapshot(QemuOpts *opts, void *opaque) ++{ ++ if (NULL == qemu_opt_get(opts, "snapshot")) { ++ qemu_opt_set(opts, "snapshot", "on"); ++ } ++ return 0; ++} ++ ++void qemu_register_boot_set(QEMUBootSetHandler *func, void *opaque) ++{ ++ boot_set_handler = func; ++ boot_set_opaque = opaque; ++} ++ ++int qemu_boot_set(const char *boot_devices) ++{ ++ if (!boot_set_handler) { ++ return -EINVAL; ++ } ++ return boot_set_handler(boot_set_opaque, boot_devices); ++} ++ ++static void validate_bootdevices(char *devices) ++{ ++ /* We just do some generic consistency checks */ ++ const char *p; ++ int bitmap = 0; ++ ++ for (p = devices; *p != '\0'; p++) { ++ /* Allowed boot devices are: ++ * a-b: floppy disk drives ++ * c-f: IDE disk drives ++ * g-m: machine implementation dependant drives ++ * n-p: network devices ++ * It's up to each machine implementation to check if the given boot ++ * devices match the actual hardware implementation and firmware ++ * features. ++ */ ++ if (*p < 'a' || *p > 'p') { ++ fprintf(stderr, "Invalid boot device '%c'\n", *p); ++ exit(1); ++ } ++ if (bitmap & (1 << (*p - 'a'))) { ++ fprintf(stderr, "Boot device '%c' was given twice\n", *p); ++ exit(1); ++ } ++ bitmap |= 1 << (*p - 'a'); ++ } ++} ++ ++static void restore_boot_devices(void *opaque) ++{ ++ char *standard_boot_devices = opaque; ++ static int first = 1; ++ ++ /* Restore boot order and remove ourselves after the first boot */ ++ if (first) { ++ first = 0; ++ return; ++ } ++ ++ qemu_boot_set(standard_boot_devices); ++ ++ qemu_unregister_reset(restore_boot_devices, standard_boot_devices); ++ qemu_free(standard_boot_devices); ++} ++ ++static void numa_add(const char *optarg) ++{ ++ char option[128]; ++ char *endptr; ++ unsigned long long value, endvalue; ++ int nodenr; ++ ++ optarg = get_opt_name(option, 128, optarg, ',') + 1; ++ if (!strcmp(option, "node")) { ++ if (get_param_value(option, 128, "nodeid", optarg) == 0) { ++ nodenr = nb_numa_nodes; ++ } else { ++ nodenr = strtoull(option, NULL, 10); ++ } ++ ++ if (get_param_value(option, 128, "mem", optarg) == 0) { ++ node_mem[nodenr] = 0; ++ } else { ++ value = strtoull(option, &endptr, 0); ++ switch (*endptr) { ++ case 0: case 'M': case 'm': ++ value <<= 20; ++ break; ++ case 'G': case 'g': ++ value <<= 30; ++ break; ++ } ++ node_mem[nodenr] = value; ++ } ++ if (get_param_value(option, 128, "cpus", optarg) == 0) { ++ node_cpumask[nodenr] = 0; ++ } else { ++ value = strtoull(option, &endptr, 10); ++ if (value >= 64) { ++ value = 63; ++ fprintf(stderr, "only 64 CPUs in NUMA mode supported.\n"); ++ } else { ++ if (*endptr == '-') { ++ endvalue = strtoull(endptr+1, &endptr, 10); ++ if (endvalue >= 63) { ++ endvalue = 62; ++ fprintf(stderr, ++ "only 63 CPUs in NUMA mode supported.\n"); ++ } ++ value = (2ULL << endvalue) - (1ULL << value); ++ } else { ++ value = 1ULL << value; ++ } ++ } ++ node_cpumask[nodenr] = value; ++ } ++ nb_numa_nodes++; ++ } ++ return; ++} ++ ++static void smp_parse(const char *optarg) ++{ ++ int smp, sockets = 0, threads = 0, cores = 0; ++ char *endptr; ++ char option[128]; ++ ++ smp = strtoul(optarg, &endptr, 10); ++ if (endptr != optarg) { ++ if (*endptr == ',') { ++ endptr++; ++ } ++ } ++ if (get_param_value(option, 128, "sockets", endptr) != 0) ++ sockets = strtoull(option, NULL, 10); ++ if (get_param_value(option, 128, "cores", endptr) != 0) ++ cores = strtoull(option, NULL, 10); ++ if (get_param_value(option, 128, "threads", endptr) != 0) ++ threads = strtoull(option, NULL, 10); ++ if (get_param_value(option, 128, "maxcpus", endptr) != 0) ++ max_cpus = strtoull(option, NULL, 10); ++ ++ /* compute missing values, prefer sockets over cores over threads */ ++ if (smp == 0 || sockets == 0) { ++ sockets = sockets > 0 ? sockets : 1; ++ cores = cores > 0 ? cores : 1; ++ threads = threads > 0 ? threads : 1; ++ if (smp == 0) { ++ smp = cores * threads * sockets; ++ } ++ } else { ++ if (cores == 0) { ++ threads = threads > 0 ? threads : 1; ++ cores = smp / (sockets * threads); ++ } else { ++ if (sockets) { ++ threads = smp / (cores * sockets); ++ } ++ } ++ } ++ smp_cpus = smp; ++ smp_cores = cores > 0 ? cores : 1; ++ smp_threads = threads > 0 ? threads : 1; ++ if (max_cpus == 0) ++ max_cpus = smp_cpus; ++} ++ ++/***********************************************************/ ++/* USB devices */ ++ ++static int usb_device_add(const char *devname) ++{ ++ const char *p; ++ USBDevice *dev = NULL; ++ ++ if (!usb_enabled) ++ return -1; ++ ++ /* drivers with .usbdevice_name entry in USBDeviceInfo */ ++ dev = usbdevice_create(devname); ++ if (dev) ++ goto done; ++ ++ /* the other ones */ ++ if (strstart(devname, "host:", &p)) { ++ dev = usb_host_device_open(p); ++ } else if (!strcmp(devname, "bt") || strstart(devname, "bt:", &p)) { ++ dev = usb_bt_init(devname[2] ? hci_init(p) : ++ bt_new_hci(qemu_find_bt_vlan(0))); ++ } else { ++ return -1; ++ } ++ if (!dev) ++ return -1; ++ ++done: ++ return 0; ++} ++ ++static int usb_device_del(const char *devname) ++{ ++ int bus_num, addr; ++ const char *p; ++ ++ if (strstart(devname, "host:", &p)) ++ return usb_host_device_close(p); ++ ++ if (!usb_enabled) ++ return -1; ++ ++ p = strchr(devname, '.'); ++ if (!p) ++ return -1; ++ bus_num = strtoul(devname, NULL, 0); ++ addr = strtoul(p + 1, NULL, 0); ++ ++ return usb_device_delete_addr(bus_num, addr); ++} ++ ++static int usb_parse(const char *cmdline) ++{ ++ int r; ++ r = usb_device_add(cmdline); ++ if (r < 0) { ++ fprintf(stderr, "qemu: could not add USB device '%s'\n", cmdline); ++ } ++ return r; ++} ++ ++void do_usb_add(Monitor *mon, const QDict *qdict) ++{ ++ const char *devname = qdict_get_str(qdict, "devname"); ++ if (usb_device_add(devname) < 0) { ++ error_report("could not add USB device '%s'", devname); ++ } ++} ++ ++void do_usb_del(Monitor *mon, const QDict *qdict) ++{ ++ const char *devname = qdict_get_str(qdict, "devname"); ++ if (usb_device_del(devname) < 0) { ++ error_report("could not delete USB device '%s'", devname); ++ } ++} ++ ++/***********************************************************/ ++/* PCMCIA/Cardbus */ ++ ++static struct pcmcia_socket_entry_s { ++ PCMCIASocket *socket; ++ struct pcmcia_socket_entry_s *next; ++} *pcmcia_sockets = 0; ++ ++void pcmcia_socket_register(PCMCIASocket *socket) ++{ ++ struct pcmcia_socket_entry_s *entry; ++ ++ entry = qemu_malloc(sizeof(struct pcmcia_socket_entry_s)); ++ entry->socket = socket; ++ entry->next = pcmcia_sockets; ++ pcmcia_sockets = entry; ++} ++ ++void pcmcia_socket_unregister(PCMCIASocket *socket) ++{ ++ struct pcmcia_socket_entry_s *entry, **ptr; ++ ++ ptr = &pcmcia_sockets; ++ for (entry = *ptr; entry; ptr = &entry->next, entry = *ptr) ++ if (entry->socket == socket) { ++ *ptr = entry->next; ++ qemu_free(entry); ++ } ++} ++ ++void pcmcia_info(Monitor *mon) ++{ ++ struct pcmcia_socket_entry_s *iter; ++ ++ if (!pcmcia_sockets) ++ monitor_printf(mon, "No PCMCIA sockets\n"); ++ ++ for (iter = pcmcia_sockets; iter; iter = iter->next) ++ monitor_printf(mon, "%s: %s\n", iter->socket->slot_string, ++ iter->socket->attached ? iter->socket->card_string : ++ "Empty"); ++} ++ ++/***********************************************************/ ++/* I/O handling */ ++ ++typedef struct IOHandlerRecord { ++ int fd; ++ IOCanReadHandler *fd_read_poll; ++ IOHandler *fd_read; ++ IOHandler *fd_write; ++ int deleted; ++ void *opaque; ++ /* temporary data */ ++ struct pollfd *ufd; ++ QLIST_ENTRY(IOHandlerRecord) next; ++} IOHandlerRecord; ++ ++static QLIST_HEAD(, IOHandlerRecord) io_handlers = ++ QLIST_HEAD_INITIALIZER(io_handlers); ++ ++ ++/* XXX: fd_read_poll should be suppressed, but an API change is ++ necessary in the character devices to suppress fd_can_read(). */ ++int qemu_set_fd_handler2(int fd, ++ IOCanReadHandler *fd_read_poll, ++ IOHandler *fd_read, ++ IOHandler *fd_write, ++ void *opaque) ++{ ++ IOHandlerRecord *ioh; ++ ++ if (!fd_read && !fd_write) { ++ QLIST_FOREACH(ioh, &io_handlers, next) { ++ if (ioh->fd == fd) { ++ ioh->deleted = 1; ++ break; ++ } ++ } ++ } else { ++ QLIST_FOREACH(ioh, &io_handlers, next) { ++ if (ioh->fd == fd) ++ goto found; ++ } ++ ioh = qemu_mallocz(sizeof(IOHandlerRecord)); ++ QLIST_INSERT_HEAD(&io_handlers, ioh, next); ++ found: ++ ioh->fd = fd; ++ ioh->fd_read_poll = fd_read_poll; ++ ioh->fd_read = fd_read; ++ ioh->fd_write = fd_write; ++ ioh->opaque = opaque; ++ ioh->deleted = 0; ++ } ++ qemu_notify_event(); ++ return 0; ++} ++ ++int qemu_set_fd_handler(int fd, ++ IOHandler *fd_read, ++ IOHandler *fd_write, ++ void *opaque) ++{ ++ return qemu_set_fd_handler2(fd, NULL, fd_read, fd_write, opaque); ++} ++ ++/***********************************************************/ ++/* machine registration */ ++ ++static QEMUMachine *first_machine = NULL; ++QEMUMachine *current_machine = NULL; ++ ++int qemu_register_machine(QEMUMachine *m) ++{ ++ QEMUMachine **pm; ++ pm = &first_machine; ++ while (*pm != NULL) ++ pm = &(*pm)->next; ++ m->next = NULL; ++ *pm = m; ++ return 0; ++} ++ ++static QEMUMachine *find_machine(const char *name) ++{ ++ QEMUMachine *m; ++ ++ for(m = first_machine; m != NULL; m = m->next) { ++ if (!strcmp(m->name, name)) ++ return m; ++ if (m->alias && !strcmp(m->alias, name)) ++ return m; ++ } ++ return NULL; ++} ++ ++static QEMUMachine *find_default_machine(void) ++{ ++ QEMUMachine *m; ++ ++ for(m = first_machine; m != NULL; m = m->next) { ++ if (m->is_default) { ++ return m; ++ } ++ } ++ return NULL; ++} ++ ++/***********************************************************/ ++/* main execution loop */ ++ ++static void gui_update(void *opaque) ++{ ++ uint64_t interval = GUI_REFRESH_INTERVAL; ++ DisplayState *ds = opaque; ++ DisplayChangeListener *dcl = ds->listeners; ++ ++ qemu_flush_coalesced_mmio_buffer(); ++ dpy_refresh(ds); ++ ++ while (dcl != NULL) { ++ if (dcl->gui_timer_interval && ++ dcl->gui_timer_interval < interval) ++ interval = dcl->gui_timer_interval; ++ dcl = dcl->next; ++ } ++ qemu_mod_timer(ds->gui_timer, interval + qemu_get_clock(rt_clock)); ++} ++ ++static void nographic_update(void *opaque) ++{ ++ uint64_t interval = GUI_REFRESH_INTERVAL; ++ ++ qemu_flush_coalesced_mmio_buffer(); ++ qemu_mod_timer(nographic_timer, interval + qemu_get_clock(rt_clock)); ++} ++ ++struct vm_change_state_entry { ++ VMChangeStateHandler *cb; ++ void *opaque; ++ QLIST_ENTRY (vm_change_state_entry) entries; ++}; ++ ++static QLIST_HEAD(vm_change_state_head, vm_change_state_entry) vm_change_state_head; ++ ++VMChangeStateEntry *qemu_add_vm_change_state_handler(VMChangeStateHandler *cb, ++ void *opaque) ++{ ++ VMChangeStateEntry *e; ++ ++ e = qemu_mallocz(sizeof (*e)); ++ ++ e->cb = cb; ++ e->opaque = opaque; ++ QLIST_INSERT_HEAD(&vm_change_state_head, e, entries); ++ return e; ++} ++ ++void qemu_del_vm_change_state_handler(VMChangeStateEntry *e) ++{ ++ QLIST_REMOVE (e, entries); ++ qemu_free (e); ++} ++ ++void vm_state_notify(int running, int reason) ++{ ++ VMChangeStateEntry *e; ++ ++ for (e = vm_change_state_head.lh_first; e; e = e->entries.le_next) { ++ e->cb(e->opaque, running, reason); ++ } ++} ++ ++void vm_start(void) ++{ ++ if (!vm_running) { ++ cpu_enable_ticks(); ++ vm_running = 1; ++ vm_state_notify(1, 0); ++ resume_all_vcpus(); ++ monitor_protocol_event(QEVENT_RESUME, NULL); ++ } ++} ++ ++/* reset/shutdown handler */ ++ ++typedef struct QEMUResetEntry { ++ QTAILQ_ENTRY(QEMUResetEntry) entry; ++ QEMUResetHandler *func; ++ void *opaque; ++} QEMUResetEntry; ++ ++static QTAILQ_HEAD(reset_handlers, QEMUResetEntry) reset_handlers = ++ QTAILQ_HEAD_INITIALIZER(reset_handlers); ++static int reset_requested; ++static int shutdown_requested; ++static int powerdown_requested; ++int debug_requested; ++int vmstop_requested; ++ ++int qemu_no_shutdown(void) ++{ ++ int r = no_shutdown; ++ no_shutdown = 0; ++ return r; ++} ++ ++int qemu_shutdown_requested(void) ++{ ++ int r = shutdown_requested; ++ shutdown_requested = 0; ++ return r; ++} ++ ++int qemu_reset_requested(void) ++{ ++ int r = reset_requested; ++ reset_requested = 0; ++ return r; ++} ++ ++int qemu_powerdown_requested(void) ++{ ++ int r = powerdown_requested; ++ powerdown_requested = 0; ++ return r; ++} ++ ++static int qemu_debug_requested(void) ++{ ++ int r = debug_requested; ++ debug_requested = 0; ++ return r; ++} ++ ++static int qemu_vmstop_requested(void) ++{ ++ int r = vmstop_requested; ++ vmstop_requested = 0; ++ return r; ++} ++ ++void qemu_register_reset(QEMUResetHandler *func, void *opaque) ++{ ++ QEMUResetEntry *re = qemu_mallocz(sizeof(QEMUResetEntry)); ++ ++ re->func = func; ++ re->opaque = opaque; ++ QTAILQ_INSERT_TAIL(&reset_handlers, re, entry); ++} ++ ++void qemu_unregister_reset(QEMUResetHandler *func, void *opaque) ++{ ++ QEMUResetEntry *re; ++ ++ QTAILQ_FOREACH(re, &reset_handlers, entry) { ++ if (re->func == func && re->opaque == opaque) { ++ QTAILQ_REMOVE(&reset_handlers, re, entry); ++ qemu_free(re); ++ return; ++ } ++ } ++} ++ ++void qemu_system_reset(void) ++{ ++ QEMUResetEntry *re, *nre; ++ ++ /* reset all devices */ ++ QTAILQ_FOREACH_SAFE(re, &reset_handlers, entry, nre) { ++ re->func(re->opaque); ++ } ++ monitor_protocol_event(QEVENT_RESET, NULL); ++ cpu_synchronize_all_post_reset(); ++} ++ ++void qemu_system_reset_request(void) ++{ ++ if (no_reboot) { ++ shutdown_requested = 1; ++ } else { ++ reset_requested = 1; ++ } ++ if (cpu_single_env) { ++ cpu_single_env->stopped = 1; ++ cpu_exit(cpu_single_env); ++ } ++ qemu_notify_event(); ++} ++ ++void qemu_system_shutdown_request(void) ++{ ++ shutdown_requested = 1; ++ qemu_notify_event(); ++} ++ ++void qemu_system_powerdown_request(void) ++{ ++ powerdown_requested = 1; ++ qemu_notify_event(); ++} ++ ++void main_loop_wait(int nonblocking) ++{ ++ IOHandlerRecord *ioh; ++ fd_set rfds, wfds, xfds; ++ int ret, nfds; ++ struct timeval tv; ++ int timeout; ++ ++ if (nonblocking) ++ timeout = 0; ++ else { ++ timeout = qemu_calculate_timeout(); ++ qemu_bh_update_timeout(&timeout); ++ } ++ ++ os_host_main_loop_wait(&timeout); ++ ++ /* poll any events */ ++ /* XXX: separate device handlers from system ones */ ++ nfds = -1; ++ FD_ZERO(&rfds); ++ FD_ZERO(&wfds); ++ FD_ZERO(&xfds); ++ QLIST_FOREACH(ioh, &io_handlers, next) { ++ if (ioh->deleted) ++ continue; ++ if (ioh->fd_read && ++ (!ioh->fd_read_poll || ++ ioh->fd_read_poll(ioh->opaque) != 0)) { ++ FD_SET(ioh->fd, &rfds); ++ if (ioh->fd > nfds) ++ nfds = ioh->fd; ++ } ++ if (ioh->fd_write) { ++ FD_SET(ioh->fd, &wfds); ++ if (ioh->fd > nfds) ++ nfds = ioh->fd; ++ } ++ } ++ ++ tv.tv_sec = timeout / 1000; ++ tv.tv_usec = (timeout % 1000) * 1000; ++ ++ slirp_select_fill(&nfds, &rfds, &wfds, &xfds); ++ ++ qemu_mutex_unlock_iothread(); ++ ret = select(nfds + 1, &rfds, &wfds, &xfds, &tv); ++ qemu_mutex_lock_iothread(); ++ if (ret > 0) { ++ IOHandlerRecord *pioh; ++ ++ QLIST_FOREACH_SAFE(ioh, &io_handlers, next, pioh) { ++ if (ioh->deleted) { ++ QLIST_REMOVE(ioh, next); ++ qemu_free(ioh); ++ continue; ++ } ++ if (ioh->fd_read && FD_ISSET(ioh->fd, &rfds)) { ++ ioh->fd_read(ioh->opaque); ++ if (!(ioh->fd_read_poll && ioh->fd_read_poll(ioh->opaque))) ++ FD_CLR(ioh->fd, &rfds); ++ } ++ if (ioh->fd_write && FD_ISSET(ioh->fd, &wfds)) { ++ ioh->fd_write(ioh->opaque); ++ } ++ } ++ } ++ ++ slirp_select_poll(&rfds, &wfds, &xfds, (ret < 0)); ++ ++ qemu_run_all_timers(); ++ ++ /* Check bottom-halves last in case any of the earlier events triggered ++ them. */ ++ qemu_bh_poll(); ++ ++} ++ ++static int vm_can_run(void) ++{ ++ if (powerdown_requested) ++ return 0; ++ if (reset_requested) ++ return 0; ++ if (shutdown_requested) ++ return 0; ++ if (debug_requested) ++ return 0; ++ return 1; ++} ++ ++qemu_irq qemu_system_powerdown; ++ ++static void main_loop(void) ++{ ++ int r; ++ ++ if (kvm_enabled()) { ++ kvm_main_loop(); ++ cpu_disable_ticks(); ++ return; ++ } ++ ++ qemu_main_loop_start(); ++ ++ for (;;) { ++ do { ++ bool nonblocking = false; ++#ifdef CONFIG_PROFILER ++ int64_t ti; ++#endif ++#ifndef CONFIG_IOTHREAD ++ nonblocking = cpu_exec_all(); ++#endif ++#ifdef CONFIG_PROFILER ++ ti = profile_getclock(); ++#endif ++ main_loop_wait(nonblocking); ++#ifdef CONFIG_PROFILER ++ dev_time += profile_getclock() - ti; ++#endif ++ } while (vm_can_run()); ++ ++ if ((r = qemu_debug_requested())) { ++ vm_stop(r); ++ } ++ if (qemu_shutdown_requested()) { ++ monitor_protocol_event(QEVENT_SHUTDOWN, NULL); ++ if (no_shutdown) { ++ vm_stop(0); ++ no_shutdown = 0; ++ } else ++ break; ++ } ++ if (qemu_reset_requested()) { ++ pause_all_vcpus(); ++ qemu_system_reset(); ++ resume_all_vcpus(); ++ } ++ if (qemu_powerdown_requested()) { ++ monitor_protocol_event(QEVENT_POWERDOWN, NULL); ++ qemu_irq_raise(qemu_system_powerdown); ++ } ++ if ((r = qemu_vmstop_requested())) { ++ vm_stop(r); ++ } ++ } ++ bdrv_close_all(); ++ pause_all_vcpus(); ++} ++ ++static void version(void) ++{ ++ printf("QEMU emulator version " QEMU_VERSION QEMU_PKGVERSION ", Copyright (c) 2003-2008 Fabrice Bellard\n"); ++} ++ ++static void help(int exitcode) ++{ ++ const char *options_help = ++#define DEF(option, opt_arg, opt_enum, opt_help, arch_mask) \ ++ opt_help ++#define DEFHEADING(text) stringify(text) "\n" ++#include "qemu-options.def" ++#undef DEF ++#undef DEFHEADING ++#undef GEN_DOCS ++ ; ++ version(); ++ printf("usage: %s [options] [disk_image]\n" ++ "\n" ++ "'disk_image' is a raw hard disk image for IDE hard disk 0\n" ++ "\n" ++ "%s\n" ++ "During emulation, the following keys are useful:\n" ++ "ctrl-alt-f toggle full screen\n" ++ "ctrl-alt-n switch to virtual console 'n'\n" ++ "ctrl-alt toggle mouse and keyboard grab\n" ++ "\n" ++ "When using -nographic, press 'ctrl-a h' to get some help.\n", ++ "qemu", ++ options_help); ++ exit(exitcode); ++} ++ ++#define HAS_ARG 0x0001 ++ ++typedef struct QEMUOption { ++ const char *name; ++ int flags; ++ int index; ++ uint32_t arch_mask; ++} QEMUOption; ++ ++static const QEMUOption qemu_options[] = { ++ { "h", 0, QEMU_OPTION_h, QEMU_ARCH_ALL }, ++#define DEF(option, opt_arg, opt_enum, opt_help, arch_mask) \ ++ { option, opt_arg, opt_enum, arch_mask }, ++#define DEFHEADING(text) ++#include "qemu-options.def" ++#undef DEF ++#undef DEFHEADING ++#undef GEN_DOCS ++ { NULL }, ++}; ++static void select_vgahw (const char *p) ++{ ++ const char *opts; ++ ++ default_vga = 0; ++ vga_interface_type = VGA_NONE; ++ if (strstart(p, "std", &opts)) { ++ vga_interface_type = VGA_STD; ++ } else if (strstart(p, "cirrus", &opts)) { ++ vga_interface_type = VGA_CIRRUS; ++ } else if (strstart(p, "vmware", &opts)) { ++ vga_interface_type = VGA_VMWARE; ++ } else if (strstart(p, "xenfb", &opts)) { ++ vga_interface_type = VGA_XENFB; ++ } else if (!strstart(p, "none", &opts)) { ++ invalid_vga: ++ fprintf(stderr, "Unknown vga type: %s\n", p); ++ exit(1); ++ } ++ while (*opts) { ++ const char *nextopt; ++ ++ if (strstart(opts, ",retrace=", &nextopt)) { ++ opts = nextopt; ++ if (strstart(opts, "dumb", &nextopt)) ++ vga_retrace_method = VGA_RETRACE_DUMB; ++ else if (strstart(opts, "precise", &nextopt)) ++ vga_retrace_method = VGA_RETRACE_PRECISE; ++ else goto invalid_vga; ++ } else goto invalid_vga; ++ opts = nextopt; ++ } ++} ++ ++static int balloon_parse(const char *arg) ++{ ++ QemuOpts *opts; ++ ++ if (strcmp(arg, "none") == 0) { ++ return 0; ++ } ++ ++ if (!strncmp(arg, "virtio", 6)) { ++ if (arg[6] == ',') { ++ /* have params -> parse them */ ++ opts = qemu_opts_parse(&qemu_device_opts, arg+7, 0); ++ if (!opts) ++ return -1; ++ } else { ++ /* create empty opts */ ++ opts = qemu_opts_create(&qemu_device_opts, NULL, 0); ++ } ++ qemu_opt_set(opts, "driver", "virtio-balloon-pci"); ++ return 0; ++ } ++ ++ return -1; ++} ++ ++char *qemu_find_file(int type, const char *name) ++{ ++ int len; ++ const char *subdir; ++ char *buf; ++ ++ /* If name contains path separators then try it as a straight path. */ ++ if ((strchr(name, '/') || strchr(name, '\\')) ++ && access(name, R_OK) == 0) { ++ return qemu_strdup(name); ++ } ++ switch (type) { ++ case QEMU_FILE_TYPE_BIOS: ++ subdir = ""; ++ break; ++ case QEMU_FILE_TYPE_KEYMAP: ++ subdir = "keymaps/"; ++ break; ++ default: ++ abort(); ++ } ++ len = strlen(data_dir) + strlen(name) + strlen(subdir) + 2; ++ buf = qemu_mallocz(len); ++ snprintf(buf, len, "%s/%s%s", data_dir, subdir, name); ++ if (access(buf, R_OK)) { ++ qemu_free(buf); ++ return NULL; ++ } ++ return buf; ++} ++ ++static int device_help_func(QemuOpts *opts, void *opaque) ++{ ++ return qdev_device_help(opts); ++} ++ ++static int device_init_func(QemuOpts *opts, void *opaque) ++{ ++ DeviceState *dev; ++ ++ dev = qdev_device_add(opts); ++ if (!dev) ++ return -1; ++ return 0; ++} ++ ++static int chardev_init_func(QemuOpts *opts, void *opaque) ++{ ++ CharDriverState *chr; ++ ++ chr = qemu_chr_open_opts(opts, NULL); ++ if (!chr) ++ return -1; ++ return 0; ++} ++ ++#ifdef CONFIG_VIRTFS ++static int fsdev_init_func(QemuOpts *opts, void *opaque) ++{ ++ int ret; ++ ret = qemu_fsdev_add(opts); ++ ++ return ret; ++} ++#endif ++ ++static int mon_init_func(QemuOpts *opts, void *opaque) ++{ ++ CharDriverState *chr; ++ const char *chardev; ++ const char *mode; ++ int flags; ++ ++ mode = qemu_opt_get(opts, "mode"); ++ if (mode == NULL) { ++ mode = "readline"; ++ } ++ if (strcmp(mode, "readline") == 0) { ++ flags = MONITOR_USE_READLINE; ++ } else if (strcmp(mode, "control") == 0) { ++ flags = MONITOR_USE_CONTROL; ++ } else { ++ fprintf(stderr, "unknown monitor mode \"%s\"\n", mode); ++ exit(1); ++ } ++ ++ if (qemu_opt_get_bool(opts, "default", 0)) ++ flags |= MONITOR_IS_DEFAULT; ++ ++ chardev = qemu_opt_get(opts, "chardev"); ++ chr = qemu_chr_find(chardev); ++ if (chr == NULL) { ++ fprintf(stderr, "chardev \"%s\" not found\n", chardev); ++ exit(1); ++ } ++ ++ monitor_init(chr, flags); ++ return 0; ++} ++ ++static void monitor_parse(const char *optarg, const char *mode) ++{ ++ static int monitor_device_index = 0; ++ QemuOpts *opts; ++ const char *p; ++ char label[32]; ++ int def = 0; ++ ++ if (strstart(optarg, "chardev:", &p)) { ++ snprintf(label, sizeof(label), "%s", p); ++ } else { ++ snprintf(label, sizeof(label), "compat_monitor%d", ++ monitor_device_index); ++ if (monitor_device_index == 0) { ++ def = 1; ++ } ++ opts = qemu_chr_parse_compat(label, optarg); ++ if (!opts) { ++ fprintf(stderr, "parse error: %s\n", optarg); ++ exit(1); ++ } ++ } ++ ++ opts = qemu_opts_create(&qemu_mon_opts, label, 1); ++ if (!opts) { ++ fprintf(stderr, "duplicate chardev: %s\n", label); ++ exit(1); ++ } ++ qemu_opt_set(opts, "mode", mode); ++ qemu_opt_set(opts, "chardev", label); ++ if (def) ++ qemu_opt_set(opts, "default", "on"); ++ monitor_device_index++; ++} ++ ++struct device_config { ++ enum { ++ DEV_USB, /* -usbdevice */ ++ DEV_BT, /* -bt */ ++ DEV_SERIAL, /* -serial */ ++ DEV_PARALLEL, /* -parallel */ ++ DEV_VIRTCON, /* -virtioconsole */ ++ DEV_DEBUGCON, /* -debugcon */ ++ } type; ++ const char *cmdline; ++ QTAILQ_ENTRY(device_config) next; ++}; ++QTAILQ_HEAD(, device_config) device_configs = QTAILQ_HEAD_INITIALIZER(device_configs); ++ ++static void add_device_config(int type, const char *cmdline) ++{ ++ struct device_config *conf; ++ ++ conf = qemu_mallocz(sizeof(*conf)); ++ conf->type = type; ++ conf->cmdline = cmdline; ++ QTAILQ_INSERT_TAIL(&device_configs, conf, next); ++} ++ ++static int foreach_device_config(int type, int (*func)(const char *cmdline)) ++{ ++ struct device_config *conf; ++ int rc; ++ ++ QTAILQ_FOREACH(conf, &device_configs, next) { ++ if (conf->type != type) ++ continue; ++ rc = func(conf->cmdline); ++ if (0 != rc) ++ return rc; ++ } ++ return 0; ++} ++ ++static int serial_parse(const char *devname) ++{ ++ static int index = 0; ++ char label[32]; ++ ++ if (strcmp(devname, "none") == 0) ++ return 0; ++ if (index == MAX_SERIAL_PORTS) { ++ fprintf(stderr, "qemu: too many serial ports\n"); ++ exit(1); ++ } ++ snprintf(label, sizeof(label), "serial%d", index); ++ serial_hds[index] = qemu_chr_open(label, devname, NULL); ++ if (!serial_hds[index]) { ++ fprintf(stderr, "qemu: could not open serial device '%s': %s\n", ++ devname, strerror(errno)); ++ return -1; ++ } ++ index++; ++ return 0; ++} ++ ++static int parallel_parse(const char *devname) ++{ ++ static int index = 0; ++ char label[32]; ++ ++ if (strcmp(devname, "none") == 0) ++ return 0; ++ if (index == MAX_PARALLEL_PORTS) { ++ fprintf(stderr, "qemu: too many parallel ports\n"); ++ exit(1); ++ } ++ snprintf(label, sizeof(label), "parallel%d", index); ++ parallel_hds[index] = qemu_chr_open(label, devname, NULL); ++ if (!parallel_hds[index]) { ++ fprintf(stderr, "qemu: could not open parallel device '%s': %s\n", ++ devname, strerror(errno)); ++ return -1; ++ } ++ index++; ++ return 0; ++} ++ ++static int virtcon_parse(const char *devname) ++{ ++ static int index = 0; ++ char label[32]; ++ QemuOpts *bus_opts, *dev_opts; ++ ++ if (strcmp(devname, "none") == 0) ++ return 0; ++ if (index == MAX_VIRTIO_CONSOLES) { ++ fprintf(stderr, "qemu: too many virtio consoles\n"); ++ exit(1); ++ } ++ ++ bus_opts = qemu_opts_create(&qemu_device_opts, NULL, 0); ++ qemu_opt_set(bus_opts, "driver", "virtio-serial"); ++ ++ dev_opts = qemu_opts_create(&qemu_device_opts, NULL, 0); ++ qemu_opt_set(dev_opts, "driver", "virtconsole"); ++ ++ snprintf(label, sizeof(label), "virtcon%d", index); ++ virtcon_hds[index] = qemu_chr_open(label, devname, NULL); ++ if (!virtcon_hds[index]) { ++ fprintf(stderr, "qemu: could not open virtio console '%s': %s\n", ++ devname, strerror(errno)); ++ return -1; ++ } ++ qemu_opt_set(dev_opts, "chardev", label); ++ ++ index++; ++ return 0; ++} ++ ++static int debugcon_parse(const char *devname) ++{ ++ QemuOpts *opts; ++ ++ if (!qemu_chr_open("debugcon", devname, NULL)) { ++ exit(1); ++ } ++ opts = qemu_opts_create(&qemu_device_opts, "debugcon", 1); ++ if (!opts) { ++ fprintf(stderr, "qemu: already have a debugcon device\n"); ++ exit(1); ++ } ++ qemu_opt_set(opts, "driver", "isa-debugcon"); ++ qemu_opt_set(opts, "chardev", "debugcon"); ++ return 0; ++} ++ ++void qemu_add_exit_notifier(Notifier *notify) ++{ ++ notifier_list_add(&exit_notifiers, notify); ++} ++ ++void qemu_remove_exit_notifier(Notifier *notify) ++{ ++ notifier_list_remove(&exit_notifiers, notify); ++} ++ ++static void qemu_run_exit_notifiers(void) ++{ ++ notifier_list_notify(&exit_notifiers); ++} ++ ++static const QEMUOption *lookup_opt(int argc, char **argv, ++ const char **poptarg, int *poptind) ++{ ++ const QEMUOption *popt; ++ int optind = *poptind; ++ char *r = argv[optind]; ++ const char *optarg; ++ ++ loc_set_cmdline(argv, optind, 1); ++ optind++; ++ /* Treat --foo the same as -foo. */ ++ if (r[1] == '-') ++ r++; ++ popt = qemu_options; ++ for(;;) { ++ if (!popt->name) { ++ error_report("invalid option"); ++ exit(1); ++ } ++ if (!strcmp(popt->name, r + 1)) ++ break; ++ popt++; ++ } ++ if (popt->flags & HAS_ARG) { ++ if (optind >= argc) { ++ error_report("requires an argument"); ++ exit(1); ++ } ++ optarg = argv[optind++]; ++ loc_set_cmdline(argv, optind - 2, 2); ++ } else { ++ optarg = NULL; ++ } ++ ++ *poptarg = optarg; ++ *poptind = optind; ++ ++ return popt; ++} ++ ++int main(int argc, char **argv, char **envp) ++{ ++ const char *gdbstub_dev = NULL; ++ int i; ++ int snapshot, linux_boot; ++ const char *icount_option = NULL; ++ const char *initrd_filename; ++ const char *kernel_filename, *kernel_cmdline; ++ char boot_devices[33] = "cad"; /* default to HD->floppy->CD-ROM */ ++ DisplayState *ds; ++ DisplayChangeListener *dcl; ++ int cyls, heads, secs, translation; ++ QemuOpts *hda_opts = NULL, *opts; ++ int optind; ++ const char *optarg; ++ const char *loadvm = NULL; ++ QEMUMachine *machine; ++ const char *cpu_model; ++ int tb_size; ++ const char *pid_file = NULL; ++ const char *incoming = NULL; ++ int show_vnc_port = 0; ++ int defconfig = 1; ++ ++ atexit(qemu_run_exit_notifiers); ++ error_set_progname(argv[0]); ++ ++ init_clocks(); ++ ++ qemu_cache_utils_init(envp); ++ ++ QLIST_INIT (&vm_change_state_head); ++ os_setup_early_signal_handling(); ++ ++ module_call_init(MODULE_INIT_MACHINE); ++ machine = find_default_machine(); ++ cpu_model = NULL; ++ initrd_filename = NULL; ++ ram_size = 0; ++ snapshot = 0; ++ kernel_filename = NULL; ++ kernel_cmdline = ""; ++ cyls = heads = secs = 0; ++ translation = BIOS_ATA_TRANSLATION_AUTO; ++ ++ for (i = 0; i < MAX_NODES; i++) { ++ node_mem[i] = 0; ++ node_cpumask[i] = 0; ++ } ++ ++ assigned_devices_index = 0; ++ ++ nb_numa_nodes = 0; ++ nb_nics = 0; ++ ++ tb_size = 0; ++ autostart= 1; ++ ++ /* first pass of option parsing */ ++ optind = 1; ++ while (optind < argc) { ++ if (argv[optind][0] != '-') { ++ /* disk image */ ++ optind++; ++ continue; ++ } else { ++ const QEMUOption *popt; ++ ++ popt = lookup_opt(argc, argv, &optarg, &optind); ++ switch (popt->index) { ++ case QEMU_OPTION_nodefconfig: ++ defconfig=0; ++ break; ++ } ++ } ++ } ++ ++ if (defconfig) { ++ int ret; ++ ++ ret = qemu_read_config_file(CONFIG_QEMU_CONFDIR "/qemu.conf"); ++ if (ret < 0 && ret != -ENOENT) { ++ exit(1); ++ } ++ ++ ret = qemu_read_config_file(arch_config_name); ++ if (ret < 0 && ret != -ENOENT) { ++ exit(1); ++ } ++ } ++ cpudef_init(); ++ ++ /* second pass of option parsing */ ++ optind = 1; ++ for(;;) { ++ if (optind >= argc) ++ break; ++ if (argv[optind][0] != '-') { ++ hda_opts = drive_add(argv[optind++], HD_ALIAS, 0); ++ } else { ++ const QEMUOption *popt; ++ ++ popt = lookup_opt(argc, argv, &optarg, &optind); ++ if (!(popt->arch_mask & arch_type)) { ++ printf("Option %s not supported for this target\n", popt->name); ++ exit(1); ++ } ++ switch(popt->index) { ++ case QEMU_OPTION_M: ++ machine = find_machine(optarg); ++ if (!machine) { ++ QEMUMachine *m; ++ printf("Supported machines are:\n"); ++ for(m = first_machine; m != NULL; m = m->next) { ++ if (m->alias) ++ printf("%-10s %s (alias of %s)\n", ++ m->alias, m->desc, m->name); ++ printf("%-10s %s%s\n", ++ m->name, m->desc, ++ m->is_default ? " (default)" : ""); ++ } ++ exit(*optarg != '?'); ++ } ++ break; ++ case QEMU_OPTION_cpu: ++ /* hw initialization will check this */ ++ if (*optarg == '?') { ++ list_cpus(stdout, &fprintf, optarg); ++ exit(0); ++ } else { ++ cpu_model = optarg; ++ } ++ break; ++ case QEMU_OPTION_initrd: ++ initrd_filename = optarg; ++ break; ++ case QEMU_OPTION_hda: ++ if (cyls == 0) ++ hda_opts = drive_add(optarg, HD_ALIAS, 0); ++ else ++ hda_opts = drive_add(optarg, HD_ALIAS ++ ",cyls=%d,heads=%d,secs=%d%s", ++ 0, cyls, heads, secs, ++ translation == BIOS_ATA_TRANSLATION_LBA ? ++ ",trans=lba" : ++ translation == BIOS_ATA_TRANSLATION_NONE ? ++ ",trans=none" : ""); ++ break; ++ case QEMU_OPTION_hdb: ++ case QEMU_OPTION_hdc: ++ case QEMU_OPTION_hdd: ++ drive_add(optarg, HD_ALIAS, popt->index - QEMU_OPTION_hda); ++ break; ++ case QEMU_OPTION_drive: ++ drive_add(NULL, "%s", optarg); ++ break; ++ case QEMU_OPTION_set: ++ if (qemu_set_option(optarg) != 0) ++ exit(1); ++ break; ++ case QEMU_OPTION_global: ++ if (qemu_global_option(optarg) != 0) ++ exit(1); ++ break; ++ case QEMU_OPTION_mtdblock: ++ drive_add(optarg, MTD_ALIAS); ++ break; ++ case QEMU_OPTION_sd: ++ drive_add(optarg, SD_ALIAS); ++ break; ++ case QEMU_OPTION_pflash: ++ drive_add(optarg, PFLASH_ALIAS); ++ break; ++ case QEMU_OPTION_snapshot: ++ snapshot = 1; ++ break; ++ case QEMU_OPTION_hdachs: ++ { ++ const char *p; ++ p = optarg; ++ cyls = strtol(p, (char **)&p, 0); ++ if (cyls < 1 || cyls > 16383) ++ goto chs_fail; ++ if (*p != ',') ++ goto chs_fail; ++ p++; ++ heads = strtol(p, (char **)&p, 0); ++ if (heads < 1 || heads > 16) ++ goto chs_fail; ++ if (*p != ',') ++ goto chs_fail; ++ p++; ++ secs = strtol(p, (char **)&p, 0); ++ if (secs < 1 || secs > 63) ++ goto chs_fail; ++ if (*p == ',') { ++ p++; ++ if (!strcmp(p, "none")) ++ translation = BIOS_ATA_TRANSLATION_NONE; ++ else if (!strcmp(p, "lba")) ++ translation = BIOS_ATA_TRANSLATION_LBA; ++ else if (!strcmp(p, "auto")) ++ translation = BIOS_ATA_TRANSLATION_AUTO; ++ else ++ goto chs_fail; ++ } else if (*p != '\0') { ++ chs_fail: ++ fprintf(stderr, "qemu: invalid physical CHS format\n"); ++ exit(1); ++ } ++ if (hda_opts != NULL) { ++ char num[16]; ++ snprintf(num, sizeof(num), "%d", cyls); ++ qemu_opt_set(hda_opts, "cyls", num); ++ snprintf(num, sizeof(num), "%d", heads); ++ qemu_opt_set(hda_opts, "heads", num); ++ snprintf(num, sizeof(num), "%d", secs); ++ qemu_opt_set(hda_opts, "secs", num); ++ if (translation == BIOS_ATA_TRANSLATION_LBA) ++ qemu_opt_set(hda_opts, "trans", "lba"); ++ if (translation == BIOS_ATA_TRANSLATION_NONE) ++ qemu_opt_set(hda_opts, "trans", "none"); ++ } ++ } ++ break; ++ case QEMU_OPTION_numa: ++ if (nb_numa_nodes >= MAX_NODES) { ++ fprintf(stderr, "qemu: too many NUMA nodes\n"); ++ exit(1); ++ } ++ numa_add(optarg); ++ break; ++ case QEMU_OPTION_nographic: ++ display_type = DT_NOGRAPHIC; ++ break; ++#ifdef CONFIG_CURSES ++ case QEMU_OPTION_curses: ++ display_type = DT_CURSES; ++ break; ++#endif ++ case QEMU_OPTION_portrait: ++ graphic_rotate = 1; ++ break; ++ case QEMU_OPTION_kernel: ++ kernel_filename = optarg; ++ break; ++ case QEMU_OPTION_append: ++ kernel_cmdline = optarg; ++ break; ++ case QEMU_OPTION_cdrom: ++ drive_add(optarg, CDROM_ALIAS); ++ break; ++ case QEMU_OPTION_boot: ++ { ++ static const char * const params[] = { ++ "order", "once", "menu", NULL ++ }; ++ char buf[sizeof(boot_devices)]; ++ char *standard_boot_devices; ++ int legacy = 0; ++ ++ if (!strchr(optarg, '=')) { ++ legacy = 1; ++ pstrcpy(buf, sizeof(buf), optarg); ++ } else if (check_params(buf, sizeof(buf), params, optarg) < 0) { ++ fprintf(stderr, ++ "qemu: unknown boot parameter '%s' in '%s'\n", ++ buf, optarg); ++ exit(1); ++ } ++ ++ if (legacy || ++ get_param_value(buf, sizeof(buf), "order", optarg)) { ++ validate_bootdevices(buf); ++ pstrcpy(boot_devices, sizeof(boot_devices), buf); ++ } ++ if (!legacy) { ++ if (get_param_value(buf, sizeof(buf), ++ "once", optarg)) { ++ validate_bootdevices(buf); ++ standard_boot_devices = qemu_strdup(boot_devices); ++ pstrcpy(boot_devices, sizeof(boot_devices), buf); ++ qemu_register_reset(restore_boot_devices, ++ standard_boot_devices); ++ } ++ if (get_param_value(buf, sizeof(buf), ++ "menu", optarg)) { ++ if (!strcmp(buf, "on")) { ++ boot_menu = 1; ++ } else if (!strcmp(buf, "off")) { ++ boot_menu = 0; ++ } else { ++ fprintf(stderr, ++ "qemu: invalid option value '%s'\n", ++ buf); ++ exit(1); ++ } ++ } ++ } ++ } ++ break; ++ case QEMU_OPTION_fda: ++ case QEMU_OPTION_fdb: ++ drive_add(optarg, FD_ALIAS, popt->index - QEMU_OPTION_fda); ++ break; ++ case QEMU_OPTION_no_fd_bootchk: ++ fd_bootchk = 0; ++ break; ++ case QEMU_OPTION_netdev: ++ if (net_client_parse(&qemu_netdev_opts, optarg) == -1) { ++ exit(1); ++ } ++ break; ++ case QEMU_OPTION_net: ++ if (net_client_parse(&qemu_net_opts, optarg) == -1) { ++ exit(1); ++ } ++ break; ++#ifdef CONFIG_SLIRP ++ case QEMU_OPTION_tftp: ++ legacy_tftp_prefix = optarg; ++ break; ++ case QEMU_OPTION_bootp: ++ legacy_bootp_filename = optarg; ++ break; ++ case QEMU_OPTION_redir: ++ if (net_slirp_redir(optarg) < 0) ++ exit(1); ++ break; ++#endif ++ case QEMU_OPTION_bt: ++ add_device_config(DEV_BT, optarg); ++ break; ++ case QEMU_OPTION_audio_help: ++ if (!(audio_available())) { ++ printf("Option %s not supported for this target\n", popt->name); ++ exit(1); ++ } ++ AUD_help (); ++ exit (0); ++ break; ++ case QEMU_OPTION_soundhw: ++ if (!(audio_available())) { ++ printf("Option %s not supported for this target\n", popt->name); ++ exit(1); ++ } ++ select_soundhw (optarg); ++ break; ++ case QEMU_OPTION_h: ++ help(0); ++ break; ++ case QEMU_OPTION_version: ++ version(); ++ exit(0); ++ break; ++ case QEMU_OPTION_m: { ++ uint64_t value; ++ char *ptr; ++ ++ value = strtoul(optarg, &ptr, 10); ++ switch (*ptr) { ++ case 0: case 'M': case 'm': ++ value <<= 20; ++ break; ++ case 'G': case 'g': ++ value <<= 30; ++ break; ++ default: ++ fprintf(stderr, "qemu: invalid ram size: %s\n", optarg); ++ exit(1); ++ } ++ ++ /* On 32-bit hosts, QEMU is limited by virtual address space */ ++ if (value > (2047 << 20) && HOST_LONG_BITS == 32) { ++ fprintf(stderr, "qemu: at most 2047 MB RAM can be simulated\n"); ++ exit(1); ++ } ++ if (value != (uint64_t)(ram_addr_t)value) { ++ fprintf(stderr, "qemu: ram size too large\n"); ++ exit(1); ++ } ++ ram_size = value; ++ break; ++ } ++ case QEMU_OPTION_mempath: ++ mem_path = optarg; ++ break; ++#ifdef MAP_POPULATE ++ case QEMU_OPTION_mem_prealloc: ++ mem_prealloc = 1; ++ break; ++#endif ++ case QEMU_OPTION_d: ++ set_cpu_log(optarg); ++ break; ++ case QEMU_OPTION_s: ++ gdbstub_dev = "tcp::" DEFAULT_GDBSTUB_PORT; ++ break; ++ case QEMU_OPTION_gdb: ++ gdbstub_dev = optarg; ++ break; ++ case QEMU_OPTION_L: ++ data_dir = optarg; ++ break; ++ case QEMU_OPTION_bios: ++ bios_name = optarg; ++ break; ++ case QEMU_OPTION_singlestep: ++ singlestep = 1; ++ break; ++ case QEMU_OPTION_S: ++ autostart = 0; ++ break; ++ case QEMU_OPTION_k: ++ keyboard_layout = optarg; ++ break; ++ case QEMU_OPTION_localtime: ++ rtc_utc = 0; ++ break; ++ case QEMU_OPTION_vga: ++ select_vgahw (optarg); ++ break; ++ case QEMU_OPTION_g: ++ { ++ const char *p; ++ int w, h, depth; ++ p = optarg; ++ w = strtol(p, (char **)&p, 10); ++ if (w <= 0) { ++ graphic_error: ++ fprintf(stderr, "qemu: invalid resolution or depth\n"); ++ exit(1); ++ } ++ if (*p != 'x') ++ goto graphic_error; ++ p++; ++ h = strtol(p, (char **)&p, 10); ++ if (h <= 0) ++ goto graphic_error; ++ if (*p == 'x') { ++ p++; ++ depth = strtol(p, (char **)&p, 10); ++ if (depth != 8 && depth != 15 && depth != 16 && ++ depth != 24 && depth != 32) ++ goto graphic_error; ++ } else if (*p == '\0') { ++ depth = graphic_depth; ++ } else { ++ goto graphic_error; ++ } ++ ++ graphic_width = w; ++ graphic_height = h; ++ graphic_depth = depth; ++ } ++ break; ++ case QEMU_OPTION_echr: ++ { ++ char *r; ++ term_escape_char = strtol(optarg, &r, 0); ++ if (r == optarg) ++ printf("Bad argument to echr\n"); ++ break; ++ } ++ case QEMU_OPTION_monitor: ++ monitor_parse(optarg, "readline"); ++ default_monitor = 0; ++ break; ++ case QEMU_OPTION_qmp: ++ monitor_parse(optarg, "control"); ++ default_monitor = 0; ++ break; ++ case QEMU_OPTION_mon: ++ opts = qemu_opts_parse(&qemu_mon_opts, optarg, 1); ++ if (!opts) { ++ exit(1); ++ } ++ default_monitor = 0; ++ break; ++ case QEMU_OPTION_chardev: ++ opts = qemu_opts_parse(&qemu_chardev_opts, optarg, 1); ++ if (!opts) { ++ exit(1); ++ } ++ break; ++#ifdef CONFIG_VIRTFS ++ case QEMU_OPTION_fsdev: ++ opts = qemu_opts_parse(&qemu_fsdev_opts, optarg, 1); ++ if (!opts) { ++ fprintf(stderr, "parse error: %s\n", optarg); ++ exit(1); ++ } ++ break; ++ case QEMU_OPTION_virtfs: { ++ char *arg_fsdev = NULL; ++ char *arg_9p = NULL; ++ int len = 0; ++ ++ opts = qemu_opts_parse(&qemu_virtfs_opts, optarg, 1); ++ if (!opts) { ++ fprintf(stderr, "parse error: %s\n", optarg); ++ exit(1); ++ } ++ ++ if (qemu_opt_get(opts, "fstype") == NULL || ++ qemu_opt_get(opts, "mount_tag") == NULL || ++ qemu_opt_get(opts, "path") == NULL || ++ qemu_opt_get(opts, "security_model") == NULL) { ++ fprintf(stderr, "Usage: -virtfs fstype,path=/share_path/," ++ "security_model=[mapped|passthrough]," ++ "mnt_tag=tag.\n"); ++ exit(1); ++ } ++ ++ len = strlen(",id=,path=,security_model="); ++ len += strlen(qemu_opt_get(opts, "fstype")); ++ len += strlen(qemu_opt_get(opts, "mount_tag")); ++ len += strlen(qemu_opt_get(opts, "path")); ++ len += strlen(qemu_opt_get(opts, "security_model")); ++ arg_fsdev = qemu_malloc((len + 1) * sizeof(*arg_fsdev)); ++ ++ if (!arg_fsdev) { ++ fprintf(stderr, "No memory to parse -fsdev for %s\n", ++ optarg); ++ exit(1); ++ } ++ ++ sprintf(arg_fsdev, "%s,id=%s,path=%s,security_model=%s", ++ qemu_opt_get(opts, "fstype"), ++ qemu_opt_get(opts, "mount_tag"), ++ qemu_opt_get(opts, "path"), ++ qemu_opt_get(opts, "security_model")); ++ ++ len = strlen("virtio-9p-pci,fsdev=,mount_tag="); ++ len += 2*strlen(qemu_opt_get(opts, "mount_tag")); ++ arg_9p = qemu_malloc((len + 1) * sizeof(*arg_9p)); ++ ++ if (!arg_9p) { ++ fprintf(stderr, "No memory to parse -device for %s\n", ++ optarg); ++ exit(1); ++ } ++ ++ sprintf(arg_9p, "virtio-9p-pci,fsdev=%s,mount_tag=%s", ++ qemu_opt_get(opts, "mount_tag"), ++ qemu_opt_get(opts, "mount_tag")); ++ ++ if (!qemu_opts_parse(&qemu_fsdev_opts, arg_fsdev, 1)) { ++ fprintf(stderr, "parse error [fsdev]: %s\n", optarg); ++ exit(1); ++ } ++ ++ if (!qemu_opts_parse(&qemu_device_opts, arg_9p, 1)) { ++ fprintf(stderr, "parse error [device]: %s\n", optarg); ++ exit(1); ++ } ++ ++ qemu_free(arg_fsdev); ++ qemu_free(arg_9p); ++ break; ++ } ++#endif ++ case QEMU_OPTION_serial: ++ add_device_config(DEV_SERIAL, optarg); ++ default_serial = 0; ++ if (strncmp(optarg, "mon:", 4) == 0) { ++ default_monitor = 0; ++ } ++ break; ++ case QEMU_OPTION_watchdog: ++ if (watchdog) { ++ fprintf(stderr, ++ "qemu: only one watchdog option may be given\n"); ++ return 1; ++ } ++ watchdog = optarg; ++ break; ++ case QEMU_OPTION_watchdog_action: ++ if (select_watchdog_action(optarg) == -1) { ++ fprintf(stderr, "Unknown -watchdog-action parameter\n"); ++ exit(1); ++ } ++ break; ++ case QEMU_OPTION_virtiocon: ++ add_device_config(DEV_VIRTCON, optarg); ++ default_virtcon = 0; ++ if (strncmp(optarg, "mon:", 4) == 0) { ++ default_monitor = 0; ++ } ++ break; ++ case QEMU_OPTION_parallel: ++ add_device_config(DEV_PARALLEL, optarg); ++ default_parallel = 0; ++ if (strncmp(optarg, "mon:", 4) == 0) { ++ default_monitor = 0; ++ } ++ break; ++ case QEMU_OPTION_debugcon: ++ add_device_config(DEV_DEBUGCON, optarg); ++ break; ++ case QEMU_OPTION_loadvm: ++ loadvm = optarg; ++ break; ++ case QEMU_OPTION_full_screen: ++ full_screen = 1; ++ break; ++#ifdef CONFIG_SDL ++ case QEMU_OPTION_no_frame: ++ no_frame = 1; ++ break; ++ case QEMU_OPTION_alt_grab: ++ alt_grab = 1; ++ break; ++ case QEMU_OPTION_ctrl_grab: ++ ctrl_grab = 1; ++ break; ++ case QEMU_OPTION_no_quit: ++ no_quit = 1; ++ break; ++ case QEMU_OPTION_sdl: ++ display_type = DT_SDL; ++ break; ++#endif ++ case QEMU_OPTION_pidfile: ++ pid_file = optarg; ++ break; ++ case QEMU_OPTION_win2k_hack: ++ win2k_install_hack = 1; ++ break; ++ case QEMU_OPTION_rtc_td_hack: ++ rtc_td_hack = 1; ++ break; ++ case QEMU_OPTION_acpitable: ++ do_acpitable_option(optarg); ++ break; ++ case QEMU_OPTION_smbios: ++ do_smbios_option(optarg); ++ break; ++#ifdef KVM_UPSTREAM ++ case QEMU_OPTION_enable_kvm: ++ kvm_allowed = 1; ++#endif ++ break; ++ case QEMU_OPTION_no_kvm: ++ kvm_allowed = 0; ++#ifdef CONFIG_NO_CPU_EMULATION ++ fprintf(stderr, "cpu emulation not configured\n"); ++ exit(1); ++#endif ++ break; ++#ifdef CONFIG_KVM ++ case QEMU_OPTION_no_kvm_irqchip: { ++ kvm_irqchip = 0; ++ kvm_pit = 0; ++ break; ++ } ++ case QEMU_OPTION_no_kvm_pit: { ++ kvm_pit = 0; ++ break; ++ } ++ case QEMU_OPTION_no_kvm_pit_reinjection: { ++ kvm_pit_reinject = 0; ++ break; ++ } ++ case QEMU_OPTION_enable_nesting: { ++ kvm_nested = 1; ++ break; ++ } ++#endif ++#if defined(TARGET_I386) || defined(TARGET_X86_64) || defined(TARGET_IA64) || defined(__linux__) ++ case QEMU_OPTION_pcidevice: ++ if (assigned_devices_index >= MAX_DEV_ASSIGN_CMDLINE) { ++ fprintf(stderr, "Too many assigned devices\n"); ++ exit(1); ++ } ++ assigned_devices[assigned_devices_index] = optarg; ++ assigned_devices_index++; ++ break; ++#endif ++ case QEMU_OPTION_usb: ++ usb_enabled = 1; ++ break; ++ case QEMU_OPTION_usbdevice: ++ usb_enabled = 1; ++ add_device_config(DEV_USB, optarg); ++ break; ++ case QEMU_OPTION_device: ++ if (!qemu_opts_parse(&qemu_device_opts, optarg, 1)) { ++ exit(1); ++ } ++ break; ++ case QEMU_OPTION_smp: ++ smp_parse(optarg); ++ if (smp_cpus < 1) { ++ fprintf(stderr, "Invalid number of CPUs\n"); ++ exit(1); ++ } ++ if (max_cpus < smp_cpus) { ++ fprintf(stderr, "maxcpus must be equal to or greater than " ++ "smp\n"); ++ exit(1); ++ } ++ if (max_cpus > 255) { ++ fprintf(stderr, "Unsupported number of maxcpus\n"); ++ exit(1); ++ } ++ break; ++ case QEMU_OPTION_vnc: ++ display_type = DT_VNC; ++ vnc_display = optarg; ++ break; ++ case QEMU_OPTION_no_acpi: ++ acpi_enabled = 0; ++ break; ++ case QEMU_OPTION_no_hpet: ++ no_hpet = 1; ++ break; ++ case QEMU_OPTION_balloon: ++ if (balloon_parse(optarg) < 0) { ++ fprintf(stderr, "Unknown -balloon argument %s\n", optarg); ++ exit(1); ++ } ++ break; ++ case QEMU_OPTION_no_reboot: ++ no_reboot = 1; ++ break; ++ case QEMU_OPTION_no_shutdown: ++ no_shutdown = 1; ++ break; ++ case QEMU_OPTION_show_cursor: ++ cursor_hide = 0; ++ break; ++ case QEMU_OPTION_uuid: ++ if(qemu_uuid_parse(optarg, qemu_uuid) < 0) { ++ fprintf(stderr, "Fail to parse UUID string." ++ " Wrong format.\n"); ++ exit(1); ++ } ++ break; ++ case QEMU_OPTION_option_rom: ++ if (nb_option_roms >= MAX_OPTION_ROMS) { ++ fprintf(stderr, "Too many option ROMs\n"); ++ exit(1); ++ } ++ option_rom[nb_option_roms] = optarg; ++ nb_option_roms++; ++ break; ++ case QEMU_OPTION_semihosting: ++ semihosting_enabled = 1; ++ break; ++ case QEMU_OPTION_tdf: ++ time_drift_fix = 1; ++ break; ++ case QEMU_OPTION_kvm_shadow_memory: ++ kvm_shadow_memory = (int64_t)atoi(optarg) * 1024 * 1024 / 4096; ++ break; ++ case QEMU_OPTION_name: ++ qemu_name = qemu_strdup(optarg); ++ { ++ char *p = strchr(qemu_name, ','); ++ if (p != NULL) { ++ *p++ = 0; ++ if (strncmp(p, "process=", 8)) { ++ fprintf(stderr, "Unknown subargument %s to -name", p); ++ exit(1); ++ } ++ p += 8; ++ os_set_proc_name(p); ++ } ++ } ++ break; ++ case QEMU_OPTION_prom_env: ++ if (nb_prom_envs >= MAX_PROM_ENVS) { ++ fprintf(stderr, "Too many prom variables\n"); ++ exit(1); ++ } ++ prom_envs[nb_prom_envs] = optarg; ++ nb_prom_envs++; ++ break; ++ case QEMU_OPTION_old_param: ++ old_param = 1; ++ break; ++ case QEMU_OPTION_clock: ++ configure_alarms(optarg); ++ break; ++ case QEMU_OPTION_startdate: ++ configure_rtc_date_offset(optarg, 1); ++ break; ++ case QEMU_OPTION_rtc: ++ opts = qemu_opts_parse(&qemu_rtc_opts, optarg, 0); ++ if (!opts) { ++ exit(1); ++ } ++ configure_rtc(opts); ++ break; ++ case QEMU_OPTION_tb_size: ++ tb_size = strtol(optarg, NULL, 0); ++ if (tb_size < 0) ++ tb_size = 0; ++ break; ++ case QEMU_OPTION_icount: ++ icount_option = optarg; ++ break; ++ case QEMU_OPTION_incoming: ++ incoming = optarg; ++ incoming_expected = true; ++ break; ++ case QEMU_OPTION_nodefaults: ++ default_serial = 0; ++ default_parallel = 0; ++ default_virtcon = 0; ++ default_monitor = 0; ++ default_vga = 0; ++ default_net = 0; ++ default_floppy = 0; ++ default_cdrom = 0; ++ default_sdcard = 0; ++ break; ++#ifndef _WIN32 ++ case QEMU_OPTION_nvram: ++ nvram = optarg; ++ break; ++#endif ++ case QEMU_OPTION_xen_domid: ++ if (!(xen_available())) { ++ printf("Option %s not supported for this target\n", popt->name); ++ exit(1); ++ } ++ xen_domid = atoi(optarg); ++ break; ++ case QEMU_OPTION_xen_create: ++ if (!(xen_available())) { ++ printf("Option %s not supported for this target\n", popt->name); ++ exit(1); ++ } ++ xen_mode = XEN_CREATE; ++ break; ++ case QEMU_OPTION_xen_attach: ++ if (!(xen_available())) { ++ printf("Option %s not supported for this target\n", popt->name); ++ exit(1); ++ } ++ xen_mode = XEN_ATTACH; ++ break; ++ case QEMU_OPTION_readconfig: ++ { ++ int ret = qemu_read_config_file(optarg); ++ if (ret < 0) { ++ fprintf(stderr, "read config %s: %s\n", optarg, ++ strerror(-ret)); ++ exit(1); ++ } ++ break; ++ } ++#ifdef CONFIG_SPICE ++ case QEMU_OPTION_spice: ++ opts = qemu_opts_parse(&qemu_spice_opts, optarg, 0); ++ if (!opts) { ++ fprintf(stderr, "parse error: %s\n", optarg); ++ exit(1); ++ } ++ break; ++#endif ++ case QEMU_OPTION_writeconfig: ++ { ++ FILE *fp; ++ if (strcmp(optarg, "-") == 0) { ++ fp = stdout; ++ } else { ++ fp = fopen(optarg, "w"); ++ if (fp == NULL) { ++ fprintf(stderr, "open %s: %s\n", optarg, strerror(errno)); ++ exit(1); ++ } ++ } ++ qemu_config_write(fp); ++ fclose(fp); ++ break; ++ } ++ default: ++ os_parse_cmd_args(popt->index, optarg); ++ } ++ } ++ } ++ loc_set_none(); ++ ++ /* If no data_dir is specified then try to find it relative to the ++ executable path. */ ++ if (!data_dir) { ++ data_dir = os_find_datadir(argv[0]); ++ } ++ /* If all else fails use the install patch specified when building. */ ++ if (!data_dir) { ++ data_dir = CONFIG_QEMU_DATADIR; ++ } ++ ++ /* ++ * Default to max_cpus = smp_cpus, in case the user doesn't ++ * specify a max_cpus value. ++ */ ++ if (!max_cpus) ++ max_cpus = smp_cpus; ++ ++ machine->max_cpus = machine->max_cpus ?: 1; /* Default to UP */ ++ if (smp_cpus > machine->max_cpus) { ++ fprintf(stderr, "Number of SMP cpus requested (%d), exceeds max cpus " ++ "supported by machine `%s' (%d)\n", smp_cpus, machine->name, ++ machine->max_cpus); ++ exit(1); ++ } ++ ++ qemu_opts_foreach(&qemu_device_opts, default_driver_check, NULL, 0); ++ qemu_opts_foreach(&qemu_global_opts, default_driver_check, NULL, 0); ++ ++ if (machine->no_serial) { ++ default_serial = 0; ++ } ++ if (machine->no_parallel) { ++ default_parallel = 0; ++ } ++ if (!machine->use_virtcon) { ++ default_virtcon = 0; ++ } ++ if (machine->no_vga) { ++ default_vga = 0; ++ } ++ if (machine->no_floppy) { ++ default_floppy = 0; ++ } ++ if (machine->no_cdrom) { ++ default_cdrom = 0; ++ } ++ if (machine->no_sdcard) { ++ default_sdcard = 0; ++ } ++ ++ if (display_type == DT_NOGRAPHIC) { ++ if (default_parallel) ++ add_device_config(DEV_PARALLEL, "null"); ++ if (default_serial && default_monitor) { ++ add_device_config(DEV_SERIAL, "mon:stdio"); ++ } else if (default_virtcon && default_monitor) { ++ add_device_config(DEV_VIRTCON, "mon:stdio"); ++ } else { ++ if (default_serial) ++ add_device_config(DEV_SERIAL, "stdio"); ++ if (default_virtcon) ++ add_device_config(DEV_VIRTCON, "stdio"); ++ if (default_monitor) ++ monitor_parse("stdio", "readline"); ++ } ++ } else { ++ if (default_serial) ++ add_device_config(DEV_SERIAL, "vc:80Cx24C"); ++ if (default_parallel) ++ add_device_config(DEV_PARALLEL, "vc:80Cx24C"); ++ if (default_monitor) ++ monitor_parse("vc:80Cx24C", "readline"); ++ if (default_virtcon) ++ add_device_config(DEV_VIRTCON, "vc:80Cx24C"); ++ } ++ if (default_vga) ++ vga_interface_type = VGA_CIRRUS; ++ ++ socket_init(); ++ ++ if (qemu_opts_foreach(&qemu_chardev_opts, chardev_init_func, NULL, 1) != 0) ++ exit(1); ++#ifdef CONFIG_VIRTFS ++ if (qemu_opts_foreach(&qemu_fsdev_opts, fsdev_init_func, NULL, 1) != 0) { ++ exit(1); ++ } ++#endif ++ ++ os_daemonize(); ++ ++ if (pid_file && qemu_create_pidfile(pid_file) != 0) { ++ os_pidfile_error(); ++ exit(1); ++ } ++ ++ if (kvm_allowed) { ++ int ret = kvm_init(smp_cpus); ++ if (ret < 0) { ++#if defined(KVM_UPSTREAM) || defined(CONFIG_NO_CPU_EMULATION) ++ if (!kvm_available()) { ++ printf("KVM not supported for this target\n"); ++ } else { ++ fprintf(stderr, "failed to initialize KVM: %s\n", strerror(-ret)); ++ } ++ exit(1); ++#endif ++#ifdef CONFIG_KVM ++ fprintf(stderr, "Could not initialize KVM, will disable KVM support\n"); ++ kvm_allowed = 0; ++#endif ++ } ++ } ++ ++ if (qemu_init_main_loop()) { ++ fprintf(stderr, "qemu_init_main_loop failed\n"); ++ exit(1); ++ } ++ linux_boot = (kernel_filename != NULL); ++ ++ if (!linux_boot && *kernel_cmdline != '\0') { ++ fprintf(stderr, "-append only allowed with -kernel option\n"); ++ exit(1); ++ } ++ ++ if (!linux_boot && initrd_filename != NULL) { ++ fprintf(stderr, "-initrd only allowed with -kernel option\n"); ++ exit(1); ++ } ++ ++ os_set_line_buffering(); ++ ++ if (init_timer_alarm() < 0) { ++ fprintf(stderr, "could not initialize alarm timer\n"); ++ exit(1); ++ } ++ configure_icount(icount_option); ++ ++ if (net_init_clients() < 0) { ++ exit(1); ++ } ++ ++ /* init the bluetooth world */ ++ if (foreach_device_config(DEV_BT, bt_parse)) ++ exit(1); ++ ++ /* init the memory */ ++ if (ram_size == 0) ++ ram_size = DEFAULT_RAM_SIZE * 1024 * 1024; ++ ++ /* init the dynamic translator */ ++ cpu_exec_init_all(tb_size * 1024 * 1024); ++ ++ bdrv_init_with_whitelist(); ++ ++ blk_mig_init(); ++ ++ if (default_cdrom) { ++ /* we always create the cdrom drive, even if no disk is there */ ++ drive_add(NULL, CDROM_ALIAS); ++ } ++ ++ if (default_floppy) { ++ /* we always create at least one floppy */ ++ drive_add(NULL, FD_ALIAS, 0); ++ } ++ ++ if (default_sdcard) { ++ /* we always create one sd slot, even if no card is in it */ ++ drive_add(NULL, SD_ALIAS); ++ } ++ ++ /* open the virtual block devices */ ++ if (snapshot) ++ qemu_opts_foreach(&qemu_drive_opts, drive_enable_snapshot, NULL, 0); ++ if (qemu_opts_foreach(&qemu_drive_opts, drive_init_func, &machine->use_scsi, 1) != 0) ++ exit(1); ++ ++ register_savevm_live(NULL, "ram", 0, 4, NULL, ram_save_live, NULL, ++ ram_load, NULL); ++ ++ if (nb_numa_nodes > 0) { ++ int i; ++ ++ if (nb_numa_nodes > smp_cpus) { ++ nb_numa_nodes = smp_cpus; ++ } ++ ++ /* If no memory size if given for any node, assume the default case ++ * and distribute the available memory equally across all nodes ++ */ ++ for (i = 0; i < nb_numa_nodes; i++) { ++ if (node_mem[i] != 0) ++ break; ++ } ++ if (i == nb_numa_nodes) { ++ uint64_t usedmem = 0; ++ ++ /* On Linux, the each node's border has to be 8MB aligned, ++ * the final node gets the rest. ++ */ ++ for (i = 0; i < nb_numa_nodes - 1; i++) { ++ node_mem[i] = (ram_size / nb_numa_nodes) & ~((1 << 23UL) - 1); ++ usedmem += node_mem[i]; ++ } ++ node_mem[i] = ram_size - usedmem; ++ } ++ ++ for (i = 0; i < nb_numa_nodes; i++) { ++ if (node_cpumask[i] != 0) ++ break; ++ } ++ /* assigning the VCPUs round-robin is easier to implement, guest OSes ++ * must cope with this anyway, because there are BIOSes out there in ++ * real machines which also use this scheme. ++ */ ++ if (i == nb_numa_nodes) { ++ for (i = 0; i < smp_cpus; i++) { ++ node_cpumask[i % nb_numa_nodes] |= 1 << i; ++ } ++ } ++ } ++ ++ if (qemu_opts_foreach(&qemu_mon_opts, mon_init_func, NULL, 1) != 0) { ++ exit(1); ++ } ++ ++ if (foreach_device_config(DEV_SERIAL, serial_parse) < 0) ++ exit(1); ++ if (foreach_device_config(DEV_PARALLEL, parallel_parse) < 0) ++ exit(1); ++ if (foreach_device_config(DEV_VIRTCON, virtcon_parse) < 0) ++ exit(1); ++ if (foreach_device_config(DEV_DEBUGCON, debugcon_parse) < 0) ++ exit(1); ++ ++ module_call_init(MODULE_INIT_DEVICE); ++ ++ if (qemu_opts_foreach(&qemu_device_opts, device_help_func, NULL, 0) != 0) ++ exit(0); ++ ++ if (watchdog) { ++ i = select_watchdog(watchdog); ++ if (i > 0) ++ exit (i == 1 ? 1 : 0); ++ } ++ ++ if (machine->compat_props) { ++ qdev_prop_register_global_list(machine->compat_props); ++ } ++ qemu_add_globals(); ++ ++#ifdef CONFIG_SPICE ++ qemu_spice_init(); ++#endif ++ ++ machine->init(ram_size, boot_devices, ++ kernel_filename, kernel_cmdline, initrd_filename, cpu_model); ++ ++ cpu_synchronize_all_post_init(); ++ ++ /* must be after terminal init, SDL library changes signal handlers */ ++ os_setup_signal_handling(); ++ ++ set_numa_modes(); ++ ++ current_machine = machine; ++ ++ /* init USB devices */ ++ if (usb_enabled) { ++ if (foreach_device_config(DEV_USB, usb_parse) < 0) ++ exit(1); ++ } ++ ++ /* init generic devices */ ++ if (qemu_opts_foreach(&qemu_device_opts, device_init_func, NULL, 1) != 0) ++ exit(1); ++ ++ net_check_clients(); ++ ++ /* just use the first displaystate for the moment */ ++ ds = get_displaystate(); ++ ++ if (display_type == DT_DEFAULT && !using_spice) { ++#if defined(CONFIG_SDL) || defined(CONFIG_COCOA) ++ display_type = DT_SDL; ++#else ++ display_type = DT_VNC; ++ vnc_display = "localhost:0,to=99"; ++ show_vnc_port = 1; ++#endif ++ } ++ ++ ++ switch (display_type) { ++ case DT_NOGRAPHIC: ++ break; ++#if defined(CONFIG_CURSES) ++ case DT_CURSES: ++ curses_display_init(ds, full_screen); ++ break; ++#endif ++#if defined(CONFIG_SDL) ++ case DT_SDL: ++ sdl_display_init(ds, full_screen, no_frame); ++ break; ++#elif defined(CONFIG_COCOA) ++ case DT_SDL: ++ cocoa_display_init(ds, full_screen); ++ break; ++#endif ++ case DT_VNC: ++ vnc_display_init(ds); ++ if (vnc_display_open(ds, vnc_display) < 0) ++ exit(1); ++ ++ if (show_vnc_port) { ++ printf("VNC server running on `%s'\n", vnc_display_local_addr(ds)); ++ } ++ break; ++ default: ++ break; ++ } ++#ifdef CONFIG_SPICE ++ if (using_spice) { ++ qemu_spice_display_init(ds); ++ } ++#endif ++ dpy_resize(ds); ++ ++ dcl = ds->listeners; ++ while (dcl != NULL) { ++ if (dcl->dpy_refresh != NULL) { ++ ds->gui_timer = qemu_new_timer(rt_clock, gui_update, ds); ++ qemu_mod_timer(ds->gui_timer, qemu_get_clock(rt_clock)); ++ break; ++ } ++ dcl = dcl->next; ++ } ++ ++ if (display_type == DT_NOGRAPHIC || display_type == DT_VNC) { ++ nographic_timer = qemu_new_timer(rt_clock, nographic_update, NULL); ++ qemu_mod_timer(nographic_timer, qemu_get_clock(rt_clock)); ++ } ++ ++ text_consoles_set_display(ds); ++ ++ if (gdbstub_dev && gdbserver_start(gdbstub_dev) < 0) { ++ fprintf(stderr, "qemu: could not open gdbserver on device '%s'\n", ++ gdbstub_dev); ++ exit(1); ++ } ++ ++ qdev_machine_creation_done(); ++ ++ if (rom_load_all() != 0) { ++ fprintf(stderr, "rom loading failed\n"); ++ exit(1); ++ } ++ ++ qemu_system_reset(); ++ if (loadvm) { ++ if (load_vmstate(loadvm) < 0) { ++ autostart = 0; ++ } ++ } ++ ++ if (incoming) { ++ int ret = qemu_start_incoming_migration(incoming); ++ if (ret < 0) { ++ fprintf(stderr, "Migration failed. Exit code %s(%d), exiting.\n", ++ incoming, ret); ++ exit(ret); ++ } ++ } else if (autostart) { ++ vm_start(); ++ } ++ ++ os_setup_post(); ++ ++ main_loop(); ++ quit_timers(); ++ net_cleanup(); ++ ++ return 0; ++} diff --git a/app-emulation/qemu-kvm/files/qemu-kvm-guest-hang-on-usb-add.patch b/app-emulation/qemu-kvm/files/qemu-kvm-guest-hang-on-usb-add.patch new file mode 100644 index 0000000..3f2abef --- /dev/null +++ b/app-emulation/qemu-kvm/files/qemu-kvm-guest-hang-on-usb-add.patch @@ -0,0 +1,100 @@ +From 485b75728884a052b74d5458199ad45f0acbf190 Mon Sep 17 00:00:00 2001 +From: Timothy Jones <one.timothy.jones@gmail.com> +Date: Mon, 28 Jun 2010 10:38:18 -0400 +Subject: [PATCH v2] Guest OS hangs on usb_add + +This is a small patch to sligtly "intelligentify" usb device and +config descriptor parsing and to handle bug with certain usb +device (URC MX-950) reporting device desriptor length as 0x18 +instead of 18 with added vendor_id/product_id check +--- + hw/usb.h | 5 +++++ + usb-linux.c | 37 ++++++++++++++++++++++--------------- + 2 files changed, 27 insertions(+), 15 deletions(-) + +diff --git a/hw/usb.h b/hw/usb.h +index 00d2802..5c3528f 100644 +--- a/hw/usb.h ++++ b/hw/usb.h +@@ -117,6 +117,11 @@ + #define USB_DT_INTERFACE 0x04 + #define USB_DT_ENDPOINT 0x05 + ++#define USB_DT_DEVICE_LEN 18 ++#define USB_DT_CONFIG_LEN 9 ++#define USB_DT_INTERFACE_LEN 9 ++#define USB_DT_ENDPOINT_LEN 7 ++ + #define USB_ENDPOINT_XFER_CONTROL 0 + #define USB_ENDPOINT_XFER_ISOC 1 + #define USB_ENDPOINT_XFER_BULK 2 +diff --git a/usb-linux.c b/usb-linux.c +index 88273ff..2ac6562 100644 +--- a/usb-linux.c ++++ b/usb-linux.c +@@ -288,7 +288,7 @@ static void async_cancel(USBPacket *unused, void *opaque) + + static int usb_host_claim_interfaces(USBHostDevice *dev, int configuration) + { +- int dev_descr_len, config_descr_len; ++ int dev_descr_len, config_descr_total_len; + int interface, nb_interfaces; + int ret, i; + +@@ -297,32 +297,39 @@ static int usb_host_claim_interfaces(USBHostDevice *dev, int configuration) + + DPRINTF("husb: claiming interfaces. config %d\n", configuration); + +- i = 0; + dev_descr_len = dev->descr[0]; +- if (dev_descr_len > dev->descr_len) { ++ if (dev_descr_len == 0x18 && dev->descr[ 8] == 0x47 && dev->descr[ 9] == 0x46 ++ && dev->descr[10] == 0x00 && dev->descr[11] == 0x30) ++ dev_descr_len = USB_DT_DEVICE_LEN; /* for buggy MX-950 remote reporting len in hex */ ++ ++ if (dev_descr_len > dev->descr_len || dev_descr_len < USB_DT_DEVICE_LEN || dev->descr[1] != USB_DT_DEVICE) { ++ fprintf(stderr, "husb: invalid device descriptor\n"); + goto fail; + } + +- i += dev_descr_len; +- while (i < dev->descr_len) { ++ for (i = dev_descr_len; i < dev->descr_len; ) { + DPRINTF("husb: i is %d, descr_len is %d, dl %d, dt %d\n", + i, dev->descr_len, + dev->descr[i], dev->descr[i+1]); + +- if (dev->descr[i+1] != USB_DT_CONFIG) { +- i += dev->descr[i]; +- continue; ++ if (dev->descr[i] < 2) { ++ fprintf(stderr, "husb: invalid descriptor\n"); ++ goto fail; + } +- config_descr_len = dev->descr[i]; ++ if (dev->descr[i+1] == USB_DT_CONFIG) { ++ config_descr_total_len = dev->descr[i+2] + (dev->descr[i+3] << 8); + +- printf("husb: config #%d need %d\n", dev->descr[i + 5], configuration); ++ printf("husb: config #%d need %d\n", dev->descr[i + 5], configuration); + +- if (configuration < 0 || configuration == dev->descr[i + 5]) { +- configuration = dev->descr[i + 5]; +- break; +- } ++ if (configuration < 0 || configuration == dev->descr[i + 5]) { ++ configuration = dev->descr[i + 5]; ++ break; ++ } + +- i += config_descr_len; ++ i += config_descr_total_len; ++ } ++ else ++ i += dev->descr[i]; + } + + if (i >= dev->descr_len) { +-- +1.7.1 + diff --git a/app-emulation/qemu-kvm/metadata.xml b/app-emulation/qemu-kvm/metadata.xml new file mode 100644 index 0000000..29522f7 --- /dev/null +++ b/app-emulation/qemu-kvm/metadata.xml @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE pkgmetadata SYSTEM "http://www.gentoo.org/dtd/metadata.dtd"> +<pkgmetadata> + <herd>qemu</herd> + <use> + <flag name='aio'>Enables support for Linux's Async IO</flag> + <flag name='alsa'>Enable alsa output for sound emulation</flag> + <flag name='brltty'>Adds support for braille displays using brltty</flag> + <flag name='esd'>Enable esound output for sound emulation</flag> + <flag name='fdt'>Enables firmware device tree support</flag> + <flag name='jpeg'>Enable JPEG compression for the VNC console server</flag> + <flag name='kvm-trace'>Allows you to use KVM tracing</flag> + <flag name='ncurses'>Enable the ncurses-based console</flag> + <flag name='png'>Enable PNG compression for the VNC console server</flag> + <flag name='pulseaudio'>Enable pulseaudio output for sound emulation</flag> + <flag name='qemu-ifup'>Provides the qemu-ifup script for use with QEMU's + built in bridging</flag> + <flag name='rbd'>Enable rados block device backend support, see http://ceph.newdream.net/wiki/QEMU-RBD</flag> + <flag name='sdl'>Enable the SDL-based console</flag> + <flag name='spice'>Enable Spice protocol support via <pkg>app-emulation/spice</pkg></flag> + <flag name='ssl'>Enable TLS support for the VNC console server</flag> + <flag name='vde'>Enable VDE-based networking</flag> + <flag name='vhost-net'>Enable accelerated networking using vhost-net, see http://www.linux-kvm.org/page/VhostNet</flag> + <flag name='xen'>Enables support for Xen backends</flag> +</use> +</pkgmetadata> diff --git a/app-emulation/qemu-kvm/qemu-kvm-0.13.0-r99.ebuild b/app-emulation/qemu-kvm/qemu-kvm-0.13.0-r99.ebuild new file mode 100644 index 0000000..3455d67 --- /dev/null +++ b/app-emulation/qemu-kvm/qemu-kvm-0.13.0-r99.ebuild @@ -0,0 +1,261 @@ +# Copyright 1999-2011 Gentoo Foundation +# Distributed under the terms of the GNU General Public License v2 + +EAPI="2" + +if [[ ${PV} = *9999* ]]; then + EGIT_REPO_URI="git://git.kernel.org/pub/scm/virt/kvm/qemu-kvm.git" + GIT_ECLASS="git" +fi + +inherit eutils flag-o-matic ${GIT_ECLASS} linux-info toolchain-funcs + +if [[ ${PV} = *9999* ]]; then + SRC_URI="" + KEYWORDS="" +else + SRC_URI="mirror://sourceforge/kvm/${PN}/${P}.tar.gz" + KEYWORDS="~amd64 ~ppc ~ppc64 ~x86" +fi + +DESCRIPTION="QEMU + Kernel-based Virtual Machine userland tools" +HOMEPAGE="http://www.linux-kvm.org" + +LICENSE="GPL-2" +SLOT="0" +# xen is disabled until the deps are fixed +IUSE="+aio alsa bluetooth brltty curl esd fdt hardened jpeg ncurses \ +png pulseaudio qemu-ifup sasl sdl ssl static vde" + +COMMON_TARGETS="i386 x86_64 arm cris m68k microblaze mips mipsel ppc ppc64 sh4 sh4eb sparc sparc64" +IUSE_SOFTMMU_TARGETS="${COMMON_TARGETS} mips64 mips64el ppcemb" +IUSE_USER_TARGETS="${COMMON_TARGETS} alpha armeb ppc64abi32 sparc32plus" + +for target in ${IUSE_SOFTMMU_TARGETS}; do + IUSE="${IUSE} +qemu_softmmu_targets_${target}" +done + +for target in ${IUSE_USER_TARGETS}; do + IUSE="${IUSE} +qemu_user_targets_${target}" +done + +RESTRICT="test" + +RDEPEND=" + !app-emulation/kqemu + !app-emulation/qemu + !app-emulation/qemu-softmmu + !app-emulation/qemu-user + !app-emulation/qemu-kvm-spice + sys-apps/pciutils + >=sys-apps/util-linux-2.16.0 + sys-libs/zlib + aio? ( dev-libs/libaio ) + alsa? ( >=media-libs/alsa-lib-1.0.13 ) + bluetooth? ( net-wireless/bluez ) + brltty? ( app-accessibility/brltty ) + curl? ( net-misc/curl ) + esd? ( media-sound/esound ) + fdt? ( >=sys-apps/dtc-1.2.0 ) + jpeg? ( virtual/jpeg ) + ncurses? ( sys-libs/ncurses ) + png? ( media-libs/libpng ) + pulseaudio? ( media-sound/pulseaudio ) + qemu-ifup? ( sys-apps/iproute2 net-misc/bridge-utils ) + sasl? ( dev-libs/cyrus-sasl ) + sdl? ( >=media-libs/libsdl-1.2.11[X] ) + ssl? ( net-libs/gnutls ) + vde? ( net-misc/vde ) + amd64? ( >=app-emulation/spice-0.6.0 ) + amd64? ( >=app-emulation/spice-protocol-0.6.0 ) +" + +DEPEND="${RDEPEND} + app-text/texi2html + >=sys-kernel/linux-headers-2.6.29 + ssl? ( dev-util/pkgconfig ) +" + +kvm_kern_warn() { + eerror "Please enable KVM support in your kernel, found at:" + eerror + eerror " Virtualization" + eerror " Kernel-based Virtual Machine (KVM) support" + eerror +} + +pkg_setup() { + use qemu_softmmu_targets_x86_64 || ewarn "You disabled default target QEMU_SOFTMMU_TARGETS=x86_64" + + if kernel_is lt 2 6 25; then + eerror "This version of KVM requres a host kernel of 2.6.25 or higher." + eerror "Either upgrade your kernel" + else + if ! linux_config_exists; then + eerror "Unable to check your kernel for KVM support" + kvm_kern_warn + elif ! linux_chkconfig_present KVM; then + kvm_kern_warn + fi + fi + + enewgroup kvm +} + +src_prepare() { + # prevent docs to get automatically installed + sed -i '/$(DESTDIR)$(docdir)/d' Makefile || die + # Alter target makefiles to accept CFLAGS set via flag-o + sed -i 's/^\(C\|OP_C\|HELPER_C\)FLAGS=/\1FLAGS+=/' \ + Makefile Makefile.target || die + # append CFLAGS while linking + sed -i 's/$(LDFLAGS)/$(QEMU_CFLAGS) $(CFLAGS) $(LDFLAGS)/' rules.mak || die + + # remove part to make udev happy + sed -e 's~NAME="%k", ~~' -i kvm/scripts/65-kvm.rules || die + + # ${PN}-guest-hang-on-usb-add.patch was sent by Timothy Jones + # to the qemu-devel ml - bug 337988 + epatch "${FILESDIR}/qemu-0.11.0-mips64-user-fix.patch" \ + "${FILESDIR}/${PN}-0.12.3-include-madvise-defines.patch" +# "${FILESDIR}/${PN}-guest-hang-on-usb-add.patch" + + epatch "${FILESDIR}/${PN}-0.13.0-redhat-patches.patch" +} + +src_configure() { + local conf_opts audio_opts user_targets + + for target in ${IUSE_SOFTMMU_TARGETS} ; do + use "qemu_softmmu_targets_${target}" && \ + softmmu_targets="${softmmu_targets} ${target}-softmmu" + done + + for target in ${IUSE_USER_TARGETS} ; do + use "qemu_user_targets_${target}" && \ + user_targets="${user_targets} ${target}-linux-user" + done + + if [ -z "${softmmu_targets}" ]; then + conf_opts="${conf_opts} --disable-system" + else + einfo "Building the following softmmu targets: ${softmmu_targets}" + fi + + if [ ! -z "${user_targets}" ]; then + einfo "Building the following user targets: ${user_targets}" + conf_opts="${conf_opts} --enable-linux-user" + else + conf_opts="${conf_opts} --disable-linux-user" + fi + + # Fix QA issues. QEMU needs executable heaps and we need to mark it as such + conf_opts="${conf_opts} --extra-ldflags=-Wl,-z,execheap" + + # Add support for static builds + use static && conf_opts="${conf_opts} --static" + + # Fix the $(prefix)/etc issue + conf_opts="${conf_opts} --sysconfdir=/etc" + + #config options + conf_opts="${conf_opts} $(use_enable aio linux-aio)" + conf_opts="${conf_opts} $(use_enable bluetooth bluez)" + conf_opts="${conf_opts} $(use_enable brltty brlapi)" + conf_opts="${conf_opts} $(use_enable curl)" + conf_opts="${conf_opts} $(use_enable fdt)" + conf_opts="${conf_opts} $(use_enable hardened user-pie)" + conf_opts="${conf_opts} $(use_enable jpeg vnc-jpeg)" + conf_opts="${conf_opts} $(use_enable ncurses curses)" + conf_opts="${conf_opts} $(use_enable png vnc-png)" + conf_opts="${conf_opts} $(use_enable sasl vnc-sasl)" + conf_opts="${conf_opts} $(use_enable sdl)" + conf_opts="${conf_opts} $(use_enable ssl vnc-tls)" + conf_opts="${conf_opts} $(use_enable vde)" +# conf_opts="${conf_opts} $(use_enable xen)" + conf_opts="${conf_opts} --disable-xen" + conf_opts="${conf_opts} --disable-darwin-user --disable-bsd-user" + + # enable spice on amd64 + use amd64 && conf_opts="${conf_opts} --enable-spice" + + # audio options + audio_opts="oss" + use alsa && audio_opts="alsa ${audio_opts}" + use esd && audio_opts="esd ${audio_opts}" + use pulseaudio && audio_opts="pa ${audio_opts}" + use sdl && audio_opts="sdl ${audio_opts}" + ./configure --prefix=/usr \ + --disable-strip \ + --disable-werror \ + --enable-kvm \ + --enable-nptl \ + --enable-uuid \ + ${conf_opts} \ + --audio-drv-list="${audio_opts}" \ + --target-list="${softmmu_targets} ${user_targets}" \ + --cc="$(tc-getCC)" \ + --host-cc="$(tc-getBUILD_CC)" \ + || die "configure failed" + + # this is for qemu upstream's threaded support which is + # in development and broken + # the kvm project has its own support for threaded IO + # which is always on and works + # --enable-io-thread \ +} + +src_compile() { + # Restricting parallel build until we get a patch to fix this + emake -j1 || die +} + +src_install() { + emake DESTDIR="${D}" install || die "make install failed" + + if [ ! -z "${softmmu_targets}" ]; then + insinto /etc/udev/rules.d/ + doins kvm/scripts/65-kvm.rules || die + + if use qemu-ifup; then + insinto /etc/qemu/ + insopts -m0755 + doins kvm/scripts/qemu-ifup || die + fi + + if use qemu_softmmu_targets_x86_64 ; then + dobin "${FILESDIR}"/qemu-kvm + dosym /usr/bin/qemu-kvm /usr/bin/kvm + else + elog "You disabled QEMU_SOFTMMU_TARGETS=x86_64, this disables install" + elog "of /usr/bin/qemu-kvm and /usr/bin/kvm" + fi + fi + + dodoc Changelog MAINTAINERS TODO pci-ids.txt || die + newdoc pc-bios/README README.pc-bios || die + dohtml qemu-doc.html qemu-tech.html || die +} + +pkg_postinst() { + + if [ ! -z "${softmmu_targets}" ]; then + elog "If you don't have kvm compiled into the kernel, make sure you have" + elog "the kernel module loaded before running kvm. The easiest way to" + elog "ensure that the kernel module is loaded is to load it on boot." + elog "For AMD CPUs the module is called 'kvm-amd'" + elog "For Intel CPUs the module is called 'kvm-intel'" + elog "Please review /etc/conf.d/modules for how to load these" + elog + elog "Make sure your user is in the 'kvm' group" + elog "Just run 'gpasswd -a <USER> kvm', then have <USER> re-login." + elog + elog "You will need the Universal TUN/TAP driver compiled into your" + elog "kernel or loaded as a module to use the virtual network device" + elog "if using -net tap. You will also need support for 802.1d" + elog "Ethernet Bridging and a configured bridge if using the provided" + elog "kvm-ifup script from /etc/kvm." + elog + elog "The gnutls use flag was renamed to ssl, so adjust your use flags." + fi +} |