diff options
-rw-r--r-- | Makefile.objs | 11 | ||||
-rwxr-xr-x | configure | 260 | ||||
-rw-r--r-- | docs/usb2.txt | 20 | ||||
-rw-r--r-- | hw/usb.h | 1 | ||||
-rw-r--r-- | hw/usb/bus.c | 2 | ||||
-rw-r--r-- | hw/usb/dev-hid.c | 2 | ||||
-rw-r--r-- | hw/usb/dev-hub.c | 12 | ||||
-rw-r--r-- | hw/usb/hcd-xhci.c | 28 | ||||
-rw-r--r-- | hw/usb/redirect.c | 37 | ||||
-rw-r--r-- | qemu-char.c | 17 | ||||
-rw-r--r-- | qga/commands-win32.c | 56 | ||||
-rw-r--r-- | qga/main.c | 8 | ||||
-rw-r--r-- | qga/qapi-schema.json | 18 | ||||
-rw-r--r-- | tests/Makefile | 14 | ||||
-rw-r--r-- | trace-events | 1 |
15 files changed, 283 insertions, 204 deletions
diff --git a/Makefile.objs b/Makefile.objs index f99841c..e568c01 100644 --- a/Makefile.objs +++ b/Makefile.objs @@ -16,16 +16,7 @@ block-obj-y += qapi-types.o qapi-visit.o block-obj-y += qemu-coroutine.o qemu-coroutine-lock.o qemu-coroutine-io.o block-obj-y += qemu-coroutine-sleep.o -ifeq ($(CONFIG_UCONTEXT_COROUTINE),y) -block-obj-$(CONFIG_POSIX) += coroutine-ucontext.o -else -ifeq ($(CONFIG_SIGALTSTACK_COROUTINE),y) -block-obj-$(CONFIG_POSIX) += coroutine-sigaltstack.o -else -block-obj-$(CONFIG_POSIX) += coroutine-gthread.o -endif -endif -block-obj-$(CONFIG_WIN32) += coroutine-win32.o +block-obj-y += coroutine-$(CONFIG_COROUTINE_BACKEND).o ifeq ($(CONFIG_VIRTIO)$(CONFIG_VIRTFS)$(CONFIG_PCI),yyy) # Lots of the fsdev/9pcode is pulled in by vl.c via qemu_fsdev_add. @@ -27,6 +27,17 @@ printf " '%s'" "$0" "$@" >> config.log echo >> config.log echo "#" >> config.log +error_exit() { + echo + echo "ERROR: $1" + while test -n "$2"; do + echo " $2" + shift + done + echo + exit 1 +} + do_cc() { # Run the compiler, capturing its output to the log. echo $cc "$@" >> config.log @@ -46,11 +57,10 @@ do_cc() { esac echo $cc -Werror "$@" >> config.log $cc -Werror "$@" >> config.log 2>&1 && return $? - echo "ERROR: configure test passed without -Werror but failed with -Werror." - echo "This is probably a bug in the configure script. The failing command" - echo "will be at the bottom of config.log." - echo "You can run configure with --disable-werror to bypass this check." - exit 1 + error_exit "configure test passed without -Werror but failed with -Werror." \ + "This is probably a bug in the configure script. The failing command" \ + "will be at the bottom of config.log." \ + "You can run configure with --disable-werror to bypass this check." } compile_object() { @@ -494,11 +504,10 @@ SunOS) LDFLAGS="-L/opt/SUNWspro/prod/lib -R/opt/SUNWspro/prod/lib $LDFLAGS" LIBS="-lsunmath $LIBS" else - echo "QEMU will not link correctly on Solaris 8/X86 or 9/x86 without" - echo "libsunmath from the Sun Studio compilers tools, due to a lack of" - echo "C99 math features in libm.so in Solaris 8/x86 and Solaris 9/x86" - echo "Studio 11 can be downloaded from www.sun.com." - exit 1 + error_exit "QEMU will not link correctly on Solaris 8/X86 or 9/x86 without" \ + "libsunmath from the Sun Studio compilers tools, due to a lack of" \ + "C99 math features in libm.so in Solaris 8/x86 and Solaris 9/x86" \ + "Studio 11 can be downloaded from www.sun.com." fi fi fi @@ -1185,8 +1194,7 @@ if test "$ARCH" = "unknown"; then echo "Unsupported CPU = $cpu, will use TCG with TCI (experimental)" ARCH=tci else - echo "Unsupported CPU = $cpu, try --enable-tcg-interpreter" - exit 1 + error_exit "Unsupported CPU = $cpu, try --enable-tcg-interpreter" fi fi @@ -1198,8 +1206,7 @@ EOF if compile_object ; then : C compiler works ok else - echo "ERROR: \"$cc\" either does not exist or does not work" - exit 1 + error_exit "\"$cc\" either does not exist or does not work" fi # Consult white-list to determine whether to enable werror @@ -1254,8 +1261,7 @@ fi if test "$static" = "yes" ; then if test "$pie" = "yes" ; then - echo "static and pie are mutually incompatible" - exit 1 + error_exit "static and pie are mutually incompatible" else pie="no" fi @@ -1294,8 +1300,7 @@ EOF fi else if test "$pie" = "yes"; then - echo "PIE not available due to missing toolchain support" - exit 1 + error_exit "PIE not available due to missing toolchain support" else echo "Disabling PIE due to missing toolchain support" pie="no" @@ -1310,40 +1315,36 @@ if test "$solaris" = "yes" ; then if has $install; then : else - echo "Solaris install program not found. Use --install=/usr/ucb/install or" - echo "install fileutils from www.blastwave.org using pkg-get -i fileutils" - echo "to get ginstall which is used by default (which lives in /opt/csw/bin)" - exit 1 + error_exit "Solaris install program not found. Use --install=/usr/ucb/install or" \ + "install fileutils from www.blastwave.org using pkg-get -i fileutils" \ + "to get ginstall which is used by default (which lives in /opt/csw/bin)" fi if test "`path_of $install`" = "/usr/sbin/install" ; then - echo "Error: Solaris /usr/sbin/install is not an appropriate install program." - echo "try ginstall from the GNU fileutils available from www.blastwave.org" - echo "using pkg-get -i fileutils, or use --install=/usr/ucb/install" - exit 1 + error_exit "Solaris /usr/sbin/install is not an appropriate install program." \ + "try ginstall from the GNU fileutils available from www.blastwave.org" \ + "using pkg-get -i fileutils, or use --install=/usr/ucb/install" fi if has ar; then : else - echo "Error: No path includes ar" if test -f /usr/ccs/bin/ar ; then - echo "Add /usr/ccs/bin to your path and rerun configure" + error_exit "No path includes ar" \ + "Add /usr/ccs/bin to your path and rerun configure" fi - exit 1 + error_exit "No path includes ar" fi fi if ! has $python; then - echo "Python not found. Use --python=/path/to/python" - exit 1 + error_exit "Python not found. Use --python=/path/to/python" fi # Note that if the Python conditional here evaluates True we will exit # with status 1 which is a shell 'false' value. if ! "$python" -c 'import sys; sys.exit(sys.version_info < (2,4) or sys.version_info >= (3,))'; then - echo "Cannot use '$python', Python 2.4 or later is required." - echo "Note that Python 3 or later is not yet supported." - echo "Use --python=/path/to/python to specify a supported Python." - exit 1 + error_exit "Cannot use '$python', Python 2.4 or later is required." \ + "Note that Python 3 or later is not yet supported." \ + "Use --python=/path/to/python to specify a supported Python." fi if test -z "${target_list+xxx}" ; then @@ -1362,11 +1363,8 @@ esac feature_not_found() { feature=$1 - echo "ERROR" - echo "ERROR: User requested feature $feature" - echo "ERROR: configure was not able to find it" - echo "ERROR" - exit 1; + error_exit "User requested feature $feature" \ + "configure was not able to find it" } if test -z "$cross_prefix" ; then @@ -1408,8 +1406,7 @@ fi # pkg-config probe if ! has "$pkg_config_exe"; then - echo "Error: pkg-config binary '$pkg_config_exe' not found" - exit 1 + error_exit "pkg-config binary '$pkg_config_exe' not found" fi ########################################## @@ -1448,11 +1445,8 @@ EOF if compile_prog "" "-lz" ; then : else - echo - echo "Error: zlib check failed" - echo "Make sure to have the zlib libs and headers installed." - echo - exit 1 + error_exit "zlib check failed" \ + "Make sure to have the zlib libs and headers installed." fi fi @@ -1629,14 +1623,12 @@ if test "$xen_pci_passthrough" != "no"; then xen_pci_passthrough=yes else if test "$xen_pci_passthrough" = "yes"; then - echo "ERROR" - echo "ERROR: User requested feature Xen PCI Passthrough" - echo "ERROR: but this feature require /sys from Linux" if test "$xen_ctrl_version" -lt 340; then - echo "ERROR: This feature does not work with Xen 3.3" + error_exit "User requested feature Xen PCI Passthrough" \ + "This feature does not work with Xen 3.3" fi - echo "ERROR" - exit 1; + error_exit "User requested feature Xen PCI Passthrough" \ + " but this feature requires /sys from Linux" fi xen_pci_passthrough=no fi @@ -2010,11 +2002,8 @@ EOF if compile_prog "$cfl" "$lib" ; then : else - echo - echo "Error: $drv check failed" - echo "Make sure to have the $drv libs and headers installed." - echo - exit 1 + error_exit "$drv check failed" \ + "Make sure to have the $drv libs and headers installed." fi } @@ -2029,11 +2018,8 @@ for drv in $audio_drv_list; do fmod) if test -z $fmod_lib || test -z $fmod_inc; then - echo - echo "Error: You must specify path to FMOD library and headers" - echo "Example: --fmod-inc=/path/include/fmod --fmod-lib=/path/lib/libfmod-3.74.so" - echo - exit 1 + error_exit "You must specify path to FMOD library and headers" \ + "Example: --fmod-inc=/path/include/fmod --fmod-lib=/path/lib/libfmod-3.74.so" fi audio_drv_probe $drv fmod.h $fmod_lib "return FSOUND_GetVersion();" "-I $fmod_inc" libs_softmmu="$fmod_lib $libs_softmmu" @@ -2076,11 +2062,8 @@ for drv in $audio_drv_list; do *) echo "$audio_possible_drivers" | grep -q "\<$drv\>" || { - echo - echo "Error: Unknown driver '$drv' selected" - echo "Possible drivers are: $audio_possible_drivers" - echo - exit 1 + error_exit "Unknown driver '$drv' selected" \ + "Possible drivers are: $audio_possible_drivers" } ;; esac @@ -2209,8 +2192,7 @@ then LIBS="$glib_libs $LIBS" libs_qga="$glib_libs $libs_qga" else - echo "glib-$glib_req_ver required to compile QEMU" - exit 1 + error_exit "glib-$glib_req_ver required to compile QEMU" fi ########################################## @@ -2227,11 +2209,10 @@ if test "$pixman" = ""; then fi if test "$pixman" = "none"; then if test "$want_tools" != "no" -o "$softmmu" != "no"; then - echo "ERROR: pixman disabled but system emulation or tools build" - echo " enabled. You can turn off pixman only if you also" - echo " disable all system emulation targets and the tools" - echo " build with '--disable-tools --disable-system'." - exit 1 + error_exit "pixman disabled but system emulation or tools build" \ + "enabled. You can turn off pixman only if you also" \ + "disable all system emulation targets and the tools" \ + "build with '--disable-tools --disable-system'." fi pixman_cflags= pixman_libs= @@ -2240,12 +2221,11 @@ elif test "$pixman" = "system"; then pixman_libs=`$pkg_config --libs pixman-1 2>/dev/null` else if test ! -d ${source_path}/pixman/pixman; then - echo "ERROR: pixman not present. Your options:" - echo " (1) Preferred: Install the pixman devel package (any recent" - echo " distro should have packages as Xorg needs pixman too)." - echo " (2) Fetch the pixman submodule, using:" - echo " git submodule update --init pixman" - exit 1 + error_exit "pixman not present. Your options:" \ + " (1) Preferred: Install the pixman devel package (any recent" \ + " distro should have packages as Xorg needs pixman too)." \ + " (2) Fetch the pixman submodule, using:" \ + " git submodule update --init pixman" fi mkdir -p pixman/pixman pixman_cflags="-I\$(SRC_PATH)/pixman/pixman -I\$(BUILD_DIR)/pixman/pixman" @@ -2304,11 +2284,8 @@ else fi if test "$mingw32" != yes -a "$pthread" = no; then - echo - echo "Error: pthread check failed" - echo "Make sure to have the pthread libs and headers installed." - echo - exit 1 + error_exit "pthread check failed" \ + "Make sure to have the pthread libs and headers installed." fi ########################################## @@ -2363,8 +2340,7 @@ fi if test "$virtio_blk_data_plane" = "yes" -a \ "$linux_aio" != "yes" ; then - echo "Error: virtio-blk-data-plane requires Linux AIO, please try --enable-linux-aio" - exit 1 + error_exit "virtio-blk-data-plane requires Linux AIO, please try --enable-linux-aio" elif test -z "$virtio_blk_data_plane" ; then virtio_blk_data_plane=$linux_aio fi @@ -2861,10 +2837,7 @@ elif compile_prog "" "-lm" ; then LIBS="-lm $LIBS" libs_qga="-lm $libs_qga" else - echo - echo "Error: libm check failed" - echo - exit 1 + error_exit "libm check failed" fi ########################################## @@ -3040,11 +3013,8 @@ fi $python "$source_path/scripts/tracetool.py" "--backend=$trace_backend" --check-backend > /dev/null 2> /dev/null if test "$?" -ne 0 ; then - echo - echo "Error: invalid trace backend" - echo "Please choose a supported trace backend." - echo - exit 1 + error_exit "invalid trace backend" \ + "Please choose a supported trace backend." fi ########################################## @@ -3059,10 +3029,7 @@ EOF LIBS="-lust -lurcu-bp $LIBS" libs_qga="-lust -lurcu-bp $libs_qga" else - echo - echo "Error: Trace backend 'ust' missing libust header files" - echo - exit 1 + error_exit "Trace backend 'ust' missing libust header files" fi fi @@ -3070,10 +3037,7 @@ fi # For 'dtrace' backend, test if 'dtrace' command is present if test "$trace_backend" = "dtrace"; then if ! has 'dtrace' ; then - echo - echo "Error: dtrace command is not found in PATH $PATH" - echo - exit 1 + error_exit "dtrace command is not found in PATH $PATH" fi trace_backend_stap="no" if has 'stap' ; then @@ -3107,34 +3071,58 @@ fi ########################################## # check and set a backend for coroutine -# default is ucontext, but always fallback to gthread -# windows autodetected by make -if test "$coroutine" = "" -o "$coroutine" = "ucontext"; then - if test "$darwin" != "yes"; then - cat > $TMPC << EOF +# We prefer ucontext, but it's not always possible. The fallback +# is sigcontext. gthread is not selectable except explicitly, because +# it is not functional enough to run QEMU proper. (It is occasionally +# useful for debugging purposes.) On Windows the only valid backend +# is the Windows-specific one. + +ucontext_works=no +if test "$darwin" != "yes"; then + cat > $TMPC << EOF #include <ucontext.h> #ifdef __stub_makecontext #error Ignoring glibc stub makecontext which will always fail #endif int main(void) { makecontext(0, 0, 0); return 0; } EOF - if compile_prog "" "" ; then - coroutine_backend=ucontext - else - coroutine_backend=gthread - fi + if compile_prog "" "" ; then + ucontext_works=yes + fi +fi + +if test "$coroutine" = ""; then + if test "$mingw32" = "yes"; then + coroutine=win32 + elif test "$ucontext_works" = "yes"; then + coroutine=ucontext + else + coroutine=sigaltstack fi -elif test "$coroutine" = "gthread" ; then - coroutine_backend=gthread -elif test "$coroutine" = "windows" ; then - coroutine_backend=windows -elif test "$coroutine" = "sigaltstack" ; then - coroutine_backend=sigaltstack else - echo - echo "Error: unknown coroutine backend $coroutine" - echo - exit 1 + case $coroutine in + windows) + if test "$mingw32" != "yes"; then + error_exit "'windows' coroutine backend only valid for Windows" + fi + # Unfortunately the user visible backend name doesn't match the + # coroutine-*.c filename for this case, so we have to adjust it here. + coroutine=win32 + ;; + ucontext) + if test "$ucontext_works" != "yes"; then + feature_not_found "ucontext" + fi + ;; + gthread|sigaltstack) + if test "$mingw32" = "yes"; then + error_exit "only the 'windows' coroutine backend is valid for Windows" + fi + ;; + *) + error_exit "unknown coroutine backend $coroutine" + ;; + esac fi ########################################## @@ -3319,8 +3307,7 @@ if test "$softmmu" = yes ; then tools="$tools fsdev/virtfs-proxy-helper\$(EXESUF)" else if test "$virtfs" = yes; then - echo "VirtFS is supported only on Linux and requires libcap-devel and libattr-devel" - exit 1 + error_exit "VirtFS is supported only on Linux and requires libcap-devel and libattr-devel" fi virtfs=no fi @@ -3442,7 +3429,7 @@ echo "GLX support $glx" echo "libiscsi support $libiscsi" echo "build guest agent $guest_agent" echo "seccomp support $seccomp" -echo "coroutine backend $coroutine_backend" +echo "coroutine backend $coroutine" echo "GlusterFS support $glusterfs" echo "virtio-blk-data-plane $virtio_blk_data_plane" echo "gcov $gcov_tool" @@ -3775,11 +3762,7 @@ if test "$rbd" = "yes" ; then echo "CONFIG_RBD=y" >> $config_host_mak fi -if test "$coroutine_backend" = "ucontext" ; then - echo "CONFIG_UCONTEXT_COROUTINE=y" >> $config_host_mak -elif test "$coroutine_backend" = "sigaltstack" ; then - echo "CONFIG_SIGALTSTACK_COROUTINE=y" >> $config_host_mak -fi +echo "CONFIG_COROUTINE_BACKEND=$coroutine" >> $config_host_mak if test "$open_by_handle_at" = "yes" ; then echo "CONFIG_OPEN_BY_HANDLE=y" >> $config_host_mak @@ -3967,22 +3950,20 @@ case "$target" in ;; ${target_arch2}-linux-user) if test "$linux" != "yes" ; then - echo "ERROR: Target '$target' is only available on a Linux host" - exit 1 + error_exit "Target '$target' is only available on a Linux host" fi target_user_only="yes" target_linux_user="yes" ;; ${target_arch2}-bsd-user) if test "$bsd" != "yes" ; then - echo "ERROR: Target '$target' is only available on a BSD host" - exit 1 + error_exit "Target '$target' is only available on a BSD host" fi target_user_only="yes" target_bsd_user="yes" ;; *) - echo "ERROR: Target '$target' not recognised" + error_exit "Target '$target' not recognised" exit 1 ;; esac @@ -4113,8 +4094,7 @@ case "$target_arch2" in TARGET_ARCH=xtensa ;; *) - echo "Unsupported target CPU" - exit 1 + error_exit "Unsupported target CPU" ;; esac # TARGET_BASE_ARCH needs to be defined after TARGET_ARCH diff --git a/docs/usb2.txt b/docs/usb2.txt index 43dacde..c7a445a 100644 --- a/docs/usb2.txt +++ b/docs/usb2.txt @@ -11,7 +11,7 @@ one USB 2.0 bus driven by the EHCI controller. Devices must be attached to the correct controller manually. The '-usb' switch will make qemu create the UHCI controller as part of -the PIIX3 chipset. The USB 1.1 bus will carry the name "usb.0". +the PIIX3 chipset. The USB 1.1 bus will carry the name "usb-bus.0". You can use the standard -device switch to add a EHCI controller to your virtual machine. It is strongly recommended to specify an ID for @@ -27,7 +27,7 @@ a complete example: -drive if=none,id=usbstick,file=/path/to/image \ -usb \ -device usb-ehci,id=ehci \ - -device usb-tablet,bus=usb.0 \ + -device usb-tablet,bus=usb-bus.0 \ -device usb-storage,bus=ehci.0,drive=usbstick This attaches a usb tablet to the UHCI adapter and a usb mass storage @@ -88,22 +88,22 @@ ports (1-4), the emulated (1.1) USB hub has eight ports. Plugging a tablet into UHCI port 1 works like this: - -device usb-tablet,bus=usb.0,port=1 + -device usb-tablet,bus=usb-bus.0,port=1 Plugging a hub into UHCI port 2 works like this: - -device usb-hub,bus=usb.0,port=2 + -device usb-hub,bus=usb-bus.0,port=2 Plugging a virtual usb stick into port 4 of the hub just plugged works this way: - -device usb-storage,bus=usb.0,port=2.4,drive=... + -device usb-storage,bus=usb-bus.0,port=2.4,drive=... You can do basically the same in the monitor using the device_add command. If you want to unplug devices too you should specify some unique id which you can use to refer to the device ... - (qemu) device_add usb-tablet,bus=usb.0,port=1,id=my-tablet + (qemu) device_add usb-tablet,bus=usb-bus.0,port=1,id=my-tablet (qemu) device_del my-tablet ... when unplugging it with device_del. @@ -148,10 +148,10 @@ using for testing is bus 1 + port 1 for 2.0 devices and bus 3 + port 1 for 1.1 devices. Passing through any device plugged into that port and also assign them to the correct bus can be done this way: - qemu -M pc ${otheroptions} \ - -usb \ - -device usb-ehci,id=ehci \ - -device usb-host,bus=usb.0,hostbus=3,hostport=1 \ + qemu -M pc ${otheroptions} \ + -usb \ + -device usb-ehci,id=ehci \ + -device usb-host,bus=usb-bus.0,hostbus=3,hostport=1 \ -device usb-host,bus=ehci.0,hostbus=1,hostport=1 enjoy, @@ -337,6 +337,7 @@ typedef struct USBPortOps { struct USBPort { USBDevice *dev; int speedmask; + int hubcount; char path[16]; USBPortOps *ops; void *opaque; diff --git a/hw/usb/bus.c b/hw/usb/bus.c index e58cd9a..b10c290 100644 --- a/hw/usb/bus.c +++ b/hw/usb/bus.c @@ -341,8 +341,10 @@ void usb_port_location(USBPort *downstream, USBPort *upstream, int portnr) if (upstream) { snprintf(downstream->path, sizeof(downstream->path), "%s.%d", upstream->path, portnr); + downstream->hubcount = upstream->hubcount + 1; } else { snprintf(downstream->path, sizeof(downstream->path), "%d", portnr); + downstream->hubcount = 0; } } diff --git a/hw/usb/dev-hid.c b/hw/usb/dev-hid.c index 9701048..317b474 100644 --- a/hw/usb/dev-hid.c +++ b/hw/usb/dev-hid.c @@ -236,7 +236,7 @@ static const USBDescDevice desc_device_tablet2 = { .bNumInterfaces = 1, .bConfigurationValue = 1, .iConfiguration = STR_CONFIG_TABLET, - .bmAttributes = 0xa0, + .bmAttributes = 0x80, .bMaxPower = 50, .nif = 1, .ifs = &desc_iface_tablet2, diff --git a/hw/usb/dev-hub.c b/hw/usb/dev-hub.c index 504c98c..0b71abd 100644 --- a/hw/usb/dev-hub.c +++ b/hw/usb/dev-hub.c @@ -25,6 +25,7 @@ #include "trace.h" #include "hw/usb.h" #include "hw/usb/desc.h" +#include "qemu/error-report.h" #define NUM_PORTS 8 @@ -32,6 +33,7 @@ typedef struct USBHubPort { USBPort port; uint16_t wPortStatus; uint16_t wPortChange; + uint16_t wPortChange_reported; } USBHubPort; typedef struct USBHubState { @@ -466,8 +468,11 @@ static void usb_hub_handle_data(USBDevice *dev, USBPacket *p) status = 0; for(i = 0; i < NUM_PORTS; i++) { port = &s->ports[i]; - if (port->wPortChange) + if (port->wPortChange && + port->wPortChange_reported != port->wPortChange) { status |= (1 << (i + 1)); + } + port->wPortChange_reported = port->wPortChange; } if (status != 0) { for(i = 0; i < n; i++) { @@ -514,6 +519,11 @@ static int usb_hub_initfn(USBDevice *dev) USBHubPort *port; int i; + if (dev->port->hubcount == 5) { + error_report("usb hub chain too deep"); + return -1; + } + usb_desc_create_serial(dev); usb_desc_init(dev); s->intr = usb_ep_get(dev, USB_TOKEN_IN, 1); diff --git a/hw/usb/hcd-xhci.c b/hw/usb/hcd-xhci.c index 5aa342b..efd4b0d 100644 --- a/hw/usb/hcd-xhci.c +++ b/hw/usb/hcd-xhci.c @@ -452,7 +452,6 @@ struct XHCIState { MemoryRegion mem_oper; MemoryRegion mem_runtime; MemoryRegion mem_doorbell; - const char *name; unsigned int devaddr; /* properties */ @@ -1172,8 +1171,6 @@ static void xhci_set_ep_state(XHCIState *xhci, XHCIEPContext *epctx, uint32_t ctx[5]; uint32_t ctx2[2]; - fprintf(stderr, "%s: epid %d, state %d\n", - __func__, epctx->epid, state); xhci_dma_read_u32s(xhci, epctx->pctx, ctx, sizeof(ctx)); ctx[0] &= ~EP_STATE_MASK; ctx[0] |= state; @@ -2568,7 +2565,7 @@ static void xhci_process_commands(XHCIState *xhci) } break; default: - fprintf(stderr, "xhci: unimplemented command %d\n", type); + trace_usb_xhci_unimplemented("command", type); event.ccode = CC_TRB_ERROR; break; } @@ -2767,7 +2764,7 @@ static uint64_t xhci_cap_read(void *ptr, hwaddr reg, unsigned size) ret = 0x00000000; /* reserved */ break; default: - fprintf(stderr, "xhci_cap_read: reg %d unimplemented\n", (int)reg); + trace_usb_xhci_unimplemented("cap read", reg); ret = 0; } @@ -2790,8 +2787,7 @@ static uint64_t xhci_port_read(void *ptr, hwaddr reg, unsigned size) break; case 0x0c: /* reserved */ default: - fprintf(stderr, "xhci_port_read (port %d): reg 0x%x unimplemented\n", - port->portnr, (uint32_t)reg); + trace_usb_xhci_unimplemented("port read", reg); ret = 0; } @@ -2831,8 +2827,7 @@ static void xhci_port_write(void *ptr, hwaddr reg, case 0x04: /* PORTPMSC */ case 0x08: /* PORTLI */ default: - fprintf(stderr, "xhci_port_write (port %d): reg 0x%x unimplemented\n", - port->portnr, (uint32_t)reg); + trace_usb_xhci_unimplemented("port write", reg); } } @@ -2870,7 +2865,7 @@ static uint64_t xhci_oper_read(void *ptr, hwaddr reg, unsigned size) ret = xhci->config; break; default: - fprintf(stderr, "xhci_oper_read: reg 0x%x unimplemented\n", (int)reg); + trace_usb_xhci_unimplemented("oper read", reg); ret = 0; } @@ -2935,7 +2930,7 @@ static void xhci_oper_write(void *ptr, hwaddr reg, xhci->config = val & 0xff; break; default: - fprintf(stderr, "xhci_oper_write: reg 0x%x unimplemented\n", (int)reg); + trace_usb_xhci_unimplemented("oper write", reg); } } @@ -2951,8 +2946,7 @@ static uint64_t xhci_runtime_read(void *ptr, hwaddr reg, ret = xhci_mfindex_get(xhci) & 0x3fff; break; default: - fprintf(stderr, "xhci_runtime_read: reg 0x%x unimplemented\n", - (int)reg); + trace_usb_xhci_unimplemented("runtime read", reg); break; } } else { @@ -2996,7 +2990,7 @@ static void xhci_runtime_write(void *ptr, hwaddr reg, trace_usb_xhci_runtime_write(reg, val); if (reg < 0x20) { - fprintf(stderr, "%s: reg 0x%x unimplemented\n", __func__, (int)reg); + trace_usb_xhci_unimplemented("runtime write", reg); return; } @@ -3038,8 +3032,7 @@ static void xhci_runtime_write(void *ptr, hwaddr reg, xhci_events_update(xhci, v); break; default: - fprintf(stderr, "xhci_oper_write: reg 0x%x unimplemented\n", - (int)reg); + trace_usb_xhci_unimplemented("oper write", reg); } } @@ -3290,6 +3283,9 @@ static int usb_xhci_initfn(struct PCIDevice *dev) if (xhci->numintrs > MAXINTRS) { xhci->numintrs = MAXINTRS; } + while (xhci->numintrs & (xhci->numintrs - 1)) { /* ! power of 2 */ + xhci->numintrs++; + } if (xhci->numintrs < 1) { xhci->numintrs = 1; } diff --git a/hw/usb/redirect.c b/hw/usb/redirect.c index d02a7b9..0ddb081 100644 --- a/hw/usb/redirect.c +++ b/hw/usb/redirect.c @@ -104,6 +104,8 @@ struct USBRedirDevice { /* Data passed from chardev the fd_read cb to the usbredirparser read cb */ const uint8_t *read_buf; int read_buf_size; + /* Active chardev-watch-tag */ + guint watch; /* For async handling of close */ QEMUBH *chardev_close_bh; /* To delay the usb attach in case of quick chardev close + open */ @@ -254,9 +256,21 @@ static int usbredir_read(void *priv, uint8_t *data, int count) return count; } +static gboolean usbredir_write_unblocked(GIOChannel *chan, GIOCondition cond, + void *opaque) +{ + USBRedirDevice *dev = opaque; + + dev->watch = 0; + usbredirparser_do_write(dev->parser); + + return FALSE; +} + static int usbredir_write(void *priv, uint8_t *data, int count) { USBRedirDevice *dev = priv; + int r; if (!dev->cs->be_open) { return 0; @@ -267,7 +281,17 @@ static int usbredir_write(void *priv, uint8_t *data, int count) return 0; } - return qemu_chr_fe_write(dev->cs, data, count); + r = qemu_chr_fe_write(dev->cs, data, count); + if (r < count) { + if (!dev->watch) { + dev->watch = qemu_chr_fe_add_watch(dev->cs, G_IO_OUT, + usbredir_write_unblocked, dev); + } + if (r < 0) { + r = 0; + } + } + return r; } /* @@ -1085,6 +1109,10 @@ static void usbredir_chardev_close_bh(void *opaque) usbredirparser_destroy(dev->parser); dev->parser = NULL; } + if (dev->watch) { + g_source_remove(dev->watch); + dev->watch = 0; + } } static void usbredir_create_parser(USBRedirDevice *dev) @@ -1317,6 +1345,9 @@ static void usbredir_handle_destroy(USBDevice *udev) if (dev->parser) { usbredirparser_destroy(dev->parser); } + if (dev->watch) { + g_source_remove(dev->watch); + } free(dev->filter_rules); } @@ -1973,6 +2004,10 @@ static int usbredir_post_load(void *priv, int version_id) { USBRedirDevice *dev = priv; + if (dev->parser == NULL) { + return 0; + } + switch (dev->device_info.speed) { case usb_redir_speed_low: dev->dev.speed = USB_SPEED_LOW; diff --git a/qemu-char.c b/qemu-char.c index dd410ce..eae17fc 100644 --- a/qemu-char.c +++ b/qemu-char.c @@ -596,9 +596,11 @@ typedef struct IOWatchPoll { GSource parent; + GIOChannel *channel; GSource *src; IOCanReadHandler *fd_can_read; + GSourceFunc fd_read; void *opaque; } IOWatchPoll; @@ -611,15 +613,19 @@ static gboolean io_watch_poll_prepare(GSource *source, gint *timeout_) { IOWatchPoll *iwp = io_watch_poll_from_source(source); bool now_active = iwp->fd_can_read(iwp->opaque) > 0; - bool was_active = g_source_get_context(iwp->src) != NULL; + bool was_active = iwp->src != NULL; if (was_active == now_active) { return FALSE; } if (now_active) { + iwp->src = g_io_create_watch(iwp->channel, G_IO_IN | G_IO_ERR | G_IO_HUP); + g_source_set_callback(iwp->src, iwp->fd_read, iwp->opaque, NULL); g_source_attach(iwp->src, NULL); } else { - g_source_remove(g_source_get_id(iwp->src)); + g_source_destroy(iwp->src); + g_source_unref(iwp->src); + iwp->src = NULL; } return FALSE; } @@ -638,7 +644,9 @@ static gboolean io_watch_poll_dispatch(GSource *source, GSourceFunc callback, static void io_watch_poll_finalize(GSource *source) { IOWatchPoll *iwp = io_watch_poll_from_source(source); + g_source_destroy(iwp->src); g_source_unref(iwp->src); + iwp->src = NULL; } static GSourceFuncs io_watch_poll_funcs = { @@ -659,8 +667,9 @@ static guint io_add_watch_poll(GIOChannel *channel, iwp = (IOWatchPoll *) g_source_new(&io_watch_poll_funcs, sizeof(IOWatchPoll)); iwp->fd_can_read = fd_can_read; iwp->opaque = user_data; - iwp->src = g_io_create_watch(channel, G_IO_IN | G_IO_ERR | G_IO_HUP); - g_source_set_callback(iwp->src, (GSourceFunc)fd_read, user_data, NULL); + iwp->channel = channel; + iwp->fd_read = (GSourceFunc) fd_read; + iwp->src = NULL; return g_source_attach(&iwp->parent, NULL); } diff --git a/qga/commands-win32.c b/qga/commands-win32.c index b19be9d..24e4ad0 100644 --- a/qga/commands-win32.c +++ b/qga/commands-win32.c @@ -22,6 +22,12 @@ #define SHTDN_REASON_FLAG_PLANNED 0x80000000 #endif +/* multiple of 100 nanoseconds elapsed between windows baseline + * (1/1/1601) and Unix Epoch (1/1/1970), accounting for leap years */ +#define W32_FT_OFFSET (10000000ULL * 60 * 60 * 24 * \ + (365 * (1970 - 1601) + \ + (1970 - 1601) / 4 - 3)) + static void acquire_privilege(const char *name, Error **err) { HANDLE token; @@ -280,13 +286,57 @@ GuestNetworkInterfaceList *qmp_guest_network_get_interfaces(Error **err) int64_t qmp_guest_get_time(Error **errp) { - error_set(errp, QERR_UNSUPPORTED); - return -1; + SYSTEMTIME ts = {0}; + int64_t time_ns; + FILETIME tf; + + GetSystemTime(&ts); + if (ts.wYear < 1601 || ts.wYear > 30827) { + error_setg(errp, "Failed to get time"); + return -1; + } + + if (!SystemTimeToFileTime(&ts, &tf)) { + error_setg(errp, "Failed to convert system time: %d", (int)GetLastError()); + return -1; + } + + time_ns = ((((int64_t)tf.dwHighDateTime << 32) | tf.dwLowDateTime) + - W32_FT_OFFSET) * 100; + + return time_ns; } void qmp_guest_set_time(int64_t time_ns, Error **errp) { - error_set(errp, QERR_UNSUPPORTED); + SYSTEMTIME ts; + FILETIME tf; + LONGLONG time; + + if (time_ns < 0 || time_ns / 100 > INT64_MAX - W32_FT_OFFSET) { + error_setg(errp, "Time %" PRId64 "is invalid", time_ns); + return; + } + + time = time_ns / 100 + W32_FT_OFFSET; + + tf.dwLowDateTime = (DWORD) time; + tf.dwHighDateTime = (DWORD) (time >> 32); + + if (!FileTimeToSystemTime(&tf, &ts)) { + error_setg(errp, "Failed to convert system time %d", (int)GetLastError()); + return; + } + + acquire_privilege(SE_SYSTEMTIME_NAME, errp); + if (error_is_set(errp)) { + return; + } + + if (!SetSystemTime(&ts)) { + error_setg(errp, "Failed to set time to guest: %d", (int)GetLastError()); + return; + } } GuestLogicalProcessorList *qmp_guest_get_vcpus(Error **errp) @@ -889,9 +889,13 @@ int64_t ga_get_fd_handle(GAState *s, Error **errp) g_assert(!ga_is_frozen(s)); handle = s->pstate.fd_counter++; - if (s->pstate.fd_counter < 0) { - s->pstate.fd_counter = 0; + + /* This should never happen on a reasonable timeframe, as guest-file-open + * would have to be issued 2^63 times */ + if (s->pstate.fd_counter == INT64_MAX) { + abort(); } + if (!write_persistent_state(&s->pstate, s->pstate_filepath)) { error_setg(errp, "failed to commit persistent state to disk"); } diff --git a/qga/qapi-schema.json b/qga/qapi-schema.json index dac4e6f..7155b7a 100644 --- a/qga/qapi-schema.json +++ b/qga/qapi-schema.json @@ -2,6 +2,17 @@ ## # +# General note concerning the use of guest agent interfaces: +# +# "unsupported" is a higher-level error than the errors that individual +# commands might document. The caller should always be prepared to receive +# QERR_UNSUPPORTED, even if the given command doesn't specify it, or doesn't +# document any failure mode at all. +# +## + +## +# # Echo back a unique integer value, and prepend to response a # leading sentinel byte (0xFF) the client can check scan for. # @@ -562,9 +573,10 @@ # # @online: Whether the VCPU is enabled. # -# @can-offline: Whether offlining the VCPU is possible. This member is always -# filled in by the guest agent when the structure is returned, -# and always ignored on input (hence it can be omitted then). +# @can-offline: #optional Whether offlining the VCPU is possible. This member +# is always filled in by the guest agent when the structure is +# returned, and always ignored on input (hence it can be omitted +# then). # # Since: 1.5 ## diff --git a/tests/Makefile b/tests/Makefile index 567e36e..7fa15c6 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -24,19 +24,7 @@ gcov-files-test-string-input-visitor-y = qapi/string-input-visitor.c check-unit-y += tests/test-string-output-visitor$(EXESUF) gcov-files-test-string-output-visitor-y = qapi/string-output-visitor.c check-unit-y += tests/test-coroutine$(EXESUF) -ifeq ($(CONFIG_WIN32),y) -gcov-files-test-coroutine-y = coroutine-win32.c -else -ifeq ($(CONFIG_UCONTEXT_COROUTINE),y) -gcov-files-test-coroutine-y = coroutine-ucontext.c -else -ifeq ($(CONFIG_SIGALTSTACK_COROUTINE),y) -gcov-files-test-coroutine-y = coroutine-sigaltstack.c -else -gcov-files-test-coroutine-y = coroutine-gthread.c -endif -endif -endif +gcov-files-test-coroutine-y = coroutine-$(CONFIG_COROUTINE_BACKEND).c check-unit-y += tests/test-visitor-serialization$(EXESUF) check-unit-y += tests/test-iov$(EXESUF) gcov-files-test-iov-y = util/iov.c diff --git a/trace-events b/trace-events index 7f34112..412f7e4 100644 --- a/trace-events +++ b/trace-events @@ -380,6 +380,7 @@ usb_xhci_xfer_nak(void *xfer) "%p" usb_xhci_xfer_retry(void *xfer) "%p" usb_xhci_xfer_success(void *xfer, uint32_t bytes) "%p: len %d" usb_xhci_xfer_error(void *xfer, uint32_t ret) "%p: ret %d" +usb_xhci_unimplemented(const char *item, int nr) "%s (0x%x)" # hw/usb/desc.c usb_desc_device(int addr, int len, int ret) "dev %d query device, len %d, ret %d" |