aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore4
-rw-r--r--CODING_STYLE14
-rw-r--r--MAINTAINERS6
-rw-r--r--Makefile8
-rw-r--r--Makefile.objs15
-rw-r--r--Makefile.target15
-rw-r--r--VERSION2
-rw-r--r--arch_init.c4
-rw-r--r--backends/Makefile.objs2
-rw-r--r--backends/testdev.c131
-rw-r--r--block-migration.c11
-rw-r--r--block.c173
-rw-r--r--block/Makefile.objs2
-rw-r--r--block/archipelago.c1069
-rw-r--r--block/blkdebug.c20
-rw-r--r--block/bochs.c6
-rw-r--r--block/cloop.c23
-rw-r--r--block/curl.c8
-rw-r--r--block/dmg.c19
-rw-r--r--block/iscsi.c8
-rw-r--r--block/mirror.c7
-rw-r--r--block/nfs.c6
-rw-r--r--block/parallels.c58
-rw-r--r--block/qapi.c42
-rw-r--r--block/qcow.c33
-rw-r--r--block/qcow2-cache.c13
-rw-r--r--block/qcow2-cluster.c47
-rw-r--r--block/qcow2-refcount.c55
-rw-r--r--block/qcow2-snapshot.c23
-rw-r--r--block/qcow2.c70
-rw-r--r--block/qed-check.c7
-rw-r--r--block/qed.c10
-rw-r--r--block/raw-posix.c45
-rw-r--r--block/raw_bsd.c3
-rw-r--r--block/rbd.c7
-rw-r--r--block/stream.c2
-rw-r--r--block/vdi.c112
-rw-r--r--block/vhdx-endian.c11
-rw-r--r--block/vhdx-log.c55
-rw-r--r--block/vhdx.c98
-rw-r--r--block/vhdx.h1
-rw-r--r--block/vmdk.c243
-rw-r--r--block/vpc.c112
-rw-r--r--block/win32-aio.c6
-rwxr-xr-xconfigure53
-rw-r--r--cpu-exec.c122
-rw-r--r--cpus.c118
-rw-r--r--docs/image-fuzzer.txt238
-rw-r--r--docs/multiple-iothreads.txt134
-rw-r--r--docs/qmp/qmp-events.txt80
-rw-r--r--docs/specs/qcow2.txt12
-rw-r--r--docs/tracing.txt40
-rw-r--r--dump.c18
-rw-r--r--exec.c20
-rw-r--r--hw/acpi/ich9.c4
-rw-r--r--hw/arm/boot.c8
-rw-r--r--hw/arm/virt.c16
-rw-r--r--hw/audio/gus.c2
-rw-r--r--hw/audio/hda-codec.c3
-rw-r--r--hw/audio/intel-hda.c4
-rw-r--r--hw/audio/sb16.c6
-rw-r--r--hw/block/dataplane/virtio-blk.c39
-rw-r--r--hw/block/virtio-blk.c14
-rw-r--r--hw/block/xen_disk.c1
-rw-r--r--hw/bt/l2cap.c2
-rw-r--r--hw/char/cadence_uart.c15
-rw-r--r--hw/char/virtio-serial-bus.c46
-rw-r--r--hw/core/machine.c8
-rw-r--r--hw/i386/acpi-build.c101
-rw-r--r--hw/i386/acpi-dsdt.dsl94
-rw-r--r--hw/i386/acpi-dsdt.hex.generated1872
-rw-r--r--hw/i386/kvm/clock.c52
-rw-r--r--hw/i386/pc.c55
-rw-r--r--hw/i386/pc_piix.c65
-rw-r--r--hw/i386/pc_q35.c29
-rw-r--r--hw/i386/q35-acpi-dsdt.dsl4
-rw-r--r--hw/i386/ssdt-mem.dsl16
-rw-r--r--hw/i386/ssdt-misc.dsl2
-rw-r--r--hw/i386/xen/xen_apic.c1
-rw-r--r--hw/ide/ahci.c115
-rw-r--r--hw/ide/ahci.h21
-rw-r--r--hw/ide/atapi.c11
-rw-r--r--hw/ide/cmd646.c94
-rw-r--r--hw/ide/core.c101
-rw-r--r--hw/ide/internal.h38
-rw-r--r--hw/ide/macio.c9
-rw-r--r--hw/ide/pci.c45
-rw-r--r--hw/ide/pci.h7
-rw-r--r--hw/intc/apic.c2
-rw-r--r--hw/intc/i8259.c2
-rw-r--r--hw/intc/openpic.c2
-rw-r--r--hw/isa/isa-bus.c2
-rw-r--r--hw/isa/lpc_ich9.c2
-rw-r--r--hw/mem/pc-dimm.c6
-rw-r--r--hw/misc/imx_ccm.c1
-rw-r--r--hw/misc/ivshmem.c10
-rw-r--r--hw/misc/vfio.c46
-rw-r--r--hw/net/e1000.c60
-rw-r--r--hw/net/vmxnet3.c16
-rw-r--r--hw/pci-host/apb.c12
-rw-r--r--hw/pci-host/pam.c4
-rw-r--r--hw/pci-host/q35.c2
-rw-r--r--hw/pci/msi.c2
-rw-r--r--hw/pci/msix.c2
-rw-r--r--hw/ppc/e500.c2
-rw-r--r--hw/ppc/mac_newworld.c7
-rw-r--r--hw/ppc/mac_oldworld.c5
-rw-r--r--hw/ppc/ppc405_boards.c28
-rw-r--r--hw/ppc/ppc405_uc.c4
-rw-r--r--hw/ppc/ppc4xx_devs.c38
-rw-r--r--hw/sd/sdhci.c3
-rw-r--r--hw/sparc64/sun4u.c4
-rw-r--r--hw/ssi/xilinx_spi.c2
-rw-r--r--hw/timer/imx_epit.c16
-rw-r--r--hw/timer/imx_gpt.c32
-rw-r--r--hw/timer/tusb6010.c3
-rw-r--r--hw/usb/dev-audio.c2
-rw-r--r--hw/usb/dev-mtp.c6
-rw-r--r--hw/usb/hcd-ehci.c2
-rw-r--r--hw/usb/hcd-ohci.c2
-rw-r--r--hw/usb/hcd-xhci.c1
-rw-r--r--hw/virtio/vhost-backend.c2
-rw-r--r--hw/virtio/vhost-user.c6
-rw-r--r--hw/virtio/virtio-rng.c25
-rw-r--r--include/block/block.h4
-rw-r--r--include/block/block_int.h2
-rw-r--r--include/block/coroutine.h11
-rw-r--r--include/exec/helper-gen.h2
-rw-r--r--include/exec/helper-proto.h1
-rw-r--r--include/exec/helper-tcg.h1
-rw-r--r--include/exec/ram_addr.h11
-rw-r--r--include/hw/acpi/pc-hotplug.h2
-rw-r--r--include/hw/i386/pc.h15
-rw-r--r--include/hw/pci-host/pam.h2
-rw-r--r--include/hw/usb.h7
-rw-r--r--include/hw/virtio/vhost-backend.h2
-rw-r--r--include/hw/virtio/virtio-serial.h2
-rw-r--r--include/libdecnumber/decNumberLocal.h2
-rw-r--r--include/monitor/monitor.h2
-rw-r--r--include/qemu-common.h8
-rw-r--r--include/qemu/osdep.h1
-rw-r--r--include/qemu/timer.h2
-rw-r--r--include/sysemu/char.h3
-rw-r--r--include/trace-tcg.h7
-rw-r--r--include/trace.h1
-rw-r--r--kvm-all.c5
-rw-r--r--memory.c3
-rw-r--r--monitor.c20
-rw-r--r--net/slirp.c1
-rw-r--r--net/tap-bsd.c70
-rw-r--r--numa.c4
-rw-r--r--po/de_DE.po53
-rw-r--r--po/fr_FR.po54
-rw-r--r--po/it.po63
-rw-r--r--po/zh_CN.po86
-rw-r--r--qapi-schema.json3
-rw-r--r--qapi/block-core.json40
-rw-r--r--qdev-monitor.c42
-rw-r--r--qemu-char.c17
-rw-r--r--qemu-coroutine.c26
-rw-r--r--qemu-doc.texi13
-rw-r--r--qemu-img.c108
-rw-r--r--qemu-options.hx25
-rw-r--r--qga/channel-posix.c2
-rw-r--r--qga/commands-posix.c510
-rw-r--r--qga/commands-win32.c47
-rw-r--r--qga/guest-agent-core.h1
-rw-r--r--qga/main.c1
-rw-r--r--qga/qapi-schema.json96
-rw-r--r--qmp.c1
-rw-r--r--qtest.c13
-rwxr-xr-xscripts/simpletrace.py24
-rw-r--r--scripts/tracetool/__init__.py105
-rw-r--r--scripts/tracetool/format/events_h.py5
-rw-r--r--scripts/tracetool/format/simpletrace_stap.py71
-rw-r--r--scripts/tracetool/format/stap.py11
-rw-r--r--scripts/tracetool/format/tcg_h.py57
-rw-r--r--scripts/tracetool/format/tcg_helper_c.py50
-rw-r--r--scripts/tracetool/format/tcg_helper_h.py50
-rw-r--r--scripts/tracetool/format/tcg_helper_wrapper_h.py70
-rw-r--r--scripts/tracetool/format/ust_events_h.py15
-rw-r--r--scripts/tracetool/transform.py166
-rwxr-xr-xscripts/vmstate-static-checker.py97
-rw-r--r--stubs/Makefile.objs1
-rw-r--r--stubs/chr-testdev.c7
-rw-r--r--stubs/fdset-remove-fd.c3
-rw-r--r--target-alpha/translate.c3
-rw-r--r--target-arm/cpu.c2
-rw-r--r--target-arm/cpu.h4
-rw-r--r--target-arm/helper-a64.c8
-rw-r--r--target-arm/helper.c42
-rw-r--r--target-arm/internals.h29
-rw-r--r--target-arm/kvm64.c13
-rw-r--r--target-arm/op_helper.c8
-rw-r--r--target-arm/translate-a64.c2
-rw-r--r--target-arm/translate.c3
-rw-r--r--target-cris/translate.c3
-rw-r--r--target-i386/cpu.c10
-rw-r--r--target-i386/helper.c3
-rw-r--r--target-i386/translate.c3
-rw-r--r--target-lm32/translate.c3
-rw-r--r--target-m68k/translate.c3
-rw-r--r--target-microblaze/translate.c3
-rw-r--r--target-mips/op_helper.c11
-rw-r--r--target-mips/translate.c6
-rw-r--r--target-openrisc/translate.c3
-rw-r--r--target-ppc/translate.c3
-rw-r--r--target-s390x/translate.c2
-rw-r--r--target-sh4/translate.c3
-rw-r--r--target-sparc/ldst_helper.c15
-rw-r--r--target-sparc/translate.c3
-rw-r--r--target-unicore32/translate.c3
-rw-r--r--target-xtensa/translate.c3
-rw-r--r--tests/Makefile5
-rw-r--r--tests/acpi-test-data/pc/DSDTbin4499 -> 2807 bytes
-rw-r--r--tests/bios-tables-test.c6
-rw-r--r--tests/fdc-test.c2
-rw-r--r--tests/ide-test.c99
-rw-r--r--tests/image-fuzzer/qcow2/__init__.py1
-rw-r--r--tests/image-fuzzer/qcow2/fuzz.py355
-rw-r--r--tests/image-fuzzer/qcow2/layout.py476
-rwxr-xr-xtests/image-fuzzer/runner.py405
-rw-r--r--tests/libqos/malloc-pc.c5
-rw-r--r--tests/libqos/malloc.h2
-rw-r--r--tests/libqos/pci-pc.c12
-rw-r--r--tests/libqos/pci-pc.h1
-rw-r--r--tests/libqos/pci.c4
-rw-r--r--tests/libqos/pci.h4
-rw-r--r--tests/libqtest.c24
-rw-r--r--tests/libqtest.h24
-rwxr-xr-xtests/qemu-iotests/0284
-rw-r--r--tests/qemu-iotests/028.out2
-rwxr-xr-xtests/qemu-iotests/03652
-rw-r--r--tests/qemu-iotests/036.out35
-rwxr-xr-xtests/qemu-iotests/0594
-rw-r--r--tests/qemu-iotests/059.out202
-rwxr-xr-xtests/qemu-iotests/0609
-rw-r--r--tests/qemu-iotests/060.out8
-rwxr-xr-xtests/qemu-iotests/08416
-rw-r--r--tests/qemu-iotests/084.out14
-rw-r--r--tests/qemu-iotests/common6
-rw-r--r--tests/qemu-iotests/common.rc9
-rwxr-xr-xtests/qemu-iotests/qcow2.py15
-rw-r--r--tests/qemu-iotests/sample_images/iotest-version3.vmdk.bz2bin414 -> 4764 bytes
-rw-r--r--tests/test-aio.c2
-rw-r--r--tests/test-coroutine.c24
-rw-r--r--tests/test-qemu-opts.c2
-rw-r--r--tests/test-throttle.c8
-rw-r--r--tests/test-visitor-serialization.c6
-rw-r--r--tests/test-vmstate.c4
-rw-r--r--tests/usb-hcd-ehci-test.c2
-rw-r--r--tests/vhost-user-test.c11
-rw-r--r--tests/wdt_ib700-test.c134
-rw-r--r--thread-pool.c27
-rw-r--r--trace-events14
-rw-r--r--trace/Makefile.objs53
-rw-r--r--translate-all.c3
-rw-r--r--ui/spice-core.c4
-rw-r--r--ui/vnc.c5
-rw-r--r--ui/vnc.h1
-rw-r--r--util/module.c9
-rw-r--r--util/oslib-posix.c16
-rw-r--r--util/oslib-win32.c9
-rw-r--r--util/qemu-sockets.c2
-rw-r--r--vl.c58
-rw-r--r--xen-hvm.c9
266 files changed, 8036 insertions, 3188 deletions
diff --git a/.gitignore b/.gitignore
index 2286d0a109..e32a58417a 100644
--- a/.gitignore
+++ b/.gitignore
@@ -11,6 +11,10 @@
/trace/generated-tracers.dtrace
/trace/generated-events.h
/trace/generated-events.c
+/trace/generated-helpers-wrappers.h
+/trace/generated-helpers.h
+/trace/generated-helpers.c
+/trace/generated-tcg-tracers.h
/trace/generated-ust-provider.h
/trace/generated-ust.c
/libcacard/trace/generated-tracers.c
diff --git a/CODING_STYLE b/CODING_STYLE
index 4280945ff0..d46cfa5f65 100644
--- a/CODING_STYLE
+++ b/CODING_STYLE
@@ -91,3 +91,17 @@ Mixed declarations (interleaving statements and declarations within blocks)
are not allowed; declarations should be at the beginning of blocks. In other
words, the code should not generate warnings if using GCC's
-Wdeclaration-after-statement option.
+
+6. Conditional statements
+
+When comparing a variable for (in)equality with a constant, list the
+constant on the right, as in:
+
+if (a == 1) {
+ /* Reads like: "If a equals 1" */
+ do_something();
+}
+
+Rationale: Yoda conditions (as in 'if (1 == a)') are awkward to read.
+Besides, good compilers already warn users when '==' is mis-typed as '=',
+even when the constant is on the right.
diff --git a/MAINTAINERS b/MAINTAINERS
index 906f252477..59940f97ad 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1000,3 +1000,9 @@ SSH
M: Richard W.M. Jones <rjones@redhat.com>
S: Supported
F: block/ssh.c
+
+ARCHIPELAGO
+M: Chrysostomos Nanakos <cnanakos@grnet.gr>
+M: Chrysostomos Nanakos <chris@include.gr>
+S: Maintained
+F: block/archipelago.c
diff --git a/Makefile b/Makefile
index d6b9dc1ebe..b33aaacde6 100644
--- a/Makefile
+++ b/Makefile
@@ -57,6 +57,12 @@ GENERATED_HEADERS += trace/generated-tracers-dtrace.h
endif
GENERATED_SOURCES += trace/generated-tracers.c
+GENERATED_HEADERS += trace/generated-tcg-tracers.h
+
+GENERATED_HEADERS += trace/generated-helpers-wrappers.h
+GENERATED_HEADERS += trace/generated-helpers.h
+GENERATED_SOURCES += trace/generated-helpers.c
+
ifeq ($(findstring ust,$(TRACE_BACKENDS)),ust)
GENERATED_HEADERS += trace/generated-ust-provider.h
GENERATED_SOURCES += trace/generated-ust.c
@@ -202,7 +208,7 @@ Makefile: $(version-obj-y) $(version-lobj-y)
# Build libraries
libqemustub.a: $(stub-obj-y)
-libqemuutil.a: $(util-obj-y) qapi-types.o qapi-visit.o qapi-event.o
+libqemuutil.a: $(util-obj-y)
block-modules = $(foreach o,$(block-obj-m),"$(basename $(subst /,-,$o))",) NULL
util/module.o-cflags = -D'CONFIG_BLOCK_MODULES=$(block-modules)'
diff --git a/Makefile.objs b/Makefile.objs
index 1f76cea569..97db978d16 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -1,7 +1,7 @@
#######################################################################
# Common libraries for tools and emulators
stub-obj-y = stubs/
-util-obj-y = util/ qobject/ qapi/ trace/
+util-obj-y = util/ qobject/ qapi/ qapi-types.o qapi-visit.o qapi-event.o
#######################################################################
# block-obj-y is code used by both qemu system emulation and qemu-img
@@ -12,7 +12,6 @@ block-obj-y += main-loop.o iohandler.o qemu-timer.o
block-obj-$(CONFIG_POSIX) += aio-posix.o
block-obj-$(CONFIG_WIN32) += aio-win32.o
block-obj-y += block/
-block-obj-y += qapi-types.o qapi-visit.o qapi-event.o
block-obj-y += qemu-io-cmds.o
block-obj-y += qemu-coroutine.o qemu-coroutine-lock.o qemu-coroutine-io.o
@@ -88,11 +87,6 @@ common-obj-y += qmp-marshal.o
common-obj-y += qmp.o hmp.o
endif
-######################################################################
-# some qapi visitors are used by both system and user emulation:
-
-common-obj-y += qapi-visit.o qapi-types.o
-
#######################################################################
# Target-independent parts used in system and user emulation
common-obj-y += qemu-log.o
@@ -107,9 +101,14 @@ version-obj-$(CONFIG_WIN32) += $(BUILD_DIR)/version.o
version-lobj-$(CONFIG_WIN32) += $(BUILD_DIR)/version.lo
######################################################################
+# tracing
+util-obj-y += trace/
+target-obj-y += trace/
+
+######################################################################
# guest agent
# FIXME: a few definitions from qapi-types.o/qapi-visit.o are needed
# by libqemuutil.a. These should be moved to a separate .json schema.
-qga-obj-y = qga/ qapi-types.o qapi-visit.o
+qga-obj-y = qga/
qga-vss-dll-obj-y = qga/
diff --git a/Makefile.target b/Makefile.target
index 137d0b0517..1e8d7abcb3 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -38,7 +38,7 @@ config-target.h: config-target.h-timestamp
config-target.h-timestamp: config-target.mak
ifdef CONFIG_TRACE_SYSTEMTAP
-stap: $(QEMU_PROG).stp-installed $(QEMU_PROG).stp
+stap: $(QEMU_PROG).stp-installed $(QEMU_PROG).stp $(QEMU_PROG)-simpletrace.stp
ifdef CONFIG_USER_ONLY
TARGET_TYPE=user
@@ -64,6 +64,13 @@ $(QEMU_PROG).stp: $(SRC_PATH)/trace-events
--target-type=$(TARGET_TYPE) \
< $< > $@," GEN $(TARGET_DIR)$(QEMU_PROG).stp")
+$(QEMU_PROG)-simpletrace.stp: $(SRC_PATH)/trace-events
+ $(call quiet-command,$(TRACETOOL) \
+ --format=simpletrace-stap \
+ --backends=$(TRACE_BACKENDS) \
+ --probe-prefix=qemu.$(TARGET_TYPE).$(TARGET_NAME) \
+ < $< > $@," GEN $(TARGET_DIR)$(QEMU_PROG)-simpletrace.stp")
+
else
stap:
endif
@@ -152,15 +159,20 @@ endif # CONFIG_SOFTMMU
dummy := $(call unnest-vars,,obj-y)
all-obj-y := $(obj-y)
+target-obj-y :=
block-obj-y :=
common-obj-y :=
include $(SRC_PATH)/Makefile.objs
+dummy := $(call unnest-vars,,target-obj-y)
+target-obj-y-save := $(target-obj-y)
dummy := $(call unnest-vars,.., \
block-obj-y \
block-obj-m \
common-obj-y \
common-obj-m)
+target-obj-y := $(target-obj-y-save)
all-obj-y += $(common-obj-y)
+all-obj-y += $(target-obj-y)
all-obj-$(CONFIG_SOFTMMU) += $(block-obj-y)
# build either PROG or PROGW
@@ -191,6 +203,7 @@ endif
ifdef CONFIG_TRACE_SYSTEMTAP
$(INSTALL_DIR) "$(DESTDIR)$(qemu_datadir)/../systemtap/tapset"
$(INSTALL_DATA) $(QEMU_PROG).stp-installed "$(DESTDIR)$(qemu_datadir)/../systemtap/tapset/$(QEMU_PROG).stp"
+ $(INSTALL_DATA) $(QEMU_PROG)-simpletrace.stp "$(DESTDIR)$(qemu_datadir)/../systemtap/tapset/$(QEMU_PROG)-simpletrace.stp"
endif
GENERATED_HEADERS += config-target.h
diff --git a/VERSION b/VERSION
index 0a7e4e52e5..fa2d855ea8 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-2.0.92
+2.1.50
diff --git a/arch_init.c b/arch_init.c
index 8ddaf35191..28ece769d8 100644
--- a/arch_init.c
+++ b/arch_init.c
@@ -1072,8 +1072,8 @@ static int ram_load(QEMUFile *f, void *opaque, int version_id)
QTAILQ_FOREACH(block, &ram_list.blocks, next) {
if (!strncmp(id, block->idstr, sizeof(id))) {
if (block->length != length) {
- error_report("Length mismatch: %s: " RAM_ADDR_FMT
- " in != " RAM_ADDR_FMT, id, length,
+ error_report("Length mismatch: %s: 0x" RAM_ADDR_FMT
+ " in != 0x" RAM_ADDR_FMT, id, length,
block->length);
ret = -EINVAL;
}
diff --git a/backends/Makefile.objs b/backends/Makefile.objs
index 506a46c33b..31a3a894f5 100644
--- a/backends/Makefile.objs
+++ b/backends/Makefile.objs
@@ -1,7 +1,7 @@
common-obj-y += rng.o rng-egd.o
common-obj-$(CONFIG_POSIX) += rng-random.o
-common-obj-y += msmouse.o
+common-obj-y += msmouse.o testdev.o
common-obj-$(CONFIG_BRLAPI) += baum.o
baum.o-cflags := $(SDL_CFLAGS)
diff --git a/backends/testdev.c b/backends/testdev.c
new file mode 100644
index 0000000000..70d63b3b8d
--- /dev/null
+++ b/backends/testdev.c
@@ -0,0 +1,131 @@
+/*
+ * QEMU Char Device for testsuite control
+ *
+ * Copyright (c) 2014 Red Hat, Inc.
+ *
+ * Author: Paolo Bonzini <pbonzini@redhat.com>
+ *
+ * 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 "qemu-common.h"
+#include "sysemu/char.h"
+
+#define BUF_SIZE 32
+
+typedef struct {
+ CharDriverState *chr;
+ uint8_t in_buf[32];
+ int in_buf_used;
+} TestdevCharState;
+
+/* Try to interpret a whole incoming packet */
+static int testdev_eat_packet(TestdevCharState *testdev)
+{
+ const uint8_t *cur = testdev->in_buf;
+ int len = testdev->in_buf_used;
+ uint8_t c;
+ int arg;
+
+#define EAT(c) do { \
+ if (!len--) { \
+ return 0; \
+ } \
+ c = *cur++; \
+} while (0)
+
+ EAT(c);
+
+ while (isspace(c)) {
+ EAT(c);
+ }
+
+ arg = 0;
+ while (isdigit(c)) {
+ arg = arg * 10 + c - '0';
+ EAT(c);
+ }
+
+ while (isspace(c)) {
+ EAT(c);
+ }
+
+ switch (c) {
+ case 'q':
+ exit((arg << 1) | 1);
+ break;
+ default:
+ break;
+ }
+ return cur - testdev->in_buf;
+}
+
+/* The other end is writing some data. Store it and try to interpret */
+static int testdev_write(CharDriverState *chr, const uint8_t *buf, int len)
+{
+ TestdevCharState *testdev = chr->opaque;
+ int tocopy, eaten, orig_len = len;
+
+ while (len) {
+ /* Complete our buffer as much as possible */
+ tocopy = MIN(len, BUF_SIZE - testdev->in_buf_used);
+
+ memcpy(testdev->in_buf + testdev->in_buf_used, buf, tocopy);
+ testdev->in_buf_used += tocopy;
+ buf += tocopy;
+ len -= tocopy;
+
+ /* Interpret it as much as possible */
+ while (testdev->in_buf_used > 0 &&
+ (eaten = testdev_eat_packet(testdev)) > 0) {
+ memmove(testdev->in_buf, testdev->in_buf + eaten,
+ testdev->in_buf_used - eaten);
+ testdev->in_buf_used -= eaten;
+ }
+ }
+ return orig_len;
+}
+
+static void testdev_close(struct CharDriverState *chr)
+{
+ TestdevCharState *testdev = chr->opaque;
+
+ g_free(testdev);
+}
+
+CharDriverState *chr_testdev_init(void)
+{
+ TestdevCharState *testdev;
+ CharDriverState *chr;
+
+ testdev = g_malloc0(sizeof(TestdevCharState));
+ testdev->chr = chr = g_malloc0(sizeof(CharDriverState));
+
+ chr->opaque = testdev;
+ chr->chr_write = testdev_write;
+ chr->chr_close = testdev_close;
+
+ return chr;
+}
+
+static void register_types(void)
+{
+ register_char_driver_qapi("testdev", CHARDEV_BACKEND_KIND_TESTDEV, NULL);
+}
+
+type_init(register_types);
diff --git a/block-migration.c b/block-migration.c
index 25a03889f4..ba3ed36f77 100644
--- a/block-migration.c
+++ b/block-migration.c
@@ -186,7 +186,7 @@ static int bmds_aio_inflight(BlkMigDevState *bmds, int64_t sector)
{
int64_t chunk = sector / (int64_t)BDRV_SECTORS_PER_DIRTY_CHUNK;
- if ((sector << BDRV_SECTOR_BITS) < bdrv_getlength(bmds->bs)) {
+ if (sector < bdrv_nb_sectors(bmds->bs)) {
return !!(bmds->aio_bitmap[chunk / (sizeof(unsigned long) * 8)] &
(1UL << (chunk % (sizeof(unsigned long) * 8))));
} else {
@@ -223,8 +223,7 @@ static void alloc_aio_bitmap(BlkMigDevState *bmds)
BlockDriverState *bs = bmds->bs;
int64_t bitmap_size;
- bitmap_size = (bdrv_getlength(bs) >> BDRV_SECTOR_BITS) +
- BDRV_SECTORS_PER_DIRTY_CHUNK * 8 - 1;
+ bitmap_size = bdrv_nb_sectors(bs) + BDRV_SECTORS_PER_DIRTY_CHUNK * 8 - 1;
bitmap_size /= BDRV_SECTORS_PER_DIRTY_CHUNK * 8;
bmds->aio_bitmap = g_malloc0(bitmap_size);
@@ -350,7 +349,7 @@ static void init_blk_migration_it(void *opaque, BlockDriverState *bs)
int64_t sectors;
if (!bdrv_is_read_only(bs)) {
- sectors = bdrv_getlength(bs) >> BDRV_SECTOR_BITS;
+ sectors = bdrv_nb_sectors(bs);
if (sectors <= 0) {
return;
}
@@ -799,7 +798,7 @@ static int block_load(QEMUFile *f, void *opaque, int version_id)
if (bs != bs_prev) {
bs_prev = bs;
- total_sectors = bdrv_getlength(bs) >> BDRV_SECTOR_BITS;
+ total_sectors = bdrv_nb_sectors(bs);
if (total_sectors <= 0) {
error_report("Error getting length of block device %s",
device_name);
@@ -861,7 +860,7 @@ static bool block_is_active(void *opaque)
return block_mig_state.blk_enable == 1;
}
-SaveVMHandlers savevm_block_handlers = {
+static SaveVMHandlers savevm_block_handlers = {
.set_params = block_set_params,
.save_live_setup = block_save_setup,
.save_live_iterate = block_save_iterate,
diff --git a/block.c b/block.c
index 3e252a26c2..6fa0201074 100644
--- a/block.c
+++ b/block.c
@@ -57,6 +57,8 @@ struct BdrvDirtyBitmap {
#define NOT_DONE 0x7fffffff /* used while emulated sync operation in progress */
+#define COROUTINE_POOL_RESERVATION 64 /* number of coroutines to reserve */
+
static void bdrv_dev_change_media_cb(BlockDriverState *bs, bool load);
static BlockDriverAIOCB *bdrv_aio_readv_em(BlockDriverState *bs,
int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
@@ -508,19 +510,24 @@ int bdrv_create_file(const char *filename, QemuOpts *opts, Error **errp)
return ret;
}
-int bdrv_refresh_limits(BlockDriverState *bs)
+void bdrv_refresh_limits(BlockDriverState *bs, Error **errp)
{
BlockDriver *drv = bs->drv;
+ Error *local_err = NULL;
memset(&bs->bl, 0, sizeof(bs->bl));
if (!drv) {
- return 0;
+ return;
}
/* Take some limits from the children as a default */
if (bs->file) {
- bdrv_refresh_limits(bs->file);
+ bdrv_refresh_limits(bs->file, &local_err);
+ if (local_err) {
+ error_propagate(errp, local_err);
+ return;
+ }
bs->bl.opt_transfer_length = bs->file->bl.opt_transfer_length;
bs->bl.opt_mem_alignment = bs->file->bl.opt_mem_alignment;
} else {
@@ -528,7 +535,11 @@ int bdrv_refresh_limits(BlockDriverState *bs)
}
if (bs->backing_hd) {
- bdrv_refresh_limits(bs->backing_hd);
+ bdrv_refresh_limits(bs->backing_hd, &local_err);
+ if (local_err) {
+ error_propagate(errp, local_err);
+ return;
+ }
bs->bl.opt_transfer_length =
MAX(bs->bl.opt_transfer_length,
bs->backing_hd->bl.opt_transfer_length);
@@ -539,10 +550,8 @@ int bdrv_refresh_limits(BlockDriverState *bs)
/* Then let the driver override it */
if (drv->bdrv_refresh_limits) {
- return drv->bdrv_refresh_limits(bs);
+ drv->bdrv_refresh_limits(bs, errp);
}
-
- return 0;
}
/*
@@ -694,6 +703,7 @@ static int find_image_format(BlockDriverState *bs, const char *filename,
/**
* Set the current 'total_sectors' value
+ * Return 0 on success, -errno on error.
*/
static int refresh_total_sectors(BlockDriverState *bs, int64_t hint)
{
@@ -993,7 +1003,13 @@ static int bdrv_open_common(BlockDriverState *bs, BlockDriverState *file,
goto free_and_fail;
}
- bdrv_refresh_limits(bs);
+ bdrv_refresh_limits(bs, &local_err);
+ if (local_err) {
+ error_propagate(errp, local_err);
+ ret = -EINVAL;
+ goto free_and_fail;
+ }
+
assert(bdrv_opt_mem_align(bs) != 0);
assert((bs->request_alignment != 0) || bs->sg);
return 0;
@@ -1154,7 +1170,7 @@ void bdrv_set_backing_hd(BlockDriverState *bs, BlockDriverState *backing_hd)
bdrv_op_unblock(bs->backing_hd, BLOCK_OP_TYPE_COMMIT,
bs->backing_blocker);
out:
- bdrv_refresh_limits(bs);
+ bdrv_refresh_limits(bs, NULL);
}
/*
@@ -1300,7 +1316,6 @@ int bdrv_append_temp_snapshot(BlockDriverState *bs, int flags, Error **errp)
error_setg_errno(errp, -total_size, "Could not get image size");
goto out;
}
- total_size &= BDRV_SECTOR_MASK;
/* Create the temporary image */
ret = get_tmp_filename(tmp_filename, PATH_MAX + 1);
@@ -1778,7 +1793,7 @@ void bdrv_reopen_commit(BDRVReopenState *reopen_state)
BDRV_O_CACHE_WB);
reopen_state->bs->read_only = !(reopen_state->flags & BDRV_O_RDWR);
- bdrv_refresh_limits(reopen_state->bs);
+ bdrv_refresh_limits(reopen_state->bs, NULL);
}
/*
@@ -2094,6 +2109,9 @@ int bdrv_attach_dev(BlockDriverState *bs, void *dev)
}
bs->dev = dev;
bdrv_iostatus_reset(bs);
+
+ /* We're expecting I/O from the device so bump up coroutine pool size */
+ qemu_coroutine_adjust_pool_size(COROUTINE_POOL_RESERVATION);
return 0;
}
@@ -2113,6 +2131,7 @@ void bdrv_detach_dev(BlockDriverState *bs, void *dev)
bs->dev_ops = NULL;
bs->dev_opaque = NULL;
bs->guest_block_size = 512;
+ qemu_coroutine_adjust_pool_size(-COROUTINE_POOL_RESERVATION);
}
/* TODO change to return DeviceState * when all users are qdevified */
@@ -2190,6 +2209,9 @@ bool bdrv_dev_is_medium_locked(BlockDriverState *bs)
*/
int bdrv_check(BlockDriverState *bs, BdrvCheckResult *res, BdrvCheckMode fix)
{
+ if (bs->drv == NULL) {
+ return -ENOMEDIUM;
+ }
if (bs->drv->bdrv_check == NULL) {
return -ENOTSUP;
}
@@ -2256,7 +2278,14 @@ int bdrv_commit(BlockDriverState *bs)
}
total_sectors = length >> BDRV_SECTOR_BITS;
- buf = g_malloc(COMMIT_BUF_SECTORS * BDRV_SECTOR_SIZE);
+
+ /* qemu_try_blockalign() for bs will choose an alignment that works for
+ * bs->backing_hd as well, so no need to compare the alignment manually. */
+ buf = qemu_try_blockalign(bs, COMMIT_BUF_SECTORS * BDRV_SECTOR_SIZE);
+ if (buf == NULL) {
+ ret = -ENOMEM;
+ goto ro_cleanup;
+ }
for (sector = 0; sector < total_sectors; sector += n) {
ret = bdrv_is_allocated(bs, sector, COMMIT_BUF_SECTORS, &n);
@@ -2294,7 +2323,7 @@ int bdrv_commit(BlockDriverState *bs)
ret = 0;
ro_cleanup:
- g_free(buf);
+ qemu_vfree(buf);
if (ro) {
/* ignoring error return here */
@@ -2814,18 +2843,16 @@ int bdrv_write_zeroes(BlockDriverState *bs, int64_t sector_num,
*/
int bdrv_make_zero(BlockDriverState *bs, BdrvRequestFlags flags)
{
- int64_t target_size;
- int64_t ret, nb_sectors, sector_num = 0;
+ int64_t target_sectors, ret, nb_sectors, sector_num = 0;
int n;
- target_size = bdrv_getlength(bs);
- if (target_size < 0) {
- return target_size;
+ target_sectors = bdrv_nb_sectors(bs);
+ if (target_sectors < 0) {
+ return target_sectors;
}
- target_size /= BDRV_SECTOR_SIZE;
for (;;) {
- nb_sectors = target_size - sector_num;
+ nb_sectors = target_sectors - sector_num;
if (nb_sectors <= 0) {
return 0;
}
@@ -2955,7 +2982,12 @@ static int coroutine_fn bdrv_co_do_copy_on_readv(BlockDriverState *bs,
cluster_sector_num, cluster_nb_sectors);
iov.iov_len = cluster_nb_sectors * BDRV_SECTOR_SIZE;
- iov.iov_base = bounce_buffer = qemu_blockalign(bs, iov.iov_len);
+ iov.iov_base = bounce_buffer = qemu_try_blockalign(bs, iov.iov_len);
+ if (bounce_buffer == NULL) {
+ ret = -ENOMEM;
+ goto err;
+ }
+
qemu_iovec_init_external(&bounce_qiov, &iov, 1);
ret = drv->bdrv_co_readv(bs, cluster_sector_num, cluster_nb_sectors,
@@ -3043,15 +3075,14 @@ static int coroutine_fn bdrv_aligned_preadv(BlockDriverState *bs,
ret = drv->bdrv_co_readv(bs, sector_num, nb_sectors, qiov);
} else {
/* Read zeros after EOF of growable BDSes */
- int64_t len, total_sectors, max_nb_sectors;
+ int64_t total_sectors, max_nb_sectors;
- len = bdrv_getlength(bs);
- if (len < 0) {
- ret = len;
+ total_sectors = bdrv_nb_sectors(bs);
+ if (total_sectors < 0) {
+ ret = total_sectors;
goto out;
}
- total_sectors = DIV_ROUND_UP(len, BDRV_SECTOR_SIZE);
max_nb_sectors = ROUND_UP(MAX(0, total_sectors - sector_num),
align >> BDRV_SECTOR_BITS);
if (max_nb_sectors > 0) {
@@ -3240,7 +3271,11 @@ static int coroutine_fn bdrv_co_do_write_zeroes(BlockDriverState *bs,
/* Fall back to bounce buffer if write zeroes is unsupported */
iov.iov_len = num * BDRV_SECTOR_SIZE;
if (iov.iov_base == NULL) {
- iov.iov_base = qemu_blockalign(bs, num * BDRV_SECTOR_SIZE);
+ iov.iov_base = qemu_try_blockalign(bs, num * BDRV_SECTOR_SIZE);
+ if (iov.iov_base == NULL) {
+ ret = -ENOMEM;
+ goto fail;
+ }
memset(iov.iov_base, 0, num * BDRV_SECTOR_SIZE);
}
qemu_iovec_init_external(&qiov, &iov, 1);
@@ -3260,6 +3295,7 @@ static int coroutine_fn bdrv_co_do_write_zeroes(BlockDriverState *bs,
nb_sectors -= num;
}
+fail:
qemu_vfree(iov.iov_base);
return ret;
}
@@ -3523,11 +3559,12 @@ int64_t bdrv_get_allocated_file_size(BlockDriverState *bs)
}
/**
- * Length of a file in bytes. Return < 0 if error or unknown.
+ * Return number of sectors on success, -errno on error.
*/
-int64_t bdrv_getlength(BlockDriverState *bs)
+int64_t bdrv_nb_sectors(BlockDriverState *bs)
{
BlockDriver *drv = bs->drv;
+
if (!drv)
return -ENOMEDIUM;
@@ -3537,19 +3574,26 @@ int64_t bdrv_getlength(BlockDriverState *bs)
return ret;
}
}
- return bs->total_sectors * BDRV_SECTOR_SIZE;
+ return bs->total_sectors;
+}
+
+/**
+ * Return length in bytes on success, -errno on error.
+ * The length is always a multiple of BDRV_SECTOR_SIZE.
+ */
+int64_t bdrv_getlength(BlockDriverState *bs)
+{
+ int64_t ret = bdrv_nb_sectors(bs);
+
+ return ret < 0 ? ret : ret * BDRV_SECTOR_SIZE;
}
/* return 0 as number of sectors if no device present or error */
void bdrv_get_geometry(BlockDriverState *bs, uint64_t *nb_sectors_ptr)
{
- int64_t length;
- length = bdrv_getlength(bs);
- if (length < 0)
- length = 0;
- else
- length = length >> BDRV_SECTOR_BITS;
- *nb_sectors_ptr = length;
+ int64_t nb_sectors = bdrv_nb_sectors(bs);
+
+ *nb_sectors_ptr = nb_sectors < 0 ? 0 : nb_sectors;
}
void bdrv_set_on_error(BlockDriverState *bs, BlockdevOnError on_read_error,
@@ -3932,21 +3976,21 @@ static int64_t coroutine_fn bdrv_co_get_block_status(BlockDriverState *bs,
int64_t sector_num,
int nb_sectors, int *pnum)
{
- int64_t length;
+ int64_t total_sectors;
int64_t n;
int64_t ret, ret2;
- length = bdrv_getlength(bs);
- if (length < 0) {
- return length;
+ total_sectors = bdrv_nb_sectors(bs);
+ if (total_sectors < 0) {
+ return total_sectors;
}
- if (sector_num >= (length >> BDRV_SECTOR_BITS)) {
+ if (sector_num >= total_sectors) {
*pnum = 0;
return 0;
}
- n = bs->total_sectors - sector_num;
+ n = total_sectors - sector_num;
if (n < nb_sectors) {
nb_sectors = n;
}
@@ -3981,8 +4025,8 @@ static int64_t coroutine_fn bdrv_co_get_block_status(BlockDriverState *bs,
ret |= BDRV_BLOCK_ZERO;
} else if (bs->backing_hd) {
BlockDriverState *bs2 = bs->backing_hd;
- int64_t length2 = bdrv_getlength(bs2);
- if (length2 >= 0 && sector_num >= (length2 >> BDRV_SECTOR_BITS)) {
+ int64_t nb_sectors2 = bdrv_nb_sectors(bs2);
+ if (nb_sectors2 >= 0 && sector_num >= nb_sectors2) {
ret |= BDRV_BLOCK_ZERO;
}
}
@@ -4594,8 +4638,9 @@ static void bdrv_aio_bh_cb(void *opaque)
{
BlockDriverAIOCBSync *acb = opaque;
- if (!acb->is_write)
+ if (!acb->is_write && acb->ret >= 0) {
qemu_iovec_from_buf(acb->qiov, 0, acb->bounce, acb->qiov->size);
+ }
qemu_vfree(acb->bounce);
acb->common.cb(acb->common.opaque, acb->ret);
qemu_bh_delete(acb->bh);
@@ -4617,10 +4662,12 @@ static BlockDriverAIOCB *bdrv_aio_rw_vector(BlockDriverState *bs,
acb = qemu_aio_get(&bdrv_em_aiocb_info, bs, cb, opaque);
acb->is_write = is_write;
acb->qiov = qiov;
- acb->bounce = qemu_blockalign(bs, qiov->size);
+ acb->bounce = qemu_try_blockalign(bs, qiov->size);
acb->bh = aio_bh_new(bdrv_get_aio_context(bs), bdrv_aio_bh_cb, acb);
- if (is_write) {
+ if (acb->bounce == NULL) {
+ acb->ret = -ENOMEM;
+ } else if (is_write) {
qemu_iovec_to_buf(acb->qiov, 0, acb->bounce, qiov->size);
acb->ret = bs->drv->bdrv_write(bs, sector_num, acb->bounce, nb_sectors);
} else {
@@ -5234,6 +5281,19 @@ void *qemu_blockalign(BlockDriverState *bs, size_t size)
return qemu_memalign(bdrv_opt_mem_align(bs), size);
}
+void *qemu_try_blockalign(BlockDriverState *bs, size_t size)
+{
+ size_t align = bdrv_opt_mem_align(bs);
+
+ /* Ensure that NULL is never returned on success */
+ assert(align > 0);
+ if (size == 0) {
+ size = align;
+ }
+
+ return qemu_try_memalign(align, size);
+}
+
/*
* Check if all memory in this vector is sector aligned.
*/
@@ -5264,13 +5324,12 @@ BdrvDirtyBitmap *bdrv_create_dirty_bitmap(BlockDriverState *bs, int granularity,
granularity >>= BDRV_SECTOR_BITS;
assert(granularity);
- bitmap_size = bdrv_getlength(bs);
+ bitmap_size = bdrv_nb_sectors(bs);
if (bitmap_size < 0) {
error_setg_errno(errp, -bitmap_size, "could not get length of device");
errno = -bitmap_size;
return NULL;
}
- bitmap_size >>= BDRV_SECTOR_BITS;
bitmap = g_malloc0(sizeof(BdrvDirtyBitmap));
bitmap->bitmap = hbitmap_alloc(bitmap_size, ffs(granularity) - 1);
QLIST_INSERT_HEAD(&bs->dirty_bitmaps, bitmap, list);
@@ -5358,6 +5417,9 @@ void bdrv_ref(BlockDriverState *bs)
* deleted. */
void bdrv_unref(BlockDriverState *bs)
{
+ if (!bs) {
+ return;
+ }
assert(bs->refcnt > 0);
if (--bs->refcnt == 0) {
bdrv_delete(bs);
@@ -5578,7 +5640,7 @@ void bdrv_img_create(const char *filename, const char *fmt,
if (size == -1) {
if (backing_file) {
BlockDriverState *bs;
- uint64_t size;
+ int64_t size;
int back_flags;
/* backing files always opened read-only */
@@ -5596,8 +5658,13 @@ void bdrv_img_create(const char *filename, const char *fmt,
local_err = NULL;
goto out;
}
- bdrv_get_geometry(bs, &size);
- size *= 512;
+ size = bdrv_getlength(bs);
+ if (size < 0) {
+ error_setg_errno(errp, -size, "Could not get size of '%s'",
+ backing_file);
+ bdrv_unref(bs);
+ goto out;
+ }
qemu_opt_set_number(opts, BLOCK_OPT_SIZE, size);
diff --git a/block/Makefile.objs b/block/Makefile.objs
index fd88c03ece..858d2b387b 100644
--- a/block/Makefile.objs
+++ b/block/Makefile.objs
@@ -17,6 +17,7 @@ block-obj-$(CONFIG_LIBNFS) += nfs.o
block-obj-$(CONFIG_CURL) += curl.o
block-obj-$(CONFIG_RBD) += rbd.o
block-obj-$(CONFIG_GLUSTERFS) += gluster.o
+block-obj-$(CONFIG_ARCHIPELAGO) += archipelago.o
block-obj-$(CONFIG_LIBSSH2) += ssh.o
endif
@@ -35,5 +36,6 @@ gluster.o-cflags := $(GLUSTERFS_CFLAGS)
gluster.o-libs := $(GLUSTERFS_LIBS)
ssh.o-cflags := $(LIBSSH2_CFLAGS)
ssh.o-libs := $(LIBSSH2_LIBS)
+archipelago.o-libs := $(ARCHIPELAGO_LIBS)
qcow.o-libs := -lz
linux-aio.o-libs := -laio
diff --git a/block/archipelago.c b/block/archipelago.c
new file mode 100644
index 0000000000..6629d03a1d
--- /dev/null
+++ b/block/archipelago.c
@@ -0,0 +1,1069 @@
+/*
+ * QEMU Block driver for Archipelago
+ *
+ * Copyright (C) 2014 Chrysostomos Nanakos <cnanakos@grnet.gr>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ *
+ */
+
+/*
+ * VM Image on Archipelago volume is specified like this:
+ *
+ * file.driver=archipelago,file.volume=<volumename>
+ * [,file.mport=<mapperd_port>[,file.vport=<vlmcd_port>]
+ * [,file.segment=<segment_name>]]
+ *
+ * or
+ *
+ * file=archipelago:<volumename>[/mport=<mapperd_port>[:vport=<vlmcd_port>][:
+ * segment=<segment_name>]]
+ *
+ * 'archipelago' is the protocol.
+ *
+ * 'mport' is the port number on which mapperd is listening. This is optional
+ * and if not specified, QEMU will make Archipelago to use the default port.
+ *
+ * 'vport' is the port number on which vlmcd is listening. This is optional
+ * and if not specified, QEMU will make Archipelago to use the default port.
+ *
+ * 'segment' is the name of the shared memory segment Archipelago stack
+ * is using. This is optional and if not specified, QEMU will make Archipelago
+ * to use the default value, 'archipelago'.
+ *
+ * Examples:
+ *
+ * file.driver=archipelago,file.volume=my_vm_volume
+ * file.driver=archipelago,file.volume=my_vm_volume,file.mport=123
+ * file.driver=archipelago,file.volume=my_vm_volume,file.mport=123,
+ * file.vport=1234
+ * file.driver=archipelago,file.volume=my_vm_volume,file.mport=123,
+ * file.vport=1234,file.segment=my_segment
+ *
+ * or
+ *
+ * file=archipelago:my_vm_volume
+ * file=archipelago:my_vm_volume/mport=123
+ * file=archipelago:my_vm_volume/mport=123:vport=1234
+ * file=archipelago:my_vm_volume/mport=123:vport=1234:segment=my_segment
+ *
+ */
+
+#include "qemu-common.h"
+#include "block/block_int.h"
+#include "qemu/error-report.h"
+#include "qemu/thread.h"
+#include "qapi/qmp/qint.h"
+#include "qapi/qmp/qstring.h"
+#include "qapi/qmp/qjson.h"
+
+#include <inttypes.h>
+#include <xseg/xseg.h>
+#include <xseg/protocol.h>
+
+#define ARCHIP_FD_READ 0
+#define ARCHIP_FD_WRITE 1
+#define MAX_REQUEST_SIZE 524288
+
+#define ARCHIPELAGO_OPT_VOLUME "volume"
+#define ARCHIPELAGO_OPT_SEGMENT "segment"
+#define ARCHIPELAGO_OPT_MPORT "mport"
+#define ARCHIPELAGO_OPT_VPORT "vport"
+#define ARCHIPELAGO_DFL_MPORT 1001
+#define ARCHIPELAGO_DFL_VPORT 501
+
+#define archipelagolog(fmt, ...) \
+ do { \
+ fprintf(stderr, "archipelago\t%-24s: " fmt, __func__, ##__VA_ARGS__); \
+ } while (0)
+
+typedef enum {
+ ARCHIP_OP_READ,
+ ARCHIP_OP_WRITE,
+ ARCHIP_OP_FLUSH,
+ ARCHIP_OP_VOLINFO,
+} ARCHIPCmd;
+
+typedef struct ArchipelagoAIOCB {
+ BlockDriverAIOCB common;
+ QEMUBH *bh;
+ struct BDRVArchipelagoState *s;
+ QEMUIOVector *qiov;
+ ARCHIPCmd cmd;
+ bool cancelled;
+ int status;
+ int64_t size;
+ int64_t ret;
+} ArchipelagoAIOCB;
+
+typedef struct BDRVArchipelagoState {
+ ArchipelagoAIOCB *event_acb;
+ char *volname;
+ char *segment_name;
+ uint64_t size;
+ /* Archipelago specific */
+ struct xseg *xseg;
+ struct xseg_port *port;
+ xport srcport;
+ xport sport;
+ xport mportno;
+ xport vportno;
+ QemuMutex archip_mutex;
+ QemuCond archip_cond;
+ bool is_signaled;
+ /* Request handler specific */
+ QemuThread request_th;
+ QemuCond request_cond;
+ QemuMutex request_mutex;
+ bool th_is_signaled;
+ bool stopping;
+} BDRVArchipelagoState;
+
+typedef struct ArchipelagoSegmentedRequest {
+ size_t count;
+ size_t total;
+ int ref;
+ int failed;
+} ArchipelagoSegmentedRequest;
+
+typedef struct AIORequestData {
+ const char *volname;
+ off_t offset;
+ size_t size;
+ uint64_t bufidx;
+ int ret;
+ int op;
+ ArchipelagoAIOCB *aio_cb;
+ ArchipelagoSegmentedRequest *segreq;
+} AIORequestData;
+
+static void qemu_archipelago_complete_aio(void *opaque);
+
+static void init_local_signal(struct xseg *xseg, xport sport, xport srcport)
+{
+ if (xseg && (sport != srcport)) {
+ xseg_init_local_signal(xseg, srcport);
+ sport = srcport;
+ }
+}
+
+static void archipelago_finish_aiocb(AIORequestData *reqdata)
+{
+ if (reqdata->aio_cb->ret != reqdata->segreq->total) {
+ reqdata->aio_cb->ret = -EIO;
+ } else if (reqdata->aio_cb->ret == reqdata->segreq->total) {
+ reqdata->aio_cb->ret = 0;
+ }
+ reqdata->aio_cb->bh = aio_bh_new(
+ bdrv_get_aio_context(reqdata->aio_cb->common.bs),
+ qemu_archipelago_complete_aio, reqdata
+ );
+ qemu_bh_schedule(reqdata->aio_cb->bh);
+}
+
+static int wait_reply(struct xseg *xseg, xport srcport, struct xseg_port *port,
+ struct xseg_request *expected_req)
+{
+ struct xseg_request *req;
+ xseg_prepare_wait(xseg, srcport);
+ void *psd = xseg_get_signal_desc(xseg, port);
+ while (1) {
+ req = xseg_receive(xseg, srcport, X_NONBLOCK);
+ if (req) {
+ if (req != expected_req) {
+ archipelagolog("Unknown received request\n");
+ xseg_put_request(xseg, req, srcport);
+ } else if (!(req->state & XS_SERVED)) {
+ return -1;
+ } else {
+ break;
+ }
+ }
+ xseg_wait_signal(xseg, psd, 100000UL);
+ }
+ xseg_cancel_wait(xseg, srcport);
+ return 0;
+}
+
+static void xseg_request_handler(void *state)
+{
+ BDRVArchipelagoState *s = (BDRVArchipelagoState *) state;
+ void *psd = xseg_get_signal_desc(s->xseg, s->port);
+ qemu_mutex_lock(&s->request_mutex);
+
+ while (!s->stopping) {
+ struct xseg_request *req;
+ void *data;
+ xseg_prepare_wait(s->xseg, s->srcport);
+ req = xseg_receive(s->xseg, s->srcport, X_NONBLOCK);
+ if (req) {
+ AIORequestData *reqdata;
+ ArchipelagoSegmentedRequest *segreq;
+ xseg_get_req_data(s->xseg, req, (void **)&reqdata);
+
+ switch (reqdata->op) {
+ case ARCHIP_OP_READ:
+ data = xseg_get_data(s->xseg, req);
+ segreq = reqdata->segreq;
+ segreq->count += req->serviced;
+
+ qemu_iovec_from_buf(reqdata->aio_cb->qiov, reqdata->bufidx,
+ data,
+ req->serviced);
+
+ xseg_put_request(s->xseg, req, s->srcport);
+
+ if ((__sync_add_and_fetch(&segreq->ref, -1)) == 0) {
+ if (!segreq->failed) {
+ reqdata->aio_cb->ret = segreq->count;
+ archipelago_finish_aiocb(reqdata);
+ g_free(segreq);
+ } else {
+ g_free(segreq);
+ g_free(reqdata);
+ }
+ } else {
+ g_free(reqdata);
+ }
+ break;
+ case ARCHIP_OP_WRITE:
+ case ARCHIP_OP_FLUSH:
+ segreq = reqdata->segreq;
+ segreq->count += req->serviced;
+ xseg_put_request(s->xseg, req, s->srcport);
+
+ if ((__sync_add_and_fetch(&segreq->ref, -1)) == 0) {
+ if (!segreq->failed) {
+ reqdata->aio_cb->ret = segreq->count;
+ archipelago_finish_aiocb(reqdata);
+ g_free(segreq);
+ } else {
+ g_free(segreq);
+ g_free(reqdata);
+ }
+ } else {
+ g_free(reqdata);
+ }
+ break;
+ case ARCHIP_OP_VOLINFO:
+ s->is_signaled = true;
+ qemu_cond_signal(&s->archip_cond);
+ break;
+ }
+ } else {
+ xseg_wait_signal(s->xseg, psd, 100000UL);
+ }
+ xseg_cancel_wait(s->xseg, s->srcport);
+ }
+
+ s->th_is_signaled = true;
+ qemu_cond_signal(&s->request_cond);
+ qemu_mutex_unlock(&s->request_mutex);
+ qemu_thread_exit(NULL);
+}
+
+static int qemu_archipelago_xseg_init(BDRVArchipelagoState *s)
+{
+ if (xseg_initialize()) {
+ archipelagolog("Cannot initialize XSEG\n");
+ goto err_exit;
+ }
+
+ s->xseg = xseg_join("posix", s->segment_name,
+ "posixfd", NULL);
+ if (!s->xseg) {
+ archipelagolog("Cannot join XSEG shared memory segment\n");
+ goto err_exit;
+ }
+ s->port = xseg_bind_dynport(s->xseg);
+ s->srcport = s->port->portno;
+ init_local_signal(s->xseg, s->sport, s->srcport);
+ return 0;
+
+err_exit:
+ return -1;
+}
+
+static int qemu_archipelago_init(BDRVArchipelagoState *s)
+{
+ int ret;
+
+ ret = qemu_archipelago_xseg_init(s);
+ if (ret < 0) {
+ error_report("Cannot initialize XSEG. Aborting...\n");
+ goto err_exit;
+ }
+
+ qemu_cond_init(&s->archip_cond);
+ qemu_mutex_init(&s->archip_mutex);
+ qemu_cond_init(&s->request_cond);
+ qemu_mutex_init(&s->request_mutex);
+ s->th_is_signaled = false;
+ qemu_thread_create(&s->request_th, "xseg_io_th",
+ (void *) xseg_request_handler,
+ (void *) s, QEMU_THREAD_JOINABLE);
+
+err_exit:
+ return ret;
+}
+
+static void qemu_archipelago_complete_aio(void *opaque)
+{
+ AIORequestData *reqdata = (AIORequestData *) opaque;
+ ArchipelagoAIOCB *aio_cb = (ArchipelagoAIOCB *) reqdata->aio_cb;
+
+ qemu_bh_delete(aio_cb->bh);
+ aio_cb->common.cb(aio_cb->common.opaque, aio_cb->ret);
+ aio_cb->status = 0;
+
+ if (!aio_cb->cancelled) {
+ qemu_aio_release(aio_cb);
+ }
+ g_free(reqdata);
+}
+
+static void xseg_find_port(char *pstr, const char *needle, xport *aport)
+{
+ const char *a;
+ char *endptr = NULL;
+ unsigned long port;
+ if (strstart(pstr, needle, &a)) {
+ if (strlen(a) > 0) {
+ port = strtoul(a, &endptr, 10);
+ if (strlen(endptr)) {
+ *aport = -2;
+ return;
+ }
+ *aport = (xport) port;
+ }
+ }
+}
+
+static void xseg_find_segment(char *pstr, const char *needle,
+ char **segment_name)
+{
+ const char *a;
+ if (strstart(pstr, needle, &a)) {
+ if (strlen(a) > 0) {
+ *segment_name = g_strdup(a);
+ }
+ }
+}
+
+static void parse_filename_opts(const char *filename, Error **errp,
+ char **volume, char **segment_name,
+ xport *mport, xport *vport)
+{
+ const char *start;
+ char *tokens[4], *ds;
+ int idx;
+ xport lmport = NoPort, lvport = NoPort;
+
+ strstart(filename, "archipelago:", &start);
+
+ ds = g_strdup(start);
+ tokens[0] = strtok(ds, "/");
+ tokens[1] = strtok(NULL, ":");
+ tokens[2] = strtok(NULL, ":");
+ tokens[3] = strtok(NULL, "\0");
+
+ if (!strlen(tokens[0])) {
+ error_setg(errp, "volume name must be specified first");
+ g_free(ds);
+ return;
+ }
+
+ for (idx = 1; idx < 4; idx++) {
+ if (tokens[idx] != NULL) {
+ if (strstart(tokens[idx], "mport=", NULL)) {
+ xseg_find_port(tokens[idx], "mport=", &lmport);
+ }
+ if (strstart(tokens[idx], "vport=", NULL)) {
+ xseg_find_port(tokens[idx], "vport=", &lvport);
+ }
+ if (strstart(tokens[idx], "segment=", NULL)) {
+ xseg_find_segment(tokens[idx], "segment=", segment_name);
+ }
+ }
+ }
+
+ if ((lmport == -2) || (lvport == -2)) {
+ error_setg(errp, "mport and/or vport must be set");
+ g_free(ds);
+ return;
+ }
+ *volume = g_strdup(tokens[0]);
+ *mport = lmport;
+ *vport = lvport;
+ g_free(ds);
+}
+
+static void archipelago_parse_filename(const char *filename, QDict *options,
+ Error **errp)
+{
+ const char *start;
+ char *volume = NULL, *segment_name = NULL;
+ xport mport = NoPort, vport = NoPort;
+
+ if (qdict_haskey(options, ARCHIPELAGO_OPT_VOLUME)
+ || qdict_haskey(options, ARCHIPELAGO_OPT_SEGMENT)
+ || qdict_haskey(options, ARCHIPELAGO_OPT_MPORT)
+ || qdict_haskey(options, ARCHIPELAGO_OPT_VPORT)) {
+ error_setg(errp, "volume/mport/vport/segment and a file name may not"
+ " be specified at the same time");
+ return;
+ }
+
+ if (!strstart(filename, "archipelago:", &start)) {
+ error_setg(errp, "File name must start with 'archipelago:'");
+ return;
+ }
+
+ if (!strlen(start) || strstart(start, "/", NULL)) {
+ error_setg(errp, "volume name must be specified");
+ return;
+ }
+
+ parse_filename_opts(filename, errp, &volume, &segment_name, &mport, &vport);
+
+ if (volume) {
+ qdict_put(options, ARCHIPELAGO_OPT_VOLUME, qstring_from_str(volume));
+ g_free(volume);
+ }
+ if (segment_name) {
+ qdict_put(options, ARCHIPELAGO_OPT_SEGMENT,
+ qstring_from_str(segment_name));
+ g_free(segment_name);
+ }
+ if (mport != NoPort) {
+ qdict_put(options, ARCHIPELAGO_OPT_MPORT, qint_from_int(mport));
+ }
+ if (vport != NoPort) {
+ qdict_put(options, ARCHIPELAGO_OPT_VPORT, qint_from_int(vport));
+ }
+}
+
+static QemuOptsList archipelago_runtime_opts = {
+ .name = "archipelago",
+ .head = QTAILQ_HEAD_INITIALIZER(archipelago_runtime_opts.head),
+ .desc = {
+ {
+ .name = ARCHIPELAGO_OPT_VOLUME,
+ .type = QEMU_OPT_STRING,
+ .help = "Name of the volume image",
+ },
+ {
+ .name = ARCHIPELAGO_OPT_SEGMENT,
+ .type = QEMU_OPT_STRING,
+ .help = "Name of the Archipelago shared memory segment",
+ },
+ {
+ .name = ARCHIPELAGO_OPT_MPORT,
+ .type = QEMU_OPT_NUMBER,
+ .help = "Archipelago mapperd port number"
+ },
+ {
+ .name = ARCHIPELAGO_OPT_VPORT,
+ .type = QEMU_OPT_NUMBER,
+ .help = "Archipelago vlmcd port number"
+
+ },
+ { /* end of list */ }
+ },
+};
+
+static int qemu_archipelago_open(BlockDriverState *bs,
+ QDict *options,
+ int bdrv_flags,
+ Error **errp)
+{
+ int ret = 0;
+ const char *volume, *segment_name;
+ QemuOpts *opts;
+ Error *local_err = NULL;
+ BDRVArchipelagoState *s = bs->opaque;
+
+ opts = qemu_opts_create(&archipelago_runtime_opts, NULL, 0, &error_abort);
+ qemu_opts_absorb_qdict(opts, options, &local_err);
+ if (local_err) {
+ error_propagate(errp, local_err);
+ ret = -EINVAL;
+ goto err_exit;
+ }
+
+ s->mportno = qemu_opt_get_number(opts, ARCHIPELAGO_OPT_MPORT,
+ ARCHIPELAGO_DFL_MPORT);
+ s->vportno = qemu_opt_get_number(opts, ARCHIPELAGO_OPT_VPORT,
+ ARCHIPELAGO_DFL_VPORT);
+
+ segment_name = qemu_opt_get(opts, ARCHIPELAGO_OPT_SEGMENT);
+ if (segment_name == NULL) {
+ s->segment_name = g_strdup("archipelago");
+ } else {
+ s->segment_name = g_strdup(segment_name);
+ }
+
+ volume = qemu_opt_get(opts, ARCHIPELAGO_OPT_VOLUME);
+ if (volume == NULL) {
+ error_setg(errp, "archipelago block driver requires the 'volume'"
+ " option");
+ ret = -EINVAL;
+ goto err_exit;
+ }
+ s->volname = g_strdup(volume);
+
+ /* Initialize XSEG, join shared memory segment */
+ ret = qemu_archipelago_init(s);
+ if (ret < 0) {
+ error_setg(errp, "cannot initialize XSEG and join shared "
+ "memory segment");
+ goto err_exit;
+ }
+
+ qemu_opts_del(opts);
+ return 0;
+
+err_exit:
+ g_free(s->volname);
+ g_free(s->segment_name);
+ qemu_opts_del(opts);
+ return ret;
+}
+
+static void qemu_archipelago_close(BlockDriverState *bs)
+{
+ int r, targetlen;
+ char *target;
+ struct xseg_request *req;
+ BDRVArchipelagoState *s = bs->opaque;
+
+ s->stopping = true;
+
+ qemu_mutex_lock(&s->request_mutex);
+ while (!s->th_is_signaled) {
+ qemu_cond_wait(&s->request_cond,
+ &s->request_mutex);
+ }
+ qemu_mutex_unlock(&s->request_mutex);
+ qemu_thread_join(&s->request_th);
+ qemu_cond_destroy(&s->request_cond);
+ qemu_mutex_destroy(&s->request_mutex);
+
+ qemu_cond_destroy(&s->archip_cond);
+ qemu_mutex_destroy(&s->archip_mutex);
+
+ targetlen = strlen(s->volname);
+ req = xseg_get_request(s->xseg, s->srcport, s->vportno, X_ALLOC);
+ if (!req) {
+ archipelagolog("Cannot get XSEG request\n");
+ goto err_exit;
+ }
+ r = xseg_prep_request(s->xseg, req, targetlen, 0);
+ if (r < 0) {
+ xseg_put_request(s->xseg, req, s->srcport);
+ archipelagolog("Cannot prepare XSEG close request\n");
+ goto err_exit;
+ }
+
+ target = xseg_get_target(s->xseg, req);
+ memcpy(target, s->volname, targetlen);
+ req->size = req->datalen;
+ req->offset = 0;
+ req->op = X_CLOSE;
+
+ xport p = xseg_submit(s->xseg, req, s->srcport, X_ALLOC);
+ if (p == NoPort) {
+ xseg_put_request(s->xseg, req, s->srcport);
+ archipelagolog("Cannot submit XSEG close request\n");
+ goto err_exit;
+ }
+
+ xseg_signal(s->xseg, p);
+ wait_reply(s->xseg, s->srcport, s->port, req);
+
+ xseg_put_request(s->xseg, req, s->srcport);
+
+err_exit:
+ g_free(s->volname);
+ g_free(s->segment_name);
+ xseg_quit_local_signal(s->xseg, s->srcport);
+ xseg_leave_dynport(s->xseg, s->port);
+ xseg_leave(s->xseg);
+}
+
+static int qemu_archipelago_create_volume(Error **errp, const char *volname,
+ char *segment_name,
+ uint64_t size, xport mportno,
+ xport vportno)
+{
+ int ret, targetlen;
+ struct xseg *xseg = NULL;
+ struct xseg_request *req;
+ struct xseg_request_clone *xclone;
+ struct xseg_port *port;
+ xport srcport = NoPort, sport = NoPort;
+ char *target;
+
+ /* Try default values if none has been set */
+ if (mportno == (xport) -1) {
+ mportno = ARCHIPELAGO_DFL_MPORT;
+ }
+
+ if (vportno == (xport) -1) {
+ vportno = ARCHIPELAGO_DFL_VPORT;
+ }
+
+ if (xseg_initialize()) {
+ error_setg(errp, "Cannot initialize XSEG");
+ return -1;
+ }
+
+ xseg = xseg_join("posix", segment_name,
+ "posixfd", NULL);
+
+ if (!xseg) {
+ error_setg(errp, "Cannot join XSEG shared memory segment");
+ return -1;
+ }
+
+ port = xseg_bind_dynport(xseg);
+ srcport = port->portno;
+ init_local_signal(xseg, sport, srcport);
+
+ req = xseg_get_request(xseg, srcport, mportno, X_ALLOC);
+ if (!req) {
+ error_setg(errp, "Cannot get XSEG request");
+ return -1;
+ }
+
+ targetlen = strlen(volname);
+ ret = xseg_prep_request(xseg, req, targetlen,
+ sizeof(struct xseg_request_clone));
+ if (ret < 0) {
+ error_setg(errp, "Cannot prepare XSEG request");
+ goto err_exit;
+ }
+
+ target = xseg_get_target(xseg, req);
+ if (!target) {
+ error_setg(errp, "Cannot get XSEG target.\n");
+ goto err_exit;
+ }
+ memcpy(target, volname, targetlen);
+ xclone = (struct xseg_request_clone *) xseg_get_data(xseg, req);
+ memset(xclone->target, 0 , XSEG_MAX_TARGETLEN);
+ xclone->targetlen = 0;
+ xclone->size = size;
+ req->offset = 0;
+ req->size = req->datalen;
+ req->op = X_CLONE;
+
+ xport p = xseg_submit(xseg, req, srcport, X_ALLOC);
+ if (p == NoPort) {
+ error_setg(errp, "Could not submit XSEG request");
+ goto err_exit;
+ }
+ xseg_signal(xseg, p);
+
+ ret = wait_reply(xseg, srcport, port, req);
+ if (ret < 0) {
+ error_setg(errp, "wait_reply() error.");
+ }
+
+ xseg_put_request(xseg, req, srcport);
+ xseg_quit_local_signal(xseg, srcport);
+ xseg_leave_dynport(xseg, port);
+ xseg_leave(xseg);
+ return ret;
+
+err_exit:
+ xseg_put_request(xseg, req, srcport);
+ xseg_quit_local_signal(xseg, srcport);
+ xseg_leave_dynport(xseg, port);
+ xseg_leave(xseg);
+ return -1;
+}
+
+static int qemu_archipelago_create(const char *filename,
+ QemuOpts *options,
+ Error **errp)
+{
+ int ret = 0;
+ uint64_t total_size = 0;
+ char *volname = NULL, *segment_name = NULL;
+ const char *start;
+ xport mport = NoPort, vport = NoPort;
+
+ if (!strstart(filename, "archipelago:", &start)) {
+ error_setg(errp, "File name must start with 'archipelago:'");
+ return -1;
+ }
+
+ if (!strlen(start) || strstart(start, "/", NULL)) {
+ error_setg(errp, "volume name must be specified");
+ return -1;
+ }
+
+ parse_filename_opts(filename, errp, &volname, &segment_name, &mport,
+ &vport);
+ total_size = qemu_opt_get_size_del(options, BLOCK_OPT_SIZE, 0);
+
+ if (segment_name == NULL) {
+ segment_name = g_strdup("archipelago");
+ }
+
+ /* Create an Archipelago volume */
+ ret = qemu_archipelago_create_volume(errp, volname, segment_name,
+ total_size, mport,
+ vport);
+
+ g_free(volname);
+ g_free(segment_name);
+ return ret;
+}
+
+static void qemu_archipelago_aio_cancel(BlockDriverAIOCB *blockacb)
+{
+ ArchipelagoAIOCB *aio_cb = (ArchipelagoAIOCB *) blockacb;
+ aio_cb->cancelled = true;
+ while (aio_cb->status == -EINPROGRESS) {
+ aio_poll(bdrv_get_aio_context(aio_cb->common.bs), true);
+ }
+ qemu_aio_release(aio_cb);
+}
+
+static const AIOCBInfo archipelago_aiocb_info = {
+ .aiocb_size = sizeof(ArchipelagoAIOCB),
+ .cancel = qemu_archipelago_aio_cancel,
+};
+
+static int archipelago_submit_request(BDRVArchipelagoState *s,
+ uint64_t bufidx,
+ size_t count,
+ off_t offset,
+ ArchipelagoAIOCB *aio_cb,
+ ArchipelagoSegmentedRequest *segreq,
+ int op)
+{
+ int ret, targetlen;
+ char *target;
+ void *data = NULL;
+ struct xseg_request *req;
+ AIORequestData *reqdata = g_malloc(sizeof(AIORequestData));
+
+ targetlen = strlen(s->volname);
+ req = xseg_get_request(s->xseg, s->srcport, s->vportno, X_ALLOC);
+ if (!req) {
+ archipelagolog("Cannot get XSEG request\n");
+ goto err_exit2;
+ }
+ ret = xseg_prep_request(s->xseg, req, targetlen, count);
+ if (ret < 0) {
+ archipelagolog("Cannot prepare XSEG request\n");
+ goto err_exit;
+ }
+ target = xseg_get_target(s->xseg, req);
+ if (!target) {
+ archipelagolog("Cannot get XSEG target\n");
+ goto err_exit;
+ }
+ memcpy(target, s->volname, targetlen);
+ req->size = count;
+ req->offset = offset;
+
+ switch (op) {
+ case ARCHIP_OP_READ:
+ req->op = X_READ;
+ break;
+ case ARCHIP_OP_WRITE:
+ req->op = X_WRITE;
+ break;
+ case ARCHIP_OP_FLUSH:
+ req->op = X_FLUSH;
+ break;
+ }
+ reqdata->volname = s->volname;
+ reqdata->offset = offset;
+ reqdata->size = count;
+ reqdata->bufidx = bufidx;
+ reqdata->aio_cb = aio_cb;
+ reqdata->segreq = segreq;
+ reqdata->op = op;
+
+ xseg_set_req_data(s->xseg, req, reqdata);
+ if (op == ARCHIP_OP_WRITE) {
+ data = xseg_get_data(s->xseg, req);
+ if (!data) {
+ archipelagolog("Cannot get XSEG data\n");
+ goto err_exit;
+ }
+ qemu_iovec_to_buf(aio_cb->qiov, bufidx, data, count);
+ }
+
+ xport p = xseg_submit(s->xseg, req, s->srcport, X_ALLOC);
+ if (p == NoPort) {
+ archipelagolog("Could not submit XSEG request\n");
+ goto err_exit;
+ }
+ xseg_signal(s->xseg, p);
+ return 0;
+
+err_exit:
+ g_free(reqdata);
+ xseg_put_request(s->xseg, req, s->srcport);
+ return -EIO;
+err_exit2:
+ g_free(reqdata);
+ return -EIO;
+}
+
+static int archipelago_aio_segmented_rw(BDRVArchipelagoState *s,
+ size_t count,
+ off_t offset,
+ ArchipelagoAIOCB *aio_cb,
+ int op)
+{
+ int i, ret, segments_nr, last_segment_size;
+ ArchipelagoSegmentedRequest *segreq;
+
+ segreq = g_malloc(sizeof(ArchipelagoSegmentedRequest));
+
+ if (op == ARCHIP_OP_FLUSH) {
+ segments_nr = 1;
+ segreq->ref = segments_nr;
+ segreq->total = count;
+ segreq->count = 0;
+ segreq->failed = 0;
+ ret = archipelago_submit_request(s, 0, count, offset, aio_cb,
+ segreq, ARCHIP_OP_FLUSH);
+ if (ret < 0) {
+ goto err_exit;
+ }
+ return 0;
+ }
+
+ segments_nr = (int)(count / MAX_REQUEST_SIZE) + \
+ ((count % MAX_REQUEST_SIZE) ? 1 : 0);
+ last_segment_size = (int)(count % MAX_REQUEST_SIZE);
+
+ segreq->ref = segments_nr;
+ segreq->total = count;
+ segreq->count = 0;
+ segreq->failed = 0;
+
+ for (i = 0; i < segments_nr - 1; i++) {
+ ret = archipelago_submit_request(s, i * MAX_REQUEST_SIZE,
+ MAX_REQUEST_SIZE,
+ offset + i * MAX_REQUEST_SIZE,
+ aio_cb, segreq, op);
+
+ if (ret < 0) {
+ goto err_exit;
+ }
+ }
+
+ if ((segments_nr > 1) && last_segment_size) {
+ ret = archipelago_submit_request(s, i * MAX_REQUEST_SIZE,
+ last_segment_size,
+ offset + i * MAX_REQUEST_SIZE,
+ aio_cb, segreq, op);
+ } else if ((segments_nr > 1) && !last_segment_size) {
+ ret = archipelago_submit_request(s, i * MAX_REQUEST_SIZE,
+ MAX_REQUEST_SIZE,
+ offset + i * MAX_REQUEST_SIZE,
+ aio_cb, segreq, op);
+ } else if (segments_nr == 1) {
+ ret = archipelago_submit_request(s, 0, count, offset, aio_cb,
+ segreq, op);
+ }
+
+ if (ret < 0) {
+ goto err_exit;
+ }
+
+ return 0;
+
+err_exit:
+ __sync_add_and_fetch(&segreq->failed, 1);
+ if (segments_nr == 1) {
+ if (__sync_add_and_fetch(&segreq->ref, -1) == 0) {
+ g_free(segreq);
+ }
+ } else {
+ if ((__sync_add_and_fetch(&segreq->ref, -segments_nr + i)) == 0) {
+ g_free(segreq);
+ }
+ }
+
+ return ret;
+}
+
+static BlockDriverAIOCB *qemu_archipelago_aio_rw(BlockDriverState *bs,
+ int64_t sector_num,
+ QEMUIOVector *qiov,
+ int nb_sectors,
+ BlockDriverCompletionFunc *cb,
+ void *opaque,
+ int op)
+{
+ ArchipelagoAIOCB *aio_cb;
+ BDRVArchipelagoState *s = bs->opaque;
+ int64_t size, off;
+ int ret;
+
+ aio_cb = qemu_aio_get(&archipelago_aiocb_info, bs, cb, opaque);
+ aio_cb->cmd = op;
+ aio_cb->qiov = qiov;
+
+ aio_cb->ret = 0;
+ aio_cb->s = s;
+ aio_cb->cancelled = false;
+ aio_cb->status = -EINPROGRESS;
+
+ off = sector_num * BDRV_SECTOR_SIZE;
+ size = nb_sectors * BDRV_SECTOR_SIZE;
+ aio_cb->size = size;
+
+ ret = archipelago_aio_segmented_rw(s, size, off,
+ aio_cb, op);
+ if (ret < 0) {
+ goto err_exit;
+ }
+ return &aio_cb->common;
+
+err_exit:
+ error_report("qemu_archipelago_aio_rw(): I/O Error\n");
+ qemu_aio_release(aio_cb);
+ return NULL;
+}
+
+static BlockDriverAIOCB *qemu_archipelago_aio_readv(BlockDriverState *bs,
+ int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
+ BlockDriverCompletionFunc *cb, void *opaque)
+{
+ return qemu_archipelago_aio_rw(bs, sector_num, qiov, nb_sectors, cb,
+ opaque, ARCHIP_OP_READ);
+}
+
+static BlockDriverAIOCB *qemu_archipelago_aio_writev(BlockDriverState *bs,
+ int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
+ BlockDriverCompletionFunc *cb, void *opaque)
+{
+ return qemu_archipelago_aio_rw(bs, sector_num, qiov, nb_sectors, cb,
+ opaque, ARCHIP_OP_WRITE);
+}
+
+static int64_t archipelago_volume_info(BDRVArchipelagoState *s)
+{
+ uint64_t size;
+ int ret, targetlen;
+ struct xseg_request *req;
+ struct xseg_reply_info *xinfo;
+ AIORequestData *reqdata = g_malloc(sizeof(AIORequestData));
+
+ const char *volname = s->volname;
+ targetlen = strlen(volname);
+ req = xseg_get_request(s->xseg, s->srcport, s->mportno, X_ALLOC);
+ if (!req) {
+ archipelagolog("Cannot get XSEG request\n");
+ goto err_exit2;
+ }
+ ret = xseg_prep_request(s->xseg, req, targetlen,
+ sizeof(struct xseg_reply_info));
+ if (ret < 0) {
+ archipelagolog("Cannot prepare XSEG request\n");
+ goto err_exit;
+ }
+ char *target = xseg_get_target(s->xseg, req);
+ if (!target) {
+ archipelagolog("Cannot get XSEG target\n");
+ goto err_exit;
+ }
+ memcpy(target, volname, targetlen);
+ req->size = req->datalen;
+ req->offset = 0;
+ req->op = X_INFO;
+
+ reqdata->op = ARCHIP_OP_VOLINFO;
+ reqdata->volname = volname;
+ xseg_set_req_data(s->xseg, req, reqdata);
+
+ xport p = xseg_submit(s->xseg, req, s->srcport, X_ALLOC);
+ if (p == NoPort) {
+ archipelagolog("Cannot submit XSEG request\n");
+ goto err_exit;
+ }
+ xseg_signal(s->xseg, p);
+ qemu_mutex_lock(&s->archip_mutex);
+ while (!s->is_signaled) {
+ qemu_cond_wait(&s->archip_cond, &s->archip_mutex);
+ }
+ s->is_signaled = false;
+ qemu_mutex_unlock(&s->archip_mutex);
+
+ xinfo = (struct xseg_reply_info *) xseg_get_data(s->xseg, req);
+ size = xinfo->size;
+ xseg_put_request(s->xseg, req, s->srcport);
+ g_free(reqdata);
+ s->size = size;
+ return size;
+
+err_exit:
+ xseg_put_request(s->xseg, req, s->srcport);
+err_exit2:
+ g_free(reqdata);
+ return -EIO;
+}
+
+static int64_t qemu_archipelago_getlength(BlockDriverState *bs)
+{
+ int64_t ret;
+ BDRVArchipelagoState *s = bs->opaque;
+
+ ret = archipelago_volume_info(s);
+ return ret;
+}
+
+static QemuOptsList qemu_archipelago_create_opts = {
+ .name = "archipelago-create-opts",
+ .head = QTAILQ_HEAD_INITIALIZER(qemu_archipelago_create_opts.head),
+ .desc = {
+ {
+ .name = BLOCK_OPT_SIZE,
+ .type = QEMU_OPT_SIZE,
+ .help = "Virtual disk size"
+ },
+ { /* end of list */ }
+ }
+};
+
+static BlockDriverAIOCB *qemu_archipelago_aio_flush(BlockDriverState *bs,
+ BlockDriverCompletionFunc *cb, void *opaque)
+{
+ return qemu_archipelago_aio_rw(bs, 0, NULL, 0, cb, opaque,
+ ARCHIP_OP_FLUSH);
+}
+
+static BlockDriver bdrv_archipelago = {
+ .format_name = "archipelago",
+ .protocol_name = "archipelago",
+ .instance_size = sizeof(BDRVArchipelagoState),
+ .bdrv_parse_filename = archipelago_parse_filename,
+ .bdrv_file_open = qemu_archipelago_open,
+ .bdrv_close = qemu_archipelago_close,
+ .bdrv_create = qemu_archipelago_create,
+ .bdrv_getlength = qemu_archipelago_getlength,
+ .bdrv_aio_readv = qemu_archipelago_aio_readv,
+ .bdrv_aio_writev = qemu_archipelago_aio_writev,
+ .bdrv_aio_flush = qemu_archipelago_aio_flush,
+ .bdrv_has_zero_init = bdrv_has_zero_init_1,
+ .create_opts = &qemu_archipelago_create_opts,
+};
+
+static void bdrv_archipelago_init(void)
+{
+ bdrv_register(&bdrv_archipelago);
+}
+
+block_init(bdrv_archipelago_init);
diff --git a/block/blkdebug.c b/block/blkdebug.c
index f51407de3f..1586ed9664 100644
--- a/block/blkdebug.c
+++ b/block/blkdebug.c
@@ -522,6 +522,25 @@ static BlockDriverAIOCB *blkdebug_aio_writev(BlockDriverState *bs,
return bdrv_aio_writev(bs->file, sector_num, qiov, nb_sectors, cb, opaque);
}
+static BlockDriverAIOCB *blkdebug_aio_flush(BlockDriverState *bs,
+ BlockDriverCompletionFunc *cb, void *opaque)
+{
+ BDRVBlkdebugState *s = bs->opaque;
+ BlkdebugRule *rule = NULL;
+
+ QSIMPLEQ_FOREACH(rule, &s->active_rules, active_next) {
+ if (rule->options.inject.sector == -1) {
+ break;
+ }
+ }
+
+ if (rule && rule->options.inject.error) {
+ return inject_error(bs, cb, opaque, rule);
+ }
+
+ return bdrv_aio_flush(bs->file, cb, opaque);
+}
+
static void blkdebug_close(BlockDriverState *bs)
{
@@ -699,6 +718,7 @@ static BlockDriver bdrv_blkdebug = {
.bdrv_aio_readv = blkdebug_aio_readv,
.bdrv_aio_writev = blkdebug_aio_writev,
+ .bdrv_aio_flush = blkdebug_aio_flush,
.bdrv_debug_event = blkdebug_debug_event,
.bdrv_debug_breakpoint = blkdebug_debug_breakpoint,
diff --git a/block/bochs.c b/block/bochs.c
index eba23df335..6674b27438 100644
--- a/block/bochs.c
+++ b/block/bochs.c
@@ -131,7 +131,11 @@ static int bochs_open(BlockDriverState *bs, QDict *options, int flags,
return -EFBIG;
}
- s->catalog_bitmap = g_malloc(s->catalog_size * 4);
+ s->catalog_bitmap = g_try_malloc(s->catalog_size * 4);
+ if (s->catalog_size && s->catalog_bitmap == NULL) {
+ error_setg(errp, "Could not allocate memory for catalog");
+ return -ENOMEM;
+ }
ret = bdrv_pread(bs->file, le32_to_cpu(bochs.header), s->catalog_bitmap,
s->catalog_size * 4);
diff --git a/block/cloop.c b/block/cloop.c
index 8457737922..f328be06f8 100644
--- a/block/cloop.c
+++ b/block/cloop.c
@@ -116,7 +116,12 @@ static int cloop_open(BlockDriverState *bs, QDict *options, int flags,
"try increasing block size");
return -EINVAL;
}
- s->offsets = g_malloc(offsets_size);
+
+ s->offsets = g_try_malloc(offsets_size);
+ if (s->offsets == NULL) {
+ error_setg(errp, "Could not allocate offsets table");
+ return -ENOMEM;
+ }
ret = bdrv_pread(bs->file, 128 + 4 + 4, s->offsets, offsets_size);
if (ret < 0) {
@@ -158,8 +163,20 @@ static int cloop_open(BlockDriverState *bs, QDict *options, int flags,
}
/* initialize zlib engine */
- s->compressed_block = g_malloc(max_compressed_block_size + 1);
- s->uncompressed_block = g_malloc(s->block_size);
+ s->compressed_block = g_try_malloc(max_compressed_block_size + 1);
+ if (s->compressed_block == NULL) {
+ error_setg(errp, "Could not allocate compressed_block");
+ ret = -ENOMEM;
+ goto fail;
+ }
+
+ s->uncompressed_block = g_try_malloc(s->block_size);
+ if (s->uncompressed_block == NULL) {
+ error_setg(errp, "Could not allocate uncompressed_block");
+ ret = -ENOMEM;
+ goto fail;
+ }
+
if (inflateInit(&s->zstream) != Z_OK) {
ret = -EINVAL;
goto fail;
diff --git a/block/curl.c b/block/curl.c
index 79ff2f1e41..d4b85d20a5 100644
--- a/block/curl.c
+++ b/block/curl.c
@@ -640,7 +640,13 @@ static void curl_readv_bh_cb(void *p)
state->buf_start = start;
state->buf_len = acb->end + s->readahead_size;
end = MIN(start + state->buf_len, s->len) - 1;
- state->orig_buf = g_malloc(state->buf_len);
+ state->orig_buf = g_try_malloc(state->buf_len);
+ if (state->buf_len && state->orig_buf == NULL) {
+ curl_clean_state(state);
+ acb->common.cb(acb->common.opaque, -ENOMEM);
+ qemu_aio_release(acb);
+ return;
+ }
state->acb[0] = acb;
snprintf(state->range, 127, "%zd-%zd", start, end);
diff --git a/block/dmg.c b/block/dmg.c
index 1e153cd76d..e455886d2b 100644
--- a/block/dmg.c
+++ b/block/dmg.c
@@ -284,8 +284,15 @@ static int dmg_open(BlockDriverState *bs, QDict *options, int flags,
}
/* initialize zlib engine */
- s->compressed_chunk = g_malloc(max_compressed_size + 1);
- s->uncompressed_chunk = g_malloc(512 * max_sectors_per_chunk);
+ s->compressed_chunk = qemu_try_blockalign(bs->file,
+ max_compressed_size + 1);
+ s->uncompressed_chunk = qemu_try_blockalign(bs->file,
+ 512 * max_sectors_per_chunk);
+ if (s->compressed_chunk == NULL || s->uncompressed_chunk == NULL) {
+ ret = -ENOMEM;
+ goto fail;
+ }
+
if (inflateInit(&s->zstream) != Z_OK) {
ret = -EINVAL;
goto fail;
@@ -302,8 +309,8 @@ fail:
g_free(s->lengths);
g_free(s->sectors);
g_free(s->sectorcounts);
- g_free(s->compressed_chunk);
- g_free(s->uncompressed_chunk);
+ qemu_vfree(s->compressed_chunk);
+ qemu_vfree(s->uncompressed_chunk);
return ret;
}
@@ -426,8 +433,8 @@ static void dmg_close(BlockDriverState *bs)
g_free(s->lengths);
g_free(s->sectors);
g_free(s->sectorcounts);
- g_free(s->compressed_chunk);
- g_free(s->uncompressed_chunk);
+ qemu_vfree(s->compressed_chunk);
+ qemu_vfree(s->uncompressed_chunk);
inflateEnd(&s->zstream);
}
diff --git a/block/iscsi.c b/block/iscsi.c
index f3e83e2332..2c9cfc18eb 100644
--- a/block/iscsi.c
+++ b/block/iscsi.c
@@ -893,7 +893,10 @@ coroutine_fn iscsi_co_write_zeroes(BlockDriverState *bs, int64_t sector_num,
nb_blocks = sector_qemu2lun(nb_sectors, iscsilun);
if (iscsilun->zeroblock == NULL) {
- iscsilun->zeroblock = g_malloc0(iscsilun->block_size);
+ iscsilun->zeroblock = g_try_malloc0(iscsilun->block_size);
+ if (iscsilun->zeroblock == NULL) {
+ return -ENOMEM;
+ }
}
iscsi_co_init_iscsitask(iscsilun, &iTask);
@@ -1450,7 +1453,7 @@ static void iscsi_close(BlockDriverState *bs)
memset(iscsilun, 0, sizeof(IscsiLun));
}
-static int iscsi_refresh_limits(BlockDriverState *bs)
+static void iscsi_refresh_limits(BlockDriverState *bs, Error **errp)
{
IscsiLun *iscsilun = bs->opaque;
@@ -1475,7 +1478,6 @@ static int iscsi_refresh_limits(BlockDriverState *bs)
}
bs->bl.opt_transfer_length = sector_lun2qemu(iscsilun->bl.opt_xfer_len,
iscsilun);
- return 0;
}
/* Since iscsi_open() ignores bdrv_flags, there is nothing to do here in
diff --git a/block/mirror.c b/block/mirror.c
index c7a655fc58..5e7a166b39 100644
--- a/block/mirror.c
+++ b/block/mirror.c
@@ -367,7 +367,12 @@ static void coroutine_fn mirror_run(void *opaque)
}
end = s->common.len >> BDRV_SECTOR_BITS;
- s->buf = qemu_blockalign(bs, s->buf_size);
+ s->buf = qemu_try_blockalign(bs, s->buf_size);
+ if (s->buf == NULL) {
+ ret = -ENOMEM;
+ goto immediate_exit;
+ }
+
sectors_per_chunk = s->granularity >> BDRV_SECTOR_BITS;
mirror_free_init(s);
diff --git a/block/nfs.c b/block/nfs.c
index 8439e0d389..fe46c33709 100644
--- a/block/nfs.c
+++ b/block/nfs.c
@@ -172,7 +172,11 @@ static int coroutine_fn nfs_co_writev(BlockDriverState *bs,
nfs_co_init_task(client, &task);
- buf = g_malloc(nb_sectors * BDRV_SECTOR_SIZE);
+ buf = g_try_malloc(nb_sectors * BDRV_SECTOR_SIZE);
+ if (nb_sectors && buf == NULL) {
+ return -ENOMEM;
+ }
+
qemu_iovec_to_buf(iov, 0, buf, nb_sectors * BDRV_SECTOR_SIZE);
if (nfs_pwrite_async(client->context, client->fh,
diff --git a/block/parallels.c b/block/parallels.c
index 1a5bd350b3..1774ab8e8e 100644
--- a/block/parallels.c
+++ b/block/parallels.c
@@ -30,6 +30,7 @@
/**************************************************************/
#define HEADER_MAGIC "WithoutFreeSpace"
+#define HEADER_MAGIC2 "WithouFreSpacExt"
#define HEADER_VERSION 2
#define HEADER_SIZE 64
@@ -41,8 +42,10 @@ struct parallels_header {
uint32_t cylinders;
uint32_t tracks;
uint32_t catalog_entries;
- uint32_t nb_sectors;
- char padding[24];
+ uint64_t nb_sectors;
+ uint32_t inuse;
+ uint32_t data_off;
+ char padding[12];
} QEMU_PACKED;
typedef struct BDRVParallelsState {
@@ -52,6 +55,8 @@ typedef struct BDRVParallelsState {
unsigned int catalog_size;
unsigned int tracks;
+
+ unsigned int off_multiplier;
} BDRVParallelsState;
static int parallels_probe(const uint8_t *buf, int buf_size, const char *filename)
@@ -59,11 +64,12 @@ static int parallels_probe(const uint8_t *buf, int buf_size, const char *filenam
const struct parallels_header *ph = (const void *)buf;
if (buf_size < HEADER_SIZE)
- return 0;
+ return 0;
- if (!memcmp(ph->magic, HEADER_MAGIC, 16) &&
- (le32_to_cpu(ph->version) == HEADER_VERSION))
- return 100;
+ if ((!memcmp(ph->magic, HEADER_MAGIC, 16) ||
+ !memcmp(ph->magic, HEADER_MAGIC2, 16)) &&
+ (le32_to_cpu(ph->version) == HEADER_VERSION))
+ return 100;
return 0;
}
@@ -83,14 +89,19 @@ static int parallels_open(BlockDriverState *bs, QDict *options, int flags,
goto fail;
}
- if (memcmp(ph.magic, HEADER_MAGIC, 16) ||
- (le32_to_cpu(ph.version) != HEADER_VERSION)) {
- error_setg(errp, "Image not in Parallels format");
- ret = -EINVAL;
- goto fail;
- }
+ bs->total_sectors = le64_to_cpu(ph.nb_sectors);
- bs->total_sectors = le32_to_cpu(ph.nb_sectors);
+ if (le32_to_cpu(ph.version) != HEADER_VERSION) {
+ goto fail_format;
+ }
+ if (!memcmp(ph.magic, HEADER_MAGIC, 16)) {
+ s->off_multiplier = 1;
+ bs->total_sectors = 0xffffffff & bs->total_sectors;
+ } else if (!memcmp(ph.magic, HEADER_MAGIC2, 16)) {
+ s->off_multiplier = le32_to_cpu(ph.tracks);
+ } else {
+ goto fail_format;
+ }
s->tracks = le32_to_cpu(ph.tracks);
if (s->tracks == 0) {
@@ -98,6 +109,11 @@ static int parallels_open(BlockDriverState *bs, QDict *options, int flags,
ret = -EINVAL;
goto fail;
}
+ if (s->tracks > INT32_MAX/513) {
+ error_setg(errp, "Invalid image: Too big cluster");
+ ret = -EFBIG;
+ goto fail;
+ }
s->catalog_size = le32_to_cpu(ph.catalog_entries);
if (s->catalog_size > INT_MAX / 4) {
@@ -105,7 +121,11 @@ static int parallels_open(BlockDriverState *bs, QDict *options, int flags,
ret = -EFBIG;
goto fail;
}
- s->catalog_bitmap = g_malloc(s->catalog_size * 4);
+ s->catalog_bitmap = g_try_malloc(s->catalog_size * 4);
+ if (s->catalog_size && s->catalog_bitmap == NULL) {
+ ret = -ENOMEM;
+ goto fail;
+ }
ret = bdrv_pread(bs->file, 64, s->catalog_bitmap, s->catalog_size * 4);
if (ret < 0) {
@@ -113,11 +133,14 @@ static int parallels_open(BlockDriverState *bs, QDict *options, int flags,
}
for (i = 0; i < s->catalog_size; i++)
- le32_to_cpus(&s->catalog_bitmap[i]);
+ le32_to_cpus(&s->catalog_bitmap[i]);
qemu_co_mutex_init(&s->lock);
return 0;
+fail_format:
+ error_setg(errp, "Image not in Parallels format");
+ ret = -EINVAL;
fail:
g_free(s->catalog_bitmap);
return ret;
@@ -133,8 +156,9 @@ static int64_t seek_to_sector(BlockDriverState *bs, int64_t sector_num)
/* not allocated */
if ((index > s->catalog_size) || (s->catalog_bitmap[index] == 0))
- return -1;
- return (uint64_t)(s->catalog_bitmap[index] + offset) * 512;
+ return -1;
+ return
+ ((uint64_t)s->catalog_bitmap[index] * s->off_multiplier + offset) * 512;
}
static int parallels_read(BlockDriverState *bs, int64_t sector_num,
diff --git a/block/qapi.c b/block/qapi.c
index f44f6b4012..79d1e6a9f4 100644
--- a/block/qapi.c
+++ b/block/qapi.c
@@ -28,6 +28,13 @@
#include "qapi-visit.h"
#include "qapi/qmp-output-visitor.h"
#include "qapi/qmp/types.h"
+#ifdef __linux__
+#include <linux/fs.h>
+#include <sys/ioctl.h>
+#ifndef FS_NOCOW_FL
+#define FS_NOCOW_FL 0x00800000 /* Do not cow file */
+#endif
+#endif
BlockDeviceInfo *bdrv_block_device_info(BlockDriverState *bs)
{
@@ -165,19 +172,28 @@ void bdrv_query_image_info(BlockDriverState *bs,
ImageInfo **p_info,
Error **errp)
{
- uint64_t total_sectors;
+ int64_t size;
const char *backing_filename;
char backing_filename2[1024];
BlockDriverInfo bdi;
int ret;
Error *err = NULL;
- ImageInfo *info = g_new0(ImageInfo, 1);
-
- bdrv_get_geometry(bs, &total_sectors);
+ ImageInfo *info;
+#ifdef __linux__
+ int fd, attr;
+#endif
+
+ size = bdrv_getlength(bs);
+ if (size < 0) {
+ error_setg_errno(errp, -size, "Can't get size of device '%s'",
+ bdrv_get_device_name(bs));
+ return;
+ }
+ info = g_new0(ImageInfo, 1);
info->filename = g_strdup(bs->filename);
info->format = g_strdup(bdrv_get_format_name(bs));
- info->virtual_size = total_sectors * 512;
+ info->virtual_size = size;
info->actual_size = bdrv_get_allocated_file_size(bs);
info->has_actual_size = info->actual_size >= 0;
if (bdrv_is_encrypted(bs)) {
@@ -195,6 +211,18 @@ void bdrv_query_image_info(BlockDriverState *bs,
info->format_specific = bdrv_get_specific_info(bs);
info->has_format_specific = info->format_specific != NULL;
+#ifdef __linux__
+ /* get NOCOW info */
+ fd = qemu_open(bs->filename, O_RDONLY | O_NONBLOCK);
+ if (fd >= 0) {
+ if (ioctl(fd, FS_IOC_GETFLAGS, &attr) == 0 && (attr & FS_NOCOW_FL)) {
+ info->has_nocow = true;
+ info->nocow = true;
+ }
+ qemu_close(fd);
+ }
+#endif
+
backing_filename = bs->backing_file;
if (backing_filename[0] != '\0') {
info->backing_filename = g_strdup(backing_filename);
@@ -625,4 +653,8 @@ void bdrv_image_info_dump(fprintf_function func_fprintf, void *f,
func_fprintf(f, "Format specific information:\n");
bdrv_image_info_specific_dump(func_fprintf, f, info->format_specific);
}
+
+ if (info->has_nocow && info->nocow) {
+ func_fprintf(f, "NOCOW flag: set\n");
+ }
}
diff --git a/block/qcow.c b/block/qcow.c
index a874056cf3..67332f03c1 100644
--- a/block/qcow.c
+++ b/block/qcow.c
@@ -182,7 +182,12 @@ static int qcow_open(BlockDriverState *bs, QDict *options, int flags,
}
s->l1_table_offset = header.l1_table_offset;
- s->l1_table = g_malloc(s->l1_size * sizeof(uint64_t));
+ s->l1_table = g_try_malloc(s->l1_size * sizeof(uint64_t));
+ if (s->l1_table == NULL) {
+ error_setg(errp, "Could not allocate memory for L1 table");
+ ret = -ENOMEM;
+ goto fail;
+ }
ret = bdrv_pread(bs->file, s->l1_table_offset, s->l1_table,
s->l1_size * sizeof(uint64_t));
@@ -193,8 +198,16 @@ static int qcow_open(BlockDriverState *bs, QDict *options, int flags,
for(i = 0;i < s->l1_size; i++) {
be64_to_cpus(&s->l1_table[i]);
}
- /* alloc L2 cache */
- s->l2_cache = g_malloc(s->l2_size * L2_CACHE_SIZE * sizeof(uint64_t));
+
+ /* alloc L2 cache (max. 64k * 16 * 8 = 8 MB) */
+ s->l2_cache =
+ qemu_try_blockalign(bs->file,
+ s->l2_size * L2_CACHE_SIZE * sizeof(uint64_t));
+ if (s->l2_cache == NULL) {
+ error_setg(errp, "Could not allocate L2 table cache");
+ ret = -ENOMEM;
+ goto fail;
+ }
s->cluster_cache = g_malloc(s->cluster_size);
s->cluster_data = g_malloc(s->cluster_size);
s->cluster_cache_offset = -1;
@@ -226,7 +239,7 @@ static int qcow_open(BlockDriverState *bs, QDict *options, int flags,
fail:
g_free(s->l1_table);
- g_free(s->l2_cache);
+ qemu_vfree(s->l2_cache);
g_free(s->cluster_cache);
g_free(s->cluster_data);
return ret;
@@ -517,7 +530,10 @@ static coroutine_fn int qcow_co_readv(BlockDriverState *bs, int64_t sector_num,
void *orig_buf;
if (qiov->niov > 1) {
- buf = orig_buf = qemu_blockalign(bs, qiov->size);
+ buf = orig_buf = qemu_try_blockalign(bs, qiov->size);
+ if (buf == NULL) {
+ return -ENOMEM;
+ }
} else {
orig_buf = NULL;
buf = (uint8_t *)qiov->iov->iov_base;
@@ -619,7 +635,10 @@ static coroutine_fn int qcow_co_writev(BlockDriverState *bs, int64_t sector_num,
s->cluster_cache_offset = -1; /* disable compressed cache */
if (qiov->niov > 1) {
- buf = orig_buf = qemu_blockalign(bs, qiov->size);
+ buf = orig_buf = qemu_try_blockalign(bs, qiov->size);
+ if (buf == NULL) {
+ return -ENOMEM;
+ }
qemu_iovec_to_buf(qiov, 0, buf, qiov->size);
} else {
orig_buf = NULL;
@@ -685,7 +704,7 @@ static void qcow_close(BlockDriverState *bs)
BDRVQcowState *s = bs->opaque;
g_free(s->l1_table);
- g_free(s->l2_cache);
+ qemu_vfree(s->l2_cache);
g_free(s->cluster_cache);
g_free(s->cluster_data);
diff --git a/block/qcow2-cache.c b/block/qcow2-cache.c
index 8ecbb5bc00..5353b44828 100644
--- a/block/qcow2-cache.c
+++ b/block/qcow2-cache.c
@@ -53,10 +53,21 @@ Qcow2Cache *qcow2_cache_create(BlockDriverState *bs, int num_tables)
c->entries = g_malloc0(sizeof(*c->entries) * num_tables);
for (i = 0; i < c->size; i++) {
- c->entries[i].table = qemu_blockalign(bs, s->cluster_size);
+ c->entries[i].table = qemu_try_blockalign(bs->file, s->cluster_size);
+ if (c->entries[i].table == NULL) {
+ goto fail;
+ }
}
return c;
+
+fail:
+ for (i = 0; i < c->size; i++) {
+ qemu_vfree(c->entries[i].table);
+ }
+ g_free(c->entries);
+ g_free(c);
+ return NULL;
}
int qcow2_cache_destroy(BlockDriverState* bs, Qcow2Cache *c)
diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c
index 4208dc08b5..5b36018b3e 100644
--- a/block/qcow2-cluster.c
+++ b/block/qcow2-cluster.c
@@ -72,14 +72,20 @@ int qcow2_grow_l1_table(BlockDriverState *bs, uint64_t min_size,
#endif
new_l1_size2 = sizeof(uint64_t) * new_l1_size;
- new_l1_table = g_malloc0(align_offset(new_l1_size2, 512));
+ new_l1_table = qemu_try_blockalign(bs->file,
+ align_offset(new_l1_size2, 512));
+ if (new_l1_table == NULL) {
+ return -ENOMEM;
+ }
+ memset(new_l1_table, 0, align_offset(new_l1_size2, 512));
+
memcpy(new_l1_table, s->l1_table, s->l1_size * sizeof(uint64_t));
/* write new table (align to cluster) */
BLKDBG_EVENT(bs->file, BLKDBG_L1_GROW_ALLOC_TABLE);
new_l1_table_offset = qcow2_alloc_clusters(bs, new_l1_size2);
if (new_l1_table_offset < 0) {
- g_free(new_l1_table);
+ qemu_vfree(new_l1_table);
return new_l1_table_offset;
}
@@ -113,7 +119,7 @@ int qcow2_grow_l1_table(BlockDriverState *bs, uint64_t min_size,
if (ret < 0) {
goto fail;
}
- g_free(s->l1_table);
+ qemu_vfree(s->l1_table);
old_l1_table_offset = s->l1_table_offset;
s->l1_table_offset = new_l1_table_offset;
s->l1_table = new_l1_table;
@@ -123,7 +129,7 @@ int qcow2_grow_l1_table(BlockDriverState *bs, uint64_t min_size,
QCOW2_DISCARD_OTHER);
return 0;
fail:
- g_free(new_l1_table);
+ qemu_vfree(new_l1_table);
qcow2_free_clusters(bs, new_l1_table_offset, new_l1_size2,
QCOW2_DISCARD_OTHER);
return ret;
@@ -372,7 +378,10 @@ static int coroutine_fn copy_sectors(BlockDriverState *bs,
}
iov.iov_len = n * BDRV_SECTOR_SIZE;
- iov.iov_base = qemu_blockalign(bs, iov.iov_len);
+ iov.iov_base = qemu_try_blockalign(bs, iov.iov_len);
+ if (iov.iov_base == NULL) {
+ return -ENOMEM;
+ }
qemu_iovec_init_external(&qiov, &iov, 1);
@@ -702,7 +711,11 @@ int qcow2_alloc_cluster_link_l2(BlockDriverState *bs, QCowL2Meta *m)
trace_qcow2_cluster_link_l2(qemu_coroutine_self(), m->nb_clusters);
assert(m->nb_clusters > 0);
- old_cluster = g_malloc(m->nb_clusters * sizeof(uint64_t));
+ old_cluster = g_try_malloc(m->nb_clusters * sizeof(uint64_t));
+ if (old_cluster == NULL) {
+ ret = -ENOMEM;
+ goto err;
+ }
/* copy content of unmodified sectors */
ret = perform_cow(bs, m, &m->cow_start);
@@ -1106,6 +1119,17 @@ static int handle_alloc(BlockDriverState *bs, uint64_t guest_offset,
return 0;
}
+ /* !*host_offset would overwrite the image header and is reserved for "no
+ * host offset preferred". If 0 was a valid host offset, it'd trigger the
+ * following overlap check; do that now to avoid having an invalid value in
+ * *host_offset. */
+ if (!alloc_cluster_offset) {
+ ret = qcow2_pre_write_overlap_check(bs, 0, alloc_cluster_offset,
+ nb_clusters * s->cluster_size);
+ assert(ret < 0);
+ goto fail;
+ }
+
/*
* Save info needed for meta data update.
*
@@ -1562,7 +1586,10 @@ static int expand_zero_clusters_in_l1(BlockDriverState *bs, uint64_t *l1_table,
if (!is_active_l1) {
/* inactive L2 tables require a buffer to be stored in when loading
* them from disk */
- l2_table = qemu_blockalign(bs, s->cluster_size);
+ l2_table = qemu_try_blockalign(bs->file, s->cluster_size);
+ if (l2_table == NULL) {
+ return -ENOMEM;
+ }
}
for (i = 0; i < l1_size; i++) {
@@ -1740,7 +1767,11 @@ int qcow2_expand_zero_clusters(BlockDriverState *bs)
nb_clusters = size_to_clusters(s, bs->file->total_sectors *
BDRV_SECTOR_SIZE);
- expanded_clusters = g_malloc0((nb_clusters + 7) / 8);
+ expanded_clusters = g_try_malloc0((nb_clusters + 7) / 8);
+ if (expanded_clusters == NULL) {
+ ret = -ENOMEM;
+ goto fail;
+ }
ret = expand_zero_clusters_in_l1(bs, s->l1_table, s->l1_size,
&expanded_clusters, &nb_clusters);
diff --git a/block/qcow2-refcount.c b/block/qcow2-refcount.c
index cc6cf743d6..3b7747048e 100644
--- a/block/qcow2-refcount.c
+++ b/block/qcow2-refcount.c
@@ -46,19 +46,25 @@ int qcow2_refcount_init(BlockDriverState *bs)
assert(s->refcount_table_size <= INT_MAX / sizeof(uint64_t));
refcount_table_size2 = s->refcount_table_size * sizeof(uint64_t);
- s->refcount_table = g_malloc(refcount_table_size2);
+ s->refcount_table = g_try_malloc(refcount_table_size2);
+
if (s->refcount_table_size > 0) {
+ if (s->refcount_table == NULL) {
+ ret = -ENOMEM;
+ goto fail;
+ }
BLKDBG_EVENT(bs->file, BLKDBG_REFTABLE_LOAD);
ret = bdrv_pread(bs->file, s->refcount_table_offset,
s->refcount_table, refcount_table_size2);
- if (ret != refcount_table_size2)
+ if (ret < 0) {
goto fail;
+ }
for(i = 0; i < s->refcount_table_size; i++)
be64_to_cpus(&s->refcount_table[i]);
}
return 0;
fail:
- return -ENOMEM;
+ return ret;
}
void qcow2_refcount_close(BlockDriverState *bs)
@@ -344,8 +350,14 @@ static int alloc_refcount_block(BlockDriverState *bs,
uint64_t meta_offset = (blocks_used * refcount_block_clusters) *
s->cluster_size;
uint64_t table_offset = meta_offset + blocks_clusters * s->cluster_size;
- uint16_t *new_blocks = g_malloc0(blocks_clusters * s->cluster_size);
- uint64_t *new_table = g_malloc0(table_size * sizeof(uint64_t));
+ uint64_t *new_table = g_try_malloc0(table_size * sizeof(uint64_t));
+ uint16_t *new_blocks = g_try_malloc0(blocks_clusters * s->cluster_size);
+
+ assert(table_size > 0 && blocks_clusters > 0);
+ if (new_table == NULL || new_blocks == NULL) {
+ ret = -ENOMEM;
+ goto fail_table;
+ }
/* Fill the new refcount table */
memcpy(new_table, s->refcount_table,
@@ -369,6 +381,7 @@ static int alloc_refcount_block(BlockDriverState *bs,
ret = bdrv_pwrite_sync(bs->file, meta_offset, new_blocks,
blocks_clusters * s->cluster_size);
g_free(new_blocks);
+ new_blocks = NULL;
if (ret < 0) {
goto fail_table;
}
@@ -424,6 +437,7 @@ static int alloc_refcount_block(BlockDriverState *bs,
return -EAGAIN;
fail_table:
+ g_free(new_blocks);
g_free(new_table);
fail_block:
if (*refcount_block != NULL) {
@@ -847,7 +861,8 @@ int qcow2_update_snapshot_refcount(BlockDriverState *bs,
int64_t l1_table_offset, int l1_size, int addend)
{
BDRVQcowState *s = bs->opaque;
- uint64_t *l1_table, *l2_table, l2_offset, offset, l1_size2, l1_allocated;
+ uint64_t *l1_table, *l2_table, l2_offset, offset, l1_size2;
+ bool l1_allocated = false;
int64_t old_offset, old_l2_offset;
int i, j, l1_modified = 0, nb_csectors, refcount;
int ret;
@@ -862,8 +877,12 @@ int qcow2_update_snapshot_refcount(BlockDriverState *bs,
* l1_table_offset when it is the current s->l1_table_offset! Be careful
* when changing this! */
if (l1_table_offset != s->l1_table_offset) {
- l1_table = g_malloc0(align_offset(l1_size2, 512));
- l1_allocated = 1;
+ l1_table = g_try_malloc0(align_offset(l1_size2, 512));
+ if (l1_size2 && l1_table == NULL) {
+ ret = -ENOMEM;
+ goto fail;
+ }
+ l1_allocated = true;
ret = bdrv_pread(bs->file, l1_table_offset, l1_table, l1_size2);
if (ret < 0) {
@@ -875,7 +894,7 @@ int qcow2_update_snapshot_refcount(BlockDriverState *bs,
} else {
assert(l1_size == s->l1_size);
l1_table = s->l1_table;
- l1_allocated = 0;
+ l1_allocated = false;
}
for(i = 0; i < l1_size; i++) {
@@ -1197,7 +1216,11 @@ static int check_refcounts_l1(BlockDriverState *bs,
if (l1_size2 == 0) {
l1_table = NULL;
} else {
- l1_table = g_malloc(l1_size2);
+ l1_table = g_try_malloc(l1_size2);
+ if (l1_table == NULL) {
+ ret = -ENOMEM;
+ goto fail;
+ }
if (bdrv_pread(bs->file, l1_table_offset,
l1_table, l1_size2) != l1_size2)
goto fail;
@@ -1501,7 +1524,11 @@ int qcow2_check_refcounts(BlockDriverState *bs, BdrvCheckResult *res,
return -EFBIG;
}
- refcount_table = g_malloc0(nb_clusters * sizeof(uint16_t));
+ refcount_table = g_try_malloc0(nb_clusters * sizeof(uint16_t));
+ if (nb_clusters && refcount_table == NULL) {
+ res->check_errors++;
+ return -ENOMEM;
+ }
res->bfi.total_clusters =
size_to_clusters(s, bs->total_sectors * BDRV_SECTOR_SIZE);
@@ -1753,9 +1780,13 @@ int qcow2_check_metadata_overlap(BlockDriverState *bs, int ign, int64_t offset,
uint64_t l1_ofs = s->snapshots[i].l1_table_offset;
uint32_t l1_sz = s->snapshots[i].l1_size;
uint64_t l1_sz2 = l1_sz * sizeof(uint64_t);
- uint64_t *l1 = g_malloc(l1_sz2);
+ uint64_t *l1 = g_try_malloc(l1_sz2);
int ret;
+ if (l1_sz2 && l1 == NULL) {
+ return -ENOMEM;
+ }
+
ret = bdrv_pread(bs->file, l1_ofs, l1, l1_sz2);
if (ret < 0) {
g_free(l1);
diff --git a/block/qcow2-snapshot.c b/block/qcow2-snapshot.c
index 0aa9defbe2..f67b47282f 100644
--- a/block/qcow2-snapshot.c
+++ b/block/qcow2-snapshot.c
@@ -381,7 +381,12 @@ int qcow2_snapshot_create(BlockDriverState *bs, QEMUSnapshotInfo *sn_info)
sn->l1_table_offset = l1_table_offset;
sn->l1_size = s->l1_size;
- l1_table = g_malloc(s->l1_size * sizeof(uint64_t));
+ l1_table = g_try_malloc(s->l1_size * sizeof(uint64_t));
+ if (s->l1_size && l1_table == NULL) {
+ ret = -ENOMEM;
+ goto fail;
+ }
+
for(i = 0; i < s->l1_size; i++) {
l1_table[i] = cpu_to_be64(s->l1_table[i]);
}
@@ -499,7 +504,11 @@ int qcow2_snapshot_goto(BlockDriverState *bs, const char *snapshot_id)
* Decrease the refcount referenced by the old one only when the L1
* table is overwritten.
*/
- sn_l1_table = g_malloc0(cur_l1_bytes);
+ sn_l1_table = g_try_malloc0(cur_l1_bytes);
+ if (cur_l1_bytes && sn_l1_table == NULL) {
+ ret = -ENOMEM;
+ goto fail;
+ }
ret = bdrv_pread(bs->file, sn->l1_table_offset, sn_l1_table, sn_l1_bytes);
if (ret < 0) {
@@ -698,17 +707,21 @@ int qcow2_snapshot_load_tmp(BlockDriverState *bs,
return -EFBIG;
}
new_l1_bytes = sn->l1_size * sizeof(uint64_t);
- new_l1_table = g_malloc0(align_offset(new_l1_bytes, 512));
+ new_l1_table = qemu_try_blockalign(bs->file,
+ align_offset(new_l1_bytes, 512));
+ if (new_l1_table == NULL) {
+ return -ENOMEM;
+ }
ret = bdrv_pread(bs->file, sn->l1_table_offset, new_l1_table, new_l1_bytes);
if (ret < 0) {
error_setg(errp, "Failed to read l1 table for snapshot");
- g_free(new_l1_table);
+ qemu_vfree(new_l1_table);
return ret;
}
/* Switch the L1 table */
- g_free(s->l1_table);
+ qemu_vfree(s->l1_table);
s->l1_size = sn->l1_size;
s->l1_table_offset = sn->l1_table_offset;
diff --git a/block/qcow2.c b/block/qcow2.c
index b0faa6917b..435e0e11d0 100644
--- a/block/qcow2.c
+++ b/block/qcow2.c
@@ -210,20 +210,31 @@ static void GCC_FMT_ATTR(3, 4) report_unsupported(BlockDriverState *bs,
static void report_unsupported_feature(BlockDriverState *bs,
Error **errp, Qcow2Feature *table, uint64_t mask)
{
+ char *features = g_strdup("");
+ char *old;
+
while (table && table->name[0] != '\0') {
if (table->type == QCOW2_FEAT_TYPE_INCOMPATIBLE) {
- if (mask & (1 << table->bit)) {
- report_unsupported(bs, errp, "%.46s", table->name);
- mask &= ~(1 << table->bit);
+ if (mask & (1ULL << table->bit)) {
+ old = features;
+ features = g_strdup_printf("%s%s%.46s", old, *old ? ", " : "",
+ table->name);
+ g_free(old);
+ mask &= ~(1ULL << table->bit);
}
}
table++;
}
if (mask) {
- report_unsupported(bs, errp, "Unknown incompatible feature: %" PRIx64,
- mask);
+ old = features;
+ features = g_strdup_printf("%s%sUnknown incompatible feature: %" PRIx64,
+ old, *old ? ", " : "", mask);
+ g_free(old);
}
+
+ report_unsupported(bs, errp, "%s", features);
+ g_free(features);
}
/*
@@ -677,8 +688,13 @@ static int qcow2_open(BlockDriverState *bs, QDict *options, int flags,
if (s->l1_size > 0) {
- s->l1_table = g_malloc0(
+ s->l1_table = qemu_try_blockalign(bs->file,
align_offset(s->l1_size * sizeof(uint64_t), 512));
+ if (s->l1_table == NULL) {
+ error_setg(errp, "Could not allocate L1 table");
+ ret = -ENOMEM;
+ goto fail;
+ }
ret = bdrv_pread(bs->file, s->l1_table_offset, s->l1_table,
s->l1_size * sizeof(uint64_t));
if (ret < 0) {
@@ -693,11 +709,22 @@ static int qcow2_open(BlockDriverState *bs, QDict *options, int flags,
/* alloc L2 table/refcount block cache */
s->l2_table_cache = qcow2_cache_create(bs, L2_CACHE_SIZE);
s->refcount_block_cache = qcow2_cache_create(bs, REFCOUNT_CACHE_SIZE);
+ if (s->l2_table_cache == NULL || s->refcount_block_cache == NULL) {
+ error_setg(errp, "Could not allocate metadata caches");
+ ret = -ENOMEM;
+ goto fail;
+ }
s->cluster_cache = g_malloc(s->cluster_size);
/* one more sector for decompressed data alignment */
- s->cluster_data = qemu_blockalign(bs, QCOW_MAX_CRYPT_CLUSTERS * s->cluster_size
- + 512);
+ s->cluster_data = qemu_try_blockalign(bs->file, QCOW_MAX_CRYPT_CLUSTERS
+ * s->cluster_size + 512);
+ if (s->cluster_data == NULL) {
+ error_setg(errp, "Could not allocate temporary cluster buffer");
+ ret = -ENOMEM;
+ goto fail;
+ }
+
s->cluster_cache_offset = -1;
s->flags = flags;
@@ -841,7 +868,7 @@ static int qcow2_open(BlockDriverState *bs, QDict *options, int flags,
cleanup_unknown_header_ext(bs);
qcow2_free_snapshots(bs);
qcow2_refcount_close(bs);
- g_free(s->l1_table);
+ qemu_vfree(s->l1_table);
/* else pre-write overlap checks in cache_destroy may crash */
s->l1_table = NULL;
if (s->l2_table_cache) {
@@ -855,13 +882,11 @@ static int qcow2_open(BlockDriverState *bs, QDict *options, int flags,
return ret;
}
-static int qcow2_refresh_limits(BlockDriverState *bs)
+static void qcow2_refresh_limits(BlockDriverState *bs, Error **errp)
{
BDRVQcowState *s = bs->opaque;
bs->bl.write_zeroes_alignment = s->cluster_sectors;
-
- return 0;
}
static int qcow2_set_key(BlockDriverState *bs, const char *key)
@@ -1073,7 +1098,12 @@ static coroutine_fn int qcow2_co_readv(BlockDriverState *bs, int64_t sector_num,
*/
if (!cluster_data) {
cluster_data =
- qemu_blockalign(bs, QCOW_MAX_CRYPT_CLUSTERS * s->cluster_size);
+ qemu_try_blockalign(bs->file, QCOW_MAX_CRYPT_CLUSTERS
+ * s->cluster_size);
+ if (cluster_data == NULL) {
+ ret = -ENOMEM;
+ goto fail;
+ }
}
assert(cur_nr_sectors <=
@@ -1173,8 +1203,13 @@ static coroutine_fn int qcow2_co_writev(BlockDriverState *bs,
if (s->crypt_method) {
if (!cluster_data) {
- cluster_data = qemu_blockalign(bs, QCOW_MAX_CRYPT_CLUSTERS *
- s->cluster_size);
+ cluster_data = qemu_try_blockalign(bs->file,
+ QCOW_MAX_CRYPT_CLUSTERS
+ * s->cluster_size);
+ if (cluster_data == NULL) {
+ ret = -ENOMEM;
+ goto fail;
+ }
}
assert(hd_qiov.size <=
@@ -1261,7 +1296,7 @@ fail:
static void qcow2_close(BlockDriverState *bs)
{
BDRVQcowState *s = bs->opaque;
- g_free(s->l1_table);
+ qemu_vfree(s->l1_table);
/* else pre-write overlap checks in cache_destroy may crash */
s->l1_table = NULL;
@@ -1548,7 +1583,7 @@ static int preallocate(BlockDriverState *bs)
int ret;
QCowL2Meta *meta;
- nb_sectors = bdrv_getlength(bs) >> BDRV_SECTOR_BITS;
+ nb_sectors = bdrv_nb_sectors(bs);
offset = 0;
while (nb_sectors) {
@@ -1938,7 +1973,6 @@ static int qcow2_write_compressed(BlockDriverState *bs, int64_t sector_num,
/* align end of file to a sector boundary to ease reading with
sector based I/Os */
cluster_offset = bdrv_getlength(bs->file);
- cluster_offset = (cluster_offset + 511) & ~511;
bdrv_truncate(bs->file, cluster_offset);
return 0;
}
diff --git a/block/qed-check.c b/block/qed-check.c
index b473dcd61f..40a882cc93 100644
--- a/block/qed-check.c
+++ b/block/qed-check.c
@@ -227,8 +227,11 @@ int qed_check(BDRVQEDState *s, BdrvCheckResult *result, bool fix)
};
int ret;
- check.used_clusters = g_malloc0(((check.nclusters + 31) / 32) *
- sizeof(check.used_clusters[0]));
+ check.used_clusters = g_try_malloc0(((check.nclusters + 31) / 32) *
+ sizeof(check.used_clusters[0]));
+ if (check.nclusters && check.used_clusters == NULL) {
+ return -ENOMEM;
+ }
check.result->bfi.total_clusters =
(s->header.image_size + s->header.cluster_size - 1) /
diff --git a/block/qed.c b/block/qed.c
index cd4872b529..ba395af76a 100644
--- a/block/qed.c
+++ b/block/qed.c
@@ -528,13 +528,11 @@ out:
return ret;
}
-static int bdrv_qed_refresh_limits(BlockDriverState *bs)
+static void bdrv_qed_refresh_limits(BlockDriverState *bs, Error **errp)
{
BDRVQEDState *s = bs->opaque;
bs->bl.write_zeroes_alignment = s->header.cluster_size >> BDRV_SECTOR_BITS;
-
- return 0;
}
/* We have nothing to do for QED reopen, stubs just return
@@ -1242,7 +1240,11 @@ static void qed_aio_write_inplace(QEDAIOCB *acb, uint64_t offset, size_t len)
struct iovec *iov = acb->qiov->iov;
if (!iov->iov_base) {
- iov->iov_base = qemu_blockalign(acb->common.bs, iov->iov_len);
+ iov->iov_base = qemu_try_blockalign(acb->common.bs, iov->iov_len);
+ if (iov->iov_base == NULL) {
+ qed_aio_complete(acb, -ENOMEM);
+ return;
+ }
memset(iov->iov_base, 0, iov->iov_len);
}
}
diff --git a/block/raw-posix.c b/block/raw-posix.c
index 2bcc73dc37..1194eb00ad 100644
--- a/block/raw-posix.c
+++ b/block/raw-posix.c
@@ -221,7 +221,7 @@ static int raw_normalize_devicepath(const char **filename)
}
#endif
-static void raw_probe_alignment(BlockDriverState *bs)
+static void raw_probe_alignment(BlockDriverState *bs, int fd, Error **errp)
{
BDRVRawState *s = bs->opaque;
char *buf;
@@ -240,24 +240,24 @@ static void raw_probe_alignment(BlockDriverState *bs)
s->buf_align = 0;
#ifdef BLKSSZGET
- if (ioctl(s->fd, BLKSSZGET, &sector_size) >= 0) {
+ if (ioctl(fd, BLKSSZGET, &sector_size) >= 0) {
bs->request_alignment = sector_size;
}
#endif
#ifdef DKIOCGETBLOCKSIZE
- if (ioctl(s->fd, DKIOCGETBLOCKSIZE, &sector_size) >= 0) {
+ if (ioctl(fd, DKIOCGETBLOCKSIZE, &sector_size) >= 0) {
bs->request_alignment = sector_size;
}
#endif
#ifdef DIOCGSECTORSIZE
- if (ioctl(s->fd, DIOCGSECTORSIZE, &sector_size) >= 0) {
+ if (ioctl(fd, DIOCGSECTORSIZE, &sector_size) >= 0) {
bs->request_alignment = sector_size;
}
#endif
#ifdef CONFIG_XFS
if (s->is_xfs) {
struct dioattr da;
- if (xfsctl(NULL, s->fd, XFS_IOC_DIOINFO, &da) >= 0) {
+ if (xfsctl(NULL, fd, XFS_IOC_DIOINFO, &da) >= 0) {
bs->request_alignment = da.d_miniosz;
/* The kernel returns wrong information for d_mem */
/* s->buf_align = da.d_mem; */
@@ -270,7 +270,7 @@ static void raw_probe_alignment(BlockDriverState *bs)
size_t align;
buf = qemu_memalign(MAX_BLOCKSIZE, 2 * MAX_BLOCKSIZE);
for (align = 512; align <= MAX_BLOCKSIZE; align <<= 1) {
- if (pread(s->fd, buf + align, MAX_BLOCKSIZE, 0) >= 0) {
+ if (pread(fd, buf + align, MAX_BLOCKSIZE, 0) >= 0) {
s->buf_align = align;
break;
}
@@ -282,13 +282,18 @@ static void raw_probe_alignment(BlockDriverState *bs)
size_t align;
buf = qemu_memalign(s->buf_align, MAX_BLOCKSIZE);
for (align = 512; align <= MAX_BLOCKSIZE; align <<= 1) {
- if (pread(s->fd, buf, align, 0) >= 0) {
+ if (pread(fd, buf, align, 0) >= 0) {
bs->request_alignment = align;
break;
}
}
qemu_vfree(buf);
}
+
+ if (!s->buf_align || !bs->request_alignment) {
+ error_setg(errp, "Could not find working O_DIRECT alignment. "
+ "Try cache.direct=off.");
+ }
}
static void raw_parse_flags(int bdrv_flags, int *open_flags)
@@ -505,6 +510,7 @@ static int raw_reopen_prepare(BDRVReopenState *state,
BDRVRawState *s;
BDRVRawReopenState *raw_s;
int ret = 0;
+ Error *local_err = NULL;
assert(state != NULL);
assert(state->bs != NULL);
@@ -577,6 +583,19 @@ static int raw_reopen_prepare(BDRVReopenState *state,
ret = -1;
}
}
+
+ /* Fail already reopen_prepare() if we can't get a working O_DIRECT
+ * alignment with the new fd. */
+ if (raw_s->fd != -1) {
+ raw_probe_alignment(state->bs, raw_s->fd, &local_err);
+ if (local_err) {
+ qemu_close(raw_s->fd);
+ raw_s->fd = -1;
+ error_propagate(errp, local_err);
+ ret = -EINVAL;
+ }
+ }
+
return ret;
}
@@ -615,14 +634,12 @@ static void raw_reopen_abort(BDRVReopenState *state)
state->opaque = NULL;
}
-static int raw_refresh_limits(BlockDriverState *bs)
+static void raw_refresh_limits(BlockDriverState *bs, Error **errp)
{
BDRVRawState *s = bs->opaque;
- raw_probe_alignment(bs);
+ raw_probe_alignment(bs, s->fd, errp);
bs->bl.opt_mem_alignment = s->buf_align;
-
- return 0;
}
static ssize_t handle_aiocb_ioctl(RawPosixAIOData *aiocb)
@@ -781,7 +798,11 @@ static ssize_t handle_aiocb_rw(RawPosixAIOData *aiocb)
* Ok, we have to do it the hard way, copy all segments into
* a single aligned buffer.
*/
- buf = qemu_blockalign(aiocb->bs, aiocb->aio_nbytes);
+ buf = qemu_try_blockalign(aiocb->bs, aiocb->aio_nbytes);
+ if (buf == NULL) {
+ return -ENOMEM;
+ }
+
if (aiocb->aio_type & QEMU_AIO_WRITE) {
char *p = buf;
int i;
diff --git a/block/raw_bsd.c b/block/raw_bsd.c
index 492f58de69..f82f4c25df 100644
--- a/block/raw_bsd.c
+++ b/block/raw_bsd.c
@@ -94,10 +94,9 @@ static int raw_get_info(BlockDriverState *bs, BlockDriverInfo *bdi)
return bdrv_get_info(bs->file, bdi);
}
-static int raw_refresh_limits(BlockDriverState *bs)
+static void raw_refresh_limits(BlockDriverState *bs, Error **errp)
{
bs->bl = bs->file->bl;
- return 0;
}
static int raw_truncate(BlockDriverState *bs, int64_t offset)
diff --git a/block/rbd.c b/block/rbd.c
index 2b797d3e8b..4459102adf 100644
--- a/block/rbd.c
+++ b/block/rbd.c
@@ -617,7 +617,7 @@ static BlockDriverAIOCB *rbd_start_aio(BlockDriverState *bs,
RBDAIOCmd cmd)
{
RBDAIOCB *acb;
- RADOSCB *rcb;
+ RADOSCB *rcb = NULL;
rbd_completion_t c;
int64_t off, size;
char *buf;
@@ -631,7 +631,10 @@ static BlockDriverAIOCB *rbd_start_aio(BlockDriverState *bs,
if (cmd == RBD_AIO_DISCARD || cmd == RBD_AIO_FLUSH) {
acb->bounce = NULL;
} else {
- acb->bounce = qemu_blockalign(bs, qiov->size);
+ acb->bounce = qemu_try_blockalign(bs, qiov->size);
+ if (acb->bounce == NULL) {
+ goto failed;
+ }
}
acb->ret = 0;
acb->error = 0;
diff --git a/block/stream.c b/block/stream.c
index 34de8ba0d9..cdea3e8d0c 100644
--- a/block/stream.c
+++ b/block/stream.c
@@ -76,7 +76,7 @@ static void close_unused_images(BlockDriverState *top, BlockDriverState *base,
bdrv_unref(unused);
}
- bdrv_refresh_limits(top);
+ bdrv_refresh_limits(top, NULL);
}
static void coroutine_fn stream_run(void *opaque)
diff --git a/block/vdi.c b/block/vdi.c
index 197bd77c97..adc6aa9a5f 100644
--- a/block/vdi.c
+++ b/block/vdi.c
@@ -53,13 +53,6 @@
#include "block/block_int.h"
#include "qemu/module.h"
#include "migration/migration.h"
-#ifdef __linux__
-#include <linux/fs.h>
-#include <sys/ioctl.h>
-#ifndef FS_NOCOW_FL
-#define FS_NOCOW_FL 0x00800000 /* Do not cow file */
-#endif
-#endif
#if defined(CONFIG_UUID)
#include <uuid/uuid.h>
@@ -299,7 +292,12 @@ static int vdi_check(BlockDriverState *bs, BdrvCheckResult *res,
return -ENOTSUP;
}
- bmap = g_malloc(s->header.blocks_in_image * sizeof(uint32_t));
+ bmap = g_try_malloc(s->header.blocks_in_image * sizeof(uint32_t));
+ if (s->header.blocks_in_image && bmap == NULL) {
+ res->check_errors++;
+ return -ENOMEM;
+ }
+
memset(bmap, 0xff, s->header.blocks_in_image * sizeof(uint32_t));
/* Check block map and value of blocks_allocated. */
@@ -357,23 +355,23 @@ static int vdi_make_empty(BlockDriverState *bs)
static int vdi_probe(const uint8_t *buf, int buf_size, const char *filename)
{
const VdiHeader *header = (const VdiHeader *)buf;
- int result = 0;
+ int ret = 0;
logout("\n");
if (buf_size < sizeof(*header)) {
/* Header too small, no VDI. */
} else if (le32_to_cpu(header->signature) == VDI_SIGNATURE) {
- result = 100;
+ ret = 100;
}
- if (result == 0) {
+ if (ret == 0) {
logout("no vdi image\n");
} else {
logout("%s", header->text);
}
- return result;
+ return ret;
}
static int vdi_open(BlockDriverState *bs, QDict *options, int flags,
@@ -478,7 +476,12 @@ static int vdi_open(BlockDriverState *bs, QDict *options, int flags,
bmap_size = header.blocks_in_image * sizeof(uint32_t);
bmap_size = (bmap_size + SECTOR_SIZE - 1) / SECTOR_SIZE;
- s->bmap = g_malloc(bmap_size * SECTOR_SIZE);
+ s->bmap = qemu_try_blockalign(bs->file, bmap_size * SECTOR_SIZE);
+ if (s->bmap == NULL) {
+ ret = -ENOMEM;
+ goto fail;
+ }
+
ret = bdrv_read(bs->file, s->bmap_sector, (uint8_t *)s->bmap, bmap_size);
if (ret < 0) {
goto fail_free_bmap;
@@ -493,7 +496,7 @@ static int vdi_open(BlockDriverState *bs, QDict *options, int flags,
return 0;
fail_free_bmap:
- g_free(s->bmap);
+ qemu_vfree(s->bmap);
fail:
return ret;
@@ -681,8 +684,7 @@ static int vdi_co_write(BlockDriverState *bs,
static int vdi_create(const char *filename, QemuOpts *opts, Error **errp)
{
- int fd;
- int result = 0;
+ int ret = 0;
uint64_t bytes = 0;
uint32_t blocks;
size_t block_size = DEFAULT_CLUSTER_SIZE;
@@ -690,7 +692,10 @@ static int vdi_create(const char *filename, QemuOpts *opts, Error **errp)
VdiHeader header;
size_t i;
size_t bmap_size;
- bool nocow = false;
+ int64_t offset = 0;
+ Error *local_err = NULL;
+ BlockDriverState *bs = NULL;
+ uint32_t *bmap = NULL;
logout("\n");
@@ -707,37 +712,25 @@ static int vdi_create(const char *filename, QemuOpts *opts, Error **errp)
image_type = VDI_TYPE_STATIC;
}
#endif
- nocow = qemu_opt_get_bool_del(opts, BLOCK_OPT_NOCOW, false);
if (bytes > VDI_DISK_SIZE_MAX) {
- result = -ENOTSUP;
+ ret = -ENOTSUP;
error_setg(errp, "Unsupported VDI image size (size is 0x%" PRIx64
", max supported is 0x%" PRIx64 ")",
bytes, VDI_DISK_SIZE_MAX);
goto exit;
}
- fd = qemu_open(filename,
- O_WRONLY | O_CREAT | O_TRUNC | O_BINARY | O_LARGEFILE,
- 0644);
- if (fd < 0) {
- result = -errno;
+ ret = bdrv_create_file(filename, opts, &local_err);
+ if (ret < 0) {
+ error_propagate(errp, local_err);
goto exit;
}
-
- if (nocow) {
-#ifdef __linux__
- /* Set NOCOW flag to solve performance issue on fs like btrfs.
- * This is an optimisation. The FS_IOC_SETFLAGS ioctl return value will
- * be ignored since any failure of this operation should not block the
- * left work.
- */
- int attr;
- if (ioctl(fd, FS_IOC_GETFLAGS, &attr) == 0) {
- attr |= FS_NOCOW_FL;
- ioctl(fd, FS_IOC_SETFLAGS, &attr);
- }
-#endif
+ ret = bdrv_open(&bs, filename, NULL, NULL, BDRV_O_RDWR | BDRV_O_PROTOCOL,
+ NULL, &local_err);
+ if (ret < 0) {
+ error_propagate(errp, local_err);
+ goto exit;
}
/* We need enough blocks to store the given disk size,
@@ -769,13 +762,20 @@ static int vdi_create(const char *filename, QemuOpts *opts, Error **errp)
vdi_header_print(&header);
#endif
vdi_header_to_le(&header);
- if (write(fd, &header, sizeof(header)) < 0) {
- result = -errno;
- goto close_and_exit;
+ ret = bdrv_pwrite_sync(bs, offset, &header, sizeof(header));
+ if (ret < 0) {
+ error_setg(errp, "Error writing header to %s", filename);
+ goto exit;
}
+ offset += sizeof(header);
if (bmap_size > 0) {
- uint32_t *bmap = g_malloc0(bmap_size);
+ bmap = g_try_malloc0(bmap_size);
+ if (bmap == NULL) {
+ ret = -ENOMEM;
+ error_setg(errp, "Could not allocate bmap");
+ goto exit;
+ }
for (i = 0; i < blocks; i++) {
if (image_type == VDI_TYPE_STATIC) {
bmap[i] = i;
@@ -783,35 +783,33 @@ static int vdi_create(const char *filename, QemuOpts *opts, Error **errp)
bmap[i] = VDI_UNALLOCATED;
}
}
- if (write(fd, bmap, bmap_size) < 0) {
- result = -errno;
- g_free(bmap);
- goto close_and_exit;
+ ret = bdrv_pwrite_sync(bs, offset, bmap, bmap_size);
+ if (ret < 0) {
+ error_setg(errp, "Error writing bmap to %s", filename);
+ goto exit;
}
- g_free(bmap);
+ offset += bmap_size;
}
if (image_type == VDI_TYPE_STATIC) {
- if (ftruncate(fd, sizeof(header) + bmap_size + blocks * block_size)) {
- result = -errno;
- goto close_and_exit;
+ ret = bdrv_truncate(bs, offset + blocks * block_size);
+ if (ret < 0) {
+ error_setg(errp, "Failed to statically allocate %s", filename);
+ goto exit;
}
}
-close_and_exit:
- if ((close(fd) < 0) && !result) {
- result = -errno;
- }
-
exit:
- return result;
+ bdrv_unref(bs);
+ g_free(bmap);
+ return ret;
}
static void vdi_close(BlockDriverState *bs)
{
BDRVVdiState *s = bs->opaque;
- g_free(s->bmap);
+ qemu_vfree(s->bmap);
migrate_del_blocker(s->migration_blocker);
error_free(s->migration_blocker);
diff --git a/block/vhdx-endian.c b/block/vhdx-endian.c
index fe879ed995..0640d3f4a9 100644
--- a/block/vhdx-endian.c
+++ b/block/vhdx-endian.c
@@ -82,8 +82,6 @@ void vhdx_log_desc_le_import(VHDXLogDescriptor *d)
assert(d != NULL);
le32_to_cpus(&d->signature);
- le32_to_cpus(&d->trailing_bytes);
- le64_to_cpus(&d->leading_bytes);
le64_to_cpus(&d->file_offset);
le64_to_cpus(&d->sequence_number);
}
@@ -99,6 +97,15 @@ void vhdx_log_desc_le_export(VHDXLogDescriptor *d)
cpu_to_le64s(&d->sequence_number);
}
+void vhdx_log_data_le_import(VHDXLogDataSector *d)
+{
+ assert(d != NULL);
+
+ le32_to_cpus(&d->data_signature);
+ le32_to_cpus(&d->sequence_high);
+ le32_to_cpus(&d->sequence_low);
+}
+
void vhdx_log_data_le_export(VHDXLogDataSector *d)
{
assert(d != NULL);
diff --git a/block/vhdx-log.c b/block/vhdx-log.c
index a77c040ee0..eb5c7a097b 100644
--- a/block/vhdx-log.c
+++ b/block/vhdx-log.c
@@ -84,6 +84,7 @@ static int vhdx_log_peek_hdr(BlockDriverState *bs, VHDXLogEntries *log,
if (ret < 0) {
goto exit;
}
+ vhdx_log_entry_hdr_le_import(hdr);
exit:
return ret;
@@ -211,7 +212,7 @@ static bool vhdx_log_hdr_is_valid(VHDXLogEntries *log, VHDXLogEntryHeader *hdr,
{
int valid = false;
- if (memcmp(&hdr->signature, "loge", 4)) {
+ if (hdr->signature != VHDX_LOG_SIGNATURE) {
goto exit;
}
@@ -275,12 +276,12 @@ static bool vhdx_log_desc_is_valid(VHDXLogDescriptor *desc,
goto exit;
}
- if (!memcmp(&desc->signature, "zero", 4)) {
+ if (desc->signature == VHDX_LOG_ZERO_SIGNATURE) {
if (desc->zero_length % VHDX_LOG_SECTOR_SIZE == 0) {
/* valid */
ret = true;
}
- } else if (!memcmp(&desc->signature, "desc", 4)) {
+ } else if (desc->signature == VHDX_LOG_DESC_SIGNATURE) {
/* valid */
ret = true;
}
@@ -327,13 +328,15 @@ static int vhdx_compute_desc_sectors(uint32_t desc_cnt)
* passed into this function. Each descriptor will also be validated,
* and error returned if any are invalid. */
static int vhdx_log_read_desc(BlockDriverState *bs, BDRVVHDXState *s,
- VHDXLogEntries *log, VHDXLogDescEntries **buffer)
+ VHDXLogEntries *log, VHDXLogDescEntries **buffer,
+ bool convert_endian)
{
int ret = 0;
uint32_t desc_sectors;
uint32_t sectors_read;
VHDXLogEntryHeader hdr;
VHDXLogDescEntries *desc_entries = NULL;
+ VHDXLogDescriptor desc;
int i;
assert(*buffer == NULL);
@@ -342,14 +345,19 @@ static int vhdx_log_read_desc(BlockDriverState *bs, BDRVVHDXState *s,
if (ret < 0) {
goto exit;
}
- vhdx_log_entry_hdr_le_import(&hdr);
+
if (vhdx_log_hdr_is_valid(log, &hdr, s) == false) {
ret = -EINVAL;
goto exit;
}
desc_sectors = vhdx_compute_desc_sectors(hdr.descriptor_count);
- desc_entries = qemu_blockalign(bs, desc_sectors * VHDX_LOG_SECTOR_SIZE);
+ desc_entries = qemu_try_blockalign(bs->file,
+ desc_sectors * VHDX_LOG_SECTOR_SIZE);
+ if (desc_entries == NULL) {
+ ret = -ENOMEM;
+ goto exit;
+ }
ret = vhdx_log_read_sectors(bs, log, &sectors_read, desc_entries,
desc_sectors, false);
@@ -363,12 +371,19 @@ static int vhdx_log_read_desc(BlockDriverState *bs, BDRVVHDXState *s,
/* put in proper endianness, and validate each desc */
for (i = 0; i < hdr.descriptor_count; i++) {
- vhdx_log_desc_le_import(&desc_entries->desc[i]);
- if (vhdx_log_desc_is_valid(&desc_entries->desc[i], &hdr) == false) {
+ desc = desc_entries->desc[i];
+ vhdx_log_desc_le_import(&desc);
+ if (convert_endian) {
+ desc_entries->desc[i] = desc;
+ }
+ if (vhdx_log_desc_is_valid(&desc, &hdr) == false) {
ret = -EINVAL;
goto free_and_exit;
}
}
+ if (convert_endian) {
+ desc_entries->hdr = hdr;
+ }
*buffer = desc_entries;
goto exit;
@@ -403,7 +418,7 @@ static int vhdx_log_flush_desc(BlockDriverState *bs, VHDXLogDescriptor *desc,
buffer = qemu_blockalign(bs, VHDX_LOG_SECTOR_SIZE);
- if (!memcmp(&desc->signature, "desc", 4)) {
+ if (desc->signature == VHDX_LOG_DESC_SIGNATURE) {
/* data sector */
if (data == NULL) {
ret = -EFAULT;
@@ -431,10 +446,15 @@ static int vhdx_log_flush_desc(BlockDriverState *bs, VHDXLogDescriptor *desc,
memcpy(buffer+offset, &desc->trailing_bytes, 4);
- } else if (!memcmp(&desc->signature, "zero", 4)) {
+ } else if (desc->signature == VHDX_LOG_ZERO_SIGNATURE) {
/* write 'count' sectors of sector */
memset(buffer, 0, VHDX_LOG_SECTOR_SIZE);
count = desc->zero_length / VHDX_LOG_SECTOR_SIZE;
+ } else {
+ error_report("Invalid VHDX log descriptor entry signature 0x%" PRIx32,
+ desc->signature);
+ ret = -EINVAL;
+ goto exit;
}
file_offset = desc->file_offset;
@@ -493,13 +513,13 @@ static int vhdx_log_flush(BlockDriverState *bs, BDRVVHDXState *s,
goto exit;
}
- ret = vhdx_log_read_desc(bs, s, &logs->log, &desc_entries);
+ ret = vhdx_log_read_desc(bs, s, &logs->log, &desc_entries, true);
if (ret < 0) {
goto exit;
}
for (i = 0; i < desc_entries->hdr.descriptor_count; i++) {
- if (!memcmp(&desc_entries->desc[i].signature, "desc", 4)) {
+ if (desc_entries->desc[i].signature == VHDX_LOG_DESC_SIGNATURE) {
/* data sector, so read a sector to flush */
ret = vhdx_log_read_sectors(bs, &logs->log, &sectors_read,
data, 1, false);
@@ -510,6 +530,7 @@ static int vhdx_log_flush(BlockDriverState *bs, BDRVVHDXState *s,
ret = -EINVAL;
goto exit;
}
+ vhdx_log_data_le_import(data);
}
ret = vhdx_log_flush_desc(bs, &desc_entries->desc[i], data);
@@ -558,9 +579,6 @@ static int vhdx_validate_log_entry(BlockDriverState *bs, BDRVVHDXState *s,
goto inc_and_exit;
}
- vhdx_log_entry_hdr_le_import(&hdr);
-
-
if (vhdx_log_hdr_is_valid(log, &hdr, s) == false) {
goto inc_and_exit;
}
@@ -573,13 +591,13 @@ static int vhdx_validate_log_entry(BlockDriverState *bs, BDRVVHDXState *s,
desc_sectors = vhdx_compute_desc_sectors(hdr.descriptor_count);
- /* Read desc sectors, and calculate log checksum */
+ /* Read all log sectors, and calculate log checksum */
total_sectors = hdr.entry_length / VHDX_LOG_SECTOR_SIZE;
/* read_desc() will increment the read idx */
- ret = vhdx_log_read_desc(bs, s, log, &desc_buffer);
+ ret = vhdx_log_read_desc(bs, s, log, &desc_buffer, false);
if (ret < 0) {
goto free_and_exit;
}
@@ -602,7 +620,7 @@ static int vhdx_validate_log_entry(BlockDriverState *bs, BDRVVHDXState *s,
}
}
crc ^= 0xffffffff;
- if (crc != desc_buffer->hdr.checksum) {
+ if (crc != hdr.checksum) {
goto free_and_exit;
}
@@ -962,7 +980,6 @@ static int vhdx_log_write(BlockDriverState *bs, BDRVVHDXState *s,
* last data sector */
vhdx_update_checksum(buffer, total_length,
offsetof(VHDXLogEntryHeader, checksum));
- cpu_to_le32s((uint32_t *)(buffer + 4));
/* now write to the log */
ret = vhdx_log_write_sectors(bs, &s->log, &sectors_written, buffer,
diff --git a/block/vhdx.c b/block/vhdx.c
index fedcf9f9ca..f666940db7 100644
--- a/block/vhdx.c
+++ b/block/vhdx.c
@@ -135,10 +135,8 @@ typedef struct VHDXSectorInfo {
* buf: buffer pointer
* size: size of buffer (must be > crc_offset+4)
*
- * Note: The resulting checksum is in the CPU endianness, not necessarily
- * in the file format endianness (LE). Any header export to disk should
- * make sure that vhdx_header_le_export() is used to convert to the
- * correct endianness
+ * Note: The buffer should have all multi-byte data in little-endian format,
+ * and the resulting checksum is in little endian format.
*/
uint32_t vhdx_update_checksum(uint8_t *buf, size_t size, int crc_offset)
{
@@ -149,6 +147,7 @@ uint32_t vhdx_update_checksum(uint8_t *buf, size_t size, int crc_offset)
memset(buf + crc_offset, 0, sizeof(crc));
crc = crc32c(0xffffffff, buf, size);
+ cpu_to_le32s(&crc);
memcpy(buf + crc_offset, &crc, sizeof(crc));
return crc;
@@ -300,7 +299,7 @@ static int vhdx_write_header(BlockDriverState *bs_file, VHDXHeader *hdr,
{
uint8_t *buffer = NULL;
int ret;
- VHDXHeader header_le;
+ VHDXHeader *header_le;
assert(bs_file != NULL);
assert(hdr != NULL);
@@ -321,11 +320,12 @@ static int vhdx_write_header(BlockDriverState *bs_file, VHDXHeader *hdr,
}
/* overwrite the actual VHDXHeader portion */
- memcpy(buffer, hdr, sizeof(VHDXHeader));
- hdr->checksum = vhdx_update_checksum(buffer, VHDX_HEADER_SIZE,
- offsetof(VHDXHeader, checksum));
- vhdx_header_le_export(hdr, &header_le);
- ret = bdrv_pwrite_sync(bs_file, offset, &header_le, sizeof(VHDXHeader));
+ header_le = (VHDXHeader *)buffer;
+ memcpy(header_le, hdr, sizeof(VHDXHeader));
+ vhdx_header_le_export(hdr, header_le);
+ vhdx_update_checksum(buffer, VHDX_HEADER_SIZE,
+ offsetof(VHDXHeader, checksum));
+ ret = bdrv_pwrite_sync(bs_file, offset, header_le, sizeof(VHDXHeader));
exit:
qemu_vfree(buffer);
@@ -432,13 +432,14 @@ static void vhdx_parse_header(BlockDriverState *bs, BDRVVHDXState *s,
}
/* copy over just the relevant portion that we need */
memcpy(header1, buffer, sizeof(VHDXHeader));
- vhdx_header_le_import(header1);
- if (vhdx_checksum_is_valid(buffer, VHDX_HEADER_SIZE, 4) &&
- !memcmp(&header1->signature, "head", 4) &&
- header1->version == 1) {
- h1_seq = header1->sequence_number;
- h1_valid = true;
+ if (vhdx_checksum_is_valid(buffer, VHDX_HEADER_SIZE, 4)) {
+ vhdx_header_le_import(header1);
+ if (header1->signature == VHDX_HEADER_SIGNATURE &&
+ header1->version == 1) {
+ h1_seq = header1->sequence_number;
+ h1_valid = true;
+ }
}
ret = bdrv_pread(bs->file, VHDX_HEADER2_OFFSET, buffer, VHDX_HEADER_SIZE);
@@ -447,13 +448,14 @@ static void vhdx_parse_header(BlockDriverState *bs, BDRVVHDXState *s,
}
/* copy over just the relevant portion that we need */
memcpy(header2, buffer, sizeof(VHDXHeader));
- vhdx_header_le_import(header2);
- if (vhdx_checksum_is_valid(buffer, VHDX_HEADER_SIZE, 4) &&
- !memcmp(&header2->signature, "head", 4) &&
- header2->version == 1) {
- h2_seq = header2->sequence_number;
- h2_valid = true;
+ if (vhdx_checksum_is_valid(buffer, VHDX_HEADER_SIZE, 4)) {
+ vhdx_header_le_import(header2);
+ if (header2->signature == VHDX_HEADER_SIGNATURE &&
+ header2->version == 1) {
+ h2_seq = header2->sequence_number;
+ h2_valid = true;
+ }
}
/* If there is only 1 valid header (or no valid headers), we
@@ -519,15 +521,21 @@ static int vhdx_open_region_tables(BlockDriverState *bs, BDRVVHDXState *s)
goto fail;
}
memcpy(&s->rt, buffer, sizeof(s->rt));
- vhdx_region_header_le_import(&s->rt);
offset += sizeof(s->rt);
- if (!vhdx_checksum_is_valid(buffer, VHDX_HEADER_BLOCK_SIZE, 4) ||
- memcmp(&s->rt.signature, "regi", 4)) {
+ if (!vhdx_checksum_is_valid(buffer, VHDX_HEADER_BLOCK_SIZE, 4)) {
ret = -EINVAL;
goto fail;
}
+ vhdx_region_header_le_import(&s->rt);
+
+ if (s->rt.signature != VHDX_REGION_SIGNATURE) {
+ ret = -EINVAL;
+ goto fail;
+ }
+
+
/* Per spec, maximum region table entry count is 2047 */
if (s->rt.entry_count > 2047) {
ret = -EINVAL;
@@ -630,7 +638,7 @@ static int vhdx_parse_metadata(BlockDriverState *bs, BDRVVHDXState *s)
vhdx_metadata_header_le_import(&s->metadata_hdr);
- if (memcmp(&s->metadata_hdr.signature, "metadata", 8)) {
+ if (s->metadata_hdr.signature != VHDX_METADATA_SIGNATURE) {
ret = -EINVAL;
goto exit;
}
@@ -950,7 +958,11 @@ static int vhdx_open(BlockDriverState *bs, QDict *options, int flags,
}
/* s->bat is freed in vhdx_close() */
- s->bat = qemu_blockalign(bs, s->bat_rt.length);
+ s->bat = qemu_try_blockalign(bs->file, s->bat_rt.length);
+ if (s->bat == NULL) {
+ ret = -ENOMEM;
+ goto fail;
+ }
ret = bdrv_pread(bs->file, s->bat_offset, s->bat, s->bat_rt.length);
if (ret < 0) {
@@ -1540,7 +1552,8 @@ exit:
*/
static int vhdx_create_bat(BlockDriverState *bs, BDRVVHDXState *s,
uint64_t image_size, VHDXImageType type,
- bool use_zero_blocks, VHDXRegionTableEntry *rt_bat)
+ bool use_zero_blocks, uint64_t file_offset,
+ uint32_t length)
{
int ret = 0;
uint64_t data_file_offset;
@@ -1555,7 +1568,7 @@ static int vhdx_create_bat(BlockDriverState *bs, BDRVVHDXState *s,
/* this gives a data start after BAT/bitmap entries, and well
* past any metadata entries (with a 4 MB buffer for future
* expansion */
- data_file_offset = rt_bat->file_offset + rt_bat->length + 5 * MiB;
+ data_file_offset = file_offset + length + 5 * MiB;
total_sectors = image_size >> s->logical_sector_size_bits;
if (type == VHDX_TYPE_DYNAMIC) {
@@ -1579,7 +1592,11 @@ static int vhdx_create_bat(BlockDriverState *bs, BDRVVHDXState *s,
use_zero_blocks ||
bdrv_has_zero_init(bs) == 0) {
/* for a fixed file, the default BAT entry is not zero */
- s->bat = g_malloc0(rt_bat->length);
+ s->bat = g_try_malloc0(length);
+ if (length && s->bat != NULL) {
+ ret = -ENOMEM;
+ goto exit;
+ }
block_state = type == VHDX_TYPE_FIXED ? PAYLOAD_BLOCK_FULLY_PRESENT :
PAYLOAD_BLOCK_NOT_PRESENT;
block_state = use_zero_blocks ? PAYLOAD_BLOCK_ZERO : block_state;
@@ -1594,7 +1611,7 @@ static int vhdx_create_bat(BlockDriverState *bs, BDRVVHDXState *s,
cpu_to_le64s(&s->bat[sinfo.bat_idx]);
sector_num += s->sectors_per_block;
}
- ret = bdrv_pwrite(bs, rt_bat->file_offset, s->bat, rt_bat->length);
+ ret = bdrv_pwrite(bs, file_offset, s->bat, length);
if (ret < 0) {
goto exit;
}
@@ -1626,6 +1643,8 @@ static int vhdx_create_new_region_table(BlockDriverState *bs,
int ret = 0;
uint32_t offset = 0;
void *buffer = NULL;
+ uint64_t bat_file_offset;
+ uint32_t bat_length;
BDRVVHDXState *s = NULL;
VHDXRegionTableHeader *region_table;
VHDXRegionTableEntry *rt_bat;
@@ -1674,19 +1693,26 @@ static int vhdx_create_new_region_table(BlockDriverState *bs,
rt_metadata->length = 1 * MiB; /* min size, and more than enough */
*metadata_offset = rt_metadata->file_offset;
+ bat_file_offset = rt_bat->file_offset;
+ bat_length = rt_bat->length;
+
+ vhdx_region_header_le_export(region_table);
+ vhdx_region_entry_le_export(rt_bat);
+ vhdx_region_entry_le_export(rt_metadata);
+
vhdx_update_checksum(buffer, VHDX_HEADER_BLOCK_SIZE,
offsetof(VHDXRegionTableHeader, checksum));
/* The region table gives us the data we need to create the BAT,
* so do that now */
- ret = vhdx_create_bat(bs, s, image_size, type, use_zero_blocks, rt_bat);
+ ret = vhdx_create_bat(bs, s, image_size, type, use_zero_blocks,
+ bat_file_offset, bat_length);
+ if (ret < 0) {
+ goto exit;
+ }
/* Now write out the region headers to disk */
- vhdx_region_header_le_export(region_table);
- vhdx_region_entry_le_export(rt_bat);
- vhdx_region_entry_le_export(rt_metadata);
-
ret = bdrv_pwrite(bs, VHDX_REGION_TABLE_OFFSET, buffer,
VHDX_HEADER_BLOCK_SIZE);
if (ret < 0) {
diff --git a/block/vhdx.h b/block/vhdx.h
index 5370010c59..b4a12a081e 100644
--- a/block/vhdx.h
+++ b/block/vhdx.h
@@ -435,6 +435,7 @@ void vhdx_header_le_import(VHDXHeader *h);
void vhdx_header_le_export(VHDXHeader *orig_h, VHDXHeader *new_h);
void vhdx_log_desc_le_import(VHDXLogDescriptor *d);
void vhdx_log_desc_le_export(VHDXLogDescriptor *d);
+void vhdx_log_data_le_import(VHDXLogDataSector *d);
void vhdx_log_data_le_export(VHDXLogDataSector *d);
void vhdx_log_entry_hdr_le_import(VHDXLogEntryHeader *hdr);
void vhdx_log_entry_hdr_le_export(VHDXLogEntryHeader *hdr);
diff --git a/block/vmdk.c b/block/vmdk.c
index 27a78daa02..01412a8939 100644
--- a/block/vmdk.c
+++ b/block/vmdk.c
@@ -106,6 +106,7 @@ typedef struct VmdkExtent {
uint32_t l2_cache_counts[L2_CACHE_SIZE];
int64_t cluster_sectors;
+ int64_t next_cluster_sector;
char *type;
} VmdkExtent;
@@ -124,7 +125,6 @@ typedef struct BDRVVmdkState {
} BDRVVmdkState;
typedef struct VmdkMetaData {
- uint32_t offset;
unsigned int l1_index;
unsigned int l2_index;
unsigned int l2_offset;
@@ -397,6 +397,7 @@ static int vmdk_add_extent(BlockDriverState *bs,
{
VmdkExtent *extent;
BDRVVmdkState *s = bs->opaque;
+ int64_t length;
if (cluster_sectors > 0x200000) {
/* 0x200000 * 512Bytes = 1GB for one cluster is unrealistic */
@@ -412,6 +413,11 @@ static int vmdk_add_extent(BlockDriverState *bs,
return -EFBIG;
}
+ length = bdrv_getlength(file);
+ if (length < 0) {
+ return length;
+ }
+
s->extents = g_realloc(s->extents,
(s->num_extents + 1) * sizeof(VmdkExtent));
extent = &s->extents[s->num_extents];
@@ -427,6 +433,8 @@ static int vmdk_add_extent(BlockDriverState *bs,
extent->l1_entry_sectors = l2_size * cluster_sectors;
extent->l2_size = l2_size;
extent->cluster_sectors = flat ? sectors : cluster_sectors;
+ extent->next_cluster_sector =
+ ROUND_UP(DIV_ROUND_UP(length, BDRV_SECTOR_SIZE), cluster_sectors);
if (s->num_extents > 1) {
extent->end_sector = (*(extent - 1)).end_sector + extent->sectors;
@@ -448,7 +456,11 @@ static int vmdk_init_tables(BlockDriverState *bs, VmdkExtent *extent,
/* read the L1 table */
l1_size = extent->l1_size * sizeof(uint32_t);
- extent->l1_table = g_malloc(l1_size);
+ extent->l1_table = g_try_malloc(l1_size);
+ if (l1_size && extent->l1_table == NULL) {
+ return -ENOMEM;
+ }
+
ret = bdrv_pread(extent->file,
extent->l1_table_offset,
extent->l1_table,
@@ -464,7 +476,11 @@ static int vmdk_init_tables(BlockDriverState *bs, VmdkExtent *extent,
}
if (extent->l1_backup_table_offset) {
- extent->l1_backup_table = g_malloc(l1_size);
+ extent->l1_backup_table = g_try_malloc(l1_size);
+ if (l1_size && extent->l1_backup_table == NULL) {
+ ret = -ENOMEM;
+ goto fail_l1;
+ }
ret = bdrv_pread(extent->file,
extent->l1_backup_table_offset,
extent->l1_backup_table,
@@ -669,8 +685,7 @@ static int vmdk_open_vmdk4(BlockDriverState *bs,
if (le32_to_cpu(header.flags) & VMDK4_FLAG_RGD) {
l1_backup_offset = le64_to_cpu(header.rgd_offset) << 9;
}
- if (bdrv_getlength(file) <
- le64_to_cpu(header.grain_offset) * BDRV_SECTOR_SIZE) {
+ if (bdrv_nb_sectors(file) < le64_to_cpu(header.grain_offset)) {
error_setg(errp, "File truncated, expecting at least %" PRId64 " bytes",
(int64_t)(le64_to_cpu(header.grain_offset)
* BDRV_SECTOR_SIZE));
@@ -938,7 +953,7 @@ fail:
}
-static int vmdk_refresh_limits(BlockDriverState *bs)
+static void vmdk_refresh_limits(BlockDriverState *bs, Error **errp)
{
BDRVVmdkState *s = bs->opaque;
int i;
@@ -950,61 +965,99 @@ static int vmdk_refresh_limits(BlockDriverState *bs)
s->extents[i].cluster_sectors);
}
}
-
- return 0;
}
+/**
+ * get_whole_cluster
+ *
+ * Copy backing file's cluster that covers @sector_num, otherwise write zero,
+ * to the cluster at @cluster_sector_num.
+ *
+ * If @skip_start_sector < @skip_end_sector, the relative range
+ * [@skip_start_sector, @skip_end_sector) is not copied or written, and leave
+ * it for call to write user data in the request.
+ */
static int get_whole_cluster(BlockDriverState *bs,
- VmdkExtent *extent,
- uint64_t cluster_offset,
- uint64_t offset,
- bool allocate)
+ VmdkExtent *extent,
+ uint64_t cluster_sector_num,
+ uint64_t sector_num,
+ uint64_t skip_start_sector,
+ uint64_t skip_end_sector)
{
int ret = VMDK_OK;
- uint8_t *whole_grain = NULL;
+ int64_t cluster_bytes;
+ uint8_t *whole_grain;
+
+ /* For COW, align request sector_num to cluster start */
+ sector_num = QEMU_ALIGN_DOWN(sector_num, extent->cluster_sectors);
+ cluster_bytes = extent->cluster_sectors << BDRV_SECTOR_BITS;
+ whole_grain = qemu_blockalign(bs, cluster_bytes);
+ if (!bs->backing_hd) {
+ memset(whole_grain, 0, skip_start_sector << BDRV_SECTOR_BITS);
+ memset(whole_grain + (skip_end_sector << BDRV_SECTOR_BITS), 0,
+ cluster_bytes - (skip_end_sector << BDRV_SECTOR_BITS));
+ }
+
+ assert(skip_end_sector <= extent->cluster_sectors);
/* we will be here if it's first write on non-exist grain(cluster).
* try to read from parent image, if exist */
- if (bs->backing_hd) {
- whole_grain =
- qemu_blockalign(bs, extent->cluster_sectors << BDRV_SECTOR_BITS);
- if (!vmdk_is_cid_valid(bs)) {
- ret = VMDK_ERROR;
- goto exit;
- }
+ if (bs->backing_hd && !vmdk_is_cid_valid(bs)) {
+ ret = VMDK_ERROR;
+ goto exit;
+ }
- /* floor offset to cluster */
- offset -= offset % (extent->cluster_sectors * 512);
- ret = bdrv_read(bs->backing_hd, offset >> 9, whole_grain,
- extent->cluster_sectors);
+ /* Read backing data before skip range */
+ if (skip_start_sector > 0) {
+ if (bs->backing_hd) {
+ ret = bdrv_read(bs->backing_hd, sector_num,
+ whole_grain, skip_start_sector);
+ if (ret < 0) {
+ ret = VMDK_ERROR;
+ goto exit;
+ }
+ }
+ ret = bdrv_write(extent->file, cluster_sector_num, whole_grain,
+ skip_start_sector);
if (ret < 0) {
ret = VMDK_ERROR;
goto exit;
}
-
- /* Write grain only into the active image */
- ret = bdrv_write(extent->file, cluster_offset, whole_grain,
- extent->cluster_sectors);
+ }
+ /* Read backing data after skip range */
+ if (skip_end_sector < extent->cluster_sectors) {
+ if (bs->backing_hd) {
+ ret = bdrv_read(bs->backing_hd, sector_num + skip_end_sector,
+ whole_grain + (skip_end_sector << BDRV_SECTOR_BITS),
+ extent->cluster_sectors - skip_end_sector);
+ if (ret < 0) {
+ ret = VMDK_ERROR;
+ goto exit;
+ }
+ }
+ ret = bdrv_write(extent->file, cluster_sector_num + skip_end_sector,
+ whole_grain + (skip_end_sector << BDRV_SECTOR_BITS),
+ extent->cluster_sectors - skip_end_sector);
if (ret < 0) {
ret = VMDK_ERROR;
goto exit;
}
}
+
exit:
qemu_vfree(whole_grain);
return ret;
}
-static int vmdk_L2update(VmdkExtent *extent, VmdkMetaData *m_data)
+static int vmdk_L2update(VmdkExtent *extent, VmdkMetaData *m_data,
+ uint32_t offset)
{
- uint32_t offset;
- QEMU_BUILD_BUG_ON(sizeof(offset) != sizeof(m_data->offset));
- offset = cpu_to_le32(m_data->offset);
+ offset = cpu_to_le32(offset);
/* update L2 table */
if (bdrv_pwrite_sync(
extent->file,
((int64_t)m_data->l2_offset * 512)
- + (m_data->l2_index * sizeof(m_data->offset)),
+ + (m_data->l2_index * sizeof(offset)),
&offset, sizeof(offset)) < 0) {
return VMDK_ERROR;
}
@@ -1014,7 +1067,7 @@ static int vmdk_L2update(VmdkExtent *extent, VmdkMetaData *m_data)
if (bdrv_pwrite_sync(
extent->file,
((int64_t)m_data->l2_offset * 512)
- + (m_data->l2_index * sizeof(m_data->offset)),
+ + (m_data->l2_index * sizeof(offset)),
&offset, sizeof(offset)) < 0) {
return VMDK_ERROR;
}
@@ -1026,17 +1079,41 @@ static int vmdk_L2update(VmdkExtent *extent, VmdkMetaData *m_data)
return VMDK_OK;
}
+/**
+ * get_cluster_offset
+ *
+ * Look up cluster offset in extent file by sector number, and store in
+ * @cluster_offset.
+ *
+ * For flat extents, the start offset as parsed from the description file is
+ * returned.
+ *
+ * For sparse extents, look up in L1, L2 table. If allocate is true, return an
+ * offset for a new cluster and update L2 cache. If there is a backing file,
+ * COW is done before returning; otherwise, zeroes are written to the allocated
+ * cluster. Both COW and zero writing skips the sector range
+ * [@skip_start_sector, @skip_end_sector) passed in by caller, because caller
+ * has new data to write there.
+ *
+ * Returns: VMDK_OK if cluster exists and mapped in the image.
+ * VMDK_UNALLOC if cluster is not mapped and @allocate is false.
+ * VMDK_ERROR if failed.
+ */
static int get_cluster_offset(BlockDriverState *bs,
- VmdkExtent *extent,
- VmdkMetaData *m_data,
- uint64_t offset,
- int allocate,
- uint64_t *cluster_offset)
+ VmdkExtent *extent,
+ VmdkMetaData *m_data,
+ uint64_t offset,
+ bool allocate,
+ uint64_t *cluster_offset,
+ uint64_t skip_start_sector,
+ uint64_t skip_end_sector)
{
unsigned int l1_index, l2_offset, l2_index;
int min_index, i, j;
uint32_t min_count, *l2_table;
bool zeroed = false;
+ int64_t ret;
+ int32_t cluster_sector;
if (m_data) {
m_data->valid = 0;
@@ -1090,52 +1167,41 @@ static int get_cluster_offset(BlockDriverState *bs,
extent->l2_cache_counts[min_index] = 1;
found:
l2_index = ((offset >> 9) / extent->cluster_sectors) % extent->l2_size;
- *cluster_offset = le32_to_cpu(l2_table[l2_index]);
+ cluster_sector = le32_to_cpu(l2_table[l2_index]);
if (m_data) {
m_data->valid = 1;
m_data->l1_index = l1_index;
m_data->l2_index = l2_index;
- m_data->offset = *cluster_offset;
m_data->l2_offset = l2_offset;
m_data->l2_cache_entry = &l2_table[l2_index];
}
- if (extent->has_zero_grain && *cluster_offset == VMDK_GTE_ZEROED) {
+ if (extent->has_zero_grain && cluster_sector == VMDK_GTE_ZEROED) {
zeroed = true;
}
- if (!*cluster_offset || zeroed) {
+ if (!cluster_sector || zeroed) {
if (!allocate) {
return zeroed ? VMDK_ZEROED : VMDK_UNALLOC;
}
- /* Avoid the L2 tables update for the images that have snapshots. */
- *cluster_offset = bdrv_getlength(extent->file);
- if (!extent->compressed) {
- bdrv_truncate(
- extent->file,
- *cluster_offset + (extent->cluster_sectors << 9)
- );
- }
-
- *cluster_offset >>= 9;
- l2_table[l2_index] = cpu_to_le32(*cluster_offset);
+ cluster_sector = extent->next_cluster_sector;
+ extent->next_cluster_sector += extent->cluster_sectors;
/* First of all we write grain itself, to avoid race condition
* that may to corrupt the image.
* This problem may occur because of insufficient space on host disk
* or inappropriate VM shutdown.
*/
- if (get_whole_cluster(
- bs, extent, *cluster_offset, offset, allocate) == -1) {
- return VMDK_ERROR;
- }
-
- if (m_data) {
- m_data->offset = *cluster_offset;
+ ret = get_whole_cluster(bs, extent,
+ cluster_sector,
+ offset >> BDRV_SECTOR_BITS,
+ skip_start_sector, skip_end_sector);
+ if (ret) {
+ return ret;
}
}
- *cluster_offset <<= 9;
+ *cluster_offset = cluster_sector << BDRV_SECTOR_BITS;
return VMDK_OK;
}
@@ -1170,7 +1236,8 @@ static int64_t coroutine_fn vmdk_co_get_block_status(BlockDriverState *bs,
}
qemu_co_mutex_lock(&s->lock);
ret = get_cluster_offset(bs, extent, NULL,
- sector_num * 512, 0, &offset);
+ sector_num * 512, false, &offset,
+ 0, 0);
qemu_co_mutex_unlock(&s->lock);
switch (ret) {
@@ -1323,9 +1390,9 @@ static int vmdk_read(BlockDriverState *bs, int64_t sector_num,
if (!extent) {
return -EIO;
}
- ret = get_cluster_offset(
- bs, extent, NULL,
- sector_num << 9, 0, &cluster_offset);
+ ret = get_cluster_offset(bs, extent, NULL,
+ sector_num << 9, false, &cluster_offset,
+ 0, 0);
extent_begin_sector = extent->end_sector - extent->sectors;
extent_relative_sector_num = sector_num - extent_begin_sector;
index_in_cluster = extent_relative_sector_num % extent->cluster_sectors;
@@ -1406,12 +1473,17 @@ static int vmdk_write(BlockDriverState *bs, int64_t sector_num,
if (!extent) {
return -EIO;
}
- ret = get_cluster_offset(
- bs,
- extent,
- &m_data,
- sector_num << 9, !extent->compressed,
- &cluster_offset);
+ extent_begin_sector = extent->end_sector - extent->sectors;
+ extent_relative_sector_num = sector_num - extent_begin_sector;
+ index_in_cluster = extent_relative_sector_num % extent->cluster_sectors;
+ n = extent->cluster_sectors - index_in_cluster;
+ if (n > nb_sectors) {
+ n = nb_sectors;
+ }
+ ret = get_cluster_offset(bs, extent, &m_data, sector_num << 9,
+ !(extent->compressed || zeroed),
+ &cluster_offset,
+ index_in_cluster, index_in_cluster + n);
if (extent->compressed) {
if (ret == VMDK_OK) {
/* Refuse write to allocated cluster for streamOptimized */
@@ -1420,24 +1492,13 @@ static int vmdk_write(BlockDriverState *bs, int64_t sector_num,
return -EIO;
} else {
/* allocate */
- ret = get_cluster_offset(
- bs,
- extent,
- &m_data,
- sector_num << 9, 1,
- &cluster_offset);
+ ret = get_cluster_offset(bs, extent, &m_data, sector_num << 9,
+ true, &cluster_offset, 0, 0);
}
}
if (ret == VMDK_ERROR) {
return -EINVAL;
}
- extent_begin_sector = extent->end_sector - extent->sectors;
- extent_relative_sector_num = sector_num - extent_begin_sector;
- index_in_cluster = extent_relative_sector_num % extent->cluster_sectors;
- n = extent->cluster_sectors - index_in_cluster;
- if (n > nb_sectors) {
- n = nb_sectors;
- }
if (zeroed) {
/* Do zeroed write, buf is ignored */
if (extent->has_zero_grain &&
@@ -1445,9 +1506,9 @@ static int vmdk_write(BlockDriverState *bs, int64_t sector_num,
n >= extent->cluster_sectors) {
n = extent->cluster_sectors;
if (!zero_dry_run) {
- m_data.offset = VMDK_GTE_ZEROED;
/* update L2 tables */
- if (vmdk_L2update(extent, &m_data) != VMDK_OK) {
+ if (vmdk_L2update(extent, &m_data, VMDK_GTE_ZEROED)
+ != VMDK_OK) {
return -EIO;
}
}
@@ -1463,7 +1524,9 @@ static int vmdk_write(BlockDriverState *bs, int64_t sector_num,
}
if (m_data.valid) {
/* update L2 tables */
- if (vmdk_L2update(extent, &m_data) != VMDK_OK) {
+ if (vmdk_L2update(extent, &m_data,
+ cluster_offset >> BDRV_SECTOR_BITS)
+ != VMDK_OK) {
return -EIO;
}
}
@@ -2001,7 +2064,7 @@ static int vmdk_check(BlockDriverState *bs, BdrvCheckResult *result,
BDRVVmdkState *s = bs->opaque;
VmdkExtent *extent = NULL;
int64_t sector_num = 0;
- int64_t total_sectors = bdrv_getlength(bs) / BDRV_SECTOR_SIZE;
+ int64_t total_sectors = bdrv_nb_sectors(bs);
int ret;
uint64_t cluster_offset;
@@ -2022,7 +2085,7 @@ static int vmdk_check(BlockDriverState *bs, BdrvCheckResult *result,
}
ret = get_cluster_offset(bs, extent, NULL,
sector_num << BDRV_SECTOR_BITS,
- 0, &cluster_offset);
+ false, &cluster_offset, 0, 0);
if (ret == VMDK_ERROR) {
fprintf(stderr,
"ERROR: could not get cluster_offset for sector %"
diff --git a/block/vpc.c b/block/vpc.c
index 8b376a40be..055efc42d2 100644
--- a/block/vpc.c
+++ b/block/vpc.c
@@ -29,13 +29,6 @@
#if defined(CONFIG_UUID)
#include <uuid/uuid.h>
#endif
-#ifdef __linux__
-#include <linux/fs.h>
-#include <sys/ioctl.h>
-#ifndef FS_NOCOW_FL
-#define FS_NOCOW_FL 0x00800000 /* Do not cow file */
-#endif
-#endif
/**************************************************************/
@@ -276,7 +269,11 @@ static int vpc_open(BlockDriverState *bs, QDict *options, int flags,
goto fail;
}
- s->pagetable = qemu_blockalign(bs, s->max_table_entries * 4);
+ s->pagetable = qemu_try_blockalign(bs->file, s->max_table_entries * 4);
+ if (s->pagetable == NULL) {
+ ret = -ENOMEM;
+ goto fail;
+ }
s->bat_offset = be64_to_cpu(dyndisk_header->table_offset);
@@ -656,39 +653,41 @@ static int calculate_geometry(int64_t total_sectors, uint16_t* cyls,
return 0;
}
-static int create_dynamic_disk(int fd, uint8_t *buf, int64_t total_sectors)
+static int create_dynamic_disk(BlockDriverState *bs, uint8_t *buf,
+ int64_t total_sectors)
{
VHDDynDiskHeader *dyndisk_header =
(VHDDynDiskHeader *) buf;
size_t block_size, num_bat_entries;
int i;
- int ret = -EIO;
+ int ret;
+ int64_t offset = 0;
// Write the footer (twice: at the beginning and at the end)
block_size = 0x200000;
num_bat_entries = (total_sectors + block_size / 512) / (block_size / 512);
- if (write(fd, buf, HEADER_SIZE) != HEADER_SIZE) {
+ ret = bdrv_pwrite_sync(bs, offset, buf, HEADER_SIZE);
+ if (ret) {
goto fail;
}
- if (lseek(fd, 1536 + ((num_bat_entries * 4 + 511) & ~511), SEEK_SET) < 0) {
- goto fail;
- }
- if (write(fd, buf, HEADER_SIZE) != HEADER_SIZE) {
+ offset = 1536 + ((num_bat_entries * 4 + 511) & ~511);
+ ret = bdrv_pwrite_sync(bs, offset, buf, HEADER_SIZE);
+ if (ret < 0) {
goto fail;
}
// Write the initial BAT
- if (lseek(fd, 3 * 512, SEEK_SET) < 0) {
- goto fail;
- }
+ offset = 3 * 512;
memset(buf, 0xFF, 512);
for (i = 0; i < (num_bat_entries * 4 + 511) / 512; i++) {
- if (write(fd, buf, 512) != 512) {
+ ret = bdrv_pwrite_sync(bs, offset, buf, 512);
+ if (ret < 0) {
goto fail;
}
+ offset += 512;
}
// Prepare the Dynamic Disk Header
@@ -709,39 +708,35 @@ static int create_dynamic_disk(int fd, uint8_t *buf, int64_t total_sectors)
dyndisk_header->checksum = be32_to_cpu(vpc_checksum(buf, 1024));
// Write the header
- if (lseek(fd, 512, SEEK_SET) < 0) {
- goto fail;
- }
+ offset = 512;
- if (write(fd, buf, 1024) != 1024) {
+ ret = bdrv_pwrite_sync(bs, offset, buf, 1024);
+ if (ret < 0) {
goto fail;
}
- ret = 0;
fail:
return ret;
}
-static int create_fixed_disk(int fd, uint8_t *buf, int64_t total_size)
+static int create_fixed_disk(BlockDriverState *bs, uint8_t *buf,
+ int64_t total_size)
{
- int ret = -EIO;
+ int ret;
/* Add footer to total size */
- total_size += 512;
- if (ftruncate(fd, total_size) != 0) {
- ret = -errno;
- goto fail;
- }
- if (lseek(fd, -512, SEEK_END) < 0) {
- goto fail;
- }
- if (write(fd, buf, HEADER_SIZE) != HEADER_SIZE) {
- goto fail;
+ total_size += HEADER_SIZE;
+
+ ret = bdrv_truncate(bs, total_size);
+ if (ret < 0) {
+ return ret;
}
- ret = 0;
+ ret = bdrv_pwrite_sync(bs, total_size - HEADER_SIZE, buf, HEADER_SIZE);
+ if (ret < 0) {
+ return ret;
+ }
- fail:
return ret;
}
@@ -750,7 +745,7 @@ static int vpc_create(const char *filename, QemuOpts *opts, Error **errp)
uint8_t buf[1024];
VHDFooter *footer = (VHDFooter *) buf;
char *disk_type_param;
- int fd, i;
+ int i;
uint16_t cyls = 0;
uint8_t heads = 0;
uint8_t secs_per_cyl = 0;
@@ -758,7 +753,8 @@ static int vpc_create(const char *filename, QemuOpts *opts, Error **errp)
int64_t total_size;
int disk_type;
int ret = -EIO;
- bool nocow = false;
+ Error *local_err = NULL;
+ BlockDriverState *bs = NULL;
/* Read out options */
total_size = qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0);
@@ -775,28 +771,17 @@ static int vpc_create(const char *filename, QemuOpts *opts, Error **errp)
} else {
disk_type = VHD_DYNAMIC;
}
- nocow = qemu_opt_get_bool_del(opts, BLOCK_OPT_NOCOW, false);
- /* Create the file */
- fd = qemu_open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0644);
- if (fd < 0) {
- ret = -EIO;
+ ret = bdrv_create_file(filename, opts, &local_err);
+ if (ret < 0) {
+ error_propagate(errp, local_err);
goto out;
}
-
- if (nocow) {
-#ifdef __linux__
- /* Set NOCOW flag to solve performance issue on fs like btrfs.
- * This is an optimisation. The FS_IOC_SETFLAGS ioctl return value will
- * be ignored since any failure of this operation should not block the
- * left work.
- */
- int attr;
- if (ioctl(fd, FS_IOC_GETFLAGS, &attr) == 0) {
- attr |= FS_NOCOW_FL;
- ioctl(fd, FS_IOC_SETFLAGS, &attr);
- }
-#endif
+ ret = bdrv_open(&bs, filename, NULL, NULL, BDRV_O_RDWR | BDRV_O_PROTOCOL,
+ NULL, &local_err);
+ if (ret < 0) {
+ error_propagate(errp, local_err);
+ goto out;
}
/*
@@ -810,7 +795,7 @@ static int vpc_create(const char *filename, QemuOpts *opts, Error **errp)
&secs_per_cyl))
{
ret = -EFBIG;
- goto fail;
+ goto out;
}
}
@@ -856,14 +841,13 @@ static int vpc_create(const char *filename, QemuOpts *opts, Error **errp)
footer->checksum = be32_to_cpu(vpc_checksum(buf, HEADER_SIZE));
if (disk_type == VHD_DYNAMIC) {
- ret = create_dynamic_disk(fd, buf, total_sectors);
+ ret = create_dynamic_disk(bs, buf, total_sectors);
} else {
- ret = create_fixed_disk(fd, buf, total_size);
+ ret = create_fixed_disk(bs, buf, total_size);
}
-fail:
- qemu_close(fd);
out:
+ bdrv_unref(bs);
g_free(disk_type_param);
return ret;
}
diff --git a/block/win32-aio.c b/block/win32-aio.c
index 8e417f70ae..5030e3274d 100644
--- a/block/win32-aio.c
+++ b/block/win32-aio.c
@@ -139,7 +139,10 @@ BlockDriverAIOCB *win32_aio_submit(BlockDriverState *bs,
waiocb->is_read = (type == QEMU_AIO_READ);
if (qiov->niov > 1) {
- waiocb->buf = qemu_blockalign(bs, qiov->size);
+ waiocb->buf = qemu_try_blockalign(bs, qiov->size);
+ if (waiocb->buf == NULL) {
+ goto out;
+ }
if (type & QEMU_AIO_WRITE) {
iov_to_buf(qiov->iov, qiov->niov, 0, waiocb->buf, qiov->size);
}
@@ -168,6 +171,7 @@ BlockDriverAIOCB *win32_aio_submit(BlockDriverState *bs,
out_dec_count:
aio->count--;
+out:
qemu_aio_release(waiocb);
return NULL;
}
diff --git a/configure b/configure
index f7685b565c..283c71cb7a 100755
--- a/configure
+++ b/configure
@@ -326,6 +326,7 @@ seccomp=""
glusterfs=""
glusterfs_discard="no"
glusterfs_zerofill="no"
+archipelago=""
virtio_blk_data_plane=""
gtk=""
gtkabi=""
@@ -1087,6 +1088,10 @@ for opt do
;;
--enable-glusterfs) glusterfs="yes"
;;
+ --disable-archipelago) archipelago="no"
+ ;;
+ --enable-archipelago) archipelago="yes"
+ ;;
--disable-virtio-blk-data-plane) virtio_blk_data_plane="no"
;;
--enable-virtio-blk-data-plane) virtio_blk_data_plane="yes"
@@ -1382,6 +1387,8 @@ Advanced options (experts only):
--enable-coroutine-pool enable coroutine freelist (better performance)
--enable-glusterfs enable GlusterFS backend
--disable-glusterfs disable GlusterFS backend
+ --enable-archipelago enable Archipelago backend
+ --disable-archipelago disable Archipelago backend
--enable-gcov enable test coverage analysis with gcov
--gcov=GCOV use specified gcov [$gcov_tool]
--disable-tpm disable TPM support
@@ -1723,6 +1730,7 @@ fi
cat > $TMPC <<EOF
#include <sys/socket.h>
+#include <linux/ip.h>
int main(void) { return sizeof(struct mmsghdr); }
EOF
if compile_prog "" "" ; then
@@ -3071,6 +3079,33 @@ EOF
fi
fi
+
+##########################################
+# archipelago probe
+if test "$archipelago" != "no" ; then
+ cat > $TMPC <<EOF
+#include <stdio.h>
+#include <xseg/xseg.h>
+#include <xseg/protocol.h>
+int main(void) {
+ xseg_initialize();
+ return 0;
+}
+EOF
+ archipelago_libs=-lxseg
+ if compile_prog "" "$archipelago_libs"; then
+ archipelago="yes"
+ libs_tools="$archipelago_libs $libs_tools"
+ libs_softmmu="$archipelago_libs $libs_softmmu"
+ else
+ if test "$archipelago" = "yes" ; then
+ feature_not_found "Archipelago backend support" "Install libxseg devel"
+ fi
+ archipelago="no"
+ fi
+fi
+
+
##########################################
# glusterfs probe
if test "$glusterfs" != "no" ; then
@@ -3086,7 +3121,8 @@ if test "$glusterfs" != "no" ; then
fi
else
if test "$glusterfs" = "yes" ; then
- feature_not_found "GlusterFS backend support" "Install glusterfs-api devel"
+ feature_not_found "GlusterFS backend support" \
+ "Install glusterfs-api devel >= 3"
fi
glusterfs="no"
fi
@@ -3531,7 +3567,8 @@ EOF
spice_server_version=$($pkg_config --modversion spice-server)
else
if test "$spice" = "yes" ; then
- feature_not_found "spice" "Install spice-server and spice-protocol devel"
+ feature_not_found "spice" \
+ "Install spice-server(>=0.12.0) and spice-protocol(>=0.12.3) devel"
fi
spice="no"
fi
@@ -3562,7 +3599,7 @@ EOF
smartcard_nss="yes"
else
if test "$smartcard_nss" = "yes"; then
- feature_not_found "nss"
+ feature_not_found "nss" "Install nss devel >= 3.12.8"
fi
smartcard_nss="no"
fi
@@ -3578,7 +3615,7 @@ if test "$libusb" != "no" ; then
libs_softmmu="$libs_softmmu $libusb_libs"
else
if test "$libusb" = "yes"; then
- feature_not_found "libusb" "Install libusb devel"
+ feature_not_found "libusb" "Install libusb devel >= 1.0.13"
fi
libusb="no"
fi
@@ -4003,7 +4040,7 @@ if test "$libnfs" != "no" ; then
LIBS="$LIBS $libnfs_libs"
else
if test "$libnfs" = "yes" ; then
- feature_not_found "libnfs"
+ feature_not_found "libnfs" "Install libnfs devel >= 1.9.3"
fi
libnfs="no"
fi
@@ -4250,6 +4287,7 @@ echo "seccomp support $seccomp"
echo "coroutine backend $coroutine"
echo "coroutine pool $coroutine_pool"
echo "GlusterFS support $glusterfs"
+echo "Archipelago support $archipelago"
echo "virtio-blk-data-plane $virtio_blk_data_plane"
echo "gcov $gcov_tool"
echo "gcov enabled $gcov"
@@ -4688,6 +4726,11 @@ if test "$glusterfs_zerofill" = "yes" ; then
echo "CONFIG_GLUSTERFS_ZEROFILL=y" >> $config_host_mak
fi
+if test "$archipelago" = "yes" ; then
+ echo "CONFIG_ARCHIPELAGO=m" >> $config_host_mak
+ echo "ARCHIPELAGO_LIBS=$archipelago_libs" >> $config_host_mak
+fi
+
if test "$libssh2" = "yes" ; then
echo "CONFIG_LIBSSH2=m" >> $config_host_mak
echo "LIBSSH2_CFLAGS=$libssh2_cflags" >> $config_host_mak
diff --git a/cpu-exec.c b/cpu-exec.c
index 38e5f02a30..c6aad742e1 100644
--- a/cpu-exec.c
+++ b/cpu-exec.c
@@ -18,10 +18,114 @@
*/
#include "config.h"
#include "cpu.h"
+#include "trace.h"
#include "disas/disas.h"
#include "tcg.h"
#include "qemu/atomic.h"
#include "sysemu/qtest.h"
+#include "qemu/timer.h"
+
+/* -icount align implementation. */
+
+typedef struct SyncClocks {
+ int64_t diff_clk;
+ int64_t last_cpu_icount;
+ int64_t realtime_clock;
+} SyncClocks;
+
+#if !defined(CONFIG_USER_ONLY)
+/* Allow the guest to have a max 3ms advance.
+ * The difference between the 2 clocks could therefore
+ * oscillate around 0.
+ */
+#define VM_CLOCK_ADVANCE 3000000
+#define THRESHOLD_REDUCE 1.5
+#define MAX_DELAY_PRINT_RATE 2000000000LL
+#define MAX_NB_PRINTS 100
+
+static void align_clocks(SyncClocks *sc, const CPUState *cpu)
+{
+ int64_t cpu_icount;
+
+ if (!icount_align_option) {
+ return;
+ }
+
+ cpu_icount = cpu->icount_extra + cpu->icount_decr.u16.low;
+ sc->diff_clk += cpu_icount_to_ns(sc->last_cpu_icount - cpu_icount);
+ sc->last_cpu_icount = cpu_icount;
+
+ if (sc->diff_clk > VM_CLOCK_ADVANCE) {
+#ifndef _WIN32
+ struct timespec sleep_delay, rem_delay;
+ sleep_delay.tv_sec = sc->diff_clk / 1000000000LL;
+ sleep_delay.tv_nsec = sc->diff_clk % 1000000000LL;
+ if (nanosleep(&sleep_delay, &rem_delay) < 0) {
+ sc->diff_clk -= (sleep_delay.tv_sec - rem_delay.tv_sec) * 1000000000LL;
+ sc->diff_clk -= sleep_delay.tv_nsec - rem_delay.tv_nsec;
+ } else {
+ sc->diff_clk = 0;
+ }
+#else
+ Sleep(sc->diff_clk / SCALE_MS);
+ sc->diff_clk = 0;
+#endif
+ }
+}
+
+static void print_delay(const SyncClocks *sc)
+{
+ static float threshold_delay;
+ static int64_t last_realtime_clock;
+ static int nb_prints;
+
+ if (icount_align_option &&
+ sc->realtime_clock - last_realtime_clock >= MAX_DELAY_PRINT_RATE &&
+ nb_prints < MAX_NB_PRINTS) {
+ if ((-sc->diff_clk / (float)1000000000LL > threshold_delay) ||
+ (-sc->diff_clk / (float)1000000000LL <
+ (threshold_delay - THRESHOLD_REDUCE))) {
+ threshold_delay = (-sc->diff_clk / 1000000000LL) + 1;
+ printf("Warning: The guest is now late by %.1f to %.1f seconds\n",
+ threshold_delay - 1,
+ threshold_delay);
+ nb_prints++;
+ last_realtime_clock = sc->realtime_clock;
+ }
+ }
+}
+
+static void init_delay_params(SyncClocks *sc,
+ const CPUState *cpu)
+{
+ if (!icount_align_option) {
+ return;
+ }
+ sc->realtime_clock = qemu_clock_get_ns(QEMU_CLOCK_REALTIME);
+ sc->diff_clk = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) -
+ sc->realtime_clock +
+ cpu_get_clock_offset();
+ sc->last_cpu_icount = cpu->icount_extra + cpu->icount_decr.u16.low;
+ if (sc->diff_clk < max_delay) {
+ max_delay = sc->diff_clk;
+ }
+ if (sc->diff_clk > max_advance) {
+ max_advance = sc->diff_clk;
+ }
+
+ /* Print every 2s max if the guest is late. We limit the number
+ of printed messages to NB_PRINT_MAX(currently 100) */
+ print_delay(sc);
+}
+#else
+static void align_clocks(SyncClocks *sc, const CPUState *cpu)
+{
+}
+
+static void init_delay_params(SyncClocks *sc, const CPUState *cpu)
+{
+}
+#endif /* CONFIG USER ONLY */
void cpu_loop_exit(CPUState *cpu)
{
@@ -65,6 +169,9 @@ static inline tcg_target_ulong cpu_tb_exec(CPUState *cpu, uint8_t *tb_ptr)
#endif /* DEBUG_DISAS */
next_tb = tcg_qemu_tb_exec(env, tb_ptr);
+ trace_exec_tb_exit((void *) (next_tb & ~TB_EXIT_MASK),
+ next_tb & TB_EXIT_MASK);
+
if ((next_tb & TB_EXIT_MASK) > TB_EXIT_IDX1) {
/* We didn't start executing this TB (eg because the instruction
* counter hit zero); we must restore the guest PC to the address
@@ -105,6 +212,7 @@ static void cpu_exec_nocache(CPUArchState *env, int max_cycles,
max_cycles);
cpu->current_tb = tb;
/* execute the generated code */
+ trace_exec_tb_nocache(tb, tb->pc);
cpu_tb_exec(cpu, tb->tc_ptr);
cpu->current_tb = NULL;
tb_phys_invalidate(tb, -1);
@@ -227,6 +335,8 @@ int cpu_exec(CPUArchState *env)
TranslationBlock *tb;
uint8_t *tc_ptr;
uintptr_t next_tb;
+ SyncClocks sc;
+
/* This must be volatile so it is not trashed by longjmp() */
volatile bool have_tb_lock = false;
@@ -283,6 +393,13 @@ int cpu_exec(CPUArchState *env)
#endif
cpu->exception_index = -1;
+ /* Calculate difference between guest clock and host clock.
+ * This delay includes the delay of the last cycle, so
+ * what we have to do is sleep until it is 0. As for the
+ * advance/delay we gain here, we try to fix it next time.
+ */
+ init_delay_params(&sc, cpu);
+
/* prepare setjmp context for exception handling */
for(;;) {
if (sigsetjmp(cpu->jmp_env, 0) == 0) {
@@ -637,6 +754,7 @@ int cpu_exec(CPUArchState *env)
cpu->current_tb = tb;
barrier();
if (likely(!cpu->exit_request)) {
+ trace_exec_tb(tb, tb->pc);
tc_ptr = tb->tc_ptr;
/* execute the generated code */
next_tb = cpu_tb_exec(cpu, tc_ptr);
@@ -672,6 +790,7 @@ int cpu_exec(CPUArchState *env)
if (insns_left > 0) {
/* Execute remaining instructions. */
cpu_exec_nocache(env, insns_left, tb);
+ align_clocks(&sc, cpu);
}
cpu->exception_index = EXCP_INTERRUPT;
next_tb = 0;
@@ -684,6 +803,9 @@ int cpu_exec(CPUArchState *env)
}
}
cpu->current_tb = NULL;
+ /* Try to align the host and virtual clocks
+ if the guest is in advance */
+ align_clocks(&sc, cpu);
/* reset soft MMU for next block (it can currently
only be set by a memory fault) */
} /* for(;;) */
diff --git a/cpus.c b/cpus.c
index 5e7f2cf3cf..2b5c0bd7c7 100644
--- a/cpus.c
+++ b/cpus.c
@@ -64,6 +64,8 @@
#endif /* CONFIG_LINUX */
static CPUState *next_cpu;
+int64_t max_delay;
+int64_t max_advance;
bool cpu_is_stopped(CPUState *cpu)
{
@@ -102,17 +104,12 @@ static bool all_cpu_threads_idle(void)
/* Protected by TimersState seqlock */
-/* Compensate for varying guest execution speed. */
-static int64_t qemu_icount_bias;
-static int64_t vm_clock_warp_start;
+static int64_t vm_clock_warp_start = -1;
/* Conversion factor from emulated instructions to virtual clock ticks. */
static int icount_time_shift;
/* Arbitrarily pick 1MIPS as the minimum allowable speed. */
#define MAX_ICOUNT_SHIFT 10
-/* Only written by TCG thread */
-static int64_t qemu_icount;
-
static QEMUTimer *icount_rt_timer;
static QEMUTimer *icount_vm_timer;
static QEMUTimer *icount_warp_timer;
@@ -129,6 +126,11 @@ typedef struct TimersState {
int64_t cpu_clock_offset;
int32_t cpu_ticks_enabled;
int64_t dummy;
+
+ /* Compensate for varying guest execution speed. */
+ int64_t qemu_icount_bias;
+ /* Only written by TCG thread */
+ int64_t qemu_icount;
} TimersState;
static TimersState timers_state;
@@ -139,14 +141,14 @@ static int64_t cpu_get_icount_locked(void)
int64_t icount;
CPUState *cpu = current_cpu;
- icount = qemu_icount;
+ icount = timers_state.qemu_icount;
if (cpu) {
if (!cpu_can_do_io(cpu)) {
fprintf(stderr, "Bad clock read\n");
}
icount -= (cpu->icount_decr.u16.low + cpu->icount_extra);
}
- return qemu_icount_bias + (icount << icount_time_shift);
+ return timers_state.qemu_icount_bias + cpu_icount_to_ns(icount);
}
int64_t cpu_get_icount(void)
@@ -162,6 +164,11 @@ int64_t cpu_get_icount(void)
return icount;
}
+int64_t cpu_icount_to_ns(int64_t icount)
+{
+ return icount << icount_time_shift;
+}
+
/* return the host CPU cycle counter and handle stop/restart */
/* Caller must hold the BQL */
int64_t cpu_get_ticks(void)
@@ -214,6 +221,23 @@ int64_t cpu_get_clock(void)
return ti;
}
+/* return the offset between the host clock and virtual CPU clock */
+int64_t cpu_get_clock_offset(void)
+{
+ int64_t ti;
+ unsigned start;
+
+ do {
+ start = seqlock_read_begin(&timers_state.vm_clock_seqlock);
+ ti = timers_state.cpu_clock_offset;
+ if (!timers_state.cpu_ticks_enabled) {
+ ti -= get_clock();
+ }
+ } while (seqlock_read_retry(&timers_state.vm_clock_seqlock, start));
+
+ return -ti;
+}
+
/* enable cpu_get_ticks()
* Caller must hold BQL which server as mutex for vm_clock_seqlock.
*/
@@ -284,7 +308,8 @@ static void icount_adjust(void)
icount_time_shift++;
}
last_delta = delta;
- qemu_icount_bias = cur_icount - (qemu_icount << icount_time_shift);
+ timers_state.qemu_icount_bias = cur_icount
+ - (timers_state.qemu_icount << icount_time_shift);
seqlock_write_unlock(&timers_state.vm_clock_seqlock);
}
@@ -333,7 +358,7 @@ static void icount_warp_rt(void *opaque)
int64_t delta = cur_time - cur_icount;
warp_delta = MIN(warp_delta, delta);
}
- qemu_icount_bias += warp_delta;
+ timers_state.qemu_icount_bias += warp_delta;
}
vm_clock_warp_start = -1;
seqlock_write_unlock(&timers_state.vm_clock_seqlock);
@@ -351,7 +376,7 @@ void qtest_clock_warp(int64_t dest)
int64_t deadline = qemu_clock_deadline_ns_all(QEMU_CLOCK_VIRTUAL);
int64_t warp = qemu_soonest_timeout(dest - clock, deadline);
seqlock_write_lock(&timers_state.vm_clock_seqlock);
- qemu_icount_bias += warp;
+ timers_state.qemu_icount_bias += warp;
seqlock_write_unlock(&timers_state.vm_clock_seqlock);
qemu_clock_run_timers(QEMU_CLOCK_VIRTUAL);
@@ -428,6 +453,25 @@ void qemu_clock_warp(QEMUClockType type)
}
}
+static bool icount_state_needed(void *opaque)
+{
+ return use_icount;
+}
+
+/*
+ * This is a subsection for icount migration.
+ */
+static const VMStateDescription icount_vmstate_timers = {
+ .name = "timer/icount",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .fields = (VMStateField[]) {
+ VMSTATE_INT64(qemu_icount_bias, TimersState),
+ VMSTATE_INT64(qemu_icount, TimersState),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
static const VMStateDescription vmstate_timers = {
.name = "timer",
.version_id = 2,
@@ -437,23 +481,44 @@ static const VMStateDescription vmstate_timers = {
VMSTATE_INT64(dummy, TimersState),
VMSTATE_INT64_V(cpu_clock_offset, TimersState, 2),
VMSTATE_END_OF_LIST()
+ },
+ .subsections = (VMStateSubsection[]) {
+ {
+ .vmsd = &icount_vmstate_timers,
+ .needed = icount_state_needed,
+ }, {
+ /* empty */
+ }
}
};
-void configure_icount(const char *option)
+void configure_icount(QemuOpts *opts, Error **errp)
{
+ const char *option;
+ char *rem_str = NULL;
+
seqlock_init(&timers_state.vm_clock_seqlock, NULL);
vmstate_register(NULL, 0, &vmstate_timers, &timers_state);
+ option = qemu_opt_get(opts, "shift");
if (!option) {
+ if (qemu_opt_get(opts, "align") != NULL) {
+ error_setg(errp, "Please specify shift option when using align");
+ }
return;
}
-
+ icount_align_option = qemu_opt_get_bool(opts, "align", false);
icount_warp_timer = timer_new_ns(QEMU_CLOCK_REALTIME,
icount_warp_rt, NULL);
if (strcmp(option, "auto") != 0) {
- icount_time_shift = strtol(option, NULL, 0);
+ errno = 0;
+ icount_time_shift = strtol(option, &rem_str, 0);
+ if (errno != 0 || *rem_str != '\0' || !strlen(option)) {
+ error_setg(errp, "icount: Invalid shift value");
+ }
use_icount = 1;
return;
+ } else if (icount_align_option) {
+ error_setg(errp, "shift=auto and align=on are incompatible");
}
use_icount = 2;
@@ -1250,7 +1315,8 @@ static int tcg_cpu_exec(CPUArchState *env)
int64_t count;
int64_t deadline;
int decr;
- qemu_icount -= (cpu->icount_decr.u16.low + cpu->icount_extra);
+ timers_state.qemu_icount -= (cpu->icount_decr.u16.low
+ + cpu->icount_extra);
cpu->icount_decr.u16.low = 0;
cpu->icount_extra = 0;
deadline = qemu_clock_deadline_ns_all(QEMU_CLOCK_VIRTUAL);
@@ -1265,7 +1331,7 @@ static int tcg_cpu_exec(CPUArchState *env)
}
count = qemu_icount_round(deadline);
- qemu_icount += count;
+ timers_state.qemu_icount += count;
decr = (count > 0xffff) ? 0xffff : count;
count -= decr;
cpu->icount_decr.u16.low = decr;
@@ -1278,7 +1344,8 @@ static int tcg_cpu_exec(CPUArchState *env)
if (use_icount) {
/* Fold pending instructions back into the
instruction counter, and clear the interrupt flag. */
- qemu_icount -= (cpu->icount_decr.u16.low + cpu->icount_extra);
+ timers_state.qemu_icount -= (cpu->icount_decr.u16.low
+ + cpu->icount_extra);
cpu->icount_decr.u32 = 0;
cpu->icount_extra = 0;
}
@@ -1487,3 +1554,20 @@ void qmp_inject_nmi(Error **errp)
error_set(errp, QERR_UNSUPPORTED);
#endif
}
+
+void dump_drift_info(FILE *f, fprintf_function cpu_fprintf)
+{
+ if (!use_icount) {
+ return;
+ }
+
+ cpu_fprintf(f, "Host - Guest clock %"PRIi64" ms\n",
+ (cpu_get_clock() - cpu_get_icount())/SCALE_MS);
+ if (icount_align_option) {
+ cpu_fprintf(f, "Max guest delay %"PRIi64" ms\n", -max_delay/SCALE_MS);
+ cpu_fprintf(f, "Max guest advance %"PRIi64" ms\n", max_advance/SCALE_MS);
+ } else {
+ cpu_fprintf(f, "Max guest delay NA\n");
+ cpu_fprintf(f, "Max guest advance NA\n");
+ }
+}
diff --git a/docs/image-fuzzer.txt b/docs/image-fuzzer.txt
new file mode 100644
index 0000000000..0d0005d34a
--- /dev/null
+++ b/docs/image-fuzzer.txt
@@ -0,0 +1,238 @@
+# Specification for the fuzz testing tool
+#
+# Copyright (C) 2014 Maria Kustova <maria.k@catit.be>
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+
+Image fuzzer
+============
+
+Description
+-----------
+
+The goal of the image fuzzer is to catch crashes of qemu-io/qemu-img
+by providing to them randomly corrupted images.
+Test images are generated from scratch and have valid inner structure with some
+elements, e.g. L1/L2 tables, having random invalid values.
+
+
+Test runner
+-----------
+
+The test runner generates test images, executes tests utilizing generated
+images, indicates their results and collects all test related artifacts (logs,
+core dumps, test images, backing files).
+The test means execution of all available commands under test with the same
+generated test image.
+By default, the test runner generates new tests and executes them until
+keyboard interruption. But if a test seed is specified via the '--seed' runner
+parameter, then only one test with this seed will be executed, after its finish
+the runner will exit.
+
+The runner uses an external image fuzzer to generate test images. An image
+generator should be specified as a mandatory parameter of the test runner.
+Details about interactions between the runner and fuzzers see "Module
+interfaces".
+
+The runner activates generation of core dumps during test executions, but it
+assumes that core dumps will be generated in the current working directory.
+For comprehensive test results, please, set up your test environment
+properly.
+
+Paths to binaries under test (SUTs) qemu-img and qemu-io are retrieved from
+environment variables. If the environment check fails the runner will
+use SUTs installed in system paths.
+qemu-img is required for creation of backing files, so it's mandatory to set
+the related environment variable if it's not installed in the system path.
+For details about environment variables see qemu-iotests/check.
+
+The runner accepts a JSON array of fields expected to be fuzzed via the
+'--config' argument, e.g.
+
+ '[["feature_name_table"], ["header", "l1_table_offset"]]'
+
+Each sublist can have one or two strings defining image structure elements.
+In the latter case a parent element should be placed on the first position,
+and a field name on the second one.
+
+The runner accepts a list of commands under test as a JSON array via
+the '--command' argument. Each command is a list containing a SUT and all its
+arguments, e.g.
+
+ runner.py -c '[["qemu-io", "$test_img", "-c", "write $off $len"]]'
+ /tmp/test ../qcow2
+
+For variable arguments next aliases can be used:
+ - $test_img for a fuzzed img
+ - $off for an offset in the fuzzed image
+ - $len for a data size
+
+Values for last two aliases will be generated based on a size of a virtual
+disk of the generated image.
+In case when no commands are specified the runner will execute commands from
+the default list:
+ - qemu-img check
+ - qemu-img info
+ - qemu-img convert
+ - qemu-io -c read
+ - qemu-io -c write
+ - qemu-io -c aio_read
+ - qemu-io -c aio_write
+ - qemu-io -c flush
+ - qemu-io -c discard
+ - qemu-io -c truncate
+
+
+Qcow2 image generator
+---------------------
+
+The 'qcow2' generator is a Python package providing 'create_image' method as
+a single public API. See details in 'Test runner/image fuzzer' chapter of
+'Module interfaces'.
+
+Qcow2 contains two submodules: fuzz.py and layout.py.
+
+'fuzz.py' contains all fuzzing functions, one per image field. It's assumed
+that after code analysis every field will have own constraints for its value.
+For now only universal potentially dangerous values are used, e.g. type limits
+for integers or unsafe symbols as '%s' for strings. For bitmasks random amount
+of bits are set to ones. All fuzzed values are checked on non-equality to the
+current valid value of the field. In case of equality the value will be
+regenerated.
+
+'layout.py' creates a random valid image, fuzzes a random subset of the image
+fields by 'fuzz.py' module and writes a fuzzed image to the file specified.
+If a fuzzer configuration is specified, then it has the next interpretation:
+
+ 1. If a list contains a parent image element only, then some random portion
+ of fields of this element will be fuzzed every test.
+ The same behavior is applied for the entire image if no configuration is
+ used. This case is useful for the test specialization.
+
+ 2. If a list contains a parent element and a field name, then a field
+ will be always fuzzed for every test. This case is useful for regression
+ testing.
+
+For now only header fields, header extensions and L1/L2 tables are generated.
+
+Module interfaces
+-----------------
+
+* Test runner/image fuzzer
+
+The runner calls an image generator specifying the path to a test image file,
+path to a backing file and its format and a fuzzer configuration.
+An image generator is expected to provide a
+
+ 'create_image(test_img_path, backing_file_path=None,
+ backing_file_format=None, fuzz_config=None)'
+
+method that creates a test image, writes it to the specified file and returns
+the size of the virtual disk.
+The file should be created if it doesn't exist or overwritten otherwise.
+fuzz_config has a form of a list of lists. Every sublist can have one
+or two elements: first element is a name of a parent image element, second one
+if exists is a name of a field in this element.
+Example,
+ [['header', 'l1_table_offset'],
+ ['header', 'nb_snapshots'],
+ ['feature_name_table']]
+
+Random seed is set by the runner at every test execution for the regression
+purpose, so an image generator is not recommended to modify it internally.
+
+
+Overall fuzzer requirements
+===========================
+
+Input data:
+----------
+
+ - image template (generator)
+ - work directory
+ - action vector (optional)
+ - seed (optional)
+ - SUT and its arguments (optional)
+
+
+Fuzzer requirements:
+-------------------
+
+1. Should be able to inject random data
+2. Should be able to select a random value from the manually pregenerated
+ vector (boundary values, e.g. max/min cluster size)
+3. Image template should describe a general structure invariant for all
+ test images (image format description)
+4. Image template should be autonomous and other fuzzer parts should not
+ rely on it
+5. Image template should contain reference rules (not only block+size
+ description)
+6. Should generate the test image with the correct structure based on an image
+ template
+7. Should accept a seed as an argument (for regression purpose)
+8. Should generate a seed if it is not specified as an input parameter.
+9. The same seed should generate the same image for the same action vector,
+ specified or generated.
+10. Should accept a vector of actions as an argument (for test reproducing and
+ for test case specification, e.g. group of tests for header structure,
+ group of test for snapshots, etc)
+11. Action vector should be randomly generated from the pool of available
+ actions, if it is not specified as an input parameter
+12. Pool of actions should be defined automatically based on an image template
+13. Should accept a SUT and its call parameters as an argument or select them
+ randomly otherwise. As far as it's expected to be rarely changed, the list
+ of all possible test commands can be available in the test runner
+ internally.
+14. Should support an external cancellation of a test run
+15. Seed should be logged (for regression purpose)
+16. All files related to a test result should be collected: a test image,
+ SUT logs, fuzzer logs and crash dumps
+17. Should be compatible with python version 2.4-2.7
+18. Usage of external libraries should be limited as much as possible.
+
+
+Image formats:
+-------------
+
+Main target image format is qcow2, but support of image templates should
+provide an ability to add any other image format.
+
+
+Effectiveness:
+-------------
+
+The fuzzer can be controlled via template, seed and action vector;
+it makes the fuzzer itself invariant to an image format and test logic.
+It should be able to perform rather complex and precise tests, that can be
+specified via an action vector. Otherwise, knowledge about an image structure
+allows the fuzzer to generate the pool of all available areas can be fuzzed
+and randomly select some of them and so compose its own action vector.
+Also complexity of a template defines complexity of the fuzzer, so its
+functionality can be varied from simple model-independent fuzzing to smart
+model-based one.
+
+
+Glossary:
+--------
+
+Action vector is a sequence of structure elements retrieved from an image
+format, each of them will be fuzzed for the test image. It's a subset of
+elements of the action pool. Example: header, refcount table, etc.
+Action pool is all available elements of an image structure that generated
+automatically from an image template.
+Image template is a formal description of an image structure and relations
+between image blocks.
+Test image is an output image of the fuzzer defined by the current seed and
+action vector.
diff --git a/docs/multiple-iothreads.txt b/docs/multiple-iothreads.txt
new file mode 100644
index 0000000000..40b8419916
--- /dev/null
+++ b/docs/multiple-iothreads.txt
@@ -0,0 +1,134 @@
+Copyright (c) 2014 Red Hat Inc.
+
+This work is licensed under the terms of the GNU GPL, version 2 or later. See
+the COPYING file in the top-level directory.
+
+
+This document explains the IOThread feature and how to write code that runs
+outside the QEMU global mutex.
+
+The main loop and IOThreads
+---------------------------
+QEMU is an event-driven program that can do several things at once using an
+event loop. The VNC server and the QMP monitor are both processed from the
+same event loop, which monitors their file descriptors until they become
+readable and then invokes a callback.
+
+The default event loop is called the main loop (see main-loop.c). It is
+possible to create additional event loop threads using -object
+iothread,id=my-iothread.
+
+Side note: The main loop and IOThread are both event loops but their code is
+not shared completely. Sometimes it is useful to remember that although they
+are conceptually similar they are currently not interchangeable.
+
+Why IOThreads are useful
+------------------------
+IOThreads allow the user to control the placement of work. The main loop is a
+scalability bottleneck on hosts with many CPUs. Work can be spread across
+several IOThreads instead of just one main loop. When set up correctly this
+can improve I/O latency and reduce jitter seen by the guest.
+
+The main loop is also deeply associated with the QEMU global mutex, which is a
+scalability bottleneck in itself. vCPU threads and the main loop use the QEMU
+global mutex to serialize execution of QEMU code. This mutex is necessary
+because a lot of QEMU's code historically was not thread-safe.
+
+The fact that all I/O processing is done in a single main loop and that the
+QEMU global mutex is contended by all vCPU threads and the main loop explain
+why it is desirable to place work into IOThreads.
+
+The experimental virtio-blk data-plane implementation has been benchmarked and
+shows these effects:
+ftp://public.dhe.ibm.com/linux/pdfs/KVM_Virtualized_IO_Performance_Paper.pdf
+
+How to program for IOThreads
+----------------------------
+The main difference between legacy code and new code that can run in an
+IOThread is dealing explicitly with the event loop object, AioContext
+(see include/block/aio.h). Code that only works in the main loop
+implicitly uses the main loop's AioContext. Code that supports running
+in IOThreads must be aware of its AioContext.
+
+AioContext supports the following services:
+ * File descriptor monitoring (read/write/error on POSIX hosts)
+ * Event notifiers (inter-thread signalling)
+ * Timers
+ * Bottom Halves (BH) deferred callbacks
+
+There are several old APIs that use the main loop AioContext:
+ * LEGACY qemu_aio_set_fd_handler() - monitor a file descriptor
+ * LEGACY qemu_aio_set_event_notifier() - monitor an event notifier
+ * LEGACY timer_new_ms() - create a timer
+ * LEGACY qemu_bh_new() - create a BH
+ * LEGACY qemu_aio_wait() - run an event loop iteration
+
+Since they implicitly work on the main loop they cannot be used in code that
+runs in an IOThread. They might cause a crash or deadlock if called from an
+IOThread since the QEMU global mutex is not held.
+
+Instead, use the AioContext functions directly (see include/block/aio.h):
+ * aio_set_fd_handler() - monitor a file descriptor
+ * aio_set_event_notifier() - monitor an event notifier
+ * aio_timer_new() - create a timer
+ * aio_bh_new() - create a BH
+ * aio_poll() - run an event loop iteration
+
+The AioContext can be obtained from the IOThread using
+iothread_get_aio_context() or for the main loop using qemu_get_aio_context().
+Code that takes an AioContext argument works both in IOThreads or the main
+loop, depending on which AioContext instance the caller passes in.
+
+How to synchronize with an IOThread
+-----------------------------------
+AioContext is not thread-safe so some rules must be followed when using file
+descriptors, event notifiers, timers, or BHs across threads:
+
+1. AioContext functions can be called safely from file descriptor, event
+notifier, timer, or BH callbacks invoked by the AioContext. No locking is
+necessary.
+
+2. Other threads wishing to access the AioContext must use
+aio_context_acquire()/aio_context_release() for mutual exclusion. Once the
+context is acquired no other thread can access it or run event loop iterations
+in this AioContext.
+
+aio_context_acquire()/aio_context_release() calls may be nested. This
+means you can call them if you're not sure whether #1 applies.
+
+There is currently no lock ordering rule if a thread needs to acquire multiple
+AioContexts simultaneously. Therefore, it is only safe for code holding the
+QEMU global mutex to acquire other AioContexts.
+
+Side note: the best way to schedule a function call across threads is to create
+a BH in the target AioContext beforehand and then call qemu_bh_schedule(). No
+acquire/release or locking is needed for the qemu_bh_schedule() call. But be
+sure to acquire the AioContext for aio_bh_new() if necessary.
+
+The relationship between AioContext and the block layer
+-------------------------------------------------------
+The AioContext originates from the QEMU block layer because it provides a
+scoped way of running event loop iterations until all work is done. This
+feature is used to complete all in-flight block I/O requests (see
+bdrv_drain_all()). Nowadays AioContext is a generic event loop that can be
+used by any QEMU subsystem.
+
+The block layer has support for AioContext integrated. Each BlockDriverState
+is associated with an AioContext using bdrv_set_aio_context() and
+bdrv_get_aio_context(). This allows block layer code to process I/O inside the
+right AioContext. Other subsystems may wish to follow a similar approach.
+
+Block layer code must therefore expect to run in an IOThread and avoid using
+old APIs that implicitly use the main loop. See the "How to program for
+IOThreads" above for information on how to do that.
+
+If main loop code such as a QMP function wishes to access a BlockDriverState it
+must first call aio_context_acquire(bdrv_get_aio_context(bs)) to ensure the
+IOThread does not run in parallel.
+
+Long-running jobs (usually in the form of coroutines) are best scheduled in the
+BlockDriverState's AioContext to avoid the need to acquire/release around each
+bdrv_*() call. Be aware that there is currently no mechanism to get notified
+when bdrv_set_aio_context() moves this BlockDriverState to a different
+AioContext (see bdrv_detach_aio_context()/bdrv_attach_aio_context()), so you
+may need to add this if you want to support long-running jobs.
diff --git a/docs/qmp/qmp-events.txt b/docs/qmp/qmp-events.txt
index 4a6c2a2c45..d759d19748 100644
--- a/docs/qmp/qmp-events.txt
+++ b/docs/qmp/qmp-events.txt
@@ -243,6 +243,19 @@ Data:
"timestamp": { "seconds": 1368697518, "microseconds": 326866 } }
}
+POWERDOWN
+---------
+
+Emitted when the Virtual Machine is powered down through the power
+control system, such as via ACPI.
+
+Data: None.
+
+Example:
+
+{ "event": "POWERDOWN",
+ "timestamp": { "seconds": 1267040730, "microseconds": 682951 } }
+
QUORUM_FAILURE
--------------
@@ -285,7 +298,7 @@ Example:
RESET
-----
-Emitted when the Virtual Machine is reseted.
+Emitted when the Virtual Machine is reset.
Data: None.
@@ -325,7 +338,8 @@ Example:
SHUTDOWN
--------
-Emitted when the Virtual Machine is powered down.
+Emitted when the Virtual Machine has shut down, indicating that qemu
+is about to exit.
Data: None.
@@ -337,10 +351,10 @@ Example:
Note: If the command-line option "-no-shutdown" has been specified, a STOP
event will eventually follow the SHUTDOWN event.
-SPICE_CONNECTED, SPICE_DISCONNECTED
------------------------------------
+SPICE_CONNECTED
+---------------
-Emitted when a SPICE client connects or disconnects.
+Emitted when a SPICE client connects.
Data:
@@ -362,11 +376,36 @@ Example:
"client": {"port": "52873", "family": "ipv4", "host": "127.0.0.1"}
}}
+SPICE_DISCONNECTED
+------------------
+
+Emitted when a SPICE client disconnects.
+
+Data:
+
+- "server": Server information (json-object)
+ - "host": IP address (json-string)
+ - "port": port number (json-string)
+ - "family": address family (json-string, "ipv4" or "ipv6")
+- "client": Client information (json-object)
+ - "host": IP address (json-string)
+ - "port": port number (json-string)
+ - "family": address family (json-string, "ipv4" or "ipv6")
+
+Example:
+
+{ "timestamp": {"seconds": 1290688046, "microseconds": 388707},
+ "event": "SPICE_DISCONNECTED",
+ "data": {
+ "server": { "port": "5920", "family": "ipv4", "host": "127.0.0.1"},
+ "client": {"port": "52873", "family": "ipv4", "host": "127.0.0.1"}
+}}
+
SPICE_INITIALIZED
-----------------
Emitted after initial handshake and authentication takes place (if any)
-and the SPICE channel is up'n'running
+and the SPICE channel is up and running
Data:
@@ -399,6 +438,19 @@ Example:
"channel-id": 0, "tls": true}
}}
+SPICE_MIGRATE_COMPLETED
+-----------------------
+
+Emitted when SPICE migration has completed
+
+Data: None.
+
+Example:
+
+{ "timestamp": {"seconds": 1290688046, "microseconds": 417172},
+ "event": "SPICE_MIGRATE_COMPLETED" }
+
+
STOP
----
@@ -527,6 +579,22 @@ Example:
"host": "127.0.0.1", "sasl_username": "luiz" } },
"timestamp": { "seconds": 1263475302, "microseconds": 150772 } }
+VSERPORT_CHANGE
+---------------
+
+Emitted when the guest opens or closes a virtio-serial port.
+
+Data:
+
+- "id": device identifier of the virtio-serial port (json-string)
+- "open": true if the guest has opened the virtio-serial port (json-bool)
+
+Example:
+
+{ "event": "VSERPORT_CHANGE",
+ "data": { "id": "channel0", "open": true },
+ "timestamp": { "seconds": 1401385907, "microseconds": 422329 } }
+
WAKEUP
------
diff --git a/docs/specs/qcow2.txt b/docs/specs/qcow2.txt
index 3f713a6447..cfbc8b070c 100644
--- a/docs/specs/qcow2.txt
+++ b/docs/specs/qcow2.txt
@@ -135,12 +135,12 @@ be stored. Each extension has a structure like the following:
Unless stated otherwise, each header extension type shall appear at most once
in the same image.
-The remaining space between the end of the header extension area and the end of
-the first cluster can be used for the backing file name. It is not allowed to
-store other data here, so that an implementation can safely modify the header
-and add extensions without harming data of compatible features that it
-doesn't support. Compatible features that need space for additional data can
-use a header extension.
+If the image has a backing file then the backing file name should be stored in
+the remaining space between the end of the header extension area and the end of
+the first cluster. It is not allowed to store other data here, so that an
+implementation can safely modify the header and add extensions without harming
+data of compatible features that it doesn't support. Compatible features that
+need space for additional data can use a header extension.
== Feature name table ==
diff --git a/docs/tracing.txt b/docs/tracing.txt
index c6ab1c11c1..2e035a5b3c 100644
--- a/docs/tracing.txt
+++ b/docs/tracing.txt
@@ -307,3 +307,43 @@ guard such computations and avoid its compilation when the event is disabled:
You can check both if the event has been disabled and is dynamically enabled at
the same time using the 'trace_event_get_state' routine (see header
"trace/control.h" for more information).
+
+=== "tcg" ===
+
+Guest code generated by TCG can be traced by defining an event with the "tcg"
+event property. Internally, this property generates two events:
+"<eventname>_trans" to trace the event at translation time, and
+"<eventname>_exec" to trace the event at execution time.
+
+Instead of using these two events, you should instead use the function
+"trace_<eventname>_tcg" during translation (TCG code generation). This function
+will automatically call "trace_<eventname>_trans", and will generate the
+necessary TCG code to call "trace_<eventname>_exec" during guest code execution.
+
+Events with the "tcg" property can be declared in the "trace-events" file with a
+mix of native and TCG types, and "trace_<eventname>_tcg" will gracefully forward
+them to the "<eventname>_trans" and "<eventname>_exec" events. Since TCG values
+are not known at translation time, these are ignored by the "<eventname>_trans"
+event. Because of this, the entry in the "trace-events" file needs two printing
+formats (separated by a comma):
+
+ tcg foo(uint8_t a1, TCGv_i32 a2) "a1=%d", "a1=%d a2=%d"
+
+For example:
+
+ #include "trace-tcg.h"
+
+ void some_disassembly_func (...)
+ {
+ uint8_t a1 = ...;
+ TCGv_i32 a2 = ...;
+ trace_foo_tcg(a1, a2);
+ }
+
+This will immediately call:
+
+ void trace_foo_trans(uint8_t a1);
+
+and will generate the TCG code to call:
+
+ void trace_foo(uint8_t a1, uint32_t a2);
diff --git a/dump.c b/dump.c
index ce646bcc51..71d3e946e6 100644
--- a/dump.c
+++ b/dump.c
@@ -71,18 +71,14 @@ uint64_t cpu_to_dump64(DumpState *s, uint64_t val)
static int dump_cleanup(DumpState *s)
{
- int ret = 0;
-
guest_phys_blocks_free(&s->guest_phys_blocks);
memory_mapping_list_free(&s->list);
- if (s->fd != -1) {
- close(s->fd);
- }
+ close(s->fd);
if (s->resume) {
vm_start();
}
- return ret;
+ return 0;
}
static void dump_error(DumpState *s, const char *reason)
@@ -1499,6 +1495,8 @@ static int dump_init(DumpState *s, int fd, bool has_format,
s->begin = begin;
s->length = length;
+ memory_mapping_list_init(&s->list);
+
guest_phys_blocks_init(&s->guest_phys_blocks);
guest_phys_blocks_append(&s->guest_phys_blocks);
@@ -1526,7 +1524,6 @@ static int dump_init(DumpState *s, int fd, bool has_format,
}
/* get memory mapping */
- memory_mapping_list_init(&s->list);
if (paging) {
qemu_get_guest_memory_mapping(&s->list, &s->guest_phys_blocks, &err);
if (err != NULL) {
@@ -1622,12 +1619,7 @@ static int dump_init(DumpState *s, int fd, bool has_format,
return 0;
cleanup:
- guest_phys_blocks_free(&s->guest_phys_blocks);
-
- if (s->resume) {
- vm_start();
- }
-
+ dump_cleanup(s);
return -1;
}
diff --git a/exec.c b/exec.c
index 42688b69b1..5f9857cd03 100644
--- a/exec.c
+++ b/exec.c
@@ -1568,8 +1568,7 @@ static void notdirty_mem_write(void *opaque, hwaddr ram_addr,
default:
abort();
}
- cpu_physical_memory_set_dirty_flag(ram_addr, DIRTY_MEMORY_MIGRATION);
- cpu_physical_memory_set_dirty_flag(ram_addr, DIRTY_MEMORY_VGA);
+ cpu_physical_memory_set_dirty_range_nocode(ram_addr, size);
/* we remove the notdirty callback only if the code has been
flushed */
if (!cpu_physical_memory_is_clean(ram_addr)) {
@@ -1978,8 +1977,7 @@ static void invalidate_and_set_dirty(hwaddr addr,
/* invalidate code */
tb_invalidate_phys_page_range(addr, addr + length, 0);
/* set dirty bit */
- cpu_physical_memory_set_dirty_flag(addr, DIRTY_MEMORY_VGA);
- cpu_physical_memory_set_dirty_flag(addr, DIRTY_MEMORY_MIGRATION);
+ cpu_physical_memory_set_dirty_range_nocode(addr, length);
}
xen_modified_memory(addr, length);
}
@@ -2335,15 +2333,7 @@ void address_space_unmap(AddressSpace *as, void *buffer, hwaddr len,
mr = qemu_ram_addr_from_host(buffer, &addr1);
assert(mr != NULL);
if (is_write) {
- while (access_len) {
- unsigned l;
- l = TARGET_PAGE_SIZE;
- if (l > access_len)
- l = access_len;
- invalidate_and_set_dirty(addr1, l);
- addr1 += l;
- access_len -= l;
- }
+ invalidate_and_set_dirty(addr1, access_len);
}
if (xen_enabled()) {
xen_invalidate_map_cache_entry(buffer);
@@ -2581,9 +2571,7 @@ void stl_phys_notdirty(AddressSpace *as, hwaddr addr, uint32_t val)
/* invalidate code */
tb_invalidate_phys_page_range(addr1, addr1 + 4, 0);
/* set dirty bit */
- cpu_physical_memory_set_dirty_flag(addr1,
- DIRTY_MEMORY_MIGRATION);
- cpu_physical_memory_set_dirty_flag(addr1, DIRTY_MEMORY_VGA);
+ cpu_physical_memory_set_dirty_range_nocode(addr1, 4);
}
}
}
diff --git a/hw/acpi/ich9.c b/hw/acpi/ich9.c
index e7d6c77b34..7b14bbbee1 100644
--- a/hw/acpi/ich9.c
+++ b/hw/acpi/ich9.c
@@ -232,11 +232,11 @@ void ich9_pm_init(PCIDevice *lpc_pci, ICH9LPCPMRegs *pm,
acpi_gpe_init(&pm->acpi_regs, ICH9_PMIO_GPE0_LEN);
memory_region_init_io(&pm->io_gpe, OBJECT(lpc_pci), &ich9_gpe_ops, pm,
- "apci-gpe0", ICH9_PMIO_GPE0_LEN);
+ "acpi-gpe0", ICH9_PMIO_GPE0_LEN);
memory_region_add_subregion(&pm->io, ICH9_PMIO_GPE0_STS, &pm->io_gpe);
memory_region_init_io(&pm->io_smi, OBJECT(lpc_pci), &ich9_smi_ops, pm,
- "apci-smi", 8);
+ "acpi-smi", 8);
memory_region_add_subregion(&pm->io, ICH9_PMIO_SMI_EN, &pm->io_smi);
pm->irq = sci_irq;
diff --git a/hw/arm/boot.c b/hw/arm/boot.c
index 3d1f4a255b..12417617a3 100644
--- a/hw/arm/boot.c
+++ b/hw/arm/boot.c
@@ -417,8 +417,12 @@ static void do_cpu_reset(void *opaque)
if (info) {
if (!info->is_linux) {
/* Jump to the entry point. */
- env->regs[15] = info->entry & 0xfffffffe;
- env->thumb = info->entry & 1;
+ if (env->aarch64) {
+ env->pc = info->entry;
+ } else {
+ env->regs[15] = info->entry & 0xfffffffe;
+ env->thumb = info->entry & 1;
+ }
} else {
if (CPU(cpu) == first_cpu) {
if (env->aarch64) {
diff --git a/hw/arm/virt.c b/hw/arm/virt.c
index 405c61d39c..ba94298555 100644
--- a/hw/arm/virt.c
+++ b/hw/arm/virt.c
@@ -98,17 +98,17 @@ typedef struct VirtBoardInfo {
*/
static const MemMapEntry a15memmap[] = {
/* Space up to 0x8000000 is reserved for a boot ROM */
- [VIRT_FLASH] = { 0, 0x8000000 },
- [VIRT_CPUPERIPHS] = { 0x8000000, 0x20000 },
+ [VIRT_FLASH] = { 0, 0x08000000 },
+ [VIRT_CPUPERIPHS] = { 0x08000000, 0x00020000 },
/* GIC distributor and CPU interfaces sit inside the CPU peripheral space */
- [VIRT_GIC_DIST] = { 0x8000000, 0x10000 },
- [VIRT_GIC_CPU] = { 0x8010000, 0x10000 },
- [VIRT_UART] = { 0x9000000, 0x1000 },
- [VIRT_RTC] = { 0x90010000, 0x1000 },
- [VIRT_MMIO] = { 0xa000000, 0x200 },
+ [VIRT_GIC_DIST] = { 0x08000000, 0x00010000 },
+ [VIRT_GIC_CPU] = { 0x08010000, 0x00010000 },
+ [VIRT_UART] = { 0x09000000, 0x00001000 },
+ [VIRT_RTC] = { 0x09010000, 0x00001000 },
+ [VIRT_MMIO] = { 0x0a000000, 0x00000200 },
/* ...repeating for a total of NUM_VIRTIO_TRANSPORTS, each of that size */
/* 0x10000000 .. 0x40000000 reserved for PCI */
- [VIRT_MEM] = { 0x40000000, 30ULL * 1024 * 1024 * 1024 },
+ [VIRT_MEM] = { 0x40000000, 30ULL * 1024 * 1024 * 1024 },
};
static const int a15irqmap[] = {
diff --git a/hw/audio/gus.c b/hw/audio/gus.c
index bba6840477..4a43ce7adf 100644
--- a/hw/audio/gus.c
+++ b/hw/audio/gus.c
@@ -212,7 +212,7 @@ static int GUS_read_DMA (void *opaque, int nchan, int dma_pos, int dma_len)
pos += copied;
}
- if (0 == ((mode >> 4) & 1)) {
+ if (((mode >> 4) & 1) == 0) {
DMA_release_DREQ (s->emu.gusdma);
}
return dma_len;
diff --git a/hw/audio/hda-codec.c b/hw/audio/hda-codec.c
index cbcf521c5e..3c03ff5668 100644
--- a/hw/audio/hda-codec.c
+++ b/hw/audio/hda-codec.c
@@ -489,8 +489,9 @@ static int hda_audio_init(HDACodecDevice *hda, const struct desc_codec *desc)
for (i = 0; i < a->desc->nnodes; i++) {
node = a->desc->nodes + i;
param = hda_codec_find_param(node, AC_PAR_AUDIO_WIDGET_CAP);
- if (NULL == param)
+ if (param == NULL) {
continue;
+ }
type = (param->val & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT;
switch (type) {
case AC_WID_AUD_OUT:
diff --git a/hw/audio/intel-hda.c b/hw/audio/intel-hda.c
index aba45fc8c8..2885231a6d 100644
--- a/hw/audio/intel-hda.c
+++ b/hw/audio/intel-hda.c
@@ -187,6 +187,7 @@ struct IntelHDAState {
/* properties */
uint32_t debug;
uint32_t msi;
+ bool old_msi_addr;
};
#define TYPE_INTEL_HDA_GENERIC "intel-hda-generic"
@@ -1141,7 +1142,7 @@ static int intel_hda_init(PCIDevice *pci)
"intel-hda", 0x4000);
pci_register_bar(&d->pci, 0, 0, &d->mmio);
if (d->msi) {
- msi_init(&d->pci, 0x50, 1, true, false);
+ msi_init(&d->pci, d->old_msi_addr ? 0x50 : 0x60, 1, true, false);
}
hda_codec_bus_init(DEVICE(pci), &d->codecs, sizeof(d->codecs),
@@ -1235,6 +1236,7 @@ static const VMStateDescription vmstate_intel_hda = {
static Property intel_hda_properties[] = {
DEFINE_PROP_UINT32("debug", IntelHDAState, debug, 0),
DEFINE_PROP_UINT32("msi", IntelHDAState, msi, 1),
+ DEFINE_PROP_BOOL("old_msi_addr", IntelHDAState, old_msi_addr, false),
DEFINE_PROP_END_OF_LIST(),
};
diff --git a/hw/audio/sb16.c b/hw/audio/sb16.c
index 60c4b3b497..bda26d0123 100644
--- a/hw/audio/sb16.c
+++ b/hw/audio/sb16.c
@@ -928,7 +928,7 @@ static IO_WRITE_PROTO (dsp_write)
/* if (s->highspeed) */
/* break; */
- if (0 == s->needed_bytes) {
+ if (s->needed_bytes == 0) {
command (s, val);
#if 0
if (0 == s->needed_bytes) {
@@ -1212,7 +1212,7 @@ static int SB_read_DMA (void *opaque, int nchan, int dma_pos, int dma_len)
#endif
if (till <= copy) {
- if (0 == s->dma_auto) {
+ if (s->dma_auto == 0) {
copy = till;
}
}
@@ -1224,7 +1224,7 @@ static int SB_read_DMA (void *opaque, int nchan, int dma_pos, int dma_len)
if (s->left_till_irq <= 0) {
s->mixer_regs[0x82] |= (nchan & 4) ? 2 : 1;
qemu_irq_raise (s->pic);
- if (0 == s->dma_auto) {
+ if (s->dma_auto == 0) {
control (s, 0);
speaker (s, 0);
}
diff --git a/hw/block/dataplane/virtio-blk.c b/hw/block/dataplane/virtio-blk.c
index d6ba65ca23..24a6b71395 100644
--- a/hw/block/dataplane/virtio-blk.c
+++ b/hw/block/dataplane/virtio-blk.c
@@ -28,6 +28,7 @@ struct VirtIOBlockDataPlane {
bool started;
bool starting;
bool stopping;
+ bool disabled;
VirtIOBlkConf *blk;
@@ -218,8 +219,9 @@ void virtio_blk_data_plane_start(VirtIOBlockDataPlane *s)
VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus);
VirtIOBlock *vblk = VIRTIO_BLK(s->vdev);
VirtQueue *vq;
+ int r;
- if (s->started) {
+ if (s->started || s->disabled) {
return;
}
@@ -231,22 +233,23 @@ void virtio_blk_data_plane_start(VirtIOBlockDataPlane *s)
vq = virtio_get_queue(s->vdev, 0);
if (!vring_setup(&s->vring, s->vdev, 0)) {
- s->starting = false;
- return;
+ goto fail_vring;
}
/* Set up guest notifier (irq) */
- if (k->set_guest_notifiers(qbus->parent, 1, true) != 0) {
- fprintf(stderr, "virtio-blk failed to set guest notifier, "
- "ensure -enable-kvm is set\n");
- exit(1);
+ r = k->set_guest_notifiers(qbus->parent, 1, true);
+ if (r != 0) {
+ fprintf(stderr, "virtio-blk failed to set guest notifier (%d), "
+ "ensure -enable-kvm is set\n", r);
+ goto fail_guest_notifiers;
}
s->guest_notifier = virtio_queue_get_guest_notifier(vq);
/* Set up virtqueue notify */
- if (k->set_host_notifier(qbus->parent, 0, true) != 0) {
- fprintf(stderr, "virtio-blk failed to set host notifier\n");
- exit(1);
+ r = k->set_host_notifier(qbus->parent, 0, true);
+ if (r != 0) {
+ fprintf(stderr, "virtio-blk failed to set host notifier (%d)\n", r);
+ goto fail_host_notifier;
}
s->host_notifier = *virtio_queue_get_host_notifier(vq);
@@ -266,6 +269,15 @@ void virtio_blk_data_plane_start(VirtIOBlockDataPlane *s)
aio_context_acquire(s->ctx);
aio_set_event_notifier(s->ctx, &s->host_notifier, handle_notify);
aio_context_release(s->ctx);
+ return;
+
+ fail_host_notifier:
+ k->set_guest_notifiers(qbus->parent, 1, false);
+ fail_guest_notifiers:
+ vring_teardown(&s->vring, s->vdev, 0);
+ s->disabled = true;
+ fail_vring:
+ s->starting = false;
}
/* Context: QEMU global mutex held */
@@ -274,6 +286,13 @@ void virtio_blk_data_plane_stop(VirtIOBlockDataPlane *s)
BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(s->vdev)));
VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus);
VirtIOBlock *vblk = VIRTIO_BLK(s->vdev);
+
+
+ /* Better luck next time. */
+ if (s->disabled) {
+ s->disabled = false;
+ return;
+ }
if (!s->started || s->stopping) {
return;
}
diff --git a/hw/block/virtio-blk.c b/hw/block/virtio-blk.c
index c241c5002b..302c39e2be 100644
--- a/hw/block/virtio-blk.c
+++ b/hw/block/virtio-blk.c
@@ -404,19 +404,19 @@ void virtio_blk_handle_request(VirtIOBlockReq *req, MultiReqBuffer *mrb)
* NB: per existing s/n string convention the string is
* terminated by '\0' only when shorter than buffer.
*/
- strncpy(req->elem.in_sg[0].iov_base,
- s->blk.serial ? s->blk.serial : "",
- MIN(req->elem.in_sg[0].iov_len, VIRTIO_BLK_ID_BYTES));
+ const char *serial = s->blk.serial ? s->blk.serial : "";
+ size_t size = MIN(strlen(serial) + 1,
+ MIN(iov_size(in_iov, in_num),
+ VIRTIO_BLK_ID_BYTES));
+ iov_from_buf(in_iov, in_num, 0, serial, size);
virtio_blk_req_complete(req, VIRTIO_BLK_S_OK);
virtio_blk_free_request(req);
} else if (type & VIRTIO_BLK_T_OUT) {
- qemu_iovec_init_external(&req->qiov, &req->elem.out_sg[1],
- req->elem.out_num - 1);
+ qemu_iovec_init_external(&req->qiov, iov, out_num);
virtio_blk_handle_write(req, mrb);
} else if (type == VIRTIO_BLK_T_IN || type == VIRTIO_BLK_T_BARRIER) {
/* VIRTIO_BLK_T_IN is 0, so we can't just & it. */
- qemu_iovec_init_external(&req->qiov, &req->elem.in_sg[0],
- req->elem.in_num - 1);
+ qemu_iovec_init_external(&req->qiov, in_iov, in_num);
virtio_blk_handle_read(req);
} else {
virtio_blk_req_complete(req, VIRTIO_BLK_S_UNSUPP);
diff --git a/hw/block/xen_disk.c b/hw/block/xen_disk.c
index aed5b5b3e9..a221d0bfca 100644
--- a/hw/block/xen_disk.c
+++ b/hw/block/xen_disk.c
@@ -589,6 +589,7 @@ static int blk_send_response_one(struct ioreq *ioreq)
break;
default:
dst = NULL;
+ return 0;
}
memcpy(dst, &resp, sizeof(resp));
blkdev->rings.common.rsp_prod_pvt++;
diff --git a/hw/bt/l2cap.c b/hw/bt/l2cap.c
index 2301d6f87f..591e047781 100644
--- a/hw/bt/l2cap.c
+++ b/hw/bt/l2cap.c
@@ -429,7 +429,7 @@ static struct l2cap_chan_s *l2cap_channel_open(struct l2cap_instance_s *l2cap,
status = L2CAP_CS_NO_INFO;
} else {
g_free(ch);
-
+ ch = NULL;
result = L2CAP_CR_NO_MEM;
status = L2CAP_CS_NO_INFO;
}
diff --git a/hw/char/cadence_uart.c b/hw/char/cadence_uart.c
index dbbc167425..a5736cbc07 100644
--- a/hw/char/cadence_uart.c
+++ b/hw/char/cadence_uart.c
@@ -175,8 +175,10 @@ static void uart_send_breaks(UartState *s)
{
int break_enabled = 1;
- qemu_chr_fe_ioctl(s->chr, CHR_IOCTL_SERIAL_SET_BREAK,
- &break_enabled);
+ if (s->chr) {
+ qemu_chr_fe_ioctl(s->chr, CHR_IOCTL_SERIAL_SET_BREAK,
+ &break_enabled);
+ }
}
static void uart_parameters_setup(UartState *s)
@@ -227,7 +229,9 @@ static void uart_parameters_setup(UartState *s)
packet_size += ssp.data_bits + ssp.stop_bits;
s->char_tx_time = (get_ticks_per_sec() / ssp.speed) * packet_size;
- qemu_chr_fe_ioctl(s->chr, CHR_IOCTL_SERIAL_SET_PARAMS, &ssp);
+ if (s->chr) {
+ qemu_chr_fe_ioctl(s->chr, CHR_IOCTL_SERIAL_SET_PARAMS, &ssp);
+ }
}
static int uart_can_receive(void *opaque)
@@ -295,6 +299,7 @@ static gboolean cadence_uart_xmit(GIOChannel *chan, GIOCondition cond,
/* instant drain the fifo when there's no back-end */
if (!s->chr) {
s->tx_count = 0;
+ return FALSE;
}
if (!s->tx_count) {
@@ -375,7 +380,9 @@ static void uart_read_rx_fifo(UartState *s, uint32_t *c)
*c = s->rx_fifo[rx_rpos];
s->rx_count--;
- qemu_chr_accept_input(s->chr);
+ if (s->chr) {
+ qemu_chr_accept_input(s->chr);
+ }
} else {
*c = 0;
}
diff --git a/hw/char/virtio-serial-bus.c b/hw/char/virtio-serial-bus.c
index 07bebc03ac..3931085983 100644
--- a/hw/char/virtio-serial-bus.c
+++ b/hw/char/virtio-serial-bus.c
@@ -26,6 +26,10 @@
#include "hw/virtio/virtio-serial.h"
#include "hw/virtio/virtio-access.h"
+struct VirtIOSerialDevices {
+ QLIST_HEAD(, VirtIOSerial) devices;
+} vserdevices;
+
static VirtIOSerialPort *find_port_by_id(VirtIOSerial *vser, uint32_t id)
{
VirtIOSerialPort *port;
@@ -52,6 +56,22 @@ static VirtIOSerialPort *find_port_by_vq(VirtIOSerial *vser, VirtQueue *vq)
return NULL;
}
+static VirtIOSerialPort *find_port_by_name(char *name)
+{
+ VirtIOSerial *vser;
+
+ QLIST_FOREACH(vser, &vserdevices.devices, next) {
+ VirtIOSerialPort *port;
+
+ QTAILQ_FOREACH(port, &vser->ports, next) {
+ if (!strcmp(port->name, name)) {
+ return port;
+ }
+ }
+ }
+ return NULL;
+}
+
static bool use_multiport(VirtIOSerial *vser)
{
VirtIODevice *vdev = VIRTIO_DEVICE(vser);
@@ -797,10 +817,18 @@ static void add_port(VirtIOSerial *vser, uint32_t port_id)
static void remove_port(VirtIOSerial *vser, uint32_t port_id)
{
VirtIOSerialPort *port;
- unsigned int i;
- i = port_id / 32;
- vser->ports_map[i] &= ~(1U << (port_id % 32));
+ /*
+ * Don't mark port 0 removed -- we explicitly reserve it for
+ * backward compat with older guests, ensure a virtconsole device
+ * unplug retains the reservation.
+ */
+ if (port_id) {
+ unsigned int i;
+
+ i = port_id / 32;
+ vser->ports_map[i] &= ~(1U << (port_id % 32));
+ }
port = find_port_by_id(vser, port_id);
/*
@@ -843,6 +871,12 @@ static void virtser_port_device_realize(DeviceState *dev, Error **errp)
return;
}
+ if (find_port_by_name(port->name)) {
+ error_setg(errp, "virtio-serial-bus: A port already exists by name %s",
+ port->name);
+ return;
+ }
+
if (port->id == VIRTIO_CONSOLE_BAD_ID) {
if (plugging_port0) {
port->id = 0;
@@ -975,6 +1009,8 @@ static void virtio_serial_device_realize(DeviceState *dev, Error **errp)
*/
register_savevm(dev, "virtio-console", -1, 3, virtio_serial_save,
virtio_serial_load, vser);
+
+ QLIST_INSERT_HEAD(&vserdevices.devices, vser, next);
}
static void virtio_serial_port_class_init(ObjectClass *klass, void *data)
@@ -1003,6 +1039,8 @@ static void virtio_serial_device_unrealize(DeviceState *dev, Error **errp)
VirtIODevice *vdev = VIRTIO_DEVICE(dev);
VirtIOSerial *vser = VIRTIO_SERIAL(dev);
+ QLIST_REMOVE(vser, next);
+
unregister_savevm(dev, "virtio-console", vser);
g_free(vser->ivqs);
@@ -1027,6 +1065,8 @@ static void virtio_serial_class_init(ObjectClass *klass, void *data)
DeviceClass *dc = DEVICE_CLASS(klass);
VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass);
+ QLIST_INIT(&vserdevices.devices);
+
dc->props = virtio_serial_properties;
set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
vdc->realize = virtio_serial_device_realize;
diff --git a/hw/core/machine.c b/hw/core/machine.c
index cbba6791d2..7a66c57ab7 100644
--- a/hw/core/machine.c
+++ b/hw/core/machine.c
@@ -239,11 +239,11 @@ static void machine_initfn(Object *obj)
{
object_property_add_str(obj, "accel",
machine_get_accel, machine_set_accel, NULL);
- object_property_add_bool(obj, "kernel_irqchip",
+ object_property_add_bool(obj, "kernel-irqchip",
machine_get_kernel_irqchip,
machine_set_kernel_irqchip,
NULL);
- object_property_add(obj, "kvm_shadow_mem", "int",
+ object_property_add(obj, "kvm-shadow-mem", "int",
machine_get_kvm_shadow_mem,
machine_set_kvm_shadow_mem,
NULL, NULL, NULL);
@@ -257,11 +257,11 @@ static void machine_initfn(Object *obj)
machine_get_dtb, machine_set_dtb, NULL);
object_property_add_str(obj, "dumpdtb",
machine_get_dumpdtb, machine_set_dumpdtb, NULL);
- object_property_add(obj, "phandle_start", "int",
+ object_property_add(obj, "phandle-start", "int",
machine_get_phandle_start,
machine_set_phandle_start,
NULL, NULL, NULL);
- object_property_add_str(obj, "dt_compatible",
+ object_property_add_str(obj, "dt-compatible",
machine_get_dt_compatible,
machine_set_dt_compatible,
NULL);
diff --git a/hw/i386/acpi-build.c b/hw/i386/acpi-build.c
index ebc5f034e3..10b84d039b 100644
--- a/hw/i386/acpi-build.c
+++ b/hw/i386/acpi-build.c
@@ -25,7 +25,9 @@
#include <glib.h>
#include "qemu-common.h"
#include "qemu/bitmap.h"
+#include "qemu/osdep.h"
#include "qemu/range.h"
+#include "qemu/error-report.h"
#include "hw/pci/pci.h"
#include "qom/cpu.h"
#include "hw/i386/pc.h"
@@ -52,6 +54,16 @@
#include "qapi/qmp/qint.h"
#include "qom/qom-qobject.h"
+/* These are used to size the ACPI tables for -M pc-i440fx-1.7 and
+ * -M pc-i440fx-2.0. Even if the actual amount of AML generated grows
+ * a little bit, there should be plenty of free space since the DSDT
+ * shrunk by ~1.5k between QEMU 2.0 and QEMU 2.1.
+ */
+#define ACPI_BUILD_LEGACY_CPU_AML_SIZE 97
+#define ACPI_BUILD_ALIGN_SIZE 0x1000
+
+#define ACPI_BUILD_TABLE_SIZE 0x20000
+
typedef struct AcpiCpuInfo {
DECLARE_BITMAP(found_cpus, ACPI_CPU_HOTPLUG_ID_LIMIT);
} AcpiCpuInfo;
@@ -64,6 +76,7 @@ typedef struct AcpiMcfgInfo {
typedef struct AcpiPmInfo {
bool s3_disabled;
bool s4_disabled;
+ bool pcihp_bridge_en;
uint8_t s4_val;
uint16_t sci_int;
uint8_t acpi_enable_cmd;
@@ -85,6 +98,7 @@ typedef struct AcpiBuildPciBusHotplugState {
GArray *device_table;
GArray *notify_table;
struct AcpiBuildPciBusHotplugState *parent;
+ bool pcihp_bridge_en;
} AcpiBuildPciBusHotplugState;
static void acpi_get_dsdt(AcpiMiscInfo *info)
@@ -188,6 +202,9 @@ static void acpi_get_pm_info(AcpiPmInfo *pm)
NULL);
pm->gpe0_blk_len = object_property_get_int(obj, ACPI_PM_PROP_GPE0_BLK_LEN,
NULL);
+ pm->pcihp_bridge_en =
+ object_property_get_bool(obj, "acpi-pci-hotplug-with-bridge-support",
+ NULL);
}
static void acpi_get_misc_info(AcpiMiscInfo *info)
@@ -768,11 +785,13 @@ static void acpi_set_pci_info(void)
}
static void build_pci_bus_state_init(AcpiBuildPciBusHotplugState *state,
- AcpiBuildPciBusHotplugState *parent)
+ AcpiBuildPciBusHotplugState *parent,
+ bool pcihp_bridge_en)
{
state->parent = parent;
state->device_table = build_alloc_array();
state->notify_table = build_alloc_array();
+ state->pcihp_bridge_en = pcihp_bridge_en;
}
static void build_pci_bus_state_cleanup(AcpiBuildPciBusHotplugState *state)
@@ -786,7 +805,7 @@ static void *build_pci_bus_begin(PCIBus *bus, void *parent_state)
AcpiBuildPciBusHotplugState *parent = parent_state;
AcpiBuildPciBusHotplugState *child = g_malloc(sizeof *child);
- build_pci_bus_state_init(child, parent);
+ build_pci_bus_state_init(child, parent, parent->pcihp_bridge_en);
return child;
}
@@ -807,6 +826,14 @@ static void build_pci_bus_end(PCIBus *bus, void *bus_state)
GArray *method;
bool bus_hotplug_support = false;
+ /*
+ * Skip bridge subtree creation if bridge hotplug is disabled
+ * to make acpi tables compatible with legacy machine types.
+ */
+ if (!child->pcihp_bridge_en && bus->parent_dev) {
+ return;
+ }
+
if (bus->parent_dev) {
op = 0x82; /* DeviceOp */
build_append_nameseg(bus_table, "S%.02X_",
@@ -844,6 +871,7 @@ static void build_pci_bus_end(PCIBus *bus, void *bus_state)
PCIDeviceClass *pc;
PCIDevice *pdev = bus->devices[i];
int slot = PCI_SLOT(i);
+ bool bridge_in_acpi;
if (!pdev) {
continue;
@@ -853,7 +881,13 @@ static void build_pci_bus_end(PCIBus *bus, void *bus_state)
pc = PCI_DEVICE_GET_CLASS(pdev);
dc = DEVICE_GET_CLASS(pdev);
- if (pc->class_id == PCI_CLASS_BRIDGE_ISA || pc->is_bridge) {
+ /* When hotplug for bridges is enabled, bridges are
+ * described in ACPI separately (see build_pci_bus_end).
+ * In this case they aren't themselves hot-pluggable.
+ */
+ bridge_in_acpi = pc->is_bridge && child->pcihp_bridge_en;
+
+ if (pc->class_id == PCI_CLASS_BRIDGE_ISA || bridge_in_acpi) {
set_bit(slot, slot_device_system);
}
@@ -865,7 +899,7 @@ static void build_pci_bus_end(PCIBus *bus, void *bus_state)
}
}
- if (!dc->hotpluggable || pc->is_bridge) {
+ if (!dc->hotpluggable || bridge_in_acpi) {
clear_bit(slot, slot_hotplug_enable);
}
}
@@ -1130,7 +1164,7 @@ build_ssdt(GArray *table_data, GArray *linker,
bus = PCI_HOST_BRIDGE(pci_host)->bus;
}
- build_pci_bus_state_init(&hotplug_state, NULL);
+ build_pci_bus_state_init(&hotplug_state, NULL, pm->pcihp_bridge_en);
if (bus) {
/* Scan all PCI buses. Generate tables to support hotplug. */
@@ -1359,7 +1393,7 @@ build_rsdp(GArray *rsdp_table, GArray *linker, unsigned rsdt)
{
AcpiRsdpDescriptor *rsdp = acpi_data_push(rsdp_table, sizeof *rsdp);
- bios_linker_loader_alloc(linker, ACPI_BUILD_RSDP_FILE, 1,
+ bios_linker_loader_alloc(linker, ACPI_BUILD_RSDP_FILE, 16,
true /* fseg memory */);
memcpy(&rsdp->signature, "RSD PTR ", 8);
@@ -1440,13 +1474,14 @@ static
void acpi_build(PcGuestInfo *guest_info, AcpiBuildTables *tables)
{
GArray *table_offsets;
- unsigned facs, dsdt, rsdt;
+ unsigned facs, ssdt, dsdt, rsdt;
AcpiCpuInfo cpu;
AcpiPmInfo pm;
AcpiMiscInfo misc;
AcpiMcfgInfo mcfg;
PcPciInfo pci;
uint8_t *u;
+ size_t aml_len = 0;
acpi_get_cpu_info(&cpu);
acpi_get_pm_info(&pm);
@@ -1474,13 +1509,20 @@ void acpi_build(PcGuestInfo *guest_info, AcpiBuildTables *tables)
dsdt = tables->table_data->len;
build_dsdt(tables->table_data, tables->linker, &misc);
+ /* Count the size of the DSDT and SSDT, we will need it for legacy
+ * sizing of ACPI tables.
+ */
+ aml_len += tables->table_data->len - dsdt;
+
/* ACPI tables pointed to by RSDT */
acpi_add_table(table_offsets, tables->table_data);
build_fadt(tables->table_data, tables->linker, &pm, facs, dsdt);
+ ssdt = tables->table_data->len;
acpi_add_table(table_offsets, tables->table_data);
build_ssdt(tables->table_data, tables->linker, &cpu, &pm, &misc, &pci,
guest_info);
+ aml_len += tables->table_data->len - ssdt;
acpi_add_table(table_offsets, tables->table_data);
build_madt(tables->table_data, tables->linker, &cpu, guest_info);
@@ -1513,14 +1555,53 @@ void acpi_build(PcGuestInfo *guest_info, AcpiBuildTables *tables)
/* RSDP is in FSEG memory, so allocate it separately */
build_rsdp(tables->rsdp, tables->linker, rsdt);
- /* We'll expose it all to Guest so align size to reduce
+ /* We'll expose it all to Guest so we want to reduce
* chance of size changes.
* RSDP is small so it's easy to keep it immutable, no need to
* bother with alignment.
+ *
+ * We used to align the tables to 4k, but of course this would
+ * too simple to be enough. 4k turned out to be too small an
+ * alignment very soon, and in fact it is almost impossible to
+ * keep the table size stable for all (max_cpus, max_memory_slots)
+ * combinations. So the table size is always 64k for pc-i440fx-2.1
+ * and we give an error if the table grows beyond that limit.
+ *
+ * We still have the problem of migrating from "-M pc-i440fx-2.0". For
+ * that, we exploit the fact that QEMU 2.1 generates _smaller_ tables
+ * than 2.0 and we can always pad the smaller tables with zeros. We can
+ * then use the exact size of the 2.0 tables.
+ *
+ * All this is for PIIX4, since QEMU 2.0 didn't support Q35 migration.
*/
- acpi_align_size(tables->table_data, 0x1000);
+ if (guest_info->legacy_acpi_table_size) {
+ /* Subtracting aml_len gives the size of fixed tables. Then add the
+ * size of the PIIX4 DSDT/SSDT in QEMU 2.0.
+ */
+ int legacy_aml_len =
+ guest_info->legacy_acpi_table_size +
+ ACPI_BUILD_LEGACY_CPU_AML_SIZE * max_cpus;
+ int legacy_table_size =
+ ROUND_UP(tables->table_data->len - aml_len + legacy_aml_len,
+ ACPI_BUILD_ALIGN_SIZE);
+ if (tables->table_data->len > legacy_table_size) {
+ /* Should happen only with PCI bridges and -M pc-i440fx-2.0. */
+ error_report("Warning: migration may not work.");
+ }
+ g_array_set_size(tables->table_data, legacy_table_size);
+ } else {
+ /* Make sure we have a buffer in case we need to resize the tables. */
+ if (tables->table_data->len > ACPI_BUILD_TABLE_SIZE / 2) {
+ /* As of QEMU 2.1, this fires with 160 VCPUs and 255 memory slots. */
+ error_report("Warning: ACPI tables are larger than 64k.");
+ error_report("Warning: migration may not work.");
+ error_report("Warning: please remove CPUs, NUMA nodes, "
+ "memory slots or PCI bridges.");
+ }
+ acpi_align_size(tables->table_data, ACPI_BUILD_TABLE_SIZE);
+ }
- acpi_align_size(tables->linker, 0x1000);
+ acpi_align_size(tables->linker, ACPI_BUILD_ALIGN_SIZE);
/* Cleanup memory that's no longer used. */
g_array_free(table_offsets, true);
diff --git a/hw/i386/acpi-dsdt.dsl b/hw/i386/acpi-dsdt.dsl
index 3cc0ea0f9a..559f4b6653 100644
--- a/hw/i386/acpi-dsdt.dsl
+++ b/hw/i386/acpi-dsdt.dsl
@@ -181,57 +181,45 @@ DefinitionBlock (
Scope(\_SB) {
Scope(PCI0) {
- Name(_PRT, Package() {
- /* PCI IRQ routing table, example from ACPI 2.0a specification,
- section 6.2.8.1 */
- /* Note: we provide the same info as the PCI routing
- table of the Bochs BIOS */
-
-#define prt_slot(nr, lnk0, lnk1, lnk2, lnk3) \
- Package() { nr##ffff, 0, lnk0, 0 }, \
- Package() { nr##ffff, 1, lnk1, 0 }, \
- Package() { nr##ffff, 2, lnk2, 0 }, \
- Package() { nr##ffff, 3, lnk3, 0 }
-
-#define prt_slot0(nr) prt_slot(nr, LNKD, LNKA, LNKB, LNKC)
-#define prt_slot1(nr) prt_slot(nr, LNKA, LNKB, LNKC, LNKD)
-#define prt_slot2(nr) prt_slot(nr, LNKB, LNKC, LNKD, LNKA)
-#define prt_slot3(nr) prt_slot(nr, LNKC, LNKD, LNKA, LNKB)
-
- prt_slot0(0x0000),
- /* Device 1 is power mgmt device, and can only use irq 9 */
- prt_slot(0x0001, LNKS, LNKB, LNKC, LNKD),
- prt_slot2(0x0002),
- prt_slot3(0x0003),
- prt_slot0(0x0004),
- prt_slot1(0x0005),
- prt_slot2(0x0006),
- prt_slot3(0x0007),
- prt_slot0(0x0008),
- prt_slot1(0x0009),
- prt_slot2(0x000a),
- prt_slot3(0x000b),
- prt_slot0(0x000c),
- prt_slot1(0x000d),
- prt_slot2(0x000e),
- prt_slot3(0x000f),
- prt_slot0(0x0010),
- prt_slot1(0x0011),
- prt_slot2(0x0012),
- prt_slot3(0x0013),
- prt_slot0(0x0014),
- prt_slot1(0x0015),
- prt_slot2(0x0016),
- prt_slot3(0x0017),
- prt_slot0(0x0018),
- prt_slot1(0x0019),
- prt_slot2(0x001a),
- prt_slot3(0x001b),
- prt_slot0(0x001c),
- prt_slot1(0x001d),
- prt_slot2(0x001e),
- prt_slot3(0x001f),
- })
+ Method (_PRT, 0) {
+ Store(Package(128) {}, Local0)
+ Store(Zero, Local1)
+ While(LLess(Local1, 128)) {
+ // slot = pin >> 2
+ Store(ShiftRight(Local1, 2), Local2)
+
+ // lnk = (slot + pin) & 3
+ Store(And(Add(Local1, Local2), 3), Local3)
+ If (LEqual(Local3, 0)) {
+ Store(Package(4) { Zero, Zero, LNKD, Zero }, Local4)
+ }
+ If (LEqual(Local3, 1)) {
+ // device 1 is the power-management device, needs SCI
+ If (LEqual(Local1, 4)) {
+ Store(Package(4) { Zero, Zero, LNKS, Zero }, Local4)
+ } Else {
+ Store(Package(4) { Zero, Zero, LNKA, Zero }, Local4)
+ }
+ }
+ If (LEqual(Local3, 2)) {
+ Store(Package(4) { Zero, Zero, LNKB, Zero }, Local4)
+ }
+ If (LEqual(Local3, 3)) {
+ Store(Package(4) { Zero, Zero, LNKC, Zero }, Local4)
+ }
+
+ // Complete the interrupt routing entry:
+ // Package(4) { 0x[slot]FFFF, [pin], [link], 0) }
+
+ Store(Or(ShiftLeft(Local2, 16), 0xFFFF), Index(Local4, 0))
+ Store(And(Local1, 3), Index(Local4, 1))
+ Store(Local4, Index(Local0, Local1))
+
+ Increment(Local1)
+ }
+
+ Return(Local0)
+ }
}
Field(PCI0.ISA.P40C, ByteAcc, NoLock, Preserve) {
@@ -314,7 +302,7 @@ DefinitionBlock (
/****************************************************************
* General purpose events
****************************************************************/
- External(\_SB.PCI0.MEMORY_HOPTLUG_DEVICE.MEMORY_SLOT_SCAN_METHOD, MethodObj)
+ External(\_SB.PCI0.MEMORY_HOTPLUG_DEVICE.MEMORY_SLOT_SCAN_METHOD, MethodObj)
Scope(\_GPE) {
Name(_HID, "ACPI0006")
@@ -333,7 +321,7 @@ DefinitionBlock (
}
Method(_E03) {
// Memory hotplug event
- \_SB.PCI0.MEMORY_HOPTLUG_DEVICE.MEMORY_SLOT_SCAN_METHOD()
+ \_SB.PCI0.MEMORY_HOTPLUG_DEVICE.MEMORY_SLOT_SCAN_METHOD()
}
Method(_L04) {
}
diff --git a/hw/i386/acpi-dsdt.hex.generated b/hw/i386/acpi-dsdt.hex.generated
index ee490e89c3..a21bf410e5 100644
--- a/hw/i386/acpi-dsdt.hex.generated
+++ b/hw/i386/acpi-dsdt.hex.generated
@@ -3,12 +3,12 @@ static unsigned char AcpiDsdtAmlCode[] = {
0x53,
0x44,
0x54,
-0x93,
-0x11,
+0xf7,
+0xa,
0x0,
0x0,
0x1,
-0xf5,
+0x1f,
0x42,
0x58,
0x50,
@@ -31,9 +31,9 @@ static unsigned char AcpiDsdtAmlCode[] = {
0x4e,
0x54,
0x4c,
-0x15,
-0x11,
-0x13,
+0x28,
+0x5,
+0x10,
0x20,
0x10,
0x49,
@@ -1439,1419 +1439,68 @@ static unsigned char AcpiDsdtAmlCode[] = {
0xa4,
0x0,
0x10,
-0x4a,
-0xa0,
+0x4e,
+0x36,
0x5f,
0x53,
0x42,
0x5f,
0x10,
-0x47,
-0x74,
+0x4b,
+0xa,
0x50,
0x43,
0x49,
0x30,
-0x8,
+0x14,
+0x44,
+0xa,
0x5f,
0x50,
0x52,
0x54,
-0x12,
-0x4b,
-0x73,
-0x80,
-0x12,
-0xb,
-0x4,
-0xb,
-0xff,
-0xff,
-0x0,
-0x4c,
-0x4e,
-0x4b,
-0x44,
-0x0,
-0x12,
-0xb,
-0x4,
-0xb,
-0xff,
-0xff,
-0x1,
-0x4c,
-0x4e,
-0x4b,
-0x41,
-0x0,
-0x12,
-0xc,
-0x4,
-0xb,
-0xff,
-0xff,
-0xa,
-0x2,
-0x4c,
-0x4e,
-0x4b,
-0x42,
-0x0,
-0x12,
-0xc,
-0x4,
-0xb,
-0xff,
-0xff,
-0xa,
-0x3,
-0x4c,
-0x4e,
-0x4b,
-0x43,
-0x0,
-0x12,
-0xd,
-0x4,
-0xc,
-0xff,
-0xff,
-0x1,
-0x0,
-0x0,
-0x4c,
-0x4e,
-0x4b,
-0x53,
-0x0,
-0x12,
-0xd,
-0x4,
-0xc,
-0xff,
-0xff,
-0x1,
-0x0,
-0x1,
-0x4c,
-0x4e,
-0x4b,
-0x42,
-0x0,
-0x12,
-0xe,
-0x4,
-0xc,
-0xff,
-0xff,
-0x1,
-0x0,
-0xa,
-0x2,
-0x4c,
-0x4e,
-0x4b,
-0x43,
-0x0,
-0x12,
-0xe,
-0x4,
-0xc,
-0xff,
-0xff,
-0x1,
-0x0,
-0xa,
-0x3,
-0x4c,
-0x4e,
-0x4b,
-0x44,
-0x0,
-0x12,
-0xd,
-0x4,
-0xc,
-0xff,
-0xff,
-0x2,
-0x0,
-0x0,
-0x4c,
-0x4e,
-0x4b,
-0x42,
-0x0,
-0x12,
-0xd,
-0x4,
-0xc,
-0xff,
-0xff,
-0x2,
-0x0,
-0x1,
-0x4c,
-0x4e,
-0x4b,
-0x43,
-0x0,
-0x12,
-0xe,
-0x4,
-0xc,
-0xff,
-0xff,
-0x2,
-0x0,
-0xa,
-0x2,
-0x4c,
-0x4e,
-0x4b,
-0x44,
-0x0,
-0x12,
-0xe,
-0x4,
-0xc,
-0xff,
-0xff,
-0x2,
-0x0,
-0xa,
-0x3,
-0x4c,
-0x4e,
-0x4b,
-0x41,
-0x0,
-0x12,
-0xd,
-0x4,
-0xc,
-0xff,
-0xff,
-0x3,
-0x0,
-0x0,
-0x4c,
-0x4e,
-0x4b,
-0x43,
-0x0,
-0x12,
-0xd,
-0x4,
-0xc,
-0xff,
-0xff,
-0x3,
-0x0,
-0x1,
-0x4c,
-0x4e,
-0x4b,
-0x44,
-0x0,
-0x12,
-0xe,
-0x4,
-0xc,
-0xff,
-0xff,
-0x3,
-0x0,
-0xa,
-0x2,
-0x4c,
-0x4e,
-0x4b,
-0x41,
-0x0,
-0x12,
-0xe,
-0x4,
-0xc,
-0xff,
-0xff,
-0x3,
-0x0,
-0xa,
-0x3,
-0x4c,
-0x4e,
-0x4b,
-0x42,
-0x0,
-0x12,
-0xd,
-0x4,
-0xc,
-0xff,
-0xff,
-0x4,
-0x0,
-0x0,
-0x4c,
-0x4e,
-0x4b,
-0x44,
-0x0,
-0x12,
-0xd,
-0x4,
-0xc,
-0xff,
-0xff,
-0x4,
-0x0,
-0x1,
-0x4c,
-0x4e,
-0x4b,
-0x41,
-0x0,
-0x12,
-0xe,
-0x4,
-0xc,
-0xff,
-0xff,
-0x4,
-0x0,
-0xa,
-0x2,
-0x4c,
-0x4e,
-0x4b,
-0x42,
-0x0,
-0x12,
-0xe,
-0x4,
-0xc,
-0xff,
-0xff,
-0x4,
-0x0,
-0xa,
-0x3,
-0x4c,
-0x4e,
-0x4b,
-0x43,
-0x0,
-0x12,
-0xd,
-0x4,
-0xc,
-0xff,
-0xff,
-0x5,
-0x0,
-0x0,
-0x4c,
-0x4e,
-0x4b,
-0x41,
-0x0,
-0x12,
-0xd,
-0x4,
-0xc,
-0xff,
-0xff,
-0x5,
-0x0,
-0x1,
-0x4c,
-0x4e,
-0x4b,
-0x42,
-0x0,
-0x12,
-0xe,
-0x4,
-0xc,
-0xff,
-0xff,
-0x5,
-0x0,
-0xa,
-0x2,
-0x4c,
-0x4e,
-0x4b,
-0x43,
-0x0,
-0x12,
-0xe,
-0x4,
-0xc,
-0xff,
-0xff,
-0x5,
-0x0,
-0xa,
-0x3,
-0x4c,
-0x4e,
-0x4b,
-0x44,
-0x0,
-0x12,
-0xd,
-0x4,
-0xc,
-0xff,
-0xff,
-0x6,
-0x0,
-0x0,
-0x4c,
-0x4e,
-0x4b,
-0x42,
-0x0,
-0x12,
-0xd,
-0x4,
-0xc,
-0xff,
-0xff,
-0x6,
-0x0,
-0x1,
-0x4c,
-0x4e,
-0x4b,
-0x43,
-0x0,
-0x12,
-0xe,
-0x4,
-0xc,
-0xff,
-0xff,
-0x6,
-0x0,
-0xa,
-0x2,
-0x4c,
-0x4e,
-0x4b,
-0x44,
-0x0,
-0x12,
-0xe,
-0x4,
-0xc,
-0xff,
-0xff,
-0x6,
-0x0,
-0xa,
-0x3,
-0x4c,
-0x4e,
-0x4b,
-0x41,
-0x0,
-0x12,
-0xd,
-0x4,
-0xc,
-0xff,
-0xff,
-0x7,
-0x0,
-0x0,
-0x4c,
-0x4e,
-0x4b,
-0x43,
-0x0,
-0x12,
-0xd,
-0x4,
-0xc,
-0xff,
-0xff,
-0x7,
-0x0,
-0x1,
-0x4c,
-0x4e,
-0x4b,
-0x44,
-0x0,
-0x12,
-0xe,
-0x4,
-0xc,
-0xff,
-0xff,
-0x7,
-0x0,
-0xa,
-0x2,
-0x4c,
-0x4e,
-0x4b,
-0x41,
-0x0,
-0x12,
-0xe,
-0x4,
-0xc,
-0xff,
-0xff,
-0x7,
-0x0,
-0xa,
-0x3,
-0x4c,
-0x4e,
-0x4b,
-0x42,
-0x0,
-0x12,
-0xd,
-0x4,
-0xc,
-0xff,
-0xff,
-0x8,
-0x0,
-0x0,
-0x4c,
-0x4e,
-0x4b,
-0x44,
-0x0,
-0x12,
-0xd,
-0x4,
-0xc,
-0xff,
-0xff,
-0x8,
-0x0,
-0x1,
-0x4c,
-0x4e,
-0x4b,
-0x41,
0x0,
+0x70,
0x12,
-0xe,
-0x4,
-0xc,
-0xff,
-0xff,
-0x8,
-0x0,
-0xa,
0x2,
-0x4c,
-0x4e,
-0x4b,
-0x42,
-0x0,
-0x12,
-0xe,
-0x4,
-0xc,
-0xff,
-0xff,
-0x8,
-0x0,
-0xa,
-0x3,
-0x4c,
-0x4e,
-0x4b,
-0x43,
-0x0,
-0x12,
-0xd,
-0x4,
-0xc,
-0xff,
-0xff,
-0x9,
-0x0,
-0x0,
-0x4c,
-0x4e,
-0x4b,
-0x41,
-0x0,
-0x12,
-0xd,
-0x4,
-0xc,
-0xff,
-0xff,
-0x9,
+0x80,
+0x60,
+0x70,
0x0,
-0x1,
-0x4c,
-0x4e,
-0x4b,
+0x61,
+0xa2,
0x42,
-0x0,
-0x12,
-0xe,
-0x4,
-0xc,
-0xff,
-0xff,
0x9,
-0x0,
-0xa,
-0x2,
-0x4c,
-0x4e,
-0x4b,
-0x43,
-0x0,
-0x12,
-0xe,
-0x4,
-0xc,
-0xff,
-0xff,
-0x9,
-0x0,
-0xa,
-0x3,
-0x4c,
-0x4e,
-0x4b,
-0x44,
-0x0,
-0x12,
-0xd,
-0x4,
-0xc,
-0xff,
-0xff,
-0xa,
-0x0,
-0x0,
-0x4c,
-0x4e,
-0x4b,
-0x42,
-0x0,
-0x12,
-0xd,
-0x4,
-0xc,
-0xff,
-0xff,
-0xa,
-0x0,
-0x1,
-0x4c,
-0x4e,
-0x4b,
-0x43,
-0x0,
-0x12,
-0xe,
-0x4,
-0xc,
-0xff,
-0xff,
-0xa,
-0x0,
-0xa,
-0x2,
-0x4c,
-0x4e,
-0x4b,
-0x44,
-0x0,
-0x12,
-0xe,
-0x4,
-0xc,
-0xff,
-0xff,
-0xa,
-0x0,
-0xa,
-0x3,
-0x4c,
-0x4e,
-0x4b,
-0x41,
-0x0,
-0x12,
-0xd,
-0x4,
-0xc,
-0xff,
-0xff,
-0xb,
-0x0,
-0x0,
-0x4c,
-0x4e,
-0x4b,
-0x43,
-0x0,
-0x12,
-0xd,
-0x4,
-0xc,
-0xff,
-0xff,
-0xb,
-0x0,
-0x1,
-0x4c,
-0x4e,
-0x4b,
-0x44,
-0x0,
-0x12,
-0xe,
-0x4,
-0xc,
-0xff,
-0xff,
-0xb,
-0x0,
-0xa,
-0x2,
-0x4c,
-0x4e,
-0x4b,
-0x41,
-0x0,
-0x12,
-0xe,
-0x4,
-0xc,
-0xff,
-0xff,
-0xb,
-0x0,
-0xa,
-0x3,
-0x4c,
-0x4e,
-0x4b,
-0x42,
-0x0,
-0x12,
-0xd,
-0x4,
-0xc,
-0xff,
-0xff,
-0xc,
-0x0,
-0x0,
-0x4c,
-0x4e,
-0x4b,
-0x44,
-0x0,
-0x12,
-0xd,
-0x4,
-0xc,
-0xff,
-0xff,
-0xc,
-0x0,
-0x1,
-0x4c,
-0x4e,
-0x4b,
-0x41,
-0x0,
-0x12,
-0xe,
-0x4,
-0xc,
-0xff,
-0xff,
-0xc,
-0x0,
-0xa,
-0x2,
-0x4c,
-0x4e,
-0x4b,
-0x42,
-0x0,
-0x12,
-0xe,
-0x4,
-0xc,
-0xff,
-0xff,
-0xc,
-0x0,
-0xa,
-0x3,
-0x4c,
-0x4e,
-0x4b,
-0x43,
-0x0,
-0x12,
-0xd,
-0x4,
-0xc,
-0xff,
-0xff,
-0xd,
-0x0,
-0x0,
-0x4c,
-0x4e,
-0x4b,
-0x41,
-0x0,
-0x12,
-0xd,
-0x4,
-0xc,
-0xff,
-0xff,
-0xd,
-0x0,
-0x1,
-0x4c,
-0x4e,
-0x4b,
-0x42,
-0x0,
-0x12,
-0xe,
-0x4,
-0xc,
-0xff,
-0xff,
-0xd,
-0x0,
-0xa,
-0x2,
-0x4c,
-0x4e,
-0x4b,
-0x43,
-0x0,
-0x12,
-0xe,
-0x4,
-0xc,
-0xff,
-0xff,
-0xd,
-0x0,
-0xa,
-0x3,
-0x4c,
-0x4e,
-0x4b,
-0x44,
-0x0,
-0x12,
-0xd,
-0x4,
-0xc,
-0xff,
-0xff,
-0xe,
-0x0,
-0x0,
-0x4c,
-0x4e,
-0x4b,
-0x42,
-0x0,
-0x12,
-0xd,
-0x4,
-0xc,
-0xff,
-0xff,
-0xe,
-0x0,
-0x1,
-0x4c,
-0x4e,
-0x4b,
-0x43,
-0x0,
-0x12,
-0xe,
-0x4,
-0xc,
-0xff,
-0xff,
-0xe,
-0x0,
-0xa,
-0x2,
-0x4c,
-0x4e,
-0x4b,
-0x44,
-0x0,
-0x12,
-0xe,
-0x4,
-0xc,
-0xff,
-0xff,
-0xe,
-0x0,
+0x95,
+0x61,
0xa,
-0x3,
-0x4c,
-0x4e,
-0x4b,
-0x41,
-0x0,
-0x12,
-0xd,
-0x4,
-0xc,
-0xff,
-0xff,
-0xf,
-0x0,
-0x0,
-0x4c,
-0x4e,
-0x4b,
-0x43,
-0x0,
-0x12,
-0xd,
-0x4,
-0xc,
-0xff,
-0xff,
-0xf,
-0x0,
-0x1,
-0x4c,
-0x4e,
-0x4b,
-0x44,
-0x0,
-0x12,
-0xe,
-0x4,
-0xc,
-0xff,
-0xff,
-0xf,
-0x0,
+0x80,
+0x70,
+0x7a,
+0x61,
0xa,
0x2,
-0x4c,
-0x4e,
-0x4b,
-0x41,
0x0,
-0x12,
-0xe,
-0x4,
-0xc,
-0xff,
-0xff,
-0xf,
+0x62,
+0x70,
+0x7b,
+0x72,
+0x61,
+0x62,
0x0,
0xa,
0x3,
-0x4c,
-0x4e,
-0x4b,
-0x42,
0x0,
-0x12,
-0xd,
-0x4,
-0xc,
-0xff,
-0xff,
-0x10,
-0x0,
-0x0,
-0x4c,
-0x4e,
-0x4b,
-0x44,
-0x0,
-0x12,
-0xd,
-0x4,
-0xc,
-0xff,
-0xff,
-0x10,
-0x0,
-0x1,
-0x4c,
-0x4e,
-0x4b,
-0x41,
-0x0,
-0x12,
-0xe,
-0x4,
-0xc,
-0xff,
-0xff,
-0x10,
-0x0,
-0xa,
-0x2,
-0x4c,
-0x4e,
-0x4b,
-0x42,
-0x0,
-0x12,
-0xe,
-0x4,
-0xc,
-0xff,
-0xff,
+0x63,
+0xa0,
0x10,
+0x93,
+0x63,
0x0,
-0xa,
-0x3,
-0x4c,
-0x4e,
-0x4b,
-0x43,
-0x0,
-0x12,
-0xd,
-0x4,
-0xc,
-0xff,
-0xff,
-0x11,
-0x0,
-0x0,
-0x4c,
-0x4e,
-0x4b,
-0x41,
-0x0,
-0x12,
-0xd,
-0x4,
-0xc,
-0xff,
-0xff,
-0x11,
-0x0,
-0x1,
-0x4c,
-0x4e,
-0x4b,
-0x42,
-0x0,
-0x12,
-0xe,
-0x4,
-0xc,
-0xff,
-0xff,
-0x11,
-0x0,
-0xa,
-0x2,
-0x4c,
-0x4e,
-0x4b,
-0x43,
-0x0,
-0x12,
-0xe,
-0x4,
-0xc,
-0xff,
-0xff,
-0x11,
-0x0,
-0xa,
-0x3,
-0x4c,
-0x4e,
-0x4b,
-0x44,
-0x0,
-0x12,
-0xd,
-0x4,
-0xc,
-0xff,
-0xff,
-0x12,
-0x0,
-0x0,
-0x4c,
-0x4e,
-0x4b,
-0x42,
-0x0,
-0x12,
-0xd,
-0x4,
-0xc,
-0xff,
-0xff,
-0x12,
-0x0,
-0x1,
-0x4c,
-0x4e,
-0x4b,
-0x43,
-0x0,
-0x12,
-0xe,
-0x4,
-0xc,
-0xff,
-0xff,
-0x12,
-0x0,
-0xa,
-0x2,
-0x4c,
-0x4e,
-0x4b,
-0x44,
-0x0,
-0x12,
-0xe,
-0x4,
-0xc,
-0xff,
-0xff,
-0x12,
-0x0,
-0xa,
-0x3,
-0x4c,
-0x4e,
-0x4b,
-0x41,
-0x0,
-0x12,
-0xd,
-0x4,
-0xc,
-0xff,
-0xff,
-0x13,
-0x0,
-0x0,
-0x4c,
-0x4e,
-0x4b,
-0x43,
-0x0,
-0x12,
-0xd,
-0x4,
-0xc,
-0xff,
-0xff,
-0x13,
-0x0,
-0x1,
-0x4c,
-0x4e,
-0x4b,
-0x44,
-0x0,
-0x12,
-0xe,
-0x4,
-0xc,
-0xff,
-0xff,
-0x13,
-0x0,
-0xa,
-0x2,
-0x4c,
-0x4e,
-0x4b,
-0x41,
-0x0,
-0x12,
-0xe,
-0x4,
-0xc,
-0xff,
-0xff,
-0x13,
-0x0,
-0xa,
-0x3,
-0x4c,
-0x4e,
-0x4b,
-0x42,
-0x0,
-0x12,
-0xd,
-0x4,
-0xc,
-0xff,
-0xff,
-0x14,
-0x0,
-0x0,
-0x4c,
-0x4e,
-0x4b,
-0x44,
-0x0,
-0x12,
-0xd,
-0x4,
-0xc,
-0xff,
-0xff,
-0x14,
-0x0,
-0x1,
-0x4c,
-0x4e,
-0x4b,
-0x41,
-0x0,
-0x12,
-0xe,
-0x4,
-0xc,
-0xff,
-0xff,
-0x14,
-0x0,
-0xa,
-0x2,
-0x4c,
-0x4e,
-0x4b,
-0x42,
-0x0,
-0x12,
-0xe,
-0x4,
-0xc,
-0xff,
-0xff,
-0x14,
-0x0,
-0xa,
-0x3,
-0x4c,
-0x4e,
-0x4b,
-0x43,
-0x0,
-0x12,
-0xd,
-0x4,
-0xc,
-0xff,
-0xff,
-0x15,
-0x0,
-0x0,
-0x4c,
-0x4e,
-0x4b,
-0x41,
-0x0,
-0x12,
-0xd,
-0x4,
-0xc,
-0xff,
-0xff,
-0x15,
-0x0,
-0x1,
-0x4c,
-0x4e,
-0x4b,
-0x42,
-0x0,
-0x12,
-0xe,
-0x4,
-0xc,
-0xff,
-0xff,
-0x15,
-0x0,
-0xa,
-0x2,
-0x4c,
-0x4e,
-0x4b,
-0x43,
-0x0,
-0x12,
-0xe,
-0x4,
-0xc,
-0xff,
-0xff,
-0x15,
-0x0,
-0xa,
-0x3,
-0x4c,
-0x4e,
-0x4b,
-0x44,
-0x0,
-0x12,
-0xd,
-0x4,
-0xc,
-0xff,
-0xff,
-0x16,
-0x0,
-0x0,
-0x4c,
-0x4e,
-0x4b,
-0x42,
-0x0,
-0x12,
-0xd,
-0x4,
-0xc,
-0xff,
-0xff,
-0x16,
-0x0,
-0x1,
-0x4c,
-0x4e,
-0x4b,
-0x43,
-0x0,
-0x12,
-0xe,
-0x4,
-0xc,
-0xff,
-0xff,
-0x16,
-0x0,
-0xa,
-0x2,
-0x4c,
-0x4e,
-0x4b,
-0x44,
-0x0,
-0x12,
-0xe,
-0x4,
-0xc,
-0xff,
-0xff,
-0x16,
-0x0,
-0xa,
-0x3,
-0x4c,
-0x4e,
-0x4b,
-0x41,
-0x0,
-0x12,
-0xd,
-0x4,
-0xc,
-0xff,
-0xff,
-0x17,
-0x0,
-0x0,
-0x4c,
-0x4e,
-0x4b,
-0x43,
-0x0,
-0x12,
-0xd,
-0x4,
-0xc,
-0xff,
-0xff,
-0x17,
-0x0,
-0x1,
-0x4c,
-0x4e,
-0x4b,
-0x44,
-0x0,
-0x12,
-0xe,
-0x4,
-0xc,
-0xff,
-0xff,
-0x17,
-0x0,
-0xa,
-0x2,
-0x4c,
-0x4e,
-0x4b,
-0x41,
-0x0,
-0x12,
-0xe,
-0x4,
-0xc,
-0xff,
-0xff,
-0x17,
-0x0,
-0xa,
-0x3,
-0x4c,
-0x4e,
-0x4b,
-0x42,
-0x0,
+0x70,
0x12,
-0xd,
+0x9,
0x4,
-0xc,
-0xff,
-0xff,
-0x18,
0x0,
0x0,
0x4c,
@@ -2859,456 +1508,115 @@ static unsigned char AcpiDsdtAmlCode[] = {
0x4b,
0x44,
0x0,
-0x12,
-0xd,
-0x4,
-0xc,
-0xff,
-0xff,
-0x18,
-0x0,
+0x64,
+0xa0,
+0x24,
+0x93,
+0x63,
0x1,
-0x4c,
-0x4e,
-0x4b,
-0x41,
-0x0,
-0x12,
-0xe,
-0x4,
-0xc,
-0xff,
-0xff,
-0x18,
-0x0,
-0xa,
-0x2,
-0x4c,
-0x4e,
-0x4b,
-0x42,
-0x0,
-0x12,
-0xe,
-0x4,
-0xc,
-0xff,
-0xff,
-0x18,
-0x0,
+0xa0,
+0x11,
+0x93,
+0x61,
0xa,
-0x3,
-0x4c,
-0x4e,
-0x4b,
-0x43,
-0x0,
-0x12,
-0xd,
-0x4,
-0xc,
-0xff,
-0xff,
-0x19,
-0x0,
-0x0,
-0x4c,
-0x4e,
-0x4b,
-0x41,
-0x0,
-0x12,
-0xd,
0x4,
-0xc,
-0xff,
-0xff,
-0x19,
-0x0,
-0x1,
-0x4c,
-0x4e,
-0x4b,
-0x42,
-0x0,
-0x12,
-0xe,
-0x4,
-0xc,
-0xff,
-0xff,
-0x19,
-0x0,
-0xa,
-0x2,
-0x4c,
-0x4e,
-0x4b,
-0x43,
-0x0,
-0x12,
-0xe,
-0x4,
-0xc,
-0xff,
-0xff,
-0x19,
-0x0,
-0xa,
-0x3,
-0x4c,
-0x4e,
-0x4b,
-0x44,
-0x0,
+0x70,
0x12,
-0xd,
+0x9,
0x4,
-0xc,
-0xff,
-0xff,
-0x1a,
0x0,
0x0,
0x4c,
0x4e,
0x4b,
-0x42,
+0x53,
0x0,
-0x12,
+0x64,
+0xa1,
0xd,
-0x4,
-0xc,
-0xff,
-0xff,
-0x1a,
-0x0,
-0x1,
-0x4c,
-0x4e,
-0x4b,
-0x43,
-0x0,
+0x70,
0x12,
-0xe,
+0x9,
0x4,
-0xc,
-0xff,
-0xff,
-0x1a,
-0x0,
-0xa,
-0x2,
-0x4c,
-0x4e,
-0x4b,
-0x44,
0x0,
-0x12,
-0xe,
-0x4,
-0xc,
-0xff,
-0xff,
-0x1a,
0x0,
-0xa,
-0x3,
0x4c,
0x4e,
0x4b,
0x41,
0x0,
-0x12,
-0xd,
-0x4,
-0xc,
-0xff,
-0xff,
-0x1b,
-0x0,
-0x0,
-0x4c,
-0x4e,
-0x4b,
-0x43,
-0x0,
-0x12,
-0xd,
-0x4,
-0xc,
-0xff,
-0xff,
-0x1b,
-0x0,
-0x1,
-0x4c,
-0x4e,
-0x4b,
-0x44,
-0x0,
-0x12,
-0xe,
-0x4,
-0xc,
-0xff,
-0xff,
-0x1b,
-0x0,
+0x64,
+0xa0,
+0x11,
+0x93,
+0x63,
0xa,
0x2,
-0x4c,
-0x4e,
-0x4b,
-0x41,
-0x0,
-0x12,
-0xe,
-0x4,
-0xc,
-0xff,
-0xff,
-0x1b,
-0x0,
-0xa,
-0x3,
-0x4c,
-0x4e,
-0x4b,
-0x42,
-0x0,
+0x70,
0x12,
-0xd,
+0x9,
0x4,
-0xc,
-0xff,
-0xff,
-0x1c,
-0x0,
-0x0,
-0x4c,
-0x4e,
-0x4b,
-0x44,
0x0,
-0x12,
-0xd,
-0x4,
-0xc,
-0xff,
-0xff,
-0x1c,
0x0,
-0x1,
-0x4c,
-0x4e,
-0x4b,
-0x41,
-0x0,
-0x12,
-0xe,
-0x4,
-0xc,
-0xff,
-0xff,
-0x1c,
-0x0,
-0xa,
-0x2,
0x4c,
0x4e,
0x4b,
0x42,
0x0,
-0x12,
-0xe,
-0x4,
-0xc,
-0xff,
-0xff,
-0x1c,
-0x0,
+0x64,
+0xa0,
+0x11,
+0x93,
+0x63,
0xa,
0x3,
-0x4c,
-0x4e,
-0x4b,
-0x43,
-0x0,
-0x12,
-0xd,
-0x4,
-0xc,
-0xff,
-0xff,
-0x1d,
-0x0,
-0x0,
-0x4c,
-0x4e,
-0x4b,
-0x41,
-0x0,
+0x70,
0x12,
-0xd,
+0x9,
0x4,
-0xc,
-0xff,
-0xff,
-0x1d,
-0x0,
-0x1,
-0x4c,
-0x4e,
-0x4b,
-0x42,
0x0,
-0x12,
-0xe,
-0x4,
-0xc,
-0xff,
-0xff,
-0x1d,
0x0,
-0xa,
-0x2,
0x4c,
0x4e,
0x4b,
0x43,
0x0,
-0x12,
-0xe,
-0x4,
-0xc,
-0xff,
-0xff,
-0x1d,
-0x0,
+0x64,
+0x70,
+0x7d,
+0x79,
+0x62,
0xa,
-0x3,
-0x4c,
-0x4e,
-0x4b,
-0x44,
-0x0,
-0x12,
-0xd,
-0x4,
-0xc,
-0xff,
-0xff,
-0x1e,
-0x0,
-0x0,
-0x4c,
-0x4e,
-0x4b,
-0x42,
-0x0,
-0x12,
-0xd,
-0x4,
-0xc,
-0xff,
-0xff,
-0x1e,
-0x0,
-0x1,
-0x4c,
-0x4e,
-0x4b,
-0x43,
+0x10,
0x0,
-0x12,
-0xe,
-0x4,
-0xc,
+0xb,
0xff,
0xff,
-0x1e,
0x0,
-0xa,
-0x2,
-0x4c,
-0x4e,
-0x4b,
-0x44,
+0x88,
+0x64,
0x0,
-0x12,
-0xe,
-0x4,
-0xc,
-0xff,
-0xff,
-0x1e,
0x0,
+0x70,
+0x7b,
+0x61,
0xa,
0x3,
-0x4c,
-0x4e,
-0x4b,
-0x41,
-0x0,
-0x12,
-0xd,
-0x4,
-0xc,
-0xff,
-0xff,
-0x1f,
-0x0,
-0x0,
-0x4c,
-0x4e,
-0x4b,
-0x43,
-0x0,
-0x12,
-0xd,
-0x4,
-0xc,
-0xff,
-0xff,
-0x1f,
0x0,
+0x88,
+0x64,
0x1,
-0x4c,
-0x4e,
-0x4b,
-0x44,
-0x0,
-0x12,
-0xe,
-0x4,
-0xc,
-0xff,
-0xff,
-0x1f,
-0x0,
-0xa,
-0x2,
-0x4c,
-0x4e,
-0x4b,
-0x41,
0x0,
-0x12,
-0xe,
-0x4,
-0xc,
-0xff,
-0xff,
-0x1f,
-0x0,
-0xa,
-0x3,
-0x4c,
-0x4e,
-0x4b,
-0x42,
+0x70,
+0x64,
+0x88,
+0x60,
+0x61,
0x0,
+0x75,
+0x61,
+0xa4,
+0x60,
0x5b,
0x81,
0x24,
diff --git a/hw/i386/kvm/clock.c b/hw/i386/kvm/clock.c
index 272a88acb5..07b9c0e581 100644
--- a/hw/i386/kvm/clock.c
+++ b/hw/i386/kvm/clock.c
@@ -14,10 +14,8 @@
*/
#include "qemu-common.h"
-#include "qemu/host-utils.h"
#include "sysemu/sysemu.h"
#include "sysemu/kvm.h"
-#include "sysemu/cpus.h"
#include "hw/sysbus.h"
#include "hw/kvm/clock.h"
@@ -36,48 +34,6 @@ typedef struct KVMClockState {
bool clock_valid;
} KVMClockState;
-struct pvclock_vcpu_time_info {
- uint32_t version;
- uint32_t pad0;
- uint64_t tsc_timestamp;
- uint64_t system_time;
- uint32_t tsc_to_system_mul;
- int8_t tsc_shift;
- uint8_t flags;
- uint8_t pad[2];
-} __attribute__((__packed__)); /* 32 bytes */
-
-static uint64_t kvmclock_current_nsec(KVMClockState *s)
-{
- CPUState *cpu = first_cpu;
- CPUX86State *env = cpu->env_ptr;
- hwaddr kvmclock_struct_pa = env->system_time_msr & ~1ULL;
- uint64_t migration_tsc = env->tsc;
- struct pvclock_vcpu_time_info time;
- uint64_t delta;
- uint64_t nsec_lo;
- uint64_t nsec_hi;
- uint64_t nsec;
-
- if (!(env->system_time_msr & 1ULL)) {
- /* KVM clock not active */
- return 0;
- }
-
- cpu_physical_memory_read(kvmclock_struct_pa, &time, sizeof(time));
-
- assert(time.tsc_timestamp <= migration_tsc);
- delta = migration_tsc - time.tsc_timestamp;
- if (time.tsc_shift < 0) {
- delta >>= -time.tsc_shift;
- } else {
- delta <<= time.tsc_shift;
- }
-
- mulu64(&nsec_lo, &nsec_hi, delta, time.tsc_to_system_mul);
- nsec = (nsec_lo >> 32) | (nsec_hi << 32);
- return nsec + time.system_time;
-}
static void kvmclock_vm_state_change(void *opaque, int running,
RunState state)
@@ -89,15 +45,9 @@ static void kvmclock_vm_state_change(void *opaque, int running,
if (running) {
struct kvm_clock_data data;
- uint64_t time_at_migration = kvmclock_current_nsec(s);
s->clock_valid = false;
- /* We can't rely on the migrated clock value, just discard it */
- if (time_at_migration) {
- s->clock = time_at_migration;
- }
-
data.clock = s->clock;
data.flags = 0;
ret = kvm_vm_ioctl(kvm_state, KVM_SET_CLOCK, &data);
@@ -125,8 +75,6 @@ static void kvmclock_vm_state_change(void *opaque, int running,
if (s->clock_valid) {
return;
}
-
- cpu_synchronize_all_states();
ret = kvm_vm_ioctl(kvm_state, KVM_GET_CLOCK, &data);
if (ret < 0) {
fprintf(stderr, "KVM_GET_CLOCK failed: %s\n", strerror(ret));
diff --git a/hw/i386/pc.c b/hw/i386/pc.c
index 2cf22b1293..8fa8d2f781 100644
--- a/hw/i386/pc.c
+++ b/hw/i386/pc.c
@@ -1066,35 +1066,6 @@ typedef struct PcRomPciInfo {
uint64_t w64_max;
} PcRomPciInfo;
-static void pc_fw_cfg_guest_info(PcGuestInfo *guest_info)
-{
- PcRomPciInfo *info;
- Object *pci_info;
- bool ambiguous = false;
-
- if (!guest_info->has_pci_info || !guest_info->fw_cfg) {
- return;
- }
- pci_info = object_resolve_path_type("", TYPE_PCI_HOST_BRIDGE, &ambiguous);
- g_assert(!ambiguous);
- if (!pci_info) {
- return;
- }
-
- info = g_malloc(sizeof *info);
- info->w32_min = cpu_to_le64(object_property_get_int(pci_info,
- PCI_HOST_PROP_PCI_HOLE_START, NULL));
- info->w32_max = cpu_to_le64(object_property_get_int(pci_info,
- PCI_HOST_PROP_PCI_HOLE_END, NULL));
- info->w64_min = cpu_to_le64(object_property_get_int(pci_info,
- PCI_HOST_PROP_PCI_HOLE64_START, NULL));
- info->w64_max = cpu_to_le64(object_property_get_int(pci_info,
- PCI_HOST_PROP_PCI_HOLE64_END, NULL));
- /* Pass PCI hole info to guest via a side channel.
- * Required so guest PCI enumeration does the right thing. */
- fw_cfg_add_file(guest_info->fw_cfg, "etc/pci-info", info, sizeof *info);
-}
-
typedef struct PcGuestInfoState {
PcGuestInfo info;
Notifier machine_done;
@@ -1106,7 +1077,6 @@ void pc_guest_info_machine_done(Notifier *notifier, void *data)
PcGuestInfoState *guest_info_state = container_of(notifier,
PcGuestInfoState,
machine_done);
- pc_fw_cfg_guest_info(&guest_info_state->info);
acpi_setup(&guest_info_state->info);
}
@@ -1190,6 +1160,31 @@ void pc_acpi_init(const char *default_dsdt)
}
}
+FWCfgState *xen_load_linux(const char *kernel_filename,
+ const char *kernel_cmdline,
+ const char *initrd_filename,
+ ram_addr_t below_4g_mem_size,
+ PcGuestInfo *guest_info)
+{
+ int i;
+ FWCfgState *fw_cfg;
+
+ assert(kernel_filename != NULL);
+
+ fw_cfg = fw_cfg_init(BIOS_CFG_IOPORT, BIOS_CFG_IOPORT + 1, 0, 0);
+ rom_set_fw(fw_cfg);
+
+ load_linux(fw_cfg, kernel_filename, initrd_filename,
+ kernel_cmdline, below_4g_mem_size);
+ for (i = 0; i < nb_option_roms; i++) {
+ assert(!strcmp(option_rom[i].name, "linuxboot.bin") ||
+ !strcmp(option_rom[i].name, "multiboot.bin"));
+ rom_add_option(option_rom[i].name, option_rom[i].bootindex);
+ }
+ guest_info->fw_cfg = fw_cfg;
+ return fw_cfg;
+}
+
FWCfgState *pc_memory_init(MachineState *machine,
MemoryRegion *system_memory,
ram_addr_t below_4g_mem_size,
diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c
index 2dccb3401b..47ac1b528d 100644
--- a/hw/i386/pc_piix.c
+++ b/hw/i386/pc_piix.c
@@ -59,8 +59,8 @@ static const int ide_iobase[MAX_IDE_BUS] = { 0x1f0, 0x170 };
static const int ide_iobase2[MAX_IDE_BUS] = { 0x3f6, 0x376 };
static const int ide_irq[MAX_IDE_BUS] = { 14, 15 };
-static bool has_pci_info;
static bool has_acpi_build = true;
+static int legacy_acpi_table_size;
static bool smbios_defaults = true;
static bool smbios_legacy_mode;
/* Make sure that guest addresses aligned at 1Gbyte boundaries get mapped to
@@ -114,7 +114,7 @@ static void pc_init1(MachineState *machine,
lowmem = 0xe0000000;
}
- /* Handle the machine opt max-ram-below-4g. It is basicly doing
+ /* Handle the machine opt max-ram-below-4g. It is basically doing
* min(qemu limit, user limit).
*/
if (lowmem > pc_machine->max_ram_below_4g) {
@@ -163,8 +163,8 @@ static void pc_init1(MachineState *machine,
guest_info = pc_guest_info_init(below_4g_mem_size, above_4g_mem_size);
guest_info->has_acpi_build = has_acpi_build;
+ guest_info->legacy_acpi_table_size = legacy_acpi_table_size;
- guest_info->has_pci_info = has_pci_info;
guest_info->isapc_ram_fw = !pci_enabled;
guest_info->has_reserved_memory = has_reserved_memory;
@@ -180,6 +180,13 @@ static void pc_init1(MachineState *machine,
fw_cfg = pc_memory_init(machine, system_memory,
below_4g_mem_size, above_4g_mem_size,
rom_memory, &ram_memory, guest_info);
+ } else if (machine->kernel_filename != NULL) {
+ /* For xen HVM direct kernel boot, load linux here */
+ fw_cfg = xen_load_linux(machine->kernel_filename,
+ machine->kernel_cmdline,
+ machine->initrd_filename,
+ below_4g_mem_size,
+ guest_info);
}
gsi_state = g_malloc0(sizeof(*gsi_state));
@@ -297,6 +304,23 @@ static void pc_init_pci(MachineState *machine)
static void pc_compat_2_0(MachineState *machine)
{
+ /* This value depends on the actual DSDT and SSDT compiled into
+ * the source QEMU; unfortunately it depends on the binary and
+ * not on the machine type, so we cannot make pc-i440fx-1.7 work on
+ * both QEMU 1.7 and QEMU 2.0.
+ *
+ * Large variations cause migration to fail for more than one
+ * consecutive value of the "-smp" maxcpus option.
+ *
+ * For small variations of the kind caused by different iasl versions,
+ * the 4k rounding usually leaves slack. However, there could be still
+ * one or two values that break. For QEMU 1.7 and QEMU 2.0 the
+ * slack is only ~10 bytes before one "-smp maxcpus" value breaks!
+ *
+ * 6652 is valid for QEMU 2.0, the right value for pc-i440fx-1.7 on
+ * QEMU 1.7 it is 6414. For RHEL/CentOS 7.0 it is 6418.
+ */
+ legacy_acpi_table_size = 6652;
smbios_legacy_mode = true;
has_reserved_memory = false;
}
@@ -307,13 +331,13 @@ static void pc_compat_1_7(MachineState *machine)
smbios_defaults = false;
gigabyte_align = false;
option_rom_has_mr = true;
+ legacy_acpi_table_size = 6414;
x86_cpu_compat_disable_kvm_features(FEAT_1_ECX, CPUID_EXT_X2APIC);
}
static void pc_compat_1_6(MachineState *machine)
{
pc_compat_1_7(machine);
- has_pci_info = false;
rom_file_has_mr = false;
has_acpi_build = false;
}
@@ -386,25 +410,15 @@ static void pc_init_pci_1_2(MachineState *machine)
pc_init_pci(machine);
}
-/* PC init function for pc-0.10 to pc-0.13, and reused by xenfv */
+/* PC init function for pc-0.10 to pc-0.13 */
static void pc_init_pci_no_kvmclock(MachineState *machine)
{
- has_pci_info = false;
- has_acpi_build = false;
- smbios_defaults = false;
- gigabyte_align = false;
- smbios_legacy_mode = true;
- has_reserved_memory = false;
- option_rom_has_mr = true;
- rom_file_has_mr = false;
- x86_cpu_compat_disable_kvm_features(FEAT_KVM, KVM_FEATURE_PV_EOI);
- enable_compat_apic_id_mode();
+ pc_compat_1_2(machine);
pc_init1(machine, 1, 0);
}
static void pc_init_isa(MachineState *machine)
{
- has_pci_info = false;
has_acpi_build = false;
smbios_defaults = false;
gigabyte_align = false;
@@ -439,16 +453,28 @@ static void pc_xen_hvm_init(MachineState *machine)
.desc = "Standard PC (i440FX + PIIX, 1996)", \
.hot_add_cpu = pc_hot_add_cpu
-#define PC_I440FX_2_1_MACHINE_OPTIONS \
+#define PC_I440FX_2_2_MACHINE_OPTIONS \
PC_I440FX_MACHINE_OPTIONS, \
.default_machine_opts = "firmware=bios-256k.bin"
+static QEMUMachine pc_i440fx_machine_v2_2 = {
+ PC_I440FX_2_2_MACHINE_OPTIONS,
+ .name = "pc-i440fx-2.2",
+ .alias = "pc",
+ .init = pc_init_pci,
+ .is_default = 1,
+};
+
+#define PC_I440FX_2_1_MACHINE_OPTIONS PC_I440FX_2_2_MACHINE_OPTIONS
+
static QEMUMachine pc_i440fx_machine_v2_1 = {
PC_I440FX_2_1_MACHINE_OPTIONS,
.name = "pc-i440fx-2.1",
- .alias = "pc",
.init = pc_init_pci,
- .is_default = 1,
+ .compat_props = (GlobalProperty[]) {
+ PC_COMPAT_2_1,
+ { /* end of list */ }
+ },
};
#define PC_I440FX_2_0_MACHINE_OPTIONS PC_I440FX_2_1_MACHINE_OPTIONS
@@ -885,6 +911,7 @@ static QEMUMachine xenfv_machine = {
static void pc_machine_init(void)
{
+ qemu_register_pc_machine(&pc_i440fx_machine_v2_2);
qemu_register_pc_machine(&pc_i440fx_machine_v2_1);
qemu_register_pc_machine(&pc_i440fx_machine_v2_0);
qemu_register_pc_machine(&pc_i440fx_machine_v1_7);
diff --git a/hw/i386/pc_q35.c b/hw/i386/pc_q35.c
index 36b6ab0bce..4b5a27404a 100644
--- a/hw/i386/pc_q35.c
+++ b/hw/i386/pc_q35.c
@@ -49,7 +49,6 @@
/* ICH9 AHCI has 6 ports */
#define MAX_SATA_PORTS 6
-static bool has_pci_info;
static bool has_acpi_build = true;
static bool smbios_defaults = true;
static bool smbios_legacy_mode;
@@ -103,7 +102,7 @@ static void pc_q35_init(MachineState *machine)
lowmem = 0xb0000000;
}
- /* Handle the machine opt max-ram-below-4g. It is basicly doing
+ /* Handle the machine opt max-ram-below-4g. It is basically doing
* min(qemu limit, user limit).
*/
if (lowmem > pc_machine->max_ram_below_4g) {
@@ -150,11 +149,15 @@ static void pc_q35_init(MachineState *machine)
}
guest_info = pc_guest_info_init(below_4g_mem_size, above_4g_mem_size);
- guest_info->has_pci_info = has_pci_info;
guest_info->isapc_ram_fw = false;
guest_info->has_acpi_build = has_acpi_build;
guest_info->has_reserved_memory = has_reserved_memory;
+ /* Migration was not supported in 2.0 for Q35, so do not bother
+ * with this hack (see hw/i386/acpi-build.c).
+ */
+ guest_info->legacy_acpi_table_size = 0;
+
if (smbios_defaults) {
MachineClass *mc = MACHINE_GET_CLASS(machine);
/* These values are guest ABI, do not change */
@@ -231,7 +234,7 @@ static void pc_q35_init(MachineState *machine)
gsi_state->i8259_irq[i] = i8259[i];
}
if (pci_enabled) {
- ioapic_init_gsi(gsi_state, NULL);
+ ioapic_init_gsi(gsi_state, "q35");
}
qdev_init_nofail(icc_bridge);
@@ -291,7 +294,6 @@ static void pc_compat_1_7(MachineState *machine)
static void pc_compat_1_6(MachineState *machine)
{
pc_compat_1_7(machine);
- has_pci_info = false;
rom_file_has_mr = false;
has_acpi_build = false;
}
@@ -343,15 +345,27 @@ static void pc_q35_init_1_4(MachineState *machine)
.desc = "Standard PC (Q35 + ICH9, 2009)", \
.hot_add_cpu = pc_hot_add_cpu
-#define PC_Q35_2_1_MACHINE_OPTIONS \
+#define PC_Q35_2_2_MACHINE_OPTIONS \
PC_Q35_MACHINE_OPTIONS, \
.default_machine_opts = "firmware=bios-256k.bin"
+static QEMUMachine pc_q35_machine_v2_2 = {
+ PC_Q35_2_2_MACHINE_OPTIONS,
+ .name = "pc-q35-2.2",
+ .alias = "q35",
+ .init = pc_q35_init,
+};
+
+#define PC_Q35_2_1_MACHINE_OPTIONS PC_Q35_2_2_MACHINE_OPTIONS
+
static QEMUMachine pc_q35_machine_v2_1 = {
PC_Q35_2_1_MACHINE_OPTIONS,
.name = "pc-q35-2.1",
- .alias = "q35",
.init = pc_q35_init,
+ .compat_props = (GlobalProperty[]) {
+ PC_COMPAT_2_1,
+ { /* end of list */ }
+ },
};
#define PC_Q35_2_0_MACHINE_OPTIONS PC_Q35_2_1_MACHINE_OPTIONS
@@ -416,6 +430,7 @@ static QEMUMachine pc_q35_machine_v1_4 = {
static void pc_q35_machine_init(void)
{
+ qemu_register_pc_machine(&pc_q35_machine_v2_2);
qemu_register_pc_machine(&pc_q35_machine_v2_1);
qemu_register_pc_machine(&pc_q35_machine_v2_0);
qemu_register_pc_machine(&pc_q35_machine_v1_7);
diff --git a/hw/i386/q35-acpi-dsdt.dsl b/hw/i386/q35-acpi-dsdt.dsl
index 8c3eae73bf..054b035b08 100644
--- a/hw/i386/q35-acpi-dsdt.dsl
+++ b/hw/i386/q35-acpi-dsdt.dsl
@@ -410,7 +410,7 @@ DefinitionBlock (
/****************************************************************
* General purpose events
****************************************************************/
- External(\_SB.PCI0.MEMORY_HOPTLUG_DEVICE.MEMORY_SLOT_SCAN_METHOD, MethodObj)
+ External(\_SB.PCI0.MEMORY_HOTPLUG_DEVICE.MEMORY_SLOT_SCAN_METHOD, MethodObj)
Scope(\_GPE) {
Name(_HID, "ACPI0006")
@@ -425,7 +425,7 @@ DefinitionBlock (
}
Method(_E03) {
// Memory hotplug event
- \_SB.PCI0.MEMORY_HOPTLUG_DEVICE.MEMORY_SLOT_SCAN_METHOD()
+ \_SB.PCI0.MEMORY_HOTPLUG_DEVICE.MEMORY_SLOT_SCAN_METHOD()
}
Method(_L04) {
}
diff --git a/hw/i386/ssdt-mem.dsl b/hw/i386/ssdt-mem.dsl
index 8e17bd1f97..22ff5ddfc3 100644
--- a/hw/i386/ssdt-mem.dsl
+++ b/hw/i386/ssdt-mem.dsl
@@ -39,10 +39,10 @@ ACPI_EXTRACT_ALL_CODE ssdm_mem_aml
DefinitionBlock ("ssdt-mem.aml", "SSDT", 0x02, "BXPC", "CSSDT", 0x1)
{
- External(\_SB.PCI0.MEMORY_HOPTLUG_DEVICE.MEMORY_SLOT_CRS_METHOD, MethodObj)
- External(\_SB.PCI0.MEMORY_HOPTLUG_DEVICE.MEMORY_SLOT_STATUS_METHOD, MethodObj)
- External(\_SB.PCI0.MEMORY_HOPTLUG_DEVICE.MEMORY_SLOT_OST_METHOD, MethodObj)
- External(\_SB.PCI0.MEMORY_HOPTLUG_DEVICE.MEMORY_SLOT_PROXIMITY_METHOD, MethodObj)
+ External(\_SB.PCI0.MEMORY_HOTPLUG_DEVICE.MEMORY_SLOT_CRS_METHOD, MethodObj)
+ External(\_SB.PCI0.MEMORY_HOTPLUG_DEVICE.MEMORY_SLOT_STATUS_METHOD, MethodObj)
+ External(\_SB.PCI0.MEMORY_HOTPLUG_DEVICE.MEMORY_SLOT_OST_METHOD, MethodObj)
+ External(\_SB.PCI0.MEMORY_HOTPLUG_DEVICE.MEMORY_SLOT_PROXIMITY_METHOD, MethodObj)
Scope(\_SB) {
/* v------------------ DO NOT EDIT ------------------v */
@@ -58,19 +58,19 @@ DefinitionBlock ("ssdt-mem.aml", "SSDT", 0x02, "BXPC", "CSSDT", 0x1)
Name(_HID, EISAID("PNP0C80"))
Method(_CRS, 0) {
- Return(\_SB.PCI0.MEMORY_HOPTLUG_DEVICE.MEMORY_SLOT_CRS_METHOD(_UID))
+ Return(\_SB.PCI0.MEMORY_HOTPLUG_DEVICE.MEMORY_SLOT_CRS_METHOD(_UID))
}
Method(_STA, 0) {
- Return(\_SB.PCI0.MEMORY_HOPTLUG_DEVICE.MEMORY_SLOT_STATUS_METHOD(_UID))
+ Return(\_SB.PCI0.MEMORY_HOTPLUG_DEVICE.MEMORY_SLOT_STATUS_METHOD(_UID))
}
Method(_PXM, 0) {
- Return(\_SB.PCI0.MEMORY_HOPTLUG_DEVICE.MEMORY_SLOT_PROXIMITY_METHOD(_UID))
+ Return(\_SB.PCI0.MEMORY_HOTPLUG_DEVICE.MEMORY_SLOT_PROXIMITY_METHOD(_UID))
}
Method(_OST, 3) {
- \_SB.PCI0.MEMORY_HOPTLUG_DEVICE.MEMORY_SLOT_OST_METHOD(_UID, Arg0, Arg1, Arg2)
+ \_SB.PCI0.MEMORY_HOTPLUG_DEVICE.MEMORY_SLOT_OST_METHOD(_UID, Arg0, Arg1, Arg2)
}
}
}
diff --git a/hw/i386/ssdt-misc.dsl b/hw/i386/ssdt-misc.dsl
index d329b8ba57..0fd448000b 100644
--- a/hw/i386/ssdt-misc.dsl
+++ b/hw/i386/ssdt-misc.dsl
@@ -120,7 +120,7 @@ DefinitionBlock ("ssdt-misc.aml", "SSDT", 0x01, "BXPC", "BXSSDTSUSP", 0x1)
External(MEMORY_SLOT_NOTIFY_METHOD, MethodObj)
Scope(\_SB.PCI0) {
- Device(MEMORY_HOPTLUG_DEVICE) {
+ Device(MEMORY_HOTPLUG_DEVICE) {
Name(_HID, "PNP0A06")
Name(_UID, "Memory hotplug resources")
diff --git a/hw/i386/xen/xen_apic.c b/hw/i386/xen/xen_apic.c
index 63bb7f77c6..f5acd6a096 100644
--- a/hw/i386/xen/xen_apic.c
+++ b/hw/i386/xen/xen_apic.c
@@ -40,6 +40,7 @@ static void xen_apic_realize(DeviceState *dev, Error **errp)
{
APICCommonState *s = APIC_COMMON(dev);
+ s->vapic_control = 0;
memory_region_init_io(&s->io_memory, OBJECT(s), &xen_apic_io_ops, s,
"xen-apic-msi", APIC_SPACE_SIZE);
diff --git a/hw/ide/ahci.c b/hw/ide/ahci.c
index aa0ef4233b..932b0d508c 100644
--- a/hw/ide/ahci.c
+++ b/hw/ide/ahci.c
@@ -584,7 +584,72 @@ static void ahci_write_fis_sdb(AHCIState *s, int port, uint32_t finished)
s->dev[port].finished |= finished;
*(uint32_t*)(sdb_fis + 4) = cpu_to_le32(s->dev[port].finished);
- ahci_trigger_irq(s, &s->dev[port], PORT_IRQ_STAT_SDBS);
+ ahci_trigger_irq(s, &s->dev[port], PORT_IRQ_SDB_FIS);
+}
+
+static void ahci_write_fis_pio(AHCIDevice *ad, uint16_t len)
+{
+ AHCIPortRegs *pr = &ad->port_regs;
+ uint8_t *pio_fis, *cmd_fis;
+ uint64_t tbl_addr;
+ dma_addr_t cmd_len = 0x80;
+
+ if (!ad->res_fis || !(pr->cmd & PORT_CMD_FIS_RX)) {
+ return;
+ }
+
+ /* map cmd_fis */
+ tbl_addr = le64_to_cpu(ad->cur_cmd->tbl_addr);
+ cmd_fis = dma_memory_map(ad->hba->as, tbl_addr, &cmd_len,
+ DMA_DIRECTION_TO_DEVICE);
+
+ if (cmd_fis == NULL) {
+ DPRINTF(ad->port_no, "dma_memory_map failed in ahci_write_fis_pio");
+ ahci_trigger_irq(ad->hba, ad, PORT_IRQ_HBUS_ERR);
+ return;
+ }
+
+ if (cmd_len != 0x80) {
+ DPRINTF(ad->port_no,
+ "dma_memory_map mapped too few bytes in ahci_write_fis_pio");
+ dma_memory_unmap(ad->hba->as, cmd_fis, cmd_len,
+ DMA_DIRECTION_TO_DEVICE, cmd_len);
+ ahci_trigger_irq(ad->hba, ad, PORT_IRQ_HBUS_ERR);
+ return;
+ }
+
+ pio_fis = &ad->res_fis[RES_FIS_PSFIS];
+
+ pio_fis[0] = 0x5f;
+ pio_fis[1] = (ad->hba->control_regs.irqstatus ? (1 << 6) : 0);
+ pio_fis[2] = ad->port.ifs[0].status;
+ pio_fis[3] = ad->port.ifs[0].error;
+
+ pio_fis[4] = cmd_fis[4];
+ pio_fis[5] = cmd_fis[5];
+ pio_fis[6] = cmd_fis[6];
+ pio_fis[7] = cmd_fis[7];
+ pio_fis[8] = cmd_fis[8];
+ pio_fis[9] = cmd_fis[9];
+ pio_fis[10] = cmd_fis[10];
+ pio_fis[11] = cmd_fis[11];
+ pio_fis[12] = cmd_fis[12];
+ pio_fis[13] = cmd_fis[13];
+ pio_fis[14] = 0;
+ pio_fis[15] = ad->port.ifs[0].status;
+ pio_fis[16] = len & 255;
+ pio_fis[17] = len >> 8;
+ pio_fis[18] = 0;
+ pio_fis[19] = 0;
+
+ if (pio_fis[2] & ERR_STAT) {
+ ahci_trigger_irq(ad->hba, ad, PORT_IRQ_TF_ERR);
+ }
+
+ ahci_trigger_irq(ad->hba, ad, PORT_IRQ_PIOS_FIS);
+
+ dma_memory_unmap(ad->hba->as, cmd_fis, cmd_len,
+ DMA_DIRECTION_TO_DEVICE, cmd_len);
}
static void ahci_write_fis_d2h(AHCIDevice *ad, uint8_t *cmd_fis)
@@ -629,7 +694,7 @@ static void ahci_write_fis_d2h(AHCIDevice *ad, uint8_t *cmd_fis)
}
if (d2h_fis[2] & ERR_STAT) {
- ahci_trigger_irq(ad->hba, ad, PORT_IRQ_STAT_TFES);
+ ahci_trigger_irq(ad->hba, ad, PORT_IRQ_TF_ERR);
}
ahci_trigger_irq(ad->hba, ad, PORT_IRQ_D2H_REG_FIS);
@@ -969,11 +1034,6 @@ static int handle_cmd(AHCIState *s, int port, int slot)
/* We're ready to process the command in FIS byte 2. */
ide_exec_cmd(&s->dev[port].port, cmd_fis[2]);
-
- if ((s->dev[port].port.ifs[0].status & (READY_STAT|DRQ_STAT|BUSY_STAT)) ==
- READY_STAT) {
- ahci_write_fis_d2h(&s->dev[port], cmd_fis);
- }
}
out:
@@ -991,7 +1051,7 @@ out:
}
/* DMA dev <-> ram */
-static int ahci_start_transfer(IDEDMA *dma)
+static void ahci_start_transfer(IDEDMA *dma)
{
AHCIDevice *ad = DO_UPCAST(AHCIDevice, dma, dma);
IDEState *s = &ad->port.ifs[0];
@@ -1038,11 +1098,9 @@ out:
s->end_transfer_func(s);
if (!(s->status & DRQ_STAT)) {
- /* done with DMA */
- ahci_trigger_irq(ad->hba, ad, PORT_IRQ_STAT_DSS);
+ /* done with PIO send/receive */
+ ahci_write_fis_pio(ad, le32_to_cpu(ad->cur_cmd->status));
}
-
- return 0;
}
static void ahci_start_dma(IDEDMA *dma, IDEState *s,
@@ -1104,28 +1162,11 @@ static int ahci_dma_set_unit(IDEDMA *dma, int unit)
return 0;
}
-static int ahci_dma_add_status(IDEDMA *dma, int status)
-{
- AHCIDevice *ad = DO_UPCAST(AHCIDevice, dma, dma);
- DPRINTF(ad->port_no, "set status: %x\n", status);
-
- if (status & BM_STATUS_INT) {
- ahci_trigger_irq(ad->hba, ad, PORT_IRQ_STAT_DSS);
- }
-
- return 0;
-}
-
-static int ahci_dma_set_inactive(IDEDMA *dma)
-{
- return 0;
-}
-
-static int ahci_async_cmd_done(IDEDMA *dma)
+static void ahci_cmd_done(IDEDMA *dma)
{
AHCIDevice *ad = DO_UPCAST(AHCIDevice, dma, dma);
- DPRINTF(ad->port_no, "async cmd done\n");
+ DPRINTF(ad->port_no, "cmd done\n");
/* update d2h status */
ahci_write_fis_d2h(ad, NULL);
@@ -1135,8 +1176,6 @@ static int ahci_async_cmd_done(IDEDMA *dma)
ad->check_bh = qemu_bh_new(ahci_check_cmd_bh, ad);
qemu_bh_schedule(ad->check_bh);
}
-
- return 0;
}
static void ahci_irq_set(void *opaque, int n, int level)
@@ -1147,22 +1186,14 @@ static void ahci_dma_restart_cb(void *opaque, int running, RunState state)
{
}
-static int ahci_dma_reset(IDEDMA *dma)
-{
- return 0;
-}
-
static const IDEDMAOps ahci_dma_ops = {
.start_dma = ahci_start_dma,
.start_transfer = ahci_start_transfer,
.prepare_buf = ahci_dma_prepare_buf,
.rw_buf = ahci_dma_rw_buf,
.set_unit = ahci_dma_set_unit,
- .add_status = ahci_dma_add_status,
- .set_inactive = ahci_dma_set_inactive,
- .async_cmd_done = ahci_async_cmd_done,
+ .cmd_done = ahci_cmd_done,
.restart_cb = ahci_dma_restart_cb,
- .reset = ahci_dma_reset,
};
void ahci_init(AHCIState *s, DeviceState *qdev, AddressSpace *as, int ports)
diff --git a/hw/ide/ahci.h b/hw/ide/ahci.h
index f418b30ce7..1543df7b7d 100644
--- a/hw/ide/ahci.h
+++ b/hw/ide/ahci.h
@@ -132,27 +132,6 @@
#define PORT_CMD_ICC_PARTIAL (0x2 << 28) /* Put i/f in partial state */
#define PORT_CMD_ICC_SLUMBER (0x6 << 28) /* Put i/f in slumber state */
-#define PORT_IRQ_STAT_DHRS (1 << 0) /* Device to Host Register FIS */
-#define PORT_IRQ_STAT_PSS (1 << 1) /* PIO Setup FIS */
-#define PORT_IRQ_STAT_DSS (1 << 2) /* DMA Setup FIS */
-#define PORT_IRQ_STAT_SDBS (1 << 3) /* Set Device Bits */
-#define PORT_IRQ_STAT_UFS (1 << 4) /* Unknown FIS */
-#define PORT_IRQ_STAT_DPS (1 << 5) /* Descriptor Processed */
-#define PORT_IRQ_STAT_PCS (1 << 6) /* Port Connect Change Status */
-#define PORT_IRQ_STAT_DMPS (1 << 7) /* Device Mechanical Presence
- Status */
-#define PORT_IRQ_STAT_PRCS (1 << 22) /* File Ready Status */
-#define PORT_IRQ_STAT_IPMS (1 << 23) /* Incorrect Port Multiplier
- Status */
-#define PORT_IRQ_STAT_OFS (1 << 24) /* Overflow Status */
-#define PORT_IRQ_STAT_INFS (1 << 26) /* Interface Non-Fatal Error
- Status */
-#define PORT_IRQ_STAT_IFS (1 << 27) /* Interface Fatal Error */
-#define PORT_IRQ_STAT_HBDS (1 << 28) /* Host Bus Data Error Status */
-#define PORT_IRQ_STAT_HBFS (1 << 29) /* Host Bus Fatal Error Status */
-#define PORT_IRQ_STAT_TFES (1 << 30) /* Task File Error Status */
-#define PORT_IRQ_STAT_CPDS (1U << 31) /* Code Port Detect Status */
-
/* ap->flags bits */
#define AHCI_FLAG_NO_NCQ (1 << 24)
#define AHCI_FLAG_IGN_IRQ_IF_ERR (1 << 25) /* ignore IRQ_IF_ERR */
diff --git a/hw/ide/atapi.c b/hw/ide/atapi.c
index f7d2009c00..3d92b52dbc 100644
--- a/hw/ide/atapi.c
+++ b/hw/ide/atapi.c
@@ -174,9 +174,9 @@ void ide_atapi_cmd_reply_end(IDEState *s)
#endif
if (s->packet_transfer_size <= 0) {
/* end of transfer */
- ide_transfer_stop(s);
s->status = READY_STAT | SEEK_STAT;
s->nsector = (s->nsector & ~7) | ATAPI_INT_REASON_IO | ATAPI_INT_REASON_CD;
+ ide_transfer_stop(s);
ide_set_irq(s->bus);
#ifdef DEBUG_IDE_ATAPI
printf("status=0x%x\n", s->status);
@@ -255,8 +255,7 @@ static void ide_atapi_cmd_reply(IDEState *s, int size, int max_size)
if (s->atapi_dma) {
bdrv_acct_start(s->bs, &s->acct, size, BDRV_ACCT_READ);
s->status = READY_STAT | SEEK_STAT | DRQ_STAT;
- s->bus->dma->ops->start_dma(s->bus->dma, s,
- ide_atapi_cmd_read_dma_cb);
+ ide_start_dma(s, ide_atapi_cmd_read_dma_cb);
} else {
s->status = READY_STAT | SEEK_STAT;
ide_atapi_cmd_reply_end(s);
@@ -356,8 +355,7 @@ static void ide_atapi_cmd_read_dma_cb(void *opaque, int ret)
eot:
bdrv_acct_done(s->bs, &s->acct);
- s->bus->dma->ops->add_status(s->bus->dma, BM_STATUS_INT);
- ide_set_inactive(s);
+ ide_set_inactive(s, false);
}
/* start a CD-CDROM read command with DMA */
@@ -375,8 +373,7 @@ static void ide_atapi_cmd_read_dma(IDEState *s, int lba, int nb_sectors,
/* XXX: check if BUSY_STAT should be set */
s->status = READY_STAT | SEEK_STAT | DRQ_STAT | BUSY_STAT;
- s->bus->dma->ops->start_dma(s->bus->dma, s,
- ide_atapi_cmd_read_dma_cb);
+ ide_start_dma(s, ide_atapi_cmd_read_dma_cb);
}
static void ide_atapi_cmd_read(IDEState *s, int lba, int nb_sectors,
diff --git a/hw/ide/cmd646.c b/hw/ide/cmd646.c
index 1295ed0f58..91048f202f 100644
--- a/hw/ide/cmd646.c
+++ b/hw/ide/cmd646.c
@@ -33,6 +33,13 @@
#include <hw/ide/pci.h>
/* CMD646 specific */
+#define CFR 0x50
+#define CFR_INTR_CH0 0x04
+#define CNTRL 0x51
+#define CNTRL_EN_CH0 0x04
+#define CNTRL_EN_CH1 0x08
+#define ARTTIM23 0x57
+#define ARTTIM23_INTR_CH1 0x10
#define MRDMODE 0x71
#define MRDMODE_INTR_CH0 0x04
#define MRDMODE_INTR_CH1 0x08
@@ -41,7 +48,7 @@
#define UDIDETCR0 0x73
#define UDIDETCR1 0x7B
-static void cmd646_update_irq(PCIIDEState *d);
+static void cmd646_update_irq(PCIDevice *pd);
static uint64_t cmd646_cmd_read(void *opaque, hwaddr addr,
unsigned size)
@@ -123,6 +130,38 @@ static void setup_cmd646_bar(PCIIDEState *d, int bus_num)
"cmd646-data", 8);
}
+static void cmd646_update_dma_interrupts(PCIDevice *pd)
+{
+ /* Sync DMA interrupt status from UDMA interrupt status */
+ if (pd->config[MRDMODE] & MRDMODE_INTR_CH0) {
+ pd->config[CFR] |= CFR_INTR_CH0;
+ } else {
+ pd->config[CFR] &= ~CFR_INTR_CH0;
+ }
+
+ if (pd->config[MRDMODE] & MRDMODE_INTR_CH1) {
+ pd->config[ARTTIM23] |= ARTTIM23_INTR_CH1;
+ } else {
+ pd->config[ARTTIM23] &= ~ARTTIM23_INTR_CH1;
+ }
+}
+
+static void cmd646_update_udma_interrupts(PCIDevice *pd)
+{
+ /* Sync UDMA interrupt status from DMA interrupt status */
+ if (pd->config[CFR] & CFR_INTR_CH0) {
+ pd->config[MRDMODE] |= MRDMODE_INTR_CH0;
+ } else {
+ pd->config[MRDMODE] &= ~MRDMODE_INTR_CH0;
+ }
+
+ if (pd->config[ARTTIM23] & ARTTIM23_INTR_CH1) {
+ pd->config[MRDMODE] |= MRDMODE_INTR_CH1;
+ } else {
+ pd->config[MRDMODE] &= ~MRDMODE_INTR_CH1;
+ }
+}
+
static uint64_t bmdma_read(void *opaque, hwaddr addr,
unsigned size)
{
@@ -181,7 +220,8 @@ static void bmdma_write(void *opaque, hwaddr addr,
case 1:
pci_dev->config[MRDMODE] =
(pci_dev->config[MRDMODE] & ~0x30) | (val & 0x30);
- cmd646_update_irq(bm->pci_dev);
+ cmd646_update_dma_interrupts(pci_dev);
+ cmd646_update_irq(pci_dev);
break;
case 2:
bm->status = (val & 0x60) | (bm->status & 1) | (bm->status & ~val & 0x06);
@@ -219,11 +259,8 @@ static void bmdma_setup_bar(PCIIDEState *d)
}
}
-/* XXX: call it also when the MRDMODE is changed from the PCI config
- registers */
-static void cmd646_update_irq(PCIIDEState *d)
+static void cmd646_update_irq(PCIDevice *pd)
{
- PCIDevice *pd = PCI_DEVICE(d);
int pci_level;
pci_level = ((pd->config[MRDMODE] & MRDMODE_INTR_CH0) &&
@@ -246,7 +283,8 @@ static void cmd646_set_irq(void *opaque, int channel, int level)
} else {
pd->config[MRDMODE] &= ~irq_mask;
}
- cmd646_update_irq(d);
+ cmd646_update_dma_interrupts(pd);
+ cmd646_update_irq(pd);
}
static void cmd646_reset(void *opaque)
@@ -259,6 +297,34 @@ static void cmd646_reset(void *opaque)
}
}
+static uint32_t cmd646_pci_config_read(PCIDevice *d,
+ uint32_t address, int len)
+{
+ return pci_default_read_config(d, address, len);
+}
+
+static void cmd646_pci_config_write(PCIDevice *d, uint32_t addr, uint32_t val,
+ int l)
+{
+ uint32_t i;
+
+ pci_default_write_config(d, addr, val, l);
+
+ for (i = addr; i < addr + l; i++) {
+ switch (i) {
+ case CFR:
+ case ARTTIM23:
+ cmd646_update_udma_interrupts(d);
+ break;
+ case MRDMODE:
+ cmd646_update_dma_interrupts(d);
+ break;
+ }
+ }
+
+ cmd646_update_irq(d);
+}
+
/* CMD646 PCI IDE controller */
static int pci_cmd646_ide_initfn(PCIDevice *dev)
{
@@ -269,12 +335,20 @@ static int pci_cmd646_ide_initfn(PCIDevice *dev)
pci_conf[PCI_CLASS_PROG] = 0x8f;
- pci_conf[0x51] = 0x04; // enable IDE0
+ pci_conf[CNTRL] = CNTRL_EN_CH0; // enable IDE0
if (d->secondary) {
/* XXX: if not enabled, really disable the seconday IDE controller */
- pci_conf[0x51] |= 0x08; /* enable IDE1 */
+ pci_conf[CNTRL] |= CNTRL_EN_CH1; /* enable IDE1 */
}
+ /* Set write-to-clear interrupt bits */
+ dev->wmask[CFR] = 0x0;
+ dev->w1cmask[CFR] = CFR_INTR_CH0;
+ dev->wmask[ARTTIM23] = 0x0;
+ dev->w1cmask[ARTTIM23] = ARTTIM23_INTR_CH1;
+ dev->wmask[MRDMODE] = 0x0;
+ dev->w1cmask[MRDMODE] = MRDMODE_INTR_CH0 | MRDMODE_INTR_CH1;
+
setup_cmd646_bar(d, 0);
setup_cmd646_bar(d, 1);
pci_register_bar(dev, 0, PCI_BASE_ADDRESS_SPACE_IO, &d->cmd646_bar[0].data);
@@ -342,6 +416,8 @@ static void cmd646_ide_class_init(ObjectClass *klass, void *data)
k->device_id = PCI_DEVICE_ID_CMD_646;
k->revision = 0x07;
k->class_id = PCI_CLASS_STORAGE_IDE;
+ k->config_read = cmd646_pci_config_read;
+ k->config_write = cmd646_pci_config_write;
dc->props = cmd646_ide_properties;
}
diff --git a/hw/ide/core.c b/hw/ide/core.c
index db191a6c3e..b48127f921 100644
--- a/hw/ide/core.c
+++ b/hw/ide/core.c
@@ -420,6 +420,7 @@ BlockDriverAIOCB *ide_issue_trim(BlockDriverState *bs,
static inline void ide_abort_command(IDEState *s)
{
+ ide_transfer_stop(s);
s->status = READY_STAT | ERR_STAT;
s->error = ABRT_ERR;
}
@@ -434,7 +435,16 @@ void ide_transfer_start(IDEState *s, uint8_t *buf, int size,
if (!(s->status & ERR_STAT)) {
s->status |= DRQ_STAT;
}
- s->bus->dma->ops->start_transfer(s->bus->dma);
+ if (s->bus->dma->ops->start_transfer) {
+ s->bus->dma->ops->start_transfer(s->bus->dma);
+ }
+}
+
+static void ide_cmd_done(IDEState *s)
+{
+ if (s->bus->dma->ops->cmd_done) {
+ s->bus->dma->ops->cmd_done(s->bus->dma);
+ }
}
void ide_transfer_stop(IDEState *s)
@@ -443,6 +453,7 @@ void ide_transfer_stop(IDEState *s)
s->data_ptr = s->io_buffer;
s->data_end = s->io_buffer;
s->status &= ~DRQ_STAT;
+ ide_cmd_done(s);
}
int64_t ide_get_sector(IDEState *s)
@@ -521,8 +532,8 @@ static void ide_sector_read_cb(void *opaque, int ret)
bdrv_acct_done(s->bs, &s->acct);
if (ret != 0) {
- if (ide_handle_rw_error(s, -ret, BM_STATUS_PIO_RETRY |
- BM_STATUS_RETRY_READ)) {
+ if (ide_handle_rw_error(s, -ret, IDE_RETRY_PIO |
+ IDE_RETRY_READ)) {
return;
}
}
@@ -585,39 +596,32 @@ static void dma_buf_commit(IDEState *s)
qemu_sglist_destroy(&s->sg);
}
-static void ide_async_cmd_done(IDEState *s)
-{
- if (s->bus->dma->ops->async_cmd_done) {
- s->bus->dma->ops->async_cmd_done(s->bus->dma);
- }
-}
-
-void ide_set_inactive(IDEState *s)
+void ide_set_inactive(IDEState *s, bool more)
{
s->bus->dma->aiocb = NULL;
- s->bus->dma->ops->set_inactive(s->bus->dma);
- ide_async_cmd_done(s);
+ if (s->bus->dma->ops->set_inactive) {
+ s->bus->dma->ops->set_inactive(s->bus->dma, more);
+ }
+ ide_cmd_done(s);
}
void ide_dma_error(IDEState *s)
{
- ide_transfer_stop(s);
- s->error = ABRT_ERR;
- s->status = READY_STAT | ERR_STAT;
- ide_set_inactive(s);
+ ide_abort_command(s);
+ ide_set_inactive(s, false);
ide_set_irq(s->bus);
}
static int ide_handle_rw_error(IDEState *s, int error, int op)
{
- bool is_read = (op & BM_STATUS_RETRY_READ) != 0;
+ bool is_read = (op & IDE_RETRY_READ) != 0;
BlockErrorAction action = bdrv_get_error_action(s->bs, is_read, error);
if (action == BLOCK_ERROR_ACTION_STOP) {
s->bus->dma->ops->set_unit(s->bus->dma, s->unit);
s->bus->error_status = op;
} else if (action == BLOCK_ERROR_ACTION_REPORT) {
- if (op & BM_STATUS_DMA_RETRY) {
+ if (op & IDE_RETRY_DMA) {
dma_buf_commit(s);
ide_dma_error(s);
} else {
@@ -636,12 +640,12 @@ void ide_dma_cb(void *opaque, int ret)
bool stay_active = false;
if (ret < 0) {
- int op = BM_STATUS_DMA_RETRY;
+ int op = IDE_RETRY_DMA;
if (s->dma_cmd == IDE_DMA_READ)
- op |= BM_STATUS_RETRY_READ;
+ op |= IDE_RETRY_READ;
else if (s->dma_cmd == IDE_DMA_TRIM)
- op |= BM_STATUS_RETRY_TRIM;
+ op |= IDE_RETRY_TRIM;
if (ide_handle_rw_error(s, -ret, op)) {
return;
@@ -688,7 +692,8 @@ void ide_dma_cb(void *opaque, int ret)
sector_num, n, s->dma_cmd);
#endif
- if (!ide_sect_range_ok(s, sector_num, n)) {
+ if ((s->dma_cmd == IDE_DMA_READ || s->dma_cmd == IDE_DMA_WRITE) &&
+ !ide_sect_range_ok(s, sector_num, n)) {
dma_buf_commit(s);
ide_dma_error(s);
return;
@@ -715,10 +720,7 @@ eot:
if (s->dma_cmd == IDE_DMA_READ || s->dma_cmd == IDE_DMA_WRITE) {
bdrv_acct_done(s->bs, &s->acct);
}
- ide_set_inactive(s);
- if (stay_active) {
- s->bus->dma->ops->add_status(s->bus->dma, BM_STATUS_DMAING);
- }
+ ide_set_inactive(s, stay_active);
}
static void ide_sector_start_dma(IDEState *s, enum ide_dma_cmd dma_cmd)
@@ -741,7 +743,14 @@ static void ide_sector_start_dma(IDEState *s, enum ide_dma_cmd dma_cmd)
break;
}
- s->bus->dma->ops->start_dma(s->bus->dma, s, ide_dma_cb);
+ ide_start_dma(s, ide_dma_cb);
+}
+
+void ide_start_dma(IDEState *s, BlockDriverCompletionFunc *cb)
+{
+ if (s->bus->dma->ops->start_dma) {
+ s->bus->dma->ops->start_dma(s->bus->dma, s, cb);
+ }
}
static void ide_sector_write_timer_cb(void *opaque)
@@ -761,7 +770,7 @@ static void ide_sector_write_cb(void *opaque, int ret)
s->status &= ~BUSY_STAT;
if (ret != 0) {
- if (ide_handle_rw_error(s, -ret, BM_STATUS_PIO_RETRY)) {
+ if (ide_handle_rw_error(s, -ret, IDE_RETRY_PIO)) {
return;
}
}
@@ -831,16 +840,20 @@ static void ide_flush_cb(void *opaque, int ret)
{
IDEState *s = opaque;
+ s->pio_aiocb = NULL;
+
if (ret < 0) {
/* XXX: What sector number to set here? */
- if (ide_handle_rw_error(s, -ret, BM_STATUS_RETRY_FLUSH)) {
+ if (ide_handle_rw_error(s, -ret, IDE_RETRY_FLUSH)) {
return;
}
}
- bdrv_acct_done(s->bs, &s->acct);
+ if (s->bs) {
+ bdrv_acct_done(s->bs, &s->acct);
+ }
s->status = READY_STAT | SEEK_STAT;
- ide_async_cmd_done(s);
+ ide_cmd_done(s);
ide_set_irq(s->bus);
}
@@ -853,7 +866,7 @@ void ide_flush_cache(IDEState *s)
s->status |= BUSY_STAT;
bdrv_acct_start(s->bs, &s->acct, 0, BDRV_ACCT_FLUSH);
- bdrv_aio_flush(s->bs, ide_flush_cb, s);
+ s->pio_aiocb = bdrv_aio_flush(s->bs, ide_flush_cb, s);
}
static void ide_cfata_metadata_inquiry(IDEState *s)
@@ -1764,6 +1777,7 @@ void ide_exec_cmd(IDEBus *bus, uint32_t val)
s->status |= SEEK_STAT;
}
+ ide_cmd_done(s);
ide_set_irq(s->bus);
}
}
@@ -2086,7 +2100,9 @@ void ide_bus_reset(IDEBus *bus)
}
/* reset dma provider too */
- bus->dma->ops->reset(bus->dma);
+ if (bus->dma->ops->reset) {
+ bus->dma->ops->reset(bus->dma);
+ }
}
static bool ide_cd_is_tray_open(void *opaque)
@@ -2196,16 +2212,6 @@ static void ide_init1(IDEBus *bus, int unit)
ide_sector_write_timer_cb, s);
}
-static void ide_nop_start(IDEDMA *dma, IDEState *s,
- BlockDriverCompletionFunc *cb)
-{
-}
-
-static int ide_nop(IDEDMA *dma)
-{
- return 0;
-}
-
static int ide_nop_int(IDEDMA *dma, int x)
{
return 0;
@@ -2216,15 +2222,10 @@ static void ide_nop_restart(void *opaque, int x, RunState y)
}
static const IDEDMAOps ide_dma_nop_ops = {
- .start_dma = ide_nop_start,
- .start_transfer = ide_nop,
.prepare_buf = ide_nop_int,
.rw_buf = ide_nop_int,
.set_unit = ide_nop_int,
- .add_status = ide_nop_int,
- .set_inactive = ide_nop,
.restart_cb = ide_nop_restart,
- .reset = ide_nop,
};
static IDEDMA ide_dma_nop = {
@@ -2341,7 +2342,7 @@ static bool ide_drive_pio_state_needed(void *opaque)
IDEState *s = opaque;
return ((s->status & DRQ_STAT) != 0)
- || (s->bus->error_status & BM_STATUS_PIO_RETRY);
+ || (s->bus->error_status & IDE_RETRY_PIO);
}
static bool ide_tray_state_needed(void *opaque)
diff --git a/hw/ide/internal.h b/hw/ide/internal.h
index 0567a522f5..5c19f79437 100644
--- a/hw/ide/internal.h
+++ b/hw/ide/internal.h
@@ -320,8 +320,9 @@ typedef enum { IDE_HD, IDE_CD, IDE_CFATA } IDEDriveKind;
typedef void EndTransferFunc(IDEState *);
typedef void DMAStartFunc(IDEDMA *, IDEState *, BlockDriverCompletionFunc *);
-typedef int DMAFunc(IDEDMA *);
+typedef void DMAVoidFunc(IDEDMA *);
typedef int DMAIntFunc(IDEDMA *, int);
+typedef void DMAStopFunc(IDEDMA *, bool);
typedef void DMARestartFunc(void *, int, RunState);
struct unreported_events {
@@ -427,15 +428,14 @@ struct IDEState {
struct IDEDMAOps {
DMAStartFunc *start_dma;
- DMAFunc *start_transfer;
+ DMAVoidFunc *start_transfer;
DMAIntFunc *prepare_buf;
DMAIntFunc *rw_buf;
DMAIntFunc *set_unit;
- DMAIntFunc *add_status;
- DMAFunc *set_inactive;
- DMAFunc *async_cmd_done;
+ DMAStopFunc *set_inactive;
+ DMAVoidFunc *cmd_done;
DMARestartFunc *restart_cb;
- DMAFunc *reset;
+ DMAVoidFunc *reset;
};
struct IDEDMA {
@@ -484,23 +484,12 @@ struct IDEDevice {
uint64_t wwn;
};
-#define BM_STATUS_DMAING 0x01
-#define BM_STATUS_ERROR 0x02
-#define BM_STATUS_INT 0x04
-
-/* FIXME These are not status register bits */
-#define BM_STATUS_DMA_RETRY 0x08
-#define BM_STATUS_PIO_RETRY 0x10
-#define BM_STATUS_RETRY_READ 0x20
-#define BM_STATUS_RETRY_FLUSH 0x40
-#define BM_STATUS_RETRY_TRIM 0x80
-
-#define BM_MIGRATION_COMPAT_STATUS_BITS \
- (BM_STATUS_DMA_RETRY | BM_STATUS_PIO_RETRY | \
- BM_STATUS_RETRY_READ | BM_STATUS_RETRY_FLUSH)
-
-#define BM_CMD_START 0x01
-#define BM_CMD_READ 0x08
+/* These are used for the error_status field of IDEBus */
+#define IDE_RETRY_DMA 0x08
+#define IDE_RETRY_PIO 0x10
+#define IDE_RETRY_READ 0x20
+#define IDE_RETRY_FLUSH 0x40
+#define IDE_RETRY_TRIM 0x80
static inline IDEState *idebus_active_if(IDEBus *bus)
{
@@ -532,6 +521,7 @@ void ide_bus_reset(IDEBus *bus);
int64_t ide_get_sector(IDEState *s);
void ide_set_sector(IDEState *s, int64_t sector_num);
+void ide_start_dma(IDEState *s, BlockDriverCompletionFunc *cb);
void ide_dma_error(IDEState *s);
void ide_atapi_cmd_ok(IDEState *s);
@@ -564,7 +554,7 @@ void ide_flush_cache(IDEState *s);
void ide_transfer_start(IDEState *s, uint8_t *buf, int size,
EndTransferFunc *end_transfer_func);
void ide_transfer_stop(IDEState *s);
-void ide_set_inactive(IDEState *s);
+void ide_set_inactive(IDEState *s, bool more);
BlockDriverAIOCB *ide_issue_trim(BlockDriverState *bs,
int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
BlockDriverCompletionFunc *cb, void *opaque);
diff --git a/hw/ide/macio.c b/hw/ide/macio.c
index c14a1ddddb..b0c0d400d9 100644
--- a/hw/ide/macio.c
+++ b/hw/ide/macio.c
@@ -545,11 +545,6 @@ static void macio_ide_reset(DeviceState *dev)
ide_bus_reset(&d->bus);
}
-static int ide_nop(IDEDMA *dma)
-{
- return 0;
-}
-
static int ide_nop_int(IDEDMA *dma, int x)
{
return 0;
@@ -571,14 +566,10 @@ static void ide_dbdma_start(IDEDMA *dma, IDEState *s,
static const IDEDMAOps dbdma_ops = {
.start_dma = ide_dbdma_start,
- .start_transfer = ide_nop,
.prepare_buf = ide_nop_int,
.rw_buf = ide_nop_int,
.set_unit = ide_nop_int,
- .add_status = ide_nop_int,
- .set_inactive = ide_nop,
.restart_cb = ide_nop_restart,
- .reset = ide_nop,
};
static void macio_ide_realizefn(DeviceState *dev, Error **errp)
diff --git a/hw/ide/pci.c b/hw/ide/pci.c
index 6257a21ed2..2397f355cc 100644
--- a/hw/ide/pci.c
+++ b/hw/ide/pci.c
@@ -33,6 +33,10 @@
#define BMDMA_PAGE_SIZE 4096
+#define BM_MIGRATION_COMPAT_STATUS_BITS \
+ (IDE_RETRY_DMA | IDE_RETRY_PIO | \
+ IDE_RETRY_READ | IDE_RETRY_FLUSH)
+
static void bmdma_start_dma(IDEDMA *dma, IDEState *s,
BlockDriverCompletionFunc *dma_cb)
{
@@ -152,23 +156,17 @@ static int bmdma_set_unit(IDEDMA *dma, int unit)
return 0;
}
-static int bmdma_add_status(IDEDMA *dma, int status)
-{
- BMDMAState *bm = DO_UPCAST(BMDMAState, dma, dma);
- bm->status |= status;
-
- return 0;
-}
-
-static int bmdma_set_inactive(IDEDMA *dma)
+static void bmdma_set_inactive(IDEDMA *dma, bool more)
{
BMDMAState *bm = DO_UPCAST(BMDMAState, dma, dma);
- bm->status &= ~BM_STATUS_DMAING;
bm->dma_cb = NULL;
bm->unit = -1;
-
- return 0;
+ if (more) {
+ bm->status |= BM_STATUS_DMAING;
+ } else {
+ bm->status &= ~BM_STATUS_DMAING;
+ }
}
static void bmdma_restart_dma(BMDMAState *bm, enum ide_dma_cmd dma_cmd)
@@ -200,7 +198,7 @@ static void bmdma_restart_bh(void *opaque)
return;
}
- is_read = (bus->error_status & BM_STATUS_RETRY_READ) != 0;
+ is_read = (bus->error_status & IDE_RETRY_READ) != 0;
/* The error status must be cleared before resubmitting the request: The
* request may fail again, and this case can only be distinguished if the
@@ -208,19 +206,19 @@ static void bmdma_restart_bh(void *opaque)
error_status = bus->error_status;
bus->error_status = 0;
- if (error_status & BM_STATUS_DMA_RETRY) {
- if (error_status & BM_STATUS_RETRY_TRIM) {
+ if (error_status & IDE_RETRY_DMA) {
+ if (error_status & IDE_RETRY_TRIM) {
bmdma_restart_dma(bm, IDE_DMA_TRIM);
} else {
bmdma_restart_dma(bm, is_read ? IDE_DMA_READ : IDE_DMA_WRITE);
}
- } else if (error_status & BM_STATUS_PIO_RETRY) {
+ } else if (error_status & IDE_RETRY_PIO) {
if (is_read) {
ide_sector_read(bmdma_active_if(bm));
} else {
ide_sector_write(bmdma_active_if(bm));
}
- } else if (error_status & BM_STATUS_RETRY_FLUSH) {
+ } else if (error_status & IDE_RETRY_FLUSH) {
ide_flush_cache(bmdma_active_if(bm));
}
}
@@ -243,11 +241,11 @@ static void bmdma_cancel(BMDMAState *bm)
{
if (bm->status & BM_STATUS_DMAING) {
/* cancel DMA request */
- bmdma_set_inactive(&bm->dma);
+ bmdma_set_inactive(&bm->dma, false);
}
}
-static int bmdma_reset(IDEDMA *dma)
+static void bmdma_reset(IDEDMA *dma)
{
BMDMAState *bm = DO_UPCAST(BMDMAState, dma, dma);
@@ -264,13 +262,6 @@ static int bmdma_reset(IDEDMA *dma)
bm->cur_prd_len = 0;
bm->sector_num = 0;
bm->nsector = 0;
-
- return 0;
-}
-
-static int bmdma_start_transfer(IDEDMA *dma)
-{
- return 0;
}
static void bmdma_irq(void *opaque, int n, int level)
@@ -504,11 +495,9 @@ void pci_ide_create_devs(PCIDevice *dev, DriveInfo **hd_table)
static const struct IDEDMAOps bmdma_ops = {
.start_dma = bmdma_start_dma,
- .start_transfer = bmdma_start_transfer,
.prepare_buf = bmdma_prepare_buf,
.rw_buf = bmdma_rw_buf,
.set_unit = bmdma_set_unit,
- .add_status = bmdma_add_status,
.set_inactive = bmdma_set_inactive,
.restart_cb = bmdma_restart_cb,
.reset = bmdma_reset,
diff --git a/hw/ide/pci.h b/hw/ide/pci.h
index 2428275c8d..517711f913 100644
--- a/hw/ide/pci.h
+++ b/hw/ide/pci.h
@@ -3,6 +3,13 @@
#include <hw/ide/internal.h>
+#define BM_STATUS_DMAING 0x01
+#define BM_STATUS_ERROR 0x02
+#define BM_STATUS_INT 0x04
+
+#define BM_CMD_START 0x01
+#define BM_CMD_READ 0x08
+
typedef struct BMDMAState {
IDEDMA dma;
uint8_t cmd;
diff --git a/hw/intc/apic.c b/hw/intc/apic.c
index ef19e5515c..03ff9e94f2 100644
--- a/hw/intc/apic.c
+++ b/hw/intc/apic.c
@@ -698,7 +698,7 @@ static uint32_t apic_mem_readl(void *opaque, hwaddr addr)
val = s->log_dest << 24;
break;
case 0x0e:
- val = s->dest_mode << 28;
+ val = (s->dest_mode << 28) | 0xfffffff;
break;
case 0x0f:
val = s->spurious_vec;
diff --git a/hw/intc/i8259.c b/hw/intc/i8259.c
index d0b0c52b97..a563b82c4e 100644
--- a/hw/intc/i8259.c
+++ b/hw/intc/i8259.c
@@ -472,7 +472,7 @@ qemu_irq *i8259_init(ISABus *bus, qemu_irq parent_irq)
ISADevice *isadev;
int i;
- irq_set = g_malloc(ISA_NUM_IRQS * sizeof(qemu_irq));
+ irq_set = g_new0(qemu_irq, ISA_NUM_IRQS);
isadev = i8259_init_chip(TYPE_I8259, bus, true);
dev = DEVICE(isadev);
diff --git a/hw/intc/openpic.c b/hw/intc/openpic.c
index 028529e13d..7d1f3b9497 100644
--- a/hw/intc/openpic.c
+++ b/hw/intc/openpic.c
@@ -1627,7 +1627,7 @@ static void openpic_realize(DeviceState *dev, Error **errp)
}
for (i = 0; i < opp->nb_cpus; i++) {
- opp->dst[i].irqs = g_new(qemu_irq, OPENPIC_OUTPUT_NB);
+ opp->dst[i].irqs = g_new0(qemu_irq, OPENPIC_OUTPUT_NB);
for (j = 0; j < OPENPIC_OUTPUT_NB; j++) {
sysbus_init_irq(d, &opp->dst[i].irqs[j]);
}
diff --git a/hw/isa/isa-bus.c b/hw/isa/isa-bus.c
index b28981bfde..cc85e538b1 100644
--- a/hw/isa/isa-bus.c
+++ b/hw/isa/isa-bus.c
@@ -50,7 +50,7 @@ ISABus *isa_bus_new(DeviceState *dev, MemoryRegion *address_space_io)
fprintf(stderr, "Can't create a second ISA bus\n");
return NULL;
}
- if (NULL == dev) {
+ if (!dev) {
dev = qdev_create(NULL, "isabus-bridge");
qdev_init_nofail(dev);
}
diff --git a/hw/isa/lpc_ich9.c b/hw/isa/lpc_ich9.c
index b846d81990..177023bcaf 100644
--- a/hw/isa/lpc_ich9.c
+++ b/hw/isa/lpc_ich9.c
@@ -7,7 +7,7 @@
* VA Linux Systems Japan K.K.
* Copyright (C) 2012 Jason Baron <jbaron@redhat.com>
*
- * This is based on piix_pci.c, but heavily modified.
+ * This is based on piix.c, but heavily modified.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
diff --git a/hw/mem/pc-dimm.c b/hw/mem/pc-dimm.c
index 08f49ed53b..5bfc5b7483 100644
--- a/hw/mem/pc-dimm.c
+++ b/hw/mem/pc-dimm.c
@@ -252,6 +252,12 @@ static void pc_dimm_realize(DeviceState *dev, Error **errp)
error_setg(errp, "'" PC_DIMM_MEMDEV_PROP "' property is not set");
return;
}
+ if (dimm->node >= nb_numa_nodes) {
+ error_setg(errp, "'DIMM property " PC_DIMM_NODE_PROP " has value %"
+ PRIu32 "' which exceeds the number of numa nodes: %d",
+ dimm->node, nb_numa_nodes);
+ return;
+ }
}
static MemoryRegion *pc_dimm_get_memory_region(PCDIMMDevice *dimm)
diff --git a/hw/misc/imx_ccm.c b/hw/misc/imx_ccm.c
index 750b9061db..0920288634 100644
--- a/hw/misc/imx_ccm.c
+++ b/hw/misc/imx_ccm.c
@@ -67,6 +67,7 @@ static const VMStateDescription vmstate_imx_ccm = {
VMSTATE_UINT32(pmcr0, IMXCCMState),
VMSTATE_UINT32(pmcr1, IMXCCMState),
VMSTATE_UINT32(pll_refclk_freq, IMXCCMState),
+ VMSTATE_END_OF_LIST()
},
.post_load = imx_ccm_post_load,
};
diff --git a/hw/misc/ivshmem.c b/hw/misc/ivshmem.c
index 156edd2f17..bd9d7182af 100644
--- a/hw/misc/ivshmem.c
+++ b/hw/misc/ivshmem.c
@@ -324,7 +324,11 @@ static int check_shm_size(IVShmemState *s, int fd) {
struct stat buf;
- fstat(fd, &buf);
+ if (fstat(fd, &buf) < 0) {
+ fprintf(stderr, "ivshmem: exiting: fstat on fd %d failed: %s\n",
+ fd, strerror(errno));
+ return -1;
+ }
if (s->ivshmem_size > buf.st_size) {
fprintf(stderr,
@@ -479,8 +483,8 @@ static void ivshmem_read(void *opaque, const uint8_t * buf, int flags)
"ivshmem.bar2", s->ivshmem_size, map_ptr);
vmstate_register_ram(&s->ivshmem, DEVICE(s));
- IVSHMEM_DPRINTF("guest h/w addr = %" PRIu64 ", size = %" PRIu64 "\n",
- s->ivshmem_offset, s->ivshmem_size);
+ IVSHMEM_DPRINTF("guest h/w addr = %p, size = %" PRIu64 "\n",
+ map_ptr, s->ivshmem_size);
memory_region_add_subregion(&s->bar, 0, &s->ivshmem);
diff --git a/hw/misc/vfio.c b/hw/misc/vfio.c
index 813c2cc5c5..0617b70ea6 100644
--- a/hw/misc/vfio.c
+++ b/hw/misc/vfio.c
@@ -120,11 +120,19 @@ typedef struct VFIOINTx {
} VFIOINTx;
typedef struct VFIOMSIVector {
- EventNotifier interrupt; /* eventfd triggered on interrupt */
- EventNotifier kvm_interrupt; /* eventfd triggered for KVM irqfd bypass */
+ /*
+ * Two interrupt paths are configured per vector. The first, is only used
+ * for interrupts injected via QEMU. This is typically the non-accel path,
+ * but may also be used when we want QEMU to handle masking and pending
+ * bits. The KVM path bypasses QEMU and is therefore higher performance,
+ * but requires masking at the device. virq is used to track the MSI route
+ * through KVM, thus kvm_interrupt is only available when virq is set to a
+ * valid (>= 0) value.
+ */
+ EventNotifier interrupt;
+ EventNotifier kvm_interrupt;
struct VFIODevice *vdev; /* back pointer to device */
- MSIMessage msg; /* cache the MSI message so we know when it changes */
- int virq; /* KVM irqchip route for QEMU bypass */
+ int virq;
bool use;
} VFIOMSIVector;
@@ -681,13 +689,24 @@ static int vfio_enable_vectors(VFIODevice *vdev, bool msix)
fds = (int32_t *)&irq_set->data;
for (i = 0; i < vdev->nr_vectors; i++) {
- if (!vdev->msi_vectors[i].use) {
- fds[i] = -1;
- } else if (vdev->msi_vectors[i].virq >= 0) {
- fds[i] = event_notifier_get_fd(&vdev->msi_vectors[i].kvm_interrupt);
- } else {
- fds[i] = event_notifier_get_fd(&vdev->msi_vectors[i].interrupt);
+ int fd = -1;
+
+ /*
+ * MSI vs MSI-X - The guest has direct access to MSI mask and pending
+ * bits, therefore we always use the KVM signaling path when setup.
+ * MSI-X mask and pending bits are emulated, so we want to use the
+ * KVM signaling path only when configured and unmasked.
+ */
+ if (vdev->msi_vectors[i].use) {
+ if (vdev->msi_vectors[i].virq < 0 ||
+ (msix && msix_is_masked(&vdev->pdev, i))) {
+ fd = event_notifier_get_fd(&vdev->msi_vectors[i].interrupt);
+ } else {
+ fd = event_notifier_get_fd(&vdev->msi_vectors[i].kvm_interrupt);
+ }
}
+
+ fds[i] = fd;
}
ret = ioctl(vdev->fd, VFIO_DEVICE_SET_IRQS, irq_set);
@@ -724,7 +743,6 @@ static void vfio_add_kvm_msi_virq(VFIOMSIVector *vector, MSIMessage *msg,
return;
}
- vector->msg = *msg;
vector->virq = virq;
}
@@ -740,7 +758,6 @@ static void vfio_remove_kvm_msi_virq(VFIOMSIVector *vector)
static void vfio_update_kvm_msi_virq(VFIOMSIVector *vector, MSIMessage msg)
{
kvm_irqchip_update_msi_route(kvm_state, vector->virq, msg);
- vector->msg = msg;
}
static int vfio_msix_vector_do_use(PCIDevice *pdev, unsigned int nr,
@@ -919,6 +936,7 @@ retry:
for (i = 0; i < vdev->nr_vectors; i++) {
VFIOMSIVector *vector = &vdev->msi_vectors[i];
+ MSIMessage msg = msi_get_message(&vdev->pdev, i);
vector->vdev = vdev;
vector->virq = -1;
@@ -931,13 +949,11 @@ retry:
qemu_set_fd_handler(event_notifier_get_fd(&vector->interrupt),
vfio_msi_interrupt, NULL, vector);
- vector->msg = msi_get_message(&vdev->pdev, i);
-
/*
* Attempt to enable route through KVM irqchip,
* default to userspace handling if unavailable.
*/
- vfio_add_kvm_msi_virq(vector, &vector->msg, false);
+ vfio_add_kvm_msi_virq(vector, &msg, false);
}
/* Set interrupt type prior to possible interrupts */
diff --git a/hw/net/e1000.c b/hw/net/e1000.c
index 21c38fa520..272df00f4a 100644
--- a/hw/net/e1000.c
+++ b/hw/net/e1000.c
@@ -186,21 +186,31 @@ e1000_link_up(E1000State *s)
s->phy_reg[PHY_STATUS] |= MII_SR_LINK_STATUS;
}
+static bool
+have_autoneg(E1000State *s)
+{
+ return (s->compat_flags & E1000_FLAG_AUTONEG) &&
+ (s->phy_reg[PHY_CTRL] & MII_CR_AUTO_NEG_EN);
+}
+
static void
set_phy_ctrl(E1000State *s, int index, uint16_t val)
{
+ /* bits 0-5 reserved; MII_CR_[RESTART_AUTO_NEG,RESET] are self clearing */
+ s->phy_reg[PHY_CTRL] = val & ~(0x3f |
+ MII_CR_RESET |
+ MII_CR_RESTART_AUTO_NEG);
+
/*
* QEMU 1.3 does not support link auto-negotiation emulation, so if we
* migrate during auto negotiation, after migration the link will be
* down.
*/
- if (!(s->compat_flags & E1000_FLAG_AUTONEG)) {
- return;
- }
- if ((val & MII_CR_AUTO_NEG_EN) && (val & MII_CR_RESTART_AUTO_NEG)) {
+ if (have_autoneg(s) && (val & MII_CR_RESTART_AUTO_NEG)) {
e1000_link_down(s);
DBGOUT(PHY, "Start link auto negotiation\n");
- timer_mod(s->autoneg_timer, qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) + 500);
+ timer_mod(s->autoneg_timer,
+ qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) + 500);
}
}
@@ -223,13 +233,30 @@ static const char phy_regcap[0x20] = {
/* PHY_ID2 documented in 8254x_GBe_SDM.pdf, pp. 250 */
static const uint16_t phy_reg_init[] = {
- [PHY_CTRL] = 0x1140,
- [PHY_STATUS] = 0x794d, /* link initially up with not completed autoneg */
- [PHY_ID1] = 0x141, /* [PHY_ID2] configured per DevId, from e1000_reset() */
- [PHY_1000T_CTRL] = 0x0e00, [M88E1000_PHY_SPEC_CTRL] = 0x360,
- [M88E1000_EXT_PHY_SPEC_CTRL] = 0x0d60, [PHY_AUTONEG_ADV] = 0xde1,
- [PHY_LP_ABILITY] = 0x1e0, [PHY_1000T_STATUS] = 0x3c00,
+ [PHY_CTRL] = MII_CR_SPEED_SELECT_MSB |
+ MII_CR_FULL_DUPLEX |
+ MII_CR_AUTO_NEG_EN,
+
+ [PHY_STATUS] = MII_SR_EXTENDED_CAPS |
+ MII_SR_LINK_STATUS | /* link initially up */
+ MII_SR_AUTONEG_CAPS |
+ /* MII_SR_AUTONEG_COMPLETE: initially NOT completed */
+ MII_SR_PREAMBLE_SUPPRESS |
+ MII_SR_EXTENDED_STATUS |
+ MII_SR_10T_HD_CAPS |
+ MII_SR_10T_FD_CAPS |
+ MII_SR_100X_HD_CAPS |
+ MII_SR_100X_FD_CAPS,
+
+ [PHY_ID1] = 0x141,
+ /* [PHY_ID2] configured per DevId, from e1000_reset() */
+ [PHY_AUTONEG_ADV] = 0xde1,
+ [PHY_LP_ABILITY] = 0x1e0,
+ [PHY_1000T_CTRL] = 0x0e00,
+ [PHY_1000T_STATUS] = 0x3c00,
+ [M88E1000_PHY_SPEC_CTRL] = 0x360,
[M88E1000_PHY_SPEC_STATUS] = 0xac00,
+ [M88E1000_EXT_PHY_SPEC_CTRL] = 0x0d60,
};
static const uint32_t mac_reg_init[] = {
@@ -446,8 +473,9 @@ set_mdic(E1000State *s, int index, uint32_t val)
} else {
if (addr < NPHYWRITEOPS && phyreg_writeops[addr]) {
phyreg_writeops[addr](s, index, data);
+ } else {
+ s->phy_reg[addr] = data;
}
- s->phy_reg[addr] = data;
}
}
s->mac_reg[MDIC] = val | E1000_MDIC_READY;
@@ -848,14 +876,6 @@ receive_filter(E1000State *s, const uint8_t *buf, int size)
return 0;
}
-static bool
-have_autoneg(E1000State *s)
-{
- return (s->compat_flags & E1000_FLAG_AUTONEG) &&
- (s->phy_reg[PHY_CTRL] & MII_CR_AUTO_NEG_EN) &&
- (s->phy_reg[PHY_CTRL] & MII_CR_RESTART_AUTO_NEG);
-}
-
static void
e1000_set_link_status(NetClientState *nc)
{
diff --git a/hw/net/vmxnet3.c b/hw/net/vmxnet3.c
index f11525cef2..791321fa49 100644
--- a/hw/net/vmxnet3.c
+++ b/hw/net/vmxnet3.c
@@ -1009,7 +1009,7 @@ vmxnet3_indicate_packet(VMXNET3State *s)
vmxnet3_dump_rx_descr(&rxd);
- if (0 != ready_rxcd_pa) {
+ if (ready_rxcd_pa != 0) {
cpu_physical_memory_write(ready_rxcd_pa, &rxcd, sizeof(rxcd));
}
@@ -1020,7 +1020,7 @@ vmxnet3_indicate_packet(VMXNET3State *s)
rxcd.gen = new_rxcd_gen;
rxcd.rqID = RXQ_IDX + rx_ridx * s->rxq_num;
- if (0 == bytes_left) {
+ if (bytes_left == 0) {
vmxnet3_rx_update_descr(s->rx_pkt, &rxcd);
}
@@ -1038,16 +1038,16 @@ vmxnet3_indicate_packet(VMXNET3State *s)
num_frags++;
}
- if (0 != ready_rxcd_pa) {
+ if (ready_rxcd_pa != 0) {
rxcd.eop = 1;
- rxcd.err = (0 != bytes_left);
+ rxcd.err = (bytes_left != 0);
cpu_physical_memory_write(ready_rxcd_pa, &rxcd, sizeof(rxcd));
/* Flush RX descriptor changes */
smp_wmb();
}
- if (0 != new_rxcd_pa) {
+ if (new_rxcd_pa != 0) {
vmxnet3_revert_rxc_descr(s, RXQ_IDX);
}
@@ -1190,8 +1190,8 @@ static void vmxnet3_update_mcast_filters(VMXNET3State *s)
s->mcast_list_len = list_bytes / sizeof(s->mcast_list[0]);
s->mcast_list = g_realloc(s->mcast_list, list_bytes);
- if (NULL == s->mcast_list) {
- if (0 == s->mcast_list_len) {
+ if (!s->mcast_list) {
+ if (s->mcast_list_len == 0) {
VMW_CFPRN("Current multicast list is empty");
} else {
VMW_ERPRN("Failed to allocate multicast list of %d elements",
@@ -1667,7 +1667,7 @@ vmxnet3_io_bar1_write(void *opaque,
* memory address. We save it to temp variable and set the
* shared address only after we get the high part
*/
- if (0 == val) {
+ if (val == 0) {
s->device_active = false;
}
s->temp_shared_guest_driver_memory = val;
diff --git a/hw/pci-host/apb.c b/hw/pci-host/apb.c
index d238a84f95..60bd81e477 100644
--- a/hw/pci-host/apb.c
+++ b/hw/pci-host/apb.c
@@ -94,6 +94,7 @@ do { printf("IOMMU: " fmt , ## __VA_ARGS__); } while (0)
#define IOMMU_CTRL_TSB_SHIFT 16
#define IOMMU_BASE 0x8
+#define IOMMU_FLUSH 0x10
#define IOMMU_TTE_DATA_V (1ULL << 63)
#define IOMMU_TTE_DATA_SIZE (1ULL << 61)
@@ -352,6 +353,9 @@ static void iommu_config_write(void *opaque, hwaddr addr,
is->regs[IOMMU_BASE >> 3] &= 0xffffffff00000000ULL;
is->regs[IOMMU_BASE >> 3] |= val & 0xffffffffULL;
break;
+ case IOMMU_FLUSH:
+ case IOMMU_FLUSH + 0x4:
+ break;
default:
qemu_log_mask(LOG_UNIMP,
"apb iommu: Unimplemented register write "
@@ -387,6 +391,10 @@ static uint64_t iommu_config_read(void *opaque, hwaddr addr, unsigned size)
case IOMMU_BASE + 0x4:
val = is->regs[IOMMU_BASE >> 3] & 0xffffffffULL;
break;
+ case IOMMU_FLUSH:
+ case IOMMU_FLUSH + 0x4:
+ val = 0;
+ break;
default:
qemu_log_mask(LOG_UNIMP,
"apb iommu: Unimplemented register read "
@@ -415,7 +423,7 @@ static void apb_config_writel (void *opaque, hwaddr addr,
/* XXX: not implemented yet */
break;
case 0x200 ... 0x217: /* IOMMU */
- iommu_config_write(is, (addr & 0xf), val, size);
+ iommu_config_write(is, (addr & 0x1f), val, size);
break;
case 0xc00 ... 0xc3f: /* PCI interrupt control */
if (addr & 4) {
@@ -497,7 +505,7 @@ static uint64_t apb_config_readl (void *opaque,
/* XXX: not implemented yet */
break;
case 0x200 ... 0x217: /* IOMMU */
- val = iommu_config_read(is, (addr & 0xf), size);
+ val = iommu_config_read(is, (addr & 0x1f), size);
break;
case 0xc00 ... 0xc3f: /* PCI interrupt control */
if (addr & 4) {
diff --git a/hw/pci-host/pam.c b/hw/pci-host/pam.c
index e1e95aabcd..8272de3f28 100644
--- a/hw/pci-host/pam.c
+++ b/hw/pci-host/pam.c
@@ -1,12 +1,12 @@
/*
- * QEMU i440FX/PIIX3 PCI Bridge Emulation
+ * QEMU Smram/pam logic implementation
*
* Copyright (c) 2006 Fabrice Bellard
* Copyright (c) 2011 Isaku Yamahata <yamahata at valinux co jp>
* VA Linux Systems Japan K.K.
* Copyright (c) 2012 Jason Baron <jbaron@redhat.com>
*
- * Split out from piix_pci.c
+ * Split out from piix.c
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
diff --git a/hw/pci-host/q35.c b/hw/pci-host/q35.c
index a0a3068dd5..37f228e77e 100644
--- a/hw/pci-host/q35.c
+++ b/hw/pci-host/q35.c
@@ -7,7 +7,7 @@
* VA Linux Systems Japan K.K.
* Copyright (C) 2012 Jason Baron <jbaron@redhat.com>
*
- * This is based on piix_pci.c, but heavily modified.
+ * This is based on piix.c, but heavily modified.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
diff --git a/hw/pci/msi.c b/hw/pci/msi.c
index a4a3040d4d..52d23130d9 100644
--- a/hw/pci/msi.c
+++ b/hw/pci/msi.c
@@ -291,7 +291,7 @@ void msi_notify(PCIDevice *dev, unsigned int vector)
"notify vector 0x%x"
" address: 0x%"PRIx64" data: 0x%"PRIx32"\n",
vector, msg.address, msg.data);
- stl_le_phys(&address_space_memory, msg.address, msg.data);
+ stl_le_phys(&dev->bus_master_as, msg.address, msg.data);
}
/* Normally called by pci_default_write_config(). */
diff --git a/hw/pci/msix.c b/hw/pci/msix.c
index 3c07d226b2..24de2605fb 100644
--- a/hw/pci/msix.c
+++ b/hw/pci/msix.c
@@ -435,7 +435,7 @@ void msix_notify(PCIDevice *dev, unsigned vector)
msg = msix_get_message(dev, vector);
- stl_le_phys(&address_space_memory, msg.address, msg.data);
+ stl_le_phys(&dev->bus_master_as, msg.address, msg.data);
}
void msix_reset(PCIDevice *dev)
diff --git a/hw/ppc/e500.c b/hw/ppc/e500.c
index 1a5b30d3ce..16c85efab5 100644
--- a/hw/ppc/e500.c
+++ b/hw/ppc/e500.c
@@ -583,7 +583,7 @@ static qemu_irq *ppce500_init_mpic(PPCE500Params *params, MemoryRegion *ccsr,
SysBusDevice *s;
int i;
- mpic = g_new(qemu_irq, 256);
+ mpic = g_new0(qemu_irq, 256);
if (kvm_enabled()) {
QemuOpts *machine_opts = qemu_get_machine_opts();
diff --git a/hw/ppc/mac_newworld.c b/hw/ppc/mac_newworld.c
index 7e97af4a23..1ec4bb490b 100644
--- a/hw/ppc/mac_newworld.c
+++ b/hw/ppc/mac_newworld.c
@@ -204,8 +204,9 @@ static void ppc_core99_init(MachineState *machine)
memory_region_add_subregion(get_system_memory(), 0, ram);
/* allocate and load BIOS */
- memory_region_allocate_system_memory(bios, NULL, "ppc_core99.bios",
- BIOS_SIZE);
+ memory_region_init_ram(bios, NULL, "ppc_core99.bios", BIOS_SIZE);
+ vmstate_register_ram_global(bios);
+
if (bios_name == NULL)
bios_name = PROM_FILENAME;
filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
@@ -345,7 +346,7 @@ static void ppc_core99_init(MachineState *machine)
}
}
- pic = g_new(qemu_irq, 64);
+ pic = g_new0(qemu_irq, 64);
dev = qdev_create(NULL, TYPE_OPENPIC);
qdev_prop_set_uint32(dev, "model", OPENPIC_MODEL_RAVEN);
diff --git a/hw/ppc/mac_oldworld.c b/hw/ppc/mac_oldworld.c
index afae8253e9..cd9bdbc53e 100644
--- a/hw/ppc/mac_oldworld.c
+++ b/hw/ppc/mac_oldworld.c
@@ -135,8 +135,9 @@ static void ppc_heathrow_init(MachineState *machine)
memory_region_add_subregion(sysmem, 0, ram);
/* allocate and load BIOS */
- memory_region_allocate_system_memory(bios, NULL, "ppc_heathrow.bios",
- BIOS_SIZE);
+ memory_region_init_ram(bios, NULL, "ppc_heathrow.bios", BIOS_SIZE);
+ vmstate_register_ram_global(bios);
+
if (bios_name == NULL)
bios_name = PROM_FILENAME;
filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
diff --git a/hw/ppc/ppc405_boards.c b/hw/ppc/ppc405_boards.c
index 6b566cd8e5..11d33792fb 100644
--- a/hw/ppc/ppc405_boards.c
+++ b/hw/ppc/ppc405_boards.c
@@ -214,7 +214,8 @@ static void ref405ep_init(MachineState *machine)
33333333, &pic, kernel_filename == NULL ? 0 : 1);
/* allocate SRAM */
sram_size = 512 * 1024;
- memory_region_allocate_system_memory(sram, NULL, "ef405ep.sram", sram_size);
+ memory_region_init_ram(sram, NULL, "ef405ep.sram", sram_size);
+ vmstate_register_ram_global(sram);
memory_region_add_subregion(sysmem, 0xFFF00000, sram);
/* allocate and load BIOS */
#ifdef DEBUG_BOARD_INIT
@@ -245,8 +246,9 @@ static void ref405ep_init(MachineState *machine)
printf("Load BIOS from file\n");
#endif
bios = g_new(MemoryRegion, 1);
- memory_region_allocate_system_memory(bios, NULL, "ef405ep.bios",
- BIOS_SIZE);
+ memory_region_init_ram(bios, NULL, "ef405ep.bios", BIOS_SIZE);
+ vmstate_register_ram_global(bios);
+
if (bios_name == NULL)
bios_name = BIOS_FILENAME;
filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
@@ -508,6 +510,7 @@ static void taihu_405ep_init(MachineState *machine)
MemoryRegion *sysmem = get_system_memory();
MemoryRegion *bios;
MemoryRegion *ram_memories = g_malloc(2 * sizeof(*ram_memories));
+ MemoryRegion *ram = g_malloc0(sizeof(*ram));
hwaddr ram_bases[2], ram_sizes[2];
long bios_size;
target_ulong kernel_base, initrd_base;
@@ -517,15 +520,20 @@ static void taihu_405ep_init(MachineState *machine)
DriveInfo *dinfo;
/* RAM is soldered to the board so the size cannot be changed */
- memory_region_allocate_system_memory(&ram_memories[0], NULL,
- "taihu_405ep.ram-0", 0x04000000);
+ ram_size = 0x08000000;
+ memory_region_allocate_system_memory(ram, NULL, "taihu_405ep.ram",
+ ram_size);
+
ram_bases[0] = 0;
ram_sizes[0] = 0x04000000;
- memory_region_allocate_system_memory(&ram_memories[1], NULL,
- "taihu_405ep.ram-1", 0x04000000);
+ memory_region_init_alias(&ram_memories[0], NULL,
+ "taihu_405ep.ram-0", ram, ram_bases[0],
+ ram_sizes[0]);
ram_bases[1] = 0x04000000;
ram_sizes[1] = 0x04000000;
- ram_size = 0x08000000;
+ memory_region_init_alias(&ram_memories[1], NULL,
+ "taihu_405ep.ram-1", ram, ram_bases[1],
+ ram_sizes[1]);
#ifdef DEBUG_BOARD_INIT
printf("%s: register cpu\n", __func__);
#endif
@@ -564,8 +572,8 @@ static void taihu_405ep_init(MachineState *machine)
if (bios_name == NULL)
bios_name = BIOS_FILENAME;
bios = g_new(MemoryRegion, 1);
- memory_region_allocate_system_memory(bios, NULL, "taihu_405ep.bios",
- BIOS_SIZE);
+ memory_region_init_ram(bios, NULL, "taihu_405ep.bios", BIOS_SIZE);
+ vmstate_register_ram_global(bios);
filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
if (filename) {
bios_size = load_image(filename, memory_region_get_ram_ptr(bios));
diff --git a/hw/ppc/ppc405_uc.c b/hw/ppc/ppc405_uc.c
index fcd5f2d917..a73e918a14 100644
--- a/hw/ppc/ppc405_uc.c
+++ b/hw/ppc/ppc405_uc.c
@@ -974,8 +974,8 @@ static void ppc405_ocm_init(CPUPPCState *env)
ocm = g_malloc0(sizeof(ppc405_ocm_t));
/* XXX: Size is 4096 or 0x04000000 */
- memory_region_allocate_system_memory(&ocm->isarc_ram, NULL, "ppc405.ocm",
- 4096);
+ memory_region_init_ram(&ocm->isarc_ram, NULL, "ppc405.ocm", 4096);
+ vmstate_register_ram_global(&ocm->isarc_ram);
memory_region_init_alias(&ocm->dsarc_ram, NULL, "ppc405.dsarc", &ocm->isarc_ram,
0, 4096);
qemu_register_reset(&ocm_reset, ocm);
diff --git a/hw/ppc/ppc4xx_devs.c b/hw/ppc/ppc4xx_devs.c
index 405bbe718b..2f38ff7d26 100644
--- a/hw/ppc/ppc4xx_devs.c
+++ b/hw/ppc/ppc4xx_devs.c
@@ -683,28 +683,20 @@ ram_addr_t ppc4xx_sdram_adjust(ram_addr_t ram_size, int nr_banks,
hwaddr ram_sizes[],
const unsigned int sdram_bank_sizes[])
{
+ MemoryRegion *ram = g_malloc0(sizeof(*ram));
ram_addr_t size_left = ram_size;
ram_addr_t base = 0;
+ unsigned int bank_size;
int i;
int j;
for (i = 0; i < nr_banks; i++) {
for (j = 0; sdram_bank_sizes[j] != 0; j++) {
- unsigned int bank_size = sdram_bank_sizes[j];
-
+ bank_size = sdram_bank_sizes[j];
if (bank_size <= size_left) {
- char name[32];
- snprintf(name, sizeof(name), "ppc4xx.sdram%d", i);
- memory_region_allocate_system_memory(&ram_memories[i], NULL,
- name, bank_size);
- ram_bases[i] = base;
- ram_sizes[i] = bank_size;
- base += bank_size;
size_left -= bank_size;
- break;
}
}
-
if (!size_left) {
/* No need to use the remaining banks. */
break;
@@ -712,9 +704,31 @@ ram_addr_t ppc4xx_sdram_adjust(ram_addr_t ram_size, int nr_banks,
}
ram_size -= size_left;
- if (size_left)
+ if (size_left) {
printf("Truncating memory to %d MiB to fit SDRAM controller limits.\n",
(int)(ram_size >> 20));
+ }
+
+ memory_region_allocate_system_memory(ram, NULL, "ppc4xx.sdram", ram_size);
+
+ size_left = ram_size;
+ for (i = 0; i < nr_banks && size_left; i++) {
+ for (j = 0; sdram_bank_sizes[j] != 0; j++) {
+ bank_size = sdram_bank_sizes[j];
+
+ if (bank_size <= size_left) {
+ char name[32];
+ snprintf(name, sizeof(name), "ppc4xx.sdram%d", i);
+ memory_region_init_alias(&ram_memories[i], NULL, name, ram,
+ base, bank_size);
+ ram_bases[i] = base;
+ ram_sizes[i] = bank_size;
+ base += bank_size;
+ size_left -= bank_size;
+ break;
+ }
+ }
+ }
return ram_size;
}
diff --git a/hw/sd/sdhci.c b/hw/sd/sdhci.c
index b5a9eee3e2..f9fe700add 100644
--- a/hw/sd/sdhci.c
+++ b/hw/sd/sdhci.c
@@ -702,7 +702,8 @@ static void sdhci_do_adma(SDHCIState *s)
length -= block_size - begin;
}
dma_memory_read(&address_space_memory, dscr.addr,
- &s->fifo_buffer[begin], s->data_count);
+ &s->fifo_buffer[begin],
+ s->data_count - begin);
dscr.addr += s->data_count - begin;
if (s->data_count == block_size) {
for (n = 0; n < block_size; n++) {
diff --git a/hw/sparc64/sun4u.c b/hw/sparc64/sun4u.c
index 33c311bf28..b9f3bee9ae 100644
--- a/hw/sparc64/sun4u.c
+++ b/hw/sparc64/sun4u.c
@@ -609,8 +609,8 @@ pci_ebus_init1(PCIDevice *pci_dev)
0, 0x1000000);
pci_register_bar(pci_dev, 0, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->bar0);
memory_region_init_alias(&s->bar1, OBJECT(s), "bar1", get_system_io(),
- 0, 0x800000);
- pci_register_bar(pci_dev, 1, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->bar1);
+ 0, 0x1000);
+ pci_register_bar(pci_dev, 1, PCI_BASE_ADDRESS_SPACE_IO, &s->bar1);
return 0;
}
diff --git a/hw/ssi/xilinx_spi.c b/hw/ssi/xilinx_spi.c
index 207f47a1c0..620573caca 100644
--- a/hw/ssi/xilinx_spi.c
+++ b/hw/ssi/xilinx_spi.c
@@ -329,7 +329,7 @@ static int xilinx_spi_init(SysBusDevice *sbd)
s->spi = ssi_create_bus(dev, "spi");
sysbus_init_irq(sbd, &s->irq);
- s->cs_lines = g_new(qemu_irq, s->num_cs);
+ s->cs_lines = g_new0(qemu_irq, s->num_cs);
ssi_auto_connect_slaves(dev, s->cs_lines, s->spi);
for (i = 0; i < s->num_cs; ++i) {
sysbus_init_irq(sbd, &s->cs_lines[i]);
diff --git a/hw/timer/imx_epit.c b/hw/timer/imx_epit.c
index c855eba43c..ffefc22f43 100644
--- a/hw/timer/imx_epit.c
+++ b/hw/timer/imx_epit.c
@@ -83,7 +83,7 @@ static char const *imx_epit_reg_name(uint32_t reg)
#define CR_CLKSRC_SHIFT (24)
#define CR_CLKSRC_MASK (0x3 << CR_CLKSRC_SHIFT)
-#define TIMER_MAX 0XFFFFFFFFUL
+#define EPIT_TIMER_MAX 0XFFFFFFFFUL
/*
* Exact clock frequencies vary from board to board.
@@ -155,7 +155,7 @@ static void imx_epit_reset(DeviceState *dev)
*/
s->cr &= (CR_EN|CR_ENMOD|CR_STOPEN|CR_DOZEN|CR_WAITEN|CR_DBGEN);
s->sr = 0;
- s->lr = TIMER_MAX;
+ s->lr = EPIT_TIMER_MAX;
s->cmp = 0;
s->cnt = 0;
/* stop both timers */
@@ -163,9 +163,9 @@ static void imx_epit_reset(DeviceState *dev)
ptimer_stop(s->timer_reload);
/* compute new frequency */
imx_epit_set_freq(s);
- /* init both timers to TIMER_MAX */
- ptimer_set_limit(s->timer_cmp, TIMER_MAX, 1);
- ptimer_set_limit(s->timer_reload, TIMER_MAX, 1);
+ /* init both timers to EPIT_TIMER_MAX */
+ ptimer_set_limit(s->timer_cmp, EPIT_TIMER_MAX, 1);
+ ptimer_set_limit(s->timer_reload, EPIT_TIMER_MAX, 1);
if (s->freq && (s->cr & CR_EN)) {
/* if the timer is still enabled, restart it */
ptimer_run(s->timer_reload, 0);
@@ -227,7 +227,7 @@ static void imx_epit_reload_compare_timer(IMXEPITState *s)
/* It'll fire in this round of the timer */
next = tmp - s->cmp;
} else { /* catch it next time around */
- next = tmp - s->cmp + ((s->cr & CR_RLD) ? TIMER_MAX : s->lr);
+ next = tmp - s->cmp + ((s->cr & CR_RLD) ? EPIT_TIMER_MAX : s->lr);
}
ptimer_set_count(s->timer_cmp, next);
}
@@ -260,8 +260,8 @@ static void imx_epit_write(void *opaque, hwaddr offset, uint64_t value,
ptimer_set_limit(s->timer_reload, s->lr, 1);
ptimer_set_limit(s->timer_cmp, s->lr, 1);
} else {
- ptimer_set_limit(s->timer_reload, TIMER_MAX, 1);
- ptimer_set_limit(s->timer_cmp, TIMER_MAX, 1);
+ ptimer_set_limit(s->timer_reload, EPIT_TIMER_MAX, 1);
+ ptimer_set_limit(s->timer_cmp, EPIT_TIMER_MAX, 1);
}
}
diff --git a/hw/timer/imx_gpt.c b/hw/timer/imx_gpt.c
index 56ee4db991..3b3101084b 100644
--- a/hw/timer/imx_gpt.c
+++ b/hw/timer/imx_gpt.c
@@ -80,11 +80,11 @@ static char const *imx_gpt_reg_name(uint32_t reg)
* GPT : General purpose timer
*
* This timer counts up continuously while it is enabled, resetting itself
- * to 0 when it reaches TIMER_MAX (in freerun mode) or when it
+ * to 0 when it reaches GPT_TIMER_MAX (in freerun mode) or when it
* reaches the value of one of the ocrX (in periodic mode).
*/
-#define TIMER_MAX 0XFFFFFFFFUL
+#define GPT_TIMER_MAX 0XFFFFFFFFUL
/* Control register. Not all of these bits have any effect (yet) */
#define GPT_CR_EN (1 << 0) /* GPT Enable */
@@ -218,7 +218,7 @@ static inline uint32_t imx_gpt_find_limit(uint32_t count, uint32_t reg,
static void imx_gpt_compute_next_timeout(IMXGPTState *s, bool event)
{
- uint32_t timeout = TIMER_MAX;
+ uint32_t timeout = GPT_TIMER_MAX;
uint32_t count = 0;
long long limit;
@@ -230,10 +230,10 @@ static void imx_gpt_compute_next_timeout(IMXGPTState *s, bool event)
if (event) {
/* This is a timer event */
- if ((s->cr & GPT_CR_FRR) && (s->next_timeout != TIMER_MAX)) {
+ if ((s->cr & GPT_CR_FRR) && (s->next_timeout != GPT_TIMER_MAX)) {
/*
* if we are in free running mode and we have not reached
- * the TIMER_MAX limit, then update the count
+ * the GPT_TIMER_MAX limit, then update the count
*/
count = imx_gpt_update_count(s);
}
@@ -267,7 +267,7 @@ static void imx_gpt_compute_next_timeout(IMXGPTState *s, bool event)
if ((s->ir & GPT_IR_OF3IE) && (timeout == s->ocr3)) {
s->next_int |= GPT_SR_OF3;
}
- if ((s->ir & GPT_IR_ROVIE) && (timeout == TIMER_MAX)) {
+ if ((s->ir & GPT_IR_ROVIE) && (timeout == GPT_TIMER_MAX)) {
s->next_int |= GPT_SR_ROV;
}
@@ -370,20 +370,20 @@ static void imx_gpt_reset(DeviceState *dev)
s->pr = 0;
s->ir = 0;
s->cnt = 0;
- s->ocr1 = TIMER_MAX;
- s->ocr2 = TIMER_MAX;
- s->ocr3 = TIMER_MAX;
+ s->ocr1 = GPT_TIMER_MAX;
+ s->ocr2 = GPT_TIMER_MAX;
+ s->ocr3 = GPT_TIMER_MAX;
s->icr1 = 0;
s->icr2 = 0;
- s->next_timeout = TIMER_MAX;
+ s->next_timeout = GPT_TIMER_MAX;
s->next_int = 0;
/* compute new freq */
imx_gpt_set_freq(s);
- /* reset the limit to TIMER_MAX */
- ptimer_set_limit(s->timer, TIMER_MAX, 1);
+ /* reset the limit to GPT_TIMER_MAX */
+ ptimer_set_limit(s->timer, GPT_TIMER_MAX, 1);
/* if the timer is still enabled, restart it */
if (s->freq && (s->cr & GPT_CR_EN)) {
@@ -415,8 +415,8 @@ static void imx_gpt_write(void *opaque, hwaddr offset, uint64_t value,
if ((oldreg ^ s->cr) & GPT_CR_EN) {
if (s->cr & GPT_CR_EN) {
if (s->cr & GPT_CR_ENMOD) {
- s->next_timeout = TIMER_MAX;
- ptimer_set_count(s->timer, TIMER_MAX);
+ s->next_timeout = GPT_TIMER_MAX;
+ ptimer_set_count(s->timer, GPT_TIMER_MAX);
imx_gpt_compute_next_timeout(s, false);
}
ptimer_run(s->timer, 1);
@@ -451,8 +451,8 @@ static void imx_gpt_write(void *opaque, hwaddr offset, uint64_t value,
/* In non-freerun mode, reset count when this register is written */
if (!(s->cr & GPT_CR_FRR)) {
- s->next_timeout = TIMER_MAX;
- ptimer_set_limit(s->timer, TIMER_MAX, 1);
+ s->next_timeout = GPT_TIMER_MAX;
+ ptimer_set_limit(s->timer, GPT_TIMER_MAX, 1);
}
/* compute the new timeout */
diff --git a/hw/timer/tusb6010.c b/hw/timer/tusb6010.c
index bd2a89e020..459c748e1b 100644
--- a/hw/timer/tusb6010.c
+++ b/hw/timer/tusb6010.c
@@ -282,9 +282,6 @@ static void tusb_gpio_intr_update(TUSBState *s)
/* TODO: How is this signalled? */
}
-extern CPUReadMemoryFunc * const musb_read[];
-extern CPUWriteMemoryFunc * const musb_write[];
-
static uint32_t tusb_async_readb(void *opaque, hwaddr addr)
{
TUSBState *s = (TUSBState *) opaque;
diff --git a/hw/usb/dev-audio.c b/hw/usb/dev-audio.c
index bfebfe90f3..7b9957b3c3 100644
--- a/hw/usb/dev-audio.c
+++ b/hw/usb/dev-audio.c
@@ -371,7 +371,7 @@ static void output_callback(void *opaque, int avail)
return;
}
data = streambuf_get(&s->out.buf);
- if (NULL == data) {
+ if (!data) {
return;
}
AUD_write(s->out.voice, data, USBAUDIO_PACKET_SIZE);
diff --git a/hw/usb/dev-mtp.c b/hw/usb/dev-mtp.c
index 1b51a90022..0820046906 100644
--- a/hw/usb/dev-mtp.c
+++ b/hw/usb/dev-mtp.c
@@ -832,7 +832,7 @@ static void usb_mtp_command(MTPState *s, MTPControl *c)
return;
}
data_in = usb_mtp_get_object(s, c, o);
- if (NULL == data_in) {
+ if (data_in == NULL) {
usb_mtp_queue_result(s, RES_GENERAL_ERROR,
c->trans, 0, 0, 0);
return;
@@ -851,7 +851,7 @@ static void usb_mtp_command(MTPState *s, MTPControl *c)
return;
}
data_in = usb_mtp_get_partial_object(s, c, o);
- if (NULL == data_in) {
+ if (data_in == NULL) {
usb_mtp_queue_result(s, RES_GENERAL_ERROR,
c->trans, 0, 0, 0);
return;
@@ -1090,7 +1090,7 @@ static const VMStateDescription vmstate_usb_mtp = {
};
static Property mtp_properties[] = {
- DEFINE_PROP_STRING("root", MTPState, root),
+ DEFINE_PROP_STRING("x-root", MTPState, root),
DEFINE_PROP_STRING("desc", MTPState, desc),
DEFINE_PROP_END_OF_LIST(),
};
diff --git a/hw/usb/hcd-ehci.c b/hw/usb/hcd-ehci.c
index a00a93c3eb..448e0073dd 100644
--- a/hw/usb/hcd-ehci.c
+++ b/hw/usb/hcd-ehci.c
@@ -1596,7 +1596,7 @@ static EHCIQueue *ehci_state_fetchqh(EHCIState *ehci, int async)
entry = ehci_get_fetch_addr(ehci, async);
q = ehci_find_queue_by_qh(ehci, entry, async);
- if (NULL == q) {
+ if (q == NULL) {
q = ehci_alloc_queue(ehci, entry, async);
}
diff --git a/hw/usb/hcd-ohci.c b/hw/usb/hcd-ohci.c
index cace945844..13afdf5919 100644
--- a/hw/usb/hcd-ohci.c
+++ b/hw/usb/hcd-ohci.c
@@ -2021,7 +2021,7 @@ static const VMStateDescription vmstate_ohci_eof_timer = {
},
};
-const VMStateDescription vmstate_ohci_state = {
+static const VMStateDescription vmstate_ohci_state = {
.name = "ohci-core",
.version_id = 1,
.minimum_version_id = 1,
diff --git a/hw/usb/hcd-xhci.c b/hw/usb/hcd-xhci.c
index 7f2af8925f..58c4b11527 100644
--- a/hw/usb/hcd-xhci.c
+++ b/hw/usb/hcd-xhci.c
@@ -3737,6 +3737,7 @@ static const VMStateDescription vmstate_xhci_event = {
VMSTATE_UINT32(flags, XHCIEvent),
VMSTATE_UINT8(slotid, XHCIEvent),
VMSTATE_UINT8(epid, XHCIEvent),
+ VMSTATE_END_OF_LIST()
}
};
diff --git a/hw/virtio/vhost-backend.c b/hw/virtio/vhost-backend.c
index 35316c40d9..ff4f2001bb 100644
--- a/hw/virtio/vhost-backend.c
+++ b/hw/virtio/vhost-backend.c
@@ -14,8 +14,6 @@
#include <sys/ioctl.h>
-extern const VhostOps user_ops;
-
static int vhost_kernel_call(struct vhost_dev *dev, unsigned long int request,
void *arg)
{
diff --git a/hw/virtio/vhost-user.c b/hw/virtio/vhost-user.c
index 38e580642f..4e88d9c5e9 100644
--- a/hw/virtio/vhost-user.c
+++ b/hw/virtio/vhost-user.c
@@ -216,7 +216,11 @@ static int vhost_user_call(struct vhost_dev *dev, unsigned long int request,
case VHOST_SET_MEM_TABLE:
for (i = 0; i < dev->mem->nregions; ++i) {
struct vhost_memory_region *reg = dev->mem->regions + i;
- fd = qemu_get_ram_fd(reg->guest_phys_addr);
+ ram_addr_t ram_addr;
+
+ assert((uintptr_t)reg->userspace_addr == reg->userspace_addr);
+ qemu_ram_addr_from_host((void *)(uintptr_t)reg->userspace_addr, &ram_addr);
+ fd = qemu_get_ram_fd(ram_addr);
if (fd > 0) {
msg.memory.regions[fd_num].userspace_addr = reg->userspace_addr;
msg.memory.regions[fd_num].memory_size = reg->memory_size;
diff --git a/hw/virtio/virtio-rng.c b/hw/virtio/virtio-rng.c
index 1356aca8d6..e85a979754 100644
--- a/hw/virtio/virtio-rng.c
+++ b/hw/virtio/virtio-rng.c
@@ -16,6 +16,7 @@
#include "hw/virtio/virtio-rng.h"
#include "sysemu/rng.h"
#include "qom/object_interfaces.h"
+#include "trace.h"
static bool is_guest_ready(VirtIORNG *vrng)
{
@@ -24,6 +25,7 @@ static bool is_guest_ready(VirtIORNG *vrng)
&& (vdev->status & VIRTIO_CONFIG_S_DRIVER_OK)) {
return true;
}
+ trace_virtio_rng_guest_not_ready(vrng);
return false;
}
@@ -62,6 +64,7 @@ static void chr_read(void *opaque, const void *buf, size_t size)
offset += len;
virtqueue_push(vrng->vq, &elem, len);
+ trace_virtio_rng_pushed(vrng, len);
}
virtio_notify(vdev, vrng->vq);
}
@@ -81,6 +84,9 @@ static void virtio_rng_process(VirtIORNG *vrng)
quota = MIN((uint64_t)vrng->quota_remaining, (uint64_t)UINT32_MAX);
}
size = get_request_size(vrng->vq, quota);
+
+ trace_virtio_rng_request(vrng, size, quota);
+
size = MIN(vrng->quota_remaining, size);
if (size) {
rng_backend_request_entropy(vrng->rng, size, chr_read, vrng);
@@ -142,8 +148,15 @@ static void virtio_rng_device_realize(DeviceState *dev, Error **errp)
Error *local_err = NULL;
if (!vrng->conf.period_ms > 0) {
- error_set(errp, QERR_INVALID_PARAMETER_VALUE, "period",
- "a positive number");
+ error_setg(errp, "'period' parameter expects a positive integer");
+ return;
+ }
+
+ /* Workaround: Property parsing does not enforce unsigned integers,
+ * So this is a hack to reject such numbers. */
+ if (vrng->conf.max_bytes > INT64_MAX) {
+ error_setg(errp, "'max-bytes' parameter must be non-negative, "
+ "and less than 2^63");
return;
}
@@ -171,17 +184,15 @@ static void virtio_rng_device_realize(DeviceState *dev, Error **errp)
"rng", NULL);
}
- virtio_init(vdev, "virtio-rng", VIRTIO_ID_RNG, 0);
-
vrng->rng = vrng->conf.rng;
if (vrng->rng == NULL) {
- error_set(errp, QERR_INVALID_PARAMETER_VALUE, "rng", "a valid object");
+ error_setg(errp, "'rng' parameter expects a valid object");
return;
}
- vrng->vq = virtio_add_queue(vdev, 8, handle_input);
+ virtio_init(vdev, "virtio-rng", VIRTIO_ID_RNG, 0);
- assert(vrng->conf.max_bytes <= INT64_MAX);
+ vrng->vq = virtio_add_queue(vdev, 8, handle_input);
vrng->quota_remaining = vrng->conf.max_bytes;
vrng->rate_limit_timer = timer_new_ms(QEMU_CLOCK_VIRTUAL,
diff --git a/include/block/block.h b/include/block/block.h
index 32d36760fd..e94b701667 100644
--- a/include/block/block.h
+++ b/include/block/block.h
@@ -275,10 +275,11 @@ BlockDriverState *bdrv_find_backing_image(BlockDriverState *bs,
const char *backing_file);
int bdrv_get_backing_file_depth(BlockDriverState *bs);
int bdrv_truncate(BlockDriverState *bs, int64_t offset);
+int64_t bdrv_nb_sectors(BlockDriverState *bs);
int64_t bdrv_getlength(BlockDriverState *bs);
int64_t bdrv_get_allocated_file_size(BlockDriverState *bs);
void bdrv_get_geometry(BlockDriverState *bs, uint64_t *nb_sectors_ptr);
-int bdrv_refresh_limits(BlockDriverState *bs);
+void bdrv_refresh_limits(BlockDriverState *bs, Error **errp);
int bdrv_commit(BlockDriverState *bs);
int bdrv_commit_all(void);
int bdrv_change_backing_file(BlockDriverState *bs,
@@ -454,6 +455,7 @@ void bdrv_img_create(const char *filename, const char *fmt,
size_t bdrv_opt_mem_align(BlockDriverState *bs);
void bdrv_set_guest_block_size(BlockDriverState *bs, int align);
void *qemu_blockalign(BlockDriverState *bs, size_t size);
+void *qemu_try_blockalign(BlockDriverState *bs, size_t size);
bool bdrv_qiov_is_aligned(BlockDriverState *bs, QEMUIOVector *qiov);
struct HBitmapIter;
diff --git a/include/block/block_int.h b/include/block/block_int.h
index f6c3befed8..7b541a0691 100644
--- a/include/block/block_int.h
+++ b/include/block/block_int.h
@@ -240,7 +240,7 @@ struct BlockDriver {
int (*bdrv_debug_resume)(BlockDriverState *bs, const char *tag);
bool (*bdrv_debug_is_suspended)(BlockDriverState *bs, const char *tag);
- int (*bdrv_refresh_limits)(BlockDriverState *bs);
+ void (*bdrv_refresh_limits)(BlockDriverState *bs, Error **errp);
/*
* Returns 1 if newly created images are guaranteed to contain only
diff --git a/include/block/coroutine.h b/include/block/coroutine.h
index b408f96b82..b9b7f488c9 100644
--- a/include/block/coroutine.h
+++ b/include/block/coroutine.h
@@ -223,4 +223,15 @@ void coroutine_fn co_aio_sleep_ns(AioContext *ctx, QEMUClockType type,
* Note that this function clobbers the handlers for the file descriptor.
*/
void coroutine_fn yield_until_fd_readable(int fd);
+
+/**
+ * Add or subtract from the coroutine pool size
+ *
+ * The coroutine implementation keeps a pool of coroutines to be reused by
+ * qemu_coroutine_create(). This makes coroutine creation cheap. Heavy
+ * coroutine users should call this to reserve pool space. Call it again with
+ * a negative number to release pool space.
+ */
+void qemu_coroutine_adjust_pool_size(int n);
+
#endif /* QEMU_COROUTINE_H */
diff --git a/include/exec/helper-gen.h b/include/exec/helper-gen.h
index a04a0341e2..0d0da3aeb3 100644
--- a/include/exec/helper-gen.h
+++ b/include/exec/helper-gen.h
@@ -57,6 +57,8 @@ static inline void glue(gen_helper_, name)(dh_retvar_decl(ret) \
}
#include "helper.h"
+#include "trace/generated-helpers.h"
+#include "trace/generated-helpers-wrappers.h"
#include "tcg-runtime.h"
#undef DEF_HELPER_FLAGS_0
diff --git a/include/exec/helper-proto.h b/include/exec/helper-proto.h
index 828951c609..effdd4383a 100644
--- a/include/exec/helper-proto.h
+++ b/include/exec/helper-proto.h
@@ -27,6 +27,7 @@ dh_ctype(ret) HELPER(name) (dh_ctype(t1), dh_ctype(t2), dh_ctype(t3), \
dh_ctype(t4), dh_ctype(t5));
#include "helper.h"
+#include "trace/generated-helpers.h"
#include "tcg-runtime.h"
#undef DEF_HELPER_FLAGS_0
diff --git a/include/exec/helper-tcg.h b/include/exec/helper-tcg.h
index d704c81126..79fa3c8c81 100644
--- a/include/exec/helper-tcg.h
+++ b/include/exec/helper-tcg.h
@@ -36,6 +36,7 @@
| dh_sizemask(t5, 5) },
#include "helper.h"
+#include "trace/generated-helpers.h"
#include "tcg-runtime.h"
#undef DEF_HELPER_FLAGS_0
diff --git a/include/exec/ram_addr.h b/include/exec/ram_addr.h
index e9eb831ee3..6593be1310 100644
--- a/include/exec/ram_addr.h
+++ b/include/exec/ram_addr.h
@@ -71,6 +71,17 @@ static inline void cpu_physical_memory_set_dirty_flag(ram_addr_t addr,
set_bit(addr >> TARGET_PAGE_BITS, ram_list.dirty_memory[client]);
}
+static inline void cpu_physical_memory_set_dirty_range_nocode(ram_addr_t start,
+ ram_addr_t length)
+{
+ unsigned long end, page;
+
+ end = TARGET_PAGE_ALIGN(start + length) >> TARGET_PAGE_BITS;
+ page = start >> TARGET_PAGE_BITS;
+ bitmap_set(ram_list.dirty_memory[DIRTY_MEMORY_MIGRATION], page, end - page);
+ bitmap_set(ram_list.dirty_memory[DIRTY_MEMORY_VGA], page, end - page);
+}
+
static inline void cpu_physical_memory_set_dirty_range(ram_addr_t start,
ram_addr_t length)
{
diff --git a/include/hw/acpi/pc-hotplug.h b/include/hw/acpi/pc-hotplug.h
index bf5157d7c3..b9db29576c 100644
--- a/include/hw/acpi/pc-hotplug.h
+++ b/include/hw/acpi/pc-hotplug.h
@@ -32,7 +32,7 @@
#define ACPI_MEMORY_HOTPLUG_IO_LEN 24
#define ACPI_MEMORY_HOTPLUG_BASE 0x0a00
-#define MEMORY_HOPTLUG_DEVICE MHPD
+#define MEMORY_HOTPLUG_DEVICE MHPD
#define MEMORY_SLOTS_NUMBER MDNR
#define MEMORY_HOTPLUG_IO_REGION HPMR
#define MEMORY_SLOT_ADDR_LOW MRBL
diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h
index 1c0c382d8c..0fca9e3fd7 100644
--- a/include/hw/i386/pc.h
+++ b/include/hw/i386/pc.h
@@ -85,7 +85,6 @@ typedef struct PcPciInfo {
#define ACPI_PM_PROP_GPE0_BLK_LEN "gpe0_blk_len"
struct PcGuestInfo {
- bool has_pci_info;
bool isapc_ram_fw;
hwaddr ram_size, ram_size_below_4g;
unsigned apic_id_limit;
@@ -94,6 +93,7 @@ struct PcGuestInfo {
uint64_t *node_mem;
uint64_t *node_cpu;
FWCfgState *fw_cfg;
+ int legacy_acpi_table_size;
bool has_acpi_build;
bool has_reserved_memory;
};
@@ -187,6 +187,11 @@ PcGuestInfo *pc_guest_info_init(ram_addr_t below_4g_mem_size,
void pc_pci_as_mapping_init(Object *owner, MemoryRegion *system_memory,
MemoryRegion *pci_address_space);
+FWCfgState *xen_load_linux(const char *kernel_filename,
+ const char *kernel_cmdline,
+ const char *initrd_filename,
+ ram_addr_t below_4g_mem_size,
+ PcGuestInfo *guest_info);
FWCfgState *pc_memory_init(MachineState *machine,
MemoryRegion *system_memory,
ram_addr_t below_4g_mem_size,
@@ -294,7 +299,15 @@ int e820_add_entry(uint64_t, uint64_t, uint32_t);
int e820_get_num_entries(void);
bool e820_get_entry(int, uint32_t, uint64_t *, uint64_t *);
+#define PC_COMPAT_2_1 \
+ {\
+ .driver = "intel-hda",\
+ .property = "old_msi_addr",\
+ .value = "on",\
+ }
+
#define PC_COMPAT_2_0 \
+ PC_COMPAT_2_1, \
{\
.driver = "virtio-scsi-pci",\
.property = "any_layout",\
diff --git a/include/hw/pci-host/pam.h b/include/hw/pci-host/pam.h
index a8b87b89a7..4d03e4bf18 100644
--- a/include/hw/pci-host/pam.h
+++ b/include/hw/pci-host/pam.h
@@ -7,7 +7,7 @@
* VA Linux Systems Japan K.K.
* Copyright (c) 2012 Jason Baron <jbaron@redhat.com>
*
- * Split out from piix_pci.c
+ * Split out from piix.c
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
diff --git a/include/hw/usb.h b/include/hw/usb.h
index 8bcab48d29..223a5aef8f 100644
--- a/include/hw/usb.h
+++ b/include/hw/usb.h
@@ -475,7 +475,8 @@ void usb_host_info(Monitor *mon, const QDict *qdict);
#define VM_USB_HUB_SIZE 8
-/* usb-musb.c */
+/* hw/usb/hdc-musb.c */
+
enum musb_irq_source_e {
musb_irq_suspend = 0,
musb_irq_resume,
@@ -494,6 +495,10 @@ enum musb_irq_source_e {
};
typedef struct MUSBState MUSBState;
+
+extern CPUReadMemoryFunc * const musb_read[];
+extern CPUWriteMemoryFunc * const musb_write[];
+
MUSBState *musb_init(DeviceState *parent_device, int gpio_base);
void musb_reset(MUSBState *s);
uint32_t musb_core_intr_get(MUSBState *s);
diff --git a/include/hw/virtio/vhost-backend.h b/include/hw/virtio/vhost-backend.h
index d31768a1d4..e472f29714 100644
--- a/include/hw/virtio/vhost-backend.h
+++ b/include/hw/virtio/vhost-backend.h
@@ -32,6 +32,8 @@ typedef struct VhostOps {
vhost_backend_cleanup vhost_backend_cleanup;
} VhostOps;
+extern const VhostOps user_ops;
+
int vhost_set_backend_type(struct vhost_dev *dev,
VhostBackendType backend_type);
diff --git a/include/hw/virtio/virtio-serial.h b/include/hw/virtio/virtio-serial.h
index 4746312a83..a679e54aab 100644
--- a/include/hw/virtio/virtio-serial.h
+++ b/include/hw/virtio/virtio-serial.h
@@ -202,6 +202,8 @@ struct VirtIOSerial {
QTAILQ_HEAD(, VirtIOSerialPort) ports;
+ QLIST_ENTRY(VirtIOSerial) next;
+
/* bitmap for identifying active ports */
uint32_t *ports_map;
diff --git a/include/libdecnumber/decNumberLocal.h b/include/libdecnumber/decNumberLocal.h
index cd4eb79e80..71ed77bf21 100644
--- a/include/libdecnumber/decNumberLocal.h
+++ b/include/libdecnumber/decNumberLocal.h
@@ -153,7 +153,7 @@
/* ---------------------------------------------------------------- */
- /* Definitions for arbitary-precision modules (only valid after */
+ /* Definitions for arbitrary-precision modules (only valid after */
/* decNumber.h has been included) */
/* ---------------------------------------------------------------- */
diff --git a/include/monitor/monitor.h b/include/monitor/monitor.h
index 3d6929d6cd..78a5fc8197 100644
--- a/include/monitor/monitor.h
+++ b/include/monitor/monitor.h
@@ -64,7 +64,7 @@ AddfdInfo *monitor_fdset_add_fd(int fd, bool has_fdset_id, int64_t fdset_id,
Error **errp);
int monitor_fdset_get_fd(int64_t fdset_id, int flags);
int monitor_fdset_dup_fd_add(int64_t fdset_id, int dup_fd);
-int monitor_fdset_dup_fd_remove(int dup_fd);
+void monitor_fdset_dup_fd_remove(int dup_fd);
int monitor_fdset_dup_fd_find(int dup_fd);
#endif /* !MONITOR_H */
diff --git a/include/qemu-common.h b/include/qemu-common.h
index 6ef8282234..bcf7a6ad43 100644
--- a/include/qemu-common.h
+++ b/include/qemu-common.h
@@ -41,6 +41,7 @@
#include <assert.h>
#include <signal.h>
#include "glib-compat.h"
+#include "qemu/option.h"
#ifdef _WIN32
#include "sysemu/os-win32.h"
@@ -105,8 +106,13 @@ static inline char *realpath(const char *path, char *resolved_path)
#endif
/* icount */
-void configure_icount(const char *option);
+void configure_icount(QemuOpts *opts, Error **errp);
extern int use_icount;
+extern int icount_align_option;
+/* drift information for info jit command */
+extern int64_t max_delay;
+extern int64_t max_advance;
+void dump_drift_info(FILE *f, fprintf_function cpu_fprintf);
#include "qemu/osdep.h"
#include "qemu/bswap.h"
diff --git a/include/qemu/osdep.h b/include/qemu/osdep.h
index 8480d523f0..9dd43fc2db 100644
--- a/include/qemu/osdep.h
+++ b/include/qemu/osdep.h
@@ -95,6 +95,7 @@ typedef signed int int_fast16_t;
#define qemu_printf printf
int qemu_daemon(int nochdir, int noclose);
+void *qemu_try_memalign(size_t alignment, size_t size);
void *qemu_memalign(size_t alignment, size_t size);
void *qemu_anon_ram_alloc(size_t size);
void qemu_vfree(void *ptr);
diff --git a/include/qemu/timer.h b/include/qemu/timer.h
index 7f9a074c2a..5f5210d543 100644
--- a/include/qemu/timer.h
+++ b/include/qemu/timer.h
@@ -745,6 +745,8 @@ static inline int64_t get_clock(void)
/* icount */
int64_t cpu_get_icount(void);
int64_t cpu_get_clock(void);
+int64_t cpu_get_clock_offset(void);
+int64_t cpu_icount_to_ns(int64_t icount);
/*******************************************/
/* host CPU ticks (if available) */
diff --git a/include/sysemu/char.h b/include/sysemu/char.h
index 0bbd631e72..98cd4c958e 100644
--- a/include/sysemu/char.h
+++ b/include/sysemu/char.h
@@ -358,6 +358,9 @@ CharDriverState *qemu_char_get_next_serial(void);
/* msmouse */
CharDriverState *qemu_chr_open_msmouse(void);
+/* testdev.c */
+CharDriverState *chr_testdev_init(void);
+
/* baum.c */
CharDriverState *chr_baum_init(void);
diff --git a/include/trace-tcg.h b/include/trace-tcg.h
new file mode 100644
index 0000000000..6f6bdbb44a
--- /dev/null
+++ b/include/trace-tcg.h
@@ -0,0 +1,7 @@
+#ifndef TRACE_TCG_H
+#define TRACE_TCG_H
+
+#include "trace/generated-tcg-tracers.h"
+#include "trace/generated-events.h"
+
+#endif /* TRACE_TCG_H */
diff --git a/include/trace.h b/include/trace.h
index c15f498128..44a1f1f8c7 100644
--- a/include/trace.h
+++ b/include/trace.h
@@ -2,5 +2,6 @@
#define TRACE_H
#include "trace/generated-tracers.h"
+#include "trace/generated-events.h"
#endif /* TRACE_H */
diff --git a/kvm-all.c b/kvm-all.c
index 3ae30eeb68..1402f4f429 100644
--- a/kvm-all.c
+++ b/kvm-all.c
@@ -2077,12 +2077,13 @@ void kvm_remove_all_breakpoints(CPUState *cpu)
{
struct kvm_sw_breakpoint *bp, *next;
KVMState *s = cpu->kvm_state;
+ CPUState *tmpcpu;
QTAILQ_FOREACH_SAFE(bp, &s->kvm_sw_breakpoints, entry, next) {
if (kvm_arch_remove_sw_breakpoint(cpu, bp) != 0) {
/* Try harder to find a CPU that currently sees the breakpoint. */
- CPU_FOREACH(cpu) {
- if (kvm_arch_remove_sw_breakpoint(cpu, bp) == 0) {
+ CPU_FOREACH(tmpcpu) {
+ if (kvm_arch_remove_sw_breakpoint(tmpcpu, bp) == 0) {
break;
}
}
diff --git a/memory.c b/memory.c
index 031ff516ae..d0966c027f 100644
--- a/memory.c
+++ b/memory.c
@@ -56,8 +56,7 @@ static void memory_init(void)
typedef struct AddrRange AddrRange;
/*
- * Note using signed integers limits us to physical addresses at most
- * 63 bits wide. They are needed for negative offsetting in aliases
+ * Note that signed integers are needed for negative offsetting in aliases
* (large MemoryRegion::alias_offset).
*/
struct AddrRange {
diff --git a/monitor.c b/monitor.c
index 5bc70a642d..34cee74eb3 100644
--- a/monitor.c
+++ b/monitor.c
@@ -1047,6 +1047,7 @@ static void do_info_registers(Monitor *mon, const QDict *qdict)
static void do_info_jit(Monitor *mon, const QDict *qdict)
{
dump_exec_info((FILE *)mon, monitor_fprintf);
+ dump_drift_info((FILE *)mon, monitor_fprintf);
}
static void do_info_history(Monitor *mon, const QDict *qdict)
@@ -2541,8 +2542,10 @@ static int monitor_fdset_dup_fd_find_remove(int dup_fd, bool remove)
if (QLIST_EMPTY(&mon_fdset->dup_fds)) {
monitor_fdset_cleanup(mon_fdset);
}
+ return -1;
+ } else {
+ return mon_fdset->id;
}
- return mon_fdset->id;
}
}
}
@@ -2554,9 +2557,9 @@ int monitor_fdset_dup_fd_find(int dup_fd)
return monitor_fdset_dup_fd_find_remove(dup_fd, false);
}
-int monitor_fdset_dup_fd_remove(int dup_fd)
+void monitor_fdset_dup_fd_remove(int dup_fd)
{
- return monitor_fdset_dup_fd_find_remove(dup_fd, true);
+ monitor_fdset_dup_fd_find_remove(dup_fd, true);
}
int monitor_handle_fd_param(Monitor *mon, const char *fdname)
@@ -4520,16 +4523,15 @@ void netdev_del_completion(ReadLineState *rs, int nb_args, const char *str)
void watchdog_action_completion(ReadLineState *rs, int nb_args, const char *str)
{
+ int i;
+
if (nb_args != 2) {
return;
}
readline_set_completion_index(rs, strlen(str));
- add_completion_option(rs, str, "reset");
- add_completion_option(rs, str, "shutdown");
- add_completion_option(rs, str, "poweroff");
- add_completion_option(rs, str, "pause");
- add_completion_option(rs, str, "debug");
- add_completion_option(rs, str, "none");
+ for (i = 0; WatchdogExpirationAction_lookup[i]; i++) {
+ add_completion_option(rs, str, WatchdogExpirationAction_lookup[i]);
+ }
}
void migrate_set_capability_completion(ReadLineState *rs, int nb_args,
diff --git a/net/slirp.c b/net/slirp.c
index 8fddc03841..647039ec39 100644
--- a/net/slirp.c
+++ b/net/slirp.c
@@ -282,6 +282,7 @@ static SlirpState *slirp_lookup(Monitor *mon, const char *vlan,
NetClientState *nc;
nc = net_hub_find_client_by_name(strtol(vlan, NULL, 0), stack);
if (!nc) {
+ monitor_printf(mon, "unrecognized (vlan-id, stackname) pair\n");
return NULL;
}
if (strcmp(nc->model, "user")) {
diff --git a/net/tap-bsd.c b/net/tap-bsd.c
index 90f8a02276..bf91bd03fd 100644
--- a/net/tap-bsd.c
+++ b/net/tap-bsd.c
@@ -27,12 +27,13 @@
#include "sysemu/sysemu.h"
#include "qemu/error-report.h"
-#ifdef __NetBSD__
+#if defined(__NetBSD__) || defined(__FreeBSD__)
#include <sys/ioctl.h>
#include <net/if.h>
#include <net/if_tap.h>
#endif
+#ifndef __FreeBSD__
int tap_open(char *ifname, int ifname_size, int *vnet_hdr,
int vnet_hdr_required, int mq_required)
{
@@ -108,6 +109,73 @@ int tap_open(char *ifname, int ifname_size, int *vnet_hdr,
return fd;
}
+#else /* __FreeBSD__ */
+
+#define PATH_NET_TAP "/dev/tap"
+
+int tap_open(char *ifname, int ifname_size, int *vnet_hdr,
+ int vnet_hdr_required, int mq_required)
+{
+ int fd, s, ret;
+ struct ifreq ifr;
+
+ TFR(fd = open(PATH_NET_TAP, O_RDWR));
+ if (fd < 0) {
+ error_report("could not open %s: %s", PATH_NET_TAP, strerror(errno));
+ return -1;
+ }
+
+ memset(&ifr, 0, sizeof(ifr));
+
+ ret = ioctl(fd, TAPGIFNAME, (void *)&ifr);
+ if (ret < 0) {
+ error_report("could not get tap interface name");
+ goto error;
+ }
+
+ if (ifname[0] != '\0') {
+ /* User requested the interface to have a specific name */
+ s = socket(AF_LOCAL, SOCK_DGRAM, 0);
+ if (s < 0) {
+ error_report("could not open socket to set interface name");
+ goto error;
+ }
+ ifr.ifr_data = ifname;
+ ret = ioctl(s, SIOCSIFNAME, (void *)&ifr);
+ close(s);
+ if (ret < 0) {
+ error_report("could not set tap interface name");
+ goto error;
+ }
+ } else {
+ pstrcpy(ifname, ifname_size, ifr.ifr_name);
+ }
+
+ if (*vnet_hdr) {
+ /* BSD doesn't have IFF_VNET_HDR */
+ *vnet_hdr = 0;
+
+ if (vnet_hdr_required && !*vnet_hdr) {
+ error_report("vnet_hdr=1 requested, but no kernel "
+ "support for IFF_VNET_HDR available");
+ goto error;
+ }
+ }
+ if (mq_required) {
+ error_report("mq_required requested, but not kernel support"
+ "for IFF_MULTI_QUEUE available");
+ goto error;
+ }
+
+ fcntl(fd, F_SETFL, O_NONBLOCK);
+ return fd;
+
+error:
+ close(fd);
+ return -1;
+}
+#endif /* __FreeBSD__ */
+
int tap_set_sndbuf(int fd, const NetdevTapOptions *tap)
{
return 0;
diff --git a/numa.c b/numa.c
index 7bf7834b7f..c78cec96a8 100644
--- a/numa.c
+++ b/numa.c
@@ -210,8 +210,8 @@ void set_numa_nodes(void)
numa_total += numa_info[i].node_mem;
}
if (numa_total != ram_size) {
- error_report("total memory for NUMA nodes (%" PRIu64 ")"
- " should equal RAM size (" RAM_ADDR_FMT ")",
+ error_report("total memory for NUMA nodes (0x%" PRIx64 ")"
+ " should equal RAM size (0x" RAM_ADDR_FMT ")",
numa_total, ram_size);
exit(1);
}
diff --git a/po/de_DE.po b/po/de_DE.po
index dec68c9ee8..dcdcf229dd 100644
--- a/po/de_DE.po
+++ b/po/de_DE.po
@@ -6,7 +6,7 @@ msgid ""
msgstr ""
"Project-Id-Version: QEMU 1.4.50\n"
"Report-Msgid-Bugs-To: qemu-devel@nongnu.org\n"
-"POT-Creation-Date: 2013-07-05 22:36+0200\n"
+"POT-Creation-Date: 2014-07-17 20:39+0200\n"
"PO-Revision-Date: 2012-02-28 16:00+0100\n"
"Last-Translator: Kevin Wolf <kwolf@redhat.com>\n"
"Language-Team: Deutsch <de@li.org>\n"
@@ -16,49 +16,70 @@ msgstr ""
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n!=1);\n"
-#: ui/gtk.c:214
+#: ui/gtk.c:321
msgid " - Press Ctrl+Alt+G to release grab"
msgstr " - Strg+Alt+G drücken, um Eingabegeräte freizugeben"
-#: ui/gtk.c:218
+#: ui/gtk.c:325
msgid " [Paused]"
msgstr " [Angehalten]"
-#: ui/gtk.c:1318
+#: ui/gtk.c:1601
msgid "_Pause"
msgstr "_Angehalten"
-#: ui/gtk.c:1324
+#: ui/gtk.c:1607
msgid "_Reset"
msgstr "_Reset"
-#: ui/gtk.c:1327
+#: ui/gtk.c:1610
msgid "Power _Down"
msgstr "_Herunterfahren"
-#: ui/gtk.c:1381
+#: ui/gtk.c:1616
+msgid "_Quit"
+msgstr "_Beenden"
+
+#: ui/gtk.c:1692
+msgid "_Fullscreen"
+msgstr "_Vollbild"
+
+#: ui/gtk.c:1702
+msgid "Zoom _In"
+msgstr "_Heranzoomen"
+
+#: ui/gtk.c:1709
+msgid "Zoom _Out"
+msgstr "_Wegzoomen"
+
+#: ui/gtk.c:1716
+msgid "Best _Fit"
+msgstr "_Einpassen"
+
+#: ui/gtk.c:1723
msgid "Zoom To _Fit"
msgstr "Auf _Fenstergröße skalieren"
-#: ui/gtk.c:1387
+#: ui/gtk.c:1729
msgid "Grab On _Hover"
msgstr "Tastatur _automatisch einfangen"
-#: ui/gtk.c:1390
+#: ui/gtk.c:1732
msgid "_Grab Input"
msgstr "_Eingabegeräte einfangen"
-#: ui/gtk.c:1416
+#: ui/gtk.c:1761
msgid "Show _Tabs"
-msgstr "_Tableiste anzeigen"
+msgstr "Reiter anzeigen"
+
+#: ui/gtk.c:1764
+msgid "Detach Tab"
+msgstr "Reiter abtrennen"
-#: ui/gtk.c:1430
+#: ui/gtk.c:1778
msgid "_Machine"
msgstr "_Maschine"
-#: ui/gtk.c:1435
+#: ui/gtk.c:1783
msgid "_View"
msgstr "_Ansicht"
-
-#~ msgid "_File"
-#~ msgstr "_Datei"
diff --git a/po/fr_FR.po b/po/fr_FR.po
index ec54eb95a8..bbb5ef87b3 100644
--- a/po/fr_FR.po
+++ b/po/fr_FR.po
@@ -1,13 +1,13 @@
# French translation for QEMU.
# This file is put in the public domain.
#
-# Aurelien Jarno <aurelien@aurel32.net>, 2013.
+# Aurelien Jarno <aurelien@aurel32.net>, 2013, 2014.
msgid ""
msgstr ""
"Project-Id-Version: QEMU 1.4.50\n"
"Report-Msgid-Bugs-To: qemu-devel@nongnu.org\n"
-"POT-Creation-Date: 2013-07-05 22:36+0200\n"
-"PO-Revision-Date: 2013-03-31 19:39+0200\n"
+"POT-Creation-Date: 2014-07-28 23:14+0200\n"
+"PO-Revision-Date: 2014-07-28 23:25+0200\n"
"Last-Translator: Aurelien Jarno <aurelien@aurel32.net>\n"
"Language-Team: French <FR@li.org>\n"
"Language: fr\n"
@@ -17,46 +17,70 @@ msgstr ""
"Plural-Forms: nplurals=2; plural=n != 1;\n"
"X-Generator: Lokalize 1.4\n"
-#: ui/gtk.c:214
+#: ui/gtk.c:321
msgid " - Press Ctrl+Alt+G to release grab"
msgstr "- Appuyer sur Ctrl+Alt+G pour arrêter la capture"
-#: ui/gtk.c:218
+#: ui/gtk.c:325
msgid " [Paused]"
msgstr " [En pause]"
-#: ui/gtk.c:1318
+#: ui/gtk.c:1601
msgid "_Pause"
msgstr "_Pause"
-#: ui/gtk.c:1324
+#: ui/gtk.c:1607
msgid "_Reset"
msgstr "_Réinitialiser"
-#: ui/gtk.c:1327
+#: ui/gtk.c:1610
msgid "Power _Down"
msgstr "_Éteindre"
-#: ui/gtk.c:1381
+#: ui/gtk.c:1616
+msgid "_Quit"
+msgstr "_Quitter"
+
+#: ui/gtk.c:1692
+msgid "_Fullscreen"
+msgstr "Mode _plein écran"
+
+#: ui/gtk.c:1702
+msgid "Zoom _In"
+msgstr "Zoom _avant"
+
+#: ui/gtk.c:1709
+msgid "Zoom _Out"
+msgstr "_Zoom arrière"
+
+#: ui/gtk.c:1716
+msgid "Best _Fit"
+msgstr "Zoom _idéal"
+
+#: ui/gtk.c:1723
msgid "Zoom To _Fit"
-msgstr "Zoomer pour _ajuster"
+msgstr "Zoomer pour a_juster"
-#: ui/gtk.c:1387
+#: ui/gtk.c:1729
msgid "Grab On _Hover"
msgstr "Capturer en _survolant"
-#: ui/gtk.c:1390
+#: ui/gtk.c:1732
msgid "_Grab Input"
msgstr "_Capturer les entrées"
-#: ui/gtk.c:1416
+#: ui/gtk.c:1761
msgid "Show _Tabs"
msgstr "Montrer les _onglets"
-#: ui/gtk.c:1430
+#: ui/gtk.c:1764
+msgid "Detach Tab"
+msgstr "_Détacher l'onglet"
+
+#: ui/gtk.c:1778
msgid "_Machine"
msgstr "_Machine"
-#: ui/gtk.c:1435
+#: ui/gtk.c:1783
msgid "_View"
msgstr "_Vue"
diff --git a/po/it.po b/po/it.po
index a62665cb22..e46fb3a8bc 100644
--- a/po/it.po
+++ b/po/it.po
@@ -1,13 +1,13 @@
# Italian translation for QEMU.
# This file is put in the public domain.
-# Paolo Bonzini <pbonzini@redhat.com>, 2012.
+# Paolo Bonzini <pbonzini@redhat.com>, 2012-2014.
#
msgid ""
msgstr ""
"Project-Id-Version: QEMU 1.4.50\n"
"Report-Msgid-Bugs-To: qemu-devel@nongnu.org\n"
-"POT-Creation-Date: 2013-07-05 22:36+0200\n"
-"PO-Revision-Date: 2012-02-27 08:23+0100\n"
+"POT-Creation-Date: 2014-07-29 08:14+0200\n"
+"PO-Revision-Date: 2014-07-29 08:25+0200\n"
"Last-Translator: Paolo Bonzini <pbonzini@redhat.com>\n"
"Language-Team: Italian <it@li.org>\n"
"Language: it\n"
@@ -16,49 +16,66 @@ msgstr ""
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
-#: ui/gtk.c:214
+#: ui/gtk.c:321
msgid " - Press Ctrl+Alt+G to release grab"
-msgstr ""
+msgstr " - Premere Ctrl+Alt+G per rilasciare l'input"
-#: ui/gtk.c:218
+#: ui/gtk.c:325
msgid " [Paused]"
-msgstr ""
+msgstr " [Pausa]"
-#: ui/gtk.c:1318
+#: ui/gtk.c:1601
msgid "_Pause"
-msgstr ""
+msgstr "_Pausa"
-#: ui/gtk.c:1324
+#: ui/gtk.c:1607
msgid "_Reset"
-msgstr ""
+msgstr "_Reset"
-#: ui/gtk.c:1327
+#: ui/gtk.c:1610
msgid "Power _Down"
-msgstr ""
+msgstr "_Spegni"
+
+#: ui/gtk.c:1616
+msgid "_Quit"
+msgstr "_Esci"
-#: ui/gtk.c:1381
+#: ui/gtk.c:1702
+msgid "Zoom _In"
+msgstr "_Aumenta zoom"
+
+#: ui/gtk.c:1709
+msgid "Zoom _Out"
+msgstr "_Riduci zoom"
+
+#: ui/gtk.c:1716
+msgid "Best _Fit"
+msgstr "A_nnulla zoom"
+
+#: ui/gtk.c:1723
msgid "Zoom To _Fit"
msgstr "Adatta alla _finestra"
-#: ui/gtk.c:1387
+#: ui/gtk.c:1729
msgid "Grab On _Hover"
msgstr "Cattura _automatica input"
-#: ui/gtk.c:1390
+#: ui/gtk.c:1732
msgid "_Grab Input"
msgstr "_Cattura input"
-#: ui/gtk.c:1416
+#: ui/gtk.c:1761
msgid "Show _Tabs"
msgstr "Mostra _tab"
-#: ui/gtk.c:1430
+#: ui/gtk.c:1764
+msgid "Detach Tab"
+msgstr "_Sposta in una nuova finestra"
+
+#: ui/gtk.c:1778
msgid "_Machine"
-msgstr ""
+msgstr "_Macchina virtuale"
-#: ui/gtk.c:1435
+#: ui/gtk.c:1783
msgid "_View"
msgstr "_Visualizza"
-
-#~ msgid "_File"
-#~ msgstr "_File"
diff --git a/po/zh_CN.po b/po/zh_CN.po
new file mode 100644
index 0000000000..2b1d42e97b
--- /dev/null
+++ b/po/zh_CN.po
@@ -0,0 +1,86 @@
+# Chinese translation for QEMU.
+# This file is put in the public domain.
+#
+# Fam Zheng <famz@redhat.com>, 2014
+msgid ""
+msgstr ""
+"Project-Id-Version: QEMU 2.2\n"
+"Report-Msgid-Bugs-To: qemu-devel@nongnu.org\n"
+"POT-Creation-Date: 2014-07-31 10:03+0800\n"
+"PO-Revision-Date: 2014-07-31 10:00+0800\n"
+"Last-Translator: Fam Zheng <famz@redhat.com>\n"
+"Language-Team: Chinese <zh@li.org>\n"
+"Language: zh\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=n != 1;\n"
+"X-Generator: Lokalize 1.4\n"
+
+#: ui/gtk.c:321
+msgid " - Press Ctrl+Alt+G to release grab"
+msgstr " - 按下 Ctrl+Alt+G 取消捕获"
+
+#: ui/gtk.c:325
+msgid " [Paused]"
+msgstr " [已暂停]"
+
+#: ui/gtk.c:1601
+msgid "_Pause"
+msgstr "暂停(_P)"
+
+#: ui/gtk.c:1607
+msgid "_Reset"
+msgstr "重置(_R)"
+
+#: ui/gtk.c:1610
+msgid "Power _Down"
+msgstr "关闭电源(_D)"
+
+#: ui/gtk.c:1616
+msgid "_Quit"
+msgstr "退出(_Q)"
+
+#: ui/gtk.c:1692
+msgid "_Fullscreen"
+msgstr "全屏(_F)"
+
+#: ui/gtk.c:1702
+msgid "Zoom _In"
+msgstr "放大(_I)"
+
+#: ui/gtk.c:1709
+msgid "Zoom _Out"
+msgstr "缩小(_O)"
+
+#: ui/gtk.c:1716
+msgid "Best _Fit"
+msgstr "最合适大小(_F)"
+
+#: ui/gtk.c:1723
+msgid "Zoom To _Fit"
+msgstr "缩放以适应大小(_F)"
+
+#: ui/gtk.c:1729
+msgid "Grab On _Hover"
+msgstr "鼠标经过时捕获(_H)"
+
+#: ui/gtk.c:1732
+msgid "_Grab Input"
+msgstr "捕获输入(_G)"
+
+#: ui/gtk.c:1761
+msgid "Show _Tabs"
+msgstr "显示标签页(_T)"
+
+#: ui/gtk.c:1764
+msgid "Detach Tab"
+msgstr "分离标签页"
+
+#: ui/gtk.c:1778
+msgid "_Machine"
+msgstr "虚拟机(_M)"
+
+#: ui/gtk.c:1783
+msgid "_View"
+msgstr "视图(_V)"
diff --git a/qapi-schema.json b/qapi-schema.json
index b11aad2068..341f417a5f 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -2749,7 +2749,7 @@
#
# Configuration info for the new chardev backend.
#
-# Since: 1.4
+# Since: 1.4 (testdev since 2.2)
##
{ 'type': 'ChardevDummy', 'data': { } }
@@ -2764,6 +2764,7 @@
'mux' : 'ChardevMux',
'msmouse': 'ChardevDummy',
'braille': 'ChardevDummy',
+ 'testdev': 'ChardevDummy',
'stdio' : 'ChardevStdio',
'console': 'ChardevDummy',
'spicevmc' : 'ChardevSpiceChannel',
diff --git a/qapi/block-core.json b/qapi/block-core.json
index e378653a77..fb74c56e32 100644
--- a/qapi/block-core.json
+++ b/qapi/block-core.json
@@ -115,6 +115,8 @@
# @format-specific: #optional structure supplying additional format-specific
# information (since 1.7)
#
+# @nocow: #optional info of whether NOCOW flag is set or not. (since 2.2)
+#
# Since: 1.3
#
##
@@ -126,7 +128,8 @@
'*backing-filename': 'str', '*full-backing-filename': 'str',
'*backing-filename-format': 'str', '*snapshots': ['SnapshotInfo'],
'*backing-image': 'ImageInfo',
- '*format-specific': 'ImageInfoSpecific' } }
+ '*format-specific': 'ImageInfoSpecific',
+ '*nocow': 'bool' } }
##
# @ImageCheck:
@@ -194,6 +197,7 @@
# 'file', 'file', 'ftp', 'ftps', 'host_cdrom', 'host_device',
# 'host_floppy', 'http', 'https', 'nbd', 'parallels', 'qcow',
# 'qcow2', 'raw', 'tftp', 'vdi', 'vmdk', 'vpc', 'vvfat'
+# 2.2: 'archipelago'
#
# @backing_file: #optional the name of the backing file (for copy-on-write)
#
@@ -1143,7 +1147,7 @@
# Since: 2.0
##
{ 'enum': 'BlockdevDriver',
- 'data': [ 'file', 'host_device', 'host_cdrom', 'host_floppy',
+ 'data': [ 'archipelago', 'file', 'host_device', 'host_cdrom', 'host_floppy',
'http', 'https', 'ftp', 'ftps', 'tftp', 'vvfat', 'blkdebug',
'blkverify', 'bochs', 'cloop', 'cow', 'dmg', 'parallels', 'qcow',
'qcow2', 'qed', 'raw', 'vdi', 'vhdx', 'vmdk', 'vpc', 'quorum' ] }
@@ -1273,6 +1277,37 @@
'*pass-discard-snapshot': 'bool',
'*pass-discard-other': 'bool' } }
+
+##
+# @BlockdevOptionsArchipelago
+#
+# Driver specific block device options for Archipelago.
+#
+# @volume: Name of the Archipelago volume image
+#
+# @mport: #optional The port number on which mapperd is
+# listening. This is optional
+# and if not specified, QEMU will make Archipelago
+# use the default port (1001).
+#
+# @vport: #optional The port number on which vlmcd is
+# listening. This is optional
+# and if not specified, QEMU will make Archipelago
+# use the default port (501).
+#
+# @segment: #optional The name of the shared memory segment
+# Archipelago stack is using. This is optional
+# and if not specified, QEMU will make Archipelago
+# use the default value, 'archipelago'.
+# Since: 2.2
+##
+{ 'type': 'BlockdevOptionsArchipelago',
+ 'data': { 'volume': 'str',
+ '*mport': 'int',
+ '*vport': 'int',
+ '*segment': 'str' } }
+
+
##
# @BlkdebugEvent
#
@@ -1416,6 +1451,7 @@
'base': 'BlockdevOptionsBase',
'discriminator': 'driver',
'data': {
+ 'archipelago':'BlockdevOptionsArchipelago',
'file': 'BlockdevOptionsFile',
'host_device':'BlockdevOptionsFile',
'host_cdrom': 'BlockdevOptionsFile',
diff --git a/qdev-monitor.c b/qdev-monitor.c
index f87f3d89cd..fb9ee24b3a 100644
--- a/qdev-monitor.c
+++ b/qdev-monitor.c
@@ -182,9 +182,10 @@ static const char *find_typename_by_alias(const char *alias)
int qdev_device_help(QemuOpts *opts)
{
+ Error *local_err = NULL;
const char *driver;
- Property *prop;
- ObjectClass *klass;
+ DevicePropertyInfoList *prop_list;
+ DevicePropertyInfoList *prop;
driver = qemu_opt_get(opts, "driver");
if (driver && is_help_option(driver)) {
@@ -196,35 +197,28 @@ int qdev_device_help(QemuOpts *opts)
return 0;
}
- klass = object_class_by_name(driver);
- if (!klass) {
+ if (!object_class_by_name(driver)) {
const char *typename = find_typename_by_alias(driver);
if (typename) {
driver = typename;
- klass = object_class_by_name(driver);
}
}
- if (!object_class_dynamic_cast(klass, TYPE_DEVICE)) {
- return 0;
+ prop_list = qmp_device_list_properties(driver, &local_err);
+ if (!prop_list) {
+ error_printf("%s\n", error_get_pretty(local_err));
+ error_free(local_err);
+ return 1;
}
- do {
- for (prop = DEVICE_CLASS(klass)->props; prop && prop->name; prop++) {
- /*
- * TODO Properties without a parser are just for dirty hacks.
- * qdev_prop_ptr is the only such PropertyInfo. It's marked
- * for removal. This conditional should be removed along with
- * it.
- */
- if (!prop->info->set) {
- continue; /* no way to set it, don't show */
- }
- error_printf("%s.%s=%s\n", driver, prop->name,
- prop->info->legacy_name ?: prop->info->name);
- }
- klass = object_class_get_parent(klass);
- } while (klass != object_class_by_name(TYPE_DEVICE));
+
+ for (prop = prop_list; prop; prop = prop->next) {
+ error_printf("%s.%s=%s\n", driver,
+ prop->value->name,
+ prop->value->type);
+ }
+
+ qapi_free_DevicePropertyInfoList(prop_list);
return 1;
}
@@ -694,7 +688,7 @@ void qmp_device_del(const char *id, Error **errp)
DeviceState *dev;
dev = qdev_find_recursive(sysbus_get_default(), id);
- if (NULL == dev) {
+ if (!dev) {
error_set(errp, QERR_DEVICE_NOT_FOUND, id);
return;
}
diff --git a/qemu-char.c b/qemu-char.c
index 7acc03f161..d4f327ab6d 100644
--- a/qemu-char.c
+++ b/qemu-char.c
@@ -975,7 +975,7 @@ static CharDriverState *qemu_chr_open_fd(int fd_in, int fd_out)
s = g_malloc0(sizeof(FDCharDriver));
s->fd_in = io_channel_from_fd(fd_in);
s->fd_out = io_channel_from_fd(fd_out);
- fcntl(fd_out, F_SETFL, O_NONBLOCK);
+ qemu_set_nonblock(fd_out);
s->chr = chr;
chr->opaque = s;
chr->chr_add_watch = fd_chr_add_watch;
@@ -1062,7 +1062,7 @@ static CharDriverState *qemu_chr_open_stdio(ChardevStdio *opts)
}
old_fd0_flags = fcntl(0, F_GETFL);
tcgetattr (0, &oldtty);
- fcntl(0, F_SETFL, O_NONBLOCK);
+ qemu_set_nonblock(0);
atexit(term_exit);
chr = qemu_chr_open_fd(0, 1);
@@ -1168,6 +1168,9 @@ static int pty_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
static GSource *pty_chr_add_watch(CharDriverState *chr, GIOCondition cond)
{
PtyCharDriver *s = chr->opaque;
+ if (!s->connected) {
+ return NULL;
+ }
return g_io_create_watch(s->fd, cond);
}
@@ -3253,6 +3256,7 @@ QemuOpts *qemu_chr_parse_compat(const char *label, const char *filename)
strcmp(filename, "pty") == 0 ||
strcmp(filename, "msmouse") == 0 ||
strcmp(filename, "braille") == 0 ||
+ strcmp(filename, "testdev") == 0 ||
strcmp(filename, "stdio") == 0) {
qemu_opt_set(opts, "backend", filename);
return opts;
@@ -3664,6 +3668,10 @@ int qemu_chr_fe_add_watch(CharDriverState *s, GIOCondition cond,
}
src = s->chr_add_watch(s, cond);
+ if (!src) {
+ return -EINVAL;
+ }
+
g_source_set_callback(src, (GSourceFunc)func, user_data, NULL);
tag = g_source_attach(src, NULL);
g_source_unref(src);
@@ -4050,6 +4058,9 @@ ChardevReturn *qmp_chardev_add(const char *id, ChardevBackend *backend,
chr = chr_baum_init();
break;
#endif
+ case CHARDEV_BACKEND_KIND_TESTDEV:
+ chr = chr_testdev_init();
+ break;
case CHARDEV_BACKEND_KIND_STDIO:
chr = qemu_chr_open_stdio(backend->stdio);
break;
@@ -4110,7 +4121,7 @@ void qmp_chardev_remove(const char *id, Error **errp)
CharDriverState *chr;
chr = qemu_chr_find(id);
- if (NULL == chr) {
+ if (chr == NULL) {
error_setg(errp, "Chardev '%s' not found", id);
return;
}
diff --git a/qemu-coroutine.c b/qemu-coroutine.c
index 470852100a..bd574aa1b5 100644
--- a/qemu-coroutine.c
+++ b/qemu-coroutine.c
@@ -19,14 +19,14 @@
#include "block/coroutine_int.h"
enum {
- /* Maximum free pool size prevents holding too many freed coroutines */
- POOL_MAX_SIZE = 64,
+ POOL_DEFAULT_SIZE = 64,
};
/** Free list to speed up creation */
static QemuMutex pool_lock;
static QSLIST_HEAD(, Coroutine) pool = QSLIST_HEAD_INITIALIZER(pool);
static unsigned int pool_size;
+static unsigned int pool_max_size = POOL_DEFAULT_SIZE;
Coroutine *qemu_coroutine_create(CoroutineEntry *entry)
{
@@ -55,7 +55,7 @@ static void coroutine_delete(Coroutine *co)
{
if (CONFIG_COROUTINE_POOL) {
qemu_mutex_lock(&pool_lock);
- if (pool_size < POOL_MAX_SIZE) {
+ if (pool_size < pool_max_size) {
QSLIST_INSERT_HEAD(&pool, co, pool_next);
co->caller = NULL;
pool_size++;
@@ -137,3 +137,23 @@ void coroutine_fn qemu_coroutine_yield(void)
self->caller = NULL;
coroutine_swap(self, to);
}
+
+void qemu_coroutine_adjust_pool_size(int n)
+{
+ qemu_mutex_lock(&pool_lock);
+
+ pool_max_size += n;
+
+ /* Callers should never take away more than they added */
+ assert(pool_max_size >= POOL_DEFAULT_SIZE);
+
+ /* Trim oversized pool down to new max */
+ while (pool_size > pool_max_size) {
+ Coroutine *co = QSLIST_FIRST(&pool);
+ QSLIST_REMOVE_HEAD(&pool, pool_next);
+ pool_size--;
+ qemu_coroutine_delete(co);
+ }
+
+ qemu_mutex_unlock(&pool_lock);
+}
diff --git a/qemu-doc.texi b/qemu-doc.texi
index 551619abd7..2b232ae8b7 100644
--- a/qemu-doc.texi
+++ b/qemu-doc.texi
@@ -1205,9 +1205,16 @@ In order to check that the user mode network is working, you can ping
the address 10.0.2.2 and verify that you got an address in the range
10.0.2.x from the QEMU virtual DHCP server.
-Note that @code{ping} is not supported reliably to the internet as it
-would require root privileges. It means you can only ping the local
-router (10.0.2.2).
+Note that ICMP traffic in general does not work with user mode networking.
+@code{ping}, aka. ICMP echo, to the local router (10.0.2.2) shall work,
+however. If you're using QEMU on Linux >= 3.0, it can use unprivileged ICMP
+ping sockets to allow @code{ping} to the Internet. The host admin has to set
+the ping_group_range in order to grant access to those sockets. To allow ping
+for GID 100 (usually users group):
+
+@example
+echo 100 100 > /proc/sys/net/ipv4/ping_group_range
+@end example
When using the built-in TFTP server, the router is also the TFTP
server.
diff --git a/qemu-img.c b/qemu-img.c
index c98896b281..18caa4b450 100644
--- a/qemu-img.c
+++ b/qemu-img.c
@@ -185,15 +185,20 @@ static int GCC_FMT_ATTR(2, 3) qprintf(bool quiet, const char *fmt, ...)
static int read_password(char *buf, int buf_size)
{
int c, i;
+
printf("Password: ");
fflush(stdout);
i = 0;
for(;;) {
c = getchar();
- if (c == '\n')
+ if (c < 0) {
+ buf[i] = '\0';
+ return -1;
+ } else if (c == '\n') {
break;
- if (i < (buf_size - 1))
+ } else if (i < (buf_size - 1)) {
buf[i++] = c;
+ }
}
buf[i] = '\0';
return 0;
@@ -246,7 +251,6 @@ static int read_password(char *buf, int buf_size)
if (errno == EAGAIN || errno == EINTR) {
continue;
} else {
- ret = -1;
break;
}
} else if (ret == 0) {
@@ -956,7 +960,6 @@ static int img_compare(int argc, char **argv)
int64_t sector_num = 0;
int64_t nb_sectors;
int c, pnum;
- uint64_t bs_sectors;
uint64_t progress_base;
for (;;) {
@@ -1018,10 +1021,20 @@ static int img_compare(int argc, char **argv)
buf1 = qemu_blockalign(bs1, IO_BUF_SIZE);
buf2 = qemu_blockalign(bs2, IO_BUF_SIZE);
- bdrv_get_geometry(bs1, &bs_sectors);
- total_sectors1 = bs_sectors;
- bdrv_get_geometry(bs2, &bs_sectors);
- total_sectors2 = bs_sectors;
+ total_sectors1 = bdrv_nb_sectors(bs1);
+ if (total_sectors1 < 0) {
+ error_report("Can't get size of %s: %s",
+ filename1, strerror(-total_sectors1));
+ ret = 4;
+ goto out;
+ }
+ total_sectors2 = bdrv_nb_sectors(bs2);
+ if (total_sectors2 < 0) {
+ error_report("Can't get size of %s: %s",
+ filename2, strerror(-total_sectors2));
+ ret = 4;
+ goto out;
+ }
total_sectors = MIN(total_sectors1, total_sectors2);
progress_base = MAX(total_sectors1, total_sectors2);
@@ -1183,7 +1196,7 @@ static int img_convert(int argc, char **argv)
BlockDriver *drv, *proto_drv;
BlockDriverState **bs = NULL, *out_bs = NULL;
int64_t total_sectors, nb_sectors, sector_num, bs_offset;
- uint64_t bs_sectors;
+ int64_t *bs_sectors = NULL;
uint8_t * buf = NULL;
size_t bufsectors = IO_BUF_SIZE / BDRV_SECTOR_SIZE;
const uint8_t *buf1;
@@ -1324,7 +1337,8 @@ static int img_convert(int argc, char **argv)
qemu_progress_print(0, 100);
- bs = g_malloc0(bs_n * sizeof(BlockDriverState *));
+ bs = g_new0(BlockDriverState *, bs_n);
+ bs_sectors = g_new(int64_t, bs_n);
total_sectors = 0;
for (bs_i = 0; bs_i < bs_n; bs_i++) {
@@ -1338,8 +1352,14 @@ static int img_convert(int argc, char **argv)
ret = -1;
goto out;
}
- bdrv_get_geometry(bs[bs_i], &bs_sectors);
- total_sectors += bs_sectors;
+ bs_sectors[bs_i] = bdrv_nb_sectors(bs[bs_i]);
+ if (bs_sectors[bs_i] < 0) {
+ error_report("Could not get size of %s: %s",
+ argv[optind + bs_i], strerror(-bs_sectors[bs_i]));
+ ret = -1;
+ goto out;
+ }
+ total_sectors += bs_sectors[bs_i];
}
if (sn_opts) {
@@ -1457,7 +1477,6 @@ static int img_convert(int argc, char **argv)
bs_i = 0;
bs_offset = 0;
- bdrv_get_geometry(bs[0], &bs_sectors);
/* increase bufsectors from the default 4096 (2M) if opt_transfer_length
* or discard_alignment of the out_bs is greater. Limit to 32768 (16MB)
@@ -1470,13 +1489,13 @@ static int img_convert(int argc, char **argv)
buf = qemu_blockalign(out_bs, bufsectors * BDRV_SECTOR_SIZE);
if (skip_create) {
- int64_t output_length = bdrv_getlength(out_bs);
- if (output_length < 0) {
+ int64_t output_sectors = bdrv_nb_sectors(out_bs);
+ if (output_sectors < 0) {
error_report("unable to get output image length: %s\n",
- strerror(-output_length));
+ strerror(-output_sectors));
ret = -1;
goto out;
- } else if (output_length < total_sectors << BDRV_SECTOR_BITS) {
+ } else if (output_sectors < total_sectors) {
error_report("output file is smaller than input file");
ret = -1;
goto out;
@@ -1524,19 +1543,19 @@ static int img_convert(int argc, char **argv)
buf2 = buf;
while (remainder > 0) {
int nlow;
- while (bs_num == bs_sectors) {
+ while (bs_num == bs_sectors[bs_i]) {
+ bs_offset += bs_sectors[bs_i];
bs_i++;
assert (bs_i < bs_n);
- bs_offset += bs_sectors;
- bdrv_get_geometry(bs[bs_i], &bs_sectors);
bs_num = 0;
/* printf("changing part: sector_num=%" PRId64 ", "
"bs_i=%d, bs_offset=%" PRId64 ", bs_sectors=%" PRId64
- "\n", sector_num, bs_i, bs_offset, bs_sectors); */
+ "\n", sector_num, bs_i, bs_offset, bs_sectors[bs_i]); */
}
- assert (bs_num < bs_sectors);
+ assert (bs_num < bs_sectors[bs_i]);
- nlow = (remainder > bs_sectors - bs_num) ? bs_sectors - bs_num : remainder;
+ nlow = remainder > bs_sectors[bs_i] - bs_num
+ ? bs_sectors[bs_i] - bs_num : remainder;
ret = bdrv_read(bs[bs_i], bs_num, buf2, nlow);
if (ret < 0) {
@@ -1597,14 +1616,13 @@ restart:
break;
}
- while (sector_num - bs_offset >= bs_sectors) {
+ while (sector_num - bs_offset >= bs_sectors[bs_i]) {
+ bs_offset += bs_sectors[bs_i];
bs_i ++;
assert (bs_i < bs_n);
- bs_offset += bs_sectors;
- bdrv_get_geometry(bs[bs_i], &bs_sectors);
/* printf("changing part: sector_num=%" PRId64 ", bs_i=%d, "
"bs_offset=%" PRId64 ", bs_sectors=%" PRId64 "\n",
- sector_num, bs_i, bs_offset, bs_sectors); */
+ sector_num, bs_i, bs_offset, bs_sectors[bs_i]); */
}
if ((out_baseimg || has_zero_init) &&
@@ -1657,7 +1675,7 @@ restart:
}
}
- n = MIN(n, bs_sectors - (sector_num - bs_offset));
+ n = MIN(n, bs_sectors[bs_i] - (sector_num - bs_offset));
sectors_read += n;
if (count_allocated_sectors) {
@@ -1715,6 +1733,7 @@ out:
}
g_free(bs);
}
+ g_free(bs_sectors);
fail_getopt:
g_free(options);
@@ -2414,9 +2433,9 @@ static int img_rebase(int argc, char **argv)
* the image is the same as the original one at any time.
*/
if (!unsafe) {
- uint64_t num_sectors;
- uint64_t old_backing_num_sectors;
- uint64_t new_backing_num_sectors = 0;
+ int64_t num_sectors;
+ int64_t old_backing_num_sectors;
+ int64_t new_backing_num_sectors = 0;
uint64_t sector;
int n;
uint8_t * buf_old;
@@ -2426,10 +2445,31 @@ static int img_rebase(int argc, char **argv)
buf_old = qemu_blockalign(bs, IO_BUF_SIZE);
buf_new = qemu_blockalign(bs, IO_BUF_SIZE);
- bdrv_get_geometry(bs, &num_sectors);
- bdrv_get_geometry(bs_old_backing, &old_backing_num_sectors);
+ num_sectors = bdrv_nb_sectors(bs);
+ if (num_sectors < 0) {
+ error_report("Could not get size of '%s': %s",
+ filename, strerror(-num_sectors));
+ ret = -1;
+ goto out;
+ }
+ old_backing_num_sectors = bdrv_nb_sectors(bs_old_backing);
+ if (old_backing_num_sectors < 0) {
+ char backing_name[1024];
+
+ bdrv_get_backing_filename(bs, backing_name, sizeof(backing_name));
+ error_report("Could not get size of '%s': %s",
+ backing_name, strerror(-old_backing_num_sectors));
+ ret = -1;
+ goto out;
+ }
if (bs_new_backing) {
- bdrv_get_geometry(bs_new_backing, &new_backing_num_sectors);
+ new_backing_num_sectors = bdrv_nb_sectors(bs_new_backing);
+ if (new_backing_num_sectors < 0) {
+ error_report("Could not get size of '%s': %s",
+ out_baseimg, strerror(-new_backing_num_sectors));
+ ret = -1;
+ goto out;
+ }
}
if (num_sectors != 0) {
diff --git a/qemu-options.hx b/qemu-options.hx
index 9e5468678b..c573dd8893 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -427,7 +427,7 @@ DEF("drive", HAS_ARG, QEMU_OPTION_drive,
" [,serial=s][,addr=A][,rerror=ignore|stop|report]\n"
" [,werror=ignore|stop|report|enospc][,id=name][,aio=threads|native]\n"
" [,readonly=on|off][,copy-on-read=on|off]\n"
- " [,detect-zeroes=on|off|unmap]\n"
+ " [,discard=ignore|unmap][,detect-zeroes=on|off|unmap]\n"
" [[,bps=b]|[[,bps_rd=r][,bps_wr=w]]]\n"
" [[,iops=i]|[[,iops_rd=r][,iops_wr=w]]]\n"
" [[,bps_max=bm]|[[,bps_rd_max=rm][,bps_wr_max=wm]]]\n"
@@ -1437,14 +1437,14 @@ DEF("net", HAS_ARG, QEMU_OPTION_net,
"-net l2tpv3[,vlan=n][,name=str],src=srcaddr,dst=dstaddr[,srcport=srcport][,dstport=dstport],txsession=txsession[,rxsession=rxsession][,ipv6=on/off][,udp=on/off][,cookie64=on/off][,counter][,pincounter][,txcookie=txcookie][,rxcookie=rxcookie][,offset=offset]\n"
" connect the VLAN to an Ethernet over L2TPv3 pseudowire\n"
" Linux kernel 3.3+ as well as most routers can talk\n"
- " L2TPv3. This transport allows to connect a VM to a VM,\n"
+ " L2TPv3. This transport allows connecting a VM to a VM,\n"
" VM to a router and even VM to Host. It is a nearly-universal\n"
" standard (RFC3391). Note - this implementation uses static\n"
" pre-configured tunnels (same as the Linux kernel).\n"
" use 'src=' to specify source address\n"
" use 'dst=' to specify destination address\n"
" use 'udp=on' to specify udp encapsulation\n"
- " use 'dstport=' to specify destination udp port\n"
+ " use 'srcport=' to specify source udp port\n"
" use 'dstport=' to specify destination udp port\n"
" use 'ipv6=on' to force v6\n"
" L2TPv3 uses cookies to prevent misconfiguration as\n"
@@ -1926,7 +1926,7 @@ ETEXI
DEF("chardev", HAS_ARG, QEMU_OPTION_chardev,
"-chardev null,id=id[,mux=on|off]\n"
- "-chardev socket,id=id[,host=host],port=host[,to=to][,ipv4][,ipv6][,nodelay]\n"
+ "-chardev socket,id=id[,host=host],port=port[,to=to][,ipv4][,ipv6][,nodelay]\n"
" [,server][,nowait][,telnet][,mux=on|off] (tcp)\n"
"-chardev socket,id=id,path=path[,server][,nowait][,telnet],[mux=on|off] (unix)\n"
"-chardev udp,id=id[,host=host],port=port[,localaddr=localaddr]\n"
@@ -3011,11 +3011,11 @@ re-inject them.
ETEXI
DEF("icount", HAS_ARG, QEMU_OPTION_icount, \
- "-icount [N|auto]\n" \
+ "-icount [shift=N|auto][,align=on|off]\n" \
" enable virtual instruction counter with 2^N clock ticks per\n" \
- " instruction\n", QEMU_ARCH_ALL)
+ " instruction and enable aligning the host and virtual clocks\n", QEMU_ARCH_ALL)
STEXI
-@item -icount [@var{N}|auto]
+@item -icount [shift=@var{N}|auto]
@findex -icount
Enable virtual instruction counter. The virtual cpu will execute one
instruction every 2^@var{N} ns of virtual time. If @code{auto} is specified
@@ -3026,6 +3026,17 @@ Note that while this option can give deterministic behavior, it does not
provide cycle accurate emulation. Modern CPUs contain superscalar out of
order cores with complex cache hierarchies. The number of instructions
executed often has little or no correlation with actual performance.
+
+@option{align=on} will activate the delay algorithm which will try to
+to synchronise the host clock and the virtual clock. The goal is to
+have a guest running at the real frequency imposed by the shift option.
+Whenever the guest clock is behind the host clock and if
+@option{align=on} is specified then we print a messsage to the user
+to inform about the delay.
+Currently this option does not work when @option{shift} is @code{auto}.
+Note: The sync algorithm will work for those shift values for which
+the guest clock runs ahead of the host clock. Typically this happens
+when the shift value is high (how high depends on the host machine).
ETEXI
DEF("watchdog", HAS_ARG, QEMU_OPTION_watchdog, \
diff --git a/qga/channel-posix.c b/qga/channel-posix.c
index e65dda3822..8aad4fee9f 100644
--- a/qga/channel-posix.c
+++ b/qga/channel-posix.c
@@ -42,7 +42,7 @@ static gboolean ga_channel_listen_accept(GIOChannel *channel,
g_warning("error converting fd to gsocket: %s", strerror(errno));
goto out;
}
- fcntl(client_fd, F_SETFL, O_NONBLOCK);
+ qemu_set_nonblock(client_fd);
ret = ga_channel_client_add(c, client_fd);
if (ret) {
g_warning("error setting up connection");
diff --git a/qga/commands-posix.c b/qga/commands-posix.c
index 34ddba0531..7eed7f4592 100644
--- a/qga/commands-posix.c
+++ b/qga/commands-posix.c
@@ -18,6 +18,7 @@
#include <unistd.h>
#include <errno.h>
#include <fcntl.h>
+#include <dirent.h>
#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
@@ -575,6 +576,7 @@ static void guest_file_init(void)
typedef struct FsMount {
char *dirname;
char *devtype;
+ unsigned int devmajor, devminor;
QTAILQ_ENTRY(FsMount) next;
} FsMount;
@@ -596,15 +598,40 @@ static void free_fs_mount_list(FsMountList *mounts)
}
}
+static int dev_major_minor(const char *devpath,
+ unsigned int *devmajor, unsigned int *devminor)
+{
+ struct stat st;
+
+ *devmajor = 0;
+ *devminor = 0;
+
+ if (stat(devpath, &st) < 0) {
+ slog("failed to stat device file '%s': %s", devpath, strerror(errno));
+ return -1;
+ }
+ if (S_ISDIR(st.st_mode)) {
+ /* It is bind mount */
+ return -2;
+ }
+ if (S_ISBLK(st.st_mode)) {
+ *devmajor = major(st.st_rdev);
+ *devminor = minor(st.st_rdev);
+ return 0;
+ }
+ return -1;
+}
+
/*
* Walk the mount table and build a list of local file systems
*/
-static void build_fs_mount_list(FsMountList *mounts, Error **errp)
+static void build_fs_mount_list_from_mtab(FsMountList *mounts, Error **errp)
{
struct mntent *ment;
FsMount *mount;
char const *mtab = "/proc/self/mounts";
FILE *fp;
+ unsigned int devmajor, devminor;
fp = setmntent(mtab, "r");
if (!fp) {
@@ -624,26 +651,429 @@ static void build_fs_mount_list(FsMountList *mounts, Error **errp)
(strcmp(ment->mnt_type, "cifs") == 0)) {
continue;
}
+ if (dev_major_minor(ment->mnt_fsname, &devmajor, &devminor) == -2) {
+ /* Skip bind mounts */
+ continue;
+ }
mount = g_malloc0(sizeof(FsMount));
mount->dirname = g_strdup(ment->mnt_dir);
mount->devtype = g_strdup(ment->mnt_type);
+ mount->devmajor = devmajor;
+ mount->devminor = devminor;
QTAILQ_INSERT_TAIL(mounts, mount, next);
}
endmntent(fp);
}
+
+static void decode_mntname(char *name, int len)
+{
+ int i, j = 0;
+ for (i = 0; i <= len; i++) {
+ if (name[i] != '\\') {
+ name[j++] = name[i];
+ } else if (name[i + 1] == '\\') {
+ name[j++] = '\\';
+ i++;
+ } else if (name[i + 1] >= '0' && name[i + 1] <= '3' &&
+ name[i + 2] >= '0' && name[i + 2] <= '7' &&
+ name[i + 3] >= '0' && name[i + 3] <= '7') {
+ name[j++] = (name[i + 1] - '0') * 64 +
+ (name[i + 2] - '0') * 8 +
+ (name[i + 3] - '0');
+ i += 3;
+ } else {
+ name[j++] = name[i];
+ }
+ }
+}
+
+static void build_fs_mount_list(FsMountList *mounts, Error **errp)
+{
+ FsMount *mount;
+ char const *mountinfo = "/proc/self/mountinfo";
+ FILE *fp;
+ char *line = NULL, *dash;
+ size_t n;
+ char check;
+ unsigned int devmajor, devminor;
+ int ret, dir_s, dir_e, type_s, type_e, dev_s, dev_e;
+
+ fp = fopen(mountinfo, "r");
+ if (!fp) {
+ build_fs_mount_list_from_mtab(mounts, errp);
+ return;
+ }
+
+ while (getline(&line, &n, fp) != -1) {
+ ret = sscanf(line, "%*u %*u %u:%u %*s %n%*s%n%c",
+ &devmajor, &devminor, &dir_s, &dir_e, &check);
+ if (ret < 3) {
+ continue;
+ }
+ dash = strstr(line + dir_e, " - ");
+ if (!dash) {
+ continue;
+ }
+ ret = sscanf(dash, " - %n%*s%n %n%*s%n%c",
+ &type_s, &type_e, &dev_s, &dev_e, &check);
+ if (ret < 1) {
+ continue;
+ }
+ line[dir_e] = 0;
+ dash[type_e] = 0;
+ dash[dev_e] = 0;
+ decode_mntname(line + dir_s, dir_e - dir_s);
+ decode_mntname(dash + dev_s, dev_e - dev_s);
+ if (devmajor == 0) {
+ /* btrfs reports major number = 0 */
+ if (strcmp("btrfs", dash + type_s) != 0 ||
+ dev_major_minor(dash + dev_s, &devmajor, &devminor) < 0) {
+ continue;
+ }
+ }
+
+ mount = g_malloc0(sizeof(FsMount));
+ mount->dirname = g_strdup(line + dir_s);
+ mount->devtype = g_strdup(dash + type_s);
+ mount->devmajor = devmajor;
+ mount->devminor = devminor;
+
+ QTAILQ_INSERT_TAIL(mounts, mount, next);
+ }
+ free(line);
+
+ fclose(fp);
+}
#endif
#if defined(CONFIG_FSFREEZE)
+static char *get_pci_driver(char const *syspath, int pathlen, Error **errp)
+{
+ char *path;
+ char *dpath;
+ char *driver = NULL;
+ char buf[PATH_MAX];
+ ssize_t len;
+
+ path = g_strndup(syspath, pathlen);
+ dpath = g_strdup_printf("%s/driver", path);
+ len = readlink(dpath, buf, sizeof(buf) - 1);
+ if (len != -1) {
+ buf[len] = 0;
+ driver = g_strdup(basename(buf));
+ }
+ g_free(dpath);
+ g_free(path);
+ return driver;
+}
+
+static int compare_uint(const void *_a, const void *_b)
+{
+ unsigned int a = *(unsigned int *)_a;
+ unsigned int b = *(unsigned int *)_b;
+
+ return a < b ? -1 : a > b ? 1 : 0;
+}
+
+/* Walk the specified sysfs and build a sorted list of host or ata numbers */
+static int build_hosts(char const *syspath, char const *host, bool ata,
+ unsigned int *hosts, int hosts_max, Error **errp)
+{
+ char *path;
+ DIR *dir;
+ struct dirent *entry;
+ int i = 0;
+
+ path = g_strndup(syspath, host - syspath);
+ dir = opendir(path);
+ if (!dir) {
+ error_setg_errno(errp, errno, "opendir(\"%s\")", path);
+ g_free(path);
+ return -1;
+ }
+
+ while (i < hosts_max) {
+ entry = readdir(dir);
+ if (!entry) {
+ break;
+ }
+ if (ata && sscanf(entry->d_name, "ata%d", hosts + i) == 1) {
+ ++i;
+ } else if (!ata && sscanf(entry->d_name, "host%d", hosts + i) == 1) {
+ ++i;
+ }
+ }
+
+ qsort(hosts, i, sizeof(hosts[0]), compare_uint);
+
+ g_free(path);
+ closedir(dir);
+ return i;
+}
+
+/* Store disk device info specified by @sysfs into @fs */
+static void build_guest_fsinfo_for_real_device(char const *syspath,
+ GuestFilesystemInfo *fs,
+ Error **errp)
+{
+ unsigned int pci[4], host, hosts[8], tgt[3];
+ int i, nhosts = 0, pcilen;
+ GuestDiskAddress *disk;
+ GuestPCIAddress *pciaddr;
+ GuestDiskAddressList *list = NULL;
+ bool has_ata = false, has_host = false, has_tgt = false;
+ char *p, *q, *driver = NULL;
+
+ p = strstr(syspath, "/devices/pci");
+ if (!p || sscanf(p + 12, "%*x:%*x/%x:%x:%x.%x%n",
+ pci, pci + 1, pci + 2, pci + 3, &pcilen) < 4) {
+ g_debug("only pci device is supported: sysfs path \"%s\"", syspath);
+ return;
+ }
+
+ driver = get_pci_driver(syspath, (p + 12 + pcilen) - syspath, errp);
+ if (!driver) {
+ goto cleanup;
+ }
+
+ p = strstr(syspath, "/target");
+ if (p && sscanf(p + 7, "%*u:%*u:%*u/%*u:%u:%u:%u",
+ tgt, tgt + 1, tgt + 2) == 3) {
+ has_tgt = true;
+ }
+
+ p = strstr(syspath, "/ata");
+ if (p) {
+ q = p + 4;
+ has_ata = true;
+ } else {
+ p = strstr(syspath, "/host");
+ q = p + 5;
+ }
+ if (p && sscanf(q, "%u", &host) == 1) {
+ has_host = true;
+ nhosts = build_hosts(syspath, p, has_ata, hosts,
+ sizeof(hosts) / sizeof(hosts[0]), errp);
+ if (nhosts < 0) {
+ goto cleanup;
+ }
+ }
+
+ pciaddr = g_malloc0(sizeof(*pciaddr));
+ pciaddr->domain = pci[0];
+ pciaddr->bus = pci[1];
+ pciaddr->slot = pci[2];
+ pciaddr->function = pci[3];
+
+ disk = g_malloc0(sizeof(*disk));
+ disk->pci_controller = pciaddr;
+
+ list = g_malloc0(sizeof(*list));
+ list->value = disk;
+
+ if (strcmp(driver, "ata_piix") == 0) {
+ /* a host per ide bus, target*:0:<unit>:0 */
+ if (!has_host || !has_tgt) {
+ g_debug("invalid sysfs path '%s' (driver '%s')", syspath, driver);
+ goto cleanup;
+ }
+ for (i = 0; i < nhosts; i++) {
+ if (host == hosts[i]) {
+ disk->bus_type = GUEST_DISK_BUS_TYPE_IDE;
+ disk->bus = i;
+ disk->unit = tgt[1];
+ break;
+ }
+ }
+ if (i >= nhosts) {
+ g_debug("no host for '%s' (driver '%s')", syspath, driver);
+ goto cleanup;
+ }
+ } else if (strcmp(driver, "sym53c8xx") == 0) {
+ /* scsi(LSI Logic): target*:0:<unit>:0 */
+ if (!has_tgt) {
+ g_debug("invalid sysfs path '%s' (driver '%s')", syspath, driver);
+ goto cleanup;
+ }
+ disk->bus_type = GUEST_DISK_BUS_TYPE_SCSI;
+ disk->unit = tgt[1];
+ } else if (strcmp(driver, "virtio-pci") == 0) {
+ if (has_tgt) {
+ /* virtio-scsi: target*:0:0:<unit> */
+ disk->bus_type = GUEST_DISK_BUS_TYPE_SCSI;
+ disk->unit = tgt[2];
+ } else {
+ /* virtio-blk: 1 disk per 1 device */
+ disk->bus_type = GUEST_DISK_BUS_TYPE_VIRTIO;
+ }
+ } else if (strcmp(driver, "ahci") == 0) {
+ /* ahci: 1 host per 1 unit */
+ if (!has_host || !has_tgt) {
+ g_debug("invalid sysfs path '%s' (driver '%s')", syspath, driver);
+ goto cleanup;
+ }
+ for (i = 0; i < nhosts; i++) {
+ if (host == hosts[i]) {
+ disk->unit = i;
+ disk->bus_type = GUEST_DISK_BUS_TYPE_SATA;
+ break;
+ }
+ }
+ if (i >= nhosts) {
+ g_debug("no host for '%s' (driver '%s')", syspath, driver);
+ goto cleanup;
+ }
+ } else {
+ g_debug("unknown driver '%s' (sysfs path '%s')", driver, syspath);
+ goto cleanup;
+ }
+
+ list->next = fs->disk;
+ fs->disk = list;
+ g_free(driver);
+ return;
+
+cleanup:
+ if (list) {
+ qapi_free_GuestDiskAddressList(list);
+ }
+ g_free(driver);
+}
+
+static void build_guest_fsinfo_for_device(char const *devpath,
+ GuestFilesystemInfo *fs,
+ Error **errp);
+
+/* Store a list of slave devices of virtual volume specified by @syspath into
+ * @fs */
+static void build_guest_fsinfo_for_virtual_device(char const *syspath,
+ GuestFilesystemInfo *fs,
+ Error **errp)
+{
+ DIR *dir;
+ char *dirpath;
+ struct dirent entry, *result;
+
+ dirpath = g_strdup_printf("%s/slaves", syspath);
+ dir = opendir(dirpath);
+ if (!dir) {
+ error_setg_errno(errp, errno, "opendir(\"%s\")", dirpath);
+ g_free(dirpath);
+ return;
+ }
+ g_free(dirpath);
+
+ for (;;) {
+ if (readdir_r(dir, &entry, &result) != 0) {
+ error_setg_errno(errp, errno, "readdir_r(\"%s\")", dirpath);
+ break;
+ }
+ if (!result) {
+ break;
+ }
+
+ if (entry.d_type == DT_LNK) {
+ g_debug(" slave device '%s'", entry.d_name);
+ dirpath = g_strdup_printf("%s/slaves/%s", syspath, entry.d_name);
+ build_guest_fsinfo_for_device(dirpath, fs, errp);
+ g_free(dirpath);
+
+ if (*errp) {
+ break;
+ }
+ }
+ }
+
+ closedir(dir);
+}
+
+/* Dispatch to functions for virtual/real device */
+static void build_guest_fsinfo_for_device(char const *devpath,
+ GuestFilesystemInfo *fs,
+ Error **errp)
+{
+ char *syspath = realpath(devpath, NULL);
+
+ if (!syspath) {
+ error_setg_errno(errp, errno, "realpath(\"%s\")", devpath);
+ return;
+ }
+
+ if (!fs->name) {
+ fs->name = g_strdup(basename(syspath));
+ }
+
+ g_debug(" parse sysfs path '%s'", syspath);
+
+ if (strstr(syspath, "/devices/virtual/block/")) {
+ build_guest_fsinfo_for_virtual_device(syspath, fs, errp);
+ } else {
+ build_guest_fsinfo_for_real_device(syspath, fs, errp);
+ }
+
+ free(syspath);
+}
+
+/* Return a list of the disk device(s)' info which @mount lies on */
+static GuestFilesystemInfo *build_guest_fsinfo(struct FsMount *mount,
+ Error **errp)
+{
+ GuestFilesystemInfo *fs = g_malloc0(sizeof(*fs));
+ char *devpath = g_strdup_printf("/sys/dev/block/%u:%u",
+ mount->devmajor, mount->devminor);
+
+ fs->mountpoint = g_strdup(mount->dirname);
+ fs->type = g_strdup(mount->devtype);
+ build_guest_fsinfo_for_device(devpath, fs, errp);
+
+ g_free(devpath);
+ return fs;
+}
+
+GuestFilesystemInfoList *qmp_guest_get_fsinfo(Error **errp)
+{
+ FsMountList mounts;
+ struct FsMount *mount;
+ GuestFilesystemInfoList *new, *ret = NULL;
+ Error *local_err = NULL;
+
+ QTAILQ_INIT(&mounts);
+ build_fs_mount_list(&mounts, &local_err);
+ if (local_err) {
+ error_propagate(errp, local_err);
+ return NULL;
+ }
+
+ QTAILQ_FOREACH(mount, &mounts, next) {
+ g_debug("Building guest fsinfo for '%s'", mount->dirname);
+
+ new = g_malloc0(sizeof(*ret));
+ new->value = build_guest_fsinfo(mount, &local_err);
+ new->next = ret;
+ ret = new;
+ if (local_err) {
+ error_propagate(errp, local_err);
+ qapi_free_GuestFilesystemInfoList(ret);
+ ret = NULL;
+ break;
+ }
+ }
+
+ free_fs_mount_list(&mounts);
+ return ret;
+}
+
+
typedef enum {
FSFREEZE_HOOK_THAW = 0,
FSFREEZE_HOOK_FREEZE,
} FsfreezeHookArg;
-const char *fsfreeze_hook_arg_string[] = {
+static const char *fsfreeze_hook_arg_string[] = {
"thaw",
"freeze",
};
@@ -710,13 +1140,21 @@ GuestFsfreezeStatus qmp_guest_fsfreeze_status(Error **errp)
return GUEST_FSFREEZE_STATUS_THAWED;
}
+int64_t qmp_guest_fsfreeze_freeze(Error **errp)
+{
+ return qmp_guest_fsfreeze_freeze_list(false, NULL, errp);
+}
+
/*
* Walk list of mounted file systems in the guest, and freeze the ones which
* are real local file systems.
*/
-int64_t qmp_guest_fsfreeze_freeze(Error **errp)
+int64_t qmp_guest_fsfreeze_freeze_list(bool has_mountpoints,
+ strList *mountpoints,
+ Error **errp)
{
int ret = 0, i = 0;
+ strList *list;
FsMountList mounts;
struct FsMount *mount;
Error *local_err = NULL;
@@ -741,6 +1179,19 @@ int64_t qmp_guest_fsfreeze_freeze(Error **errp)
ga_set_frozen(ga_state);
QTAILQ_FOREACH_REVERSE(mount, &mounts, FsMountList, next) {
+ /* To issue fsfreeze in the reverse order of mounts, check if the
+ * mount is listed in the list here */
+ if (has_mountpoints) {
+ for (list = mountpoints; list; list = list->next) {
+ if (strcmp(list->value, mount->dirname) == 0) {
+ break;
+ }
+ }
+ if (!list) {
+ continue;
+ }
+ }
+
fd = qemu_open(mount->dirname, O_RDONLY);
if (fd == -1) {
error_setg_errno(errp, errno, "failed to open %s", mount->dirname);
@@ -1460,6 +1911,12 @@ int64_t qmp_guest_set_vcpus(GuestLogicalProcessorList *vcpus, Error **errp)
#if !defined(CONFIG_FSFREEZE)
+GuestFilesystemInfoList *qmp_guest_get_fsinfo(Error **errp)
+{
+ error_set(errp, QERR_UNSUPPORTED);
+ return NULL;
+}
+
GuestFsfreezeStatus qmp_guest_fsfreeze_status(Error **errp)
{
error_set(errp, QERR_UNSUPPORTED);
@@ -1474,6 +1931,15 @@ int64_t qmp_guest_fsfreeze_freeze(Error **errp)
return 0;
}
+int64_t qmp_guest_fsfreeze_freeze_list(bool has_mountpoints,
+ strList *mountpoints,
+ Error **errp)
+{
+ error_set(errp, QERR_UNSUPPORTED);
+
+ return 0;
+}
+
int64_t qmp_guest_fsfreeze_thaw(Error **errp)
{
error_set(errp, QERR_UNSUPPORTED);
@@ -1489,6 +1955,44 @@ void qmp_guest_fstrim(bool has_minimum, int64_t minimum, Error **errp)
}
#endif
+/* add unsupported commands to the blacklist */
+GList *ga_command_blacklist_init(GList *blacklist)
+{
+#if !defined(__linux__)
+ {
+ const char *list[] = {
+ "guest-suspend-disk", "guest-suspend-ram",
+ "guest-suspend-hybrid", "guest-network-get-interfaces",
+ "guest-get-vcpus", "guest-set-vcpus", NULL};
+ char **p = (char **)list;
+
+ while (*p) {
+ blacklist = g_list_append(blacklist, *p++);
+ }
+ }
+#endif
+
+#if !defined(CONFIG_FSFREEZE)
+ {
+ const char *list[] = {
+ "guest-get-fsinfo", "guest-fsfreeze-status",
+ "guest-fsfreeze-freeze", "guest-fsfreeze-freeze-list",
+ "guest-fsfreeze-thaw", "guest-get-fsinfo", NULL};
+ char **p = (char **)list;
+
+ while (*p) {
+ blacklist = g_list_append(blacklist, *p++);
+ }
+ }
+#endif
+
+#if !defined(CONFIG_FSTRIM)
+ blacklist = g_list_append(blacklist, (char *)"guest-fstrim");
+#endif
+
+ return blacklist;
+}
+
/* register init/cleanup routines for stateful command groups */
void ga_command_state_init(GAState *s, GACommandState *cs)
{
diff --git a/qga/commands-win32.c b/qga/commands-win32.c
index e76939651a..3bcbeae8ff 100644
--- a/qga/commands-win32.c
+++ b/qga/commands-win32.c
@@ -152,6 +152,12 @@ void qmp_guest_file_flush(int64_t handle, Error **errp)
error_set(errp, QERR_UNSUPPORTED);
}
+GuestFilesystemInfoList *qmp_guest_get_fsinfo(Error **errp)
+{
+ error_set(errp, QERR_UNSUPPORTED);
+ return NULL;
+}
+
/*
* Return status of freeze/thaw
*/
@@ -206,6 +212,15 @@ error:
return 0;
}
+int64_t qmp_guest_fsfreeze_freeze_list(bool has_mountpoints,
+ strList *mountpoints,
+ Error **errp)
+{
+ error_set(errp, QERR_UNSUPPORTED);
+
+ return 0;
+}
+
/*
* Thaw local file systems using Volume Shadow-copy Service.
*/
@@ -431,10 +446,40 @@ int64_t qmp_guest_set_vcpus(GuestLogicalProcessorList *vcpus, Error **errp)
return -1;
}
+/* add unsupported commands to the blacklist */
+GList *ga_command_blacklist_init(GList *blacklist)
+{
+ const char *list_unsupported[] = {
+ "guest-file-open", "guest-file-close", "guest-file-read",
+ "guest-file-write", "guest-file-seek", "guest-file-flush",
+ "guest-suspend-hybrid", "guest-network-get-interfaces",
+ "guest-get-vcpus", "guest-set-vcpus",
+ "guest-fsfreeze-freeze-list", "guest-get-fsinfo",
+ "guest-fstrim", NULL};
+ char **p = (char **)list_unsupported;
+
+ while (*p) {
+ blacklist = g_list_append(blacklist, *p++);
+ }
+
+ if (!vss_init(true)) {
+ const char *list[] = {
+ "guest-get-fsinfo", "guest-fsfreeze-status",
+ "guest-fsfreeze-freeze", "guest-fsfreeze-thaw", NULL};
+ p = (char **)list;
+
+ while (*p) {
+ blacklist = g_list_append(blacklist, *p++);
+ }
+ }
+
+ return blacklist;
+}
+
/* register init/cleanup routines for stateful command groups */
void ga_command_state_init(GAState *s, GACommandState *cs)
{
- if (vss_init(true)) {
+ if (!vss_initialized()) {
ga_command_state_add(cs, NULL, guest_fsfreeze_cleanup);
}
}
diff --git a/qga/guest-agent-core.h b/qga/guest-agent-core.h
index e422208b4e..e92c6abafb 100644
--- a/qga/guest-agent-core.h
+++ b/qga/guest-agent-core.h
@@ -19,6 +19,7 @@ typedef struct GAState GAState;
typedef struct GACommandState GACommandState;
extern GAState *ga_state;
+GList *ga_command_blacklist_init(GList *blacklist);
void ga_command_state_init(GAState *s, GACommandState *cs);
void ga_command_state_add(GACommandState *cs,
void (*init)(void),
diff --git a/qga/main.c b/qga/main.c
index 8b927c9db7..227f2bdb88 100644
--- a/qga/main.c
+++ b/qga/main.c
@@ -1144,6 +1144,7 @@ int main(int argc, char **argv)
goto out_bad;
}
+ blacklist = ga_command_blacklist_init(blacklist);
if (blacklist) {
s->blacklist = blacklist;
do {
diff --git a/qga/qapi-schema.json b/qga/qapi-schema.json
index a8cdcb35c4..376e79f583 100644
--- a/qga/qapi-schema.json
+++ b/qga/qapi-schema.json
@@ -387,6 +387,23 @@
'returns': 'int' }
##
+# @guest-fsfreeze-freeze-list:
+#
+# Sync and freeze specified guest filesystems
+#
+# @mountpoints: #optional an array of mountpoints of filesystems to be frozen.
+# If omitted, every mounted filesystem is frozen.
+#
+# Returns: Number of file systems currently frozen. On error, all filesystems
+# will be thawed.
+#
+# Since: 2.2
+##
+{ 'command': 'guest-fsfreeze-freeze-list',
+ 'data': { '*mountpoints': ['str'] },
+ 'returns': 'int' }
+
+##
# @guest-fsfreeze-thaw:
#
# Unfreeze all frozen guest filesystems
@@ -642,3 +659,82 @@
{ 'command': 'guest-set-vcpus',
'data': {'vcpus': ['GuestLogicalProcessor'] },
'returns': 'int' }
+
+##
+# @GuestDiskBusType
+#
+# An enumeration of bus type of disks
+#
+# @ide: IDE disks
+# @fdc: floppy disks
+# @scsi: SCSI disks
+# @virtio: virtio disks
+# @xen: Xen disks
+# @usb: USB disks
+# @uml: UML disks
+# @sata: SATA disks
+# @sd: SD cards
+#
+# Since: 2.2
+##
+{ 'enum': 'GuestDiskBusType',
+ 'data': [ 'ide', 'fdc', 'scsi', 'virtio', 'xen', 'usb', 'uml', 'sata',
+ 'sd' ] }
+
+##
+# @GuestPCIAddress:
+#
+# @domain: domain id
+# @bus: bus id
+# @slot: slot id
+# @function: function id
+#
+# Since: 2.2
+##
+{ 'type': 'GuestPCIAddress',
+ 'data': {'domain': 'int', 'bus': 'int',
+ 'slot': 'int', 'function': 'int'} }
+
+##
+# @GuestDiskAddress:
+#
+# @pci-controller: controller's PCI address
+# @type: bus type
+# @bus: bus id
+# @target: target id
+# @unit: unit id
+#
+# Since: 2.2
+##
+{ 'type': 'GuestDiskAddress',
+ 'data': {'pci-controller': 'GuestPCIAddress',
+ 'bus-type': 'GuestDiskBusType',
+ 'bus': 'int', 'target': 'int', 'unit': 'int'} }
+
+##
+# @GuestFilesystemInfo
+#
+# @name: disk name
+# @mountpoint: mount point path
+# @type: file system type string
+# @disk: an array of disk hardware information that the volume lies on,
+# which may be empty if the disk type is not supported
+#
+# Since: 2.2
+##
+{ 'type': 'GuestFilesystemInfo',
+ 'data': {'name': 'str', 'mountpoint': 'str', 'type': 'str',
+ 'disk': ['GuestDiskAddress']} }
+
+##
+# @guest-get-fsinfo:
+#
+# Returns: The list of filesystems information mounted in the guest.
+# The returned mountpoints may be specified to
+# @guest-fsfreeze-freeze-list.
+# Network filesystems (such as CIFS and NFS) are not listed.
+#
+# Since: 2.2
+##
+{ 'command': 'guest-get-fsinfo',
+ 'returns': ['GuestFilesystemInfo'] }
diff --git a/qmp.c b/qmp.c
index 0d2553abf5..c6767c4df3 100644
--- a/qmp.c
+++ b/qmp.c
@@ -509,6 +509,7 @@ DevicePropertyInfoList *qmp_device_list_properties(const char *typename,
if (strcmp(prop->name, "type") == 0 ||
strcmp(prop->name, "realized") == 0 ||
strcmp(prop->name, "hotpluggable") == 0 ||
+ strcmp(prop->name, "hotplugged") == 0 ||
strcmp(prop->name, "parent_bus") == 0) {
continue;
}
diff --git a/qtest.c b/qtest.c
index 04a6dc1f0f..ef0d99191c 100644
--- a/qtest.c
+++ b/qtest.c
@@ -19,6 +19,9 @@
#include "hw/irq.h"
#include "sysemu/sysemu.h"
#include "sysemu/cpus.h"
+#include "qemu/config-file.h"
+#include "qemu/option.h"
+#include "qemu/error-report.h"
#define MAX_IRQ 256
@@ -509,10 +512,16 @@ static void qtest_event(void *opaque, int event)
}
}
-int qtest_init_accel(MachineClass *mc)
+static void configure_qtest_icount(const char *options)
{
- configure_icount("0");
+ QemuOpts *opts = qemu_opts_parse(qemu_find_opts("icount"), options, 1);
+ configure_icount(opts, &error_abort);
+ qemu_opts_del(opts);
+}
+int qtest_init_accel(MachineClass *mc)
+{
+ configure_qtest_icount("0");
return 0;
}
diff --git a/scripts/simpletrace.py b/scripts/simpletrace.py
index 1aa9460e49..3916c6d14a 100755
--- a/scripts/simpletrace.py
+++ b/scripts/simpletrace.py
@@ -58,8 +58,8 @@ def read_record(edict, fobj):
rechdr = read_header(fobj, rec_header_fmt)
return get_record(edict, rechdr, fobj) # return tuple of record elements
-def read_trace_file(edict, fobj):
- """Deserialize trace records from a file, yielding record tuples (event_num, timestamp, pid, arg1, ..., arg6)."""
+def read_trace_header(fobj):
+ """Read and verify trace file header"""
header = read_header(fobj, log_header_fmt)
if header is None or \
header[0] != header_event_id or \
@@ -73,6 +73,8 @@ def read_trace_file(edict, fobj):
raise ValueError('Log format %d not supported with this QEMU release!'
% log_version)
+def read_trace_records(edict, fobj):
+ """Deserialize trace records from a file, yielding record tuples (event_num, timestamp, pid, arg1, ..., arg6)."""
while True:
rec = read_record(edict, fobj)
if rec is None:
@@ -102,13 +104,16 @@ class Analyzer(object):
"""Called at the end of the trace."""
pass
-def process(events, log, analyzer):
+def process(events, log, analyzer, read_header=True):
"""Invoke an analyzer on each event in a log."""
if isinstance(events, str):
events = _read_events(open(events, 'r'))
if isinstance(log, str):
log = open(log, 'rb')
+ if read_header:
+ read_trace_header(log)
+
dropped_event = Event.build("Dropped_Event(uint64_t num_events_dropped)")
edict = {dropped_event_id: dropped_event}
@@ -137,7 +142,7 @@ def process(events, log, analyzer):
analyzer.begin()
fn_cache = {}
- for rec in read_trace_file(edict, log):
+ for rec in read_trace_records(edict, log):
event_num = rec[0]
event = edict[event_num]
if event_num not in fn_cache:
@@ -152,12 +157,17 @@ def run(analyzer):
advanced scripts will want to call process() instead."""
import sys
- if len(sys.argv) != 3:
- sys.stderr.write('usage: %s <trace-events> <trace-file>\n' % sys.argv[0])
+ read_header = True
+ if len(sys.argv) == 4 and sys.argv[1] == '--no-header':
+ read_header = False
+ del sys.argv[1]
+ elif len(sys.argv) != 3:
+ sys.stderr.write('usage: %s [--no-header] <trace-events> ' \
+ '<trace-file>\n' % sys.argv[0])
sys.exit(1)
events = _read_events(open(sys.argv[1], 'r'))
- process(events, sys.argv[2], analyzer)
+ process(events, sys.argv[2], analyzer, read_header=read_header)
if __name__ == '__main__':
class Formatter(Analyzer):
diff --git a/scripts/tracetool/__init__.py b/scripts/tracetool/__init__.py
index e8e8edcc4c..36c789de8f 100644
--- a/scripts/tracetool/__init__.py
+++ b/scripts/tracetool/__init__.py
@@ -15,9 +15,11 @@ __email__ = "stefanha@linux.vnet.ibm.com"
import re
import sys
+import weakref
import tracetool.format
import tracetool.backend
+import tracetool.transform
def error_write(*lines):
@@ -108,6 +110,18 @@ class Arguments:
"""List of argument types."""
return [ type_ for type_, _ in self._args ]
+ def transform(self, *trans):
+ """Return a new Arguments instance with transformed types.
+
+ The types in the resulting Arguments instance are transformed according
+ to tracetool.transform.transform_type.
+ """
+ res = []
+ for type_, name in self._args:
+ res.append((tracetool.transform.transform_type(type_, *trans),
+ name))
+ return Arguments(res)
+
class Event(object):
"""Event description.
@@ -122,13 +136,21 @@ class Event(object):
Properties of the event.
args : Arguments
The event arguments.
+ arg_fmts : str
+ The format strings for each argument.
"""
- _CRE = re.compile("((?P<props>.*)\s+)?(?P<name>[^(\s]+)\((?P<args>[^)]*)\)\s*(?P<fmt>\".*)?")
+ _CRE = re.compile("((?P<props>.*)\s+)?"
+ "(?P<name>[^(\s]+)"
+ "\((?P<args>[^)]*)\)"
+ "\s*"
+ "(?:(?:(?P<fmt_trans>\".+),)?\s*(?P<fmt>\".+))?"
+ "\s*")
+ _FMT = re.compile("(%\w+|%.*PRI\S+)")
- _VALID_PROPS = set(["disable"])
+ _VALID_PROPS = set(["disable", "tcg", "tcg-trans", "tcg-exec"])
- def __init__(self, name, props, fmt, args):
+ def __init__(self, name, props, fmt, args, arg_fmts, orig=None):
"""
Parameters
----------
@@ -136,20 +158,32 @@ class Event(object):
Event name.
props : list of str
Property names.
- fmt : str
- Event printing format.
+ fmt : str, list of str
+ Event printing format (or formats).
args : Arguments
Event arguments.
+ arg_fmts : list of str
+ Format strings for each argument.
+ orig : Event or None
+ Original Event before transformation.
+
"""
self.name = name
self.properties = props
self.fmt = fmt
self.args = args
+ self.arg_fmts = arg_fmts
+
+ if orig is None:
+ self.original = weakref.ref(self)
+ else:
+ self.original = orig
unknown_props = set(self.properties) - self._VALID_PROPS
if len(unknown_props) > 0:
raise ValueError("Unknown properties: %s"
% ", ".join(unknown_props))
+ assert isinstance(self.fmt, str) or len(self.fmt) == 2
def copy(self):
"""Create a new copy."""
@@ -172,24 +206,50 @@ class Event(object):
name = groups["name"]
props = groups["props"].split()
fmt = groups["fmt"]
+ fmt_trans = groups["fmt_trans"]
+ if len(fmt_trans) > 0:
+ fmt = [fmt_trans, fmt]
args = Arguments.build(groups["args"])
+ arg_fmts = Event._FMT.findall(fmt)
+
+ if "tcg-trans" in props:
+ raise ValueError("Invalid property 'tcg-trans'")
+ if "tcg-exec" in props:
+ raise ValueError("Invalid property 'tcg-exec'")
+ if "tcg" not in props and not isinstance(fmt, str):
+ raise ValueError("Only events with 'tcg' property can have two formats")
+ if "tcg" in props and isinstance(fmt, str):
+ raise ValueError("Events with 'tcg' property must have two formats")
- return Event(name, props, fmt, args)
+ return Event(name, props, fmt, args, arg_fmts)
def __repr__(self):
"""Evaluable string representation for this object."""
+ if isinstance(self.fmt, str):
+ fmt = self.fmt
+ else:
+ fmt = "%s, %s" % (self.fmt[0], self.fmt[1])
return "Event('%s %s(%s) %s')" % (" ".join(self.properties),
self.name,
self.args,
- self.fmt)
+ fmt)
QEMU_TRACE = "trace_%(name)s"
+ QEMU_TRACE_TCG = QEMU_TRACE + "_tcg"
def api(self, fmt=None):
if fmt is None:
fmt = Event.QEMU_TRACE
return fmt % {"name": self.name}
+ def transform(self, *trans):
+ """Return a new Event with transformed Arguments."""
+ return Event(self.name,
+ list(self.properties),
+ self.fmt,
+ self.args.transform(*trans),
+ self)
+
def _read_events(fobj):
res = []
@@ -272,4 +332,35 @@ def generate(fevents, format, backends,
events = _read_events(fevents)
+ # transform TCG-enabled events
+ new_events = []
+ for event in events:
+ if "tcg" not in event.properties:
+ new_events.append(event)
+ else:
+ event_trans = event.copy()
+ event_trans.name += "_trans"
+ event_trans.properties += ["tcg-trans"]
+ event_trans.fmt = event.fmt[0]
+ args_trans = []
+ for atrans, aorig in zip(
+ event_trans.transform(tracetool.transform.TCG_2_HOST).args,
+ event.args):
+ if atrans == aorig:
+ args_trans.append(atrans)
+ event_trans.args = Arguments(args_trans)
+ event_trans = event_trans.copy()
+
+ event_exec = event.copy()
+ event_exec.name += "_exec"
+ event_exec.properties += ["tcg-exec"]
+ event_exec.fmt = event.fmt[1]
+ event_exec = event_exec.transform(tracetool.transform.TCG_2_HOST)
+
+ new_event = [event_trans, event_exec]
+ event.event_trans, event.event_exec = new_event
+
+ new_events.extend(new_event)
+ events = new_events
+
tracetool.format.generate(events, format, backend)
diff --git a/scripts/tracetool/format/events_h.py b/scripts/tracetool/format/events_h.py
index 25d913bb25..9f114a3497 100644
--- a/scripts/tracetool/format/events_h.py
+++ b/scripts/tracetool/format/events_h.py
@@ -40,6 +40,11 @@ def generate(events, backend):
enabled = 0
else:
enabled = 1
+ if "tcg-trans" in e.properties:
+ # a single define for the two "sub-events"
+ out('#define TRACE_%(name)s_ENABLED %(enabled)d',
+ name=e.original.original.name.upper(),
+ enabled=enabled)
out('#define TRACE_%s_ENABLED %d' % (e.name.upper(), enabled))
out('#include "trace/event-internal.h"',
diff --git a/scripts/tracetool/format/simpletrace_stap.py b/scripts/tracetool/format/simpletrace_stap.py
new file mode 100644
index 0000000000..7e44bc1811
--- /dev/null
+++ b/scripts/tracetool/format/simpletrace_stap.py
@@ -0,0 +1,71 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+"""
+Generate .stp file that outputs simpletrace binary traces (DTrace with SystemTAP only).
+"""
+
+__author__ = "Stefan Hajnoczi <redhat.com>"
+__copyright__ = "Copyright (C) 2014, Red Hat, Inc."
+__license__ = "GPL version 2 or (at your option) any later version"
+
+__maintainer__ = "Stefan Hajnoczi"
+__email__ = "stefanha@redhat.com"
+
+
+from tracetool import out
+from tracetool.backend.dtrace import binary, probeprefix
+from tracetool.backend.simple import is_string
+from tracetool.format.stap import stap_escape
+
+
+def generate(events, backend):
+ out('/* This file is autogenerated by tracetool, do not edit. */',
+ '')
+
+ for event_id, e in enumerate(events):
+ if 'disable' in e.properties:
+ continue
+
+ out('probe %(probeprefix)s.simpletrace.%(name)s = %(probeprefix)s.%(name)s ?',
+ '{',
+ probeprefix=probeprefix(),
+ name=e.name)
+
+ # Calculate record size
+ sizes = ['24'] # sizeof(TraceRecord)
+ for type_, name in e.args:
+ name = stap_escape(name)
+ if is_string(type_):
+ out(' try {',
+ ' arg%(name)s_str = %(name)s ? user_string_n(%(name)s, 512) : "<null>"',
+ ' } catch {}',
+ ' arg%(name)s_len = strlen(arg%(name)s_str)',
+ name=name)
+ sizes.append('4 + arg%s_len' % name)
+ else:
+ sizes.append('8')
+ sizestr = ' + '.join(sizes)
+
+ # Generate format string and value pairs for record header and arguments
+ fields = [('8b', str(event_id)),
+ ('8b', 'gettimeofday_ns()'),
+ ('4b', sizestr),
+ ('4b', 'pid()')]
+ for type_, name in e.args:
+ name = stap_escape(name)
+ if is_string(type_):
+ fields.extend([('4b', 'arg%s_len' % name),
+ ('.*s', 'arg%s_len, arg%s_str' % (name, name))])
+ else:
+ fields.append(('8b', name))
+
+ # Emit the entire record in a single SystemTap printf()
+ fmt_str = '%'.join(fmt for fmt, _ in fields)
+ arg_str = ', '.join(arg for _, arg in fields)
+ out(' printf("%%%(fmt_str)s", %(arg_str)s)',
+ fmt_str=fmt_str, arg_str=arg_str)
+
+ out('}')
+
+ out()
diff --git a/scripts/tracetool/format/stap.py b/scripts/tracetool/format/stap.py
index e24abf7f11..9e780f1b06 100644
--- a/scripts/tracetool/format/stap.py
+++ b/scripts/tracetool/format/stap.py
@@ -27,6 +27,13 @@ RESERVED_WORDS = (
)
+def stap_escape(identifier):
+ # Append underscore to reserved keywords
+ if identifier in RESERVED_WORDS:
+ return identifier + '_'
+ return identifier
+
+
def generate(events, backend):
events = [e for e in events
if "disable" not in e.properties]
@@ -45,9 +52,7 @@ def generate(events, backend):
i = 1
if len(e.args) > 0:
for name in e.args.names():
- # Append underscore to reserved keywords
- if name in RESERVED_WORDS:
- name += '_'
+ name = stap_escape(name)
out(' %s = $arg%d;' % (name, i))
i += 1
diff --git a/scripts/tracetool/format/tcg_h.py b/scripts/tracetool/format/tcg_h.py
new file mode 100644
index 0000000000..f676b66622
--- /dev/null
+++ b/scripts/tracetool/format/tcg_h.py
@@ -0,0 +1,57 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+"""
+Generate .h file for TCG code generation.
+"""
+
+__author__ = "Lluís Vilanova <vilanova@ac.upc.edu>"
+__copyright__ = "Copyright 2012-2014, Lluís Vilanova <vilanova@ac.upc.edu>"
+__license__ = "GPL version 2 or (at your option) any later version"
+
+__maintainer__ = "Stefan Hajnoczi"
+__email__ = "stefanha@linux.vnet.ibm.com"
+
+
+from tracetool import out
+
+
+def generate(events, backend):
+ out('/* This file is autogenerated by tracetool, do not edit. */',
+ '/* You must include this file after the inclusion of helper.h */',
+ '',
+ '#ifndef TRACE__GENERATED_TCG_TRACERS_H',
+ '#define TRACE__GENERATED_TCG_TRACERS_H',
+ '',
+ '#include <stdint.h>',
+ '',
+ '#include "trace.h"',
+ '#include "exec/helper-proto.h"',
+ '',
+ )
+
+ for e in events:
+ # just keep one of them
+ if "tcg-trans" not in e.properties:
+ continue
+
+ # get the original event definition
+ e = e.original.original
+
+ out('static inline void %(name_tcg)s(%(args)s)',
+ '{',
+ name_tcg=e.api(e.QEMU_TRACE_TCG),
+ args=e.args)
+
+ if "disable" not in e.properties:
+ out(' %(name_trans)s(%(argnames_trans)s);',
+ ' gen_helper_%(name_exec)s(%(argnames_exec)s);',
+ name_trans=e.event_trans.api(e.QEMU_TRACE),
+ name_exec=e.event_exec.api(e.QEMU_TRACE),
+ argnames_trans=", ".join(e.event_trans.args.names()),
+ argnames_exec=", ".join(e.event_exec.args.names()))
+
+ out('}')
+
+ out('',
+ '#endif /* TRACE__GENERATED_TCG_TRACERS_H */')
diff --git a/scripts/tracetool/format/tcg_helper_c.py b/scripts/tracetool/format/tcg_helper_c.py
new file mode 100644
index 0000000000..96655a0590
--- /dev/null
+++ b/scripts/tracetool/format/tcg_helper_c.py
@@ -0,0 +1,50 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+"""
+Generate trace/generated-helpers.c.
+"""
+
+__author__ = "Lluís Vilanova <vilanova@ac.upc.edu>"
+__copyright__ = "Copyright 2012-2014, Lluís Vilanova <vilanova@ac.upc.edu>"
+__license__ = "GPL version 2 or (at your option) any later version"
+
+__maintainer__ = "Stefan Hajnoczi"
+__email__ = "stefanha@linux.vnet.ibm.com"
+
+
+from tracetool import out
+from tracetool.transform import *
+
+
+def generate(events, backend):
+ events = [e for e in events
+ if "disable" not in e.properties]
+
+ out('/* This file is autogenerated by tracetool, do not edit. */',
+ '',
+ '#include "qemu-common.h"',
+ '#include "trace.h"',
+ '#include "exec/helper-proto.h"',
+ '',
+ )
+
+ for e in events:
+ if "tcg-exec" not in e.properties:
+ continue
+
+ # tracetool.generate always transforms types to host
+ e_args = e.original.args
+
+ values = ["(%s)%s" % (t, n)
+ for t, n in e.args.transform(TCG_2_TCG_HELPER_DEF)]
+
+ out('void %(name_tcg)s(%(args)s)',
+ '{',
+ ' %(name)s(%(values)s);',
+ '}',
+ name_tcg="helper_%s_proxy" % e.api(),
+ name=e.api(),
+ args=e_args.transform(HOST_2_TCG_COMPAT, TCG_2_TCG_HELPER_DEF),
+ values=", ".join(values),
+ )
diff --git a/scripts/tracetool/format/tcg_helper_h.py b/scripts/tracetool/format/tcg_helper_h.py
new file mode 100644
index 0000000000..a8ba7ba8e3
--- /dev/null
+++ b/scripts/tracetool/format/tcg_helper_h.py
@@ -0,0 +1,50 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+"""
+Generate trace/generated-helpers.h.
+"""
+
+__author__ = "Lluís Vilanova <vilanova@ac.upc.edu>"
+__copyright__ = "Copyright 2012-2014, Lluís Vilanova <vilanova@ac.upc.edu>"
+__license__ = "GPL version 2 or (at your option) any later version"
+
+__maintainer__ = "Stefan Hajnoczi"
+__email__ = "stefanha@linux.vnet.ibm.com"
+
+
+from tracetool import out
+from tracetool.transform import *
+
+
+def generate(events, backend):
+ events = [e for e in events
+ if "disable" not in e.properties]
+
+ out('/* This file is autogenerated by tracetool, do not edit. */',
+ '',
+ )
+
+ for e in events:
+ if "tcg-exec" not in e.properties:
+ continue
+
+ # tracetool.generate always transforms types to host
+ e_args = e.original.args
+
+ # TCG helper proxy declaration
+ fmt = "DEF_HELPER_FLAGS_%(argc)d(%(name)s, %(flags)svoid%(types)s)"
+ args = e_args.transform(HOST_2_TCG_COMPAT, HOST_2_TCG,
+ TCG_2_TCG_HELPER_DECL)
+ types = ", ".join(args.types())
+ if types != "":
+ types = ", " + types
+
+ flags = "TCG_CALL_NO_RWG, "
+
+ out(fmt,
+ flags=flags,
+ argc=len(args),
+ name=e.api() + "_proxy",
+ types=types,
+ )
diff --git a/scripts/tracetool/format/tcg_helper_wrapper_h.py b/scripts/tracetool/format/tcg_helper_wrapper_h.py
new file mode 100644
index 0000000000..cac5a878f9
--- /dev/null
+++ b/scripts/tracetool/format/tcg_helper_wrapper_h.py
@@ -0,0 +1,70 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+"""
+Generate trace/generated-helpers-wrappers.h.
+"""
+
+__author__ = "Lluís Vilanova <vilanova@ac.upc.edu>"
+__copyright__ = "Copyright 2012-2014, Lluís Vilanova <vilanova@ac.upc.edu>"
+__license__ = "GPL version 2 or (at your option) any later version"
+
+__maintainer__ = "Stefan Hajnoczi"
+__email__ = "stefanha@linux.vnet.ibm.com"
+
+
+from tracetool import out
+from tracetool.transform import *
+
+
+def generate(events, backend):
+ events = [e for e in events
+ if "disable" not in e.properties]
+
+ out('/* This file is autogenerated by tracetool, do not edit. */',
+ '',
+ '#define tcg_temp_new_nop(v) (v)',
+ '#define tcg_temp_free_nop(v)',
+ '',
+ )
+
+ for e in events:
+ if "tcg-exec" not in e.properties:
+ continue
+
+ # tracetool.generate always transforms types to host
+ e_args = e.original.args
+
+ # mixed-type to TCG helper bridge
+ args_tcg_compat = e_args.transform(HOST_2_TCG_COMPAT)
+
+ code_new = [
+ "%(tcg_type)s __%(name)s = %(tcg_func)s(%(name)s);" %
+ {"tcg_type": transform_type(type_, HOST_2_TCG),
+ "tcg_func": transform_type(type_, HOST_2_TCG_TMP_NEW),
+ "name": name}
+ for (type_, name) in args_tcg_compat
+ ]
+
+ code_free = [
+ "%(tcg_func)s(__%(name)s);" %
+ {"tcg_func": transform_type(type_, HOST_2_TCG_TMP_FREE),
+ "name": name}
+ for (type_, name) in args_tcg_compat
+ ]
+
+ gen_name = "gen_helper_" + e.api()
+
+ out('static inline void %(name)s(%(args)s)',
+ '{',
+ ' %(code_new)s',
+ ' %(proxy_name)s(%(tmp_names)s);',
+ ' %(code_free)s',
+ '}',
+ name=gen_name,
+ args=e_args,
+ proxy_name=gen_name + "_proxy",
+ code_new="\n ".join(code_new),
+ code_free="\n ".join(code_free),
+ tmp_names=", ".join(["__%s" % name for _, name in e_args]),
+ )
diff --git a/scripts/tracetool/format/ust_events_h.py b/scripts/tracetool/format/ust_events_h.py
index 5102565470..d18989942a 100644
--- a/scripts/tracetool/format/ust_events_h.py
+++ b/scripts/tracetool/format/ust_events_h.py
@@ -63,13 +63,20 @@ def generate(events, backend):
name=e.name,
args=", ".join(", ".join(i) for i in e.args))
- for t, n in e.args:
- if ('int' in t) or ('long' in t) or ('unsigned' in t) or ('size_t' in t):
+ types = e.args.types()
+ names = e.args.names()
+ fmts = e.arg_fmts
+ for t,n,f in zip(types, names, fmts):
+ if ('char *' in t) or ('char*' in t):
+ out(' ctf_string(' + n + ', ' + n + ')')
+ elif ("%p" in f) or ("x" in f) or ("PRIx" in f):
+ out(' ctf_integer_hex('+ t + ', ' + n + ', ' + n + ')')
+ elif ("ptr" in t) or ("*" in t):
+ out(' ctf_integer_hex('+ t + ', ' + n + ', ' + n + ')')
+ elif ('int' in t) or ('long' in t) or ('unsigned' in t) or ('size_t' in t):
out(' ctf_integer(' + t + ', ' + n + ', ' + n + ')')
elif ('double' in t) or ('float' in t):
out(' ctf_float(' + t + ', ' + n + ', ' + n + ')')
- elif ('char *' in t) or ('char*' in t):
- out(' ctf_string(' + n + ', ' + n + ')')
elif ('void *' in t) or ('void*' in t):
out(' ctf_integer_hex(unsigned long, ' + n + ', ' + n + ')')
diff --git a/scripts/tracetool/transform.py b/scripts/tracetool/transform.py
new file mode 100644
index 0000000000..fc5e679ed4
--- /dev/null
+++ b/scripts/tracetool/transform.py
@@ -0,0 +1,166 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+"""
+Type-transformation rules.
+"""
+
+__author__ = "Lluís Vilanova <vilanova@ac.upc.edu>"
+__copyright__ = "Copyright 2012-2014, Lluís Vilanova <vilanova@ac.upc.edu>"
+__license__ = "GPL version 2 or (at your option) any later version"
+
+__maintainer__ = "Stefan Hajnoczi"
+__email__ = "stefanha@linux.vnet.ibm.com"
+
+
+def _transform_type(type_, trans):
+ if isinstance(trans, str):
+ return trans
+ elif isinstance(trans, dict):
+ if type_ in trans:
+ return _transform_type(type_, trans[type_])
+ elif None in trans:
+ return _transform_type(type_, trans[None])
+ else:
+ return type_
+ elif callable(trans):
+ return trans(type_)
+ else:
+ raise ValueError("Invalid type transformation rule: %s" % trans)
+
+
+def transform_type(type_, *trans):
+ """Return a new type transformed according to the given rules.
+
+ Applies each of the transformation rules in trans in order.
+
+ If an element of trans is a string, return it.
+
+ If an element of trans is a function, call it with type_ as its only
+ argument.
+
+ If an element of trans is a dict, search type_ in its keys. If type_ is
+ a key, use the value as a transformation rule for type_. Otherwise, if
+ None is a key use the value as a transformation rule for type_.
+
+ Otherwise, return type_.
+
+ Parameters
+ ----------
+ type_ : str
+ Type to transform.
+ trans : list of function or dict
+ Type transformation rules.
+ """
+ if len(trans) == 0:
+ raise ValueError
+ res = type_
+ for t in trans:
+ res = _transform_type(res, t)
+ return res
+
+
+##################################################
+# tcg -> host
+
+def _tcg_2_host(type_):
+ if type_ == "TCGv":
+ # force a fixed-size type (target-independent)
+ return "uint64_t"
+ else:
+ return type_
+
+TCG_2_HOST = {
+ "TCGv_i32": "uint32_t",
+ "TCGv_i64": "uint64_t",
+ "TCGv_ptr": "void *",
+ None: _tcg_2_host,
+ }
+
+
+##################################################
+# host -> host compatible with tcg sizes
+
+HOST_2_TCG_COMPAT = {
+ "uint8_t": "uint32_t",
+ }
+
+
+##################################################
+# host/tcg -> tcg
+
+def _host_2_tcg(type_):
+ if type_.startswith("TCGv"):
+ return type_
+ raise ValueError("Don't know how to translate '%s' into a TCG type\n" % type_)
+
+HOST_2_TCG = {
+ "uint32_t": "TCGv_i32",
+ "uint64_t": "TCGv_i64",
+ "void *" : "TCGv_ptr",
+ None: _host_2_tcg,
+ }
+
+
+##################################################
+# tcg -> tcg helper definition
+
+def _tcg_2_helper_def(type_):
+ if type_ == "TCGv":
+ return "target_ulong"
+ else:
+ return type_
+
+TCG_2_TCG_HELPER_DEF = {
+ "TCGv_i32": "uint32_t",
+ "TCGv_i64": "uint64_t",
+ "TCGv_ptr": "void *",
+ None: _tcg_2_helper_def,
+ }
+
+
+##################################################
+# tcg -> tcg helper declaration
+
+def _tcg_2_tcg_helper_decl_error(type_):
+ raise ValueError("Don't know how to translate type '%s' into a TCG helper declaration type\n" % type_)
+
+TCG_2_TCG_HELPER_DECL = {
+ "TCGv" : "tl",
+ "TCGv_ptr": "ptr",
+ "TCGv_i32": "i32",
+ "TCGv_i64": "i64",
+ None: _tcg_2_tcg_helper_decl_error,
+ }
+
+
+##################################################
+# host/tcg -> tcg temporal constant allocation
+
+def _host_2_tcg_tmp_new(type_):
+ if type_.startswith("TCGv"):
+ return "tcg_temp_new_nop"
+ raise ValueError("Don't know how to translate type '%s' into a TCG temporal allocation" % type_)
+
+HOST_2_TCG_TMP_NEW = {
+ "uint32_t": "tcg_const_i32",
+ "uint64_t": "tcg_const_i64",
+ "void *" : "tcg_const_ptr",
+ None: _host_2_tcg_tmp_new,
+ }
+
+
+##################################################
+# host/tcg -> tcg temporal constant deallocation
+
+def _host_2_tcg_tmp_free(type_):
+ if type_.startswith("TCGv"):
+ return "tcg_temp_free_nop"
+ raise ValueError("Don't know how to translate type '%s' into a TCG temporal deallocation" % type_)
+
+HOST_2_TCG_TMP_FREE = {
+ "uint32_t": "tcg_temp_free_i32",
+ "uint64_t": "tcg_temp_free_i64",
+ "void *" : "tcg_temp_free_ptr",
+ None: _host_2_tcg_tmp_free,
+ }
diff --git a/scripts/vmstate-static-checker.py b/scripts/vmstate-static-checker.py
index 1604e680dc..f7ce3fc483 100755
--- a/scripts/vmstate-static-checker.py
+++ b/scripts/vmstate-static-checker.py
@@ -42,30 +42,44 @@ def check_fields_match(name, s_field, d_field):
# Some fields changed names between qemu versions. This list
# is used to whitelist such changes in each section / description.
changed_names = {
+ 'apic': ['timer', 'timer_expiry'],
'e1000': ['dev', 'parent_obj'],
'ehci': ['dev', 'pcidev'],
'I440FX': ['dev', 'parent_obj'],
'ich9_ahci': ['card', 'parent_obj'],
+ 'ich9-ahci': ['ahci', 'ich9_ahci'],
+ 'ioh3420': ['PCIDevice', 'PCIEDevice'],
'ioh-3240-express-root-port': ['port.br.dev',
'parent_obj.parent_obj.parent_obj',
'port.br.dev.exp.aer_log',
'parent_obj.parent_obj.parent_obj.exp.aer_log'],
+ 'lsiscsi': ['dev', 'parent_obj'],
'mch': ['d', 'parent_obj'],
'pci_bridge': ['bridge.dev', 'parent_obj', 'bridge.dev.shpc', 'shpc'],
'pcnet': ['pci_dev', 'parent_obj'],
'PIIX3': ['pci_irq_levels', 'pci_irq_levels_vmstate'],
'piix4_pm': ['dev', 'parent_obj', 'pci0_status',
- 'acpi_pci_hotplug.acpi_pcihp_pci_status[0x0]'],
+ 'acpi_pci_hotplug.acpi_pcihp_pci_status[0x0]',
+ 'pm1a.sts', 'ar.pm1.evt.sts', 'pm1a.en', 'ar.pm1.evt.en',
+ 'pm1_cnt.cnt', 'ar.pm1.cnt.cnt',
+ 'tmr.timer', 'ar.tmr.timer',
+ 'tmr.overflow_time', 'ar.tmr.overflow_time',
+ 'gpe', 'ar.gpe'],
'rtl8139': ['dev', 'parent_obj'],
'qxl': ['num_surfaces', 'ssd.num_surfaces'],
+ 'usb-ccid': ['abProtocolDataStructure', 'abProtocolDataStructure.data'],
'usb-host': ['dev', 'parent_obj'],
'usb-mouse': ['usb-ptr-queue', 'HIDPointerEventQueue'],
'usb-tablet': ['usb-ptr-queue', 'HIDPointerEventQueue'],
+ 'vmware_vga': ['card', 'parent_obj'],
+ 'vmware_vga_internal': ['depth', 'new_depth'],
'xhci': ['pci_dev', 'parent_obj'],
+ 'x3130-upstream': ['PCIDevice', 'PCIEDevice'],
'xio3130-express-downstream-port': ['port.br.dev',
'parent_obj.parent_obj.parent_obj',
'port.br.dev.exp.aer_log',
'parent_obj.parent_obj.parent_obj.exp.aer_log'],
+ 'xio3130-downstream': ['PCIDevice', 'PCIEDevice'],
'xio3130-express-upstream-port': ['br.dev', 'parent_obj.parent_obj',
'br.dev.exp.aer_log',
'parent_obj.parent_obj.exp.aer_log'],
@@ -79,6 +93,18 @@ def check_fields_match(name, s_field, d_field):
return False
+def get_changed_sec_name(sec):
+ # Section names can change -- see commit 292b1634 for an example.
+ changes = {
+ "ICH9 LPC": "ICH9-LPC",
+ }
+
+ for item in changes:
+ if item == sec:
+ return changes[item]
+ if changes[item] == sec:
+ return item
+ return ""
def exists_in_substruct(fields, item):
# Some QEMU versions moved a few fields inside a substruct. This
@@ -118,6 +144,7 @@ def check_fields(src_fields, dest_fields, desc, sec):
advance_src = True
advance_dest = True
+ unused_count = 0
while True:
if advance_src:
@@ -130,9 +157,10 @@ def check_fields(src_fields, dest_fields, desc, sec):
s_iter = s_iter_list.pop()
continue
else:
- # We want to avoid advancing just once -- when entering a
- # dest substruct, or when exiting one.
- advance_src = True
+ if unused_count == 0:
+ # We want to avoid advancing just once -- when entering a
+ # dest substruct, or when exiting one.
+ advance_src = True
if advance_dest:
try:
@@ -151,7 +179,37 @@ def check_fields(src_fields, dest_fields, desc, sec):
advance_src = False
continue
else:
- advance_dest = True
+ if unused_count == 0:
+ advance_dest = True
+
+ if unused_count > 0:
+ if advance_dest == False:
+ unused_count = unused_count - s_item["size"]
+ if unused_count == 0:
+ advance_dest = True
+ continue
+ if unused_count < 0:
+ print "Section \"" + sec + "\",",
+ print "Description \"" + desc + "\":",
+ print "unused size mismatch near \"",
+ print s_item["field"] + "\""
+ bump_taint()
+ break
+ continue
+
+ if advance_src == False:
+ unused_count = unused_count - d_item["size"]
+ if unused_count == 0:
+ advance_src = True
+ continue
+ if unused_count < 0:
+ print "Section \"" + sec + "\",",
+ print "Description \"" + desc + "\":",
+ print "unused size mismatch near \"",
+ print d_item["field"] + "\""
+ bump_taint()
+ break
+ continue
if not check_fields_match(desc, s_item["field"], d_item["field"]):
# Some fields were put in substructs, keeping the
@@ -182,6 +240,20 @@ def check_fields(src_fields, dest_fields, desc, sec):
advance_dest = False
continue
+ if s_item["field"] == "unused" or d_item["field"] == "unused":
+ if s_item["size"] == d_item["size"]:
+ continue
+
+ if d_item["field"] == "unused":
+ advance_dest = False
+ unused_count = d_item["size"] - s_item["size"]
+ continue
+
+ if s_item["field"] == "unused":
+ advance_src = False
+ unused_count = s_item["size"] - d_item["size"]
+ continue
+
print "Section \"" + sec + "\",",
print "Description \"" + desc + "\":",
print "expected field \"" + s_item["field"] + "\",",
@@ -314,13 +386,18 @@ def main():
dest_data = temp
for sec in src_data:
- if not sec in dest_data:
- print "Section \"" + sec + "\" does not exist in dest"
- bump_taint()
- continue
+ dest_sec = sec
+ if not dest_sec in dest_data:
+ # Either the section name got changed, or the section
+ # doesn't exist in dest.
+ dest_sec = get_changed_sec_name(sec)
+ if not dest_sec in dest_data:
+ print "Section \"" + sec + "\" does not exist in dest"
+ bump_taint()
+ continue
s = src_data[sec]
- d = dest_data[sec]
+ d = dest_data[dest_sec]
if sec == "vmschkmachine":
check_machine_type(s, d)
diff --git a/stubs/Makefile.objs b/stubs/Makefile.objs
index 528e1617b3..5e347d04bd 100644
--- a/stubs/Makefile.objs
+++ b/stubs/Makefile.objs
@@ -2,6 +2,7 @@ stub-obj-y += arch-query-cpu-def.o
stub-obj-y += bdrv-commit-all.o
stub-obj-y += chr-baum-init.o
stub-obj-y += chr-msmouse.o
+stub-obj-y += chr-testdev.o
stub-obj-y += clock-warp.o
stub-obj-y += cpu-get-clock.o
stub-obj-y += cpu-get-icount.o
diff --git a/stubs/chr-testdev.c b/stubs/chr-testdev.c
new file mode 100644
index 0000000000..23112a2c07
--- /dev/null
+++ b/stubs/chr-testdev.c
@@ -0,0 +1,7 @@
+#include "qemu-common.h"
+#include "sysemu/char.h"
+
+CharDriverState *chr_testdev_init(void)
+{
+ return 0;
+}
diff --git a/stubs/fdset-remove-fd.c b/stubs/fdset-remove-fd.c
index b3886d9f45..7f6d61e619 100644
--- a/stubs/fdset-remove-fd.c
+++ b/stubs/fdset-remove-fd.c
@@ -1,7 +1,6 @@
#include "qemu-common.h"
#include "monitor/monitor.h"
-int monitor_fdset_dup_fd_remove(int dupfd)
+void monitor_fdset_dup_fd_remove(int dupfd)
{
- return -1;
}
diff --git a/target-alpha/translate.c b/target-alpha/translate.c
index cc81e774df..76658a074a 100644
--- a/target-alpha/translate.c
+++ b/target-alpha/translate.c
@@ -26,6 +26,9 @@
#include "exec/helper-proto.h"
#include "exec/helper-gen.h"
+#include "trace-tcg.h"
+
+
#undef ALPHA_DEBUG_DISAS
#define CONFIG_SOFTFLOAT_INLINE
diff --git a/target-arm/cpu.c b/target-arm/cpu.c
index 05e52e0e83..7cebb76656 100644
--- a/target-arm/cpu.c
+++ b/target-arm/cpu.c
@@ -447,7 +447,7 @@ static void arm1026_initfn(Object *obj)
ARMCPRegInfo ifar = {
.name = "IFAR", .cp = 15, .crn = 6, .crm = 0, .opc1 = 0, .opc2 = 1,
.access = PL1_RW,
- .fieldoffset = offsetofhigh32(CPUARMState, cp15.far_el1),
+ .fieldoffset = offsetofhigh32(CPUARMState, cp15.far_el[1]),
.resetvalue = 0
};
define_one_arm_cp_reg(cpu, &ifar);
diff --git a/target-arm/cpu.h b/target-arm/cpu.h
index 369d4727ae..79205ba335 100644
--- a/target-arm/cpu.h
+++ b/target-arm/cpu.h
@@ -185,9 +185,9 @@ typedef struct CPUARMState {
uint32_t pmsav5_data_ap; /* PMSAv5 MPU data access permissions */
uint32_t pmsav5_insn_ap; /* PMSAv5 MPU insn access permissions */
uint32_t ifsr_el2; /* Fault status registers. */
- uint64_t esr_el[2];
+ uint64_t esr_el[4];
uint32_t c6_region[8]; /* MPU base/size registers. */
- uint64_t far_el1; /* Fault address registers. */
+ uint64_t far_el[4]; /* Fault address registers. */
uint64_t par_el1; /* Translation result. */
uint32_t c9_insn; /* Cache lockdown registers. */
uint32_t c9_data;
diff --git a/target-arm/helper-a64.c b/target-arm/helper-a64.c
index 2b4ce6ac60..2e9ef64786 100644
--- a/target-arm/helper-a64.c
+++ b/target-arm/helper-a64.c
@@ -465,13 +465,13 @@ void aarch64_cpu_do_interrupt(CPUState *cs)
}
env->cp15.esr_el[1] = env->exception.syndrome;
- env->cp15.far_el1 = env->exception.vaddress;
+ env->cp15.far_el[1] = env->exception.vaddress;
switch (cs->exception_index) {
case EXCP_PREFETCH_ABORT:
case EXCP_DATA_ABORT:
qemu_log_mask(CPU_LOG_INT, "...with FAR 0x%" PRIx64 "\n",
- env->cp15.far_el1);
+ env->cp15.far_el[1]);
break;
case EXCP_BKPT:
case EXCP_UDEF:
@@ -489,8 +489,7 @@ void aarch64_cpu_do_interrupt(CPUState *cs)
if (is_a64(env)) {
env->banked_spsr[aarch64_banked_spsr_index(1)] = pstate_read(env);
- env->sp_el[arm_current_pl(env)] = env->xregs[31];
- env->xregs[31] = env->sp_el[1];
+ aarch64_save_sp(env, arm_current_pl(env));
env->elr_el[1] = env->pc;
} else {
env->banked_spsr[0] = cpsr_read(env);
@@ -508,6 +507,7 @@ void aarch64_cpu_do_interrupt(CPUState *cs)
pstate_write(env, PSTATE_DAIF | PSTATE_MODE_EL1h);
env->aarch64 = 1;
+ aarch64_restore_sp(env, 1);
env->pc = addr;
cs->interrupt_request |= CPU_INTERRUPT_EXITTB;
diff --git a/target-arm/helper.c b/target-arm/helper.c
index d3438560e6..f630d96306 100644
--- a/target-arm/helper.c
+++ b/target-arm/helper.c
@@ -521,7 +521,7 @@ static const ARMCPRegInfo v6_cp_reginfo[] = {
.access = PL0_W, .type = ARM_CP_NOP },
{ .name = "IFAR", .cp = 15, .crn = 6, .crm = 0, .opc1 = 0, .opc2 = 2,
.access = PL1_RW,
- .fieldoffset = offsetofhigh32(CPUARMState, cp15.far_el1),
+ .fieldoffset = offsetofhigh32(CPUARMState, cp15.far_el[1]),
.resetvalue = 0, },
/* Watchpoint Fault Address Register : should actually only be present
* for 1136, 1176, 11MPCore.
@@ -1516,7 +1516,7 @@ static const ARMCPRegInfo vmsa_cp_reginfo[] = {
/* 64-bit FAR; this entry also gives us the AArch32 DFAR */
{ .name = "FAR_EL1", .state = ARM_CP_STATE_BOTH,
.opc0 = 3, .crn = 6, .crm = 0, .opc1 = 0, .opc2 = 0,
- .access = PL1_RW, .fieldoffset = offsetof(CPUARMState, cp15.far_el1),
+ .access = PL1_RW, .fieldoffset = offsetof(CPUARMState, cp15.far_el[1]),
.resetvalue = 0, },
REGINFO_SENTINEL
};
@@ -1801,12 +1801,17 @@ static CPAccessResult aa64_cacheop_access(CPUARMState *env,
return CP_ACCESS_OK;
}
+/* See: D4.7.2 TLB maintenance requirements and the TLB maintenance instructions
+ * Page D4-1736 (DDI0487A.b)
+ */
+
static void tlbi_aa64_va_write(CPUARMState *env, const ARMCPRegInfo *ri,
uint64_t value)
{
/* Invalidate by VA (AArch64 version) */
ARMCPU *cpu = arm_env_get_cpu(env);
- uint64_t pageaddr = value << 12;
+ uint64_t pageaddr = sextract64(value << 12, 0, 56);
+
tlb_flush_page(CPU(cpu), pageaddr);
}
@@ -1815,7 +1820,8 @@ static void tlbi_aa64_vaa_write(CPUARMState *env, const ARMCPRegInfo *ri,
{
/* Invalidate by VA, all ASIDs (AArch64 version) */
ARMCPU *cpu = arm_env_get_cpu(env);
- uint64_t pageaddr = value << 12;
+ uint64_t pageaddr = sextract64(value << 12, 0, 56);
+
tlb_flush_page(CPU(cpu), pageaddr);
}
@@ -1853,7 +1859,7 @@ static uint64_t aa64_dczid_read(CPUARMState *env, const ARMCPRegInfo *ri)
static CPAccessResult sp_el0_access(CPUARMState *env, const ARMCPRegInfo *ri)
{
- if (!env->pstate & PSTATE_SP) {
+ if (!(env->pstate & PSTATE_SP)) {
/* Access to SP_EL0 is undefined if it's being used as
* the stack pointer.
*/
@@ -2127,6 +2133,13 @@ static const ARMCPRegInfo v8_el2_cp_reginfo[] = {
.opc0 = 3, .opc1 = 4, .crn = 4, .crm = 0, .opc2 = 1,
.access = PL2_RW,
.fieldoffset = offsetof(CPUARMState, elr_el[2]) },
+ { .name = "ESR_EL2", .state = ARM_CP_STATE_AA64,
+ .type = ARM_CP_NO_MIGRATE,
+ .opc0 = 3, .opc1 = 4, .crn = 5, .crm = 2, .opc2 = 0,
+ .access = PL2_RW, .fieldoffset = offsetof(CPUARMState, cp15.esr_el[2]) },
+ { .name = "FAR_EL2", .state = ARM_CP_STATE_AA64,
+ .opc0 = 3, .opc1 = 4, .crn = 6, .crm = 0, .opc2 = 0,
+ .access = PL2_RW, .fieldoffset = offsetof(CPUARMState, cp15.far_el[2]) },
{ .name = "SPSR_EL2", .state = ARM_CP_STATE_AA64,
.type = ARM_CP_NO_MIGRATE,
.opc0 = 3, .opc1 = 4, .crn = 4, .crm = 0, .opc2 = 0,
@@ -2145,6 +2158,13 @@ static const ARMCPRegInfo v8_el3_cp_reginfo[] = {
.opc0 = 3, .opc1 = 6, .crn = 4, .crm = 0, .opc2 = 1,
.access = PL3_RW,
.fieldoffset = offsetof(CPUARMState, elr_el[3]) },
+ { .name = "ESR_EL3", .state = ARM_CP_STATE_AA64,
+ .type = ARM_CP_NO_MIGRATE,
+ .opc0 = 3, .opc1 = 6, .crn = 5, .crm = 2, .opc2 = 0,
+ .access = PL3_RW, .fieldoffset = offsetof(CPUARMState, cp15.esr_el[3]) },
+ { .name = "FAR_EL3", .state = ARM_CP_STATE_AA64,
+ .opc0 = 3, .opc1 = 6, .crn = 6, .crm = 0, .opc2 = 0,
+ .access = PL3_RW, .fieldoffset = offsetof(CPUARMState, cp15.far_el[3]) },
{ .name = "SPSR_EL3", .state = ARM_CP_STATE_AA64,
.type = ARM_CP_NO_MIGRATE,
.opc0 = 3, .opc1 = 6, .crn = 4, .crm = 0, .opc2 = 0,
@@ -3425,8 +3445,8 @@ void arm_cpu_do_interrupt(CPUState *cs)
/* Fall through to prefetch abort. */
case EXCP_PREFETCH_ABORT:
env->cp15.ifsr_el2 = env->exception.fsr;
- env->cp15.far_el1 = deposit64(env->cp15.far_el1, 32, 32,
- env->exception.vaddress);
+ env->cp15.far_el[1] = deposit64(env->cp15.far_el[1], 32, 32,
+ env->exception.vaddress);
qemu_log_mask(CPU_LOG_INT, "...with IFSR 0x%x IFAR 0x%x\n",
env->cp15.ifsr_el2, (uint32_t)env->exception.vaddress);
new_mode = ARM_CPU_MODE_ABT;
@@ -3436,8 +3456,8 @@ void arm_cpu_do_interrupt(CPUState *cs)
break;
case EXCP_DATA_ABORT:
env->cp15.esr_el[1] = env->exception.fsr;
- env->cp15.far_el1 = deposit64(env->cp15.far_el1, 0, 32,
- env->exception.vaddress);
+ env->cp15.far_el[1] = deposit64(env->cp15.far_el[1], 0, 32,
+ env->exception.vaddress);
qemu_log_mask(CPU_LOG_INT, "...with DFSR 0x%x DFAR 0x%x\n",
(uint32_t)env->cp15.esr_el[1],
(uint32_t)env->exception.vaddress);
@@ -4142,8 +4162,8 @@ int arm_cpu_handle_mmu_fault(CPUState *cs, vaddr address,
&page_size);
if (ret == 0) {
/* Map a single [sub]page. */
- phys_addr &= ~(hwaddr)0x3ff;
- address &= ~(target_ulong)0x3ff;
+ phys_addr &= TARGET_PAGE_MASK;
+ address &= TARGET_PAGE_MASK;
tlb_set_page(cs, address, phys_addr, prot, mmu_idx, page_size);
return 0;
}
diff --git a/target-arm/internals.h b/target-arm/internals.h
index 564b5fa602..08fa69757d 100644
--- a/target-arm/internals.h
+++ b/target-arm/internals.h
@@ -105,6 +105,24 @@ enum arm_fprounding {
int arm_rmode_to_sf(int rmode);
+static inline void aarch64_save_sp(CPUARMState *env, int el)
+{
+ if (env->pstate & PSTATE_SP) {
+ env->sp_el[el] = env->xregs[31];
+ } else {
+ env->sp_el[0] = env->xregs[31];
+ }
+}
+
+static inline void aarch64_restore_sp(CPUARMState *env, int el)
+{
+ if (env->pstate & PSTATE_SP) {
+ env->xregs[31] = env->sp_el[el];
+ } else {
+ env->xregs[31] = env->sp_el[0];
+ }
+}
+
static inline void update_spsel(CPUARMState *env, uint32_t imm)
{
unsigned int cur_el = arm_current_pl(env);
@@ -114,21 +132,14 @@ static inline void update_spsel(CPUARMState *env, uint32_t imm)
if (!((imm ^ env->pstate) & PSTATE_SP)) {
return;
}
+ aarch64_save_sp(env, cur_el);
env->pstate = deposit32(env->pstate, 0, 1, imm);
/* We rely on illegal updates to SPsel from EL0 to get trapped
* at translation time.
*/
assert(cur_el >= 1 && cur_el <= 3);
- if (env->pstate & PSTATE_SP) {
- /* Switch from using SP_EL0 to using SP_ELx */
- env->sp_el[0] = env->xregs[31];
- env->xregs[31] = env->sp_el[cur_el];
- } else {
- /* Switch from SP_EL0 to SP_ELx */
- env->sp_el[cur_el] = env->xregs[31];
- env->xregs[31] = env->sp_el[0];
- }
+ aarch64_restore_sp(env, cur_el);
}
/* Valid Syndrome Register EC field values */
diff --git a/target-arm/kvm64.c b/target-arm/kvm64.c
index 5d217ca2ad..c615286158 100644
--- a/target-arm/kvm64.c
+++ b/target-arm/kvm64.c
@@ -21,6 +21,7 @@
#include "sysemu/kvm.h"
#include "kvm_arm.h"
#include "cpu.h"
+#include "internals.h"
#include "hw/arm/arm.h"
static inline void set_feature(uint64_t *features, int feature)
@@ -132,11 +133,7 @@ int kvm_arch_put_registers(CPUState *cs, int level)
/* KVM puts SP_EL0 in regs.sp and SP_EL1 in regs.sp_el1. On the
* QEMU side we keep the current SP in xregs[31] as well.
*/
- if (env->pstate & PSTATE_SP) {
- env->sp_el[1] = env->xregs[31];
- } else {
- env->sp_el[0] = env->xregs[31];
- }
+ aarch64_save_sp(env, 1);
reg.id = AARCH64_CORE_REG(regs.sp);
reg.addr = (uintptr_t) &env->sp_el[0];
@@ -235,11 +232,7 @@ int kvm_arch_get_registers(CPUState *cs)
/* KVM puts SP_EL0 in regs.sp and SP_EL1 in regs.sp_el1. On the
* QEMU side we keep the current SP in xregs[31] as well.
*/
- if (env->pstate & PSTATE_SP) {
- env->xregs[31] = env->sp_el[1];
- } else {
- env->xregs[31] = env->sp_el[0];
- }
+ aarch64_restore_sp(env, 1);
reg.id = AARCH64_CORE_REG(regs.pc);
reg.addr = (uintptr_t) &env->pc;
diff --git a/target-arm/op_helper.c b/target-arm/op_helper.c
index 9c1ef525a3..25ad902e04 100644
--- a/target-arm/op_helper.c
+++ b/target-arm/op_helper.c
@@ -376,11 +376,7 @@ void HELPER(exception_return)(CPUARMState *env)
uint32_t spsr = env->banked_spsr[spsr_idx];
int new_el, i;
- if (env->pstate & PSTATE_SP) {
- env->sp_el[cur_el] = env->xregs[31];
- } else {
- env->sp_el[0] = env->xregs[31];
- }
+ aarch64_save_sp(env, cur_el);
env->exclusive_addr = -1;
@@ -414,7 +410,7 @@ void HELPER(exception_return)(CPUARMState *env)
}
env->aarch64 = 1;
pstate_write(env, spsr);
- env->xregs[31] = env->sp_el[new_el];
+ aarch64_restore_sp(env, new_el);
env->pc = env->elr_el[cur_el];
}
diff --git a/target-arm/translate-a64.c b/target-arm/translate-a64.c
index 33b5025fee..f04ca49631 100644
--- a/target-arm/translate-a64.c
+++ b/target-arm/translate-a64.c
@@ -35,6 +35,8 @@
#include "exec/helper-proto.h"
#include "exec/helper-gen.h"
+#include "trace-tcg.h"
+
static TCGv_i64 cpu_X[32];
static TCGv_i64 cpu_pc;
static TCGv_i32 cpu_NF, cpu_ZF, cpu_CF, cpu_VF;
diff --git a/target-arm/translate.c b/target-arm/translate.c
index cf4e767ff8..40121858d6 100644
--- a/target-arm/translate.c
+++ b/target-arm/translate.c
@@ -35,6 +35,9 @@
#include "exec/helper-proto.h"
#include "exec/helper-gen.h"
+#include "trace-tcg.h"
+
+
#define ENABLE_ARCH_4T arm_feature(env, ARM_FEATURE_V4T)
#define ENABLE_ARCH_5 arm_feature(env, ARM_FEATURE_V5)
/* currently all emulated v5 cores are also v5TE, so don't bother */
diff --git a/target-cris/translate.c b/target-cris/translate.c
index ab0e47962b..e37b04e69d 100644
--- a/target-cris/translate.c
+++ b/target-cris/translate.c
@@ -33,6 +33,9 @@
#include "exec/helper-gen.h"
+#include "trace-tcg.h"
+
+
#define DISAS_CRIS 0
#if DISAS_CRIS
# define LOG_DIS(...) qemu_log_mask(CPU_LOG_TB_IN_ASM, ## __VA_ARGS__)
diff --git a/target-i386/cpu.c b/target-i386/cpu.c
index 6d008ab5ee..217500c735 100644
--- a/target-i386/cpu.c
+++ b/target-i386/cpu.c
@@ -1716,9 +1716,9 @@ static void x86_set_hv_spinlocks(Object *obj, Visitor *v, void *opaque,
if (value < min || value > max) {
error_setg(errp, "Property %s.%s doesn't take value %" PRId64
- " (minimum: %" PRId64 ", maximum: %" PRId64 ")",
- object_get_typename(obj), name ? name : "null",
- value, min, max);
+ " (minimum: %" PRId64 ", maximum: %" PRId64 ")",
+ object_get_typename(obj), name ? name : "null",
+ value, min, max);
return;
}
cpu->hyperv_spinlock_attempts = value;
@@ -1808,8 +1808,8 @@ static void x86_cpu_parse_featurestr(CPUState *cs, char *features,
}
if (numvalue < min) {
error_report("hv-spinlocks value shall always be >= 0x%x"
- ", fixup will be removed in future versions",
- min);
+ ", fixup will be removed in future versions",
+ min);
numvalue = min;
}
snprintf(num, sizeof(num), "%" PRId32, numvalue);
diff --git a/target-i386/helper.c b/target-i386/helper.c
index 11ca8649b5..47b982b437 100644
--- a/target-i386/helper.c
+++ b/target-i386/helper.c
@@ -750,7 +750,8 @@ do_check_protect_pse36:
/* the page can be put in the TLB */
prot = PAGE_READ;
if (!(ptep & PG_NX_MASK) &&
- !((env->cr[4] & CR4_SMEP_MASK) && (ptep & PG_USER_MASK))) {
+ (mmu_idx == MMU_USER_IDX ||
+ !((env->cr[4] & CR4_SMEP_MASK) && (ptep & PG_USER_MASK)))) {
prot |= PAGE_EXEC;
}
if (pte & PG_DIRTY_MASK) {
diff --git a/target-i386/translate.c b/target-i386/translate.c
index 6fcd8245d2..418173e0ea 100644
--- a/target-i386/translate.c
+++ b/target-i386/translate.c
@@ -32,6 +32,9 @@
#include "exec/helper-proto.h"
#include "exec/helper-gen.h"
+#include "trace-tcg.h"
+
+
#define PREFIX_REPZ 0x01
#define PREFIX_REPNZ 0x02
#define PREFIX_LOCK 0x04
diff --git a/target-lm32/translate.c b/target-lm32/translate.c
index a51ade9a15..8454e8b517 100644
--- a/target-lm32/translate.c
+++ b/target-lm32/translate.c
@@ -27,6 +27,9 @@
#include "exec/helper-gen.h"
+#include "trace-tcg.h"
+
+
#define DISAS_LM32 1
#if DISAS_LM32
# define LOG_DIS(...) qemu_log_mask(CPU_LOG_TB_IN_ASM, ## __VA_ARGS__)
diff --git a/target-m68k/translate.c b/target-m68k/translate.c
index 50df4d3844..efd4cfc3c7 100644
--- a/target-m68k/translate.c
+++ b/target-m68k/translate.c
@@ -27,6 +27,9 @@
#include "exec/helper-proto.h"
#include "exec/helper-gen.h"
+#include "trace-tcg.h"
+
+
//#define DEBUG_DISPATCH 1
/* Fake floating point. */
diff --git a/target-microblaze/translate.c b/target-microblaze/translate.c
index 03ea15803b..fd2b771645 100644
--- a/target-microblaze/translate.c
+++ b/target-microblaze/translate.c
@@ -26,6 +26,9 @@
#include "exec/cpu_ldst.h"
#include "exec/helper-gen.h"
+#include "trace-tcg.h"
+
+
#define SIM_COMPAT 0
#define DISAS_GNU 1
#define DISAS_MB 1
diff --git a/target-mips/op_helper.c b/target-mips/op_helper.c
index 27651a4a00..df97b35f87 100644
--- a/target-mips/op_helper.c
+++ b/target-mips/op_helper.c
@@ -21,6 +21,7 @@
#include "qemu/host-utils.h"
#include "exec/helper-proto.h"
#include "exec/cpu_ldst.h"
+#include "sysemu/kvm.h"
#ifndef CONFIG_USER_ONLY
static inline void cpu_mips_tlb_flush (CPUMIPSState *env, int flush_global);
@@ -2168,6 +2169,16 @@ void mips_cpu_unassigned_access(CPUState *cs, hwaddr addr,
MIPSCPU *cpu = MIPS_CPU(cs);
CPUMIPSState *env = &cpu->env;
+ /*
+ * Raising an exception with KVM enabled will crash because it won't be from
+ * the main execution loop so the longjmp won't have a matching setjmp.
+ * Until we can trigger a bus error exception through KVM lets just ignore
+ * the access.
+ */
+ if (kvm_enabled()) {
+ return;
+ }
+
if (is_exec) {
helper_raise_exception(env, EXCP_IBE);
} else {
diff --git a/target-mips/translate.c b/target-mips/translate.c
index d7b8c4dbc8..06db150325 100644
--- a/target-mips/translate.c
+++ b/target-mips/translate.c
@@ -30,6 +30,9 @@
#include "exec/helper-gen.h"
#include "sysemu/kvm.h"
+#include "trace-tcg.h"
+
+
#define MIPS_DEBUG_DISAS 0
//#define MIPS_DEBUG_SIGN_EXTENSIONS
@@ -15300,6 +15303,9 @@ static void decode_opc (CPUMIPSState *env, DisasContext *ctx)
gen_load_gpr(t1, rs);
gen_helper_dinsv(cpu_gpr[rt], cpu_env, t1, t0);
+
+ tcg_temp_free(t0);
+ tcg_temp_free(t1);
break;
}
default: /* Invalid */
diff --git a/target-openrisc/translate.c b/target-openrisc/translate.c
index 55ff935d5e..407bd9762f 100644
--- a/target-openrisc/translate.c
+++ b/target-openrisc/translate.c
@@ -31,6 +31,9 @@
#include "exec/helper-proto.h"
#include "exec/helper-gen.h"
+#include "trace-tcg.h"
+
+
#define OPENRISC_DISAS
#ifdef OPENRISC_DISAS
diff --git a/target-ppc/translate.c b/target-ppc/translate.c
index b23933f7bd..c07bb01a7a 100644
--- a/target-ppc/translate.c
+++ b/target-ppc/translate.c
@@ -27,6 +27,9 @@
#include "exec/helper-proto.h"
#include "exec/helper-gen.h"
+#include "trace-tcg.h"
+
+
#define CPU_SINGLE_STEP 0x1
#define CPU_BRANCH_STEP 0x2
#define GDBSTUB_SINGLE_STEP 0x4
diff --git a/target-s390x/translate.c b/target-s390x/translate.c
index e2a1d05f15..0cb036f667 100644
--- a/target-s390x/translate.c
+++ b/target-s390x/translate.c
@@ -42,6 +42,8 @@ static TCGv_ptr cpu_env;
#include "exec/helper-proto.h"
#include "exec/helper-gen.h"
+#include "trace-tcg.h"
+
/* Information that (most) every instruction needs to manipulate. */
typedef struct DisasContext DisasContext;
diff --git a/target-sh4/translate.c b/target-sh4/translate.c
index 8126818142..3088edc6a6 100644
--- a/target-sh4/translate.c
+++ b/target-sh4/translate.c
@@ -28,6 +28,9 @@
#include "exec/helper-proto.h"
#include "exec/helper-gen.h"
+#include "trace-tcg.h"
+
+
typedef struct DisasContext {
struct TranslationBlock *tb;
target_ulong pc;
diff --git a/target-sparc/ldst_helper.c b/target-sparc/ldst_helper.c
index 03bd9f9706..1a62e193bd 100644
--- a/target-sparc/ldst_helper.c
+++ b/target-sparc/ldst_helper.c
@@ -2154,7 +2154,6 @@ void helper_stf_asi(CPUSPARCState *env, target_ulong addr, int asi, int size,
unsigned int i;
target_ulong val;
- helper_check_align(env, addr, 3);
addr = asi_address_mask(env, asi, addr);
switch (asi) {
@@ -2192,7 +2191,21 @@ void helper_stf_asi(CPUSPARCState *env, target_ulong addr, int asi, int size,
}
return;
+ case 0xd2: /* 16-bit floating point load primary */
+ case 0xd3: /* 16-bit floating point load secondary */
+ case 0xda: /* 16-bit floating point load primary, LE */
+ case 0xdb: /* 16-bit floating point load secondary, LE */
+ helper_check_align(env, addr, 1);
+ /* Fall through */
+ case 0xd0: /* 8-bit floating point load primary */
+ case 0xd1: /* 8-bit floating point load secondary */
+ case 0xd8: /* 8-bit floating point load primary, LE */
+ case 0xd9: /* 8-bit floating point load secondary, LE */
+ val = env->fpr[rd / 2].l.lower;
+ helper_st_asi(env, addr, val, asi & 0x8d, ((asi & 2) >> 1) + 1);
+ return;
default:
+ helper_check_align(env, addr, 3);
break;
}
diff --git a/target-sparc/translate.c b/target-sparc/translate.c
index 1ab07a18a2..78c4e21cff 100644
--- a/target-sparc/translate.c
+++ b/target-sparc/translate.c
@@ -32,6 +32,9 @@
#include "exec/helper-gen.h"
+#include "trace-tcg.h"
+
+
#define DEBUG_DISAS
#define DYNAMIC_PC 1 /* dynamic pc value */
diff --git a/target-unicore32/translate.c b/target-unicore32/translate.c
index e3643c23cd..653c225187 100644
--- a/target-unicore32/translate.c
+++ b/target-unicore32/translate.c
@@ -23,6 +23,9 @@
#include "exec/helper-proto.h"
#include "exec/helper-gen.h"
+#include "trace-tcg.h"
+
+
/* internal defines */
typedef struct DisasContext {
target_ulong pc;
diff --git a/target-xtensa/translate.c b/target-xtensa/translate.c
index 2f22cce845..badca195f4 100644
--- a/target-xtensa/translate.c
+++ b/target-xtensa/translate.c
@@ -41,6 +41,9 @@
#include "exec/helper-proto.h"
#include "exec/helper-gen.h"
+#include "trace-tcg.h"
+
+
typedef struct DisasContext {
const XtensaConfig *config;
TranslationBlock *tb;
diff --git a/tests/Makefile b/tests/Makefile
index fa25c70712..837e9c89e7 100644
--- a/tests/Makefile
+++ b/tests/Makefile
@@ -141,6 +141,8 @@ check-qtest-i386-y += tests/i440fx-test$(EXESUF)
check-qtest-i386-y += tests/fw_cfg-test$(EXESUF)
check-qtest-i386-y += tests/blockdev-test$(EXESUF)
check-qtest-i386-y += tests/qdev-monitor-test$(EXESUF)
+check-qtest-i386-y += tests/wdt_ib700-test$(EXESUF)
+gcov-files-i386-y += hw/watchdog/watchdog.c hw/watchdog/wdt_ib700.c
check-qtest-i386-y += $(check-qtest-pci-y)
gcov-files-i386-y += $(gcov-files-pci-y)
check-qtest-i386-y += tests/vmxnet3-test$(EXESUF)
@@ -280,7 +282,7 @@ tests/test-qmp-event$(EXESUF): tests/test-qmp-event.o $(test-qapi-obj-y) libqemu
tests/test-qmp-output-visitor$(EXESUF): tests/test-qmp-output-visitor.o $(test-qapi-obj-y) libqemuutil.a libqemustub.a
tests/test-qmp-input-visitor$(EXESUF): tests/test-qmp-input-visitor.o $(test-qapi-obj-y) libqemuutil.a libqemustub.a
tests/test-qmp-input-strict$(EXESUF): tests/test-qmp-input-strict.o $(test-qapi-obj-y) libqemuutil.a libqemustub.a
-tests/test-qmp-commands$(EXESUF): tests/test-qmp-commands.o tests/test-qmp-marshal.o $(test-qapi-obj-y) qapi-types.o qapi-visit.o libqemuutil.a libqemustub.a
+tests/test-qmp-commands$(EXESUF): tests/test-qmp-commands.o tests/test-qmp-marshal.o $(test-qapi-obj-y) libqemuutil.a libqemustub.a
tests/test-visitor-serialization$(EXESUF): tests/test-visitor-serialization.o $(test-qapi-obj-y) libqemuutil.a libqemustub.a
tests/test-opts-visitor$(EXESUF): tests/test-opts-visitor.o $(test-qapi-obj-y) libqemuutil.a libqemustub.a
@@ -311,6 +313,7 @@ tests/pcnet-test$(EXESUF): tests/pcnet-test.o
tests/eepro100-test$(EXESUF): tests/eepro100-test.o
tests/vmxnet3-test$(EXESUF): tests/vmxnet3-test.o
tests/ne2000-test$(EXESUF): tests/ne2000-test.o
+tests/wdt_ib700-test$(EXESUF): tests/wdt_ib700-test.o
tests/virtio-balloon-test$(EXESUF): tests/virtio-balloon-test.o
tests/virtio-blk-test$(EXESUF): tests/virtio-blk-test.o
tests/virtio-net-test$(EXESUF): tests/virtio-net-test.o
diff --git a/tests/acpi-test-data/pc/DSDT b/tests/acpi-test-data/pc/DSDT
index 7ed03fd37e..d37ec34454 100644
--- a/tests/acpi-test-data/pc/DSDT
+++ b/tests/acpi-test-data/pc/DSDT
Binary files differ
diff --git a/tests/bios-tables-test.c b/tests/bios-tables-test.c
index 62771f7608..045eb27577 100644
--- a/tests/bios-tables-test.c
+++ b/tests/bios-tables-test.c
@@ -487,7 +487,11 @@ static GString *normalize_asl(gchar *asl_code)
/* strip comments (different generation days) */
comment = g_strstr_len(asl->str, asl->len, COMMENT_END);
if (comment) {
- asl = g_string_erase(asl, 0, comment + sizeof(COMMENT_END) - asl->str);
+ comment += strlen(COMMENT_END);
+ while (*comment == '\n') {
+ comment++;
+ }
+ asl = g_string_erase(asl, 0, comment - asl->str);
}
/* strip def block name (it has file path in it) */
diff --git a/tests/fdc-test.c b/tests/fdc-test.c
index c8e1e7bd18..203074cdad 100644
--- a/tests/fdc-test.c
+++ b/tests/fdc-test.c
@@ -65,7 +65,7 @@ enum {
DSKCHG = 0x80,
};
-char test_image[] = "/tmp/qtest.XXXXXX";
+static char test_image[] = "/tmp/qtest.XXXXXX";
#define assert_bit_set(data, mask) g_assert_cmphex((data) & (mask), ==, (mask))
#define assert_bit_clear(data, mask) g_assert_cmphex((data) & (mask), ==, 0)
diff --git a/tests/ide-test.c b/tests/ide-test.c
index 4a0d97f197..ffce6ed669 100644
--- a/tests/ide-test.c
+++ b/tests/ide-test.c
@@ -106,6 +106,7 @@ static QPCIBus *pcibus = NULL;
static QGuestAllocator *guest_malloc;
static char tmp_path[] = "/tmp/qtest.XXXXXX";
+static char debug_path[] = "/tmp/qtest-blkdebug.XXXXXX";
static void ide_test_start(const char *cmdline_fmt, ...)
{
@@ -119,6 +120,8 @@ static void ide_test_start(const char *cmdline_fmt, ...)
qtest_start(cmdline);
qtest_irq_intercept_in(global_qtest, "ioapic");
guest_malloc = pc_alloc_init();
+
+ g_free(cmdline);
}
static void ide_test_quit(void)
@@ -145,7 +148,7 @@ static QPCIDevice *get_pci_device(uint16_t *bmdma_base)
g_assert(device_id == PCI_DEVICE_ID_INTEL_82371SB_1);
/* Map bmdma BAR */
- *bmdma_base = (uint16_t)(uintptr_t) qpci_iomap(dev, 4);
+ *bmdma_base = (uint16_t)(uintptr_t) qpci_iomap(dev, 4, NULL);
qpci_device_enable(dev);
@@ -489,6 +492,91 @@ static void test_flush(void)
ide_test_quit();
}
+static void prepare_blkdebug_script(const char *debug_fn, const char *event)
+{
+ FILE *debug_file = fopen(debug_fn, "w");
+ int ret;
+
+ fprintf(debug_file, "[inject-error]\n");
+ fprintf(debug_file, "event = \"%s\"\n", event);
+ fprintf(debug_file, "errno = \"5\"\n");
+ fprintf(debug_file, "state = \"1\"\n");
+ fprintf(debug_file, "immediately = \"off\"\n");
+ fprintf(debug_file, "once = \"on\"\n");
+
+ fprintf(debug_file, "[set-state]\n");
+ fprintf(debug_file, "event = \"%s\"\n", event);
+ fprintf(debug_file, "new_state = \"2\"\n");
+ fflush(debug_file);
+ g_assert(!ferror(debug_file));
+
+ ret = fclose(debug_file);
+ g_assert(ret == 0);
+}
+
+static void test_retry_flush(void)
+{
+ uint8_t data;
+ const char *s;
+ QDict *response;
+
+ prepare_blkdebug_script(debug_path, "flush_to_disk");
+
+ ide_test_start(
+ "-vnc none "
+ "-drive file=blkdebug:%s:%s,if=ide,cache=writeback,rerror=stop,werror=stop",
+ debug_path, tmp_path);
+
+ /* FLUSH CACHE command on device 0*/
+ outb(IDE_BASE + reg_device, 0);
+ outb(IDE_BASE + reg_command, CMD_FLUSH_CACHE);
+
+ /* Check status while request is in flight*/
+ data = inb(IDE_BASE + reg_status);
+ assert_bit_set(data, BSY | DRDY);
+ assert_bit_clear(data, DF | ERR | DRQ);
+
+ for (;; response = NULL) {
+ response = qmp_receive();
+ if ((qdict_haskey(response, "event")) &&
+ (strcmp(qdict_get_str(response, "event"), "STOP") == 0)) {
+ QDECREF(response);
+ break;
+ }
+ QDECREF(response);
+ }
+
+ /* Complete the command */
+ s = "{'execute':'cont' }";
+ qmp_discard_response(s);
+
+ /* Check registers */
+ data = inb(IDE_BASE + reg_device);
+ g_assert_cmpint(data & DEV, ==, 0);
+
+ do {
+ data = inb(IDE_BASE + reg_status);
+ } while (data & BSY);
+
+ assert_bit_set(data, DRDY);
+ assert_bit_clear(data, BSY | DF | ERR | DRQ);
+
+ ide_test_quit();
+}
+
+static void test_flush_nodev(void)
+{
+ ide_test_start("");
+
+ /* FLUSH CACHE command on device 0*/
+ outb(IDE_BASE + reg_device, 0);
+ outb(IDE_BASE + reg_command, CMD_FLUSH_CACHE);
+
+ /* Just testing that qemu doesn't crash... */
+
+ ide_test_quit();
+}
+
int main(int argc, char **argv)
{
const char *arch = qtest_get_arch();
@@ -501,6 +589,11 @@ int main(int argc, char **argv)
return 0;
}
+ /* Create temporary blkdebug instructions */
+ fd = mkstemp(debug_path);
+ g_assert(fd >= 0);
+ close(fd);
+
/* Create a temporary raw image */
fd = mkstemp(tmp_path);
g_assert(fd >= 0);
@@ -521,11 +614,15 @@ int main(int argc, char **argv)
qtest_add_func("/ide/bmdma/teardown", test_bmdma_teardown);
qtest_add_func("/ide/flush", test_flush);
+ qtest_add_func("/ide/flush_nodev", test_flush_nodev);
+
+ qtest_add_func("/ide/retry/flush", test_retry_flush);
ret = g_test_run();
/* Cleanup */
unlink(tmp_path);
+ unlink(debug_path);
return ret;
}
diff --git a/tests/image-fuzzer/qcow2/__init__.py b/tests/image-fuzzer/qcow2/__init__.py
new file mode 100644
index 0000000000..e2ebe19311
--- /dev/null
+++ b/tests/image-fuzzer/qcow2/__init__.py
@@ -0,0 +1 @@
+from layout import create_image
diff --git a/tests/image-fuzzer/qcow2/fuzz.py b/tests/image-fuzzer/qcow2/fuzz.py
new file mode 100644
index 0000000000..57527f9b4a
--- /dev/null
+++ b/tests/image-fuzzer/qcow2/fuzz.py
@@ -0,0 +1,355 @@
+# Fuzzing functions for qcow2 fields
+#
+# Copyright (C) 2014 Maria Kustova <maria.k@catit.be>
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+
+import random
+
+
+UINT8 = 0xff
+UINT32 = 0xffffffff
+UINT64 = 0xffffffffffffffff
+# Most significant bit orders
+UINT32_M = 31
+UINT64_M = 63
+# Fuzz vectors
+UINT8_V = [0, 0x10, UINT8/4, UINT8/2 - 1, UINT8/2, UINT8/2 + 1, UINT8 - 1,
+ UINT8]
+UINT32_V = [0, 0x100, 0x1000, 0x10000, 0x100000, UINT32/4, UINT32/2 - 1,
+ UINT32/2, UINT32/2 + 1, UINT32 - 1, UINT32]
+UINT64_V = UINT32_V + [0x1000000, 0x10000000, 0x100000000, UINT64/4,
+ UINT64/2 - 1, UINT64/2, UINT64/2 + 1, UINT64 - 1,
+ UINT64]
+STRING_V = ['%s%p%x%d', '.1024d', '%.2049d', '%p%p%p%p', '%x%x%x%x',
+ '%d%d%d%d', '%s%s%s%s', '%99999999999s', '%08x', '%%20d', '%%20n',
+ '%%20x', '%%20s', '%s%s%s%s%s%s%s%s%s%s', '%p%p%p%p%p%p%p%p%p%p',
+ '%#0123456x%08x%x%s%p%d%n%o%u%c%h%l%q%j%z%Z%t%i%e%g%f%a%C%S%08x%%',
+ '%s x 129', '%x x 257']
+
+
+def random_from_intervals(intervals):
+ """Select a random integer number from the list of specified intervals.
+
+ Each interval is a tuple of lower and upper limits of the interval. The
+ limits are included. Intervals in a list should not overlap.
+ """
+ total = reduce(lambda x, y: x + y[1] - y[0] + 1, intervals, 0)
+ r = random.randint(0, total - 1) + intervals[0][0]
+ for x in zip(intervals, intervals[1:]):
+ r = r + (r > x[0][1]) * (x[1][0] - x[0][1] - 1)
+ return r
+
+
+def random_bits(bit_ranges):
+ """Generate random binary mask with ones in the specified bit ranges.
+
+ Each bit_ranges is a list of tuples of lower and upper limits of bit
+ positions will be fuzzed. The limits are included. Random amount of bits
+ in range limits will be set to ones. The mask is returned in decimal
+ integer format.
+ """
+ bit_numbers = []
+ # Select random amount of random positions in bit_ranges
+ for rng in bit_ranges:
+ bit_numbers += random.sample(range(rng[0], rng[1] + 1),
+ random.randint(0, rng[1] - rng[0] + 1))
+ val = 0
+ # Set bits on selected positions to ones
+ for bit in bit_numbers:
+ val |= 1 << bit
+ return val
+
+
+def truncate_string(strings, length):
+ """Return strings truncated to specified length."""
+ if type(strings) == list:
+ return [s[:length] for s in strings]
+ else:
+ return strings[:length]
+
+
+def validator(current, pick, choices):
+ """Return a value not equal to the current selected by the pick
+ function from choices.
+ """
+ while True:
+ val = pick(choices)
+ if not val == current:
+ return val
+
+
+def int_validator(current, intervals):
+ """Return a random value from intervals not equal to the current.
+
+ This function is useful for selection from valid values except current one.
+ """
+ return validator(current, random_from_intervals, intervals)
+
+
+def bit_validator(current, bit_ranges):
+ """Return a random bit mask not equal to the current.
+
+ This function is useful for selection from valid values except current one.
+ """
+ return validator(current, random_bits, bit_ranges)
+
+
+def string_validator(current, strings):
+ """Return a random string value from the list not equal to the current.
+
+ This function is useful for selection from valid values except current one.
+ """
+ return validator(current, random.choice, strings)
+
+
+def selector(current, constraints, validate=int_validator):
+ """Select one value from all defined by constraints.
+
+ Each constraint produces one random value satisfying to it. The function
+ randomly selects one value satisfying at least one constraint (depending on
+ constraints overlaps).
+ """
+ def iter_validate(c):
+ """Apply validate() only to constraints represented as lists.
+
+ This auxiliary function replaces short circuit conditions not supported
+ in Python 2.4
+ """
+ if type(c) == list:
+ return validate(current, c)
+ else:
+ return c
+
+ fuzz_values = [iter_validate(c) for c in constraints]
+ # Remove current for cases it's implicitly specified in constraints
+ # Duplicate validator functionality to prevent decreasing of probability
+ # to get one of allowable values
+ # TODO: remove validators after implementation of intelligent selection
+ # of fields will be fuzzed
+ try:
+ fuzz_values.remove(current)
+ except ValueError:
+ pass
+ return random.choice(fuzz_values)
+
+
+def magic(current):
+ """Fuzz magic header field.
+
+ The function just returns the current magic value and provides uniformity
+ of calls for all fuzzing functions.
+ """
+ return current
+
+
+def version(current):
+ """Fuzz version header field."""
+ constraints = UINT32_V + [
+ [(2, 3)], # correct values
+ [(0, 1), (4, UINT32)]
+ ]
+ return selector(current, constraints)
+
+
+def backing_file_offset(current):
+ """Fuzz backing file offset header field."""
+ constraints = UINT64_V
+ return selector(current, constraints)
+
+
+def backing_file_size(current):
+ """Fuzz backing file size header field."""
+ constraints = UINT32_V
+ return selector(current, constraints)
+
+
+def cluster_bits(current):
+ """Fuzz cluster bits header field."""
+ constraints = UINT32_V + [
+ [(9, 20)], # correct values
+ [(0, 9), (20, UINT32)]
+ ]
+ return selector(current, constraints)
+
+
+def size(current):
+ """Fuzz image size header field."""
+ constraints = UINT64_V
+ return selector(current, constraints)
+
+
+def crypt_method(current):
+ """Fuzz crypt method header field."""
+ constraints = UINT32_V + [
+ 1,
+ [(2, UINT32)]
+ ]
+ return selector(current, constraints)
+
+
+def l1_size(current):
+ """Fuzz L1 table size header field."""
+ constraints = UINT32_V
+ return selector(current, constraints)
+
+
+def l1_table_offset(current):
+ """Fuzz L1 table offset header field."""
+ constraints = UINT64_V
+ return selector(current, constraints)
+
+
+def refcount_table_offset(current):
+ """Fuzz refcount table offset header field."""
+ constraints = UINT64_V
+ return selector(current, constraints)
+
+
+def refcount_table_clusters(current):
+ """Fuzz refcount table clusters header field."""
+ constraints = UINT32_V
+ return selector(current, constraints)
+
+
+def nb_snapshots(current):
+ """Fuzz number of snapshots header field."""
+ constraints = UINT32_V
+ return selector(current, constraints)
+
+
+def snapshots_offset(current):
+ """Fuzz snapshots offset header field."""
+ constraints = UINT64_V
+ return selector(current, constraints)
+
+
+def incompatible_features(current):
+ """Fuzz incompatible features header field."""
+ constraints = [
+ [(0, 1)], # allowable values
+ [(0, UINT64_M)]
+ ]
+ return selector(current, constraints, bit_validator)
+
+
+def compatible_features(current):
+ """Fuzz compatible features header field."""
+ constraints = [
+ [(0, UINT64_M)]
+ ]
+ return selector(current, constraints, bit_validator)
+
+
+def autoclear_features(current):
+ """Fuzz autoclear features header field."""
+ constraints = [
+ [(0, UINT64_M)]
+ ]
+ return selector(current, constraints, bit_validator)
+
+
+def refcount_order(current):
+ """Fuzz number of refcount order header field."""
+ constraints = UINT32_V
+ return selector(current, constraints)
+
+
+def header_length(current):
+ """Fuzz number of refcount order header field."""
+ constraints = UINT32_V + [
+ 72,
+ 104,
+ [(0, UINT32)]
+ ]
+ return selector(current, constraints)
+
+
+def bf_name(current):
+ """Fuzz the backing file name."""
+ constraints = [
+ truncate_string(STRING_V, len(current))
+ ]
+ return selector(current, constraints, string_validator)
+
+
+def ext_magic(current):
+ """Fuzz magic field of a header extension."""
+ constraints = UINT32_V
+ return selector(current, constraints)
+
+
+def ext_length(current):
+ """Fuzz length field of a header extension."""
+ constraints = UINT32_V
+ return selector(current, constraints)
+
+
+def bf_format(current):
+ """Fuzz backing file format in the corresponding header extension."""
+ constraints = [
+ truncate_string(STRING_V, len(current)),
+ truncate_string(STRING_V, (len(current) + 7) & ~7) # Fuzz padding
+ ]
+ return selector(current, constraints, string_validator)
+
+
+def feature_type(current):
+ """Fuzz feature type field of a feature name table header extension."""
+ constraints = UINT8_V
+ return selector(current, constraints)
+
+
+def feature_bit_number(current):
+ """Fuzz bit number field of a feature name table header extension."""
+ constraints = UINT8_V
+ return selector(current, constraints)
+
+
+def feature_name(current):
+ """Fuzz feature name field of a feature name table header extension."""
+ constraints = [
+ truncate_string(STRING_V, len(current)),
+ truncate_string(STRING_V, 46) # Fuzz padding (field length = 46)
+ ]
+ return selector(current, constraints, string_validator)
+
+
+def l1_entry(current):
+ """Fuzz an entry of the L1 table."""
+ constraints = UINT64_V
+ # Reserved bits are ignored
+ # Added a possibility when only flags are fuzzed
+ offset = 0x7fffffffffffffff & random.choice([selector(current,
+ constraints),
+ current])
+ is_cow = random.randint(0, 1)
+ return offset + (is_cow << UINT64_M)
+
+
+def l2_entry(current):
+ """Fuzz an entry of an L2 table."""
+ constraints = UINT64_V
+ # Reserved bits are ignored
+ # Add a possibility when only flags are fuzzed
+ offset = 0x3ffffffffffffffe & random.choice([selector(current,
+ constraints),
+ current])
+ is_compressed = random.randint(0, 1)
+ is_cow = random.randint(0, 1)
+ is_zero = random.randint(0, 1)
+ value = offset + (is_cow << UINT64_M) + \
+ (is_compressed << UINT64_M - 1) + is_zero
+ return value
diff --git a/tests/image-fuzzer/qcow2/layout.py b/tests/image-fuzzer/qcow2/layout.py
new file mode 100644
index 0000000000..730c771d3c
--- /dev/null
+++ b/tests/image-fuzzer/qcow2/layout.py
@@ -0,0 +1,476 @@
+# Generator of fuzzed qcow2 images
+#
+# Copyright (C) 2014 Maria Kustova <maria.k@catit.be>
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+
+import random
+import struct
+import fuzz
+from math import ceil
+from os import urandom
+from itertools import chain
+
+MAX_IMAGE_SIZE = 10 * (1 << 20)
+# Standard sizes
+UINT32_S = 4
+UINT64_S = 8
+
+
+class Field(object):
+
+ """Atomic image element (field).
+
+ The class represents an image field as quadruple of a data format
+ of value necessary for its packing to binary form, an offset from
+ the beginning of the image, a value and a name.
+
+ The field can be iterated as a list [format, offset, value, name].
+ """
+
+ __slots__ = ('fmt', 'offset', 'value', 'name')
+
+ def __init__(self, fmt, offset, val, name):
+ self.fmt = fmt
+ self.offset = offset
+ self.value = val
+ self.name = name
+
+ def __iter__(self):
+ return iter([self.fmt, self.offset, self.value, self.name])
+
+ def __repr__(self):
+ return "Field(fmt='%s', offset=%d, value=%s, name=%s)" % \
+ (self.fmt, self.offset, str(self.value), self.name)
+
+
+class FieldsList(object):
+
+ """List of fields.
+
+ The class allows access to a field in the list by its name.
+ """
+
+ def __init__(self, meta_data=None):
+ if meta_data is None:
+ self.data = []
+ else:
+ self.data = [Field(*f)
+ for f in meta_data]
+
+ def __getitem__(self, name):
+ return [x for x in self.data if x.name == name]
+
+ def __iter__(self):
+ return iter(self.data)
+
+ def __len__(self):
+ return len(self.data)
+
+
+class Image(object):
+
+ """ Qcow2 image object.
+
+ This class allows to create qcow2 images with random valid structures and
+ values, fuzz them via external qcow2.fuzz module and write the result to
+ a file.
+ """
+
+ def __init__(self, backing_file_name=None):
+ """Create a random valid qcow2 image with the correct header and stored
+ backing file name.
+ """
+ cluster_bits, self.image_size = self._size_params()
+ self.cluster_size = 1 << cluster_bits
+ self.header = FieldsList()
+ self.backing_file_name = FieldsList()
+ self.backing_file_format = FieldsList()
+ self.feature_name_table = FieldsList()
+ self.end_of_extension_area = FieldsList()
+ self.l2_tables = FieldsList()
+ self.l1_table = FieldsList()
+ self.ext_offset = 0
+ self.create_header(cluster_bits, backing_file_name)
+ self.set_backing_file_name(backing_file_name)
+ self.data_clusters = self._alloc_data(self.image_size,
+ self.cluster_size)
+ # Percentage of fields will be fuzzed
+ self.bias = random.uniform(0.2, 0.5)
+
+ def __iter__(self):
+ return chain(self.header, self.backing_file_format,
+ self.feature_name_table, self.end_of_extension_area,
+ self.backing_file_name, self.l1_table, self.l2_tables)
+
+ def create_header(self, cluster_bits, backing_file_name=None):
+ """Generate a random valid header."""
+ meta_header = [
+ ['>4s', 0, "QFI\xfb", 'magic'],
+ ['>I', 4, random.randint(2, 3), 'version'],
+ ['>Q', 8, 0, 'backing_file_offset'],
+ ['>I', 16, 0, 'backing_file_size'],
+ ['>I', 20, cluster_bits, 'cluster_bits'],
+ ['>Q', 24, self.image_size, 'size'],
+ ['>I', 32, 0, 'crypt_method'],
+ ['>I', 36, 0, 'l1_size'],
+ ['>Q', 40, 0, 'l1_table_offset'],
+ ['>Q', 48, 0, 'refcount_table_offset'],
+ ['>I', 56, 0, 'refcount_table_clusters'],
+ ['>I', 60, 0, 'nb_snapshots'],
+ ['>Q', 64, 0, 'snapshots_offset'],
+ ['>Q', 72, 0, 'incompatible_features'],
+ ['>Q', 80, 0, 'compatible_features'],
+ ['>Q', 88, 0, 'autoclear_features'],
+ # Only refcount_order = 4 is supported by current (07.2014)
+ # implementation of QEMU
+ ['>I', 96, 4, 'refcount_order'],
+ ['>I', 100, 0, 'header_length']
+ ]
+ self.header = FieldsList(meta_header)
+
+ if self.header['version'][0].value == 2:
+ self.header['header_length'][0].value = 72
+ else:
+ self.header['incompatible_features'][0].value = \
+ random.getrandbits(2)
+ self.header['compatible_features'][0].value = random.getrandbits(1)
+ self.header['header_length'][0].value = 104
+ # Extensions start at the header last field offset and the field size
+ self.ext_offset = struct.calcsize(
+ self.header['header_length'][0].fmt) + \
+ self.header['header_length'][0].offset
+ end_of_extension_area_len = 2 * UINT32_S
+ free_space = self.cluster_size - self.ext_offset - \
+ end_of_extension_area_len
+ # If the backing file name specified and there is enough space for it
+ # in the first cluster, then it's placed in the very end of the first
+ # cluster.
+ if (backing_file_name is not None) and \
+ (free_space >= len(backing_file_name)):
+ self.header['backing_file_size'][0].value = len(backing_file_name)
+ self.header['backing_file_offset'][0].value = \
+ self.cluster_size - len(backing_file_name)
+
+ def set_backing_file_name(self, backing_file_name=None):
+ """Add the name of the backing file at the offset specified
+ in the header.
+ """
+ if (backing_file_name is not None) and \
+ (not self.header['backing_file_offset'][0].value == 0):
+ data_len = len(backing_file_name)
+ data_fmt = '>' + str(data_len) + 's'
+ self.backing_file_name = FieldsList([
+ [data_fmt, self.header['backing_file_offset'][0].value,
+ backing_file_name, 'bf_name']
+ ])
+
+ def set_backing_file_format(self, backing_file_fmt=None):
+ """Generate the header extension for the backing file format."""
+ if backing_file_fmt is not None:
+ # Calculation of the free space available in the first cluster
+ end_of_extension_area_len = 2 * UINT32_S
+ high_border = (self.header['backing_file_offset'][0].value or
+ (self.cluster_size - 1)) - \
+ end_of_extension_area_len
+ free_space = high_border - self.ext_offset
+ ext_size = 2 * UINT32_S + ((len(backing_file_fmt) + 7) & ~7)
+
+ if free_space >= ext_size:
+ ext_data_len = len(backing_file_fmt)
+ ext_data_fmt = '>' + str(ext_data_len) + 's'
+ ext_padding_len = 7 - (ext_data_len - 1) % 8
+ self.backing_file_format = FieldsList([
+ ['>I', self.ext_offset, 0xE2792ACA, 'ext_magic'],
+ ['>I', self.ext_offset + UINT32_S, ext_data_len,
+ 'ext_length'],
+ [ext_data_fmt, self.ext_offset + UINT32_S * 2,
+ backing_file_fmt, 'bf_format']
+ ])
+ self.ext_offset = \
+ struct.calcsize(
+ self.backing_file_format['bf_format'][0].fmt) + \
+ ext_padding_len + \
+ self.backing_file_format['bf_format'][0].offset
+
+ def create_feature_name_table(self):
+ """Generate a random header extension for names of features used in
+ the image.
+ """
+ def gen_feat_ids():
+ """Return random feature type and feature bit."""
+ return (random.randint(0, 2), random.randint(0, 63))
+
+ end_of_extension_area_len = 2 * UINT32_S
+ high_border = (self.header['backing_file_offset'][0].value or
+ (self.cluster_size - 1)) - \
+ end_of_extension_area_len
+ free_space = high_border - self.ext_offset
+ # Sum of sizes of 'magic' and 'length' header extension fields
+ ext_header_len = 2 * UINT32_S
+ fnt_entry_size = 6 * UINT64_S
+ num_fnt_entries = min(10, (free_space - ext_header_len) /
+ fnt_entry_size)
+ if not num_fnt_entries == 0:
+ feature_tables = []
+ feature_ids = []
+ inner_offset = self.ext_offset + ext_header_len
+ feat_name = 'some cool feature'
+ while len(feature_tables) < num_fnt_entries * 3:
+ feat_type, feat_bit = gen_feat_ids()
+ # Remove duplicates
+ while (feat_type, feat_bit) in feature_ids:
+ feat_type, feat_bit = gen_feat_ids()
+ feature_ids.append((feat_type, feat_bit))
+ feat_fmt = '>' + str(len(feat_name)) + 's'
+ feature_tables += [['B', inner_offset,
+ feat_type, 'feature_type'],
+ ['B', inner_offset + 1, feat_bit,
+ 'feature_bit_number'],
+ [feat_fmt, inner_offset + 2,
+ feat_name, 'feature_name']
+ ]
+ inner_offset += fnt_entry_size
+ # No padding for the extension is necessary, because
+ # the extension length is multiple of 8
+ self.feature_name_table = FieldsList([
+ ['>I', self.ext_offset, 0x6803f857, 'ext_magic'],
+ # One feature table contains 3 fields and takes 48 bytes
+ ['>I', self.ext_offset + UINT32_S,
+ len(feature_tables) / 3 * 48, 'ext_length']
+ ] + feature_tables)
+ self.ext_offset = inner_offset
+
+ def set_end_of_extension_area(self):
+ """Generate a mandatory header extension marking end of header
+ extensions.
+ """
+ self.end_of_extension_area = FieldsList([
+ ['>I', self.ext_offset, 0, 'ext_magic'],
+ ['>I', self.ext_offset + UINT32_S, 0, 'ext_length']
+ ])
+
+ def create_l_structures(self):
+ """Generate random valid L1 and L2 tables."""
+ def create_l2_entry(host, guest, l2_cluster):
+ """Generate one L2 entry."""
+ offset = l2_cluster * self.cluster_size
+ l2_size = self.cluster_size / UINT64_S
+ entry_offset = offset + UINT64_S * (guest % l2_size)
+ cluster_descriptor = host * self.cluster_size
+ if not self.header['version'][0].value == 2:
+ cluster_descriptor += random.randint(0, 1)
+ # While snapshots are not supported, bit #63 = 1
+ # Compressed clusters are not supported => bit #62 = 0
+ entry_val = (1 << 63) + cluster_descriptor
+ return ['>Q', entry_offset, entry_val, 'l2_entry']
+
+ def create_l1_entry(l2_cluster, l1_offset, guest):
+ """Generate one L1 entry."""
+ l2_size = self.cluster_size / UINT64_S
+ entry_offset = l1_offset + UINT64_S * (guest / l2_size)
+ # While snapshots are not supported bit #63 = 1
+ entry_val = (1 << 63) + l2_cluster * self.cluster_size
+ return ['>Q', entry_offset, entry_val, 'l1_entry']
+
+ if len(self.data_clusters) == 0:
+ # All metadata for an empty guest image needs 4 clusters:
+ # header, rfc table, rfc block, L1 table.
+ # Header takes cluster #0, other clusters ##1-3 can be used
+ l1_offset = random.randint(1, 3) * self.cluster_size
+ l1 = [['>Q', l1_offset, 0, 'l1_entry']]
+ l2 = []
+ else:
+ meta_data = self._get_metadata()
+ guest_clusters = random.sample(range(self.image_size /
+ self.cluster_size),
+ len(self.data_clusters))
+ # Number of entries in a L1/L2 table
+ l_size = self.cluster_size / UINT64_S
+ # Number of clusters necessary for L1 table
+ l1_size = int(ceil((max(guest_clusters) + 1) / float(l_size**2)))
+ l1_start = self._get_adjacent_clusters(self.data_clusters |
+ meta_data, l1_size)
+ meta_data |= set(range(l1_start, l1_start + l1_size))
+ l1_offset = l1_start * self.cluster_size
+ # Indices of L2 tables
+ l2_ids = []
+ # Host clusters allocated for L2 tables
+ l2_clusters = []
+ # L1 entries
+ l1 = []
+ # L2 entries
+ l2 = []
+ for host, guest in zip(self.data_clusters, guest_clusters):
+ l2_id = guest / l_size
+ if l2_id not in l2_ids:
+ l2_ids.append(l2_id)
+ l2_clusters.append(self._get_adjacent_clusters(
+ self.data_clusters | meta_data | set(l2_clusters),
+ 1))
+ l1.append(create_l1_entry(l2_clusters[-1], l1_offset,
+ guest))
+ l2.append(create_l2_entry(host, guest,
+ l2_clusters[l2_ids.index(l2_id)]))
+ self.l2_tables = FieldsList(l2)
+ self.l1_table = FieldsList(l1)
+ self.header['l1_size'][0].value = int(ceil(UINT64_S * self.image_size /
+ float(self.cluster_size**2)))
+ self.header['l1_table_offset'][0].value = l1_offset
+
+ def fuzz(self, fields_to_fuzz=None):
+ """Fuzz an image by corrupting values of a random subset of its fields.
+
+ Without parameters the method fuzzes an entire image.
+
+ If 'fields_to_fuzz' is specified then only fields in this list will be
+ fuzzed. 'fields_to_fuzz' can contain both individual fields and more
+ general image elements as a header or tables.
+
+ In the first case the field will be fuzzed always.
+ In the second a random subset of fields will be selected and fuzzed.
+ """
+ def coin():
+ """Return boolean value proportional to a portion of fields to be
+ fuzzed.
+ """
+ return random.random() < self.bias
+
+ if fields_to_fuzz is None:
+ for field in self:
+ if coin():
+ field.value = getattr(fuzz, field.name)(field.value)
+ else:
+ for item in fields_to_fuzz:
+ if len(item) == 1:
+ for field in getattr(self, item[0]):
+ if coin():
+ field.value = getattr(fuzz,
+ field.name)(field.value)
+ else:
+ # If fields with the requested name were not generated
+ # getattr(self, item[0])[item[1]] returns an empty list
+ for field in getattr(self, item[0])[item[1]]:
+ field.value = getattr(fuzz, field.name)(field.value)
+
+ def write(self, filename):
+ """Write an entire image to the file."""
+ image_file = open(filename, 'w')
+ for field in self:
+ image_file.seek(field.offset)
+ image_file.write(struct.pack(field.fmt, field.value))
+
+ for cluster in sorted(self.data_clusters):
+ image_file.seek(cluster * self.cluster_size)
+ image_file.write(urandom(self.cluster_size))
+
+ # Align the real image size to the cluster size
+ image_file.seek(0, 2)
+ size = image_file.tell()
+ rounded = (size + self.cluster_size - 1) & ~(self.cluster_size - 1)
+ if rounded > size:
+ image_file.seek(rounded - 1)
+ image_file.write("\0")
+ image_file.close()
+
+ @staticmethod
+ def _size_params():
+ """Generate a random image size aligned to a random correct
+ cluster size.
+ """
+ cluster_bits = random.randrange(9, 21)
+ cluster_size = 1 << cluster_bits
+ img_size = random.randrange(0, MAX_IMAGE_SIZE + 1, cluster_size)
+ return (cluster_bits, img_size)
+
+ @staticmethod
+ def _get_available_clusters(used, number):
+ """Return a set of indices of not allocated clusters.
+
+ 'used' contains indices of currently allocated clusters.
+ All clusters that cannot be allocated between 'used' clusters will have
+ indices appended to the end of 'used'.
+ """
+ append_id = max(used) + 1
+ free = set(range(1, append_id)) - used
+ if len(free) >= number:
+ return set(random.sample(free, number))
+ else:
+ return free | set(range(append_id, append_id + number - len(free)))
+
+ @staticmethod
+ def _get_adjacent_clusters(used, size):
+ """Return an index of the first cluster in the sequence of free ones.
+
+ 'used' contains indices of currently allocated clusters. 'size' is the
+ length of the sequence of free clusters.
+ If the sequence of 'size' is not available between 'used' clusters, its
+ first index will be append to the end of 'used'.
+ """
+ def get_cluster_id(lst, length):
+ """Return the first index of the sequence of the specified length
+ or None if the sequence cannot be inserted in the list.
+ """
+ if len(lst) != 0:
+ pairs = []
+ pair = (lst[0], 1)
+ for i in range(1, len(lst)):
+ if lst[i] == lst[i-1] + 1:
+ pair = (lst[i], pair[1] + 1)
+ else:
+ pairs.append(pair)
+ pair = (lst[i], 1)
+ pairs.append(pair)
+ random.shuffle(pairs)
+ for x, s in pairs:
+ if s >= length:
+ return x - length + 1
+ return None
+
+ append_id = max(used) + 1
+ free = list(set(range(1, append_id)) - used)
+ idx = get_cluster_id(free, size)
+ if idx is None:
+ return append_id
+ else:
+ return idx
+
+ @staticmethod
+ def _alloc_data(img_size, cluster_size):
+ """Return a set of random indices of clusters allocated for guest data.
+ """
+ num_of_cls = img_size/cluster_size
+ return set(random.sample(range(1, num_of_cls + 1),
+ random.randint(0, num_of_cls)))
+
+ def _get_metadata(self):
+ """Return indices of clusters allocated for image metadata."""
+ ids = set()
+ for x in self:
+ ids.add(x.offset/self.cluster_size)
+ return ids
+
+
+def create_image(test_img_path, backing_file_name=None, backing_file_fmt=None,
+ fields_to_fuzz=None):
+ """Create a fuzzed image and write it to the specified file."""
+ image = Image(backing_file_name)
+ image.set_backing_file_format(backing_file_fmt)
+ image.create_feature_name_table()
+ image.set_end_of_extension_area()
+ image.create_l_structures()
+ image.fuzz(fields_to_fuzz)
+ image.write(test_img_path)
+ return image.image_size
diff --git a/tests/image-fuzzer/runner.py b/tests/image-fuzzer/runner.py
new file mode 100755
index 0000000000..58079d331e
--- /dev/null
+++ b/tests/image-fuzzer/runner.py
@@ -0,0 +1,405 @@
+#!/usr/bin/env python
+
+# Tool for running fuzz tests
+#
+# Copyright (C) 2014 Maria Kustova <maria.k@catit.be>
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+
+import sys
+import os
+import signal
+import subprocess
+import random
+import shutil
+from itertools import count
+import getopt
+import StringIO
+import resource
+
+try:
+ import json
+except ImportError:
+ try:
+ import simplejson as json
+ except ImportError:
+ print >>sys.stderr, \
+ "Warning: Module for JSON processing is not found.\n" \
+ "'--config' and '--command' options are not supported."
+
+# Backing file sizes in MB
+MAX_BACKING_FILE_SIZE = 10
+MIN_BACKING_FILE_SIZE = 1
+
+
+def multilog(msg, *output):
+ """ Write an object to all of specified file descriptors."""
+ for fd in output:
+ fd.write(msg)
+ fd.flush()
+
+
+def str_signal(sig):
+ """ Convert a numeric value of a system signal to the string one
+ defined by the current operational system.
+ """
+ for k, v in signal.__dict__.items():
+ if v == sig:
+ return k
+
+
+def run_app(fd, q_args):
+ """Start an application with specified arguments and return its exit code
+ or kill signal depending on the result of execution.
+ """
+ devnull = open('/dev/null', 'r+')
+ process = subprocess.Popen(q_args, stdin=devnull,
+ stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE)
+ out, err = process.communicate()
+ fd.write(out)
+ fd.write(err)
+ return process.returncode
+
+
+class TestException(Exception):
+ """Exception for errors risen by TestEnv objects."""
+ pass
+
+
+class TestEnv(object):
+
+ """Test object.
+
+ The class sets up test environment, generates backing and test images
+ and executes application under tests with specified arguments and a test
+ image provided.
+
+ All logs are collected.
+
+ The summary log will contain short descriptions and statuses of tests in
+ a run.
+
+ The test log will include application (e.g. 'qemu-img') logs besides info
+ sent to the summary log.
+ """
+
+ def __init__(self, test_id, seed, work_dir, run_log,
+ cleanup=True, log_all=False):
+ """Set test environment in a specified work directory.
+
+ Path to qemu-img and qemu-io will be retrieved from 'QEMU_IMG' and
+ 'QEMU_IO' environment variables.
+ """
+ if seed is not None:
+ self.seed = seed
+ else:
+ self.seed = str(random.randint(0, sys.maxint))
+ random.seed(self.seed)
+
+ self.init_path = os.getcwd()
+ self.work_dir = work_dir
+ self.current_dir = os.path.join(work_dir, 'test-' + test_id)
+ self.qemu_img = os.environ.get('QEMU_IMG', 'qemu-img')\
+ .strip().split(' ')
+ self.qemu_io = os.environ.get('QEMU_IO', 'qemu-io').strip().split(' ')
+ self.commands = [['qemu-img', 'check', '-f', 'qcow2', '$test_img'],
+ ['qemu-img', 'info', '-f', 'qcow2', '$test_img'],
+ ['qemu-io', '$test_img', '-c', 'read $off $len'],
+ ['qemu-io', '$test_img', '-c', 'write $off $len'],
+ ['qemu-io', '$test_img', '-c',
+ 'aio_read $off $len'],
+ ['qemu-io', '$test_img', '-c',
+ 'aio_write $off $len'],
+ ['qemu-io', '$test_img', '-c', 'flush'],
+ ['qemu-io', '$test_img', '-c',
+ 'discard $off $len'],
+ ['qemu-io', '$test_img', '-c',
+ 'truncate $off']]
+ for fmt in ['raw', 'vmdk', 'vdi', 'cow', 'qcow2', 'file',
+ 'qed', 'vpc']:
+ self.commands.append(
+ ['qemu-img', 'convert', '-f', 'qcow2', '-O', fmt,
+ '$test_img', 'converted_image.' + fmt])
+
+ try:
+ os.makedirs(self.current_dir)
+ except OSError, e:
+ print >>sys.stderr, \
+ "Error: The working directory '%s' cannot be used. Reason: %s"\
+ % (self.work_dir, e[1])
+ raise TestException
+ self.log = open(os.path.join(self.current_dir, "test.log"), "w")
+ self.parent_log = open(run_log, "a")
+ self.failed = False
+ self.cleanup = cleanup
+ self.log_all = log_all
+
+ def _create_backing_file(self):
+ """Create a backing file in the current directory.
+
+ Return a tuple of a backing file name and format.
+
+ Format of a backing file is randomly chosen from all formats supported
+ by 'qemu-img create'.
+ """
+ # All formats supported by the 'qemu-img create' command.
+ backing_file_fmt = random.choice(['raw', 'vmdk', 'vdi', 'cow', 'qcow2',
+ 'file', 'qed', 'vpc'])
+ backing_file_name = 'backing_img.' + backing_file_fmt
+ backing_file_size = random.randint(MIN_BACKING_FILE_SIZE,
+ MAX_BACKING_FILE_SIZE) * (1 << 20)
+ cmd = self.qemu_img + ['create', '-f', backing_file_fmt,
+ backing_file_name, str(backing_file_size)]
+ temp_log = StringIO.StringIO()
+ retcode = run_app(temp_log, cmd)
+ if retcode == 0:
+ temp_log.close()
+ return (backing_file_name, backing_file_fmt)
+ else:
+ multilog("Warning: The %s backing file was not created.\n\n"
+ % backing_file_fmt, sys.stderr, self.log, self.parent_log)
+ self.log.write("Log for the failure:\n" + temp_log.getvalue() +
+ '\n\n')
+ temp_log.close()
+ return (None, None)
+
+ def execute(self, input_commands=None, fuzz_config=None):
+ """ Execute a test.
+
+ The method creates backing and test images, runs test app and analyzes
+ its exit status. If the application was killed by a signal, the test
+ is marked as failed.
+ """
+ if input_commands is None:
+ commands = self.commands
+ else:
+ commands = input_commands
+
+ os.chdir(self.current_dir)
+ backing_file_name, backing_file_fmt = self._create_backing_file()
+ img_size = image_generator.create_image('test.img',
+ backing_file_name,
+ backing_file_fmt,
+ fuzz_config)
+ for item in commands:
+ shutil.copy('test.img', 'copy.img')
+ # 'off' and 'len' are multiple of the sector size
+ sector_size = 512
+ start = random.randrange(0, img_size + 1, sector_size)
+ end = random.randrange(start, img_size + 1, sector_size)
+
+ if item[0] == 'qemu-img':
+ current_cmd = list(self.qemu_img)
+ elif item[0] == 'qemu-io':
+ current_cmd = list(self.qemu_io)
+ else:
+ multilog("Warning: test command '%s' is not defined.\n" \
+ % item[0], sys.stderr, self.log, self.parent_log)
+ continue
+ # Replace all placeholders with their real values
+ for v in item[1:]:
+ c = (v
+ .replace('$test_img', 'copy.img')
+ .replace('$off', str(start))
+ .replace('$len', str(end - start)))
+ current_cmd.append(c)
+
+ # Log string with the test header
+ test_summary = "Seed: %s\nCommand: %s\nTest directory: %s\n" \
+ "Backing file: %s\n" \
+ % (self.seed, " ".join(current_cmd),
+ self.current_dir, backing_file_name)
+
+ temp_log = StringIO.StringIO()
+ try:
+ retcode = run_app(temp_log, current_cmd)
+ except OSError, e:
+ multilog(test_summary + "Error: Start of '%s' failed. " \
+ "Reason: %s\n\n" % (os.path.basename(
+ current_cmd[0]), e[1]),
+ sys.stderr, self.log, self.parent_log)
+ raise TestException
+
+ if retcode < 0:
+ self.log.write(temp_log.getvalue())
+ multilog(test_summary + "FAIL: Test terminated by signal " +
+ "%s\n\n" % str_signal(-retcode), sys.stderr, self.log,
+ self.parent_log)
+ self.failed = True
+ else:
+ if self.log_all:
+ self.log.write(temp_log.getvalue())
+ multilog(test_summary + "PASS: Application exited with" +
+ " the code '%d'\n\n" % retcode, sys.stdout,
+ self.log, self.parent_log)
+ temp_log.close()
+ os.remove('copy.img')
+
+ def finish(self):
+ """Restore the test environment after a test execution."""
+ self.log.close()
+ self.parent_log.close()
+ os.chdir(self.init_path)
+ if self.cleanup and not self.failed:
+ shutil.rmtree(self.current_dir)
+
+if __name__ == '__main__':
+
+ def usage():
+ print """
+ Usage: runner.py [OPTION...] TEST_DIR IMG_GENERATOR
+
+ Set up test environment in TEST_DIR and run a test in it. A module for
+ test image generation should be specified via IMG_GENERATOR.
+ Example:
+ runner.py -c '[["qemu-img", "info", "$test_img"]]' /tmp/test qcow2
+
+ Optional arguments:
+ -h, --help display this help and exit
+ -c, --command=JSON run tests for all commands specified in
+ the JSON array
+ -s, --seed=STRING seed for a test image generation,
+ by default will be generated randomly
+ --config=JSON take fuzzer configuration from the JSON
+ array
+ -k, --keep_passed don't remove folders of passed tests
+ -v, --verbose log information about passed tests
+
+ JSON:
+
+ '--command' accepts a JSON array of commands. Each command presents
+ an application under test with all its paramaters as a list of strings,
+ e.g.
+ ["qemu-io", "$test_img", "-c", "write $off $len"]
+
+ Supported application aliases: 'qemu-img' and 'qemu-io'.
+ Supported argument aliases: $test_img for the fuzzed image, $off
+ for an offset, $len for length.
+
+ Values for $off and $len will be generated based on the virtual disk
+ size of the fuzzed image
+ Paths to 'qemu-img' and 'qemu-io' are retrevied from 'QEMU_IMG' and
+ 'QEMU_IO' environment variables
+
+ '--config' accepts a JSON array of fields to be fuzzed, e.g.
+ '[["header"], ["header", "version"]]'
+ Each of the list elements can consist of a complex image element only
+ as ["header"] or ["feature_name_table"] or an exact field as
+ ["header", "version"]. In the first case random portion of the element
+ fields will be fuzzed, in the second one the specified field will be
+ fuzzed always.
+
+ If '--config' argument is specified, fields not listed in
+ the configuration array will not be fuzzed.
+ """
+
+ def run_test(test_id, seed, work_dir, run_log, cleanup, log_all,
+ command, fuzz_config):
+ """Setup environment for one test and execute this test."""
+ try:
+ test = TestEnv(test_id, seed, work_dir, run_log, cleanup,
+ log_all)
+ except TestException:
+ sys.exit(1)
+
+ # Python 2.4 doesn't support 'finally' and 'except' in the same 'try'
+ # block
+ try:
+ try:
+ test.execute(command, fuzz_config)
+ except TestException:
+ sys.exit(1)
+ finally:
+ test.finish()
+
+ try:
+ opts, args = getopt.gnu_getopt(sys.argv[1:], 'c:hs:kv',
+ ['command=', 'help', 'seed=', 'config=',
+ 'keep_passed', 'verbose'])
+ except getopt.error, e:
+ print >>sys.stderr, \
+ "Error: %s\n\nTry 'runner.py --help' for more information" % e
+ sys.exit(1)
+
+ command = None
+ cleanup = True
+ log_all = False
+ seed = None
+ config = None
+ for opt, arg in opts:
+ if opt in ('-h', '--help'):
+ usage()
+ sys.exit()
+ elif opt in ('-c', '--command'):
+ try:
+ command = json.loads(arg)
+ except (TypeError, ValueError, NameError), e:
+ print >>sys.stderr, \
+ "Error: JSON array of test commands cannot be loaded.\n" \
+ "Reason: %s" % e
+ sys.exit(1)
+ elif opt in ('-k', '--keep_passed'):
+ cleanup = False
+ elif opt in ('-v', '--verbose'):
+ log_all = True
+ elif opt in ('-s', '--seed'):
+ seed = arg
+ elif opt == '--config':
+ try:
+ config = json.loads(arg)
+ except (TypeError, ValueError, NameError), e:
+ print >>sys.stderr, \
+ "Error: JSON array with the fuzzer configuration cannot" \
+ " be loaded\nReason: %s" % e
+ sys.exit(1)
+
+ if not len(args) == 2:
+ print >>sys.stderr, \
+ "Expected two parameters\nTry 'runner.py --help'" \
+ " for more information."
+ sys.exit(1)
+
+ work_dir = os.path.realpath(args[0])
+ # run_log is created in 'main', because multiple tests are expected to
+ # log in it
+ run_log = os.path.join(work_dir, 'run.log')
+
+ # Add the path to the image generator module to sys.path
+ sys.path.append(os.path.realpath(os.path.dirname(args[1])))
+ # Remove a script extension from image generator module if any
+ generator_name = os.path.splitext(os.path.basename(args[1]))[0]
+
+ try:
+ image_generator = __import__(generator_name)
+ except ImportError, e:
+ print >>sys.stderr, \
+ "Error: The image generator '%s' cannot be imported.\n" \
+ "Reason: %s" % (generator_name, e)
+ sys.exit(1)
+
+ # Enable core dumps
+ resource.setrlimit(resource.RLIMIT_CORE, (-1, -1))
+ # If a seed is specified, only one test will be executed.
+ # Otherwise runner will terminate after a keyboard interruption
+ for test_id in count(1):
+ try:
+ run_test(str(test_id), seed, work_dir, run_log, cleanup,
+ log_all, command, config)
+ except (KeyboardInterrupt, SystemExit):
+ sys.exit(1)
+
+ if seed is not None:
+ break
diff --git a/tests/libqos/malloc-pc.c b/tests/libqos/malloc-pc.c
index db1496c667..be1d97f8bb 100644
--- a/tests/libqos/malloc-pc.c
+++ b/tests/libqos/malloc-pc.c
@@ -36,7 +36,7 @@ static uint64_t pc_alloc(QGuestAllocator *allocator, size_t size)
size += (PAGE_SIZE - 1);
- size &= PAGE_SIZE;
+ size &= -PAGE_SIZE;
g_assert_cmpint((s->start + size), <=, s->end);
@@ -67,5 +67,8 @@ QGuestAllocator *pc_alloc_init(void)
/* Respect PCI hole */
s->end = MIN(ram_size, 0xE0000000);
+ /* clean-up */
+ g_free(fw_cfg);
+
return &s->alloc;
}
diff --git a/tests/libqos/malloc.h b/tests/libqos/malloc.h
index 46f6000763..556538121e 100644
--- a/tests/libqos/malloc.h
+++ b/tests/libqos/malloc.h
@@ -32,7 +32,7 @@ static inline uint64_t guest_alloc(QGuestAllocator *allocator, size_t size)
static inline void guest_free(QGuestAllocator *allocator, uint64_t addr)
{
- allocator->alloc(allocator, addr);
+ allocator->free(allocator, addr);
}
#endif
diff --git a/tests/libqos/pci-pc.c b/tests/libqos/pci-pc.c
index 4adf4006ae..0609294af0 100644
--- a/tests/libqos/pci-pc.c
+++ b/tests/libqos/pci-pc.c
@@ -144,7 +144,7 @@ static void qpci_pc_config_writel(QPCIBus *bus, int devfn, uint8_t offset, uint3
outl(0xcfc, value);
}
-static void *qpci_pc_iomap(QPCIBus *bus, QPCIDevice *dev, int barno)
+static void *qpci_pc_iomap(QPCIBus *bus, QPCIDevice *dev, int barno, uint64_t *sizeptr)
{
QPCIBusPC *s = container_of(bus, QPCIBusPC, bus);
static const int bar_reg_map[] = {
@@ -173,6 +173,9 @@ static void *qpci_pc_iomap(QPCIBus *bus, QPCIDevice *dev, int barno)
if (size == 0) {
return NULL;
}
+ if (sizeptr) {
+ *sizeptr = size;
+ }
if (io_type == PCI_BASE_ADDRESS_SPACE_IO) {
uint16_t loc;
@@ -237,3 +240,10 @@ QPCIBus *qpci_init_pc(void)
return &ret->bus;
}
+
+void qpci_free_pc(QPCIBus *bus)
+{
+ QPCIBusPC *s = container_of(bus, QPCIBusPC, bus);
+
+ g_free(s);
+}
diff --git a/tests/libqos/pci-pc.h b/tests/libqos/pci-pc.h
index 4f7475f6f7..26211790cd 100644
--- a/tests/libqos/pci-pc.h
+++ b/tests/libqos/pci-pc.h
@@ -16,5 +16,6 @@
#include "libqos/pci.h"
QPCIBus *qpci_init_pc(void);
+void qpci_free_pc(QPCIBus *bus);
#endif
diff --git a/tests/libqos/pci.c b/tests/libqos/pci.c
index c9a0b9134a..ce0b308a83 100644
--- a/tests/libqos/pci.c
+++ b/tests/libqos/pci.c
@@ -138,9 +138,9 @@ void qpci_io_writel(QPCIDevice *dev, void *data, uint32_t value)
dev->bus->io_writel(dev->bus, data, value);
}
-void *qpci_iomap(QPCIDevice *dev, int barno)
+void *qpci_iomap(QPCIDevice *dev, int barno, uint64_t *sizeptr)
{
- return dev->bus->iomap(dev->bus, dev, barno);
+ return dev->bus->iomap(dev->bus, dev, barno, sizeptr);
}
void qpci_iounmap(QPCIDevice *dev, void *data)
diff --git a/tests/libqos/pci.h b/tests/libqos/pci.h
index 3439431540..9ee048b154 100644
--- a/tests/libqos/pci.h
+++ b/tests/libqos/pci.h
@@ -41,7 +41,7 @@ struct QPCIBus
void (*config_writel)(QPCIBus *bus, int devfn,
uint8_t offset, uint32_t value);
- void *(*iomap)(QPCIBus *bus, QPCIDevice *dev, int barno);
+ void *(*iomap)(QPCIBus *bus, QPCIDevice *dev, int barno, uint64_t *sizeptr);
void (*iounmap)(QPCIBus *bus, void *data);
};
@@ -74,7 +74,7 @@ void qpci_io_writeb(QPCIDevice *dev, void *data, uint8_t value);
void qpci_io_writew(QPCIDevice *dev, void *data, uint16_t value);
void qpci_io_writel(QPCIDevice *dev, void *data, uint32_t value);
-void *qpci_iomap(QPCIDevice *dev, int barno);
+void *qpci_iomap(QPCIDevice *dev, int barno, uint64_t *sizeptr);
void qpci_iounmap(QPCIDevice *dev, void *data);
#endif
diff --git a/tests/libqtest.c b/tests/libqtest.c
index 98e8f4b648..ed55686ce0 100644
--- a/tests/libqtest.c
+++ b/tests/libqtest.c
@@ -167,11 +167,12 @@ QTestState *qtest_init(const char *extra_args)
if (s->qemu_pid == 0) {
command = g_strdup_printf("exec %s "
"-qtest unix:%s,nowait "
- "-qtest-log /dev/null "
+ "-qtest-log %s "
"-qmp unix:%s,nowait "
"-machine accel=qtest "
"-display none "
"%s", qemu_binary, socket_path,
+ getenv("QTEST_LOG") ? "/dev/fd/2" : "/dev/null",
qmp_socket_path,
extra_args ?: "");
execlp("/bin/sh", "sh", "-c", command, NULL);
@@ -358,6 +359,7 @@ static void qmp_response(JSONMessageParser *parser, QList *tokens)
QDict *qtest_qmp_receive(QTestState *s)
{
QMPResponseParser qmp;
+ bool log = getenv("QTEST_LOG") != NULL;
qmp.response = NULL;
json_message_parser_init(&qmp.parser, qmp_response);
@@ -375,6 +377,9 @@ QDict *qtest_qmp_receive(QTestState *s)
exit(1);
}
+ if (log) {
+ len = write(2, &c, 1);
+ }
json_message_parser_feed(&qmp.parser, &c, 1);
}
json_message_parser_destroy(&qmp.parser);
@@ -397,10 +402,14 @@ QDict *qtest_qmpv(QTestState *s, const char *fmt, va_list ap)
/* No need to send anything for an empty QObject. */
if (qobj) {
+ int log = getenv("QTEST_LOG") != NULL;
QString *qstr = qobject_to_json(qobj);
const char *str = qstring_get_str(qstr);
size_t size = qstring_get_length(qstr);
+ if (log) {
+ fprintf(stderr, "%s", str);
+ }
/* Send QMP request */
socket_send(s->qmp_fd, str, size);
@@ -639,6 +648,7 @@ void qtest_add_func(const char *str, void (*fn))
{
gchar *path = g_strdup_printf("/%s/%s", qtest_get_arch(), str);
g_test_add_func(path, fn);
+ g_free(path);
}
void qtest_memwrite(QTestState *s, uint64_t addr, const void *data, size_t size)
@@ -654,6 +664,18 @@ void qtest_memwrite(QTestState *s, uint64_t addr, const void *data, size_t size)
qtest_rsp(s, 0);
}
+void qtest_memset(QTestState *s, uint64_t addr, uint8_t pattern, size_t size)
+{
+ size_t i;
+
+ qtest_sendf(s, "write 0x%" PRIx64 " 0x%zx 0x", addr, size);
+ for (i = 0; i < size; i++) {
+ qtest_sendf(s, "%02x", pattern);
+ }
+ qtest_sendf(s, "\n");
+ qtest_rsp(s, 0);
+}
+
QDict *qmp(const char *fmt, ...)
{
va_list ap;
diff --git a/tests/libqtest.h b/tests/libqtest.h
index 8f323c7030..1be0934f07 100644
--- a/tests/libqtest.h
+++ b/tests/libqtest.h
@@ -283,6 +283,17 @@ void qtest_memread(QTestState *s, uint64_t addr, void *data, size_t size);
void qtest_memwrite(QTestState *s, uint64_t addr, const void *data, size_t size);
/**
+ * qtest_memset:
+ * @s: #QTestState instance to operate on.
+ * @addr: Guest address to write to.
+ * @patt: Byte pattern to fill the guest memory region with.
+ * @size: Number of bytes to write.
+ *
+ * Write a pattern to guest memory.
+ */
+void qtest_memset(QTestState *s, uint64_t addr, uint8_t patt, size_t size);
+
+/**
* qtest_clock_step_next:
* @s: #QTestState instance to operate on.
*
@@ -621,6 +632,19 @@ static inline void memwrite(uint64_t addr, const void *data, size_t size)
}
/**
+ * qmemset:
+ * @addr: Guest address to write to.
+ * @patt: Byte pattern to fill the guest memory region with.
+ * @size: Number of bytes to write.
+ *
+ * Write a pattern to guest memory.
+ */
+static inline void qmemset(uint64_t addr, uint8_t patt, size_t size)
+{
+ qtest_memset(global_qtest, addr, patt, size);
+}
+
+/**
* clock_step_next:
*
* Advance the QEMU_CLOCK_VIRTUAL to the next deadline.
diff --git a/tests/qemu-iotests/028 b/tests/qemu-iotests/028
index d5718c5594..9e701e1c2b 100755
--- a/tests/qemu-iotests/028
+++ b/tests/qemu-iotests/028
@@ -110,7 +110,9 @@ _launch_qemu -drive file="${TEST_IMG}",cache=${CACHEMODE},id=disk
h=$QEMU_HANDLE
QEMU_COMM_TIMEOUT=1
-_send_qemu_cmd $h "drive_backup disk ${TEST_IMG}.copy" "(qemu)"
+# Silence output since it contains the disk image path and QEMU's readline
+# character echoing makes it very hard to filter the output
+_send_qemu_cmd $h "drive_backup disk ${TEST_IMG}.copy" "(qemu)" >/dev/null
qemu_cmd_repeat=20 _send_qemu_cmd $h "info block-jobs" "No active jobs"
_send_qemu_cmd $h 'quit' ""
diff --git a/tests/qemu-iotests/028.out b/tests/qemu-iotests/028.out
index 38099e44c9..0e1a5ae65d 100644
--- a/tests/qemu-iotests/028.out
+++ b/tests/qemu-iotests/028.out
@@ -468,8 +468,6 @@ No errors were found on the image.
block-backup
-QEMU X.Y.Z monitor - type 'help' for more information
-(qemu) ddrdridrivdrivedrive_drive_bdrive_badrive_bacdrive_backdrive_backudrive_backupdrive_backup drive_backup ddrive_backup didrive_backup disdrive_backup diskdrive_backup disk drive_backup disk /drive_backup disk /hdrive_backup disk /hodrive_backup disk /homdrive_backup disk /homedrive_backup disk /home/drive_backup disk /home/kdrive_backup disk /home/kwdrive_backup disk /home/kwodrive_backup disk /home/kwoldrive_backup disk /home/kwolfdrive_backup disk /home/kwolf/drive_backup disk /home/kwolf/sdrive_backup disk /home/kwolf/sodrive_backup disk /home/kwolf/soudrive_backup disk /home/kwolf/sourdrive_backup disk /home/kwolf/sourcdrive_backup disk /home/kwolf/sourcedrive_backup disk /home/kwolf/source/drive_backup disk /home/kwolf/source/qdrive_backup disk /home/kwolf/source/qedrive_backup disk /home/kwolf/source/qemdrive_backup disk /home/kwolf/source/qemudrive_backup disk /home/kwolf/source/qemu/drive_backup disk /home/kwolf/source/qemu/tdrive_backup disk /home/kwolf/source/qemu/tedrive_backup disk /home/kwolf/source/qemu/tesdrive_backup disk /home/kwolf/source/qemu/testdrive_backup disk /home/kwolf/source/qemu/testsdrive_backup disk /home/kwolf/source/qemu/tests/drive_backup disk /home/kwolf/source/qemu/tests/qdrive_backup disk /home/kwolf/source/qemu/tests/qedrive_backup disk /home/kwolf/source/qemu/tests/qemdrive_backup disk /home/kwolf/source/qemu/tests/qemudrive_backup disk /home/kwolf/source/qemu/tests/qemu-drive_backup disk /home/kwolf/source/qemu/tests/qemu-idrive_backup disk /home/kwolf/source/qemu/tests/qemu-iodrive_backup disk /home/kwolf/source/qemu/tests/qemu-iotdrive_backup disk /home/kwolf/source/qemu/tests/qemu-iotedrive_backup disk /home/kwolf/source/qemu/tests/qemu-iotesdrive_backup disk /home/kwolf/source/qemu/tests/qemu-iotestdrive_backup disk /home/kwolf/source/qemu/tests/qemu-iotestsdrive_backup disk /home/kwolf/source/qemu/tests/qemu-iotests/drive_backup disk /home/kwolf/source/qemu/tests/qemu-iotests/sdrive_backup disk /home/kwolf/source/qemu/tests/qemu-iotests/scdrive_backup disk /home/kwolf/source/qemu/tests/qemu-iotests/scrdrive_backup disk /home/kwolf/source/qemu/tests/qemu-iotests/scradrive_backup disk /home/kwolf/source/qemu/tests/qemu-iotests/scratdrive_backup disk /home/kwolf/source/qemu/tests/qemu-iotests/scratcdrive_backup disk TEST_DIRdrive_backup disk TEST_DIR/drive_backup disk TEST_DIR/tdrive_backup disk TEST_DIR/t.drive_backup disk TEST_DIR/t.qdrive_backup disk TEST_DIR/t.qcdrive_backup disk TEST_DIR/t.qcodrive_backup disk TEST_DIR/t.qcowdrive_backup disk TEST_DIR/t.qcow2drive_backup disk TEST_DIR/t.qcow2.drive_backup disk TEST_DIR/t.qcow2.cdrive_backup disk TEST_DIR/t.qcow2.codrive_backup disk TEST_DIR/t.qcow2.copdrive_backup disk TEST_DIR/t.qcow2.copy
Formatting 'TEST_DIR/t.qcow2.copy', fmt=qcow2 size=4294968832 backing_file='TEST_DIR/t.qcow2.base' backing_fmt='qcow2' encryption=off cluster_size=65536 lazy_refcounts=off
(qemu) iininfinfoinfo info binfo blinfo bloinfo blocinfo blockinfo block-info block-jinfo block-joinfo block-jobinfo block-jobs
Type backup, device disk: Completed 0 of 4294968832 bytes, speed limit 0 bytes/s
diff --git a/tests/qemu-iotests/036 b/tests/qemu-iotests/036
index a77365347d..392f1ef3e6 100755
--- a/tests/qemu-iotests/036
+++ b/tests/qemu-iotests/036
@@ -1,6 +1,6 @@
#!/bin/bash
#
-# Test that qcow2 unknown autoclear feature bits are cleared
+# Test qcow2 feature bits
#
# Copyright (C) 2011 Red Hat, Inc.
# Copyright IBM, Corp. 2010
@@ -50,6 +50,56 @@ _supported_os Linux
# Only qcow2v3 and later supports feature bits
IMGOPTS="compat=1.1"
+echo
+echo === Image with unknown incompatible feature bit ===
+echo
+_make_test_img 64M
+$PYTHON qcow2.py "$TEST_IMG" set-feature-bit incompatible 63
+
+# Without feature table
+$PYTHON qcow2.py "$TEST_IMG" dump-header
+_img_info
+
+# With feature table containing bit 63
+printf "\x00\x3f%s" "Test feature" | $PYTHON qcow2.py "$TEST_IMG" add-header-ext-stdio 0x6803f857
+_img_info
+
+echo
+echo === Image with multiple incompatible feature bits ===
+echo
+_make_test_img 64M
+$PYTHON qcow2.py "$TEST_IMG" set-feature-bit incompatible 61
+$PYTHON qcow2.py "$TEST_IMG" set-feature-bit incompatible 62
+$PYTHON qcow2.py "$TEST_IMG" set-feature-bit incompatible 63
+
+# Without feature table
+_img_info
+
+# With feature table containing bit 63
+printf "\x00\x3f%s" "Test feature" | $PYTHON qcow2.py "$TEST_IMG" add-header-ext-stdio 0x6803f857
+_img_info
+
+# With feature table containing bit 61
+$PYTHON qcow2.py "$TEST_IMG" del-header-ext 0x6803f857
+printf "\x00\x3d%s" "Test feature" | $PYTHON qcow2.py "$TEST_IMG" add-header-ext-stdio 0x6803f857
+_img_info
+
+# With feature table containing bits 61 and 62
+$PYTHON qcow2.py "$TEST_IMG" del-header-ext 0x6803f857
+printf "\x00\x3d%s\x00%40s\x00\x3e%s\x00%40s" "test1" "" "test2" "" | $PYTHON qcow2.py "$TEST_IMG" add-header-ext-stdio 0x6803f857
+_img_info
+
+# With feature table containing all bits
+$PYTHON qcow2.py "$TEST_IMG" del-header-ext 0x6803f857
+printf "\x00\x3d%s\x00%40s\x00\x3e%s\x00%40s\x00\x3f%s\x00%40s" "test1" "" "test2" "" "test3" "" | $PYTHON qcow2.py "$TEST_IMG" add-header-ext-stdio 0x6803f857
+_img_info
+
+# With feature table containing unrelated bits, including compatible/autoclear
+$PYTHON qcow2.py "$TEST_IMG" del-header-ext 0x6803f857
+printf "\x01\x3d%s\x00%40s\x00\x3e%s\x00%40s\x02\x3f%s\x00%40s\x00\x3c%s\x00%40s" "test1" "" "test2" "" "test3" "" "test4" "" | $PYTHON qcow2.py "$TEST_IMG" add-header-ext-stdio 0x6803f857
+_img_info
+
+
echo === Create image with unknown autoclear feature bit ===
echo
_make_test_img 64M
diff --git a/tests/qemu-iotests/036.out b/tests/qemu-iotests/036.out
index 55a3e6e441..720bd89161 100644
--- a/tests/qemu-iotests/036.out
+++ b/tests/qemu-iotests/036.out
@@ -1,4 +1,39 @@
QA output created by 036
+
+=== Image with unknown incompatible feature bit ===
+
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
+magic 0x514649fb
+version 3
+backing_file_offset 0x0
+backing_file_size 0x0
+cluster_bits 16
+size 67108864
+crypt_method 0
+l1_size 1
+l1_table_offset 0x30000
+refcount_table_offset 0x10000
+refcount_table_clusters 1
+nb_snapshots 0
+snapshot_offset 0x0
+incompatible_features 0x8000000000000000
+compatible_features 0x0
+autoclear_features 0x0
+refcount_order 4
+header_length 104
+
+qemu-img: Could not open 'TEST_DIR/t.IMGFMT': 'image' uses a IMGFMT feature which is not supported by this qemu version: Unknown incompatible feature: 8000000000000000
+qemu-img: Could not open 'TEST_DIR/t.IMGFMT': 'image' uses a IMGFMT feature which is not supported by this qemu version: Test feature
+
+=== Image with multiple incompatible feature bits ===
+
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
+qemu-img: Could not open 'TEST_DIR/t.IMGFMT': 'image' uses a IMGFMT feature which is not supported by this qemu version: Unknown incompatible feature: e000000000000000
+qemu-img: Could not open 'TEST_DIR/t.IMGFMT': 'image' uses a IMGFMT feature which is not supported by this qemu version: Test feature, Unknown incompatible feature: 6000000000000000
+qemu-img: Could not open 'TEST_DIR/t.IMGFMT': 'image' uses a IMGFMT feature which is not supported by this qemu version: Test feature, Unknown incompatible feature: c000000000000000
+qemu-img: Could not open 'TEST_DIR/t.IMGFMT': 'image' uses a IMGFMT feature which is not supported by this qemu version: test1, test2, Unknown incompatible feature: 8000000000000000
+qemu-img: Could not open 'TEST_DIR/t.IMGFMT': 'image' uses a IMGFMT feature which is not supported by this qemu version: test1, test2, test3
+qemu-img: Could not open 'TEST_DIR/t.IMGFMT': 'image' uses a IMGFMT feature which is not supported by this qemu version: test2, Unknown incompatible feature: a000000000000000
=== Create image with unknown autoclear feature bit ===
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
diff --git a/tests/qemu-iotests/059 b/tests/qemu-iotests/059
index 26a2fd3e0e..3c053c29b4 100755
--- a/tests/qemu-iotests/059
+++ b/tests/qemu-iotests/059
@@ -114,6 +114,10 @@ echo
echo "=== Testing version 3 ==="
_use_sample_img iotest-version3.vmdk.bz2
_img_info
+for i in {0..99}; do
+ $QEMU_IO -r -c "read -P $(( i % 10 + 0x30 )) $(( i * 64 * 1024 * 10 + i * 512 )) 512" $TEST_IMG \
+ | _filter_qemu_io
+done
echo
echo "=== Testing 4TB monolithicFlat creation and IO ==="
diff --git a/tests/qemu-iotests/059.out b/tests/qemu-iotests/059.out
index eba0dedda0..0dadba658f 100644
--- a/tests/qemu-iotests/059.out
+++ b/tests/qemu-iotests/059.out
@@ -2056,8 +2056,208 @@ wrote 512/512 bytes at offset 10240
=== Testing version 3 ===
image: TEST_DIR/iotest-version3.IMGFMT
file format: IMGFMT
-virtual size: 1.0G (1073741824 bytes)
+virtual size: 16G (17179869184 bytes)
cluster_size: 65536
+read 512/512 bytes at offset 0
+512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+read 512/512 bytes at offset 655872
+512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+read 512/512 bytes at offset 1311744
+512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+read 512/512 bytes at offset 1967616
+512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+read 512/512 bytes at offset 2623488
+512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+read 512/512 bytes at offset 3279360
+512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+read 512/512 bytes at offset 3935232
+512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+read 512/512 bytes at offset 4591104
+512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+read 512/512 bytes at offset 5246976
+512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+read 512/512 bytes at offset 5902848
+512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+read 512/512 bytes at offset 6558720
+512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+read 512/512 bytes at offset 7214592
+512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+read 512/512 bytes at offset 7870464
+512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+read 512/512 bytes at offset 8526336
+512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+read 512/512 bytes at offset 9182208
+512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+read 512/512 bytes at offset 9838080
+512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+read 512/512 bytes at offset 10493952
+512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+read 512/512 bytes at offset 11149824
+512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+read 512/512 bytes at offset 11805696
+512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+read 512/512 bytes at offset 12461568
+512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+read 512/512 bytes at offset 13117440
+512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+read 512/512 bytes at offset 13773312
+512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+read 512/512 bytes at offset 14429184
+512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+read 512/512 bytes at offset 15085056
+512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+read 512/512 bytes at offset 15740928
+512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+read 512/512 bytes at offset 16396800
+512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+read 512/512 bytes at offset 17052672
+512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+read 512/512 bytes at offset 17708544
+512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+read 512/512 bytes at offset 18364416
+512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+read 512/512 bytes at offset 19020288
+512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+read 512/512 bytes at offset 19676160
+512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+read 512/512 bytes at offset 20332032
+512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+read 512/512 bytes at offset 20987904
+512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+read 512/512 bytes at offset 21643776
+512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+read 512/512 bytes at offset 22299648
+512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+read 512/512 bytes at offset 22955520
+512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+read 512/512 bytes at offset 23611392
+512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+read 512/512 bytes at offset 24267264
+512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+read 512/512 bytes at offset 24923136
+512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+read 512/512 bytes at offset 25579008
+512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+read 512/512 bytes at offset 26234880
+512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+read 512/512 bytes at offset 26890752
+512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+read 512/512 bytes at offset 27546624
+512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+read 512/512 bytes at offset 28202496
+512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+read 512/512 bytes at offset 28858368
+512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+read 512/512 bytes at offset 29514240
+512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+read 512/512 bytes at offset 30170112
+512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+read 512/512 bytes at offset 30825984
+512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+read 512/512 bytes at offset 31481856
+512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+read 512/512 bytes at offset 32137728
+512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+read 512/512 bytes at offset 32793600
+512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+read 512/512 bytes at offset 33449472
+512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+read 512/512 bytes at offset 34105344
+512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+read 512/512 bytes at offset 34761216
+512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+read 512/512 bytes at offset 35417088
+512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+read 512/512 bytes at offset 36072960
+512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+read 512/512 bytes at offset 36728832
+512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+read 512/512 bytes at offset 37384704
+512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+read 512/512 bytes at offset 38040576
+512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+read 512/512 bytes at offset 38696448
+512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+read 512/512 bytes at offset 39352320
+512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+read 512/512 bytes at offset 40008192
+512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+read 512/512 bytes at offset 40664064
+512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+read 512/512 bytes at offset 41319936
+512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+read 512/512 bytes at offset 41975808
+512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+read 512/512 bytes at offset 42631680
+512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+read 512/512 bytes at offset 43287552
+512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+read 512/512 bytes at offset 43943424
+512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+read 512/512 bytes at offset 44599296
+512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+read 512/512 bytes at offset 45255168
+512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+read 512/512 bytes at offset 45911040
+512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+read 512/512 bytes at offset 46566912
+512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+read 512/512 bytes at offset 47222784
+512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+read 512/512 bytes at offset 47878656
+512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+read 512/512 bytes at offset 48534528
+512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+read 512/512 bytes at offset 49190400
+512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+read 512/512 bytes at offset 49846272
+512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+read 512/512 bytes at offset 50502144
+512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+read 512/512 bytes at offset 51158016
+512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+read 512/512 bytes at offset 51813888
+512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+read 512/512 bytes at offset 52469760
+512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+read 512/512 bytes at offset 53125632
+512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+read 512/512 bytes at offset 53781504
+512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+read 512/512 bytes at offset 54437376
+512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+read 512/512 bytes at offset 55093248
+512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+read 512/512 bytes at offset 55749120
+512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+read 512/512 bytes at offset 56404992
+512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+read 512/512 bytes at offset 57060864
+512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+read 512/512 bytes at offset 57716736
+512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+read 512/512 bytes at offset 58372608
+512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+read 512/512 bytes at offset 59028480
+512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+read 512/512 bytes at offset 59684352
+512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+read 512/512 bytes at offset 60340224
+512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+read 512/512 bytes at offset 60996096
+512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+read 512/512 bytes at offset 61651968
+512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+read 512/512 bytes at offset 62307840
+512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+read 512/512 bytes at offset 62963712
+512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+read 512/512 bytes at offset 63619584
+512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+read 512/512 bytes at offset 64275456
+512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+read 512/512 bytes at offset 64931328
+512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
=== Testing 4TB monolithicFlat creation and IO ===
Formatting 'TEST_DIR/iotest-version3.IMGFMT', fmt=IMGFMT size=4398046511104
diff --git a/tests/qemu-iotests/060 b/tests/qemu-iotests/060
index 3cffc12fec..830386fdaa 100755
--- a/tests/qemu-iotests/060
+++ b/tests/qemu-iotests/060
@@ -164,6 +164,15 @@ wait_break 0
write 64k 64k
resume 0" | $QEMU_IO | _filter_qemu_io
+echo
+echo "=== Testing unallocated image header ==="
+echo
+_make_test_img 64M
+# Create L1/L2
+$QEMU_IO -c "$OPEN_RW" -c "write 0 64k" | _filter_qemu_io
+poke_file "$TEST_IMG" "$rb_offset" "\x00\x00"
+$QEMU_IO -c "$OPEN_RW" -c "write 64k 64k" | _filter_qemu_io
+
# success, all done
echo "*** done"
rm -f $seq.full
diff --git a/tests/qemu-iotests/060.out b/tests/qemu-iotests/060.out
index a517948036..c27c952412 100644
--- a/tests/qemu-iotests/060.out
+++ b/tests/qemu-iotests/060.out
@@ -93,4 +93,12 @@ blkdebug: Suspended request '0'
write failed: Input/output error
blkdebug: Resuming request '0'
aio_write failed: No medium found
+
+=== Testing unallocated image header ===
+
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
+wrote 65536/65536 bytes at offset 0
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+qcow2: Preventing invalid write on metadata (overlaps with qcow2_header); image marked as corrupt.
+write failed: Input/output error
*** done
diff --git a/tests/qemu-iotests/084 b/tests/qemu-iotests/084
index cb4d7b729e..ae33c2cba4 100755
--- a/tests/qemu-iotests/084
+++ b/tests/qemu-iotests/084
@@ -1,6 +1,7 @@
#!/bin/bash
#
-# Test case for VDI header corruption; image too large, and too many blocks
+# Test case for VDI header corruption; image too large, and too many blocks.
+# Also simple test for creating dynamic and static VDI images.
#
# Copyright (C) 2013 Red Hat, Inc.
#
@@ -43,14 +44,25 @@ _supported_fmt vdi
_supported_proto generic
_supported_os Linux
+size=64M
ds_offset=368 # disk image size field offset
bs_offset=376 # block size field offset
bii_offset=384 # block in image field offset
echo
+echo "=== Statically allocated image creation ==="
+echo
+_make_test_img $size -o static
+_img_info
+stat -c"disk image file size in bytes: %s" "${TEST_IMG}"
+_cleanup_test_img
+
+echo
echo "=== Testing image size bounds ==="
echo
-_make_test_img 64M
+_make_test_img $size
+_img_info
+stat -c"disk image file size in bytes: %s" "${TEST_IMG}"
# check for image size too large
# poke max image size, and appropriate blocks_in_image value
diff --git a/tests/qemu-iotests/084.out b/tests/qemu-iotests/084.out
index c7120d9b0b..ea29ae0b9d 100644
--- a/tests/qemu-iotests/084.out
+++ b/tests/qemu-iotests/084.out
@@ -1,8 +1,22 @@
QA output created by 084
+=== Statically allocated image creation ===
+
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
+image: TEST_DIR/t.IMGFMT
+file format: IMGFMT
+virtual size: 64M (67108864 bytes)
+cluster_size: 1048576
+disk image file size in bytes: 67109888
+
=== Testing image size bounds ===
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
+image: TEST_DIR/t.IMGFMT
+file format: IMGFMT
+virtual size: 64M (67108864 bytes)
+cluster_size: 1048576
+disk image file size in bytes: 1024
Test 1: Maximum size (1024 TB):
qemu-img: Could not open 'TEST_DIR/t.IMGFMT': Could not open 'TEST_DIR/t.IMGFMT': Invalid argument
diff --git a/tests/qemu-iotests/common b/tests/qemu-iotests/common
index e4083f4212..70df659d5b 100644
--- a/tests/qemu-iotests/common
+++ b/tests/qemu-iotests/common
@@ -152,6 +152,7 @@ check options
-nbd test nbd
-ssh test ssh
-nfs test nfs
+ -archipelago test archipelago
-xdiff graphical mode diff
-nocache use O_DIRECT on backing file
-misalign misalign memory allocations
@@ -263,6 +264,11 @@ testlist options
xpand=false
;;
+ -archipelago)
+ IMGPROTO=archipelago
+ xpand=false
+ ;;
+
-nocache)
CACHEMODE="none"
CACHEMODE_IS_DEFAULT=false
diff --git a/tests/qemu-iotests/common.rc b/tests/qemu-iotests/common.rc
index e0ea7e3a7d..3fd691e6cd 100644
--- a/tests/qemu-iotests/common.rc
+++ b/tests/qemu-iotests/common.rc
@@ -64,6 +64,8 @@ elif [ "$IMGPROTO" = "ssh" ]; then
elif [ "$IMGPROTO" = "nfs" ]; then
TEST_DIR="nfs://127.0.0.1/$TEST_DIR"
TEST_IMG=$TEST_DIR/t.$IMGFMT
+elif [ "$IMGPROTO" = "archipelago" ]; then
+ TEST_IMG="archipelago:at.$IMGFMT"
else
TEST_IMG=$IMGPROTO:$TEST_DIR/t.$IMGFMT
fi
@@ -163,7 +165,8 @@ _make_test_img()
-e "s# lazy_refcounts=\\(on\\|off\\)##g" \
-e "s# block_size=[0-9]\\+##g" \
-e "s# block_state_zero=\\(on\\|off\\)##g" \
- -e "s# log_size=[0-9]\\+##g"
+ -e "s# log_size=[0-9]\\+##g" \
+ -e "s/archipelago:a/TEST_DIR\//g"
# Start an NBD server on the image file, which is what we'll be talking to
if [ $IMGPROTO = "nbd" ]; then
@@ -206,6 +209,10 @@ _cleanup_test_img()
rbd --no-progress rm "$TEST_DIR/t.$IMGFMT" > /dev/null
;;
+ archipelago)
+ vlmc remove "at.$IMGFMT" > /dev/null
+ ;;
+
sheepdog)
collie vdi delete "$TEST_DIR/t.$IMGFMT"
;;
diff --git a/tests/qemu-iotests/qcow2.py b/tests/qemu-iotests/qcow2.py
index 44a2b45641..2058596964 100755
--- a/tests/qemu-iotests/qcow2.py
+++ b/tests/qemu-iotests/qcow2.py
@@ -176,6 +176,10 @@ def cmd_add_header_ext(fd, magic, data):
h.extensions.append(QcowHeaderExtension.create(magic, data))
h.update(fd)
+def cmd_add_header_ext_stdio(fd, magic):
+ data = sys.stdin.read()
+ cmd_add_header_ext(fd, magic, data)
+
def cmd_del_header_ext(fd, magic):
try:
magic = int(magic, 0)
@@ -220,11 +224,12 @@ def cmd_set_feature_bit(fd, group, bit):
h.update(fd)
cmds = [
- [ 'dump-header', cmd_dump_header, 0, 'Dump image header and header extensions' ],
- [ 'set-header', cmd_set_header, 2, 'Set a field in the header'],
- [ 'add-header-ext', cmd_add_header_ext, 2, 'Add a header extension' ],
- [ 'del-header-ext', cmd_del_header_ext, 1, 'Delete a header extension' ],
- [ 'set-feature-bit', cmd_set_feature_bit, 2, 'Set a feature bit'],
+ [ 'dump-header', cmd_dump_header, 0, 'Dump image header and header extensions' ],
+ [ 'set-header', cmd_set_header, 2, 'Set a field in the header'],
+ [ 'add-header-ext', cmd_add_header_ext, 2, 'Add a header extension' ],
+ [ 'add-header-ext-stdio', cmd_add_header_ext_stdio, 1, 'Add a header extension, data from stdin' ],
+ [ 'del-header-ext', cmd_del_header_ext, 1, 'Delete a header extension' ],
+ [ 'set-feature-bit', cmd_set_feature_bit, 2, 'Set a feature bit'],
]
def main(filename, cmd, args):
diff --git a/tests/qemu-iotests/sample_images/iotest-version3.vmdk.bz2 b/tests/qemu-iotests/sample_images/iotest-version3.vmdk.bz2
index 30abf217e7..619329a246 100644
--- a/tests/qemu-iotests/sample_images/iotest-version3.vmdk.bz2
+++ b/tests/qemu-iotests/sample_images/iotest-version3.vmdk.bz2
Binary files differ
diff --git a/tests/test-aio.c b/tests/test-aio.c
index 4c40a4971f..f12b6e0ae8 100644
--- a/tests/test-aio.c
+++ b/tests/test-aio.c
@@ -15,7 +15,7 @@
#include "qemu/timer.h"
#include "qemu/sockets.h"
-AioContext *ctx;
+static AioContext *ctx;
typedef struct {
EventNotifier e;
diff --git a/tests/test-coroutine.c b/tests/test-coroutine.c
index 760636ddc4..6e634f4a78 100644
--- a/tests/test-coroutine.c
+++ b/tests/test-coroutine.c
@@ -288,6 +288,29 @@ static void perf_yield(void)
maxcycles, duration);
}
+static __attribute__((noinline)) void dummy(unsigned *i)
+{
+ (*i)--;
+}
+
+static void perf_baseline(void)
+{
+ unsigned int i, maxcycles;
+ double duration;
+
+ maxcycles = 100000000;
+ i = maxcycles;
+
+ g_test_timer_start();
+ while (i > 0) {
+ dummy(&i);
+ }
+ duration = g_test_timer_elapsed();
+
+ g_test_message("Function call %u iterations: %f s\n",
+ maxcycles, duration);
+}
+
int main(int argc, char **argv)
{
g_test_init(&argc, &argv, NULL);
@@ -301,6 +324,7 @@ int main(int argc, char **argv)
g_test_add_func("/perf/lifecycle", perf_lifecycle);
g_test_add_func("/perf/nesting", perf_nesting);
g_test_add_func("/perf/yield", perf_yield);
+ g_test_add_func("/perf/function-call", perf_baseline);
}
return g_test_run();
}
diff --git a/tests/test-qemu-opts.c b/tests/test-qemu-opts.c
index 3653507f56..ca08ac523d 100644
--- a/tests/test-qemu-opts.c
+++ b/tests/test-qemu-opts.c
@@ -56,7 +56,7 @@ static QemuOptsList opts_list_02 = {
},
};
-QemuOptsList opts_list_03 = {
+static QemuOptsList opts_list_03 = {
.name = "opts_list_03",
.head = QTAILQ_HEAD_INITIALIZER(opts_list_03.head),
.desc = {
diff --git a/tests/test-throttle.c b/tests/test-throttle.c
index 3de6ab80e0..000ae31af9 100644
--- a/tests/test-throttle.c
+++ b/tests/test-throttle.c
@@ -15,10 +15,10 @@
#include "block/aio.h"
#include "qemu/throttle.h"
-AioContext *ctx;
-LeakyBucket bkt;
-ThrottleConfig cfg;
-ThrottleState ts;
+static AioContext *ctx;
+static LeakyBucket bkt;
+static ThrottleConfig cfg;
+static ThrottleState ts;
/* useful function */
static bool double_cmp(double x, double y)
diff --git a/tests/test-visitor-serialization.c b/tests/test-visitor-serialization.c
index 74d6481992..7ad1886397 100644
--- a/tests/test-visitor-serialization.c
+++ b/tests/test-visitor-serialization.c
@@ -372,8 +372,8 @@ static void test_primitive_lists(gconstpointer opaque)
TestArgs *args = (TestArgs *) opaque;
const SerializeOps *ops = args->ops;
PrimitiveType *pt = args->test_data;
- PrimitiveList pl = { .value = { 0 } };
- PrimitiveList pl_copy = { .value = { 0 } };
+ PrimitiveList pl = { .value = { NULL } };
+ PrimitiveList pl_copy = { .value = { NULL } };
PrimitiveList *pl_copy_ptr = &pl_copy;
Error *err = NULL;
void *serialize_data;
@@ -771,7 +771,7 @@ static void test_nested_struct_list(gconstpointer opaque)
g_free(args);
}
-PrimitiveType pt_values[] = {
+static PrimitiveType pt_values[] = {
/* string tests */
{
.description = "string_empty",
diff --git a/tests/test-vmstate.c b/tests/test-vmstate.c
index a462335c4b..d72c64c90b 100644
--- a/tests/test-vmstate.c
+++ b/tests/test-vmstate.c
@@ -29,8 +29,8 @@
#include "migration/vmstate.h"
#include "block/coroutine.h"
-char temp_file[] = "/tmp/vmst.test.XXXXXX";
-int temp_fd;
+static char temp_file[] = "/tmp/vmst.test.XXXXXX";
+static int temp_fd;
/* Fake yield_until_fd_readable() implementation so we don't have to pull the
* coroutine code as dependency.
diff --git a/tests/usb-hcd-ehci-test.c b/tests/usb-hcd-ehci-test.c
index bcdf62fc3b..c990492835 100644
--- a/tests/usb-hcd-ehci-test.c
+++ b/tests/usb-hcd-ehci-test.c
@@ -34,7 +34,7 @@ static void pci_init_one(struct qhc *hc, uint32_t devfn, int bar)
hc->dev = qpci_device_find(pcibus, devfn);
g_assert(hc->dev != NULL);
qpci_device_enable(hc->dev);
- hc->base = qpci_iomap(hc->dev, bar);
+ hc->base = qpci_iomap(hc->dev, bar, NULL);
g_assert(hc->base != NULL);
}
diff --git a/tests/vhost-user-test.c b/tests/vhost-user-test.c
index 406ba70941..75fedf0977 100644
--- a/tests/vhost-user-test.c
+++ b/tests/vhost-user-test.c
@@ -76,6 +76,7 @@ typedef struct VhostUserMemoryRegion {
uint64_t guest_phys_addr;
uint64_t memory_size;
uint64_t userspace_addr;
+ uint64_t mmap_offset;
} VhostUserMemoryRegion;
typedef struct VhostUserMemory {
@@ -205,6 +206,7 @@ static void read_guest_mem(void)
uint32_t *guest_mem;
gint64 end_time;
int i, j;
+ size_t size;
g_mutex_lock(data_mutex);
@@ -231,8 +233,13 @@ static void read_guest_mem(void)
g_assert_cmpint(memory.regions[i].memory_size, >, 1024);
- guest_mem = mmap(0, memory.regions[i].memory_size,
- PROT_READ | PROT_WRITE, MAP_SHARED, fds[i], 0);
+ size = memory.regions[i].memory_size + memory.regions[i].mmap_offset;
+
+ guest_mem = mmap(0, size, PROT_READ | PROT_WRITE,
+ MAP_SHARED, fds[i], 0);
+
+ g_assert(guest_mem != MAP_FAILED);
+ guest_mem += (memory.regions[i].mmap_offset / sizeof(*guest_mem));
for (j = 0; j < 256; j++) {
uint32_t a = readl(memory.regions[i].guest_phys_addr + j*4);
diff --git a/tests/wdt_ib700-test.c b/tests/wdt_ib700-test.c
new file mode 100644
index 0000000000..513a533852
--- /dev/null
+++ b/tests/wdt_ib700-test.c
@@ -0,0 +1,134 @@
+/*
+ * QTest testcase for the IB700 watchdog
+ *
+ * Copyright (c) 2014 Red Hat, Inc.
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#include <glib.h>
+#include <string.h>
+#include "libqtest.h"
+#include "qemu/osdep.h"
+
+#define NS_PER_SEC 1000000000ULL
+
+static void qmp_check_no_event(void)
+{
+ QDict *resp = qmp("{'execute':'query-status'}");
+ g_assert(qdict_haskey(resp, "return"));
+ QDECREF(resp);
+}
+
+static QDict *qmp_get_event(const char *name)
+{
+ QDict *event = qmp("");
+ QDict *data;
+ g_assert(qdict_haskey(event, "event"));
+ g_assert(!strcmp(qdict_get_str(event, "event"), name));
+
+ if (qdict_haskey(event, "data")) {
+ data = qdict_get_qdict(event, "data");
+ QINCREF(data);
+ } else {
+ data = NULL;
+ }
+
+ QDECREF(event);
+ return data;
+}
+
+static QDict *ib700_program_and_wait(QTestState *s)
+{
+ clock_step(NS_PER_SEC * 40);
+ qmp_check_no_event();
+
+ /* 2 second limit */
+ outb(0x443, 14);
+
+ /* Ping */
+ clock_step(NS_PER_SEC);
+ qmp_check_no_event();
+ outb(0x443, 14);
+
+ /* Disable */
+ clock_step(NS_PER_SEC);
+ qmp_check_no_event();
+ outb(0x441, 1);
+ clock_step(3 * NS_PER_SEC);
+ qmp_check_no_event();
+
+ /* Enable and let it fire */
+ outb(0x443, 13);
+ clock_step(3 * NS_PER_SEC);
+ qmp_check_no_event();
+ clock_step(2 * NS_PER_SEC);
+ return qmp_get_event("WATCHDOG");
+}
+
+
+static void ib700_pause(void)
+{
+ QDict *d;
+ QTestState *s = qtest_start("-watchdog-action pause -device ib700");
+ qtest_irq_intercept_in(s, "ioapic");
+ d = ib700_program_and_wait(s);
+ g_assert(!strcmp(qdict_get_str(d, "action"), "pause"));
+ QDECREF(d);
+ d = qmp_get_event("STOP");
+ QDECREF(d);
+ qtest_end();
+}
+
+static void ib700_reset(void)
+{
+ QDict *d;
+ QTestState *s = qtest_start("-watchdog-action reset -device ib700");
+ qtest_irq_intercept_in(s, "ioapic");
+ d = ib700_program_and_wait(s);
+ g_assert(!strcmp(qdict_get_str(d, "action"), "reset"));
+ QDECREF(d);
+ d = qmp_get_event("RESET");
+ QDECREF(d);
+ qtest_end();
+}
+
+static void ib700_shutdown(void)
+{
+ QDict *d;
+ QTestState *s = qtest_start("-watchdog-action reset -no-reboot -device ib700");
+ qtest_irq_intercept_in(s, "ioapic");
+ d = ib700_program_and_wait(s);
+ g_assert(!strcmp(qdict_get_str(d, "action"), "reset"));
+ QDECREF(d);
+ d = qmp_get_event("SHUTDOWN");
+ QDECREF(d);
+ qtest_end();
+}
+
+static void ib700_none(void)
+{
+ QDict *d;
+ QTestState *s = qtest_start("-watchdog-action none -device ib700");
+ qtest_irq_intercept_in(s, "ioapic");
+ d = ib700_program_and_wait(s);
+ g_assert(!strcmp(qdict_get_str(d, "action"), "none"));
+ QDECREF(d);
+ qtest_end();
+}
+
+int main(int argc, char **argv)
+{
+ int ret;
+
+ g_test_init(&argc, &argv, NULL);
+ qtest_add_func("/wdt_ib700/pause", ib700_pause);
+ qtest_add_func("/wdt_ib700/reset", ib700_reset);
+ qtest_add_func("/wdt_ib700/shutdown", ib700_shutdown);
+ qtest_add_func("/wdt_ib700/none", ib700_none);
+
+ ret = g_test_run();
+
+ return ret;
+}
diff --git a/thread-pool.c b/thread-pool.c
index dfb699dd94..23888dcfc4 100644
--- a/thread-pool.c
+++ b/thread-pool.c
@@ -21,7 +21,6 @@
#include "block/coroutine.h"
#include "trace.h"
#include "block/block_int.h"
-#include "qemu/event_notifier.h"
#include "block/thread-pool.h"
#include "qemu/main-loop.h"
@@ -57,8 +56,8 @@ struct ThreadPoolElement {
};
struct ThreadPool {
- EventNotifier notifier;
AioContext *ctx;
+ QEMUBH *completion_bh;
QemuMutex lock;
QemuCond check_cancel;
QemuCond worker_stopped;
@@ -119,7 +118,7 @@ static void *worker_thread(void *opaque)
qemu_cond_broadcast(&pool->check_cancel);
}
- event_notifier_set(&pool->notifier);
+ qemu_bh_schedule(pool->completion_bh);
}
pool->cur_threads--;
@@ -168,12 +167,11 @@ static void spawn_thread(ThreadPool *pool)
}
}
-static void event_notifier_ready(EventNotifier *notifier)
+static void thread_pool_completion_bh(void *opaque)
{
- ThreadPool *pool = container_of(notifier, ThreadPool, notifier);
+ ThreadPool *pool = opaque;
ThreadPoolElement *elem, *next;
- event_notifier_test_and_clear(notifier);
restart:
QLIST_FOREACH_SAFE(elem, &pool->head, all, next) {
if (elem->state != THREAD_CANCELED && elem->state != THREAD_DONE) {
@@ -187,6 +185,12 @@ restart:
QLIST_REMOVE(elem, all);
/* Read state before ret. */
smp_rmb();
+
+ /* Schedule ourselves in case elem->common.cb() calls aio_poll() to
+ * wait for another request that completed at the same time.
+ */
+ qemu_bh_schedule(pool->completion_bh);
+
elem->common.cb(elem->common.opaque, elem->ret);
qemu_aio_release(elem);
goto restart;
@@ -215,7 +219,7 @@ static void thread_pool_cancel(BlockDriverAIOCB *acb)
qemu_sem_timedwait(&pool->sem, 0) == 0) {
QTAILQ_REMOVE(&pool->request_list, elem, reqs);
elem->state = THREAD_CANCELED;
- event_notifier_set(&pool->notifier);
+ qemu_bh_schedule(pool->completion_bh);
} else {
pool->pending_cancellations++;
while (elem->state != THREAD_CANCELED && elem->state != THREAD_DONE) {
@@ -224,7 +228,7 @@ static void thread_pool_cancel(BlockDriverAIOCB *acb)
pool->pending_cancellations--;
}
qemu_mutex_unlock(&pool->lock);
- event_notifier_ready(&pool->notifier);
+ thread_pool_completion_bh(pool);
}
static const AIOCBInfo thread_pool_aiocb_info = {
@@ -293,8 +297,8 @@ static void thread_pool_init_one(ThreadPool *pool, AioContext *ctx)
}
memset(pool, 0, sizeof(*pool));
- event_notifier_init(&pool->notifier, false);
pool->ctx = ctx;
+ pool->completion_bh = aio_bh_new(ctx, thread_pool_completion_bh, pool);
qemu_mutex_init(&pool->lock);
qemu_cond_init(&pool->check_cancel);
qemu_cond_init(&pool->worker_stopped);
@@ -304,8 +308,6 @@ static void thread_pool_init_one(ThreadPool *pool, AioContext *ctx)
QLIST_INIT(&pool->head);
QTAILQ_INIT(&pool->request_list);
-
- aio_set_event_notifier(ctx, &pool->notifier, event_notifier_ready);
}
ThreadPool *thread_pool_new(AioContext *ctx)
@@ -339,11 +341,10 @@ void thread_pool_free(ThreadPool *pool)
qemu_mutex_unlock(&pool->lock);
- aio_set_event_notifier(pool->ctx, &pool->notifier, NULL);
+ qemu_bh_delete(pool->completion_bh);
qemu_sem_destroy(&pool->sem);
qemu_cond_destroy(&pool->check_cancel);
qemu_cond_destroy(&pool->worker_stopped);
qemu_mutex_destroy(&pool->lock);
- event_notifier_cleanup(&pool->notifier);
g_free(pool);
}
diff --git a/trace-events b/trace-events
index 11a17a8a40..81bc915edd 100644
--- a/trace-events
+++ b/trace-events
@@ -41,6 +41,11 @@ virtio_irq(void *vq) "vq %p"
virtio_notify(void *vdev, void *vq) "vdev %p vq %p"
virtio_set_status(void *vdev, uint8_t val) "vdev %p val %u"
+# hw/virtio/virtio-rng.c
+virtio_rng_guest_not_ready(void *rng) "rng %p: guest not ready"
+virtio_rng_pushed(void *rng, size_t len) "rng %p: %zd bytes pushed"
+virtio_rng_request(void *rng, size_t size, unsigned quota) "rng %p: %zd bytes requested, %u bytes quota left"
+
# hw/char/virtio-serial-bus.c
virtio_serial_send_control_event(unsigned int port, uint16_t event, uint16_t value) "port %u, event %u, value %u"
virtio_serial_throttle_port(unsigned int port, bool throttle) "port %u, throttle %d"
@@ -1265,6 +1270,15 @@ kvm_failed_spr_get(int str, const char *msg) "Warning: Unable to retrieve SPR %d
kvm_failed_reg_get(uint64_t id, const char *msg) "Warning: Unable to retrieve ONEREG %" PRIu64 " from KVM: %s"
kvm_failed_reg_set(uint64_t id, const char *msg) "Warning: Unable to set ONEREG %" PRIu64 " to KVM: %s"
+# TCG related tracing (mostly disabled by default)
+# cpu-exec.c
+disable exec_tb(void *tb, uintptr_t pc) "tb:%p pc=0x%"PRIxPTR
+disable exec_tb_nocache(void *tb, uintptr_t pc) "tb:%p pc=0x%"PRIxPTR
+disable exec_tb_exit(void *next_tb, unsigned int flags) "tb:%p flags=%x"
+
+# translate-all.c
+translate_block(void *tb, uintptr_t pc, uint8_t *tb_code) "tb:%p, pc:0x%"PRIxPTR", tb_code:%p"
+
# memory.c
memory_region_ops_read(void *mr, uint64_t addr, uint64_t value, unsigned size) "mr %p addr %#"PRIx64" value %#"PRIx64" size %u"
memory_region_ops_write(void *mr, uint64_t addr, uint64_t value, unsigned size) "mr %p addr %#"PRIx64" value %#"PRIx64" size %u"
diff --git a/trace/Makefile.objs b/trace/Makefile.objs
index d7a86969a4..387f191fd4 100644
--- a/trace/Makefile.objs
+++ b/trace/Makefile.objs
@@ -49,6 +49,9 @@ util-obj-y += generated-events.o
######################################################################
# Auto-generated tracing routines
+##################################################
+# Execution level
+
$(obj)/generated-tracers.h: $(obj)/generated-tracers.h-timestamp
@cmp -s $< $@ || cp $< $@
$(obj)/generated-tracers.h-timestamp: $(SRC_PATH)/trace-events $(BUILD_DIR)/config-host.mak
@@ -57,8 +60,8 @@ $(obj)/generated-tracers.h-timestamp: $(SRC_PATH)/trace-events $(BUILD_DIR)/conf
--backends=$(TRACE_BACKENDS) \
< $< > $@," GEN $(patsubst %-timestamp,%,$@)")
-######################################################################
-# Auto-generated tracing routines (non-DTrace)
+##############################
+# non-DTrace
$(obj)/generated-tracers.c: $(obj)/generated-tracers.c-timestamp
@cmp -s $< $@ || cp $< $@
@@ -70,9 +73,8 @@ $(obj)/generated-tracers.c-timestamp: $(SRC_PATH)/trace-events $(BUILD_DIR)/conf
$(obj)/generated-tracers.o: $(obj)/generated-tracers.c $(obj)/generated-tracers.h
-
-######################################################################
-# Auto-generated DTrace code
+##############################
+# DTrace
# Normal practice is to name DTrace probe file with a '.d' extension
# but that gets picked up by QEMU's Makefile as an external dependency
@@ -94,6 +96,47 @@ $(obj)/generated-tracers-dtrace.o: $(obj)/generated-tracers-dtrace.dtrace
util-obj-y += generated-tracers-dtrace.o
endif
+##################################################
+# Translation level
+
+$(obj)/generated-helpers-wrappers.h: $(obj)/generated-helpers-wrappers.h-timestamp
+$(obj)/generated-helpers-wrappers.h-timestamp: $(SRC_PATH)/trace-events $(BUILD_DIR)/config-host.mak
+ $(call quiet-command,$(TRACETOOL) \
+ --format=tcg-helper-wrapper-h \
+ --backend=$(TRACE_BACKENDS) \
+ < $< > $@," GEN $(patsubst %-timestamp,%,$@)")
+ @cmp -s $@ $(patsubst %-timestamp,%,$@) || cp $@ $(patsubst %-timestamp,%,$@)
+
+$(obj)/generated-helpers.h: $(obj)/generated-helpers.h-timestamp
+$(obj)/generated-helpers.h-timestamp: $(SRC_PATH)/trace-events $(BUILD_DIR)/config-host.mak
+ $(call quiet-command,$(TRACETOOL) \
+ --format=tcg-helper-h \
+ --backend=$(TRACE_BACKENDS) \
+ < $< > $@," GEN $(patsubst %-timestamp,%,$@)")
+ @cmp -s $@ $(patsubst %-timestamp,%,$@) || cp $@ $(patsubst %-timestamp,%,$@)
+
+$(obj)/generated-helpers.c: $(obj)/generated-helpers.c-timestamp
+$(obj)/generated-helpers.c-timestamp: $(SRC_PATH)/trace-events $(BUILD_DIR)/config-host.mak
+ $(call quiet-command,$(TRACETOOL) \
+ --format=tcg-helper-c \
+ --backend=$(TRACE_BACKENDS) \
+ < $< > $@," GEN $(patsubst %-timestamp,%,$@)")
+ @cmp -s $@ $(patsubst %-timestamp,%,$@) || cp $@ $(patsubst %-timestamp,%,$@)
+
+$(obj)/generated-helpers.o: $(obj)/generated-helpers.c
+
+target-obj-y += generated-helpers.o
+
+
+$(obj)/generated-tcg-tracers.h: $(obj)/generated-tcg-tracers.h-timestamp
+$(obj)/generated-tcg-tracers.h-timestamp: $(SRC_PATH)/trace-events $(BUILD_DIR)/config-host.mak
+ $(call quiet-command,$(TRACETOOL) \
+ --format=tcg-h \
+ --backend=$(TRACE_BACKENDS) \
+ < $< > $@," GEN $(patsubst %-timestamp,%,$@)")
+ @cmp -s $@ $(patsubst %-timestamp,%,$@) || cp $@ $(patsubst %-timestamp,%,$@)
+
+
######################################################################
# Backend code
diff --git a/translate-all.c b/translate-all.c
index 8f7e11b0a5..2e0265ae27 100644
--- a/translate-all.c
+++ b/translate-all.c
@@ -33,6 +33,7 @@
#include "qemu-common.h"
#define NO_CPU_IO_DEFS
#include "cpu.h"
+#include "trace.h"
#include "disas/disas.h"
#include "tcg.h"
#if defined(CONFIG_USER_ONLY)
@@ -158,6 +159,8 @@ int cpu_gen_code(CPUArchState *env, TranslationBlock *tb, int *gen_code_size_ptr
gen_intermediate_code(env, tb);
+ trace_translate_block(tb, tb->pc, tb->tc_ptr);
+
/* generate machine code */
gen_code_buf = tb->tc_ptr;
tb->tb_next_offset[0] = 0xffff;
diff --git a/ui/spice-core.c b/ui/spice-core.c
index 7bb91e6bad..1a2fb4b237 100644
--- a/ui/spice-core.c
+++ b/ui/spice-core.c
@@ -677,7 +677,7 @@ void qemu_spice_init(void)
if (tls_port) {
x509_dir = qemu_opt_get(opts, "x509-dir");
- if (NULL == x509_dir) {
+ if (!x509_dir) {
x509_dir = ".";
}
@@ -803,7 +803,7 @@ void qemu_spice_init(void)
seamless_migration = qemu_opt_get_bool(opts, "seamless-migration", 0);
spice_server_set_seamless_migration(spice_server, seamless_migration);
- if (0 != spice_server_init(spice_server, &core_interface)) {
+ if (spice_server_init(spice_server, &core_interface) != 0) {
error_report("failed to initialize spice server");
exit(1);
};
diff --git a/ui/vnc.c b/ui/vnc.c
index 548588aab8..f8d9b7db95 100644
--- a/ui/vnc.c
+++ b/ui/vnc.c
@@ -887,6 +887,7 @@ static int find_and_clear_dirty_height(struct VncState *vs,
static int vnc_update_client(VncState *vs, int has_dirty, bool sync)
{
+ vs->has_dirty += has_dirty;
if (vs->need_update && vs->csock != -1) {
VncDisplay *vd = vs->vd;
VncJob *job;
@@ -898,7 +899,7 @@ static int vnc_update_client(VncState *vs, int has_dirty, bool sync)
/* kernel send buffers are full -> drop frames to throttle */
return 0;
- if (!has_dirty && !vs->audio_cap && !vs->force_update)
+ if (!vs->has_dirty && !vs->audio_cap && !vs->force_update)
return 0;
/*
@@ -941,6 +942,7 @@ static int vnc_update_client(VncState *vs, int has_dirty, bool sync)
vnc_jobs_join(vs);
}
vs->force_update = 0;
+ vs->has_dirty = 0;
return n;
}
@@ -1878,6 +1880,7 @@ static void framebuffer_update_request(VncState *vs, int incremental,
return;
}
+ vs->force_update = 1;
vnc_set_area_dirty(vs->dirty, width, height, x, y, w, h);
}
diff --git a/ui/vnc.h b/ui/vnc.h
index 8f582fdc6c..334de9ddb1 100644
--- a/ui/vnc.h
+++ b/ui/vnc.h
@@ -263,6 +263,7 @@ struct VncState
VncDisplay *vd;
int need_update;
int force_update;
+ int has_dirty;
uint32_t features;
int absolute;
int last_x;
diff --git a/util/module.c b/util/module.c
index 214effb39f..4bd4a94d87 100644
--- a/util/module.c
+++ b/util/module.c
@@ -202,18 +202,13 @@ static void module_load(module_init_type type)
for (i = 0; i < ARRAY_SIZE(dirs); i++) {
fname = g_strdup_printf("%s/%s%s", dirs[i], *mp, HOST_DSOSUF);
ret = module_load_file(fname);
+ g_free(fname);
+ fname = NULL;
/* Try loading until loaded a module file */
if (!ret) {
break;
}
- g_free(fname);
- fname = NULL;
- }
- if (ret == -ENOENT) {
- fprintf(stderr, "Can't find module: %s\n", *mp);
}
-
- g_free(fname);
}
for (i = 0; i < ARRAY_SIZE(dirs); i++) {
diff --git a/util/oslib-posix.c b/util/oslib-posix.c
index cdbfb2e270..016a047cfc 100644
--- a/util/oslib-posix.c
+++ b/util/oslib-posix.c
@@ -94,7 +94,7 @@ void *qemu_oom_check(void *ptr)
return ptr;
}
-void *qemu_memalign(size_t alignment, size_t size)
+void *qemu_try_memalign(size_t alignment, size_t size)
{
void *ptr;
@@ -106,19 +106,23 @@ void *qemu_memalign(size_t alignment, size_t size)
int ret;
ret = posix_memalign(&ptr, alignment, size);
if (ret != 0) {
- fprintf(stderr, "Failed to allocate %zu B: %s\n",
- size, strerror(ret));
- abort();
+ errno = ret;
+ ptr = NULL;
}
#elif defined(CONFIG_BSD)
- ptr = qemu_oom_check(valloc(size));
+ ptr = valloc(size);
#else
- ptr = qemu_oom_check(memalign(alignment, size));
+ ptr = memalign(alignment, size);
#endif
trace_qemu_memalign(alignment, size, ptr);
return ptr;
}
+void *qemu_memalign(size_t alignment, size_t size)
+{
+ return qemu_oom_check(qemu_try_memalign(alignment, size));
+}
+
/* alloc shared memory pages */
void *qemu_anon_ram_alloc(size_t size)
{
diff --git a/util/oslib-win32.c b/util/oslib-win32.c
index 507cedd84d..a3eab4acba 100644
--- a/util/oslib-win32.c
+++ b/util/oslib-win32.c
@@ -50,18 +50,23 @@ void *qemu_oom_check(void *ptr)
return ptr;
}
-void *qemu_memalign(size_t alignment, size_t size)
+void *qemu_try_memalign(size_t alignment, size_t size)
{
void *ptr;
if (!size) {
abort();
}
- ptr = qemu_oom_check(VirtualAlloc(NULL, size, MEM_COMMIT, PAGE_READWRITE));
+ ptr = VirtualAlloc(NULL, size, MEM_COMMIT, PAGE_READWRITE);
trace_qemu_memalign(alignment, size, ptr);
return ptr;
}
+void *qemu_memalign(size_t alignment, size_t size)
+{
+ return qemu_oom_check(qemu_try_memalign(alignment, size));
+}
+
void *qemu_anon_ram_alloc(size_t size)
{
void *ptr;
diff --git a/util/qemu-sockets.c b/util/qemu-sockets.c
index 74cf0786e5..5d38395f2d 100644
--- a/util/qemu-sockets.c
+++ b/util/qemu-sockets.c
@@ -732,7 +732,7 @@ int unix_connect_opts(QemuOpts *opts, Error **errp,
ConnectState *connect_state = NULL;
int sock, rc;
- if (NULL == path) {
+ if (path == NULL) {
error_setg(errp, "unix connect: no path specified");
return -1;
}
diff --git a/vl.c b/vl.c
index 6e084c2da2..b796c67e9d 100644
--- a/vl.c
+++ b/vl.c
@@ -183,6 +183,7 @@ uint8_t *boot_splash_filedata;
size_t boot_splash_filedata_size;
uint8_t qemu_extra_params_fw[2];
+int icount_align_option;
typedef struct FWBootEntry FWBootEntry;
struct FWBootEntry {
@@ -537,6 +538,23 @@ static QemuOptsList qemu_mem_opts = {
},
};
+static QemuOptsList qemu_icount_opts = {
+ .name = "icount",
+ .implied_opt_name = "shift",
+ .merge_lists = true,
+ .head = QTAILQ_HEAD_INITIALIZER(qemu_icount_opts.head),
+ .desc = {
+ {
+ .name = "shift",
+ .type = QEMU_OPT_STRING,
+ }, {
+ .name = "align",
+ .type = QEMU_OPT_BOOL,
+ },
+ { /* end of list */ }
+ },
+};
+
/**
* Get machine options
*
@@ -1136,7 +1154,7 @@ static int drive_init_func(QemuOpts *opts, void *opaque)
static int drive_enable_snapshot(QemuOpts *opts, void *opaque)
{
- if (NULL == qemu_opt_get(opts, "snapshot")) {
+ if (qemu_opt_get(opts, "snapshot") == NULL) {
qemu_opt_set(opts, "snapshot", "on");
}
return 0;
@@ -2488,8 +2506,9 @@ static int foreach_device_config(int type, int (*func)(const char *cmdline))
loc_push_restore(&conf->loc);
rc = func(conf->cmdline);
loc_pop(&conf->loc);
- if (0 != rc)
+ if (rc) {
return rc;
+ }
}
return 0;
}
@@ -2823,15 +2842,25 @@ static int object_set_property(const char *name, const char *value, void *opaque
Object *obj = OBJECT(opaque);
StringInputVisitor *siv;
Error *local_err = NULL;
+ char *c, *qom_name;
if (strcmp(name, "qom-type") == 0 || strcmp(name, "id") == 0 ||
strcmp(name, "type") == 0) {
return 0;
}
+ qom_name = g_strdup(name);
+ c = qom_name;
+ while (*c++) {
+ if (*c == '_') {
+ *c = '-';
+ }
+ }
+
siv = string_input_visitor_new(value);
- object_property_set(obj, string_input_get_visitor(siv), name, &local_err);
+ object_property_set(obj, string_input_get_visitor(siv), qom_name, &local_err);
string_input_visitor_cleanup(siv);
+ g_free(qom_name);
if (local_err) {
qerror_report_err(local_err);
@@ -2889,6 +2918,7 @@ out:
g_free(dummy);
if (err) {
qerror_report_err(err);
+ error_free(err);
return -1;
}
return 0;
@@ -2898,13 +2928,12 @@ int main(int argc, char **argv, char **envp)
{
int i;
int snapshot, linux_boot;
- const char *icount_option = NULL;
const char *initrd_filename;
const char *kernel_filename, *kernel_cmdline;
const char *boot_order;
DisplayState *ds;
int cyls, heads, secs, translation;
- QemuOpts *hda_opts = NULL, *opts, *machine_opts;
+ QemuOpts *hda_opts = NULL, *opts, *machine_opts, *icount_opts = NULL;
QemuOptsList *olist;
int optind;
const char *optarg;
@@ -2969,6 +2998,7 @@ int main(int argc, char **argv, char **envp)
qemu_add_opts(&qemu_msg_opts);
qemu_add_opts(&qemu_name_opts);
qemu_add_opts(&qemu_numa_opts);
+ qemu_add_opts(&qemu_icount_opts);
runstate_init();
@@ -3315,6 +3345,7 @@ int main(int argc, char **argv, char **envp)
error_report("ram size too large");
exit(EXIT_FAILURE);
}
+ maxram_size = ram_size;
maxmem_str = qemu_opt_get(opts, "maxmem");
slots_str = qemu_opt_get(opts, "slots");
@@ -3819,7 +3850,11 @@ int main(int argc, char **argv, char **envp)
}
break;
case QEMU_OPTION_icount:
- icount_option = optarg;
+ icount_opts = qemu_opts_parse(qemu_find_opts("icount"),
+ optarg, 1);
+ if (!icount_opts) {
+ exit(1);
+ }
break;
case QEMU_OPTION_incoming:
incoming = optarg;
@@ -4295,11 +4330,14 @@ int main(int argc, char **argv, char **envp)
qemu_spice_init();
#endif
- if (icount_option && (kvm_enabled() || xen_enabled())) {
- fprintf(stderr, "-icount is not allowed with kvm or xen\n");
- exit(1);
+ if (icount_opts) {
+ if (kvm_enabled() || xen_enabled()) {
+ fprintf(stderr, "-icount is not allowed with kvm or xen\n");
+ exit(1);
+ }
+ configure_icount(icount_opts, &error_abort);
+ qemu_opts_del(icount_opts);
}
- configure_icount(icount_option);
/* clean up network at qemu process termination */
atexit(&net_cleanup);
diff --git a/xen-hvm.c b/xen-hvm.c
index c928b36a45..91de2e230b 100644
--- a/xen-hvm.c
+++ b/xen-hvm.c
@@ -165,7 +165,7 @@ static void xen_ram_init(ram_addr_t *below_4g_mem_size,
PC_MACHINE_MAX_RAM_BELOW_4G,
&error_abort);
- /* Handle the machine opt max-ram-below-4g. It is basicly doing
+ /* Handle the machine opt max-ram-below-4g. It is basically doing
* min(xen limit, user limit).
*/
if (HVM_BELOW_4G_RAM_END <= user_lowmem) {
@@ -513,11 +513,14 @@ static void xen_sync_dirty_bitmap(XenIOState *state,
start_addr >> TARGET_PAGE_BITS, npages,
bitmap);
if (rc < 0) {
- if (rc != -ENODATA) {
+#ifndef ENODATA
+#define ENODATA ENOENT
+#endif
+ if (errno == ENODATA) {
memory_region_set_dirty(framebuffer, 0, size);
DPRINTF("xen: track_dirty_vram failed (0x" TARGET_FMT_plx
", 0x" TARGET_FMT_plx "): %s\n",
- start_addr, start_addr + size, strerror(-rc));
+ start_addr, start_addr + size, strerror(errno));
}
return;
}