aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--MAINTAINERS66
-rw-r--r--Makefile9
-rw-r--r--block.c34
-rw-r--r--block/blkdebug.c6
-rw-r--r--block/block-backend.c10
-rw-r--r--block/iscsi.c2
-rw-r--r--block/qcow2-cluster.c11
-rw-r--r--block/qcow2-refcount.c545
-rw-r--r--block/qcow2.c111
-rw-r--r--block/qcow2.h32
-rw-r--r--block/raw-posix.c185
-rw-r--r--block/raw_bsd.c12
-rw-r--r--block/sheepdog.c171
-rw-r--r--block/vdi.c25
-rw-r--r--block/vpc.c60
-rw-r--r--bsd-user/main.c6
-rw-r--r--default-configs/arm-softmmu.mak4
-rw-r--r--exec.c1
-rw-r--r--hw/arm/Makefile.objs2
-rw-r--r--hw/arm/integratorcp.c95
-rw-r--r--hw/arm/netduino2.c57
-rw-r--r--hw/arm/stm32f205_soc.c160
-rw-r--r--hw/arm/vexpress.c6
-rw-r--r--hw/arm/virt.c10
-rw-r--r--hw/block/block.c24
-rw-r--r--hw/block/hd-geometry.c10
-rw-r--r--hw/block/nvme.c1
-rw-r--r--hw/block/pflash_cfi01.c4
-rw-r--r--hw/block/pflash_cfi02.c4
-rw-r--r--hw/block/virtio-blk.c17
-rw-r--r--hw/char/Makefile.objs1
-rw-r--r--hw/char/stm32f2xx_usart.c229
-rw-r--r--hw/char/virtio-serial-bus.c2
-rw-r--r--hw/core/loader.c2
-rw-r--r--hw/core/qdev-properties-system.c22
-rw-r--r--hw/core/qdev-properties.c3
-rw-r--r--hw/i386/pc.c35
-rw-r--r--hw/ide/ahci.c43
-rw-r--r--hw/ide/atapi.c3
-rw-r--r--hw/ide/cmd646.c3
-rw-r--r--hw/ide/core.c116
-rw-r--r--hw/ide/internal.h16
-rw-r--r--hw/ide/isa.c3
-rw-r--r--hw/ide/macio.c6
-rw-r--r--hw/ide/pci.c109
-rw-r--r--hw/ide/pci.h12
-rw-r--r--hw/ide/piix.c3
-rw-r--r--hw/ide/qdev.c1
-rw-r--r--hw/ide/via.c3
-rw-r--r--hw/m68k/dummy_m68k.c6
-rw-r--r--hw/misc/Makefile.objs1
-rw-r--r--hw/misc/stm32f2xx_syscfg.c160
-rw-r--r--hw/ppc/ppc.c161
-rw-r--r--hw/ppc/ppc405_boards.c2
-rw-r--r--hw/ppc/prep.c163
-rw-r--r--hw/s390x/ipl.c24
-rw-r--r--hw/s390x/s390-virtio-bus.c97
-rw-r--r--hw/s390x/s390-virtio-bus.h2
-rw-r--r--hw/s390x/s390-virtio-ccw.c10
-rw-r--r--hw/s390x/virtio-ccw.c134
-rw-r--r--hw/s390x/virtio-ccw.h2
-rw-r--r--hw/scsi/esp-pci.c28
-rw-r--r--hw/scsi/lsi53c895a.c13
-rw-r--r--hw/scsi/megasas.c12
-rw-r--r--hw/scsi/scsi-bus.c6
-rw-r--r--hw/scsi/scsi-disk.c7
-rw-r--r--hw/sparc/sun4m.c10
-rw-r--r--hw/sparc64/sun4u.c20
-rw-r--r--hw/timer/Makefile.objs2
-rw-r--r--hw/timer/m48t59.c359
-rw-r--r--hw/timer/stm32f2xx_timer.c328
-rw-r--r--hw/unicore32/puv3.c6
-rw-r--r--hw/usb/dev-storage.c8
-rw-r--r--include/block/block.h13
-rw-r--r--include/block/block_int.h17
-rw-r--r--include/block/coroutine_int.h1
-rw-r--r--include/elf.h2
-rw-r--r--include/hw/arm/stm32f205_soc.h57
-rw-r--r--include/hw/block/block.h5
-rw-r--r--include/hw/char/stm32f2xx_usart.h73
-rw-r--r--include/hw/elf_ops.h78
-rw-r--r--include/hw/i386/topology.h (renamed from target-i386/topology.h)6
-rw-r--r--include/hw/misc/stm32f2xx_syscfg.h61
-rw-r--r--include/hw/qdev-properties.h8
-rw-r--r--include/hw/timer/m48t59.h61
-rw-r--r--include/hw/timer/stm32f2xx_timer.h101
-rw-r--r--include/qemu/bitops.h2
-rw-r--r--include/qom/cpu.h12
-rw-r--r--include/standard-headers/linux/virtio_net.h54
-rw-r--r--include/sysemu/block-backend.h2
-rw-r--r--include/ui/console.h1
-rw-r--r--linux-headers/asm-arm/kvm.h2
-rw-r--r--linux-headers/asm-arm64/kvm.h9
-rw-r--r--linux-headers/asm-s390/kvm.h37
-rw-r--r--linux-headers/asm-x86/hyperv.h11
-rw-r--r--linux-headers/linux/kvm.h20
-rw-r--r--linux-user/main.c10
-rw-r--r--pc-bios/openbios-ppcbin746588 -> 746588 bytes
-rw-r--r--pc-bios/openbios-sparc32bin381512 -> 381512 bytes
-rw-r--r--pc-bios/openbios-sparc64bin1616768 -> 1616768 bytes
-rw-r--r--pc-bios/s390-ccw.imgbin17752 -> 13616 bytes
-rw-r--r--pc-bios/s390-ccw/Makefile11
-rw-r--r--pc-bios/s390-ccw/main.c1
-rw-r--r--pc-bios/s390-ccw/s390-ccw.h1
-rw-r--r--pc-bios/s390-ccw/virtio.c5
-rw-r--r--qapi/block-core.json5
-rw-r--r--qemu-coroutine.c38
-rw-r--r--qemu-doc.texi7
-rw-r--r--qmp.c1
m---------roms/openbios0
-rwxr-xr-xscripts/kvm/kvm_stat5
-rw-r--r--scripts/kvm/kvm_stat.texi55
-rw-r--r--target-alpha/cpu.h9
-rw-r--r--target-arm/cpu.h9
-rw-r--r--target-arm/cpu64.c1
-rw-r--r--target-cris/cpu.h9
-rw-r--r--target-i386/cpu-qom.h1
-rw-r--r--target-i386/cpu.c130
-rw-r--r--target-i386/cpu.h11
-rw-r--r--target-i386/kvm.c2
-rw-r--r--target-i386/seg_helper.c4
-rw-r--r--target-lm32/cpu.h9
-rw-r--r--target-m68k/cpu.h9
-rw-r--r--target-microblaze/cpu.h9
-rw-r--r--target-mips/cpu-qom.h4
-rw-r--r--target-mips/cpu.c1
-rw-r--r--target-mips/cpu.h28
-rw-r--r--target-mips/machine.c571
-rw-r--r--target-mips/msa_helper.c12
-rw-r--r--target-mips/translate_init.c10
-rw-r--r--target-moxie/cpu.h9
-rw-r--r--target-openrisc/cpu.h9
-rw-r--r--target-ppc/cpu.h9
-rw-r--r--target-s390x/cpu.c2
-rw-r--r--target-s390x/cpu.h42
-rw-r--r--target-s390x/helper.c35
-rw-r--r--target-s390x/kvm.c416
-rw-r--r--target-s390x/machine.c5
-rw-r--r--target-s390x/misc_helper.c4
-rw-r--r--target-sh4/cpu.h9
-rw-r--r--target-sparc/cpu.h9
-rw-r--r--target-tricore/cpu.h10
-rw-r--r--target-unicore32/cpu.h6
-rw-r--r--target-unicore32/helper.c10
-rw-r--r--target-xtensa/cpu.h9
-rw-r--r--tests/Makefile6
-rw-r--r--tests/ahci-test.c234
-rw-r--r--tests/ide-test.c20
-rw-r--r--tests/libqos/ahci.c44
-rw-r--r--tests/libqos/ahci.h5
-rw-r--r--tests/libqos/malloc-generic.c39
-rw-r--r--tests/libqos/malloc-generic.h21
-rw-r--r--tests/libqos/virtio-mmio.c198
-rw-r--r--tests/libqos/virtio-mmio.h46
-rw-r--r--tests/libqos/virtio-pci.c66
-rw-r--r--tests/libqos/virtio-pci.h24
-rw-r--r--tests/libqos/virtio.c8
-rw-r--r--tests/libqos/virtio.h16
-rwxr-xr-xtests/qemu-iotests/0042
-rw-r--r--tests/qemu-iotests/006.out6
-rwxr-xr-xtests/qemu-iotests/0073
-rwxr-xr-xtests/qemu-iotests/0152
-rwxr-xr-xtests/qemu-iotests/0267
-rw-r--r--tests/qemu-iotests/026.out24
-rwxr-xr-xtests/qemu-iotests/0292
-rw-r--r--tests/qemu-iotests/049.out108
-rwxr-xr-xtests/qemu-iotests/0519
-rw-r--r--tests/qemu-iotests/051.out17
-rwxr-xr-xtests/qemu-iotests/0582
-rw-r--r--tests/qemu-iotests/060.out1
-rwxr-xr-xtests/qemu-iotests/06523
-rwxr-xr-xtests/qemu-iotests/0672
-rw-r--r--tests/qemu-iotests/067.out5
-rwxr-xr-xtests/qemu-iotests/07910
-rw-r--r--tests/qemu-iotests/079.out38
-rwxr-xr-xtests/qemu-iotests/0802
-rw-r--r--tests/qemu-iotests/082.out48
-rw-r--r--tests/qemu-iotests/085.out38
-rwxr-xr-xtests/qemu-iotests/0892
-rw-r--r--tests/qemu-iotests/089.out2
-rwxr-xr-xtests/qemu-iotests/1042
-rwxr-xr-xtests/qemu-iotests/1082
-rwxr-xr-xtests/qemu-iotests/112187
-rw-r--r--tests/qemu-iotests/112.out84
-rwxr-xr-xtests/qemu-iotests/128 (renamed from tests/qemu-iotests/006)46
-rw-r--r--tests/qemu-iotests/128.out5
-rw-r--r--tests/qemu-iotests/common.filter3
-rw-r--r--tests/qemu-iotests/group4
-rw-r--r--tests/test-coroutine.c26
-rw-r--r--tests/test-x86-cpuid.c2
-rw-r--r--tests/virtio-blk-test.c329
-rw-r--r--trace-events1
-rw-r--r--ui/vnc-ws.c3
-rw-r--r--ui/vnc.c22
-rw-r--r--util/qemu-thread-posix.c6
-rw-r--r--util/rcu.c33
-rw-r--r--vl.c7
197 files changed, 5830 insertions, 2050 deletions
diff --git a/MAINTAINERS b/MAINTAINERS
index 50343e9a7..d7e9ba2da 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -157,6 +157,7 @@ F: hw/sh4/
SPARC
M: Blue Swirl <blauwirbel@gmail.com>
+M: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
S: Maintained
F: target-sparc/
F: hw/sparc/
@@ -516,11 +517,13 @@ SPARC Machines
--------------
Sun4m
M: Blue Swirl <blauwirbel@gmail.com>
+M: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
S: Maintained
F: hw/sparc/sun4m.c
Sun4u
M: Blue Swirl <blauwirbel@gmail.com>
+M: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
S: Maintained
F: hw/sparc64/sun4u.c
@@ -602,11 +605,25 @@ S: Maintained
F: hw/misc/edu.c
IDE
-M: Kevin Wolf <kwolf@redhat.com>
-M: Stefan Hajnoczi <stefanha@redhat.com>
-S: Odd Fixes
+M: John Snow <jsnow@redhat.com>
+L: qemu-block@nongnu.org
+S: Supported
F: include/hw/ide.h
F: hw/ide/
+F: hw/block/block.c
+F: hw/block/cdrom.c
+F: hw/block/hd-geometry.c
+F: tests/ide-test.c
+F: tests/ahci-test.c
+T: git git://github.com/jnsnow/qemu.git ide
+
+Floppy
+M: John Snow <jsnow@redhat.com>
+L: qemu-block@nongnu.org
+S: Supported
+F: hw/block/fdc.c
+F: include/hw/block/fdc.h
+T: git git://github.com/jnsnow/qemu.git ide
OMAP
M: Peter Maydell <peter.maydell@linaro.org>
@@ -766,6 +783,18 @@ F: tests/qemu-iotests/
T: git git://repo.or.cz/qemu/kevin.git block
T: git git://github.com/stefanha/qemu.git block
+Block Jobs
+M: Jeff Cody <jcody@redhat.com>
+L: qemu-block@nongnu.org
+S: Supported
+F: blockjob.c
+F: include/block/blockjob.h
+F: block/backup.c
+F: block/commit.c
+F: block/stream.h
+F: block/mirror.c
+T: git git://github.com/codyprime/qemu-kvm-jtc.git block
+
Character Devices
M: Paolo Bonzini <pbonzini@redhat.com>
S: Maintained
@@ -1070,20 +1099,28 @@ F: block/vmdk.c
RBD
M: Josh Durgin <josh.durgin@inktank.com>
+M: Jeff Cody <jcody@redhat.com>
+L: qemu-block@nongnu.org
S: Supported
F: block/rbd.c
+T: git git://github.com/codyprime/qemu-kvm-jtc.git block
Sheepdog
M: Hitoshi Mitake <mitake.hitoshi@lab.ntt.co.jp>
M: Liu Yuan <namei.unix@gmail.com>
+M: Jeff Cody <jcody@redhat.com>
+L: qemu-block@nongnu.org
L: sheepdog@lists.wpkg.org
S: Supported
F: block/sheepdog.c
+T: git git://github.com/codyprime/qemu-kvm-jtc.git block
VHDX
M: Jeff Cody <jcody@redhat.com>
+L: qemu-block@nongnu.org
S: Supported
F: block/vhdx*
+T: git git://github.com/codyprime/qemu-kvm-jtc.git block
VDI
M: Stefan Weil <sw@weilnetz.de>
@@ -1098,19 +1135,42 @@ S: Supported
F: block/iscsi.c
NFS
+M: Jeff Cody <jcody@redhat.com>
M: Peter Lieven <pl@kamp.de>
+L: qemu-block@nongnu.org
S: Maintained
F: block/nfs.c
+T: git git://github.com/codyprime/qemu-kvm-jtc.git block
SSH
M: Richard W.M. Jones <rjones@redhat.com>
+M: Jeff Cody <jcody@redhat.com>
+L: qemu-block@nongnu.org
S: Supported
F: block/ssh.c
+T: git git://github.com/codyprime/qemu-kvm-jtc.git block
ARCHIPELAGO
M: Chrysostomos Nanakos <chris@include.gr>
+M: Jeff Cody <jcody@redhat.com>
+L: qemu-block@nongnu.org
S: Maintained
F: block/archipelago.c
+T: git git://github.com/codyprime/qemu-kvm-jtc.git block
+
+CURL
+M: Jeff Cody <jcody@redhat.com>
+L: qemu-block@nongnu.org
+S: Supported
+F: block/curl.c
+T: git git://github.com/codyprime/qemu-kvm-jtc.git block
+
+GLUSTER
+M: Jeff Cody <jcody@redhat.com>
+L: qemu-block@nongnu.org
+S: Supported
+F: block/gluster.c
+T: git git://github.com/codyprime/qemu-kvm-jtc.git block
Bootdevice
M: Gonglei <arei.gonglei@huawei.com>
diff --git a/Makefile b/Makefile
index d92d4cd57..884b59dc0 100644
--- a/Makefile
+++ b/Makefile
@@ -84,6 +84,9 @@ HELPERS-$(CONFIG_LINUX) = qemu-bridge-helper$(EXESUF)
ifdef BUILD_DOCS
DOCS=qemu-doc.html qemu-tech.html qemu.1 qemu-img.1 qemu-nbd.8 qmp-commands.txt
+ifdef CONFIG_LINUX
+DOCS+=kvm_stat.1
+endif
ifdef CONFIG_VIRTFS
DOCS+=fsdev/virtfs-proxy-helper.1
endif
@@ -490,6 +493,12 @@ qemu-nbd.8: qemu-nbd.texi
$(POD2MAN) --section=8 --center=" " --release=" " qemu-nbd.pod > $@, \
" GEN $@")
+kvm_stat.1: scripts/kvm/kvm_stat.texi
+ $(call quiet-command, \
+ perl -Ww -- $(SRC_PATH)/scripts/texi2pod.pl $< kvm_stat.pod && \
+ $(POD2MAN) --section=1 --center=" " --release=" " kvm_stat.pod > $@, \
+ " GEN $@")
+
dvi: qemu-doc.dvi qemu-tech.dvi
html: qemu-doc.html qemu-tech.html
info: qemu-doc.info qemu-tech.info
diff --git a/block.c b/block.c
index 28ea19aaf..191a84794 100644
--- a/block.c
+++ b/block.c
@@ -568,6 +568,40 @@ void bdrv_refresh_limits(BlockDriverState *bs, Error **errp)
}
}
+/**
+ * Try to get @bs's logical and physical block size.
+ * On success, store them in @bsz struct and return 0.
+ * On failure return -errno.
+ * @bs must not be empty.
+ */
+int bdrv_probe_blocksizes(BlockDriverState *bs, BlockSizes *bsz)
+{
+ BlockDriver *drv = bs->drv;
+
+ if (drv && drv->bdrv_probe_blocksizes) {
+ return drv->bdrv_probe_blocksizes(bs, bsz);
+ }
+
+ return -ENOTSUP;
+}
+
+/**
+ * Try to get @bs's geometry (cyls, heads, sectors).
+ * On success, store them in @geo struct and return 0.
+ * On failure return -errno.
+ * @bs must not be empty.
+ */
+int bdrv_probe_geometry(BlockDriverState *bs, HDGeometry *geo)
+{
+ BlockDriver *drv = bs->drv;
+
+ if (drv && drv->bdrv_probe_geometry) {
+ return drv->bdrv_probe_geometry(bs, geo);
+ }
+
+ return -ENOTSUP;
+}
+
/*
* Create a uniquely-named empty temporary file.
* Return 0 upon success, otherwise a negative errno value.
diff --git a/block/blkdebug.c b/block/blkdebug.c
index 9ce35cd03..63611e0a3 100644
--- a/block/blkdebug.c
+++ b/block/blkdebug.c
@@ -472,12 +472,14 @@ static BlockAIOCB *inject_error(BlockDriverState *bs,
int error = rule->options.inject.error;
struct BlkdebugAIOCB *acb;
QEMUBH *bh;
+ bool immediately = rule->options.inject.immediately;
if (rule->options.inject.once) {
- QSIMPLEQ_INIT(&s->active_rules);
+ QSIMPLEQ_REMOVE(&s->active_rules, rule, BlkdebugRule, active_next);
+ remove_rule(rule);
}
- if (rule->options.inject.immediately) {
+ if (immediately) {
return NULL;
}
diff --git a/block/block-backend.c b/block/block-backend.c
index bfb041823..48b6e4c05 100644
--- a/block/block-backend.c
+++ b/block/block-backend.c
@@ -892,3 +892,13 @@ int blk_load_vmstate(BlockBackend *blk, uint8_t *buf, int64_t pos, int size)
{
return bdrv_load_vmstate(blk->bs, buf, pos, size);
}
+
+int blk_probe_blocksizes(BlockBackend *blk, BlockSizes *bsz)
+{
+ return bdrv_probe_blocksizes(blk->bs, bsz);
+}
+
+int blk_probe_geometry(BlockBackend *blk, HDGeometry *geo)
+{
+ return bdrv_probe_geometry(blk->bs, geo);
+}
diff --git a/block/iscsi.c b/block/iscsi.c
index 1fa855acd..3e34b1f3a 100644
--- a/block/iscsi.c
+++ b/block/iscsi.c
@@ -1326,7 +1326,7 @@ static int iscsi_open(BlockDriverState *bs, QDict *options, int flags,
goto out;
}
- if (iscsi_url->user != NULL) {
+ if (iscsi_url->user[0] != '\0') {
ret = iscsi_set_initiator_username_pwd(iscsi, iscsi_url->user,
iscsi_url->passwd);
if (ret != 0) {
diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c
index 183177d51..ed2b44d29 100644
--- a/block/qcow2-cluster.c
+++ b/block/qcow2-cluster.c
@@ -1640,7 +1640,7 @@ static int expand_zero_clusters_in_l1(BlockDriverState *bs, uint64_t *l1_table,
for (i = 0; i < l1_size; i++) {
uint64_t l2_offset = l1_table[i] & L1E_OFFSET_MASK;
bool l2_dirty = false;
- int l2_refcount;
+ uint64_t l2_refcount;
if (!l2_offset) {
/* unallocated */
@@ -1672,9 +1672,9 @@ static int expand_zero_clusters_in_l1(BlockDriverState *bs, uint64_t *l1_table,
goto fail;
}
- l2_refcount = qcow2_get_refcount(bs, l2_offset >> s->cluster_bits);
- if (l2_refcount < 0) {
- ret = l2_refcount;
+ ret = qcow2_get_refcount(bs, l2_offset >> s->cluster_bits,
+ &l2_refcount);
+ if (ret < 0) {
goto fail;
}
@@ -1707,7 +1707,8 @@ static int expand_zero_clusters_in_l1(BlockDriverState *bs, uint64_t *l1_table,
/* For shared L2 tables, set the refcount accordingly (it is
* already 1 and needs to be l2_refcount) */
ret = qcow2_update_cluster_refcount(bs,
- offset >> s->cluster_bits, l2_refcount - 1,
+ offset >> s->cluster_bits,
+ refcount_diff(1, l2_refcount), false,
QCOW2_DISCARD_OTHER);
if (ret < 0) {
qcow2_free_clusters(bs, offset, s->cluster_size,
diff --git a/block/qcow2-refcount.c b/block/qcow2-refcount.c
index 9b80ca79e..dc8d186a8 100644
--- a/block/qcow2-refcount.c
+++ b/block/qcow2-refcount.c
@@ -29,8 +29,52 @@
static int64_t alloc_clusters_noref(BlockDriverState *bs, uint64_t size);
static int QEMU_WARN_UNUSED_RESULT update_refcount(BlockDriverState *bs,
- int64_t offset, int64_t length,
- int addend, enum qcow2_discard_type type);
+ int64_t offset, int64_t length, uint64_t addend,
+ bool decrease, enum qcow2_discard_type type);
+
+static uint64_t get_refcount_ro0(const void *refcount_array, uint64_t index);
+static uint64_t get_refcount_ro1(const void *refcount_array, uint64_t index);
+static uint64_t get_refcount_ro2(const void *refcount_array, uint64_t index);
+static uint64_t get_refcount_ro3(const void *refcount_array, uint64_t index);
+static uint64_t get_refcount_ro4(const void *refcount_array, uint64_t index);
+static uint64_t get_refcount_ro5(const void *refcount_array, uint64_t index);
+static uint64_t get_refcount_ro6(const void *refcount_array, uint64_t index);
+
+static void set_refcount_ro0(void *refcount_array, uint64_t index,
+ uint64_t value);
+static void set_refcount_ro1(void *refcount_array, uint64_t index,
+ uint64_t value);
+static void set_refcount_ro2(void *refcount_array, uint64_t index,
+ uint64_t value);
+static void set_refcount_ro3(void *refcount_array, uint64_t index,
+ uint64_t value);
+static void set_refcount_ro4(void *refcount_array, uint64_t index,
+ uint64_t value);
+static void set_refcount_ro5(void *refcount_array, uint64_t index,
+ uint64_t value);
+static void set_refcount_ro6(void *refcount_array, uint64_t index,
+ uint64_t value);
+
+
+static Qcow2GetRefcountFunc *const get_refcount_funcs[] = {
+ &get_refcount_ro0,
+ &get_refcount_ro1,
+ &get_refcount_ro2,
+ &get_refcount_ro3,
+ &get_refcount_ro4,
+ &get_refcount_ro5,
+ &get_refcount_ro6
+};
+
+static Qcow2SetRefcountFunc *const set_refcount_funcs[] = {
+ &set_refcount_ro0,
+ &set_refcount_ro1,
+ &set_refcount_ro2,
+ &set_refcount_ro3,
+ &set_refcount_ro4,
+ &set_refcount_ro5,
+ &set_refcount_ro6
+};
/*********************************************************/
@@ -42,6 +86,11 @@ int qcow2_refcount_init(BlockDriverState *bs)
unsigned int refcount_table_size2, i;
int ret;
+ assert(s->refcount_order >= 0 && s->refcount_order <= 6);
+
+ s->get_refcount = get_refcount_funcs[s->refcount_order];
+ s->set_refcount = set_refcount_funcs[s->refcount_order];
+
assert(s->refcount_table_size <= INT_MAX / sizeof(uint64_t));
refcount_table_size2 = s->refcount_table_size * sizeof(uint64_t);
s->refcount_table = g_try_malloc(refcount_table_size2);
@@ -72,6 +121,95 @@ void qcow2_refcount_close(BlockDriverState *bs)
}
+static uint64_t get_refcount_ro0(const void *refcount_array, uint64_t index)
+{
+ return (((const uint8_t *)refcount_array)[index / 8] >> (index % 8)) & 0x1;
+}
+
+static void set_refcount_ro0(void *refcount_array, uint64_t index,
+ uint64_t value)
+{
+ assert(!(value >> 1));
+ ((uint8_t *)refcount_array)[index / 8] &= ~(0x1 << (index % 8));
+ ((uint8_t *)refcount_array)[index / 8] |= value << (index % 8);
+}
+
+static uint64_t get_refcount_ro1(const void *refcount_array, uint64_t index)
+{
+ return (((const uint8_t *)refcount_array)[index / 4] >> (2 * (index % 4)))
+ & 0x3;
+}
+
+static void set_refcount_ro1(void *refcount_array, uint64_t index,
+ uint64_t value)
+{
+ assert(!(value >> 2));
+ ((uint8_t *)refcount_array)[index / 4] &= ~(0x3 << (2 * (index % 4)));
+ ((uint8_t *)refcount_array)[index / 4] |= value << (2 * (index % 4));
+}
+
+static uint64_t get_refcount_ro2(const void *refcount_array, uint64_t index)
+{
+ return (((const uint8_t *)refcount_array)[index / 2] >> (4 * (index % 2)))
+ & 0xf;
+}
+
+static void set_refcount_ro2(void *refcount_array, uint64_t index,
+ uint64_t value)
+{
+ assert(!(value >> 4));
+ ((uint8_t *)refcount_array)[index / 2] &= ~(0xf << (4 * (index % 2)));
+ ((uint8_t *)refcount_array)[index / 2] |= value << (4 * (index % 2));
+}
+
+static uint64_t get_refcount_ro3(const void *refcount_array, uint64_t index)
+{
+ return ((const uint8_t *)refcount_array)[index];
+}
+
+static void set_refcount_ro3(void *refcount_array, uint64_t index,
+ uint64_t value)
+{
+ assert(!(value >> 8));
+ ((uint8_t *)refcount_array)[index] = value;
+}
+
+static uint64_t get_refcount_ro4(const void *refcount_array, uint64_t index)
+{
+ return be16_to_cpu(((const uint16_t *)refcount_array)[index]);
+}
+
+static void set_refcount_ro4(void *refcount_array, uint64_t index,
+ uint64_t value)
+{
+ assert(!(value >> 16));
+ ((uint16_t *)refcount_array)[index] = cpu_to_be16(value);
+}
+
+static uint64_t get_refcount_ro5(const void *refcount_array, uint64_t index)
+{
+ return be32_to_cpu(((const uint32_t *)refcount_array)[index]);
+}
+
+static void set_refcount_ro5(void *refcount_array, uint64_t index,
+ uint64_t value)
+{
+ assert(!(value >> 32));
+ ((uint32_t *)refcount_array)[index] = cpu_to_be32(value);
+}
+
+static uint64_t get_refcount_ro6(const void *refcount_array, uint64_t index)
+{
+ return be64_to_cpu(((const uint64_t *)refcount_array)[index]);
+}
+
+static void set_refcount_ro6(void *refcount_array, uint64_t index,
+ uint64_t value)
+{
+ ((uint64_t *)refcount_array)[index] = cpu_to_be64(value);
+}
+
+
static int load_refcount_block(BlockDriverState *bs,
int64_t refcount_block_offset,
void **refcount_block)
@@ -87,26 +225,29 @@ static int load_refcount_block(BlockDriverState *bs,
}
/*
- * Returns the refcount of the cluster given by its index. Any non-negative
- * return value is the refcount of the cluster, negative values are -errno
- * and indicate an error.
+ * Retrieves the refcount of the cluster given by its index and stores it in
+ * *refcount. Returns 0 on success and -errno on failure.
*/
-int qcow2_get_refcount(BlockDriverState *bs, int64_t cluster_index)
+int qcow2_get_refcount(BlockDriverState *bs, int64_t cluster_index,
+ uint64_t *refcount)
{
BDRVQcowState *s = bs->opaque;
uint64_t refcount_table_index, block_index;
int64_t refcount_block_offset;
int ret;
- uint16_t *refcount_block;
- uint16_t refcount;
+ void *refcount_block;
refcount_table_index = cluster_index >> s->refcount_block_bits;
- if (refcount_table_index >= s->refcount_table_size)
+ if (refcount_table_index >= s->refcount_table_size) {
+ *refcount = 0;
return 0;
+ }
refcount_block_offset =
s->refcount_table[refcount_table_index] & REFT_OFFSET_MASK;
- if (!refcount_block_offset)
+ if (!refcount_block_offset) {
+ *refcount = 0;
return 0;
+ }
if (offset_into_cluster(s, refcount_block_offset)) {
qcow2_signal_corruption(bs, true, -1, -1, "Refblock offset %#" PRIx64
@@ -116,21 +257,20 @@ int qcow2_get_refcount(BlockDriverState *bs, int64_t cluster_index)
}
ret = qcow2_cache_get(bs, s->refcount_block_cache, refcount_block_offset,
- (void**) &refcount_block);
+ &refcount_block);
if (ret < 0) {
return ret;
}
block_index = cluster_index & (s->refcount_block_size - 1);
- refcount = be16_to_cpu(refcount_block[block_index]);
+ *refcount = s->get_refcount(refcount_block, block_index);
- ret = qcow2_cache_put(bs, s->refcount_block_cache,
- (void**) &refcount_block);
+ ret = qcow2_cache_put(bs, s->refcount_block_cache, &refcount_block);
if (ret < 0) {
return ret;
}
- return refcount;
+ return 0;
}
/*
@@ -169,7 +309,7 @@ static int in_same_refcount_block(BDRVQcowState *s, uint64_t offset_a,
* Returns 0 on success or -errno in error case
*/
static int alloc_refcount_block(BlockDriverState *bs,
- int64_t cluster_index, uint16_t **refcount_block)
+ int64_t cluster_index, void **refcount_block)
{
BDRVQcowState *s = bs->opaque;
unsigned int refcount_table_index;
@@ -196,7 +336,7 @@ static int alloc_refcount_block(BlockDriverState *bs,
}
return load_refcount_block(bs, refcount_block_offset,
- (void**) refcount_block);
+ refcount_block);
}
}
@@ -246,7 +386,7 @@ static int alloc_refcount_block(BlockDriverState *bs,
if (in_same_refcount_block(s, new_block, cluster_index << s->cluster_bits)) {
/* Zero the new refcount block before updating it */
ret = qcow2_cache_get_empty(bs, s->refcount_block_cache, new_block,
- (void**) refcount_block);
+ refcount_block);
if (ret < 0) {
goto fail_block;
}
@@ -256,11 +396,11 @@ static int alloc_refcount_block(BlockDriverState *bs,
/* The block describes itself, need to update the cache */
int block_index = (new_block >> s->cluster_bits) &
(s->refcount_block_size - 1);
- (*refcount_block)[block_index] = cpu_to_be16(1);
+ s->set_refcount(*refcount_block, block_index, 1);
} else {
/* Described somewhere else. This can recurse at most twice before we
* arrive at a block that describes itself. */
- ret = update_refcount(bs, new_block, s->cluster_size, 1,
+ ret = update_refcount(bs, new_block, s->cluster_size, 1, false,
QCOW2_DISCARD_NEVER);
if (ret < 0) {
goto fail_block;
@@ -274,7 +414,7 @@ static int alloc_refcount_block(BlockDriverState *bs,
/* Initialize the new refcount block only after updating its refcount,
* update_refcount uses the refcount cache itself */
ret = qcow2_cache_get_empty(bs, s->refcount_block_cache, new_block,
- (void**) refcount_block);
+ refcount_block);
if (ret < 0) {
goto fail_block;
}
@@ -308,7 +448,7 @@ static int alloc_refcount_block(BlockDriverState *bs,
return -EAGAIN;
}
- ret = qcow2_cache_put(bs, s->refcount_block_cache, (void**) refcount_block);
+ ret = qcow2_cache_put(bs, s->refcount_block_cache, refcount_block);
if (ret < 0) {
goto fail_block;
}
@@ -362,7 +502,7 @@ static int alloc_refcount_block(BlockDriverState *bs,
s->cluster_size;
uint64_t table_offset = meta_offset + blocks_clusters * s->cluster_size;
uint64_t *new_table = g_try_new0(uint64_t, table_size);
- uint16_t *new_blocks = g_try_malloc0(blocks_clusters * s->cluster_size);
+ void *new_blocks = g_try_malloc0(blocks_clusters * s->cluster_size);
assert(table_size > 0 && blocks_clusters > 0);
if (new_table == NULL || new_blocks == NULL) {
@@ -384,7 +524,7 @@ static int alloc_refcount_block(BlockDriverState *bs,
uint64_t table_clusters = size_to_clusters(s, table_size * sizeof(uint64_t));
int block = 0;
for (i = 0; i < table_clusters + blocks_clusters; i++) {
- new_blocks[block++] = cpu_to_be16(1);
+ s->set_refcount(new_blocks, block++, 1);
}
/* Write refcount blocks to disk */
@@ -437,7 +577,7 @@ static int alloc_refcount_block(BlockDriverState *bs,
qcow2_free_clusters(bs, old_table_offset, old_table_size * sizeof(uint64_t),
QCOW2_DISCARD_OTHER);
- ret = load_refcount_block(bs, new_block, (void**) refcount_block);
+ ret = load_refcount_block(bs, new_block, refcount_block);
if (ret < 0) {
return ret;
}
@@ -452,7 +592,7 @@ fail_table:
g_free(new_table);
fail_block:
if (*refcount_block != NULL) {
- qcow2_cache_put(bs, s->refcount_block_cache, (void**) refcount_block);
+ qcow2_cache_put(bs, s->refcount_block_cache, refcount_block);
}
return ret;
}
@@ -527,18 +667,25 @@ found:
}
/* XXX: cache several refcount block clusters ? */
+/* @addend is the absolute value of the addend; if @decrease is set, @addend
+ * will be subtracted from the current refcount, otherwise it will be added */
static int QEMU_WARN_UNUSED_RESULT update_refcount(BlockDriverState *bs,
- int64_t offset, int64_t length, int addend, enum qcow2_discard_type type)
+ int64_t offset,
+ int64_t length,
+ uint64_t addend,
+ bool decrease,
+ enum qcow2_discard_type type)
{
BDRVQcowState *s = bs->opaque;
int64_t start, last, cluster_offset;
- uint16_t *refcount_block = NULL;
+ void *refcount_block = NULL;
int64_t old_table_index = -1;
int ret;
#ifdef DEBUG_ALLOC2
- fprintf(stderr, "update_refcount: offset=%" PRId64 " size=%" PRId64 " addend=%d\n",
- offset, length, addend);
+ fprintf(stderr, "update_refcount: offset=%" PRId64 " size=%" PRId64
+ " addend=%s%" PRIu64 "\n", offset, length, decrease ? "-" : "",
+ addend);
#endif
if (length < 0) {
return -EINVAL;
@@ -546,7 +693,7 @@ static int QEMU_WARN_UNUSED_RESULT update_refcount(BlockDriverState *bs,
return 0;
}
- if (addend < 0) {
+ if (decrease) {
qcow2_cache_set_dependency(bs, s->refcount_block_cache,
s->l2_table_cache);
}
@@ -556,7 +703,8 @@ static int QEMU_WARN_UNUSED_RESULT update_refcount(BlockDriverState *bs,
for(cluster_offset = start; cluster_offset <= last;
cluster_offset += s->cluster_size)
{
- int block_index, refcount;
+ int block_index;
+ uint64_t refcount;
int64_t cluster_index = cluster_offset >> s->cluster_bits;
int64_t table_index = cluster_index >> s->refcount_block_bits;
@@ -564,7 +712,7 @@ static int QEMU_WARN_UNUSED_RESULT update_refcount(BlockDriverState *bs,
if (table_index != old_table_index) {
if (refcount_block) {
ret = qcow2_cache_put(bs, s->refcount_block_cache,
- (void**) &refcount_block);
+ &refcount_block);
if (ret < 0) {
goto fail;
}
@@ -582,16 +730,23 @@ static int QEMU_WARN_UNUSED_RESULT update_refcount(BlockDriverState *bs,
/* we can update the count and save it */
block_index = cluster_index & (s->refcount_block_size - 1);
- refcount = be16_to_cpu(refcount_block[block_index]);
- refcount += addend;
- if (refcount < 0 || refcount > 0xffff) {
+ refcount = s->get_refcount(refcount_block, block_index);
+ if (decrease ? (refcount - addend > refcount)
+ : (refcount + addend < refcount ||
+ refcount + addend > s->refcount_max))
+ {
ret = -EINVAL;
goto fail;
}
+ if (decrease) {
+ refcount -= addend;
+ } else {
+ refcount += addend;
+ }
if (refcount == 0 && cluster_index < s->free_cluster_index) {
s->free_cluster_index = cluster_index;
}
- refcount_block[block_index] = cpu_to_be16(refcount);
+ s->set_refcount(refcount_block, block_index, refcount);
if (refcount == 0 && s->discard_passthrough[type]) {
update_refcount_discard(bs, cluster_offset, s->cluster_size);
@@ -607,8 +762,7 @@ fail:
/* Write last changed block to disk */
if (refcount_block) {
int wret;
- wret = qcow2_cache_put(bs, s->refcount_block_cache,
- (void**) &refcount_block);
+ wret = qcow2_cache_put(bs, s->refcount_block_cache, &refcount_block);
if (wret < 0) {
return ret < 0 ? ret : wret;
}
@@ -620,8 +774,8 @@ fail:
*/
if (ret < 0) {
int dummy;
- dummy = update_refcount(bs, offset, cluster_offset - offset, -addend,
- QCOW2_DISCARD_NEVER);
+ dummy = update_refcount(bs, offset, cluster_offset - offset, addend,
+ !decrease, QCOW2_DISCARD_NEVER);
(void)dummy;
}
@@ -631,24 +785,26 @@ fail:
/*
* Increases or decreases the refcount of a given cluster.
*
- * If the return value is non-negative, it is the new refcount of the cluster.
- * If it is negative, it is -errno and indicates an error.
+ * @addend is the absolute value of the addend; if @decrease is set, @addend
+ * will be subtracted from the current refcount, otherwise it will be added.
+ *
+ * On success 0 is returned; on failure -errno is returned.
*/
int qcow2_update_cluster_refcount(BlockDriverState *bs,
int64_t cluster_index,
- int addend,
+ uint64_t addend, bool decrease,
enum qcow2_discard_type type)
{
BDRVQcowState *s = bs->opaque;
int ret;
ret = update_refcount(bs, cluster_index << s->cluster_bits, 1, addend,
- type);
+ decrease, type);
if (ret < 0) {
return ret;
}
- return qcow2_get_refcount(bs, cluster_index);
+ return 0;
}
@@ -662,17 +818,17 @@ int qcow2_update_cluster_refcount(BlockDriverState *bs,
static int64_t alloc_clusters_noref(BlockDriverState *bs, uint64_t size)
{
BDRVQcowState *s = bs->opaque;
- uint64_t i, nb_clusters;
- int refcount;
+ uint64_t i, nb_clusters, refcount;
+ int ret;
nb_clusters = size_to_clusters(s, size);
retry:
for(i = 0; i < nb_clusters; i++) {
uint64_t next_cluster_index = s->free_cluster_index++;
- refcount = qcow2_get_refcount(bs, next_cluster_index);
+ ret = qcow2_get_refcount(bs, next_cluster_index, &refcount);
- if (refcount < 0) {
- return refcount;
+ if (ret < 0) {
+ return ret;
} else if (refcount != 0) {
goto retry;
}
@@ -706,7 +862,7 @@ int64_t qcow2_alloc_clusters(BlockDriverState *bs, uint64_t size)
return offset;
}
- ret = update_refcount(bs, offset, size, 1, QCOW2_DISCARD_NEVER);
+ ret = update_refcount(bs, offset, size, 1, false, QCOW2_DISCARD_NEVER);
} while (ret == -EAGAIN);
if (ret < 0) {
@@ -720,9 +876,9 @@ int qcow2_alloc_clusters_at(BlockDriverState *bs, uint64_t offset,
int nb_clusters)
{
BDRVQcowState *s = bs->opaque;
- uint64_t cluster_index;
+ uint64_t cluster_index, refcount;
uint64_t i;
- int refcount, ret;
+ int ret;
assert(nb_clusters >= 0);
if (nb_clusters == 0) {
@@ -733,17 +889,16 @@ int qcow2_alloc_clusters_at(BlockDriverState *bs, uint64_t offset,
/* Check how many clusters there are free */
cluster_index = offset >> s->cluster_bits;
for(i = 0; i < nb_clusters; i++) {
- refcount = qcow2_get_refcount(bs, cluster_index++);
-
- if (refcount < 0) {
- return refcount;
+ ret = qcow2_get_refcount(bs, cluster_index++, &refcount);
+ if (ret < 0) {
+ return ret;
} else if (refcount != 0) {
break;
}
}
/* And then allocate them */
- ret = update_refcount(bs, offset, i << s->cluster_bits, 1,
+ ret = update_refcount(bs, offset, i << s->cluster_bits, 1, false,
QCOW2_DISCARD_NEVER);
} while (ret == -EAGAIN);
@@ -770,12 +925,13 @@ int64_t qcow2_alloc_bytes(BlockDriverState *bs, int size)
offset = s->free_byte_offset;
if (offset) {
- int refcount = qcow2_get_refcount(bs, offset >> s->cluster_bits);
- if (refcount < 0) {
- return refcount;
+ uint64_t refcount;
+ ret = qcow2_get_refcount(bs, offset >> s->cluster_bits, &refcount);
+ if (ret < 0) {
+ return ret;
}
- if (refcount == 0xffff) {
+ if (refcount == s->refcount_max) {
offset = 0;
}
}
@@ -793,7 +949,7 @@ int64_t qcow2_alloc_bytes(BlockDriverState *bs, int size)
}
assert(offset);
- ret = update_refcount(bs, offset, size, 1, QCOW2_DISCARD_NEVER);
+ ret = update_refcount(bs, offset, size, 1, false, QCOW2_DISCARD_NEVER);
if (ret < 0) {
return ret;
}
@@ -817,7 +973,7 @@ void qcow2_free_clusters(BlockDriverState *bs,
int ret;
BLKDBG_EVENT(bs->file, BLKDBG_CLUSTER_FREE);
- ret = update_refcount(bs, offset, size, -1, type);
+ ret = update_refcount(bs, offset, size, 1, true, type);
if (ret < 0) {
fprintf(stderr, "qcow2_free_clusters failed: %s\n", strerror(-ret));
/* TODO Remember the clusters to free them later and avoid leaking */
@@ -876,12 +1032,14 @@ 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;
+ uint64_t *l1_table, *l2_table, l2_offset, offset, l1_size2, refcount;
bool l1_allocated = false;
int64_t old_offset, old_l2_offset;
- int i, j, l1_modified = 0, nb_csectors, refcount;
+ int i, j, l1_modified = 0, nb_csectors;
int ret;
+ assert(addend >= -1 && addend <= 1);
+
l2_table = NULL;
l1_table = NULL;
l1_size2 = l1_size * sizeof(uint64_t);
@@ -946,7 +1104,7 @@ int qcow2_update_snapshot_refcount(BlockDriverState *bs,
if (addend != 0) {
ret = update_refcount(bs,
(offset & s->cluster_offset_mask) & ~511,
- nb_csectors * 512, addend,
+ nb_csectors * 512, abs(addend), addend < 0,
QCOW2_DISCARD_SNAPSHOT);
if (ret < 0) {
goto fail;
@@ -976,15 +1134,16 @@ int qcow2_update_snapshot_refcount(BlockDriverState *bs,
break;
}
if (addend != 0) {
- refcount = qcow2_update_cluster_refcount(bs,
- cluster_index, addend,
+ ret = qcow2_update_cluster_refcount(bs,
+ cluster_index, abs(addend), addend < 0,
QCOW2_DISCARD_SNAPSHOT);
- } else {
- refcount = qcow2_get_refcount(bs, cluster_index);
+ if (ret < 0) {
+ goto fail;
+ }
}
- if (refcount < 0) {
- ret = refcount;
+ ret = qcow2_get_refcount(bs, cluster_index, &refcount);
+ if (ret < 0) {
goto fail;
}
break;
@@ -1017,13 +1176,17 @@ int qcow2_update_snapshot_refcount(BlockDriverState *bs,
if (addend != 0) {
- refcount = qcow2_update_cluster_refcount(bs, l2_offset >>
- s->cluster_bits, addend, QCOW2_DISCARD_SNAPSHOT);
- } else {
- refcount = qcow2_get_refcount(bs, l2_offset >> s->cluster_bits);
+ ret = qcow2_update_cluster_refcount(bs, l2_offset >>
+ s->cluster_bits,
+ abs(addend), addend < 0,
+ QCOW2_DISCARD_SNAPSHOT);
+ if (ret < 0) {
+ goto fail;
+ }
}
- if (refcount < 0) {
- ret = refcount;
+ ret = qcow2_get_refcount(bs, l2_offset >> s->cluster_bits,
+ &refcount);
+ if (ret < 0) {
goto fail;
} else if (refcount == 1) {
l2_offset |= QCOW_OFLAG_COPIED;
@@ -1068,6 +1231,63 @@ fail:
/* refcount checking functions */
+static size_t refcount_array_byte_size(BDRVQcowState *s, uint64_t entries)
+{
+ /* This assertion holds because there is no way we can address more than
+ * 2^(64 - 9) clusters at once (with cluster size 512 = 2^9, and because
+ * offsets have to be representable in bytes); due to every cluster
+ * corresponding to one refcount entry, we are well below that limit */
+ assert(entries < (UINT64_C(1) << (64 - 9)));
+
+ /* Thanks to the assertion this will not overflow, because
+ * s->refcount_order < 7.
+ * (note: x << s->refcount_order == x * s->refcount_bits) */
+ return DIV_ROUND_UP(entries << s->refcount_order, 8);
+}
+
+/**
+ * Reallocates *array so that it can hold new_size entries. *size must contain
+ * the current number of entries in *array. If the reallocation fails, *array
+ * and *size will not be modified and -errno will be returned. If the
+ * reallocation is successful, *array will be set to the new buffer, *size
+ * will be set to new_size and 0 will be returned. The size of the reallocated
+ * refcount array buffer will be aligned to a cluster boundary, and the newly
+ * allocated area will be zeroed.
+ */
+static int realloc_refcount_array(BDRVQcowState *s, void **array,
+ int64_t *size, int64_t new_size)
+{
+ size_t old_byte_size, new_byte_size;
+ void *new_ptr;
+
+ /* Round to clusters so the array can be directly written to disk */
+ old_byte_size = size_to_clusters(s, refcount_array_byte_size(s, *size))
+ * s->cluster_size;
+ new_byte_size = size_to_clusters(s, refcount_array_byte_size(s, new_size))
+ * s->cluster_size;
+
+ if (new_byte_size == old_byte_size) {
+ *size = new_size;
+ return 0;
+ }
+
+ assert(new_byte_size > 0);
+
+ new_ptr = g_try_realloc(*array, new_byte_size);
+ if (!new_ptr) {
+ return -ENOMEM;
+ }
+
+ if (new_byte_size > old_byte_size) {
+ memset((void *)((uintptr_t)new_ptr + old_byte_size), 0,
+ new_byte_size - old_byte_size);
+ }
+
+ *array = new_ptr;
+ *size = new_size;
+
+ return 0;
+}
/*
* Increases the refcount for a range of clusters in a given refcount table.
@@ -1078,12 +1298,13 @@ fail:
*/
static int inc_refcounts(BlockDriverState *bs,
BdrvCheckResult *res,
- uint16_t **refcount_table,
+ void **refcount_table,
int64_t *refcount_table_size,
int64_t offset, int64_t size)
{
BDRVQcowState *s = bs->opaque;
- uint64_t start, last, cluster_offset, k;
+ uint64_t start, last, cluster_offset, k, refcount;
+ int ret;
if (size <= 0) {
return 0;
@@ -1095,30 +1316,22 @@ static int inc_refcounts(BlockDriverState *bs,
cluster_offset += s->cluster_size) {
k = cluster_offset >> s->cluster_bits;
if (k >= *refcount_table_size) {
- int64_t old_refcount_table_size = *refcount_table_size;
- uint16_t *new_refcount_table;
-
- *refcount_table_size = k + 1;
- new_refcount_table = g_try_realloc(*refcount_table,
- *refcount_table_size *
- sizeof(**refcount_table));
- if (!new_refcount_table) {
- *refcount_table_size = old_refcount_table_size;
+ ret = realloc_refcount_array(s, refcount_table,
+ refcount_table_size, k + 1);
+ if (ret < 0) {
res->check_errors++;
- return -ENOMEM;
+ return ret;
}
- *refcount_table = new_refcount_table;
-
- memset(*refcount_table + old_refcount_table_size, 0,
- (*refcount_table_size - old_refcount_table_size) *
- sizeof(**refcount_table));
}
- if (++(*refcount_table)[k] == 0) {
+ refcount = s->get_refcount(*refcount_table, k);
+ if (refcount == s->refcount_max) {
fprintf(stderr, "ERROR: overflow cluster offset=0x%" PRIx64
"\n", cluster_offset);
res->corruptions++;
+ continue;
}
+ s->set_refcount(*refcount_table, k, refcount + 1);
}
return 0;
@@ -1138,8 +1351,9 @@ enum {
* error occurred.
*/
static int check_refcounts_l2(BlockDriverState *bs, BdrvCheckResult *res,
- uint16_t **refcount_table, int64_t *refcount_table_size, int64_t l2_offset,
- int flags)
+ void **refcount_table,
+ int64_t *refcount_table_size, int64_t l2_offset,
+ int flags)
{
BDRVQcowState *s = bs->opaque;
uint64_t *l2_table, l2_entry;
@@ -1256,7 +1470,7 @@ fail:
*/
static int check_refcounts_l1(BlockDriverState *bs,
BdrvCheckResult *res,
- uint16_t **refcount_table,
+ void **refcount_table,
int64_t *refcount_table_size,
int64_t l1_table_offset, int l1_size,
int flags)
@@ -1341,7 +1555,7 @@ static int check_oflag_copied(BlockDriverState *bs, BdrvCheckResult *res,
BDRVQcowState *s = bs->opaque;
uint64_t *l2_table = qemu_blockalign(bs, s->cluster_size);
int ret;
- int refcount;
+ uint64_t refcount;
int i, j;
for (i = 0; i < s->l1_size; i++) {
@@ -1353,14 +1567,15 @@ static int check_oflag_copied(BlockDriverState *bs, BdrvCheckResult *res,
continue;
}
- refcount = qcow2_get_refcount(bs, l2_offset >> s->cluster_bits);
- if (refcount < 0) {
+ ret = qcow2_get_refcount(bs, l2_offset >> s->cluster_bits,
+ &refcount);
+ if (ret < 0) {
/* don't print message nor increment check_errors */
continue;
}
if ((refcount == 1) != ((l1_entry & QCOW_OFLAG_COPIED) != 0)) {
fprintf(stderr, "%s OFLAG_COPIED L2 cluster: l1_index=%d "
- "l1_entry=%" PRIx64 " refcount=%d\n",
+ "l1_entry=%" PRIx64 " refcount=%" PRIu64 "\n",
fix & BDRV_FIX_ERRORS ? "Repairing" :
"ERROR",
i, l1_entry, refcount);
@@ -1395,15 +1610,16 @@ static int check_oflag_copied(BlockDriverState *bs, BdrvCheckResult *res,
if ((cluster_type == QCOW2_CLUSTER_NORMAL) ||
((cluster_type == QCOW2_CLUSTER_ZERO) && (data_offset != 0))) {
- refcount = qcow2_get_refcount(bs,
- data_offset >> s->cluster_bits);
- if (refcount < 0) {
+ ret = qcow2_get_refcount(bs,
+ data_offset >> s->cluster_bits,
+ &refcount);
+ if (ret < 0) {
/* don't print message nor increment check_errors */
continue;
}
if ((refcount == 1) != ((l2_entry & QCOW_OFLAG_COPIED) != 0)) {
fprintf(stderr, "%s OFLAG_COPIED data cluster: "
- "l2_entry=%" PRIx64 " refcount=%d\n",
+ "l2_entry=%" PRIx64 " refcount=%" PRIu64 "\n",
fix & BDRV_FIX_ERRORS ? "Repairing" :
"ERROR",
l2_entry, refcount);
@@ -1453,7 +1669,7 @@ fail:
*/
static int check_refblocks(BlockDriverState *bs, BdrvCheckResult *res,
BdrvCheckMode fix, bool *rebuild,
- uint16_t **refcount_table, int64_t *nb_clusters)
+ void **refcount_table, int64_t *nb_clusters)
{
BDRVQcowState *s = bs->opaque;
int64_t i, size;
@@ -1478,8 +1694,7 @@ static int check_refblocks(BlockDriverState *bs, BdrvCheckResult *res,
fix & BDRV_FIX_ERRORS ? "Repairing" : "ERROR", i);
if (fix & BDRV_FIX_ERRORS) {
- int64_t old_nb_clusters = *nb_clusters;
- uint16_t *new_refcount_table;
+ int64_t new_nb_clusters;
if (offset > INT64_MAX - s->cluster_size) {
ret = -EINVAL;
@@ -1496,22 +1711,15 @@ static int check_refblocks(BlockDriverState *bs, BdrvCheckResult *res,
goto resize_fail;
}
- *nb_clusters = size_to_clusters(s, size);
- assert(*nb_clusters >= old_nb_clusters);
+ new_nb_clusters = size_to_clusters(s, size);
+ assert(new_nb_clusters >= *nb_clusters);
- new_refcount_table = g_try_realloc(*refcount_table,
- *nb_clusters *
- sizeof(**refcount_table));
- if (!new_refcount_table) {
- *nb_clusters = old_nb_clusters;
+ ret = realloc_refcount_array(s, refcount_table,
+ nb_clusters, new_nb_clusters);
+ if (ret < 0) {
res->check_errors++;
- return -ENOMEM;
+ return ret;
}
- *refcount_table = new_refcount_table;
-
- memset(*refcount_table + old_nb_clusters, 0,
- (*nb_clusters - old_nb_clusters) *
- sizeof(**refcount_table));
if (cluster >= *nb_clusters) {
ret = -EINVAL;
@@ -1546,9 +1754,10 @@ resize_fail:
if (ret < 0) {
return ret;
}
- if ((*refcount_table)[cluster] != 1) {
+ if (s->get_refcount(*refcount_table, cluster) != 1) {
fprintf(stderr, "ERROR refcount block %" PRId64
- " refcount=%d\n", i, (*refcount_table)[cluster]);
+ " refcount=%" PRIu64 "\n", i,
+ s->get_refcount(*refcount_table, cluster));
res->corruptions++;
*rebuild = true;
}
@@ -1563,7 +1772,7 @@ resize_fail:
*/
static int calculate_refcounts(BlockDriverState *bs, BdrvCheckResult *res,
BdrvCheckMode fix, bool *rebuild,
- uint16_t **refcount_table, int64_t *nb_clusters)
+ void **refcount_table, int64_t *nb_clusters)
{
BDRVQcowState *s = bs->opaque;
int64_t i;
@@ -1571,10 +1780,12 @@ static int calculate_refcounts(BlockDriverState *bs, BdrvCheckResult *res,
int ret;
if (!*refcount_table) {
- *refcount_table = g_try_new0(uint16_t, *nb_clusters);
- if (*nb_clusters && *refcount_table == NULL) {
+ int64_t old_size = 0;
+ ret = realloc_refcount_array(s, refcount_table,
+ &old_size, *nb_clusters);
+ if (ret < 0) {
res->check_errors++;
- return -ENOMEM;
+ return ret;
}
}
@@ -1625,22 +1836,23 @@ static int calculate_refcounts(BlockDriverState *bs, BdrvCheckResult *res,
static void compare_refcounts(BlockDriverState *bs, BdrvCheckResult *res,
BdrvCheckMode fix, bool *rebuild,
int64_t *highest_cluster,
- uint16_t *refcount_table, int64_t nb_clusters)
+ void *refcount_table, int64_t nb_clusters)
{
BDRVQcowState *s = bs->opaque;
int64_t i;
- int refcount1, refcount2, ret;
+ uint64_t refcount1, refcount2;
+ int ret;
for (i = 0, *highest_cluster = 0; i < nb_clusters; i++) {
- refcount1 = qcow2_get_refcount(bs, i);
- if (refcount1 < 0) {
+ ret = qcow2_get_refcount(bs, i, &refcount1);
+ if (ret < 0) {
fprintf(stderr, "Can't get refcount for cluster %" PRId64 ": %s\n",
- i, strerror(-refcount1));
+ i, strerror(-ret));
res->check_errors++;
continue;
}
- refcount2 = refcount_table[i];
+ refcount2 = s->get_refcount(refcount_table, i);
if (refcount1 > 0 || refcount2 > 0) {
*highest_cluster = i;
@@ -1657,7 +1869,8 @@ static void compare_refcounts(BlockDriverState *bs, BdrvCheckResult *res,
num_fixed = &res->corruptions_fixed;
}
- fprintf(stderr, "%s cluster %" PRId64 " refcount=%d reference=%d\n",
+ fprintf(stderr, "%s cluster %" PRId64 " refcount=%" PRIu64
+ " reference=%" PRIu64 "\n",
num_fixed != NULL ? "Repairing" :
refcount1 < refcount2 ? "ERROR" :
"Leaked",
@@ -1665,7 +1878,8 @@ static void compare_refcounts(BlockDriverState *bs, BdrvCheckResult *res,
if (num_fixed) {
ret = update_refcount(bs, i << s->cluster_bits, 1,
- refcount2 - refcount1,
+ refcount_diff(refcount1, refcount2),
+ refcount1 > refcount2,
QCOW2_DISCARD_ALWAYS);
if (ret >= 0) {
(*num_fixed)++;
@@ -1697,7 +1911,7 @@ static void compare_refcounts(BlockDriverState *bs, BdrvCheckResult *res,
*/
static int64_t alloc_clusters_imrt(BlockDriverState *bs,
int cluster_count,
- uint16_t **refcount_table,
+ void **refcount_table,
int64_t *imrt_nb_clusters,
int64_t *first_free_cluster)
{
@@ -1705,6 +1919,7 @@ static int64_t alloc_clusters_imrt(BlockDriverState *bs,
int64_t cluster = *first_free_cluster, i;
bool first_gap = true;
int contiguous_free_clusters;
+ int ret;
/* Starting at *first_free_cluster, find a range of at least cluster_count
* continuously free clusters */
@@ -1713,7 +1928,7 @@ static int64_t alloc_clusters_imrt(BlockDriverState *bs,
contiguous_free_clusters < cluster_count;
cluster++)
{
- if (!(*refcount_table)[cluster]) {
+ if (!s->get_refcount(*refcount_table, cluster)) {
contiguous_free_clusters++;
if (first_gap) {
/* If this is the first free cluster found, update
@@ -1734,34 +1949,24 @@ static int64_t alloc_clusters_imrt(BlockDriverState *bs,
/* If no such range could be found, grow the in-memory refcount table
* accordingly to append free clusters at the end of the image */
if (contiguous_free_clusters < cluster_count) {
- int64_t old_imrt_nb_clusters = *imrt_nb_clusters;
- uint16_t *new_refcount_table;
-
/* contiguous_free_clusters clusters are already empty at the image end;
* we need cluster_count clusters; therefore, we have to allocate
* cluster_count - contiguous_free_clusters new clusters at the end of
* the image (which is the current value of cluster; note that cluster
* may exceed old_imrt_nb_clusters if *first_free_cluster pointed beyond
* the image end) */
- *imrt_nb_clusters = cluster + cluster_count - contiguous_free_clusters;
- new_refcount_table = g_try_realloc(*refcount_table,
- *imrt_nb_clusters *
- sizeof(**refcount_table));
- if (!new_refcount_table) {
- *imrt_nb_clusters = old_imrt_nb_clusters;
- return -ENOMEM;
+ ret = realloc_refcount_array(s, refcount_table, imrt_nb_clusters,
+ cluster + cluster_count
+ - contiguous_free_clusters);
+ if (ret < 0) {
+ return ret;
}
- *refcount_table = new_refcount_table;
-
- memset(*refcount_table + old_imrt_nb_clusters, 0,
- (*imrt_nb_clusters - old_imrt_nb_clusters) *
- sizeof(**refcount_table));
}
/* Go back to the first free cluster */
cluster -= contiguous_free_clusters;
for (i = 0; i < cluster_count; i++) {
- (*refcount_table)[cluster + i] = 1;
+ s->set_refcount(*refcount_table, cluster + i, 1);
}
return cluster << s->cluster_bits;
@@ -1777,7 +1982,7 @@ static int64_t alloc_clusters_imrt(BlockDriverState *bs,
*/
static int rebuild_refcount_structure(BlockDriverState *bs,
BdrvCheckResult *res,
- uint16_t **refcount_table,
+ void **refcount_table,
int64_t *nb_clusters)
{
BDRVQcowState *s = bs->opaque;
@@ -1785,8 +1990,8 @@ static int rebuild_refcount_structure(BlockDriverState *bs,
int64_t refblock_offset, refblock_start, refblock_index;
uint32_t reftable_size = 0;
uint64_t *on_disk_reftable = NULL;
- uint16_t *on_disk_refblock;
- int i, ret = 0;
+ void *on_disk_refblock;
+ int ret = 0;
struct {
uint64_t reftable_offset;
uint32_t reftable_clusters;
@@ -1796,7 +2001,7 @@ static int rebuild_refcount_structure(BlockDriverState *bs,
write_refblocks:
for (; cluster < *nb_clusters; cluster++) {
- if (!(*refcount_table)[cluster]) {
+ if (!s->get_refcount(*refcount_table, cluster)) {
continue;
}
@@ -1869,17 +2074,13 @@ write_refblocks:
goto fail;
}
- on_disk_refblock = qemu_blockalign0(bs->file, s->cluster_size);
- for (i = 0; i < s->refcount_block_size &&
- refblock_start + i < *nb_clusters; i++)
- {
- on_disk_refblock[i] =
- cpu_to_be16((*refcount_table)[refblock_start + i]);
- }
+ /* The size of *refcount_table is always cluster-aligned, therefore the
+ * write operation will not overflow */
+ on_disk_refblock = (void *)((char *) *refcount_table +
+ refblock_index * s->cluster_size);
ret = bdrv_write(bs->file, refblock_offset / BDRV_SECTOR_SIZE,
- (void *)on_disk_refblock, s->cluster_sectors);
- qemu_vfree(on_disk_refblock);
+ on_disk_refblock, s->cluster_sectors);
if (ret < 0) {
fprintf(stderr, "ERROR writing refblock: %s\n", strerror(-ret));
goto fail;
@@ -1974,7 +2175,7 @@ int qcow2_check_refcounts(BlockDriverState *bs, BdrvCheckResult *res,
BDRVQcowState *s = bs->opaque;
BdrvCheckResult pre_compare_res;
int64_t size, highest_cluster, nb_clusters;
- uint16_t *refcount_table = NULL;
+ void *refcount_table = NULL;
bool rebuild = false;
int ret;
@@ -2023,7 +2224,7 @@ int qcow2_check_refcounts(BlockDriverState *bs, BdrvCheckResult *res,
/* Because the old reftable has been exchanged for a new one the
* references have to be recalculated */
rebuild = false;
- memset(refcount_table, 0, nb_clusters * sizeof(uint16_t));
+ memset(refcount_table, 0, refcount_array_byte_size(s, nb_clusters));
ret = calculate_refcounts(bs, res, 0, &rebuild, &refcount_table,
&nb_clusters);
if (ret < 0) {
diff --git a/block/qcow2.c b/block/qcow2.c
index 50e0a947d..8bfb094e5 100644
--- a/block/qcow2.c
+++ b/block/qcow2.c
@@ -677,13 +677,16 @@ static int qcow2_open(BlockDriverState *bs, QDict *options, int flags,
}
/* Check support for various header values */
- if (header.refcount_order != 4) {
- report_unsupported(bs, errp, "%d bit reference counts",
- 1 << header.refcount_order);
- ret = -ENOTSUP;
+ if (header.refcount_order > 6) {
+ error_setg(errp, "Reference count entry width too large; may not "
+ "exceed 64 bits");
+ ret = -EINVAL;
goto fail;
}
s->refcount_order = header.refcount_order;
+ s->refcount_bits = 1 << s->refcount_order;
+ s->refcount_max = UINT64_C(1) << (s->refcount_bits - 1);
+ s->refcount_max += s->refcount_max - 1;
if (header.crypt_method > QCOW_CRYPT_AES) {
error_setg(errp, "Unsupported encryption method: %" PRIu32,
@@ -1780,7 +1783,7 @@ static int preallocate(BlockDriverState *bs)
static int qcow2_create2(const char *filename, int64_t total_size,
const char *backing_file, const char *backing_format,
int flags, size_t cluster_size, PreallocMode prealloc,
- QemuOpts *opts, int version,
+ QemuOpts *opts, int version, int refcount_order,
Error **errp)
{
/* Calculate cluster_bits */
@@ -1813,9 +1816,21 @@ static int qcow2_create2(const char *filename, int64_t total_size,
int ret;
if (prealloc == PREALLOC_MODE_FULL || prealloc == PREALLOC_MODE_FALLOC) {
+ /* Note: The following calculation does not need to be exact; if it is a
+ * bit off, either some bytes will be "leaked" (which is fine) or we
+ * will need to increase the file size by some bytes (which is fine,
+ * too, as long as the bulk is allocated here). Therefore, using
+ * floating point arithmetic is fine. */
int64_t meta_size = 0;
uint64_t nreftablee, nrefblocke, nl1e, nl2e;
int64_t aligned_total_size = align_offset(total_size, cluster_size);
+ int refblock_bits, refblock_size;
+ /* refcount entry size in bytes */
+ double rces = (1 << refcount_order) / 8.;
+
+ /* see qcow2_open() */
+ refblock_bits = cluster_bits - (refcount_order - 3);
+ refblock_size = 1 << refblock_bits;
/* header: 1 cluster */
meta_size += cluster_size;
@@ -1840,20 +1855,20 @@ static int qcow2_create2(const char *filename, int64_t total_size,
* c = cluster size
* y1 = number of refcount blocks entries
* y2 = meta size including everything
+ * rces = refcount entry size in bytes
* then,
* y1 = (y2 + a)/c
- * y2 = y1 * sizeof(u16) + y1 * sizeof(u16) * sizeof(u64) / c + m
+ * y2 = y1 * rces + y1 * rces * sizeof(u64) / c + m
* we can get y1:
- * y1 = (a + m) / (c - sizeof(u16) - sizeof(u16) * sizeof(u64) / c)
+ * y1 = (a + m) / (c - rces - rces * sizeof(u64) / c)
*/
- nrefblocke = (aligned_total_size + meta_size + cluster_size) /
- (cluster_size - sizeof(uint16_t) -
- 1.0 * sizeof(uint16_t) * sizeof(uint64_t) / cluster_size);
- nrefblocke = align_offset(nrefblocke, cluster_size / sizeof(uint16_t));
- meta_size += nrefblocke * sizeof(uint16_t);
+ nrefblocke = (aligned_total_size + meta_size + cluster_size)
+ / (cluster_size - rces - rces * sizeof(uint64_t)
+ / cluster_size);
+ meta_size += DIV_ROUND_UP(nrefblocke, refblock_size) * cluster_size;
/* total size of refcount tables */
- nreftablee = nrefblocke * sizeof(uint16_t) / cluster_size;
+ nreftablee = nrefblocke / refblock_size;
nreftablee = align_offset(nreftablee, cluster_size / sizeof(uint64_t));
meta_size += nreftablee * sizeof(uint64_t);
@@ -1889,7 +1904,7 @@ static int qcow2_create2(const char *filename, int64_t total_size,
.l1_size = cpu_to_be32(0),
.refcount_table_offset = cpu_to_be64(cluster_size),
.refcount_table_clusters = cpu_to_be32(1),
- .refcount_order = cpu_to_be32(4),
+ .refcount_order = cpu_to_be32(refcount_order),
.header_length = cpu_to_be32(sizeof(*header)),
};
@@ -2008,6 +2023,8 @@ static int qcow2_create(const char *filename, QemuOpts *opts, Error **errp)
size_t cluster_size = DEFAULT_CLUSTER_SIZE;
PreallocMode prealloc;
int version = 3;
+ uint64_t refcount_bits = 16;
+ int refcount_order;
Error *local_err = NULL;
int ret;
@@ -2062,8 +2079,28 @@ static int qcow2_create(const char *filename, QemuOpts *opts, Error **errp)
goto finish;
}
+ refcount_bits = qemu_opt_get_number_del(opts, BLOCK_OPT_REFCOUNT_BITS,
+ refcount_bits);
+ if (refcount_bits > 64 || !is_power_of_2(refcount_bits)) {
+ error_setg(errp, "Refcount width must be a power of two and may not "
+ "exceed 64 bits");
+ ret = -EINVAL;
+ goto finish;
+ }
+
+ if (version < 3 && refcount_bits != 16) {
+ error_setg(errp, "Different refcount widths than 16 bits require "
+ "compatibility level 1.1 or above (use compat=1.1 or "
+ "greater)");
+ ret = -EINVAL;
+ goto finish;
+ }
+
+ refcount_order = ffs(refcount_bits) - 1;
+
ret = qcow2_create2(filename, size, backing_file, backing_fmt, flags,
- cluster_size, prealloc, opts, version, &local_err);
+ cluster_size, prealloc, opts, version, refcount_order,
+ &local_err);
if (local_err) {
error_propagate(errp, local_err);
}
@@ -2479,7 +2516,8 @@ static ImageInfoSpecific *qcow2_get_specific_info(BlockDriverState *bs)
};
if (s->qcow_version == 2) {
*spec_info->qcow2 = (ImageInfoSpecificQCow2){
- .compat = g_strdup("0.10"),
+ .compat = g_strdup("0.10"),
+ .refcount_bits = s->refcount_bits,
};
} else if (s->qcow_version == 3) {
*spec_info->qcow2 = (ImageInfoSpecificQCow2){
@@ -2490,6 +2528,7 @@ static ImageInfoSpecific *qcow2_get_specific_info(BlockDriverState *bs)
.corrupt = s->incompatible_features &
QCOW2_INCOMPAT_CORRUPT,
.has_corrupt = true,
+ .refcount_bits = s->refcount_bits,
};
}
@@ -2642,8 +2681,8 @@ static int qcow2_amend_options(BlockDriverState *bs, QemuOpts *opts,
continue;
}
- if (!strcmp(desc->name, "compat")) {
- compat = qemu_opt_get(opts, "compat");
+ if (!strcmp(desc->name, BLOCK_OPT_COMPAT_LEVEL)) {
+ compat = qemu_opt_get(opts, BLOCK_OPT_COMPAT_LEVEL);
if (!compat) {
/* preserve default */
} else if (!strcmp(compat, "0.10")) {
@@ -2654,33 +2693,37 @@ static int qcow2_amend_options(BlockDriverState *bs, QemuOpts *opts,
fprintf(stderr, "Unknown compatibility level %s.\n", compat);
return -EINVAL;
}
- } else if (!strcmp(desc->name, "preallocation")) {
+ } else if (!strcmp(desc->name, BLOCK_OPT_PREALLOC)) {
fprintf(stderr, "Cannot change preallocation mode.\n");
return -ENOTSUP;
- } else if (!strcmp(desc->name, "size")) {
- new_size = qemu_opt_get_size(opts, "size", 0);
- } else if (!strcmp(desc->name, "backing_file")) {
- backing_file = qemu_opt_get(opts, "backing_file");
- } else if (!strcmp(desc->name, "backing_fmt")) {
- backing_format = qemu_opt_get(opts, "backing_fmt");
- } else if (!strcmp(desc->name, "encryption")) {
- encrypt = qemu_opt_get_bool(opts, "encryption", s->crypt_method);
+ } else if (!strcmp(desc->name, BLOCK_OPT_SIZE)) {
+ new_size = qemu_opt_get_size(opts, BLOCK_OPT_SIZE, 0);
+ } else if (!strcmp(desc->name, BLOCK_OPT_BACKING_FILE)) {
+ backing_file = qemu_opt_get(opts, BLOCK_OPT_BACKING_FILE);
+ } else if (!strcmp(desc->name, BLOCK_OPT_BACKING_FMT)) {
+ backing_format = qemu_opt_get(opts, BLOCK_OPT_BACKING_FMT);
+ } else if (!strcmp(desc->name, BLOCK_OPT_ENCRYPT)) {
+ encrypt = qemu_opt_get_bool(opts, BLOCK_OPT_ENCRYPT,
+ s->crypt_method);
if (encrypt != !!s->crypt_method) {
fprintf(stderr, "Changing the encryption flag is not "
"supported.\n");
return -ENOTSUP;
}
- } else if (!strcmp(desc->name, "cluster_size")) {
- cluster_size = qemu_opt_get_size(opts, "cluster_size",
+ } else if (!strcmp(desc->name, BLOCK_OPT_CLUSTER_SIZE)) {
+ cluster_size = qemu_opt_get_size(opts, BLOCK_OPT_CLUSTER_SIZE,
cluster_size);
if (cluster_size != s->cluster_size) {
fprintf(stderr, "Changing the cluster size is not "
"supported.\n");
return -ENOTSUP;
}
- } else if (!strcmp(desc->name, "lazy_refcounts")) {
- lazy_refcounts = qemu_opt_get_bool(opts, "lazy_refcounts",
+ } else if (!strcmp(desc->name, BLOCK_OPT_LAZY_REFCOUNTS)) {
+ lazy_refcounts = qemu_opt_get_bool(opts, BLOCK_OPT_LAZY_REFCOUNTS,
lazy_refcounts);
+ } else if (!strcmp(desc->name, BLOCK_OPT_REFCOUNT_BITS)) {
+ error_report("Cannot change refcount entry width");
+ return -ENOTSUP;
} else {
/* if this assertion fails, this probably means a new option was
* added without having it covered here */
@@ -2850,6 +2893,12 @@ static QemuOptsList qcow2_create_opts = {
.help = "Postpone refcount updates",
.def_value_str = "off"
},
+ {
+ .name = BLOCK_OPT_REFCOUNT_BITS,
+ .type = QEMU_OPT_NUMBER,
+ .help = "Width of a reference count entry in bits",
+ .def_value_str = "16"
+ },
{ /* end of list */ }
}
};
diff --git a/block/qcow2.h b/block/qcow2.h
index 6e39a1b63..aa6d36781 100644
--- a/block/qcow2.h
+++ b/block/qcow2.h
@@ -213,6 +213,11 @@ typedef struct Qcow2DiscardRegion {
QTAILQ_ENTRY(Qcow2DiscardRegion) next;
} Qcow2DiscardRegion;
+typedef uint64_t Qcow2GetRefcountFunc(const void *refcount_array,
+ uint64_t index);
+typedef void Qcow2SetRefcountFunc(void *refcount_array,
+ uint64_t index, uint64_t value);
+
typedef struct BDRVQcowState {
int cluster_bits;
int cluster_size;
@@ -258,6 +263,11 @@ typedef struct BDRVQcowState {
int qcow_version;
bool use_lazy_refcounts;
int refcount_order;
+ int refcount_bits;
+ uint64_t refcount_max;
+
+ Qcow2GetRefcountFunc *get_refcount;
+ Qcow2SetRefcountFunc *set_refcount;
bool discard_passthrough[QCOW2_DISCARD_MAX];
@@ -275,17 +285,6 @@ typedef struct BDRVQcowState {
bool cache_discards;
} BDRVQcowState;
-/* XXX: use std qcow open function ? */
-typedef struct QCowCreateState {
- int cluster_size;
- int cluster_bits;
- uint16_t *refcount_block;
- uint64_t *refcount_table;
- int64_t l1_table_offset;
- int64_t refcount_table_offset;
- int64_t refcount_block_offset;
-} QCowCreateState;
-
struct QCowAIOCB;
typedef struct Qcow2COWRegion {
@@ -468,6 +467,11 @@ static inline uint64_t l2meta_cow_end(QCowL2Meta *m)
+ (m->cow_end.nb_sectors << BDRV_SECTOR_BITS);
}
+static inline uint64_t refcount_diff(uint64_t r1, uint64_t r2)
+{
+ return r1 > r2 ? r1 - r2 : r2 - r1;
+}
+
// FIXME Need qcow2_ prefix to global functions
/* qcow2.c functions */
@@ -487,10 +491,12 @@ void qcow2_signal_corruption(BlockDriverState *bs, bool fatal, int64_t offset,
int qcow2_refcount_init(BlockDriverState *bs);
void qcow2_refcount_close(BlockDriverState *bs);
-int qcow2_get_refcount(BlockDriverState *bs, int64_t cluster_index);
+int qcow2_get_refcount(BlockDriverState *bs, int64_t cluster_index,
+ uint64_t *refcount);
int qcow2_update_cluster_refcount(BlockDriverState *bs, int64_t cluster_index,
- int addend, enum qcow2_discard_type type);
+ uint64_t addend, bool decrease,
+ enum qcow2_discard_type type);
int64_t qcow2_alloc_clusters(BlockDriverState *bs, uint64_t size);
int qcow2_alloc_clusters_at(BlockDriverState *bs, uint64_t offset,
diff --git a/block/raw-posix.c b/block/raw-posix.c
index b5f077a8f..f0b4488d1 100644
--- a/block/raw-posix.c
+++ b/block/raw-posix.c
@@ -56,6 +56,10 @@
#include <linux/cdrom.h>
#include <linux/fd.h>
#include <linux/fs.h>
+#include <linux/hdreg.h>
+#ifdef __s390__
+#include <asm/dasd.h>
+#endif
#ifndef FS_NOCOW_FL
#define FS_NOCOW_FL 0x00800000 /* Do not cow file */
#endif
@@ -218,39 +222,100 @@ static int raw_normalize_devicepath(const char **filename)
}
#endif
-static void raw_probe_alignment(BlockDriverState *bs, int fd, Error **errp)
+/*
+ * Get logical block size via ioctl. On success store it in @sector_size_p.
+ */
+static int probe_logical_blocksize(int fd, unsigned int *sector_size_p)
{
- BDRVRawState *s = bs->opaque;
- char *buf;
unsigned int sector_size;
+ bool success = false;
- /* For /dev/sg devices the alignment is not really used.
- With buffered I/O, we don't have any restrictions. */
- if (bs->sg || !s->needs_alignment) {
- bs->request_alignment = 1;
- s->buf_align = 1;
- return;
- }
+ errno = ENOTSUP;
/* Try a few ioctls to get the right size */
- bs->request_alignment = 0;
- s->buf_align = 0;
-
#ifdef BLKSSZGET
if (ioctl(fd, BLKSSZGET, &sector_size) >= 0) {
- bs->request_alignment = sector_size;
+ *sector_size_p = sector_size;
+ success = true;
}
#endif
#ifdef DKIOCGETBLOCKSIZE
if (ioctl(fd, DKIOCGETBLOCKSIZE, &sector_size) >= 0) {
- bs->request_alignment = sector_size;
+ *sector_size_p = sector_size;
+ success = true;
}
#endif
#ifdef DIOCGSECTORSIZE
if (ioctl(fd, DIOCGSECTORSIZE, &sector_size) >= 0) {
- bs->request_alignment = sector_size;
+ *sector_size_p = sector_size;
+ success = true;
+ }
+#endif
+
+ return success ? 0 : -errno;
+}
+
+/**
+ * Get physical block size of @fd.
+ * On success, store it in @blk_size and return 0.
+ * On failure, return -errno.
+ */
+static int probe_physical_blocksize(int fd, unsigned int *blk_size)
+{
+#ifdef BLKPBSZGET
+ if (ioctl(fd, BLKPBSZGET, blk_size) < 0) {
+ return -errno;
+ }
+ return 0;
+#else
+ return -ENOTSUP;
+#endif
+}
+
+/* Check if read is allowed with given memory buffer and length.
+ *
+ * This function is used to check O_DIRECT memory buffer and request alignment.
+ */
+static bool raw_is_io_aligned(int fd, void *buf, size_t len)
+{
+ ssize_t ret = pread(fd, buf, len, 0);
+
+ if (ret >= 0) {
+ return true;
+ }
+
+#ifdef __linux__
+ /* The Linux kernel returns EINVAL for misaligned O_DIRECT reads. Ignore
+ * other errors (e.g. real I/O error), which could happen on a failed
+ * drive, since we only care about probing alignment.
+ */
+ if (errno != EINVAL) {
+ return true;
}
#endif
+
+ return false;
+}
+
+static void raw_probe_alignment(BlockDriverState *bs, int fd, Error **errp)
+{
+ BDRVRawState *s = bs->opaque;
+ char *buf;
+
+ /* For /dev/sg devices the alignment is not really used.
+ With buffered I/O, we don't have any restrictions. */
+ if (bs->sg || !s->needs_alignment) {
+ bs->request_alignment = 1;
+ s->buf_align = 1;
+ return;
+ }
+
+ bs->request_alignment = 0;
+ s->buf_align = 0;
+ /* Let's try to use the logical blocksize for the alignment. */
+ if (probe_logical_blocksize(fd, &bs->request_alignment) < 0) {
+ bs->request_alignment = 0;
+ }
#ifdef CONFIG_XFS
if (s->is_xfs) {
struct dioattr da;
@@ -267,7 +332,7 @@ static void raw_probe_alignment(BlockDriverState *bs, int fd, Error **errp)
size_t align;
buf = qemu_memalign(MAX_BLOCKSIZE, 2 * MAX_BLOCKSIZE);
for (align = 512; align <= MAX_BLOCKSIZE; align <<= 1) {
- if (pread(fd, buf + align, MAX_BLOCKSIZE, 0) >= 0) {
+ if (raw_is_io_aligned(fd, buf + align, MAX_BLOCKSIZE)) {
s->buf_align = align;
break;
}
@@ -279,7 +344,7 @@ static void raw_probe_alignment(BlockDriverState *bs, int fd, Error **errp)
size_t align;
buf = qemu_memalign(s->buf_align, MAX_BLOCKSIZE);
for (align = 512; align <= MAX_BLOCKSIZE; align <<= 1) {
- if (pread(fd, buf, align, 0) >= 0) {
+ if (raw_is_io_aligned(fd, buf, align)) {
bs->request_alignment = align;
break;
}
@@ -655,6 +720,86 @@ static void raw_refresh_limits(BlockDriverState *bs, Error **errp)
bs->bl.opt_mem_alignment = s->buf_align;
}
+static int check_for_dasd(int fd)
+{
+#ifdef BIODASDINFO2
+ struct dasd_information2_t info = {0};
+
+ return ioctl(fd, BIODASDINFO2, &info);
+#else
+ return -1;
+#endif
+}
+
+/**
+ * Try to get @bs's logical and physical block size.
+ * On success, store them in @bsz and return zero.
+ * On failure, return negative errno.
+ */
+static int hdev_probe_blocksizes(BlockDriverState *bs, BlockSizes *bsz)
+{
+ BDRVRawState *s = bs->opaque;
+ int ret;
+
+ /* If DASD, get blocksizes */
+ if (check_for_dasd(s->fd) < 0) {
+ return -ENOTSUP;
+ }
+ ret = probe_logical_blocksize(s->fd, &bsz->log);
+ if (ret < 0) {
+ return ret;
+ }
+ return probe_physical_blocksize(s->fd, &bsz->phys);
+}
+
+/**
+ * Try to get @bs's geometry: cyls, heads, sectors.
+ * On success, store them in @geo and return 0.
+ * On failure return -errno.
+ * (Allows block driver to assign default geometry values that guest sees)
+ */
+#ifdef __linux__
+static int hdev_probe_geometry(BlockDriverState *bs, HDGeometry *geo)
+{
+ BDRVRawState *s = bs->opaque;
+ struct hd_geometry ioctl_geo = {0};
+ uint32_t blksize;
+
+ /* If DASD, get its geometry */
+ if (check_for_dasd(s->fd) < 0) {
+ return -ENOTSUP;
+ }
+ if (ioctl(s->fd, HDIO_GETGEO, &ioctl_geo) < 0) {
+ return -errno;
+ }
+ /* HDIO_GETGEO may return success even though geo contains zeros
+ (e.g. certain multipath setups) */
+ if (!ioctl_geo.heads || !ioctl_geo.sectors || !ioctl_geo.cylinders) {
+ return -ENOTSUP;
+ }
+ /* Do not return a geometry for partition */
+ if (ioctl_geo.start != 0) {
+ return -ENOTSUP;
+ }
+ geo->heads = ioctl_geo.heads;
+ geo->sectors = ioctl_geo.sectors;
+ if (!probe_physical_blocksize(s->fd, &blksize)) {
+ /* overwrite cyls: HDIO_GETGEO result is incorrect for big drives */
+ geo->cylinders = bdrv_nb_sectors(bs) / (blksize / BDRV_SECTOR_SIZE)
+ / (geo->heads * geo->sectors);
+ return 0;
+ }
+ geo->cylinders = ioctl_geo.cylinders;
+
+ return 0;
+}
+#else /* __linux__ */
+static int hdev_probe_geometry(BlockDriverState *bs, HDGeometry *geo)
+{
+ return -ENOTSUP;
+}
+#endif
+
static ssize_t handle_aiocb_ioctl(RawPosixAIOData *aiocb)
{
int ret;
@@ -944,7 +1089,9 @@ static ssize_t handle_aiocb_write_zeroes_block(RawPosixAIOData *aiocb)
static ssize_t handle_aiocb_write_zeroes(RawPosixAIOData *aiocb)
{
+#if defined(CONFIG_FALLOCATE) || defined(CONFIG_XFS)
BDRVRawState *s = aiocb->bs->opaque;
+#endif
if (aiocb->aio_type & QEMU_AIO_BLKDEV) {
return handle_aiocb_write_zeroes_block(aiocb);
@@ -2194,6 +2341,8 @@ static BlockDriver bdrv_host_device = {
.bdrv_get_info = raw_get_info,
.bdrv_get_allocated_file_size
= raw_get_allocated_file_size,
+ .bdrv_probe_blocksizes = hdev_probe_blocksizes,
+ .bdrv_probe_geometry = hdev_probe_geometry,
.bdrv_detach_aio_context = raw_detach_aio_context,
.bdrv_attach_aio_context = raw_attach_aio_context,
diff --git a/block/raw_bsd.c b/block/raw_bsd.c
index 05b02c76d..e3d2d0468 100644
--- a/block/raw_bsd.c
+++ b/block/raw_bsd.c
@@ -235,6 +235,16 @@ static int raw_probe(const uint8_t *buf, int buf_size, const char *filename)
return 1;
}
+static int raw_probe_blocksizes(BlockDriverState *bs, BlockSizes *bsz)
+{
+ return bdrv_probe_blocksizes(bs->file, bsz);
+}
+
+static int raw_probe_geometry(BlockDriverState *bs, HDGeometry *geo)
+{
+ return bdrv_probe_geometry(bs->file, geo);
+}
+
BlockDriver bdrv_raw = {
.format_name = "raw",
.bdrv_probe = &raw_probe,
@@ -252,6 +262,8 @@ BlockDriver bdrv_raw = {
.has_variable_length = true,
.bdrv_get_info = &raw_get_info,
.bdrv_refresh_limits = &raw_refresh_limits,
+ .bdrv_probe_blocksizes = &raw_probe_blocksizes,
+ .bdrv_probe_geometry = &raw_probe_geometry,
.bdrv_is_inserted = &raw_is_inserted,
.bdrv_media_changed = &raw_media_changed,
.bdrv_eject = &raw_eject,
diff --git a/block/sheepdog.c b/block/sheepdog.c
index d17ee360c..c14172cfa 100644
--- a/block/sheepdog.c
+++ b/block/sheepdog.c
@@ -37,6 +37,7 @@
#define SD_OP_READ_VDIS 0x15
#define SD_OP_FLUSH_VDI 0x16
#define SD_OP_DEL_VDI 0x17
+#define SD_OP_GET_CLUSTER_DEFAULT 0x18
#define SD_FLAG_CMD_WRITE 0x01
#define SD_FLAG_CMD_COW 0x02
@@ -91,6 +92,7 @@
#define SD_NR_VDIS (1U << 24)
#define SD_DATA_OBJ_SIZE (UINT64_C(1) << 22)
#define SD_MAX_VDI_SIZE (SD_DATA_OBJ_SIZE * MAX_DATA_OBJS)
+#define SD_DEFAULT_BLOCK_SIZE_SHIFT 22
/*
* For erasure coding, we use at most SD_EC_MAX_STRIP for data strips and
* (SD_EC_MAX_STRIP - 1) for parity strips
@@ -167,7 +169,8 @@ typedef struct SheepdogVdiReq {
uint32_t base_vdi_id;
uint8_t copies;
uint8_t copy_policy;
- uint8_t reserved[2];
+ uint8_t store_policy;
+ uint8_t block_size_shift;
uint32_t snapid;
uint32_t type;
uint32_t pad[2];
@@ -186,6 +189,21 @@ typedef struct SheepdogVdiRsp {
uint32_t pad[5];
} SheepdogVdiRsp;
+typedef struct SheepdogClusterRsp {
+ uint8_t proto_ver;
+ uint8_t opcode;
+ uint16_t flags;
+ uint32_t epoch;
+ uint32_t id;
+ uint32_t data_length;
+ uint32_t result;
+ uint8_t nr_copies;
+ uint8_t copy_policy;
+ uint8_t block_size_shift;
+ uint8_t __pad1;
+ uint32_t __pad2[6];
+} SheepdogClusterRsp;
+
typedef struct SheepdogInode {
char name[SD_MAX_VDI_LEN];
char tag[SD_MAX_VDI_TAG_LEN];
@@ -527,6 +545,7 @@ static SheepdogAIOCB *sd_aio_setup(BlockDriverState *bs, QEMUIOVector *qiov,
return acb;
}
+/* Return -EIO in case of error, file descriptor on success */
static int connect_to_sdog(BDRVSheepdogState *s, Error **errp)
{
int fd;
@@ -546,11 +565,14 @@ static int connect_to_sdog(BDRVSheepdogState *s, Error **errp)
if (fd >= 0) {
qemu_set_nonblock(fd);
+ } else {
+ fd = -EIO;
}
return fd;
}
+/* Return 0 on success and -errno in case of error */
static coroutine_fn int send_co_req(int sockfd, SheepdogReq *hdr, void *data,
unsigned int *wlen)
{
@@ -559,11 +581,13 @@ static coroutine_fn int send_co_req(int sockfd, SheepdogReq *hdr, void *data,
ret = qemu_co_send(sockfd, hdr, sizeof(*hdr));
if (ret != sizeof(*hdr)) {
error_report("failed to send a req, %s", strerror(errno));
+ ret = -socket_error();
return ret;
}
ret = qemu_co_send(sockfd, data, *wlen);
if (ret != *wlen) {
+ ret = -socket_error();
error_report("failed to send a req, %s", strerror(errno));
}
@@ -638,6 +662,11 @@ out:
srco->finished = true;
}
+/*
+ * Send the request to the sheep in a synchronous manner.
+ *
+ * Return 0 on success, -errno in case of error.
+ */
static int do_req(int sockfd, AioContext *aio_context, SheepdogReq *hdr,
void *data, unsigned int *wlen, unsigned int *rlen)
{
@@ -1541,6 +1570,7 @@ static int do_sd_create(BDRVSheepdogState *s, uint32_t *vdi_id, int snapshot,
hdr.vdi_size = s->inode.vdi_size;
hdr.copy_policy = s->inode.copy_policy;
hdr.copies = s->inode.nr_copies;
+ hdr.block_size_shift = s->inode.block_size_shift;
ret = do_req(fd, s->aio_context, (SheepdogReq *)&hdr, buf, &wlen, &rlen);
@@ -1566,9 +1596,12 @@ static int do_sd_create(BDRVSheepdogState *s, uint32_t *vdi_id, int snapshot,
static int sd_prealloc(const char *filename, Error **errp)
{
BlockDriverState *bs = NULL;
+ BDRVSheepdogState *base = NULL;
+ unsigned long buf_size;
uint32_t idx, max_idx;
+ uint32_t object_size;
int64_t vdi_size;
- void *buf = g_malloc0(SD_DATA_OBJ_SIZE);
+ void *buf = NULL;
int ret;
ret = bdrv_open(&bs, filename, NULL, NULL, BDRV_O_RDWR | BDRV_O_PROTOCOL,
@@ -1582,18 +1615,24 @@ static int sd_prealloc(const char *filename, Error **errp)
ret = vdi_size;
goto out;
}
- max_idx = DIV_ROUND_UP(vdi_size, SD_DATA_OBJ_SIZE);
+
+ base = bs->opaque;
+ object_size = (UINT32_C(1) << base->inode.block_size_shift);
+ buf_size = MIN(object_size, SD_DATA_OBJ_SIZE);
+ buf = g_malloc0(buf_size);
+
+ max_idx = DIV_ROUND_UP(vdi_size, buf_size);
for (idx = 0; idx < max_idx; idx++) {
/*
* The created image can be a cloned image, so we need to read
* a data from the source image.
*/
- ret = bdrv_pread(bs, idx * SD_DATA_OBJ_SIZE, buf, SD_DATA_OBJ_SIZE);
+ ret = bdrv_pread(bs, idx * buf_size, buf, buf_size);
if (ret < 0) {
goto out;
}
- ret = bdrv_pwrite(bs, idx * SD_DATA_OBJ_SIZE, buf, SD_DATA_OBJ_SIZE);
+ ret = bdrv_pwrite(bs, idx * buf_size, buf, buf_size);
if (ret < 0) {
goto out;
}
@@ -1666,6 +1705,27 @@ static int parse_redundancy(BDRVSheepdogState *s, const char *opt)
return 0;
}
+static int parse_block_size_shift(BDRVSheepdogState *s, QemuOpts *opt)
+{
+ struct SheepdogInode *inode = &s->inode;
+ uint64_t object_size;
+ int obj_order;
+
+ object_size = qemu_opt_get_size_del(opt, BLOCK_OPT_OBJECT_SIZE, 0);
+ if (object_size) {
+ if ((object_size - 1) & object_size) { /* not a power of 2? */
+ return -EINVAL;
+ }
+ obj_order = ffs(object_size) - 1;
+ if (obj_order < 20 || obj_order > 31) {
+ return -EINVAL;
+ }
+ inode->block_size_shift = (uint8_t)obj_order;
+ }
+
+ return 0;
+}
+
static int sd_create(const char *filename, QemuOpts *opts,
Error **errp)
{
@@ -1676,6 +1736,7 @@ static int sd_create(const char *filename, QemuOpts *opts,
BDRVSheepdogState *s;
char tag[SD_MAX_VDI_TAG_LEN];
uint32_t snapid;
+ uint64_t max_vdi_size;
bool prealloc = false;
s = g_new0(BDRVSheepdogState, 1);
@@ -1714,10 +1775,11 @@ static int sd_create(const char *filename, QemuOpts *opts,
goto out;
}
}
-
- if (s->inode.vdi_size > SD_MAX_VDI_SIZE) {
- error_setg(errp, "too big image size");
- ret = -EINVAL;
+ ret = parse_block_size_shift(s, opts);
+ if (ret < 0) {
+ error_setg(errp, "Invalid object_size."
+ " obect_size needs to be power of 2"
+ " and be limited from 2^20 to 2^31");
goto out;
}
@@ -1754,6 +1816,51 @@ static int sd_create(const char *filename, QemuOpts *opts,
}
s->aio_context = qemu_get_aio_context();
+
+ /* if block_size_shift is not specified, get cluster default value */
+ if (s->inode.block_size_shift == 0) {
+ SheepdogVdiReq hdr;
+ SheepdogClusterRsp *rsp = (SheepdogClusterRsp *)&hdr;
+ Error *local_err = NULL;
+ int fd;
+ unsigned int wlen = 0, rlen = 0;
+
+ fd = connect_to_sdog(s, &local_err);
+ if (fd < 0) {
+ error_report("%s", error_get_pretty(local_err));
+ error_free(local_err);
+ ret = -EIO;
+ goto out;
+ }
+
+ memset(&hdr, 0, sizeof(hdr));
+ hdr.opcode = SD_OP_GET_CLUSTER_DEFAULT;
+ hdr.proto_ver = SD_PROTO_VER;
+
+ ret = do_req(fd, s->aio_context, (SheepdogReq *)&hdr,
+ NULL, &wlen, &rlen);
+ closesocket(fd);
+ if (ret) {
+ error_setg_errno(errp, -ret, "failed to get cluster default");
+ goto out;
+ }
+ if (rsp->result == SD_RES_SUCCESS) {
+ s->inode.block_size_shift = rsp->block_size_shift;
+ } else {
+ s->inode.block_size_shift = SD_DEFAULT_BLOCK_SIZE_SHIFT;
+ }
+ }
+
+ max_vdi_size = (UINT64_C(1) << s->inode.block_size_shift) * MAX_DATA_OBJS;
+
+ if (s->inode.vdi_size > max_vdi_size) {
+ error_setg(errp, "An image is too large."
+ " The maximum image size is %"PRIu64 "GB",
+ max_vdi_size / 1024 / 1024 / 1024);
+ ret = -EINVAL;
+ goto out;
+ }
+
ret = do_sd_create(s, &vid, 0, errp);
if (ret) {
goto out;
@@ -1823,11 +1930,13 @@ static int sd_truncate(BlockDriverState *bs, int64_t offset)
BDRVSheepdogState *s = bs->opaque;
int ret, fd;
unsigned int datalen;
+ uint64_t max_vdi_size;
+ max_vdi_size = (UINT64_C(1) << s->inode.block_size_shift) * MAX_DATA_OBJS;
if (offset < s->inode.vdi_size) {
error_report("shrinking is not supported");
return -EINVAL;
- } else if (offset > SD_MAX_VDI_SIZE) {
+ } else if (offset > max_vdi_size) {
error_report("too big image size");
return -EINVAL;
}
@@ -2005,9 +2114,10 @@ static int coroutine_fn sd_co_rw_vector(void *p)
SheepdogAIOCB *acb = p;
int ret = 0;
unsigned long len, done = 0, total = acb->nb_sectors * BDRV_SECTOR_SIZE;
- unsigned long idx = acb->sector_num * BDRV_SECTOR_SIZE / SD_DATA_OBJ_SIZE;
+ unsigned long idx;
+ uint32_t object_size;
uint64_t oid;
- uint64_t offset = (acb->sector_num * BDRV_SECTOR_SIZE) % SD_DATA_OBJ_SIZE;
+ uint64_t offset;
BDRVSheepdogState *s = acb->common.bs->opaque;
SheepdogInode *inode = &s->inode;
AIOReq *aio_req;
@@ -2024,6 +2134,10 @@ static int coroutine_fn sd_co_rw_vector(void *p)
}
}
+ object_size = (UINT32_C(1) << inode->block_size_shift);
+ idx = acb->sector_num * BDRV_SECTOR_SIZE / object_size;
+ offset = (acb->sector_num * BDRV_SECTOR_SIZE) % object_size;
+
/*
* Make sure we don't free the aiocb before we are done with all requests.
* This additional reference is dropped at the end of this function.
@@ -2037,7 +2151,7 @@ static int coroutine_fn sd_co_rw_vector(void *p)
oid = vid_to_data_oid(inode->data_vdi_id[idx], idx);
- len = MIN(total - done, SD_DATA_OBJ_SIZE - offset);
+ len = MIN(total - done, object_size - offset);
switch (acb->aiocb_type) {
case AIOCB_READ_UDATA:
@@ -2061,7 +2175,7 @@ static int coroutine_fn sd_co_rw_vector(void *p)
* We discard the object only when the whole object is
* 1) allocated 2) trimmed. Otherwise, simply skip it.
*/
- if (len != SD_DATA_OBJ_SIZE || inode->data_vdi_id[idx] == 0) {
+ if (len != object_size || inode->data_vdi_id[idx] == 0) {
goto done;
}
break;
@@ -2225,9 +2339,8 @@ static int sd_snapshot_create(BlockDriverState *bs, QEMUSnapshotInfo *sn_info)
ret = do_sd_create(s, &new_vid, 1, &local_err);
if (ret < 0) {
- error_report_err(local_err);
- error_report("failed to create inode for snapshot. %s",
- strerror(errno));
+ error_report("failed to create inode for snapshot: %s",
+ error_get_pretty(local_err));
goto cleanup;
}
@@ -2414,6 +2527,7 @@ static int do_load_save_vmstate(BDRVSheepdogState *s, uint8_t *data,
uint64_t offset;
uint32_t vdi_index;
uint32_t vdi_id = load ? s->inode.parent_vdi_id : s->inode.vdi_id;
+ uint32_t object_size = (UINT32_C(1) << s->inode.block_size_shift);
fd = connect_to_sdog(s, &local_err);
if (fd < 0) {
@@ -2422,10 +2536,10 @@ static int do_load_save_vmstate(BDRVSheepdogState *s, uint8_t *data,
}
while (remaining) {
- vdi_index = pos / SD_DATA_OBJ_SIZE;
- offset = pos % SD_DATA_OBJ_SIZE;
+ vdi_index = pos / object_size;
+ offset = pos % object_size;
- data_len = MIN(remaining, SD_DATA_OBJ_SIZE - offset);
+ data_len = MIN(remaining, object_size - offset);
vmstate_oid = vid_to_vmstate_oid(vdi_id, vdi_index);
@@ -2512,10 +2626,11 @@ sd_co_get_block_status(BlockDriverState *bs, int64_t sector_num, int nb_sectors,
{
BDRVSheepdogState *s = bs->opaque;
SheepdogInode *inode = &s->inode;
+ uint32_t object_size = (UINT32_C(1) << inode->block_size_shift);
uint64_t offset = sector_num * BDRV_SECTOR_SIZE;
- unsigned long start = offset / SD_DATA_OBJ_SIZE,
+ unsigned long start = offset / object_size,
end = DIV_ROUND_UP((sector_num + nb_sectors) *
- BDRV_SECTOR_SIZE, SD_DATA_OBJ_SIZE);
+ BDRV_SECTOR_SIZE, object_size);
unsigned long idx;
int64_t ret = BDRV_BLOCK_DATA | BDRV_BLOCK_OFFSET_VALID | offset;
@@ -2534,7 +2649,7 @@ sd_co_get_block_status(BlockDriverState *bs, int64_t sector_num, int nb_sectors,
}
}
- *pnum = (idx - start) * SD_DATA_OBJ_SIZE / BDRV_SECTOR_SIZE;
+ *pnum = (idx - start) * object_size / BDRV_SECTOR_SIZE;
if (*pnum > nb_sectors) {
*pnum = nb_sectors;
}
@@ -2545,14 +2660,15 @@ static int64_t sd_get_allocated_file_size(BlockDriverState *bs)
{
BDRVSheepdogState *s = bs->opaque;
SheepdogInode *inode = &s->inode;
- unsigned long i, last = DIV_ROUND_UP(inode->vdi_size, SD_DATA_OBJ_SIZE);
+ uint32_t object_size = (UINT32_C(1) << inode->block_size_shift);
+ unsigned long i, last = DIV_ROUND_UP(inode->vdi_size, object_size);
uint64_t size = 0;
for (i = 0; i < last; i++) {
if (inode->data_vdi_id[i] == 0) {
continue;
}
- size += SD_DATA_OBJ_SIZE;
+ size += object_size;
}
return size;
}
@@ -2581,6 +2697,11 @@ static QemuOptsList sd_create_opts = {
.type = QEMU_OPT_STRING,
.help = "Redundancy of the image"
},
+ {
+ .name = BLOCK_OPT_OBJECT_SIZE,
+ .type = QEMU_OPT_SIZE,
+ .help = "Object size of the image"
+ },
{ /* end of list */ }
}
};
diff --git a/block/vdi.c b/block/vdi.c
index 74030c6e3..53bd02fe2 100644
--- a/block/vdi.c
+++ b/block/vdi.c
@@ -53,6 +53,7 @@
#include "block/block_int.h"
#include "qemu/module.h"
#include "migration/migration.h"
+#include "block/coroutine.h"
#if defined(CONFIG_UUID)
#include <uuid/uuid.h>
@@ -196,6 +197,8 @@ typedef struct {
/* VDI header (converted to host endianness). */
VdiHeader header;
+ CoMutex write_lock;
+
Error *migration_blocker;
} BDRVVdiState;
@@ -504,6 +507,8 @@ static int vdi_open(BlockDriverState *bs, QDict *options, int flags,
"vdi", bdrv_get_device_name(bs), "live migration");
migrate_add_blocker(s->migration_blocker);
+ qemu_co_mutex_init(&s->write_lock);
+
return 0;
fail_free_bmap:
@@ -639,11 +644,31 @@ static int vdi_co_write(BlockDriverState *bs,
buf, n_sectors * SECTOR_SIZE);
memset(block + (sector_in_block + n_sectors) * SECTOR_SIZE, 0,
(s->block_sectors - n_sectors - sector_in_block) * SECTOR_SIZE);
+
+ /* Note that this coroutine does not yield anywhere from reading the
+ * bmap entry until here, so in regards to all the coroutines trying
+ * to write to this cluster, the one doing the allocation will
+ * always be the first to try to acquire the lock.
+ * Therefore, it is also the first that will actually be able to
+ * acquire the lock and thus the padded cluster is written before
+ * the other coroutines can write to the affected area. */
+ qemu_co_mutex_lock(&s->write_lock);
ret = bdrv_write(bs->file, offset, block, s->block_sectors);
+ qemu_co_mutex_unlock(&s->write_lock);
} else {
uint64_t offset = s->header.offset_data / SECTOR_SIZE +
(uint64_t)bmap_entry * s->block_sectors +
sector_in_block;
+ qemu_co_mutex_lock(&s->write_lock);
+ /* This lock is only used to make sure the following write operation
+ * is executed after the write issued by the coroutine allocating
+ * this cluster, therefore we do not need to keep it locked.
+ * As stated above, the allocating coroutine will always try to lock
+ * the mutex before all the other concurrent accesses to that
+ * cluster, therefore at this point we can be absolutely certain
+ * that that write operation has returned (there may be other writes
+ * in flight, but they do not concern this very operation). */
+ qemu_co_mutex_unlock(&s->write_lock);
ret = bdrv_write(bs->file, offset, buf, n_sectors);
}
diff --git a/block/vpc.c b/block/vpc.c
index 46803b14b..1533b6a64 100644
--- a/block/vpc.c
+++ b/block/vpc.c
@@ -597,6 +597,51 @@ static coroutine_fn int vpc_co_write(BlockDriverState *bs, int64_t sector_num,
return ret;
}
+static int64_t coroutine_fn vpc_co_get_block_status(BlockDriverState *bs,
+ int64_t sector_num, int nb_sectors, int *pnum)
+{
+ BDRVVPCState *s = bs->opaque;
+ VHDFooter *footer = (VHDFooter*) s->footer_buf;
+ int64_t start, offset, next;
+ bool allocated;
+ int n;
+
+ if (be32_to_cpu(footer->type) == VHD_FIXED) {
+ *pnum = nb_sectors;
+ return BDRV_BLOCK_RAW | BDRV_BLOCK_OFFSET_VALID | BDRV_BLOCK_DATA |
+ (sector_num << BDRV_SECTOR_BITS);
+ }
+
+ offset = get_sector_offset(bs, sector_num, 0);
+ start = offset;
+ allocated = (offset != -1);
+ *pnum = 0;
+
+ do {
+ /* All sectors in a block are contiguous (without using the bitmap) */
+ n = ROUND_UP(sector_num + 1, s->block_size / BDRV_SECTOR_SIZE)
+ - sector_num;
+ n = MIN(n, nb_sectors);
+
+ *pnum += n;
+ sector_num += n;
+ nb_sectors -= n;
+ next = start + (*pnum * BDRV_SECTOR_SIZE);
+
+ if (nb_sectors == 0) {
+ break;
+ }
+
+ offset = get_sector_offset(bs, sector_num, 0);
+ } while ((allocated && offset == next) || (!allocated && offset == -1));
+
+ if (allocated) {
+ return BDRV_BLOCK_DATA | BDRV_BLOCK_OFFSET_VALID | start;
+ } else {
+ return 0;
+ }
+}
+
/*
* Calculates the number of cylinders, heads and sectors per cylinder
* based on a given number of sectors. This is the algorithm described
@@ -801,6 +846,7 @@ static int vpc_create(const char *filename, QemuOpts *opts, Error **errp)
}
total_sectors = (int64_t) cyls * heads * secs_per_cyl;
+ total_size = total_sectors * BDRV_SECTOR_SIZE;
/* Prepare the Hard Disk Footer */
memset(buf, 0, 1024);
@@ -822,13 +868,8 @@ static int vpc_create(const char *filename, QemuOpts *opts, Error **errp)
/* Version of Virtual PC 2007 */
footer->major = cpu_to_be16(0x0005);
footer->minor = cpu_to_be16(0x0003);
- if (disk_type == VHD_DYNAMIC) {
- footer->orig_size = cpu_to_be64(total_sectors * 512);
- footer->size = cpu_to_be64(total_sectors * 512);
- } else {
- footer->orig_size = cpu_to_be64(total_size);
- footer->size = cpu_to_be64(total_size);
- }
+ footer->orig_size = cpu_to_be64(total_size);
+ footer->size = cpu_to_be64(total_size);
footer->cyls = cpu_to_be16(cyls);
footer->heads = heads;
footer->secs_per_cyl = secs_per_cyl;
@@ -907,8 +948,9 @@ static BlockDriver bdrv_vpc = {
.bdrv_reopen_prepare = vpc_reopen_prepare,
.bdrv_create = vpc_create,
- .bdrv_read = vpc_co_read,
- .bdrv_write = vpc_co_write,
+ .bdrv_read = vpc_co_read,
+ .bdrv_write = vpc_co_write,
+ .bdrv_co_get_block_status = vpc_co_get_block_status,
.bdrv_get_info = vpc_get_info,
diff --git a/bsd-user/main.c b/bsd-user/main.c
index 0e8c26c13..1bb27548f 100644
--- a/bsd-user/main.c
+++ b/bsd-user/main.c
@@ -908,12 +908,12 @@ int main(int argc, char **argv)
cpu_exec_init_all();
/* NOTE: we need to init the CPU at this stage to get
qemu_host_page_size */
- env = cpu_init(cpu_model);
- if (!env) {
+ cpu = cpu_init(cpu_model);
+ if (!cpu) {
fprintf(stderr, "Unable to find CPU definition\n");
exit(1);
}
- cpu = ENV_GET_CPU(env);
+ env = cpu->env_ptr;
#if defined(TARGET_SPARC) || defined(TARGET_PPC)
cpu_reset(cpu);
#endif
diff --git a/default-configs/arm-softmmu.mak b/default-configs/arm-softmmu.mak
index 149ae1b59..87d4e34d1 100644
--- a/default-configs/arm-softmmu.mak
+++ b/default-configs/arm-softmmu.mak
@@ -80,6 +80,10 @@ CONFIG_NSERIES=y
CONFIG_REALVIEW=y
CONFIG_ZAURUS=y
CONFIG_ZYNQ=y
+CONFIG_STM32F2XX_TIMER=y
+CONFIG_STM32F2XX_USART=y
+CONFIG_STM32F2XX_SYSCFG=y
+CONFIG_STM32F205_SOC=y
CONFIG_VERSATILE_PCI=y
CONFIG_VERSATILE_I2C=y
diff --git a/exec.c b/exec.c
index bc37c7b48..e97071a3e 100644
--- a/exec.c
+++ b/exec.c
@@ -551,6 +551,7 @@ void cpu_exec_init(CPUArchState *env)
#ifndef CONFIG_USER_ONLY
cpu->as = &address_space_memory;
cpu->thread_id = qemu_get_thread_id();
+ cpu_reload_memory_map(cpu);
#endif
QTAILQ_INSERT_TAIL(&cpus, cpu, node);
#if defined(CONFIG_USER_ONLY)
diff --git a/hw/arm/Makefile.objs b/hw/arm/Makefile.objs
index 6088e5365..2577f6809 100644
--- a/hw/arm/Makefile.objs
+++ b/hw/arm/Makefile.objs
@@ -3,8 +3,10 @@ obj-$(CONFIG_DIGIC) += digic_boards.o
obj-y += integratorcp.o kzm.o mainstone.o musicpal.o nseries.o
obj-y += omap_sx1.o palm.o realview.o spitz.o stellaris.o
obj-y += tosa.o versatilepb.o vexpress.o virt.o xilinx_zynq.o z2.o
+obj-y += netduino2.o
obj-y += armv7m.o exynos4210.o pxa2xx.o pxa2xx_gpio.o pxa2xx_pic.o
obj-$(CONFIG_DIGIC) += digic.o
obj-y += omap1.o omap2.o strongarm.o
obj-$(CONFIG_ALLWINNER_A10) += allwinner-a10.o cubieboard.o
+obj-$(CONFIG_STM32F205_SOC) += stm32f205_soc.o
diff --git a/hw/arm/integratorcp.c b/hw/arm/integratorcp.c
index 949ae1ed3..cb609cdbd 100644
--- a/hw/arm/integratorcp.c
+++ b/hw/arm/integratorcp.c
@@ -406,16 +406,39 @@ static int icp_pic_init(SysBusDevice *sbd)
/* CP control registers. */
+#define TYPE_ICP_CONTROL_REGS "icp-ctrl-regs"
+#define ICP_CONTROL_REGS(obj) \
+ OBJECT_CHECK(ICPCtrlRegsState, (obj), TYPE_ICP_CONTROL_REGS)
+
+typedef struct ICPCtrlRegsState {
+ /*< private >*/
+ SysBusDevice parent_obj;
+ /*< public >*/
+
+ MemoryRegion iomem;
+
+ qemu_irq mmc_irq;
+ uint32_t intreg_state;
+} ICPCtrlRegsState;
+
+#define ICP_GPIO_MMC_WPROT "mmc-wprot"
+#define ICP_GPIO_MMC_CARDIN "mmc-cardin"
+
+#define ICP_INTREG_WPROT (1 << 0)
+#define ICP_INTREG_CARDIN (1 << 3)
+
static uint64_t icp_control_read(void *opaque, hwaddr offset,
unsigned size)
{
+ ICPCtrlRegsState *s = opaque;
+
switch (offset >> 2) {
case 0: /* CP_IDFIELD */
return 0x41034003;
case 1: /* CP_FLASHPROG */
return 0;
case 2: /* CP_INTREG */
- return 0;
+ return s->intreg_state;
case 3: /* CP_DECODE */
return 0x11;
default:
@@ -427,9 +450,14 @@ static uint64_t icp_control_read(void *opaque, hwaddr offset,
static void icp_control_write(void *opaque, hwaddr offset,
uint64_t value, unsigned size)
{
+ ICPCtrlRegsState *s = opaque;
+
switch (offset >> 2) {
- case 1: /* CP_FLASHPROG */
case 2: /* CP_INTREG */
+ s->intreg_state &= ~(value & ICP_INTREG_CARDIN);
+ qemu_set_irq(s->mmc_irq, !!(s->intreg_state & ICP_INTREG_CARDIN));
+ break;
+ case 1: /* CP_FLASHPROG */
case 3: /* CP_DECODE */
/* Nothing interesting implemented yet. */
break;
@@ -444,15 +472,41 @@ static const MemoryRegionOps icp_control_ops = {
.endianness = DEVICE_NATIVE_ENDIAN,
};
-static void icp_control_init(hwaddr base)
+static void icp_control_mmc_wprot(void *opaque, int line, int level)
{
- MemoryRegion *io;
+ ICPCtrlRegsState *s = opaque;
- io = (MemoryRegion *)g_malloc0(sizeof(MemoryRegion));
- memory_region_init_io(io, NULL, &icp_control_ops, NULL,
- "control", 0x00800000);
- memory_region_add_subregion(get_system_memory(), base, io);
- /* ??? Save/restore. */
+ s->intreg_state &= ~ICP_INTREG_WPROT;
+ if (level) {
+ s->intreg_state |= ICP_INTREG_WPROT;
+ }
+}
+
+static void icp_control_mmc_cardin(void *opaque, int line, int level)
+{
+ ICPCtrlRegsState *s = opaque;
+
+ /* line is released by writing to CP_INTREG */
+ if (level) {
+ s->intreg_state |= ICP_INTREG_CARDIN;
+ qemu_set_irq(s->mmc_irq, 1);
+ }
+}
+
+static void icp_control_init(Object *obj)
+{
+ SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
+ ICPCtrlRegsState *s = ICP_CONTROL_REGS(obj);
+ DeviceState *dev = DEVICE(obj);
+
+ memory_region_init_io(&s->iomem, OBJECT(s), &icp_control_ops, s,
+ "icp_ctrl_regs", 0x00800000);
+ sysbus_init_mmio(sbd, &s->iomem);
+
+ qdev_init_gpio_in_named(dev, icp_control_mmc_wprot, ICP_GPIO_MMC_WPROT, 1);
+ qdev_init_gpio_in_named(dev, icp_control_mmc_cardin,
+ ICP_GPIO_MMC_CARDIN, 1);
+ sysbus_init_irq(sbd, &s->mmc_irq);
}
@@ -477,7 +531,7 @@ static void integratorcp_init(MachineState *machine)
MemoryRegion *ram = g_new(MemoryRegion, 1);
MemoryRegion *ram_alias = g_new(MemoryRegion, 1);
qemu_irq pic[32];
- DeviceState *dev;
+ DeviceState *dev, *sic, *icp;
int i;
Error *err = NULL;
@@ -535,17 +589,24 @@ static void integratorcp_init(MachineState *machine)
for (i = 0; i < 32; i++) {
pic[i] = qdev_get_gpio_in(dev, i);
}
- sysbus_create_simple(TYPE_INTEGRATOR_PIC, 0xca000000, pic[26]);
+ sic = sysbus_create_simple(TYPE_INTEGRATOR_PIC, 0xca000000, pic[26]);
sysbus_create_varargs("integrator_pit", 0x13000000,
pic[5], pic[6], pic[7], NULL);
sysbus_create_simple("pl031", 0x15000000, pic[8]);
sysbus_create_simple("pl011", 0x16000000, pic[1]);
sysbus_create_simple("pl011", 0x17000000, pic[2]);
- icp_control_init(0xcb000000);
+ icp = sysbus_create_simple(TYPE_ICP_CONTROL_REGS, 0xcb000000,
+ qdev_get_gpio_in(sic, 3));
sysbus_create_simple("pl050_keyboard", 0x18000000, pic[3]);
sysbus_create_simple("pl050_mouse", 0x19000000, pic[4]);
sysbus_create_simple(TYPE_INTEGRATOR_DEBUG, 0x1a000000, 0);
- sysbus_create_varargs("pl181", 0x1c000000, pic[23], pic[24], NULL);
+
+ dev = sysbus_create_varargs("pl181", 0x1c000000, pic[23], pic[24], NULL);
+ qdev_connect_gpio_out(dev, 0,
+ qdev_get_gpio_in_named(icp, ICP_GPIO_MMC_WPROT, 0));
+ qdev_connect_gpio_out(dev, 1,
+ qdev_get_gpio_in_named(icp, ICP_GPIO_MMC_CARDIN, 0));
+
if (nd_table[0].used)
smc91c111_init(&nd_table[0], 0xc8000000, pic[27]);
@@ -606,10 +667,18 @@ static const TypeInfo icp_pic_info = {
.class_init = icp_pic_class_init,
};
+static const TypeInfo icp_ctrl_regs_info = {
+ .name = TYPE_ICP_CONTROL_REGS,
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(ICPCtrlRegsState),
+ .instance_init = icp_control_init,
+};
+
static void integratorcp_register_types(void)
{
type_register_static(&icp_pic_info);
type_register_static(&core_info);
+ type_register_static(&icp_ctrl_regs_info);
}
type_init(integratorcp_register_types)
diff --git a/hw/arm/netduino2.c b/hw/arm/netduino2.c
new file mode 100644
index 000000000..8f26780ef
--- /dev/null
+++ b/hw/arm/netduino2.c
@@ -0,0 +1,57 @@
+/*
+ * Netduino 2 Machine Model
+ *
+ * Copyright (c) 2014 Alistair Francis <alistair@alistair23.me>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "hw/boards.h"
+#include "qemu/error-report.h"
+#include "hw/arm/stm32f205_soc.h"
+
+static void netduino2_init(MachineState *machine)
+{
+ DeviceState *dev;
+ Error *err = NULL;
+
+ dev = qdev_create(NULL, TYPE_STM32F205_SOC);
+ if (machine->kernel_filename) {
+ qdev_prop_set_string(dev, "kernel-filename", machine->kernel_filename);
+ }
+ qdev_prop_set_string(dev, "cpu-model", "cortex-m3");
+ object_property_set_bool(OBJECT(dev), true, "realized", &err);
+ if (err != NULL) {
+ error_report("%s", error_get_pretty(err));
+ exit(1);
+ }
+}
+
+static QEMUMachine netduino2_machine = {
+ .name = "netduino2",
+ .desc = "Netduino 2 Machine",
+ .init = netduino2_init,
+};
+
+static void netduino2_machine_init(void)
+{
+ qemu_register_machine(&netduino2_machine);
+}
+
+machine_init(netduino2_machine_init);
diff --git a/hw/arm/stm32f205_soc.c b/hw/arm/stm32f205_soc.c
new file mode 100644
index 000000000..0f3bdc77b
--- /dev/null
+++ b/hw/arm/stm32f205_soc.c
@@ -0,0 +1,160 @@
+/*
+ * STM32F205 SoC
+ *
+ * Copyright (c) 2014 Alistair Francis <alistair@alistair23.me>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "hw/arm/arm.h"
+#include "exec/address-spaces.h"
+#include "hw/arm/stm32f205_soc.h"
+
+/* At the moment only Timer 2 to 5 are modelled */
+static const uint32_t timer_addr[STM_NUM_TIMERS] = { 0x40000000, 0x40000400,
+ 0x40000800, 0x40000C00 };
+static const uint32_t usart_addr[STM_NUM_USARTS] = { 0x40011000, 0x40004400,
+ 0x40004800, 0x40004C00, 0x40005000, 0x40011400 };
+
+static const int timer_irq[STM_NUM_TIMERS] = {28, 29, 30, 50};
+static const int usart_irq[STM_NUM_USARTS] = {37, 38, 39, 52, 53, 71};
+
+static void stm32f205_soc_initfn(Object *obj)
+{
+ STM32F205State *s = STM32F205_SOC(obj);
+ int i;
+
+ object_initialize(&s->syscfg, sizeof(s->syscfg), TYPE_STM32F2XX_SYSCFG);
+ qdev_set_parent_bus(DEVICE(&s->syscfg), sysbus_get_default());
+
+ for (i = 0; i < STM_NUM_USARTS; i++) {
+ object_initialize(&s->usart[i], sizeof(s->usart[i]),
+ TYPE_STM32F2XX_USART);
+ qdev_set_parent_bus(DEVICE(&s->usart[i]), sysbus_get_default());
+ }
+
+ for (i = 0; i < STM_NUM_TIMERS; i++) {
+ object_initialize(&s->timer[i], sizeof(s->timer[i]),
+ TYPE_STM32F2XX_TIMER);
+ qdev_set_parent_bus(DEVICE(&s->timer[i]), sysbus_get_default());
+ }
+}
+
+static void stm32f205_soc_realize(DeviceState *dev_soc, Error **errp)
+{
+ STM32F205State *s = STM32F205_SOC(dev_soc);
+ DeviceState *syscfgdev, *usartdev, *timerdev;
+ SysBusDevice *syscfgbusdev, *usartbusdev, *timerbusdev;
+ qemu_irq *pic;
+ Error *err = NULL;
+ int i;
+
+ MemoryRegion *system_memory = get_system_memory();
+ MemoryRegion *sram = g_new(MemoryRegion, 1);
+ MemoryRegion *flash = g_new(MemoryRegion, 1);
+ MemoryRegion *flash_alias = g_new(MemoryRegion, 1);
+
+ memory_region_init_ram(flash, NULL, "STM32F205.flash", FLASH_SIZE,
+ &error_abort);
+ memory_region_init_alias(flash_alias, NULL, "STM32F205.flash.alias",
+ flash, 0, FLASH_SIZE);
+
+ vmstate_register_ram_global(flash);
+
+ memory_region_set_readonly(flash, true);
+ memory_region_set_readonly(flash_alias, true);
+
+ memory_region_add_subregion(system_memory, FLASH_BASE_ADDRESS, flash);
+ memory_region_add_subregion(system_memory, 0, flash_alias);
+
+ memory_region_init_ram(sram, NULL, "STM32F205.sram", SRAM_SIZE,
+ &error_abort);
+ vmstate_register_ram_global(sram);
+ memory_region_add_subregion(system_memory, SRAM_BASE_ADDRESS, sram);
+
+ pic = armv7m_init(get_system_memory(), FLASH_SIZE, 96,
+ s->kernel_filename, s->cpu_model);
+
+ /* System configuration controller */
+ syscfgdev = DEVICE(&s->syscfg);
+ object_property_set_bool(OBJECT(&s->syscfg), true, "realized", &err);
+ if (err != NULL) {
+ error_propagate(errp, err);
+ return;
+ }
+ syscfgbusdev = SYS_BUS_DEVICE(syscfgdev);
+ sysbus_mmio_map(syscfgbusdev, 0, 0x40013800);
+ sysbus_connect_irq(syscfgbusdev, 0, pic[71]);
+
+ /* Attach UART (uses USART registers) and USART controllers */
+ for (i = 0; i < STM_NUM_USARTS; i++) {
+ usartdev = DEVICE(&(s->usart[i]));
+ object_property_set_bool(OBJECT(&s->usart[i]), true, "realized", &err);
+ if (err != NULL) {
+ error_propagate(errp, err);
+ return;
+ }
+ usartbusdev = SYS_BUS_DEVICE(usartdev);
+ sysbus_mmio_map(usartbusdev, 0, usart_addr[i]);
+ sysbus_connect_irq(usartbusdev, 0, pic[usart_irq[i]]);
+ }
+
+ /* Timer 2 to 5 */
+ for (i = 0; i < STM_NUM_TIMERS; i++) {
+ timerdev = DEVICE(&(s->timer[i]));
+ qdev_prop_set_uint64(timerdev, "clock-frequency", 1000000000);
+ object_property_set_bool(OBJECT(&s->timer[i]), true, "realized", &err);
+ if (err != NULL) {
+ error_propagate(errp, err);
+ return;
+ }
+ timerbusdev = SYS_BUS_DEVICE(timerdev);
+ sysbus_mmio_map(timerbusdev, 0, timer_addr[i]);
+ sysbus_connect_irq(timerbusdev, 0, pic[timer_irq[i]]);
+ }
+}
+
+static Property stm32f205_soc_properties[] = {
+ DEFINE_PROP_STRING("kernel-filename", STM32F205State, kernel_filename),
+ DEFINE_PROP_STRING("cpu-model", STM32F205State, cpu_model),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void stm32f205_soc_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+
+ dc->realize = stm32f205_soc_realize;
+ dc->props = stm32f205_soc_properties;
+}
+
+static const TypeInfo stm32f205_soc_info = {
+ .name = TYPE_STM32F205_SOC,
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(STM32F205State),
+ .instance_init = stm32f205_soc_initfn,
+ .class_init = stm32f205_soc_class_init,
+};
+
+static void stm32f205_soc_types(void)
+{
+ type_register_static(&stm32f205_soc_info);
+}
+
+type_init(stm32f205_soc_types)
diff --git a/hw/arm/vexpress.c b/hw/arm/vexpress.c
index 5933454cf..8496c1622 100644
--- a/hw/arm/vexpress.c
+++ b/hw/arm/vexpress.c
@@ -515,9 +515,9 @@ static pflash_t *ve_pflash_cfi01_register(hwaddr base, const char *name,
{
DeviceState *dev = qdev_create(NULL, "cfi.pflash01");
- if (di && qdev_prop_set_drive(dev, "drive",
- blk_by_legacy_dinfo(di))) {
- abort();
+ if (di) {
+ qdev_prop_set_drive(dev, "drive", blk_by_legacy_dinfo(di),
+ &error_abort);
}
qdev_prop_set_uint32(dev, "num-blocks",
diff --git a/hw/arm/virt.c b/hw/arm/virt.c
index 69f51ac0d..9072bc2b1 100644
--- a/hw/arm/virt.c
+++ b/hw/arm/virt.c
@@ -522,9 +522,9 @@ static void create_one_flash(const char *name, hwaddr flashbase,
DeviceState *dev = qdev_create(NULL, "cfi.pflash01");
const uint64_t sectorlength = 256 * 1024;
- if (dinfo && qdev_prop_set_drive(dev, "drive",
- blk_by_legacy_dinfo(dinfo))) {
- abort();
+ if (dinfo) {
+ qdev_prop_set_drive(dev, "drive", blk_by_legacy_dinfo(dinfo),
+ &error_abort);
}
qdev_prop_set_uint32(dev, "num-blocks", flashsize / sectorlength);
@@ -758,6 +758,7 @@ static void machvirt_init(MachineState *machine)
CPUClass *cc = CPU_CLASS(oc);
Object *cpuobj;
Error *err = NULL;
+ char *cpuopts = g_strdup(cpustr[1]);
if (!oc) {
fprintf(stderr, "Unable to find CPU definition\n");
@@ -766,7 +767,8 @@ static void machvirt_init(MachineState *machine)
cpuobj = object_new(object_class_get_name(oc));
/* Handle any CPU options specified by the user */
- cc->parse_features(CPU(cpuobj), cpustr[1], &err);
+ cc->parse_features(CPU(cpuobj), cpuopts, &err);
+ g_free(cpuopts);
if (err) {
error_report("%s", error_get_pretty(err));
exit(1);
diff --git a/hw/block/block.c b/hw/block/block.c
index a625773d4..f7243e5b9 100644
--- a/hw/block/block.c
+++ b/hw/block/block.c
@@ -25,6 +25,30 @@ void blkconf_serial(BlockConf *conf, char **serial)
}
}
+void blkconf_blocksizes(BlockConf *conf)
+{
+ BlockBackend *blk = conf->blk;
+ BlockSizes blocksizes;
+ int backend_ret;
+
+ backend_ret = blk_probe_blocksizes(blk, &blocksizes);
+ /* fill in detected values if they are not defined via qemu command line */
+ if (!conf->physical_block_size) {
+ if (!backend_ret) {
+ conf->physical_block_size = blocksizes.phys;
+ } else {
+ conf->physical_block_size = BDRV_SECTOR_SIZE;
+ }
+ }
+ if (!conf->logical_block_size) {
+ if (!backend_ret) {
+ conf->logical_block_size = blocksizes.log;
+ } else {
+ conf->logical_block_size = BDRV_SECTOR_SIZE;
+ }
+ }
+}
+
void blkconf_geometry(BlockConf *conf, int *ptrans,
unsigned cyls_max, unsigned heads_max, unsigned secs_max,
Error **errp)
diff --git a/hw/block/hd-geometry.c b/hw/block/hd-geometry.c
index 6fcf74df4..b187878fa 100644
--- a/hw/block/hd-geometry.c
+++ b/hw/block/hd-geometry.c
@@ -121,8 +121,16 @@ void hd_geometry_guess(BlockBackend *blk,
int *ptrans)
{
int cylinders, heads, secs, translation;
+ HDGeometry geo;
- if (guess_disk_lchs(blk, &cylinders, &heads, &secs) < 0) {
+ /* Try to probe the backing device geometry, otherwise fallback
+ to the old logic. (as of 12/2014 probing only succeeds on DASDs) */
+ if (blk_probe_geometry(blk, &geo) == 0) {
+ *pcyls = geo.cylinders;
+ *psecs = geo.sectors;
+ *pheads = geo.heads;
+ translation = BIOS_ATA_TRANSLATION_NONE;
+ } else if (guess_disk_lchs(blk, &cylinders, &heads, &secs) < 0) {
/* no LCHS guess: use a standard physical disk geometry */
guess_chs_for_size(blk, pcyls, pheads, psecs);
translation = hd_bios_chs_auto_trans(*pcyls, *pheads, *psecs);
diff --git a/hw/block/nvme.c b/hw/block/nvme.c
index ce079aefd..0f3dfb90e 100644
--- a/hw/block/nvme.c
+++ b/hw/block/nvme.c
@@ -765,6 +765,7 @@ static int nvme_init(PCIDevice *pci_dev)
if (!n->serial) {
return -1;
}
+ blkconf_blocksizes(&n->conf);
pci_conf = pci_dev->config;
pci_conf[PCI_INTERRUPT_PIN] = 1;
diff --git a/hw/block/pflash_cfi01.c b/hw/block/pflash_cfi01.c
index 89d380e59..d28269508 100644
--- a/hw/block/pflash_cfi01.c
+++ b/hw/block/pflash_cfi01.c
@@ -969,8 +969,8 @@ pflash_t *pflash_cfi01_register(hwaddr base,
{
DeviceState *dev = qdev_create(NULL, TYPE_CFI_PFLASH01);
- if (blk && qdev_prop_set_drive(dev, "drive", blk)) {
- abort();
+ if (blk) {
+ qdev_prop_set_drive(dev, "drive", blk, &error_abort);
}
qdev_prop_set_uint32(dev, "num-blocks", nb_blocs);
qdev_prop_set_uint64(dev, "sector-length", sector_len);
diff --git a/hw/block/pflash_cfi02.c b/hw/block/pflash_cfi02.c
index 389b4aa1f..074a005f6 100644
--- a/hw/block/pflash_cfi02.c
+++ b/hw/block/pflash_cfi02.c
@@ -773,8 +773,8 @@ pflash_t *pflash_cfi02_register(hwaddr base,
{
DeviceState *dev = qdev_create(NULL, TYPE_CFI_PFLASH02);
- if (blk && qdev_prop_set_drive(dev, "drive", blk)) {
- abort();
+ if (blk) {
+ qdev_prop_set_drive(dev, "drive", blk, &error_abort);
}
qdev_prop_set_uint32(dev, "num-blocks", nb_blocs);
qdev_prop_set_uint32(dev, "sector-length", sector_len);
diff --git a/hw/block/virtio-blk.c b/hw/block/virtio-blk.c
index 1e5b91862..000c38d2a 100644
--- a/hw/block/virtio-blk.c
+++ b/hw/block/virtio-blk.c
@@ -201,6 +201,7 @@ static int virtio_blk_handle_scsi_req(VirtIOBlockReq *req)
#ifdef __linux__
int i;
VirtIOBlockIoctlReq *ioctl_req;
+ BlockAIOCB *acb;
#endif
/*
@@ -278,8 +279,13 @@ static int virtio_blk_handle_scsi_req(VirtIOBlockReq *req)
ioctl_req->hdr.sbp = elem->in_sg[elem->in_num - 3].iov_base;
ioctl_req->hdr.mx_sb_len = elem->in_sg[elem->in_num - 3].iov_len;
- blk_aio_ioctl(blk->blk, SG_IO, &ioctl_req->hdr,
- virtio_blk_ioctl_complete, ioctl_req);
+ acb = blk_aio_ioctl(blk->blk, SG_IO, &ioctl_req->hdr,
+ virtio_blk_ioctl_complete, ioctl_req);
+ if (!acb) {
+ g_free(ioctl_req);
+ status = VIRTIO_BLK_S_UNSUPP;
+ goto fail;
+ }
return -EINPROGRESS;
#else
abort();
@@ -591,12 +597,6 @@ static void virtio_blk_handle_output(VirtIODevice *vdev, VirtQueue *vq)
if (mrb.num_reqs) {
virtio_blk_submit_multireq(s->blk, &mrb);
}
-
- /*
- * FIXME: Want to check for completions before returning to guest mode,
- * so cached reads and writes are reported as quickly as possible. But
- * that should be done in the generic block layer.
- */
}
static void virtio_blk_dma_restart_bh(void *opaque)
@@ -884,6 +884,7 @@ static void virtio_blk_device_realize(DeviceState *dev, Error **errp)
error_propagate(errp, err);
return;
}
+ blkconf_blocksizes(&conf->conf);
virtio_init(vdev, "virtio-blk", VIRTIO_ID_BLOCK,
sizeof(struct virtio_blk_config));
diff --git a/hw/char/Makefile.objs b/hw/char/Makefile.objs
index 317385d26..5931cc840 100644
--- a/hw/char/Makefile.objs
+++ b/hw/char/Makefile.objs
@@ -15,6 +15,7 @@ obj-$(CONFIG_OMAP) += omap_uart.o
obj-$(CONFIG_SH4) += sh_serial.o
obj-$(CONFIG_PSERIES) += spapr_vty.o
obj-$(CONFIG_DIGIC) += digic-uart.o
+obj-$(CONFIG_STM32F2XX_USART) += stm32f2xx_usart.o
common-obj-$(CONFIG_ETRAXFS) += etraxfs_ser.o
common-obj-$(CONFIG_ISA_DEBUG) += debugcon.o
diff --git a/hw/char/stm32f2xx_usart.c b/hw/char/stm32f2xx_usart.c
new file mode 100644
index 000000000..260b05304
--- /dev/null
+++ b/hw/char/stm32f2xx_usart.c
@@ -0,0 +1,229 @@
+/*
+ * STM32F2XX USART
+ *
+ * Copyright (c) 2014 Alistair Francis <alistair@alistair23.me>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "hw/char/stm32f2xx_usart.h"
+
+#ifndef STM_USART_ERR_DEBUG
+#define STM_USART_ERR_DEBUG 0
+#endif
+
+#define DB_PRINT_L(lvl, fmt, args...) do { \
+ if (STM_USART_ERR_DEBUG >= lvl) { \
+ qemu_log("%s: " fmt, __func__, ## args); \
+ } \
+} while (0);
+
+#define DB_PRINT(fmt, args...) DB_PRINT_L(1, fmt, ## args)
+
+static int stm32f2xx_usart_can_receive(void *opaque)
+{
+ STM32F2XXUsartState *s = opaque;
+
+ if (!(s->usart_sr & USART_SR_RXNE)) {
+ return 1;
+ }
+
+ return 0;
+}
+
+static void stm32f2xx_usart_receive(void *opaque, const uint8_t *buf, int size)
+{
+ STM32F2XXUsartState *s = opaque;
+
+ s->usart_dr = *buf;
+
+ if (!(s->usart_cr1 & USART_CR1_UE && s->usart_cr1 & USART_CR1_RE)) {
+ /* USART not enabled - drop the chars */
+ DB_PRINT("Dropping the chars\n");
+ return;
+ }
+
+ s->usart_sr |= USART_SR_RXNE;
+
+ if (s->usart_cr1 & USART_CR1_RXNEIE) {
+ qemu_set_irq(s->irq, 1);
+ }
+
+ DB_PRINT("Receiving: %c\n", s->usart_dr);
+}
+
+static void stm32f2xx_usart_reset(DeviceState *dev)
+{
+ STM32F2XXUsartState *s = STM32F2XX_USART(dev);
+
+ s->usart_sr = USART_SR_RESET;
+ s->usart_dr = 0x00000000;
+ s->usart_brr = 0x00000000;
+ s->usart_cr1 = 0x00000000;
+ s->usart_cr2 = 0x00000000;
+ s->usart_cr3 = 0x00000000;
+ s->usart_gtpr = 0x00000000;
+
+ qemu_set_irq(s->irq, 0);
+}
+
+static uint64_t stm32f2xx_usart_read(void *opaque, hwaddr addr,
+ unsigned int size)
+{
+ STM32F2XXUsartState *s = opaque;
+ uint64_t retvalue;
+
+ DB_PRINT("Read 0x%"HWADDR_PRIx"\n", addr);
+
+ switch (addr) {
+ case USART_SR:
+ retvalue = s->usart_sr;
+ s->usart_sr &= ~USART_SR_TC;
+ if (s->chr) {
+ qemu_chr_accept_input(s->chr);
+ }
+ return retvalue;
+ case USART_DR:
+ DB_PRINT("Value: 0x%" PRIx32 ", %c\n", s->usart_dr, (char) s->usart_dr);
+ s->usart_sr |= USART_SR_TXE;
+ s->usart_sr &= ~USART_SR_RXNE;
+ if (s->chr) {
+ qemu_chr_accept_input(s->chr);
+ }
+ qemu_set_irq(s->irq, 0);
+ return s->usart_dr & 0x3FF;
+ case USART_BRR:
+ return s->usart_brr;
+ case USART_CR1:
+ return s->usart_cr1;
+ case USART_CR2:
+ return s->usart_cr2;
+ case USART_CR3:
+ return s->usart_cr3;
+ case USART_GTPR:
+ return s->usart_gtpr;
+ default:
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: Bad offset 0x%"HWADDR_PRIx"\n", __func__, addr);
+ return 0;
+ }
+
+ return 0;
+}
+
+static void stm32f2xx_usart_write(void *opaque, hwaddr addr,
+ uint64_t val64, unsigned int size)
+{
+ STM32F2XXUsartState *s = opaque;
+ uint32_t value = val64;
+ unsigned char ch;
+
+ DB_PRINT("Write 0x%" PRIx32 ", 0x%"HWADDR_PRIx"\n", value, addr);
+
+ switch (addr) {
+ case USART_SR:
+ if (value <= 0x3FF) {
+ s->usart_sr = value;
+ } else {
+ s->usart_sr &= value;
+ }
+ if (!(s->usart_sr & USART_SR_RXNE)) {
+ qemu_set_irq(s->irq, 0);
+ }
+ return;
+ case USART_DR:
+ if (value < 0xF000) {
+ ch = value;
+ if (s->chr) {
+ qemu_chr_fe_write_all(s->chr, &ch, 1);
+ }
+ s->usart_sr |= USART_SR_TC;
+ s->usart_sr &= ~USART_SR_TXE;
+ }
+ return;
+ case USART_BRR:
+ s->usart_brr = value;
+ return;
+ case USART_CR1:
+ s->usart_cr1 = value;
+ if (s->usart_cr1 & USART_CR1_RXNEIE &&
+ s->usart_sr & USART_SR_RXNE) {
+ qemu_set_irq(s->irq, 1);
+ }
+ return;
+ case USART_CR2:
+ s->usart_cr2 = value;
+ return;
+ case USART_CR3:
+ s->usart_cr3 = value;
+ return;
+ case USART_GTPR:
+ s->usart_gtpr = value;
+ return;
+ default:
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: Bad offset 0x%"HWADDR_PRIx"\n", __func__, addr);
+ }
+}
+
+static const MemoryRegionOps stm32f2xx_usart_ops = {
+ .read = stm32f2xx_usart_read,
+ .write = stm32f2xx_usart_write,
+ .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static void stm32f2xx_usart_init(Object *obj)
+{
+ STM32F2XXUsartState *s = STM32F2XX_USART(obj);
+
+ sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->irq);
+
+ memory_region_init_io(&s->mmio, obj, &stm32f2xx_usart_ops, s,
+ TYPE_STM32F2XX_USART, 0x2000);
+ sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->mmio);
+
+ s->chr = qemu_char_get_next_serial();
+
+ if (s->chr) {
+ qemu_chr_add_handlers(s->chr, stm32f2xx_usart_can_receive,
+ stm32f2xx_usart_receive, NULL, s);
+ }
+}
+
+static void stm32f2xx_usart_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+
+ dc->reset = stm32f2xx_usart_reset;
+}
+
+static const TypeInfo stm32f2xx_usart_info = {
+ .name = TYPE_STM32F2XX_USART,
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(STM32F2XXUsartState),
+ .instance_init = stm32f2xx_usart_init,
+ .class_init = stm32f2xx_usart_class_init,
+};
+
+static void stm32f2xx_usart_register_types(void)
+{
+ type_register_static(&stm32f2xx_usart_info);
+}
+
+type_init(stm32f2xx_usart_register_types)
diff --git a/hw/char/virtio-serial-bus.c b/hw/char/virtio-serial-bus.c
index 9a029d213..c86814f05 100644
--- a/hw/char/virtio-serial-bus.c
+++ b/hw/char/virtio-serial-bus.c
@@ -64,7 +64,7 @@ static VirtIOSerialPort *find_port_by_name(char *name)
VirtIOSerialPort *port;
QTAILQ_FOREACH(port, &vser->ports, next) {
- if (!strcmp(port->name, name)) {
+ if (port->name && !strcmp(port->name, name)) {
return port;
}
}
diff --git a/hw/core/loader.c b/hw/core/loader.c
index e45dc0b17..76d8acace 100644
--- a/hw/core/loader.c
+++ b/hw/core/loader.c
@@ -297,6 +297,7 @@ static void *load_at(int fd, int offset, int size)
#undef elf_phdr
#undef elf_shdr
#undef elf_sym
+#undef elf_rela
#undef elf_note
#undef elf_word
#undef elf_sword
@@ -307,6 +308,7 @@ static void *load_at(int fd, int offset, int size)
#define elf_note elf64_note
#define elf_shdr elf64_shdr
#define elf_sym elf64_sym
+#define elf_rela elf64_rela
#define elf_word uint64_t
#define elf_sword int64_t
#define bswapSZs bswap64s
diff --git a/hw/core/qdev-properties-system.c b/hw/core/qdev-properties-system.c
index a2e44bd4e..c413226a9 100644
--- a/hw/core/qdev-properties-system.c
+++ b/hw/core/qdev-properties-system.c
@@ -341,27 +341,25 @@ PropertyInfo qdev_prop_vlan = {
.set = set_vlan,
};
-int qdev_prop_set_drive(DeviceState *dev, const char *name,
- BlockBackend *value)
+void qdev_prop_set_drive(DeviceState *dev, const char *name,
+ BlockBackend *value, Error **errp)
{
- Error *err = NULL;
- object_property_set_str(OBJECT(dev),
- value ? blk_name(value) : "", name, &err);
- if (err) {
- qerror_report_err(err);
- error_free(err);
- return -1;
- }
- return 0;
+ object_property_set_str(OBJECT(dev), value ? blk_name(value) : "",
+ name, errp);
}
void qdev_prop_set_drive_nofail(DeviceState *dev, const char *name,
BlockBackend *value)
{
- if (qdev_prop_set_drive(dev, name, value) < 0) {
+ Error *err = NULL;
+
+ qdev_prop_set_drive(dev, name, value, &err);
+ if (err) {
+ error_report_err(err);
exit(1);
}
}
+
void qdev_prop_set_chr(DeviceState *dev, const char *name,
CharDriverState *value)
{
diff --git a/hw/core/qdev-properties.c b/hw/core/qdev-properties.c
index 5a4e4d5ec..570d5f0ba 100644
--- a/hw/core/qdev-properties.c
+++ b/hw/core/qdev-properties.c
@@ -580,7 +580,8 @@ static void set_blocksize(Object *obj, Visitor *v, void *opaque,
error_propagate(errp, local_err);
return;
}
- if (value < min || value > max) {
+ /* value of 0 means "unset" */
+ if (value && (value < min || value > max)) {
error_set(errp, QERR_PROPERTY_VALUE_OUT_OF_RANGE,
dev->id?:"", name, (int64_t)value, min, max);
return;
diff --git a/hw/i386/pc.c b/hw/i386/pc.c
index 79eaad5fe..b5b2aadb5 100644
--- a/hw/i386/pc.c
+++ b/hw/i386/pc.c
@@ -25,6 +25,8 @@
#include "hw/i386/pc.h"
#include "hw/char/serial.h"
#include "hw/i386/apic.h"
+#include "hw/i386/topology.h"
+#include "sysemu/cpus.h"
#include "hw/block/fdc.h"
#include "hw/ide.h"
#include "hw/pci/pci.h"
@@ -629,6 +631,39 @@ bool e820_get_entry(int idx, uint32_t type, uint64_t *address, uint64_t *length)
return false;
}
+/* Enables contiguous-apic-ID mode, for compatibility */
+static bool compat_apic_id_mode;
+
+void enable_compat_apic_id_mode(void)
+{
+ compat_apic_id_mode = true;
+}
+
+/* Calculates initial APIC ID for a specific CPU index
+ *
+ * Currently we need to be able to calculate the APIC ID from the CPU index
+ * alone (without requiring a CPU object), as the QEMU<->Seabios interfaces have
+ * no concept of "CPU index", and the NUMA tables on fw_cfg need the APIC ID of
+ * all CPUs up to max_cpus.
+ */
+static uint32_t x86_cpu_apic_id_from_index(unsigned int cpu_index)
+{
+ uint32_t correct_id;
+ static bool warned;
+
+ correct_id = x86_apicid_from_cpu_idx(smp_cores, smp_threads, cpu_index);
+ if (compat_apic_id_mode) {
+ if (cpu_index != correct_id && !warned) {
+ error_report("APIC IDs set in compatibility mode, "
+ "CPU topology won't match the configuration");
+ warned = true;
+ }
+ return cpu_index;
+ } else {
+ return correct_id;
+ }
+}
+
/* Calculates the limit to CPU APIC ID values
*
* This function returns the limit for the APIC ID value, so that all
diff --git a/hw/ide/ahci.c b/hw/ide/ahci.c
index 5651372be..e1ae36f7c 100644
--- a/hw/ide/ahci.c
+++ b/hw/ide/ahci.c
@@ -1160,6 +1160,11 @@ static void ahci_start_dma(IDEDMA *dma, IDEState *s,
dma_cb(s, 0);
}
+static void ahci_restart_dma(IDEDMA *dma)
+{
+ /* Nothing to do, ahci_start_dma already resets s->io_buffer_offset. */
+}
+
/**
* Called in DMA R/W chains to read the PRDT, utilizing ahci_populate_sglist.
* Not currently invoked by PIO R/W chains,
@@ -1226,12 +1231,6 @@ static int ahci_dma_rw_buf(IDEDMA *dma, int is_write)
return 1;
}
-static int ahci_dma_set_unit(IDEDMA *dma, int unit)
-{
- /* only a single unit per link */
- return 0;
-}
-
static void ahci_cmd_done(IDEDMA *dma)
{
AHCIDevice *ad = DO_UPCAST(AHCIDevice, dma, dma);
@@ -1252,19 +1251,14 @@ static void ahci_irq_set(void *opaque, int n, int level)
{
}
-static void ahci_dma_restart_cb(void *opaque, int running, RunState state)
-{
-}
-
static const IDEDMAOps ahci_dma_ops = {
.start_dma = ahci_start_dma,
+ .restart_dma = ahci_restart_dma,
.start_transfer = ahci_start_transfer,
.prepare_buf = ahci_dma_prepare_buf,
.commit_buf = ahci_commit_buf,
.rw_buf = ahci_dma_rw_buf,
- .set_unit = ahci_dma_set_unit,
.cmd_done = ahci_cmd_done,
- .restart_cb = ahci_dma_restart_cb,
};
void ahci_init(AHCIState *s, DeviceState *qdev, AddressSpace *as, int ports)
@@ -1294,6 +1288,7 @@ void ahci_init(AHCIState *s, DeviceState *qdev, AddressSpace *as, int ports)
ad->port_no = i;
ad->port.dma = &ad->dma;
ad->port.dma->ops = &ahci_dma_ops;
+ ide_register_restart_cb(&ad->port);
}
}
@@ -1333,6 +1328,7 @@ static const VMStateDescription vmstate_ahci_device = {
.version_id = 1,
.fields = (VMStateField[]) {
VMSTATE_IDE_BUS(port, AHCIDevice),
+ VMSTATE_IDE_DRIVE(port.ifs[0], AHCIDevice),
VMSTATE_UINT32(port_state, AHCIDevice),
VMSTATE_UINT32(finished, AHCIDevice),
VMSTATE_UINT32(port_regs.lst_addr, AHCIDevice),
@@ -1371,16 +1367,23 @@ static int ahci_state_post_load(void *opaque, int version_id)
map_page(s->as, &ad->res_fis,
((uint64_t)pr->fis_addr_hi << 32) | pr->fis_addr, 256);
/*
- * All pending i/o should be flushed out on a migrate. However,
- * we might not have cleared the busy_slot since this is done
- * in a bh. Also, issue i/o against any slots that are pending.
+ * If an error is present, ad->busy_slot will be valid and not -1.
+ * In this case, an operation is waiting to resume and will re-check
+ * for additional AHCI commands to execute upon completion.
+ *
+ * In the case where no error was present, busy_slot will be -1,
+ * and we should check to see if there are additional commands waiting.
*/
- if ((ad->busy_slot != -1) &&
- !(ad->port.ifs[0].status & (BUSY_STAT|DRQ_STAT))) {
- pr->cmd_issue &= ~(1 << ad->busy_slot);
- ad->busy_slot = -1;
+ if (ad->busy_slot == -1) {
+ check_cmd(s, i);
+ } else {
+ /* We are in the middle of a command, and may need to access
+ * the command header in guest memory again. */
+ if (ad->busy_slot < 0 || ad->busy_slot >= AHCI_MAX_CMDS) {
+ return -1;
+ }
+ ad->cur_cmd = &((AHCICmdHdr *)ad->lst)[ad->busy_slot];
}
- check_cmd(s, i);
}
return 0;
diff --git a/hw/ide/atapi.c b/hw/ide/atapi.c
index 1bf8b3452..950e311d3 100644
--- a/hw/ide/atapi.c
+++ b/hw/ide/atapi.c
@@ -252,7 +252,6 @@ static void ide_atapi_cmd_reply(IDEState *s, int size, int max_size)
s->packet_transfer_size = size;
s->io_buffer_size = size; /* dma: send the reply data as one chunk */
s->elementary_transfer_size = 0;
- s->io_buffer_index = 0;
if (s->atapi_dma) {
block_acct_start(blk_get_stats(s->blk), &s->acct, size,
@@ -261,6 +260,7 @@ static void ide_atapi_cmd_reply(IDEState *s, int size, int max_size)
ide_start_dma(s, ide_atapi_cmd_read_dma_cb);
} else {
s->status = READY_STAT | SEEK_STAT;
+ s->io_buffer_index = 0;
ide_atapi_cmd_reply_end(s);
}
}
@@ -368,7 +368,6 @@ static void ide_atapi_cmd_read_dma(IDEState *s, int lba, int nb_sectors,
{
s->lba = lba;
s->packet_transfer_size = nb_sectors * sector_size;
- s->io_buffer_index = 0;
s->io_buffer_size = 0;
s->cd_sector_size = sector_size;
diff --git a/hw/ide/cmd646.c b/hw/ide/cmd646.c
index dafa9ec7c..66fb9d96d 100644
--- a/hw/ide/cmd646.c
+++ b/hw/ide/cmd646.c
@@ -368,8 +368,7 @@ static void pci_cmd646_ide_realize(PCIDevice *dev, Error **errp)
bmdma_init(&d->bus[i], &d->bmdma[i], d);
d->bmdma[i].bus = &d->bus[i];
- qemu_add_vm_change_state_handler(d->bus[i].dma->ops->restart_cb,
- &d->bmdma[i].dma);
+ ide_register_restart_cb(&d->bus[i]);
}
vmstate_register(DEVICE(dev), 0, &vmstate_ide_pci, d);
diff --git a/hw/ide/core.c b/hw/ide/core.c
index ac3f015a8..ef52f3516 100644
--- a/hw/ide/core.c
+++ b/hw/ide/core.c
@@ -561,6 +561,8 @@ static bool ide_sect_range_ok(IDEState *s,
return true;
}
+static void ide_sector_read(IDEState *s);
+
static void ide_sector_read_cb(void *opaque, int ret)
{
IDEState *s = opaque;
@@ -595,7 +597,7 @@ static void ide_sector_read_cb(void *opaque, int ret)
s->io_buffer_offset += 512 * n;
}
-void ide_sector_read(IDEState *s)
+static void ide_sector_read(IDEState *s)
{
int64_t sector_num;
int n;
@@ -646,6 +648,9 @@ static void dma_buf_commit(IDEState *s, uint32_t tx_bytes)
void ide_set_inactive(IDEState *s, bool more)
{
s->bus->dma->aiocb = NULL;
+ s->bus->retry_unit = -1;
+ s->bus->retry_sector_num = 0;
+ s->bus->retry_nsector = 0;
if (s->bus->dma->ops->set_inactive) {
s->bus->dma->ops->set_inactive(s->bus->dma, more);
}
@@ -666,7 +671,7 @@ static int ide_handle_rw_error(IDEState *s, int error, int op)
BlockErrorAction action = blk_get_error_action(s->blk, is_read, error);
if (action == BLOCK_ERROR_ACTION_STOP) {
- s->bus->dma->ops->set_unit(s->bus->dma, s->unit);
+ assert(s->bus->retry_unit == s->unit);
s->bus->error_status = op;
} else if (action == BLOCK_ERROR_ACTION_REPORT) {
if (op & IDE_RETRY_DMA) {
@@ -679,7 +684,7 @@ static int ide_handle_rw_error(IDEState *s, int error, int op)
return action != BLOCK_ERROR_ACTION_IGNORE;
}
-void ide_dma_cb(void *opaque, int ret)
+static void ide_dma_cb(void *opaque, int ret)
{
IDEState *s = opaque;
int n;
@@ -777,7 +782,6 @@ eot:
static void ide_sector_start_dma(IDEState *s, enum ide_dma_cmd dma_cmd)
{
s->status = READY_STAT | SEEK_STAT | DRQ_STAT | BUSY_STAT;
- s->io_buffer_index = 0;
s->io_buffer_size = 0;
s->dma_cmd = dma_cmd;
@@ -799,11 +803,17 @@ static void ide_sector_start_dma(IDEState *s, enum ide_dma_cmd dma_cmd)
void ide_start_dma(IDEState *s, BlockCompletionFunc *cb)
{
+ s->io_buffer_index = 0;
+ s->bus->retry_unit = s->unit;
+ s->bus->retry_sector_num = ide_get_sector(s);
+ s->bus->retry_nsector = s->nsector;
if (s->bus->dma->ops->start_dma) {
s->bus->dma->ops->start_dma(s->bus->dma, s, cb);
}
}
+static void ide_sector_write(IDEState *s);
+
static void ide_sector_write_timer_cb(void *opaque)
{
IDEState *s = opaque;
@@ -863,7 +873,7 @@ static void ide_sector_write_cb(void *opaque, int ret)
}
}
-void ide_sector_write(IDEState *s)
+static void ide_sector_write(IDEState *s)
{
int64_t sector_num;
int n;
@@ -917,7 +927,7 @@ static void ide_flush_cb(void *opaque, int ret)
ide_set_irq(s->bus);
}
-void ide_flush_cache(IDEState *s)
+static void ide_flush_cache(IDEState *s)
{
if (s->blk == NULL) {
ide_flush_cb(s, 0);
@@ -2314,22 +2324,101 @@ static int ide_nop_int(IDEDMA *dma, int x)
return 0;
}
-static int32_t ide_nop_int32(IDEDMA *dma, int x)
+static void ide_nop(IDEDMA *dma)
{
- return 0;
}
-static void ide_nop_restart(void *opaque, int x, RunState y)
+static int32_t ide_nop_int32(IDEDMA *dma, int x)
{
+ return 0;
}
static const IDEDMAOps ide_dma_nop_ops = {
.prepare_buf = ide_nop_int32,
+ .restart_dma = ide_nop,
.rw_buf = ide_nop_int,
- .set_unit = ide_nop_int,
- .restart_cb = ide_nop_restart,
};
+static void ide_restart_dma(IDEState *s, enum ide_dma_cmd dma_cmd)
+{
+ s->unit = s->bus->retry_unit;
+ ide_set_sector(s, s->bus->retry_sector_num);
+ s->nsector = s->bus->retry_nsector;
+ s->bus->dma->ops->restart_dma(s->bus->dma);
+ s->io_buffer_size = 0;
+ s->dma_cmd = dma_cmd;
+ ide_start_dma(s, ide_dma_cb);
+}
+
+static void ide_restart_bh(void *opaque)
+{
+ IDEBus *bus = opaque;
+ IDEState *s;
+ bool is_read;
+ int error_status;
+
+ qemu_bh_delete(bus->bh);
+ bus->bh = NULL;
+
+ error_status = bus->error_status;
+ if (bus->error_status == 0) {
+ return;
+ }
+
+ s = idebus_active_if(bus);
+ 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
+ * called function can set a new error status. */
+ bus->error_status = 0;
+
+ if (error_status & IDE_RETRY_DMA) {
+ if (error_status & IDE_RETRY_TRIM) {
+ ide_restart_dma(s, IDE_DMA_TRIM);
+ } else {
+ ide_restart_dma(s, is_read ? IDE_DMA_READ : IDE_DMA_WRITE);
+ }
+ } else if (error_status & IDE_RETRY_PIO) {
+ if (is_read) {
+ ide_sector_read(s);
+ } else {
+ ide_sector_write(s);
+ }
+ } else if (error_status & IDE_RETRY_FLUSH) {
+ ide_flush_cache(s);
+ } else {
+ /*
+ * We've not got any bits to tell us about ATAPI - but
+ * we do have the end_transfer_func that tells us what
+ * we're trying to do.
+ */
+ if (s->end_transfer_func == ide_atapi_cmd) {
+ ide_atapi_dma_restart(s);
+ }
+ }
+}
+
+static void ide_restart_cb(void *opaque, int running, RunState state)
+{
+ IDEBus *bus = opaque;
+
+ if (!running)
+ return;
+
+ if (!bus->bh) {
+ bus->bh = qemu_bh_new(ide_restart_bh, bus);
+ qemu_bh_schedule(bus->bh);
+ }
+}
+
+void ide_register_restart_cb(IDEBus *bus)
+{
+ if (bus->dma->ops->restart_dma) {
+ qemu_add_vm_change_state_handler(ide_restart_cb, bus);
+ }
+}
+
static IDEDMA ide_dma_nop = {
.ops = &ide_dma_nop_ops,
.aiocb = NULL,
@@ -2557,10 +2646,13 @@ const VMStateDescription vmstate_ide_drive = {
static const VMStateDescription vmstate_ide_error_status = {
.name ="ide_bus/error",
- .version_id = 1,
+ .version_id = 2,
.minimum_version_id = 1,
.fields = (VMStateField[]) {
VMSTATE_INT32(error_status, IDEBus),
+ VMSTATE_INT64_V(retry_sector_num, IDEBus, 2),
+ VMSTATE_UINT32_V(retry_nsector, IDEBus, 2),
+ VMSTATE_UINT8_V(retry_unit, IDEBus, 2),
VMSTATE_END_OF_LIST()
}
};
diff --git a/hw/ide/internal.h b/hw/ide/internal.h
index ee9a57f03..965cc55cb 100644
--- a/hw/ide/internal.h
+++ b/hw/ide/internal.h
@@ -436,10 +436,9 @@ struct IDEDMAOps {
DMAInt32Func *prepare_buf;
DMAu32Func *commit_buf;
DMAIntFunc *rw_buf;
- DMAIntFunc *set_unit;
+ DMAVoidFunc *restart_dma;
DMAStopFunc *set_inactive;
DMAVoidFunc *cmd_done;
- DMARestartFunc *restart_cb;
DMAVoidFunc *reset;
};
@@ -455,6 +454,8 @@ struct IDEBus {
IDEDevice *master;
IDEDevice *slave;
IDEState ifs[2];
+ QEMUBH *bh;
+
int bus_id;
int max_units;
IDEDMA *dma;
@@ -463,6 +464,9 @@ struct IDEBus {
qemu_irq irq;
int error_status;
+ uint8_t retry_unit;
+ int64_t retry_sector_num;
+ uint32_t retry_nsector;
};
#define TYPE_IDE_DEVICE "ide-device"
@@ -522,6 +526,9 @@ extern const VMStateDescription vmstate_ide_drive;
#define VMSTATE_IDE_DRIVES(_field, _state) \
VMSTATE_STRUCT_ARRAY(_field, _state, 2, 3, vmstate_ide_drive, IDEState)
+#define VMSTATE_IDE_DRIVE(_field, _state) \
+ VMSTATE_STRUCT(_field, _state, 1, vmstate_ide_drive, IDEState)
+
void ide_bus_reset(IDEBus *bus);
int64_t ide_get_sector(IDEState *s);
void ide_set_sector(IDEState *s, int64_t sector_num);
@@ -550,12 +557,9 @@ int ide_init_drive(IDEState *s, BlockBackend *blk, IDEDriveKind kind,
int chs_trans);
void ide_init2(IDEBus *bus, qemu_irq irq);
void ide_init_ioport(IDEBus *bus, ISADevice *isa, int iobase, int iobase2);
+void ide_register_restart_cb(IDEBus *bus);
void ide_exec_cmd(IDEBus *bus, uint32_t val);
-void ide_dma_cb(void *opaque, int ret);
-void ide_sector_write(IDEState *s);
-void ide_sector_read(IDEState *s);
-void ide_flush_cache(IDEState *s);
void ide_transfer_start(IDEState *s, uint8_t *buf, int size,
EndTransferFunc *end_transfer_func);
diff --git a/hw/ide/isa.c b/hw/ide/isa.c
index c0c4e1b09..9f80503fa 100644
--- a/hw/ide/isa.c
+++ b/hw/ide/isa.c
@@ -74,7 +74,8 @@ static void isa_ide_realizefn(DeviceState *dev, Error **errp)
isa_init_irq(isadev, &s->irq, s->isairq);
ide_init2(&s->bus, s->irq);
vmstate_register(dev, 0, &vmstate_ide_isa, s);
-};
+ ide_register_restart_cb(&s->bus);
+}
ISADevice *isa_ide_init(ISABus *bus, int iobase, int iobase2, int isairq,
DriveInfo *hd0, DriveInfo *hd1)
diff --git a/hw/ide/macio.c b/hw/ide/macio.c
index f6074f202..a009674f4 100644
--- a/hw/ide/macio.c
+++ b/hw/ide/macio.c
@@ -558,10 +558,6 @@ static int32_t ide_nop_int32(IDEDMA *dma, int x)
return 0;
}
-static void ide_nop_restart(void *opaque, int x, RunState y)
-{
-}
-
static void ide_dbdma_start(IDEDMA *dma, IDEState *s,
BlockCompletionFunc *cb)
{
@@ -576,8 +572,6 @@ static const IDEDMAOps dbdma_ops = {
.start_dma = ide_dbdma_start,
.prepare_buf = ide_nop_int32,
.rw_buf = ide_nop_int,
- .set_unit = ide_nop_int,
- .restart_cb = ide_nop_restart,
};
static void macio_ide_realizefn(DeviceState *dev, Error **errp)
diff --git a/hw/ide/pci.c b/hw/ide/pci.c
index 913a9762d..1b3d1c12a 100644
--- a/hw/ide/pci.c
+++ b/hw/ide/pci.c
@@ -42,13 +42,10 @@ static void bmdma_start_dma(IDEDMA *dma, IDEState *s,
{
BMDMAState *bm = DO_UPCAST(BMDMAState, dma, dma);
- bm->unit = s->unit;
bm->dma_cb = dma_cb;
bm->cur_prd_last = 0;
bm->cur_prd_addr = 0;
bm->cur_prd_len = 0;
- bm->sector_num = ide_get_sector(s);
- bm->nsector = s->nsector;
if (bm->status & BM_STATUS_DMAING) {
bm->dma_cb(bmdma_active_if(bm), 0);
@@ -163,20 +160,11 @@ static int bmdma_rw_buf(IDEDMA *dma, int is_write)
return 1;
}
-static int bmdma_set_unit(IDEDMA *dma, int unit)
-{
- BMDMAState *bm = DO_UPCAST(BMDMAState, dma, dma);
- bm->unit = unit;
-
- return 0;
-}
-
static void bmdma_set_inactive(IDEDMA *dma, bool more)
{
BMDMAState *bm = DO_UPCAST(BMDMAState, dma, dma);
bm->dma_cb = NULL;
- bm->unit = -1;
if (more) {
bm->status |= BM_STATUS_DMAING;
} else {
@@ -184,83 +172,11 @@ static void bmdma_set_inactive(IDEDMA *dma, bool more)
}
}
-static void bmdma_restart_dma(BMDMAState *bm, enum ide_dma_cmd dma_cmd)
-{
- IDEState *s = bmdma_active_if(bm);
-
- ide_set_sector(s, bm->sector_num);
- s->io_buffer_index = 0;
- s->io_buffer_size = 0;
- s->nsector = bm->nsector;
- s->dma_cmd = dma_cmd;
- bm->cur_addr = bm->addr;
- bm->dma_cb = ide_dma_cb;
- bmdma_start_dma(&bm->dma, s, bm->dma_cb);
-}
-
-/* TODO This should be common IDE code */
-static void bmdma_restart_bh(void *opaque)
-{
- BMDMAState *bm = opaque;
- IDEBus *bus = bm->bus;
- bool is_read;
- int error_status;
-
- qemu_bh_delete(bm->bh);
- bm->bh = NULL;
-
- if (bm->unit == (uint8_t) -1) {
- return;
- }
-
- 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
- * called function can set a new error status. */
- error_status = bus->error_status;
- bus->error_status = 0;
-
- 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 & 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 & IDE_RETRY_FLUSH) {
- ide_flush_cache(bmdma_active_if(bm));
- } else {
- IDEState *s = bmdma_active_if(bm);
-
- /*
- * We've not got any bits to tell us about ATAPI - but
- * we do have the end_transfer_func that tells us what
- * we're trying to do.
- */
- if (s->end_transfer_func == ide_atapi_cmd) {
- ide_atapi_dma_restart(s);
- }
- }
-}
-
-static void bmdma_restart_cb(void *opaque, int running, RunState state)
+static void bmdma_restart_dma(IDEDMA *dma)
{
- IDEDMA *dma = opaque;
BMDMAState *bm = DO_UPCAST(BMDMAState, dma, dma);
- if (!running)
- return;
-
- if (!bm->bh) {
- bm->bh = qemu_bh_new(bmdma_restart_bh, &bm->dma);
- qemu_bh_schedule(bm->bh);
- }
+ bm->cur_addr = bm->addr;
}
static void bmdma_cancel(BMDMAState *bm)
@@ -286,8 +202,6 @@ static void bmdma_reset(IDEDMA *dma)
bm->cur_prd_last = 0;
bm->cur_prd_addr = 0;
bm->cur_prd_len = 0;
- bm->sector_num = 0;
- bm->nsector = 0;
}
static void bmdma_irq(void *opaque, int n, int level)
@@ -404,6 +318,9 @@ static void ide_bmdma_pre_save(void *opaque)
BMDMAState *bm = opaque;
uint8_t abused_bits = BM_MIGRATION_COMPAT_STATUS_BITS;
+ bm->migration_retry_unit = bm->bus->retry_unit;
+ bm->migration_retry_sector_num = bm->bus->retry_sector_num;
+ bm->migration_retry_nsector = bm->bus->retry_nsector;
bm->migration_compat_status =
(bm->status & ~abused_bits) | (bm->bus->error_status & abused_bits);
}
@@ -420,6 +337,11 @@ static int ide_bmdma_post_load(void *opaque, int version_id)
bm->status = bm->migration_compat_status & ~abused_bits;
bm->bus->error_status |= bm->migration_compat_status & abused_bits;
}
+ if (bm->bus->error_status) {
+ bm->bus->retry_sector_num = bm->migration_retry_sector_num;
+ bm->bus->retry_nsector = bm->migration_retry_nsector;
+ bm->bus->retry_unit = bm->migration_retry_unit;
+ }
return 0;
}
@@ -456,9 +378,9 @@ static const VMStateDescription vmstate_bmdma = {
VMSTATE_UINT8(cmd, BMDMAState),
VMSTATE_UINT8(migration_compat_status, BMDMAState),
VMSTATE_UINT32(addr, BMDMAState),
- VMSTATE_INT64(sector_num, BMDMAState),
- VMSTATE_UINT32(nsector, BMDMAState),
- VMSTATE_UINT8(unit, BMDMAState),
+ VMSTATE_INT64(migration_retry_sector_num, BMDMAState),
+ VMSTATE_UINT32(migration_retry_nsector, BMDMAState),
+ VMSTATE_UINT8(migration_retry_unit, BMDMAState),
VMSTATE_END_OF_LIST()
},
.subsections = (VMStateSubsection []) {
@@ -482,7 +404,7 @@ static int ide_pci_post_load(void *opaque, int version_id)
for(i = 0; i < 2; i++) {
/* current versions always store 0/1, but older version
stored bigger values. We only need last bit */
- d->bmdma[i].unit &= 1;
+ d->bmdma[i].migration_retry_unit &= 1;
ide_bmdma_post_load(&d->bmdma[i], -1);
}
@@ -523,9 +445,8 @@ static const struct IDEDMAOps bmdma_ops = {
.start_dma = bmdma_start_dma,
.prepare_buf = bmdma_prepare_buf,
.rw_buf = bmdma_rw_buf,
- .set_unit = bmdma_set_unit,
+ .restart_dma = bmdma_restart_dma,
.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 2e9314ad8..0f2d4b91a 100644
--- a/hw/ide/pci.h
+++ b/hw/ide/pci.h
@@ -22,18 +22,18 @@ typedef struct BMDMAState {
uint32_t cur_prd_last;
uint32_t cur_prd_addr;
uint32_t cur_prd_len;
- uint8_t unit;
BlockCompletionFunc *dma_cb;
- int64_t sector_num;
- uint32_t nsector;
MemoryRegion addr_ioport;
MemoryRegion extra_io;
- QEMUBH *bh;
qemu_irq irq;
/* Bit 0-2 and 7: BM status register
* Bit 3-6: bus->error_status */
uint8_t migration_compat_status;
+ uint8_t migration_retry_unit;
+ int64_t migration_retry_sector_num;
+ uint32_t migration_retry_nsector;
+
struct PCIIDEState *pci_dev;
} BMDMAState;
@@ -62,8 +62,8 @@ typedef struct PCIIDEState {
static inline IDEState *bmdma_active_if(BMDMAState *bmdma)
{
- assert(bmdma->unit != (uint8_t)-1);
- return bmdma->bus->ifs + bmdma->unit;
+ assert(bmdma->bus->retry_unit != (uint8_t)-1);
+ return bmdma->bus->ifs + bmdma->bus->retry_unit;
}
diff --git a/hw/ide/piix.c b/hw/ide/piix.c
index ab930843e..adb664957 100644
--- a/hw/ide/piix.c
+++ b/hw/ide/piix.c
@@ -143,8 +143,7 @@ static void pci_piix_init_ports(PCIIDEState *d) {
bmdma_init(&d->bus[i], &d->bmdma[i], d);
d->bmdma[i].bus = &d->bus[i];
- qemu_add_vm_change_state_handler(d->bus[i].dma->ops->restart_cb,
- &d->bmdma[i].dma);
+ ide_register_restart_cb(&d->bus[i]);
}
}
diff --git a/hw/ide/qdev.c b/hw/ide/qdev.c
index b4103fa00..788b36133 100644
--- a/hw/ide/qdev.c
+++ b/hw/ide/qdev.c
@@ -163,6 +163,7 @@ static int ide_dev_initfn(IDEDevice *dev, IDEDriveKind kind)
return -1;
}
+ blkconf_blocksizes(&dev->conf);
if (dev->conf.logical_block_size != 512) {
error_report("logical_block_size must be 512 for IDE");
return -1;
diff --git a/hw/ide/via.c b/hw/ide/via.c
index 7a5151c5c..e2da9ef71 100644
--- a/hw/ide/via.c
+++ b/hw/ide/via.c
@@ -166,8 +166,7 @@ static void vt82c686b_init_ports(PCIIDEState *d) {
bmdma_init(&d->bus[i], &d->bmdma[i], d);
d->bmdma[i].bus = &d->bus[i];
- qemu_add_vm_change_state_handler(d->bus[i].dma->ops->restart_cb,
- &d->bmdma[i].dma);
+ ide_register_restart_cb(&d->bus[i]);
}
}
diff --git a/hw/m68k/dummy_m68k.c b/hw/m68k/dummy_m68k.c
index facd561ef..278f4c03d 100644
--- a/hw/m68k/dummy_m68k.c
+++ b/hw/m68k/dummy_m68k.c
@@ -21,6 +21,7 @@ static void dummy_m68k_init(MachineState *machine)
ram_addr_t ram_size = machine->ram_size;
const char *cpu_model = machine->cpu_model;
const char *kernel_filename = machine->kernel_filename;
+ M68kCPU *cpu;
CPUM68KState *env;
MemoryRegion *address_space_mem = get_system_memory();
MemoryRegion *ram = g_new(MemoryRegion, 1);
@@ -30,11 +31,12 @@ static void dummy_m68k_init(MachineState *machine)
if (!cpu_model)
cpu_model = "cfv4e";
- env = cpu_init(cpu_model);
- if (!env) {
+ cpu = cpu_m68k_init(cpu_model);
+ if (!cpu) {
fprintf(stderr, "Unable to find m68k CPU definition\n");
exit(1);
}
+ env = &cpu->env;
/* Initialize CPU registers. */
env->vbr = 0;
diff --git a/hw/misc/Makefile.objs b/hw/misc/Makefile.objs
index 6c6e29681..4aa76ffec 100644
--- a/hw/misc/Makefile.objs
+++ b/hw/misc/Makefile.objs
@@ -36,6 +36,7 @@ obj-$(CONFIG_OMAP) += omap_sdrc.o
obj-$(CONFIG_OMAP) += omap_tap.o
obj-$(CONFIG_SLAVIO) += slavio_misc.o
obj-$(CONFIG_ZYNQ) += zynq_slcr.o
+obj-$(CONFIG_STM32F2XX_SYSCFG) += stm32f2xx_syscfg.o
obj-$(CONFIG_PVPANIC) += pvpanic.o
obj-$(CONFIG_EDU) += edu.o
diff --git a/hw/misc/stm32f2xx_syscfg.c b/hw/misc/stm32f2xx_syscfg.c
new file mode 100644
index 000000000..4ae4042bf
--- /dev/null
+++ b/hw/misc/stm32f2xx_syscfg.c
@@ -0,0 +1,160 @@
+/*
+ * STM32F2XX SYSCFG
+ *
+ * Copyright (c) 2014 Alistair Francis <alistair@alistair23.me>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "hw/misc/stm32f2xx_syscfg.h"
+
+#ifndef STM_SYSCFG_ERR_DEBUG
+#define STM_SYSCFG_ERR_DEBUG 0
+#endif
+
+#define DB_PRINT_L(lvl, fmt, args...) do { \
+ if (STM_SYSCFG_ERR_DEBUG >= lvl) { \
+ qemu_log("%s: " fmt, __func__, ## args); \
+ } \
+} while (0);
+
+#define DB_PRINT(fmt, args...) DB_PRINT_L(1, fmt, ## args)
+
+static void stm32f2xx_syscfg_reset(DeviceState *dev)
+{
+ STM32F2XXSyscfgState *s = STM32F2XX_SYSCFG(dev);
+
+ s->syscfg_memrmp = 0x00000000;
+ s->syscfg_pmc = 0x00000000;
+ s->syscfg_exticr1 = 0x00000000;
+ s->syscfg_exticr2 = 0x00000000;
+ s->syscfg_exticr3 = 0x00000000;
+ s->syscfg_exticr4 = 0x00000000;
+ s->syscfg_cmpcr = 0x00000000;
+}
+
+static uint64_t stm32f2xx_syscfg_read(void *opaque, hwaddr addr,
+ unsigned int size)
+{
+ STM32F2XXSyscfgState *s = opaque;
+
+ DB_PRINT("0x%"HWADDR_PRIx"\n", addr);
+
+ switch (addr) {
+ case SYSCFG_MEMRMP:
+ return s->syscfg_memrmp;
+ case SYSCFG_PMC:
+ return s->syscfg_pmc;
+ case SYSCFG_EXTICR1:
+ return s->syscfg_exticr1;
+ case SYSCFG_EXTICR2:
+ return s->syscfg_exticr2;
+ case SYSCFG_EXTICR3:
+ return s->syscfg_exticr3;
+ case SYSCFG_EXTICR4:
+ return s->syscfg_exticr4;
+ case SYSCFG_CMPCR:
+ return s->syscfg_cmpcr;
+ default:
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: Bad offset 0x%"HWADDR_PRIx"\n", __func__, addr);
+ return 0;
+ }
+
+ return 0;
+}
+
+static void stm32f2xx_syscfg_write(void *opaque, hwaddr addr,
+ uint64_t val64, unsigned int size)
+{
+ STM32F2XXSyscfgState *s = opaque;
+ uint32_t value = val64;
+
+ DB_PRINT("0x%x, 0x%"HWADDR_PRIx"\n", value, addr);
+
+ switch (addr) {
+ case SYSCFG_MEMRMP:
+ qemu_log_mask(LOG_UNIMP,
+ "%s: Changeing the memory mapping isn't supported " \
+ "in QEMU\n", __func__);
+ return;
+ case SYSCFG_PMC:
+ qemu_log_mask(LOG_UNIMP,
+ "%s: Changeing the memory mapping isn't supported " \
+ "in QEMU\n", __func__);
+ return;
+ case SYSCFG_EXTICR1:
+ s->syscfg_exticr1 = (value & 0xFFFF);
+ return;
+ case SYSCFG_EXTICR2:
+ s->syscfg_exticr2 = (value & 0xFFFF);
+ return;
+ case SYSCFG_EXTICR3:
+ s->syscfg_exticr3 = (value & 0xFFFF);
+ return;
+ case SYSCFG_EXTICR4:
+ s->syscfg_exticr4 = (value & 0xFFFF);
+ return;
+ case SYSCFG_CMPCR:
+ s->syscfg_cmpcr = value;
+ return;
+ default:
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: Bad offset 0x%"HWADDR_PRIx"\n", __func__, addr);
+ }
+}
+
+static const MemoryRegionOps stm32f2xx_syscfg_ops = {
+ .read = stm32f2xx_syscfg_read,
+ .write = stm32f2xx_syscfg_write,
+ .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static void stm32f2xx_syscfg_init(Object *obj)
+{
+ STM32F2XXSyscfgState *s = STM32F2XX_SYSCFG(obj);
+
+ sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->irq);
+
+ memory_region_init_io(&s->mmio, obj, &stm32f2xx_syscfg_ops, s,
+ TYPE_STM32F2XX_SYSCFG, 0x400);
+ sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->mmio);
+}
+
+static void stm32f2xx_syscfg_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+
+ dc->reset = stm32f2xx_syscfg_reset;
+}
+
+static const TypeInfo stm32f2xx_syscfg_info = {
+ .name = TYPE_STM32F2XX_SYSCFG,
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(STM32F2XXSyscfgState),
+ .instance_init = stm32f2xx_syscfg_init,
+ .class_init = stm32f2xx_syscfg_class_init,
+};
+
+static void stm32f2xx_syscfg_register_types(void)
+{
+ type_register_static(&stm32f2xx_syscfg_info);
+}
+
+type_init(stm32f2xx_syscfg_register_types)
diff --git a/hw/ppc/ppc.c b/hw/ppc/ppc.c
index 5ce565d5e..99db56c8d 100644
--- a/hw/ppc/ppc.c
+++ b/hw/ppc/ppc.c
@@ -1318,167 +1318,6 @@ void PPC_debug_write (void *opaque, uint32_t addr, uint32_t val)
}
}
-/*****************************************************************************/
-/* NVRAM helpers */
-static inline uint32_t nvram_read (nvram_t *nvram, uint32_t addr)
-{
- return (*nvram->read_fn)(nvram->opaque, addr);
-}
-
-static inline void nvram_write (nvram_t *nvram, uint32_t addr, uint32_t val)
-{
- (*nvram->write_fn)(nvram->opaque, addr, val);
-}
-
-static void NVRAM_set_byte(nvram_t *nvram, uint32_t addr, uint8_t value)
-{
- nvram_write(nvram, addr, value);
-}
-
-static uint8_t NVRAM_get_byte(nvram_t *nvram, uint32_t addr)
-{
- return nvram_read(nvram, addr);
-}
-
-static void NVRAM_set_word(nvram_t *nvram, uint32_t addr, uint16_t value)
-{
- nvram_write(nvram, addr, value >> 8);
- nvram_write(nvram, addr + 1, value & 0xFF);
-}
-
-static uint16_t NVRAM_get_word(nvram_t *nvram, uint32_t addr)
-{
- uint16_t tmp;
-
- tmp = nvram_read(nvram, addr) << 8;
- tmp |= nvram_read(nvram, addr + 1);
-
- return tmp;
-}
-
-static void NVRAM_set_lword(nvram_t *nvram, uint32_t addr, uint32_t value)
-{
- nvram_write(nvram, addr, value >> 24);
- nvram_write(nvram, addr + 1, (value >> 16) & 0xFF);
- nvram_write(nvram, addr + 2, (value >> 8) & 0xFF);
- nvram_write(nvram, addr + 3, value & 0xFF);
-}
-
-uint32_t NVRAM_get_lword (nvram_t *nvram, uint32_t addr)
-{
- uint32_t tmp;
-
- tmp = nvram_read(nvram, addr) << 24;
- tmp |= nvram_read(nvram, addr + 1) << 16;
- tmp |= nvram_read(nvram, addr + 2) << 8;
- tmp |= nvram_read(nvram, addr + 3);
-
- return tmp;
-}
-
-static void NVRAM_set_string(nvram_t *nvram, uint32_t addr, const char *str,
- uint32_t max)
-{
- int i;
-
- for (i = 0; i < max && str[i] != '\0'; i++) {
- nvram_write(nvram, addr + i, str[i]);
- }
- nvram_write(nvram, addr + i, str[i]);
- nvram_write(nvram, addr + max - 1, '\0');
-}
-
-int NVRAM_get_string (nvram_t *nvram, uint8_t *dst, uint16_t addr, int max)
-{
- int i;
-
- memset(dst, 0, max);
- for (i = 0; i < max; i++) {
- dst[i] = NVRAM_get_byte(nvram, addr + i);
- if (dst[i] == '\0')
- break;
- }
-
- return i;
-}
-
-static uint16_t NVRAM_crc_update (uint16_t prev, uint16_t value)
-{
- uint16_t tmp;
- uint16_t pd, pd1, pd2;
-
- tmp = prev >> 8;
- pd = prev ^ value;
- pd1 = pd & 0x000F;
- pd2 = ((pd >> 4) & 0x000F) ^ pd1;
- tmp ^= (pd1 << 3) | (pd1 << 8);
- tmp ^= pd2 | (pd2 << 7) | (pd2 << 12);
-
- return tmp;
-}
-
-static uint16_t NVRAM_compute_crc (nvram_t *nvram, uint32_t start, uint32_t count)
-{
- uint32_t i;
- uint16_t crc = 0xFFFF;
- int odd;
-
- odd = count & 1;
- count &= ~1;
- for (i = 0; i != count; i++) {
- crc = NVRAM_crc_update(crc, NVRAM_get_word(nvram, start + i));
- }
- if (odd) {
- crc = NVRAM_crc_update(crc, NVRAM_get_byte(nvram, start + i) << 8);
- }
-
- return crc;
-}
-
-#define CMDLINE_ADDR 0x017ff000
-
-int PPC_NVRAM_set_params (nvram_t *nvram, uint16_t NVRAM_size,
- const char *arch,
- uint32_t RAM_size, int boot_device,
- uint32_t kernel_image, uint32_t kernel_size,
- const char *cmdline,
- uint32_t initrd_image, uint32_t initrd_size,
- uint32_t NVRAM_image,
- int width, int height, int depth)
-{
- uint16_t crc;
-
- /* Set parameters for Open Hack'Ware BIOS */
- NVRAM_set_string(nvram, 0x00, "QEMU_BIOS", 16);
- NVRAM_set_lword(nvram, 0x10, 0x00000002); /* structure v2 */
- NVRAM_set_word(nvram, 0x14, NVRAM_size);
- NVRAM_set_string(nvram, 0x20, arch, 16);
- NVRAM_set_lword(nvram, 0x30, RAM_size);
- NVRAM_set_byte(nvram, 0x34, boot_device);
- NVRAM_set_lword(nvram, 0x38, kernel_image);
- NVRAM_set_lword(nvram, 0x3C, kernel_size);
- if (cmdline) {
- /* XXX: put the cmdline in NVRAM too ? */
- pstrcpy_targphys("cmdline", CMDLINE_ADDR, RAM_size - CMDLINE_ADDR, cmdline);
- NVRAM_set_lword(nvram, 0x40, CMDLINE_ADDR);
- NVRAM_set_lword(nvram, 0x44, strlen(cmdline));
- } else {
- NVRAM_set_lword(nvram, 0x40, 0);
- NVRAM_set_lword(nvram, 0x44, 0);
- }
- NVRAM_set_lword(nvram, 0x48, initrd_image);
- NVRAM_set_lword(nvram, 0x4C, initrd_size);
- NVRAM_set_lword(nvram, 0x50, NVRAM_image);
-
- NVRAM_set_word(nvram, 0x54, width);
- NVRAM_set_word(nvram, 0x56, height);
- NVRAM_set_word(nvram, 0x58, depth);
- crc = NVRAM_compute_crc(nvram, 0x00, 0xF8);
- NVRAM_set_word(nvram, 0xFC, crc);
-
- return 0;
-}
-
/* CPU device-tree ID helpers */
int ppc_get_vcpu_dt_id(PowerPCCPU *cpu)
{
diff --git a/hw/ppc/ppc405_boards.c b/hw/ppc/ppc405_boards.c
index 1dcea7730..ec6c4cbaf 100644
--- a/hw/ppc/ppc405_boards.c
+++ b/hw/ppc/ppc405_boards.c
@@ -283,7 +283,7 @@ static void ref405ep_init(MachineState *machine)
#ifdef DEBUG_BOARD_INIT
printf("%s: register NVRAM\n", __func__);
#endif
- m48t59_init(NULL, 0xF0000000, 0, 8192, 8);
+ m48t59_init(NULL, 0xF0000000, 0, 8192, 1968, 8);
/* Load kernel */
linux_boot = (kernel_filename != NULL);
if (linux_boot) {
diff --git a/hw/ppc/prep.c b/hw/ppc/prep.c
index 15df7f3da..7f52662d7 100644
--- a/hw/ppc/prep.c
+++ b/hw/ppc/prep.c
@@ -181,7 +181,7 @@ static const MemoryRegionOps PPC_XCSR_ops = {
/* Fake super-io ports for PREP platform (Intel 82378ZB) */
typedef struct sysctrl_t {
qemu_irq reset_irq;
- M48t59State *nvram;
+ Nvram *nvram;
uint8_t state;
uint8_t syscontrol;
int contiguous_map;
@@ -235,13 +235,17 @@ static void PREP_io_800_writeb (void *opaque, uint32_t addr, uint32_t val)
break;
case 0x0810:
/* Password protect 1 register */
- if (sysctrl->nvram != NULL)
- m48t59_toggle_lock(sysctrl->nvram, 1);
+ if (sysctrl->nvram != NULL) {
+ NvramClass *k = NVRAM_GET_CLASS(sysctrl->nvram);
+ (k->toggle_lock)(sysctrl->nvram, 1);
+ }
break;
case 0x0812:
/* Password protect 2 register */
- if (sysctrl->nvram != NULL)
- m48t59_toggle_lock(sysctrl->nvram, 2);
+ if (sysctrl->nvram != NULL) {
+ NvramClass *k = NVRAM_GET_CLASS(sysctrl->nvram);
+ (k->toggle_lock)(sysctrl->nvram, 2);
+ }
break;
case 0x0814:
/* L2 invalidate register */
@@ -360,6 +364,144 @@ static const MemoryRegionPortio prep_portio_list[] = {
static PortioList prep_port_list;
+/*****************************************************************************/
+/* NVRAM helpers */
+static inline uint32_t nvram_read(Nvram *nvram, uint32_t addr)
+{
+ NvramClass *k = NVRAM_GET_CLASS(sysctrl->nvram);
+ return (k->read)(nvram, addr);
+}
+
+static inline void nvram_write(Nvram *nvram, uint32_t addr, uint32_t val)
+{
+ NvramClass *k = NVRAM_GET_CLASS(sysctrl->nvram);
+ (k->write)(nvram, addr, val);
+}
+
+static void NVRAM_set_byte(Nvram *nvram, uint32_t addr, uint8_t value)
+{
+ nvram_write(nvram, addr, value);
+}
+
+static uint8_t NVRAM_get_byte(Nvram *nvram, uint32_t addr)
+{
+ return nvram_read(nvram, addr);
+}
+
+static void NVRAM_set_word(Nvram *nvram, uint32_t addr, uint16_t value)
+{
+ nvram_write(nvram, addr, value >> 8);
+ nvram_write(nvram, addr + 1, value & 0xFF);
+}
+
+static uint16_t NVRAM_get_word(Nvram *nvram, uint32_t addr)
+{
+ uint16_t tmp;
+
+ tmp = nvram_read(nvram, addr) << 8;
+ tmp |= nvram_read(nvram, addr + 1);
+
+ return tmp;
+}
+
+static void NVRAM_set_lword(Nvram *nvram, uint32_t addr, uint32_t value)
+{
+ nvram_write(nvram, addr, value >> 24);
+ nvram_write(nvram, addr + 1, (value >> 16) & 0xFF);
+ nvram_write(nvram, addr + 2, (value >> 8) & 0xFF);
+ nvram_write(nvram, addr + 3, value & 0xFF);
+}
+
+static void NVRAM_set_string(Nvram *nvram, uint32_t addr, const char *str,
+ uint32_t max)
+{
+ int i;
+
+ for (i = 0; i < max && str[i] != '\0'; i++) {
+ nvram_write(nvram, addr + i, str[i]);
+ }
+ nvram_write(nvram, addr + i, str[i]);
+ nvram_write(nvram, addr + max - 1, '\0');
+}
+
+static uint16_t NVRAM_crc_update (uint16_t prev, uint16_t value)
+{
+ uint16_t tmp;
+ uint16_t pd, pd1, pd2;
+
+ tmp = prev >> 8;
+ pd = prev ^ value;
+ pd1 = pd & 0x000F;
+ pd2 = ((pd >> 4) & 0x000F) ^ pd1;
+ tmp ^= (pd1 << 3) | (pd1 << 8);
+ tmp ^= pd2 | (pd2 << 7) | (pd2 << 12);
+
+ return tmp;
+}
+
+static uint16_t NVRAM_compute_crc (Nvram *nvram, uint32_t start, uint32_t count)
+{
+ uint32_t i;
+ uint16_t crc = 0xFFFF;
+ int odd;
+
+ odd = count & 1;
+ count &= ~1;
+ for (i = 0; i != count; i++) {
+ crc = NVRAM_crc_update(crc, NVRAM_get_word(nvram, start + i));
+ }
+ if (odd) {
+ crc = NVRAM_crc_update(crc, NVRAM_get_byte(nvram, start + i) << 8);
+ }
+
+ return crc;
+}
+
+#define CMDLINE_ADDR 0x017ff000
+
+static int PPC_NVRAM_set_params (Nvram *nvram, uint16_t NVRAM_size,
+ const char *arch,
+ uint32_t RAM_size, int boot_device,
+ uint32_t kernel_image, uint32_t kernel_size,
+ const char *cmdline,
+ uint32_t initrd_image, uint32_t initrd_size,
+ uint32_t NVRAM_image,
+ int width, int height, int depth)
+{
+ uint16_t crc;
+
+ /* Set parameters for Open Hack'Ware BIOS */
+ NVRAM_set_string(nvram, 0x00, "QEMU_BIOS", 16);
+ NVRAM_set_lword(nvram, 0x10, 0x00000002); /* structure v2 */
+ NVRAM_set_word(nvram, 0x14, NVRAM_size);
+ NVRAM_set_string(nvram, 0x20, arch, 16);
+ NVRAM_set_lword(nvram, 0x30, RAM_size);
+ NVRAM_set_byte(nvram, 0x34, boot_device);
+ NVRAM_set_lword(nvram, 0x38, kernel_image);
+ NVRAM_set_lword(nvram, 0x3C, kernel_size);
+ if (cmdline) {
+ /* XXX: put the cmdline in NVRAM too ? */
+ pstrcpy_targphys("cmdline", CMDLINE_ADDR, RAM_size - CMDLINE_ADDR,
+ cmdline);
+ NVRAM_set_lword(nvram, 0x40, CMDLINE_ADDR);
+ NVRAM_set_lword(nvram, 0x44, strlen(cmdline));
+ } else {
+ NVRAM_set_lword(nvram, 0x40, 0);
+ NVRAM_set_lword(nvram, 0x44, 0);
+ }
+ NVRAM_set_lword(nvram, 0x48, initrd_image);
+ NVRAM_set_lword(nvram, 0x4C, initrd_size);
+ NVRAM_set_lword(nvram, 0x50, NVRAM_image);
+
+ NVRAM_set_word(nvram, 0x54, width);
+ NVRAM_set_word(nvram, 0x56, height);
+ NVRAM_set_word(nvram, 0x58, depth);
+ crc = NVRAM_compute_crc(nvram, 0x00, 0xF8);
+ NVRAM_set_word(nvram, 0xFC, crc);
+
+ return 0;
+}
+
/* PowerPC PREP hardware initialisation */
static void ppc_prep_init(MachineState *machine)
{
@@ -372,8 +514,7 @@ static void ppc_prep_init(MachineState *machine)
MemoryRegion *sysmem = get_system_memory();
PowerPCCPU *cpu = NULL;
CPUPPCState *env = NULL;
- nvram_t nvram;
- M48t59State *m48t59;
+ Nvram *m48t59;
#if 0
MemoryRegion *xcsr = g_new(MemoryRegion, 1);
#endif
@@ -543,16 +684,14 @@ static void ppc_prep_init(MachineState *machine)
pci_create_simple(pci_bus, -1, "pci-ohci");
}
- m48t59 = m48t59_init_isa(isa_bus, 0x0074, NVRAM_SIZE, 59);
+ m48t59 = m48t59_init_isa(isa_bus, 0x0074, NVRAM_SIZE, 2000, 59);
if (m48t59 == NULL)
return;
sysctrl->nvram = m48t59;
/* Initialise NVRAM */
- nvram.opaque = m48t59;
- nvram.read_fn = &m48t59_read;
- nvram.write_fn = &m48t59_write;
- PPC_NVRAM_set_params(&nvram, NVRAM_SIZE, "PREP", ram_size, ppc_boot_device,
+ PPC_NVRAM_set_params(m48t59, NVRAM_SIZE, "PREP", ram_size,
+ ppc_boot_device,
kernel_base, kernel_size,
kernel_cmdline,
initrd_base, initrd_size,
diff --git a/hw/s390x/ipl.c b/hw/s390x/ipl.c
index b57adbd99..d6c0a4907 100644
--- a/hw/s390x/ipl.c
+++ b/hw/s390x/ipl.c
@@ -14,6 +14,7 @@
#include "sysemu/sysemu.h"
#include "cpu.h"
#include "elf.h"
+#include "exec/ram_addr.h"
#include "hw/loader.h"
#include "hw/sysbus.h"
#include "hw/s390x/virtio-ccw.h"
@@ -95,6 +96,16 @@ static const VMStateDescription vmstate_ipl = {
}
};
+static uint64_t bios_translate_addr(void *opaque, uint64_t srcaddr)
+{
+ uint64_t dstaddr = *(uint64_t *) opaque;
+ /*
+ * Assuming that our s390-ccw.img was linked for starting at address 0,
+ * we can simply add the destination address for the final location
+ */
+ return srcaddr + dstaddr;
+}
+
static int s390_ipl_init(SysBusDevice *dev)
{
S390IPLState *ipl = S390_IPL(dev);
@@ -109,6 +120,8 @@ static int s390_ipl_init(SysBusDevice *dev)
* even if an external kernel has been defined.
*/
if (!ipl->kernel || ipl->enforce_bios) {
+ uint64_t fwbase = (MIN(ram_size, 0x80000000U) - 0x200000) & ~0xffffUL;
+
if (bios_name == NULL) {
bios_name = ipl->firmware;
}
@@ -118,9 +131,14 @@ static int s390_ipl_init(SysBusDevice *dev)
hw_error("could not find stage1 bootloader\n");
}
- bios_size = load_elf(bios_filename, NULL, NULL, &ipl->bios_start_addr,
- NULL, NULL, 1, ELF_MACHINE, 0);
- if (bios_size < 0) {
+ bios_size = load_elf(bios_filename, bios_translate_addr, &fwbase,
+ &ipl->bios_start_addr, NULL, NULL, 1,
+ ELF_MACHINE, 0);
+ if (bios_size > 0) {
+ /* Adjust ELF start address to final location */
+ ipl->bios_start_addr += fwbase;
+ } else {
+ /* Try to load non-ELF file (e.g. s390-zipl.rom) */
bios_size = load_image_targphys(bios_filename, ZIPL_IMAGE_START,
4096);
ipl->bios_start_addr = ZIPL_IMAGE_START;
diff --git a/hw/s390x/s390-virtio-bus.c b/hw/s390x/s390-virtio-bus.c
index 39dc2011b..55a5581d1 100644
--- a/hw/s390x/s390-virtio-bus.c
+++ b/hw/s390x/s390-virtio-bus.c
@@ -111,7 +111,8 @@ VirtIOS390Bus *s390_virtio_bus_init(ram_addr_t *ram_size)
return bus;
}
-static int s390_virtio_device_init(VirtIOS390Device *dev, VirtIODevice *vdev)
+static void s390_virtio_device_init(VirtIOS390Device *dev,
+ VirtIODevice *vdev)
{
VirtIOS390Bus *bus;
int dev_len;
@@ -135,25 +136,26 @@ static int s390_virtio_device_init(VirtIOS390Device *dev, VirtIODevice *vdev)
if (dev->qdev.hotplugged) {
s390_virtio_irq(VIRTIO_PARAM_DEV_ADD, dev->dev_offs);
}
-
- return 0;
}
-static int s390_virtio_net_init(VirtIOS390Device *s390_dev)
+static void s390_virtio_net_realize(VirtIOS390Device *s390_dev, Error **errp)
{
DeviceState *qdev = DEVICE(s390_dev);
VirtIONetS390 *dev = VIRTIO_NET_S390(s390_dev);
DeviceState *vdev = DEVICE(&dev->vdev);
+ Error *err = NULL;
virtio_net_set_config_size(&dev->vdev, s390_dev->host_features);
virtio_net_set_netclient_name(&dev->vdev, qdev->id,
object_get_typename(OBJECT(qdev)));
qdev_set_parent_bus(vdev, BUS(&s390_dev->bus));
- if (qdev_init(vdev) < 0) {
- return -1;
+ object_property_set_bool(OBJECT(vdev), true, "realized", &err);
+ if (err) {
+ error_propagate(errp, err);
+ return;
}
- return s390_virtio_device_init(s390_dev, VIRTIO_DEVICE(vdev));
+ s390_virtio_device_init(s390_dev, VIRTIO_DEVICE(vdev));
}
static void s390_virtio_net_instance_init(Object *obj)
@@ -166,15 +168,19 @@ static void s390_virtio_net_instance_init(Object *obj)
"bootindex", &error_abort);
}
-static int s390_virtio_blk_init(VirtIOS390Device *s390_dev)
+static void s390_virtio_blk_realize(VirtIOS390Device *s390_dev, Error **errp)
{
VirtIOBlkS390 *dev = VIRTIO_BLK_S390(s390_dev);
DeviceState *vdev = DEVICE(&dev->vdev);
+ Error *err = NULL;
+
qdev_set_parent_bus(vdev, BUS(&s390_dev->bus));
- if (qdev_init(vdev) < 0) {
- return -1;
+ object_property_set_bool(OBJECT(vdev), true, "realized", &err);
+ if (err) {
+ error_propagate(errp, err);
+ return;
}
- return s390_virtio_device_init(s390_dev, VIRTIO_DEVICE(vdev));
+ s390_virtio_device_init(s390_dev, VIRTIO_DEVICE(vdev));
}
static void s390_virtio_blk_instance_init(Object *obj)
@@ -189,13 +195,13 @@ static void s390_virtio_blk_instance_init(Object *obj)
"bootindex", &error_abort);
}
-static int s390_virtio_serial_init(VirtIOS390Device *s390_dev)
+static void s390_virtio_serial_realize(VirtIOS390Device *s390_dev, Error **errp)
{
VirtIOSerialS390 *dev = VIRTIO_SERIAL_S390(s390_dev);
DeviceState *vdev = DEVICE(&dev->vdev);
DeviceState *qdev = DEVICE(s390_dev);
+ Error *err = NULL;
VirtIOS390Bus *bus;
- int r;
char *bus_name;
bus = DO_UPCAST(VirtIOS390Bus, bus, qdev->parent_bus);
@@ -211,16 +217,14 @@ static int s390_virtio_serial_init(VirtIOS390Device *s390_dev)
}
qdev_set_parent_bus(vdev, BUS(&s390_dev->bus));
- if (qdev_init(vdev) < 0) {
- return -1;
+ object_property_set_bool(OBJECT(vdev), true, "realized", &err);
+ if (err) {
+ error_propagate(errp, err);
+ return;
}
- r = s390_virtio_device_init(s390_dev, VIRTIO_DEVICE(vdev));
- if (!r) {
- bus->console = s390_dev;
- }
-
- return r;
+ s390_virtio_device_init(s390_dev, VIRTIO_DEVICE(vdev));
+ bus->console = s390_dev;
}
static void s390_virtio_serial_instance_init(Object *obj)
@@ -231,11 +235,12 @@ static void s390_virtio_serial_instance_init(Object *obj)
TYPE_VIRTIO_SERIAL);
}
-static int s390_virtio_scsi_init(VirtIOS390Device *s390_dev)
+static void s390_virtio_scsi_realize(VirtIOS390Device *s390_dev, Error **errp)
{
VirtIOSCSIS390 *dev = VIRTIO_SCSI_S390(s390_dev);
DeviceState *vdev = DEVICE(&dev->vdev);
DeviceState *qdev = DEVICE(s390_dev);
+ Error *err = NULL;
char *bus_name;
/*
@@ -249,11 +254,13 @@ static int s390_virtio_scsi_init(VirtIOS390Device *s390_dev)
}
qdev_set_parent_bus(vdev, BUS(&s390_dev->bus));
- if (qdev_init(vdev) < 0) {
- return -1;
+ object_property_set_bool(OBJECT(vdev), true, "realized", &err);
+ if (err) {
+ error_propagate(errp, err);
+ return;
}
- return s390_virtio_device_init(s390_dev, VIRTIO_DEVICE(vdev));
+ s390_virtio_device_init(s390_dev, VIRTIO_DEVICE(vdev));
}
static void s390_virtio_scsi_instance_init(Object *obj)
@@ -265,17 +272,20 @@ static void s390_virtio_scsi_instance_init(Object *obj)
}
#ifdef CONFIG_VHOST_SCSI
-static int s390_vhost_scsi_init(VirtIOS390Device *s390_dev)
+static void s390_vhost_scsi_realize(VirtIOS390Device *s390_dev, Error **errp)
{
VHostSCSIS390 *dev = VHOST_SCSI_S390(s390_dev);
DeviceState *vdev = DEVICE(&dev->vdev);
+ Error *err = NULL;
qdev_set_parent_bus(vdev, BUS(&s390_dev->bus));
- if (qdev_init(vdev) < 0) {
- return -1;
+ object_property_set_bool(OBJECT(vdev), true, "realized", &err);
+ if (err) {
+ error_propagate(errp, err);
+ return;
}
- return s390_virtio_device_init(s390_dev, VIRTIO_DEVICE(vdev));
+ s390_virtio_device_init(s390_dev, VIRTIO_DEVICE(vdev));
}
static void s390_vhost_scsi_instance_init(Object *obj)
@@ -288,21 +298,24 @@ static void s390_vhost_scsi_instance_init(Object *obj)
#endif
-static int s390_virtio_rng_init(VirtIOS390Device *s390_dev)
+static void s390_virtio_rng_realize(VirtIOS390Device *s390_dev, Error **errp)
{
VirtIORNGS390 *dev = VIRTIO_RNG_S390(s390_dev);
DeviceState *vdev = DEVICE(&dev->vdev);
+ Error *err = NULL;
qdev_set_parent_bus(vdev, BUS(&s390_dev->bus));
- if (qdev_init(vdev) < 0) {
- return -1;
+ object_property_set_bool(OBJECT(vdev), true, "realized", &err);
+ if (err) {
+ error_propagate(errp, err);
+ return;
}
object_property_set_link(OBJECT(dev),
OBJECT(dev->vdev.conf.rng), "rng",
NULL);
- return s390_virtio_device_init(s390_dev, VIRTIO_DEVICE(vdev));
+ s390_virtio_device_init(s390_dev, VIRTIO_DEVICE(vdev));
}
static void s390_virtio_rng_instance_init(Object *obj)
@@ -509,7 +522,7 @@ static void s390_virtio_net_class_init(ObjectClass *klass, void *data)
DeviceClass *dc = DEVICE_CLASS(klass);
VirtIOS390DeviceClass *k = VIRTIO_S390_DEVICE_CLASS(klass);
- k->init = s390_virtio_net_init;
+ k->realize = s390_virtio_net_realize;
dc->props = s390_virtio_net_properties;
}
@@ -525,7 +538,7 @@ static void s390_virtio_blk_class_init(ObjectClass *klass, void *data)
{
VirtIOS390DeviceClass *k = VIRTIO_S390_DEVICE_CLASS(klass);
- k->init = s390_virtio_blk_init;
+ k->realize = s390_virtio_blk_realize;
}
static const TypeInfo s390_virtio_blk = {
@@ -545,7 +558,7 @@ static void s390_virtio_serial_class_init(ObjectClass *klass, void *data)
DeviceClass *dc = DEVICE_CLASS(klass);
VirtIOS390DeviceClass *k = VIRTIO_S390_DEVICE_CLASS(klass);
- k->init = s390_virtio_serial_init;
+ k->realize = s390_virtio_serial_realize;
dc->props = s390_virtio_serial_properties;
}
@@ -567,7 +580,7 @@ static void s390_virtio_rng_class_init(ObjectClass *klass, void *data)
DeviceClass *dc = DEVICE_CLASS(klass);
VirtIOS390DeviceClass *k = VIRTIO_S390_DEVICE_CLASS(klass);
- k->init = s390_virtio_rng_init;
+ k->realize = s390_virtio_rng_realize;
dc->props = s390_virtio_rng_properties;
}
@@ -579,14 +592,14 @@ static const TypeInfo s390_virtio_rng = {
.class_init = s390_virtio_rng_class_init,
};
-static int s390_virtio_busdev_init(DeviceState *dev)
+static void s390_virtio_busdev_realize(DeviceState *dev, Error **errp)
{
VirtIOS390Device *_dev = (VirtIOS390Device *)dev;
VirtIOS390DeviceClass *_info = VIRTIO_S390_DEVICE_GET_CLASS(dev);
virtio_s390_bus_new(&_dev->bus, sizeof(_dev->bus), _dev);
- return _info->init(_dev);
+ _info->realize(_dev, errp);
}
static void s390_virtio_busdev_reset(DeviceState *dev)
@@ -600,7 +613,7 @@ static void virtio_s390_device_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
- dc->init = s390_virtio_busdev_init;
+ dc->realize = s390_virtio_busdev_realize;
dc->bus_type = TYPE_S390_VIRTIO_BUS;
dc->reset = s390_virtio_busdev_reset;
}
@@ -625,7 +638,7 @@ static void s390_virtio_scsi_class_init(ObjectClass *klass, void *data)
DeviceClass *dc = DEVICE_CLASS(klass);
VirtIOS390DeviceClass *k = VIRTIO_S390_DEVICE_CLASS(klass);
- k->init = s390_virtio_scsi_init;
+ k->realize = s390_virtio_scsi_realize;
dc->props = s390_virtio_scsi_properties;
}
@@ -648,7 +661,7 @@ static void s390_vhost_scsi_class_init(ObjectClass *klass, void *data)
DeviceClass *dc = DEVICE_CLASS(klass);
VirtIOS390DeviceClass *k = VIRTIO_S390_DEVICE_CLASS(klass);
- k->init = s390_vhost_scsi_init;
+ k->realize = s390_vhost_scsi_realize;
dc->props = s390_vhost_scsi_properties;
}
diff --git a/hw/s390x/s390-virtio-bus.h b/hw/s390x/s390-virtio-bus.h
index 92aa9d049..810a6ef1f 100644
--- a/hw/s390x/s390-virtio-bus.h
+++ b/hw/s390x/s390-virtio-bus.h
@@ -83,7 +83,7 @@ typedef struct VirtIOS390Device VirtIOS390Device;
typedef struct VirtIOS390DeviceClass {
DeviceClass qdev;
- int (*init)(VirtIOS390Device *dev);
+ void (*realize)(VirtIOS390Device *dev, Error **errp);
} VirtIOS390DeviceClass;
struct VirtIOS390Device {
diff --git a/hw/s390x/s390-virtio-ccw.c b/hw/s390x/s390-virtio-ccw.c
index 8f0ae59b5..dac00cec7 100644
--- a/hw/s390x/s390-virtio-ccw.c
+++ b/hw/s390x/s390-virtio-ccw.c
@@ -97,6 +97,7 @@ static void ccw_init(MachineState *machine)
ram_addr_t pad_size = 0;
ram_addr_t maxmem = qemu_opt_get_size(opts, "maxmem", my_ram_size);
ram_addr_t standby_mem_size = maxmem - my_ram_size;
+ uint64_t kvm_limit;
/* The storage increment size is a multiple of 1M and is a power of 2.
* The number of storage increments must be MAX_STORAGE_INCREMENTS or fewer.
@@ -121,6 +122,15 @@ static void ccw_init(MachineState *machine)
/* let's propagate the changed ram size into the global variable. */
ram_size = my_ram_size;
+ machine->maxram_size = my_ram_size + standby_mem_size;
+
+ ret = s390_set_memory_limit(machine->maxram_size, &kvm_limit);
+ if (ret == -E2BIG) {
+ hw_error("qemu: host supports a maximum of %" PRIu64 " GB",
+ kvm_limit >> 30);
+ } else if (ret) {
+ hw_error("qemu: setting the guest size failed");
+ }
/* get a BUS */
css_bus = virtual_css_bus_init();
diff --git a/hw/s390x/virtio-ccw.c b/hw/s390x/virtio-ccw.c
index ffbb9c2c8..fce52a929 100644
--- a/hw/s390x/virtio-ccw.c
+++ b/hw/s390x/virtio-ccw.c
@@ -607,7 +607,8 @@ static int virtio_ccw_cb(SubchDev *sch, CCW1 ccw)
return ret;
}
-static int virtio_ccw_device_init(VirtioCcwDevice *dev, VirtIODevice *vdev)
+static void virtio_ccw_device_realize(VirtioCcwDevice *dev,
+ VirtIODevice *vdev, Error **errp)
{
unsigned int cssid = 0;
unsigned int ssid = 0;
@@ -616,7 +617,6 @@ static int virtio_ccw_device_init(VirtioCcwDevice *dev, VirtIODevice *vdev)
bool have_devno = false;
bool found = false;
SubchDev *sch;
- int ret;
int num;
DeviceState *parent = DEVICE(dev);
@@ -639,21 +639,19 @@ static int virtio_ccw_device_init(VirtioCcwDevice *dev, VirtIODevice *vdev)
num = sscanf(dev->bus_id, "%x.%x.%04x", &cssid, &ssid, &devno);
if (num == 3) {
if ((cssid > MAX_CSSID) || (ssid > MAX_SSID)) {
- ret = -EINVAL;
- error_report("Invalid cssid or ssid: cssid %x, ssid %x",
- cssid, ssid);
+ error_setg(errp, "Invalid cssid or ssid: cssid %x, ssid %x",
+ cssid, ssid);
goto out_err;
}
/* Enforce use of virtual cssid. */
if (cssid != VIRTUAL_CSSID) {
- ret = -EINVAL;
- error_report("cssid %x not valid for virtio devices", cssid);
+ error_setg(errp, "cssid %x not valid for virtio devices",
+ cssid);
goto out_err;
}
if (css_devno_used(cssid, ssid, devno)) {
- ret = -EEXIST;
- error_report("Device %x.%x.%04x already exists", cssid, ssid,
- devno);
+ error_setg(errp, "Device %x.%x.%04x already exists",
+ cssid, ssid, devno);
goto out_err;
}
sch->cssid = cssid;
@@ -661,8 +659,7 @@ static int virtio_ccw_device_init(VirtioCcwDevice *dev, VirtIODevice *vdev)
sch->devno = devno;
have_devno = true;
} else {
- ret = -EINVAL;
- error_report("Malformed devno parameter '%s'", dev->bus_id);
+ error_setg(errp, "Malformed devno parameter '%s'", dev->bus_id);
goto out_err;
}
}
@@ -678,9 +675,8 @@ static int virtio_ccw_device_init(VirtioCcwDevice *dev, VirtIODevice *vdev)
}
}
if (!found) {
- ret = -ENODEV;
- error_report("No free subchannel found for %x.%x.%04x", cssid, ssid,
- devno);
+ error_setg(errp, "No free subchannel found for %x.%x.%04x",
+ cssid, ssid, devno);
goto out_err;
}
trace_virtio_ccw_new_device(cssid, ssid, schid, devno,
@@ -702,8 +698,7 @@ static int virtio_ccw_device_init(VirtioCcwDevice *dev, VirtIODevice *vdev)
if (devno == MAX_SCHID) {
devno = 0;
} else if (devno == schid - 1) {
- ret = -ENODEV;
- error_report("No free devno found");
+ error_setg(errp, "No free devno found");
goto out_err;
} else {
devno++;
@@ -720,8 +715,7 @@ static int virtio_ccw_device_init(VirtioCcwDevice *dev, VirtIODevice *vdev)
}
}
if (!found) {
- ret = -ENODEV;
- error_report("Virtual channel subsystem is full!");
+ error_setg(errp, "Virtual channel subsystem is full!");
goto out_err;
}
trace_virtio_ccw_new_device(cssid, ssid, schid, devno,
@@ -748,12 +742,11 @@ static int virtio_ccw_device_init(VirtioCcwDevice *dev, VirtIODevice *vdev)
css_generate_sch_crws(sch->cssid, sch->ssid, sch->schid,
parent->hotplugged, 1);
- return 0;
+ return;
out_err:
dev->sch = NULL;
g_free(sch);
- return ret;
}
static int virtio_ccw_exit(VirtioCcwDevice *dev)
@@ -771,21 +764,24 @@ static int virtio_ccw_exit(VirtioCcwDevice *dev)
return 0;
}
-static int virtio_ccw_net_init(VirtioCcwDevice *ccw_dev)
+static void virtio_ccw_net_realize(VirtioCcwDevice *ccw_dev, Error **errp)
{
DeviceState *qdev = DEVICE(ccw_dev);
VirtIONetCcw *dev = VIRTIO_NET_CCW(ccw_dev);
DeviceState *vdev = DEVICE(&dev->vdev);
+ Error *err = NULL;
virtio_net_set_config_size(&dev->vdev, ccw_dev->host_features[0]);
virtio_net_set_netclient_name(&dev->vdev, qdev->id,
object_get_typename(OBJECT(qdev)));
qdev_set_parent_bus(vdev, BUS(&ccw_dev->bus));
- if (qdev_init(vdev) < 0) {
- return -1;
+ object_property_set_bool(OBJECT(vdev), true, "realized", &err);
+ if (err) {
+ error_propagate(errp, err);
+ return;
}
- return virtio_ccw_device_init(ccw_dev, VIRTIO_DEVICE(vdev));
+ virtio_ccw_device_realize(ccw_dev, VIRTIO_DEVICE(vdev), errp);
}
static void virtio_ccw_net_instance_init(Object *obj)
@@ -798,16 +794,20 @@ static void virtio_ccw_net_instance_init(Object *obj)
"bootindex", &error_abort);
}
-static int virtio_ccw_blk_init(VirtioCcwDevice *ccw_dev)
+static void virtio_ccw_blk_realize(VirtioCcwDevice *ccw_dev, Error **errp)
{
VirtIOBlkCcw *dev = VIRTIO_BLK_CCW(ccw_dev);
DeviceState *vdev = DEVICE(&dev->vdev);
+ Error *err = NULL;
+
qdev_set_parent_bus(vdev, BUS(&ccw_dev->bus));
- if (qdev_init(vdev) < 0) {
- return -1;
+ object_property_set_bool(OBJECT(vdev), true, "realized", &err);
+ if (err) {
+ error_propagate(errp, err);
+ return;
}
- return virtio_ccw_device_init(ccw_dev, VIRTIO_DEVICE(vdev));
+ virtio_ccw_device_realize(ccw_dev, VIRTIO_DEVICE(vdev), errp);
}
static void virtio_ccw_blk_instance_init(Object *obj)
@@ -822,11 +822,12 @@ static void virtio_ccw_blk_instance_init(Object *obj)
"bootindex", &error_abort);
}
-static int virtio_ccw_serial_init(VirtioCcwDevice *ccw_dev)
+static void virtio_ccw_serial_realize(VirtioCcwDevice *ccw_dev, Error **errp)
{
VirtioSerialCcw *dev = VIRTIO_SERIAL_CCW(ccw_dev);
DeviceState *vdev = DEVICE(&dev->vdev);
DeviceState *proxy = DEVICE(ccw_dev);
+ Error *err = NULL;
char *bus_name;
/*
@@ -840,11 +841,13 @@ static int virtio_ccw_serial_init(VirtioCcwDevice *ccw_dev)
}
qdev_set_parent_bus(vdev, BUS(&ccw_dev->bus));
- if (qdev_init(vdev) < 0) {
- return -1;
+ object_property_set_bool(OBJECT(vdev), true, "realized", &err);
+ if (err) {
+ error_propagate(errp, err);
+ return;
}
- return virtio_ccw_device_init(ccw_dev, VIRTIO_DEVICE(vdev));
+ virtio_ccw_device_realize(ccw_dev, VIRTIO_DEVICE(vdev), errp);
}
@@ -856,17 +859,20 @@ static void virtio_ccw_serial_instance_init(Object *obj)
TYPE_VIRTIO_SERIAL);
}
-static int virtio_ccw_balloon_init(VirtioCcwDevice *ccw_dev)
+static void virtio_ccw_balloon_realize(VirtioCcwDevice *ccw_dev, Error **errp)
{
VirtIOBalloonCcw *dev = VIRTIO_BALLOON_CCW(ccw_dev);
DeviceState *vdev = DEVICE(&dev->vdev);
+ Error *err = NULL;
qdev_set_parent_bus(vdev, BUS(&ccw_dev->bus));
- if (qdev_init(vdev) < 0) {
- return -1;
+ object_property_set_bool(OBJECT(vdev), true, "realized", &err);
+ if (err) {
+ error_propagate(errp, err);
+ return;
}
- return virtio_ccw_device_init(ccw_dev, VIRTIO_DEVICE(vdev));
+ virtio_ccw_device_realize(ccw_dev, VIRTIO_DEVICE(vdev), errp);
}
static void balloon_ccw_stats_get_all(Object *obj, struct Visitor *v,
@@ -909,11 +915,12 @@ static void virtio_ccw_balloon_instance_init(Object *obj)
NULL, dev, NULL);
}
-static int virtio_ccw_scsi_init(VirtioCcwDevice *ccw_dev)
+static void virtio_ccw_scsi_realize(VirtioCcwDevice *ccw_dev, Error **errp)
{
VirtIOSCSICcw *dev = VIRTIO_SCSI_CCW(ccw_dev);
DeviceState *vdev = DEVICE(&dev->vdev);
DeviceState *qdev = DEVICE(ccw_dev);
+ Error *err = NULL;
char *bus_name;
/*
@@ -927,11 +934,13 @@ static int virtio_ccw_scsi_init(VirtioCcwDevice *ccw_dev)
}
qdev_set_parent_bus(vdev, BUS(&ccw_dev->bus));
- if (qdev_init(vdev) < 0) {
- return -1;
+ object_property_set_bool(OBJECT(vdev), true, "realized", &err);
+ if (err) {
+ error_propagate(errp, err);
+ return;
}
- return virtio_ccw_device_init(ccw_dev, VIRTIO_DEVICE(vdev));
+ virtio_ccw_device_realize(ccw_dev, VIRTIO_DEVICE(vdev), errp);
}
static void virtio_ccw_scsi_instance_init(Object *obj)
@@ -945,17 +954,20 @@ static void virtio_ccw_scsi_instance_init(Object *obj)
}
#ifdef CONFIG_VHOST_SCSI
-static int vhost_ccw_scsi_init(VirtioCcwDevice *ccw_dev)
+static void vhost_ccw_scsi_realize(VirtioCcwDevice *ccw_dev, Error **errp)
{
VHostSCSICcw *dev = VHOST_SCSI_CCW(ccw_dev);
DeviceState *vdev = DEVICE(&dev->vdev);
+ Error *err = NULL;
qdev_set_parent_bus(vdev, BUS(&ccw_dev->bus));
- if (qdev_init(vdev) < 0) {
- return -1;
+ object_property_set_bool(OBJECT(vdev), true, "realized", &err);
+ if (err) {
+ error_propagate(errp, err);
+ return;
}
- return virtio_ccw_device_init(ccw_dev, VIRTIO_DEVICE(vdev));
+ virtio_ccw_device_realize(ccw_dev, VIRTIO_DEVICE(vdev), errp);
}
static void vhost_ccw_scsi_instance_init(Object *obj)
@@ -967,21 +979,24 @@ static void vhost_ccw_scsi_instance_init(Object *obj)
}
#endif
-static int virtio_ccw_rng_init(VirtioCcwDevice *ccw_dev)
+static void virtio_ccw_rng_realize(VirtioCcwDevice *ccw_dev, Error **errp)
{
VirtIORNGCcw *dev = VIRTIO_RNG_CCW(ccw_dev);
DeviceState *vdev = DEVICE(&dev->vdev);
+ Error *err = NULL;
qdev_set_parent_bus(vdev, BUS(&ccw_dev->bus));
- if (qdev_init(vdev) < 0) {
- return -1;
+ object_property_set_bool(OBJECT(vdev), true, "realized", &err);
+ if (err) {
+ error_propagate(errp, err);
+ return;
}
object_property_set_link(OBJECT(dev),
OBJECT(dev->vdev.conf.rng), "rng",
NULL);
- return virtio_ccw_device_init(ccw_dev, VIRTIO_DEVICE(vdev));
+ virtio_ccw_device_realize(ccw_dev, VIRTIO_DEVICE(vdev), errp);
}
/* DeviceState to VirtioCcwDevice. Note: used on datapath,
@@ -1391,7 +1406,7 @@ static void virtio_ccw_net_class_init(ObjectClass *klass, void *data)
DeviceClass *dc = DEVICE_CLASS(klass);
VirtIOCCWDeviceClass *k = VIRTIO_CCW_DEVICE_CLASS(klass);
- k->init = virtio_ccw_net_init;
+ k->realize = virtio_ccw_net_realize;
k->exit = virtio_ccw_exit;
dc->reset = virtio_ccw_reset;
dc->props = virtio_ccw_net_properties;
@@ -1417,7 +1432,7 @@ static void virtio_ccw_blk_class_init(ObjectClass *klass, void *data)
DeviceClass *dc = DEVICE_CLASS(klass);
VirtIOCCWDeviceClass *k = VIRTIO_CCW_DEVICE_CLASS(klass);
- k->init = virtio_ccw_blk_init;
+ k->realize = virtio_ccw_blk_realize;
k->exit = virtio_ccw_exit;
dc->reset = virtio_ccw_reset;
dc->props = virtio_ccw_blk_properties;
@@ -1443,7 +1458,7 @@ static void virtio_ccw_serial_class_init(ObjectClass *klass, void *data)
DeviceClass *dc = DEVICE_CLASS(klass);
VirtIOCCWDeviceClass *k = VIRTIO_CCW_DEVICE_CLASS(klass);
- k->init = virtio_ccw_serial_init;
+ k->realize = virtio_ccw_serial_realize;
k->exit = virtio_ccw_exit;
dc->reset = virtio_ccw_reset;
dc->props = virtio_ccw_serial_properties;
@@ -1469,7 +1484,7 @@ static void virtio_ccw_balloon_class_init(ObjectClass *klass, void *data)
DeviceClass *dc = DEVICE_CLASS(klass);
VirtIOCCWDeviceClass *k = VIRTIO_CCW_DEVICE_CLASS(klass);
- k->init = virtio_ccw_balloon_init;
+ k->realize = virtio_ccw_balloon_realize;
k->exit = virtio_ccw_exit;
dc->reset = virtio_ccw_reset;
dc->props = virtio_ccw_balloon_properties;
@@ -1496,7 +1511,7 @@ static void virtio_ccw_scsi_class_init(ObjectClass *klass, void *data)
DeviceClass *dc = DEVICE_CLASS(klass);
VirtIOCCWDeviceClass *k = VIRTIO_CCW_DEVICE_CLASS(klass);
- k->init = virtio_ccw_scsi_init;
+ k->realize = virtio_ccw_scsi_realize;
k->exit = virtio_ccw_exit;
dc->reset = virtio_ccw_reset;
dc->props = virtio_ccw_scsi_properties;
@@ -1521,7 +1536,7 @@ static void vhost_ccw_scsi_class_init(ObjectClass *klass, void *data)
DeviceClass *dc = DEVICE_CLASS(klass);
VirtIOCCWDeviceClass *k = VIRTIO_CCW_DEVICE_CLASS(klass);
- k->init = vhost_ccw_scsi_init;
+ k->realize = vhost_ccw_scsi_realize;
k->exit = virtio_ccw_exit;
dc->reset = virtio_ccw_reset;
dc->props = vhost_ccw_scsi_properties;
@@ -1558,7 +1573,7 @@ static void virtio_ccw_rng_class_init(ObjectClass *klass, void *data)
DeviceClass *dc = DEVICE_CLASS(klass);
VirtIOCCWDeviceClass *k = VIRTIO_CCW_DEVICE_CLASS(klass);
- k->init = virtio_ccw_rng_init;
+ k->realize = virtio_ccw_rng_realize;
k->exit = virtio_ccw_exit;
dc->reset = virtio_ccw_reset;
dc->props = virtio_ccw_rng_properties;
@@ -1572,14 +1587,13 @@ static const TypeInfo virtio_ccw_rng = {
.class_init = virtio_ccw_rng_class_init,
};
-static int virtio_ccw_busdev_init(DeviceState *dev)
+static void virtio_ccw_busdev_realize(DeviceState *dev, Error **errp)
{
VirtioCcwDevice *_dev = (VirtioCcwDevice *)dev;
VirtIOCCWDeviceClass *_info = VIRTIO_CCW_DEVICE_GET_CLASS(dev);
virtio_ccw_bus_new(&_dev->bus, sizeof(_dev->bus), _dev);
-
- return _info->init(_dev);
+ _info->realize(_dev, errp);
}
static int virtio_ccw_busdev_exit(DeviceState *dev)
@@ -1622,7 +1636,7 @@ static void virtio_ccw_device_class_init(ObjectClass *klass, void *data)
DeviceClass *dc = DEVICE_CLASS(klass);
dc->props = virtio_ccw_properties;
- dc->init = virtio_ccw_busdev_init;
+ dc->realize = virtio_ccw_busdev_realize;
dc->exit = virtio_ccw_busdev_exit;
dc->bus_type = TYPE_VIRTUAL_CSS_BUS;
}
diff --git a/hw/s390x/virtio-ccw.h b/hw/s390x/virtio-ccw.h
index 5a1f16ee5..4fceda735 100644
--- a/hw/s390x/virtio-ccw.h
+++ b/hw/s390x/virtio-ccw.h
@@ -64,7 +64,7 @@ typedef struct VirtioCcwDevice VirtioCcwDevice;
typedef struct VirtIOCCWDeviceClass {
DeviceClass parent_class;
- int (*init)(VirtioCcwDevice *dev);
+ void (*realize)(VirtioCcwDevice *dev, Error **errp);
int (*exit)(VirtioCcwDevice *dev);
} VirtIOCCWDeviceClass;
diff --git a/hw/scsi/esp-pci.c b/hw/scsi/esp-pci.c
index 00b729735..8d2242d0a 100644
--- a/hw/scsi/esp-pci.c
+++ b/hw/scsi/esp-pci.c
@@ -342,13 +342,12 @@ static const struct SCSIBusInfo esp_pci_scsi_info = {
.cancel = esp_request_cancelled,
};
-static int esp_pci_scsi_init(PCIDevice *dev)
+static void esp_pci_scsi_realize(PCIDevice *dev, Error **errp)
{
PCIESPState *pci = PCI_ESP(dev);
DeviceState *d = DEVICE(dev);
ESPState *s = &pci->esp;
uint8_t *pci_conf;
- Error *err = NULL;
pci_conf = dev->config;
@@ -367,13 +366,8 @@ static int esp_pci_scsi_init(PCIDevice *dev)
scsi_bus_new(&s->bus, sizeof(s->bus), d, &esp_pci_scsi_info, NULL);
if (!d->hotplugged) {
- scsi_bus_legacy_handle_cmdline(&s->bus, &err);
- if (err != NULL) {
- error_free(err);
- return -1;
- }
+ scsi_bus_legacy_handle_cmdline(&s->bus, errp);
}
- return 0;
}
static void esp_pci_scsi_uninit(PCIDevice *d)
@@ -388,7 +382,7 @@ static void esp_pci_class_init(ObjectClass *klass, void *data)
DeviceClass *dc = DEVICE_CLASS(klass);
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
- k->init = esp_pci_scsi_init;
+ k->realize = esp_pci_scsi_realize;
k->exit = esp_pci_scsi_uninit;
k->vendor_id = PCI_VENDOR_ID_AMD;
k->device_id = PCI_DEVICE_ID_AMD_SCSI;
@@ -466,17 +460,19 @@ static void dc390_write_config(PCIDevice *dev,
}
}
-static int dc390_scsi_init(PCIDevice *dev)
+static void dc390_scsi_realize(PCIDevice *dev, Error **errp)
{
DC390State *pci = DC390(dev);
+ Error *err = NULL;
uint8_t *contents;
uint16_t chksum = 0;
- int i, ret;
+ int i;
/* init base class */
- ret = esp_pci_scsi_init(dev);
- if (ret < 0) {
- return ret;
+ esp_pci_scsi_realize(dev, &err);
+ if (err) {
+ error_propagate(errp, err);
+ return;
}
/* EEPROM */
@@ -503,8 +499,6 @@ static int dc390_scsi_init(PCIDevice *dev)
chksum = 0x1234 - chksum;
contents[EE_CHKSUM1] = chksum & 0xff;
contents[EE_CHKSUM2] = chksum >> 8;
-
- return 0;
}
static void dc390_class_init(ObjectClass *klass, void *data)
@@ -512,7 +506,7 @@ static void dc390_class_init(ObjectClass *klass, void *data)
DeviceClass *dc = DEVICE_CLASS(klass);
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
- k->init = dc390_scsi_init;
+ k->realize = dc390_scsi_realize;
k->config_read = dc390_read_config;
k->config_write = dc390_write_config;
set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
diff --git a/hw/scsi/lsi53c895a.c b/hw/scsi/lsi53c895a.c
index db7d4b8c9..c5b0cc5ca 100644
--- a/hw/scsi/lsi53c895a.c
+++ b/hw/scsi/lsi53c895a.c
@@ -19,7 +19,6 @@
#include "hw/pci/pci.h"
#include "hw/scsi/scsi.h"
#include "sysemu/dma.h"
-#include "qemu/error-report.h"
//#define DEBUG_LSI
//#define DEBUG_LSI_REG
@@ -2089,12 +2088,11 @@ static const struct SCSIBusInfo lsi_scsi_info = {
.cancel = lsi_request_cancelled
};
-static int lsi_scsi_init(PCIDevice *dev)
+static void lsi_scsi_realize(PCIDevice *dev, Error **errp)
{
LSIState *s = LSI53C895A(dev);
DeviceState *d = DEVICE(dev);
uint8_t *pci_conf;
- Error *err = NULL;
pci_conf = dev->config;
@@ -2117,13 +2115,8 @@ static int lsi_scsi_init(PCIDevice *dev)
scsi_bus_new(&s->bus, sizeof(s->bus), d, &lsi_scsi_info, NULL);
if (!d->hotplugged) {
- scsi_bus_legacy_handle_cmdline(&s->bus, &err);
- if (err != NULL) {
- error_free(err);
- return -1;
- }
+ scsi_bus_legacy_handle_cmdline(&s->bus, errp);
}
- return 0;
}
static void lsi_class_init(ObjectClass *klass, void *data)
@@ -2131,7 +2124,7 @@ static void lsi_class_init(ObjectClass *klass, void *data)
DeviceClass *dc = DEVICE_CLASS(klass);
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
- k->init = lsi_scsi_init;
+ k->realize = lsi_scsi_realize;
k->vendor_id = PCI_VENDOR_ID_LSI_LOGIC;
k->device_id = PCI_DEVICE_ID_LSI_53C895A;
k->class_id = PCI_CLASS_STORAGE_SCSI;
diff --git a/hw/scsi/megasas.c b/hw/scsi/megasas.c
index 4852237a7..bf83b6538 100644
--- a/hw/scsi/megasas.c
+++ b/hw/scsi/megasas.c
@@ -2320,14 +2320,13 @@ static const struct SCSIBusInfo megasas_scsi_info = {
.cancel = megasas_command_cancel,
};
-static int megasas_scsi_init(PCIDevice *dev)
+static void megasas_scsi_realize(PCIDevice *dev, Error **errp)
{
DeviceState *d = DEVICE(dev);
MegasasState *s = MEGASAS(dev);
MegasasBaseClass *b = MEGASAS_DEVICE_GET_CLASS(s);
uint8_t *pci_conf;
int i, bar_type;
- Error *err = NULL;
pci_conf = dev->config;
@@ -2407,13 +2406,8 @@ static int megasas_scsi_init(PCIDevice *dev)
scsi_bus_new(&s->bus, sizeof(s->bus), DEVICE(dev),
&megasas_scsi_info, NULL);
if (!d->hotplugged) {
- scsi_bus_legacy_handle_cmdline(&s->bus, &err);
- if (err != NULL) {
- error_free(err);
- return -1;
- }
+ scsi_bus_legacy_handle_cmdline(&s->bus, errp);
}
- return 0;
}
static void
@@ -2507,7 +2501,7 @@ static void megasas_class_init(ObjectClass *oc, void *data)
MegasasBaseClass *e = MEGASAS_DEVICE_CLASS(oc);
const MegasasInfo *info = data;
- pc->init = megasas_scsi_init;
+ pc->realize = megasas_scsi_realize;
pc->exit = megasas_scsi_uninit;
pc->vendor_id = PCI_VENDOR_ID_LSI_LOGIC;
pc->device_id = info->device_id;
diff --git a/hw/scsi/scsi-bus.c b/hw/scsi/scsi-bus.c
index dca957682..bd2c0e4ca 100644
--- a/hw/scsi/scsi-bus.c
+++ b/hw/scsi/scsi-bus.c
@@ -242,8 +242,9 @@ SCSIDevice *scsi_bus_legacy_add_drive(SCSIBus *bus, BlockBackend *blk,
if (serial && object_property_find(OBJECT(dev), "serial", NULL)) {
qdev_prop_set_string(dev, "serial", serial);
}
- if (qdev_prop_set_drive(dev, "drive", blk) < 0) {
- error_setg(errp, "Setting drive property failed");
+ qdev_prop_set_drive(dev, "drive", blk, &err);
+ if (err) {
+ error_propagate(errp, err);
object_unparent(OBJECT(dev));
return NULL;
}
@@ -273,7 +274,6 @@ void scsi_bus_legacy_handle_cmdline(SCSIBus *bus, Error **errp)
scsi_bus_legacy_add_drive(bus, blk_by_legacy_dinfo(dinfo),
unit, false, -1, NULL, &err);
if (err != NULL) {
- error_report("%s", error_get_pretty(err));
error_propagate(errp, err);
break;
}
diff --git a/hw/scsi/scsi-disk.c b/hw/scsi/scsi-disk.c
index f65618d80..54d71f4c0 100644
--- a/hw/scsi/scsi-disk.c
+++ b/hw/scsi/scsi-disk.c
@@ -2251,6 +2251,7 @@ static void scsi_realize(SCSIDevice *dev, Error **errp)
}
blkconf_serial(&s->qdev.conf, &s->serial);
+ blkconf_blocksizes(&s->qdev.conf);
if (dev->type == TYPE_DISK) {
blkconf_geometry(&dev->conf, NULL, 65535, 255, 255, &err);
if (err) {
@@ -2290,6 +2291,12 @@ static void scsi_realize(SCSIDevice *dev, Error **errp)
static void scsi_hd_realize(SCSIDevice *dev, Error **errp)
{
SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, dev);
+ /* can happen for devices without drive. The error message for missing
+ * backend will be issued in scsi_realize
+ */
+ if (s->qdev.conf.blk) {
+ blkconf_blocksizes(&s->qdev.conf);
+ }
s->qdev.blocksize = s->qdev.conf.logical_block_size;
s->qdev.type = TYPE_DISK;
if (!s->product) {
diff --git a/hw/sparc/sun4m.c b/hw/sparc/sun4m.c
index 09afccf86..b879aa91e 100644
--- a/hw/sparc/sun4m.c
+++ b/hw/sparc/sun4m.c
@@ -127,7 +127,7 @@ static void fw_cfg_boot_set(void *opaque, const char *boot_device,
fw_cfg_add_i16(opaque, FW_CFG_BOOT_DEVICE, boot_device[0]);
}
-static void nvram_init(M48t59State *nvram, uint8_t *macaddr,
+static void nvram_init(Nvram *nvram, uint8_t *macaddr,
const char *cmdline, const char *boot_devices,
ram_addr_t RAM_size, uint32_t kernel_size,
int width, int height, int depth,
@@ -137,6 +137,7 @@ static void nvram_init(M48t59State *nvram, uint8_t *macaddr,
uint32_t start, end;
uint8_t image[0x1ff0];
struct OpenBIOS_nvpart_v1 *part_header;
+ NvramClass *k = NVRAM_GET_CLASS(nvram);
memset(image, '\0', sizeof(image));
@@ -170,8 +171,9 @@ static void nvram_init(M48t59State *nvram, uint8_t *macaddr,
Sun_init_header((struct Sun_nvram *)&image[0x1fd8], macaddr,
nvram_machine_id);
- for (i = 0; i < sizeof(image); i++)
- m48t59_write(nvram, i, image[i]);
+ for (i = 0; i < sizeof(image); i++) {
+ (k->write)(nvram, i, image[i]);
+ }
}
static DeviceState *slavio_intctl;
@@ -1012,7 +1014,7 @@ static void sun4m_hw_init(const struct sun4m_hwdef *hwdef,
lance_init(&nd_table[0], hwdef->le_base, ledma, ledma_irq);
- nvram = m48t59_init(slavio_irq[0], hwdef->nvram_base, 0, 0x2000, 8);
+ nvram = m48t59_init(slavio_irq[0], hwdef->nvram_base, 0, 0x2000, 1968, 8);
slavio_timer_init_all(hwdef->counter_base, slavio_irq[19], slavio_cpu_irq, smp_cpus);
diff --git a/hw/sparc64/sun4u.c b/hw/sparc64/sun4u.c
index b310588ff..f027caf90 100644
--- a/hw/sparc64/sun4u.c
+++ b/hw/sparc64/sun4u.c
@@ -130,7 +130,7 @@ static void fw_cfg_boot_set(void *opaque, const char *boot_device,
fw_cfg_add_i16(opaque, FW_CFG_BOOT_DEVICE, boot_device[0]);
}
-static int sun4u_NVRAM_set_params(M48t59State *nvram, uint16_t NVRAM_size,
+static int sun4u_NVRAM_set_params(Nvram *nvram, uint16_t NVRAM_size,
const char *arch, ram_addr_t RAM_size,
const char *boot_devices,
uint32_t kernel_image, uint32_t kernel_size,
@@ -144,6 +144,7 @@ static int sun4u_NVRAM_set_params(M48t59State *nvram, uint16_t NVRAM_size,
uint32_t start, end;
uint8_t image[0x1ff0];
struct OpenBIOS_nvpart_v1 *part_header;
+ NvramClass *k = NVRAM_GET_CLASS(nvram);
memset(image, '\0', sizeof(image));
@@ -176,8 +177,9 @@ static int sun4u_NVRAM_set_params(M48t59State *nvram, uint16_t NVRAM_size,
Sun_init_header((struct Sun_nvram *)&image[0x1fd8], macaddr, 0x80);
- for (i = 0; i < sizeof(image); i++)
- m48t59_write(nvram, i, image[i]);
+ for (i = 0; i < sizeof(image); i++) {
+ (k->write)(nvram, i, image[i]);
+ }
return 0;
}
@@ -610,7 +612,7 @@ 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, 0x1000);
+ 0, 0x4000);
pci_register_bar(pci_dev, 1, PCI_BASE_ADDRESS_SPACE_IO, &s->bar1);
return 0;
}
@@ -818,11 +820,12 @@ static void sun4uv_init(MemoryRegion *address_space_mem,
const struct hwdef *hwdef)
{
SPARCCPU *cpu;
- M48t59State *nvram;
+ Nvram *nvram;
unsigned int i;
uint64_t initrd_addr, initrd_size, kernel_addr, kernel_size, kernel_entry;
PCIBus *pci_bus, *pci_bus2, *pci_bus3;
ISABus *isa_bus;
+ SysBusDevice *s;
qemu_irq *ivec_irqs, *pbm_irqs;
DriveInfo *hd[MAX_IDE_BUS * MAX_IDE_DEVS];
DriveInfo *fd[MAX_FD];
@@ -866,8 +869,13 @@ static void sun4uv_init(MemoryRegion *address_space_mem,
fd[i] = drive_get(IF_FLOPPY, 0, i);
}
fdctrl_init_isa(isa_bus, fd);
- nvram = m48t59_init_isa(isa_bus, 0x0074, NVRAM_SIZE, 59);
+ /* Map NVRAM into I/O (ebus) space */
+ nvram = m48t59_init(NULL, 0, 0, NVRAM_SIZE, 1968, 59);
+ s = SYS_BUS_DEVICE(nvram);
+ memory_region_add_subregion(get_system_io(), 0x2000,
+ sysbus_mmio_get_region(s, 0));
+
initrd_size = 0;
initrd_addr = 0;
kernel_size = sun4u_load_kernel(machine->kernel_filename,
diff --git a/hw/timer/Makefile.objs b/hw/timer/Makefile.objs
index 2c86c3d41..133bd0d45 100644
--- a/hw/timer/Makefile.objs
+++ b/hw/timer/Makefile.objs
@@ -31,3 +31,5 @@ obj-$(CONFIG_DIGIC) += digic-timer.o
obj-$(CONFIG_MC146818RTC) += mc146818rtc.o
obj-$(CONFIG_ALLWINNER_A10_PIT) += allwinner-a10-pit.o
+
+common-obj-$(CONFIG_STM32F2XX_TIMER) += stm32f2xx_timer.o
diff --git a/hw/timer/m48t59.c b/hw/timer/m48t59.c
index 31509d5c2..8ab683dda 100644
--- a/hw/timer/m48t59.c
+++ b/hw/timer/m48t59.c
@@ -2,6 +2,7 @@
* QEMU M48T59 and M48T08 NVRAM emulation for PPC PREP and Sparc platforms
*
* Copyright (c) 2003-2005, 2007 Jocelyn Mayer
+ * Copyright (c) 2013 Hervé Poussineau
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -37,12 +38,35 @@
#define NVRAM_PRINTF(fmt, ...) do { } while (0)
#endif
+#define TYPE_M48TXX_SYS_BUS "sysbus-m48txx"
+#define M48TXX_SYS_BUS_GET_CLASS(obj) \
+ OBJECT_GET_CLASS(M48txxSysBusDeviceClass, (obj), TYPE_M48TXX_SYS_BUS)
+#define M48TXX_SYS_BUS_CLASS(klass) \
+ OBJECT_CLASS_CHECK(M48txxSysBusDeviceClass, (klass), TYPE_M48TXX_SYS_BUS)
+#define M48TXX_SYS_BUS(obj) \
+ OBJECT_CHECK(M48txxSysBusState, (obj), TYPE_M48TXX_SYS_BUS)
+
+#define TYPE_M48TXX_ISA "isa-m48txx"
+#define M48TXX_ISA_GET_CLASS(obj) \
+ OBJECT_GET_CLASS(M48txxISADeviceClass, (obj), TYPE_M48TXX_ISA)
+#define M48TXX_ISA_CLASS(klass) \
+ OBJECT_CLASS_CHECK(M48txxISADeviceClass, (klass), TYPE_M48TXX_ISA)
+#define M48TXX_ISA(obj) \
+ OBJECT_CHECK(M48txxISAState, (obj), TYPE_M48TXX_ISA)
+
/*
* The M48T02, M48T08 and M48T59 chips are very similar. The newer '59 has
* alarm and a watchdog timer and related control registers. In the
* PPC platform there is also a nvram lock function.
*/
+typedef struct M48txxInfo {
+ const char *isa_name;
+ const char *sysbus_name;
+ uint32_t model; /* 2 = m48t02, 8 = m48t08, 59 = m48t59 */
+ uint32_t size;
+} M48txxInfo;
+
/*
* Chipset docs:
* http://www.st.com/stonline/products/literature/ds/2410/m48t02.pdf
@@ -50,12 +74,12 @@
* http://www.st.com/stonline/products/literature/od/7001/m48t59y.pdf
*/
-struct M48t59State {
+typedef struct M48t59State {
/* Hardware parameters */
qemu_irq IRQ;
MemoryRegion iomem;
- uint32_t io_base;
uint32_t size;
+ int32_t base_year;
/* RTC management */
time_t time_offset;
time_t stop_time;
@@ -70,28 +94,51 @@ struct M48t59State {
/* NVRAM storage */
uint16_t addr;
uint8_t lock;
-};
-
-#define TYPE_ISA_M48T59 "m48t59_isa"
-#define ISA_M48T59(obj) \
- OBJECT_CHECK(M48t59ISAState, (obj), TYPE_ISA_M48T59)
+} M48t59State;
-typedef struct M48t59ISAState {
+typedef struct M48txxISAState {
ISADevice parent_obj;
-
M48t59State state;
+ uint32_t io_base;
MemoryRegion io;
-} M48t59ISAState;
+} M48txxISAState;
-#define SYSBUS_M48T59(obj) \
- OBJECT_CHECK(M48t59SysBusState, (obj), TYPE_SYSBUS_M48T59)
+typedef struct M48txxISADeviceClass {
+ ISADeviceClass parent_class;
+ M48txxInfo info;
+} M48txxISADeviceClass;
-typedef struct M48t59SysBusState {
+typedef struct M48txxSysBusState {
SysBusDevice parent_obj;
-
M48t59State state;
MemoryRegion io;
-} M48t59SysBusState;
+} M48txxSysBusState;
+
+typedef struct M48txxSysBusDeviceClass {
+ SysBusDeviceClass parent_class;
+ M48txxInfo info;
+} M48txxSysBusDeviceClass;
+
+static M48txxInfo m48txx_info[] = {
+ {
+ .sysbus_name = "sysbus-m48t02",
+ .model = 2,
+ .size = 0x800,
+ },{
+ .sysbus_name = "sysbus-m48t08",
+ .model = 8,
+ .size = 0x2000,
+ },{
+ .sysbus_name = "sysbus-m48t59",
+ .model = 59,
+ .size = 0x2000,
+ },{
+ .isa_name = "isa-m48t59",
+ .model = 59,
+ .size = 0x2000,
+ }
+};
+
/* Fake timer functions */
@@ -198,9 +245,8 @@ static void set_up_watchdog(M48t59State *NVRAM, uint8_t value)
}
/* Direct access to NVRAM */
-void m48t59_write (void *opaque, uint32_t addr, uint32_t val)
+static void m48t59_write(M48t59State *NVRAM, uint32_t addr, uint32_t val)
{
- M48t59State *NVRAM = opaque;
struct tm tm;
int tmp;
@@ -346,11 +392,7 @@ void m48t59_write (void *opaque, uint32_t addr, uint32_t val)
tmp = from_bcd(val);
if (tmp >= 0 && tmp <= 99) {
get_time(NVRAM, &tm);
- if (NVRAM->model == 8) {
- tm.tm_year = from_bcd(val) + 68; // Base year is 1968
- } else {
- tm.tm_year = from_bcd(val);
- }
+ tm.tm_year = from_bcd(val) + NVRAM->base_year - 1900;
set_time(NVRAM, &tm);
}
break;
@@ -368,9 +410,8 @@ void m48t59_write (void *opaque, uint32_t addr, uint32_t val)
}
}
-uint32_t m48t59_read (void *opaque, uint32_t addr)
+static uint32_t m48t59_read(M48t59State *NVRAM, uint32_t addr)
{
- M48t59State *NVRAM = opaque;
struct tm tm;
uint32_t retval = 0xFF;
@@ -453,11 +494,7 @@ uint32_t m48t59_read (void *opaque, uint32_t addr)
case 0x07FF:
/* year */
get_time(NVRAM, &tm);
- if (NVRAM->model == 8) {
- retval = to_bcd(tm.tm_year - 68); // Base year is 1968
- } else {
- retval = to_bcd(tm.tm_year);
- }
+ retval = to_bcd((tm.tm_year + 1900 - NVRAM->base_year) % 100);
break;
default:
/* Check lock registers state */
@@ -477,10 +514,8 @@ uint32_t m48t59_read (void *opaque, uint32_t addr)
return retval;
}
-void m48t59_toggle_lock (void *opaque, int lock)
+static void m48t59_toggle_lock(M48t59State *NVRAM, int lock)
{
- M48t59State *NVRAM = opaque;
-
NVRAM->lock ^= 1 << lock;
}
@@ -616,7 +651,7 @@ static void m48t59_reset_common(M48t59State *NVRAM)
static void m48t59_reset_isa(DeviceState *d)
{
- M48t59ISAState *isa = ISA_M48T59(d);
+ M48txxISAState *isa = M48TXX_ISA(d);
M48t59State *NVRAM = &isa->state;
m48t59_reset_common(NVRAM);
@@ -624,7 +659,7 @@ static void m48t59_reset_isa(DeviceState *d)
static void m48t59_reset_sysbus(DeviceState *d)
{
- M48t59SysBusState *sys = SYSBUS_M48T59(d);
+ M48txxSysBusState *sys = M48TXX_SYS_BUS(d);
M48t59State *NVRAM = &sys->state;
m48t59_reset_common(NVRAM);
@@ -641,58 +676,63 @@ static const MemoryRegionOps m48t59_io_ops = {
};
/* Initialisation routine */
-M48t59State *m48t59_init(qemu_irq IRQ, hwaddr mem_base,
- uint32_t io_base, uint16_t size, int model)
+Nvram *m48t59_init(qemu_irq IRQ, hwaddr mem_base,
+ uint32_t io_base, uint16_t size, int base_year,
+ int model)
{
DeviceState *dev;
SysBusDevice *s;
- M48t59SysBusState *d;
- M48t59State *state;
-
- dev = qdev_create(NULL, TYPE_SYSBUS_M48T59);
- qdev_prop_set_uint32(dev, "model", model);
- qdev_prop_set_uint32(dev, "size", size);
- qdev_prop_set_uint32(dev, "io_base", io_base);
- qdev_init_nofail(dev);
- s = SYS_BUS_DEVICE(dev);
- d = SYSBUS_M48T59(dev);
- state = &d->state;
- sysbus_connect_irq(s, 0, IRQ);
- memory_region_init_io(&d->io, OBJECT(d), &m48t59_io_ops, state,
- "m48t59", 4);
- if (io_base != 0) {
- memory_region_add_subregion(get_system_io(), io_base, &d->io);
- }
- if (mem_base != 0) {
- sysbus_mmio_map(s, 0, mem_base);
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(m48txx_info); i++) {
+ if (!m48txx_info[i].sysbus_name ||
+ m48txx_info[i].size != size ||
+ m48txx_info[i].model != model) {
+ continue;
+ }
+
+ dev = qdev_create(NULL, m48txx_info[i].sysbus_name);
+ qdev_prop_set_int32(dev, "base-year", base_year);
+ qdev_init_nofail(dev);
+ s = SYS_BUS_DEVICE(dev);
+ sysbus_connect_irq(s, 0, IRQ);
+ if (io_base != 0) {
+ memory_region_add_subregion(get_system_io(), io_base,
+ sysbus_mmio_get_region(s, 1));
+ }
+ if (mem_base != 0) {
+ sysbus_mmio_map(s, 0, mem_base);
+ }
+
+ return NVRAM(s);
}
- return state;
+ assert(false);
+ return NULL;
}
-M48t59State *m48t59_init_isa(ISABus *bus, uint32_t io_base, uint16_t size,
- int model)
+Nvram *m48t59_init_isa(ISABus *bus, uint32_t io_base, uint16_t size,
+ int base_year, int model)
{
- M48t59ISAState *d;
- ISADevice *isadev;
DeviceState *dev;
- M48t59State *s;
-
- isadev = isa_create(bus, TYPE_ISA_M48T59);
- dev = DEVICE(isadev);
- qdev_prop_set_uint32(dev, "model", model);
- qdev_prop_set_uint32(dev, "size", size);
- qdev_prop_set_uint32(dev, "io_base", io_base);
- qdev_init_nofail(dev);
- d = ISA_M48T59(isadev);
- s = &d->state;
-
- memory_region_init_io(&d->io, OBJECT(d), &m48t59_io_ops, s, "m48t59", 4);
- if (io_base != 0) {
- isa_register_ioport(isadev, &d->io, io_base);
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(m48txx_info); i++) {
+ if (!m48txx_info[i].isa_name ||
+ m48txx_info[i].size != size ||
+ m48txx_info[i].model != model) {
+ continue;
+ }
+
+ dev = DEVICE(isa_create(bus, m48txx_info[i].isa_name));
+ qdev_prop_set_uint32(dev, "iobase", io_base);
+ qdev_prop_set_int32(dev, "base-year", base_year);
+ qdev_init_nofail(dev);
+ return NVRAM(dev);
}
- return s;
+ assert(false);
+ return NULL;
}
static void m48t59_realize_common(M48t59State *s, Error **errp)
@@ -709,25 +749,38 @@ static void m48t59_realize_common(M48t59State *s, Error **errp)
static void m48t59_isa_realize(DeviceState *dev, Error **errp)
{
+ M48txxISADeviceClass *u = M48TXX_ISA_GET_CLASS(dev);
ISADevice *isadev = ISA_DEVICE(dev);
- M48t59ISAState *d = ISA_M48T59(dev);
+ M48txxISAState *d = M48TXX_ISA(dev);
M48t59State *s = &d->state;
+ s->model = u->info.model;
+ s->size = u->info.size;
isa_init_irq(isadev, &s->IRQ, 8);
m48t59_realize_common(s, errp);
+ memory_region_init_io(&d->io, OBJECT(dev), &m48t59_io_ops, s, "m48t59", 4);
+ if (d->io_base != 0) {
+ isa_register_ioport(isadev, &d->io, d->io_base);
+ }
}
static int m48t59_init1(SysBusDevice *dev)
{
- M48t59SysBusState *d = SYSBUS_M48T59(dev);
+ M48txxSysBusDeviceClass *u = M48TXX_SYS_BUS_GET_CLASS(dev);
+ M48txxSysBusState *d = M48TXX_SYS_BUS(dev);
+ Object *o = OBJECT(dev);
M48t59State *s = &d->state;
Error *err = NULL;
+ s->model = u->info.model;
+ s->size = u->info.size;
sysbus_init_irq(dev, &s->IRQ);
- memory_region_init_io(&s->iomem, OBJECT(d), &nvram_ops, s,
- "m48t59.nvram", s->size);
+ memory_region_init_io(&s->iomem, o, &nvram_ops, s, "m48t59.nvram",
+ s->size);
+ memory_region_init_io(&d->io, o, &m48t59_io_ops, s, "m48t59", 4);
sysbus_init_mmio(dev, &s->iomem);
+ sysbus_init_mmio(dev, &d->io);
m48t59_realize_common(s, &err);
if (err != NULL) {
error_free(err);
@@ -737,59 +790,157 @@ static int m48t59_init1(SysBusDevice *dev)
return 0;
}
+static uint32_t m48txx_isa_read(Nvram *obj, uint32_t addr)
+{
+ M48txxISAState *d = M48TXX_ISA(obj);
+ return m48t59_read(&d->state, addr);
+}
+
+static void m48txx_isa_write(Nvram *obj, uint32_t addr, uint32_t val)
+{
+ M48txxISAState *d = M48TXX_ISA(obj);
+ m48t59_write(&d->state, addr, val);
+}
+
+static void m48txx_isa_toggle_lock(Nvram *obj, int lock)
+{
+ M48txxISAState *d = M48TXX_ISA(obj);
+ m48t59_toggle_lock(&d->state, lock);
+}
+
static Property m48t59_isa_properties[] = {
- DEFINE_PROP_UINT32("size", M48t59ISAState, state.size, -1),
- DEFINE_PROP_UINT32("model", M48t59ISAState, state.model, -1),
- DEFINE_PROP_UINT32("io_base", M48t59ISAState, state.io_base, 0),
+ DEFINE_PROP_INT32("base-year", M48txxISAState, state.base_year, 0),
+ DEFINE_PROP_UINT32("iobase", M48txxISAState, io_base, 0x74),
DEFINE_PROP_END_OF_LIST(),
};
-static void m48t59_isa_class_init(ObjectClass *klass, void *data)
+static void m48txx_isa_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
+ NvramClass *nc = NVRAM_CLASS(klass);
dc->realize = m48t59_isa_realize;
dc->reset = m48t59_reset_isa;
dc->props = m48t59_isa_properties;
- /* Reason: needs to be wired up by m48t59_init_isa() */
- dc->cannot_instantiate_with_device_add_yet = true;
+ nc->read = m48txx_isa_read;
+ nc->write = m48txx_isa_write;
+ nc->toggle_lock = m48txx_isa_toggle_lock;
}
-static const TypeInfo m48t59_isa_info = {
- .name = TYPE_ISA_M48T59,
- .parent = TYPE_ISA_DEVICE,
- .instance_size = sizeof(M48t59ISAState),
- .class_init = m48t59_isa_class_init,
-};
+static void m48txx_isa_concrete_class_init(ObjectClass *klass, void *data)
+{
+ M48txxISADeviceClass *u = M48TXX_ISA_CLASS(klass);
+ M48txxInfo *info = data;
+
+ u->info = *info;
+}
+
+static uint32_t m48txx_sysbus_read(Nvram *obj, uint32_t addr)
+{
+ M48txxSysBusState *d = M48TXX_SYS_BUS(obj);
+ return m48t59_read(&d->state, addr);
+}
+
+static void m48txx_sysbus_write(Nvram *obj, uint32_t addr, uint32_t val)
+{
+ M48txxSysBusState *d = M48TXX_SYS_BUS(obj);
+ m48t59_write(&d->state, addr, val);
+}
+
+static void m48txx_sysbus_toggle_lock(Nvram *obj, int lock)
+{
+ M48txxSysBusState *d = M48TXX_SYS_BUS(obj);
+ m48t59_toggle_lock(&d->state, lock);
+}
-static Property m48t59_properties[] = {
- DEFINE_PROP_UINT32("size", M48t59SysBusState, state.size, -1),
- DEFINE_PROP_UINT32("model", M48t59SysBusState, state.model, -1),
- DEFINE_PROP_UINT32("io_base", M48t59SysBusState, state.io_base, 0),
+static Property m48t59_sysbus_properties[] = {
+ DEFINE_PROP_INT32("base-year", M48txxSysBusState, state.base_year, 0),
DEFINE_PROP_END_OF_LIST(),
};
-static void m48t59_class_init(ObjectClass *klass, void *data)
+static void m48txx_sysbus_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
+ NvramClass *nc = NVRAM_CLASS(klass);
k->init = m48t59_init1;
dc->reset = m48t59_reset_sysbus;
- dc->props = m48t59_properties;
+ dc->props = m48t59_sysbus_properties;
+ nc->read = m48txx_sysbus_read;
+ nc->write = m48txx_sysbus_write;
+ nc->toggle_lock = m48txx_sysbus_toggle_lock;
+}
+
+static void m48txx_sysbus_concrete_class_init(ObjectClass *klass, void *data)
+{
+ M48txxSysBusDeviceClass *u = M48TXX_SYS_BUS_CLASS(klass);
+ M48txxInfo *info = data;
+
+ u->info = *info;
}
-static const TypeInfo m48t59_info = {
- .name = TYPE_SYSBUS_M48T59,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(M48t59SysBusState),
- .class_init = m48t59_class_init,
+static const TypeInfo nvram_info = {
+ .name = TYPE_NVRAM,
+ .parent = TYPE_INTERFACE,
+ .class_size = sizeof(NvramClass),
+};
+
+static const TypeInfo m48txx_sysbus_type_info = {
+ .name = TYPE_M48TXX_SYS_BUS,
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(M48txxSysBusState),
+ .abstract = true,
+ .class_init = m48txx_sysbus_class_init,
+ .interfaces = (InterfaceInfo[]) {
+ { TYPE_NVRAM },
+ { }
+ }
+};
+
+static const TypeInfo m48txx_isa_type_info = {
+ .name = TYPE_M48TXX_ISA,
+ .parent = TYPE_ISA_DEVICE,
+ .instance_size = sizeof(M48txxISAState),
+ .abstract = true,
+ .class_init = m48txx_isa_class_init,
+ .interfaces = (InterfaceInfo[]) {
+ { TYPE_NVRAM },
+ { }
+ }
};
static void m48t59_register_types(void)
{
- type_register_static(&m48t59_info);
- type_register_static(&m48t59_isa_info);
+ TypeInfo sysbus_type_info = {
+ .parent = TYPE_M48TXX_SYS_BUS,
+ .class_size = sizeof(M48txxSysBusDeviceClass),
+ .class_init = m48txx_sysbus_concrete_class_init,
+ };
+ TypeInfo isa_type_info = {
+ .parent = TYPE_M48TXX_ISA,
+ .class_size = sizeof(M48txxISADeviceClass),
+ .class_init = m48txx_isa_concrete_class_init,
+ };
+ int i;
+
+ type_register_static(&nvram_info);
+ type_register_static(&m48txx_sysbus_type_info);
+ type_register_static(&m48txx_isa_type_info);
+
+ for (i = 0; i < ARRAY_SIZE(m48txx_info); i++) {
+ if (m48txx_info[i].sysbus_name) {
+ sysbus_type_info.name = m48txx_info[i].sysbus_name;
+ sysbus_type_info.class_data = &m48txx_info[i];
+ type_register(&sysbus_type_info);
+ }
+
+ if (m48txx_info[i].isa_name) {
+ isa_type_info.name = m48txx_info[i].isa_name;
+ isa_type_info.class_data = &m48txx_info[i];
+ type_register(&isa_type_info);
+ }
+ }
}
type_init(m48t59_register_types)
diff --git a/hw/timer/stm32f2xx_timer.c b/hw/timer/stm32f2xx_timer.c
new file mode 100644
index 000000000..ecadf9df8
--- /dev/null
+++ b/hw/timer/stm32f2xx_timer.c
@@ -0,0 +1,328 @@
+/*
+ * STM32F2XX Timer
+ *
+ * Copyright (c) 2014 Alistair Francis <alistair@alistair23.me>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "hw/timer/stm32f2xx_timer.h"
+
+#ifndef STM_TIMER_ERR_DEBUG
+#define STM_TIMER_ERR_DEBUG 0
+#endif
+
+#define DB_PRINT_L(lvl, fmt, args...) do { \
+ if (STM_TIMER_ERR_DEBUG >= lvl) { \
+ qemu_log("%s: " fmt, __func__, ## args); \
+ } \
+} while (0);
+
+#define DB_PRINT(fmt, args...) DB_PRINT_L(1, fmt, ## args)
+
+static void stm32f2xx_timer_set_alarm(STM32F2XXTimerState *s, int64_t now);
+
+static void stm32f2xx_timer_interrupt(void *opaque)
+{
+ STM32F2XXTimerState *s = opaque;
+
+ DB_PRINT("Interrupt\n");
+
+ if (s->tim_dier & TIM_DIER_UIE && s->tim_cr1 & TIM_CR1_CEN) {
+ s->tim_sr |= 1;
+ qemu_irq_pulse(s->irq);
+ stm32f2xx_timer_set_alarm(s, s->hit_time);
+ }
+}
+
+static inline int64_t stm32f2xx_ns_to_ticks(STM32F2XXTimerState *s, int64_t t)
+{
+ return muldiv64(t, s->freq_hz, 1000000000ULL) / (s->tim_psc + 1);
+}
+
+static void stm32f2xx_timer_set_alarm(STM32F2XXTimerState *s, int64_t now)
+{
+ uint64_t ticks;
+ int64_t now_ticks;
+
+ if (s->tim_arr == 0) {
+ return;
+ }
+
+ DB_PRINT("Alarm set at: 0x%x\n", s->tim_cr1);
+
+ now_ticks = stm32f2xx_ns_to_ticks(s, now);
+ ticks = s->tim_arr - (now_ticks - s->tick_offset);
+
+ DB_PRINT("Alarm set in %d ticks\n", (int) ticks);
+
+ s->hit_time = muldiv64((ticks + (uint64_t) now_ticks) * (s->tim_psc + 1),
+ 1000000000ULL, s->freq_hz);
+
+ timer_mod(s->timer, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + s->hit_time);
+ DB_PRINT("Wait Time: %" PRId64 " ticks\n", s->hit_time);
+}
+
+static void stm32f2xx_timer_reset(DeviceState *dev)
+{
+ STM32F2XXTimerState *s = STM32F2XXTIMER(dev);
+ int64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
+
+ s->tim_cr1 = 0;
+ s->tim_cr2 = 0;
+ s->tim_smcr = 0;
+ s->tim_dier = 0;
+ s->tim_sr = 0;
+ s->tim_egr = 0;
+ s->tim_ccmr1 = 0;
+ s->tim_ccmr2 = 0;
+ s->tim_ccer = 0;
+ s->tim_psc = 0;
+ s->tim_arr = 0;
+ s->tim_ccr1 = 0;
+ s->tim_ccr2 = 0;
+ s->tim_ccr3 = 0;
+ s->tim_ccr4 = 0;
+ s->tim_dcr = 0;
+ s->tim_dmar = 0;
+ s->tim_or = 0;
+
+ s->tick_offset = stm32f2xx_ns_to_ticks(s, now);
+}
+
+static uint64_t stm32f2xx_timer_read(void *opaque, hwaddr offset,
+ unsigned size)
+{
+ STM32F2XXTimerState *s = opaque;
+
+ DB_PRINT("Read 0x%"HWADDR_PRIx"\n", offset);
+
+ switch (offset) {
+ case TIM_CR1:
+ return s->tim_cr1;
+ case TIM_CR2:
+ return s->tim_cr2;
+ case TIM_SMCR:
+ return s->tim_smcr;
+ case TIM_DIER:
+ return s->tim_dier;
+ case TIM_SR:
+ return s->tim_sr;
+ case TIM_EGR:
+ return s->tim_egr;
+ case TIM_CCMR1:
+ return s->tim_ccmr1;
+ case TIM_CCMR2:
+ return s->tim_ccmr2;
+ case TIM_CCER:
+ return s->tim_ccer;
+ case TIM_CNT:
+ return stm32f2xx_ns_to_ticks(s, qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL)) -
+ s->tick_offset;
+ case TIM_PSC:
+ return s->tim_psc;
+ case TIM_ARR:
+ return s->tim_arr;
+ case TIM_CCR1:
+ return s->tim_ccr1;
+ case TIM_CCR2:
+ return s->tim_ccr2;
+ case TIM_CCR3:
+ return s->tim_ccr3;
+ case TIM_CCR4:
+ return s->tim_ccr4;
+ case TIM_DCR:
+ return s->tim_dcr;
+ case TIM_DMAR:
+ return s->tim_dmar;
+ case TIM_OR:
+ return s->tim_or;
+ default:
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: Bad offset 0x%"HWADDR_PRIx"\n", __func__, offset);
+ }
+
+ return 0;
+}
+
+static void stm32f2xx_timer_write(void *opaque, hwaddr offset,
+ uint64_t val64, unsigned size)
+{
+ STM32F2XXTimerState *s = opaque;
+ uint32_t value = val64;
+ int64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
+ uint32_t timer_val = 0;
+
+ DB_PRINT("Write 0x%x, 0x%"HWADDR_PRIx"\n", value, offset);
+
+ switch (offset) {
+ case TIM_CR1:
+ s->tim_cr1 = value;
+ return;
+ case TIM_CR2:
+ s->tim_cr2 = value;
+ return;
+ case TIM_SMCR:
+ s->tim_smcr = value;
+ return;
+ case TIM_DIER:
+ s->tim_dier = value;
+ return;
+ case TIM_SR:
+ /* This is set by hardware and cleared by software */
+ s->tim_sr &= value;
+ return;
+ case TIM_EGR:
+ s->tim_egr = value;
+ if (s->tim_egr & TIM_EGR_UG) {
+ timer_val = 0;
+ break;
+ }
+ return;
+ case TIM_CCMR1:
+ s->tim_ccmr1 = value;
+ return;
+ case TIM_CCMR2:
+ s->tim_ccmr2 = value;
+ return;
+ case TIM_CCER:
+ s->tim_ccer = value;
+ return;
+ case TIM_PSC:
+ timer_val = stm32f2xx_ns_to_ticks(s, now) - s->tick_offset;
+ s->tim_psc = value;
+ value = timer_val;
+ break;
+ case TIM_CNT:
+ timer_val = value;
+ break;
+ case TIM_ARR:
+ s->tim_arr = value;
+ stm32f2xx_timer_set_alarm(s, now);
+ return;
+ case TIM_CCR1:
+ s->tim_ccr1 = value;
+ return;
+ case TIM_CCR2:
+ s->tim_ccr2 = value;
+ return;
+ case TIM_CCR3:
+ s->tim_ccr3 = value;
+ return;
+ case TIM_CCR4:
+ s->tim_ccr4 = value;
+ return;
+ case TIM_DCR:
+ s->tim_dcr = value;
+ return;
+ case TIM_DMAR:
+ s->tim_dmar = value;
+ return;
+ case TIM_OR:
+ s->tim_or = value;
+ return;
+ default:
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: Bad offset 0x%"HWADDR_PRIx"\n", __func__, offset);
+ return;
+ }
+
+ /* This means that a register write has affected the timer in a way that
+ * requires a refresh of both tick_offset and the alarm.
+ */
+ s->tick_offset = stm32f2xx_ns_to_ticks(s, now) - timer_val;
+ stm32f2xx_timer_set_alarm(s, now);
+}
+
+static const MemoryRegionOps stm32f2xx_timer_ops = {
+ .read = stm32f2xx_timer_read,
+ .write = stm32f2xx_timer_write,
+ .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static const VMStateDescription vmstate_stm32f2xx_timer = {
+ .name = TYPE_STM32F2XX_TIMER,
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .fields = (VMStateField[]) {
+ VMSTATE_INT64(tick_offset, STM32F2XXTimerState),
+ VMSTATE_UINT32(tim_cr1, STM32F2XXTimerState),
+ VMSTATE_UINT32(tim_cr2, STM32F2XXTimerState),
+ VMSTATE_UINT32(tim_smcr, STM32F2XXTimerState),
+ VMSTATE_UINT32(tim_dier, STM32F2XXTimerState),
+ VMSTATE_UINT32(tim_sr, STM32F2XXTimerState),
+ VMSTATE_UINT32(tim_egr, STM32F2XXTimerState),
+ VMSTATE_UINT32(tim_ccmr1, STM32F2XXTimerState),
+ VMSTATE_UINT32(tim_ccmr2, STM32F2XXTimerState),
+ VMSTATE_UINT32(tim_ccer, STM32F2XXTimerState),
+ VMSTATE_UINT32(tim_psc, STM32F2XXTimerState),
+ VMSTATE_UINT32(tim_arr, STM32F2XXTimerState),
+ VMSTATE_UINT32(tim_ccr1, STM32F2XXTimerState),
+ VMSTATE_UINT32(tim_ccr2, STM32F2XXTimerState),
+ VMSTATE_UINT32(tim_ccr3, STM32F2XXTimerState),
+ VMSTATE_UINT32(tim_ccr4, STM32F2XXTimerState),
+ VMSTATE_UINT32(tim_dcr, STM32F2XXTimerState),
+ VMSTATE_UINT32(tim_dmar, STM32F2XXTimerState),
+ VMSTATE_UINT32(tim_or, STM32F2XXTimerState),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static Property stm32f2xx_timer_properties[] = {
+ DEFINE_PROP_UINT64("clock-frequency", struct STM32F2XXTimerState,
+ freq_hz, 1000000000),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void stm32f2xx_timer_init(Object *obj)
+{
+ STM32F2XXTimerState *s = STM32F2XXTIMER(obj);
+
+ sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->irq);
+
+ memory_region_init_io(&s->iomem, obj, &stm32f2xx_timer_ops, s,
+ "stm32f2xx_timer", 0x4000);
+ sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->iomem);
+
+ s->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, stm32f2xx_timer_interrupt, s);
+}
+
+static void stm32f2xx_timer_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+
+ dc->reset = stm32f2xx_timer_reset;
+ dc->props = stm32f2xx_timer_properties;
+ dc->vmsd = &vmstate_stm32f2xx_timer;
+}
+
+static const TypeInfo stm32f2xx_timer_info = {
+ .name = TYPE_STM32F2XX_TIMER,
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(STM32F2XXTimerState),
+ .instance_init = stm32f2xx_timer_init,
+ .class_init = stm32f2xx_timer_class_init,
+};
+
+static void stm32f2xx_timer_register_types(void)
+{
+ type_register_static(&stm32f2xx_timer_info);
+}
+
+type_init(stm32f2xx_timer_register_types)
diff --git a/hw/unicore32/puv3.c b/hw/unicore32/puv3.c
index c41499e38..cc9a21a71 100644
--- a/hw/unicore32/puv3.c
+++ b/hw/unicore32/puv3.c
@@ -109,6 +109,7 @@ static void puv3_init(MachineState *machine)
const char *kernel_filename = machine->kernel_filename;
const char *initrd_filename = machine->initrd_filename;
CPUUniCore32State *env;
+ UniCore32CPU *cpu;
if (initrd_filename) {
hw_error("Please use kernel built-in initramdisk.\n");
@@ -118,10 +119,11 @@ static void puv3_init(MachineState *machine)
cpu_model = "UniCore-II";
}
- env = cpu_init(cpu_model);
- if (!env) {
+ cpu = uc32_cpu_init(cpu_model);
+ if (!cpu) {
hw_error("Unable to find CPU definition\n");
}
+ env = &cpu->env;
puv3_soc_init(env);
puv3_board_init(env, ram_size);
diff --git a/hw/usb/dev-storage.c b/hw/usb/dev-storage.c
index 65d9aa614..dacefd71a 100644
--- a/hw/usb/dev-storage.c
+++ b/hw/usb/dev-storage.c
@@ -611,6 +611,7 @@ static void usb_msd_realize_storage(USBDevice *dev, Error **errp)
}
blkconf_serial(&s->conf, &dev->serial);
+ blkconf_blocksizes(&s->conf);
/*
* Hack alert: this pretends to be a block device, but it's really
@@ -663,6 +664,7 @@ static void usb_msd_realize_bot(USBDevice *dev, Error **errp)
static USBDevice *usb_msd_init(USBBus *bus, const char *filename)
{
static int nr=0;
+ Error *err = NULL;
char id[8];
QemuOpts *opts;
DriveInfo *dinfo;
@@ -706,8 +708,10 @@ static USBDevice *usb_msd_init(USBBus *bus, const char *filename)
/* create guest device */
dev = usb_create(bus, "usb-storage");
- if (qdev_prop_set_drive(&dev->qdev, "drive",
- blk_by_legacy_dinfo(dinfo)) < 0) {
+ qdev_prop_set_drive(&dev->qdev, "drive", blk_by_legacy_dinfo(dinfo),
+ &err);
+ if (err) {
+ error_report_err(err);
object_unparent(OBJECT(dev));
return NULL;
}
diff --git a/include/block/block.h b/include/block/block.h
index 649c269ec..473c74634 100644
--- a/include/block/block.h
+++ b/include/block/block.h
@@ -60,6 +60,17 @@ typedef enum {
BDRV_REQ_MAY_UNMAP = 0x4,
} BdrvRequestFlags;
+typedef struct BlockSizes {
+ uint32_t phys;
+ uint32_t log;
+} BlockSizes;
+
+typedef struct HDGeometry {
+ uint32_t heads;
+ uint32_t sectors;
+ uint32_t cylinders;
+} HDGeometry;
+
#define BDRV_O_RDWR 0x0002
#define BDRV_O_SNAPSHOT 0x0008 /* open the file read only and save writes in a snapshot */
#define BDRV_O_TEMPORARY 0x0010 /* delete the file after use */
@@ -550,6 +561,8 @@ AioContext *bdrv_get_aio_context(BlockDriverState *bs);
* This function must be called with iothread lock held.
*/
void bdrv_set_aio_context(BlockDriverState *bs, AioContext *new_context);
+int bdrv_probe_blocksizes(BlockDriverState *bs, BlockSizes *bsz);
+int bdrv_probe_geometry(BlockDriverState *bs, HDGeometry *geo);
void bdrv_io_plug(BlockDriverState *bs);
void bdrv_io_unplug(BlockDriverState *bs);
diff --git a/include/block/block_int.h b/include/block/block_int.h
index b340e7e14..dccb092df 100644
--- a/include/block/block_int.h
+++ b/include/block/block_int.h
@@ -56,6 +56,8 @@
#define BLOCK_OPT_ADAPTER_TYPE "adapter_type"
#define BLOCK_OPT_REDUNDANCY "redundancy"
#define BLOCK_OPT_NOCOW "nocow"
+#define BLOCK_OPT_OBJECT_SIZE "object_size"
+#define BLOCK_OPT_REFCOUNT_BITS "refcount_bits"
#define BLOCK_PROBE_BUF_SIZE 512
@@ -273,6 +275,21 @@ struct BlockDriver {
void (*bdrv_io_unplug)(BlockDriverState *bs);
void (*bdrv_flush_io_queue)(BlockDriverState *bs);
+ /**
+ * Try to get @bs's logical and physical block size.
+ * On success, store them in @bsz and return zero.
+ * On failure, return negative errno.
+ */
+ int (*bdrv_probe_blocksizes)(BlockDriverState *bs, BlockSizes *bsz);
+ /**
+ * Try to get @bs's geometry (cyls, heads, sectors)
+ * On success, store them in @geo and return 0.
+ * On failure return -errno.
+ * Only drivers that want to override guest geometry implement this
+ * callback; see hd_geometry_guess().
+ */
+ int (*bdrv_probe_geometry)(BlockDriverState *bs, HDGeometry *geo);
+
QLIST_ENTRY(BlockDriver) list;
};
diff --git a/include/block/coroutine_int.h b/include/block/coroutine_int.h
index f133d65af..9aa1aae5d 100644
--- a/include/block/coroutine_int.h
+++ b/include/block/coroutine_int.h
@@ -31,6 +31,7 @@
typedef enum {
COROUTINE_YIELD = 1,
COROUTINE_TERMINATE = 2,
+ COROUTINE_ENTER = 3,
} CoroutineAction;
struct Coroutine {
diff --git a/include/elf.h b/include/elf.h
index a51658448..3e75f05af 100644
--- a/include/elf.h
+++ b/include/elf.h
@@ -1508,6 +1508,7 @@ struct elf32_fdpic_loadmap {
#define elf_shdr elf32_shdr
#define elf_sym elf32_sym
#define elf_addr_t Elf32_Off
+#define elf_rela elf32_rela
#ifdef ELF_USES_RELOCA
# define ELF_RELOC Elf32_Rela
@@ -1523,6 +1524,7 @@ struct elf32_fdpic_loadmap {
#define elf_shdr elf64_shdr
#define elf_sym elf64_sym
#define elf_addr_t Elf64_Off
+#define elf_rela elf64_rela
#ifdef ELF_USES_RELOCA
# define ELF_RELOC Elf64_Rela
diff --git a/include/hw/arm/stm32f205_soc.h b/include/hw/arm/stm32f205_soc.h
new file mode 100644
index 000000000..3cda17018
--- /dev/null
+++ b/include/hw/arm/stm32f205_soc.h
@@ -0,0 +1,57 @@
+/*
+ * STM32F205 SoC
+ *
+ * Copyright (c) 2014 Alistair Francis <alistair@alistair23.me>
+ *
+ * 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.
+ */
+
+#ifndef HW_ARM_STM32F205SOC_H
+#define HW_ARM_STM32F205SOC_H
+
+#include "hw/misc/stm32f2xx_syscfg.h"
+#include "hw/timer/stm32f2xx_timer.h"
+#include "hw/char/stm32f2xx_usart.h"
+
+#define TYPE_STM32F205_SOC "stm32f205_soc"
+#define STM32F205_SOC(obj) \
+ OBJECT_CHECK(STM32F205State, (obj), TYPE_STM32F205_SOC)
+
+#define STM_NUM_USARTS 6
+#define STM_NUM_TIMERS 4
+
+#define FLASH_BASE_ADDRESS 0x08000000
+#define FLASH_SIZE (1024 * 1024)
+#define SRAM_BASE_ADDRESS 0x20000000
+#define SRAM_SIZE (128 * 1024)
+
+typedef struct STM32F205State {
+ /*< private >*/
+ SysBusDevice parent_obj;
+ /*< public >*/
+
+ char *kernel_filename;
+ char *cpu_model;
+
+ STM32F2XXSyscfgState syscfg;
+ STM32F2XXUsartState usart[STM_NUM_USARTS];
+ STM32F2XXTimerState timer[STM_NUM_TIMERS];
+} STM32F205State;
+
+#endif
diff --git a/include/hw/block/block.h b/include/hw/block/block.h
index 0d0ce9a46..8d7c4b413 100644
--- a/include/hw/block/block.h
+++ b/include/hw/block/block.h
@@ -44,9 +44,9 @@ static inline unsigned int get_physical_block_exp(BlockConf *conf)
#define DEFINE_BLOCK_PROPERTIES(_state, _conf) \
DEFINE_PROP_DRIVE("drive", _state, _conf.blk), \
DEFINE_PROP_BLOCKSIZE("logical_block_size", _state, \
- _conf.logical_block_size, 512), \
+ _conf.logical_block_size), \
DEFINE_PROP_BLOCKSIZE("physical_block_size", _state, \
- _conf.physical_block_size, 512), \
+ _conf.physical_block_size), \
DEFINE_PROP_UINT16("min_io_size", _state, _conf.min_io_size, 0), \
DEFINE_PROP_UINT32("opt_io_size", _state, _conf.opt_io_size, 0), \
DEFINE_PROP_UINT32("discard_granularity", _state, \
@@ -63,6 +63,7 @@ void blkconf_serial(BlockConf *conf, char **serial);
void blkconf_geometry(BlockConf *conf, int *trans,
unsigned cyls_max, unsigned heads_max, unsigned secs_max,
Error **errp);
+void blkconf_blocksizes(BlockConf *conf);
/* Hard disk geometry */
diff --git a/include/hw/char/stm32f2xx_usart.h b/include/hw/char/stm32f2xx_usart.h
new file mode 100644
index 000000000..b97f192a4
--- /dev/null
+++ b/include/hw/char/stm32f2xx_usart.h
@@ -0,0 +1,73 @@
+/*
+ * STM32F2XX USART
+ *
+ * Copyright (c) 2014 Alistair Francis <alistair@alistair23.me>
+ *
+ * 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.
+ */
+
+#ifndef HW_STM32F2XX_USART_H
+#define HW_STM32F2XX_USART_H
+
+#include "hw/sysbus.h"
+#include "sysemu/char.h"
+#include "hw/hw.h"
+
+#define USART_SR 0x00
+#define USART_DR 0x04
+#define USART_BRR 0x08
+#define USART_CR1 0x0C
+#define USART_CR2 0x10
+#define USART_CR3 0x14
+#define USART_GTPR 0x18
+
+#define USART_SR_RESET 0x00C00000
+
+#define USART_SR_TXE (1 << 7)
+#define USART_SR_TC (1 << 6)
+#define USART_SR_RXNE (1 << 5)
+
+#define USART_CR1_UE (1 << 13)
+#define USART_CR1_RXNEIE (1 << 5)
+#define USART_CR1_TE (1 << 3)
+#define USART_CR1_RE (1 << 2)
+
+#define TYPE_STM32F2XX_USART "stm32f2xx-usart"
+#define STM32F2XX_USART(obj) \
+ OBJECT_CHECK(STM32F2XXUsartState, (obj), TYPE_STM32F2XX_USART)
+
+typedef struct {
+ /* <private> */
+ SysBusDevice parent_obj;
+
+ /* <public> */
+ MemoryRegion mmio;
+
+ uint32_t usart_sr;
+ uint32_t usart_dr;
+ uint32_t usart_brr;
+ uint32_t usart_cr1;
+ uint32_t usart_cr2;
+ uint32_t usart_cr3;
+ uint32_t usart_gtpr;
+
+ CharDriverState *chr;
+ qemu_irq irq;
+} STM32F2XXUsartState;
+#endif /* HW_STM32F2XX_USART_H */
diff --git a/include/hw/elf_ops.h b/include/hw/elf_ops.h
index a517753a6..16a627bde 100644
--- a/include/hw/elf_ops.h
+++ b/include/hw/elf_ops.h
@@ -49,6 +49,13 @@ static void glue(bswap_sym, SZ)(struct elf_sym *sym)
bswap16s(&sym->st_shndx);
}
+static void glue(bswap_rela, SZ)(struct elf_rela *rela)
+{
+ bswapSZs(&rela->r_offset);
+ bswapSZs(&rela->r_info);
+ bswapSZs((elf_word *)&rela->r_addend);
+}
+
static struct elf_shdr *glue(find_section, SZ)(struct elf_shdr *shdr_table,
int n, int type)
{
@@ -182,6 +189,75 @@ static int glue(load_symbols, SZ)(struct elfhdr *ehdr, int fd, int must_swab,
return -1;
}
+static int glue(elf_reloc, SZ)(struct elfhdr *ehdr, int fd, int must_swab,
+ uint64_t (*translate_fn)(void *, uint64_t),
+ void *translate_opaque, uint8_t *data,
+ struct elf_phdr *ph, int elf_machine)
+{
+ struct elf_shdr *reltab, *shdr_table = NULL;
+ struct elf_rela *rels = NULL;
+ int nrels, i, ret = -1;
+ elf_word wordval;
+ void *addr;
+
+ shdr_table = load_at(fd, ehdr->e_shoff,
+ sizeof(struct elf_shdr) * ehdr->e_shnum);
+ if (!shdr_table) {
+ return -1;
+ }
+ if (must_swab) {
+ for (i = 0; i < ehdr->e_shnum; i++) {
+ glue(bswap_shdr, SZ)(&shdr_table[i]);
+ }
+ }
+
+ reltab = glue(find_section, SZ)(shdr_table, ehdr->e_shnum, SHT_RELA);
+ if (!reltab) {
+ goto fail;
+ }
+ rels = load_at(fd, reltab->sh_offset, reltab->sh_size);
+ if (!rels) {
+ goto fail;
+ }
+ nrels = reltab->sh_size / sizeof(struct elf_rela);
+
+ for (i = 0; i < nrels; i++) {
+ if (must_swab) {
+ glue(bswap_rela, SZ)(&rels[i]);
+ }
+ if (rels[i].r_offset < ph->p_vaddr ||
+ rels[i].r_offset >= ph->p_vaddr + ph->p_filesz) {
+ continue;
+ }
+ addr = &data[rels[i].r_offset - ph->p_vaddr];
+ switch (elf_machine) {
+ case EM_S390:
+ switch (rels[i].r_info) {
+ case R_390_RELATIVE:
+ wordval = *(elf_word *)addr;
+ if (must_swab) {
+ bswapSZs(&wordval);
+ }
+ wordval = translate_fn(translate_opaque, wordval);
+ if (must_swab) {
+ bswapSZs(&wordval);
+ }
+ *(elf_word *)addr = wordval;
+ break;
+ default:
+ fprintf(stderr, "Unsupported relocation type %i!\n",
+ (int)rels[i].r_info);
+ }
+ }
+ }
+
+ ret = 0;
+fail:
+ g_free(rels);
+ g_free(shdr_table);
+ return ret;
+}
+
static int glue(load_elf, SZ)(const char *name, int fd,
uint64_t (*translate_fn)(void *, uint64_t),
void *translate_opaque,
@@ -271,6 +347,8 @@ static int glue(load_elf, SZ)(const char *name, int fd,
linked at the wrong physical address. */
if (translate_fn) {
addr = translate_fn(translate_opaque, ph->p_paddr);
+ glue(elf_reloc, SZ)(&ehdr, fd, must_swab, translate_fn,
+ translate_opaque, data, ph, elf_machine);
} else {
addr = ph->p_paddr;
}
diff --git a/target-i386/topology.h b/include/hw/i386/topology.h
index 07a6c5fb5..9c6f3a937 100644
--- a/target-i386/topology.h
+++ b/include/hw/i386/topology.h
@@ -21,8 +21,8 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
-#ifndef TARGET_I386_TOPOLOGY_H
-#define TARGET_I386_TOPOLOGY_H
+#ifndef HW_I386_TOPOLOGY_H
+#define HW_I386_TOPOLOGY_H
/* This file implements the APIC-ID-based CPU topology enumeration logic,
* documented at the following document:
@@ -131,4 +131,4 @@ static inline apic_id_t x86_apicid_from_cpu_idx(unsigned nr_cores,
return apicid_from_topo_ids(nr_cores, nr_threads, pkg_id, core_id, smt_id);
}
-#endif /* TARGET_I386_TOPOLOGY_H */
+#endif /* HW_I386_TOPOLOGY_H */
diff --git a/include/hw/misc/stm32f2xx_syscfg.h b/include/hw/misc/stm32f2xx_syscfg.h
new file mode 100644
index 000000000..69e6a30fc
--- /dev/null
+++ b/include/hw/misc/stm32f2xx_syscfg.h
@@ -0,0 +1,61 @@
+/*
+ * STM32F2XX SYSCFG
+ *
+ * Copyright (c) 2014 Alistair Francis <alistair@alistair23.me>
+ *
+ * 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.
+ */
+
+#ifndef HW_STM32F2XX_SYSCFG_H
+#define HW_STM32F2XX_SYSCFG_H
+
+#include "hw/sysbus.h"
+#include "hw/hw.h"
+
+#define SYSCFG_MEMRMP 0x00
+#define SYSCFG_PMC 0x04
+#define SYSCFG_EXTICR1 0x08
+#define SYSCFG_EXTICR2 0x0C
+#define SYSCFG_EXTICR3 0x10
+#define SYSCFG_EXTICR4 0x14
+#define SYSCFG_CMPCR 0x20
+
+#define TYPE_STM32F2XX_SYSCFG "stm32f2xx-syscfg"
+#define STM32F2XX_SYSCFG(obj) \
+ OBJECT_CHECK(STM32F2XXSyscfgState, (obj), TYPE_STM32F2XX_SYSCFG)
+
+typedef struct {
+ /* <private> */
+ SysBusDevice parent_obj;
+
+ /* <public> */
+ MemoryRegion mmio;
+
+ uint32_t syscfg_memrmp;
+ uint32_t syscfg_pmc;
+ uint32_t syscfg_exticr1;
+ uint32_t syscfg_exticr2;
+ uint32_t syscfg_exticr3;
+ uint32_t syscfg_exticr4;
+ uint32_t syscfg_cmpcr;
+
+ qemu_irq irq;
+} STM32F2XXSyscfgState;
+
+#endif /* HW_STM32F2XX_SYSCFG_H */
diff --git a/include/hw/qdev-properties.h b/include/hw/qdev-properties.h
index 57ee363b8..d67dad5f7 100644
--- a/include/hw/qdev-properties.h
+++ b/include/hw/qdev-properties.h
@@ -149,8 +149,8 @@ extern PropertyInfo qdev_prop_arraylen;
LostTickPolicy)
#define DEFINE_PROP_BIOS_CHS_TRANS(_n, _s, _f, _d) \
DEFINE_PROP_DEFAULT(_n, _s, _f, _d, qdev_prop_bios_chs_trans, int)
-#define DEFINE_PROP_BLOCKSIZE(_n, _s, _f, _d) \
- DEFINE_PROP_DEFAULT(_n, _s, _f, _d, qdev_prop_blocksize, uint16_t)
+#define DEFINE_PROP_BLOCKSIZE(_n, _s, _f) \
+ DEFINE_PROP_DEFAULT(_n, _s, _f, 0, qdev_prop_blocksize, uint16_t)
#define DEFINE_PROP_PCI_HOST_DEVADDR(_n, _s, _f) \
DEFINE_PROP(_n, _s, _f, qdev_prop_pci_host_devaddr, PCIHostDeviceAddress)
@@ -168,8 +168,8 @@ void qdev_prop_set_uint64(DeviceState *dev, const char *name, uint64_t value);
void qdev_prop_set_string(DeviceState *dev, const char *name, const char *value);
void qdev_prop_set_chr(DeviceState *dev, const char *name, CharDriverState *value);
void qdev_prop_set_netdev(DeviceState *dev, const char *name, NetClientState *value);
-int qdev_prop_set_drive(DeviceState *dev, const char *name,
- BlockBackend *value) QEMU_WARN_UNUSED_RESULT;
+void qdev_prop_set_drive(DeviceState *dev, const char *name,
+ BlockBackend *value, Error **errp);
void qdev_prop_set_drive_nofail(DeviceState *dev, const char *name,
BlockBackend *value);
void qdev_prop_set_macaddr(DeviceState *dev, const char *name, uint8_t *value);
diff --git a/include/hw/timer/m48t59.h b/include/hw/timer/m48t59.h
index 821752229..336792363 100644
--- a/include/hw/timer/m48t59.h
+++ b/include/hw/timer/m48t59.h
@@ -1,37 +1,34 @@
#ifndef NVRAM_H
#define NVRAM_H
-/* NVRAM helpers */
-typedef uint32_t (*nvram_read_t)(void *private, uint32_t addr);
-typedef void (*nvram_write_t)(void *private, uint32_t addr, uint32_t val);
-typedef struct nvram_t {
- void *opaque;
- nvram_read_t read_fn;
- nvram_write_t write_fn;
-} nvram_t;
-
-uint32_t NVRAM_get_lword (nvram_t *nvram, uint32_t addr);
-int NVRAM_get_string (nvram_t *nvram, uint8_t *dst, uint16_t addr, int max);
-
-int PPC_NVRAM_set_params (nvram_t *nvram, uint16_t NVRAM_size,
- const char *arch,
- uint32_t RAM_size, int boot_device,
- uint32_t kernel_image, uint32_t kernel_size,
- const char *cmdline,
- uint32_t initrd_image, uint32_t initrd_size,
- uint32_t NVRAM_image,
- int width, int height, int depth);
-
-#define TYPE_SYSBUS_M48T59 "m48t59"
-
-typedef struct M48t59State M48t59State;
-
-void m48t59_write (void *private, uint32_t addr, uint32_t val);
-uint32_t m48t59_read (void *private, uint32_t addr);
-void m48t59_toggle_lock (void *private, int lock);
-M48t59State *m48t59_init_isa(ISABus *bus, uint32_t io_base, uint16_t size,
- int type);
-M48t59State *m48t59_init(qemu_irq IRQ, hwaddr mem_base,
- uint32_t io_base, uint16_t size, int type);
+#include "qemu-common.h"
+#include "qom/object.h"
+
+#define TYPE_NVRAM "nvram"
+
+#define NVRAM_CLASS(klass) \
+ OBJECT_CLASS_CHECK(NvramClass, (klass), TYPE_NVRAM)
+#define NVRAM_GET_CLASS(obj) \
+ OBJECT_GET_CLASS(NvramClass, (obj), TYPE_NVRAM)
+#define NVRAM(obj) \
+ INTERFACE_CHECK(Nvram, (obj), TYPE_NVRAM)
+
+typedef struct Nvram {
+ Object parent;
+} Nvram;
+
+typedef struct NvramClass {
+ InterfaceClass parent;
+
+ uint32_t (*read)(Nvram *obj, uint32_t addr);
+ void (*write)(Nvram *obj, uint32_t addr, uint32_t val);
+ void (*toggle_lock)(Nvram *obj, int lock);
+} NvramClass;
+
+Nvram *m48t59_init_isa(ISABus *bus, uint32_t io_base, uint16_t size,
+ int base_year, int type);
+Nvram *m48t59_init(qemu_irq IRQ, hwaddr mem_base,
+ uint32_t io_base, uint16_t size, int base_year,
+ int type);
#endif /* !NVRAM_H */
diff --git a/include/hw/timer/stm32f2xx_timer.h b/include/hw/timer/stm32f2xx_timer.h
new file mode 100644
index 000000000..e6a83237a
--- /dev/null
+++ b/include/hw/timer/stm32f2xx_timer.h
@@ -0,0 +1,101 @@
+/*
+ * STM32F2XX Timer
+ *
+ * Copyright (c) 2014 Alistair Francis <alistair@alistair23.me>
+ *
+ * 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.
+ */
+
+#ifndef HW_STM32F2XX_TIMER_H
+#define HW_STM32F2XX_TIMER_H
+
+#include "hw/sysbus.h"
+#include "qemu/timer.h"
+#include "sysemu/sysemu.h"
+
+#define TIM_CR1 0x00
+#define TIM_CR2 0x04
+#define TIM_SMCR 0x08
+#define TIM_DIER 0x0C
+#define TIM_SR 0x10
+#define TIM_EGR 0x14
+#define TIM_CCMR1 0x18
+#define TIM_CCMR2 0x1C
+#define TIM_CCER 0x20
+#define TIM_CNT 0x24
+#define TIM_PSC 0x28
+#define TIM_ARR 0x2C
+#define TIM_CCR1 0x34
+#define TIM_CCR2 0x38
+#define TIM_CCR3 0x3C
+#define TIM_CCR4 0x40
+#define TIM_DCR 0x48
+#define TIM_DMAR 0x4C
+#define TIM_OR 0x50
+
+#define TIM_CR1_CEN 1
+
+#define TIM_EGR_UG 1
+
+#define TIM_CCER_CC2E (1 << 4)
+#define TIM_CCMR1_OC2M2 (1 << 14)
+#define TIM_CCMR1_OC2M1 (1 << 13)
+#define TIM_CCMR1_OC2M0 (1 << 12)
+#define TIM_CCMR1_OC2PE (1 << 11)
+
+#define TIM_DIER_UIE 1
+
+#define TYPE_STM32F2XX_TIMER "stm32f2xx-timer"
+#define STM32F2XXTIMER(obj) OBJECT_CHECK(STM32F2XXTimerState, \
+ (obj), TYPE_STM32F2XX_TIMER)
+
+typedef struct STM32F2XXTimerState {
+ /* <private> */
+ SysBusDevice parent_obj;
+
+ /* <public> */
+ MemoryRegion iomem;
+ QEMUTimer *timer;
+ qemu_irq irq;
+
+ int64_t tick_offset;
+ uint64_t hit_time;
+ uint64_t freq_hz;
+
+ uint32_t tim_cr1;
+ uint32_t tim_cr2;
+ uint32_t tim_smcr;
+ uint32_t tim_dier;
+ uint32_t tim_sr;
+ uint32_t tim_egr;
+ uint32_t tim_ccmr1;
+ uint32_t tim_ccmr2;
+ uint32_t tim_ccer;
+ uint32_t tim_psc;
+ uint32_t tim_arr;
+ uint32_t tim_ccr1;
+ uint32_t tim_ccr2;
+ uint32_t tim_ccr3;
+ uint32_t tim_ccr4;
+ uint32_t tim_dcr;
+ uint32_t tim_dmar;
+ uint32_t tim_or;
+} STM32F2XXTimerState;
+
+#endif /* HW_STM32F2XX_TIMER_H */
diff --git a/include/qemu/bitops.h b/include/qemu/bitops.h
index 181bd4606..90ca8df4e 100644
--- a/include/qemu/bitops.h
+++ b/include/qemu/bitops.h
@@ -354,7 +354,7 @@ static inline int32_t sextract32(uint32_t value, int start, int length)
* Returns: the sign extended value of the bit field extracted from the
* input value.
*/
-static inline uint64_t sextract64(uint64_t value, int start, int length)
+static inline int64_t sextract64(uint64_t value, int start, int length)
{
assert(start >= 0 && length > 0 && length <= 64 - start);
/* Note that this implementation relies on right shift of signed
diff --git a/include/qom/cpu.h b/include/qom/cpu.h
index 48fd6fb1d..d6279c01f 100644
--- a/include/qom/cpu.h
+++ b/include/qom/cpu.h
@@ -82,6 +82,10 @@ struct TranslationBlock;
* @do_unassigned_access: Callback for unassigned access handling.
* @do_unaligned_access: Callback for unaligned access handling, if
* the target defines #ALIGNED_ONLY.
+ * @virtio_is_big_endian: Callback to return %true if a CPU which supports
+ * runtime configurable endianness is currently big-endian. Non-configurable
+ * CPUs can use the default implementation of this method. This method should
+ * not be used by any callers other than the pre-1.0 virtio devices.
* @memory_rw_debug: Callback for GDB memory access.
* @dump_state: Callback for dumping state.
* @dump_statistics: Callback for dumping statistics.
@@ -96,6 +100,14 @@ struct TranslationBlock;
* @gdb_read_register: Callback for letting GDB read a register.
* @gdb_write_register: Callback for letting GDB write a register.
* @debug_excp_handler: Callback for handling debug exceptions.
+ * @write_elf64_note: Callback for writing a CPU-specific ELF note to a
+ * 64-bit VM coredump.
+ * @write_elf32_qemunote: Callback for writing a CPU- and QEMU-specific ELF
+ * note to a 32-bit VM coredump.
+ * @write_elf32_note: Callback for writing a CPU-specific ELF note to a
+ * 32-bit VM coredump.
+ * @write_elf32_qemunote: Callback for writing a CPU- and QEMU-specific ELF
+ * note to a 32-bit VM coredump.
* @vmsd: State description for migration.
* @gdb_num_core_regs: Number of core registers accessible to GDB.
* @gdb_core_xml_file: File name for core registers GDB XML description.
diff --git a/include/standard-headers/linux/virtio_net.h b/include/standard-headers/linux/virtio_net.h
index 95faf67b4..3209c9021 100644
--- a/include/standard-headers/linux/virtio_net.h
+++ b/include/standard-headers/linux/virtio_net.h
@@ -74,39 +74,12 @@ struct virtio_net_config {
uint16_t max_virtqueue_pairs;
} QEMU_PACKED;
-#ifndef VIRTIO_NET_NO_LEGACY
-/* This header comes first in the scatter-gather list.
- * For legacy virtio, if VIRTIO_F_ANY_LAYOUT is not negotiated, it must
- * be the first element of the scatter-gather list. If you don't
- * specify GSO or CSUM features, you can simply ignore the header. */
-struct virtio_net_hdr {
-#define VIRTIO_NET_HDR_F_NEEDS_CSUM 1 // Use csum_start, csum_offset
-#define VIRTIO_NET_HDR_F_DATA_VALID 2 // Csum is valid
- uint8_t flags;
-#define VIRTIO_NET_HDR_GSO_NONE 0 // Not a GSO frame
-#define VIRTIO_NET_HDR_GSO_TCPV4 1 // GSO frame, IPv4 TCP (TSO)
-#define VIRTIO_NET_HDR_GSO_UDP 3 // GSO frame, IPv4 UDP (UFO)
-#define VIRTIO_NET_HDR_GSO_TCPV6 4 // GSO frame, IPv6 TCP
-#define VIRTIO_NET_HDR_GSO_ECN 0x80 // TCP has ECN set
- uint8_t gso_type;
- __virtio16 hdr_len; /* Ethernet + IP + tcp/udp hdrs */
- __virtio16 gso_size; /* Bytes to append to hdr_len per frame */
- __virtio16 csum_start; /* Position to start checksumming from */
- __virtio16 csum_offset; /* Offset after that to place checksum */
-};
-
-/* This is the version of the header to use when the MRG_RXBUF
- * feature has been negotiated. */
-struct virtio_net_hdr_mrg_rxbuf {
- struct virtio_net_hdr hdr;
- __virtio16 num_buffers; /* Number of merged rx buffers */
-};
-#else /* ... VIRTIO_NET_NO_LEGACY */
/*
* This header comes first in the scatter-gather list. If you don't
* specify GSO or CSUM features, you can simply ignore the header.
*
- * This is bitwise-equivalent to the legacy struct virtio_net_hdr_mrg_rxbuf.
+ * This is bitwise-equivalent to the legacy struct virtio_net_hdr_mrg_rxbuf,
+ * only flattened.
*/
struct virtio_net_hdr_v1 {
#define VIRTIO_NET_HDR_F_NEEDS_CSUM 1 /* Use csum_start, csum_offset */
@@ -124,6 +97,29 @@ struct virtio_net_hdr_v1 {
__virtio16 csum_offset; /* Offset after that to place checksum */
__virtio16 num_buffers; /* Number of merged rx buffers */
};
+
+#ifndef VIRTIO_NET_NO_LEGACY
+/* This header comes first in the scatter-gather list.
+ * For legacy virtio, if VIRTIO_F_ANY_LAYOUT is not negotiated, it must
+ * be the first element of the scatter-gather list. If you don't
+ * specify GSO or CSUM features, you can simply ignore the header. */
+struct virtio_net_hdr {
+ /* See VIRTIO_NET_HDR_F_* */
+ uint8_t flags;
+ /* See VIRTIO_NET_HDR_GSO_* */
+ uint8_t gso_type;
+ __virtio16 hdr_len; /* Ethernet + IP + tcp/udp hdrs */
+ __virtio16 gso_size; /* Bytes to append to hdr_len per frame */
+ __virtio16 csum_start; /* Position to start checksumming from */
+ __virtio16 csum_offset; /* Offset after that to place checksum */
+};
+
+/* This is the version of the header to use when the MRG_RXBUF
+ * feature has been negotiated. */
+struct virtio_net_hdr_mrg_rxbuf {
+ struct virtio_net_hdr hdr;
+ __virtio16 num_buffers; /* Number of merged rx buffers */
+};
#endif /* ...VIRTIO_NET_NO_LEGACY */
/*
diff --git a/include/sysemu/block-backend.h b/include/sysemu/block-backend.h
index 3ff9aeeb0..77e9b9c37 100644
--- a/include/sysemu/block-backend.h
+++ b/include/sysemu/block-backend.h
@@ -164,5 +164,7 @@ int blk_discard(BlockBackend *blk, int64_t sector_num, int nb_sectors);
int blk_save_vmstate(BlockBackend *blk, const uint8_t *buf,
int64_t pos, int size);
int blk_load_vmstate(BlockBackend *blk, uint8_t *buf, int64_t pos, int size);
+int blk_probe_blocksizes(BlockBackend *blk, BlockSizes *bsz);
+int blk_probe_geometry(BlockBackend *blk, HDGeometry *geo);
#endif
diff --git a/include/ui/console.h b/include/ui/console.h
index 6e5a867fe..2f5b9f063 100644
--- a/include/ui/console.h
+++ b/include/ui/console.h
@@ -332,7 +332,6 @@ void vnc_display_init(const char *id);
void vnc_display_open(const char *id, Error **errp);
void vnc_display_add_client(const char *id, int csock, bool skipauth);
char *vnc_display_local_addr(const char *id);
-void vnc_auto_assign_id(QemuOptsList *olist, QemuOpts *opts);
#ifdef CONFIG_VNC
int vnc_display_password(const char *id, const char *password);
int vnc_display_pw_expire(const char *id, time_t expires);
diff --git a/linux-headers/asm-arm/kvm.h b/linux-headers/asm-arm/kvm.h
index 09ee408c1..0db25bc32 100644
--- a/linux-headers/asm-arm/kvm.h
+++ b/linux-headers/asm-arm/kvm.h
@@ -175,6 +175,8 @@ struct kvm_arch_memory_slot {
#define KVM_DEV_ARM_VGIC_OFFSET_SHIFT 0
#define KVM_DEV_ARM_VGIC_OFFSET_MASK (0xffffffffULL << KVM_DEV_ARM_VGIC_OFFSET_SHIFT)
#define KVM_DEV_ARM_VGIC_GRP_NR_IRQS 3
+#define KVM_DEV_ARM_VGIC_GRP_CTRL 4
+#define KVM_DEV_ARM_VGIC_CTRL_INIT 0
/* KVM_IRQ_LINE irq field index values */
#define KVM_ARM_IRQ_TYPE_SHIFT 24
diff --git a/linux-headers/asm-arm64/kvm.h b/linux-headers/asm-arm64/kvm.h
index 8e38878c8..3ef77a466 100644
--- a/linux-headers/asm-arm64/kvm.h
+++ b/linux-headers/asm-arm64/kvm.h
@@ -78,6 +78,13 @@ struct kvm_regs {
#define KVM_VGIC_V2_DIST_SIZE 0x1000
#define KVM_VGIC_V2_CPU_SIZE 0x2000
+/* Supported VGICv3 address types */
+#define KVM_VGIC_V3_ADDR_TYPE_DIST 2
+#define KVM_VGIC_V3_ADDR_TYPE_REDIST 3
+
+#define KVM_VGIC_V3_DIST_SIZE SZ_64K
+#define KVM_VGIC_V3_REDIST_SIZE (2 * SZ_64K)
+
#define KVM_ARM_VCPU_POWER_OFF 0 /* CPU is started in OFF state */
#define KVM_ARM_VCPU_EL1_32BIT 1 /* CPU running a 32bit VM */
#define KVM_ARM_VCPU_PSCI_0_2 2 /* CPU uses PSCI v0.2 */
@@ -161,6 +168,8 @@ struct kvm_arch_memory_slot {
#define KVM_DEV_ARM_VGIC_OFFSET_SHIFT 0
#define KVM_DEV_ARM_VGIC_OFFSET_MASK (0xffffffffULL << KVM_DEV_ARM_VGIC_OFFSET_SHIFT)
#define KVM_DEV_ARM_VGIC_GRP_NR_IRQS 3
+#define KVM_DEV_ARM_VGIC_GRP_CTRL 4
+#define KVM_DEV_ARM_VGIC_CTRL_INIT 0
/* KVM_IRQ_LINE irq field index values */
#define KVM_ARM_IRQ_TYPE_SHIFT 24
diff --git a/linux-headers/asm-s390/kvm.h b/linux-headers/asm-s390/kvm.h
index d36b2fa10..c5a93eb0b 100644
--- a/linux-headers/asm-s390/kvm.h
+++ b/linux-headers/asm-s390/kvm.h
@@ -57,10 +57,44 @@ struct kvm_s390_io_adapter_req {
/* kvm attr_group on vm fd */
#define KVM_S390_VM_MEM_CTRL 0
+#define KVM_S390_VM_TOD 1
+#define KVM_S390_VM_CRYPTO 2
+#define KVM_S390_VM_CPU_MODEL 3
/* kvm attributes for mem_ctrl */
#define KVM_S390_VM_MEM_ENABLE_CMMA 0
#define KVM_S390_VM_MEM_CLR_CMMA 1
+#define KVM_S390_VM_MEM_LIMIT_SIZE 2
+
+/* kvm attributes for KVM_S390_VM_TOD */
+#define KVM_S390_VM_TOD_LOW 0
+#define KVM_S390_VM_TOD_HIGH 1
+
+/* kvm attributes for KVM_S390_VM_CPU_MODEL */
+/* processor related attributes are r/w */
+#define KVM_S390_VM_CPU_PROCESSOR 0
+struct kvm_s390_vm_cpu_processor {
+ __u64 cpuid;
+ __u16 ibc;
+ __u8 pad[6];
+ __u64 fac_list[256];
+};
+
+/* machine related attributes are r/o */
+#define KVM_S390_VM_CPU_MACHINE 1
+struct kvm_s390_vm_cpu_machine {
+ __u64 cpuid;
+ __u32 ibc;
+ __u8 pad[4];
+ __u64 fac_mask[256];
+ __u64 fac_list[256];
+};
+
+/* kvm attributes for crypto */
+#define KVM_S390_VM_CRYPTO_ENABLE_AES_KW 0
+#define KVM_S390_VM_CRYPTO_ENABLE_DEA_KW 1
+#define KVM_S390_VM_CRYPTO_DISABLE_AES_KW 2
+#define KVM_S390_VM_CRYPTO_DISABLE_DEA_KW 3
/* for KVM_GET_REGS and KVM_SET_REGS */
struct kvm_regs {
@@ -107,6 +141,9 @@ struct kvm_guest_debug_arch {
struct kvm_hw_breakpoint *hw_bp;
};
+/* for KVM_SYNC_PFAULT and KVM_REG_S390_PFTOKEN */
+#define KVM_S390_PFAULT_TOKEN_INVALID 0xffffffffffffffffULL
+
#define KVM_SYNC_PREFIX (1UL << 0)
#define KVM_SYNC_GPRS (1UL << 1)
#define KVM_SYNC_ACRS (1UL << 2)
diff --git a/linux-headers/asm-x86/hyperv.h b/linux-headers/asm-x86/hyperv.h
index 462efe746..90c458e66 100644
--- a/linux-headers/asm-x86/hyperv.h
+++ b/linux-headers/asm-x86/hyperv.h
@@ -187,6 +187,17 @@
#define HV_X64_MSR_SINT14 0x4000009E
#define HV_X64_MSR_SINT15 0x4000009F
+/*
+ * Synthetic Timer MSRs. Four timers per vcpu.
+ */
+#define HV_X64_MSR_STIMER0_CONFIG 0x400000B0
+#define HV_X64_MSR_STIMER0_COUNT 0x400000B1
+#define HV_X64_MSR_STIMER1_CONFIG 0x400000B2
+#define HV_X64_MSR_STIMER1_COUNT 0x400000B3
+#define HV_X64_MSR_STIMER2_CONFIG 0x400000B4
+#define HV_X64_MSR_STIMER2_COUNT 0x400000B5
+#define HV_X64_MSR_STIMER3_CONFIG 0x400000B6
+#define HV_X64_MSR_STIMER3_COUNT 0x400000B7
#define HV_X64_MSR_HYPERCALL_ENABLE 0x00000001
#define HV_X64_MSR_HYPERCALL_PAGE_ADDRESS_SHIFT 12
diff --git a/linux-headers/linux/kvm.h b/linux-headers/linux/kvm.h
index 12045a11c..60a54c82a 100644
--- a/linux-headers/linux/kvm.h
+++ b/linux-headers/linux/kvm.h
@@ -491,6 +491,11 @@ struct kvm_s390_emerg_info {
__u16 code;
};
+#define KVM_S390_STOP_FLAG_STORE_STATUS 0x01
+struct kvm_s390_stop_info {
+ __u32 flags;
+};
+
struct kvm_s390_mchk_info {
__u64 cr14;
__u64 mcic;
@@ -509,6 +514,7 @@ struct kvm_s390_irq {
struct kvm_s390_emerg_info emerg;
struct kvm_s390_extcall_info extcall;
struct kvm_s390_prefix_info prefix;
+ struct kvm_s390_stop_info stop;
struct kvm_s390_mchk_info mchk;
char reserved[64];
} u;
@@ -647,11 +653,7 @@ struct kvm_ppc_smmu_info {
#define KVM_CAP_MP_STATE 14
#define KVM_CAP_COALESCED_MMIO 15
#define KVM_CAP_SYNC_MMU 16 /* Changes to host mmap are reflected in guest */
-#define KVM_CAP_DEVICE_ASSIGNMENT 17
#define KVM_CAP_IOMMU 18
-#ifdef __KVM_HAVE_MSI
-#define KVM_CAP_DEVICE_MSI 20
-#endif
/* Bug in KVM_SET_USER_MEMORY_REGION fixed: */
#define KVM_CAP_DESTROY_MEMORY_REGION_WORKS 21
#define KVM_CAP_USER_NMI 22
@@ -663,10 +665,6 @@ struct kvm_ppc_smmu_info {
#endif
#define KVM_CAP_IRQ_ROUTING 25
#define KVM_CAP_IRQ_INJECT_STATUS 26
-#define KVM_CAP_DEVICE_DEASSIGNMENT 27
-#ifdef __KVM_HAVE_MSIX
-#define KVM_CAP_DEVICE_MSIX 28
-#endif
#define KVM_CAP_ASSIGN_DEV_IRQ 29
/* Another bug in KVM_SET_USER_MEMORY_REGION fixed: */
#define KVM_CAP_JOIN_MEMORY_REGIONS_WORKS 30
@@ -761,6 +759,7 @@ struct kvm_ppc_smmu_info {
#define KVM_CAP_PPC_FIXUP_HCALL 103
#define KVM_CAP_PPC_ENABLE_HCALL 104
#define KVM_CAP_CHECK_EXTENSION_VM 105
+#define KVM_CAP_S390_USER_SIGP 106
#ifdef KVM_CAP_IRQ_ROUTING
@@ -960,6 +959,8 @@ enum kvm_device_type {
#define KVM_DEV_TYPE_ARM_VGIC_V2 KVM_DEV_TYPE_ARM_VGIC_V2
KVM_DEV_TYPE_FLIC,
#define KVM_DEV_TYPE_FLIC KVM_DEV_TYPE_FLIC
+ KVM_DEV_TYPE_ARM_VGIC_V3,
+#define KVM_DEV_TYPE_ARM_VGIC_V3 KVM_DEV_TYPE_ARM_VGIC_V3
KVM_DEV_TYPE_MAX,
};
@@ -1107,9 +1108,6 @@ struct kvm_s390_ucas_mapping {
#define KVM_X86_SETUP_MCE _IOW(KVMIO, 0x9c, __u64)
#define KVM_X86_GET_MCE_CAP_SUPPORTED _IOR(KVMIO, 0x9d, __u64)
#define KVM_X86_SET_MCE _IOW(KVMIO, 0x9e, struct kvm_x86_mce)
-/* IA64 stack access */
-#define KVM_IA64_VCPU_GET_STACK _IOR(KVMIO, 0x9a, void *)
-#define KVM_IA64_VCPU_SET_STACK _IOW(KVMIO, 0x9b, void *)
/* Available with KVM_CAP_VCPU_EVENTS */
#define KVM_GET_VCPU_EVENTS _IOR(KVMIO, 0x9f, struct kvm_vcpu_events)
#define KVM_SET_VCPU_EVENTS _IOW(KVMIO, 0xa0, struct kvm_vcpu_events)
diff --git a/linux-user/main.c b/linux-user/main.c
index d92702a73..6bd23af2b 100644
--- a/linux-user/main.c
+++ b/linux-user/main.c
@@ -3452,8 +3452,8 @@ void init_task_state(TaskState *ts)
CPUArchState *cpu_copy(CPUArchState *env)
{
CPUState *cpu = ENV_GET_CPU(env);
- CPUArchState *new_env = cpu_init(cpu_model);
- CPUState *new_cpu = ENV_GET_CPU(new_env);
+ CPUState *new_cpu = cpu_init(cpu_model);
+ CPUArchState *new_env = cpu->env_ptr;
CPUBreakpoint *bp;
CPUWatchpoint *wp;
@@ -3939,12 +3939,12 @@ int main(int argc, char **argv, char **envp)
cpu_exec_init_all();
/* NOTE: we need to init the CPU at this stage to get
qemu_host_page_size */
- env = cpu_init(cpu_model);
- if (!env) {
+ cpu = cpu_init(cpu_model);
+ if (!cpu) {
fprintf(stderr, "Unable to find CPU definition\n");
exit(1);
}
- cpu = ENV_GET_CPU(env);
+ env = cpu->env_ptr;
cpu_reset(cpu);
thread_cpu = cpu;
diff --git a/pc-bios/openbios-ppc b/pc-bios/openbios-ppc
index 994052f14..91e4193c2 100644
--- a/pc-bios/openbios-ppc
+++ b/pc-bios/openbios-ppc
Binary files differ
diff --git a/pc-bios/openbios-sparc32 b/pc-bios/openbios-sparc32
index 6d5a381a7..d693865c3 100644
--- a/pc-bios/openbios-sparc32
+++ b/pc-bios/openbios-sparc32
Binary files differ
diff --git a/pc-bios/openbios-sparc64 b/pc-bios/openbios-sparc64
index 61bd46bf4..e5d9e5a7b 100644
--- a/pc-bios/openbios-sparc64
+++ b/pc-bios/openbios-sparc64
Binary files differ
diff --git a/pc-bios/s390-ccw.img b/pc-bios/s390-ccw.img
index dbe5a3826..3c6b01fc8 100644
--- a/pc-bios/s390-ccw.img
+++ b/pc-bios/s390-ccw.img
Binary files differ
diff --git a/pc-bios/s390-ccw/Makefile b/pc-bios/s390-ccw/Makefile
index ad55a14a1..009bb8de1 100644
--- a/pc-bios/s390-ccw/Makefile
+++ b/pc-bios/s390-ccw/Makefile
@@ -9,10 +9,9 @@ $(call set-vpath, $(SRC_PATH)/pc-bios/s390-ccw)
.PHONY : all clean build-all
-OBJECTS=main.o bootmap.o sclp-ascii.o virtio.o start.o
-CFLAGS += -fno-stack-protector
-# XXX find a more clever to locate the bootloader
-LDFLAGS += -Wl,-Ttext,0x7e00000,-Tbss,0x7f00000 -nostdlib
+OBJECTS = start.o main.o bootmap.o sclp-ascii.o virtio.o
+CFLAGS += -fPIE -fno-stack-protector -ffreestanding
+LDFLAGS += -Wl,-pie -nostdlib
build-all: s390-ccw.img
@@ -20,7 +19,9 @@ s390-ccw.elf: $(OBJECTS)
$(call quiet-command,$(CC) $(LDFLAGS) -o $@ $(OBJECTS)," Building $(TARGET_DIR)$@")
s390-ccw.img: s390-ccw.elf
- $(call quiet-command,strip $< -o $@," Stripping $(TARGET_DIR)$@")
+ $(call quiet-command,strip --strip-unneeded $< -o $@," Stripping $(TARGET_DIR)$@")
+
+$(OBJECTS): Makefile
clean:
rm -f *.o *.d *.img *.elf *~
diff --git a/pc-bios/s390-ccw/main.c b/pc-bios/s390-ccw/main.c
index 6f707bbcd..584d4a276 100644
--- a/pc-bios/s390-ccw/main.c
+++ b/pc-bios/s390-ccw/main.c
@@ -12,6 +12,7 @@
#include "virtio.h"
char stack[PAGE_SIZE * 8] __attribute__((__aligned__(PAGE_SIZE)));
+char ring_area[PAGE_SIZE * 8] __attribute__((__aligned__(PAGE_SIZE)));
uint64_t boot_value;
static struct subchannel_id blk_schid = { .one = 1 };
diff --git a/pc-bios/s390-ccw/s390-ccw.h b/pc-bios/s390-ccw/s390-ccw.h
index ceb7418a5..9b3868bd6 100644
--- a/pc-bios/s390-ccw/s390-ccw.h
+++ b/pc-bios/s390-ccw/s390-ccw.h
@@ -52,6 +52,7 @@ void disabled_wait(void);
void virtio_panic(const char *string);
void write_subsystem_identification(void);
extern char stack[PAGE_SIZE * 8] __attribute__((__aligned__(PAGE_SIZE)));
+extern char ring_area[PAGE_SIZE * 8] __attribute__((__aligned__(PAGE_SIZE)));
extern uint64_t boot_value;
/* sclp-ascii.c */
diff --git a/pc-bios/s390-ccw/virtio.c b/pc-bios/s390-ccw/virtio.c
index 4dc91a7c4..57ff1b07e 100644
--- a/pc-bios/s390-ccw/virtio.c
+++ b/pc-bios/s390-ccw/virtio.c
@@ -362,6 +362,7 @@ void virtio_setup_block(struct subchannel_id schid)
struct vq_config_block config = {};
blk_cfg.blk_size = 0; /* mark "illegal" - setup started... */
+ guessed_disk_nature = false;
virtio_reset(schid);
@@ -378,10 +379,10 @@ void virtio_setup_block(struct subchannel_id schid)
if (run_ccw(schid, CCW_CMD_READ_CONF, &blk_cfg, sizeof(blk_cfg))) {
virtio_panic("Could not get block device configuration\n");
}
- vring_init(&block, config.num, (void *)(100 * 1024 * 1024),
+ vring_init(&block, config.num, ring_area,
KVM_S390_VIRTIO_RING_ALIGN);
- info.queue = (100ULL * 1024ULL* 1024ULL);
+ info.queue = (unsigned long long) ring_area;
info.align = KVM_S390_VIRTIO_RING_ALIGN;
info.index = 0;
info.num = config.num;
diff --git a/qapi/block-core.json b/qapi/block-core.json
index a3fdaf02b..90586a594 100644
--- a/qapi/block-core.json
+++ b/qapi/block-core.json
@@ -41,13 +41,16 @@
# @corrupt: #optional true if the image has been marked corrupt; only valid for
# compat >= 1.1 (since 2.2)
#
+# @refcount-bits: width of a refcount entry in bits (since 2.3)
+#
# Since: 1.7
##
{ 'type': 'ImageInfoSpecificQCow2',
'data': {
'compat': 'str',
'*lazy-refcounts': 'bool',
- '*corrupt': 'bool'
+ '*corrupt': 'bool',
+ 'refcount-bits': 'int'
} }
##
diff --git a/qemu-coroutine.c b/qemu-coroutine.c
index 525247b05..c17a92b10 100644
--- a/qemu-coroutine.c
+++ b/qemu-coroutine.c
@@ -99,29 +99,10 @@ static void coroutine_delete(Coroutine *co)
qemu_coroutine_delete(co);
}
-static void coroutine_swap(Coroutine *from, Coroutine *to)
-{
- CoroutineAction ret;
-
- ret = qemu_coroutine_switch(from, to, COROUTINE_YIELD);
-
- qemu_co_queue_run_restart(to);
-
- switch (ret) {
- case COROUTINE_YIELD:
- return;
- case COROUTINE_TERMINATE:
- trace_qemu_coroutine_terminate(to);
- coroutine_delete(to);
- return;
- default:
- abort();
- }
-}
-
void qemu_coroutine_enter(Coroutine *co, void *opaque)
{
Coroutine *self = qemu_coroutine_self();
+ CoroutineAction ret;
trace_qemu_coroutine_enter(self, co, opaque);
@@ -132,7 +113,20 @@ void qemu_coroutine_enter(Coroutine *co, void *opaque)
co->caller = self;
co->entry_arg = opaque;
- coroutine_swap(self, co);
+ ret = qemu_coroutine_switch(self, co, COROUTINE_ENTER);
+
+ qemu_co_queue_run_restart(co);
+
+ switch (ret) {
+ case COROUTINE_YIELD:
+ return;
+ case COROUTINE_TERMINATE:
+ trace_qemu_coroutine_terminate(co);
+ coroutine_delete(co);
+ return;
+ default:
+ abort();
+ }
}
void coroutine_fn qemu_coroutine_yield(void)
@@ -148,5 +142,5 @@ void coroutine_fn qemu_coroutine_yield(void)
}
self->caller = NULL;
- coroutine_swap(self, to);
+ qemu_coroutine_switch(self, to, COROUTINE_YIELD);
}
diff --git a/qemu-doc.texi b/qemu-doc.texi
index aabe8df2f..f5b0dc458 100644
--- a/qemu-doc.texi
+++ b/qemu-doc.texi
@@ -2052,7 +2052,7 @@ firmware implementation. The goal is to implement a 100% IEEE
A sample Linux 2.6 series kernel and ram disk image are available on
the QEMU web site. There are still issues with NetBSD and OpenBSD, but
-some kernel versions work. Please note that currently older Solaris kernels
+most kernel versions work. Please note that currently older Solaris kernels
don't work probably due to interface issues between OpenBIOS and
Solaris.
@@ -2091,8 +2091,9 @@ Set the emulated machine type. Default is SS-5.
Use the executable @file{qemu-system-sparc64} to simulate a Sun4u
(UltraSPARC PC-like machine), Sun4v (T1 PC-like machine), or generic
-Niagara (T1) machine. The emulator is not usable for anything yet, but
-it can launch some kernels.
+Niagara (T1) machine. The Sun4u emulator is mostly complete, being
+able to run Linux, NetBSD and OpenBSD in headless (-nographic) mode. The
+Sun4v and Niagara emulators are still a work in progress.
QEMU emulates the following peripherals:
diff --git a/qmp.c b/qmp.c
index d701cff5a..c479e7751 100644
--- a/qmp.c
+++ b/qmp.c
@@ -391,7 +391,6 @@ static void qmp_change_vnc_listen(const char *target, Error **errp)
return;
}
- vnc_auto_assign_id(olist, opts);
vnc_display_open("default", errp);
}
diff --git a/roms/openbios b/roms/openbios
-Subproject 038aa78d3c331731733378a73e778ee620a5b9d
+Subproject b8dea39718916f4d7d391cd1664314d52a45b87
diff --git a/scripts/kvm/kvm_stat b/scripts/kvm/kvm_stat
index c65cabda5..7e5d25612 100755
--- a/scripts/kvm/kvm_stat
+++ b/scripts/kvm/kvm_stat
@@ -519,7 +519,10 @@ def tui(screen, stats):
def refresh(sleeptime):
screen.erase()
screen.addstr(0, 0, 'kvm statistics')
- row = 2
+ screen.addstr(2, 1, 'Event')
+ screen.addstr(2, 1 + label_width + number_width - len('Total'), 'Total')
+ screen.addstr(2, 1 + label_width + number_width + 8 - len('Current'), 'Current')
+ row = 3
s = stats.get()
def sortkey(x):
if s[x][1]:
diff --git a/scripts/kvm/kvm_stat.texi b/scripts/kvm/kvm_stat.texi
new file mode 100644
index 000000000..6ce00d80e
--- /dev/null
+++ b/scripts/kvm/kvm_stat.texi
@@ -0,0 +1,55 @@
+@example
+@c man begin SYNOPSIS
+usage: kvm_stat [OPTION]...
+@c man end
+@end example
+
+@c man begin DESCRIPTION
+
+kvm_stat prints counts of KVM kernel module trace events. These events signify
+state transitions such as guest mode entry and exit.
+
+This tool is useful for observing guest behavior from the host perspective.
+Often conclusions about performance or buggy behavior can be drawn from the
+output.
+
+The set of KVM kernel module trace events may be specific to the kernel version
+or architecture. It is best to check the KVM kernel module source code for the
+meaning of events.
+
+Note that trace events are counted globally across all running guests.
+
+@c man end
+
+@c man begin OPTIONS
+@table @option
+@item -1, --once, --batch
+ run in batch mode for one second
+@item -l, --log
+ run in logging mode (like vmstat)
+@item -t, --tracepoints
+ retrieve statistics from tracepoints
+@item -d, --debugfs
+ retrieve statistics from debugfs
+@item -f, --fields=@var{fields}
+ fields to display (regex)
+@item -h, --help
+ show help message
+@end table
+
+@c man end
+
+@ignore
+
+@setfilename kvm_stat
+@settitle Report KVM kernel module event counters.
+
+@c man begin AUTHOR
+Stefan Hajnoczi <stefanha@redhat.com>
+@c man end
+
+@c man begin SEEALSO
+perf(1), trace-cmd(1)
+@c man end
+
+@end ignore
diff --git a/target-alpha/cpu.h b/target-alpha/cpu.h
index e276dbf9a..9538f1986 100644
--- a/target-alpha/cpu.h
+++ b/target-alpha/cpu.h
@@ -429,14 +429,7 @@ void alpha_translate_init(void);
AlphaCPU *cpu_alpha_init(const char *cpu_model);
-static inline CPUAlphaState *cpu_init(const char *cpu_model)
-{
- AlphaCPU *cpu = cpu_alpha_init(cpu_model);
- if (cpu == NULL) {
- return NULL;
- }
- return &cpu->env;
-}
+#define cpu_init(cpu_model) CPU(cpu_alpha_init(cpu_model))
void alpha_cpu_list(FILE *f, fprintf_function cpu_fprintf);
int cpu_alpha_exec(CPUAlphaState *s);
diff --git a/target-arm/cpu.h b/target-arm/cpu.h
index 11845a664..083211ce3 100644
--- a/target-arm/cpu.h
+++ b/target-arm/cpu.h
@@ -1569,14 +1569,7 @@ static inline bool arm_excp_unmasked(CPUState *cs, unsigned int excp_idx)
return unmasked || pstate_unmasked;
}
-static inline CPUARMState *cpu_init(const char *cpu_model)
-{
- ARMCPU *cpu = cpu_arm_init(cpu_model);
- if (cpu) {
- return &cpu->env;
- }
- return NULL;
-}
+#define cpu_init(cpu_model) CPU(cpu_arm_init(cpu_model))
#define cpu_exec cpu_arm_exec
#define cpu_gen_code cpu_arm_gen_code
diff --git a/target-arm/cpu64.c b/target-arm/cpu64.c
index 823c739f0..270bc2fec 100644
--- a/target-arm/cpu64.c
+++ b/target-arm/cpu64.c
@@ -96,6 +96,7 @@ static void aarch64_a57_initfn(Object *obj)
{
ARMCPU *cpu = ARM_CPU(obj);
+ cpu->dtb_compatible = "arm,cortex-a57";
set_feature(&cpu->env, ARM_FEATURE_V8);
set_feature(&cpu->env, ARM_FEATURE_VFP4);
set_feature(&cpu->env, ARM_FEATURE_NEON);
diff --git a/target-cris/cpu.h b/target-cris/cpu.h
index eea14b646..677b38c68 100644
--- a/target-cris/cpu.h
+++ b/target-cris/cpu.h
@@ -221,14 +221,7 @@ enum {
#define TARGET_PHYS_ADDR_SPACE_BITS 32
#define TARGET_VIRT_ADDR_SPACE_BITS 32
-static inline CPUCRISState *cpu_init(const char *cpu_model)
-{
- CRISCPU *cpu = cpu_cris_init(cpu_model);
- if (cpu == NULL) {
- return NULL;
- }
- return &cpu->env;
-}
+#define cpu_init(cpu_model) CPU(cpu_cris_init(cpu_model))
#define cpu_exec cpu_cris_exec
#define cpu_gen_code cpu_cris_gen_code
diff --git a/target-i386/cpu-qom.h b/target-i386/cpu-qom.h
index b557b619c..31a0c1e77 100644
--- a/target-i386/cpu-qom.h
+++ b/target-i386/cpu-qom.h
@@ -93,6 +93,7 @@ typedef struct X86CPU {
bool expose_kvm;
bool migratable;
bool host_features;
+ int64_t apic_id;
/* if true the CPUID code directly forward host cache leaves to the guest */
bool cache_info_passthrough;
diff --git a/target-i386/cpu.c b/target-i386/cpu.c
index d543e2b53..ed7e5d5de 100644
--- a/target-i386/cpu.c
+++ b/target-i386/cpu.c
@@ -25,7 +25,6 @@
#include "sysemu/kvm.h"
#include "sysemu/cpus.h"
#include "kvm_i386.h"
-#include "topology.h"
#include "qemu/option.h"
#include "qemu/config-file.h"
@@ -1690,7 +1689,7 @@ static void x86_cpuid_get_apic_id(Object *obj, Visitor *v, void *opaque,
const char *name, Error **errp)
{
X86CPU *cpu = X86_CPU(obj);
- int64_t value = cpu->env.cpuid_apic_id;
+ int64_t value = cpu->apic_id;
visit_type_int(v, &value, name, errp);
}
@@ -1723,11 +1722,11 @@ static void x86_cpuid_set_apic_id(Object *obj, Visitor *v, void *opaque,
return;
}
- if ((value != cpu->env.cpuid_apic_id) && cpu_exists(value)) {
+ if ((value != cpu->apic_id) && cpu_exists(value)) {
error_setg(errp, "CPU with APIC ID %" PRIi64 " exists", value);
return;
}
- cpu->env.cpuid_apic_id = value;
+ cpu->apic_id = value;
}
/* Generic getter for "feature-words" and "filtered-features" properties */
@@ -1911,34 +1910,19 @@ static void x86_cpu_parse_featurestr(CPUState *cs, char *features,
}
}
-/* generate a composite string into buf of all cpuid names in featureset
- * selected by fbits. indicate truncation at bufsize in the event of overflow.
- * if flags, suppress names undefined in featureset.
+/* Print all cpuid feature names in featureset
*/
-static void listflags(char *buf, int bufsize, uint32_t fbits,
- const char **featureset, uint32_t flags)
-{
- const char **p = &featureset[31];
- char *q, *b, bit;
- int nc;
-
- b = 4 <= bufsize ? buf + (bufsize -= 3) - 1 : NULL;
- *buf = '\0';
- for (q = buf, bit = 31; fbits && bufsize; --p, fbits &= ~(1 << bit), --bit)
- if (fbits & 1 << bit && (*p || !flags)) {
- if (*p)
- nc = snprintf(q, bufsize, "%s%s", q == buf ? "" : " ", *p);
- else
- nc = snprintf(q, bufsize, "%s[%d]", q == buf ? "" : " ", bit);
- if (bufsize <= nc) {
- if (b) {
- memcpy(b, "...", sizeof("..."));
- }
- return;
- }
- q += nc;
- bufsize -= nc;
+static void listflags(FILE *f, fprintf_function print, const char **featureset)
+{
+ int bit;
+ bool first = true;
+
+ for (bit = 0; bit < 32; bit++) {
+ if (featureset[bit]) {
+ print(f, "%s%s", first ? "" : " ", featureset[bit]);
+ first = false;
}
+ }
}
/* generate CPU information. */
@@ -1963,8 +1947,9 @@ void x86_cpu_list(FILE *f, fprintf_function cpu_fprintf)
for (i = 0; i < ARRAY_SIZE(feature_word_info); i++) {
FeatureWordInfo *fw = &feature_word_info[i];
- listflags(buf, sizeof(buf), (uint32_t)~0, fw->feat_names, 1);
- (*cpu_fprintf)(f, " %s\n", buf);
+ (*cpu_fprintf)(f, " ");
+ listflags(f, cpu_fprintf, fw->feat_names);
+ (*cpu_fprintf)(f, "\n");
}
}
@@ -2227,14 +2212,6 @@ void x86_cpudef_setup(void)
}
}
-static void get_cpuid_vendor(CPUX86State *env, uint32_t *ebx,
- uint32_t *ecx, uint32_t *edx)
-{
- *ebx = env->cpuid_vendor1;
- *edx = env->cpuid_vendor2;
- *ecx = env->cpuid_vendor3;
-}
-
void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count,
uint32_t *eax, uint32_t *ebx,
uint32_t *ecx, uint32_t *edx)
@@ -2268,11 +2245,14 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count,
switch(index) {
case 0:
*eax = env->cpuid_level;
- get_cpuid_vendor(env, ebx, ecx, edx);
+ *ebx = env->cpuid_vendor1;
+ *edx = env->cpuid_vendor2;
+ *ecx = env->cpuid_vendor3;
break;
case 1:
*eax = env->cpuid_version;
- *ebx = (env->cpuid_apic_id << 24) | 8 << 8; /* CLFLUSH size in quad words, Linux wants it. */
+ *ebx = (cpu->apic_id << 24) |
+ 8 << 8; /* CLFLUSH size in quad words, Linux wants it. */
*ecx = env->features[FEAT_1_ECX];
*edx = env->features[FEAT_1_EDX];
if (cs->nr_cores * cs->nr_threads > 1) {
@@ -2461,11 +2441,9 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count,
* So dont set it here for Intel to make Linux guests happy.
*/
if (cs->nr_cores * cs->nr_threads > 1) {
- uint32_t tebx, tecx, tedx;
- get_cpuid_vendor(env, &tebx, &tecx, &tedx);
- if (tebx != CPUID_VENDOR_INTEL_1 ||
- tedx != CPUID_VENDOR_INTEL_2 ||
- tecx != CPUID_VENDOR_INTEL_3) {
+ if (env->cpuid_vendor1 != CPUID_VENDOR_INTEL_1 ||
+ env->cpuid_vendor2 != CPUID_VENDOR_INTEL_2 ||
+ env->cpuid_vendor3 != CPUID_VENDOR_INTEL_3) {
*ecx |= 1 << 1; /* CmpLegacy bit */
}
}
@@ -2721,7 +2699,6 @@ static void mce_init(X86CPU *cpu)
#ifndef CONFIG_USER_ONLY
static void x86_cpu_apic_create(X86CPU *cpu, Error **errp)
{
- CPUX86State *env = &cpu->env;
DeviceState *dev = DEVICE(cpu);
APICCommonState *apic;
const char *apic_type = "apic";
@@ -2740,7 +2717,7 @@ static void x86_cpu_apic_create(X86CPU *cpu, Error **errp)
object_property_add_child(OBJECT(cpu), "apic",
OBJECT(cpu->apic_state), NULL);
- qdev_prop_set_uint8(cpu->apic_state, "id", env->cpuid_apic_id);
+ qdev_prop_set_uint8(cpu->apic_state, "id", cpu->apic_id);
/* TODO: convert to link<> */
apic = APIC_COMMON(cpu->apic_state);
apic->cpu = cpu;
@@ -2751,12 +2728,8 @@ static void x86_cpu_apic_realize(X86CPU *cpu, Error **errp)
if (cpu->apic_state == NULL) {
return;
}
-
- if (qdev_init(cpu->apic_state)) {
- error_setg(errp, "APIC device '%s' could not be initialized",
- object_get_typename(OBJECT(cpu->apic_state)));
- return;
- }
+ object_property_set_bool(OBJECT(cpu->apic_state), true, "realized",
+ errp);
}
#else
static void x86_cpu_apic_realize(X86CPU *cpu, Error **errp)
@@ -2780,6 +2753,11 @@ static void x86_cpu_realizefn(DeviceState *dev, Error **errp)
Error *local_err = NULL;
static bool ht_warned;
+ if (cpu->apic_id < 0) {
+ error_setg(errp, "apic-id property was not initialized properly");
+ return;
+ }
+
if (env->features[FEAT_7_0_EBX] && env->cpuid_level < 7) {
env->cpuid_level = 7;
}
@@ -2844,39 +2822,6 @@ out:
}
}
-/* Enables contiguous-apic-ID mode, for compatibility */
-static bool compat_apic_id_mode;
-
-void enable_compat_apic_id_mode(void)
-{
- compat_apic_id_mode = true;
-}
-
-/* Calculates initial APIC ID for a specific CPU index
- *
- * Currently we need to be able to calculate the APIC ID from the CPU index
- * alone (without requiring a CPU object), as the QEMU<->Seabios interfaces have
- * no concept of "CPU index", and the NUMA tables on fw_cfg need the APIC ID of
- * all CPUs up to max_cpus.
- */
-uint32_t x86_cpu_apic_id_from_index(unsigned int cpu_index)
-{
- uint32_t correct_id;
- static bool warned;
-
- correct_id = x86_apicid_from_cpu_idx(smp_cores, smp_threads, cpu_index);
- if (compat_apic_id_mode) {
- if (cpu_index != correct_id && !warned) {
- error_report("APIC IDs set in compatibility mode, "
- "CPU topology won't match the configuration");
- warned = true;
- }
- return cpu_index;
- } else {
- return correct_id;
- }
-}
-
static void x86_cpu_initfn(Object *obj)
{
CPUState *cs = CPU(obj);
@@ -2923,7 +2868,11 @@ static void x86_cpu_initfn(Object *obj)
NULL, NULL, (void *)cpu->filtered_features, NULL);
cpu->hyperv_spinlock_attempts = HYPERV_SPINLOCK_NEVER_RETRY;
- env->cpuid_apic_id = x86_cpu_apic_id_from_index(cs->cpu_index);
+
+#ifndef CONFIG_USER_ONLY
+ /* Any code creating new X86CPU objects have to set apic-id explicitly */
+ cpu->apic_id = -1;
+#endif
x86_cpu_load_def(cpu, xcc->cpu_def, &error_abort);
@@ -2937,9 +2886,8 @@ static void x86_cpu_initfn(Object *obj)
static int64_t x86_cpu_get_arch_id(CPUState *cs)
{
X86CPU *cpu = X86_CPU(cs);
- CPUX86State *env = &cpu->env;
- return env->cpuid_apic_id;
+ return cpu->apic_id;
}
static bool x86_cpu_get_paging_enabled(const CPUState *cs)
diff --git a/target-i386/cpu.h b/target-i386/cpu.h
index 478450cfb..e4c27b1fa 100644
--- a/target-i386/cpu.h
+++ b/target-i386/cpu.h
@@ -944,7 +944,6 @@ typedef struct CPUX86State {
uint32_t cpuid_version;
FeatureWordArray features;
uint32_t cpuid_model[12];
- uint32_t cpuid_apic_id;
/* MTRRs */
uint64_t mtrr_fixed[11];
@@ -1171,14 +1170,7 @@ uint64_t cpu_get_tsc(CPUX86State *env);
# define PHYS_ADDR_MASK 0xfffffffffLL
# endif
-static inline CPUX86State *cpu_init(const char *cpu_model)
-{
- X86CPU *cpu = cpu_x86_init(cpu_model);
- if (cpu == NULL) {
- return NULL;
- }
- return &cpu->env;
-}
+#define cpu_init(cpu_model) CPU(cpu_x86_init(cpu_model))
#define cpu_exec cpu_x86_exec
#define cpu_gen_code cpu_x86_gen_code
@@ -1329,7 +1321,6 @@ void x86_cpu_compat_kvm_no_autodisable(FeatureWord w, uint32_t features);
/* Return name of 32-bit register, from a R_* constant */
const char *get_register_name_32(unsigned int reg);
-uint32_t x86_cpu_apic_id_from_index(unsigned int cpu_index);
void enable_compat_apic_id_mode(void);
#define APIC_DEFAULT_ADDRESS 0xfee00000
diff --git a/target-i386/kvm.c b/target-i386/kvm.c
index acb683102..41d09e52d 100644
--- a/target-i386/kvm.c
+++ b/target-i386/kvm.c
@@ -430,7 +430,7 @@ static void cpu_update_state(void *opaque, int running, RunState state)
unsigned long kvm_arch_vcpu_id(CPUState *cs)
{
X86CPU *cpu = X86_CPU(cs);
- return cpu->env.cpuid_apic_id;
+ return cpu->apic_id;
}
#ifndef KVM_CPUID_SIGNATURE_NEXT
diff --git a/target-i386/seg_helper.c b/target-i386/seg_helper.c
index fa374d0c0..2bc757af3 100644
--- a/target-i386/seg_helper.c
+++ b/target-i386/seg_helper.c
@@ -1043,7 +1043,7 @@ void helper_sysret(CPUX86State *env, int dflag)
DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK);
env->eip = (uint32_t)env->regs[R_ECX];
}
- cpu_x86_load_seg_cache(env, R_SS, selector + 8,
+ cpu_x86_load_seg_cache(env, R_SS, (selector + 8) | 3,
0, 0xffffffff,
DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
DESC_S_MASK | (3 << DESC_DPL_SHIFT) |
@@ -1056,7 +1056,7 @@ void helper_sysret(CPUX86State *env, int dflag)
DESC_S_MASK | (3 << DESC_DPL_SHIFT) |
DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK);
env->eip = (uint32_t)env->regs[R_ECX];
- cpu_x86_load_seg_cache(env, R_SS, selector + 8,
+ cpu_x86_load_seg_cache(env, R_SS, (selector + 8) | 3,
0, 0xffffffff,
DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
DESC_S_MASK | (3 << DESC_DPL_SHIFT) |
diff --git a/target-lm32/cpu.h b/target-lm32/cpu.h
index e558c5949..11ae68d22 100644
--- a/target-lm32/cpu.h
+++ b/target-lm32/cpu.h
@@ -217,14 +217,7 @@ void lm32_watchpoint_insert(CPULM32State *env, int index, target_ulong address,
void lm32_watchpoint_remove(CPULM32State *env, int index);
bool lm32_cpu_do_semihosting(CPUState *cs);
-static inline CPULM32State *cpu_init(const char *cpu_model)
-{
- LM32CPU *cpu = cpu_lm32_init(cpu_model);
- if (cpu == NULL) {
- return NULL;
- }
- return &cpu->env;
-}
+#define cpu_init(cpu_model) CPU(cpu_lm32_init(cpu_model))
#define cpu_list lm32_cpu_list
#define cpu_exec cpu_lm32_exec
diff --git a/target-m68k/cpu.h b/target-m68k/cpu.h
index 3a1b9ab93..5f165da90 100644
--- a/target-m68k/cpu.h
+++ b/target-m68k/cpu.h
@@ -212,14 +212,7 @@ void register_m68k_insns (CPUM68KState *env);
#define TARGET_PHYS_ADDR_SPACE_BITS 32
#define TARGET_VIRT_ADDR_SPACE_BITS 32
-static inline CPUM68KState *cpu_init(const char *cpu_model)
-{
- M68kCPU *cpu = cpu_m68k_init(cpu_model);
- if (cpu == NULL) {
- return NULL;
- }
- return &cpu->env;
-}
+#define cpu_init(cpu_model) CPU(cpu_m68k_init(cpu_model))
#define cpu_exec cpu_m68k_exec
#define cpu_gen_code cpu_m68k_gen_code
diff --git a/target-microblaze/cpu.h b/target-microblaze/cpu.h
index 5794f8991..7d0622773 100644
--- a/target-microblaze/cpu.h
+++ b/target-microblaze/cpu.h
@@ -297,14 +297,7 @@ enum {
#define TARGET_PHYS_ADDR_SPACE_BITS 32
#define TARGET_VIRT_ADDR_SPACE_BITS 32
-static inline CPUMBState *cpu_init(const char *cpu_model)
-{
- MicroBlazeCPU *cpu = cpu_mb_init(cpu_model);
- if (cpu == NULL) {
- return NULL;
- }
- return &cpu->env;
-}
+#define cpu_init(cpu_model) CPU(cpu_mb_init(cpu_model))
#define cpu_exec cpu_mb_exec
#define cpu_gen_code cpu_mb_gen_code
diff --git a/target-mips/cpu-qom.h b/target-mips/cpu-qom.h
index 2ffc1bf3f..4d6f9de2e 100644
--- a/target-mips/cpu-qom.h
+++ b/target-mips/cpu-qom.h
@@ -74,6 +74,10 @@ static inline MIPSCPU *mips_env_get_cpu(CPUMIPSState *env)
#define ENV_OFFSET offsetof(MIPSCPU, env)
+#ifndef CONFIG_USER_ONLY
+extern const struct VMStateDescription vmstate_mips_cpu;
+#endif
+
void mips_cpu_do_interrupt(CPUState *cpu);
bool mips_cpu_exec_interrupt(CPUState *cpu, int int_req);
void mips_cpu_dump_state(CPUState *cpu, FILE *f, fprintf_function cpu_fprintf,
diff --git a/target-mips/cpu.c b/target-mips/cpu.c
index 98dc94e74..958c999f0 100644
--- a/target-mips/cpu.c
+++ b/target-mips/cpu.c
@@ -148,6 +148,7 @@ static void mips_cpu_class_init(ObjectClass *c, void *data)
cc->do_unassigned_access = mips_cpu_unassigned_access;
cc->do_unaligned_access = mips_cpu_do_unaligned_access;
cc->get_phys_page_debug = mips_cpu_get_phys_page_debug;
+ cc->vmsd = &vmstate_mips_cpu;
#endif
cc->gdb_num_core_regs = 73;
diff --git a/target-mips/cpu.h b/target-mips/cpu.h
index 5ea61bcee..f9d2b4c5a 100644
--- a/target-mips/cpu.h
+++ b/target-mips/cpu.h
@@ -614,8 +614,6 @@ void mips_cpu_list (FILE *f, fprintf_function cpu_fprintf);
extern void cpu_wrdsp(uint32_t rs, uint32_t mask_num, CPUMIPSState *env);
extern uint32_t cpu_rddsp(uint32_t mask_num, CPUMIPSState *env);
-#define CPU_SAVE_VERSION 5
-
/* MMU modes definitions. We carefully match the indices with our
hflags layout. */
#define MMU_MODE0_SUFFIX _kernel
@@ -739,14 +737,7 @@ void mips_tcg_init(void);
MIPSCPU *cpu_mips_init(const char *cpu_model);
int cpu_mips_signal_handler(int host_signum, void *pinfo, void *puc);
-static inline CPUMIPSState *cpu_init(const char *cpu_model)
-{
- MIPSCPU *cpu = cpu_mips_init(cpu_model);
- if (cpu == NULL) {
- return NULL;
- }
- return &cpu->env;
-}
+#define cpu_init(cpu_model) CPU(cpu_mips_init(cpu_model))
/* TODO QOM'ify CPU reset and remove */
void cpu_state_reset(CPUMIPSState *s);
@@ -788,6 +779,23 @@ static inline void restore_flush_mode(CPUMIPSState *env)
&env->active_fpu.fp_status);
}
+static inline void restore_fp_status(CPUMIPSState *env)
+{
+ restore_rounding_mode(env);
+ restore_flush_mode(env);
+}
+
+static inline void restore_msa_fp_status(CPUMIPSState *env)
+{
+ float_status *status = &env->active_tc.msa_fp_status;
+ int rounding_mode = (env->active_tc.msacsr & MSACSR_RM_MASK) >> MSACSR_RM;
+ bool flush_to_zero = (env->active_tc.msacsr & MSACSR_FS_MASK) != 0;
+
+ set_float_rounding_mode(ieee_rm[rounding_mode], status);
+ set_flush_to_zero(flush_to_zero, status);
+ set_flush_inputs_to_zero(flush_to_zero, status);
+}
+
static inline void cpu_get_tb_cpu_state(CPUMIPSState *env, target_ulong *pc,
target_ulong *cs_base, int *flags)
{
diff --git a/target-mips/machine.c b/target-mips/machine.c
index 6c76dfbe0..7d1fa32e5 100644
--- a/target-mips/machine.c
+++ b/target-mips/machine.c
@@ -1,341 +1,296 @@
#include "hw/hw.h"
-#include "hw/boards.h"
#include "cpu.h"
-static void save_tc(QEMUFile *f, TCState *tc)
+static int cpu_post_load(void *opaque, int version_id)
{
- int i;
+ MIPSCPU *cpu = opaque;
+ CPUMIPSState *env = &cpu->env;
+
+ restore_fp_status(env);
+ restore_msa_fp_status(env);
+ compute_hflags(env);
- /* Save active TC */
- for(i = 0; i < 32; i++)
- qemu_put_betls(f, &tc->gpr[i]);
- qemu_put_betls(f, &tc->PC);
- for(i = 0; i < MIPS_DSP_ACC; i++)
- qemu_put_betls(f, &tc->HI[i]);
- for(i = 0; i < MIPS_DSP_ACC; i++)
- qemu_put_betls(f, &tc->LO[i]);
- for(i = 0; i < MIPS_DSP_ACC; i++)
- qemu_put_betls(f, &tc->ACX[i]);
- qemu_put_betls(f, &tc->DSPControl);
- qemu_put_sbe32s(f, &tc->CP0_TCStatus);
- qemu_put_sbe32s(f, &tc->CP0_TCBind);
- qemu_put_betls(f, &tc->CP0_TCHalt);
- qemu_put_betls(f, &tc->CP0_TCContext);
- qemu_put_betls(f, &tc->CP0_TCSchedule);
- qemu_put_betls(f, &tc->CP0_TCScheFBack);
- qemu_put_sbe32s(f, &tc->CP0_Debug_tcstatus);
- qemu_put_betls(f, &tc->CP0_UserLocal);
+ return 0;
}
-static void save_fpu(QEMUFile *f, CPUMIPSFPUContext *fpu)
+/* FPU state */
+
+static int get_fpr(QEMUFile *f, void *pv, size_t size)
{
int i;
-
- for(i = 0; i < 32; i++)
- qemu_put_be64s(f, &fpu->fpr[i].d);
- qemu_put_s8s(f, &fpu->fp_status.float_detect_tininess);
- qemu_put_s8s(f, &fpu->fp_status.float_rounding_mode);
- qemu_put_s8s(f, &fpu->fp_status.float_exception_flags);
- qemu_put_be32s(f, &fpu->fcr0);
- qemu_put_be32s(f, &fpu->fcr31);
+ fpr_t *v = pv;
+ /* Restore entire MSA vector register */
+ for (i = 0; i < MSA_WRLEN/64; i++) {
+ qemu_get_sbe64s(f, &v->wr.d[i]);
+ }
+ return 0;
}
-void cpu_save(QEMUFile *f, void *opaque)
+static void put_fpr(QEMUFile *f, void *pv, size_t size)
{
- CPUMIPSState *env = opaque;
int i;
-
- /* Save active TC */
- save_tc(f, &env->active_tc);
-
- /* Save active FPU */
- save_fpu(f, &env->active_fpu);
-
- /* Save MVP */
- qemu_put_sbe32s(f, &env->mvp->CP0_MVPControl);
- qemu_put_sbe32s(f, &env->mvp->CP0_MVPConf0);
- qemu_put_sbe32s(f, &env->mvp->CP0_MVPConf1);
-
- /* Save TLB */
- qemu_put_be32s(f, &env->tlb->nb_tlb);
- qemu_put_be32s(f, &env->tlb->tlb_in_use);
- for(i = 0; i < MIPS_TLB_MAX; i++) {
- uint16_t flags = ((env->tlb->mmu.r4k.tlb[i].EHINV << 15) |
- (env->tlb->mmu.r4k.tlb[i].RI1 << 14) |
- (env->tlb->mmu.r4k.tlb[i].RI0 << 13) |
- (env->tlb->mmu.r4k.tlb[i].XI1 << 12) |
- (env->tlb->mmu.r4k.tlb[i].XI0 << 11) |
- (env->tlb->mmu.r4k.tlb[i].G << 10) |
- (env->tlb->mmu.r4k.tlb[i].C0 << 7) |
- (env->tlb->mmu.r4k.tlb[i].C1 << 4) |
- (env->tlb->mmu.r4k.tlb[i].V0 << 3) |
- (env->tlb->mmu.r4k.tlb[i].V1 << 2) |
- (env->tlb->mmu.r4k.tlb[i].D0 << 1) |
- (env->tlb->mmu.r4k.tlb[i].D1 << 0));
- uint8_t asid;
-
- qemu_put_betls(f, &env->tlb->mmu.r4k.tlb[i].VPN);
- qemu_put_be32s(f, &env->tlb->mmu.r4k.tlb[i].PageMask);
- asid = env->tlb->mmu.r4k.tlb[i].ASID;
- qemu_put_8s(f, &asid);
- qemu_put_be16s(f, &flags);
- qemu_put_betls(f, &env->tlb->mmu.r4k.tlb[i].PFN[0]);
- qemu_put_betls(f, &env->tlb->mmu.r4k.tlb[i].PFN[1]);
+ fpr_t *v = pv;
+ /* Save entire MSA vector register */
+ for (i = 0; i < MSA_WRLEN/64; i++) {
+ qemu_put_sbe64s(f, &v->wr.d[i]);
}
+}
+
+const VMStateInfo vmstate_info_fpr = {
+ .name = "fpr",
+ .get = get_fpr,
+ .put = put_fpr,
+};
+
+#define VMSTATE_FPR_ARRAY_V(_f, _s, _n, _v) \
+ VMSTATE_ARRAY(_f, _s, _n, _v, vmstate_info_fpr, fpr_t)
- /* Save CPU metastate */
- qemu_put_be32s(f, &env->current_tc);
- qemu_put_be32s(f, &env->current_fpu);
- qemu_put_sbe32s(f, &env->error_code);
- qemu_put_be32s(f, &env->hflags);
- qemu_put_betls(f, &env->btarget);
- i = env->bcond;
- qemu_put_sbe32s(f, &i);
-
- /* Save remaining CP1 registers */
- qemu_put_sbe32s(f, &env->CP0_Index);
- qemu_put_sbe32s(f, &env->CP0_Random);
- qemu_put_sbe32s(f, &env->CP0_VPEControl);
- qemu_put_sbe32s(f, &env->CP0_VPEConf0);
- qemu_put_sbe32s(f, &env->CP0_VPEConf1);
- qemu_put_betls(f, &env->CP0_YQMask);
- qemu_put_betls(f, &env->CP0_VPESchedule);
- qemu_put_betls(f, &env->CP0_VPEScheFBack);
- qemu_put_sbe32s(f, &env->CP0_VPEOpt);
- qemu_put_betls(f, &env->CP0_EntryLo0);
- qemu_put_betls(f, &env->CP0_EntryLo1);
- qemu_put_betls(f, &env->CP0_Context);
- qemu_put_sbe32s(f, &env->CP0_PageMask);
- qemu_put_sbe32s(f, &env->CP0_PageGrain);
- qemu_put_sbe32s(f, &env->CP0_Wired);
- qemu_put_sbe32s(f, &env->CP0_SRSConf0);
- qemu_put_sbe32s(f, &env->CP0_SRSConf1);
- qemu_put_sbe32s(f, &env->CP0_SRSConf2);
- qemu_put_sbe32s(f, &env->CP0_SRSConf3);
- qemu_put_sbe32s(f, &env->CP0_SRSConf4);
- qemu_put_sbe32s(f, &env->CP0_HWREna);
- qemu_put_betls(f, &env->CP0_BadVAddr);
- qemu_put_be32s(f, &env->CP0_BadInstr);
- qemu_put_be32s(f, &env->CP0_BadInstrP);
- qemu_put_sbe32s(f, &env->CP0_Count);
- qemu_put_betls(f, &env->CP0_EntryHi);
- qemu_put_sbe32s(f, &env->CP0_Compare);
- qemu_put_sbe32s(f, &env->CP0_Status);
- qemu_put_sbe32s(f, &env->CP0_IntCtl);
- qemu_put_sbe32s(f, &env->CP0_SRSCtl);
- qemu_put_sbe32s(f, &env->CP0_SRSMap);
- qemu_put_sbe32s(f, &env->CP0_Cause);
- qemu_put_betls(f, &env->CP0_EPC);
- qemu_put_sbe32s(f, &env->CP0_PRid);
- qemu_put_sbe32s(f, &env->CP0_EBase);
- qemu_put_sbe32s(f, &env->CP0_Config0);
- qemu_put_sbe32s(f, &env->CP0_Config1);
- qemu_put_sbe32s(f, &env->CP0_Config2);
- qemu_put_sbe32s(f, &env->CP0_Config3);
- qemu_put_sbe32s(f, &env->CP0_Config6);
- qemu_put_sbe32s(f, &env->CP0_Config7);
- qemu_put_betls(f, &env->lladdr);
- for(i = 0; i < 8; i++)
- qemu_put_betls(f, &env->CP0_WatchLo[i]);
- for(i = 0; i < 8; i++)
- qemu_put_sbe32s(f, &env->CP0_WatchHi[i]);
- qemu_put_betls(f, &env->CP0_XContext);
- qemu_put_sbe32s(f, &env->CP0_Framemask);
- qemu_put_sbe32s(f, &env->CP0_Debug);
- qemu_put_betls(f, &env->CP0_DEPC);
- qemu_put_sbe32s(f, &env->CP0_Performance0);
- qemu_put_sbe32s(f, &env->CP0_TagLo);
- qemu_put_sbe32s(f, &env->CP0_DataLo);
- qemu_put_sbe32s(f, &env->CP0_TagHi);
- qemu_put_sbe32s(f, &env->CP0_DataHi);
- qemu_put_betls(f, &env->CP0_ErrorEPC);
- qemu_put_sbe32s(f, &env->CP0_DESAVE);
- for (i = 0; i < MIPS_KSCRATCH_NUM; i++) {
- qemu_put_betls(f, &env->CP0_KScratch[i]);
+#define VMSTATE_FPR_ARRAY(_f, _s, _n) \
+ VMSTATE_FPR_ARRAY_V(_f, _s, _n, 0)
+
+static VMStateField vmstate_fpu_fields[] = {
+ VMSTATE_FPR_ARRAY(fpr, CPUMIPSFPUContext, 32),
+ VMSTATE_UINT32(fcr0, CPUMIPSFPUContext),
+ VMSTATE_UINT32(fcr31, CPUMIPSFPUContext),
+ VMSTATE_END_OF_LIST()
+};
+
+const VMStateDescription vmstate_fpu = {
+ .name = "cpu/fpu",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .fields = vmstate_fpu_fields
+};
+
+const VMStateDescription vmstate_inactive_fpu = {
+ .name = "cpu/inactive_fpu",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .fields = vmstate_fpu_fields
+};
+
+/* TC state */
+
+static VMStateField vmstate_tc_fields[] = {
+ VMSTATE_UINTTL_ARRAY(gpr, TCState, 32),
+ VMSTATE_UINTTL(PC, TCState),
+ VMSTATE_UINTTL_ARRAY(HI, TCState, MIPS_DSP_ACC),
+ VMSTATE_UINTTL_ARRAY(LO, TCState, MIPS_DSP_ACC),
+ VMSTATE_UINTTL_ARRAY(ACX, TCState, MIPS_DSP_ACC),
+ VMSTATE_UINTTL(DSPControl, TCState),
+ VMSTATE_INT32(CP0_TCStatus, TCState),
+ VMSTATE_INT32(CP0_TCBind, TCState),
+ VMSTATE_UINTTL(CP0_TCHalt, TCState),
+ VMSTATE_UINTTL(CP0_TCContext, TCState),
+ VMSTATE_UINTTL(CP0_TCSchedule, TCState),
+ VMSTATE_UINTTL(CP0_TCScheFBack, TCState),
+ VMSTATE_INT32(CP0_Debug_tcstatus, TCState),
+ VMSTATE_UINTTL(CP0_UserLocal, TCState),
+ VMSTATE_INT32(msacsr, TCState),
+ VMSTATE_END_OF_LIST()
+};
+
+const VMStateDescription vmstate_tc = {
+ .name = "cpu/tc",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .fields = vmstate_tc_fields
+};
+
+const VMStateDescription vmstate_inactive_tc = {
+ .name = "cpu/inactive_tc",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .fields = vmstate_tc_fields
+};
+
+/* MVP state */
+
+const VMStateDescription vmstate_mvp = {
+ .name = "cpu/mvp",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .fields = (VMStateField[]) {
+ VMSTATE_INT32(CP0_MVPControl, CPUMIPSMVPContext),
+ VMSTATE_INT32(CP0_MVPConf0, CPUMIPSMVPContext),
+ VMSTATE_INT32(CP0_MVPConf1, CPUMIPSMVPContext),
+ VMSTATE_END_OF_LIST()
}
+};
- /* Save inactive TC state */
- for (i = 0; i < MIPS_SHADOW_SET_MAX; i++)
- save_tc(f, &env->tcs[i]);
- for (i = 0; i < MIPS_FPU_MAX; i++)
- save_fpu(f, &env->fpus[i]);
-}
+/* TLB state */
-static void load_tc(QEMUFile *f, TCState *tc, int version_id)
+static int get_tlb(QEMUFile *f, void *pv, size_t size)
{
- int i;
+ r4k_tlb_t *v = pv;
+ uint16_t flags;
- /* Save active TC */
- for(i = 0; i < 32; i++)
- qemu_get_betls(f, &tc->gpr[i]);
- qemu_get_betls(f, &tc->PC);
- for(i = 0; i < MIPS_DSP_ACC; i++)
- qemu_get_betls(f, &tc->HI[i]);
- for(i = 0; i < MIPS_DSP_ACC; i++)
- qemu_get_betls(f, &tc->LO[i]);
- for(i = 0; i < MIPS_DSP_ACC; i++)
- qemu_get_betls(f, &tc->ACX[i]);
- qemu_get_betls(f, &tc->DSPControl);
- qemu_get_sbe32s(f, &tc->CP0_TCStatus);
- qemu_get_sbe32s(f, &tc->CP0_TCBind);
- qemu_get_betls(f, &tc->CP0_TCHalt);
- qemu_get_betls(f, &tc->CP0_TCContext);
- qemu_get_betls(f, &tc->CP0_TCSchedule);
- qemu_get_betls(f, &tc->CP0_TCScheFBack);
- qemu_get_sbe32s(f, &tc->CP0_Debug_tcstatus);
- if (version_id >= 4) {
- qemu_get_betls(f, &tc->CP0_UserLocal);
- }
+ qemu_get_betls(f, &v->VPN);
+ qemu_get_be32s(f, &v->PageMask);
+ qemu_get_8s(f, &v->ASID);
+ qemu_get_be16s(f, &flags);
+ v->G = (flags >> 10) & 1;
+ v->C0 = (flags >> 7) & 3;
+ v->C1 = (flags >> 4) & 3;
+ v->V0 = (flags >> 3) & 1;
+ v->V1 = (flags >> 2) & 1;
+ v->D0 = (flags >> 1) & 1;
+ v->D1 = (flags >> 0) & 1;
+ v->EHINV = (flags >> 15) & 1;
+ v->RI1 = (flags >> 14) & 1;
+ v->RI0 = (flags >> 13) & 1;
+ v->XI1 = (flags >> 12) & 1;
+ v->XI0 = (flags >> 11) & 1;
+ qemu_get_betls(f, &v->PFN[0]);
+ qemu_get_betls(f, &v->PFN[1]);
+
+ return 0;
}
-static void load_fpu(QEMUFile *f, CPUMIPSFPUContext *fpu)
+static void put_tlb(QEMUFile *f, void *pv, size_t size)
{
- int i;
+ r4k_tlb_t *v = pv;
+
+ uint16_t flags = ((v->EHINV << 15) |
+ (v->RI1 << 14) |
+ (v->RI0 << 13) |
+ (v->XI1 << 12) |
+ (v->XI0 << 11) |
+ (v->G << 10) |
+ (v->C0 << 7) |
+ (v->C1 << 4) |
+ (v->V0 << 3) |
+ (v->V1 << 2) |
+ (v->D0 << 1) |
+ (v->D1 << 0));
- for(i = 0; i < 32; i++)
- qemu_get_be64s(f, &fpu->fpr[i].d);
- qemu_get_s8s(f, &fpu->fp_status.float_detect_tininess);
- qemu_get_s8s(f, &fpu->fp_status.float_rounding_mode);
- qemu_get_s8s(f, &fpu->fp_status.float_exception_flags);
- qemu_get_be32s(f, &fpu->fcr0);
- qemu_get_be32s(f, &fpu->fcr31);
+ qemu_put_betls(f, &v->VPN);
+ qemu_put_be32s(f, &v->PageMask);
+ qemu_put_8s(f, &v->ASID);
+ qemu_put_be16s(f, &flags);
+ qemu_put_betls(f, &v->PFN[0]);
+ qemu_put_betls(f, &v->PFN[1]);
}
-int cpu_load(QEMUFile *f, void *opaque, int version_id)
-{
- CPUMIPSState *env = opaque;
- MIPSCPU *cpu = mips_env_get_cpu(env);
- int i;
+const VMStateInfo vmstate_info_tlb = {
+ .name = "tlb_entry",
+ .get = get_tlb,
+ .put = put_tlb,
+};
- if (version_id < 3) {
- return -EINVAL;
- }
+#define VMSTATE_TLB_ARRAY_V(_f, _s, _n, _v) \
+ VMSTATE_ARRAY(_f, _s, _n, _v, vmstate_info_tlb, r4k_tlb_t)
- /* Load active TC */
- load_tc(f, &env->active_tc, version_id);
-
- /* Load active FPU */
- load_fpu(f, &env->active_fpu);
-
- /* Load MVP */
- qemu_get_sbe32s(f, &env->mvp->CP0_MVPControl);
- qemu_get_sbe32s(f, &env->mvp->CP0_MVPConf0);
- qemu_get_sbe32s(f, &env->mvp->CP0_MVPConf1);
-
- /* Load TLB */
- qemu_get_be32s(f, &env->tlb->nb_tlb);
- qemu_get_be32s(f, &env->tlb->tlb_in_use);
- for(i = 0; i < MIPS_TLB_MAX; i++) {
- uint16_t flags;
- uint8_t asid;
-
- qemu_get_betls(f, &env->tlb->mmu.r4k.tlb[i].VPN);
- qemu_get_be32s(f, &env->tlb->mmu.r4k.tlb[i].PageMask);
- qemu_get_8s(f, &asid);
- env->tlb->mmu.r4k.tlb[i].ASID = asid;
- qemu_get_be16s(f, &flags);
- env->tlb->mmu.r4k.tlb[i].G = (flags >> 10) & 1;
- env->tlb->mmu.r4k.tlb[i].C0 = (flags >> 7) & 3;
- env->tlb->mmu.r4k.tlb[i].C1 = (flags >> 4) & 3;
- env->tlb->mmu.r4k.tlb[i].V0 = (flags >> 3) & 1;
- env->tlb->mmu.r4k.tlb[i].V1 = (flags >> 2) & 1;
- env->tlb->mmu.r4k.tlb[i].D0 = (flags >> 1) & 1;
- env->tlb->mmu.r4k.tlb[i].D1 = (flags >> 0) & 1;
- if (version_id >= 5) {
- env->tlb->mmu.r4k.tlb[i].EHINV = (flags >> 15) & 1;
- env->tlb->mmu.r4k.tlb[i].RI1 = (flags >> 14) & 1;
- env->tlb->mmu.r4k.tlb[i].RI0 = (flags >> 13) & 1;
- env->tlb->mmu.r4k.tlb[i].XI1 = (flags >> 12) & 1;
- env->tlb->mmu.r4k.tlb[i].XI0 = (flags >> 11) & 1;
- }
- qemu_get_betls(f, &env->tlb->mmu.r4k.tlb[i].PFN[0]);
- qemu_get_betls(f, &env->tlb->mmu.r4k.tlb[i].PFN[1]);
- }
+#define VMSTATE_TLB_ARRAY(_f, _s, _n) \
+ VMSTATE_TLB_ARRAY_V(_f, _s, _n, 0)
- /* Load CPU metastate */
- qemu_get_be32s(f, &env->current_tc);
- qemu_get_be32s(f, &env->current_fpu);
- qemu_get_sbe32s(f, &env->error_code);
- qemu_get_be32s(f, &env->hflags);
- qemu_get_betls(f, &env->btarget);
- qemu_get_sbe32s(f, &i);
- env->bcond = i;
-
- /* Load remaining CP1 registers */
- qemu_get_sbe32s(f, &env->CP0_Index);
- qemu_get_sbe32s(f, &env->CP0_Random);
- qemu_get_sbe32s(f, &env->CP0_VPEControl);
- qemu_get_sbe32s(f, &env->CP0_VPEConf0);
- qemu_get_sbe32s(f, &env->CP0_VPEConf1);
- qemu_get_betls(f, &env->CP0_YQMask);
- qemu_get_betls(f, &env->CP0_VPESchedule);
- qemu_get_betls(f, &env->CP0_VPEScheFBack);
- qemu_get_sbe32s(f, &env->CP0_VPEOpt);
- qemu_get_betls(f, &env->CP0_EntryLo0);
- qemu_get_betls(f, &env->CP0_EntryLo1);
- qemu_get_betls(f, &env->CP0_Context);
- qemu_get_sbe32s(f, &env->CP0_PageMask);
- qemu_get_sbe32s(f, &env->CP0_PageGrain);
- qemu_get_sbe32s(f, &env->CP0_Wired);
- qemu_get_sbe32s(f, &env->CP0_SRSConf0);
- qemu_get_sbe32s(f, &env->CP0_SRSConf1);
- qemu_get_sbe32s(f, &env->CP0_SRSConf2);
- qemu_get_sbe32s(f, &env->CP0_SRSConf3);
- qemu_get_sbe32s(f, &env->CP0_SRSConf4);
- qemu_get_sbe32s(f, &env->CP0_HWREna);
- qemu_get_betls(f, &env->CP0_BadVAddr);
- if (version_id >= 5) {
- qemu_get_be32s(f, &env->CP0_BadInstr);
- qemu_get_be32s(f, &env->CP0_BadInstrP);
- }
- qemu_get_sbe32s(f, &env->CP0_Count);
- qemu_get_betls(f, &env->CP0_EntryHi);
- qemu_get_sbe32s(f, &env->CP0_Compare);
- qemu_get_sbe32s(f, &env->CP0_Status);
- qemu_get_sbe32s(f, &env->CP0_IntCtl);
- qemu_get_sbe32s(f, &env->CP0_SRSCtl);
- qemu_get_sbe32s(f, &env->CP0_SRSMap);
- qemu_get_sbe32s(f, &env->CP0_Cause);
- qemu_get_betls(f, &env->CP0_EPC);
- qemu_get_sbe32s(f, &env->CP0_PRid);
- qemu_get_sbe32s(f, &env->CP0_EBase);
- qemu_get_sbe32s(f, &env->CP0_Config0);
- qemu_get_sbe32s(f, &env->CP0_Config1);
- qemu_get_sbe32s(f, &env->CP0_Config2);
- qemu_get_sbe32s(f, &env->CP0_Config3);
- qemu_get_sbe32s(f, &env->CP0_Config6);
- qemu_get_sbe32s(f, &env->CP0_Config7);
- qemu_get_betls(f, &env->lladdr);
- for(i = 0; i < 8; i++)
- qemu_get_betls(f, &env->CP0_WatchLo[i]);
- for(i = 0; i < 8; i++)
- qemu_get_sbe32s(f, &env->CP0_WatchHi[i]);
- qemu_get_betls(f, &env->CP0_XContext);
- qemu_get_sbe32s(f, &env->CP0_Framemask);
- qemu_get_sbe32s(f, &env->CP0_Debug);
- qemu_get_betls(f, &env->CP0_DEPC);
- qemu_get_sbe32s(f, &env->CP0_Performance0);
- qemu_get_sbe32s(f, &env->CP0_TagLo);
- qemu_get_sbe32s(f, &env->CP0_DataLo);
- qemu_get_sbe32s(f, &env->CP0_TagHi);
- qemu_get_sbe32s(f, &env->CP0_DataHi);
- qemu_get_betls(f, &env->CP0_ErrorEPC);
- qemu_get_sbe32s(f, &env->CP0_DESAVE);
- if (version_id >= 5) {
- for (i = 0; i < MIPS_KSCRATCH_NUM; i++) {
- qemu_get_betls(f, &env->CP0_KScratch[i]);
- }
+const VMStateDescription vmstate_tlb = {
+ .name = "cpu/tlb",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .fields = (VMStateField[]) {
+ VMSTATE_UINT32(nb_tlb, CPUMIPSTLBContext),
+ VMSTATE_UINT32(tlb_in_use, CPUMIPSTLBContext),
+ VMSTATE_TLB_ARRAY(mmu.r4k.tlb, CPUMIPSTLBContext, MIPS_TLB_MAX),
+ VMSTATE_END_OF_LIST()
}
+};
- /* Load inactive TC state */
- for (i = 0; i < MIPS_SHADOW_SET_MAX; i++) {
- load_tc(f, &env->tcs[i], version_id);
- }
- for (i = 0; i < MIPS_FPU_MAX; i++)
- load_fpu(f, &env->fpus[i]);
+/* MIPS CPU state */
- /* XXX: ensure compatibility for halted bit ? */
- tlb_flush(CPU(cpu), 1);
- return 0;
-}
+const VMStateDescription vmstate_mips_cpu = {
+ .name = "cpu",
+ .version_id = 6,
+ .minimum_version_id = 6,
+ .post_load = cpu_post_load,
+ .fields = (VMStateField[]) {
+ /* Active TC */
+ VMSTATE_STRUCT(env.active_tc, MIPSCPU, 1, vmstate_tc, TCState),
+
+ /* Active FPU */
+ VMSTATE_STRUCT(env.active_fpu, MIPSCPU, 1, vmstate_fpu,
+ CPUMIPSFPUContext),
+
+ /* MVP */
+ VMSTATE_STRUCT_POINTER(env.mvp, MIPSCPU, vmstate_mvp,
+ CPUMIPSMVPContext),
+
+ /* TLB */
+ VMSTATE_STRUCT_POINTER(env.tlb, MIPSCPU, vmstate_tlb,
+ CPUMIPSTLBContext),
+
+ /* CPU metastate */
+ VMSTATE_UINT32(env.current_tc, MIPSCPU),
+ VMSTATE_UINT32(env.current_fpu, MIPSCPU),
+ VMSTATE_INT32(env.error_code, MIPSCPU),
+ VMSTATE_UINTTL(env.btarget, MIPSCPU),
+ VMSTATE_UINTTL(env.bcond, MIPSCPU),
+
+ /* Remaining CP0 registers */
+ VMSTATE_INT32(env.CP0_Index, MIPSCPU),
+ VMSTATE_INT32(env.CP0_Random, MIPSCPU),
+ VMSTATE_INT32(env.CP0_VPEControl, MIPSCPU),
+ VMSTATE_INT32(env.CP0_VPEConf0, MIPSCPU),
+ VMSTATE_INT32(env.CP0_VPEConf1, MIPSCPU),
+ VMSTATE_UINTTL(env.CP0_YQMask, MIPSCPU),
+ VMSTATE_UINTTL(env.CP0_VPESchedule, MIPSCPU),
+ VMSTATE_UINTTL(env.CP0_VPEScheFBack, MIPSCPU),
+ VMSTATE_INT32(env.CP0_VPEOpt, MIPSCPU),
+ VMSTATE_UINTTL(env.CP0_EntryLo0, MIPSCPU),
+ VMSTATE_UINTTL(env.CP0_EntryLo1, MIPSCPU),
+ VMSTATE_UINTTL(env.CP0_Context, MIPSCPU),
+ VMSTATE_INT32(env.CP0_PageMask, MIPSCPU),
+ VMSTATE_INT32(env.CP0_PageGrain, MIPSCPU),
+ VMSTATE_INT32(env.CP0_Wired, MIPSCPU),
+ VMSTATE_INT32(env.CP0_SRSConf0, MIPSCPU),
+ VMSTATE_INT32(env.CP0_SRSConf1, MIPSCPU),
+ VMSTATE_INT32(env.CP0_SRSConf2, MIPSCPU),
+ VMSTATE_INT32(env.CP0_SRSConf3, MIPSCPU),
+ VMSTATE_INT32(env.CP0_SRSConf4, MIPSCPU),
+ VMSTATE_INT32(env.CP0_HWREna, MIPSCPU),
+ VMSTATE_UINTTL(env.CP0_BadVAddr, MIPSCPU),
+ VMSTATE_UINT32(env.CP0_BadInstr, MIPSCPU),
+ VMSTATE_UINT32(env.CP0_BadInstrP, MIPSCPU),
+ VMSTATE_INT32(env.CP0_Count, MIPSCPU),
+ VMSTATE_UINTTL(env.CP0_EntryHi, MIPSCPU),
+ VMSTATE_INT32(env.CP0_Compare, MIPSCPU),
+ VMSTATE_INT32(env.CP0_Status, MIPSCPU),
+ VMSTATE_INT32(env.CP0_IntCtl, MIPSCPU),
+ VMSTATE_INT32(env.CP0_SRSCtl, MIPSCPU),
+ VMSTATE_INT32(env.CP0_SRSMap, MIPSCPU),
+ VMSTATE_INT32(env.CP0_Cause, MIPSCPU),
+ VMSTATE_UINTTL(env.CP0_EPC, MIPSCPU),
+ VMSTATE_INT32(env.CP0_PRid, MIPSCPU),
+ VMSTATE_INT32(env.CP0_EBase, MIPSCPU),
+ VMSTATE_INT32(env.CP0_Config0, MIPSCPU),
+ VMSTATE_INT32(env.CP0_Config1, MIPSCPU),
+ VMSTATE_INT32(env.CP0_Config2, MIPSCPU),
+ VMSTATE_INT32(env.CP0_Config3, MIPSCPU),
+ VMSTATE_INT32(env.CP0_Config6, MIPSCPU),
+ VMSTATE_INT32(env.CP0_Config7, MIPSCPU),
+ VMSTATE_UINTTL(env.lladdr, MIPSCPU),
+ VMSTATE_UINTTL_ARRAY(env.CP0_WatchLo, MIPSCPU, 8),
+ VMSTATE_INT32_ARRAY(env.CP0_WatchHi, MIPSCPU, 8),
+ VMSTATE_UINTTL(env.CP0_XContext, MIPSCPU),
+ VMSTATE_INT32(env.CP0_Framemask, MIPSCPU),
+ VMSTATE_INT32(env.CP0_Debug, MIPSCPU),
+ VMSTATE_UINTTL(env.CP0_DEPC, MIPSCPU),
+ VMSTATE_INT32(env.CP0_Performance0, MIPSCPU),
+ VMSTATE_INT32(env.CP0_TagLo, MIPSCPU),
+ VMSTATE_INT32(env.CP0_DataLo, MIPSCPU),
+ VMSTATE_INT32(env.CP0_TagHi, MIPSCPU),
+ VMSTATE_INT32(env.CP0_DataHi, MIPSCPU),
+ VMSTATE_UINTTL(env.CP0_ErrorEPC, MIPSCPU),
+ VMSTATE_INT32(env.CP0_DESAVE, MIPSCPU),
+ VMSTATE_UINTTL_ARRAY(env.CP0_KScratch, MIPSCPU, MIPS_KSCRATCH_NUM),
+
+ /* Inactive TC */
+ VMSTATE_STRUCT_ARRAY(env.tcs, MIPSCPU, MIPS_SHADOW_SET_MAX, 1,
+ vmstate_inactive_tc, TCState),
+ VMSTATE_STRUCT_ARRAY(env.fpus, MIPSCPU, MIPS_FPU_MAX, 1,
+ vmstate_inactive_fpu, CPUMIPSFPUContext),
+
+ VMSTATE_END_OF_LIST()
+ },
+};
diff --git a/target-mips/msa_helper.c b/target-mips/msa_helper.c
index c2160a6a2..26ffdc726 100644
--- a/target-mips/msa_helper.c
+++ b/target-mips/msa_helper.c
@@ -1348,17 +1348,7 @@ void helper_msa_ctcmsa(CPUMIPSState *env, target_ulong elm, uint32_t cd)
break;
case 1:
env->active_tc.msacsr = (int32_t)elm & MSACSR_MASK;
- /* set float_status rounding mode */
- set_float_rounding_mode(
- ieee_rm[(env->active_tc.msacsr & MSACSR_RM_MASK) >> MSACSR_RM],
- &env->active_tc.msa_fp_status);
- /* set float_status flush modes */
- set_flush_to_zero(
- (env->active_tc.msacsr & MSACSR_FS_MASK) != 0 ? 1 : 0,
- &env->active_tc.msa_fp_status);
- set_flush_inputs_to_zero(
- (env->active_tc.msacsr & MSACSR_FS_MASK) != 0 ? 1 : 0,
- &env->active_tc.msa_fp_status);
+ restore_msa_fp_status(env);
/* check exception */
if ((GET_FP_ENABLE(env->active_tc.msacsr) | FP_UNIMPLEMENTED)
& GET_FP_CAUSE(env->active_tc.msacsr)) {
diff --git a/target-mips/translate_init.c b/target-mips/translate_init.c
index 9e8433a91..85a65e74b 100644
--- a/target-mips/translate_init.c
+++ b/target-mips/translate_init.c
@@ -835,6 +835,8 @@ static void msa_reset(CPUMIPSState *env)
- round to nearest / ties to even (RM bits are 0) */
env->active_tc.msacsr = 0;
+ restore_msa_fp_status(env);
+
/* tininess detected after rounding.*/
set_float_detect_tininess(float_tininess_after_rounding,
&env->active_tc.msa_fp_status);
@@ -842,14 +844,6 @@ static void msa_reset(CPUMIPSState *env)
/* clear float_status exception flags */
set_float_exception_flags(0, &env->active_tc.msa_fp_status);
- /* set float_status rounding mode */
- set_float_rounding_mode(float_round_nearest_even,
- &env->active_tc.msa_fp_status);
-
- /* set float_status flush modes */
- set_flush_to_zero(0, &env->active_tc.msa_fp_status);
- set_flush_inputs_to_zero(0, &env->active_tc.msa_fp_status);
-
/* clear float_status nan mode */
set_default_nan_mode(0, &env->active_tc.msa_fp_status);
}
diff --git a/target-moxie/cpu.h b/target-moxie/cpu.h
index d80939367..c2733a23d 100644
--- a/target-moxie/cpu.h
+++ b/target-moxie/cpu.h
@@ -121,14 +121,7 @@ void moxie_translate_init(void);
int cpu_moxie_signal_handler(int host_signum, void *pinfo,
void *puc);
-static inline CPUMoxieState *cpu_init(const char *cpu_model)
-{
- MoxieCPU *cpu = cpu_moxie_init(cpu_model);
- if (cpu == NULL) {
- return NULL;
- }
- return &cpu->env;
-}
+#define cpu_init(cpu_model) CPU(cpu_moxie_init(cpu_model))
#define cpu_exec cpu_moxie_exec
#define cpu_gen_code cpu_moxie_gen_code
diff --git a/target-openrisc/cpu.h b/target-openrisc/cpu.h
index 69b96c666..b25324bc8 100644
--- a/target-openrisc/cpu.h
+++ b/target-openrisc/cpu.h
@@ -389,14 +389,7 @@ int cpu_openrisc_get_phys_data(OpenRISCCPU *cpu,
int *prot, target_ulong address, int rw);
#endif
-static inline CPUOpenRISCState *cpu_init(const char *cpu_model)
-{
- OpenRISCCPU *cpu = cpu_openrisc_init(cpu_model);
- if (cpu) {
- return &cpu->env;
- }
- return NULL;
-}
+#define cpu_init(cpu_model) CPU(cpu_openrisc_init(cpu_model))
#include "exec/cpu-all.h"
diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h
index abc354584..f15815f11 100644
--- a/target-ppc/cpu.h
+++ b/target-ppc/cpu.h
@@ -1238,14 +1238,7 @@ static inline uint64_t ppc_dump_gpr(CPUPPCState *env, int gprn)
int ppc_dcr_read (ppc_dcr_t *dcr_env, int dcrn, uint32_t *valp);
int ppc_dcr_write (ppc_dcr_t *dcr_env, int dcrn, uint32_t val);
-static inline CPUPPCState *cpu_init(const char *cpu_model)
-{
- PowerPCCPU *cpu = cpu_ppc_init(cpu_model);
- if (cpu == NULL) {
- return NULL;
- }
- return &cpu->env;
-}
+#define cpu_init(cpu_model) CPU(cpu_ppc_init(cpu_model))
#define cpu_exec cpu_ppc_exec
#define cpu_gen_code cpu_ppc_gen_code
diff --git a/target-s390x/cpu.c b/target-s390x/cpu.c
index d2f6312e0..e0537fa22 100644
--- a/target-s390x/cpu.c
+++ b/target-s390x/cpu.c
@@ -96,6 +96,7 @@ static void s390_cpu_reset(CPUState *s)
env->pfault_token = -1UL;
scc->parent_reset(s);
+ cpu->env.sigp_order = 0;
s390_cpu_set_state(CPU_STATE_STOPPED, cpu);
tlb_flush(s, 1);
}
@@ -131,6 +132,7 @@ static void s390_cpu_full_reset(CPUState *s)
CPUS390XState *env = &cpu->env;
scc->parent_reset(s);
+ cpu->env.sigp_order = 0;
s390_cpu_set_state(CPU_STATE_STOPPED, cpu);
memset(env, 0, offsetof(CPUS390XState, cpu_num));
diff --git a/target-s390x/cpu.h b/target-s390x/cpu.h
index b6b46323d..0171de017 100644
--- a/target-s390x/cpu.h
+++ b/target-s390x/cpu.h
@@ -157,6 +157,9 @@ typedef struct CPUS390XState {
#define CPU_STATE_LOAD 0x04
uint8_t cpu_state;
+ /* currently processed sigp order */
+ uint8_t sigp_order;
+
} CPUS390XState;
#include "cpu-qom.h"
@@ -349,7 +352,10 @@ int s390_cpu_handle_mmu_fault(CPUState *cpu, vaddr address, int rw,
#include "ioinst.h"
+
#ifndef CONFIG_USER_ONLY
+void do_restart_interrupt(CPUS390XState *env);
+
static inline hwaddr decode_basedisp_s(CPUS390XState *env, uint32_t ipb)
{
hwaddr addr = 0;
@@ -411,6 +417,10 @@ S390CPU *s390_cpu_addr2state(uint16_t cpu_addr);
unsigned int s390_cpu_halt(S390CPU *cpu);
void s390_cpu_unhalt(S390CPU *cpu);
unsigned int s390_cpu_set_state(uint8_t cpu_state, S390CPU *cpu);
+static inline uint8_t s390_cpu_get_state(S390CPU *cpu)
+{
+ return cpu->env.cpu_state;
+}
/* service interrupts are floating therefore we must not pass an cpustate */
void s390_sclp_extint(uint32_t parm);
@@ -466,7 +476,7 @@ int css_do_rchp(uint8_t cssid, uint8_t chpid);
bool css_present(uint8_t cssid);
#endif
-#define cpu_init(model) (&cpu_s390x_init(model)->env)
+#define cpu_init(model) CPU(cpu_s390x_init(model))
#define cpu_exec cpu_s390x_exec
#define cpu_gen_code cpu_s390x_gen_code
#define cpu_signal_handler cpu_s390x_signal_handler
@@ -664,7 +674,7 @@ typedef struct LowCore
PSW mcck_old_psw; /* 0x160 */
PSW io_old_psw; /* 0x170 */
uint8_t pad7[0x1a0-0x180]; /* 0x180 */
- PSW restart_psw; /* 0x1a0 */
+ PSW restart_new_psw; /* 0x1a0 */
PSW external_new_psw; /* 0x1b0 */
PSW svc_new_psw; /* 0x1c0 */
PSW program_new_psw; /* 0x1d0 */
@@ -864,6 +874,7 @@ struct sysib_322 {
#define SK_F (0x1 << 3)
#define SK_ACC_MASK (0xf << 4)
+/* SIGP order codes */
#define SIGP_SENSE 0x01
#define SIGP_EXTERNAL_CALL 0x02
#define SIGP_EMERGENCY 0x03
@@ -877,7 +888,13 @@ struct sysib_322 {
#define SIGP_STORE_STATUS_ADDR 0x0e
#define SIGP_SET_ARCH 0x12
-/* cpu status bits */
+/* SIGP condition codes */
+#define SIGP_CC_ORDER_CODE_ACCEPTED 0
+#define SIGP_CC_STATUS_STORED 1
+#define SIGP_CC_BUSY 2
+#define SIGP_CC_NOT_OPERATIONAL 3
+
+/* SIGP status bits */
#define SIGP_STAT_EQUIPMENT_CHECK 0x80000000UL
#define SIGP_STAT_INCORRECT_STATE 0x00000200UL
#define SIGP_STAT_INVALID_PARAMETER 0x00000100UL
@@ -889,6 +906,11 @@ struct sysib_322 {
#define SIGP_STAT_INVALID_ORDER 0x00000002UL
#define SIGP_STAT_RECEIVER_CHECK 0x00000001UL
+/* SIGP SET ARCHITECTURE modes */
+#define SIGP_MODE_ESA_S390 0
+#define SIGP_MODE_Z_ARCH_TRANS_ALL_PSW 1
+#define SIGP_MODE_Z_ARCH_TRANS_CUR_PSW 2
+
void load_psw(CPUS390XState *env, uint64_t mask, uint64_t addr);
int mmu_translate(CPUS390XState *env, target_ulong vaddr, int rw, uint64_t asc,
target_ulong *raddr, int *flags, bool exc);
@@ -1007,6 +1029,7 @@ int kvm_s390_get_memslot_count(KVMState *s);
void kvm_s390_clear_cmma_callback(void *opaque);
int kvm_s390_set_cpu_state(S390CPU *cpu, uint8_t cpu_state);
void kvm_s390_reset_vcpu(S390CPU *cpu);
+int kvm_s390_set_mem_limit(KVMState *s, uint64_t new_limit, uint64_t *hw_limit);
#else
static inline void kvm_s390_io_interrupt(uint16_t subchannel_id,
uint16_t subchannel_nr,
@@ -1044,8 +1067,21 @@ static inline int kvm_s390_set_cpu_state(S390CPU *cpu, uint8_t cpu_state)
static inline void kvm_s390_reset_vcpu(S390CPU *cpu)
{
}
+static inline int kvm_s390_set_mem_limit(KVMState *s, uint64_t new_limit,
+ uint64_t *hw_limit)
+{
+ return 0;
+}
#endif
+static inline int s390_set_memory_limit(uint64_t new_limit, uint64_t *hw_limit)
+{
+ if (kvm_enabled()) {
+ return kvm_s390_set_mem_limit(kvm_state, new_limit, hw_limit);
+ }
+ return 0;
+}
+
static inline void cmma_reset(S390CPU *cpu)
{
if (kvm_enabled()) {
diff --git a/target-s390x/helper.c b/target-s390x/helper.c
index e0fd8fc37..f1060c2bc 100644
--- a/target-s390x/helper.c
+++ b/target-s390x/helper.c
@@ -183,7 +183,9 @@ void load_psw(CPUS390XState *env, uint64_t mask, uint64_t addr)
{
env->psw.addr = addr;
env->psw.mask = mask;
- env->cc_op = (mask >> 44) & 3;
+ if (tcg_enabled()) {
+ env->cc_op = (mask >> 44) & 3;
+ }
if (mask & PSW_MASK_WAIT) {
S390CPU *cpu = s390_env_get_cpu(env);
@@ -197,14 +199,16 @@ void load_psw(CPUS390XState *env, uint64_t mask, uint64_t addr)
static uint64_t get_psw_mask(CPUS390XState *env)
{
- uint64_t r;
+ uint64_t r = env->psw.mask;
- env->cc_op = calc_cc(env, env->cc_op, env->cc_src, env->cc_dst, env->cc_vr);
+ if (tcg_enabled()) {
+ env->cc_op = calc_cc(env, env->cc_op, env->cc_src, env->cc_dst,
+ env->cc_vr);
- r = env->psw.mask;
- r &= ~PSW_MASK_CC;
- assert(!(env->cc_op & ~3));
- r |= (uint64_t)env->cc_op << 44;
+ r &= ~PSW_MASK_CC;
+ assert(!(env->cc_op & ~3));
+ r |= (uint64_t)env->cc_op << 44;
+ }
return r;
}
@@ -229,6 +233,23 @@ static void cpu_unmap_lowcore(LowCore *lowcore)
cpu_physical_memory_unmap(lowcore, sizeof(LowCore), 1, sizeof(LowCore));
}
+void do_restart_interrupt(CPUS390XState *env)
+{
+ uint64_t mask, addr;
+ LowCore *lowcore;
+
+ lowcore = cpu_map_lowcore(env);
+
+ lowcore->restart_old_psw.mask = cpu_to_be64(get_psw_mask(env));
+ lowcore->restart_old_psw.addr = cpu_to_be64(env->psw.addr);
+ mask = be64_to_cpu(lowcore->restart_new_psw.mask);
+ addr = be64_to_cpu(lowcore->restart_new_psw.addr);
+
+ cpu_unmap_lowcore(lowcore);
+
+ load_psw(env, mask, addr);
+}
+
static void do_svc_interrupt(CPUS390XState *env)
{
uint64_t mask, addr;
diff --git a/target-s390x/kvm.c b/target-s390x/kvm.c
index b1369d584..896534bf9 100644
--- a/target-s390x/kvm.c
+++ b/target-s390x/kvm.c
@@ -38,6 +38,7 @@
#include "qapi/qmp/qjson.h"
#include "monitor/monitor.h"
#include "exec/gdbstub.h"
+#include "exec/address-spaces.h"
#include "trace.h"
#include "qapi-event.h"
#include "hw/s390x/s390-pci-inst.h"
@@ -121,6 +122,51 @@ static int cap_async_pf;
static void *legacy_s390_alloc(size_t size, uint64_t *align);
+static int kvm_s390_supports_mem_limit(KVMState *s)
+{
+ struct kvm_device_attr attr = {
+ .group = KVM_S390_VM_MEM_CTRL,
+ .attr = KVM_S390_VM_MEM_LIMIT_SIZE,
+ };
+
+ return (kvm_vm_ioctl(s, KVM_HAS_DEVICE_ATTR, &attr) == 0);
+}
+
+static int kvm_s390_query_mem_limit(KVMState *s, uint64_t *memory_limit)
+{
+ struct kvm_device_attr attr = {
+ .group = KVM_S390_VM_MEM_CTRL,
+ .attr = KVM_S390_VM_MEM_LIMIT_SIZE,
+ .addr = (uint64_t) memory_limit,
+ };
+
+ return kvm_vm_ioctl(s, KVM_GET_DEVICE_ATTR, &attr);
+}
+
+int kvm_s390_set_mem_limit(KVMState *s, uint64_t new_limit, uint64_t *hw_limit)
+{
+ int rc;
+
+ struct kvm_device_attr attr = {
+ .group = KVM_S390_VM_MEM_CTRL,
+ .attr = KVM_S390_VM_MEM_LIMIT_SIZE,
+ .addr = (uint64_t) &new_limit,
+ };
+
+ if (!kvm_s390_supports_mem_limit(s)) {
+ return 0;
+ }
+
+ rc = kvm_s390_query_mem_limit(s, hw_limit);
+ if (rc) {
+ return rc;
+ } else if (*hw_limit < new_limit) {
+ return -E2BIG;
+ }
+
+ return kvm_vm_ioctl(s, KVM_SET_DEVICE_ATTR, &attr);
+}
+
static int kvm_s390_check_clear_cmma(KVMState *s)
{
struct kvm_device_attr attr = {
@@ -186,6 +232,9 @@ int kvm_arch_init(MachineState *ms, KVMState *s)
|| !kvm_check_extension(s, KVM_CAP_S390_COW)) {
phys_mem_set_alloc(legacy_s390_alloc);
}
+
+ kvm_vm_enable_cap(s, KVM_CAP_S390_USER_SIGP, 0);
+
return 0;
}
@@ -1111,110 +1160,356 @@ static int handle_diag(S390CPU *cpu, struct kvm_run *run, uint32_t ipb)
return r;
}
-static void sigp_cpu_start(void *arg)
+typedef struct SigpInfo {
+ S390CPU *cpu;
+ uint64_t param;
+ int cc;
+ uint64_t *status_reg;
+} SigpInfo;
+
+static void set_sigp_status(SigpInfo *si, uint64_t status)
{
- CPUState *cs = arg;
- S390CPU *cpu = S390_CPU(cs);
+ *si->status_reg &= 0xffffffff00000000ULL;
+ *si->status_reg |= status;
+ si->cc = SIGP_CC_STATUS_STORED;
+}
+
+static void sigp_start(void *arg)
+{
+ SigpInfo *si = arg;
+
+ if (s390_cpu_get_state(si->cpu) != CPU_STATE_STOPPED) {
+ si->cc = SIGP_CC_ORDER_CODE_ACCEPTED;
+ return;
+ }
- s390_cpu_set_state(CPU_STATE_OPERATING, cpu);
- DPRINTF("DONE: KVM cpu start: %p\n", &cpu->env);
+ s390_cpu_set_state(CPU_STATE_OPERATING, si->cpu);
+ si->cc = SIGP_CC_ORDER_CODE_ACCEPTED;
}
-static void sigp_cpu_restart(void *arg)
+static void sigp_stop(void *arg)
{
- CPUState *cs = arg;
- S390CPU *cpu = S390_CPU(cs);
+ SigpInfo *si = arg;
+ struct kvm_s390_irq irq = {
+ .type = KVM_S390_SIGP_STOP,
+ };
+
+ if (s390_cpu_get_state(si->cpu) != CPU_STATE_OPERATING) {
+ si->cc = SIGP_CC_ORDER_CODE_ACCEPTED;
+ return;
+ }
+
+ /* disabled wait - sleeping in user space */
+ if (CPU(si->cpu)->halted) {
+ s390_cpu_set_state(CPU_STATE_STOPPED, si->cpu);
+ } else {
+ /* execute the stop function */
+ si->cpu->env.sigp_order = SIGP_STOP;
+ kvm_s390_vcpu_interrupt(si->cpu, &irq);
+ }
+ si->cc = SIGP_CC_ORDER_CODE_ACCEPTED;
+}
+
+#define KVM_S390_STORE_STATUS_DEF_ADDR offsetof(LowCore, floating_pt_save_area)
+#define SAVE_AREA_SIZE 512
+static int kvm_s390_store_status(S390CPU *cpu, hwaddr addr, bool store_arch)
+{
+ static const uint8_t ar_id = 1;
+ uint64_t ckc = cpu->env.ckc >> 8;
+ void *mem;
+ hwaddr len = SAVE_AREA_SIZE;
+
+ mem = cpu_physical_memory_map(addr, &len, 1);
+ if (!mem) {
+ return -EFAULT;
+ }
+ if (len != SAVE_AREA_SIZE) {
+ cpu_physical_memory_unmap(mem, len, 1, 0);
+ return -EFAULT;
+ }
+
+ if (store_arch) {
+ cpu_physical_memory_write(offsetof(LowCore, ar_access_id), &ar_id, 1);
+ }
+ memcpy(mem, &cpu->env.fregs, 128);
+ memcpy(mem + 128, &cpu->env.regs, 128);
+ memcpy(mem + 256, &cpu->env.psw, 16);
+ memcpy(mem + 280, &cpu->env.psa, 4);
+ memcpy(mem + 284, &cpu->env.fpc, 4);
+ memcpy(mem + 292, &cpu->env.todpr, 4);
+ memcpy(mem + 296, &cpu->env.cputm, 8);
+ memcpy(mem + 304, &ckc, 8);
+ memcpy(mem + 320, &cpu->env.aregs, 64);
+ memcpy(mem + 384, &cpu->env.cregs, 128);
+
+ cpu_physical_memory_unmap(mem, len, 1, len);
+
+ return 0;
+}
+
+static void sigp_stop_and_store_status(void *arg)
+{
+ SigpInfo *si = arg;
+ struct kvm_s390_irq irq = {
+ .type = KVM_S390_SIGP_STOP,
+ };
+
+ /* disabled wait - sleeping in user space */
+ if (s390_cpu_get_state(si->cpu) == CPU_STATE_OPERATING &&
+ CPU(si->cpu)->halted) {
+ s390_cpu_set_state(CPU_STATE_STOPPED, si->cpu);
+ }
+
+ switch (s390_cpu_get_state(si->cpu)) {
+ case CPU_STATE_OPERATING:
+ si->cpu->env.sigp_order = SIGP_STOP_STORE_STATUS;
+ kvm_s390_vcpu_interrupt(si->cpu, &irq);
+ /* store will be performed when handling the stop intercept */
+ break;
+ case CPU_STATE_STOPPED:
+ /* already stopped, just store the status */
+ cpu_synchronize_state(CPU(si->cpu));
+ kvm_s390_store_status(si->cpu, KVM_S390_STORE_STATUS_DEF_ADDR, true);
+ break;
+ }
+ si->cc = SIGP_CC_ORDER_CODE_ACCEPTED;
+}
+
+static void sigp_store_status_at_address(void *arg)
+{
+ SigpInfo *si = arg;
+ uint32_t address = si->param & 0x7ffffe00u;
+
+ /* cpu has to be stopped */
+ if (s390_cpu_get_state(si->cpu) != CPU_STATE_STOPPED) {
+ set_sigp_status(si, SIGP_STAT_INCORRECT_STATE);
+ return;
+ }
+
+ cpu_synchronize_state(CPU(si->cpu));
+
+ if (kvm_s390_store_status(si->cpu, address, false)) {
+ set_sigp_status(si, SIGP_STAT_INVALID_PARAMETER);
+ return;
+ }
+ si->cc = SIGP_CC_ORDER_CODE_ACCEPTED;
+}
+
+static void sigp_restart(void *arg)
+{
+ SigpInfo *si = arg;
struct kvm_s390_irq irq = {
.type = KVM_S390_RESTART,
};
- kvm_s390_vcpu_interrupt(cpu, &irq);
- s390_cpu_set_state(CPU_STATE_OPERATING, cpu);
+ switch (s390_cpu_get_state(si->cpu)) {
+ case CPU_STATE_STOPPED:
+ /* the restart irq has to be delivered prior to any other pending irq */
+ cpu_synchronize_state(CPU(si->cpu));
+ do_restart_interrupt(&si->cpu->env);
+ s390_cpu_set_state(CPU_STATE_OPERATING, si->cpu);
+ break;
+ case CPU_STATE_OPERATING:
+ kvm_s390_vcpu_interrupt(si->cpu, &irq);
+ break;
+ }
+ si->cc = SIGP_CC_ORDER_CODE_ACCEPTED;
}
int kvm_s390_cpu_restart(S390CPU *cpu)
{
- run_on_cpu(CPU(cpu), sigp_cpu_restart, CPU(cpu));
+ SigpInfo si = {
+ .cpu = cpu,
+ };
+
+ run_on_cpu(CPU(cpu), sigp_restart, &si);
DPRINTF("DONE: KVM cpu restart: %p\n", &cpu->env);
return 0;
}
static void sigp_initial_cpu_reset(void *arg)
{
- CPUState *cpu = arg;
- S390CPUClass *scc = S390_CPU_GET_CLASS(cpu);
+ SigpInfo *si = arg;
+ CPUState *cs = CPU(si->cpu);
+ S390CPUClass *scc = S390_CPU_GET_CLASS(si->cpu);
- cpu_synchronize_state(cpu);
- scc->initial_cpu_reset(cpu);
- cpu_synchronize_post_reset(cpu);
+ cpu_synchronize_state(cs);
+ scc->initial_cpu_reset(cs);
+ cpu_synchronize_post_reset(cs);
+ si->cc = SIGP_CC_ORDER_CODE_ACCEPTED;
}
static void sigp_cpu_reset(void *arg)
{
- CPUState *cpu = arg;
- S390CPUClass *scc = S390_CPU_GET_CLASS(cpu);
+ SigpInfo *si = arg;
+ CPUState *cs = CPU(si->cpu);
+ S390CPUClass *scc = S390_CPU_GET_CLASS(si->cpu);
- cpu_synchronize_state(cpu);
- scc->cpu_reset(cpu);
- cpu_synchronize_post_reset(cpu);
+ cpu_synchronize_state(cs);
+ scc->cpu_reset(cs);
+ cpu_synchronize_post_reset(cs);
+ si->cc = SIGP_CC_ORDER_CODE_ACCEPTED;
}
-#define SIGP_ORDER_MASK 0x000000ff
-
-static int handle_sigp(S390CPU *cpu, struct kvm_run *run, uint8_t ipa1)
+static void sigp_set_prefix(void *arg)
{
- CPUS390XState *env = &cpu->env;
- uint8_t order_code;
- uint16_t cpu_addr;
- S390CPU *target_cpu;
- uint64_t *statusreg = &env->regs[ipa1 >> 4];
- int cc;
+ SigpInfo *si = arg;
+ uint32_t addr = si->param & 0x7fffe000u;
- cpu_synchronize_state(CPU(cpu));
+ cpu_synchronize_state(CPU(si->cpu));
- /* get order code */
- order_code = decode_basedisp_rs(env, run->s390_sieic.ipb) & SIGP_ORDER_MASK;
+ if (!address_space_access_valid(&address_space_memory, addr,
+ sizeof(struct LowCore), false)) {
+ set_sigp_status(si, SIGP_STAT_INVALID_PARAMETER);
+ return;
+ }
- cpu_addr = env->regs[ipa1 & 0x0f];
- target_cpu = s390_cpu_addr2state(cpu_addr);
- if (target_cpu == NULL) {
- cc = 3; /* not operational */
- goto out;
+ /* cpu has to be stopped */
+ if (s390_cpu_get_state(si->cpu) != CPU_STATE_STOPPED) {
+ set_sigp_status(si, SIGP_STAT_INCORRECT_STATE);
+ return;
}
- switch (order_code) {
+ si->cpu->env.psa = addr;
+ cpu_synchronize_post_init(CPU(si->cpu));
+ si->cc = SIGP_CC_ORDER_CODE_ACCEPTED;
+}
+
+static int handle_sigp_single_dst(S390CPU *dst_cpu, uint8_t order,
+ uint64_t param, uint64_t *status_reg)
+{
+ SigpInfo si = {
+ .cpu = dst_cpu,
+ .param = param,
+ .status_reg = status_reg,
+ };
+
+ /* cpu available? */
+ if (dst_cpu == NULL) {
+ return SIGP_CC_NOT_OPERATIONAL;
+ }
+
+ /* only resets can break pending orders */
+ if (dst_cpu->env.sigp_order != 0 &&
+ order != SIGP_CPU_RESET &&
+ order != SIGP_INITIAL_CPU_RESET) {
+ return SIGP_CC_BUSY;
+ }
+
+ switch (order) {
case SIGP_START:
- run_on_cpu(CPU(target_cpu), sigp_cpu_start, CPU(target_cpu));
- cc = 0;
+ run_on_cpu(CPU(dst_cpu), sigp_start, &si);
+ break;
+ case SIGP_STOP:
+ run_on_cpu(CPU(dst_cpu), sigp_stop, &si);
break;
case SIGP_RESTART:
- run_on_cpu(CPU(target_cpu), sigp_cpu_restart, CPU(target_cpu));
- cc = 0;
+ run_on_cpu(CPU(dst_cpu), sigp_restart, &si);
break;
- case SIGP_SET_ARCH:
- *statusreg &= 0xffffffff00000000UL;
- *statusreg |= SIGP_STAT_INVALID_PARAMETER;
- cc = 1; /* status stored */
+ case SIGP_STOP_STORE_STATUS:
+ run_on_cpu(CPU(dst_cpu), sigp_stop_and_store_status, &si);
+ break;
+ case SIGP_STORE_STATUS_ADDR:
+ run_on_cpu(CPU(dst_cpu), sigp_store_status_at_address, &si);
+ break;
+ case SIGP_SET_PREFIX:
+ run_on_cpu(CPU(dst_cpu), sigp_set_prefix, &si);
break;
case SIGP_INITIAL_CPU_RESET:
- run_on_cpu(CPU(target_cpu), sigp_initial_cpu_reset, CPU(target_cpu));
- cc = 0;
+ run_on_cpu(CPU(dst_cpu), sigp_initial_cpu_reset, &si);
break;
case SIGP_CPU_RESET:
- run_on_cpu(CPU(target_cpu), sigp_cpu_reset, CPU(target_cpu));
- cc = 0;
+ run_on_cpu(CPU(dst_cpu), sigp_cpu_reset, &si);
break;
default:
- DPRINTF("KVM: unknown SIGP: 0x%x\n", order_code);
- *statusreg &= 0xffffffff00000000UL;
- *statusreg |= SIGP_STAT_INVALID_ORDER;
- cc = 1; /* status stored */
+ DPRINTF("KVM: unknown SIGP: 0x%x\n", order);
+ set_sigp_status(&si, SIGP_STAT_INVALID_ORDER);
+ }
+
+ return si.cc;
+}
+
+static int sigp_set_architecture(S390CPU *cpu, uint32_t param,
+ uint64_t *status_reg)
+{
+ CPUState *cur_cs;
+ S390CPU *cur_cpu;
+
+ /* due to the BQL, we are the only active cpu */
+ CPU_FOREACH(cur_cs) {
+ cur_cpu = S390_CPU(cur_cs);
+ if (cur_cpu->env.sigp_order != 0) {
+ return SIGP_CC_BUSY;
+ }
+ cpu_synchronize_state(cur_cs);
+ /* all but the current one have to be stopped */
+ if (cur_cpu != cpu &&
+ s390_cpu_get_state(cur_cpu) != CPU_STATE_STOPPED) {
+ *status_reg &= 0xffffffff00000000ULL;
+ *status_reg |= SIGP_STAT_INCORRECT_STATE;
+ return SIGP_CC_STATUS_STORED;
+ }
+ }
+
+ switch (param & 0xff) {
+ case SIGP_MODE_ESA_S390:
+ /* not supported */
+ return SIGP_CC_NOT_OPERATIONAL;
+ case SIGP_MODE_Z_ARCH_TRANS_ALL_PSW:
+ case SIGP_MODE_Z_ARCH_TRANS_CUR_PSW:
+ CPU_FOREACH(cur_cs) {
+ cur_cpu = S390_CPU(cur_cs);
+ cur_cpu->env.pfault_token = -1UL;
+ }
break;
+ default:
+ *status_reg &= 0xffffffff00000000ULL;
+ *status_reg |= SIGP_STAT_INVALID_PARAMETER;
+ return SIGP_CC_STATUS_STORED;
}
-out:
- setcc(cpu, cc);
- return 0;
+ return SIGP_CC_ORDER_CODE_ACCEPTED;
+}
+
+#define SIGP_ORDER_MASK 0x000000ff
+
+static int handle_sigp(S390CPU *cpu, struct kvm_run *run, uint8_t ipa1)
+{
+ CPUS390XState *env = &cpu->env;
+ const uint8_t r1 = ipa1 >> 4;
+ const uint8_t r3 = ipa1 & 0x0f;
+ int ret;
+ uint8_t order;
+ uint64_t *status_reg;
+ uint64_t param;
+ S390CPU *dst_cpu = NULL;
+
+ cpu_synchronize_state(CPU(cpu));
+
+ /* get order code */
+ order = decode_basedisp_rs(env, run->s390_sieic.ipb) & SIGP_ORDER_MASK;
+ status_reg = &env->regs[r1];
+ param = (r1 % 2) ? env->regs[r1] : env->regs[r1 + 1];
+
+ switch (order) {
+ case SIGP_SET_ARCH:
+ ret = sigp_set_architecture(cpu, param, status_reg);
+ break;
+ default:
+ /* all other sigp orders target a single vcpu */
+ dst_cpu = s390_cpu_addr2state(env->regs[r3]);
+ ret = handle_sigp_single_dst(dst_cpu, order, param, status_reg);
+ }
+
+ trace_kvm_sigp_finished(order, CPU(cpu)->cpu_index,
+ dst_cpu ? CPU(dst_cpu)->cpu_index : -1, ret);
+
+ if (ret >= 0) {
+ setcc(cpu, ret);
+ return 0;
+ }
+
+ return ret;
}
static int handle_instruction(S390CPU *cpu, struct kvm_run *run)
@@ -1317,6 +1612,11 @@ static int handle_intercept(S390CPU *cpu)
if (s390_cpu_set_state(CPU_STATE_STOPPED, cpu) == 0) {
qemu_system_shutdown_request();
}
+ if (cpu->env.sigp_order == SIGP_STOP_STORE_STATUS) {
+ kvm_s390_store_status(cpu, KVM_S390_STORE_STATUS_DEF_ADDR,
+ true);
+ }
+ cpu->env.sigp_order = 0;
r = EXCP_HALTED;
break;
case ICPT_SOFT_INTERCEPT:
diff --git a/target-s390x/machine.c b/target-s390x/machine.c
index fbcb0d086..bd4cea726 100644
--- a/target-s390x/machine.c
+++ b/target-s390x/machine.c
@@ -36,8 +36,8 @@ static int cpu_post_load(void *opaque, int version_id)
const VMStateDescription vmstate_s390_cpu = {
.name = "cpu",
.post_load = cpu_post_load,
- .version_id = 1,
- .minimum_version_id = 1,
+ .version_id = 2,
+ .minimum_version_id = 2,
.fields = (VMStateField[]) {
VMSTATE_UINT64(env.fregs[0].ll, S390CPU),
VMSTATE_UINT64(env.fregs[1].ll, S390CPU),
@@ -71,6 +71,7 @@ const VMStateDescription vmstate_s390_cpu = {
VMSTATE_UINT32_ARRAY(env.aregs, S390CPU, 16),
VMSTATE_UINT64_ARRAY(env.cregs, S390CPU, 16),
VMSTATE_UINT8(env.cpu_state, S390CPU),
+ VMSTATE_UINT8(env.sigp_order, S390CPU),
VMSTATE_END_OF_LIST()
},
};
diff --git a/target-s390x/misc_helper.c b/target-s390x/misc_helper.c
index 1c3df8e01..e1007fa35 100644
--- a/target-s390x/misc_helper.c
+++ b/target-s390x/misc_helper.c
@@ -456,7 +456,7 @@ uint32_t HELPER(stsi)(CPUS390XState *env, uint64_t a0,
uint32_t HELPER(sigp)(CPUS390XState *env, uint64_t order_code, uint32_t r1,
uint64_t cpu_addr)
{
- int cc = 0;
+ int cc = SIGP_CC_ORDER_CODE_ACCEPTED;
HELPER_LOG("%s: %016" PRIx64 " %08x %016" PRIx64 "\n",
__func__, order_code, r1, cpu_addr);
@@ -490,7 +490,7 @@ uint32_t HELPER(sigp)(CPUS390XState *env, uint64_t order_code, uint32_t r1,
default:
/* unknown sigp */
fprintf(stderr, "XXX unknown sigp: 0x%" PRIx64 "\n", order_code);
- cc = 3;
+ cc = SIGP_CC_NOT_OPERATIONAL;
}
return cc;
diff --git a/target-sh4/cpu.h b/target-sh4/cpu.h
index b2fb1990d..c8dea6c02 100644
--- a/target-sh4/cpu.h
+++ b/target-sh4/cpu.h
@@ -221,14 +221,7 @@ int cpu_sh4_is_cached(CPUSH4State * env, target_ulong addr);
void cpu_load_tlb(CPUSH4State * env);
-static inline CPUSH4State *cpu_init(const char *cpu_model)
-{
- SuperHCPU *cpu = cpu_sh4_init(cpu_model);
- if (cpu == NULL) {
- return NULL;
- }
- return &cpu->env;
-}
+#define cpu_init(cpu_model) CPU(cpu_sh4_init(cpu_model))
#define cpu_exec cpu_sh4_exec
#define cpu_gen_code cpu_sh4_gen_code
diff --git a/target-sparc/cpu.h b/target-sparc/cpu.h
index 0a50e5d11..f5c9006b3 100644
--- a/target-sparc/cpu.h
+++ b/target-sparc/cpu.h
@@ -594,14 +594,7 @@ hwaddr cpu_get_phys_page_nofault(CPUSPARCState *env, target_ulong addr,
int cpu_sparc_signal_handler(int host_signum, void *pinfo, void *puc);
#ifndef NO_CPU_IO_DEFS
-static inline CPUSPARCState *cpu_init(const char *cpu_model)
-{
- SPARCCPU *cpu = cpu_sparc_init(cpu_model);
- if (cpu == NULL) {
- return NULL;
- }
- return &cpu->env;
-}
+#define cpu_init(cpu_model) CPU(cpu_sparc_init(cpu_model))
#endif
#define cpu_exec cpu_sparc_exec
diff --git a/target-tricore/cpu.h b/target-tricore/cpu.h
index e5409e45f..b473426ce 100644
--- a/target-tricore/cpu.h
+++ b/target-tricore/cpu.h
@@ -378,15 +378,7 @@ static inline void cpu_get_tb_cpu_state(CPUTriCoreState *env, target_ulong *pc,
TriCoreCPU *cpu_tricore_init(const char *cpu_model);
-static inline CPUTriCoreState *cpu_init(const char *cpu_model)
-{
- TriCoreCPU *cpu = cpu_tricore_init(cpu_model);
- if (cpu == NULL) {
- return NULL;
- }
- return &cpu->env;
-
-}
+#define cpu_init(cpu_model) CPU(cpu_tricore_init(cpu_model))
/* helpers.c */
diff --git a/target-unicore32/cpu.h b/target-unicore32/cpu.h
index 50972f949..14dc8627c 100644
--- a/target-unicore32/cpu.h
+++ b/target-unicore32/cpu.h
@@ -122,11 +122,9 @@ void cpu_asr_write(CPUUniCore32State *env1, target_ulong val, target_ulong mask)
#define UC32_HWCAP_CMOV 4 /* 1 << 2 */
#define UC32_HWCAP_UCF64 8 /* 1 << 3 */
-#define cpu_init uc32_cpu_init
#define cpu_exec uc32_cpu_exec
#define cpu_signal_handler uc32_cpu_signal_handler
-CPUUniCore32State *uc32_cpu_init(const char *cpu_model);
int uc32_cpu_exec(CPUUniCore32State *s);
int uc32_cpu_signal_handler(int host_signum, void *pinfo, void *puc);
@@ -143,6 +141,10 @@ static inline int cpu_mmu_index(CPUUniCore32State *env)
#include "cpu-qom.h"
#include "exec/exec-all.h"
+UniCore32CPU *uc32_cpu_init(const char *cpu_model);
+
+#define cpu_init(cpu_model) CPU(uc32_cpu_init(cpu_model))
+
static inline void cpu_get_tb_cpu_state(CPUUniCore32State *env, target_ulong *pc,
target_ulong *cs_base, int *flags)
{
diff --git a/target-unicore32/helper.c b/target-unicore32/helper.c
index b4654fa98..ae63277c8 100644
--- a/target-unicore32/helper.c
+++ b/target-unicore32/helper.c
@@ -25,15 +25,9 @@
#define DPRINTF(fmt, ...) do {} while (0)
#endif
-CPUUniCore32State *uc32_cpu_init(const char *cpu_model)
+UniCore32CPU *uc32_cpu_init(const char *cpu_model)
{
- UniCore32CPU *cpu;
-
- cpu = UNICORE32_CPU(cpu_generic_init(TYPE_UNICORE32_CPU, cpu_model));
- if (cpu == NULL) {
- return NULL;
- }
- return &cpu->env;
+ return UNICORE32_CPU(cpu_generic_init(TYPE_UNICORE32_CPU, cpu_model));
}
uint32_t HELPER(clo)(uint32_t x)
diff --git a/target-xtensa/cpu.h b/target-xtensa/cpu.h
index 60ee56308..dfd0d1ced 100644
--- a/target-xtensa/cpu.h
+++ b/target-xtensa/cpu.h
@@ -379,14 +379,7 @@ typedef struct CPUXtensaState {
XtensaCPU *cpu_xtensa_init(const char *cpu_model);
-static inline CPUXtensaState *cpu_init(const char *cpu_model)
-{
- XtensaCPU *cpu = cpu_xtensa_init(cpu_model);
- if (cpu == NULL) {
- return NULL;
- }
- return &cpu->env;
-}
+#define cpu_init(cpu_model) CPU(cpu_xtensa_init(cpu_model))
void xtensa_translate_init(void);
void xtensa_breakpoint_handler(CPUState *cs);
diff --git a/tests/Makefile b/tests/Makefile
index 307035c26..588f43888 100644
--- a/tests/Makefile
+++ b/tests/Makefile
@@ -191,6 +191,8 @@ gcov-files-sparc-y += hw/timer/m48t59.c
gcov-files-sparc64-y += hw/timer/m48t59.c
check-qtest-arm-y = tests/tmp105-test$(EXESUF)
gcov-files-arm-y += hw/misc/tmp105.c
+check-qtest-arm-y += tests/virtio-blk-test$(EXESUF)
+gcov-files-arm-y += arm-softmmu/hw/block/virtio-blk.c
check-qtest-ppc-y += tests/boot-order-test$(EXESUF)
check-qtest-ppc64-y += tests/boot-order-test$(EXESUF)
check-qtest-ppc64-y += tests/spapr-phb-test$(EXESUF)
@@ -239,8 +241,6 @@ $(test-obj-y): QEMU_INCLUDES += -Itests
QEMU_CFLAGS += -I$(SRC_PATH)/tests
qom-core-obj = qom/object.o qom/qom-qobject.o qom/container.o
-tests/test-x86-cpuid.o: QEMU_INCLUDES += -I$(SRC_PATH)/target-i386
-
tests/check-qint$(EXESUF): tests/check-qint.o libqemuutil.a
tests/check-qstring$(EXESUF): tests/check-qstring.o libqemuutil.a
tests/check-qdict$(EXESUF): tests/check-qdict.o libqemuutil.a
@@ -315,8 +315,8 @@ libqos-pc-obj-y = $(libqos-obj-y) tests/libqos/pci-pc.o
libqos-pc-obj-y += tests/libqos/malloc-pc.o tests/libqos/libqos-pc.o
libqos-pc-obj-y += tests/libqos/ahci.o
libqos-omap-obj-y = $(libqos-obj-y) tests/libqos/i2c-omap.o
-libqos-virtio-obj-y = $(libqos-obj-y) $(libqos-pc-obj-y) tests/libqos/virtio.o tests/libqos/virtio-pci.o
libqos-usb-obj-y = $(libqos-pc-obj-y) tests/libqos/usb.o
+libqos-virtio-obj-y = $(libqos-pc-obj-y) tests/libqos/virtio.o tests/libqos/virtio-pci.o tests/libqos/virtio-mmio.o tests/libqos/malloc-generic.o
tests/rtc-test$(EXESUF): tests/rtc-test.o
tests/m48t59-test$(EXESUF): tests/m48t59-test.o
diff --git a/tests/ahci-test.c b/tests/ahci-test.c
index 53fd068c8..cf0b98b96 100644
--- a/tests/ahci-test.c
+++ b/tests/ahci-test.c
@@ -107,6 +107,21 @@ static void ahci_shutdown(AHCIQState *ahci)
qtest_shutdown(qs);
}
+/**
+ * Boot and fully enable the HBA device.
+ * @see ahci_boot, ahci_pci_enable and ahci_hba_enable.
+ */
+static AHCIQState *ahci_boot_and_enable(void)
+{
+ AHCIQState *ahci;
+ ahci = ahci_boot();
+
+ ahci_pci_enable(ahci);
+ ahci_hba_enable(ahci);
+
+ return ahci;
+}
+
/*** Specification Adherence Tests ***/
/**
@@ -716,12 +731,12 @@ static void ahci_test_identify(AHCIQState *ahci)
g_assert_cmphex(sect_size, ==, 0x200);
}
-static void ahci_test_dma_rw_simple(AHCIQState *ahci)
+static void ahci_test_io_rw_simple(AHCIQState *ahci, unsigned bufsize,
+ uint8_t read_cmd, uint8_t write_cmd)
{
uint64_t ptr;
uint8_t port;
unsigned i;
- const unsigned bufsize = 4096;
unsigned char *tx = g_malloc(bufsize);
unsigned char *rx = g_malloc0(bufsize);
@@ -736,16 +751,16 @@ static void ahci_test_dma_rw_simple(AHCIQState *ahci)
ptr = ahci_alloc(ahci, bufsize);
g_assert(ptr);
- /* Write some indicative pattern to our 4K buffer. */
+ /* Write some indicative pattern to our buffer. */
for (i = 0; i < bufsize; i++) {
tx[i] = (bufsize - i);
}
memwrite(ptr, tx, bufsize);
/* Write this buffer to disk, then read it back to the DMA buffer. */
- ahci_guest_io(ahci, port, CMD_WRITE_DMA, ptr, bufsize);
+ ahci_guest_io(ahci, port, write_cmd, ptr, bufsize);
qmemset(ptr, 0x00, bufsize);
- ahci_guest_io(ahci, port, CMD_READ_DMA, ptr, bufsize);
+ ahci_guest_io(ahci, port, read_cmd, ptr, bufsize);
/*** Read back the Data ***/
memread(ptr, rx, bufsize);
@@ -831,25 +846,204 @@ static void test_identify(void)
{
AHCIQState *ahci;
- ahci = ahci_boot();
- ahci_pci_enable(ahci);
- ahci_hba_enable(ahci);
+ ahci = ahci_boot_and_enable();
ahci_test_identify(ahci);
ahci_shutdown(ahci);
}
/**
- * Perform a simple DMA R/W test, using a single PRD and non-NCQ commands.
+ * Fragmented DMA test: Perform a standard 4K DMA read/write
+ * test, but make sure the physical regions are fragmented to
+ * be very small, each just 32 bytes, to see how AHCI performs
+ * with chunks defined to be much less than a sector.
*/
-static void test_dma_rw_simple(void)
+static void test_dma_fragmented(void)
{
AHCIQState *ahci;
+ AHCICommand *cmd;
+ uint8_t px;
+ size_t bufsize = 4096;
+ unsigned char *tx = g_malloc(bufsize);
+ unsigned char *rx = g_malloc0(bufsize);
+ unsigned i;
+ uint64_t ptr;
+
+ ahci = ahci_boot_and_enable();
+ px = ahci_port_select(ahci);
+ ahci_port_clear(ahci, px);
+
+ /* create pattern */
+ for (i = 0; i < bufsize; i++) {
+ tx[i] = (bufsize - i);
+ }
+
+ /* Create a DMA buffer in guest memory, and write our pattern to it. */
+ ptr = guest_alloc(ahci->parent->alloc, bufsize);
+ g_assert(ptr);
+ memwrite(ptr, tx, bufsize);
+
+ cmd = ahci_command_create(CMD_WRITE_DMA);
+ ahci_command_adjust(cmd, 0, ptr, bufsize, 32);
+ ahci_command_commit(ahci, cmd, px);
+ ahci_command_issue(ahci, cmd);
+ ahci_command_verify(ahci, cmd);
+ g_free(cmd);
+
+ cmd = ahci_command_create(CMD_READ_DMA);
+ ahci_command_adjust(cmd, 0, ptr, bufsize, 32);
+ ahci_command_commit(ahci, cmd, px);
+ ahci_command_issue(ahci, cmd);
+ ahci_command_verify(ahci, cmd);
+ g_free(cmd);
+
+ /* Read back the guest's receive buffer into local memory */
+ memread(ptr, rx, bufsize);
+ guest_free(ahci->parent->alloc, ptr);
+
+ g_assert_cmphex(memcmp(tx, rx, bufsize), ==, 0);
- ahci = ahci_boot();
- ahci_pci_enable(ahci);
- ahci_hba_enable(ahci);
- ahci_test_dma_rw_simple(ahci);
ahci_shutdown(ahci);
+
+ g_free(rx);
+ g_free(tx);
+}
+
+/******************************************************************************/
+/* AHCI I/O Test Matrix Definitions */
+
+enum BuffLen {
+ LEN_BEGIN = 0,
+ LEN_SIMPLE = LEN_BEGIN,
+ LEN_DOUBLE,
+ LEN_LONG,
+ LEN_SHORT,
+ NUM_LENGTHS
+};
+
+static const char *buff_len_str[NUM_LENGTHS] = { "simple", "double",
+ "long", "short" };
+
+enum AddrMode {
+ ADDR_MODE_BEGIN = 0,
+ ADDR_MODE_LBA28 = ADDR_MODE_BEGIN,
+ ADDR_MODE_LBA48,
+ NUM_ADDR_MODES
+};
+
+static const char *addr_mode_str[NUM_ADDR_MODES] = { "lba28", "lba48" };
+
+enum IOMode {
+ MODE_BEGIN = 0,
+ MODE_PIO = MODE_BEGIN,
+ MODE_DMA,
+ NUM_MODES
+};
+
+static const char *io_mode_str[NUM_MODES] = { "pio", "dma" };
+
+enum IOOps {
+ IO_BEGIN = 0,
+ IO_READ = IO_BEGIN,
+ IO_WRITE,
+ NUM_IO_OPS
+};
+
+typedef struct AHCIIOTestOptions {
+ enum BuffLen length;
+ enum AddrMode address_type;
+ enum IOMode io_type;
+} AHCIIOTestOptions;
+
+/**
+ * Table of possible I/O ATA commands given a set of enumerations.
+ */
+static const uint8_t io_cmds[NUM_MODES][NUM_ADDR_MODES][NUM_IO_OPS] = {
+ [MODE_PIO] = {
+ [ADDR_MODE_LBA28] = {
+ [IO_READ] = CMD_READ_PIO,
+ [IO_WRITE] = CMD_WRITE_PIO },
+ [ADDR_MODE_LBA48] = {
+ [IO_READ] = CMD_READ_PIO_EXT,
+ [IO_WRITE] = CMD_WRITE_PIO_EXT }
+ },
+ [MODE_DMA] = {
+ [ADDR_MODE_LBA28] = {
+ [IO_READ] = CMD_READ_DMA,
+ [IO_WRITE] = CMD_WRITE_DMA },
+ [ADDR_MODE_LBA48] = {
+ [IO_READ] = CMD_READ_DMA_EXT,
+ [IO_WRITE] = CMD_WRITE_DMA_EXT }
+ }
+};
+
+/**
+ * Test a Read/Write pattern using various commands, addressing modes,
+ * transfer modes, and buffer sizes.
+ */
+static void test_io_rw_interface(enum AddrMode lba48, enum IOMode dma,
+ unsigned bufsize)
+{
+ AHCIQState *ahci;
+
+ ahci = ahci_boot_and_enable();
+ ahci_test_io_rw_simple(ahci, bufsize,
+ io_cmds[dma][lba48][IO_READ],
+ io_cmds[dma][lba48][IO_WRITE]);
+ ahci_shutdown(ahci);
+}
+
+/**
+ * Demultiplex the test data and invoke the actual test routine.
+ */
+static void test_io_interface(gconstpointer opaque)
+{
+ AHCIIOTestOptions *opts = (AHCIIOTestOptions *)opaque;
+ unsigned bufsize;
+
+ switch (opts->length) {
+ case LEN_SIMPLE:
+ bufsize = 4096;
+ break;
+ case LEN_DOUBLE:
+ bufsize = 8192;
+ break;
+ case LEN_LONG:
+ bufsize = 4096 * 64;
+ break;
+ case LEN_SHORT:
+ bufsize = 512;
+ break;
+ default:
+ g_assert_not_reached();
+ }
+
+ test_io_rw_interface(opts->address_type, opts->io_type, bufsize);
+ g_free(opts);
+ return;
+}
+
+static void create_ahci_io_test(enum IOMode type, enum AddrMode addr,
+ enum BuffLen len)
+{
+ static const char *arch;
+ char *name;
+ AHCIIOTestOptions *opts = g_malloc(sizeof(AHCIIOTestOptions));
+
+ opts->length = len;
+ opts->address_type = addr;
+ opts->io_type = type;
+
+ if (!arch) {
+ arch = qtest_get_arch();
+ }
+
+ name = g_strdup_printf("/%s/ahci/io/%s/%s/%s", arch,
+ io_mode_str[type],
+ addr_mode_str[addr],
+ buff_len_str[len]);
+
+ g_test_add_data_func(name, opts, test_io_interface);
+ g_free(name);
}
/******************************************************************************/
@@ -860,6 +1054,7 @@ int main(int argc, char **argv)
int fd;
int ret;
int c;
+ int i, j, k;
static struct option long_options[] = {
{"pedantic", no_argument, 0, 'p' },
@@ -907,7 +1102,16 @@ int main(int argc, char **argv)
qtest_add_func("/ahci/hba_spec", test_hba_spec);
qtest_add_func("/ahci/hba_enable", test_hba_enable);
qtest_add_func("/ahci/identify", test_identify);
- qtest_add_func("/ahci/dma/simple", test_dma_rw_simple);
+
+ for (i = MODE_BEGIN; i < NUM_MODES; i++) {
+ for (j = ADDR_MODE_BEGIN; j < NUM_ADDR_MODES; j++) {
+ for (k = LEN_BEGIN; k < NUM_LENGTHS; k++) {
+ create_ahci_io_test(i, j, k);
+ }
+ }
+ }
+
+ qtest_add_func("/ahci/io/dma/lba28/fragmented", test_dma_fragmented);
ret = g_test_run();
diff --git a/tests/ide-test.c b/tests/ide-test.c
index 29f4039bd..b28a3023c 100644
--- a/tests/ide-test.c
+++ b/tests/ide-test.c
@@ -118,7 +118,6 @@ static void ide_test_start(const char *cmdline_fmt, ...)
va_end(ap);
qtest_start(cmdline);
- qtest_irq_intercept_in(global_qtest, "ioapic");
guest_malloc = pc_alloc_init();
g_free(cmdline);
@@ -388,6 +387,7 @@ static void test_bmdma_setup(void)
"-drive file=%s,if=ide,serial=%s,cache=writeback,format=raw "
"-global ide-hd.ver=%s",
tmp_path, "testdisk", "version");
+ qtest_irq_intercept_in(global_qtest, "ioapic");
}
static void test_bmdma_teardown(void)
@@ -516,7 +516,7 @@ static void prepare_blkdebug_script(const char *debug_fn, const char *event)
g_assert(ret == 0);
}
-static void test_retry_flush(void)
+static void test_retry_flush(const char *machine)
{
uint8_t data;
const char *s;
@@ -580,6 +580,16 @@ static void test_flush_nodev(void)
ide_test_quit();
}
+static void test_pci_retry_flush(const char *machine)
+{
+ test_retry_flush("pc");
+}
+
+static void test_isa_retry_flush(const char *machine)
+{
+ test_retry_flush("isapc");
+}
+
int main(int argc, char **argv)
{
const char *arch = qtest_get_arch();
@@ -617,9 +627,9 @@ 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);
+ qtest_add_func("/ide/flush/nodev", test_flush_nodev);
+ qtest_add_func("/ide/flush/retry_pci", test_pci_retry_flush);
+ qtest_add_func("/ide/flush/retry_isa", test_isa_retry_flush);
ret = g_test_run();
diff --git a/tests/libqos/ahci.c b/tests/libqos/ahci.c
index a6105c750..b0f39a5e3 100644
--- a/tests/libqos/ahci.c
+++ b/tests/libqos/ahci.c
@@ -487,7 +487,7 @@ void ahci_get_command_header(AHCIQState *ahci, uint8_t port,
void ahci_set_command_header(AHCIQState *ahci, uint8_t port,
uint8_t slot, AHCICommandHeader *cmd)
{
- AHCICommandHeader tmp;
+ AHCICommandHeader tmp = { .flags = 0 };
uint64_t ba = ahci->port[port].clb;
ba += slot * sizeof(AHCICommandHeader);
@@ -713,6 +713,40 @@ void ahci_command_free(AHCICommand *cmd)
g_free(cmd);
}
+void ahci_command_set_flags(AHCICommand *cmd, uint16_t cmdh_flags)
+{
+ cmd->header.flags |= cmdh_flags;
+}
+
+void ahci_command_clr_flags(AHCICommand *cmd, uint16_t cmdh_flags)
+{
+ cmd->header.flags &= ~cmdh_flags;
+}
+
+void ahci_command_set_offset(AHCICommand *cmd, uint64_t lba_sect)
+{
+ RegH2DFIS *fis = &(cmd->fis);
+ if (cmd->props->lba28) {
+ g_assert_cmphex(lba_sect, <=, 0xFFFFFFF);
+ } else if (cmd->props->lba48) {
+ g_assert_cmphex(lba_sect, <=, 0xFFFFFFFFFFFF);
+ } else {
+ /* Can't set offset if we don't know the format. */
+ g_assert_not_reached();
+ }
+
+ /* LBA28 uses the low nibble of the device/control register for LBA24:27 */
+ fis->lba_lo[0] = (lba_sect & 0xFF);
+ fis->lba_lo[1] = (lba_sect >> 8) & 0xFF;
+ fis->lba_lo[2] = (lba_sect >> 16) & 0xFF;
+ if (cmd->props->lba28) {
+ fis->device = (fis->device & 0xF0) || (lba_sect >> 24) & 0x0F;
+ }
+ fis->lba_hi[0] = (lba_sect >> 24) & 0xFF;
+ fis->lba_hi[1] = (lba_sect >> 32) & 0xFF;
+ fis->lba_hi[2] = (lba_sect >> 40) & 0xFF;
+}
+
void ahci_command_set_buffer(AHCICommand *cmd, uint64_t buffer)
{
cmd->buffer = buffer;
@@ -740,6 +774,14 @@ void ahci_command_set_prd_size(AHCICommand *cmd, unsigned prd_size)
ahci_command_set_sizes(cmd, cmd->xbytes, prd_size);
}
+void ahci_command_adjust(AHCICommand *cmd, uint64_t offset, uint64_t buffer,
+ uint64_t xbytes, unsigned prd_size)
+{
+ ahci_command_set_sizes(cmd, xbytes, prd_size);
+ ahci_command_set_buffer(cmd, buffer);
+ ahci_command_set_offset(cmd, offset);
+}
+
void ahci_command_commit(AHCIQState *ahci, AHCICommand *cmd, uint8_t port)
{
uint16_t i, prdtl;
diff --git a/tests/libqos/ahci.h b/tests/libqos/ahci.h
index 39b99d365..888545d5a 100644
--- a/tests/libqos/ahci.h
+++ b/tests/libqos/ahci.h
@@ -537,11 +537,16 @@ void ahci_command_verify(AHCIQState *ahci, AHCICommand *cmd);
void ahci_command_free(AHCICommand *cmd);
/* Command adjustments */
+void ahci_command_set_flags(AHCICommand *cmd, uint16_t cmdh_flags);
+void ahci_command_clr_flags(AHCICommand *cmd, uint16_t cmdh_flags);
+void ahci_command_set_offset(AHCICommand *cmd, uint64_t lba_sect);
void ahci_command_set_buffer(AHCICommand *cmd, uint64_t buffer);
void ahci_command_set_size(AHCICommand *cmd, uint64_t xbytes);
void ahci_command_set_prd_size(AHCICommand *cmd, unsigned prd_size);
void ahci_command_set_sizes(AHCICommand *cmd, uint64_t xbytes,
unsigned prd_size);
+void ahci_command_adjust(AHCICommand *cmd, uint64_t lba_sect, uint64_t gbuffer,
+ uint64_t xbytes, unsigned prd_size);
/* Command Misc */
uint8_t ahci_command_slot(AHCICommand *cmd);
diff --git a/tests/libqos/malloc-generic.c b/tests/libqos/malloc-generic.c
new file mode 100644
index 000000000..d30a2f424
--- /dev/null
+++ b/tests/libqos/malloc-generic.c
@@ -0,0 +1,39 @@
+/*
+ * Basic libqos generic malloc support
+ *
+ * Copyright (c) 2014 Marc Marí
+ *
+ * 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 "libqos/malloc-generic.h"
+#include "libqos/malloc.h"
+
+/*
+ * Mostly for valgrind happiness, but it does offer
+ * a chokepoint for debugging guest memory leaks, too.
+ */
+void generic_alloc_uninit(QGuestAllocator *allocator)
+{
+ alloc_uninit(allocator);
+}
+
+QGuestAllocator *generic_alloc_init_flags(uint64_t base_addr, uint64_t size,
+ uint32_t page_size, QAllocOpts flags)
+{
+ QGuestAllocator *s;
+ uint64_t start = base_addr + (1 << 20); /* Start at 1MB */
+
+ s = alloc_init_flags(flags, start, start + size);
+ alloc_set_page_size(s, page_size);
+
+ return s;
+}
+
+inline QGuestAllocator *generic_alloc_init(uint64_t base_addr, uint64_t size,
+ uint32_t page_size)
+{
+ return generic_alloc_init_flags(base_addr, size, page_size, ALLOC_NO_FLAGS);
+}
diff --git a/tests/libqos/malloc-generic.h b/tests/libqos/malloc-generic.h
new file mode 100644
index 000000000..90104ecec
--- /dev/null
+++ b/tests/libqos/malloc-generic.h
@@ -0,0 +1,21 @@
+/*
+ * Basic libqos generic malloc support
+ *
+ * Copyright (c) 2014 Marc Marí
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#ifndef LIBQOS_MALLOC_GENERIC_H
+#define LIBQOS_MALLOC_GENERIC_H
+
+#include "libqos/malloc.h"
+
+QGuestAllocator *generic_alloc_init(uint64_t base_addr, uint64_t size,
+ uint32_t page_size);
+QGuestAllocator *generic_alloc_init_flags(uint64_t base_addr, uint64_t size,
+ uint32_t page_size, QAllocOpts flags);
+void generic_alloc_uninit(QGuestAllocator *allocator);
+
+#endif
diff --git a/tests/libqos/virtio-mmio.c b/tests/libqos/virtio-mmio.c
new file mode 100644
index 000000000..b3e62e77d
--- /dev/null
+++ b/tests/libqos/virtio-mmio.c
@@ -0,0 +1,198 @@
+/*
+ * libqos virtio MMIO driver
+ *
+ * Copyright (c) 2014 Marc Marí
+ *
+ * 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 <stdio.h>
+#include "libqtest.h"
+#include "libqos/virtio.h"
+#include "libqos/virtio-mmio.h"
+#include "libqos/malloc.h"
+#include "libqos/malloc-generic.h"
+
+static uint8_t qvirtio_mmio_config_readb(QVirtioDevice *d, uint64_t addr)
+{
+ QVirtioMMIODevice *dev = (QVirtioMMIODevice *)d;
+ return readb(dev->addr + addr);
+}
+
+static uint16_t qvirtio_mmio_config_readw(QVirtioDevice *d, uint64_t addr)
+{
+ QVirtioMMIODevice *dev = (QVirtioMMIODevice *)d;
+ return readw(dev->addr + addr);
+}
+
+static uint32_t qvirtio_mmio_config_readl(QVirtioDevice *d, uint64_t addr)
+{
+ QVirtioMMIODevice *dev = (QVirtioMMIODevice *)d;
+ return readl(dev->addr + addr);
+}
+
+static uint64_t qvirtio_mmio_config_readq(QVirtioDevice *d, uint64_t addr)
+{
+ QVirtioMMIODevice *dev = (QVirtioMMIODevice *)d;
+ return readq(dev->addr + addr);
+}
+
+static uint32_t qvirtio_mmio_get_features(QVirtioDevice *d)
+{
+ QVirtioMMIODevice *dev = (QVirtioMMIODevice *)d;
+ writel(dev->addr + QVIRTIO_MMIO_HOST_FEATURES_SEL, 0);
+ return readl(dev->addr + QVIRTIO_MMIO_HOST_FEATURES);
+}
+
+static void qvirtio_mmio_set_features(QVirtioDevice *d, uint32_t features)
+{
+ QVirtioMMIODevice *dev = (QVirtioMMIODevice *)d;
+ dev->features = features;
+ writel(dev->addr + QVIRTIO_MMIO_GUEST_FEATURES_SEL, 0);
+ writel(dev->addr + QVIRTIO_MMIO_GUEST_FEATURES, features);
+}
+
+static uint32_t qvirtio_mmio_get_guest_features(QVirtioDevice *d)
+{
+ QVirtioMMIODevice *dev = (QVirtioMMIODevice *)d;
+ return dev->features;
+}
+
+static uint8_t qvirtio_mmio_get_status(QVirtioDevice *d)
+{
+ QVirtioMMIODevice *dev = (QVirtioMMIODevice *)d;
+ return (uint8_t)readl(dev->addr + QVIRTIO_MMIO_DEVICE_STATUS);
+}
+
+static void qvirtio_mmio_set_status(QVirtioDevice *d, uint8_t status)
+{
+ QVirtioMMIODevice *dev = (QVirtioMMIODevice *)d;
+ writel(dev->addr + QVIRTIO_MMIO_DEVICE_STATUS, (uint32_t)status);
+}
+
+static bool qvirtio_mmio_get_queue_isr_status(QVirtioDevice *d, QVirtQueue *vq)
+{
+ QVirtioMMIODevice *dev = (QVirtioMMIODevice *)d;
+ uint32_t isr;
+
+ isr = readl(dev->addr + QVIRTIO_MMIO_INTERRUPT_STATUS) & 1;
+ if (isr != 0) {
+ writel(dev->addr + QVIRTIO_MMIO_INTERRUPT_ACK, 1);
+ return true;
+ }
+
+ return false;
+}
+
+static bool qvirtio_mmio_get_config_isr_status(QVirtioDevice *d)
+{
+ QVirtioMMIODevice *dev = (QVirtioMMIODevice *)d;
+ uint32_t isr;
+
+ isr = readl(dev->addr + QVIRTIO_MMIO_INTERRUPT_STATUS) & 2;
+ if (isr != 0) {
+ writel(dev->addr + QVIRTIO_MMIO_INTERRUPT_ACK, 2);
+ return true;
+ }
+
+ return false;
+}
+
+static void qvirtio_mmio_queue_select(QVirtioDevice *d, uint16_t index)
+{
+ QVirtioMMIODevice *dev = (QVirtioMMIODevice *)d;
+ writel(dev->addr + QVIRTIO_MMIO_QUEUE_SEL, (uint32_t)index);
+
+ g_assert_cmphex(readl(dev->addr + QVIRTIO_MMIO_QUEUE_PFN), ==, 0);
+}
+
+static uint16_t qvirtio_mmio_get_queue_size(QVirtioDevice *d)
+{
+ QVirtioMMIODevice *dev = (QVirtioMMIODevice *)d;
+ return (uint16_t)readl(dev->addr + QVIRTIO_MMIO_QUEUE_NUM_MAX);
+}
+
+static void qvirtio_mmio_set_queue_address(QVirtioDevice *d, uint32_t pfn)
+{
+ QVirtioMMIODevice *dev = (QVirtioMMIODevice *)d;
+ writel(dev->addr + QVIRTIO_MMIO_QUEUE_PFN, pfn);
+}
+
+static QVirtQueue *qvirtio_mmio_virtqueue_setup(QVirtioDevice *d,
+ QGuestAllocator *alloc, uint16_t index)
+{
+ QVirtioMMIODevice *dev = (QVirtioMMIODevice *)d;
+ QVirtQueue *vq;
+ uint64_t addr;
+
+ vq = g_malloc0(sizeof(*vq));
+ qvirtio_mmio_queue_select(d, index);
+ writel(dev->addr + QVIRTIO_MMIO_QUEUE_ALIGN, dev->page_size);
+
+ vq->index = index;
+ vq->size = qvirtio_mmio_get_queue_size(d);
+ vq->free_head = 0;
+ vq->num_free = vq->size;
+ vq->align = dev->page_size;
+ vq->indirect = (dev->features & QVIRTIO_F_RING_INDIRECT_DESC) != 0;
+ vq->event = (dev->features & QVIRTIO_F_RING_EVENT_IDX) != 0;
+
+ writel(dev->addr + QVIRTIO_MMIO_QUEUE_NUM, vq->size);
+
+ /* Check different than 0 */
+ g_assert_cmpint(vq->size, !=, 0);
+
+ /* Check power of 2 */
+ g_assert_cmpint(vq->size & (vq->size - 1), ==, 0);
+
+ addr = guest_alloc(alloc, qvring_size(vq->size, dev->page_size));
+ qvring_init(alloc, vq, addr);
+ qvirtio_mmio_set_queue_address(d, vq->desc / dev->page_size);
+
+ return vq;
+}
+
+static void qvirtio_mmio_virtqueue_kick(QVirtioDevice *d, QVirtQueue *vq)
+{
+ QVirtioMMIODevice *dev = (QVirtioMMIODevice *)d;
+ writel(dev->addr + QVIRTIO_MMIO_QUEUE_NOTIFY, vq->index);
+}
+
+const QVirtioBus qvirtio_mmio = {
+ .config_readb = qvirtio_mmio_config_readb,
+ .config_readw = qvirtio_mmio_config_readw,
+ .config_readl = qvirtio_mmio_config_readl,
+ .config_readq = qvirtio_mmio_config_readq,
+ .get_features = qvirtio_mmio_get_features,
+ .set_features = qvirtio_mmio_set_features,
+ .get_guest_features = qvirtio_mmio_get_guest_features,
+ .get_status = qvirtio_mmio_get_status,
+ .set_status = qvirtio_mmio_set_status,
+ .get_queue_isr_status = qvirtio_mmio_get_queue_isr_status,
+ .get_config_isr_status = qvirtio_mmio_get_config_isr_status,
+ .queue_select = qvirtio_mmio_queue_select,
+ .get_queue_size = qvirtio_mmio_get_queue_size,
+ .set_queue_address = qvirtio_mmio_set_queue_address,
+ .virtqueue_setup = qvirtio_mmio_virtqueue_setup,
+ .virtqueue_kick = qvirtio_mmio_virtqueue_kick,
+};
+
+QVirtioMMIODevice *qvirtio_mmio_init_device(uint64_t addr, uint32_t page_size)
+{
+ QVirtioMMIODevice *dev;
+ uint32_t magic;
+ dev = g_malloc0(sizeof(*dev));
+
+ magic = readl(addr + QVIRTIO_MMIO_MAGIC_VALUE);
+ g_assert(magic == ('v' | 'i' << 8 | 'r' << 16 | 't' << 24));
+
+ dev->addr = addr;
+ dev->page_size = page_size;
+ dev->vdev.device_type = readl(addr + QVIRTIO_MMIO_DEVICE_ID);
+
+ writel(addr + QVIRTIO_MMIO_GUEST_PAGE_SIZE, page_size);
+
+ return dev;
+}
diff --git a/tests/libqos/virtio-mmio.h b/tests/libqos/virtio-mmio.h
new file mode 100644
index 000000000..e3e52b9ce
--- /dev/null
+++ b/tests/libqos/virtio-mmio.h
@@ -0,0 +1,46 @@
+/*
+ * libqos virtio MMIO definitions
+ *
+ * Copyright (c) 2014 Marc Marí
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#ifndef LIBQOS_VIRTIO_MMIO_H
+#define LIBQOS_VIRTIO_MMIO_H
+
+#include "libqos/virtio.h"
+
+#define QVIRTIO_MMIO_MAGIC_VALUE 0x000
+#define QVIRTIO_MMIO_VERSION 0x004
+#define QVIRTIO_MMIO_DEVICE_ID 0x008
+#define QVIRTIO_MMIO_VENDOR_ID 0x00C
+#define QVIRTIO_MMIO_HOST_FEATURES 0x010
+#define QVIRTIO_MMIO_HOST_FEATURES_SEL 0x014
+#define QVIRTIO_MMIO_GUEST_FEATURES 0x020
+#define QVIRTIO_MMIO_GUEST_FEATURES_SEL 0x024
+#define QVIRTIO_MMIO_GUEST_PAGE_SIZE 0x028
+#define QVIRTIO_MMIO_QUEUE_SEL 0x030
+#define QVIRTIO_MMIO_QUEUE_NUM_MAX 0x034
+#define QVIRTIO_MMIO_QUEUE_NUM 0x038
+#define QVIRTIO_MMIO_QUEUE_ALIGN 0x03C
+#define QVIRTIO_MMIO_QUEUE_PFN 0x040
+#define QVIRTIO_MMIO_QUEUE_NOTIFY 0x050
+#define QVIRTIO_MMIO_INTERRUPT_STATUS 0x060
+#define QVIRTIO_MMIO_INTERRUPT_ACK 0x064
+#define QVIRTIO_MMIO_DEVICE_STATUS 0x070
+#define QVIRTIO_MMIO_DEVICE_SPECIFIC 0x100
+
+typedef struct QVirtioMMIODevice {
+ QVirtioDevice vdev;
+ uint64_t addr;
+ uint32_t page_size;
+ uint32_t features; /* As it cannot be read later, save it */
+} QVirtioMMIODevice;
+
+extern const QVirtioBus qvirtio_mmio;
+
+QVirtioMMIODevice *qvirtio_mmio_init_device(uint64_t addr, uint32_t page_size);
+
+#endif
diff --git a/tests/libqos/virtio-pci.c b/tests/libqos/virtio-pci.c
index 788ebaff4..f9fb924b8 100644
--- a/tests/libqos/virtio-pci.c
+++ b/tests/libqos/virtio-pci.c
@@ -60,25 +60,25 @@ static void qvirtio_pci_assign_device(QVirtioDevice *d, void *data)
*vpcidev = (QVirtioPCIDevice *)d;
}
-static uint8_t qvirtio_pci_config_readb(QVirtioDevice *d, void *addr)
+static uint8_t qvirtio_pci_config_readb(QVirtioDevice *d, uint64_t addr)
{
QVirtioPCIDevice *dev = (QVirtioPCIDevice *)d;
- return qpci_io_readb(dev->pdev, addr);
+ return qpci_io_readb(dev->pdev, (void *)(uintptr_t)addr);
}
-static uint16_t qvirtio_pci_config_readw(QVirtioDevice *d, void *addr)
+static uint16_t qvirtio_pci_config_readw(QVirtioDevice *d, uint64_t addr)
{
QVirtioPCIDevice *dev = (QVirtioPCIDevice *)d;
- return qpci_io_readw(dev->pdev, addr);
+ return qpci_io_readw(dev->pdev, (void *)(uintptr_t)addr);
}
-static uint32_t qvirtio_pci_config_readl(QVirtioDevice *d, void *addr)
+static uint32_t qvirtio_pci_config_readl(QVirtioDevice *d, uint64_t addr)
{
QVirtioPCIDevice *dev = (QVirtioPCIDevice *)d;
- return qpci_io_readl(dev->pdev, addr);
+ return qpci_io_readl(dev->pdev, (void *)(uintptr_t)addr);
}
-static uint64_t qvirtio_pci_config_readq(QVirtioDevice *d, void *addr)
+static uint64_t qvirtio_pci_config_readq(QVirtioDevice *d, uint64_t addr)
{
QVirtioPCIDevice *dev = (QVirtioPCIDevice *)d;
int i;
@@ -86,11 +86,13 @@ static uint64_t qvirtio_pci_config_readq(QVirtioDevice *d, void *addr)
if (qtest_big_endian()) {
for (i = 0; i < 8; ++i) {
- u64 |= (uint64_t)qpci_io_readb(dev->pdev, addr + i) << (7 - i) * 8;
+ u64 |= (uint64_t)qpci_io_readb(dev->pdev,
+ (void *)(uintptr_t)addr + i) << (7 - i) * 8;
}
} else {
for (i = 0; i < 8; ++i) {
- u64 |= (uint64_t)qpci_io_readb(dev->pdev, addr + i) << i * 8;
+ u64 |= (uint64_t)qpci_io_readb(dev->pdev,
+ (void *)(uintptr_t)addr + i) << i * 8;
}
}
@@ -100,31 +102,31 @@ static uint64_t qvirtio_pci_config_readq(QVirtioDevice *d, void *addr)
static uint32_t qvirtio_pci_get_features(QVirtioDevice *d)
{
QVirtioPCIDevice *dev = (QVirtioPCIDevice *)d;
- return qpci_io_readl(dev->pdev, dev->addr + QVIRTIO_DEVICE_FEATURES);
+ return qpci_io_readl(dev->pdev, dev->addr + QVIRTIO_PCI_DEVICE_FEATURES);
}
static void qvirtio_pci_set_features(QVirtioDevice *d, uint32_t features)
{
QVirtioPCIDevice *dev = (QVirtioPCIDevice *)d;
- qpci_io_writel(dev->pdev, dev->addr + QVIRTIO_GUEST_FEATURES, features);
+ qpci_io_writel(dev->pdev, dev->addr + QVIRTIO_PCI_GUEST_FEATURES, features);
}
static uint32_t qvirtio_pci_get_guest_features(QVirtioDevice *d)
{
QVirtioPCIDevice *dev = (QVirtioPCIDevice *)d;
- return qpci_io_readl(dev->pdev, dev->addr + QVIRTIO_GUEST_FEATURES);
+ return qpci_io_readl(dev->pdev, dev->addr + QVIRTIO_PCI_GUEST_FEATURES);
}
static uint8_t qvirtio_pci_get_status(QVirtioDevice *d)
{
QVirtioPCIDevice *dev = (QVirtioPCIDevice *)d;
- return qpci_io_readb(dev->pdev, dev->addr + QVIRTIO_DEVICE_STATUS);
+ return qpci_io_readb(dev->pdev, dev->addr + QVIRTIO_PCI_DEVICE_STATUS);
}
static void qvirtio_pci_set_status(QVirtioDevice *d, uint8_t status)
{
QVirtioPCIDevice *dev = (QVirtioPCIDevice *)d;
- qpci_io_writeb(dev->pdev, dev->addr + QVIRTIO_DEVICE_STATUS, status);
+ qpci_io_writeb(dev->pdev, dev->addr + QVIRTIO_PCI_DEVICE_STATUS, status);
}
static bool qvirtio_pci_get_queue_isr_status(QVirtioDevice *d, QVirtQueue *vq)
@@ -140,11 +142,15 @@ static bool qvirtio_pci_get_queue_isr_status(QVirtioDevice *d, QVirtQueue *vq)
return qpci_msix_pending(dev->pdev, vqpci->msix_entry);
} else {
data = readl(vqpci->msix_addr);
- writel(vqpci->msix_addr, 0);
- return data == vqpci->msix_data;
+ if (data == vqpci->msix_data) {
+ writel(vqpci->msix_addr, 0);
+ return true;
+ } else {
+ return false;
+ }
}
} else {
- return qpci_io_readb(dev->pdev, dev->addr + QVIRTIO_ISR_STATUS) & 1;
+ return qpci_io_readb(dev->pdev, dev->addr + QVIRTIO_PCI_ISR_STATUS) & 1;
}
}
@@ -160,30 +166,34 @@ static bool qvirtio_pci_get_config_isr_status(QVirtioDevice *d)
return qpci_msix_pending(dev->pdev, dev->config_msix_entry);
} else {
data = readl(dev->config_msix_addr);
- writel(dev->config_msix_addr, 0);
- return data == dev->config_msix_data;
+ if (data == dev->config_msix_data) {
+ writel(dev->config_msix_addr, 0);
+ return true;
+ } else {
+ return false;
+ }
}
} else {
- return qpci_io_readb(dev->pdev, dev->addr + QVIRTIO_ISR_STATUS) & 2;
+ return qpci_io_readb(dev->pdev, dev->addr + QVIRTIO_PCI_ISR_STATUS) & 2;
}
}
static void qvirtio_pci_queue_select(QVirtioDevice *d, uint16_t index)
{
QVirtioPCIDevice *dev = (QVirtioPCIDevice *)d;
- qpci_io_writeb(dev->pdev, dev->addr + QVIRTIO_QUEUE_SELECT, index);
+ qpci_io_writeb(dev->pdev, dev->addr + QVIRTIO_PCI_QUEUE_SELECT, index);
}
static uint16_t qvirtio_pci_get_queue_size(QVirtioDevice *d)
{
QVirtioPCIDevice *dev = (QVirtioPCIDevice *)d;
- return qpci_io_readw(dev->pdev, dev->addr + QVIRTIO_QUEUE_SIZE);
+ return qpci_io_readw(dev->pdev, dev->addr + QVIRTIO_PCI_QUEUE_SIZE);
}
static void qvirtio_pci_set_queue_address(QVirtioDevice *d, uint32_t pfn)
{
QVirtioPCIDevice *dev = (QVirtioPCIDevice *)d;
- qpci_io_writel(dev->pdev, dev->addr + QVIRTIO_QUEUE_ADDRESS, pfn);
+ qpci_io_writel(dev->pdev, dev->addr + QVIRTIO_PCI_QUEUE_ADDRESS, pfn);
}
static QVirtQueue *qvirtio_pci_virtqueue_setup(QVirtioDevice *d,
@@ -225,7 +235,7 @@ static QVirtQueue *qvirtio_pci_virtqueue_setup(QVirtioDevice *d,
static void qvirtio_pci_virtqueue_kick(QVirtioDevice *d, QVirtQueue *vq)
{
QVirtioPCIDevice *dev = (QVirtioPCIDevice *)d;
- qpci_io_writew(dev->pdev, dev->addr + QVIRTIO_QUEUE_NOTIFY, vq->index);
+ qpci_io_writew(dev->pdev, dev->addr + QVIRTIO_PCI_QUEUE_NOTIFY, vq->index);
}
const QVirtioBus qvirtio_pci = {
@@ -305,8 +315,8 @@ void qvirtqueue_pci_msix_setup(QVirtioPCIDevice *d, QVirtQueuePCI *vqpci,
control & ~PCI_MSIX_ENTRY_CTRL_MASKBIT);
qvirtio_pci_queue_select(&d->vdev, vqpci->vq.index);
- qpci_io_writew(d->pdev, d->addr + QVIRTIO_MSIX_QUEUE_VECTOR, entry);
- vector = qpci_io_readw(d->pdev, d->addr + QVIRTIO_MSIX_QUEUE_VECTOR);
+ qpci_io_writew(d->pdev, d->addr + QVIRTIO_PCI_MSIX_QUEUE_VECTOR, entry);
+ vector = qpci_io_readw(d->pdev, d->addr + QVIRTIO_PCI_MSIX_QUEUE_VECTOR);
g_assert_cmphex(vector, !=, QVIRTIO_MSI_NO_VECTOR);
}
@@ -337,7 +347,7 @@ void qvirtio_pci_set_msix_configuration_vector(QVirtioPCIDevice *d,
qpci_io_writel(d->pdev, addr + PCI_MSIX_ENTRY_VECTOR_CTRL,
control & ~PCI_MSIX_ENTRY_CTRL_MASKBIT);
- qpci_io_writew(d->pdev, d->addr + QVIRTIO_MSIX_CONF_VECTOR, entry);
- vector = qpci_io_readw(d->pdev, d->addr + QVIRTIO_MSIX_CONF_VECTOR);
+ qpci_io_writew(d->pdev, d->addr + QVIRTIO_PCI_MSIX_CONF_VECTOR, entry);
+ vector = qpci_io_readw(d->pdev, d->addr + QVIRTIO_PCI_MSIX_CONF_VECTOR);
g_assert_cmphex(vector, !=, QVIRTIO_MSI_NO_VECTOR);
}
diff --git a/tests/libqos/virtio-pci.h b/tests/libqos/virtio-pci.h
index 883f7ff26..8f0e52ad4 100644
--- a/tests/libqos/virtio-pci.h
+++ b/tests/libqos/virtio-pci.h
@@ -13,18 +13,18 @@
#include "libqos/virtio.h"
#include "libqos/pci.h"
-#define QVIRTIO_DEVICE_FEATURES 0x00
-#define QVIRTIO_GUEST_FEATURES 0x04
-#define QVIRTIO_QUEUE_ADDRESS 0x08
-#define QVIRTIO_QUEUE_SIZE 0x0C
-#define QVIRTIO_QUEUE_SELECT 0x0E
-#define QVIRTIO_QUEUE_NOTIFY 0x10
-#define QVIRTIO_DEVICE_STATUS 0x12
-#define QVIRTIO_ISR_STATUS 0x13
-#define QVIRTIO_MSIX_CONF_VECTOR 0x14
-#define QVIRTIO_MSIX_QUEUE_VECTOR 0x16
-#define QVIRTIO_DEVICE_SPECIFIC_MSIX 0x18
-#define QVIRTIO_DEVICE_SPECIFIC_NO_MSIX 0x14
+#define QVIRTIO_PCI_DEVICE_FEATURES 0x00
+#define QVIRTIO_PCI_GUEST_FEATURES 0x04
+#define QVIRTIO_PCI_QUEUE_ADDRESS 0x08
+#define QVIRTIO_PCI_QUEUE_SIZE 0x0C
+#define QVIRTIO_PCI_QUEUE_SELECT 0x0E
+#define QVIRTIO_PCI_QUEUE_NOTIFY 0x10
+#define QVIRTIO_PCI_DEVICE_STATUS 0x12
+#define QVIRTIO_PCI_ISR_STATUS 0x13
+#define QVIRTIO_PCI_MSIX_CONF_VECTOR 0x14
+#define QVIRTIO_PCI_MSIX_QUEUE_VECTOR 0x16
+#define QVIRTIO_PCI_DEVICE_SPECIFIC_MSIX 0x18
+#define QVIRTIO_PCI_DEVICE_SPECIFIC_NO_MSIX 0x14
#define QVIRTIO_PCI_ALIGN 4096
diff --git a/tests/libqos/virtio.c b/tests/libqos/virtio.c
index a06128924..3205b88d9 100644
--- a/tests/libqos/virtio.c
+++ b/tests/libqos/virtio.c
@@ -12,25 +12,25 @@
#include "libqos/virtio.h"
uint8_t qvirtio_config_readb(const QVirtioBus *bus, QVirtioDevice *d,
- void *addr)
+ uint64_t addr)
{
return bus->config_readb(d, addr);
}
uint16_t qvirtio_config_readw(const QVirtioBus *bus, QVirtioDevice *d,
- void *addr)
+ uint64_t addr)
{
return bus->config_readw(d, addr);
}
uint32_t qvirtio_config_readl(const QVirtioBus *bus, QVirtioDevice *d,
- void *addr)
+ uint64_t addr)
{
return bus->config_readl(d, addr);
}
uint64_t qvirtio_config_readq(const QVirtioBus *bus, QVirtioDevice *d,
- void *addr)
+ uint64_t addr)
{
return bus->config_readq(d, addr);
}
diff --git a/tests/libqos/virtio.h b/tests/libqos/virtio.h
index 29fbacbc9..2449feec5 100644
--- a/tests/libqos/virtio.h
+++ b/tests/libqos/virtio.h
@@ -93,10 +93,10 @@ typedef struct QVRingIndirectDesc {
} QVRingIndirectDesc;
typedef struct QVirtioBus {
- uint8_t (*config_readb)(QVirtioDevice *d, void *addr);
- uint16_t (*config_readw)(QVirtioDevice *d, void *addr);
- uint32_t (*config_readl)(QVirtioDevice *d, void *addr);
- uint64_t (*config_readq)(QVirtioDevice *d, void *addr);
+ uint8_t (*config_readb)(QVirtioDevice *d, uint64_t addr);
+ uint16_t (*config_readw)(QVirtioDevice *d, uint64_t addr);
+ uint32_t (*config_readl)(QVirtioDevice *d, uint64_t addr);
+ uint64_t (*config_readq)(QVirtioDevice *d, uint64_t addr);
/* Get features of the device */
uint32_t (*get_features)(QVirtioDevice *d);
@@ -144,13 +144,13 @@ static inline uint32_t qvring_size(uint32_t num, uint32_t align)
}
uint8_t qvirtio_config_readb(const QVirtioBus *bus, QVirtioDevice *d,
- void *addr);
+ uint64_t addr);
uint16_t qvirtio_config_readw(const QVirtioBus *bus, QVirtioDevice *d,
- void *addr);
+ uint64_t addr);
uint32_t qvirtio_config_readl(const QVirtioBus *bus, QVirtioDevice *d,
- void *addr);
+ uint64_t addr);
uint64_t qvirtio_config_readq(const QVirtioBus *bus, QVirtioDevice *d,
- void *addr);
+ uint64_t addr);
uint32_t qvirtio_get_features(const QVirtioBus *bus, QVirtioDevice *d);
void qvirtio_set_features(const QVirtioBus *bus, QVirtioDevice *d,
uint32_t features);
diff --git a/tests/qemu-iotests/004 b/tests/qemu-iotests/004
index 651072ef8..2ad77ed51 100755
--- a/tests/qemu-iotests/004
+++ b/tests/qemu-iotests/004
@@ -38,7 +38,7 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
. ./common.rc
. ./common.filter
-_supported_fmt generic
+_supported_fmt raw qcow qcow2 qed vdi vmdk vhdx
_supported_proto generic
_supported_os Linux
diff --git a/tests/qemu-iotests/006.out b/tests/qemu-iotests/006.out
deleted file mode 100644
index d135841b7..000000000
--- a/tests/qemu-iotests/006.out
+++ /dev/null
@@ -1,6 +0,0 @@
-QA output created by 006
-
-creating 128GB image
-qemu-img: The image size is too large for file format 'vpc'
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=137438953472
-*** done
diff --git a/tests/qemu-iotests/007 b/tests/qemu-iotests/007
index fe1a74380..7b5aff59b 100755
--- a/tests/qemu-iotests/007
+++ b/tests/qemu-iotests/007
@@ -43,6 +43,9 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
_supported_fmt qcow2
_supported_proto generic
_supported_os Linux
+# refcount_bits must be at least 4 so we can create ten internal snapshots
+# (1 bit supports none, 2 bits support two, 4 bits support 14)
+_unsupported_imgopts 'refcount_bits=\(1\|2\)[^0-9]'
echo
echo "creating image"
diff --git a/tests/qemu-iotests/015 b/tests/qemu-iotests/015
index 099d75723..6f2609524 100755
--- a/tests/qemu-iotests/015
+++ b/tests/qemu-iotests/015
@@ -43,6 +43,8 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
_supported_fmt qcow2
_supported_proto generic
_supported_os Linux
+# Internal snapshots are (currently) impossible with refcount_bits=1
+_unsupported_imgopts 'refcount_bits=1[^0-9]'
echo
echo "creating image"
diff --git a/tests/qemu-iotests/026 b/tests/qemu-iotests/026
index df2884ba5..0fc3244c7 100755
--- a/tests/qemu-iotests/026
+++ b/tests/qemu-iotests/026
@@ -46,6 +46,13 @@ _supported_proto file
_supported_os Linux
_default_cache_mode "writethrough"
_supported_cache_modes "writethrough" "none"
+# The refcount table tests expect a certain minimum width for refcount entries
+# (so that the refcount table actually needs to grow); that minimum is 16 bits,
+# being the default refcount entry width.
+# 32 and 64 bits do not work either, however, due to different leaked cluster
+# count on error.
+# Thus, the only remaining option is refcount_bits=16.
+_unsupported_imgopts 'refcount_bits=\([^1]\|.\([^6]\|$\)\)'
echo "Errors while writing 128 kB"
echo
diff --git a/tests/qemu-iotests/026.out b/tests/qemu-iotests/026.out
index 524f7ee21..5e964fb5a 100644
--- a/tests/qemu-iotests/026.out
+++ b/tests/qemu-iotests/026.out
@@ -140,19 +140,13 @@ No errors were found on the image.
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: l2_update; errno: 5; imm: off; once: on; write
-Failed to flush the L2 table cache: Input/output error
write failed: Input/output error
-
-127 leaked clusters were found on the image.
-This means waste of disk space, but no harm to data.
+No errors were found on the image.
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: l2_update; errno: 5; imm: off; once: on; write -b
-Failed to flush the L2 table cache: Input/output error
write failed: Input/output error
-
-127 leaked clusters were found on the image.
-This means waste of disk space, but no harm to data.
+No errors were found on the image.
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: l2_update; errno: 5; imm: off; once: off; write
@@ -174,19 +168,13 @@ This means waste of disk space, but no harm to data.
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: l2_update; errno: 28; imm: off; once: on; write
-Failed to flush the L2 table cache: No space left on device
write failed: No space left on device
-
-127 leaked clusters were found on the image.
-This means waste of disk space, but no harm to data.
+No errors were found on the image.
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: l2_update; errno: 28; imm: off; once: on; write -b
-Failed to flush the L2 table cache: No space left on device
write failed: No space left on device
-
-127 leaked clusters were found on the image.
-This means waste of disk space, but no harm to data.
+No errors were found on the image.
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: l2_update; errno: 28; imm: off; once: off; write
@@ -356,13 +344,11 @@ No errors were found on the image.
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: refblock_update_part; errno: 5; imm: off; once: on; write
-Failed to flush the refcount block cache: Input/output error
write failed: Input/output error
No errors were found on the image.
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: refblock_update_part; errno: 5; imm: off; once: on; write -b
-Failed to flush the refcount block cache: Input/output error
write failed: Input/output error
No errors were found on the image.
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
@@ -382,13 +368,11 @@ No errors were found on the image.
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: refblock_update_part; errno: 28; imm: off; once: on; write
-Failed to flush the refcount block cache: No space left on device
write failed: No space left on device
No errors were found on the image.
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
Event: refblock_update_part; errno: 28; imm: off; once: on; write -b
-Failed to flush the refcount block cache: No space left on device
write failed: No space left on device
No errors were found on the image.
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
diff --git a/tests/qemu-iotests/029 b/tests/qemu-iotests/029
index fa46ace67..b9cd826c7 100755
--- a/tests/qemu-iotests/029
+++ b/tests/qemu-iotests/029
@@ -44,6 +44,8 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
_supported_fmt qcow2
_supported_proto generic
_supported_os Linux
+# Internal snapshots are (currently) impossible with refcount_bits=1
+_unsupported_imgopts 'refcount_bits=1[^0-9]'
offset_size=24
offset_l1_size=36
diff --git a/tests/qemu-iotests/049.out b/tests/qemu-iotests/049.out
index b6311b01b..765afdd2a 100644
--- a/tests/qemu-iotests/049.out
+++ b/tests/qemu-iotests/049.out
@@ -4,90 +4,90 @@ QA output created by 049
== 1. Traditional size parameter ==
qemu-img create -f qcow2 TEST_DIR/t.qcow2 1024
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1024 encryption=off cluster_size=65536 lazy_refcounts=off
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1024 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
qemu-img create -f qcow2 TEST_DIR/t.qcow2 1024b
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1024 encryption=off cluster_size=65536 lazy_refcounts=off
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1024 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
qemu-img create -f qcow2 TEST_DIR/t.qcow2 1k
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1024 encryption=off cluster_size=65536 lazy_refcounts=off
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1024 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
qemu-img create -f qcow2 TEST_DIR/t.qcow2 1K
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1024 encryption=off cluster_size=65536 lazy_refcounts=off
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1024 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
qemu-img create -f qcow2 TEST_DIR/t.qcow2 1M
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1048576 encryption=off cluster_size=65536 lazy_refcounts=off
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1048576 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
qemu-img create -f qcow2 TEST_DIR/t.qcow2 1G
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1073741824 encryption=off cluster_size=65536 lazy_refcounts=off
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1073741824 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
qemu-img create -f qcow2 TEST_DIR/t.qcow2 1T
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1099511627776 encryption=off cluster_size=65536 lazy_refcounts=off
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1099511627776 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
qemu-img create -f qcow2 TEST_DIR/t.qcow2 1024.0
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1024 encryption=off cluster_size=65536 lazy_refcounts=off
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1024 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
qemu-img create -f qcow2 TEST_DIR/t.qcow2 1024.0b
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1024 encryption=off cluster_size=65536 lazy_refcounts=off
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1024 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
qemu-img create -f qcow2 TEST_DIR/t.qcow2 1.5k
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1536 encryption=off cluster_size=65536 lazy_refcounts=off
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1536 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
qemu-img create -f qcow2 TEST_DIR/t.qcow2 1.5K
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1536 encryption=off cluster_size=65536 lazy_refcounts=off
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1536 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
qemu-img create -f qcow2 TEST_DIR/t.qcow2 1.5M
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1572864 encryption=off cluster_size=65536 lazy_refcounts=off
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1572864 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
qemu-img create -f qcow2 TEST_DIR/t.qcow2 1.5G
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1610612736 encryption=off cluster_size=65536 lazy_refcounts=off
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1610612736 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
qemu-img create -f qcow2 TEST_DIR/t.qcow2 1.5T
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1649267441664 encryption=off cluster_size=65536 lazy_refcounts=off
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1649267441664 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
== 2. Specifying size via -o ==
qemu-img create -f qcow2 -o size=1024 TEST_DIR/t.qcow2
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1024 encryption=off cluster_size=65536 lazy_refcounts=off
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1024 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
qemu-img create -f qcow2 -o size=1024b TEST_DIR/t.qcow2
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1024 encryption=off cluster_size=65536 lazy_refcounts=off
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1024 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
qemu-img create -f qcow2 -o size=1k TEST_DIR/t.qcow2
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1024 encryption=off cluster_size=65536 lazy_refcounts=off
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1024 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
qemu-img create -f qcow2 -o size=1K TEST_DIR/t.qcow2
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1024 encryption=off cluster_size=65536 lazy_refcounts=off
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1024 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
qemu-img create -f qcow2 -o size=1M TEST_DIR/t.qcow2
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1048576 encryption=off cluster_size=65536 lazy_refcounts=off
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1048576 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
qemu-img create -f qcow2 -o size=1G TEST_DIR/t.qcow2
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1073741824 encryption=off cluster_size=65536 lazy_refcounts=off
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1073741824 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
qemu-img create -f qcow2 -o size=1T TEST_DIR/t.qcow2
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1099511627776 encryption=off cluster_size=65536 lazy_refcounts=off
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1099511627776 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
qemu-img create -f qcow2 -o size=1024.0 TEST_DIR/t.qcow2
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1024 encryption=off cluster_size=65536 lazy_refcounts=off
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1024 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
qemu-img create -f qcow2 -o size=1024.0b TEST_DIR/t.qcow2
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1024 encryption=off cluster_size=65536 lazy_refcounts=off
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1024 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
qemu-img create -f qcow2 -o size=1.5k TEST_DIR/t.qcow2
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1536 encryption=off cluster_size=65536 lazy_refcounts=off
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1536 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
qemu-img create -f qcow2 -o size=1.5K TEST_DIR/t.qcow2
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1536 encryption=off cluster_size=65536 lazy_refcounts=off
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1536 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
qemu-img create -f qcow2 -o size=1.5M TEST_DIR/t.qcow2
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1572864 encryption=off cluster_size=65536 lazy_refcounts=off
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1572864 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
qemu-img create -f qcow2 -o size=1.5G TEST_DIR/t.qcow2
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1610612736 encryption=off cluster_size=65536 lazy_refcounts=off
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1610612736 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
qemu-img create -f qcow2 -o size=1.5T TEST_DIR/t.qcow2
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1649267441664 encryption=off cluster_size=65536 lazy_refcounts=off
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1649267441664 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
== 3. Invalid sizes ==
@@ -97,7 +97,7 @@ qemu-img: Image size must be less than 8 EiB!
qemu-img create -f qcow2 -o size=-1024 TEST_DIR/t.qcow2
qemu-img: qcow2 doesn't support shrinking images yet
qemu-img: TEST_DIR/t.qcow2: Could not resize image: Operation not supported
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=-1024 encryption=off cluster_size=65536 lazy_refcounts=off
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=-1024 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
qemu-img create -f qcow2 TEST_DIR/t.qcow2 -- -1k
qemu-img: Image size must be less than 8 EiB!
@@ -105,14 +105,14 @@ qemu-img: Image size must be less than 8 EiB!
qemu-img create -f qcow2 -o size=-1k TEST_DIR/t.qcow2
qemu-img: qcow2 doesn't support shrinking images yet
qemu-img: TEST_DIR/t.qcow2: Could not resize image: Operation not supported
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=-1024 encryption=off cluster_size=65536 lazy_refcounts=off
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=-1024 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
qemu-img create -f qcow2 TEST_DIR/t.qcow2 -- 1kilobyte
qemu-img: Invalid image size specified! You may use k, M, G, T, P or E suffixes for
qemu-img: kilobytes, megabytes, gigabytes, terabytes, petabytes and exabytes.
qemu-img create -f qcow2 -o size=1kilobyte TEST_DIR/t.qcow2
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1024 encryption=off cluster_size=65536 lazy_refcounts=off
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1024 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
qemu-img create -f qcow2 TEST_DIR/t.qcow2 -- foobar
qemu-img: Invalid image size specified! You may use k, M, G, T, P or E suffixes for
@@ -125,84 +125,84 @@ qemu-img: TEST_DIR/t.qcow2: Invalid options for file format 'qcow2'
== Check correct interpretation of suffixes for cluster size ==
qemu-img create -f qcow2 -o cluster_size=1024 TEST_DIR/t.qcow2 64M
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 encryption=off cluster_size=1024 lazy_refcounts=off
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 encryption=off cluster_size=1024 lazy_refcounts=off refcount_bits=16
qemu-img create -f qcow2 -o cluster_size=1024b TEST_DIR/t.qcow2 64M
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 encryption=off cluster_size=1024 lazy_refcounts=off
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 encryption=off cluster_size=1024 lazy_refcounts=off refcount_bits=16
qemu-img create -f qcow2 -o cluster_size=1k TEST_DIR/t.qcow2 64M
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 encryption=off cluster_size=1024 lazy_refcounts=off
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 encryption=off cluster_size=1024 lazy_refcounts=off refcount_bits=16
qemu-img create -f qcow2 -o cluster_size=1K TEST_DIR/t.qcow2 64M
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 encryption=off cluster_size=1024 lazy_refcounts=off
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 encryption=off cluster_size=1024 lazy_refcounts=off refcount_bits=16
qemu-img create -f qcow2 -o cluster_size=1M TEST_DIR/t.qcow2 64M
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 encryption=off cluster_size=1048576 lazy_refcounts=off
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 encryption=off cluster_size=1048576 lazy_refcounts=off refcount_bits=16
qemu-img create -f qcow2 -o cluster_size=1024.0 TEST_DIR/t.qcow2 64M
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 encryption=off cluster_size=1024 lazy_refcounts=off
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 encryption=off cluster_size=1024 lazy_refcounts=off refcount_bits=16
qemu-img create -f qcow2 -o cluster_size=1024.0b TEST_DIR/t.qcow2 64M
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 encryption=off cluster_size=1024 lazy_refcounts=off
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 encryption=off cluster_size=1024 lazy_refcounts=off refcount_bits=16
qemu-img create -f qcow2 -o cluster_size=0.5k TEST_DIR/t.qcow2 64M
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 encryption=off cluster_size=512 lazy_refcounts=off
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 encryption=off cluster_size=512 lazy_refcounts=off refcount_bits=16
qemu-img create -f qcow2 -o cluster_size=0.5K TEST_DIR/t.qcow2 64M
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 encryption=off cluster_size=512 lazy_refcounts=off
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 encryption=off cluster_size=512 lazy_refcounts=off refcount_bits=16
qemu-img create -f qcow2 -o cluster_size=0.5M TEST_DIR/t.qcow2 64M
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 encryption=off cluster_size=524288 lazy_refcounts=off
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 encryption=off cluster_size=524288 lazy_refcounts=off refcount_bits=16
== Check compat level option ==
qemu-img create -f qcow2 -o compat=0.10 TEST_DIR/t.qcow2 64M
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 compat='0.10' encryption=off cluster_size=65536 lazy_refcounts=off
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 compat='0.10' encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
qemu-img create -f qcow2 -o compat=1.1 TEST_DIR/t.qcow2 64M
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 compat='1.1' encryption=off cluster_size=65536 lazy_refcounts=off
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 compat='1.1' encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
qemu-img create -f qcow2 -o compat=0.42 TEST_DIR/t.qcow2 64M
qemu-img: TEST_DIR/t.qcow2: Invalid compatibility level: '0.42'
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 compat='0.42' encryption=off cluster_size=65536 lazy_refcounts=off
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 compat='0.42' encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
qemu-img create -f qcow2 -o compat=foobar TEST_DIR/t.qcow2 64M
qemu-img: TEST_DIR/t.qcow2: Invalid compatibility level: 'foobar'
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 compat='foobar' encryption=off cluster_size=65536 lazy_refcounts=off
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 compat='foobar' encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
== Check preallocation option ==
qemu-img create -f qcow2 -o preallocation=off TEST_DIR/t.qcow2 64M
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 encryption=off cluster_size=65536 preallocation='off' lazy_refcounts=off
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 encryption=off cluster_size=65536 preallocation='off' lazy_refcounts=off refcount_bits=16
qemu-img create -f qcow2 -o preallocation=metadata TEST_DIR/t.qcow2 64M
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 encryption=off cluster_size=65536 preallocation='metadata' lazy_refcounts=off
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 encryption=off cluster_size=65536 preallocation='metadata' lazy_refcounts=off refcount_bits=16
qemu-img create -f qcow2 -o preallocation=1234 TEST_DIR/t.qcow2 64M
qemu-img: TEST_DIR/t.qcow2: invalid parameter value: 1234
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 encryption=off cluster_size=65536 preallocation='1234' lazy_refcounts=off
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 encryption=off cluster_size=65536 preallocation='1234' lazy_refcounts=off refcount_bits=16
== Check encryption option ==
qemu-img create -f qcow2 -o encryption=off TEST_DIR/t.qcow2 64M
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 encryption=off cluster_size=65536 lazy_refcounts=off
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
qemu-img create -f qcow2 -o encryption=on TEST_DIR/t.qcow2 64M
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 encryption=on cluster_size=65536 lazy_refcounts=off
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 encryption=on cluster_size=65536 lazy_refcounts=off refcount_bits=16
== Check lazy_refcounts option (only with v3) ==
qemu-img create -f qcow2 -o compat=1.1,lazy_refcounts=off TEST_DIR/t.qcow2 64M
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 compat='1.1' encryption=off cluster_size=65536 lazy_refcounts=off
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 compat='1.1' encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
qemu-img create -f qcow2 -o compat=1.1,lazy_refcounts=on TEST_DIR/t.qcow2 64M
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 compat='1.1' encryption=off cluster_size=65536 lazy_refcounts=on
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 compat='1.1' encryption=off cluster_size=65536 lazy_refcounts=on refcount_bits=16
qemu-img create -f qcow2 -o compat=0.10,lazy_refcounts=off TEST_DIR/t.qcow2 64M
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 compat='0.10' encryption=off cluster_size=65536 lazy_refcounts=off
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 compat='0.10' encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
qemu-img create -f qcow2 -o compat=0.10,lazy_refcounts=on TEST_DIR/t.qcow2 64M
qemu-img: TEST_DIR/t.qcow2: Lazy refcounts only supported with compatibility level 1.1 and above (use compat=1.1 or greater)
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 compat='0.10' encryption=off cluster_size=65536 lazy_refcounts=on
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 compat='0.10' encryption=off cluster_size=65536 lazy_refcounts=on refcount_bits=16
*** done
diff --git a/tests/qemu-iotests/051 b/tests/qemu-iotests/051
index 27138a229..0360f37e5 100755
--- a/tests/qemu-iotests/051
+++ b/tests/qemu-iotests/051
@@ -41,6 +41,9 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
_supported_fmt qcow2
_supported_proto file
_supported_os Linux
+# A compat=0.10 image is created in this test which does not support anything
+# other than refcount_bits=16
+_unsupported_imgopts 'refcount_bits=\([^1]\|.\([^6]\|$\)\)'
function do_run_qemu()
{
@@ -96,6 +99,12 @@ run_qemu -drive file="$TEST_IMG",driver=raw,format=qcow2
run_qemu -drive file="$TEST_IMG",driver=qcow2,format=qcow2
echo
+echo === Device without drive ===
+echo
+
+run_qemu -device virtio-scsi-pci -device scsi-hd
+
+echo
echo === Overriding backing file ===
echo
diff --git a/tests/qemu-iotests/051.out b/tests/qemu-iotests/051.out
index bf52bf02d..09895e613 100644
--- a/tests/qemu-iotests/051.out
+++ b/tests/qemu-iotests/051.out
@@ -47,6 +47,14 @@ Testing: -drive file=TEST_DIR/t.qcow2,driver=qcow2,format=qcow2
QEMU_PROG: -drive file=TEST_DIR/t.qcow2,driver=qcow2,format=qcow2: Cannot specify both 'driver' and 'format'
+=== Device without drive ===
+
+Testing: -device virtio-scsi-pci -device scsi-hd
+QEMU X.Y.Z monitor - type 'help' for more information
+(qemu) QEMU_PROG: -device scsi-hd: drive property not set
+QEMU_PROG: -device scsi-hd: Device 'scsi-hd' could not be initialized
+
+
=== Overriding backing file ===
Testing: -drive file=TEST_DIR/t.qcow2,driver=qcow2,backing.file.filename=TEST_DIR/t.qcow2.orig -nodefaults
@@ -115,8 +123,7 @@ QEMU X.Y.Z monitor - type 'help' for more information
Testing: -drive if=ide
QEMU X.Y.Z monitor - type 'help' for more information
(qemu) QEMU_PROG: Device needs media, but drive is empty
-QEMU_PROG: Device initialization failed.
-QEMU_PROG: Initialization of device ide-hd failed
+QEMU_PROG: Initialization of device ide-hd failed: Device initialization failed.
Testing: -drive if=virtio
QEMU X.Y.Z monitor - type 'help' for more information
@@ -127,8 +134,7 @@ QEMU_PROG: -drive if=virtio: Device 'virtio-blk-pci' could not be initialized
Testing: -drive if=scsi
QEMU X.Y.Z monitor - type 'help' for more information
(qemu) QEMU_PROG: -drive if=scsi: Device needs media, but drive is empty
-QEMU_PROG: Device initialization failed.
-QEMU_PROG: Initialization of device lsi53c895a failed
+QEMU_PROG: Initialization of device lsi53c895a failed: Device initialization failed.
Testing: -drive if=none,id=disk -device ide-cd,drive=disk
QEMU X.Y.Z monitor - type 'help' for more information
@@ -178,8 +184,7 @@ QEMU X.Y.Z monitor - type 'help' for more information
Testing: -drive file=TEST_DIR/t.qcow2,if=ide,readonly=on
QEMU X.Y.Z monitor - type 'help' for more information
(qemu) QEMU_PROG: Can't use a read-only drive
-QEMU_PROG: Device initialization failed.
-QEMU_PROG: Initialization of device ide-hd failed
+QEMU_PROG: Initialization of device ide-hd failed: Device initialization failed.
Testing: -drive file=TEST_DIR/t.qcow2,if=virtio,readonly=on
QEMU X.Y.Z monitor - type 'help' for more information
diff --git a/tests/qemu-iotests/058 b/tests/qemu-iotests/058
index a60b34b46..f2bdd0bff 100755
--- a/tests/qemu-iotests/058
+++ b/tests/qemu-iotests/058
@@ -89,6 +89,8 @@ _supported_fmt qcow2
_supported_proto file
_supported_os Linux
_require_command QEMU_NBD
+# Internal snapshots are (currently) impossible with refcount_bits=1
+_unsupported_imgopts 'refcount_bits=1[^0-9]'
# Use -f raw instead of -f $IMGFMT for the NBD connection
QEMU_IO_NBD="$QEMU_IO -f raw --cache=$CACHEMODE"
diff --git a/tests/qemu-iotests/060.out b/tests/qemu-iotests/060.out
index dc9f6b757..751118951 100644
--- a/tests/qemu-iotests/060.out
+++ b/tests/qemu-iotests/060.out
@@ -18,6 +18,7 @@ cluster_size: 65536
Format specific information:
compat: 1.1
lazy refcounts: false
+ refcount bits: 16
corrupt: true
qemu-io: can't open device TEST_DIR/t.IMGFMT: IMGFMT: Image is corrupt; cannot be opened read/write
read 512/512 bytes at offset 0
diff --git a/tests/qemu-iotests/065 b/tests/qemu-iotests/065
index 8d3a9c9af..72aa9707c 100755
--- a/tests/qemu-iotests/065
+++ b/tests/qemu-iotests/065
@@ -88,34 +88,41 @@ class TestQMP(TestImageInfoSpecific):
class TestQCow2(TestQemuImgInfo):
'''Testing a qcow2 version 2 image'''
img_options = 'compat=0.10'
- json_compare = { 'compat': '0.10' }
- human_compare = [ 'compat: 0.10' ]
+ json_compare = { 'compat': '0.10', 'refcount-bits': 16 }
+ human_compare = [ 'compat: 0.10', 'refcount bits: 16' ]
class TestQCow3NotLazy(TestQemuImgInfo):
'''Testing a qcow2 version 3 image with lazy refcounts disabled'''
img_options = 'compat=1.1,lazy_refcounts=off'
- json_compare = { 'compat': '1.1', 'lazy-refcounts': False, 'corrupt': False }
- human_compare = [ 'compat: 1.1', 'lazy refcounts: false', 'corrupt: false' ]
+ json_compare = { 'compat': '1.1', 'lazy-refcounts': False,
+ 'refcount-bits': 16, 'corrupt': False }
+ human_compare = [ 'compat: 1.1', 'lazy refcounts: false',
+ 'refcount bits: 16', 'corrupt: false' ]
class TestQCow3Lazy(TestQemuImgInfo):
'''Testing a qcow2 version 3 image with lazy refcounts enabled'''
img_options = 'compat=1.1,lazy_refcounts=on'
- json_compare = { 'compat': '1.1', 'lazy-refcounts': True, 'corrupt': False }
- human_compare = [ 'compat: 1.1', 'lazy refcounts: true', 'corrupt: false' ]
+ json_compare = { 'compat': '1.1', 'lazy-refcounts': True,
+ 'refcount-bits': 16, 'corrupt': False }
+ human_compare = [ 'compat: 1.1', 'lazy refcounts: true',
+ 'refcount bits: 16', 'corrupt: false' ]
class TestQCow3NotLazyQMP(TestQMP):
'''Testing a qcow2 version 3 image with lazy refcounts disabled, opening
with lazy refcounts enabled'''
img_options = 'compat=1.1,lazy_refcounts=off'
qemu_options = 'lazy-refcounts=on'
- compare = { 'compat': '1.1', 'lazy-refcounts': False, 'corrupt': False }
+ compare = { 'compat': '1.1', 'lazy-refcounts': False,
+ 'refcount-bits': 16, 'corrupt': False }
+
class TestQCow3LazyQMP(TestQMP):
'''Testing a qcow2 version 3 image with lazy refcounts enabled, opening
with lazy refcounts disabled'''
img_options = 'compat=1.1,lazy_refcounts=on'
qemu_options = 'lazy-refcounts=off'
- compare = { 'compat': '1.1', 'lazy-refcounts': True, 'corrupt': False }
+ compare = { 'compat': '1.1', 'lazy-refcounts': True,
+ 'refcount-bits': 16, 'corrupt': False }
TestImageInfoSpecific = None
TestQemuImgInfo = None
diff --git a/tests/qemu-iotests/067 b/tests/qemu-iotests/067
index 0508c696a..83eefa394 100755
--- a/tests/qemu-iotests/067
+++ b/tests/qemu-iotests/067
@@ -35,6 +35,8 @@ status=1 # failure is the default!
_supported_fmt qcow2
_supported_proto file
_supported_os Linux
+# Because anything other than 16 would change the output of query-block
+_unsupported_imgopts 'refcount_bits=\([^1]\|.\([^6]\|$\)\)'
function do_run_qemu()
{
diff --git a/tests/qemu-iotests/067.out b/tests/qemu-iotests/067.out
index 00b3eaefc..6ff41bc7a 100644
--- a/tests/qemu-iotests/067.out
+++ b/tests/qemu-iotests/067.out
@@ -32,6 +32,7 @@ Testing: -drive file=TEST_DIR/t.qcow2,format=qcow2,if=none,id=disk -device virti
"data": {
"compat": "1.1",
"lazy-refcounts": false,
+ "refcount-bits": 16,
"corrupt": false
}
},
@@ -208,6 +209,7 @@ Testing: -drive file=TEST_DIR/t.qcow2,format=qcow2,if=none,id=disk
"data": {
"compat": "1.1",
"lazy-refcounts": false,
+ "refcount-bits": 16,
"corrupt": false
}
},
@@ -414,6 +416,7 @@ Testing:
"data": {
"compat": "1.1",
"lazy-refcounts": false,
+ "refcount-bits": 16,
"corrupt": false
}
},
@@ -599,6 +602,7 @@ Testing:
"data": {
"compat": "1.1",
"lazy-refcounts": false,
+ "refcount-bits": 16,
"corrupt": false
}
},
@@ -710,6 +714,7 @@ Testing:
"data": {
"compat": "1.1",
"lazy-refcounts": false,
+ "refcount-bits": 16,
"corrupt": false
}
},
diff --git a/tests/qemu-iotests/079 b/tests/qemu-iotests/079
index 6613cfb18..ade6efa0d 100755
--- a/tests/qemu-iotests/079
+++ b/tests/qemu-iotests/079
@@ -42,19 +42,13 @@ _supported_fmt qcow2
_supported_proto file nfs
_supported_os Linux
-function test_qemu_img()
-{
- echo qemu-img "$@" | _filter_testdir
- $QEMU_IMG "$@" 2>&1 | _filter_testdir
- echo
-}
-
echo "=== Check option preallocation and cluster_size ==="
echo
cluster_sizes="16384 32768 65536 131072 262144 524288 1048576 2097152 4194304"
for s in $cluster_sizes; do
- test_qemu_img create -f $IMGFMT -o preallocation=metadata,cluster_size=$s "$TEST_IMG" 4G
+ IMGOPTS=$(_optstr_add "$IMGOPTS" "preallocation=metadata,cluster_size=$s") \
+ _make_test_img 4G
done
# success, all done
diff --git a/tests/qemu-iotests/079.out b/tests/qemu-iotests/079.out
index ef4b8c911..6dc5d5763 100644
--- a/tests/qemu-iotests/079.out
+++ b/tests/qemu-iotests/079.out
@@ -1,32 +1,14 @@
QA output created by 079
=== Check option preallocation and cluster_size ===
-qemu-img create -f qcow2 -o preallocation=metadata,cluster_size=16384 TEST_DIR/t.qcow2 4G
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=4294967296 encryption=off cluster_size=16384 preallocation='metadata' lazy_refcounts=off
-
-qemu-img create -f qcow2 -o preallocation=metadata,cluster_size=32768 TEST_DIR/t.qcow2 4G
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=4294967296 encryption=off cluster_size=32768 preallocation='metadata' lazy_refcounts=off
-
-qemu-img create -f qcow2 -o preallocation=metadata,cluster_size=65536 TEST_DIR/t.qcow2 4G
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=4294967296 encryption=off cluster_size=65536 preallocation='metadata' lazy_refcounts=off
-
-qemu-img create -f qcow2 -o preallocation=metadata,cluster_size=131072 TEST_DIR/t.qcow2 4G
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=4294967296 encryption=off cluster_size=131072 preallocation='metadata' lazy_refcounts=off
-
-qemu-img create -f qcow2 -o preallocation=metadata,cluster_size=262144 TEST_DIR/t.qcow2 4G
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=4294967296 encryption=off cluster_size=262144 preallocation='metadata' lazy_refcounts=off
-
-qemu-img create -f qcow2 -o preallocation=metadata,cluster_size=524288 TEST_DIR/t.qcow2 4G
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=4294967296 encryption=off cluster_size=524288 preallocation='metadata' lazy_refcounts=off
-
-qemu-img create -f qcow2 -o preallocation=metadata,cluster_size=1048576 TEST_DIR/t.qcow2 4G
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=4294967296 encryption=off cluster_size=1048576 preallocation='metadata' lazy_refcounts=off
-
-qemu-img create -f qcow2 -o preallocation=metadata,cluster_size=2097152 TEST_DIR/t.qcow2 4G
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=4294967296 encryption=off cluster_size=2097152 preallocation='metadata' lazy_refcounts=off
-
-qemu-img create -f qcow2 -o preallocation=metadata,cluster_size=4194304 TEST_DIR/t.qcow2 4G
-qemu-img: TEST_DIR/t.qcow2: Cluster size must be a power of two between 512 and 2048k
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=4294967296 encryption=off cluster_size=4194304 preallocation='metadata' lazy_refcounts=off
-
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=4294967296 preallocation='metadata'
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=4294967296 preallocation='metadata'
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=4294967296 preallocation='metadata'
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=4294967296 preallocation='metadata'
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=4294967296 preallocation='metadata'
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=4294967296 preallocation='metadata'
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=4294967296 preallocation='metadata'
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=4294967296 preallocation='metadata'
+qemu-img: TEST_DIR/t.IMGFMT: Cluster size must be a power of two between 512 and 2048k
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=4294967296 preallocation='metadata'
*** done
diff --git a/tests/qemu-iotests/080 b/tests/qemu-iotests/080
index 73795f198..a2c58aebd 100755
--- a/tests/qemu-iotests/080
+++ b/tests/qemu-iotests/080
@@ -42,6 +42,8 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
_supported_fmt qcow2
_supported_proto file
_supported_os Linux
+# Internal snapshots are (currently) impossible with refcount_bits=1
+_unsupported_imgopts 'refcount_bits=1[^0-9]'
header_size=104
diff --git a/tests/qemu-iotests/082.out b/tests/qemu-iotests/082.out
index d0234e613..3a749b825 100644
--- a/tests/qemu-iotests/082.out
+++ b/tests/qemu-iotests/082.out
@@ -3,14 +3,14 @@ QA output created by 082
=== create: Options specified more than once ===
Testing: create -f foo -f qcow2 TEST_DIR/t.qcow2 128M
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=134217728 encryption=off cluster_size=65536 lazy_refcounts=off
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=134217728 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
image: TEST_DIR/t.IMGFMT
file format: IMGFMT
virtual size: 128M (134217728 bytes)
cluster_size: 65536
Testing: create -f qcow2 -o cluster_size=4k -o lazy_refcounts=on TEST_DIR/t.qcow2 128M
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=134217728 encryption=off cluster_size=4096 lazy_refcounts=on
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=134217728 encryption=off cluster_size=4096 lazy_refcounts=on refcount_bits=16
image: TEST_DIR/t.IMGFMT
file format: IMGFMT
virtual size: 128M (134217728 bytes)
@@ -18,10 +18,11 @@ cluster_size: 4096
Format specific information:
compat: 1.1
lazy refcounts: true
+ refcount bits: 16
corrupt: false
Testing: create -f qcow2 -o cluster_size=4k -o lazy_refcounts=on -o cluster_size=8k TEST_DIR/t.qcow2 128M
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=134217728 encryption=off cluster_size=8192 lazy_refcounts=on
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=134217728 encryption=off cluster_size=8192 lazy_refcounts=on refcount_bits=16
image: TEST_DIR/t.IMGFMT
file format: IMGFMT
virtual size: 128M (134217728 bytes)
@@ -29,10 +30,11 @@ cluster_size: 8192
Format specific information:
compat: 1.1
lazy refcounts: true
+ refcount bits: 16
corrupt: false
Testing: create -f qcow2 -o cluster_size=4k,cluster_size=8k TEST_DIR/t.qcow2 128M
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=134217728 encryption=off cluster_size=8192 lazy_refcounts=off
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=134217728 encryption=off cluster_size=8192 lazy_refcounts=off refcount_bits=16
image: TEST_DIR/t.IMGFMT
file format: IMGFMT
virtual size: 128M (134217728 bytes)
@@ -50,6 +52,7 @@ encryption Encrypt the image
cluster_size qcow2 cluster size
preallocation Preallocation mode (allowed values: off, metadata, falloc, full)
lazy_refcounts Postpone refcount updates
+refcount_bits Width of a reference count entry in bits
nocow Turn off copy-on-write (valid only on btrfs)
Testing: create -f qcow2 -o ? TEST_DIR/t.qcow2 128M
@@ -62,6 +65,7 @@ encryption Encrypt the image
cluster_size qcow2 cluster size
preallocation Preallocation mode (allowed values: off, metadata, falloc, full)
lazy_refcounts Postpone refcount updates
+refcount_bits Width of a reference count entry in bits
nocow Turn off copy-on-write (valid only on btrfs)
Testing: create -f qcow2 -o cluster_size=4k,help TEST_DIR/t.qcow2 128M
@@ -74,6 +78,7 @@ encryption Encrypt the image
cluster_size qcow2 cluster size
preallocation Preallocation mode (allowed values: off, metadata, falloc, full)
lazy_refcounts Postpone refcount updates
+refcount_bits Width of a reference count entry in bits
nocow Turn off copy-on-write (valid only on btrfs)
Testing: create -f qcow2 -o cluster_size=4k,? TEST_DIR/t.qcow2 128M
@@ -86,6 +91,7 @@ encryption Encrypt the image
cluster_size qcow2 cluster size
preallocation Preallocation mode (allowed values: off, metadata, falloc, full)
lazy_refcounts Postpone refcount updates
+refcount_bits Width of a reference count entry in bits
nocow Turn off copy-on-write (valid only on btrfs)
Testing: create -f qcow2 -o help,cluster_size=4k TEST_DIR/t.qcow2 128M
@@ -98,6 +104,7 @@ encryption Encrypt the image
cluster_size qcow2 cluster size
preallocation Preallocation mode (allowed values: off, metadata, falloc, full)
lazy_refcounts Postpone refcount updates
+refcount_bits Width of a reference count entry in bits
nocow Turn off copy-on-write (valid only on btrfs)
Testing: create -f qcow2 -o ?,cluster_size=4k TEST_DIR/t.qcow2 128M
@@ -110,6 +117,7 @@ encryption Encrypt the image
cluster_size qcow2 cluster size
preallocation Preallocation mode (allowed values: off, metadata, falloc, full)
lazy_refcounts Postpone refcount updates
+refcount_bits Width of a reference count entry in bits
nocow Turn off copy-on-write (valid only on btrfs)
Testing: create -f qcow2 -o cluster_size=4k -o help TEST_DIR/t.qcow2 128M
@@ -122,6 +130,7 @@ encryption Encrypt the image
cluster_size qcow2 cluster size
preallocation Preallocation mode (allowed values: off, metadata, falloc, full)
lazy_refcounts Postpone refcount updates
+refcount_bits Width of a reference count entry in bits
nocow Turn off copy-on-write (valid only on btrfs)
Testing: create -f qcow2 -o cluster_size=4k -o ? TEST_DIR/t.qcow2 128M
@@ -134,13 +143,14 @@ encryption Encrypt the image
cluster_size qcow2 cluster size
preallocation Preallocation mode (allowed values: off, metadata, falloc, full)
lazy_refcounts Postpone refcount updates
+refcount_bits Width of a reference count entry in bits
nocow Turn off copy-on-write (valid only on btrfs)
Testing: create -f qcow2 -o backing_file=TEST_DIR/t.qcow2,,help TEST_DIR/t.qcow2 128M
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=134217728 backing_file='TEST_DIR/t.qcow2,help' encryption=off cluster_size=65536 lazy_refcounts=off
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=134217728 backing_file='TEST_DIR/t.qcow2,help' encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
Testing: create -f qcow2 -o backing_file=TEST_DIR/t.qcow2,,? TEST_DIR/t.qcow2 128M
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=134217728 backing_file='TEST_DIR/t.qcow2,?' encryption=off cluster_size=65536 lazy_refcounts=off
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=134217728 backing_file='TEST_DIR/t.qcow2,?' encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
Testing: create -f qcow2 -o backing_file=TEST_DIR/t.qcow2, -o help TEST_DIR/t.qcow2 128M
qemu-img: Invalid option list: backing_file=TEST_DIR/t.qcow2,
@@ -161,6 +171,7 @@ encryption Encrypt the image
cluster_size qcow2 cluster size
preallocation Preallocation mode (allowed values: off, metadata, falloc, full)
lazy_refcounts Postpone refcount updates
+refcount_bits Width of a reference count entry in bits
Testing: create -o help
Supported options:
@@ -169,7 +180,7 @@ size Virtual disk size
=== convert: Options specified more than once ===
Testing: create -f qcow2 TEST_DIR/t.qcow2 128M
-Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=134217728 encryption=off cluster_size=65536 lazy_refcounts=off
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=134217728 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
Testing: convert -f foo -f qcow2 TEST_DIR/t.qcow2 TEST_DIR/t.qcow2.base
image: TEST_DIR/t.IMGFMT.base
@@ -190,6 +201,7 @@ cluster_size: 4096
Format specific information:
compat: 1.1
lazy refcounts: true
+ refcount bits: 16
corrupt: false
Testing: convert -O qcow2 -o cluster_size=4k -o lazy_refcounts=on -o cluster_size=8k TEST_DIR/t.qcow2 TEST_DIR/t.qcow2.base
@@ -200,6 +212,7 @@ cluster_size: 8192
Format specific information:
compat: 1.1
lazy refcounts: true
+ refcount bits: 16
corrupt: false
Testing: convert -O qcow2 -o cluster_size=4k,cluster_size=8k TEST_DIR/t.qcow2 TEST_DIR/t.qcow2.base
@@ -220,6 +233,7 @@ encryption Encrypt the image
cluster_size qcow2 cluster size
preallocation Preallocation mode (allowed values: off, metadata, falloc, full)
lazy_refcounts Postpone refcount updates
+refcount_bits Width of a reference count entry in bits
nocow Turn off copy-on-write (valid only on btrfs)
Testing: convert -O qcow2 -o ? TEST_DIR/t.qcow2 TEST_DIR/t.qcow2.base
@@ -232,6 +246,7 @@ encryption Encrypt the image
cluster_size qcow2 cluster size
preallocation Preallocation mode (allowed values: off, metadata, falloc, full)
lazy_refcounts Postpone refcount updates
+refcount_bits Width of a reference count entry in bits
nocow Turn off copy-on-write (valid only on btrfs)
Testing: convert -O qcow2 -o cluster_size=4k,help TEST_DIR/t.qcow2 TEST_DIR/t.qcow2.base
@@ -244,6 +259,7 @@ encryption Encrypt the image
cluster_size qcow2 cluster size
preallocation Preallocation mode (allowed values: off, metadata, falloc, full)
lazy_refcounts Postpone refcount updates
+refcount_bits Width of a reference count entry in bits
nocow Turn off copy-on-write (valid only on btrfs)
Testing: convert -O qcow2 -o cluster_size=4k,? TEST_DIR/t.qcow2 TEST_DIR/t.qcow2.base
@@ -256,6 +272,7 @@ encryption Encrypt the image
cluster_size qcow2 cluster size
preallocation Preallocation mode (allowed values: off, metadata, falloc, full)
lazy_refcounts Postpone refcount updates
+refcount_bits Width of a reference count entry in bits
nocow Turn off copy-on-write (valid only on btrfs)
Testing: convert -O qcow2 -o help,cluster_size=4k TEST_DIR/t.qcow2 TEST_DIR/t.qcow2.base
@@ -268,6 +285,7 @@ encryption Encrypt the image
cluster_size qcow2 cluster size
preallocation Preallocation mode (allowed values: off, metadata, falloc, full)
lazy_refcounts Postpone refcount updates
+refcount_bits Width of a reference count entry in bits
nocow Turn off copy-on-write (valid only on btrfs)
Testing: convert -O qcow2 -o ?,cluster_size=4k TEST_DIR/t.qcow2 TEST_DIR/t.qcow2.base
@@ -280,6 +298,7 @@ encryption Encrypt the image
cluster_size qcow2 cluster size
preallocation Preallocation mode (allowed values: off, metadata, falloc, full)
lazy_refcounts Postpone refcount updates
+refcount_bits Width of a reference count entry in bits
nocow Turn off copy-on-write (valid only on btrfs)
Testing: convert -O qcow2 -o cluster_size=4k -o help TEST_DIR/t.qcow2 TEST_DIR/t.qcow2.base
@@ -292,6 +311,7 @@ encryption Encrypt the image
cluster_size qcow2 cluster size
preallocation Preallocation mode (allowed values: off, metadata, falloc, full)
lazy_refcounts Postpone refcount updates
+refcount_bits Width of a reference count entry in bits
nocow Turn off copy-on-write (valid only on btrfs)
Testing: convert -O qcow2 -o cluster_size=4k -o ? TEST_DIR/t.qcow2 TEST_DIR/t.qcow2.base
@@ -304,6 +324,7 @@ encryption Encrypt the image
cluster_size qcow2 cluster size
preallocation Preallocation mode (allowed values: off, metadata, falloc, full)
lazy_refcounts Postpone refcount updates
+refcount_bits Width of a reference count entry in bits
nocow Turn off copy-on-write (valid only on btrfs)
Testing: convert -O qcow2 -o backing_file=TEST_DIR/t.qcow2,,help TEST_DIR/t.qcow2 TEST_DIR/t.qcow2.base
@@ -331,6 +352,7 @@ encryption Encrypt the image
cluster_size qcow2 cluster size
preallocation Preallocation mode (allowed values: off, metadata, falloc, full)
lazy_refcounts Postpone refcount updates
+refcount_bits Width of a reference count entry in bits
Testing: convert -o help
Supported options:
@@ -346,6 +368,7 @@ cluster_size: 65536
Format specific information:
compat: 1.1
lazy refcounts: true
+ refcount bits: 16
corrupt: false
Testing: amend -f qcow2 -o size=130M -o lazy_refcounts=off TEST_DIR/t.qcow2
@@ -356,6 +379,7 @@ cluster_size: 65536
Format specific information:
compat: 1.1
lazy refcounts: false
+ refcount bits: 16
corrupt: false
Testing: amend -f qcow2 -o size=8M -o lazy_refcounts=on -o size=132M TEST_DIR/t.qcow2
@@ -366,6 +390,7 @@ cluster_size: 65536
Format specific information:
compat: 1.1
lazy refcounts: true
+ refcount bits: 16
corrupt: false
Testing: amend -f qcow2 -o size=4M,size=148M TEST_DIR/t.qcow2
@@ -386,6 +411,7 @@ encryption Encrypt the image
cluster_size qcow2 cluster size
preallocation Preallocation mode (allowed values: off, metadata, falloc, full)
lazy_refcounts Postpone refcount updates
+refcount_bits Width of a reference count entry in bits
nocow Turn off copy-on-write (valid only on btrfs)
Testing: amend -f qcow2 -o ? TEST_DIR/t.qcow2
@@ -398,6 +424,7 @@ encryption Encrypt the image
cluster_size qcow2 cluster size
preallocation Preallocation mode (allowed values: off, metadata, falloc, full)
lazy_refcounts Postpone refcount updates
+refcount_bits Width of a reference count entry in bits
nocow Turn off copy-on-write (valid only on btrfs)
Testing: amend -f qcow2 -o cluster_size=4k,help TEST_DIR/t.qcow2
@@ -410,6 +437,7 @@ encryption Encrypt the image
cluster_size qcow2 cluster size
preallocation Preallocation mode (allowed values: off, metadata, falloc, full)
lazy_refcounts Postpone refcount updates
+refcount_bits Width of a reference count entry in bits
nocow Turn off copy-on-write (valid only on btrfs)
Testing: amend -f qcow2 -o cluster_size=4k,? TEST_DIR/t.qcow2
@@ -422,6 +450,7 @@ encryption Encrypt the image
cluster_size qcow2 cluster size
preallocation Preallocation mode (allowed values: off, metadata, falloc, full)
lazy_refcounts Postpone refcount updates
+refcount_bits Width of a reference count entry in bits
nocow Turn off copy-on-write (valid only on btrfs)
Testing: amend -f qcow2 -o help,cluster_size=4k TEST_DIR/t.qcow2
@@ -434,6 +463,7 @@ encryption Encrypt the image
cluster_size qcow2 cluster size
preallocation Preallocation mode (allowed values: off, metadata, falloc, full)
lazy_refcounts Postpone refcount updates
+refcount_bits Width of a reference count entry in bits
nocow Turn off copy-on-write (valid only on btrfs)
Testing: amend -f qcow2 -o ?,cluster_size=4k TEST_DIR/t.qcow2
@@ -446,6 +476,7 @@ encryption Encrypt the image
cluster_size qcow2 cluster size
preallocation Preallocation mode (allowed values: off, metadata, falloc, full)
lazy_refcounts Postpone refcount updates
+refcount_bits Width of a reference count entry in bits
nocow Turn off copy-on-write (valid only on btrfs)
Testing: amend -f qcow2 -o cluster_size=4k -o help TEST_DIR/t.qcow2
@@ -458,6 +489,7 @@ encryption Encrypt the image
cluster_size qcow2 cluster size
preallocation Preallocation mode (allowed values: off, metadata, falloc, full)
lazy_refcounts Postpone refcount updates
+refcount_bits Width of a reference count entry in bits
nocow Turn off copy-on-write (valid only on btrfs)
Testing: amend -f qcow2 -o cluster_size=4k -o ? TEST_DIR/t.qcow2
@@ -470,6 +502,7 @@ encryption Encrypt the image
cluster_size qcow2 cluster size
preallocation Preallocation mode (allowed values: off, metadata, falloc, full)
lazy_refcounts Postpone refcount updates
+refcount_bits Width of a reference count entry in bits
nocow Turn off copy-on-write (valid only on btrfs)
Testing: amend -f qcow2 -o backing_file=TEST_DIR/t.qcow2,,help TEST_DIR/t.qcow2
@@ -499,6 +532,7 @@ encryption Encrypt the image
cluster_size qcow2 cluster size
preallocation Preallocation mode (allowed values: off, metadata, falloc, full)
lazy_refcounts Postpone refcount updates
+refcount_bits Width of a reference count entry in bits
Testing: convert -o help
Supported options:
diff --git a/tests/qemu-iotests/085.out b/tests/qemu-iotests/085.out
index 0f2b17f99..5eb8b947c 100644
--- a/tests/qemu-iotests/085.out
+++ b/tests/qemu-iotests/085.out
@@ -11,7 +11,7 @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728
=== Create a single snapshot on virtio0 ===
-Formatting 'TEST_DIR/1-snapshot-v0.qcow2', fmt=qcow2 size=134217728 backing_file='TEST_DIR/t.qcow2.orig' backing_fmt='qcow2' encryption=off cluster_size=65536 lazy_refcounts=off
+Formatting 'TEST_DIR/1-snapshot-v0.qcow2', fmt=qcow2 size=134217728 backing_file='TEST_DIR/t.qcow2.orig' backing_fmt='qcow2' encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
{"return": {}}
=== Invalid command - missing device and nodename ===
@@ -25,31 +25,31 @@ Formatting 'TEST_DIR/1-snapshot-v0.qcow2', fmt=qcow2 size=134217728 backing_file
=== Create several transactional group snapshots ===
-Formatting 'TEST_DIR/2-snapshot-v0.qcow2', fmt=qcow2 size=134217728 backing_file='TEST_DIR/1-snapshot-v0.qcow2' backing_fmt='qcow2' encryption=off cluster_size=65536 lazy_refcounts=off
-Formatting 'TEST_DIR/2-snapshot-v1.qcow2', fmt=qcow2 size=134217728 backing_file='TEST_DIR/t.qcow2' backing_fmt='qcow2' encryption=off cluster_size=65536 lazy_refcounts=off
+Formatting 'TEST_DIR/2-snapshot-v0.qcow2', fmt=qcow2 size=134217728 backing_file='TEST_DIR/1-snapshot-v0.qcow2' backing_fmt='qcow2' encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
+Formatting 'TEST_DIR/2-snapshot-v1.qcow2', fmt=qcow2 size=134217728 backing_file='TEST_DIR/t.qcow2' backing_fmt='qcow2' encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
{"return": {}}
-Formatting 'TEST_DIR/3-snapshot-v0.qcow2', fmt=qcow2 size=134217728 backing_file='TEST_DIR/2-snapshot-v0.qcow2' backing_fmt='qcow2' encryption=off cluster_size=65536 lazy_refcounts=off
-Formatting 'TEST_DIR/3-snapshot-v1.qcow2', fmt=qcow2 size=134217728 backing_file='TEST_DIR/2-snapshot-v1.qcow2' backing_fmt='qcow2' encryption=off cluster_size=65536 lazy_refcounts=off
+Formatting 'TEST_DIR/3-snapshot-v0.qcow2', fmt=qcow2 size=134217728 backing_file='TEST_DIR/2-snapshot-v0.qcow2' backing_fmt='qcow2' encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
+Formatting 'TEST_DIR/3-snapshot-v1.qcow2', fmt=qcow2 size=134217728 backing_file='TEST_DIR/2-snapshot-v1.qcow2' backing_fmt='qcow2' encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
{"return": {}}
-Formatting 'TEST_DIR/4-snapshot-v0.qcow2', fmt=qcow2 size=134217728 backing_file='TEST_DIR/3-snapshot-v0.qcow2' backing_fmt='qcow2' encryption=off cluster_size=65536 lazy_refcounts=off
-Formatting 'TEST_DIR/4-snapshot-v1.qcow2', fmt=qcow2 size=134217728 backing_file='TEST_DIR/3-snapshot-v1.qcow2' backing_fmt='qcow2' encryption=off cluster_size=65536 lazy_refcounts=off
+Formatting 'TEST_DIR/4-snapshot-v0.qcow2', fmt=qcow2 size=134217728 backing_file='TEST_DIR/3-snapshot-v0.qcow2' backing_fmt='qcow2' encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
+Formatting 'TEST_DIR/4-snapshot-v1.qcow2', fmt=qcow2 size=134217728 backing_file='TEST_DIR/3-snapshot-v1.qcow2' backing_fmt='qcow2' encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
{"return": {}}
-Formatting 'TEST_DIR/5-snapshot-v0.qcow2', fmt=qcow2 size=134217728 backing_file='TEST_DIR/4-snapshot-v0.qcow2' backing_fmt='qcow2' encryption=off cluster_size=65536 lazy_refcounts=off
-Formatting 'TEST_DIR/5-snapshot-v1.qcow2', fmt=qcow2 size=134217728 backing_file='TEST_DIR/4-snapshot-v1.qcow2' backing_fmt='qcow2' encryption=off cluster_size=65536 lazy_refcounts=off
+Formatting 'TEST_DIR/5-snapshot-v0.qcow2', fmt=qcow2 size=134217728 backing_file='TEST_DIR/4-snapshot-v0.qcow2' backing_fmt='qcow2' encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
+Formatting 'TEST_DIR/5-snapshot-v1.qcow2', fmt=qcow2 size=134217728 backing_file='TEST_DIR/4-snapshot-v1.qcow2' backing_fmt='qcow2' encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
{"return": {}}
-Formatting 'TEST_DIR/6-snapshot-v0.qcow2', fmt=qcow2 size=134217728 backing_file='TEST_DIR/5-snapshot-v0.qcow2' backing_fmt='qcow2' encryption=off cluster_size=65536 lazy_refcounts=off
-Formatting 'TEST_DIR/6-snapshot-v1.qcow2', fmt=qcow2 size=134217728 backing_file='TEST_DIR/5-snapshot-v1.qcow2' backing_fmt='qcow2' encryption=off cluster_size=65536 lazy_refcounts=off
+Formatting 'TEST_DIR/6-snapshot-v0.qcow2', fmt=qcow2 size=134217728 backing_file='TEST_DIR/5-snapshot-v0.qcow2' backing_fmt='qcow2' encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
+Formatting 'TEST_DIR/6-snapshot-v1.qcow2', fmt=qcow2 size=134217728 backing_file='TEST_DIR/5-snapshot-v1.qcow2' backing_fmt='qcow2' encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
{"return": {}}
-Formatting 'TEST_DIR/7-snapshot-v0.qcow2', fmt=qcow2 size=134217728 backing_file='TEST_DIR/6-snapshot-v0.qcow2' backing_fmt='qcow2' encryption=off cluster_size=65536 lazy_refcounts=off
-Formatting 'TEST_DIR/7-snapshot-v1.qcow2', fmt=qcow2 size=134217728 backing_file='TEST_DIR/6-snapshot-v1.qcow2' backing_fmt='qcow2' encryption=off cluster_size=65536 lazy_refcounts=off
+Formatting 'TEST_DIR/7-snapshot-v0.qcow2', fmt=qcow2 size=134217728 backing_file='TEST_DIR/6-snapshot-v0.qcow2' backing_fmt='qcow2' encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
+Formatting 'TEST_DIR/7-snapshot-v1.qcow2', fmt=qcow2 size=134217728 backing_file='TEST_DIR/6-snapshot-v1.qcow2' backing_fmt='qcow2' encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
{"return": {}}
-Formatting 'TEST_DIR/8-snapshot-v0.qcow2', fmt=qcow2 size=134217728 backing_file='TEST_DIR/7-snapshot-v0.qcow2' backing_fmt='qcow2' encryption=off cluster_size=65536 lazy_refcounts=off
-Formatting 'TEST_DIR/8-snapshot-v1.qcow2', fmt=qcow2 size=134217728 backing_file='TEST_DIR/7-snapshot-v1.qcow2' backing_fmt='qcow2' encryption=off cluster_size=65536 lazy_refcounts=off
+Formatting 'TEST_DIR/8-snapshot-v0.qcow2', fmt=qcow2 size=134217728 backing_file='TEST_DIR/7-snapshot-v0.qcow2' backing_fmt='qcow2' encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
+Formatting 'TEST_DIR/8-snapshot-v1.qcow2', fmt=qcow2 size=134217728 backing_file='TEST_DIR/7-snapshot-v1.qcow2' backing_fmt='qcow2' encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
{"return": {}}
-Formatting 'TEST_DIR/9-snapshot-v0.qcow2', fmt=qcow2 size=134217728 backing_file='TEST_DIR/8-snapshot-v0.qcow2' backing_fmt='qcow2' encryption=off cluster_size=65536 lazy_refcounts=off
-Formatting 'TEST_DIR/9-snapshot-v1.qcow2', fmt=qcow2 size=134217728 backing_file='TEST_DIR/8-snapshot-v1.qcow2' backing_fmt='qcow2' encryption=off cluster_size=65536 lazy_refcounts=off
+Formatting 'TEST_DIR/9-snapshot-v0.qcow2', fmt=qcow2 size=134217728 backing_file='TEST_DIR/8-snapshot-v0.qcow2' backing_fmt='qcow2' encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
+Formatting 'TEST_DIR/9-snapshot-v1.qcow2', fmt=qcow2 size=134217728 backing_file='TEST_DIR/8-snapshot-v1.qcow2' backing_fmt='qcow2' encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
{"return": {}}
-Formatting 'TEST_DIR/10-snapshot-v0.qcow2', fmt=qcow2 size=134217728 backing_file='TEST_DIR/9-snapshot-v0.qcow2' backing_fmt='qcow2' encryption=off cluster_size=65536 lazy_refcounts=off
-Formatting 'TEST_DIR/10-snapshot-v1.qcow2', fmt=qcow2 size=134217728 backing_file='TEST_DIR/9-snapshot-v1.qcow2' backing_fmt='qcow2' encryption=off cluster_size=65536 lazy_refcounts=off
+Formatting 'TEST_DIR/10-snapshot-v0.qcow2', fmt=qcow2 size=134217728 backing_file='TEST_DIR/9-snapshot-v0.qcow2' backing_fmt='qcow2' encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
+Formatting 'TEST_DIR/10-snapshot-v1.qcow2', fmt=qcow2 size=134217728 backing_file='TEST_DIR/9-snapshot-v1.qcow2' backing_fmt='qcow2' encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
{"return": {}}
*** done
diff --git a/tests/qemu-iotests/089 b/tests/qemu-iotests/089
index 6f74cecde..3e0038dde 100755
--- a/tests/qemu-iotests/089
+++ b/tests/qemu-iotests/089
@@ -41,6 +41,8 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
_supported_fmt qcow2
_supported_proto file
_supported_os Linux
+# Because anything other than 16 would change the output of qemu_io -c info
+_unsupported_imgopts 'refcount_bits=\([^1]\|.\([^6]\|$\)\)'
# Using an image filename containing quotation marks will render the JSON data
# below invalid. In that case, we have little choice but simply not to run this
diff --git a/tests/qemu-iotests/089.out b/tests/qemu-iotests/089.out
index a6d37118c..5b541a340 100644
--- a/tests/qemu-iotests/089.out
+++ b/tests/qemu-iotests/089.out
@@ -43,6 +43,7 @@ vm state offset: 512 MiB
Format specific information:
compat: 1.1
lazy refcounts: false
+ refcount bits: 16
corrupt: false
format name: IMGFMT
cluster size: 64 KiB
@@ -50,5 +51,6 @@ vm state offset: 512 MiB
Format specific information:
compat: 1.1
lazy refcounts: false
+ refcount bits: 16
corrupt: false
*** done
diff --git a/tests/qemu-iotests/104 b/tests/qemu-iotests/104
index f32752bb6..2e35ea80d 100755
--- a/tests/qemu-iotests/104
+++ b/tests/qemu-iotests/104
@@ -34,7 +34,7 @@ trap "exit \$status" 0 1 2 3 15
. ./common.rc
. ./common.filter
-_supported_fmt generic
+_supported_fmt raw qcow qcow2 qed vdi vmdk vhdx
_supported_proto generic
_supported_os Linux
diff --git a/tests/qemu-iotests/108 b/tests/qemu-iotests/108
index 12fc92a63..ce447498e 100755
--- a/tests/qemu-iotests/108
+++ b/tests/qemu-iotests/108
@@ -43,6 +43,8 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
_supported_fmt qcow2
_supported_proto file
_supported_os Linux
+# This test directly modifies a refblock so it relies on refcount_bits being 16
+_unsupported_imgopts 'refcount_bits=\([^1]\|.\([^6]\|$\)\)'
echo
echo '=== Repairing an image without any refcount table ==='
diff --git a/tests/qemu-iotests/112 b/tests/qemu-iotests/112
new file mode 100755
index 000000000..3f054a3fc
--- /dev/null
+++ b/tests/qemu-iotests/112
@@ -0,0 +1,187 @@
+#!/bin/bash
+#
+# Test cases for different refcount_bits values
+#
+# Copyright (C) 2015 Red Hat, Inc.
+#
+# 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/>.
+#
+
+# creator
+owner=mreitz@redhat.com
+
+seq="$(basename $0)"
+echo "QA output created by $seq"
+
+here="$PWD"
+tmp=/tmp/$$
+status=1 # failure is the default!
+
+_cleanup()
+{
+ _cleanup_test_img
+}
+trap "_cleanup; exit \$status" 0 1 2 3 15
+
+# get standard environment, filters and checks
+. ./common.rc
+. ./common.filter
+
+# This tests qcow2-specific low-level functionality
+_supported_fmt qcow2
+_supported_proto file
+_supported_os Linux
+# This test will set refcount_bits on its own which would conflict with the
+# manual setting; compat will be overridden as well
+_unsupported_imgopts refcount_bits 'compat=0.10'
+
+function print_refcount_bits()
+{
+ $QEMU_IMG info "$TEST_IMG" | sed -n '/refcount bits:/ s/^ *//p'
+}
+
+echo
+echo '=== refcount_bits limits ==='
+echo
+
+# Must be positive (non-zero)
+IMGOPTS="$IMGOPTS,refcount_bits=0" _make_test_img 64M
+# Must be positive (non-negative)
+IMGOPTS="$IMGOPTS,refcount_bits=-1" _make_test_img 64M
+# May not exceed 64
+IMGOPTS="$IMGOPTS,refcount_bits=128" _make_test_img 64M
+# Must be a power of two
+IMGOPTS="$IMGOPTS,refcount_bits=42" _make_test_img 64M
+
+# 1 is the minimum
+IMGOPTS="$IMGOPTS,refcount_bits=1" _make_test_img 64M
+print_refcount_bits
+
+# 64 is the maximum
+IMGOPTS="$IMGOPTS,refcount_bits=64" _make_test_img 64M
+print_refcount_bits
+
+# 16 is the default
+_make_test_img 64M
+print_refcount_bits
+
+echo
+echo '=== refcount_bits and compat=0.10 ==='
+echo
+
+# Should work
+IMGOPTS="$IMGOPTS,compat=0.10,refcount_bits=16" _make_test_img 64M
+print_refcount_bits
+
+# Should not work
+IMGOPTS="$IMGOPTS,compat=0.10,refcount_bits=1" _make_test_img 64M
+IMGOPTS="$IMGOPTS,compat=0.10,refcount_bits=64" _make_test_img 64M
+
+
+echo
+echo '=== Snapshot limit on refcount_bits=1 ==='
+echo
+
+IMGOPTS="$IMGOPTS,refcount_bits=1" _make_test_img 64M
+print_refcount_bits
+
+$QEMU_IO -c 'write 0 512' "$TEST_IMG" | _filter_qemu_io
+
+# Should fail for now; in the future, this might be supported by automatically
+# copying all clusters with overflowing refcount
+$QEMU_IMG snapshot -c foo "$TEST_IMG"
+
+# The new L1 table could/should be leaked
+_check_test_img
+
+echo
+echo '=== Snapshot limit on refcount_bits=2 ==='
+echo
+
+IMGOPTS="$IMGOPTS,refcount_bits=2" _make_test_img 64M
+print_refcount_bits
+
+$QEMU_IO -c 'write 0 512' "$TEST_IMG" | _filter_qemu_io
+
+# Should succeed
+$QEMU_IMG snapshot -c foo "$TEST_IMG"
+$QEMU_IMG snapshot -c bar "$TEST_IMG"
+# Should fail (4th reference)
+$QEMU_IMG snapshot -c baz "$TEST_IMG"
+
+# The new L1 table could/should be leaked
+_check_test_img
+
+echo
+echo '=== Compressed clusters with refcount_bits=1 ==='
+echo
+
+IMGOPTS="$IMGOPTS,refcount_bits=1" _make_test_img 64M
+print_refcount_bits
+
+# Both should fit into a single host cluster; instead of failing to increase the
+# refcount of that cluster, qemu should just allocate a new cluster and make
+# this operation succeed
+$QEMU_IO -c 'write -P 0 -c 0 64k' \
+ -c 'write -P 1 -c 64k 64k' \
+ "$TEST_IMG" | _filter_qemu_io
+
+_check_test_img
+
+echo
+echo '=== MSb set in 64 bit refcount ==='
+echo
+
+IMGOPTS="$IMGOPTS,refcount_bits=64" _make_test_img 64M
+print_refcount_bits
+
+$QEMU_IO -c 'write 0 512' "$TEST_IMG" | _filter_qemu_io
+
+# Set the MSb in the refblock entry of the data cluster
+poke_file "$TEST_IMG" $((0x20028)) "\x80\x00\x00\x00\x00\x00\x00\x00"
+
+# Clear OFLAG_COPIED in the L2 entry of the data cluster
+poke_file "$TEST_IMG" $((0x40000)) "\x00\x00\x00\x00\x00\x05\x00\x00"
+
+# Try to write to that cluster (should work, even though the MSb is set)
+$QEMU_IO -c 'write 0 512' "$TEST_IMG" | _filter_qemu_io
+
+echo
+echo '=== Snapshot on maximum 64 bit refcount value ==='
+echo
+
+IMGOPTS="$IMGOPTS,refcount_bits=64" _make_test_img 64M
+print_refcount_bits
+
+$QEMU_IO -c 'write 0 512' "$TEST_IMG" | _filter_qemu_io
+
+# Set the refblock entry to the maximum value possible
+poke_file "$TEST_IMG" $((0x20028)) "\xff\xff\xff\xff\xff\xff\xff\xff"
+
+# Clear OFLAG_COPIED in the L2 entry of the data cluster
+poke_file "$TEST_IMG" $((0x40000)) "\x00\x00\x00\x00\x00\x05\x00\x00"
+
+# Try a snapshot (should correctly identify the overflow; may work in the future
+# by falling back to COW)
+$QEMU_IMG snapshot -c foo "$TEST_IMG"
+
+# The new L1 table could/should be leaked; and obviously the data cluster is
+# leaked (refcount=UINT64_MAX reference=1)
+_check_test_img
+
+
+# success, all done
+echo '*** done'
+rm -f $seq.full
+status=0
diff --git a/tests/qemu-iotests/112.out b/tests/qemu-iotests/112.out
new file mode 100644
index 000000000..9a98633f6
--- /dev/null
+++ b/tests/qemu-iotests/112.out
@@ -0,0 +1,84 @@
+QA output created by 112
+
+=== refcount_bits limits ===
+
+qemu-img: TEST_DIR/t.IMGFMT: Refcount width must be a power of two and may not exceed 64 bits
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
+qemu-img: TEST_DIR/t.IMGFMT: Refcount width must be a power of two and may not exceed 64 bits
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 refcount_bits=-1
+qemu-img: TEST_DIR/t.IMGFMT: Refcount width must be a power of two and may not exceed 64 bits
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
+qemu-img: TEST_DIR/t.IMGFMT: Refcount width must be a power of two and may not exceed 64 bits
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
+refcount bits: 1
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
+refcount bits: 64
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
+refcount bits: 16
+
+=== refcount_bits and compat=0.10 ===
+
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
+refcount bits: 16
+qemu-img: TEST_DIR/t.IMGFMT: Different refcount widths than 16 bits require compatibility level 1.1 or above (use compat=1.1 or greater)
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
+qemu-img: TEST_DIR/t.IMGFMT: Different refcount widths than 16 bits require compatibility level 1.1 or above (use compat=1.1 or greater)
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
+
+=== Snapshot limit on refcount_bits=1 ===
+
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
+refcount bits: 1
+wrote 512/512 bytes at offset 0
+512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+qemu-img: Could not create snapshot 'foo': -22 (Invalid argument)
+Leaked cluster 6 refcount=1 reference=0
+
+1 leaked clusters were found on the image.
+This means waste of disk space, but no harm to data.
+
+=== Snapshot limit on refcount_bits=2 ===
+
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
+refcount bits: 2
+wrote 512/512 bytes at offset 0
+512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+qemu-img: Could not create snapshot 'baz': -22 (Invalid argument)
+Leaked cluster 7 refcount=1 reference=0
+
+1 leaked clusters were found on the image.
+This means waste of disk space, but no harm to data.
+
+=== Compressed clusters with refcount_bits=1 ===
+
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
+refcount bits: 1
+wrote 65536/65536 bytes at offset 0
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+wrote 65536/65536 bytes at offset 65536
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+No errors were found on the image.
+
+=== MSb set in 64 bit refcount ===
+
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
+refcount bits: 64
+wrote 512/512 bytes at offset 0
+512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+wrote 512/512 bytes at offset 0
+512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+
+=== Snapshot on maximum 64 bit refcount value ===
+
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
+refcount bits: 64
+wrote 512/512 bytes at offset 0
+512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+qemu-img: Could not create snapshot 'foo': -22 (Invalid argument)
+Leaked cluster 5 refcount=18446744073709551615 reference=1
+Leaked cluster 6 refcount=1 reference=0
+
+2 leaked clusters were found on the image.
+This means waste of disk space, but no harm to data.
+*** done
diff --git a/tests/qemu-iotests/006 b/tests/qemu-iotests/128
index 0c0cf5d32..249a86558 100755
--- a/tests/qemu-iotests/006
+++ b/tests/qemu-iotests/128
@@ -1,9 +1,8 @@
#!/bin/bash
#
-# Make sure qemu-img rejects > 127GB images for the vpc format as the format
-# doesn't support this.
+# Test that opening O_DIRECT succeeds when image file I/O produces EIO
#
-# Copyright (C) 2009 Red Hat, Inc.
+# Copyright (C) 2015 Red Hat, Inc.
#
# 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
@@ -20,7 +19,7 @@
#
# creator
-owner=hch@lst.de
+owner=stefanha@redhat.com
seq=`basename $0`
echo "QA output created by $seq"
@@ -29,9 +28,34 @@ here=`pwd`
tmp=/tmp/$$
status=1 # failure is the default!
+devname="eiodev$$"
+
+_setup_eiodev()
+{
+ # This test should either be run as root or with passwordless sudo
+ for cmd in "" "sudo -n"; do
+ echo "0 $((1024 * 1024 * 1024 / 512)) error" | \
+ $cmd dmsetup create "$devname" 2>/dev/null
+ if [ "$?" -eq 0 ]; then
+ return
+ fi
+ done
+ _notrun "root privileges required to run dmsetup"
+}
+
+_cleanup_eiodev()
+{
+ for cmd in "" "sudo -n"; do
+ $cmd dmsetup remove "$devname" 2>/dev/null
+ if [ "$?" -eq 0 ]; then
+ return
+ fi
+ done
+}
+
_cleanup()
{
- _cleanup_test_img
+ _cleanup_eiodev
}
trap "_cleanup; exit \$status" 0 1 2 3 15
@@ -39,14 +63,18 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
. ./common.rc
. ./common.filter
-_supported_fmt vpc
-_supported_proto generic
+_supported_fmt raw
+_supported_proto file
_supported_os Linux
+_setup_eiodev
+
+TEST_IMG="/dev/mapper/$devname"
echo
-echo "creating 128GB image"
-_make_test_img 128G
+echo "== reading from error device =="
+# Opening image should succeed but the read operation should fail
+$QEMU_IO --format "$IMGFMT" --nocache -c "read 0 65536" "$TEST_IMG" | _filter_qemu_io
# success, all done
echo "*** done"
diff --git a/tests/qemu-iotests/128.out b/tests/qemu-iotests/128.out
new file mode 100644
index 000000000..4e43f5faa
--- /dev/null
+++ b/tests/qemu-iotests/128.out
@@ -0,0 +1,5 @@
+QA output created by 128
+
+== reading from error device ==
+read failed: Input/output error
+*** done
diff --git a/tests/qemu-iotests/common.filter b/tests/qemu-iotests/common.filter
index 06e1bb045..012a8122d 100644
--- a/tests/qemu-iotests/common.filter
+++ b/tests/qemu-iotests/common.filter
@@ -192,7 +192,8 @@ _filter_img_create()
-e "s# block_size=[0-9]\\+##g" \
-e "s# block_state_zero=\\(on\\|off\\)##g" \
-e "s# log_size=[0-9]\\+##g" \
- -e "s/archipelago:a/TEST_DIR\//g"
+ -e "s/archipelago:a/TEST_DIR\//g" \
+ -e "s# refcount_bits=[0-9]\\+##g"
}
_filter_img_info()
diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group
index 0d3b95c25..71f19d4ec 100644
--- a/tests/qemu-iotests/group
+++ b/tests/qemu-iotests/group
@@ -12,7 +12,7 @@
003 rw auto
004 rw auto quick
005 img auto quick
-006 img auto
+# 006 was removed, do not reuse
007 snapshot auto
008 rw auto quick
009 rw auto quick
@@ -116,7 +116,9 @@
109 rw auto
110 rw auto backing quick
111 rw auto quick
+112 rw auto
113 rw auto quick
114 rw auto quick
116 rw auto quick
123 rw auto quick
+128 rw auto quick
diff --git a/tests/test-coroutine.c b/tests/test-coroutine.c
index 27d1b6f8e..b552d9f5e 100644
--- a/tests/test-coroutine.c
+++ b/tests/test-coroutine.c
@@ -13,6 +13,7 @@
#include <glib.h>
#include "block/coroutine.h"
+#include "block/coroutine_int.h"
/*
* Check that qemu_in_coroutine() works
@@ -122,6 +123,30 @@ static void test_yield(void)
g_assert_cmpint(i, ==, 5); /* coroutine must yield 5 times */
}
+static void coroutine_fn c2_fn(void *opaque)
+{
+ qemu_coroutine_yield();
+}
+
+static void coroutine_fn c1_fn(void *opaque)
+{
+ Coroutine *c2 = opaque;
+ qemu_coroutine_enter(c2, NULL);
+}
+
+static void test_co_queue(void)
+{
+ Coroutine *c1;
+ Coroutine *c2;
+
+ c1 = qemu_coroutine_create(c1_fn);
+ c2 = qemu_coroutine_create(c2_fn);
+
+ qemu_coroutine_enter(c1, c2);
+ memset(c1, 0xff, sizeof(Coroutine));
+ qemu_coroutine_enter(c2, NULL);
+}
+
/*
* Check that creation, enter, and return work
*/
@@ -343,6 +368,7 @@ static void perf_cost(void)
int main(int argc, char **argv)
{
g_test_init(&argc, &argv, NULL);
+ g_test_add_func("/basic/co_queue", test_co_queue);
g_test_add_func("/basic/lifecycle", test_lifecycle);
g_test_add_func("/basic/yield", test_yield);
g_test_add_func("/basic/nesting", test_nesting);
diff --git a/tests/test-x86-cpuid.c b/tests/test-x86-cpuid.c
index 8d9f96a11..6cd20d4a2 100644
--- a/tests/test-x86-cpuid.c
+++ b/tests/test-x86-cpuid.c
@@ -24,7 +24,7 @@
#include <glib.h>
-#include "topology.h"
+#include "hw/i386/topology.h"
static void test_topo_bits(void)
{
diff --git a/tests/virtio-blk-test.c b/tests/virtio-blk-test.c
index 89d7cbf91..4078321a2 100644
--- a/tests/virtio-blk-test.c
+++ b/tests/virtio-blk-test.c
@@ -16,9 +16,11 @@
#include "libqtest.h"
#include "libqos/virtio.h"
#include "libqos/virtio-pci.h"
+#include "libqos/virtio-mmio.h"
#include "libqos/pci-pc.h"
#include "libqos/malloc.h"
#include "libqos/malloc-pc.h"
+#include "libqos/malloc-generic.h"
#include "qemu/bswap.h"
#define QVIRTIO_BLK_F_BARRIER 0x00000001
@@ -42,10 +44,14 @@
#define TEST_IMAGE_SIZE (64 * 1024 * 1024)
#define QVIRTIO_BLK_TIMEOUT_US (30 * 1000 * 1000)
+#define PCI_SLOT_HP 0x06
#define PCI_SLOT 0x04
#define PCI_FN 0x00
-#define PCI_SLOT_HP 0x06
+#define MMIO_PAGE_SIZE 4096
+#define MMIO_DEV_BASE_ADDR 0x0A003E00
+#define MMIO_RAM_ADDR 0x40000000
+#define MMIO_RAM_SIZE 0x20000000
typedef struct QVirtioBlkReq {
uint32_t type;
@@ -55,11 +61,10 @@ typedef struct QVirtioBlkReq {
uint8_t status;
} QVirtioBlkReq;
-static QPCIBus *test_start(void)
+static char *drive_create(void)
{
- char *cmdline;
- char tmp_path[] = "/tmp/qtest.XXXXXX";
int fd, ret;
+ char *tmp_path = g_strdup("/tmp/qtest.XXXXXX");
/* Create a temporary raw image */
fd = mkstemp(tmp_path);
@@ -68,24 +73,52 @@ static QPCIBus *test_start(void)
g_assert_cmpint(ret, ==, 0);
close(fd);
+ return tmp_path;
+}
+
+static QPCIBus *pci_test_start(void)
+{
+ char *cmdline;
+ char *tmp_path;
+
+ tmp_path = drive_create();
+
cmdline = g_strdup_printf("-drive if=none,id=drive0,file=%s,format=raw "
- "-drive if=none,id=drive1,file=/dev/null,format=raw "
- "-device virtio-blk-pci,id=drv0,drive=drive0,"
- "addr=%x.%x",
- tmp_path, PCI_SLOT, PCI_FN);
+ "-drive if=none,id=drive1,file=/dev/null,format=raw "
+ "-device virtio-blk-pci,id=drv0,drive=drive0,"
+ "addr=%x.%x",
+ tmp_path, PCI_SLOT, PCI_FN);
qtest_start(cmdline);
unlink(tmp_path);
+ g_free(tmp_path);
g_free(cmdline);
return qpci_init_pc();
}
+static void arm_test_start(void)
+{
+ char *cmdline;
+ char *tmp_path;
+
+ tmp_path = drive_create();
+
+ cmdline = g_strdup_printf("-machine virt "
+ "-drive if=none,id=drive0,file=%s,format=raw "
+ "-device virtio-blk-device,drive=drive0",
+ tmp_path);
+ qtest_start(cmdline);
+ unlink(tmp_path);
+ g_free(tmp_path);
+ g_free(cmdline);
+}
+
static void test_end(void)
{
qtest_end();
}
-static QVirtioPCIDevice *virtio_blk_init(QPCIBus *bus, int slot)
+static QVirtioPCIDevice *virtio_blk_pci_init(QPCIBus *bus, int slot)
{
QVirtioPCIDevice *dev;
@@ -135,14 +168,10 @@ static uint64_t virtio_blk_request(QGuestAllocator *alloc, QVirtioBlkReq *req,
return addr;
}
-static void pci_basic(void)
+static void test_basic(const QVirtioBus *bus, QVirtioDevice *dev,
+ QGuestAllocator *alloc, QVirtQueue *vq, uint64_t device_specific)
{
- QVirtioPCIDevice *dev;
- QPCIBus *bus;
- QVirtQueuePCI *vqpci;
- QGuestAllocator *alloc;
QVirtioBlkReq req;
- void *addr;
uint64_t req_addr;
uint64_t capacity;
uint32_t features;
@@ -150,29 +179,19 @@ static void pci_basic(void)
uint8_t status;
char *data;
- bus = test_start();
+ capacity = qvirtio_config_readq(bus, dev, device_specific);
- dev = virtio_blk_init(bus, PCI_SLOT);
-
- /* MSI-X is not enabled */
- addr = dev->addr + QVIRTIO_DEVICE_SPECIFIC_NO_MSIX;
-
- capacity = qvirtio_config_readq(&qvirtio_pci, &dev->vdev, addr);
g_assert_cmpint(capacity, ==, TEST_IMAGE_SIZE / 512);
- features = qvirtio_get_features(&qvirtio_pci, &dev->vdev);
+ features = qvirtio_get_features(bus, dev);
features = features & ~(QVIRTIO_F_BAD_FEATURE |
QVIRTIO_F_RING_INDIRECT_DESC | QVIRTIO_F_RING_EVENT_IDX |
QVIRTIO_BLK_F_SCSI);
- qvirtio_set_features(&qvirtio_pci, &dev->vdev, features);
-
- alloc = pc_alloc_init();
- vqpci = (QVirtQueuePCI *)qvirtqueue_setup(&qvirtio_pci, &dev->vdev,
- alloc, 0);
+ qvirtio_set_features(bus, dev, features);
- qvirtio_set_driver_ok(&qvirtio_pci, &dev->vdev);
+ qvirtio_set_driver_ok(bus, dev);
- /* Write and read with 2 descriptor layout */
+ /* Write and read with 3 descriptor layout */
/* Write request */
req.type = QVIRTIO_BLK_T_OUT;
req.ioprio = 1;
@@ -184,12 +203,13 @@ static void pci_basic(void)
g_free(req.data);
- free_head = qvirtqueue_add(&vqpci->vq, req_addr, 528, false, true);
- qvirtqueue_add(&vqpci->vq, req_addr + 528, 1, true, false);
- qvirtqueue_kick(&qvirtio_pci, &dev->vdev, &vqpci->vq, free_head);
+ free_head = qvirtqueue_add(vq, req_addr, 16, false, true);
+ qvirtqueue_add(vq, req_addr + 16, 512, false, true);
+ qvirtqueue_add(vq, req_addr + 528, 1, true, false);
- qvirtio_wait_queue_isr(&qvirtio_pci, &dev->vdev, &vqpci->vq,
- QVIRTIO_BLK_TIMEOUT_US);
+ qvirtqueue_kick(bus, dev, vq, free_head);
+
+ qvirtio_wait_queue_isr(bus, dev, vq, QVIRTIO_BLK_TIMEOUT_US);
status = readb(req_addr + 528);
g_assert_cmpint(status, ==, 0);
@@ -205,13 +225,13 @@ static void pci_basic(void)
g_free(req.data);
- free_head = qvirtqueue_add(&vqpci->vq, req_addr, 16, false, true);
- qvirtqueue_add(&vqpci->vq, req_addr + 16, 513, true, false);
+ free_head = qvirtqueue_add(vq, req_addr, 16, false, true);
+ qvirtqueue_add(vq, req_addr + 16, 512, true, true);
+ qvirtqueue_add(vq, req_addr + 528, 1, true, false);
- qvirtqueue_kick(&qvirtio_pci, &dev->vdev, &vqpci->vq, free_head);
+ qvirtqueue_kick(bus, dev, vq, free_head);
- qvirtio_wait_queue_isr(&qvirtio_pci, &dev->vdev, &vqpci->vq,
- QVIRTIO_BLK_TIMEOUT_US);
+ qvirtio_wait_queue_isr(bus, dev, vq, QVIRTIO_BLK_TIMEOUT_US);
status = readb(req_addr + 528);
g_assert_cmpint(status, ==, 0);
@@ -222,61 +242,84 @@ static void pci_basic(void)
guest_free(alloc, req_addr);
- /* Write and read with 3 descriptor layout */
- /* Write request */
- req.type = QVIRTIO_BLK_T_OUT;
- req.ioprio = 1;
- req.sector = 1;
- req.data = g_malloc0(512);
- strcpy(req.data, "TEST");
+ if (features & QVIRTIO_F_ANY_LAYOUT) {
+ /* Write and read with 2 descriptor layout */
+ /* Write request */
+ req.type = QVIRTIO_BLK_T_OUT;
+ req.ioprio = 1;
+ req.sector = 1;
+ req.data = g_malloc0(512);
+ strcpy(req.data, "TEST");
- req_addr = virtio_blk_request(alloc, &req, 512);
+ req_addr = virtio_blk_request(alloc, &req, 512);
- free_head = qvirtqueue_add(&vqpci->vq, req_addr, 16, false, true);
- qvirtqueue_add(&vqpci->vq, req_addr + 16, 512, false, true);
- qvirtqueue_add(&vqpci->vq, req_addr + 528, 1, true, false);
+ g_free(req.data);
- qvirtqueue_kick(&qvirtio_pci, &dev->vdev, &vqpci->vq, free_head);
+ free_head = qvirtqueue_add(vq, req_addr, 528, false, true);
+ qvirtqueue_add(vq, req_addr + 528, 1, true, false);
+ qvirtqueue_kick(bus, dev, vq, free_head);
- qvirtio_wait_queue_isr(&qvirtio_pci, &dev->vdev, &vqpci->vq,
- QVIRTIO_BLK_TIMEOUT_US);
- status = readb(req_addr + 528);
- g_assert_cmpint(status, ==, 0);
+ qvirtio_wait_queue_isr(bus, dev, vq, QVIRTIO_BLK_TIMEOUT_US);
+ status = readb(req_addr + 528);
+ g_assert_cmpint(status, ==, 0);
- guest_free(alloc, req_addr);
+ guest_free(alloc, req_addr);
- /* Read request */
- req.type = QVIRTIO_BLK_T_IN;
- req.ioprio = 1;
- req.sector = 1;
- req.data = g_malloc0(512);
+ /* Read request */
+ req.type = QVIRTIO_BLK_T_IN;
+ req.ioprio = 1;
+ req.sector = 1;
+ req.data = g_malloc0(512);
- req_addr = virtio_blk_request(alloc, &req, 512);
+ req_addr = virtio_blk_request(alloc, &req, 512);
- g_free(req.data);
+ g_free(req.data);
- free_head = qvirtqueue_add(&vqpci->vq, req_addr, 16, false, true);
- qvirtqueue_add(&vqpci->vq, req_addr + 16, 512, true, true);
- qvirtqueue_add(&vqpci->vq, req_addr + 528, 1, true, false);
+ free_head = qvirtqueue_add(vq, req_addr, 16, false, true);
+ qvirtqueue_add(vq, req_addr + 16, 513, true, false);
- qvirtqueue_kick(&qvirtio_pci, &dev->vdev, &vqpci->vq, free_head);
+ qvirtqueue_kick(bus, dev, vq, free_head);
- qvirtio_wait_queue_isr(&qvirtio_pci, &dev->vdev, &vqpci->vq,
- QVIRTIO_BLK_TIMEOUT_US);
- status = readb(req_addr + 528);
- g_assert_cmpint(status, ==, 0);
+ qvirtio_wait_queue_isr(bus, dev, vq, QVIRTIO_BLK_TIMEOUT_US);
+ status = readb(req_addr + 528);
+ g_assert_cmpint(status, ==, 0);
- data = g_malloc0(512);
- memread(req_addr + 16, data, 512);
- g_assert_cmpstr(data, ==, "TEST");
- g_free(data);
+ data = g_malloc0(512);
+ memread(req_addr + 16, data, 512);
+ g_assert_cmpstr(data, ==, "TEST");
+ g_free(data);
- guest_free(alloc, req_addr);
+ guest_free(alloc, req_addr);
+ }
+}
+
+static void pci_basic(void)
+{
+ QVirtioPCIDevice *dev;
+ QPCIBus *bus;
+ QVirtQueuePCI *vqpci;
+ QGuestAllocator *alloc;
+ void *addr;
+
+ bus = pci_test_start();
+ dev = virtio_blk_pci_init(bus, PCI_SLOT);
+
+ alloc = pc_alloc_init();
+ vqpci = (QVirtQueuePCI *)qvirtqueue_setup(&qvirtio_pci, &dev->vdev,
+ alloc, 0);
+
+ /* MSI-X is not enabled */
+ addr = dev->addr + QVIRTIO_PCI_DEVICE_SPECIFIC_NO_MSIX;
+
+ test_basic(&qvirtio_pci, &dev->vdev, alloc, &vqpci->vq,
+ (uint64_t)(uintptr_t)addr);
/* End test */
guest_free(alloc, vqpci->vq.desc);
+ pc_alloc_uninit(alloc);
qvirtio_pci_device_disable(dev);
g_free(dev);
+ qpci_free_pc(bus);
test_end();
}
@@ -296,14 +339,15 @@ static void pci_indirect(void)
uint8_t status;
char *data;
- bus = test_start();
+ bus = pci_test_start();
- dev = virtio_blk_init(bus, PCI_SLOT);
+ dev = virtio_blk_pci_init(bus, PCI_SLOT);
/* MSI-X is not enabled */
- addr = dev->addr + QVIRTIO_DEVICE_SPECIFIC_NO_MSIX;
+ addr = dev->addr + QVIRTIO_PCI_DEVICE_SPECIFIC_NO_MSIX;
- capacity = qvirtio_config_readq(&qvirtio_pci, &dev->vdev, addr);
+ capacity = qvirtio_config_readq(&qvirtio_pci, &dev->vdev,
+ (uint64_t)(uintptr_t)addr);
g_assert_cmpint(capacity, ==, TEST_IMAGE_SIZE / 512);
features = qvirtio_get_features(&qvirtio_pci, &dev->vdev);
@@ -374,8 +418,10 @@ static void pci_indirect(void)
/* End test */
guest_free(alloc, vqpci->vq.desc);
+ pc_alloc_uninit(alloc);
qvirtio_pci_device_disable(dev);
g_free(dev);
+ qpci_free_pc(bus);
test_end();
}
@@ -387,14 +433,15 @@ static void pci_config(void)
void *addr;
uint64_t capacity;
- bus = test_start();
+ bus = pci_test_start();
- dev = virtio_blk_init(bus, PCI_SLOT);
+ dev = virtio_blk_pci_init(bus, PCI_SLOT);
/* MSI-X is not enabled */
- addr = dev->addr + QVIRTIO_DEVICE_SPECIFIC_NO_MSIX;
+ addr = dev->addr + QVIRTIO_PCI_DEVICE_SPECIFIC_NO_MSIX;
- capacity = qvirtio_config_readq(&qvirtio_pci, &dev->vdev, addr);
+ capacity = qvirtio_config_readq(&qvirtio_pci, &dev->vdev,
+ (uint64_t)(uintptr_t)addr);
g_assert_cmpint(capacity, ==, TEST_IMAGE_SIZE / 512);
qvirtio_set_driver_ok(&qvirtio_pci, &dev->vdev);
@@ -403,11 +450,13 @@ static void pci_config(void)
" 'size': %d } }", n_size);
qvirtio_wait_config_isr(&qvirtio_pci, &dev->vdev, QVIRTIO_BLK_TIMEOUT_US);
- capacity = qvirtio_config_readq(&qvirtio_pci, &dev->vdev, addr);
+ capacity = qvirtio_config_readq(&qvirtio_pci, &dev->vdev,
+ (uint64_t)(uintptr_t)addr);
g_assert_cmpint(capacity, ==, n_size / 512);
qvirtio_pci_device_disable(dev);
g_free(dev);
+ qpci_free_pc(bus);
test_end();
}
@@ -427,18 +476,19 @@ static void pci_msix(void)
uint8_t status;
char *data;
- bus = test_start();
+ bus = pci_test_start();
alloc = pc_alloc_init();
- dev = virtio_blk_init(bus, PCI_SLOT);
+ dev = virtio_blk_pci_init(bus, PCI_SLOT);
qpci_msix_enable(dev->pdev);
qvirtio_pci_set_msix_configuration_vector(dev, alloc, 0);
/* MSI-X is enabled */
- addr = dev->addr + QVIRTIO_DEVICE_SPECIFIC_MSIX;
+ addr = dev->addr + QVIRTIO_PCI_DEVICE_SPECIFIC_MSIX;
- capacity = qvirtio_config_readq(&qvirtio_pci, &dev->vdev, addr);
+ capacity = qvirtio_config_readq(&qvirtio_pci, &dev->vdev,
+ (uint64_t)(uintptr_t)addr);
g_assert_cmpint(capacity, ==, TEST_IMAGE_SIZE / 512);
features = qvirtio_get_features(&qvirtio_pci, &dev->vdev);
@@ -458,7 +508,8 @@ static void pci_msix(void)
qvirtio_wait_config_isr(&qvirtio_pci, &dev->vdev, QVIRTIO_BLK_TIMEOUT_US);
- capacity = qvirtio_config_readq(&qvirtio_pci, &dev->vdev, addr);
+ capacity = qvirtio_config_readq(&qvirtio_pci, &dev->vdev,
+ (uint64_t)(uintptr_t)addr);
g_assert_cmpint(capacity, ==, n_size / 512);
/* Write request */
@@ -472,7 +523,8 @@ static void pci_msix(void)
g_free(req.data);
- free_head = qvirtqueue_add(&vqpci->vq, req_addr, 528, false, true);
+ free_head = qvirtqueue_add(&vqpci->vq, req_addr, 16, false, true);
+ qvirtqueue_add(&vqpci->vq, req_addr + 16, 512, false, true);
qvirtqueue_add(&vqpci->vq, req_addr + 528, 1, true, false);
qvirtqueue_kick(&qvirtio_pci, &dev->vdev, &vqpci->vq, free_head);
@@ -495,7 +547,8 @@ static void pci_msix(void)
g_free(req.data);
free_head = qvirtqueue_add(&vqpci->vq, req_addr, 16, false, true);
- qvirtqueue_add(&vqpci->vq, req_addr + 16, 513, true, false);
+ qvirtqueue_add(&vqpci->vq, req_addr + 16, 512, true, true);
+ qvirtqueue_add(&vqpci->vq, req_addr + 528, 1, true, false);
qvirtqueue_kick(&qvirtio_pci, &dev->vdev, &vqpci->vq, free_head);
@@ -514,10 +567,12 @@ static void pci_msix(void)
guest_free(alloc, req_addr);
/* End test */
- guest_free(alloc, (uint64_t)vqpci->vq.desc);
+ guest_free(alloc, vqpci->vq.desc);
+ pc_alloc_uninit(alloc);
qpci_msix_disable(dev->pdev);
qvirtio_pci_device_disable(dev);
g_free(dev);
+ qpci_free_pc(bus);
test_end();
}
@@ -536,18 +591,19 @@ static void pci_idx(void)
uint8_t status;
char *data;
- bus = test_start();
+ bus = pci_test_start();
alloc = pc_alloc_init();
- dev = virtio_blk_init(bus, PCI_SLOT);
+ dev = virtio_blk_pci_init(bus, PCI_SLOT);
qpci_msix_enable(dev->pdev);
qvirtio_pci_set_msix_configuration_vector(dev, alloc, 0);
/* MSI-X is enabled */
- addr = dev->addr + QVIRTIO_DEVICE_SPECIFIC_MSIX;
+ addr = dev->addr + QVIRTIO_PCI_DEVICE_SPECIFIC_MSIX;
- capacity = qvirtio_config_readq(&qvirtio_pci, &dev->vdev, addr);
+ capacity = qvirtio_config_readq(&qvirtio_pci, &dev->vdev,
+ (uint64_t)(uintptr_t)addr);
g_assert_cmpint(capacity, ==, TEST_IMAGE_SIZE / 512);
features = qvirtio_get_features(&qvirtio_pci, &dev->vdev);
@@ -573,7 +629,8 @@ static void pci_idx(void)
g_free(req.data);
- free_head = qvirtqueue_add(&vqpci->vq, req_addr, 528, false, true);
+ free_head = qvirtqueue_add(&vqpci->vq, req_addr, 16, false, true);
+ qvirtqueue_add(&vqpci->vq, req_addr + 16, 512, false, true);
qvirtqueue_add(&vqpci->vq, req_addr + 528, 1, true, false);
qvirtqueue_kick(&qvirtio_pci, &dev->vdev, &vqpci->vq, free_head);
@@ -593,7 +650,8 @@ static void pci_idx(void)
/* Notify after processing the third request */
qvirtqueue_set_used_event(&vqpci->vq, 2);
- free_head = qvirtqueue_add(&vqpci->vq, req_addr, 528, false, true);
+ free_head = qvirtqueue_add(&vqpci->vq, req_addr, 16, false, true);
+ qvirtqueue_add(&vqpci->vq, req_addr + 16, 512, false, true);
qvirtqueue_add(&vqpci->vq, req_addr + 528, 1, true, false);
qvirtqueue_kick(&qvirtio_pci, &dev->vdev, &vqpci->vq, free_head);
@@ -616,11 +674,11 @@ static void pci_idx(void)
g_free(req.data);
free_head = qvirtqueue_add(&vqpci->vq, req_addr, 16, false, true);
- qvirtqueue_add(&vqpci->vq, req_addr + 16, 513, true, false);
+ qvirtqueue_add(&vqpci->vq, req_addr + 16, 512, true, true);
+ qvirtqueue_add(&vqpci->vq, req_addr + 528, 1, true, false);
qvirtqueue_kick(&qvirtio_pci, &dev->vdev, &vqpci->vq, free_head);
-
qvirtio_wait_queue_isr(&qvirtio_pci, &dev->vdev, &vqpci->vq,
QVIRTIO_BLK_TIMEOUT_US);
@@ -636,45 +694,94 @@ static void pci_idx(void)
/* End test */
guest_free(alloc, vqpci->vq.desc);
+ pc_alloc_uninit(alloc);
qpci_msix_disable(dev->pdev);
qvirtio_pci_device_disable(dev);
g_free(dev);
+ qpci_free_pc(bus);
test_end();
}
-static void hotplug(void)
+static void pci_hotplug(void)
{
QPCIBus *bus;
QVirtioPCIDevice *dev;
- bus = test_start();
+ bus = pci_test_start();
/* plug secondary disk */
qpci_plug_device_test("virtio-blk-pci", "drv1", PCI_SLOT_HP,
"'drive': 'drive1'");
- dev = virtio_blk_init(bus, PCI_SLOT_HP);
+ dev = virtio_blk_pci_init(bus, PCI_SLOT_HP);
g_assert(dev);
qvirtio_pci_device_disable(dev);
g_free(dev);
/* unplug secondary disk */
qpci_unplug_acpi_device_test("drv1", PCI_SLOT_HP);
+ qpci_free_pc(bus);
+ test_end();
+}
+
+static void mmio_basic(void)
+{
+ QVirtioMMIODevice *dev;
+ QVirtQueue *vq;
+ QGuestAllocator *alloc;
+ int n_size = TEST_IMAGE_SIZE / 2;
+ uint64_t capacity;
+
+ arm_test_start();
+
+ dev = qvirtio_mmio_init_device(MMIO_DEV_BASE_ADDR, MMIO_PAGE_SIZE);
+ g_assert(dev != NULL);
+ g_assert_cmphex(dev->vdev.device_type, ==, QVIRTIO_BLK_DEVICE_ID);
+
+ qvirtio_reset(&qvirtio_mmio, &dev->vdev);
+ qvirtio_set_acknowledge(&qvirtio_mmio, &dev->vdev);
+ qvirtio_set_driver(&qvirtio_mmio, &dev->vdev);
+
+ alloc = generic_alloc_init(MMIO_RAM_ADDR, MMIO_RAM_SIZE, MMIO_PAGE_SIZE);
+ vq = qvirtqueue_setup(&qvirtio_mmio, &dev->vdev, alloc, 0);
+
+ test_basic(&qvirtio_mmio, &dev->vdev, alloc, vq,
+ QVIRTIO_MMIO_DEVICE_SPECIFIC);
+
+ qmp("{ 'execute': 'block_resize', 'arguments': { 'device': 'drive0', "
+ " 'size': %d } }", n_size);
+
+ qvirtio_wait_queue_isr(&qvirtio_mmio, &dev->vdev, vq,
+ QVIRTIO_BLK_TIMEOUT_US);
+
+ capacity = qvirtio_config_readq(&qvirtio_mmio, &dev->vdev,
+ QVIRTIO_MMIO_DEVICE_SPECIFIC);
+ g_assert_cmpint(capacity, ==, n_size / 512);
+
+ /* End test */
+ guest_free(alloc, vq->desc);
+ generic_alloc_uninit(alloc);
+ g_free(dev);
test_end();
}
int main(int argc, char **argv)
{
int ret;
+ const char *arch = qtest_get_arch();
g_test_init(&argc, &argv, NULL);
- g_test_add_func("/virtio/blk/pci/basic", pci_basic);
- g_test_add_func("/virtio/blk/pci/indirect", pci_indirect);
- g_test_add_func("/virtio/blk/pci/config", pci_config);
- g_test_add_func("/virtio/blk/pci/msix", pci_msix);
- g_test_add_func("/virtio/blk/pci/idx", pci_idx);
- g_test_add_func("/virtio/blk/pci/hotplug", hotplug);
+ if (strcmp(arch, "i386") == 0 || strcmp(arch, "x86_64") == 0) {
+ qtest_add_func("/virtio/blk/pci/basic", pci_basic);
+ qtest_add_func("/virtio/blk/pci/indirect", pci_indirect);
+ qtest_add_func("/virtio/blk/pci/config", pci_config);
+ qtest_add_func("/virtio/blk/pci/msix", pci_msix);
+ qtest_add_func("/virtio/blk/pci/idx", pci_idx);
+ qtest_add_func("/virtio/blk/pci/hotplug", pci_hotplug);
+ } else if (strcmp(arch, "arm") == 0) {
+ qtest_add_func("/virtio/blk/mmio/basic", mmio_basic);
+ }
ret = g_test_run();
diff --git a/trace-events b/trace-events
index 4ac588c27..30eba926c 100644
--- a/trace-events
+++ b/trace-events
@@ -1581,6 +1581,7 @@ mhp_pc_dimm_assigned_address(uint64_t addr) "0x%"PRIx64
kvm_enable_cmma(int rc) "CMMA: enabling with result code %d"
kvm_clear_cmma(int rc) "CMMA: clearing with result code %d"
kvm_failed_cpu_state_set(int cpu_index, uint8_t state, const char *msg) "Warning: Unable to set cpu %d state %" PRIu8 " to KVM: %s"
+kvm_sigp_finished(uint8_t order, int cpu_index, int dst_index, int cc) "SIGP: Finished order %u on cpu %d -> cpu %d with cc=%d"
# hw/dma/i8257.c
i8257_unregistered_dma(int nchan, int dma_pos, int dma_len) "unregistered DMA channel used nchan=%d dma_pos=%d dma_len=%d"
diff --git a/ui/vnc-ws.c b/ui/vnc-ws.c
index e304bafeb..d75950d7b 100644
--- a/ui/vnc-ws.c
+++ b/ui/vnc-ws.c
@@ -207,8 +207,7 @@ static void vncws_send_handshake_response(VncState *vs, const char* key)
}
response = g_strdup_printf(WS_HANDSHAKE, accept);
- vnc_write(vs, response, strlen(response));
- vnc_flush(vs);
+ vnc_client_write_buf(vs, (const uint8_t *)response, strlen(response));
g_free(accept);
g_free(response);
diff --git a/ui/vnc.c b/ui/vnc.c
index 10a272450..ff0b5bda9 100644
--- a/ui/vnc.c
+++ b/ui/vnc.c
@@ -3687,12 +3687,7 @@ void vnc_display_add_client(const char *id, int csock, bool skipauth)
vnc_connect(vs, csock, skipauth, false);
}
-QemuOpts *vnc_parse_func(const char *str)
-{
- return qemu_opts_parse(qemu_find_opts("vnc"), str, 1);
-}
-
-void vnc_auto_assign_id(QemuOptsList *olist, QemuOpts *opts)
+static void vnc_auto_assign_id(QemuOptsList *olist, QemuOpts *opts)
{
int i = 2;
char *id;
@@ -3705,18 +3700,25 @@ void vnc_auto_assign_id(QemuOptsList *olist, QemuOpts *opts)
qemu_opts_set_id(opts, id);
}
-int vnc_init_func(QemuOpts *opts, void *opaque)
+QemuOpts *vnc_parse_func(const char *str)
{
- Error *local_err = NULL;
QemuOptsList *olist = qemu_find_opts("vnc");
- char *id = (char *)qemu_opts_id(opts);
+ QemuOpts *opts = qemu_opts_parse(olist, str, 1);
+ const char *id = qemu_opts_id(opts);
if (!id) {
/* auto-assign id if not present */
vnc_auto_assign_id(olist, opts);
- id = (char *)qemu_opts_id(opts);
}
+ return opts;
+}
+
+int vnc_init_func(QemuOpts *opts, void *opaque)
+{
+ Error *local_err = NULL;
+ char *id = (char *)qemu_opts_id(opts);
+ assert(id);
vnc_display_init(id);
vnc_display_open(id, &local_err);
if (local_err != NULL) {
diff --git a/util/qemu-thread-posix.c b/util/qemu-thread-posix.c
index 50a29d8f7..ba67cec62 100644
--- a/util/qemu-thread-posix.c
+++ b/util/qemu-thread-posix.c
@@ -51,12 +51,8 @@ static void error_exit(int err, const char *msg)
void qemu_mutex_init(QemuMutex *mutex)
{
int err;
- pthread_mutexattr_t mutexattr;
- pthread_mutexattr_init(&mutexattr);
- pthread_mutexattr_settype(&mutexattr, PTHREAD_MUTEX_ERRORCHECK);
- err = pthread_mutex_init(&mutex->lock, &mutexattr);
- pthread_mutexattr_destroy(&mutexattr);
+ err = pthread_mutex_init(&mutex->lock, NULL);
if (err)
error_exit(err, __func__);
}
diff --git a/util/rcu.c b/util/rcu.c
index bd73b8eb4..27802a4be 100644
--- a/util/rcu.c
+++ b/util/rcu.c
@@ -283,7 +283,7 @@ void rcu_unregister_thread(void)
qemu_mutex_unlock(&rcu_gp_lock);
}
-static void __attribute__((__constructor__)) rcu_init(void)
+static void rcu_init_complete(void)
{
QemuThread thread;
@@ -291,8 +291,39 @@ static void __attribute__((__constructor__)) rcu_init(void)
qemu_event_init(&rcu_gp_event, true);
qemu_event_init(&rcu_call_ready_event, false);
+
+ /* The caller is assumed to have iothread lock, so the call_rcu thread
+ * must have been quiescent even after forking, just recreate it.
+ */
qemu_thread_create(&thread, "call_rcu", call_rcu_thread,
NULL, QEMU_THREAD_DETACHED);
rcu_register_thread();
}
+
+#ifdef CONFIG_POSIX
+static void rcu_init_lock(void)
+{
+ qemu_mutex_lock(&rcu_gp_lock);
+}
+
+static void rcu_init_unlock(void)
+{
+ qemu_mutex_unlock(&rcu_gp_lock);
+}
+
+static void rcu_init_child(void)
+{
+ qemu_mutex_unlock(&rcu_gp_lock);
+ memset(&registry, 0, sizeof(registry));
+ rcu_init_complete();
+}
+#endif
+
+static void __attribute__((__constructor__)) rcu_init(void)
+{
+#ifdef CONFIG_POSIX
+ pthread_atfork(rcu_init_lock, rcu_init_unlock, rcu_init_child);
+#endif
+ rcu_init_complete();
+}
diff --git a/vl.c b/vl.c
index b47e223a4..eba5d4c99 100644
--- a/vl.c
+++ b/vl.c
@@ -2001,7 +2001,6 @@ static DisplayType select_display(const char *p)
} else if (strstart(p, "vnc", &opts)) {
#ifdef CONFIG_VNC
if (*opts == '=') {
- display_remote++;
if (vnc_parse_func(opts+1) == NULL) {
exit(1);
}
@@ -3477,7 +3476,6 @@ int main(int argc, char **argv, char **envp)
break;
case QEMU_OPTION_vnc:
#ifdef CONFIG_VNC
- display_remote++;
if (vnc_parse_func(optarg) == NULL) {
exit(1);
}
@@ -3970,6 +3968,11 @@ int main(int argc, char **argv, char **envp)
}
}
+#if defined(CONFIG_VNC)
+ if (!QTAILQ_EMPTY(&(qemu_find_opts("vnc")->head))) {
+ display_remote++;
+ }
+#endif
if (display_type == DT_DEFAULT && !display_remote) {
#if defined(CONFIG_GTK)
display_type = DT_GTK;