aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--MAINTAINERS16
-rw-r--r--audio/audio.c2
-rw-r--r--audio/wavcapture.c1
-rw-r--r--block.c26
-rw-r--r--block/blkdebug.c8
-rwxr-xr-xblock/blkreplay.c3
-rw-r--r--block/blkverify.c3
-rw-r--r--block/block-backend.c7
-rw-r--r--block/commit.c5
-rw-r--r--block/crypto.c5
-rw-r--r--block/file-posix.c21
-rw-r--r--block/file-win32.c7
-rw-r--r--block/gluster.c7
-rw-r--r--block/io.c16
-rw-r--r--block/iscsi.c6
-rw-r--r--block/mirror.c2
-rw-r--r--block/nfs.c12
-rw-r--r--block/parallels.c13
-rw-r--r--block/qcow.c6
-rw-r--r--block/qcow2-refcount.c5
-rw-r--r--block/qcow2.c31
-rw-r--r--block/qed.c8
-rw-r--r--block/raw-format.c6
-rw-r--r--block/rbd.c3
-rw-r--r--block/sheepdog.c14
-rw-r--r--block/vdi.c4
-rw-r--r--block/vhdx-log.c2
-rw-r--r--block/vhdx.c25
-rw-r--r--block/vmdk.c13
-rw-r--r--block/vpc.c13
-rw-r--r--blockdev.c21
-rw-r--r--chardev/char-mux.c11
-rw-r--r--chardev/char-mux.h2
-rw-r--r--chardev/char-pty.c2
-rw-r--r--chardev/char-socket.c122
-rw-r--r--chardev/char-udp.c26
-rw-r--r--chardev/char.c159
-rw-r--r--default-configs/s390x-softmmu.mak1
-rw-r--r--gdbstub.c112
-rw-r--r--hmp.c174
-rw-r--r--hmp.h4
-rw-r--r--hw/audio/Makefile.objs2
-rw-r--r--hw/audio/adlib.c47
-rw-r--r--hw/audio/fmopl.c277
-rw-r--r--hw/audio/fmopl.h175
-rw-r--r--hw/audio/gus.c2
-rw-r--r--hw/audio/gusemu.h22
-rw-r--r--hw/audio/gusemu_hal.c74
-rw-r--r--hw/audio/gusemu_mixer.c28
-rw-r--r--hw/audio/hda-codec.c3
-rw-r--r--hw/audio/intel-hda.c5
-rw-r--r--hw/audio/intel-hda.h2
-rw-r--r--hw/char/Makefile.objs1
-rw-r--r--hw/char/terminal3270.c293
-rw-r--r--hw/input/hid.c4
-rw-r--r--hw/input/trace-events1
-rw-r--r--hw/openrisc/cputimer.c1
-rw-r--r--hw/s390x/3270-ccw.c174
-rw-r--r--hw/s390x/Makefile.objs1
-rw-r--r--hw/s390x/css.c24
-rw-r--r--hw/s390x/ipl.c39
-rw-r--r--hw/s390x/ipl.h3
-rw-r--r--hw/s390x/s390-virtio-ccw.c37
-rw-r--r--hw/s390x/sclp.c9
-rw-r--r--hw/usb/ccid-card-passthru.c2
-rw-r--r--hw/usb/redirect.c2
-rw-r--r--hw/vfio/common.c14
-rw-r--r--hw/vfio/pci.c4
-rw-r--r--hw/xen/xen-common.c2
-rw-r--r--include/block/block.h2
-rw-r--r--include/block/block_int.h8
-rw-r--r--include/exec/ram_addr.h13
-rw-r--r--include/hw/s390x/3270-ccw.h53
-rw-r--r--include/hw/s390x/css.h2
-rw-r--r--include/hw/s390x/s390-virtio-ccw.h1
-rw-r--r--include/migration/cpu.h7
-rw-r--r--include/migration/migration.h3
-rw-r--r--include/migration/vmstate.h18
-rw-r--r--include/sysemu/block-backend.h4
-rw-r--r--include/sysemu/char.h18
-rw-r--r--include/sysemu/sysemu.h5
-rw-r--r--linux-user/elfload.c2
-rw-r--r--linux-user/main.c18
-rw-r--r--linux-user/openrisc/target_cpu.h6
-rw-r--r--linux-user/openrisc/target_signal.h2
-rw-r--r--linux-user/signal.c17
-rw-r--r--migration/exec.c4
-rw-r--r--migration/migration.c2
-rw-r--r--migration/postcopy-ram.c7
-rw-r--r--migration/postcopy-ram.h (renamed from include/migration/postcopy-ram.h)3
-rw-r--r--migration/ram.c269
-rw-r--r--migration/savevm.c193
-rw-r--r--migration/socket.c1
-rw-r--r--migration/tls.c1
-rw-r--r--migration/trace-events2
-rw-r--r--monitor.c13
-rw-r--r--net/vhost-user.c2
-rw-r--r--pc-bios/s390-ccw.imgbin26456 -> 26472 bytes
-rw-r--r--pc-bios/s390-ccw/Makefile2
-rw-r--r--pc-bios/s390-ccw/bootmap.c34
-rw-r--r--pc-bios/s390-ccw/bootmap.h24
-rw-r--r--pc-bios/s390-ccw/main.c38
-rw-r--r--pc-bios/s390-ccw/s390-ccw.h17
-rw-r--r--pc-bios/s390-ccw/sclp.c (renamed from pc-bios/s390-ccw/sclp-ascii.c)12
-rw-r--r--pc-bios/s390-ccw/sclp.h2
-rw-r--r--qapi-schema.json3
-rw-r--r--qemu-img-cmds.hx8
-rw-r--r--qemu-img.c313
-rw-r--r--qemu-img.texi7
-rw-r--r--qemu-io-cmds.c5
-rw-r--r--qemu-options.hx4
-rw-r--r--qom/container.c1
-rw-r--r--replay/replay-snapshot.c2
-rw-r--r--scripts/tracetool/__init__.py4
-rw-r--r--target/openrisc/cpu.c16
-rw-r--r--target/openrisc/cpu.h46
-rw-r--r--target/openrisc/gdbstub.c4
-rw-r--r--target/openrisc/interrupt.c11
-rw-r--r--target/openrisc/machine.c76
-rw-r--r--target/openrisc/mmu.c24
-rw-r--r--target/openrisc/sys_helper.c35
-rw-r--r--target/openrisc/translate.c5
-rwxr-xr-xtests/qemu-iotests/0262
-rw-r--r--tests/qemu-iotests/026.out2
-rw-r--r--tests/qemu-iotests/026.out.nocache2
-rw-r--r--tests/qemu-iotests/028.out2
-rwxr-xr-xtests/qemu-iotests/0514
-rw-r--r--tests/qemu-iotests/051.out109
-rw-r--r--tests/qemu-iotests/051.pc.out135
-rwxr-xr-xtests/qemu-iotests/06612
-rw-r--r--tests/qemu-iotests/066.out12
-rwxr-xr-xtests/qemu-iotests/0684
-rw-r--r--tests/qemu-iotests/068.out6
-rwxr-xr-xtests/qemu-iotests/1096
-rw-r--r--tests/qemu-iotests/109.out20
-rw-r--r--tests/qemu-iotests/122.out4
-rw-r--r--tests/qemu-iotests/130.out4
-rwxr-xr-xtests/qemu-iotests/1422
-rw-r--r--tests/qemu-iotests/142.out10
-rwxr-xr-xtests/qemu-iotests/1453
-rw-r--r--tests/qemu-iotests/145.out2
-rwxr-xr-xtests/qemu-iotests/181119
-rw-r--r--tests/qemu-iotests/181.out38
-rw-r--r--tests/qemu-iotests/common11
-rw-r--r--tests/qemu-iotests/common.config24
-rw-r--r--tests/qemu-iotests/common.filter13
-rw-r--r--tests/qemu-iotests/common.qemu4
-rw-r--r--tests/qemu-iotests/common.rc4
-rw-r--r--tests/qemu-iotests/group1
-rw-r--r--tests/test-char.c366
-rw-r--r--tests/vhost-user-test.c2
-rw-r--r--ui/console.c2
-rw-r--r--ui/gtk.c2
-rw-r--r--ui/input.c18
-rw-r--r--util/qemu-config.c6
-rw-r--r--util/qemu-progress.c3
-rw-r--r--vl.c3
157 files changed, 2837 insertions, 1661 deletions
diff --git a/MAINTAINERS b/MAINTAINERS
index a1d2b3a..b27ea53 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -196,8 +196,8 @@ F: hw/nios2/
F: disas/nios2.c
OpenRISC
-M: Jia Liu <proljc@gmail.com>
-S: Maintained
+M: Stafford Horne <shorne@gmail.com>
+S: Odd Fixes
F: target/openrisc/
F: hw/openrisc/
F: tests/tcg/openrisc/
@@ -1546,6 +1546,18 @@ F: net/colo*
F: net/filter-rewriter.c
F: net/filter-mirror.c
+Record/replay
+M: Pavel Dovgalyuk <pavel.dovgaluk@ispras.ru>
+R: Paolo Bonzini <pbonzini@redhat.com>
+W: http://wiki.qemu.org/Features/record-replay
+S: Supported
+F: replay/*
+F: block/blkreplay.c
+F: net/filter-replay.c
+F: include/sysemu/replay.h
+F: docs/replay.txt
+F: stubs/replay.c
+
Usermode Emulation
------------------
Overall
diff --git a/audio/audio.c b/audio/audio.c
index c8898d8..beafed2 100644
--- a/audio/audio.c
+++ b/audio/audio.c
@@ -2028,6 +2028,8 @@ void AUD_del_capture (CaptureVoiceOut *cap, void *cb_opaque)
sw = sw1;
}
QLIST_REMOVE (cap, entries);
+ g_free (cap->hw.mix_buf);
+ g_free (cap->buf);
g_free (cap);
}
return;
diff --git a/audio/wavcapture.c b/audio/wavcapture.c
index 8bfb9e7..5863803 100644
--- a/audio/wavcapture.c
+++ b/audio/wavcapture.c
@@ -88,6 +88,7 @@ static void wav_capture_destroy (void *opaque)
WAVState *wav = opaque;
AUD_del_capture (wav->cap, wav);
+ g_free (wav);
}
static void wav_capture_info (void *opaque)
diff --git a/block.c b/block.c
index 5db266b..6c6bb3e 100644
--- a/block.c
+++ b/block.c
@@ -1204,7 +1204,7 @@ static int bdrv_open_common(BlockDriverState *bs, BlockBackend *file,
filename = qdict_get_try_str(options, "filename");
}
- if (drv->bdrv_needs_filename && !filename) {
+ if (drv->bdrv_needs_filename && (!filename || !filename[0])) {
error_setg(errp, "The '%s' block driver requires a file name",
drv->format_name);
ret = -EINVAL;
@@ -3307,26 +3307,30 @@ exit:
/**
* Truncate file to 'offset' bytes (needed only for file protocols)
*/
-int bdrv_truncate(BdrvChild *child, int64_t offset)
+int bdrv_truncate(BdrvChild *child, int64_t offset, Error **errp)
{
BlockDriverState *bs = child->bs;
BlockDriver *drv = bs->drv;
int ret;
- /* FIXME: Some format block drivers use this function instead of implicitly
- * growing their file by writing beyond its end.
- * See bdrv_aligned_pwritev() for an explanation why we currently
- * cannot assert this permission in that case. */
- // assert(child->perm & BLK_PERM_RESIZE);
+ assert(child->perm & BLK_PERM_RESIZE);
- if (!drv)
+ if (!drv) {
+ error_setg(errp, "No medium inserted");
return -ENOMEDIUM;
- if (!drv->bdrv_truncate)
+ }
+ if (!drv->bdrv_truncate) {
+ error_setg(errp, "Image format driver does not support resize");
return -ENOTSUP;
- if (bs->read_only)
+ }
+ if (bs->read_only) {
+ error_setg(errp, "Image is read-only");
return -EACCES;
+ }
+
+ assert(!(bs->open_flags & BDRV_O_INACTIVE));
- ret = drv->bdrv_truncate(bs, offset);
+ ret = drv->bdrv_truncate(bs, offset, errp);
if (ret == 0) {
ret = refresh_total_sectors(bs, offset >> BDRV_SECTOR_BITS);
bdrv_dirty_bitmap_truncate(bs);
diff --git a/block/blkdebug.c b/block/blkdebug.c
index 67e8024..d2a7561 100644
--- a/block/blkdebug.c
+++ b/block/blkdebug.c
@@ -389,14 +389,12 @@ static int blkdebug_open(BlockDriverState *bs, QDict *options, int flags,
} else if (align) {
error_setg(errp, "Invalid alignment");
ret = -EINVAL;
- goto fail_unref;
+ goto out;
}
ret = 0;
goto out;
-fail_unref:
- bdrv_unref_child(bs, bs->file);
out:
if (ret < 0) {
g_free(s->config_file);
@@ -661,9 +659,9 @@ static int64_t blkdebug_getlength(BlockDriverState *bs)
return bdrv_getlength(bs->file->bs);
}
-static int blkdebug_truncate(BlockDriverState *bs, int64_t offset)
+static int blkdebug_truncate(BlockDriverState *bs, int64_t offset, Error **errp)
{
- return bdrv_truncate(bs->file, offset);
+ return bdrv_truncate(bs->file, offset, errp);
}
static void blkdebug_refresh_filename(BlockDriverState *bs, QDict *options)
diff --git a/block/blkreplay.c b/block/blkreplay.c
index e110211..6aa5fd4 100755
--- a/block/blkreplay.c
+++ b/block/blkreplay.c
@@ -37,9 +37,6 @@ static int blkreplay_open(BlockDriverState *bs, QDict *options, int flags,
ret = 0;
fail:
- if (ret < 0) {
- bdrv_unref_child(bs, bs->file);
- }
return ret;
}
diff --git a/block/blkverify.c b/block/blkverify.c
index 9a1e21c..af23281 100644
--- a/block/blkverify.c
+++ b/block/blkverify.c
@@ -142,9 +142,6 @@ static int blkverify_open(BlockDriverState *bs, QDict *options, int flags,
ret = 0;
fail:
- if (ret < 0) {
- bdrv_unref_child(bs, bs->file);
- }
qemu_opts_del(opts);
return ret;
}
diff --git a/block/block-backend.c b/block/block-backend.c
index 7405024..f5bf13e 100644
--- a/block/block-backend.c
+++ b/block/block-backend.c
@@ -420,7 +420,7 @@ void monitor_remove_blk(BlockBackend *blk)
* Return @blk's name, a non-null string.
* Returns an empty string iff @blk is not referenced by the monitor.
*/
-const char *blk_name(BlockBackend *blk)
+const char *blk_name(const BlockBackend *blk)
{
return blk->name ?: "";
}
@@ -1746,13 +1746,14 @@ int blk_pwrite_compressed(BlockBackend *blk, int64_t offset, const void *buf,
BDRV_REQ_WRITE_COMPRESSED);
}
-int blk_truncate(BlockBackend *blk, int64_t offset)
+int blk_truncate(BlockBackend *blk, int64_t offset, Error **errp)
{
if (!blk_is_available(blk)) {
+ error_setg(errp, "No medium inserted");
return -ENOMEDIUM;
}
- return bdrv_truncate(blk->root, offset);
+ return bdrv_truncate(blk->root, offset, errp);
}
static void blk_pdiscard_entry(void *opaque)
diff --git a/block/commit.c b/block/commit.c
index 91d2c34..76a0d98 100644
--- a/block/commit.c
+++ b/block/commit.c
@@ -151,7 +151,7 @@ static void coroutine_fn commit_run(void *opaque)
}
if (base_len < s->common.len) {
- ret = blk_truncate(s->base, s->common.len);
+ ret = blk_truncate(s->base, s->common.len, NULL);
if (ret) {
goto out;
}
@@ -511,8 +511,9 @@ int bdrv_commit(BlockDriverState *bs)
* grow the backing file image if possible. If not possible,
* we must return an error */
if (length > backing_length) {
- ret = blk_truncate(backing, length);
+ ret = blk_truncate(backing, length, &local_err);
if (ret < 0) {
+ error_report_err(local_err);
goto ro_cleanup;
}
}
diff --git a/block/crypto.c b/block/crypto.c
index 34549b2..6828180 100644
--- a/block/crypto.c
+++ b/block/crypto.c
@@ -381,7 +381,8 @@ static int block_crypto_create_generic(QCryptoBlockFormat format,
return ret;
}
-static int block_crypto_truncate(BlockDriverState *bs, int64_t offset)
+static int block_crypto_truncate(BlockDriverState *bs, int64_t offset,
+ Error **errp)
{
BlockCrypto *crypto = bs->opaque;
size_t payload_offset =
@@ -389,7 +390,7 @@ static int block_crypto_truncate(BlockDriverState *bs, int64_t offset)
offset += payload_offset;
- return bdrv_truncate(bs->file, offset);
+ return bdrv_truncate(bs->file, offset, errp);
}
static void block_crypto_close(BlockDriverState *bs)
diff --git a/block/file-posix.c b/block/file-posix.c
index 0c48968..1941fb6 100644
--- a/block/file-posix.c
+++ b/block/file-posix.c
@@ -25,8 +25,6 @@
#include "qapi/error.h"
#include "qemu/cutils.h"
#include "qemu/error-report.h"
-#include "qemu/timer.h"
-#include "qemu/log.h"
#include "block/block_int.h"
#include "qemu/module.h"
#include "trace.h"
@@ -1409,24 +1407,31 @@ static void raw_close(BlockDriverState *bs)
}
}
-static int raw_truncate(BlockDriverState *bs, int64_t offset)
+static int raw_truncate(BlockDriverState *bs, int64_t offset, Error **errp)
{
BDRVRawState *s = bs->opaque;
struct stat st;
+ int ret;
if (fstat(s->fd, &st)) {
- return -errno;
+ ret = -errno;
+ error_setg_errno(errp, -ret, "Failed to fstat() the file");
+ return ret;
}
if (S_ISREG(st.st_mode)) {
if (ftruncate(s->fd, offset) < 0) {
- return -errno;
+ ret = -errno;
+ error_setg_errno(errp, -ret, "Failed to resize the file");
+ return ret;
}
} else if (S_ISCHR(st.st_mode) || S_ISBLK(st.st_mode)) {
- if (offset > raw_getlength(bs)) {
- return -EINVAL;
- }
+ if (offset > raw_getlength(bs)) {
+ error_setg(errp, "Cannot grow device files");
+ return -EINVAL;
+ }
} else {
+ error_setg(errp, "Resizing this file is not supported");
return -ENOTSUP;
}
diff --git a/block/file-win32.c b/block/file-win32.c
index 800fabd..7872e00 100644
--- a/block/file-win32.c
+++ b/block/file-win32.c
@@ -24,7 +24,6 @@
#include "qemu/osdep.h"
#include "qapi/error.h"
#include "qemu/cutils.h"
-#include "qemu/timer.h"
#include "block/block_int.h"
#include "qemu/module.h"
#include "block/raw-aio.h"
@@ -461,7 +460,7 @@ static void raw_close(BlockDriverState *bs)
}
}
-static int raw_truncate(BlockDriverState *bs, int64_t offset)
+static int raw_truncate(BlockDriverState *bs, int64_t offset, Error **errp)
{
BDRVRawState *s = bs->opaque;
LONG low, high;
@@ -476,11 +475,11 @@ static int raw_truncate(BlockDriverState *bs, int64_t offset)
*/
dwPtrLow = SetFilePointer(s->hfile, low, &high, FILE_BEGIN);
if (dwPtrLow == INVALID_SET_FILE_POINTER && GetLastError() != NO_ERROR) {
- fprintf(stderr, "SetFilePointer error: %lu\n", GetLastError());
+ error_setg_win32(errp, GetLastError(), "SetFilePointer error");
return -EIO;
}
if (SetEndOfFile(s->hfile) == 0) {
- fprintf(stderr, "SetEndOfFile error: %lu\n", GetLastError());
+ error_setg_win32(errp, GetLastError(), "SetEndOfFile error");
return -EIO;
}
return 0;
diff --git a/block/gluster.c b/block/gluster.c
index cf29b5f..1d4e2f7 100644
--- a/block/gluster.c
+++ b/block/gluster.c
@@ -1092,14 +1092,17 @@ static coroutine_fn int qemu_gluster_co_rw(BlockDriverState *bs,
return acb.ret;
}
-static int qemu_gluster_truncate(BlockDriverState *bs, int64_t offset)
+static int qemu_gluster_truncate(BlockDriverState *bs, int64_t offset,
+ Error **errp)
{
int ret;
BDRVGlusterState *s = bs->opaque;
ret = glfs_ftruncate(s->fd, offset);
if (ret < 0) {
- return -errno;
+ ret = -errno;
+ error_setg_errno(errp, -ret, "Failed to truncate file");
+ return ret;
}
return 0;
diff --git a/block/io.c b/block/io.c
index a7142e0..40bd94f 100644
--- a/block/io.c
+++ b/block/io.c
@@ -1362,16 +1362,8 @@ static int coroutine_fn bdrv_aligned_pwritev(BdrvChild *child,
assert(!waited || !req->serialising);
assert(req->overlap_offset <= offset);
assert(offset + bytes <= req->overlap_offset + req->overlap_bytes);
- /* FIXME: Block migration uses the BlockBackend of the guest device at a
- * point when it has not yet taken write permissions. This will be
- * fixed by a future patch, but for now we have to bypass this
- * assertion for block migration to work. */
- // assert(child->perm & BLK_PERM_WRITE);
- /* FIXME: Because of the above, we also cannot guarantee that all format
- * BDS take the BLK_PERM_RESIZE permission on their file BDS, since
- * they are not obligated to do so if they do not have any parent
- * that has taken the permission to write to them. */
- // assert(end_sector <= bs->total_sectors || child->perm & BLK_PERM_RESIZE);
+ assert(child->perm & BLK_PERM_WRITE);
+ assert(end_sector <= bs->total_sectors || child->perm & BLK_PERM_RESIZE);
ret = notifier_with_return_list_notify(&bs->before_write_notifiers, req);
@@ -1452,7 +1444,7 @@ static int coroutine_fn bdrv_co_do_zero_pwritev(BdrvChild *child,
int ret = 0;
head_padding_bytes = offset & (align - 1);
- tail_padding_bytes = align - ((offset + bytes) & (align - 1));
+ tail_padding_bytes = (align - (offset + bytes)) & (align - 1);
assert(flags & BDRV_REQ_ZERO_WRITE);
@@ -2308,7 +2300,7 @@ int coroutine_fn bdrv_co_flush(BlockDriverState *bs)
bdrv_inc_in_flight(bs);
- if (!bs || !bdrv_is_inserted(bs) || bdrv_is_read_only(bs) ||
+ if (!bdrv_is_inserted(bs) || bdrv_is_read_only(bs) ||
bdrv_is_sg(bs)) {
goto early_exit;
}
diff --git a/block/iscsi.c b/block/iscsi.c
index 42fb0b0..5daa201 100644
--- a/block/iscsi.c
+++ b/block/iscsi.c
@@ -2059,22 +2059,24 @@ static void iscsi_reopen_commit(BDRVReopenState *reopen_state)
}
}
-static int iscsi_truncate(BlockDriverState *bs, int64_t offset)
+static int iscsi_truncate(BlockDriverState *bs, int64_t offset, Error **errp)
{
IscsiLun *iscsilun = bs->opaque;
Error *local_err = NULL;
if (iscsilun->type != TYPE_DISK) {
+ error_setg(errp, "Cannot resize non-disk iSCSI devices");
return -ENOTSUP;
}
iscsi_readcapacity_sync(iscsilun, &local_err);
if (local_err != NULL) {
- error_free(local_err);
+ error_propagate(errp, local_err);
return -EIO;
}
if (offset > iscsi_getlength(bs)) {
+ error_setg(errp, "Cannot grow iSCSI devices");
return -EINVAL;
}
diff --git a/block/mirror.c b/block/mirror.c
index 9f5eb69..e86f8f8 100644
--- a/block/mirror.c
+++ b/block/mirror.c
@@ -724,7 +724,7 @@ static void coroutine_fn mirror_run(void *opaque)
}
if (s->bdev_length > base_length) {
- ret = blk_truncate(s->target, s->bdev_length);
+ ret = blk_truncate(s->target, s->bdev_length, NULL);
if (ret < 0) {
goto immediate_exit;
}
diff --git a/block/nfs.c b/block/nfs.c
index 6541dec..76572ae 100644
--- a/block/nfs.c
+++ b/block/nfs.c
@@ -764,10 +764,18 @@ static int64_t nfs_get_allocated_file_size(BlockDriverState *bs)
return (task.ret < 0 ? task.ret : st.st_blocks * 512);
}
-static int nfs_file_truncate(BlockDriverState *bs, int64_t offset)
+static int nfs_file_truncate(BlockDriverState *bs, int64_t offset, Error **errp)
{
NFSClient *client = bs->opaque;
- return nfs_ftruncate(client->context, client->fh, offset);
+ int ret;
+
+ ret = nfs_ftruncate(client->context, client->fh, offset);
+ if (ret < 0) {
+ error_setg_errno(errp, -ret, "Failed to truncate file");
+ return ret;
+ }
+
+ return 0;
}
/* Note that this will not re-establish a connection with the NFS server
diff --git a/block/parallels.c b/block/parallels.c
index 90acf79..8be46a7 100644
--- a/block/parallels.c
+++ b/block/parallels.c
@@ -223,7 +223,8 @@ static int64_t allocate_clusters(BlockDriverState *bs, int64_t sector_num,
space << BDRV_SECTOR_BITS, 0);
} else {
ret = bdrv_truncate(bs->file,
- (s->data_end + space) << BDRV_SECTOR_BITS);
+ (s->data_end + space) << BDRV_SECTOR_BITS,
+ NULL);
}
if (ret < 0) {
return ret;
@@ -456,8 +457,10 @@ static int parallels_check(BlockDriverState *bs, BdrvCheckResult *res,
size - res->image_end_offset);
res->leaks += count;
if (fix & BDRV_FIX_LEAKS) {
- ret = bdrv_truncate(bs->file, res->image_end_offset);
+ Error *local_err = NULL;
+ ret = bdrv_truncate(bs->file, res->image_end_offset, &local_err);
if (ret < 0) {
+ error_report_err(local_err);
res->check_errors++;
return ret;
}
@@ -504,7 +507,7 @@ static int parallels_create(const char *filename, QemuOpts *opts, Error **errp)
blk_set_allow_write_beyond_eof(file, true);
- ret = blk_truncate(file, 0);
+ ret = blk_truncate(file, 0, errp);
if (ret < 0) {
goto exit;
}
@@ -696,7 +699,7 @@ static int parallels_open(BlockDriverState *bs, QDict *options, int flags,
}
if (!(flags & BDRV_O_RESIZE) || !bdrv_has_zero_init(bs->file->bs) ||
- bdrv_truncate(bs->file, bdrv_getlength(bs->file->bs)) != 0) {
+ bdrv_truncate(bs->file, bdrv_getlength(bs->file->bs), NULL) != 0) {
s->prealloc_mode = PRL_PREALLOC_MODE_FALLOCATE;
}
@@ -739,7 +742,7 @@ static void parallels_close(BlockDriverState *bs)
}
if (bs->open_flags & BDRV_O_RDWR) {
- bdrv_truncate(bs->file, s->data_end << BDRV_SECTOR_BITS);
+ bdrv_truncate(bs->file, s->data_end << BDRV_SECTOR_BITS, NULL);
}
g_free(s->bat_dirty_bmap);
diff --git a/block/qcow.c b/block/qcow.c
index 9d6ac83..5d147b9 100644
--- a/block/qcow.c
+++ b/block/qcow.c
@@ -473,7 +473,7 @@ static uint64_t get_cluster_offset(BlockDriverState *bs,
/* round to cluster size */
cluster_offset = (cluster_offset + s->cluster_size - 1) &
~(s->cluster_size - 1);
- bdrv_truncate(bs->file, cluster_offset + s->cluster_size);
+ bdrv_truncate(bs->file, cluster_offset + s->cluster_size, NULL);
/* if encrypted, we must initialize the cluster
content which won't be written */
if (bs->encrypted &&
@@ -833,7 +833,7 @@ static int qcow_create(const char *filename, QemuOpts *opts, Error **errp)
blk_set_allow_write_beyond_eof(qcow_blk, true);
- ret = blk_truncate(qcow_blk, 0);
+ ret = blk_truncate(qcow_blk, 0, errp);
if (ret < 0) {
goto exit;
}
@@ -916,7 +916,7 @@ static int qcow_make_empty(BlockDriverState *bs)
if (bdrv_pwrite_sync(bs->file, s->l1_table_offset, s->l1_table,
l1_length) < 0)
return -1;
- ret = bdrv_truncate(bs->file, s->l1_table_offset + l1_length);
+ ret = bdrv_truncate(bs->file, s->l1_table_offset + l1_length, NULL);
if (ret < 0)
return ret;
diff --git a/block/qcow2-refcount.c b/block/qcow2-refcount.c
index 9e96f64..4efca7e 100644
--- a/block/qcow2-refcount.c
+++ b/block/qcow2-refcount.c
@@ -1728,14 +1728,17 @@ static int check_refblocks(BlockDriverState *bs, BdrvCheckResult *res,
if (fix & BDRV_FIX_ERRORS) {
int64_t new_nb_clusters;
+ Error *local_err = NULL;
if (offset > INT64_MAX - s->cluster_size) {
ret = -EINVAL;
goto resize_fail;
}
- ret = bdrv_truncate(bs->file, offset + s->cluster_size);
+ ret = bdrv_truncate(bs->file, offset + s->cluster_size,
+ &local_err);
if (ret < 0) {
+ error_report_err(local_err);
goto resize_fail;
}
size = bdrv_getlength(bs->file->bs);
diff --git a/block/qcow2.c b/block/qcow2.c
index 6a92d2e..5c1573c 100644
--- a/block/qcow2.c
+++ b/block/qcow2.c
@@ -2294,9 +2294,9 @@ static int qcow2_create2(const char *filename, int64_t total_size,
}
/* Okay, now that we have a valid image, let's give it the right size */
- ret = blk_truncate(blk, total_size);
+ ret = blk_truncate(blk, total_size, errp);
if (ret < 0) {
- error_setg_errno(errp, -ret, "Could not resize image");
+ error_prepend(errp, "Could not resize image: ");
goto out;
}
@@ -2515,7 +2515,12 @@ static coroutine_fn int qcow2_co_pdiscard(BlockDriverState *bs,
if (!QEMU_IS_ALIGNED(offset | count, s->cluster_size)) {
assert(count < s->cluster_size);
- return -ENOTSUP;
+ /* Ignore partial clusters, except for the special case of the
+ * complete partial cluster at the end of an unaligned file */
+ if (!QEMU_IS_ALIGNED(offset, s->cluster_size) ||
+ offset + count != bs->total_sectors * BDRV_SECTOR_SIZE) {
+ return -ENOTSUP;
+ }
}
qemu_co_mutex_lock(&s->lock);
@@ -2525,32 +2530,33 @@ static coroutine_fn int qcow2_co_pdiscard(BlockDriverState *bs,
return ret;
}
-static int qcow2_truncate(BlockDriverState *bs, int64_t offset)
+static int qcow2_truncate(BlockDriverState *bs, int64_t offset, Error **errp)
{
BDRVQcow2State *s = bs->opaque;
int64_t new_l1_size;
int ret;
if (offset & 511) {
- error_report("The new size must be a multiple of 512");
+ error_setg(errp, "The new size must be a multiple of 512");
return -EINVAL;
}
/* cannot proceed if image has snapshots */
if (s->nb_snapshots) {
- error_report("Can't resize an image which has snapshots");
+ error_setg(errp, "Can't resize an image which has snapshots");
return -ENOTSUP;
}
/* shrinking is currently not supported */
if (offset < bs->total_sectors * 512) {
- error_report("qcow2 doesn't support shrinking images yet");
+ error_setg(errp, "qcow2 doesn't support shrinking images yet");
return -ENOTSUP;
}
new_l1_size = size_to_l1(s, offset);
ret = qcow2_grow_l1_table(bs, new_l1_size, true);
if (ret < 0) {
+ error_setg_errno(errp, -ret, "Failed to grow the L1 table");
return ret;
}
@@ -2559,6 +2565,7 @@ static int qcow2_truncate(BlockDriverState *bs, int64_t offset)
ret = bdrv_pwrite_sync(bs->file, offsetof(QCowHeader, size),
&offset, sizeof(uint64_t));
if (ret < 0) {
+ error_setg_errno(errp, -ret, "Failed to update the image size");
return ret;
}
@@ -2584,7 +2591,7 @@ qcow2_co_pwritev_compressed(BlockDriverState *bs, uint64_t offset,
/* align end of file to a sector boundary to ease reading with
sector based I/Os */
cluster_offset = bdrv_getlength(bs->file->bs);
- return bdrv_truncate(bs->file, cluster_offset);
+ return bdrv_truncate(bs->file, cluster_offset, NULL);
}
buf = qemu_blockalign(bs, s->cluster_size);
@@ -2674,6 +2681,7 @@ fail:
static int make_completely_empty(BlockDriverState *bs)
{
BDRVQcow2State *s = bs->opaque;
+ Error *local_err = NULL;
int ret, l1_clusters;
int64_t offset;
uint64_t *new_reftable = NULL;
@@ -2798,8 +2806,10 @@ static int make_completely_empty(BlockDriverState *bs)
goto fail;
}
- ret = bdrv_truncate(bs->file, (3 + l1_clusters) * s->cluster_size);
+ ret = bdrv_truncate(bs->file, (3 + l1_clusters) * s->cluster_size,
+ &local_err);
if (ret < 0) {
+ error_report_err(local_err);
goto fail;
}
@@ -3273,9 +3283,10 @@ static int qcow2_amend_options(BlockDriverState *bs, QemuOpts *opts,
return ret;
}
- ret = blk_truncate(blk, new_size);
+ ret = blk_truncate(blk, new_size, &local_err);
blk_unref(blk);
if (ret < 0) {
+ error_report_err(local_err);
return ret;
}
}
diff --git a/block/qed.c b/block/qed.c
index 5ec7fd8..fd76817 100644
--- a/block/qed.c
+++ b/block/qed.c
@@ -635,7 +635,7 @@ static int qed_create(const char *filename, uint32_t cluster_size,
blk_set_allow_write_beyond_eof(blk, true);
/* File must start empty and grow, check truncate is supported */
- ret = blk_truncate(blk, 0);
+ ret = blk_truncate(blk, 0, errp);
if (ret < 0) {
goto out;
}
@@ -1518,7 +1518,7 @@ static int coroutine_fn bdrv_qed_co_pwrite_zeroes(BlockDriverState *bs,
return cb.ret;
}
-static int bdrv_qed_truncate(BlockDriverState *bs, int64_t offset)
+static int bdrv_qed_truncate(BlockDriverState *bs, int64_t offset, Error **errp)
{
BDRVQEDState *s = bs->opaque;
uint64_t old_image_size;
@@ -1526,11 +1526,12 @@ static int bdrv_qed_truncate(BlockDriverState *bs, int64_t offset)
if (!qed_is_image_size_valid(offset, s->header.cluster_size,
s->header.table_size)) {
+ error_setg(errp, "Invalid image size specified");
return -EINVAL;
}
- /* Shrinking is currently not supported */
if ((uint64_t)offset < s->header.image_size) {
+ error_setg(errp, "Shrinking images is currently not supported");
return -ENOTSUP;
}
@@ -1539,6 +1540,7 @@ static int bdrv_qed_truncate(BlockDriverState *bs, int64_t offset)
ret = qed_write_header_sync(s);
if (ret < 0) {
s->header.image_size = old_image_size;
+ error_setg_errno(errp, -ret, "Failed to update the image size");
}
return ret;
}
diff --git a/block/raw-format.c b/block/raw-format.c
index 86fbc65..36e6503 100644
--- a/block/raw-format.c
+++ b/block/raw-format.c
@@ -327,21 +327,23 @@ static void raw_refresh_limits(BlockDriverState *bs, Error **errp)
}
}
-static int raw_truncate(BlockDriverState *bs, int64_t offset)
+static int raw_truncate(BlockDriverState *bs, int64_t offset, Error **errp)
{
BDRVRawState *s = bs->opaque;
if (s->has_size) {
+ error_setg(errp, "Cannot resize fixed-size raw disks");
return -ENOTSUP;
}
if (INT64_MAX - offset < s->offset) {
+ error_setg(errp, "Disk size too large for the chosen offset");
return -EINVAL;
}
s->size = offset;
offset += s->offset;
- return bdrv_truncate(bs->file, offset);
+ return bdrv_truncate(bs->file, offset, errp);
}
static int raw_media_changed(BlockDriverState *bs)
diff --git a/block/rbd.c b/block/rbd.c
index 6471f4f..fbf3059 100644
--- a/block/rbd.c
+++ b/block/rbd.c
@@ -916,13 +916,14 @@ static int64_t qemu_rbd_getlength(BlockDriverState *bs)
return info.size;
}
-static int qemu_rbd_truncate(BlockDriverState *bs, int64_t offset)
+static int qemu_rbd_truncate(BlockDriverState *bs, int64_t offset, Error **errp)
{
BDRVRBDState *s = bs->opaque;
int r;
r = rbd_resize(s->image, offset);
if (r < 0) {
+ error_setg_errno(errp, -r, "Failed to resize file");
return r;
}
diff --git a/block/sheepdog.c b/block/sheepdog.c
index b2a5998..fe8fd92 100644
--- a/block/sheepdog.c
+++ b/block/sheepdog.c
@@ -2159,9 +2159,8 @@ static int64_t sd_getlength(BlockDriverState *bs)
return s->inode.vdi_size;
}
-static int sd_truncate(BlockDriverState *bs, int64_t offset)
+static int sd_truncate(BlockDriverState *bs, int64_t offset, Error **errp)
{
- Error *local_err = NULL;
BDRVSheepdogState *s = bs->opaque;
int ret, fd;
unsigned int datalen;
@@ -2169,16 +2168,15 @@ static int sd_truncate(BlockDriverState *bs, int64_t offset)
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");
+ error_setg(errp, "shrinking is not supported");
return -EINVAL;
} else if (offset > max_vdi_size) {
- error_report("too big image size");
+ error_setg(errp, "too big image size");
return -EINVAL;
}
- fd = connect_to_sdog(s, &local_err);
+ fd = connect_to_sdog(s, errp);
if (fd < 0) {
- error_report_err(local_err);
return fd;
}
@@ -2191,7 +2189,7 @@ static int sd_truncate(BlockDriverState *bs, int64_t offset)
close(fd);
if (ret < 0) {
- error_report("failed to update an inode.");
+ error_setg_errno(errp, -ret, "failed to update an inode");
}
return ret;
@@ -2456,7 +2454,7 @@ static coroutine_fn int sd_co_writev(BlockDriverState *bs, int64_t sector_num,
BDRVSheepdogState *s = bs->opaque;
if (offset > s->inode.vdi_size) {
- ret = sd_truncate(bs, offset);
+ ret = sd_truncate(bs, offset, NULL);
if (ret < 0) {
return ret;
}
diff --git a/block/vdi.c b/block/vdi.c
index 9b4f70e..d12d9cd 100644
--- a/block/vdi.c
+++ b/block/vdi.c
@@ -832,9 +832,9 @@ static int vdi_create(const char *filename, QemuOpts *opts, Error **errp)
}
if (image_type == VDI_TYPE_STATIC) {
- ret = blk_truncate(blk, offset + blocks * block_size);
+ ret = blk_truncate(blk, offset + blocks * block_size, errp);
if (ret < 0) {
- error_setg(errp, "Failed to statically allocate %s", filename);
+ error_prepend(errp, "Failed to statically allocate %s", filename);
goto exit;
}
}
diff --git a/block/vhdx-log.c b/block/vhdx-log.c
index 67a91c0..3f4c2aa 100644
--- a/block/vhdx-log.c
+++ b/block/vhdx-log.c
@@ -548,7 +548,7 @@ static int vhdx_log_flush(BlockDriverState *bs, BDRVVHDXState *s,
if (new_file_size % (1024*1024)) {
/* round up to nearest 1MB boundary */
new_file_size = ((new_file_size >> 20) + 1) << 20;
- bdrv_truncate(bs->file, new_file_size);
+ bdrv_truncate(bs->file, new_file_size, NULL);
}
}
qemu_vfree(desc_entries);
diff --git a/block/vhdx.c b/block/vhdx.c
index 052a753..e8fe3fb 100644
--- a/block/vhdx.c
+++ b/block/vhdx.c
@@ -1171,7 +1171,7 @@ static int vhdx_allocate_block(BlockDriverState *bs, BDRVVHDXState *s,
/* per the spec, the address for a block is in units of 1MB */
*new_offset = ROUND_UP(*new_offset, 1024 * 1024);
- return bdrv_truncate(bs->file, *new_offset + s->block_size);
+ return bdrv_truncate(bs->file, *new_offset + s->block_size, NULL);
}
/*
@@ -1586,7 +1586,7 @@ exit:
static int vhdx_create_bat(BlockBackend *blk, BDRVVHDXState *s,
uint64_t image_size, VHDXImageType type,
bool use_zero_blocks, uint64_t file_offset,
- uint32_t length)
+ uint32_t length, Error **errp)
{
int ret = 0;
uint64_t data_file_offset;
@@ -1607,16 +1607,17 @@ static int vhdx_create_bat(BlockBackend *blk, BDRVVHDXState *s,
if (type == VHDX_TYPE_DYNAMIC) {
/* All zeroes, so we can just extend the file - the end of the BAT
* is the furthest thing we have written yet */
- ret = blk_truncate(blk, data_file_offset);
+ ret = blk_truncate(blk, data_file_offset, errp);
if (ret < 0) {
goto exit;
}
} else if (type == VHDX_TYPE_FIXED) {
- ret = blk_truncate(blk, data_file_offset + image_size);
+ ret = blk_truncate(blk, data_file_offset + image_size, errp);
if (ret < 0) {
goto exit;
}
} else {
+ error_setg(errp, "Unsupported image type");
ret = -ENOTSUP;
goto exit;
}
@@ -1627,6 +1628,7 @@ static int vhdx_create_bat(BlockBackend *blk, BDRVVHDXState *s,
/* for a fixed file, the default BAT entry is not zero */
s->bat = g_try_malloc0(length);
if (length && s->bat == NULL) {
+ error_setg(errp, "Failed to allocate memory for the BAT");
ret = -ENOMEM;
goto exit;
}
@@ -1646,6 +1648,7 @@ static int vhdx_create_bat(BlockBackend *blk, BDRVVHDXState *s,
}
ret = blk_pwrite(blk, file_offset, s->bat, length, 0);
if (ret < 0) {
+ error_setg_errno(errp, -ret, "Failed to write the BAT");
goto exit;
}
}
@@ -1671,7 +1674,8 @@ static int vhdx_create_new_region_table(BlockBackend *blk,
uint32_t log_size,
bool use_zero_blocks,
VHDXImageType type,
- uint64_t *metadata_offset)
+ uint64_t *metadata_offset,
+ Error **errp)
{
int ret = 0;
uint32_t offset = 0;
@@ -1740,7 +1744,7 @@ static int vhdx_create_new_region_table(BlockBackend *blk,
/* The region table gives us the data we need to create the BAT,
* so do that now */
ret = vhdx_create_bat(blk, s, image_size, type, use_zero_blocks,
- bat_file_offset, bat_length);
+ bat_file_offset, bat_length, errp);
if (ret < 0) {
goto exit;
}
@@ -1749,12 +1753,14 @@ static int vhdx_create_new_region_table(BlockBackend *blk,
ret = blk_pwrite(blk, VHDX_REGION_TABLE_OFFSET, buffer,
VHDX_HEADER_BLOCK_SIZE, 0);
if (ret < 0) {
+ error_setg_errno(errp, -ret, "Failed to write first region table");
goto exit;
}
ret = blk_pwrite(blk, VHDX_REGION_TABLE2_OFFSET, buffer,
VHDX_HEADER_BLOCK_SIZE, 0);
if (ret < 0) {
+ error_setg_errno(errp, -ret, "Failed to write second region table");
goto exit;
}
@@ -1825,6 +1831,7 @@ static int vhdx_create(const char *filename, QemuOpts *opts, Error **errp)
ret = -ENOTSUP;
goto exit;
} else {
+ error_setg(errp, "Invalid subformat '%s'", type);
ret = -EINVAL;
goto exit;
}
@@ -1879,12 +1886,14 @@ static int vhdx_create(const char *filename, QemuOpts *opts, Error **errp)
ret = blk_pwrite(blk, VHDX_FILE_ID_OFFSET, &signature, sizeof(signature),
0);
if (ret < 0) {
+ error_setg_errno(errp, -ret, "Failed to write file signature");
goto delete_and_exit;
}
if (creator) {
ret = blk_pwrite(blk, VHDX_FILE_ID_OFFSET + sizeof(signature),
creator, creator_items * sizeof(gunichar2), 0);
if (ret < 0) {
+ error_setg_errno(errp, -ret, "Failed to write creator field");
goto delete_and_exit;
}
}
@@ -1893,13 +1902,14 @@ static int vhdx_create(const char *filename, QemuOpts *opts, Error **errp)
/* Creates (B),(C) */
ret = vhdx_create_new_headers(blk, image_size, log_size);
if (ret < 0) {
+ error_setg_errno(errp, -ret, "Failed to write image headers");
goto delete_and_exit;
}
/* Creates (D),(E),(G) explicitly. (F) created as by-product */
ret = vhdx_create_new_region_table(blk, image_size, block_size, 512,
log_size, use_zero_blocks, image_type,
- &metadata_offset);
+ &metadata_offset, errp);
if (ret < 0) {
goto delete_and_exit;
}
@@ -1908,6 +1918,7 @@ static int vhdx_create(const char *filename, QemuOpts *opts, Error **errp)
ret = vhdx_create_new_metadata(blk, image_size, block_size, 512,
metadata_offset, image_type);
if (ret < 0) {
+ error_setg_errno(errp, -ret, "Failed to initialize metadata");
goto delete_and_exit;
}
diff --git a/block/vmdk.c b/block/vmdk.c
index a9bd22b..c61b9cc 100644
--- a/block/vmdk.c
+++ b/block/vmdk.c
@@ -1714,10 +1714,7 @@ static int vmdk_create_extent(const char *filename, int64_t filesize,
blk_set_allow_write_beyond_eof(blk, true);
if (flat) {
- ret = blk_truncate(blk, filesize);
- if (ret < 0) {
- error_setg_errno(errp, -ret, "Could not truncate file");
- }
+ ret = blk_truncate(blk, filesize, errp);
goto exit;
}
magic = cpu_to_be32(VMDK4_MAGIC);
@@ -1780,9 +1777,8 @@ static int vmdk_create_extent(const char *filename, int64_t filesize,
goto exit;
}
- ret = blk_truncate(blk, le64_to_cpu(header.grain_offset) << 9);
+ ret = blk_truncate(blk, le64_to_cpu(header.grain_offset) << 9, errp);
if (ret < 0) {
- error_setg_errno(errp, -ret, "Could not truncate file");
goto exit;
}
@@ -2090,10 +2086,7 @@ static int vmdk_create(const char *filename, QemuOpts *opts, Error **errp)
/* bdrv_pwrite write padding zeros to align to sector, we don't need that
* for description file */
if (desc_offset == 0) {
- ret = blk_truncate(new_blk, desc_len);
- if (ret < 0) {
- error_setg_errno(errp, -ret, "Could not truncate file");
- }
+ ret = blk_truncate(new_blk, desc_len, errp);
}
exit:
if (new_blk) {
diff --git a/block/vpc.c b/block/vpc.c
index f591d4b..ecfee77 100644
--- a/block/vpc.c
+++ b/block/vpc.c
@@ -851,20 +851,21 @@ static int create_dynamic_disk(BlockBackend *blk, uint8_t *buf,
}
static int create_fixed_disk(BlockBackend *blk, uint8_t *buf,
- int64_t total_size)
+ int64_t total_size, Error **errp)
{
int ret;
/* Add footer to total size */
total_size += HEADER_SIZE;
- ret = blk_truncate(blk, total_size);
+ ret = blk_truncate(blk, total_size, errp);
if (ret < 0) {
return ret;
}
ret = blk_pwrite(blk, total_size - HEADER_SIZE, buf, HEADER_SIZE, 0);
if (ret < 0) {
+ error_setg_errno(errp, -ret, "Unable to write VHD header");
return ret;
}
@@ -996,11 +997,11 @@ static int vpc_create(const char *filename, QemuOpts *opts, Error **errp)
if (disk_type == VHD_DYNAMIC) {
ret = create_dynamic_disk(blk, buf, total_sectors);
+ if (ret < 0) {
+ error_setg(errp, "Unable to create or write VHD header");
+ }
} else {
- ret = create_fixed_disk(blk, buf, total_size);
- }
- if (ret < 0) {
- error_setg(errp, "Unable to create or write VHD header");
+ ret = create_fixed_disk(blk, buf, total_size, errp);
}
out:
diff --git a/blockdev.c b/blockdev.c
index 6428206..4d8cded 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -2930,26 +2930,7 @@ void qmp_block_resize(bool has_device, const char *device,
/* complete all in-flight operations before resizing the device */
bdrv_drain_all();
- ret = blk_truncate(blk, size);
- switch (ret) {
- case 0:
- break;
- case -ENOMEDIUM:
- error_setg(errp, QERR_DEVICE_HAS_NO_MEDIUM, device);
- break;
- case -ENOTSUP:
- error_setg(errp, QERR_UNSUPPORTED);
- break;
- case -EACCES:
- error_setg(errp, "Device '%s' is read only", device);
- break;
- case -EBUSY:
- error_setg(errp, QERR_DEVICE_IN_USE, device);
- break;
- default:
- error_setg_errno(errp, -ret, "Could not resize");
- break;
- }
+ ret = blk_truncate(blk, size, errp);
out:
blk_unref(blk);
diff --git a/chardev/char-mux.c b/chardev/char-mux.c
index 5547a36..37d42c6 100644
--- a/chardev/char-mux.c
+++ b/chardev/char-mux.c
@@ -114,7 +114,7 @@ static void mux_print_help(Chardev *chr)
}
}
-void mux_chr_send_event(MuxChardev *d, int mux_nr, int event)
+static void mux_chr_send_event(MuxChardev *d, int mux_nr, int event)
{
CharBackend *be = d->backends[mux_nr];
@@ -222,9 +222,9 @@ static void mux_chr_read(void *opaque, const uint8_t *buf, int size)
bool muxes_realized;
-static void mux_chr_event(void *opaque, int event)
+void mux_chr_send_all_event(Chardev *chr, int event)
{
- MuxChardev *d = MUX_CHARDEV(opaque);
+ MuxChardev *d = MUX_CHARDEV(chr);
int i;
if (!muxes_realized) {
@@ -237,6 +237,11 @@ static void mux_chr_event(void *opaque, int event)
}
}
+static void mux_chr_event(void *opaque, int event)
+{
+ mux_chr_send_all_event(CHARDEV(opaque), event);
+}
+
static GSource *mux_chr_add_watch(Chardev *s, GIOCondition cond)
{
MuxChardev *d = MUX_CHARDEV(s);
diff --git a/chardev/char-mux.h b/chardev/char-mux.h
index 9a2fffc..3f41dfc 100644
--- a/chardev/char-mux.h
+++ b/chardev/char-mux.h
@@ -58,6 +58,6 @@ typedef struct MuxChardev {
void mux_chr_set_handlers(Chardev *chr, GMainContext *context);
void mux_set_focus(Chardev *chr, int focus);
-void mux_chr_send_event(MuxChardev *d, int mux_nr, int event);
+void mux_chr_send_all_event(Chardev *chr, int event);
#endif /* CHAR_MUX_H */
diff --git a/chardev/char-pty.c b/chardev/char-pty.c
index a6337be..aa9d0cb 100644
--- a/chardev/char-pty.c
+++ b/chardev/char-pty.c
@@ -185,7 +185,7 @@ static gboolean qemu_chr_be_generic_open_func(gpointer opaque)
PtyChardev *s = PTY_CHARDEV(opaque);
s->open_tag = 0;
- qemu_chr_be_generic_open(chr);
+ qemu_chr_be_event(chr, CHR_EVENT_OPENED);
return FALSE;
}
diff --git a/chardev/char-socket.c b/chardev/char-socket.c
index 36ab0d6..9d5f062 100644
--- a/chardev/char-socket.c
+++ b/chardev/char-socket.c
@@ -55,6 +55,7 @@ typedef struct {
SocketAddress *addr;
bool is_listen;
bool is_telnet;
+ bool is_tn3270;
guint reconnect_timer;
int64_t reconnect_time;
@@ -141,19 +142,25 @@ static int tcp_chr_read_poll(void *opaque)
return s->max_size;
}
-#define IAC 255
-#define IAC_BREAK 243
static void tcp_chr_process_IAC_bytes(Chardev *chr,
SocketChardev *s,
uint8_t *buf, int *size)
{
- /* Handle any telnet client's basic IAC options to satisfy char by
- * char mode with no echo. All IAC options will be removed from
- * the buf and the do_telnetopt variable will be used to track the
- * state of the width of the IAC information.
+ /* Handle any telnet or tn3270 client's basic IAC options.
+ * For telnet options, it satisfies char by char mode with no echo.
+ * For tn3270 options, it satisfies binary mode with EOR.
+ * All IAC options will be removed from the buf and the do_opt
+ * pointer will be used to track the state of the width of the
+ * IAC information.
*
- * IAC commands come in sets of 3 bytes with the exception of the
- * "IAC BREAK" command and the double IAC.
+ * RFC854: "All TELNET commands consist of at least a two byte sequence.
+ * The commands dealing with option negotiation are three byte sequences,
+ * the third byte being the code for the option referenced."
+ * "IAC BREAK", "IAC IP", "IAC NOP" and the double IAC are two bytes.
+ * "IAC SB", "IAC SE" and "IAC EOR" are saved to split up data boundary
+ * for tn3270.
+ * NOP, Break and Interrupt Process(IP) might be encountered during a TN3270
+ * session, and NOP and IP need to be done later.
*/
int i;
@@ -174,6 +181,18 @@ static void tcp_chr_process_IAC_bytes(Chardev *chr,
/* Handle IAC break commands by sending a serial break */
qemu_chr_be_event(chr, CHR_EVENT_BREAK);
s->do_telnetopt++;
+ } else if (s->is_tn3270 && ((unsigned char)buf[i] == IAC_EOR
+ || (unsigned char)buf[i] == IAC_SB
+ || (unsigned char)buf[i] == IAC_SE)
+ && s->do_telnetopt == 2) {
+ buf[j++] = IAC;
+ buf[j++] = buf[i];
+ s->do_telnetopt++;
+ } else if (s->is_tn3270 && ((unsigned char)buf[i] == IAC_IP
+ || (unsigned char)buf[i] == IAC_NOP)
+ && s->do_telnetopt == 2) {
+ /* TODO: IP and NOP need to be implemented later. */
+ s->do_telnetopt++;
}
s->do_telnetopt++;
}
@@ -366,6 +385,15 @@ static char *SocketAddress_to_str(const char *prefix, SocketAddress *addr,
}
}
+static void update_disconnected_filename(SocketChardev *s)
+{
+ Chardev *chr = CHARDEV(s);
+
+ g_free(chr->filename);
+ chr->filename = SocketAddress_to_str("disconnected:", s->addr,
+ s->is_listen, s->is_telnet);
+}
+
static void tcp_chr_disconnect(Chardev *chr)
{
SocketChardev *s = SOCKET_CHARDEV(chr);
@@ -380,8 +408,7 @@ static void tcp_chr_disconnect(Chardev *chr)
s->listen_tag = qio_channel_add_watch(
QIO_CHANNEL(s->listen_ioc), G_IO_IN, tcp_chr_accept, chr, NULL);
}
- chr->filename = SocketAddress_to_str("disconnected:", s->addr,
- s->is_listen, s->is_telnet);
+ update_disconnected_filename(s);
qemu_chr_be_event(chr, CHR_EVENT_CLOSED);
if (s->reconnect_time) {
qemu_chr_socket_restart_timer(chr);
@@ -489,7 +516,7 @@ static void tcp_chr_connect(void *opaque)
tcp_chr_read,
chr, NULL);
}
- qemu_chr_be_generic_open(chr);
+ qemu_chr_be_event(chr, CHR_EVENT_OPENED);
}
static void tcp_chr_update_read_handler(Chardev *chr,
@@ -512,7 +539,7 @@ static void tcp_chr_update_read_handler(Chardev *chr,
typedef struct {
Chardev *chr;
- char buf[12];
+ char buf[21];
size_t buflen;
} TCPChardevTelnetInit;
@@ -550,9 +577,6 @@ static void tcp_chr_telnet_init(Chardev *chr)
TCPChardevTelnetInit *init = g_new0(TCPChardevTelnetInit, 1);
size_t n = 0;
- init->chr = chr;
- init->buflen = 12;
-
#define IACSET(x, a, b, c) \
do { \
x[n++] = a; \
@@ -560,12 +584,26 @@ static void tcp_chr_telnet_init(Chardev *chr)
x[n++] = c; \
} while (0)
- /* Prep the telnet negotion to put telnet in binary,
- * no echo, single char mode */
- IACSET(init->buf, 0xff, 0xfb, 0x01); /* IAC WILL ECHO */
- IACSET(init->buf, 0xff, 0xfb, 0x03); /* IAC WILL Suppress go ahead */
- IACSET(init->buf, 0xff, 0xfb, 0x00); /* IAC WILL Binary */
- IACSET(init->buf, 0xff, 0xfd, 0x00); /* IAC DO Binary */
+ init->chr = chr;
+ if (!s->is_tn3270) {
+ init->buflen = 12;
+ /* Prep the telnet negotion to put telnet in binary,
+ * no echo, single char mode */
+ IACSET(init->buf, 0xff, 0xfb, 0x01); /* IAC WILL ECHO */
+ IACSET(init->buf, 0xff, 0xfb, 0x03); /* IAC WILL Suppress go ahead */
+ IACSET(init->buf, 0xff, 0xfb, 0x00); /* IAC WILL Binary */
+ IACSET(init->buf, 0xff, 0xfd, 0x00); /* IAC DO Binary */
+ } else {
+ init->buflen = 21;
+ /* Prep the TN3270 negotion based on RFC1576 */
+ IACSET(init->buf, 0xff, 0xfd, 0x19); /* IAC DO EOR */
+ IACSET(init->buf, 0xff, 0xfb, 0x19); /* IAC WILL EOR */
+ IACSET(init->buf, 0xff, 0xfd, 0x00); /* IAC DO BINARY */
+ IACSET(init->buf, 0xff, 0xfb, 0x00); /* IAC WILL BINARY */
+ IACSET(init->buf, 0xff, 0xfd, 0x18); /* IAC DO TERMINAL TYPE */
+ IACSET(init->buf, 0xff, 0xfa, 0x18); /* IAC SB TERMINAL TYPE */
+ IACSET(init->buf, 0x01, 0xff, 0xf0); /* SEND IAC SE */
+ }
#undef IACSET
@@ -585,7 +623,8 @@ static void tcp_chr_tls_handshake(QIOTask *task,
if (qio_task_propagate_error(task, NULL)) {
tcp_chr_disconnect(chr);
} else {
- if (s->do_telnetopt) {
+ /* tn3270 does not support TLS yet */
+ if (s->do_telnetopt && !s->is_tn3270) {
tcp_chr_telnet_init(chr);
} else {
tcp_chr_connect(chr);
@@ -824,12 +863,14 @@ static void qmp_chardev_open_socket(Chardev *chr,
bool do_nodelay = sock->has_nodelay ? sock->nodelay : false;
bool is_listen = sock->has_server ? sock->server : true;
bool is_telnet = sock->has_telnet ? sock->telnet : false;
+ bool is_tn3270 = sock->has_tn3270 ? sock->tn3270 : false;
bool is_waitconnect = sock->has_wait ? sock->wait : false;
int64_t reconnect = sock->has_reconnect ? sock->reconnect : 0;
QIOChannelSocket *sioc = NULL;
s->is_listen = is_listen;
s->is_telnet = is_telnet;
+ s->is_tn3270 = is_tn3270;
s->do_nodelay = do_nodelay;
if (sock->tls_creds) {
Object *creds;
@@ -875,11 +916,10 @@ static void qmp_chardev_open_socket(Chardev *chr,
/* be isn't opened until we get a connection */
*be_opened = false;
- chr->filename = SocketAddress_to_str("disconnected:",
- addr, is_listen, is_telnet);
+ update_disconnected_filename(s);
if (is_listen) {
- if (is_telnet) {
+ if (is_telnet || is_tn3270) {
s->do_telnetopt = 1;
}
} else if (reconnect > 0) {
@@ -904,6 +944,11 @@ static void qmp_chardev_open_socket(Chardev *chr,
if (qio_channel_socket_listen_sync(sioc, s->addr, errp) < 0) {
goto error;
}
+
+ qapi_free_SocketAddress(s->addr);
+ s->addr = socket_local_address(sioc->fd, errp);
+ update_disconnected_filename(s);
+
s->listen_ioc = sioc;
if (is_waitconnect &&
qemu_chr_wait_connected(chr, errp) < 0) {
@@ -933,6 +978,7 @@ static void qemu_chr_parse_socket(QemuOpts *opts, ChardevBackend *backend,
bool is_listen = qemu_opt_get_bool(opts, "server", false);
bool is_waitconnect = is_listen && qemu_opt_get_bool(opts, "wait", true);
bool is_telnet = qemu_opt_get_bool(opts, "telnet", false);
+ bool is_tn3270 = qemu_opt_get_bool(opts, "tn3270", false);
bool do_nodelay = !qemu_opt_get_bool(opts, "delay", true);
int64_t reconnect = qemu_opt_get_number(opts, "reconnect", 0);
const char *path = qemu_opt_get(opts, "path");
@@ -968,6 +1014,8 @@ static void qemu_chr_parse_socket(QemuOpts *opts, ChardevBackend *backend,
sock->server = is_listen;
sock->has_telnet = true;
sock->telnet = is_telnet;
+ sock->has_tn3270 = true;
+ sock->tn3270 = is_tn3270;
sock->has_wait = true;
sock->wait = is_waitconnect;
sock->has_reconnect = true;
@@ -997,6 +1045,23 @@ static void qemu_chr_parse_socket(QemuOpts *opts, ChardevBackend *backend,
sock->addr = addr;
}
+static void
+char_socket_get_addr(Object *obj, Visitor *v, const char *name,
+ void *opaque, Error **errp)
+{
+ SocketChardev *s = SOCKET_CHARDEV(obj);
+
+ visit_type_SocketAddress(v, name, &s->addr, errp);
+}
+
+static bool
+char_socket_get_connected(Object *obj, Error **errp)
+{
+ SocketChardev *s = SOCKET_CHARDEV(obj);
+
+ return s->connected;
+}
+
static void char_socket_class_init(ObjectClass *oc, void *data)
{
ChardevClass *cc = CHARDEV_CLASS(oc);
@@ -1012,6 +1077,13 @@ static void char_socket_class_init(ObjectClass *oc, void *data)
cc->chr_add_client = tcp_chr_add_client;
cc->chr_add_watch = tcp_chr_add_watch;
cc->chr_update_read_handler = tcp_chr_update_read_handler;
+
+ object_class_property_add(oc, "addr", "SocketAddress",
+ char_socket_get_addr, NULL,
+ NULL, NULL, &error_abort);
+
+ object_class_property_add_bool(oc, "connected", char_socket_get_connected,
+ NULL, &error_abort);
}
static const TypeInfo char_socket_type_info = {
diff --git a/chardev/char-udp.c b/chardev/char-udp.c
index 804bd22..1958c36 100644
--- a/chardev/char-udp.c
+++ b/chardev/char-udp.c
@@ -51,6 +51,18 @@ static int udp_chr_write(Chardev *chr, const uint8_t *buf, int len)
s->ioc, (const char *)buf, len, NULL);
}
+static void udp_chr_flush_buffer(UdpChardev *s)
+{
+ Chardev *chr = CHARDEV(s);
+
+ while (s->max_size > 0 && s->bufptr < s->bufcnt) {
+ int n = MIN(s->max_size, s->bufcnt - s->bufptr);
+ qemu_chr_be_write(chr, &s->buf[s->bufptr], n);
+ s->bufptr += n;
+ s->max_size = qemu_chr_be_can_write(chr);
+ }
+}
+
static int udp_chr_read_poll(void *opaque)
{
Chardev *chr = CHARDEV(opaque);
@@ -61,11 +73,8 @@ static int udp_chr_read_poll(void *opaque)
/* If there were any stray characters in the queue process them
* first
*/
- while (s->max_size > 0 && s->bufptr < s->bufcnt) {
- qemu_chr_be_write(chr, &s->buf[s->bufptr], 1);
- s->bufptr++;
- s->max_size = qemu_chr_be_can_write(chr);
- }
+ udp_chr_flush_buffer(s);
+
return s->max_size;
}
@@ -85,13 +94,8 @@ static gboolean udp_chr_read(QIOChannel *chan, GIOCondition cond, void *opaque)
return FALSE;
}
s->bufcnt = ret;
-
s->bufptr = 0;
- while (s->max_size > 0 && s->bufptr < s->bufcnt) {
- qemu_chr_be_write(chr, &s->buf[s->bufptr], 1);
- s->bufptr++;
- s->max_size = qemu_chr_be_can_write(chr);
- }
+ udp_chr_flush_buffer(s);
return TRUE;
}
diff --git a/chardev/char.c b/chardev/char.c
index 3df1163..fadfedb 100644
--- a/chardev/char.c
+++ b/chardev/char.c
@@ -42,8 +42,10 @@
/***********************************************************/
/* character device */
-static QTAILQ_HEAD(ChardevHead, Chardev) chardevs =
- QTAILQ_HEAD_INITIALIZER(chardevs);
+static Object *get_chardevs_root(void)
+{
+ return container_get(object_get_root(), "/chardevs");
+}
void qemu_chr_be_event(Chardev *s, int event)
{
@@ -66,12 +68,6 @@ void qemu_chr_be_event(Chardev *s, int event)
be->chr_event(be->opaque, event);
}
-void qemu_chr_be_generic_open(Chardev *s)
-{
- qemu_chr_be_event(s, CHR_EVENT_OPENED);
-}
-
-
/* Not reporting errors from writing to logfile, as logs are
* defined to be "best effort" only */
static void qemu_chr_fe_write_log(Chardev *s,
@@ -453,26 +449,24 @@ static const TypeInfo char_type_info = {
* mux will receive CHR_EVENT_OPENED notifications for the BE
* immediately.
*/
-static void muxes_realize_done(Notifier *notifier, void *unused)
+static int open_muxes(Object *child, void *opaque)
{
- Chardev *chr;
+ if (CHARDEV_IS_MUX(child)) {
+ /* send OPENED to all already-attached FEs */
+ mux_chr_send_all_event(CHARDEV(child), CHR_EVENT_OPENED);
+ /* mark mux as OPENED so any new FEs will immediately receive
+ * OPENED event
+ */
+ qemu_chr_be_event(CHARDEV(child), CHR_EVENT_OPENED);
+ }
- QTAILQ_FOREACH(chr, &chardevs, next) {
- if (CHARDEV_IS_MUX(chr)) {
- MuxChardev *d = MUX_CHARDEV(chr);
- int i;
+ return 0;
+}
- /* send OPENED to all already-attached FEs */
- for (i = 0; i < d->mux_cnt; i++) {
- mux_chr_send_event(d, i, CHR_EVENT_OPENED);
- }
- /* mark mux as OPENED so any new FEs will immediately receive
- * OPENED event
- */
- qemu_chr_be_generic_open(chr);
- }
- }
+static void muxes_realize_done(Notifier *notifier, void *unused)
+{
muxes_realized = true;
+ object_child_foreach(get_chardevs_root(), open_muxes, NULL);
}
static Notifier muxes_realize_notify = {
@@ -581,7 +575,7 @@ void qemu_chr_fe_set_handlers(CharBackend *b,
/* We're connecting to an already opened device, so let's make sure we
also get the open event */
if (s->be_open) {
- qemu_chr_be_generic_open(s);
+ qemu_chr_be_event(s, CHR_EVENT_OPENED);
}
}
@@ -696,7 +690,8 @@ QemuOpts *qemu_chr_parse_compat(const char *label, const char *filename)
return opts;
}
if (strstart(filename, "tcp:", &p) ||
- strstart(filename, "telnet:", &p)) {
+ strstart(filename, "telnet:", &p) ||
+ strstart(filename, "tn3270:", &p)) {
if (sscanf(p, "%64[^:]:%32[^,]%n", host, port, &pos) < 2) {
host[0] = 0;
if (sscanf(p, ":%32[^,]%n", port, &pos) < 1)
@@ -712,8 +707,11 @@ QemuOpts *qemu_chr_parse_compat(const char *label, const char *filename)
goto fail;
}
}
- if (strstart(filename, "telnet:", &p))
+ if (strstart(filename, "telnet:", &p)) {
qemu_opt_set(opts, "telnet", "on", &error_abort);
+ } else if (strstart(filename, "tn3270:", &p)) {
+ qemu_opt_set(opts, "tn3270", "on", &error_abort);
+ }
return opts;
}
if (strstart(filename, "udp:", &p)) {
@@ -770,7 +768,7 @@ void qemu_chr_parse_common(QemuOpts *opts, ChardevCommon *backend)
const char *logfile = qemu_opt_get(opts, "logfile");
backend->has_logfile = logfile != NULL;
- backend->logfile = logfile ? g_strdup(logfile) : NULL;
+ backend->logfile = g_strdup(logfile);
backend->has_logappend = true;
backend->logappend = qemu_opt_get_bool(opts, "logappend", false);
@@ -805,26 +803,6 @@ static const ChardevClass *char_get_class(const char *driver, Error **errp)
return cc;
}
-static Chardev *qemu_chardev_add(const char *id, const char *typename,
- ChardevBackend *backend, Error **errp)
-{
- Chardev *chr;
-
- chr = qemu_chr_find(id);
- if (chr) {
- error_setg(errp, "Chardev '%s' already exists", id);
- return NULL;
- }
-
- chr = qemu_chardev_new(id, typename, backend, errp);
- if (!chr) {
- return NULL;
- }
-
- QTAILQ_INSERT_TAIL(&chardevs, chr, next);
- return chr;
-}
-
static const struct ChardevAlias {
const char *typename;
const char *alias;
@@ -941,9 +919,10 @@ Chardev *qemu_chr_new_from_opts(QemuOpts *opts,
backend->u.null.data = ccom; /* Any ChardevCommon member would work */
}
- chr = qemu_chardev_add(bid ? bid : id,
+ chr = qemu_chardev_new(bid ? bid : id,
object_class_get_name(OBJECT_CLASS(cc)),
backend, errp);
+
if (chr == NULL) {
goto out;
}
@@ -955,9 +934,9 @@ Chardev *qemu_chr_new_from_opts(QemuOpts *opts,
backend->type = CHARDEV_BACKEND_KIND_MUX;
backend->u.mux.data = g_new0(ChardevMux, 1);
backend->u.mux.data->chardev = g_strdup(bid);
- mux = qemu_chardev_add(id, TYPE_CHARDEV_MUX, backend, errp);
+ mux = qemu_chardev_new(id, TYPE_CHARDEV_MUX, backend, errp);
if (mux == NULL) {
- qemu_chr_delete(chr);
+ object_unparent(OBJECT(chr));
chr = NULL;
goto out;
}
@@ -1071,27 +1050,29 @@ void qemu_chr_fe_disconnect(CharBackend *be)
}
}
-void qemu_chr_delete(Chardev *chr)
+static int qmp_query_chardev_foreach(Object *obj, void *data)
{
- QTAILQ_REMOVE(&chardevs, chr, next);
- object_unref(OBJECT(chr));
+ Chardev *chr = CHARDEV(obj);
+ ChardevInfoList **list = data;
+ ChardevInfoList *info = g_malloc0(sizeof(*info));
+
+ info->value = g_malloc0(sizeof(*info->value));
+ info->value->label = g_strdup(chr->label);
+ info->value->filename = g_strdup(chr->filename);
+ info->value->frontend_open = chr->be && chr->be->fe_open;
+
+ info->next = *list;
+ *list = info;
+
+ return 0;
}
ChardevInfoList *qmp_query_chardev(Error **errp)
{
ChardevInfoList *chr_list = NULL;
- Chardev *chr;
-
- QTAILQ_FOREACH(chr, &chardevs, next) {
- ChardevInfoList *info = g_malloc0(sizeof(*info));
- info->value = g_malloc0(sizeof(*info->value));
- info->value->label = g_strdup(chr->label);
- info->value->filename = g_strdup(chr->filename);
- info->value->frontend_open = chr->be && chr->be->fe_open;
- info->next = chr_list;
- chr_list = info;
- }
+ object_child_foreach(get_chardevs_root(),
+ qmp_query_chardev_foreach, &chr_list);
return chr_list;
}
@@ -1119,14 +1100,9 @@ ChardevBackendInfoList *qmp_query_chardev_backends(Error **errp)
Chardev *qemu_chr_find(const char *name)
{
- Chardev *chr;
+ Object *obj = object_resolve_path_component(get_chardevs_root(), name);
- QTAILQ_FOREACH(chr, &chardevs, next) {
- if (strcmp(chr->label, name) != 0)
- continue;
- return chr;
- }
- return NULL;
+ return obj ? CHARDEV(obj) : NULL;
}
QemuOptsList qemu_chardev_opts = {
@@ -1177,6 +1153,9 @@ QemuOptsList qemu_chardev_opts = {
.name = "telnet",
.type = QEMU_OPT_BOOL,
},{
+ .name = "tn3270",
+ .type = QEMU_OPT_BOOL,
+ },{
.name = "tls-creds",
.type = QEMU_OPT_STRING,
},{
@@ -1236,22 +1215,23 @@ void qemu_chr_set_feature(Chardev *chr,
}
Chardev *qemu_chardev_new(const char *id, const char *typename,
- ChardevBackend *backend, Error **errp)
+ ChardevBackend *backend,
+ Error **errp)
{
+ Object *obj;
Chardev *chr = NULL;
Error *local_err = NULL;
bool be_opened = true;
assert(g_str_has_prefix(typename, "chardev-"));
- chr = CHARDEV(object_new(typename));
+ obj = object_new(typename);
+ chr = CHARDEV(obj);
chr->label = g_strdup(id);
qemu_char_open(chr, backend, &be_opened, &local_err);
if (local_err) {
- error_propagate(errp, local_err);
- object_unref(OBJECT(chr));
- return NULL;
+ goto end;
}
if (!chr->filename) {
@@ -1261,6 +1241,21 @@ Chardev *qemu_chardev_new(const char *id, const char *typename,
qemu_chr_be_event(chr, CHR_EVENT_OPENED);
}
+ if (id) {
+ object_property_add_child(get_chardevs_root(), id, obj, &local_err);
+ if (local_err) {
+ goto end;
+ }
+ object_unref(obj);
+ }
+
+end:
+ if (local_err) {
+ error_propagate(errp, local_err);
+ object_unref(obj);
+ return NULL;
+ }
+
return chr;
}
@@ -1276,7 +1271,7 @@ ChardevReturn *qmp_chardev_add(const char *id, ChardevBackend *backend,
return NULL;
}
- chr = qemu_chardev_add(id, object_class_get_name(OBJECT_CLASS(cc)),
+ chr = qemu_chardev_new(id, object_class_get_name(OBJECT_CLASS(cc)),
backend, errp);
if (!chr) {
return NULL;
@@ -1309,16 +1304,12 @@ void qmp_chardev_remove(const char *id, Error **errp)
"Chardev '%s' cannot be unplugged in record/replay mode", id);
return;
}
- qemu_chr_delete(chr);
+ object_unparent(OBJECT(chr));
}
void qemu_chr_cleanup(void)
{
- Chardev *chr, *tmp;
-
- QTAILQ_FOREACH_SAFE(chr, &chardevs, next, tmp) {
- qemu_chr_delete(chr);
- }
+ object_unparent(get_chardevs_root());
}
static void register_types(void)
diff --git a/default-configs/s390x-softmmu.mak b/default-configs/s390x-softmmu.mak
index 36e15de..9615a48 100644
--- a/default-configs/s390x-softmmu.mak
+++ b/default-configs/s390x-softmmu.mak
@@ -2,6 +2,7 @@ CONFIG_PCI=y
CONFIG_VIRTIO_PCI=y
CONFIG_VIRTIO=y
CONFIG_SCLPCONSOLE=y
+CONFIG_TERMINAL3270=y
CONFIG_S390_FLIC=y
CONFIG_S390_FLIC_KVM=$(CONFIG_KVM)
CONFIG_WDT_DIAG288=y
diff --git a/gdbstub.c b/gdbstub.c
index 9911153..86eed4f 100644
--- a/gdbstub.c
+++ b/gdbstub.c
@@ -286,6 +286,8 @@ enum RSState {
RS_INACTIVE,
RS_IDLE,
RS_GETLINE,
+ RS_GETLINE_ESC,
+ RS_GETLINE_RLE,
RS_CHKSUM1,
RS_CHKSUM2,
};
@@ -296,7 +298,8 @@ typedef struct GDBState {
enum RSState state; /* parsing state */
char line_buf[MAX_PACKET_LENGTH];
int line_buf_index;
- int line_csum;
+ int line_sum; /* running checksum */
+ int line_csum; /* checksum at the end of the packet */
uint8_t last_packet[MAX_PACKET_LENGTH + 4];
int last_packet_len;
int signal;
@@ -1508,7 +1511,6 @@ void gdb_do_syscall(gdb_syscall_complete_cb cb, const char *fmt, ...)
static void gdb_read_byte(GDBState *s, int ch)
{
- int i, csum;
uint8_t reply;
#ifndef CONFIG_USER_ONLY
@@ -1542,35 +1544,123 @@ static void gdb_read_byte(GDBState *s, int ch)
switch(s->state) {
case RS_IDLE:
if (ch == '$') {
+ /* start of command packet */
s->line_buf_index = 0;
+ s->line_sum = 0;
s->state = RS_GETLINE;
+ } else {
+#ifdef DEBUG_GDB
+ printf("gdbstub received garbage between packets: 0x%x\n", ch);
+#endif
}
break;
case RS_GETLINE:
+ if (ch == '}') {
+ /* start escape sequence */
+ s->state = RS_GETLINE_ESC;
+ s->line_sum += ch;
+ } else if (ch == '*') {
+ /* start run length encoding sequence */
+ s->state = RS_GETLINE_RLE;
+ s->line_sum += ch;
+ } else if (ch == '#') {
+ /* end of command, start of checksum*/
+ s->state = RS_CHKSUM1;
+ } else if (s->line_buf_index >= sizeof(s->line_buf) - 1) {
+#ifdef DEBUG_GDB
+ printf("gdbstub command buffer overrun, dropping command\n");
+#endif
+ s->state = RS_IDLE;
+ } else {
+ /* unescaped command character */
+ s->line_buf[s->line_buf_index++] = ch;
+ s->line_sum += ch;
+ }
+ break;
+ case RS_GETLINE_ESC:
if (ch == '#') {
- s->state = RS_CHKSUM1;
+ /* unexpected end of command in escape sequence */
+ s->state = RS_CHKSUM1;
} else if (s->line_buf_index >= sizeof(s->line_buf) - 1) {
+ /* command buffer overrun */
+#ifdef DEBUG_GDB
+ printf("gdbstub command buffer overrun, dropping command\n");
+#endif
s->state = RS_IDLE;
} else {
- s->line_buf[s->line_buf_index++] = ch;
+ /* parse escaped character and leave escape state */
+ s->line_buf[s->line_buf_index++] = ch ^ 0x20;
+ s->line_sum += ch;
+ s->state = RS_GETLINE;
+ }
+ break;
+ case RS_GETLINE_RLE:
+ if (ch < ' ') {
+ /* invalid RLE count encoding */
+#ifdef DEBUG_GDB
+ printf("gdbstub got invalid RLE count: 0x%x\n", ch);
+#endif
+ s->state = RS_GETLINE;
+ } else {
+ /* decode repeat length */
+ int repeat = (unsigned char)ch - ' ' + 3;
+ if (s->line_buf_index + repeat >= sizeof(s->line_buf) - 1) {
+ /* that many repeats would overrun the command buffer */
+#ifdef DEBUG_GDB
+ printf("gdbstub command buffer overrun,"
+ " dropping command\n");
+#endif
+ s->state = RS_IDLE;
+ } else if (s->line_buf_index < 1) {
+ /* got a repeat but we have nothing to repeat */
+#ifdef DEBUG_GDB
+ printf("gdbstub got invalid RLE sequence\n");
+#endif
+ s->state = RS_GETLINE;
+ } else {
+ /* repeat the last character */
+ memset(s->line_buf + s->line_buf_index,
+ s->line_buf[s->line_buf_index - 1], repeat);
+ s->line_buf_index += repeat;
+ s->line_sum += ch;
+ s->state = RS_GETLINE;
+ }
}
break;
case RS_CHKSUM1:
+ /* get high hex digit of checksum */
+ if (!isxdigit(ch)) {
+#ifdef DEBUG_GDB
+ printf("gdbstub got invalid command checksum digit\n");
+#endif
+ s->state = RS_GETLINE;
+ break;
+ }
s->line_buf[s->line_buf_index] = '\0';
s->line_csum = fromhex(ch) << 4;
s->state = RS_CHKSUM2;
break;
case RS_CHKSUM2:
- s->line_csum |= fromhex(ch);
- csum = 0;
- for(i = 0; i < s->line_buf_index; i++) {
- csum += s->line_buf[i];
+ /* get low hex digit of checksum */
+ if (!isxdigit(ch)) {
+#ifdef DEBUG_GDB
+ printf("gdbstub got invalid command checksum digit\n");
+#endif
+ s->state = RS_GETLINE;
+ break;
}
- if (s->line_csum != (csum & 0xff)) {
+ s->line_csum |= fromhex(ch);
+
+ if (s->line_csum != (s->line_sum & 0xff)) {
+ /* send NAK reply */
reply = '-';
put_buffer(s, &reply, 1);
+#ifdef DEBUG_GDB
+ printf("gdbstub got command packet with incorrect checksum\n");
+#endif
s->state = RS_IDLE;
} else {
+ /* send ACK reply */
reply = '+';
put_buffer(s, &reply, 1);
s->state = gdb_handle_packet(s, s->line_buf);
@@ -1611,7 +1701,7 @@ void gdb_exit(CPUArchState *env, int code)
#ifndef CONFIG_USER_ONLY
qemu_chr_fe_deinit(&s->chr);
- qemu_chr_delete(chr);
+ object_unparent(OBJECT(chr));
#endif
}
@@ -1912,7 +2002,7 @@ int gdbserver_start(const char *device)
monitor_init(mon_chr, 0);
} else {
if (qemu_chr_fe_get_driver(&s->chr)) {
- qemu_chr_delete(qemu_chr_fe_get_driver(&s->chr));
+ object_unparent(OBJECT(qemu_chr_fe_get_driver(&s->chr)));
}
mon_chr = s->mon_chr;
memset(s, 0, sizeof(GDBState));
diff --git a/hmp.c b/hmp.c
index ab407d6..bd7b1ca 100644
--- a/hmp.c
+++ b/hmp.c
@@ -19,6 +19,7 @@
#include "net/eth.h"
#include "sysemu/char.h"
#include "sysemu/block-backend.h"
+#include "sysemu/sysemu.h"
#include "qemu/config-file.h"
#include "qemu/option.h"
#include "qemu/timer.h"
@@ -1268,6 +1269,179 @@ void hmp_snapshot_delete_blkdev_internal(Monitor *mon, const QDict *qdict)
hmp_handle_error(mon, &err);
}
+void hmp_loadvm(Monitor *mon, const QDict *qdict)
+{
+ int saved_vm_running = runstate_is_running();
+ const char *name = qdict_get_str(qdict, "name");
+
+ vm_stop(RUN_STATE_RESTORE_VM);
+
+ if (load_vmstate(name) == 0 && saved_vm_running) {
+ vm_start();
+ }
+}
+
+void hmp_savevm(Monitor *mon, const QDict *qdict)
+{
+ save_vmstate(qdict_get_try_str(qdict, "name"));
+}
+
+void hmp_delvm(Monitor *mon, const QDict *qdict)
+{
+ BlockDriverState *bs;
+ Error *err;
+ const char *name = qdict_get_str(qdict, "name");
+
+ if (bdrv_all_delete_snapshot(name, &bs, &err) < 0) {
+ error_reportf_err(err,
+ "Error while deleting snapshot on device '%s': ",
+ bdrv_get_device_name(bs));
+ }
+}
+
+void hmp_info_snapshots(Monitor *mon, const QDict *qdict)
+{
+ BlockDriverState *bs, *bs1;
+ BdrvNextIterator it1;
+ QEMUSnapshotInfo *sn_tab, *sn;
+ bool no_snapshot = true;
+ int nb_sns, i;
+ int total;
+ int *global_snapshots;
+ AioContext *aio_context;
+
+ typedef struct SnapshotEntry {
+ QEMUSnapshotInfo sn;
+ QTAILQ_ENTRY(SnapshotEntry) next;
+ } SnapshotEntry;
+
+ typedef struct ImageEntry {
+ const char *imagename;
+ QTAILQ_ENTRY(ImageEntry) next;
+ QTAILQ_HEAD(, SnapshotEntry) snapshots;
+ } ImageEntry;
+
+ QTAILQ_HEAD(, ImageEntry) image_list =
+ QTAILQ_HEAD_INITIALIZER(image_list);
+
+ ImageEntry *image_entry, *next_ie;
+ SnapshotEntry *snapshot_entry;
+
+ bs = bdrv_all_find_vmstate_bs();
+ if (!bs) {
+ monitor_printf(mon, "No available block device supports snapshots\n");
+ return;
+ }
+ aio_context = bdrv_get_aio_context(bs);
+
+ aio_context_acquire(aio_context);
+ nb_sns = bdrv_snapshot_list(bs, &sn_tab);
+ aio_context_release(aio_context);
+
+ if (nb_sns < 0) {
+ monitor_printf(mon, "bdrv_snapshot_list: error %d\n", nb_sns);
+ return;
+ }
+
+ for (bs1 = bdrv_first(&it1); bs1; bs1 = bdrv_next(&it1)) {
+ int bs1_nb_sns = 0;
+ ImageEntry *ie;
+ SnapshotEntry *se;
+ AioContext *ctx = bdrv_get_aio_context(bs1);
+
+ aio_context_acquire(ctx);
+ if (bdrv_can_snapshot(bs1)) {
+ sn = NULL;
+ bs1_nb_sns = bdrv_snapshot_list(bs1, &sn);
+ if (bs1_nb_sns > 0) {
+ no_snapshot = false;
+ ie = g_new0(ImageEntry, 1);
+ ie->imagename = bdrv_get_device_name(bs1);
+ QTAILQ_INIT(&ie->snapshots);
+ QTAILQ_INSERT_TAIL(&image_list, ie, next);
+ for (i = 0; i < bs1_nb_sns; i++) {
+ se = g_new0(SnapshotEntry, 1);
+ se->sn = sn[i];
+ QTAILQ_INSERT_TAIL(&ie->snapshots, se, next);
+ }
+ }
+ g_free(sn);
+ }
+ aio_context_release(ctx);
+ }
+
+ if (no_snapshot) {
+ monitor_printf(mon, "There is no snapshot available.\n");
+ return;
+ }
+
+ global_snapshots = g_new0(int, nb_sns);
+ total = 0;
+ for (i = 0; i < nb_sns; i++) {
+ SnapshotEntry *next_sn;
+ if (bdrv_all_find_snapshot(sn_tab[i].name, &bs1) == 0) {
+ global_snapshots[total] = i;
+ total++;
+ QTAILQ_FOREACH(image_entry, &image_list, next) {
+ QTAILQ_FOREACH_SAFE(snapshot_entry, &image_entry->snapshots,
+ next, next_sn) {
+ if (!strcmp(sn_tab[i].name, snapshot_entry->sn.name)) {
+ QTAILQ_REMOVE(&image_entry->snapshots, snapshot_entry,
+ next);
+ g_free(snapshot_entry);
+ }
+ }
+ }
+ }
+ }
+
+ monitor_printf(mon, "List of snapshots present on all disks:\n");
+
+ if (total > 0) {
+ bdrv_snapshot_dump((fprintf_function)monitor_printf, mon, NULL);
+ monitor_printf(mon, "\n");
+ for (i = 0; i < total; i++) {
+ sn = &sn_tab[global_snapshots[i]];
+ /* The ID is not guaranteed to be the same on all images, so
+ * overwrite it.
+ */
+ pstrcpy(sn->id_str, sizeof(sn->id_str), "--");
+ bdrv_snapshot_dump((fprintf_function)monitor_printf, mon, sn);
+ monitor_printf(mon, "\n");
+ }
+ } else {
+ monitor_printf(mon, "None\n");
+ }
+
+ QTAILQ_FOREACH(image_entry, &image_list, next) {
+ if (QTAILQ_EMPTY(&image_entry->snapshots)) {
+ continue;
+ }
+ monitor_printf(mon,
+ "\nList of partial (non-loadable) snapshots on '%s':\n",
+ image_entry->imagename);
+ bdrv_snapshot_dump((fprintf_function)monitor_printf, mon, NULL);
+ monitor_printf(mon, "\n");
+ QTAILQ_FOREACH(snapshot_entry, &image_entry->snapshots, next) {
+ bdrv_snapshot_dump((fprintf_function)monitor_printf, mon,
+ &snapshot_entry->sn);
+ monitor_printf(mon, "\n");
+ }
+ }
+
+ QTAILQ_FOREACH_SAFE(image_entry, &image_list, next, next_ie) {
+ SnapshotEntry *next_sn;
+ QTAILQ_FOREACH_SAFE(snapshot_entry, &image_entry->snapshots, next,
+ next_sn) {
+ g_free(snapshot_entry);
+ }
+ g_free(image_entry);
+ }
+ g_free(sn_tab);
+ g_free(global_snapshots);
+
+}
+
void hmp_migrate_cancel(Monitor *mon, const QDict *qdict)
{
qmp_migrate_cancel(NULL);
diff --git a/hmp.h b/hmp.h
index 799fd37..37bb65a 100644
--- a/hmp.h
+++ b/hmp.h
@@ -63,6 +63,10 @@ void hmp_snapshot_blkdev_internal(Monitor *mon, const QDict *qdict);
void hmp_snapshot_delete_blkdev_internal(Monitor *mon, const QDict *qdict);
void hmp_drive_mirror(Monitor *mon, const QDict *qdict);
void hmp_drive_backup(Monitor *mon, const QDict *qdict);
+void hmp_loadvm(Monitor *mon, const QDict *qdict);
+void hmp_savevm(Monitor *mon, const QDict *qdict);
+void hmp_delvm(Monitor *mon, const QDict *qdict);
+void hmp_info_snapshots(Monitor *mon, const QDict *qdict);
void hmp_migrate_cancel(Monitor *mon, const QDict *qdict);
void hmp_migrate_incoming(Monitor *mon, const QDict *qdict);
void hmp_migrate_set_downtime(Monitor *mon, const QDict *qdict);
diff --git a/hw/audio/Makefile.objs b/hw/audio/Makefile.objs
index 7ce85a2..bb6f07a 100644
--- a/hw/audio/Makefile.objs
+++ b/hw/audio/Makefile.objs
@@ -14,5 +14,3 @@ common-obj-$(CONFIG_PL041) += pl041.o lm4549.o
common-obj-$(CONFIG_CS4231) += cs4231.o
common-obj-$(CONFIG_MARVELL_88W8618) += marvell_88w8618.o
common-obj-$(CONFIG_MILKYMIST) += milkymist-ac97.o
-
-$(obj)/adlib.o $(obj)/fmopl.o: QEMU_CFLAGS += -DBUILD_Y8950=0
diff --git a/hw/audio/adlib.c b/hw/audio/adlib.c
index 7836446..09b8248 100644
--- a/hw/audio/adlib.c
+++ b/hw/audio/adlib.c
@@ -33,11 +33,7 @@
#define ADLIB_KILL_TIMERS 1
-#ifdef HAS_YMF262
-#define ADLIB_DESC "Yamaha YMF262 (OPL3)"
-#else
#define ADLIB_DESC "Yamaha YM3812 (OPL2)"
-#endif
#ifdef DEBUG
#include "qemu/timer.h"
@@ -50,14 +46,8 @@
#define ldebug(...)
#endif
-#ifdef HAS_YMF262
-#include "ymf262.h"
-void YMF262UpdateOneQEMU (int which, INT16 *dst, int length);
-#define SHIFT 2
-#else
#include "fmopl.h"
#define SHIFT 1
-#endif
#define TYPE_ADLIB "adlib"
#define ADLIB(obj) OBJECT_CHECK(AdlibState, (obj), TYPE_ADLIB)
@@ -80,9 +70,7 @@ typedef struct {
SWVoiceOut *voice;
int left, pos, samples;
QEMUAudioTimeStamp ats;
-#ifndef HAS_YMF262
FM_OPL *opl;
-#endif
PortioList port_list;
} AdlibState;
@@ -90,11 +78,7 @@ static AdlibState *glob_adlib;
static void adlib_stop_opl_timer (AdlibState *s, size_t n)
{
-#ifdef HAS_YMF262
- YMF262TimerOver (0, n);
-#else
OPLTimerOver (s->opl, n);
-#endif
s->ticking[n] = 0;
}
@@ -131,11 +115,7 @@ static void adlib_write(void *opaque, uint32_t nport, uint32_t val)
adlib_kill_timers (s);
-#ifdef HAS_YMF262
- YMF262Write (0, a, val);
-#else
OPLWrite (s->opl, a, val);
-#endif
}
static uint32_t adlib_read(void *opaque, uint32_t nport)
@@ -145,12 +125,8 @@ static uint32_t adlib_read(void *opaque, uint32_t nport)
int a = nport & 3;
adlib_kill_timers (s);
-
-#ifdef HAS_YMF262
- data = YMF262Read (0, a);
-#else
data = OPLRead (s->opl, a);
-#endif
+
return data;
}
@@ -240,11 +216,7 @@ static void adlib_callback (void *opaque, int free)
return;
}
-#ifdef HAS_YMF262
- YMF262UpdateOneQEMU (0, s->mixbuf + s->pos * 2, samples);
-#else
YM3812UpdateOne (s->opl, s->mixbuf + s->pos, samples);
-#endif
while (samples) {
written = write_audio (s, samples);
@@ -263,14 +235,10 @@ static void adlib_callback (void *opaque, int free)
static void Adlib_fini (AdlibState *s)
{
-#ifdef HAS_YMF262
- YMF262Shutdown ();
-#else
if (s->opl) {
OPLDestroy (s->opl);
s->opl = NULL;
}
-#endif
g_free(s->mixbuf);
@@ -297,17 +265,7 @@ static void adlib_realizefn (DeviceState *dev, Error **errp)
}
glob_adlib = s;
-#ifdef HAS_YMF262
- if (YMF262Init (1, 14318180, s->freq)) {
- error_setg (errp, "YMF262Init %d failed", s->freq);
- return;
- }
- else {
- YMF262SetTimerHandler (0, timer_handler, 0);
- s->enabled = 1;
- }
-#else
- s->opl = OPLCreate (OPL_TYPE_YM3812, 3579545, s->freq);
+ s->opl = OPLCreate (3579545, s->freq);
if (!s->opl) {
error_setg (errp, "OPLCreate %d failed", s->freq);
return;
@@ -316,7 +274,6 @@ static void adlib_realizefn (DeviceState *dev, Error **errp)
OPLSetTimerHandler (s->opl, timer_handler, 0);
s->enabled = 1;
}
-#endif
as.freq = s->freq;
as.nchannels = SHIFT;
diff --git a/hw/audio/fmopl.c b/hw/audio/fmopl.c
index 731110f..202f752 100644
--- a/hw/audio/fmopl.c
+++ b/hw/audio/fmopl.c
@@ -30,21 +30,15 @@
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
-#define HAS_YM3812 1
-
#include "qemu/osdep.h"
#include <math.h>
//#include "driver.h" /* use M.A.M.E. */
#include "fmopl.h"
-
+#include "qemu/osdep.h"
#ifndef PI
#define PI 3.14159265358979323846
#endif
-#ifndef ARRAY_SIZE
-#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
-#endif
-
/* -------------------- for debug --------------------- */
/* #define OPL_OUTPUT_LOG */
#ifdef OPL_OUTPUT_LOG
@@ -124,7 +118,7 @@ static const int slot_array[32]=
/* key scale level */
/* table is 3dB/OCT , DV converts this in TL step at 6dB/OCT */
#define DV (EG_STEP/2)
-static const UINT32 KSL_TABLE[8*16]=
+static const uint32_t KSL_TABLE[8*16]=
{
/* OCT 0 */
0.000/DV, 0.000/DV, 0.000/DV, 0.000/DV,
@@ -172,7 +166,7 @@ static const UINT32 KSL_TABLE[8*16]=
/* sustain lebel table (3db per step) */
/* 0 - 15: 0, 3, 6, 9,12,15,18,21,24,27,30,33,36,39,42,93 (dB)*/
#define SC(db) (db*((3/EG_STEP)*(1<<ENV_BITS)))+EG_DST
-static const INT32 SL_TABLE[16]={
+static const int32_t SL_TABLE[16]={
SC( 0),SC( 1),SC( 2),SC(3 ),SC(4 ),SC(5 ),SC(6 ),SC( 7),
SC( 8),SC( 9),SC(10),SC(11),SC(12),SC(13),SC(14),SC(31)
};
@@ -182,22 +176,22 @@ static const INT32 SL_TABLE[16]={
/* TotalLevel : 48 24 12 6 3 1.5 0.75 (dB) */
/* TL_TABLE[ 0 to TL_MAX ] : plus section */
/* TL_TABLE[ TL_MAX to TL_MAX+TL_MAX-1 ] : minus section */
-static INT32 *TL_TABLE;
+static int32_t *TL_TABLE;
/* pointers to TL_TABLE with sinwave output offset */
-static INT32 **SIN_TABLE;
+static int32_t **SIN_TABLE;
/* LFO table */
-static INT32 *AMS_TABLE;
-static INT32 *VIB_TABLE;
+static int32_t *AMS_TABLE;
+static int32_t *VIB_TABLE;
/* envelope output curve table */
/* attack + decay + OFF */
-static INT32 ENV_CURVE[2*EG_ENT+1];
+static int32_t ENV_CURVE[2*EG_ENT+1];
/* multiple table */
#define ML 2
-static const UINT32 MUL_TABLE[16]= {
+static const uint32_t MUL_TABLE[16]= {
/* 1/2, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15 */
0.50*ML, 1.00*ML, 2.00*ML, 3.00*ML, 4.00*ML, 5.00*ML, 6.00*ML, 7.00*ML,
8.00*ML, 9.00*ML,10.00*ML,10.00*ML,12.00*ML,12.00*ML,15.00*ML,15.00*ML
@@ -205,7 +199,7 @@ static const UINT32 MUL_TABLE[16]= {
#undef ML
/* dummy attack / decay rate ( when rate == 0 ) */
-static INT32 RATE_0[16]=
+static int32_t RATE_0[16]=
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
/* -------------------- static state --------------------- */
@@ -221,14 +215,14 @@ static OPL_CH *S_CH;
static OPL_CH *E_CH;
static OPL_SLOT *SLOT7_1, *SLOT7_2, *SLOT8_1, *SLOT8_2;
-static INT32 outd[1];
-static INT32 ams;
-static INT32 vib;
-static INT32 *ams_table;
-static INT32 *vib_table;
-static INT32 amsIncr;
-static INT32 vibIncr;
-static INT32 feedback2; /* connect for SLOT 2 */
+static int32_t outd[1];
+static int32_t ams;
+static int32_t vib;
+static int32_t *ams_table;
+static int32_t *vib_table;
+static int32_t amsIncr;
+static int32_t vibIncr;
+static int32_t feedback2; /* connect for SLOT 2 */
/* log output level */
#define LOG_ERR 3 /* ERROR */
@@ -262,8 +256,6 @@ static inline void OPL_STATUS_SET(FM_OPL *OPL,int flag)
if(OPL->status & OPL->statusmask)
{ /* IRQ on */
OPL->status |= 0x80;
- /* callback user interrupt handler (IRQ is OFF to ON) */
- if(OPL->IRQHandler) (OPL->IRQHandler)(OPL->IRQParam,1);
}
}
}
@@ -278,8 +270,6 @@ static inline void OPL_STATUS_RESET(FM_OPL *OPL,int flag)
if (!(OPL->status & OPL->statusmask) )
{
OPL->status &= 0x7f;
- /* callback user interrupt handler (IRQ is ON to OFF) */
- if(OPL->IRQHandler) (OPL->IRQHandler)(OPL->IRQParam,0);
}
}
}
@@ -321,7 +311,7 @@ static inline void OPL_KEYOFF(OPL_SLOT *SLOT)
/* ---------- calcrate Envelope Generator & Phase Generator ---------- */
/* return : envelope output */
-static inline UINT32 OPL_CALC_SLOT( OPL_SLOT *SLOT )
+static inline uint32_t OPL_CALC_SLOT( OPL_SLOT *SLOT )
{
/* calcrate envelope generator */
if( (SLOT->evc+=SLOT->evs) >= SLOT->eve )
@@ -361,7 +351,7 @@ static inline UINT32 OPL_CALC_SLOT( OPL_SLOT *SLOT )
/* set algorithm connection */
static void set_algorithm( OPL_CH *CH)
{
- INT32 *carrier = &outd[0];
+ int32_t *carrier = &outd[0];
CH->connect1 = CH->CON ? carrier : &feedback2;
CH->connect2 = carrier;
}
@@ -453,7 +443,7 @@ static inline void set_sl_rr(FM_OPL *OPL,int slot,int v)
/* ---------- calcrate one of channel ---------- */
static inline void OPL_CALC_CH( OPL_CH *CH )
{
- UINT32 env_out;
+ uint32_t env_out;
OPL_SLOT *SLOT;
feedback2 = 0;
@@ -498,9 +488,9 @@ static inline void OPL_CALC_CH( OPL_CH *CH )
#define WHITE_NOISE_db 6.0
static inline void OPL_CALC_RH( OPL_CH *CH )
{
- UINT32 env_tam,env_sd,env_top,env_hh;
+ uint32_t env_tam,env_sd,env_top,env_hh;
int whitenoise = (rand()&1)*(WHITE_NOISE_db/EG_STEP);
- INT32 tone8;
+ int32_t tone8;
OPL_SLOT *SLOT;
int env_out;
@@ -618,20 +608,20 @@ static int OPLOpenTable( void )
double pom;
/* allocate dynamic tables */
- if( (TL_TABLE = malloc(TL_MAX*2*sizeof(INT32))) == NULL)
+ if( (TL_TABLE = malloc(TL_MAX*2*sizeof(int32_t))) == NULL)
return 0;
- if( (SIN_TABLE = malloc(SIN_ENT*4 *sizeof(INT32 *))) == NULL)
+ if( (SIN_TABLE = malloc(SIN_ENT*4 *sizeof(int32_t *))) == NULL)
{
free(TL_TABLE);
return 0;
}
- if( (AMS_TABLE = malloc(AMS_ENT*2 *sizeof(INT32))) == NULL)
+ if( (AMS_TABLE = malloc(AMS_ENT*2 *sizeof(int32_t))) == NULL)
{
free(TL_TABLE);
free(SIN_TABLE);
return 0;
}
- if( (VIB_TABLE = malloc(VIB_ENT*2 *sizeof(INT32))) == NULL)
+ if( (VIB_TABLE = malloc(VIB_ENT*2 *sizeof(int32_t))) == NULL)
{
free(TL_TABLE);
free(SIN_TABLE);
@@ -763,18 +753,15 @@ static void OPLWriteReg(FM_OPL *OPL, int r, int v)
{
case 0x01:
/* wave selector enable */
- if(OPL->type&OPL_TYPE_WAVESEL)
+ OPL->wavesel = v&0x20;
+ if(!OPL->wavesel)
{
- OPL->wavesel = v&0x20;
- if(!OPL->wavesel)
+ /* preset compatible mode */
+ int c;
+ for(c=0;c<OPL->max_ch;c++)
{
- /* preset compatible mode */
- int c;
- for(c=0;c<OPL->max_ch;c++)
- {
- OPL->P_CH[c].SLOT[SLOT1].wavetable = &SIN_TABLE[0];
- OPL->P_CH[c].SLOT[SLOT2].wavetable = &SIN_TABLE[0];
- }
+ OPL->P_CH[c].SLOT[SLOT1].wavetable = &SIN_TABLE[0];
+ OPL->P_CH[c].SLOT[SLOT2].wavetable = &SIN_TABLE[0];
}
}
return;
@@ -791,8 +778,8 @@ static void OPLWriteReg(FM_OPL *OPL, int r, int v)
}
else
{ /* set IRQ mask ,timer enable*/
- UINT8 st1 = v&1;
- UINT8 st2 = (v>>1)&1;
+ uint8_t st1 = v&1;
+ uint8_t st2 = (v>>1)&1;
/* IRQRST,T1MSK,t2MSK,EOSMSK,BRMSK,x,ST2,ST1 */
OPL_STATUS_RESET(OPL,v&0x78);
OPL_STATUSMASK_SET(OPL,((~v)&0x78)|0x01);
@@ -812,57 +799,6 @@ static void OPLWriteReg(FM_OPL *OPL, int r, int v)
}
}
return;
-#if BUILD_Y8950
- case 0x06: /* Key Board OUT */
- if(OPL->type&OPL_TYPE_KEYBOARD)
- {
- if(OPL->keyboardhandler_w)
- OPL->keyboardhandler_w(OPL->keyboard_param,v);
- else
- LOG(LOG_WAR,("OPL:write unmapped KEYBOARD port\n"));
- }
- return;
- case 0x07: /* DELTA-T control : START,REC,MEMDATA,REPT,SPOFF,x,x,RST */
- if(OPL->type&OPL_TYPE_ADPCM)
- YM_DELTAT_ADPCM_Write(OPL->deltat,r-0x07,v);
- return;
- case 0x08: /* MODE,DELTA-T : CSM,NOTESEL,x,x,smpl,da/ad,64k,rom */
- OPL->mode = v;
- v&=0x1f; /* for DELTA-T unit */
- case 0x09: /* START ADD */
- case 0x0a:
- case 0x0b: /* STOP ADD */
- case 0x0c:
- case 0x0d: /* PRESCALE */
- case 0x0e:
- case 0x0f: /* ADPCM data */
- case 0x10: /* DELTA-N */
- case 0x11: /* DELTA-N */
- case 0x12: /* EG-CTRL */
- if(OPL->type&OPL_TYPE_ADPCM)
- YM_DELTAT_ADPCM_Write(OPL->deltat,r-0x07,v);
- return;
-#if 0
- case 0x15: /* DAC data */
- case 0x16:
- case 0x17: /* SHIFT */
- return;
- case 0x18: /* I/O CTRL (Direction) */
- if(OPL->type&OPL_TYPE_IO)
- OPL->portDirection = v&0x0f;
- return;
- case 0x19: /* I/O DATA */
- if(OPL->type&OPL_TYPE_IO)
- {
- OPL->portLatch = v;
- if(OPL->porthandler_w)
- OPL->porthandler_w(OPL->port_param,v&OPL->portDirection);
- }
- return;
- case 0x1a: /* PCM data */
- return;
-#endif
-#endif
}
break;
case 0x20: /* am,vib,ksr,eg type,mul */
@@ -891,7 +827,7 @@ static void OPLWriteReg(FM_OPL *OPL, int r, int v)
case 0xbd:
/* amsep,vibdep,r,bd,sd,tom,tc,hh */
{
- UINT8 rkey = OPL->rhythm^v;
+ uint8_t rkey = OPL->rhythm^v;
OPL->ams_table = &AMS_TABLE[v&0x80 ? AMS_ENT : 0];
OPL->vib_table = &VIB_TABLE[v&0x40 ? VIB_ENT : 0];
OPL->rhythm = v&0x3f;
@@ -1032,20 +968,19 @@ static void OPL_UnLockTable(void)
OPLCloseTable();
}
-#if (BUILD_YM3812 || BUILD_YM3526)
/*******************************************************************************/
/* YM3812 local section */
/*******************************************************************************/
/* ---------- update one of chip ----------- */
-void YM3812UpdateOne(FM_OPL *OPL, INT16 *buffer, int length)
+void YM3812UpdateOne(FM_OPL *OPL, int16_t *buffer, int length)
{
int i;
int data;
- OPLSAMPLE *buf = buffer;
- UINT32 amsCnt = OPL->amsCnt;
- UINT32 vibCnt = OPL->vibCnt;
- UINT8 rhythm = OPL->rhythm&0x20;
+ int16_t *buf = buffer;
+ uint32_t amsCnt = OPL->amsCnt;
+ uint32_t vibCnt = OPL->vibCnt;
+ uint8_t rhythm = OPL->rhythm&0x20;
OPL_CH *CH,*R_CH;
if( (void *)OPL != cur_chip ){
@@ -1095,72 +1030,9 @@ void YM3812UpdateOne(FM_OPL *OPL, INT16 *buffer, int length)
}
#endif
}
-#endif /* (BUILD_YM3812 || BUILD_YM3526) */
-
-#if BUILD_Y8950
-
-void Y8950UpdateOne(FM_OPL *OPL, INT16 *buffer, int length)
-{
- int i;
- int data;
- OPLSAMPLE *buf = buffer;
- UINT32 amsCnt = OPL->amsCnt;
- UINT32 vibCnt = OPL->vibCnt;
- UINT8 rhythm = OPL->rhythm&0x20;
- OPL_CH *CH,*R_CH;
- YM_DELTAT *DELTAT = OPL->deltat;
-
- /* setup DELTA-T unit */
- YM_DELTAT_DECODE_PRESET(DELTAT);
-
- if( (void *)OPL != cur_chip ){
- cur_chip = (void *)OPL;
- /* channel pointers */
- S_CH = OPL->P_CH;
- E_CH = &S_CH[9];
- /* rhythm slot */
- SLOT7_1 = &S_CH[7].SLOT[SLOT1];
- SLOT7_2 = &S_CH[7].SLOT[SLOT2];
- SLOT8_1 = &S_CH[8].SLOT[SLOT1];
- SLOT8_2 = &S_CH[8].SLOT[SLOT2];
- /* LFO state */
- amsIncr = OPL->amsIncr;
- vibIncr = OPL->vibIncr;
- ams_table = OPL->ams_table;
- vib_table = OPL->vib_table;
- }
- R_CH = rhythm ? &S_CH[6] : E_CH;
- for( i=0; i < length ; i++ )
- {
- /* channel A channel B channel C */
- /* LFO */
- ams = ams_table[(amsCnt+=amsIncr)>>AMS_SHIFT];
- vib = vib_table[(vibCnt+=vibIncr)>>VIB_SHIFT];
- outd[0] = 0;
- /* deltaT ADPCM */
- if( DELTAT->portstate )
- YM_DELTAT_ADPCM_CALC(DELTAT);
- /* FM part */
- for(CH=S_CH ; CH < R_CH ; CH++)
- OPL_CALC_CH(CH);
- /* Rythn part */
- if(rhythm)
- OPL_CALC_RH(S_CH);
- /* limit check */
- data = Limit( outd[0] , OPL_MAXOUT, OPL_MINOUT );
- /* store to sound buffer */
- buf[i] = data >> OPL_OUTSB;
- }
- OPL->amsCnt = amsCnt;
- OPL->vibCnt = vibCnt;
- /* deltaT START flag */
- if( !DELTAT->portstate )
- OPL->status &= 0xfe;
-}
-#endif
/* ---------- reset one of chip ---------- */
-void OPLResetChip(FM_OPL *OPL)
+static void OPLResetChip(FM_OPL *OPL)
{
int c,s;
int i;
@@ -1189,23 +1061,11 @@ void OPLResetChip(FM_OPL *OPL)
CH->SLOT[s].evs = 0;
}
}
-#if BUILD_Y8950
- if(OPL->type&OPL_TYPE_ADPCM)
- {
- YM_DELTAT *DELTAT = OPL->deltat;
-
- DELTAT->freqbase = OPL->freqbase;
- DELTAT->output_pointer = outd;
- DELTAT->portshift = 5;
- DELTAT->output_range = DELTAT_MIXING_LEVEL<<TL_BITS;
- YM_DELTAT_ADPCM_Reset(DELTAT,0);
- }
-#endif
}
/* ---------- Create one of vietual YM3812 ---------- */
/* 'rate' is sampling rate and 'bufsiz' is the size of the */
-FM_OPL *OPLCreate(int type, int clock, int rate)
+FM_OPL *OPLCreate(int clock, int rate)
{
char *ptr;
FM_OPL *OPL;
@@ -1216,9 +1076,6 @@ FM_OPL *OPLCreate(int type, int clock, int rate)
/* allocate OPL state space */
state_size = sizeof(FM_OPL);
state_size += sizeof(OPL_CH)*max_ch;
-#if BUILD_Y8950
- if(type&OPL_TYPE_ADPCM) state_size+= sizeof(YM_DELTAT);
-#endif
/* allocate memory block */
ptr = malloc(state_size);
if(ptr==NULL) return NULL;
@@ -1226,11 +1083,7 @@ FM_OPL *OPLCreate(int type, int clock, int rate)
memset(ptr,0,state_size);
OPL = (FM_OPL *)ptr; ptr+=sizeof(FM_OPL);
OPL->P_CH = (OPL_CH *)ptr; ptr+=sizeof(OPL_CH)*max_ch;
-#if BUILD_Y8950
- if(type&OPL_TYPE_ADPCM) OPL->deltat = (YM_DELTAT *)ptr; ptr+=sizeof(YM_DELTAT);
-#endif
/* set channel state pointer */
- OPL->type = type;
OPL->clock = clock;
OPL->rate = rate;
OPL->max_ch = max_ch;
@@ -1280,31 +1133,7 @@ void OPLSetTimerHandler(FM_OPL *OPL,OPL_TIMERHANDLER TimerHandler,int channelOff
OPL->TimerHandler = TimerHandler;
OPL->TimerParam = channelOffset;
}
-void OPLSetIRQHandler(FM_OPL *OPL,OPL_IRQHANDLER IRQHandler,int param)
-{
- OPL->IRQHandler = IRQHandler;
- OPL->IRQParam = param;
-}
-void OPLSetUpdateHandler(FM_OPL *OPL,OPL_UPDATEHANDLER UpdateHandler,int param)
-{
- OPL->UpdateHandler = UpdateHandler;
- OPL->UpdateParam = param;
-}
-#if BUILD_Y8950
-void OPLSetPortHandler(FM_OPL *OPL,OPL_PORTHANDLER_W PortHandler_w,OPL_PORTHANDLER_R PortHandler_r,int param)
-{
- OPL->porthandler_w = PortHandler_w;
- OPL->porthandler_r = PortHandler_r;
- OPL->port_param = param;
-}
-void OPLSetKeyboardHandler(FM_OPL *OPL,OPL_PORTHANDLER_W KeyboardHandler_w,OPL_PORTHANDLER_R KeyboardHandler_r,int param)
-{
- OPL->keyboardhandler_w = KeyboardHandler_w;
- OPL->keyboardhandler_r = KeyboardHandler_r;
- OPL->keyboard_param = param;
-}
-#endif
/* ---------- YM3812 I/O interface ---------- */
int OPLWrite(FM_OPL *OPL,int a,int v)
{
@@ -1314,7 +1143,6 @@ int OPLWrite(FM_OPL *OPL,int a,int v)
}
else
{ /* data port */
- if(OPL->UpdateHandler) OPL->UpdateHandler(OPL->UpdateParam,0);
#ifdef OPL_OUTPUT_LOG
if(opl_dbg_fp)
{
@@ -1338,28 +1166,12 @@ unsigned char OPLRead(FM_OPL *OPL,int a)
switch(OPL->address)
{
case 0x05: /* KeyBoard IN */
- if(OPL->type&OPL_TYPE_KEYBOARD)
- {
- if(OPL->keyboardhandler_r)
- return OPL->keyboardhandler_r(OPL->keyboard_param);
- else {
- LOG(LOG_WAR,("OPL:read unmapped KEYBOARD port\n"));
- }
- }
return 0;
#if 0
case 0x0f: /* ADPCM-DATA */
return 0;
#endif
case 0x19: /* I/O DATA */
- if(OPL->type&OPL_TYPE_IO)
- {
- if(OPL->porthandler_r)
- return OPL->porthandler_r(OPL->port_param);
- else {
- LOG(LOG_WAR,("OPL:read unmapped I/O port\n"));
- }
- }
return 0;
case 0x1a: /* PCM-DATA */
return 0;
@@ -1380,7 +1192,6 @@ int OPLTimerOver(FM_OPL *OPL,int c)
if( OPL->mode & 0x80 )
{ /* CSM mode total level latch and auto key on */
int ch;
- if(OPL->UpdateHandler) OPL->UpdateHandler(OPL->UpdateParam,0);
for(ch=0;ch<9;ch++)
CSMKeyControll( &OPL->P_CH[ch] );
}
diff --git a/hw/audio/fmopl.h b/hw/audio/fmopl.h
index fdda7f9..fc9f16b 100644
--- a/hw/audio/fmopl.h
+++ b/hw/audio/fmopl.h
@@ -1,174 +1,103 @@
#ifndef FMOPL_H
#define FMOPL_H
-/* --- select emulation chips --- */
-#define BUILD_YM3812 (HAS_YM3812)
-//#define BUILD_YM3526 (HAS_YM3526)
-//#define BUILD_Y8950 (HAS_Y8950)
-
-/* --- system optimize --- */
-/* select bit size of output : 8 or 16 */
-#define OPL_OUTPUT_BIT 16
-
-/* compiler dependence */
-#ifndef OSD_CPU_H
-#define OSD_CPU_H
-typedef unsigned char UINT8; /* unsigned 8bit */
-typedef unsigned short UINT16; /* unsigned 16bit */
-typedef unsigned int UINT32; /* unsigned 32bit */
-typedef signed char INT8; /* signed 8bit */
-typedef signed short INT16; /* signed 16bit */
-typedef signed int INT32; /* signed 32bit */
-#endif
-
-#if (OPL_OUTPUT_BIT==16)
-typedef INT16 OPLSAMPLE;
-#endif
-#if (OPL_OUTPUT_BIT==8)
-typedef unsigned char OPLSAMPLE;
-#endif
-
-
-#if BUILD_Y8950
-#include "ymdeltat.h"
-#endif
+#include <stdint.h>
typedef void (*OPL_TIMERHANDLER)(int channel,double interval_Sec);
-typedef void (*OPL_IRQHANDLER)(int param,int irq);
-typedef void (*OPL_UPDATEHANDLER)(int param,int min_interval_us);
-typedef void (*OPL_PORTHANDLER_W)(int param,unsigned char data);
-typedef unsigned char (*OPL_PORTHANDLER_R)(int param);
/* !!!!! here is private section , do not access there member direct !!!!! */
-#define OPL_TYPE_WAVESEL 0x01 /* waveform select */
-#define OPL_TYPE_ADPCM 0x02 /* DELTA-T ADPCM unit */
-#define OPL_TYPE_KEYBOARD 0x04 /* keyboard interface */
-#define OPL_TYPE_IO 0x08 /* I/O port */
-
/* Saving is necessary for member of the 'R' mark for suspend/resume */
/* ---------- OPL one of slot ---------- */
typedef struct fm_opl_slot {
- INT32 TL; /* total level :TL << 8 */
- INT32 TLL; /* adjusted now TL */
- UINT8 KSR; /* key scale rate :(shift down bit) */
- INT32 *AR; /* attack rate :&AR_TABLE[AR<<2] */
- INT32 *DR; /* decay rate :&DR_TALBE[DR<<2] */
- INT32 SL; /* sustin level :SL_TALBE[SL] */
- INT32 *RR; /* release rate :&DR_TABLE[RR<<2] */
- UINT8 ksl; /* keyscale level :(shift down bits) */
- UINT8 ksr; /* key scale rate :kcode>>KSR */
- UINT32 mul; /* multiple :ML_TABLE[ML] */
- UINT32 Cnt; /* frequency count : */
- UINT32 Incr; /* frequency step : */
+ int32_t TL; /* total level :TL << 8 */
+ int32_t TLL; /* adjusted now TL */
+ uint8_t KSR; /* key scale rate :(shift down bit) */
+ int32_t *AR; /* attack rate :&AR_TABLE[AR<<2] */
+ int32_t *DR; /* decay rate :&DR_TALBE[DR<<2] */
+ int32_t SL; /* sustin level :SL_TALBE[SL] */
+ int32_t *RR; /* release rate :&DR_TABLE[RR<<2] */
+ uint8_t ksl; /* keyscale level :(shift down bits) */
+ uint8_t ksr; /* key scale rate :kcode>>KSR */
+ uint32_t mul; /* multiple :ML_TABLE[ML] */
+ uint32_t Cnt; /* frequency count : */
+ uint32_t Incr; /* frequency step : */
/* envelope generator state */
- UINT8 eg_typ; /* envelope type flag */
- UINT8 evm; /* envelope phase */
- INT32 evc; /* envelope counter */
- INT32 eve; /* envelope counter end point */
- INT32 evs; /* envelope counter step */
- INT32 evsa; /* envelope step for AR :AR[ksr] */
- INT32 evsd; /* envelope step for DR :DR[ksr] */
- INT32 evsr; /* envelope step for RR :RR[ksr] */
+ uint8_t eg_typ; /* envelope type flag */
+ uint8_t evm; /* envelope phase */
+ int32_t evc; /* envelope counter */
+ int32_t eve; /* envelope counter end point */
+ int32_t evs; /* envelope counter step */
+ int32_t evsa; /* envelope step for AR :AR[ksr] */
+ int32_t evsd; /* envelope step for DR :DR[ksr] */
+ int32_t evsr; /* envelope step for RR :RR[ksr] */
/* LFO */
- UINT8 ams; /* ams flag */
- UINT8 vib; /* vibrate flag */
+ uint8_t ams; /* ams flag */
+ uint8_t vib; /* vibrate flag */
/* wave selector */
- INT32 **wavetable;
+ int32_t **wavetable;
}OPL_SLOT;
/* ---------- OPL one of channel ---------- */
typedef struct fm_opl_channel {
OPL_SLOT SLOT[2];
- UINT8 CON; /* connection type */
- UINT8 FB; /* feed back :(shift down bit) */
- INT32 *connect1; /* slot1 output pointer */
- INT32 *connect2; /* slot2 output pointer */
- INT32 op1_out[2]; /* slot1 output for selfeedback */
+ uint8_t CON; /* connection type */
+ uint8_t FB; /* feed back :(shift down bit) */
+ int32_t *connect1; /* slot1 output pointer */
+ int32_t *connect2; /* slot2 output pointer */
+ int32_t op1_out[2]; /* slot1 output for selfeedback */
/* phase generator state */
- UINT32 block_fnum; /* block+fnum : */
- UINT8 kcode; /* key code : KeyScaleCode */
- UINT32 fc; /* Freq. Increment base */
- UINT32 ksl_base; /* KeyScaleLevel Base step */
- UINT8 keyon; /* key on/off flag */
+ uint32_t block_fnum; /* block+fnum : */
+ uint8_t kcode; /* key code : KeyScaleCode */
+ uint32_t fc; /* Freq. Increment base */
+ uint32_t ksl_base; /* KeyScaleLevel Base step */
+ uint8_t keyon; /* key on/off flag */
} OPL_CH;
/* OPL state */
typedef struct fm_opl_f {
- UINT8 type; /* chip type */
int clock; /* master clock (Hz) */
int rate; /* sampling rate (Hz) */
double freqbase; /* frequency base */
double TimerBase; /* Timer base time (==sampling time) */
- UINT8 address; /* address register */
- UINT8 status; /* status flag */
- UINT8 statusmask; /* status mask */
- UINT32 mode; /* Reg.08 : CSM , notesel,etc. */
+ uint8_t address; /* address register */
+ uint8_t status; /* status flag */
+ uint8_t statusmask; /* status mask */
+ uint32_t mode; /* Reg.08 : CSM , notesel,etc. */
/* Timer */
int T[2]; /* timer counter */
- UINT8 st[2]; /* timer enable */
+ uint8_t st[2]; /* timer enable */
/* FM channel slots */
OPL_CH *P_CH; /* pointer of CH */
int max_ch; /* maximum channel */
/* Rhythm sention */
- UINT8 rhythm; /* Rhythm mode , key flag */
-#if BUILD_Y8950
- /* Delta-T ADPCM unit (Y8950) */
- YM_DELTAT *deltat; /* DELTA-T ADPCM */
-#endif
- /* Keyboard / I/O interface unit (Y8950) */
- UINT8 portDirection;
- UINT8 portLatch;
- OPL_PORTHANDLER_R porthandler_r;
- OPL_PORTHANDLER_W porthandler_w;
- int port_param;
- OPL_PORTHANDLER_R keyboardhandler_r;
- OPL_PORTHANDLER_W keyboardhandler_w;
- int keyboard_param;
+ uint8_t rhythm; /* Rhythm mode , key flag */
/* time tables */
- INT32 AR_TABLE[75]; /* atttack rate tables */
- INT32 DR_TABLE[75]; /* decay rate tables */
- UINT32 FN_TABLE[1024]; /* fnumber -> increment counter */
+ int32_t AR_TABLE[75]; /* atttack rate tables */
+ int32_t DR_TABLE[75]; /* decay rate tables */
+ uint32_t FN_TABLE[1024]; /* fnumber -> increment counter */
/* LFO */
- INT32 *ams_table;
- INT32 *vib_table;
- INT32 amsCnt;
- INT32 amsIncr;
- INT32 vibCnt;
- INT32 vibIncr;
+ int32_t *ams_table;
+ int32_t *vib_table;
+ int32_t amsCnt;
+ int32_t amsIncr;
+ int32_t vibCnt;
+ int32_t vibIncr;
/* wave selector enable flag */
- UINT8 wavesel;
+ uint8_t wavesel;
/* external event callback handler */
OPL_TIMERHANDLER TimerHandler; /* TIMER handler */
int TimerParam; /* TIMER parameter */
- OPL_IRQHANDLER IRQHandler; /* IRQ handler */
- int IRQParam; /* IRQ parameter */
- OPL_UPDATEHANDLER UpdateHandler; /* stream update handler */
- int UpdateParam; /* stream update parameter */
} FM_OPL;
/* ---------- Generic interface section ---------- */
-#define OPL_TYPE_YM3526 (0)
-#define OPL_TYPE_YM3812 (OPL_TYPE_WAVESEL)
-#define OPL_TYPE_Y8950 (OPL_TYPE_ADPCM|OPL_TYPE_KEYBOARD|OPL_TYPE_IO)
-
-FM_OPL *OPLCreate(int type, int clock, int rate);
+FM_OPL *OPLCreate(int clock, int rate);
void OPLDestroy(FM_OPL *OPL);
void OPLSetTimerHandler(FM_OPL *OPL,OPL_TIMERHANDLER TimerHandler,int channelOffset);
-void OPLSetIRQHandler(FM_OPL *OPL,OPL_IRQHANDLER IRQHandler,int param);
-void OPLSetUpdateHandler(FM_OPL *OPL,OPL_UPDATEHANDLER UpdateHandler,int param);
-/* Y8950 port handlers */
-void OPLSetPortHandler(FM_OPL *OPL,OPL_PORTHANDLER_W PortHandler_w,OPL_PORTHANDLER_R PortHandler_r,int param);
-void OPLSetKeyboardHandler(FM_OPL *OPL,OPL_PORTHANDLER_W KeyboardHandler_w,OPL_PORTHANDLER_R KeyboardHandler_r,int param);
-void OPLResetChip(FM_OPL *OPL);
int OPLWrite(FM_OPL *OPL,int a,int v);
unsigned char OPLRead(FM_OPL *OPL,int a);
int OPLTimerOver(FM_OPL *OPL,int c);
-/* YM3626/YM3812 local section */
-void YM3812UpdateOne(FM_OPL *OPL, INT16 *buffer, int length);
-
-void Y8950UpdateOne(FM_OPL *OPL, INT16 *buffer, int length);
-
+void YM3812UpdateOne(FM_OPL *OPL, int16_t *buffer, int length);
#endif
diff --git a/hw/audio/gus.c b/hw/audio/gus.c
index 3d08a65..ec103a4 100644
--- a/hw/audio/gus.c
+++ b/hw/audio/gus.c
@@ -53,7 +53,7 @@ typedef struct GUSState {
uint32_t freq;
uint32_t port;
int pos, left, shift, irqs;
- GUSsample *mixbuf;
+ int16_t *mixbuf;
uint8_t himem[1024 * 1024 + 32 + 4096];
int samples;
SWVoiceOut *voice;
diff --git a/hw/audio/gusemu.h b/hw/audio/gusemu.h
index 9aec7bf..ab591ee 100644
--- a/hw/audio/gusemu.h
+++ b/hw/audio/gusemu.h
@@ -25,26 +25,10 @@
#ifndef GUSEMU_H
#define GUSEMU_H
-/* data types (need to be adjusted if neither a VC6 nor a C99 compatible compiler is used) */
-
-#if defined _WIN32 && defined _MSC_VER /* doesn't support other win32 compilers yet, do it yourself... */
- typedef unsigned char GUSbyte;
- typedef unsigned short GUSword;
- typedef unsigned int GUSdword;
- typedef signed char GUSchar;
- typedef signed short GUSsample;
-#else
- typedef int8_t GUSchar;
- typedef uint8_t GUSbyte;
- typedef uint16_t GUSword;
- typedef uint32_t GUSdword;
- typedef int16_t GUSsample;
-#endif
-
typedef struct _GUSEmuState
{
- GUSbyte *himemaddr; /* 1024*1024 bytes used for storing uploaded samples (+32 additional bytes for read padding) */
- GUSbyte *gusdatapos; /* (gusdataend-gusdata) bytes used for storing emulated GF1/mixer register states (32*32+4 bytes in initial GUSemu32 version) */
+ uint8_t *himemaddr; /* 1024*1024 bytes used for storing uploaded samples (+32 additional bytes for read padding) */
+ uint8_t *gusdatapos; /* (gusdataend-gusdata) bytes used for storing emulated GF1/mixer register states (32*32+4 bytes in initial GUSemu32 version) */
uint32_t gusirq;
uint32_t gusdma;
unsigned int timer1fraction;
@@ -92,7 +76,7 @@ void gus_dma_transferdata(GUSEmuState *state, char *dma_addr, unsigned int count
/* If the interrupts are asynchronous, it may be needed to use a separate thread mixing into a temporary */
/* audio buffer in order to avoid quality loss caused by large numsamples and elapsed_time values. */
-void gus_mixvoices(GUSEmuState *state, unsigned int playback_freq, unsigned int numsamples, GUSsample *bufferpos);
+void gus_mixvoices(GUSEmuState *state, unsigned int playback_freq, unsigned int numsamples, int16_t *bufferpos);
/* recommended range: 10 < numsamples < 100 */
/* lower values may result in increased rounding error, higher values often cause audible timing delays */
diff --git a/hw/audio/gusemu_hal.c b/hw/audio/gusemu_hal.c
index 973d6b9..1150fc4 100644
--- a/hw/audio/gusemu_hal.c
+++ b/hw/audio/gusemu_hal.c
@@ -31,15 +31,15 @@
#include "gusemu.h"
#define GUSregb(position) (* (gusptr+(position)))
-#define GUSregw(position) (*(GUSword *) (gusptr+(position)))
-#define GUSregd(position) (*(GUSdword *)(gusptr+(position)))
+#define GUSregw(position) (*(uint16_t *) (gusptr+(position)))
+#define GUSregd(position) (*(uint16_t *)(gusptr+(position)))
/* size given in bytes */
unsigned int gus_read(GUSEmuState * state, int port, int size)
{
int value_read = 0;
- GUSbyte *gusptr;
+ uint8_t *gusptr;
gusptr = state->gusdatapos;
GUSregd(portaccesses)++;
@@ -125,7 +125,7 @@ unsigned int gus_read(GUSEmuState * state, int port, int size)
if (!GUSregb(IRQStatReg2x6))
GUS_irqclear(state, state->gusirq);
}
- return (GUSbyte) value_read;
+ return (uint8_t) value_read;
/* DramDMAmemPosReg */
/* case 0x42: value_read=GUSregw(GUS42DMAStart); break;*/
/* 43h+44h write only */
@@ -173,12 +173,12 @@ unsigned int gus_read(GUSEmuState * state, int port, int size)
value_read = value_read >> 8;
value_read &= 0xff;
}
- return (GUSword) value_read;
+ return (uint16_t) value_read;
/* case 0x306: */ /* Mixer/Version info */
/* return 0xff; */ /* Pre 3.6 boards, ICS mixer NOT present */
case 0x307: /* DRAMaccess */
{
- GUSbyte *adr;
+ uint8_t *adr;
adr = state->himemaddr + (GUSregd(GUSDRAMPOS24bit) & 0xfffff);
return *adr;
}
@@ -189,14 +189,14 @@ unsigned int gus_read(GUSEmuState * state, int port, int size)
void gus_write(GUSEmuState * state, int port, int size, unsigned int data)
{
- GUSbyte *gusptr;
+ uint8_t *gusptr;
gusptr = state->gusdatapos;
GUSregd(portaccesses)++;
switch (port & 0xff0f)
{
case 0x200: /* MixerCtrlReg */
- GUSregb(MixerCtrlReg2x0) = (GUSbyte) data;
+ GUSregb(MixerCtrlReg2x0) = (uint8_t) data;
break;
case 0x206: /* IRQstatReg / SB2x6IRQ */
if (GUSregb(GUS45TimerCtrl) & 0x20) /* SB IRQ enabled? -> set 2x6IRQ bit */
@@ -208,7 +208,7 @@ void gus_write(GUSEmuState * state, int port, int size, unsigned int data)
break;
case 0x308: /* AdLib 388h */
case 0x208: /* AdLibCommandReg */
- GUSregb(AdLibCommand2xA) = (GUSbyte) data;
+ GUSregb(AdLibCommand2xA) = (uint8_t) data;
break;
case 0x309: /* AdLib 389h */
case 0x209: /* AdLibDataReg */
@@ -217,11 +217,11 @@ void gus_write(GUSEmuState * state, int port, int size, unsigned int data)
if (data & 0x80)
GUSregb(TimerStatus2x8) &= 0x1f; /* AdLib IRQ reset? -> clear maskable adl. timer int regs */
else
- GUSregb(TimerDataReg2x9) = (GUSbyte) data;
+ GUSregb(TimerDataReg2x9) = (uint8_t) data;
}
else
{
- GUSregb(AdLibData2x9) = (GUSbyte) data;
+ GUSregb(AdLibData2x9) = (uint8_t) data;
if (GUSregb(GUS45TimerCtrl) & 0x02)
{
GUSregb(TimerStatus2x8) |= 0x01;
@@ -231,16 +231,16 @@ void gus_write(GUSEmuState * state, int port, int size, unsigned int data)
}
break;
case 0x20A:
- GUSregb(AdLibStatus2x8) = (GUSbyte) data;
+ GUSregb(AdLibStatus2x8) = (uint8_t) data;
break; /* AdLibStatus2x8 */
case 0x20B: /* GUS hidden registers */
switch (GUSregb(RegCtrl_2xF) & 0x7)
{
case 0:
if (GUSregb(MixerCtrlReg2x0) & 0x40)
- GUSregb(IRQ_2xB) = (GUSbyte) data; /* control register select bit */
+ GUSregb(IRQ_2xB) = (uint8_t) data; /* control register select bit */
else
- GUSregb(DMA_2xB) = (GUSbyte) data;
+ GUSregb(DMA_2xB) = (uint8_t) data;
break;
/* case 1-4: general purpose emulation regs */
case 5: /* clear stat reg 2xF */
@@ -249,7 +249,7 @@ void gus_write(GUSEmuState * state, int port, int size, unsigned int data)
GUS_irqclear(state, state->gusirq);
break;
case 6: /* Jumper reg (Joystick/MIDI enable) */
- GUSregb(Jumper_2xB) = (GUSbyte) data;
+ GUSregb(Jumper_2xB) = (uint8_t) data;
break;
default:;
}
@@ -262,20 +262,20 @@ void gus_write(GUSEmuState * state, int port, int size, unsigned int data)
GUS_irqrequest(state, state->gusirq, 1);
}
case 0x20D: /* SB2xCd no IRQ */
- GUSregb(SB2xCd) = (GUSbyte) data;
+ GUSregb(SB2xCd) = (uint8_t) data;
break;
case 0x20E: /* SB2xE */
- GUSregb(SB2xE) = (GUSbyte) data;
+ GUSregb(SB2xE) = (uint8_t) data;
break;
case 0x20F:
- GUSregb(RegCtrl_2xF) = (GUSbyte) data;
+ GUSregb(RegCtrl_2xF) = (uint8_t) data;
break; /* CtrlReg2xF */
case 0x302: /* VoiceSelReg */
- GUSregb(VoiceSelReg3x2) = (GUSbyte) data;
+ GUSregb(VoiceSelReg3x2) = (uint8_t) data;
break;
case 0x303: /* FunkSelReg */
- GUSregb(FunkSelReg3x3) = (GUSbyte) data;
- if ((GUSbyte) data == 0x8f) /* set irqstatreg, get voicereg and clear IRQ */
+ GUSregb(FunkSelReg3x3) = (uint8_t) data;
+ if ((uint8_t) data == 0x8f) /* set irqstatreg, get voicereg and clear IRQ */
{
int voice;
if (GUSregd(voicewavetableirq)) /* WavetableIRQ */
@@ -318,15 +318,15 @@ void gus_write(GUSEmuState * state, int port, int size, unsigned int data)
case 0x304:
case 0x305:
{
- GUSword writedata = (GUSword) data;
- GUSword readmask = 0x0000;
+ uint16_t writedata = (uint16_t) data;
+ uint16_t readmask = 0x0000;
if (size == 1)
{
readmask = 0xff00;
writedata &= 0xff;
if ((port & 0xff0f) == 0x305)
{
- writedata = (GUSword) (writedata << 8);
+ writedata = (uint16_t) (writedata << 8);
readmask = 0x00ff;
}
}
@@ -353,17 +353,17 @@ void gus_write(GUSEmuState * state, int port, int size, unsigned int data)
break; /* reset flag active? */
offset = 2 * (GUSregb(FunkSelReg3x3) & 0x0f);
offset += (GUSregb(VoiceSelReg3x2) & 0x1f) << 5; /* = Voice*32 + Funktion*2 */
- GUSregw(offset) = (GUSword) ((GUSregw(offset) & readmask) | writedata);
+ GUSregw(offset) = (uint16_t) ((GUSregw(offset) & readmask) | writedata);
}
break;
/* voice unspecific functions */
case 0x0e: /* NumVoices */
- GUSregb(NumVoices) = (GUSbyte) data;
+ GUSregb(NumVoices) = (uint8_t) data;
break;
/* case 0x0f: */ /* read only */
/* common functions */
case 0x41: /* DramDMAContrReg */
- GUSregb(GUS41DMACtrl) = (GUSbyte) data;
+ GUSregb(GUS41DMACtrl) = (uint8_t) data;
if (data & 0x01)
GUS_dmarequest(state);
break;
@@ -380,7 +380,7 @@ void gus_write(GUSEmuState * state, int port, int size, unsigned int data)
(GUSregd(GUSDRAMPOS24bit) & 0xffff) | ((data & 0x0f) << 16);
break;
case 0x45: /* TCtrlReg */
- GUSregb(GUS45TimerCtrl) = (GUSbyte) data;
+ GUSregb(GUS45TimerCtrl) = (uint8_t) data;
if (!(data & 0x20))
GUSregb(TimerStatus2x8) &= 0xe7; /* sb IRQ dis? -> clear 2x8/2xC sb IRQ flags */
if (!(data & 0x02))
@@ -434,18 +434,18 @@ void gus_write(GUSEmuState * state, int port, int size, unsigned int data)
GUS_irqclear(state, state->gusirq);
break;
case 0x46: /* Counter1 */
- GUSregb(GUS46Counter1) = (GUSbyte) data;
+ GUSregb(GUS46Counter1) = (uint8_t) data;
break;
case 0x47: /* Counter2 */
- GUSregb(GUS47Counter2) = (GUSbyte) data;
+ GUSregb(GUS47Counter2) = (uint8_t) data;
break;
/* case 0x48: */ /* sampling freq reg not emulated (same as interwave) */
case 0x49: /* SampCtrlReg */
- GUSregb(GUS49SampCtrl) = (GUSbyte) data;
+ GUSregb(GUS49SampCtrl) = (uint8_t) data;
break;
/* case 0x4b: */ /* joystick trim not emulated */
case 0x4c: /* GUSreset */
- GUSregb(GUS4cReset) = (GUSbyte) data;
+ GUSregb(GUS4cReset) = (uint8_t) data;
if (!(GUSregb(GUS4cReset) & 1)) /* reset... */
{
GUSregd(voicewavetableirq) = 0;
@@ -471,9 +471,9 @@ void gus_write(GUSEmuState * state, int port, int size, unsigned int data)
break;
case 0x307: /* DRAMaccess */
{
- GUSbyte *adr;
+ uint8_t *adr;
adr = state->himemaddr + (GUSregd(GUSDRAMPOS24bit) & 0xfffff);
- *adr = (GUSbyte) data;
+ *adr = (uint8_t) data;
}
break;
}
@@ -510,7 +510,7 @@ void gus_dma_transferdata(GUSEmuState * state, char *dma_addr, unsigned int coun
char *srcaddr;
char *destaddr;
char msbmask = 0;
- GUSbyte *gusptr;
+ uint8_t *gusptr;
gusptr = state->gusdatapos;
srcaddr = dma_addr; /* system memory address */
@@ -521,8 +521,8 @@ void gus_dma_transferdata(GUSEmuState * state, char *dma_addr, unsigned int coun
destaddr = (char *) state->himemaddr + offset; /* wavetable RAM address */
}
- GUSregw(GUS42DMAStart) += (GUSword) (count >> 4); /* ToDo: add 16bit GUS page limit? */
- GUSregb(GUS50DMAHigh) = (GUSbyte) ((count + GUSregb(GUS50DMAHigh)) & 0xf); /* ToDo: add 16bit GUS page limit? */
+ GUSregw(GUS42DMAStart) += (uint16_t) (count >> 4); /* ToDo: add 16bit GUS page limit? */
+ GUSregb(GUS50DMAHigh) = (uint8_t) ((count + GUSregb(GUS50DMAHigh)) & 0xf); /* ToDo: add 16bit GUS page limit? */
if (GUSregb(GUS41DMACtrl) & 0x02) /* direction, 0 := sysram->gusram */
{
diff --git a/hw/audio/gusemu_mixer.c b/hw/audio/gusemu_mixer.c
index 701e8fb..00b9861 100644
--- a/hw/audio/gusemu_mixer.c
+++ b/hw/audio/gusemu_mixer.c
@@ -27,26 +27,26 @@
#include "gustate.h"
#define GUSregb(position) (* (gusptr+(position)))
-#define GUSregw(position) (*(GUSword *) (gusptr+(position)))
-#define GUSregd(position) (*(GUSdword *)(gusptr+(position)))
+#define GUSregw(position) (*(uint16_t *) (gusptr+(position)))
+#define GUSregd(position) (*(uint16_t *)(gusptr+(position)))
-#define GUSvoice(position) (*(GUSword *)(voiceptr+(position)))
+#define GUSvoice(position) (*(uint16_t *)(voiceptr+(position)))
/* samples are always 16bit stereo (4 bytes each, first right then left interleaved) */
void gus_mixvoices(GUSEmuState * state, unsigned int playback_freq, unsigned int numsamples,
- GUSsample *bufferpos)
+ int16_t *bufferpos)
{
/* note that byte registers are stored in the upper half of each voice register! */
- GUSbyte *gusptr;
+ uint8_t *gusptr;
int Voice;
- GUSword *voiceptr;
+ uint16_t *voiceptr;
unsigned int count;
for (count = 0; count < numsamples * 2; count++)
*(bufferpos + count) = 0; /* clear */
gusptr = state->gusdatapos;
- voiceptr = (GUSword *) gusptr;
+ voiceptr = (uint16_t *) gusptr;
if (!(GUSregb(GUS4cReset) & 0x01)) /* reset flag active? */
return;
@@ -85,16 +85,16 @@ void gus_mixvoices(GUSEmuState * state, unsigned int playback_freq, unsigned int
if (GUSvoice(wVSRControl) & 0x400) /* 16bit */
{
int offset = ((CurrPos >> 9) & 0xc0000) + (((CurrPos >> 9) & 0x1ffff) << 1);
- GUSchar *adr;
- adr = (GUSchar *) state->himemaddr + offset;
+ int8_t *adr;
+ adr = (int8_t *) state->himemaddr + offset;
sample1 = (*adr & 0xff) + (*(adr + 1) * 256);
sample2 = (*(adr + 2) & 0xff) + (*(adr + 2 + 1) * 256);
}
else /* 8bit */
{
int offset = (CurrPos >> 9) & 0xfffff;
- GUSchar *adr;
- adr = (GUSchar *) state->himemaddr + offset;
+ int8_t *adr;
+ adr = (int8_t *) state->himemaddr + offset;
sample1 = (*adr) * 256;
sample2 = (*(adr + 1)) * 256;
}
@@ -171,8 +171,8 @@ void gus_mixvoices(GUSEmuState * state, unsigned int playback_freq, unsigned int
}
/* mix samples into buffer */
- *(bufferpos + 2 * sample) += (GUSsample) ((sample1 * PanningPos) >> 4); /* right */
- *(bufferpos + 2 * sample + 1) += (GUSsample) ((sample1 * (15 - PanningPos)) >> 4); /* left */
+ *(bufferpos + 2 * sample) += (int16_t) ((sample1 * PanningPos) >> 4); /* right */
+ *(bufferpos + 2 * sample + 1) += (int16_t) ((sample1 * (15 - PanningPos)) >> 4); /* left */
}
/* write back voice and volume */
GUSvoice(wVSRCurrVol) = Volume32 / 32;
@@ -187,7 +187,7 @@ void gus_irqgen(GUSEmuState * state, unsigned int elapsed_time)
/* time given in microseconds */
{
int requestedIRQs = 0;
- GUSbyte *gusptr;
+ uint8_t *gusptr;
gusptr = state->gusdatapos;
if (GUSregb(TimerDataReg2x9) & 1) /* start timer 1 (80us decrement rate) */
{
diff --git a/hw/audio/hda-codec.c b/hw/audio/hda-codec.c
index 52d4640..5402cd1 100644
--- a/hw/audio/hda-codec.c
+++ b/hw/audio/hda-codec.c
@@ -520,7 +520,7 @@ static int hda_audio_init(HDACodecDevice *hda, const struct desc_codec *desc)
return 0;
}
-static int hda_audio_exit(HDACodecDevice *hda)
+static void hda_audio_exit(HDACodecDevice *hda)
{
HDAAudioState *a = HDA_AUDIO(hda);
HDAAudioStream *st;
@@ -539,7 +539,6 @@ static int hda_audio_exit(HDACodecDevice *hda)
}
}
AUD_remove_card(&a->card);
- return 0;
}
static int hda_audio_post_load(void *opaque, int version)
diff --git a/hw/audio/intel-hda.c b/hw/audio/intel-hda.c
index 537face..2c497eb 100644
--- a/hw/audio/intel-hda.c
+++ b/hw/audio/intel-hda.c
@@ -70,7 +70,7 @@ static void hda_codec_dev_realize(DeviceState *qdev, Error **errp)
}
}
-static int hda_codec_dev_exit(DeviceState *qdev)
+static void hda_codec_dev_unrealize(DeviceState *qdev, Error **errp)
{
HDACodecDevice *dev = HDA_CODEC_DEVICE(qdev);
HDACodecDeviceClass *cdc = HDA_CODEC_DEVICE_GET_CLASS(dev);
@@ -78,7 +78,6 @@ static int hda_codec_dev_exit(DeviceState *qdev)
if (cdc->exit) {
cdc->exit(dev);
}
- return 0;
}
HDACodecDevice *hda_codec_find(HDACodecBus *bus, uint32_t cad)
@@ -1318,7 +1317,7 @@ static void hda_codec_device_class_init(ObjectClass *klass, void *data)
{
DeviceClass *k = DEVICE_CLASS(klass);
k->realize = hda_codec_dev_realize;
- k->exit = hda_codec_dev_exit;
+ k->unrealize = hda_codec_dev_unrealize;
set_bit(DEVICE_CATEGORY_SOUND, k->categories);
k->bus_type = TYPE_HDA_BUS;
k->props = hda_props;
diff --git a/hw/audio/intel-hda.h b/hw/audio/intel-hda.h
index d784bcf..53b78da 100644
--- a/hw/audio/intel-hda.h
+++ b/hw/audio/intel-hda.h
@@ -38,7 +38,7 @@ typedef struct HDACodecDeviceClass
DeviceClass parent_class;
int (*init)(HDACodecDevice *dev);
- int (*exit)(HDACodecDevice *dev);
+ void (*exit)(HDACodecDevice *dev);
void (*command)(HDACodecDevice *dev, uint32_t nid, uint32_t data);
void (*stream)(HDACodecDevice *dev, uint32_t stnr, bool running, bool output);
} HDACodecDeviceClass;
diff --git a/hw/char/Makefile.objs b/hw/char/Makefile.objs
index 725fdc4..55fcb68 100644
--- a/hw/char/Makefile.objs
+++ b/hw/char/Makefile.objs
@@ -29,3 +29,4 @@ common-obj-$(CONFIG_MILKYMIST) += milkymist-uart.o
common-obj-$(CONFIG_SCLPCONSOLE) += sclpconsole.o sclpconsole-lm.o
obj-$(CONFIG_VIRTIO) += virtio-serial-bus.o
+obj-$(CONFIG_TERMINAL3270) += terminal3270.o
diff --git a/hw/char/terminal3270.c b/hw/char/terminal3270.c
new file mode 100644
index 0000000..b2dda01
--- /dev/null
+++ b/hw/char/terminal3270.c
@@ -0,0 +1,293 @@
+/*
+ * Terminal 3270 implementation
+ *
+ * Copyright 2017 IBM Corp.
+ *
+ * Authors: Yang Chen <bjcyang@linux.vnet.ibm.com>
+ * Jing Liu <liujbjl@linux.vnet.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or (at
+ * your option) any later version. See the COPYING file in the top-level
+ * directory.
+ */
+
+#include "qemu/osdep.h"
+#include "qapi/error.h"
+#include "sysemu/char.h"
+#include "hw/s390x/3270-ccw.h"
+
+/* Enough spaces for different window sizes. */
+#define INPUT_BUFFER_SIZE 1000
+/*
+ * 1 for header, 1024*2 for datastream, 2 for tail
+ * Reserve enough spaces for telnet IAC escape.
+ */
+#define OUTPUT_BUFFER_SIZE 2051
+
+typedef struct Terminal3270 {
+ EmulatedCcw3270Device cdev;
+ CharBackend chr;
+ uint8_t inv[INPUT_BUFFER_SIZE];
+ uint8_t outv[OUTPUT_BUFFER_SIZE];
+ int in_len;
+ int out_len;
+ bool handshake_done;
+ guint timer_tag;
+} Terminal3270;
+
+#define TYPE_TERMINAL_3270 "x-terminal3270"
+#define TERMINAL_3270(obj) \
+ OBJECT_CHECK(Terminal3270, (obj), TYPE_TERMINAL_3270)
+
+static int terminal_can_read(void *opaque)
+{
+ Terminal3270 *t = opaque;
+
+ return INPUT_BUFFER_SIZE - t->in_len;
+}
+
+/*
+ * Protocol handshake done,
+ * signal guest by an unsolicited DE irq.
+ */
+static void TN3270_handshake_done(Terminal3270 *t)
+{
+ CcwDevice *ccw_dev = CCW_DEVICE(t);
+ SubchDev *sch = ccw_dev->sch;
+
+ t->handshake_done = true;
+ sch->curr_status.scsw.dstat = SCSW_DSTAT_DEVICE_END;
+ css_conditional_io_interrupt(sch);
+}
+
+/*
+ * Called when the interval is timeout to detect
+ * if the client is still alive by Timing Mark.
+ */
+static gboolean send_timing_mark_cb(gpointer opaque)
+{
+ Terminal3270 *t = opaque;
+ const uint8_t timing[] = {0xff, 0xfd, 0x06};
+
+ qemu_chr_fe_write_all(&t->chr, timing, sizeof(timing));
+ return true;
+}
+
+/*
+ * Receive inbound data from socket.
+ * For data given to guest, drop the data boundary IAC, IAC_EOR.
+ * TODO:
+ * Using "Reset" key on x3270 may result multiple commands in one packet.
+ * This usually happens when the user meets a poor traffic of the network.
+ * As of now, for such case, we simply terminate the connection,
+ * and we should come back here later with a better solution.
+ */
+static void terminal_read(void *opaque, const uint8_t *buf, int size)
+{
+ Terminal3270 *t = opaque;
+ CcwDevice *ccw_dev = CCW_DEVICE(t);
+ SubchDev *sch = ccw_dev->sch;
+ int end;
+
+ assert(size <= (INPUT_BUFFER_SIZE - t->in_len));
+
+ if (t->timer_tag) {
+ g_source_remove(t->timer_tag);
+ t->timer_tag = 0;
+ }
+ t->timer_tag = g_timeout_add_seconds(600, send_timing_mark_cb, t);
+
+ memcpy(&t->inv[t->in_len], buf, size);
+ t->in_len += size;
+ if (t->in_len < 2) {
+ return;
+ }
+
+ if (!t->handshake_done) {
+ /*
+ * Receiving Terminal Type is the last step of handshake.
+ * The data format: IAC SB Terminal-Type IS <terminal type> IAC SE
+ * The code for Terminal-Type is 0x18, for IS is 0.
+ * Simply check the data format and mark handshake_done.
+ */
+ if (t->in_len > 6 && t->inv[2] == 0x18 && t->inv[3] == 0x0 &&
+ t->inv[t->in_len - 2] == IAC && t->inv[t->in_len - 1] == IAC_SE) {
+ TN3270_handshake_done(t);
+ t->in_len = 0;
+ }
+ return;
+ }
+
+ for (end = 0; end < t->in_len - 1; end++) {
+ if (t->inv[end] == IAC && t->inv[end + 1] == IAC_EOR) {
+ break;
+ }
+ }
+ if (end == t->in_len - 2) {
+ /* Data is valid for consuming. */
+ t->in_len -= 2;
+ sch->curr_status.scsw.dstat = SCSW_DSTAT_ATTENTION;
+ css_conditional_io_interrupt(sch);
+ } else if (end < t->in_len - 2) {
+ /* "Reset" key is used. */
+ qemu_chr_fe_disconnect(&t->chr);
+ } else {
+ /* Gathering data. */
+ return;
+ }
+}
+
+static void chr_event(void *opaque, int event)
+{
+ Terminal3270 *t = opaque;
+ CcwDevice *ccw_dev = CCW_DEVICE(t);
+ SubchDev *sch = ccw_dev->sch;
+
+ /* Ensure the initial status correct, always reset them. */
+ t->in_len = 0;
+ t->out_len = 0;
+ t->handshake_done = false;
+ if (t->timer_tag) {
+ g_source_remove(t->timer_tag);
+ t->timer_tag = 0;
+ }
+
+ switch (event) {
+ case CHR_EVENT_OPENED:
+ /*
+ * 3270 does handshake firstly by the negotiate options in
+ * char-socket.c. Once qemu receives the terminal-type of the
+ * client, mark handshake done and trigger everything rolling again.
+ */
+ t->timer_tag = g_timeout_add_seconds(600, send_timing_mark_cb, t);
+ break;
+ case CHR_EVENT_CLOSED:
+ sch->curr_status.scsw.dstat = SCSW_DSTAT_DEVICE_END;
+ css_conditional_io_interrupt(sch);
+ break;
+ }
+}
+
+static void terminal_init(EmulatedCcw3270Device *dev, Error **errp)
+{
+ Terminal3270 *t = TERMINAL_3270(dev);
+ static bool terminal_available;
+
+ if (terminal_available) {
+ error_setg(errp, "Multiple 3270 terminals are not supported.");
+ return;
+ }
+ terminal_available = true;
+ qemu_chr_fe_set_handlers(&t->chr, terminal_can_read,
+ terminal_read, chr_event, t, NULL, true);
+}
+
+static int read_payload_3270(EmulatedCcw3270Device *dev, uint32_t cda,
+ uint16_t count)
+{
+ Terminal3270 *t = TERMINAL_3270(dev);
+ int len;
+
+ len = MIN(count, t->in_len);
+ cpu_physical_memory_write(cda, t->inv, len);
+ t->in_len -= len;
+
+ return len;
+}
+
+/* TN3270 uses binary transmission, which needs escape IAC to IAC IAC */
+static int insert_IAC_escape_char(uint8_t *outv, int out_len)
+{
+ int IAC_num = 0, new_out_len, i, j;
+
+ for (i = 0; i < out_len; i++) {
+ if (outv[i] == IAC) {
+ IAC_num++;
+ }
+ }
+ if (IAC_num == 0) {
+ return out_len;
+ }
+ new_out_len = out_len + IAC_num;
+ for (i = out_len - 1, j = new_out_len - 1; j > i && i >= 0; i--, j--) {
+ outv[j] = outv[i];
+ if (outv[i] == IAC) {
+ outv[--j] = IAC;
+ }
+ }
+ return new_out_len;
+}
+
+/*
+ * Write 3270 outbound to socket.
+ * Return the count of 3270 data field if succeeded, zero if failed.
+ */
+static int write_payload_3270(EmulatedCcw3270Device *dev, uint8_t cmd,
+ uint32_t cda, uint16_t count)
+{
+ Terminal3270 *t = TERMINAL_3270(dev);
+ int retval = 0;
+
+ assert(count <= (OUTPUT_BUFFER_SIZE - 3) / 2);
+
+ if (!t->handshake_done) {
+ if (!(t->outv[0] == IAC && t->outv[1] != IAC)) {
+ /*
+ * Before having finished 3270 negotiation,
+ * sending outbound data except protocol options is prohibited.
+ */
+ return 0;
+ }
+ }
+ if (!qemu_chr_fe_get_driver(&t->chr)) {
+ /* We just say we consumed all data if there's no backend. */
+ return count;
+ }
+ t->outv[0] = cmd;
+ cpu_physical_memory_read(cda, &t->outv[1], count);
+ t->out_len = count + 1;
+
+ t->out_len = insert_IAC_escape_char(t->outv, t->out_len);
+ t->outv[t->out_len++] = IAC;
+ t->outv[t->out_len++] = IAC_EOR;
+
+ retval = qemu_chr_fe_write_all(&t->chr, t->outv, t->out_len);
+ return (retval <= 0) ? 0 : (retval - 3);
+}
+
+static Property terminal_properties[] = {
+ DEFINE_PROP_CHR("chardev", Terminal3270, chr),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static const VMStateDescription terminal3270_vmstate = {
+ .name = TYPE_TERMINAL_3270,
+ .unmigratable = 1,
+};
+
+static void terminal_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ EmulatedCcw3270Class *ck = EMULATED_CCW_3270_CLASS(klass);
+
+ dc->props = terminal_properties;
+ dc->vmsd = &terminal3270_vmstate;
+ ck->init = terminal_init;
+ ck->read_payload_3270 = read_payload_3270;
+ ck->write_payload_3270 = write_payload_3270;
+}
+
+static const TypeInfo ccw_terminal_info = {
+ .name = TYPE_TERMINAL_3270,
+ .parent = TYPE_EMULATED_CCW_3270,
+ .instance_size = sizeof(Terminal3270),
+ .class_init = terminal_class_init,
+ .class_size = sizeof(EmulatedCcw3270Class),
+};
+
+static void register_types(void)
+{
+ type_register_static(&ccw_terminal_info);
+}
+
+type_init(register_types)
diff --git a/hw/input/hid.c b/hw/input/hid.c
index fa9cc4c..93887ec 100644
--- a/hw/input/hid.c
+++ b/hw/input/hid.c
@@ -256,6 +256,10 @@ static void hid_keyboard_process_keycode(HIDState *hs)
slot = hs->head & QUEUE_MASK; QUEUE_INCR(hs->head); hs->n--;
keycode = hs->kbd.keycodes[slot];
+ if (!hs->n) {
+ trace_hid_kbd_queue_empty();
+ }
+
key = keycode & 0x7f;
index = key | ((hs->kbd.modifiers & (1 << 8)) >> 1);
hid_code = hid_usage_keys[index];
diff --git a/hw/input/trace-events b/hw/input/trace-events
index f3bfbed..5a87818 100644
--- a/hw/input/trace-events
+++ b/hw/input/trace-events
@@ -24,6 +24,7 @@ milkymist_softusb_pulse_irq(void) "Pulse IRQ"
# hw/input/hid.c
hid_kbd_queue_full(void) "queue full"
+hid_kbd_queue_empty(void) "queue empty"
# hw/input/virtio
virtio_input_queue_full(void) "queue full"
diff --git a/hw/openrisc/cputimer.c b/hw/openrisc/cputimer.c
index a98c799..febc469 100644
--- a/hw/openrisc/cputimer.c
+++ b/hw/openrisc/cputimer.c
@@ -61,6 +61,7 @@ void cpu_openrisc_timer_update(OpenRISCCPU *cpu)
}
next = now + (uint64_t)wait * TIMER_PERIOD;
timer_mod(cpu->env.timer, next);
+ qemu_cpu_kick(CPU(cpu));
}
void cpu_openrisc_count_start(OpenRISCCPU *cpu)
diff --git a/hw/s390x/3270-ccw.c b/hw/s390x/3270-ccw.c
new file mode 100644
index 0000000..a7a5b41
--- /dev/null
+++ b/hw/s390x/3270-ccw.c
@@ -0,0 +1,174 @@
+/*
+ * Emulated ccw-attached 3270 implementation
+ *
+ * Copyright 2017 IBM Corp.
+ * Author(s): Yang Chen <bjcyang@linux.vnet.ibm.com>
+ * Jing Liu <liujbjl@linux.vnet.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or (at
+ * your option) any later version. See the COPYING file in the top-level
+ * directory.
+ */
+#include "qemu/osdep.h"
+#include "qapi/error.h"
+#include "qemu/module.h"
+#include "cpu.h"
+#include "hw/s390x/css.h"
+#include "hw/s390x/css-bridge.h"
+#include "hw/s390x/3270-ccw.h"
+
+/* Handle READ ccw commands from guest */
+static int handle_payload_3270_read(EmulatedCcw3270Device *dev, CCW1 *ccw)
+{
+ EmulatedCcw3270Class *ck = EMULATED_CCW_3270_GET_CLASS(dev);
+ CcwDevice *ccw_dev = CCW_DEVICE(dev);
+ int len;
+
+ if (!ccw->cda) {
+ return -EFAULT;
+ }
+
+ len = ck->read_payload_3270(dev, ccw->cda, ccw->count);
+ ccw_dev->sch->curr_status.scsw.count = ccw->count - len;
+
+ return 0;
+}
+
+/* Handle WRITE ccw commands to write data to client */
+static int handle_payload_3270_write(EmulatedCcw3270Device *dev, CCW1 *ccw)
+{
+ EmulatedCcw3270Class *ck = EMULATED_CCW_3270_GET_CLASS(dev);
+ CcwDevice *ccw_dev = CCW_DEVICE(dev);
+ int len;
+
+ if (!ccw->cda) {
+ return -EFAULT;
+ }
+
+ len = ck->write_payload_3270(dev, ccw->cmd_code, ccw->cda, ccw->count);
+
+ if (len <= 0) {
+ return -EIO;
+ }
+
+ ccw_dev->sch->curr_status.scsw.count = ccw->count - len;
+ return 0;
+}
+
+static int emulated_ccw_3270_cb(SubchDev *sch, CCW1 ccw)
+{
+ int rc = 0;
+ EmulatedCcw3270Device *dev = sch->driver_data;
+
+ switch (ccw.cmd_code) {
+ case TC_WRITESF:
+ case TC_WRITE:
+ case TC_EWRITE:
+ case TC_EWRITEA:
+ rc = handle_payload_3270_write(dev, &ccw);
+ break;
+ case TC_RDBUF:
+ case TC_READMOD:
+ rc = handle_payload_3270_read(dev, &ccw);
+ break;
+ default:
+ rc = -ENOSYS;
+ break;
+ }
+
+ if (rc == -EIO) {
+ /* I/O error, specific devices generate specific conditions */
+ SCSW *s = &sch->curr_status.scsw;
+
+ sch->curr_status.scsw.dstat = SCSW_DSTAT_UNIT_CHECK;
+ sch->sense_data[0] = 0x40; /* intervention-req */
+ s->ctrl &= ~SCSW_ACTL_START_PEND;
+ s->ctrl &= ~SCSW_CTRL_MASK_STCTL;
+ s->ctrl |= SCSW_STCTL_PRIMARY | SCSW_STCTL_SECONDARY |
+ SCSW_STCTL_ALERT | SCSW_STCTL_STATUS_PEND;
+ }
+
+ return rc;
+}
+
+static void emulated_ccw_3270_realize(DeviceState *ds, Error **errp)
+{
+ uint16_t chpid;
+ EmulatedCcw3270Device *dev = EMULATED_CCW_3270(ds);
+ EmulatedCcw3270Class *ck = EMULATED_CCW_3270_GET_CLASS(dev);
+ CcwDevice *cdev = CCW_DEVICE(ds);
+ CCWDeviceClass *cdk = CCW_DEVICE_GET_CLASS(cdev);
+ SubchDev *sch = css_create_virtual_sch(cdev->devno, errp);
+ Error *err = NULL;
+
+ if (!sch) {
+ return;
+ }
+
+ if (!ck->init) {
+ goto out_err;
+ }
+
+ sch->driver_data = dev;
+ cdev->sch = sch;
+ chpid = css_find_free_chpid(sch->cssid);
+
+ if (chpid > MAX_CHPID) {
+ error_setg(&err, "No available chpid to use.");
+ goto out_err;
+ }
+
+ sch->id.reserved = 0xff;
+ sch->id.cu_type = EMULATED_CCW_3270_CU_TYPE;
+ css_sch_build_virtual_schib(sch, (uint8_t)chpid,
+ EMULATED_CCW_3270_CHPID_TYPE);
+ sch->ccw_cb = emulated_ccw_3270_cb;
+
+ ck->init(dev, &err);
+ if (err) {
+ goto out_err;
+ }
+
+ cdk->realize(cdev, &err);
+ if (err) {
+ goto out_err;
+ }
+
+ return;
+
+out_err:
+ error_propagate(errp, err);
+ css_subch_assign(sch->cssid, sch->ssid, sch->schid, sch->devno, NULL);
+ cdev->sch = NULL;
+ g_free(sch);
+}
+
+static Property emulated_ccw_3270_properties[] = {
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void emulated_ccw_3270_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+
+ dc->props = emulated_ccw_3270_properties;
+ dc->bus_type = TYPE_VIRTUAL_CSS_BUS;
+ dc->realize = emulated_ccw_3270_realize;
+ dc->hotpluggable = false;
+}
+
+static const TypeInfo emulated_ccw_3270_info = {
+ .name = TYPE_EMULATED_CCW_3270,
+ .parent = TYPE_CCW_DEVICE,
+ .instance_size = sizeof(EmulatedCcw3270Device),
+ .class_init = emulated_ccw_3270_class_init,
+ .class_size = sizeof(EmulatedCcw3270Class),
+ .abstract = true,
+};
+
+static void emulated_ccw_register(void)
+{
+ type_register_static(&emulated_ccw_3270_info);
+}
+
+type_init(emulated_ccw_register)
diff --git a/hw/s390x/Makefile.objs b/hw/s390x/Makefile.objs
index 41ac4ec..36bd4b1 100644
--- a/hw/s390x/Makefile.objs
+++ b/hw/s390x/Makefile.objs
@@ -7,6 +7,7 @@ obj-y += sclpcpu.o
obj-y += ipl.o
obj-y += css.o
obj-y += s390-virtio-ccw.o
+obj-y += 3270-ccw.o
obj-y += virtio-ccw.o
obj-y += css-bridge.o
obj-y += ccw-device.o
diff --git a/hw/s390x/css.c b/hw/s390x/css.c
index c03bb20..15c4f4b 100644
--- a/hw/s390x/css.c
+++ b/hw/s390x/css.c
@@ -576,6 +576,9 @@ static void sch_handle_start_func(SubchDev *sch, ORB *orb)
s->dstat = SCSW_DSTAT_CHANNEL_END | SCSW_DSTAT_DEVICE_END;
s->cpa = sch->channel_prog + 8;
break;
+ case -EIO:
+ /* I/O errors, status depends on specific devices */
+ break;
case -ENOSYS:
/* unsupported command, generate unit check (command reject) */
s->ctrl &= ~SCSW_ACTL_START_PEND;
@@ -1302,6 +1305,27 @@ bool css_schid_final(int m, uint8_t cssid, uint8_t ssid, uint16_t schid)
(MAX_SCHID + 1) / sizeof(unsigned long));
}
+unsigned int css_find_free_chpid(uint8_t cssid)
+{
+ CssImage *css = channel_subsys.css[cssid];
+ unsigned int chpid;
+
+ if (!css) {
+ return MAX_CHPID + 1;
+ }
+
+ for (chpid = 0; chpid <= MAX_CHPID; chpid++) {
+ /* skip reserved chpid */
+ if (chpid == VIRTIO_CCW_CHPID) {
+ continue;
+ }
+ if (!css->chpids[chpid].in_use) {
+ return chpid;
+ }
+ }
+ return MAX_CHPID + 1;
+}
+
static int css_add_virtual_chpid(uint8_t cssid, uint8_t chpid, uint8_t type)
{
CssImage *css;
diff --git a/hw/s390x/ipl.c b/hw/s390x/ipl.c
index 7978c7d..75d3c68 100644
--- a/hw/s390x/ipl.c
+++ b/hw/s390x/ipl.c
@@ -17,8 +17,10 @@
#include "cpu.h"
#include "elf.h"
#include "hw/loader.h"
+#include "hw/boards.h"
#include "hw/s390x/virtio-ccw.h"
#include "hw/s390x/css.h"
+#include "hw/s390x/ebcdic.h"
#include "ipl.h"
#include "qemu/error-report.h"
@@ -243,12 +245,17 @@ static bool s390_gen_initial_iplb(S390IPLState *ipl)
ipl->iplb.pbt = S390_IPL_TYPE_CCW;
ipl->iplb.ccw.devno = cpu_to_be16(ccw_dev->sch->devno);
ipl->iplb.ccw.ssid = ccw_dev->sch->ssid & 3;
- return true;
} else if (sd) {
SCSIBus *bus = scsi_bus_from_device(sd);
VirtIOSCSI *vdev = container_of(bus, VirtIOSCSI, bus);
VirtIOSCSICcw *scsi_ccw = container_of(vdev, VirtIOSCSICcw, vdev);
- CcwDevice *ccw_dev = CCW_DEVICE(scsi_ccw);
+ CcwDevice *ccw_dev;
+
+ ccw_dev = (CcwDevice *)object_dynamic_cast(OBJECT(scsi_ccw),
+ TYPE_CCW_DEVICE);
+ if (!ccw_dev) { /* It might be a PCI device instead */
+ return false;
+ }
ipl->iplb.len = cpu_to_be32(S390_IPLB_MIN_QEMU_SCSI_LEN);
ipl->iplb.blk0_len =
@@ -259,13 +266,39 @@ static bool s390_gen_initial_iplb(S390IPLState *ipl)
ipl->iplb.scsi.channel = cpu_to_be16(sd->channel);
ipl->iplb.scsi.devno = cpu_to_be16(ccw_dev->sch->devno);
ipl->iplb.scsi.ssid = ccw_dev->sch->ssid & 3;
- return true;
+ } else {
+ return false; /* unknown device */
}
+
+ if (!s390_ipl_set_loadparm(ipl->iplb.loadparm)) {
+ ipl->iplb.flags |= DIAG308_FLAGS_LP_VALID;
+ }
+ return true;
}
return false;
}
+int s390_ipl_set_loadparm(uint8_t *loadparm)
+{
+ MachineState *machine = MACHINE(qdev_get_machine());
+ char *lp = object_property_get_str(OBJECT(machine), "loadparm", NULL);
+
+ if (lp) {
+ int i;
+
+ /* lp is an uppercase string without leading/embedded spaces */
+ for (i = 0; i < 8 && lp[i]; i++) {
+ loadparm[i] = ascii2ebcdic[(uint8_t) lp[i]];
+ }
+
+ g_free(lp);
+ return 0;
+ }
+
+ return -1;
+}
+
static int load_netboot_image(Error **errp)
{
S390IPLState *ipl = get_ipl_device();
diff --git a/hw/s390x/ipl.h b/hw/s390x/ipl.h
index 46930e4..8a705e0 100644
--- a/hw/s390x/ipl.h
+++ b/hw/s390x/ipl.h
@@ -57,6 +57,8 @@ struct IplBlockQemuScsi {
} QEMU_PACKED;
typedef struct IplBlockQemuScsi IplBlockQemuScsi;
+#define DIAG308_FLAGS_LP_VALID 0x80
+
union IplParameterBlock {
struct {
uint32_t len;
@@ -82,6 +84,7 @@ union IplParameterBlock {
} QEMU_PACKED;
typedef union IplParameterBlock IplParameterBlock;
+int s390_ipl_set_loadparm(uint8_t *loadparm);
void s390_ipl_update_diag308(IplParameterBlock *iplb);
void s390_ipl_prepare_cpu(S390CPU *cpu);
IplParameterBlock *s390_ipl_get_iplb(void);
diff --git a/hw/s390x/s390-virtio-ccw.c b/hw/s390x/s390-virtio-ccw.c
index 04bd0eb..fdd4384 100644
--- a/hw/s390x/s390-virtio-ccw.c
+++ b/hw/s390x/s390-virtio-ccw.c
@@ -274,6 +274,36 @@ bool cpu_model_allowed(void)
return true;
}
+static char *machine_get_loadparm(Object *obj, Error **errp)
+{
+ S390CcwMachineState *ms = S390_CCW_MACHINE(obj);
+
+ return g_memdup(ms->loadparm, sizeof(ms->loadparm));
+}
+
+static void machine_set_loadparm(Object *obj, const char *val, Error **errp)
+{
+ S390CcwMachineState *ms = S390_CCW_MACHINE(obj);
+ int i;
+
+ for (i = 0; i < sizeof(ms->loadparm) && val[i]; i++) {
+ uint8_t c = toupper(val[i]); /* mimic HMC */
+
+ if (('A' <= c && c <= 'Z') || ('0' <= c && c <= '9') || (c == '.') ||
+ (c == ' ')) {
+ ms->loadparm[i] = c;
+ } else {
+ error_setg(errp, "LOADPARM: invalid character '%c' (ASCII 0x%02x)",
+ c, c);
+ return;
+ }
+ }
+
+ for (; i < sizeof(ms->loadparm); i++) {
+ ms->loadparm[i] = ' '; /* pad right with spaces */
+ }
+}
+
static inline void s390_machine_initfn(Object *obj)
{
object_property_add_bool(obj, "aes-key-wrap",
@@ -291,6 +321,13 @@ static inline void s390_machine_initfn(Object *obj)
"enable/disable DEA key wrapping using the CPACF wrapping key",
NULL);
object_property_set_bool(obj, true, "dea-key-wrap", NULL);
+ object_property_add_str(obj, "loadparm",
+ machine_get_loadparm, machine_set_loadparm, NULL);
+ object_property_set_description(obj, "loadparm",
+ "Up to 8 chars in set of [A-Za-z0-9. ] (lower case chars converted"
+ " to upper case) to pass to machine loader, boot manager,"
+ " and guest kernel",
+ NULL);
}
static const TypeInfo ccw_machine_info = {
diff --git a/hw/s390x/sclp.c b/hw/s390x/sclp.c
index e741da1..b4f6dd5 100644
--- a/hw/s390x/sclp.c
+++ b/hw/s390x/sclp.c
@@ -23,6 +23,7 @@
#include "hw/s390x/sclp.h"
#include "hw/s390x/event-facility.h"
#include "hw/s390x/s390-pci-bus.h"
+#include "hw/s390x/ipl.h"
static inline SCLPDevice *get_sclp_device(void)
{
@@ -57,6 +58,7 @@ static void read_SCP_info(SCLPDevice *sclp, SCCB *sccb)
int cpu_count = 0;
int rnsize, rnmax;
int slots = MIN(machine->ram_slots, s390_get_memslot_count(kvm_state));
+ IplParameterBlock *ipib = s390_ipl_get_iplb();
CPU_FOREACH(cpu) {
cpu_count++;
@@ -129,6 +131,13 @@ static void read_SCP_info(SCLPDevice *sclp, SCCB *sccb)
read_info->rnmax2 = cpu_to_be64(rnmax);
}
+ if (ipib && ipib->flags & DIAG308_FLAGS_LP_VALID) {
+ memcpy(&read_info->loadparm, &ipib->loadparm,
+ sizeof(read_info->loadparm));
+ } else {
+ s390_ipl_set_loadparm(read_info->loadparm);
+ }
+
sccb->h.response_code = cpu_to_be16(SCLP_RC_NORMAL_READ_COMPLETION);
}
diff --git a/hw/usb/ccid-card-passthru.c b/hw/usb/ccid-card-passthru.c
index daab0d5..a41b0d6 100644
--- a/hw/usb/ccid-card-passthru.c
+++ b/hw/usb/ccid-card-passthru.c
@@ -267,7 +267,7 @@ static void ccid_card_vscard_drop_connection(PassthruState *card)
Chardev *chr = qemu_chr_fe_get_driver(&card->cs);
qemu_chr_fe_deinit(&card->cs);
- qemu_chr_delete(chr);
+ object_unparent(OBJECT(chr));
card->vscard_in_pos = card->vscard_in_hdr = 0;
}
diff --git a/hw/usb/redirect.c b/hw/usb/redirect.c
index 0efe62f..b001a27 100644
--- a/hw/usb/redirect.c
+++ b/hw/usb/redirect.c
@@ -1433,7 +1433,7 @@ static void usbredir_unrealize(USBDevice *udev, Error **errp)
Chardev *chr = qemu_chr_fe_get_driver(&dev->cs);
qemu_chr_fe_deinit(&dev->cs);
- qemu_chr_delete(chr);
+ object_unparent(OBJECT(chr));
/* Note must be done after qemu_chr_close, as that causes a close event */
qemu_bh_delete(dev->chardev_close_bh);
diff --git a/hw/vfio/common.c b/hw/vfio/common.c
index 6b33b9f..a8f12ee 100644
--- a/hw/vfio/common.c
+++ b/hw/vfio/common.c
@@ -119,6 +119,9 @@ void vfio_region_write(void *opaque, hwaddr addr,
case 4:
buf.dword = cpu_to_le32(data);
break;
+ case 8:
+ buf.qword = cpu_to_le64(data);
+ break;
default:
hw_error("vfio: unsupported write size, %d bytes", size);
break;
@@ -173,6 +176,9 @@ uint64_t vfio_region_read(void *opaque,
case 4:
data = le32_to_cpu(buf.dword);
break;
+ case 8:
+ data = le64_to_cpu(buf.qword);
+ break;
default:
hw_error("vfio: unsupported read size, %d bytes", size);
break;
@@ -190,6 +196,14 @@ const MemoryRegionOps vfio_region_ops = {
.read = vfio_region_read,
.write = vfio_region_write,
.endianness = DEVICE_LITTLE_ENDIAN,
+ .valid = {
+ .min_access_size = 1,
+ .max_access_size = 8,
+ },
+ .impl = {
+ .min_access_size = 1,
+ .max_access_size = 8,
+ },
};
/*
diff --git a/hw/vfio/pci.c b/hw/vfio/pci.c
index 03a3d01..32aca77 100644
--- a/hw/vfio/pci.c
+++ b/hw/vfio/pci.c
@@ -2625,8 +2625,8 @@ static void vfio_realize(PCIDevice *pdev, Error **errp)
if (!(~vdev->host.domain || ~vdev->host.bus ||
~vdev->host.slot || ~vdev->host.function)) {
error_setg(errp, "No provided host device");
- error_append_hint(errp, "Use -vfio-pci,host=DDDD:BB:DD.F "
- "or -vfio-pci,sysfsdev=PATH_TO_DEVICE\n");
+ error_append_hint(errp, "Use -device vfio-pci,host=DDDD:BB:DD.F "
+ "or -device vfio-pci,sysfsdev=PATH_TO_DEVICE\n");
return;
}
vdev->vbasedev.sysfsdev =
diff --git a/hw/xen/xen-common.c b/hw/xen/xen-common.c
index ae76150..a9055e9 100644
--- a/hw/xen/xen-common.c
+++ b/hw/xen/xen-common.c
@@ -38,7 +38,7 @@ static int store_dev_info(int domid, Chardev *cs, const char *string)
int ret = -1;
/* Only continue if we're talking to a pty. */
- if (strncmp(cs->filename, "pty:", 4)) {
+ if (!CHARDEV_IS_PTY(cs)) {
return 0;
}
pts = cs->filename + 4;
diff --git a/include/block/block.h b/include/block/block.h
index 144df0d..862eb56 100644
--- a/include/block/block.h
+++ b/include/block/block.h
@@ -294,7 +294,7 @@ BlockDriverState *bdrv_find_backing_image(BlockDriverState *bs,
const char *backing_file);
int bdrv_get_backing_file_depth(BlockDriverState *bs);
void bdrv_refresh_filename(BlockDriverState *bs);
-int bdrv_truncate(BdrvChild *child, int64_t offset);
+int bdrv_truncate(BdrvChild *child, int64_t offset, Error **errp);
int64_t bdrv_nb_sectors(BlockDriverState *bs);
int64_t bdrv_getlength(BlockDriverState *bs);
int64_t bdrv_get_allocated_file_size(BlockDriverState *bs);
diff --git a/include/block/block_int.h b/include/block/block_int.h
index 4f8cd29..8773940 100644
--- a/include/block/block_int.h
+++ b/include/block/block_int.h
@@ -196,7 +196,7 @@ struct BlockDriver {
int coroutine_fn (*bdrv_co_flush_to_os)(BlockDriverState *bs);
const char *protocol_name;
- int (*bdrv_truncate)(BlockDriverState *bs, int64_t offset);
+ int (*bdrv_truncate)(BlockDriverState *bs, int64_t offset, Error **errp);
int64_t (*bdrv_getlength)(BlockDriverState *bs);
bool has_variable_length;
@@ -252,7 +252,7 @@ struct BlockDriver {
* Returns 0 for completed check, -errno for internal errors.
* The check results are stored in result.
*/
- int (*bdrv_check)(BlockDriverState* bs, BdrvCheckResult *result,
+ int (*bdrv_check)(BlockDriverState *bs, BdrvCheckResult *result,
BdrvCheckMode fix);
int (*bdrv_amend_options)(BlockDriverState *bs, QemuOpts *opts,
@@ -454,13 +454,13 @@ struct BdrvChildRole {
/* Returns a name that is supposedly more useful for human users than the
* node name for identifying the node in question (in particular, a BB
* name), or NULL if the parent can't provide a better name. */
- const char* (*get_name)(BdrvChild *child);
+ const char *(*get_name)(BdrvChild *child);
/* Returns a malloced string that describes the parent of the child for a
* human reader. This could be a node-name, BlockBackend name, qdev ID or
* QOM path of the device owning the BlockBackend, job type and ID etc. The
* caller is responsible for freeing the memory. */
- char* (*get_parent_desc)(BdrvChild *child);
+ char *(*get_parent_desc)(BdrvChild *child);
/*
* If this pair of functions is implemented, the parent doesn't issue new
diff --git a/include/exec/ram_addr.h b/include/exec/ram_addr.h
index dbe2f08..140efa8 100644
--- a/include/exec/ram_addr.h
+++ b/include/exec/ram_addr.h
@@ -39,6 +39,14 @@ struct RAMBlock {
QLIST_HEAD(, RAMBlockNotifier) ramblock_notifiers;
int fd;
size_t page_size;
+ /* dirty bitmap used during migration */
+ unsigned long *bmap;
+ /* bitmap of pages that haven't been sent even once
+ * only maintained and used in postcopy at the moment
+ * where it's used to send the dirtymap at the start
+ * of the postcopy phase
+ */
+ unsigned long *unsentmap;
};
static inline bool offset_in_ramblock(RAMBlock *b, ram_addr_t offset)
@@ -360,16 +368,15 @@ static inline void cpu_physical_memory_clear_dirty_range(ram_addr_t start,
static inline
-uint64_t cpu_physical_memory_sync_dirty_bitmap(unsigned long *dest,
- RAMBlock *rb,
+uint64_t cpu_physical_memory_sync_dirty_bitmap(RAMBlock *rb,
ram_addr_t start,
ram_addr_t length,
uint64_t *real_dirty_pages)
{
ram_addr_t addr;
- start = rb->offset + start;
unsigned long page = BIT_WORD(start >> TARGET_PAGE_BITS);
uint64_t num_dirty = 0;
+ unsigned long *dest = rb->bmap;
/* start address is aligned at the start of a word? */
if (((page * BITS_PER_LONG) << TARGET_PAGE_BITS) == start) {
diff --git a/include/hw/s390x/3270-ccw.h b/include/hw/s390x/3270-ccw.h
new file mode 100644
index 0000000..46bee25
--- /dev/null
+++ b/include/hw/s390x/3270-ccw.h
@@ -0,0 +1,53 @@
+/*
+ * Emulated ccw-attached 3270 definitions
+ *
+ * Copyright 2017 IBM Corp.
+ * Author(s): Yang Chen <bjcyang@linux.vnet.ibm.com>
+ * Jing Liu <liujbjl@linux.vnet.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or (at
+ * your option) any later version. See the COPYING file in the top-level
+ * directory.
+ */
+
+#ifndef HW_S390X_3270_CCW_H
+#define HW_S390X_3270_CCW_H
+
+#include "hw/sysbus.h"
+#include "hw/s390x/css.h"
+#include "hw/s390x/ccw-device.h"
+
+#define EMULATED_CCW_3270_CU_TYPE 0x3270
+#define EMULATED_CCW_3270_CHPID_TYPE 0x1a
+
+#define TYPE_EMULATED_CCW_3270 "emulated-ccw-3270"
+
+/* Local Channel Commands */
+#define TC_WRITE 0x01 /* Write */
+#define TC_RDBUF 0x02 /* Read buffer */
+#define TC_EWRITE 0x05 /* Erase write */
+#define TC_READMOD 0x06 /* Read modified */
+#define TC_EWRITEA 0x0d /* Erase write alternate */
+#define TC_WRITESF 0x11 /* Write structured field */
+
+#define EMULATED_CCW_3270(obj) \
+ OBJECT_CHECK(EmulatedCcw3270Device, (obj), TYPE_EMULATED_CCW_3270)
+#define EMULATED_CCW_3270_CLASS(klass) \
+ OBJECT_CLASS_CHECK(EmulatedCcw3270Class, (klass), TYPE_EMULATED_CCW_3270)
+#define EMULATED_CCW_3270_GET_CLASS(obj) \
+ OBJECT_GET_CLASS(EmulatedCcw3270Class, (obj), TYPE_EMULATED_CCW_3270)
+
+typedef struct EmulatedCcw3270Device {
+ CcwDevice parent_obj;
+} EmulatedCcw3270Device;
+
+typedef struct EmulatedCcw3270Class {
+ CCWDeviceClass parent_class;
+
+ void (*init)(EmulatedCcw3270Device *, Error **);
+ int (*read_payload_3270)(EmulatedCcw3270Device *, uint32_t, uint16_t);
+ int (*write_payload_3270)(EmulatedCcw3270Device *, uint8_t, uint32_t,
+ uint16_t);
+} EmulatedCcw3270Class;
+
+#endif
diff --git a/include/hw/s390x/css.h b/include/hw/s390x/css.h
index f1f0d7f..e61fa74 100644
--- a/include/hw/s390x/css.h
+++ b/include/hw/s390x/css.h
@@ -28,6 +28,7 @@
#define MAX_CIWS 62
#define VIRTUAL_CSSID 0xfe
+#define VIRTIO_CCW_CHPID 0 /* used by convention */
typedef struct CIW {
uint8_t type;
@@ -115,6 +116,7 @@ bool css_devno_used(uint8_t cssid, uint8_t ssid, uint16_t devno);
void css_subch_assign(uint8_t cssid, uint8_t ssid, uint16_t schid,
uint16_t devno, SubchDev *sch);
void css_sch_build_virtual_schib(SubchDev *sch, uint8_t chpid, uint8_t type);
+unsigned int css_find_free_chpid(uint8_t cssid);
uint16_t css_build_subchannel_id(SubchDev *sch);
void css_reset(void);
void css_reset_sch(SubchDev *sch);
diff --git a/include/hw/s390x/s390-virtio-ccw.h b/include/hw/s390x/s390-virtio-ccw.h
index 6ecae00..7b8a3e4 100644
--- a/include/hw/s390x/s390-virtio-ccw.h
+++ b/include/hw/s390x/s390-virtio-ccw.h
@@ -28,6 +28,7 @@ typedef struct S390CcwMachineState {
/*< public >*/
bool aes_key_wrap;
bool dea_key_wrap;
+ uint8_t loadparm[8];
} S390CcwMachineState;
typedef struct S390CcwMachineClass {
diff --git a/include/migration/cpu.h b/include/migration/cpu.h
index f3d5dfc..a40bd35 100644
--- a/include/migration/cpu.h
+++ b/include/migration/cpu.h
@@ -18,6 +18,8 @@
VMSTATE_UINT64_EQUAL_V(_f, _s, _v)
#define VMSTATE_UINTTL_ARRAY_V(_f, _s, _n, _v) \
VMSTATE_UINT64_ARRAY_V(_f, _s, _n, _v)
+#define VMSTATE_UINTTL_2DARRAY_V(_f, _s, _n1, _n2, _v) \
+ VMSTATE_UINT64_2DARRAY_V(_f, _s, _n1, _n2, _v)
#define VMSTATE_UINTTL_TEST(_f, _s, _t) \
VMSTATE_UINT64_TEST(_f, _s, _t)
#define vmstate_info_uinttl vmstate_info_uint64
@@ -37,6 +39,8 @@
VMSTATE_UINT32_EQUAL_V(_f, _s, _v)
#define VMSTATE_UINTTL_ARRAY_V(_f, _s, _n, _v) \
VMSTATE_UINT32_ARRAY_V(_f, _s, _n, _v)
+#define VMSTATE_UINTTL_2DARRAY_V(_f, _s, _n1, _n2, _v) \
+ VMSTATE_UINT32_2DARRAY_V(_f, _s, _n1, _n2, _v)
#define VMSTATE_UINTTL_TEST(_f, _s, _t) \
VMSTATE_UINT32_TEST(_f, _s, _t)
#define vmstate_info_uinttl vmstate_info_uint32
@@ -48,5 +52,8 @@
VMSTATE_UINTTL_EQUAL_V(_f, _s, 0)
#define VMSTATE_UINTTL_ARRAY(_f, _s, _n) \
VMSTATE_UINTTL_ARRAY_V(_f, _s, _n, 0)
+#define VMSTATE_UINTTL_2DARRAY(_f, _s, _n1, _n2) \
+ VMSTATE_UINTTL_2DARRAY_V(_f, _s, _n1, _n2, 0)
+
#endif
diff --git a/include/migration/migration.h b/include/migration/migration.h
index ba1a16c..e29cb01 100644
--- a/include/migration/migration.h
+++ b/include/migration/migration.h
@@ -266,7 +266,8 @@ uint64_t xbzrle_mig_pages_cache_miss(void);
double xbzrle_mig_cache_miss_rate(void);
void ram_handle_compressed(void *host, uint8_t ch, uint64_t size);
-void ram_debug_dump_bitmap(unsigned long *todump, bool expected);
+void ram_debug_dump_bitmap(unsigned long *todump, bool expected,
+ unsigned long pages);
/* For outgoing discard bitmap */
int ram_postcopy_send_discard_bitmap(MigrationState *ms);
/* For incoming postcopy discard */
diff --git a/include/migration/vmstate.h b/include/migration/vmstate.h
index dad3984..f4bf3f1 100644
--- a/include/migration/vmstate.h
+++ b/include/migration/vmstate.h
@@ -500,6 +500,19 @@ extern const VMStateInfo vmstate_info_qtailq;
.offset = vmstate_offset_array(_state, _field, _type, _num),\
}
+#define VMSTATE_STRUCT_2DARRAY_TEST(_field, _state, _n1, _n2, _test, \
+ _version, _vmsd, _type) { \
+ .name = (stringify(_field)), \
+ .num = (_n1) * (_n2), \
+ .field_exists = (_test), \
+ .version_id = (_version), \
+ .vmsd = &(_vmsd), \
+ .size = sizeof(_type), \
+ .flags = VMS_STRUCT | VMS_ARRAY, \
+ .offset = vmstate_offset_2darray(_state, _field, _type, \
+ _n1, _n2), \
+}
+
#define VMSTATE_STRUCT_VARRAY_UINT8(_field, _state, _field_num, _version, _vmsd, _type) { \
.name = (stringify(_field)), \
.num_offset = vmstate_offset_value(_state, _field_num, uint8_t), \
@@ -747,6 +760,11 @@ extern const VMStateInfo vmstate_info_qtailq;
VMSTATE_STRUCT_ARRAY_TEST(_field, _state, _num, NULL, _version, \
_vmsd, _type)
+#define VMSTATE_STRUCT_2DARRAY(_field, _state, _n1, _n2, _version, \
+ _vmsd, _type) \
+ VMSTATE_STRUCT_2DARRAY_TEST(_field, _state, _n1, _n2, NULL, \
+ _version, _vmsd, _type)
+
#define VMSTATE_BUFFER_UNSAFE_INFO(_field, _state, _version, _info, _size) \
VMSTATE_BUFFER_UNSAFE_INFO_TEST(_field, _state, NULL, _version, _info, \
_size)
diff --git a/include/sysemu/block-backend.h b/include/sysemu/block-backend.h
index 7462228..840ad61 100644
--- a/include/sysemu/block-backend.h
+++ b/include/sysemu/block-backend.h
@@ -99,7 +99,7 @@ int blk_get_refcnt(BlockBackend *blk);
void blk_ref(BlockBackend *blk);
void blk_unref(BlockBackend *blk);
void blk_remove_all_bs(void);
-const char *blk_name(BlockBackend *blk);
+const char *blk_name(const BlockBackend *blk);
BlockBackend *blk_by_name(const char *name);
BlockBackend *blk_next(BlockBackend *blk);
bool monitor_add_blk(BlockBackend *blk, const char *name, Error **errp);
@@ -225,7 +225,7 @@ int coroutine_fn blk_co_pwrite_zeroes(BlockBackend *blk, int64_t offset,
int count, BdrvRequestFlags flags);
int blk_pwrite_compressed(BlockBackend *blk, int64_t offset, const void *buf,
int count);
-int blk_truncate(BlockBackend *blk, int64_t offset);
+int blk_truncate(BlockBackend *blk, int64_t offset, Error **errp);
int blk_pdiscard(BlockBackend *blk, int64_t offset, int count);
int blk_save_vmstate(BlockBackend *blk, const uint8_t *buf,
int64_t pos, int size);
diff --git a/include/sysemu/char.h b/include/sysemu/char.h
index 450881d..ea9f2cb 100644
--- a/include/sysemu/char.h
+++ b/include/sysemu/char.h
@@ -7,6 +7,14 @@
#include "qemu/bitmap.h"
#include "qom/object.h"
+#define IAC_EOR 239
+#define IAC_SE 240
+#define IAC_NOP 241
+#define IAC_BREAK 243
+#define IAC_IP 244
+#define IAC_SB 250
+#define IAC 255
+
/* character device */
typedef enum {
@@ -95,7 +103,6 @@ struct Chardev {
int be_open;
guint fd_in_tag;
DECLARE_BITMAP(features, QEMU_CHAR_FEATURE_LAST);
- QTAILQ_ENTRY(Chardev) next;
};
/**
@@ -171,14 +178,6 @@ int qemu_chr_fe_wait_connected(CharBackend *be, Error **errp);
Chardev *qemu_chr_new_noreplay(const char *label, const char *filename);
/**
- * @qemu_chr_delete:
- *
- * Destroy a character backend and remove it from the list of
- * identified character backends.
- */
-void qemu_chr_delete(Chardev *chr);
-
-/**
* @qemu_chr_fe_set_echo:
*
* Ask the backend to override its normal echo setting. This only really
@@ -427,7 +426,6 @@ void qemu_chr_fe_set_handlers(CharBackend *b,
*/
void qemu_chr_fe_take_focus(CharBackend *b);
-void qemu_chr_be_generic_open(Chardev *s);
void qemu_chr_fe_accept_input(CharBackend *be);
int qemu_chr_add_client(Chardev *s, int fd);
Chardev *qemu_chr_find(const char *name);
diff --git a/include/sysemu/sysemu.h b/include/sysemu/sysemu.h
index 16175f7..15656b7 100644
--- a/include/sysemu/sysemu.h
+++ b/include/sysemu/sysemu.h
@@ -75,11 +75,8 @@ void qemu_remove_exit_notifier(Notifier *notify);
void qemu_add_machine_init_done_notifier(Notifier *notify);
void qemu_remove_machine_init_done_notifier(Notifier *notify);
-void hmp_savevm(Monitor *mon, const QDict *qdict);
-int save_vmstate(Monitor *mon, const char *name);
+int save_vmstate(const char *name);
int load_vmstate(const char *name);
-void hmp_delvm(Monitor *mon, const QDict *qdict);
-void hmp_info_snapshots(Monitor *mon, const QDict *qdict);
void qemu_announce_self(void);
diff --git a/linux-user/elfload.c b/linux-user/elfload.c
index f520d77..ce77317 100644
--- a/linux-user/elfload.c
+++ b/linux-user/elfload.c
@@ -1052,7 +1052,7 @@ static void elf_core_copy_regs(target_elf_gregset_t *regs,
int i;
for (i = 0; i < 32; i++) {
- (*regs)[i] = tswapreg(env->gpr[i]);
+ (*regs)[i] = tswapreg(cpu_get_gpr(env, i));
}
(*regs)[32] = tswapreg(env->pc);
(*regs)[33] = tswapreg(cpu_get_sr(env));
diff --git a/linux-user/main.c b/linux-user/main.c
index 10a3bb3..79d621b 100644
--- a/linux-user/main.c
+++ b/linux-user/main.c
@@ -2590,17 +2590,17 @@ void cpu_loop(CPUOpenRISCState *env)
case EXCP_SYSCALL:
env->pc += 4; /* 0xc00; */
ret = do_syscall(env,
- env->gpr[11], /* return value */
- env->gpr[3], /* r3 - r7 are params */
- env->gpr[4],
- env->gpr[5],
- env->gpr[6],
- env->gpr[7],
- env->gpr[8], 0, 0);
+ cpu_get_gpr(env, 11), /* return value */
+ cpu_get_gpr(env, 3), /* r3 - r7 are params */
+ cpu_get_gpr(env, 4),
+ cpu_get_gpr(env, 5),
+ cpu_get_gpr(env, 6),
+ cpu_get_gpr(env, 7),
+ cpu_get_gpr(env, 8), 0, 0);
if (ret == -TARGET_ERESTARTSYS) {
env->pc -= 4;
} else if (ret != -TARGET_QEMU_ESIGRETURN) {
- env->gpr[11] = ret;
+ cpu_set_gpr(env, 11, ret);
}
break;
case EXCP_DPF:
@@ -4765,7 +4765,7 @@ int main(int argc, char **argv, char **envp)
int i;
for (i = 0; i < 32; i++) {
- env->gpr[i] = regs->gpr[i];
+ cpu_set_gpr(env, i, regs->gpr[i]);
}
env->pc = regs->pc;
cpu_set_sr(env, regs->sr);
diff --git a/linux-user/openrisc/target_cpu.h b/linux-user/openrisc/target_cpu.h
index f283d96..606ad6f 100644
--- a/linux-user/openrisc/target_cpu.h
+++ b/linux-user/openrisc/target_cpu.h
@@ -23,14 +23,14 @@
static inline void cpu_clone_regs(CPUOpenRISCState *env, target_ulong newsp)
{
if (newsp) {
- env->gpr[1] = newsp;
+ cpu_set_gpr(env, 1, newsp);
}
- env->gpr[11] = 0;
+ cpu_set_gpr(env, 11, 0);
}
static inline void cpu_set_tls(CPUOpenRISCState *env, target_ulong newtls)
{
- env->gpr[10] = newtls;
+ cpu_set_gpr(env, 10, newtls);
}
#endif
diff --git a/linux-user/openrisc/target_signal.h b/linux-user/openrisc/target_signal.h
index 9f2c493..95a733e 100644
--- a/linux-user/openrisc/target_signal.h
+++ b/linux-user/openrisc/target_signal.h
@@ -20,7 +20,7 @@ typedef struct target_sigaltstack {
static inline abi_ulong get_sp_from_cpustate(CPUOpenRISCState *state)
{
- return state->gpr[1];
+ return cpu_get_gpr(state, 1);
}
diff --git a/linux-user/signal.c b/linux-user/signal.c
index a67db04..3d18d1b 100644
--- a/linux-user/signal.c
+++ b/linux-user/signal.c
@@ -4411,7 +4411,7 @@ static void setup_sigcontext(struct target_sigcontext *sc,
CPUOpenRISCState *regs,
unsigned long mask)
{
- unsigned long usp = regs->gpr[1];
+ unsigned long usp = cpu_get_gpr(regs, 1);
/* copy the regs. they are first in sc so we can use sc directly */
@@ -4436,7 +4436,7 @@ static inline abi_ulong get_sigframe(struct target_sigaction *ka,
CPUOpenRISCState *regs,
size_t frame_size)
{
- unsigned long sp = regs->gpr[1];
+ unsigned long sp = cpu_get_gpr(regs, 1);
int onsigstack = on_sig_stack(sp);
/* redzone */
@@ -4489,7 +4489,8 @@ static void setup_rt_frame(int sig, struct target_sigaction *ka,
__put_user(0, &frame->uc.tuc_link);
__put_user(target_sigaltstack_used.ss_sp,
&frame->uc.tuc_stack.ss_sp);
- __put_user(sas_ss_flags(env->gpr[1]), &frame->uc.tuc_stack.ss_flags);
+ __put_user(sas_ss_flags(cpu_get_gpr(env, 1)),
+ &frame->uc.tuc_stack.ss_flags);
__put_user(target_sigaltstack_used.ss_size,
&frame->uc.tuc_stack.ss_size);
setup_sigcontext(&frame->sc, env, set->sig[0]);
@@ -4512,13 +4513,13 @@ static void setup_rt_frame(int sig, struct target_sigaction *ka,
/* Set up registers for signal handler */
env->pc = (unsigned long)ka->_sa_handler; /* what we enter NOW */
- env->gpr[9] = (unsigned long)return_ip; /* what we enter LATER */
- env->gpr[3] = (unsigned long)sig; /* arg 1: signo */
- env->gpr[4] = (unsigned long)&frame->info; /* arg 2: (siginfo_t*) */
- env->gpr[5] = (unsigned long)&frame->uc; /* arg 3: ucontext */
+ cpu_set_gpr(env, 9, (unsigned long)return_ip); /* what we enter LATER */
+ cpu_set_gpr(env, 3, (unsigned long)sig); /* arg 1: signo */
+ cpu_set_gpr(env, 4, (unsigned long)&frame->info); /* arg 2: (siginfo_t*) */
+ cpu_set_gpr(env, 5, (unsigned long)&frame->uc); /* arg 3: ucontext */
/* actually move the usp to reflect the stacked frame */
- env->gpr[1] = (unsigned long)frame;
+ cpu_set_gpr(env, 1, (unsigned long)frame);
return;
diff --git a/migration/exec.c b/migration/exec.c
index 9157721..aba9089 100644
--- a/migration/exec.c
+++ b/migration/exec.c
@@ -32,7 +32,7 @@ void exec_start_outgoing_migration(MigrationState *s, const char *command, Error
trace_migration_exec_outgoing(command);
ioc = QIO_CHANNEL(qio_channel_command_new_spawn(argv,
- O_WRONLY,
+ O_RDWR,
errp));
if (!ioc) {
return;
@@ -59,7 +59,7 @@ void exec_start_incoming_migration(const char *command, Error **errp)
trace_migration_exec_incoming(command);
ioc = QIO_CHANNEL(qio_channel_command_new_spawn(argv,
- O_RDONLY,
+ O_RDWR,
errp));
if (!ioc) {
return;
diff --git a/migration/migration.c b/migration/migration.c
index 353f272..799952c 100644
--- a/migration/migration.c
+++ b/migration/migration.c
@@ -26,7 +26,7 @@
#include "qemu/sockets.h"
#include "qemu/rcu.h"
#include "migration/block.h"
-#include "migration/postcopy-ram.h"
+#include "postcopy-ram.h"
#include "qemu/thread.h"
#include "qmp-commands.h"
#include "trace.h"
diff --git a/migration/postcopy-ram.c b/migration/postcopy-ram.c
index 85fd8d7..cdadaf6 100644
--- a/migration/postcopy-ram.c
+++ b/migration/postcopy-ram.c
@@ -20,7 +20,7 @@
#include "qemu-common.h"
#include "migration/migration.h"
-#include "migration/postcopy-ram.h"
+#include "postcopy-ram.h"
#include "sysemu/sysemu.h"
#include "sysemu/balloon.h"
#include "qemu/error-report.h"
@@ -33,7 +33,6 @@
struct PostcopyDiscardState {
const char *ramblock_name;
- uint64_t offset; /* Bitmap entry for the 1st bit of this RAMBlock */
uint16_t cur_entry;
/*
* Start and length of a discard range (bytes)
@@ -717,14 +716,12 @@ void *postcopy_get_tmp_page(MigrationIncomingState *mis)
* returns: a new PDS.
*/
PostcopyDiscardState *postcopy_discard_send_init(MigrationState *ms,
- unsigned long offset,
const char *name)
{
PostcopyDiscardState *res = g_malloc0(sizeof(PostcopyDiscardState));
if (res) {
res->ramblock_name = name;
- res->offset = offset;
}
return res;
@@ -745,7 +742,7 @@ void postcopy_discard_send_range(MigrationState *ms, PostcopyDiscardState *pds,
{
size_t tp_size = qemu_target_page_size();
/* Convert to byte offsets within the RAM block */
- pds->start_list[pds->cur_entry] = (start - pds->offset) * tp_size;
+ pds->start_list[pds->cur_entry] = start * tp_size;
pds->length_list[pds->cur_entry] = length * tp_size;
trace_postcopy_discard_send_range(pds->ramblock_name, start, length);
pds->cur_entry++;
diff --git a/include/migration/postcopy-ram.h b/migration/postcopy-ram.h
index 8e036b9..4c25f03 100644
--- a/include/migration/postcopy-ram.h
+++ b/migration/postcopy-ram.h
@@ -43,12 +43,9 @@ int postcopy_ram_prepare_discard(MigrationIncomingState *mis);
/*
* Called at the start of each RAMBlock by the bitmap code.
- * 'offset' is the bitmap offset of the named RAMBlock in the migration
- * bitmap.
* Returns a new PDS
*/
PostcopyDiscardState *postcopy_discard_send_init(MigrationState *ms,
- unsigned long offset,
const char *name);
/*
diff --git a/migration/ram.c b/migration/ram.c
index f48664e..293d27c 100644
--- a/migration/ram.c
+++ b/migration/ram.c
@@ -36,7 +36,7 @@
#include "qemu/timer.h"
#include "qemu/main-loop.h"
#include "migration/migration.h"
-#include "migration/postcopy-ram.h"
+#include "postcopy-ram.h"
#include "exec/address-spaces.h"
#include "migration/page_cache.h"
#include "qemu/error-report.h"
@@ -138,19 +138,6 @@ out:
return ret;
}
-struct RAMBitmap {
- struct rcu_head rcu;
- /* Main migration bitmap */
- unsigned long *bmap;
- /* bitmap of pages that haven't been sent even once
- * only maintained and used in postcopy at the moment
- * where it's used to send the dirtymap at the start
- * of the postcopy phase
- */
- unsigned long *unsentmap;
-};
-typedef struct RAMBitmap RAMBitmap;
-
/*
* An outstanding page request, on the source, having been received
* and queued
@@ -220,8 +207,6 @@ struct RAMState {
uint64_t postcopy_requests;
/* protects modification of the bitmap */
QemuMutex bitmap_mutex;
- /* Ram Bitmap protected by RCU */
- RAMBitmap *ram_bitmap;
/* The RAMBlock used in the last src_page_requests */
RAMBlock *last_req_rb;
/* Queue of outstanding page requests from the destination */
@@ -614,22 +599,17 @@ static inline
unsigned long migration_bitmap_find_dirty(RAMState *rs, RAMBlock *rb,
unsigned long start)
{
- unsigned long base = rb->offset >> TARGET_PAGE_BITS;
- unsigned long nr = base + start;
- uint64_t rb_size = rb->used_length;
- unsigned long size = base + (rb_size >> TARGET_PAGE_BITS);
- unsigned long *bitmap;
-
+ unsigned long size = rb->used_length >> TARGET_PAGE_BITS;
+ unsigned long *bitmap = rb->bmap;
unsigned long next;
- bitmap = atomic_rcu_read(&rs->ram_bitmap)->bmap;
- if (rs->ram_bulk_stage && nr > base) {
- next = nr + 1;
+ if (rs->ram_bulk_stage && start > 0) {
+ next = start + 1;
} else {
- next = find_next_bit(bitmap, size, nr);
+ next = find_next_bit(bitmap, size, start);
}
- return next - base;
+ return next;
}
static inline bool migration_bitmap_clear_dirty(RAMState *rs,
@@ -637,10 +617,8 @@ static inline bool migration_bitmap_clear_dirty(RAMState *rs,
unsigned long page)
{
bool ret;
- unsigned long *bitmap = atomic_rcu_read(&rs->ram_bitmap)->bmap;
- unsigned long nr = (rb->offset >> TARGET_PAGE_BITS) + page;
- ret = test_and_clear_bit(nr, bitmap);
+ ret = test_and_clear_bit(page, rb->bmap);
if (ret) {
rs->migration_dirty_pages--;
@@ -651,10 +629,8 @@ static inline bool migration_bitmap_clear_dirty(RAMState *rs,
static void migration_bitmap_sync_range(RAMState *rs, RAMBlock *rb,
ram_addr_t start, ram_addr_t length)
{
- unsigned long *bitmap;
- bitmap = atomic_rcu_read(&rs->ram_bitmap)->bmap;
rs->migration_dirty_pages +=
- cpu_physical_memory_sync_dirty_bitmap(bitmap, rb, start, length,
+ cpu_physical_memory_sync_dirty_bitmap(rb, start, length,
&rs->num_dirty_pages_period);
}
@@ -812,6 +788,7 @@ static int ram_save_page(RAMState *rs, PageSearchStatus *pss, bool last_stage)
ram_addr_t offset = pss->page << TARGET_PAGE_BITS;
p = block->host + offset;
+ trace_ram_save_page(block->idstr, (uint64_t)offset, p);
/* In doubt sent page as normal */
bytes_xmit = 0;
@@ -1153,17 +1130,13 @@ static bool get_queued_page(RAMState *rs, PageSearchStatus *pss)
* search already sent it.
*/
if (block) {
- unsigned long *bitmap;
unsigned long page;
- bitmap = atomic_rcu_read(&rs->ram_bitmap)->bmap;
- page = (block->offset + offset) >> TARGET_PAGE_BITS;
- dirty = test_bit(page, bitmap);
+ page = offset >> TARGET_PAGE_BITS;
+ dirty = test_bit(page, block->bmap);
if (!dirty) {
trace_get_queued_page_not_dirty(block->idstr, (uint64_t)offset,
- page,
- test_bit(page,
- atomic_rcu_read(&rs->ram_bitmap)->unsentmap));
+ page, test_bit(page, block->unsentmap));
} else {
trace_get_queued_page(block->idstr, (uint64_t)offset, page);
}
@@ -1301,16 +1274,13 @@ static int ram_save_target_page(RAMState *rs, PageSearchStatus *pss,
/* Check the pages is dirty and if it is send it */
if (migration_bitmap_clear_dirty(rs, pss->block, pss->page)) {
- unsigned long *unsentmap;
/*
* If xbzrle is on, stop using the data compression after first
* round of migration even if compression is enabled. In theory,
* xbzrle can do better than compression.
*/
- unsigned long page =
- (pss->block->offset >> TARGET_PAGE_BITS) + pss->page;
- if (migrate_use_compression()
- && (rs->ram_bulk_stage || !migrate_use_xbzrle())) {
+ if (migrate_use_compression() &&
+ (rs->ram_bulk_stage || !migrate_use_xbzrle())) {
res = ram_save_compressed_page(rs, pss, last_stage);
} else {
res = ram_save_page(rs, pss, last_stage);
@@ -1319,9 +1289,8 @@ static int ram_save_target_page(RAMState *rs, PageSearchStatus *pss,
if (res < 0) {
return res;
}
- unsentmap = atomic_rcu_read(&rs->ram_bitmap)->unsentmap;
- if (unsentmap) {
- clear_bit(page, unsentmap);
+ if (pss->block->unsentmap) {
+ clear_bit(pss->page, pss->block->unsentmap);
}
}
@@ -1451,25 +1420,20 @@ void free_xbzrle_decoded_buf(void)
xbzrle_decoded_buf = NULL;
}
-static void migration_bitmap_free(RAMBitmap *bmap)
-{
- g_free(bmap->bmap);
- g_free(bmap->unsentmap);
- g_free(bmap);
-}
-
static void ram_migration_cleanup(void *opaque)
{
- RAMState *rs = opaque;
+ RAMBlock *block;
/* caller have hold iothread lock or is in a bh, so there is
* no writing race against this migration_bitmap
*/
- RAMBitmap *bitmap = rs->ram_bitmap;
- atomic_rcu_set(&rs->ram_bitmap, NULL);
- if (bitmap) {
- memory_global_dirty_log_stop();
- call_rcu(bitmap, migration_bitmap_free, rcu);
+ memory_global_dirty_log_stop();
+
+ QLIST_FOREACH_RCU(block, &ram_list.blocks, next) {
+ g_free(block->bmap);
+ block->bmap = NULL;
+ g_free(block->unsentmap);
+ block->unsentmap = NULL;
}
XBZRLE_cache_lock();
@@ -1501,27 +1465,22 @@ static void ram_state_reset(RAMState *rs)
* of; it won't bother printing lines that are all this value.
* If 'todump' is null the migration bitmap is dumped.
*/
-void ram_debug_dump_bitmap(unsigned long *todump, bool expected)
+void ram_debug_dump_bitmap(unsigned long *todump, bool expected,
+ unsigned long pages)
{
- unsigned long ram_pages = last_ram_page();
- RAMState *rs = &ram_state;
int64_t cur;
int64_t linelen = 128;
char linebuf[129];
- if (!todump) {
- todump = atomic_rcu_read(&rs->ram_bitmap)->bmap;
- }
-
- for (cur = 0; cur < ram_pages; cur += linelen) {
+ for (cur = 0; cur < pages; cur += linelen) {
int64_t curb;
bool found = false;
/*
* Last line; catch the case where the line length
* is longer than remaining ram
*/
- if (cur + linelen > ram_pages) {
- linelen = ram_pages - cur;
+ if (cur + linelen > pages) {
+ linelen = pages - cur;
}
for (curb = 0; curb < linelen; curb++) {
bool thisbit = test_bit(cur + curb, todump);
@@ -1539,14 +1498,12 @@ void ram_debug_dump_bitmap(unsigned long *todump, bool expected)
void ram_postcopy_migrated_memory_release(MigrationState *ms)
{
- RAMState *rs = &ram_state;
struct RAMBlock *block;
- unsigned long *bitmap = atomic_rcu_read(&rs->ram_bitmap)->bmap;
QLIST_FOREACH_RCU(block, &ram_list.blocks, next) {
- unsigned long first = block->offset >> TARGET_PAGE_BITS;
- unsigned long range = first + (block->used_length >> TARGET_PAGE_BITS);
- unsigned long run_start = find_next_zero_bit(bitmap, range, first);
+ unsigned long *bitmap = block->bmap;
+ unsigned long range = block->used_length >> TARGET_PAGE_BITS;
+ unsigned long run_start = find_next_zero_bit(bitmap, range, 0);
while (run_start < range) {
unsigned long run_end = find_next_bit(bitmap, range, run_start + 1);
@@ -1573,16 +1530,13 @@ void ram_postcopy_migrated_memory_release(MigrationState *ms)
*/
static int postcopy_send_discard_bm_ram(MigrationState *ms,
PostcopyDiscardState *pds,
- unsigned long start,
- unsigned long length)
+ RAMBlock *block)
{
- RAMState *rs = &ram_state;
- unsigned long end = start + length; /* one after the end */
+ unsigned long end = block->used_length >> TARGET_PAGE_BITS;
unsigned long current;
- unsigned long *unsentmap;
+ unsigned long *unsentmap = block->unsentmap;
- unsentmap = atomic_rcu_read(&rs->ram_bitmap)->unsentmap;
- for (current = start; current < end; ) {
+ for (current = 0; current < end; ) {
unsigned long one = find_next_bit(unsentmap, end, current);
if (one <= end) {
@@ -1625,18 +1579,15 @@ static int postcopy_each_ram_send_discard(MigrationState *ms)
int ret;
QLIST_FOREACH_RCU(block, &ram_list.blocks, next) {
- unsigned long first = block->offset >> TARGET_PAGE_BITS;
- PostcopyDiscardState *pds = postcopy_discard_send_init(ms,
- first,
- block->idstr);
+ PostcopyDiscardState *pds =
+ postcopy_discard_send_init(ms, block->idstr);
/*
* Postcopy sends chunks of bitmap over the wire, but it
* just needs indexes at this point, avoids it having
* target page specific code.
*/
- ret = postcopy_send_discard_bm_ram(ms, pds, first,
- block->used_length >> TARGET_PAGE_BITS);
+ ret = postcopy_send_discard_bm_ram(ms, pds, block);
postcopy_discard_send_finish(ms, pds);
if (ret) {
return ret;
@@ -1667,12 +1618,10 @@ static void postcopy_chunk_hostpages_pass(MigrationState *ms, bool unsent_pass,
PostcopyDiscardState *pds)
{
RAMState *rs = &ram_state;
- unsigned long *bitmap;
- unsigned long *unsentmap;
+ unsigned long *bitmap = block->bmap;
+ unsigned long *unsentmap = block->unsentmap;
unsigned int host_ratio = block->page_size / TARGET_PAGE_SIZE;
- unsigned long first = block->offset >> TARGET_PAGE_BITS;
- unsigned long len = block->used_length >> TARGET_PAGE_BITS;
- unsigned long last = first + (len - 1);
+ unsigned long pages = block->used_length >> TARGET_PAGE_BITS;
unsigned long run_start;
if (block->page_size == TARGET_PAGE_SIZE) {
@@ -1680,18 +1629,15 @@ static void postcopy_chunk_hostpages_pass(MigrationState *ms, bool unsent_pass,
return;
}
- bitmap = atomic_rcu_read(&rs->ram_bitmap)->bmap;
- unsentmap = atomic_rcu_read(&rs->ram_bitmap)->unsentmap;
-
if (unsent_pass) {
/* Find a sent page */
- run_start = find_next_zero_bit(unsentmap, last + 1, first);
+ run_start = find_next_zero_bit(unsentmap, pages, 0);
} else {
/* Find a dirty page */
- run_start = find_next_bit(bitmap, last + 1, first);
+ run_start = find_next_bit(bitmap, pages, 0);
}
- while (run_start <= last) {
+ while (run_start < pages) {
bool do_fixup = false;
unsigned long fixup_start_addr;
unsigned long host_offset;
@@ -1711,9 +1657,9 @@ static void postcopy_chunk_hostpages_pass(MigrationState *ms, bool unsent_pass,
/* Find the end of this run */
unsigned long run_end;
if (unsent_pass) {
- run_end = find_next_bit(unsentmap, last + 1, run_start + 1);
+ run_end = find_next_bit(unsentmap, pages, run_start + 1);
} else {
- run_end = find_next_zero_bit(bitmap, last + 1, run_start + 1);
+ run_end = find_next_zero_bit(bitmap, pages, run_start + 1);
}
/*
* If the end isn't at the start of a host page, then the
@@ -1770,11 +1716,10 @@ static void postcopy_chunk_hostpages_pass(MigrationState *ms, bool unsent_pass,
if (unsent_pass) {
/* Find the next sent page for the next iteration */
- run_start = find_next_zero_bit(unsentmap, last + 1,
- run_start);
+ run_start = find_next_zero_bit(unsentmap, pages, run_start);
} else {
/* Find the next dirty page for the next iteration */
- run_start = find_next_bit(bitmap, last + 1, run_start);
+ run_start = find_next_bit(bitmap, pages, run_start);
}
}
}
@@ -1791,34 +1736,22 @@ static void postcopy_chunk_hostpages_pass(MigrationState *ms, bool unsent_pass,
* Returns zero on success
*
* @ms: current migration state
+ * @block: block we want to work with
*/
-static int postcopy_chunk_hostpages(MigrationState *ms)
+static int postcopy_chunk_hostpages(MigrationState *ms, RAMBlock *block)
{
- RAMState *rs = &ram_state;
- struct RAMBlock *block;
-
- /* Easiest way to make sure we don't resume in the middle of a host-page */
- rs->last_seen_block = NULL;
- rs->last_sent_block = NULL;
- rs->last_page = 0;
-
- QLIST_FOREACH_RCU(block, &ram_list.blocks, next) {
- unsigned long first = block->offset >> TARGET_PAGE_BITS;
-
- PostcopyDiscardState *pds =
- postcopy_discard_send_init(ms, first, block->idstr);
-
- /* First pass: Discard all partially sent host pages */
- postcopy_chunk_hostpages_pass(ms, true, block, pds);
- /*
- * Second pass: Ensure that all partially dirty host pages are made
- * fully dirty.
- */
- postcopy_chunk_hostpages_pass(ms, false, block, pds);
+ PostcopyDiscardState *pds =
+ postcopy_discard_send_init(ms, block->idstr);
- postcopy_discard_send_finish(ms, pds);
- } /* ram_list loop */
+ /* First pass: Discard all partially sent host pages */
+ postcopy_chunk_hostpages_pass(ms, true, block, pds);
+ /*
+ * Second pass: Ensure that all partially dirty host pages are made
+ * fully dirty.
+ */
+ postcopy_chunk_hostpages_pass(ms, false, block, pds);
+ postcopy_discard_send_finish(ms, pds);
return 0;
}
@@ -1840,43 +1773,49 @@ static int postcopy_chunk_hostpages(MigrationState *ms)
int ram_postcopy_send_discard_bitmap(MigrationState *ms)
{
RAMState *rs = &ram_state;
+ RAMBlock *block;
int ret;
- unsigned long *bitmap, *unsentmap;
rcu_read_lock();
/* This should be our last sync, the src is now paused */
migration_bitmap_sync(rs);
- unsentmap = atomic_rcu_read(&rs->ram_bitmap)->unsentmap;
- if (!unsentmap) {
- /* We don't have a safe way to resize the sentmap, so
- * if the bitmap was resized it will be NULL at this
- * point.
- */
- error_report("migration ram resized during precopy phase");
- rcu_read_unlock();
- return -EINVAL;
- }
-
- /* Deal with TPS != HPS and huge pages */
- ret = postcopy_chunk_hostpages(ms);
- if (ret) {
- rcu_read_unlock();
- return ret;
- }
-
- /*
- * Update the unsentmap to be unsentmap = unsentmap | dirty
- */
- bitmap = atomic_rcu_read(&rs->ram_bitmap)->bmap;
- bitmap_or(unsentmap, unsentmap, bitmap, last_ram_page());
+ /* Easiest way to make sure we don't resume in the middle of a host-page */
+ rs->last_seen_block = NULL;
+ rs->last_sent_block = NULL;
+ rs->last_page = 0;
+ QLIST_FOREACH_RCU(block, &ram_list.blocks, next) {
+ unsigned long pages = block->used_length >> TARGET_PAGE_BITS;
+ unsigned long *bitmap = block->bmap;
+ unsigned long *unsentmap = block->unsentmap;
+
+ if (!unsentmap) {
+ /* We don't have a safe way to resize the sentmap, so
+ * if the bitmap was resized it will be NULL at this
+ * point.
+ */
+ error_report("migration ram resized during precopy phase");
+ rcu_read_unlock();
+ return -EINVAL;
+ }
+ /* Deal with TPS != HPS and huge pages */
+ ret = postcopy_chunk_hostpages(ms, block);
+ if (ret) {
+ rcu_read_unlock();
+ return ret;
+ }
- trace_ram_postcopy_send_discard_bitmap();
+ /*
+ * Update the unsentmap to be unsentmap = unsentmap | dirty
+ */
+ bitmap_or(unsentmap, unsentmap, bitmap, pages);
#ifdef DEBUG_POSTCOPY
- ram_debug_dump_bitmap(unsentmap, true);
+ ram_debug_dump_bitmap(unsentmap, true, pages);
#endif
+ }
+ trace_ram_postcopy_send_discard_bitmap();
ret = postcopy_each_ram_send_discard(ms);
rcu_read_unlock();
@@ -1918,8 +1857,6 @@ err:
static int ram_state_init(RAMState *rs)
{
- unsigned long ram_bitmap_pages;
-
memset(rs, 0, sizeof(*rs));
qemu_mutex_init(&rs->bitmap_mutex);
qemu_mutex_init(&rs->src_page_req_mutex);
@@ -1961,16 +1898,19 @@ static int ram_state_init(RAMState *rs)
rcu_read_lock();
ram_state_reset(rs);
- rs->ram_bitmap = g_new0(RAMBitmap, 1);
/* Skip setting bitmap if there is no RAM */
if (ram_bytes_total()) {
- ram_bitmap_pages = last_ram_page();
- rs->ram_bitmap->bmap = bitmap_new(ram_bitmap_pages);
- bitmap_set(rs->ram_bitmap->bmap, 0, ram_bitmap_pages);
+ RAMBlock *block;
- if (migrate_postcopy_ram()) {
- rs->ram_bitmap->unsentmap = bitmap_new(ram_bitmap_pages);
- bitmap_set(rs->ram_bitmap->unsentmap, 0, ram_bitmap_pages);
+ QLIST_FOREACH_RCU(block, &ram_list.blocks, next) {
+ unsigned long pages = block->max_length >> TARGET_PAGE_BITS;
+
+ block->bmap = bitmap_new(pages);
+ bitmap_set(block->bmap, 0, pages);
+ if (migrate_postcopy_ram()) {
+ block->unsentmap = bitmap_new(pages);
+ bitmap_set(block->unsentmap, 0, pages);
+ }
}
}
@@ -2611,6 +2551,7 @@ static int ram_load(QEMUFile *f, void *opaque, int version_id)
ret = -EINVAL;
break;
}
+ trace_ram_load_loop(block->idstr, (uint64_t)addr, flags, host);
}
switch (flags & ~RAM_SAVE_FLAG_CONTINUE) {
diff --git a/migration/savevm.c b/migration/savevm.c
index 03ae1bd..352a8f2 100644
--- a/migration/savevm.c
+++ b/migration/savevm.c
@@ -33,15 +33,12 @@
#include "hw/qdev.h"
#include "hw/xen/xen.h"
#include "net/net.h"
-#include "monitor/monitor.h"
#include "sysemu/sysemu.h"
#include "qemu/timer.h"
-#include "audio/audio.h"
#include "migration/migration.h"
-#include "migration/postcopy-ram.h"
+#include "postcopy-ram.h"
#include "qapi/qmp/qerror.h"
#include "qemu/error-report.h"
-#include "qemu/sockets.h"
#include "qemu/queue.h"
#include "sysemu/cpus.h"
#include "exec/memory.h"
@@ -50,7 +47,6 @@
#include "qemu/bitops.h"
#include "qemu/iov.h"
#include "block/snapshot.h"
-#include "block/qapi.h"
#include "qemu/cutils.h"
#include "io/channel-buffer.h"
#include "io/channel-file.h"
@@ -1622,6 +1618,14 @@ static void loadvm_postcopy_handle_run_bh(void *opaque)
error_report_err(local_err);
}
+ /* If we get an error here, just don't restart the VM yet. */
+ blk_resume_after_migration(&local_err);
+ if (local_err) {
+ error_free(local_err);
+ local_err = NULL;
+ autostart = false;
+ }
+
trace_loadvm_postcopy_handle_run_cpu_sync();
cpu_synchronize_all_post_init();
@@ -2070,7 +2074,7 @@ int qemu_loadvm_state(QEMUFile *f)
return ret;
}
-int save_vmstate(Monitor *mon, const char *name)
+int save_vmstate(const char *name)
{
BlockDriverState *bs, *bs1;
QEMUSnapshotInfo sn1, *sn = &sn1, old_sn1, *old_sn = &old_sn1;
@@ -2084,8 +2088,8 @@ int save_vmstate(Monitor *mon, const char *name)
AioContext *aio_context;
if (!bdrv_all_can_snapshot(&bs)) {
- monitor_printf(mon, "Device '%s' is writable but does not "
- "support snapshots.\n", bdrv_get_device_name(bs));
+ error_report("Device '%s' is writable but does not support snapshots",
+ bdrv_get_device_name(bs));
return ret;
}
@@ -2102,7 +2106,7 @@ int save_vmstate(Monitor *mon, const char *name)
bs = bdrv_all_find_vmstate_bs();
if (bs == NULL) {
- monitor_printf(mon, "No block device can accept snapshots\n");
+ error_report("No block device can accept snapshots");
return ret;
}
aio_context = bdrv_get_aio_context(bs);
@@ -2111,7 +2115,7 @@ int save_vmstate(Monitor *mon, const char *name)
ret = global_state_store();
if (ret) {
- monitor_printf(mon, "Error saving global state\n");
+ error_report("Error saving global state");
return ret;
}
vm_stop(RUN_STATE_SAVE_VM);
@@ -2143,7 +2147,7 @@ int save_vmstate(Monitor *mon, const char *name)
/* save the VM state */
f = qemu_fopen_bdrv(bs, 1);
if (!f) {
- monitor_printf(mon, "Could not open VM state file\n");
+ error_report("Could not open VM state file");
goto the_end;
}
ret = qemu_savevm_state(f, &local_err);
@@ -2156,8 +2160,8 @@ int save_vmstate(Monitor *mon, const char *name)
ret = bdrv_all_create_snapshot(sn, bs, vm_state_size, &bs);
if (ret < 0) {
- monitor_printf(mon, "Error while creating snapshot on '%s'\n",
- bdrv_get_device_name(bs));
+ error_report("Error while creating snapshot on '%s'",
+ bdrv_get_device_name(bs));
goto the_end;
}
@@ -2171,11 +2175,6 @@ int save_vmstate(Monitor *mon, const char *name)
return ret;
}
-void hmp_savevm(Monitor *mon, const QDict *qdict)
-{
- save_vmstate(mon, qdict_get_try_str(qdict, "name"));
-}
-
void qmp_xen_save_devices_state(const char *filename, Error **errp)
{
QEMUFile *f;
@@ -2245,7 +2244,7 @@ int load_vmstate(const char *name)
MigrationIncomingState *mis = migration_incoming_get_current();
if (!bdrv_all_can_snapshot(&bs)) {
- error_report("Device '%s' is writable but does not support snapshots.",
+ error_report("Device '%s' is writable but does not support snapshots",
bdrv_get_device_name(bs));
return -ENOTSUP;
}
@@ -2309,162 +2308,6 @@ int load_vmstate(const char *name)
return 0;
}
-void hmp_delvm(Monitor *mon, const QDict *qdict)
-{
- BlockDriverState *bs;
- Error *err;
- const char *name = qdict_get_str(qdict, "name");
-
- if (bdrv_all_delete_snapshot(name, &bs, &err) < 0) {
- error_reportf_err(err,
- "Error while deleting snapshot on device '%s': ",
- bdrv_get_device_name(bs));
- }
-}
-
-void hmp_info_snapshots(Monitor *mon, const QDict *qdict)
-{
- BlockDriverState *bs, *bs1;
- BdrvNextIterator it1;
- QEMUSnapshotInfo *sn_tab, *sn;
- bool no_snapshot = true;
- int nb_sns, i;
- int total;
- int *global_snapshots;
- AioContext *aio_context;
-
- typedef struct SnapshotEntry {
- QEMUSnapshotInfo sn;
- QTAILQ_ENTRY(SnapshotEntry) next;
- } SnapshotEntry;
-
- typedef struct ImageEntry {
- const char *imagename;
- QTAILQ_ENTRY(ImageEntry) next;
- QTAILQ_HEAD(, SnapshotEntry) snapshots;
- } ImageEntry;
-
- QTAILQ_HEAD(, ImageEntry) image_list =
- QTAILQ_HEAD_INITIALIZER(image_list);
-
- ImageEntry *image_entry, *next_ie;
- SnapshotEntry *snapshot_entry;
-
- bs = bdrv_all_find_vmstate_bs();
- if (!bs) {
- monitor_printf(mon, "No available block device supports snapshots\n");
- return;
- }
- aio_context = bdrv_get_aio_context(bs);
-
- aio_context_acquire(aio_context);
- nb_sns = bdrv_snapshot_list(bs, &sn_tab);
- aio_context_release(aio_context);
-
- if (nb_sns < 0) {
- monitor_printf(mon, "bdrv_snapshot_list: error %d\n", nb_sns);
- return;
- }
-
- for (bs1 = bdrv_first(&it1); bs1; bs1 = bdrv_next(&it1)) {
- int bs1_nb_sns = 0;
- ImageEntry *ie;
- SnapshotEntry *se;
- AioContext *ctx = bdrv_get_aio_context(bs1);
-
- aio_context_acquire(ctx);
- if (bdrv_can_snapshot(bs1)) {
- sn = NULL;
- bs1_nb_sns = bdrv_snapshot_list(bs1, &sn);
- if (bs1_nb_sns > 0) {
- no_snapshot = false;
- ie = g_new0(ImageEntry, 1);
- ie->imagename = bdrv_get_device_name(bs1);
- QTAILQ_INIT(&ie->snapshots);
- QTAILQ_INSERT_TAIL(&image_list, ie, next);
- for (i = 0; i < bs1_nb_sns; i++) {
- se = g_new0(SnapshotEntry, 1);
- se->sn = sn[i];
- QTAILQ_INSERT_TAIL(&ie->snapshots, se, next);
- }
- }
- g_free(sn);
- }
- aio_context_release(ctx);
- }
-
- if (no_snapshot) {
- monitor_printf(mon, "There is no snapshot available.\n");
- return;
- }
-
- global_snapshots = g_new0(int, nb_sns);
- total = 0;
- for (i = 0; i < nb_sns; i++) {
- SnapshotEntry *next_sn;
- if (bdrv_all_find_snapshot(sn_tab[i].name, &bs1) == 0) {
- global_snapshots[total] = i;
- total++;
- QTAILQ_FOREACH(image_entry, &image_list, next) {
- QTAILQ_FOREACH_SAFE(snapshot_entry, &image_entry->snapshots,
- next, next_sn) {
- if (!strcmp(sn_tab[i].name, snapshot_entry->sn.name)) {
- QTAILQ_REMOVE(&image_entry->snapshots, snapshot_entry,
- next);
- g_free(snapshot_entry);
- }
- }
- }
- }
- }
-
- monitor_printf(mon, "List of snapshots present on all disks:\n");
-
- if (total > 0) {
- bdrv_snapshot_dump((fprintf_function)monitor_printf, mon, NULL);
- monitor_printf(mon, "\n");
- for (i = 0; i < total; i++) {
- sn = &sn_tab[global_snapshots[i]];
- /* The ID is not guaranteed to be the same on all images, so
- * overwrite it.
- */
- pstrcpy(sn->id_str, sizeof(sn->id_str), "--");
- bdrv_snapshot_dump((fprintf_function)monitor_printf, mon, sn);
- monitor_printf(mon, "\n");
- }
- } else {
- monitor_printf(mon, "None\n");
- }
-
- QTAILQ_FOREACH(image_entry, &image_list, next) {
- if (QTAILQ_EMPTY(&image_entry->snapshots)) {
- continue;
- }
- monitor_printf(mon,
- "\nList of partial (non-loadable) snapshots on '%s':\n",
- image_entry->imagename);
- bdrv_snapshot_dump((fprintf_function)monitor_printf, mon, NULL);
- monitor_printf(mon, "\n");
- QTAILQ_FOREACH(snapshot_entry, &image_entry->snapshots, next) {
- bdrv_snapshot_dump((fprintf_function)monitor_printf, mon,
- &snapshot_entry->sn);
- monitor_printf(mon, "\n");
- }
- }
-
- QTAILQ_FOREACH_SAFE(image_entry, &image_list, next, next_ie) {
- SnapshotEntry *next_sn;
- QTAILQ_FOREACH_SAFE(snapshot_entry, &image_entry->snapshots, next,
- next_sn) {
- g_free(snapshot_entry);
- }
- g_free(image_entry);
- }
- g_free(sn_tab);
- g_free(global_snapshots);
-
-}
-
void vmstate_register_ram(MemoryRegion *mr, DeviceState *dev)
{
qemu_ram_set_idstr(mr->ram_block,
diff --git a/migration/socket.c b/migration/socket.c
index 13966f1..dc88812 100644
--- a/migration/socket.c
+++ b/migration/socket.c
@@ -79,7 +79,6 @@ static void socket_outgoing_migration(QIOTask *task,
if (qio_task_propagate_error(task, &err)) {
trace_migration_socket_outgoing_error(error_get_pretty(err));
- data->s->to_dst_file = NULL;
migrate_fd_error(data->s, err);
error_free(err);
} else {
diff --git a/migration/tls.c b/migration/tls.c
index 45bec44..a33ecb7 100644
--- a/migration/tls.c
+++ b/migration/tls.c
@@ -116,7 +116,6 @@ static void migration_tls_outgoing_handshake(QIOTask *task,
if (qio_task_propagate_error(task, &err)) {
trace_migration_tls_outgoing_handshake_error(error_get_pretty(err));
- s->to_dst_file = NULL;
migrate_fd_error(s, err);
error_free(err);
} else {
diff --git a/migration/trace-events b/migration/trace-events
index b8f01a2..5b8ccf3 100644
--- a/migration/trace-events
+++ b/migration/trace-events
@@ -69,8 +69,10 @@ migration_bitmap_sync_start(void) ""
migration_bitmap_sync_end(uint64_t dirty_pages) "dirty_pages %" PRIu64
migration_throttle(void) ""
ram_discard_range(const char *rbname, uint64_t start, size_t len) "%s: start: %" PRIx64 " %zx"
+ram_load_loop(const char *rbname, uint64_t addr, int flags, void *host) "%s: addr: %" PRIx64 " flags: %x host: %p"
ram_load_postcopy_loop(uint64_t addr, int flags) "@%" PRIx64 " %x"
ram_postcopy_send_discard_bitmap(void) ""
+ram_save_page(const char *rbname, uint64_t offset, void *host) "%s: offset: %" PRIx64 " host: %p"
ram_save_queue_pages(const char *rbname, size_t start, size_t len) "%s: start: %zx len: %zx"
# migration/migration.c
diff --git a/monitor.c b/monitor.c
index 62c9f81..ce11029 100644
--- a/monitor.c
+++ b/monitor.c
@@ -37,7 +37,6 @@
#include "net/slirp.h"
#include "sysemu/char.h"
#include "ui/qemu-spice.h"
-#include "sysemu/sysemu.h"
#include "sysemu/numa.h"
#include "monitor/monitor.h"
#include "qemu/config-file.h"
@@ -1954,18 +1953,6 @@ void qmp_closefd(const char *fdname, Error **errp)
error_setg(errp, QERR_FD_NOT_FOUND, fdname);
}
-static void hmp_loadvm(Monitor *mon, const QDict *qdict)
-{
- int saved_vm_running = runstate_is_running();
- const char *name = qdict_get_str(qdict, "name");
-
- vm_stop(RUN_STATE_RESTORE_VM);
-
- if (load_vmstate(name) == 0 && saved_vm_running) {
- vm_start();
- }
-}
-
int monitor_get_fd(Monitor *mon, const char *fdname, Error **errp)
{
mon_fd_t *monfd;
diff --git a/net/vhost-user.c b/net/vhost-user.c
index e7e6340..00a0c1c 100644
--- a/net/vhost-user.c
+++ b/net/vhost-user.c
@@ -154,7 +154,7 @@ static void vhost_user_cleanup(NetClientState *nc)
Chardev *chr = qemu_chr_fe_get_driver(&s->chr);
qemu_chr_fe_deinit(&s->chr);
- qemu_chr_delete(chr);
+ object_unparent(OBJECT(chr));
}
qemu_purge_queued_packets(nc);
diff --git a/pc-bios/s390-ccw.img b/pc-bios/s390-ccw.img
index 2a4adfa..0b01d49 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 0339c24..79a46b6 100644
--- a/pc-bios/s390-ccw/Makefile
+++ b/pc-bios/s390-ccw/Makefile
@@ -9,7 +9,7 @@ $(call set-vpath, $(SRC_PATH)/pc-bios/s390-ccw)
.PHONY : all clean build-all
-OBJECTS = start.o main.o bootmap.o sclp-ascii.o virtio.o virtio-scsi.o
+OBJECTS = start.o main.o bootmap.o sclp.o virtio.o virtio-scsi.o
QEMU_CFLAGS := $(filter -W%, $(QEMU_CFLAGS))
QEMU_CFLAGS += -ffreestanding -fno-delete-null-pointer-checks -msoft-float
QEMU_CFLAGS += -march=z900 -fPIE -fno-strict-aliasing
diff --git a/pc-bios/s390-ccw/bootmap.c b/pc-bios/s390-ccw/bootmap.c
index b21c877..523fa78 100644
--- a/pc-bios/s390-ccw/bootmap.c
+++ b/pc-bios/s390-ccw/bootmap.c
@@ -183,15 +183,21 @@ static block_number_t load_eckd_segments(block_number_t blk, uint64_t *address)
static void run_eckd_boot_script(block_number_t mbr_block_nr)
{
int i;
+ unsigned int loadparm = get_loadparm_index();
block_number_t block_nr;
uint64_t address;
- ScsiMbr *scsi_mbr = (void *)sec;
+ ScsiMbr *bte = (void *)sec; /* Eckd bootmap table entry */
BootMapScript *bms = (void *)sec;
+ debug_print_int("loadparm", loadparm);
+ IPL_assert(loadparm < 31, "loadparm value greater than"
+ " maximum number of boot entries allowed");
+
memset(sec, FREE_SPACE_FILLER, sizeof(sec));
read_block(mbr_block_nr, sec, "Cannot read MBR");
- block_nr = eckd_block_num((void *)&(scsi_mbr->blockptr));
+ block_nr = eckd_block_num((void *)&(bte->blockptr[loadparm]));
+ IPL_assert(block_nr != -1, "No Boot Map");
memset(sec, FREE_SPACE_FILLER, sizeof(sec));
read_block(block_nr, sec, "Cannot read Boot Map Script");
@@ -444,7 +450,8 @@ static void ipl_scsi(void)
uint8_t *ns, *ns_end;
int program_table_entries = 0;
const int pte_len = sizeof(ScsiBlockPtr);
- ScsiBlockPtr *prog_table_entry;
+ ScsiBlockPtr *prog_table_entry = NULL;
+ unsigned int loadparm = get_loadparm_index();
/* Grab the MBR */
memset(sec, FREE_SPACE_FILLER, sizeof(sec));
@@ -458,15 +465,16 @@ static void ipl_scsi(void)
debug_print_int("MBR Version", mbr->version_id);
IPL_check(mbr->version_id == 1,
"Unknown MBR layout version, assuming version 1");
- debug_print_int("program table", mbr->blockptr.blockno);
- IPL_assert(mbr->blockptr.blockno, "No Program Table");
+ debug_print_int("program table", mbr->blockptr[0].blockno);
+ IPL_assert(mbr->blockptr[0].blockno, "No Program Table");
/* Parse the program table */
- read_block(mbr->blockptr.blockno, sec,
+ read_block(mbr->blockptr[0].blockno, sec,
"Error reading Program Table");
IPL_assert(magic_match(sec, ZIPL_MAGIC), "No zIPL magic in PT");
+ debug_print_int("loadparm index", loadparm);
ns_end = sec + virtio_get_block_size();
for (ns = (sec + pte_len); (ns + pte_len) < ns_end; ns += pte_len) {
prog_table_entry = (ScsiBlockPtr *)ns;
@@ -475,16 +483,15 @@ static void ipl_scsi(void)
}
program_table_entries++;
+ if (program_table_entries == loadparm + 1) {
+ break; /* selected entry found */
+ }
}
debug_print_int("program table entries", program_table_entries);
IPL_assert(program_table_entries != 0, "Empty Program Table");
- /* Run the default entry */
-
- prog_table_entry = (ScsiBlockPtr *)(sec + pte_len);
-
zipl_run(prog_table_entry); /* no return */
}
@@ -648,6 +655,7 @@ static IsoBcSection *find_iso_bc_entry(void)
IsoBcEntry *e = (IsoBcEntry *)sec;
uint32_t offset = find_iso_bc();
int i;
+ unsigned int loadparm = get_loadparm_index();
if (!offset) {
return NULL;
@@ -668,7 +676,11 @@ static IsoBcSection *find_iso_bc_entry(void)
for (i = 1; i < ISO_BC_ENTRY_PER_SECTOR; i++) {
if (e[i].id == ISO_BC_BOOTABLE_SECTION) {
if (is_iso_bc_entry_compatible(&e[i].body.sect)) {
- return &e[i].body.sect;
+ if (loadparm <= 1) {
+ /* found, default, or unspecified */
+ return &e[i].body.sect;
+ }
+ loadparm--;
}
}
}
diff --git a/pc-bios/s390-ccw/bootmap.h b/pc-bios/s390-ccw/bootmap.h
index bea1687..7f36782 100644
--- a/pc-bios/s390-ccw/bootmap.h
+++ b/pc-bios/s390-ccw/bootmap.h
@@ -70,7 +70,7 @@ typedef struct ScsiMbr {
uint8_t magic[4];
uint32_t version_id;
uint8_t reserved[8];
- ScsiBlockPtr blockptr;
+ ScsiBlockPtr blockptr[];
} __attribute__ ((packed)) ScsiMbr;
#define ZIPL_MAGIC "zIPL"
@@ -264,28 +264,6 @@ typedef enum {
/* utility code below */
-static const unsigned char ebc2asc[256] =
- /* 0123456789abcdef0123456789abcdef */
- "................................" /* 1F */
- "................................" /* 3F */
- " ...........<(+|&.........!$*);." /* 5F first.chr.here.is.real.space */
- "-/.........,%_>?.........`:#@'=\""/* 7F */
- ".abcdefghi.......jklmnopqr......" /* 9F */
- "..stuvwxyz......................" /* BF */
- ".ABCDEFGHI.......JKLMNOPQR......" /* DF */
- "..STUVWXYZ......0123456789......";/* FF */
-
-static inline void ebcdic_to_ascii(const char *src,
- char *dst,
- unsigned int size)
-{
- unsigned int i;
- for (i = 0; i < size; i++) {
- unsigned c = src[i];
- dst[i] = ebc2asc[c];
- }
-}
-
static inline void print_volser(const void *volser)
{
char ascii[8];
diff --git a/pc-bios/s390-ccw/main.c b/pc-bios/s390-ccw/main.c
index 0946766..1cacc1b 100644
--- a/pc-bios/s390-ccw/main.c
+++ b/pc-bios/s390-ccw/main.c
@@ -14,6 +14,18 @@
char stack[PAGE_SIZE * 8] __attribute__((__aligned__(PAGE_SIZE)));
static SubChannelId blk_schid = { .one = 1 };
IplParameterBlock iplb __attribute__((__aligned__(PAGE_SIZE)));
+static char loadparm[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
+
+const unsigned char ebc2asc[256] =
+ /* 0123456789abcdef0123456789abcdef */
+ "................................" /* 1F */
+ "................................" /* 3F */
+ " ...........<(+|&.........!$*);." /* 5F first.chr.here.is.real.space */
+ "-/.........,%_>?.........`:#@'=\""/* 7F */
+ ".abcdefghi.......jklmnopqr......" /* 9F */
+ "..stuvwxyz......................" /* BF */
+ ".ABCDEFGHI.......JKLMNOPQR......" /* DF */
+ "..STUVWXYZ......0123456789......";/* FF */
/*
* Priniciples of Operations (SA22-7832-09) chapter 17 requires that
@@ -29,7 +41,6 @@ void write_subsystem_identification(void)
*zeroes = 0;
}
-
void panic(const char *string)
{
sclp_print(string);
@@ -37,6 +48,26 @@ void panic(const char *string)
while (1) { }
}
+unsigned int get_loadparm_index(void)
+{
+ const char *lp = loadparm;
+ int i;
+ unsigned int idx = 0;
+
+ for (i = 0; i < 8; i++) {
+ char c = lp[i];
+
+ if (c < '0' || c > '9') {
+ break;
+ }
+
+ idx *= 10;
+ idx += c - '0';
+ }
+
+ return idx;
+}
+
static bool find_dev(Schib *schib, int dev_no)
{
int i, r;
@@ -73,6 +104,7 @@ static void virtio_setup(void)
int ssid;
bool found = false;
uint16_t dev_no;
+ char ldp[] = "LOADPARM=[________]\n";
VDev *vdev = virtio_get_device();
/*
@@ -82,6 +114,10 @@ static void virtio_setup(void)
*/
enable_mss_facility();
+ sclp_get_loadparm_ascii(loadparm);
+ memcpy(ldp + 10, loadparm, 8);
+ sclp_print(ldp);
+
if (store_iplb(&iplb)) {
switch (iplb.pbt) {
case S390_IPL_TYPE_CCW:
diff --git a/pc-bios/s390-ccw/s390-ccw.h b/pc-bios/s390-ccw/s390-ccw.h
index ded67bc..07d8cbc 100644
--- a/pc-bios/s390-ccw/s390-ccw.h
+++ b/pc-bios/s390-ccw/s390-ccw.h
@@ -62,10 +62,12 @@ void consume_sclp_int(void);
void panic(const char *string);
void write_subsystem_identification(void);
extern char stack[PAGE_SIZE * 8] __attribute__((__aligned__(PAGE_SIZE)));
+unsigned int get_loadparm_index(void);
-/* sclp-ascii.c */
+/* sclp.c */
void sclp_print(const char *string);
void sclp_setup(void);
+void sclp_get_loadparm_ascii(char *loadparm);
/* virtio.c */
unsigned long virtio_load_direct(ulong rec_list1, ulong rec_list2,
@@ -189,4 +191,17 @@ static inline void IPL_check(bool term, const char *message)
}
}
+extern const unsigned char ebc2asc[256];
+static inline void ebcdic_to_ascii(const char *src,
+ char *dst,
+ unsigned int size)
+{
+ unsigned int i;
+
+ for (i = 0; i < size; i++) {
+ unsigned c = src[i];
+ dst[i] = ebc2asc[c];
+ }
+}
+
#endif /* S390_CCW_H */
diff --git a/pc-bios/s390-ccw/sclp-ascii.c b/pc-bios/s390-ccw/sclp.c
index dc1c3e4..a1639ba 100644
--- a/pc-bios/s390-ccw/sclp-ascii.c
+++ b/pc-bios/s390-ccw/sclp.c
@@ -80,3 +80,15 @@ void sclp_print(const char *str)
sclp_service_call(SCLP_CMD_WRITE_EVENT_DATA, sccb);
}
+
+void sclp_get_loadparm_ascii(char *loadparm)
+{
+
+ ReadInfo *sccb = (void *)_sccb;
+
+ memset((char *)_sccb, 0, sizeof(ReadInfo));
+ sccb->h.length = sizeof(ReadInfo);
+ if (!sclp_service_call(SCLP_CMDW_READ_SCP_INFO, sccb)) {
+ ebcdic_to_ascii((char *) sccb->loadparm, loadparm, 8);
+ }
+}
diff --git a/pc-bios/s390-ccw/sclp.h b/pc-bios/s390-ccw/sclp.h
index 3cbfb78..0dd987f 100644
--- a/pc-bios/s390-ccw/sclp.h
+++ b/pc-bios/s390-ccw/sclp.h
@@ -55,6 +55,8 @@ typedef struct ReadInfo {
SCCBHeader h;
uint16_t rnmax;
uint8_t rnsize;
+ uint8_t reserved[13];
+ uint8_t loadparm[8];
} __attribute__((packed)) ReadInfo;
typedef struct SCCB {
diff --git a/qapi-schema.json b/qapi-schema.json
index 01b087f..5bb8cb7 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -4877,6 +4877,8 @@
# @nodelay: set TCP_NODELAY socket option (default: false)
# @telnet: enable telnet protocol on server
# sockets (default: false)
+# @tn3270: enable tn3270 protocol on server
+# sockets (default: false) (Since: 2.10)
# @reconnect: For a client socket, if a socket is disconnected,
# then attempt a reconnect after the given number of seconds.
# Setting this to zero disables this function. (default: 0)
@@ -4890,6 +4892,7 @@
'*wait' : 'bool',
'*nodelay' : 'bool',
'*telnet' : 'bool',
+ '*tn3270' : 'bool',
'*reconnect' : 'int' },
'base': 'ChardevCommon' }
diff --git a/qemu-img-cmds.hx b/qemu-img-cmds.hx
index 8ac7822..bf4ce59 100644
--- a/qemu-img-cmds.hx
+++ b/qemu-img-cmds.hx
@@ -22,9 +22,9 @@ STEXI
ETEXI
DEF("create", img_create,
- "create [-q] [--object objectdef] [-f fmt] [-o options] filename [size]")
+ "create [-q] [--object objectdef] [-f fmt] [-b backing_file] [-F backing_fmt] [-o options] filename [size]")
STEXI
-@item create [--object @var{objectdef}] [-q] [-f @var{fmt}] [-o @var{options}] @var{filename} [@var{size}]
+@item create [--object @var{objectdef}] [-q] [-f @var{fmt}] [-b @var{backing_file}] [-F @var{backing_fmt}] [-o @var{options}] @var{filename} [@var{size}]
ETEXI
DEF("commit", img_commit,
@@ -40,9 +40,9 @@ STEXI
ETEXI
DEF("convert", img_convert,
- "convert [--object objectdef] [--image-opts] [-c] [-p] [-q] [-n] [-f fmt] [-t cache] [-T src_cache] [-O output_fmt] [-o options] [-s snapshot_id_or_name] [-l snapshot_param] [-S sparse_size] [-m num_coroutines] [-W] filename [filename2 [...]] output_filename")
+ "convert [--object objectdef] [--image-opts] [-c] [-p] [-q] [-n] [-f fmt] [-t cache] [-T src_cache] [-O output_fmt] [-B backing_file] [-o options] [-s snapshot_id_or_name] [-l snapshot_param] [-S sparse_size] [-m num_coroutines] [-W] filename [filename2 [...]] output_filename")
STEXI
-@item convert [--object @var{objectdef}] [--image-opts] [-c] [-p] [-q] [-n] [-f @var{fmt}] [-t @var{cache}] [-T @var{src_cache}] [-O @var{output_fmt}] [-o @var{options}] [-s @var{snapshot_id_or_name}] [-l @var{snapshot_param}] [-S @var{sparse_size}] [-m @var{num_coroutines}] [-W] @var{filename} [@var{filename2} [...]] @var{output_filename}
+@item convert [--object @var{objectdef}] [--image-opts] [-c] [-p] [-q] [-n] [-f @var{fmt}] [-t @var{cache}] [-T @var{src_cache}] [-O @var{output_fmt}] [-B @var{backing_file}] [-o @var{options}] [-s @var{snapshot_id_or_name}] [-l @var{snapshot_param}] [-S @var{sparse_size}] [-m @var{num_coroutines}] [-W] @var{filename} [@var{filename2} [...]] @var{output_filename}
ETEXI
DEF("dd", img_dd,
diff --git a/qemu-img.c b/qemu-img.c
index bbe1574..c719636 100644
--- a/qemu-img.c
+++ b/qemu-img.c
@@ -1522,7 +1522,7 @@ typedef struct ImgConvertState {
int min_sparse;
size_t cluster_sectors;
size_t buf_sectors;
- int num_coroutines;
+ long num_coroutines;
int running_coroutines;
Coroutine *co[MAX_COROUTINES];
int64_t wait_sector_num[MAX_COROUTINES];
@@ -1554,9 +1554,15 @@ static int convert_iteration_sectors(ImgConvertState *s, int64_t sector_num)
if (s->sector_next_status <= sector_num) {
BlockDriverState *file;
- ret = bdrv_get_block_status(blk_bs(s->src[src_cur]),
- sector_num - src_cur_offset,
- n, &n, &file);
+ if (s->target_has_backing) {
+ ret = bdrv_get_block_status(blk_bs(s->src[src_cur]),
+ sector_num - src_cur_offset,
+ n, &n, &file);
+ } else {
+ ret = bdrv_get_block_status_above(blk_bs(s->src[src_cur]), NULL,
+ sector_num - src_cur_offset,
+ n, &n, &file);
+ }
if (ret < 0) {
return ret;
}
@@ -1565,26 +1571,8 @@ static int convert_iteration_sectors(ImgConvertState *s, int64_t sector_num)
s->status = BLK_ZERO;
} else if (ret & BDRV_BLOCK_DATA) {
s->status = BLK_DATA;
- } else if (!s->target_has_backing) {
- /* Without a target backing file we must copy over the contents of
- * the backing file as well. */
- /* Check block status of the backing file chain to avoid
- * needlessly reading zeroes and limiting the iteration to the
- * buffer size */
- ret = bdrv_get_block_status_above(blk_bs(s->src[src_cur]), NULL,
- sector_num - src_cur_offset,
- n, &n, &file);
- if (ret < 0) {
- return ret;
- }
-
- if (ret & BDRV_BLOCK_ZERO) {
- s->status = BLK_ZERO;
- } else {
- s->status = BLK_DATA;
- }
} else {
- s->status = BLK_BACKING_FILE;
+ s->status = s->target_has_backing ? BLK_BACKING_FILE : BLK_DATA;
}
s->sector_next_status = sector_num + n;
@@ -1661,6 +1649,8 @@ static int coroutine_fn convert_co_write(ImgConvertState *s, int64_t sector_num,
while (nb_sectors > 0) {
int n = nb_sectors;
+ BdrvRequestFlags flags = s->compressed ? BDRV_REQ_WRITE_COMPRESSED : 0;
+
switch (status) {
case BLK_BACKING_FILE:
/* If we have a backing file, leave clusters unallocated that are
@@ -1670,43 +1660,24 @@ static int coroutine_fn convert_co_write(ImgConvertState *s, int64_t sector_num,
break;
case BLK_DATA:
- /* We must always write compressed clusters as a whole, so don't
- * try to find zeroed parts in the buffer. We can only save the
- * write if the buffer is completely zeroed and we're allowed to
- * keep the target sparse. */
- if (s->compressed) {
- if (s->has_zero_init && s->min_sparse &&
- buffer_is_zero(buf, n * BDRV_SECTOR_SIZE))
- {
- assert(!s->target_has_backing);
- break;
- }
-
- iov.iov_base = buf;
- iov.iov_len = n << BDRV_SECTOR_BITS;
- qemu_iovec_init_external(&qiov, &iov, 1);
-
- ret = blk_co_pwritev(s->target, sector_num << BDRV_SECTOR_BITS,
- n << BDRV_SECTOR_BITS, &qiov,
- BDRV_REQ_WRITE_COMPRESSED);
- if (ret < 0) {
- return ret;
- }
- break;
- }
-
- /* If there is real non-zero data or we're told to keep the target
- * fully allocated (-S 0), we must write it. Otherwise we can treat
- * it as zero sectors. */
+ /* If we're told to keep the target fully allocated (-S 0) or there
+ * is real non-zero data, we must write it. Otherwise we can treat
+ * it as zero sectors.
+ * Compressed clusters need to be written as a whole, so in that
+ * case we can only save the write if the buffer is completely
+ * zeroed. */
if (!s->min_sparse ||
- is_allocated_sectors_min(buf, n, &n, s->min_sparse))
+ (!s->compressed &&
+ is_allocated_sectors_min(buf, n, &n, s->min_sparse)) ||
+ (s->compressed &&
+ !buffer_is_zero(buf, n * BDRV_SECTOR_SIZE)))
{
iov.iov_base = buf;
iov.iov_len = n << BDRV_SECTOR_BITS;
qemu_iovec_init_external(&qiov, &iov, 1);
ret = blk_co_pwritev(s->target, sector_num << BDRV_SECTOR_BITS,
- n << BDRV_SECTOR_BITS, &qiov, 0);
+ n << BDRV_SECTOR_BITS, &qiov, flags);
if (ret < 0) {
return ret;
}
@@ -1716,6 +1687,7 @@ static int coroutine_fn convert_co_write(ImgConvertState *s, int64_t sector_num,
case BLK_ZERO:
if (s->has_zero_init) {
+ assert(!s->target_has_backing);
break;
}
ret = blk_co_pwrite_zeroes(s->target,
@@ -1916,39 +1888,29 @@ static int convert_do_copy(ImgConvertState *s)
static int img_convert(int argc, char **argv)
{
- int c, bs_n, bs_i, compress, cluster_sectors, skip_create;
- int64_t ret = 0;
- int progress = 0, flags, src_flags;
- bool writethrough, src_writethrough;
- const char *fmt, *out_fmt, *cache, *src_cache, *out_baseimg, *out_filename;
+ int c, bs_i, flags, src_flags = 0;
+ const char *fmt = NULL, *out_fmt = "raw", *cache = "unsafe",
+ *src_cache = BDRV_DEFAULT_CACHE, *out_baseimg = NULL,
+ *out_filename, *out_baseimg_param, *snapshot_name = NULL;
BlockDriver *drv, *proto_drv;
- BlockBackend **blk = NULL, *out_blk = NULL;
- BlockDriverState **bs = NULL, *out_bs = NULL;
- int64_t total_sectors;
- int64_t *bs_sectors = NULL;
- size_t bufsectors = IO_BUF_SIZE / BDRV_SECTOR_SIZE;
BlockDriverInfo bdi;
- QemuOpts *opts = NULL;
+ BlockDriverState *out_bs;
+ QemuOpts *opts = NULL, *sn_opts = NULL;
QemuOptsList *create_opts = NULL;
- const char *out_baseimg_param;
char *options = NULL;
- const char *snapshot_name = NULL;
- int min_sparse = 8; /* Need at least 4k of zeros for sparse detection */
- bool quiet = false;
Error *local_err = NULL;
- QemuOpts *sn_opts = NULL;
- ImgConvertState state;
- bool image_opts = false;
- bool wr_in_order = true;
- long num_coroutines = 8;
+ bool writethrough, src_writethrough, quiet = false, image_opts = false,
+ skip_create = false, progress = false;
+ int64_t ret = -EINVAL;
+
+ ImgConvertState s = (ImgConvertState) {
+ /* Need at least 4k of zeros for sparse detection */
+ .min_sparse = 8,
+ .buf_sectors = IO_BUF_SIZE / BDRV_SECTOR_SIZE,
+ .wr_in_order = true,
+ .num_coroutines = 8,
+ };
- fmt = NULL;
- out_fmt = "raw";
- cache = "unsafe";
- src_cache = BDRV_DEFAULT_CACHE;
- out_baseimg = NULL;
- compress = 0;
- skip_create = 0;
for(;;) {
static const struct option long_options[] = {
{"help", no_argument, 0, 'h'},
@@ -1981,22 +1943,19 @@ static int img_convert(int argc, char **argv)
out_baseimg = optarg;
break;
case 'c':
- compress = 1;
+ s.compressed = true;
break;
case 'e':
error_report("option -e is deprecated, please use \'-o "
"encryption\' instead!");
- ret = -1;
goto fail_getopt;
case '6':
error_report("option -6 is deprecated, please use \'-o "
"compat6\' instead!");
- ret = -1;
goto fail_getopt;
case 'o':
if (!is_valid_option_list(optarg)) {
error_report("Invalid option list: %s", optarg);
- ret = -1;
goto fail_getopt;
}
if (!options) {
@@ -2017,7 +1976,6 @@ static int img_convert(int argc, char **argv)
if (!sn_opts) {
error_report("Failed in parsing snapshot param '%s'",
optarg);
- ret = -1;
goto fail_getopt;
}
} else {
@@ -2031,15 +1989,14 @@ static int img_convert(int argc, char **argv)
sval = cvtnum(optarg);
if (sval < 0) {
error_report("Invalid minimum zero buffer size for sparse output specified");
- ret = -1;
goto fail_getopt;
}
- min_sparse = sval / BDRV_SECTOR_SIZE;
+ s.min_sparse = sval / BDRV_SECTOR_SIZE;
break;
}
case 'p':
- progress = 1;
+ progress = true;
break;
case 't':
cache = optarg;
@@ -2051,27 +2008,28 @@ static int img_convert(int argc, char **argv)
quiet = true;
break;
case 'n':
- skip_create = 1;
+ skip_create = true;
break;
case 'm':
- if (qemu_strtol(optarg, NULL, 0, &num_coroutines) ||
- num_coroutines < 1 || num_coroutines > MAX_COROUTINES) {
+ if (qemu_strtol(optarg, NULL, 0, &s.num_coroutines) ||
+ s.num_coroutines < 1 || s.num_coroutines > MAX_COROUTINES) {
error_report("Invalid number of coroutines. Allowed number of"
" coroutines is between 1 and %d", MAX_COROUTINES);
- ret = -1;
goto fail_getopt;
}
break;
case 'W':
- wr_in_order = false;
+ s.wr_in_order = false;
break;
- case OPTION_OBJECT:
- opts = qemu_opts_parse_noisily(&qemu_object_opts,
- optarg, true);
- if (!opts) {
+ case OPTION_OBJECT: {
+ QemuOpts *object_opts;
+ object_opts = qemu_opts_parse_noisily(&qemu_object_opts,
+ optarg, true);
+ if (!object_opts) {
goto fail_getopt;
}
break;
+ }
case OPTION_IMAGE_OPTS:
image_opts = true;
break;
@@ -2084,83 +2042,73 @@ static int img_convert(int argc, char **argv)
goto fail_getopt;
}
- if (!wr_in_order && compress) {
+ if (!s.wr_in_order && s.compressed) {
error_report("Out of order write and compress are mutually exclusive");
- ret = -1;
goto fail_getopt;
}
- /* Initialize before goto out */
- if (quiet) {
- progress = 0;
- }
- qemu_progress_init(progress, 1.0);
-
- bs_n = argc - optind - 1;
- out_filename = bs_n >= 1 ? argv[argc - 1] : NULL;
+ s.src_num = argc - optind - 1;
+ out_filename = s.src_num >= 1 ? argv[argc - 1] : NULL;
if (options && has_help_option(options)) {
ret = print_block_option_help(out_filename, out_fmt);
- goto out;
+ goto fail_getopt;
}
- if (bs_n < 1) {
- error_exit("Must specify image file name");
+ if (s.src_num < 1) {
+ error_report("Must specify image file name");
+ goto fail_getopt;
}
- if (bs_n > 1 && out_baseimg) {
- error_report("-B makes no sense when concatenating multiple input "
- "images");
- ret = -1;
- goto out;
- }
-
- src_flags = 0;
+ /* ret is still -EINVAL until here */
ret = bdrv_parse_cache_mode(src_cache, &src_flags, &src_writethrough);
if (ret < 0) {
error_report("Invalid source cache option: %s", src_cache);
- goto out;
+ goto fail_getopt;
}
+ /* Initialize before goto out */
+ if (quiet) {
+ progress = false;
+ }
+ qemu_progress_init(progress, 1.0);
qemu_progress_print(0, 100);
- blk = g_new0(BlockBackend *, bs_n);
- bs = g_new0(BlockDriverState *, bs_n);
- bs_sectors = g_new(int64_t, bs_n);
+ s.src = g_new0(BlockBackend *, s.src_num);
+ s.src_sectors = g_new(int64_t, s.src_num);
- total_sectors = 0;
- for (bs_i = 0; bs_i < bs_n; bs_i++) {
- blk[bs_i] = img_open(image_opts, argv[optind + bs_i],
- fmt, src_flags, src_writethrough, quiet);
- if (!blk[bs_i]) {
+ for (bs_i = 0; bs_i < s.src_num; bs_i++) {
+ s.src[bs_i] = img_open(image_opts, argv[optind + bs_i],
+ fmt, src_flags, src_writethrough, quiet);
+ if (!s.src[bs_i]) {
ret = -1;
goto out;
}
- bs[bs_i] = blk_bs(blk[bs_i]);
- bs_sectors[bs_i] = blk_nb_sectors(blk[bs_i]);
- if (bs_sectors[bs_i] < 0) {
+ s.src_sectors[bs_i] = blk_nb_sectors(s.src[bs_i]);
+ if (s.src_sectors[bs_i] < 0) {
error_report("Could not get size of %s: %s",
- argv[optind + bs_i], strerror(-bs_sectors[bs_i]));
+ argv[optind + bs_i], strerror(-s.src_sectors[bs_i]));
ret = -1;
goto out;
}
- total_sectors += bs_sectors[bs_i];
+ s.total_sectors += s.src_sectors[bs_i];
}
if (sn_opts) {
- bdrv_snapshot_load_tmp(bs[0],
+ bdrv_snapshot_load_tmp(blk_bs(s.src[0]),
qemu_opt_get(sn_opts, SNAPSHOT_OPT_ID),
qemu_opt_get(sn_opts, SNAPSHOT_OPT_NAME),
&local_err);
} else if (snapshot_name != NULL) {
- if (bs_n > 1) {
+ if (s.src_num > 1) {
error_report("No support for concatenating multiple snapshot");
ret = -1;
goto out;
}
- bdrv_snapshot_load_tmp_by_id_or_name(bs[0], snapshot_name, &local_err);
+ bdrv_snapshot_load_tmp_by_id_or_name(blk_bs(s.src[0]), snapshot_name,
+ &local_err);
}
if (local_err) {
error_reportf_err(local_err, "Failed to load snapshot: ");
@@ -2211,7 +2159,7 @@ static int img_convert(int argc, char **argv)
}
}
- qemu_opt_set_number(opts, BLOCK_OPT_SIZE, total_sectors * 512,
+ qemu_opt_set_number(opts, BLOCK_OPT_SIZE, s.total_sectors * 512,
&error_abort);
ret = add_old_style_options(out_fmt, opts, out_baseimg, NULL);
if (ret < 0) {
@@ -2224,9 +2172,17 @@ static int img_convert(int argc, char **argv)
if (out_baseimg_param) {
out_baseimg = out_baseimg_param;
}
+ s.target_has_backing = (bool) out_baseimg;
+
+ if (s.src_num > 1 && out_baseimg) {
+ error_report("Having a backing file for the target makes no sense when "
+ "concatenating multiple input images");
+ ret = -1;
+ goto out;
+ }
/* Check if compression is supported */
- if (compress) {
+ if (s.compressed) {
bool encryption =
qemu_opt_get_bool(opts, BLOCK_OPT_ENCRYPT, false);
const char *preallocation =
@@ -2265,7 +2221,7 @@ static int img_convert(int argc, char **argv)
}
}
- flags = min_sparse ? (BDRV_O_RDWR | BDRV_O_UNMAP) : BDRV_O_RDWR;
+ flags = s.min_sparse ? (BDRV_O_RDWR | BDRV_O_UNMAP) : BDRV_O_RDWR;
ret = bdrv_parse_cache_mode(cache, &flags, &writethrough);
if (ret < 0) {
error_report("Invalid cache option: %s", cache);
@@ -2277,64 +2233,48 @@ static int img_convert(int argc, char **argv)
* the bdrv_create() call which takes different params.
* Not critical right now, so fix can wait...
*/
- out_blk = img_open_file(out_filename, out_fmt, flags, writethrough, quiet);
- if (!out_blk) {
+ s.target = img_open_file(out_filename, out_fmt, flags, writethrough, quiet);
+ if (!s.target) {
ret = -1;
goto out;
}
- out_bs = blk_bs(out_blk);
+ out_bs = blk_bs(s.target);
/* increase bufsectors from the default 4096 (2M) if opt_transfer
* or discard_alignment of the out_bs is greater. Limit to 32768 (16MB)
* as maximum. */
- bufsectors = MIN(32768,
- MAX(bufsectors,
- MAX(out_bs->bl.opt_transfer >> BDRV_SECTOR_BITS,
- out_bs->bl.pdiscard_alignment >>
- BDRV_SECTOR_BITS)));
+ s.buf_sectors = MIN(32768,
+ MAX(s.buf_sectors,
+ MAX(out_bs->bl.opt_transfer >> BDRV_SECTOR_BITS,
+ out_bs->bl.pdiscard_alignment >>
+ BDRV_SECTOR_BITS)));
if (skip_create) {
- int64_t output_sectors = blk_nb_sectors(out_blk);
+ int64_t output_sectors = blk_nb_sectors(s.target);
if (output_sectors < 0) {
error_report("unable to get output image length: %s",
strerror(-output_sectors));
ret = -1;
goto out;
- } else if (output_sectors < total_sectors) {
+ } else if (output_sectors < s.total_sectors) {
error_report("output file is smaller than input file");
ret = -1;
goto out;
}
}
- cluster_sectors = 0;
ret = bdrv_get_info(out_bs, &bdi);
if (ret < 0) {
- if (compress) {
+ if (s.compressed) {
error_report("could not get block driver info");
goto out;
}
} else {
- compress = compress || bdi.needs_compressed_writes;
- cluster_sectors = bdi.cluster_size / BDRV_SECTOR_SIZE;
- }
-
- state = (ImgConvertState) {
- .src = blk,
- .src_sectors = bs_sectors,
- .src_num = bs_n,
- .total_sectors = total_sectors,
- .target = out_blk,
- .compressed = compress,
- .target_has_backing = (bool) out_baseimg,
- .min_sparse = min_sparse,
- .cluster_sectors = cluster_sectors,
- .buf_sectors = bufsectors,
- .wr_in_order = wr_in_order,
- .num_coroutines = num_coroutines,
- };
- ret = convert_do_copy(&state);
+ s.compressed = s.compressed || bdi.needs_compressed_writes;
+ s.cluster_sectors = bdi.cluster_size / BDRV_SECTOR_SIZE;
+ }
+ ret = convert_do_copy(&s);
out:
if (!ret) {
qemu_progress_print(100, 0);
@@ -2343,22 +2283,18 @@ out:
qemu_opts_del(opts);
qemu_opts_free(create_opts);
qemu_opts_del(sn_opts);
- blk_unref(out_blk);
- g_free(bs);
- if (blk) {
- for (bs_i = 0; bs_i < bs_n; bs_i++) {
- blk_unref(blk[bs_i]);
+ blk_unref(s.target);
+ if (s.src) {
+ for (bs_i = 0; bs_i < s.src_num; bs_i++) {
+ blk_unref(s.src[bs_i]);
}
- g_free(blk);
+ g_free(s.src);
}
- g_free(bs_sectors);
+ g_free(s.src_sectors);
fail_getopt:
g_free(options);
- if (ret) {
- return 1;
- }
- return 0;
+ return !!ret;
}
@@ -3500,20 +3436,11 @@ static int img_resize(int argc, char **argv)
goto out;
}
- ret = blk_truncate(blk, total_size);
- switch (ret) {
- case 0:
+ ret = blk_truncate(blk, total_size, &err);
+ if (!ret) {
qprintf(quiet, "Image resized.\n");
- break;
- case -ENOTSUP:
- error_report("This image does not support resize");
- break;
- case -EACCES:
- error_report("Image is read-only");
- break;
- default:
- error_report("Error resizing image: %s", strerror(-ret));
- break;
+ } else {
+ error_report_err(err);
}
out:
blk_unref(blk);
diff --git a/qemu-img.texi b/qemu-img.texi
index c81db3e..50a2364 100644
--- a/qemu-img.texi
+++ b/qemu-img.texi
@@ -84,7 +84,8 @@ with or without a command shows help and lists the supported formats
@item -p
display progress bar (compare, convert and rebase commands only).
If the @var{-p} option is not used for a command that supports it, the
-progress is reported when the process receives a @code{SIGUSR1} signal.
+progress is reported when the process receives a @code{SIGUSR1} or
+@code{SIGINFO} signal.
@item -q
Quiet mode - do not print any output (except errors). There's no progress bar
in case both @var{-q} and @var{-p} options are used.
@@ -224,7 +225,7 @@ If @code{-r} is specified, exit codes representing the image state refer to the
state after (the attempt at) repairing it. That is, a successful @code{-r all}
will yield the exit code 0, independently of the image state before.
-@item create [-f @var{fmt}] [-o @var{options}] @var{filename} [@var{size}]
+@item create [-f @var{fmt}] [-b @var{backing_file}] [-F @var{backing_fmt}] [-o @var{options}] @var{filename} [@var{size}]
Create the new disk image @var{filename} of size @var{size} and format
@var{fmt}. Depending on the file format, you can add one or more @var{options}
@@ -302,7 +303,7 @@ Error on reading data
@end table
-@item convert [-c] [-p] [-n] [-f @var{fmt}] [-t @var{cache}] [-T @var{src_cache}] [-O @var{output_fmt}] [-o @var{options}] [-s @var{snapshot_id_or_name}] [-l @var{snapshot_param}] [-m @var{num_coroutines}] [-W] [-S @var{sparse_size}] @var{filename} [@var{filename2} [...]] @var{output_filename}
+@item convert [-c] [-p] [-n] [-f @var{fmt}] [-t @var{cache}] [-T @var{src_cache}] [-O @var{output_fmt}] [-B @var{backing_file}] [-o @var{options}] [-s @var{snapshot_id_or_name}] [-l @var{snapshot_param}] [-m @var{num_coroutines}] [-W] [-S @var{sparse_size}] @var{filename} [@var{filename2} [...]] @var{output_filename}
Convert the disk image @var{filename} or a snapshot @var{snapshot_param}(@var{snapshot_id_or_name} is deprecated)
to disk image @var{output_filename} using format @var{output_fmt}. It can be optionally compressed (@code{-c}
diff --git a/qemu-io-cmds.c b/qemu-io-cmds.c
index 312fc6d..21af9e6 100644
--- a/qemu-io-cmds.c
+++ b/qemu-io-cmds.c
@@ -1567,6 +1567,7 @@ static const cmdinfo_t flush_cmd = {
static int truncate_f(BlockBackend *blk, int argc, char **argv)
{
+ Error *local_err = NULL;
int64_t offset;
int ret;
@@ -1576,9 +1577,9 @@ static int truncate_f(BlockBackend *blk, int argc, char **argv)
return 0;
}
- ret = blk_truncate(blk, offset);
+ ret = blk_truncate(blk, offset, &local_err);
if (ret < 0) {
- printf("truncate: %s\n", strerror(-ret));
+ error_report_err(local_err);
return 0;
}
diff --git a/qemu-options.hx b/qemu-options.hx
index 787b9c3..f68829f 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -803,8 +803,8 @@ STEXI
Force hard disk 0 physical geometry (1 <= @var{c} <= 16383, 1 <=
@var{h} <= 16, 1 <= @var{s} <= 63) and optionally force the BIOS
translation mode (@var{t}=none, lba or auto). Usually QEMU can guess
-all those parameters. This option is useful for old MS-DOS disk
-images.
+all those parameters. This option is deprecated, please use
+@code{-device ide-hd,cyls=c,heads=h,secs=s,...} instead.
ETEXI
DEF("fsdev", HAS_ARG, QEMU_OPTION_fsdev,
diff --git a/qom/container.c b/qom/container.c
index c9eb49b..f6ccaf7 100644
--- a/qom/container.c
+++ b/qom/container.c
@@ -40,6 +40,7 @@ Object *container_get(Object *root, const char *path)
if (!child) {
child = object_new("container");
object_property_add_child(obj, parts[i], child, NULL);
+ object_unref(child);
}
}
diff --git a/replay/replay-snapshot.c b/replay/replay-snapshot.c
index 65e2d37..8cced46 100644
--- a/replay/replay-snapshot.c
+++ b/replay/replay-snapshot.c
@@ -64,7 +64,7 @@ void replay_vmstate_init(void)
{
if (replay_snapshot) {
if (replay_mode == REPLAY_MODE_RECORD) {
- if (save_vmstate(cur_mon, replay_snapshot) != 0) {
+ if (save_vmstate(replay_snapshot) != 0) {
error_report("Could not create snapshot for icount record");
exit(1);
}
diff --git a/scripts/tracetool/__init__.py b/scripts/tracetool/__init__.py
index 365446f..1ffbc1d 100644
--- a/scripts/tracetool/__init__.py
+++ b/scripts/tracetool/__init__.py
@@ -191,6 +191,10 @@ class Event(object):
self.event_trans = event_trans
self.event_exec = event_exec
+ if len(args) > 10:
+ raise ValueError("Event '%s' has more than maximum permitted "
+ "argument count" % name)
+
if orig is None:
self.original = weakref.ref(self)
else:
diff --git a/target/openrisc/cpu.c b/target/openrisc/cpu.c
index 7fd2b9a..1d6330c 100644
--- a/target/openrisc/cpu.c
+++ b/target/openrisc/cpu.c
@@ -51,8 +51,8 @@ static void openrisc_cpu_reset(CPUState *s)
cpu->env.lock_addr = -1;
s->exception_index = -1;
- cpu->env.upr = UPR_UP | UPR_DMP | UPR_IMP | UPR_PICP | UPR_TTP;
- cpu->env.cpucfgr = CPUCFGR_OB32S | CPUCFGR_OF32S;
+ cpu->env.upr = UPR_UP | UPR_DMP | UPR_IMP | UPR_PICP | UPR_TTP |
+ UPR_PMP;
cpu->env.dmmucfgr = (DMMUCFGR_NTW & (0 << 2)) | (DMMUCFGR_NTS & (6 << 2));
cpu->env.immucfgr = (IMMUCFGR_NTW & (0 << 2)) | (IMMUCFGR_NTS & (6 << 2));
@@ -65,12 +65,6 @@ static void openrisc_cpu_reset(CPUState *s)
#endif
}
-static inline void set_feature(OpenRISCCPU *cpu, int feature)
-{
- cpu->feature |= feature;
- cpu->env.cpucfgr = cpu->feature;
-}
-
static void openrisc_cpu_realizefn(DeviceState *dev, Error **errp)
{
CPUState *cs = CPU(dev);
@@ -132,15 +126,15 @@ static void or1200_initfn(Object *obj)
{
OpenRISCCPU *cpu = OPENRISC_CPU(obj);
- set_feature(cpu, OPENRISC_FEATURE_OB32S);
- set_feature(cpu, OPENRISC_FEATURE_OF32S);
+ cpu->env.cpucfgr = CPUCFGR_NSGF | CPUCFGR_OB32S | CPUCFGR_OF32S |
+ CPUCFGR_EVBARP;
}
static void openrisc_any_initfn(Object *obj)
{
OpenRISCCPU *cpu = OPENRISC_CPU(obj);
- set_feature(cpu, OPENRISC_FEATURE_OB32S);
+ cpu->env.cpucfgr = CPUCFGR_NSGF | CPUCFGR_OB32S | CPUCFGR_EVBARP;
}
typedef struct OpenRISCCPUInfo {
diff --git a/target/openrisc/cpu.h b/target/openrisc/cpu.h
index 418a0e6..2721432 100644
--- a/target/openrisc/cpu.h
+++ b/target/openrisc/cpu.h
@@ -111,6 +111,11 @@ enum {
CPUCFGR_OF32S = (1 << 7),
CPUCFGR_OF64S = (1 << 8),
CPUCFGR_OV64S = (1 << 9),
+ /* CPUCFGR_ND = (1 << 10), */
+ /* CPUCFGR_AVRP = (1 << 11), */
+ CPUCFGR_EVBARP = (1 << 12),
+ /* CPUCFGR_ISRP = (1 << 13), */
+ /* CPUCFGR_AECSRP = (1 << 14), */
};
/* DMMU configure register */
@@ -135,6 +140,15 @@ enum {
IMMUCFGR_HTR = (1 << 11),
};
+/* Power management register */
+enum {
+ PMR_SDF = (15 << 0),
+ PMR_DME = (1 << 4),
+ PMR_SME = (1 << 5),
+ PMR_DCGE = (1 << 6),
+ PMR_SUME = (1 << 7),
+};
+
/* Float point control status register */
enum {
FPCSR_FPEE = 1,
@@ -191,17 +205,6 @@ enum {
SR_SCE = (1 << 17),
};
-/* OpenRISC Hardware Capabilities */
-enum {
- OPENRISC_FEATURE_NSGF = (15 << 0),
- OPENRISC_FEATURE_CGF = (1 << 4),
- OPENRISC_FEATURE_OB32S = (1 << 5),
- OPENRISC_FEATURE_OB64S = (1 << 6),
- OPENRISC_FEATURE_OF32S = (1 << 7),
- OPENRISC_FEATURE_OF64S = (1 << 8),
- OPENRISC_FEATURE_OV64S = (1 << 9),
-};
-
/* Tick Timer Mode Register */
enum {
TTMR_TP = (0xfffffff),
@@ -269,7 +272,8 @@ typedef struct CPUOpenRISCTLBContext {
#endif
typedef struct CPUOpenRISCState {
- target_ulong gpr[32]; /* General registers */
+ target_ulong shadow_gpr[16][32]; /* Shadow registers */
+
target_ulong pc; /* Program counter */
target_ulong ppc; /* Prev PC */
target_ulong jmp_pc; /* Jump PC */
@@ -285,10 +289,11 @@ typedef struct CPUOpenRISCState {
uint32_t sr; /* Supervisor register, without SR_{F,CY,OV} */
uint32_t vr; /* Version register */
uint32_t upr; /* Unit presence register */
- uint32_t cpucfgr; /* CPU configure register */
uint32_t dmmucfgr; /* DMMU configure register */
uint32_t immucfgr; /* IMMU configure register */
uint32_t esr; /* Exception supervisor register */
+ uint32_t evbar; /* Exception vector base address register */
+ uint32_t pmr; /* Power Management Register */
uint32_t fpcsr; /* Float register */
float_status fp_status;
@@ -303,6 +308,8 @@ typedef struct CPUOpenRISCState {
CPU_COMMON
/* Fields from here on are preserved across CPU reset. */
+ uint32_t cpucfgr; /* CPU configure register */
+
#ifndef CONFIG_USER_ONLY
CPUOpenRISCTLBContext * tlb;
@@ -329,7 +336,6 @@ typedef struct OpenRISCCPU {
CPUOpenRISCState env;
- uint32_t feature; /* CPU Capabilities */
} OpenRISCCPU;
static inline OpenRISCCPU *openrisc_env_get_cpu(CPUOpenRISCState *env)
@@ -392,6 +398,16 @@ int cpu_openrisc_get_phys_data(OpenRISCCPU *cpu,
#define TB_FLAGS_R0_0 2
#define TB_FLAGS_OVE SR_OVE
+static inline uint32_t cpu_get_gpr(const CPUOpenRISCState *env, int i)
+{
+ return env->shadow_gpr[0][i];
+}
+
+static inline void cpu_set_gpr(CPUOpenRISCState *env, int i, uint32_t val)
+{
+ env->shadow_gpr[0][i] = val;
+}
+
static inline void cpu_get_tb_cpu_state(CPUOpenRISCState *env,
target_ulong *pc,
target_ulong *cs_base, uint32_t *flags)
@@ -399,7 +415,7 @@ static inline void cpu_get_tb_cpu_state(CPUOpenRISCState *env,
*pc = env->pc;
*cs_base = 0;
*flags = (env->dflag
- | (env->gpr[0] == 0 ? TB_FLAGS_R0_0 : 0)
+ | (cpu_get_gpr(env, 0) == 0 ? TB_FLAGS_R0_0 : 0)
| (env->sr & SR_OVE));
}
diff --git a/target/openrisc/gdbstub.c b/target/openrisc/gdbstub.c
index b18c7e9..f9af650 100644
--- a/target/openrisc/gdbstub.c
+++ b/target/openrisc/gdbstub.c
@@ -28,7 +28,7 @@ int openrisc_cpu_gdb_read_register(CPUState *cs, uint8_t *mem_buf, int n)
CPUOpenRISCState *env = &cpu->env;
if (n < 32) {
- return gdb_get_reg32(mem_buf, env->gpr[n]);
+ return gdb_get_reg32(mem_buf, cpu_get_gpr(env, n));
} else {
switch (n) {
case 32: /* PPC */
@@ -61,7 +61,7 @@ int openrisc_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n)
tmp = ldl_p(mem_buf);
if (n < 32) {
- env->gpr[n] = tmp;
+ cpu_set_gpr(env, n, tmp);
} else {
switch (n) {
case 32: /* PPC */
diff --git a/target/openrisc/interrupt.c b/target/openrisc/interrupt.c
index a2eec6f..3959671 100644
--- a/target/openrisc/interrupt.c
+++ b/target/openrisc/interrupt.c
@@ -60,12 +60,21 @@ void openrisc_cpu_do_interrupt(CPUState *cs)
env->sr |= SR_SM;
env->sr &= ~SR_IEE;
env->sr &= ~SR_TEE;
+ env->pmr &= ~PMR_DME;
+ env->pmr &= ~PMR_SME;
env->tlb->cpu_openrisc_map_address_data = &cpu_openrisc_get_phys_nommu;
env->tlb->cpu_openrisc_map_address_code = &cpu_openrisc_get_phys_nommu;
env->lock_addr = -1;
if (cs->exception_index > 0 && cs->exception_index < EXCP_NR) {
- env->pc = (cs->exception_index << 8);
+ hwaddr vect_pc = cs->exception_index << 8;
+ if (env->cpucfgr & CPUCFGR_EVBARP) {
+ vect_pc |= env->evbar;
+ }
+ if (env->sr & SR_EPH) {
+ vect_pc |= 0xf0000000;
+ }
+ env->pc = vect_pc;
} else {
cpu_abort(cs, "Unhandled exception 0x%x\n", cs->exception_index);
}
diff --git a/target/openrisc/machine.c b/target/openrisc/machine.c
index 686eaa3..a20cce7 100644
--- a/target/openrisc/machine.c
+++ b/target/openrisc/machine.c
@@ -24,6 +24,63 @@
#include "hw/boards.h"
#include "migration/cpu.h"
+static int env_post_load(void *opaque, int version_id)
+{
+ CPUOpenRISCState *env = opaque;
+
+ /* Restore MMU handlers */
+ if (env->sr & SR_DME) {
+ env->tlb->cpu_openrisc_map_address_data =
+ &cpu_openrisc_get_phys_data;
+ } else {
+ env->tlb->cpu_openrisc_map_address_data =
+ &cpu_openrisc_get_phys_nommu;
+ }
+
+ if (env->sr & SR_IME) {
+ env->tlb->cpu_openrisc_map_address_code =
+ &cpu_openrisc_get_phys_code;
+ } else {
+ env->tlb->cpu_openrisc_map_address_code =
+ &cpu_openrisc_get_phys_nommu;
+ }
+
+
+ return 0;
+}
+
+static const VMStateDescription vmstate_tlb_entry = {
+ .name = "tlb_entry",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .minimum_version_id_old = 1,
+ .fields = (VMStateField[]) {
+ VMSTATE_UINTTL(mr, OpenRISCTLBEntry),
+ VMSTATE_UINTTL(tr, OpenRISCTLBEntry),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static const VMStateDescription vmstate_cpu_tlb = {
+ .name = "cpu_tlb",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .minimum_version_id_old = 1,
+ .fields = (VMStateField[]) {
+ VMSTATE_STRUCT_2DARRAY(itlb, CPUOpenRISCTLBContext,
+ ITLB_WAYS, ITLB_SIZE, 0,
+ vmstate_tlb_entry, OpenRISCTLBEntry),
+ VMSTATE_STRUCT_2DARRAY(dtlb, CPUOpenRISCTLBContext,
+ DTLB_WAYS, DTLB_SIZE, 0,
+ vmstate_tlb_entry, OpenRISCTLBEntry),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+#define VMSTATE_CPU_TLB(_f, _s) \
+ VMSTATE_STRUCT_POINTER(_f, _s, vmstate_cpu_tlb, CPUOpenRISCTLBContext)
+
+
static int get_sr(QEMUFile *f, void *opaque, size_t size, VMStateField *field)
{
CPUOpenRISCState *env = opaque;
@@ -47,10 +104,11 @@ static const VMStateInfo vmstate_sr = {
static const VMStateDescription vmstate_env = {
.name = "env",
- .version_id = 4,
- .minimum_version_id = 4,
+ .version_id = 6,
+ .minimum_version_id = 6,
+ .post_load = env_post_load,
.fields = (VMStateField[]) {
- VMSTATE_UINTTL_ARRAY(gpr, CPUOpenRISCState, 32),
+ VMSTATE_UINTTL_2DARRAY(shadow_gpr, CPUOpenRISCState, 16, 32),
VMSTATE_UINTTL(pc, CPUOpenRISCState),
VMSTATE_UINTTL(ppc, CPUOpenRISCState),
VMSTATE_UINTTL(jmp_pc, CPUOpenRISCState),
@@ -79,9 +137,21 @@ static const VMStateDescription vmstate_env = {
VMSTATE_UINT32(cpucfgr, CPUOpenRISCState),
VMSTATE_UINT32(dmmucfgr, CPUOpenRISCState),
VMSTATE_UINT32(immucfgr, CPUOpenRISCState),
+ VMSTATE_UINT32(evbar, CPUOpenRISCState),
+ VMSTATE_UINT32(pmr, CPUOpenRISCState),
VMSTATE_UINT32(esr, CPUOpenRISCState),
VMSTATE_UINT32(fpcsr, CPUOpenRISCState),
VMSTATE_UINT64(mac, CPUOpenRISCState),
+
+ VMSTATE_CPU_TLB(tlb, CPUOpenRISCState),
+
+ VMSTATE_TIMER_PTR(timer, CPUOpenRISCState),
+ VMSTATE_UINT32(ttmr, CPUOpenRISCState),
+ VMSTATE_UINT32(ttcr, CPUOpenRISCState),
+
+ VMSTATE_UINT32(picmr, CPUOpenRISCState),
+ VMSTATE_UINT32(picsr, CPUOpenRISCState),
+
VMSTATE_END_OF_LIST()
}
};
diff --git a/target/openrisc/mmu.c b/target/openrisc/mmu.c
index 56b11d3..ce2a29d 100644
--- a/target/openrisc/mmu.c
+++ b/target/openrisc/mmu.c
@@ -124,7 +124,7 @@ static int cpu_openrisc_get_phys_addr(OpenRISCCPU *cpu,
{
int ret = TLBRET_MATCH;
- if (rw == 2) { /* ITLB */
+ if (rw == MMU_INST_FETCH) { /* ITLB */
*physical = 0;
ret = cpu->env.tlb->cpu_openrisc_map_address_code(cpu, physical,
prot, address, rw);
@@ -221,12 +221,28 @@ hwaddr openrisc_cpu_get_phys_page_debug(CPUState *cs, vaddr addr)
OpenRISCCPU *cpu = OPENRISC_CPU(cs);
hwaddr phys_addr;
int prot;
+ int miss;
- if (cpu_openrisc_get_phys_addr(cpu, &phys_addr, &prot, addr, 0)) {
- return -1;
+ /* Check memory for any kind of address, since during debug the
+ gdb can ask for anything, check data tlb for address */
+ miss = cpu_openrisc_get_phys_addr(cpu, &phys_addr, &prot, addr, 0);
+
+ /* Check instruction tlb */
+ if (miss) {
+ miss = cpu_openrisc_get_phys_addr(cpu, &phys_addr, &prot, addr,
+ MMU_INST_FETCH);
+ }
+
+ /* Last, fall back to a plain address */
+ if (miss) {
+ miss = cpu_openrisc_get_phys_nommu(cpu, &phys_addr, &prot, addr, 0);
}
- return phys_addr;
+ if (miss) {
+ return -1;
+ } else {
+ return phys_addr;
+ }
}
void cpu_openrisc_mmu_init(OpenRISCCPU *cpu)
diff --git a/target/openrisc/sys_helper.c b/target/openrisc/sys_helper.c
index 60c3193..abdef5d 100644
--- a/target/openrisc/sys_helper.c
+++ b/target/openrisc/sys_helper.c
@@ -22,6 +22,7 @@
#include "cpu.h"
#include "exec/exec-all.h"
#include "exec/helper-proto.h"
+#include "exception.h"
#define TO_SPR(group, number) (((group) << 11) + (number))
@@ -39,6 +40,10 @@ void HELPER(mtspr)(CPUOpenRISCState *env,
env->vr = rb;
break;
+ case TO_SPR(0, 11): /* EVBAR */
+ env->evbar = rb;
+ break;
+
case TO_SPR(0, 16): /* NPC */
cpu_restore_state(cs, GETPC());
/* ??? Mirror or1ksim in not trashing delayed branch state
@@ -88,6 +93,11 @@ void HELPER(mtspr)(CPUOpenRISCState *env,
case TO_SPR(0, 64): /* ESR */
env->esr = rb;
break;
+
+ case TO_SPR(0, 1024) ... TO_SPR(0, 1024 + (16 * 32)): /* Shadow GPRs */
+ idx = (spr - 1024);
+ env->shadow_gpr[idx / 32][idx % 32] = rb;
+
case TO_SPR(1, 512) ... TO_SPR(1, 512+DTLB_SIZE-1): /* DTLBW0MR 0-127 */
idx = spr - TO_SPR(1, 512);
if (!(rb & 1)) {
@@ -132,6 +142,15 @@ void HELPER(mtspr)(CPUOpenRISCState *env,
case TO_SPR(5, 2): /* MACHI */
env->mac = deposit64(env->mac, 32, 32, rb);
break;
+ case TO_SPR(8, 0): /* PMR */
+ env->pmr = rb;
+ if (env->pmr & PMR_DME || env->pmr & PMR_SME) {
+ cpu_restore_state(cs, GETPC());
+ env->pc += 4;
+ cs->halted = 1;
+ raise_exception(cpu, EXCP_HALTED);
+ }
+ break;
case TO_SPR(9, 0): /* PICMR */
env->picmr |= rb;
break;
@@ -206,6 +225,9 @@ target_ulong HELPER(mfspr)(CPUOpenRISCState *env,
case TO_SPR(0, 4): /* IMMUCFGR */
return env->immucfgr;
+ case TO_SPR(0, 11): /* EVBAR */
+ return env->evbar;
+
case TO_SPR(0, 16): /* NPC (equals PC) */
cpu_restore_state(cs, GETPC());
return env->pc;
@@ -226,6 +248,16 @@ target_ulong HELPER(mfspr)(CPUOpenRISCState *env,
case TO_SPR(0, 64): /* ESR */
return env->esr;
+ case TO_SPR(0, 128): /* COREID */
+ return 0;
+
+ case TO_SPR(0, 129): /* NUMCORES */
+ return 1;
+
+ case TO_SPR(0, 1024) ... TO_SPR(0, 1024 + (16 * 32)): /* Shadow GPRs */
+ idx = (spr - 1024);
+ return env->shadow_gpr[idx / 32][idx % 32];
+
case TO_SPR(1, 512) ... TO_SPR(1, 512+DTLB_SIZE-1): /* DTLBW0MR 0-127 */
idx = spr - TO_SPR(1, 512);
return env->tlb->dtlb[0][idx].mr;
@@ -265,6 +297,9 @@ target_ulong HELPER(mfspr)(CPUOpenRISCState *env,
return env->mac >> 32;
break;
+ case TO_SPR(8, 0): /* PMR */
+ return env->pmr;
+
case TO_SPR(9, 0): /* PICMR */
return env->picmr;
diff --git a/target/openrisc/translate.c b/target/openrisc/translate.c
index 7c4cbf2..e49518e 100644
--- a/target/openrisc/translate.c
+++ b/target/openrisc/translate.c
@@ -107,7 +107,8 @@ void openrisc_translate_init(void)
"mac");
for (i = 0; i < 32; i++) {
cpu_R[i] = tcg_global_mem_new(cpu_env,
- offsetof(CPUOpenRISCState, gpr[i]),
+ offsetof(CPUOpenRISCState,
+ shadow_gpr[0][i]),
regnames[i]);
}
cpu_R0 = cpu_R[0];
@@ -1662,7 +1663,7 @@ void openrisc_cpu_dump_state(CPUState *cs, FILE *f,
cpu_fprintf(f, "PC=%08x\n", env->pc);
for (i = 0; i < 32; ++i) {
- cpu_fprintf(f, "R%02d=%08x%c", i, env->gpr[i],
+ cpu_fprintf(f, "R%02d=%08x%c", i, cpu_get_gpr(env, i),
(i % 4) == 3 ? '\n' : ' ');
}
}
diff --git a/tests/qemu-iotests/026 b/tests/qemu-iotests/026
index f5a7f02..7fadfba 100755
--- a/tests/qemu-iotests/026
+++ b/tests/qemu-iotests/026
@@ -119,7 +119,7 @@ done
echo
-echo === Refcout table growth tests ===
+echo === Refcount table growth tests ===
echo
CLUSTER_SIZE=512
diff --git a/tests/qemu-iotests/026.out b/tests/qemu-iotests/026.out
index 59b8f74..86a50a2 100644
--- a/tests/qemu-iotests/026.out
+++ b/tests/qemu-iotests/026.out
@@ -462,7 +462,7 @@ Event: cluster_alloc; errno: 28; imm: off; once: off; write -b
write failed: No space left on device
No errors were found on the image.
-=== Refcout table growth tests ===
+=== Refcount table growth tests ===
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
diff --git a/tests/qemu-iotests/026.out.nocache b/tests/qemu-iotests/026.out.nocache
index b4aeebc..ea2e166 100644
--- a/tests/qemu-iotests/026.out.nocache
+++ b/tests/qemu-iotests/026.out.nocache
@@ -470,7 +470,7 @@ Event: cluster_alloc; errno: 28; imm: off; once: off; write -b
write failed: No space left on device
No errors were found on the image.
-=== Refcout table growth tests ===
+=== Refcount table growth tests ===
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
diff --git a/tests/qemu-iotests/028.out b/tests/qemu-iotests/028.out
index acd2870..7d54aeb 100644
--- a/tests/qemu-iotests/028.out
+++ b/tests/qemu-iotests/028.out
@@ -469,7 +469,7 @@ No errors were found on the image.
block-backup
Formatting 'TEST_DIR/t.IMGFMT.copy', fmt=IMGFMT size=4294968832 backing_file=TEST_DIR/t.IMGFMT.base backing_fmt=IMGFMT
-(qemu) iininfinfoinfo info binfo blinfo bloinfo blocinfo blockinfo block-info block-jinfo block-joinfo block-jobinfo block-jobs
+(qemu) info block-jobs
No active jobs
=== IO: pattern 195
read 512/512 bytes at offset 3221194240
diff --git a/tests/qemu-iotests/051 b/tests/qemu-iotests/051
index 630cb7a..26c29de 100755
--- a/tests/qemu-iotests/051
+++ b/tests/qemu-iotests/051
@@ -60,7 +60,8 @@ function do_run_qemu()
function run_qemu()
{
- do_run_qemu "$@" 2>&1 | _filter_testdir | _filter_qemu | _filter_generated_node_ids
+ do_run_qemu "$@" 2>&1 | _filter_testdir | _filter_qemu |
+ _filter_generated_node_ids | _filter_hmp
}
size=128M
@@ -231,6 +232,7 @@ echo === Leaving out required options ===
echo
run_qemu -drive driver=file
+run_qemu -drive driver=file,filename=
run_qemu -drive driver=nbd
run_qemu -drive driver=raw
run_qemu -drive file.driver=file
diff --git a/tests/qemu-iotests/051.out b/tests/qemu-iotests/051.out
index 7524c62..4d3b1ff 100644
--- a/tests/qemu-iotests/051.out
+++ b/tests/qemu-iotests/051.out
@@ -58,12 +58,12 @@ QEMU X.Y.Z monitor - type 'help' for more information
Testing: -drive file=TEST_DIR/t.qcow2,driver=qcow2,backing.file.filename=TEST_DIR/t.qcow2.orig,if=none,id=drive0 -nodefaults
QEMU X.Y.Z monitor - type 'help' for more information
-(qemu) iininfinfoinfo info binfo blinfo bloinfo blocinfo block
+(qemu) info block
drive0 (NODE_NAME): TEST_DIR/t.qcow2 (qcow2)
Removable device: not locked, tray closed
Cache mode: writeback
Backing file: TEST_DIR/t.qcow2.orig (chain depth: 1)
-(qemu) qququiquit
+(qemu) quit
Testing: -drive file=TEST_DIR/t.qcow2,driver=raw,backing.file.filename=TEST_DIR/t.qcow2.orig
QEMU_PROG: -drive file=TEST_DIR/t.qcow2,driver=raw,backing.file.filename=TEST_DIR/t.qcow2.orig: Driver doesn't support backing files
@@ -79,11 +79,11 @@ QEMU_PROG: -drive file=TEST_DIR/t.qcow2,file.backing.driver=qcow2,file.backing.f
Testing: -drive file=TEST_DIR/t.qcow2,format=qcow2,lazy-refcounts=on
QEMU X.Y.Z monitor - type 'help' for more information
-(qemu) qququiquit
+(qemu) quit
Testing: -drive file=TEST_DIR/t.qcow2,format=qcow2,lazy-refcounts=off
QEMU X.Y.Z monitor - type 'help' for more information
-(qemu) qququiquit
+(qemu) quit
Testing: -drive file=TEST_DIR/t.qcow2,format=qcow2,lazy-refcounts=
QEMU_PROG: -drive file=TEST_DIR/t.qcow2,format=qcow2,lazy-refcounts=: Parameter 'lazy-refcounts' expects 'on' or 'off'
@@ -103,7 +103,7 @@ QEMU_PROG: -drive file=TEST_DIR/t.qcow2,format=qcow2,lazy-refcounts=on: Lazy ref
Testing: -drive file=TEST_DIR/t.qcow2,format=qcow2,lazy-refcounts=off
QEMU X.Y.Z monitor - type 'help' for more information
-(qemu) qququiquit
+(qemu) quit
=== No medium ===
@@ -117,93 +117,93 @@ QEMU X.Y.Z monitor - type 'help' for more information
Testing: -drive file=TEST_DIR/t.qcow2,if=virtio,readonly=on
QEMU X.Y.Z monitor - type 'help' for more information
-(qemu) qququiquit
+(qemu) quit
=== Cache modes ===
Testing: -drive driver=null-co,cache=none
QEMU X.Y.Z monitor - type 'help' for more information
-(qemu) qququiquit
+(qemu) quit
Testing: -drive driver=null-co,cache=directsync
QEMU X.Y.Z monitor - type 'help' for more information
-(qemu) qququiquit
+(qemu) quit
Testing: -drive driver=null-co,cache=writeback
QEMU X.Y.Z monitor - type 'help' for more information
-(qemu) qququiquit
+(qemu) quit
Testing: -drive driver=null-co,cache=writethrough
QEMU X.Y.Z monitor - type 'help' for more information
-(qemu) qququiquit
+(qemu) quit
Testing: -drive driver=null-co,cache=unsafe
QEMU X.Y.Z monitor - type 'help' for more information
-(qemu) qququiquit
+(qemu) quit
Testing: -drive driver=null-co,cache=invalid_value
QEMU_PROG: -drive driver=null-co,cache=invalid_value: invalid cache option
Testing: -drive file=TEST_DIR/t.qcow2,cache=writeback,backing.file.filename=TEST_DIR/t.qcow2.base,backing.cache.no-flush=on,backing.node-name=backing,backing.file.node-name=backing-file,file.node-name=file,if=none,id=drive0 -nodefaults
QEMU X.Y.Z monitor - type 'help' for more information
-(qemu) iininfinfoinfo info binfo blinfo bloinfo blocinfo block
+(qemu) info block
drive0 (NODE_NAME): TEST_DIR/t.qcow2 (qcow2)
Removable device: not locked, tray closed
Cache mode: writeback
Backing file: TEST_DIR/t.qcow2.base (chain depth: 1)
-(qemu) iininfinfoinfo info binfo blinfo bloinfo blocinfo blockinfo block info block finfo block fiinfo block filinfo block file
+(qemu) info block file
file: TEST_DIR/t.qcow2 (file)
Cache mode: writeback
-(qemu) iininfinfoinfo info binfo blinfo bloinfo blocinfo blockinfo block info block binfo block bainfo block bacinfo block backinfo block backiinfo block backininfo block backing
+(qemu) info block backing
backing: TEST_DIR/t.qcow2.base (qcow2, read-only)
Cache mode: writeback, ignore flushes
-(qemu) iininfinfoinfo info binfo blinfo bloinfo blocinfo blockinfo block info block binfo block bainfo block bacinfo block backinfo block backiinfo block backininfo block backinginfo block backing-info block backing-finfo block backing-fiinfo block backing-filinfo block backing-file
+(qemu) info block backing-file
backing-file: TEST_DIR/t.qcow2.base (file, read-only)
Cache mode: writeback, ignore flushes
-(qemu) qququiquit
+(qemu) quit
Testing: -drive file=TEST_DIR/t.qcow2,cache=writethrough,backing.file.filename=TEST_DIR/t.qcow2.base,backing.cache.no-flush=on,backing.node-name=backing,backing.file.node-name=backing-file,file.node-name=file,if=none,id=drive0 -nodefaults
QEMU X.Y.Z monitor - type 'help' for more information
-(qemu) iininfinfoinfo info binfo blinfo bloinfo blocinfo block
+(qemu) info block
drive0 (NODE_NAME): TEST_DIR/t.qcow2 (qcow2)
Removable device: not locked, tray closed
Cache mode: writethrough
Backing file: TEST_DIR/t.qcow2.base (chain depth: 1)
-(qemu) iininfinfoinfo info binfo blinfo bloinfo blocinfo blockinfo block info block finfo block fiinfo block filinfo block file
+(qemu) info block file
file: TEST_DIR/t.qcow2 (file)
Cache mode: writeback
-(qemu) iininfinfoinfo info binfo blinfo bloinfo blocinfo blockinfo block info block binfo block bainfo block bacinfo block backinfo block backiinfo block backininfo block backing
+(qemu) info block backing
backing: TEST_DIR/t.qcow2.base (qcow2, read-only)
Cache mode: writeback, ignore flushes
-(qemu) iininfinfoinfo info binfo blinfo bloinfo blocinfo blockinfo block info block binfo block bainfo block bacinfo block backinfo block backiinfo block backininfo block backinginfo block backing-info block backing-finfo block backing-fiinfo block backing-filinfo block backing-file
+(qemu) info block backing-file
backing-file: TEST_DIR/t.qcow2.base (file, read-only)
Cache mode: writeback, ignore flushes
-(qemu) qququiquit
+(qemu) quit
Testing: -drive file=TEST_DIR/t.qcow2,cache=unsafe,backing.file.filename=TEST_DIR/t.qcow2.base,backing.cache.no-flush=on,backing.node-name=backing,backing.file.node-name=backing-file,file.node-name=file,if=none,id=drive0 -nodefaults
QEMU X.Y.Z monitor - type 'help' for more information
-(qemu) iininfinfoinfo info binfo blinfo bloinfo blocinfo block
+(qemu) info block
drive0 (NODE_NAME): TEST_DIR/t.qcow2 (qcow2)
Removable device: not locked, tray closed
Cache mode: writeback, ignore flushes
Backing file: TEST_DIR/t.qcow2.base (chain depth: 1)
-(qemu) iininfinfoinfo info binfo blinfo bloinfo blocinfo blockinfo block info block finfo block fiinfo block filinfo block file
+(qemu) info block file
file: TEST_DIR/t.qcow2 (file)
Cache mode: writeback, ignore flushes
-(qemu) iininfinfoinfo info binfo blinfo bloinfo blocinfo blockinfo block info block binfo block bainfo block bacinfo block backinfo block backiinfo block backininfo block backing
+(qemu) info block backing
backing: TEST_DIR/t.qcow2.base (qcow2, read-only)
Cache mode: writeback, ignore flushes
-(qemu) iininfinfoinfo info binfo blinfo bloinfo blocinfo blockinfo block info block binfo block bainfo block bacinfo block backinfo block backiinfo block backininfo block backinginfo block backing-info block backing-finfo block backing-fiinfo block backing-filinfo block backing-file
+(qemu) info block backing-file
backing-file: TEST_DIR/t.qcow2.base (file, read-only)
Cache mode: writeback, ignore flushes
-(qemu) qququiquit
+(qemu) quit
Testing: -drive file=TEST_DIR/t.qcow2,cache=invalid_value,backing.file.filename=TEST_DIR/t.qcow2.base,backing.cache.no-flush=on,backing.node-name=backing,backing.file.node-name=backing-file,file.node-name=file,if=none,id=drive0 -nodefaults
QEMU_PROG: -drive file=TEST_DIR/t.qcow2,cache=invalid_value,backing.file.filename=TEST_DIR/t.qcow2.base,backing.cache.no-flush=on,backing.node-name=backing,backing.file.node-name=backing-file,file.node-name=file,if=none,id=drive0: invalid cache option
@@ -213,7 +213,7 @@ QEMU_PROG: -drive file=TEST_DIR/t.qcow2,cache=invalid_value,backing.file.filenam
Testing: -drive file=TEST_DIR/t.qcow2,file.driver=file
QEMU X.Y.Z monitor - type 'help' for more information
-(qemu) qququiquit
+(qemu) quit
=== Leaving out required options ===
@@ -221,6 +221,9 @@ QEMU X.Y.Z monitor - type 'help' for more information
Testing: -drive driver=file
QEMU_PROG: -drive driver=file: The 'file' block driver requires a file name
+Testing: -drive driver=file,filename=
+QEMU_PROG: -drive driver=file,filename=: The 'file' block driver requires a file name
+
Testing: -drive driver=nbd
QEMU_PROG: -drive driver=nbd: NBD server address missing
@@ -307,15 +310,15 @@ QEMU_PROG: -drive file=TEST_DIR/t.qcow2,throttling.bps-total=-5: bps/iops/max va
Testing: -drive file=TEST_DIR/t.qcow2,bps=0
QEMU X.Y.Z monitor - type 'help' for more information
-(qemu) qququiquit
+(qemu) quit
Testing: -drive file=TEST_DIR/t.qcow2,bps=1
QEMU X.Y.Z monitor - type 'help' for more information
-(qemu) qququiquit
+(qemu) quit
Testing: -drive file=TEST_DIR/t.qcow2,bps=1000000000000000
QEMU X.Y.Z monitor - type 'help' for more information
-(qemu) qququiquit
+(qemu) quit
Testing: -drive file=TEST_DIR/t.qcow2,bps=1000000000000001
QEMU_PROG: -drive file=TEST_DIR/t.qcow2,bps=1000000000000001: bps/iops/max values must be within [0, 1000000000000000]
@@ -337,11 +340,11 @@ QEMU_PROG: -drive file.filename=foo:bar: Could not open 'foo:bar': No such file
Testing: -hda file:TEST_DIR/t.qcow2
QEMU X.Y.Z monitor - type 'help' for more information
-(qemu) qququiquit
+(qemu) quit
Testing: -drive file=file:TEST_DIR/t.qcow2
QEMU X.Y.Z monitor - type 'help' for more information
-(qemu) qququiquit
+(qemu) quit
Testing: -drive file.filename=file:TEST_DIR/t.qcow2
QEMU_PROG: -drive file.filename=file:TEST_DIR/t.qcow2: Could not open 'file:TEST_DIR/t.qcow2': No such file or directory
@@ -353,78 +356,78 @@ wrote 4096/4096 bytes at offset 0
4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
Testing: -drive file=TEST_DIR/t.qcow2,if=none,id=drive0 -snapshot
QEMU X.Y.Z monitor - type 'help' for more information
-(qemu) qqeqemqemuqemu-qemu-iqemu-ioqemu-io qemu-io dqemu-io drqemu-io driqemu-io drivqemu-io driveqemu-io drive0qemu-io drive0 qemu-io drive0 "qemu-io drive0 "wqemu-io drive0 "wrqemu-io drive0 "wriqemu-io drive0 "writqemu-io drive0 "writeqemu-io drive0 "write qemu-io drive0 "write -qemu-io drive0 "write -Pqemu-io drive0 "write -P qemu-io drive0 "write -P 0qemu-io drive0 "write -P 0xqemu-io drive0 "write -P 0x2qemu-io drive0 "write -P 0x22qemu-io drive0 "write -P 0x22 qemu-io drive0 "write -P 0x22 0qemu-io drive0 "write -P 0x22 0 qemu-io drive0 "write -P 0x22 0 4qemu-io drive0 "write -P 0x22 0 4kqemu-io drive0 "write -P 0x22 0 4k"
+(qemu) qemu-io drive0 "write -P 0x22 0 4k"
wrote 4096/4096 bytes at offset 0
4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
-(qemu) qququiquit
+(qemu) quit
Testing: -drive file=TEST_DIR/t.qcow2,snapshot=on,if=none,id=drive0
QEMU X.Y.Z monitor - type 'help' for more information
-(qemu) qqeqemqemuqemu-qemu-iqemu-ioqemu-io qemu-io dqemu-io drqemu-io driqemu-io drivqemu-io driveqemu-io drive0qemu-io drive0 qemu-io drive0 "qemu-io drive0 "wqemu-io drive0 "wrqemu-io drive0 "wriqemu-io drive0 "writqemu-io drive0 "writeqemu-io drive0 "write qemu-io drive0 "write -qemu-io drive0 "write -Pqemu-io drive0 "write -P qemu-io drive0 "write -P 0qemu-io drive0 "write -P 0xqemu-io drive0 "write -P 0x2qemu-io drive0 "write -P 0x22qemu-io drive0 "write -P 0x22 qemu-io drive0 "write -P 0x22 0qemu-io drive0 "write -P 0x22 0 qemu-io drive0 "write -P 0x22 0 4qemu-io drive0 "write -P 0x22 0 4kqemu-io drive0 "write -P 0x22 0 4k"
+(qemu) qemu-io drive0 "write -P 0x22 0 4k"
wrote 4096/4096 bytes at offset 0
4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
-(qemu) qququiquit
+(qemu) quit
Testing: -drive file.filename=TEST_DIR/t.qcow2,driver=qcow2,snapshot=on,if=none,id=drive0
QEMU X.Y.Z monitor - type 'help' for more information
-(qemu) qqeqemqemuqemu-qemu-iqemu-ioqemu-io qemu-io dqemu-io drqemu-io driqemu-io drivqemu-io driveqemu-io drive0qemu-io drive0 qemu-io drive0 "qemu-io drive0 "wqemu-io drive0 "wrqemu-io drive0 "wriqemu-io drive0 "writqemu-io drive0 "writeqemu-io drive0 "write qemu-io drive0 "write -qemu-io drive0 "write -Pqemu-io drive0 "write -P qemu-io drive0 "write -P 0qemu-io drive0 "write -P 0xqemu-io drive0 "write -P 0x2qemu-io drive0 "write -P 0x22qemu-io drive0 "write -P 0x22 qemu-io drive0 "write -P 0x22 0qemu-io drive0 "write -P 0x22 0 qemu-io drive0 "write -P 0x22 0 4qemu-io drive0 "write -P 0x22 0 4kqemu-io drive0 "write -P 0x22 0 4k"
+(qemu) qemu-io drive0 "write -P 0x22 0 4k"
wrote 4096/4096 bytes at offset 0
4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
-(qemu) qququiquit
+(qemu) quit
Testing: -drive file.filename=TEST_DIR/t.qcow2,driver=qcow2,if=none,id=drive0 -snapshot
QEMU X.Y.Z monitor - type 'help' for more information
-(qemu) qqeqemqemuqemu-qemu-iqemu-ioqemu-io qemu-io dqemu-io drqemu-io driqemu-io drivqemu-io driveqemu-io drive0qemu-io drive0 qemu-io drive0 "qemu-io drive0 "wqemu-io drive0 "wrqemu-io drive0 "wriqemu-io drive0 "writqemu-io drive0 "writeqemu-io drive0 "write qemu-io drive0 "write -qemu-io drive0 "write -Pqemu-io drive0 "write -P qemu-io drive0 "write -P 0qemu-io drive0 "write -P 0xqemu-io drive0 "write -P 0x2qemu-io drive0 "write -P 0x22qemu-io drive0 "write -P 0x22 qemu-io drive0 "write -P 0x22 0qemu-io drive0 "write -P 0x22 0 qemu-io drive0 "write -P 0x22 0 4qemu-io drive0 "write -P 0x22 0 4kqemu-io drive0 "write -P 0x22 0 4k"
+(qemu) qemu-io drive0 "write -P 0x22 0 4k"
wrote 4096/4096 bytes at offset 0
4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
-(qemu) qququiquit
+(qemu) quit
Testing: -drive file=file:TEST_DIR/t.qcow2,if=none,id=drive0 -snapshot
QEMU X.Y.Z monitor - type 'help' for more information
-(qemu) qqeqemqemuqemu-qemu-iqemu-ioqemu-io qemu-io dqemu-io drqemu-io driqemu-io drivqemu-io driveqemu-io drive0qemu-io drive0 qemu-io drive0 "qemu-io drive0 "wqemu-io drive0 "wrqemu-io drive0 "wriqemu-io drive0 "writqemu-io drive0 "writeqemu-io drive0 "write qemu-io drive0 "write -qemu-io drive0 "write -Pqemu-io drive0 "write -P qemu-io drive0 "write -P 0qemu-io drive0 "write -P 0xqemu-io drive0 "write -P 0x2qemu-io drive0 "write -P 0x22qemu-io drive0 "write -P 0x22 qemu-io drive0 "write -P 0x22 0qemu-io drive0 "write -P 0x22 0 qemu-io drive0 "write -P 0x22 0 4qemu-io drive0 "write -P 0x22 0 4kqemu-io drive0 "write -P 0x22 0 4k"
+(qemu) qemu-io drive0 "write -P 0x22 0 4k"
wrote 4096/4096 bytes at offset 0
4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
-(qemu) qququiquit
+(qemu) quit
Testing: -drive file=file:TEST_DIR/t.qcow2,snapshot=on,if=none,id=drive0
QEMU X.Y.Z monitor - type 'help' for more information
-(qemu) qqeqemqemuqemu-qemu-iqemu-ioqemu-io qemu-io dqemu-io drqemu-io driqemu-io drivqemu-io driveqemu-io drive0qemu-io drive0 qemu-io drive0 "qemu-io drive0 "wqemu-io drive0 "wrqemu-io drive0 "wriqemu-io drive0 "writqemu-io drive0 "writeqemu-io drive0 "write qemu-io drive0 "write -qemu-io drive0 "write -Pqemu-io drive0 "write -P qemu-io drive0 "write -P 0qemu-io drive0 "write -P 0xqemu-io drive0 "write -P 0x2qemu-io drive0 "write -P 0x22qemu-io drive0 "write -P 0x22 qemu-io drive0 "write -P 0x22 0qemu-io drive0 "write -P 0x22 0 qemu-io drive0 "write -P 0x22 0 4qemu-io drive0 "write -P 0x22 0 4kqemu-io drive0 "write -P 0x22 0 4k"
+(qemu) qemu-io drive0 "write -P 0x22 0 4k"
wrote 4096/4096 bytes at offset 0
4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
-(qemu) qququiquit
+(qemu) quit
Testing: -drive file=TEST_DIR/t.qcow2,if=none,id=drive0 -snapshot
QEMU X.Y.Z monitor - type 'help' for more information
-(qemu) qqeqemqemuqemu-qemu-iqemu-ioqemu-io qemu-io dqemu-io drqemu-io driqemu-io drivqemu-io driveqemu-io drive0qemu-io drive0 qemu-io drive0 "qemu-io drive0 "wqemu-io drive0 "wrqemu-io drive0 "wriqemu-io drive0 "writqemu-io drive0 "writeqemu-io drive0 "write qemu-io drive0 "write -qemu-io drive0 "write -Pqemu-io drive0 "write -P qemu-io drive0 "write -P 0qemu-io drive0 "write -P 0xqemu-io drive0 "write -P 0x2qemu-io drive0 "write -P 0x22qemu-io drive0 "write -P 0x22 qemu-io drive0 "write -P 0x22 0qemu-io drive0 "write -P 0x22 0 qemu-io drive0 "write -P 0x22 0 4qemu-io drive0 "write -P 0x22 0 4kqemu-io drive0 "write -P 0x22 0 4k"
+(qemu) qemu-io drive0 "write -P 0x22 0 4k"
wrote 4096/4096 bytes at offset 0
4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
-(qemu) qququiquit
+(qemu) quit
Testing: -drive file=TEST_DIR/t.qcow2,snapshot=on,if=none,id=drive0
QEMU X.Y.Z monitor - type 'help' for more information
-(qemu) qqeqemqemuqemu-qemu-iqemu-ioqemu-io qemu-io dqemu-io drqemu-io driqemu-io drivqemu-io driveqemu-io drive0qemu-io drive0 qemu-io drive0 "qemu-io drive0 "wqemu-io drive0 "wrqemu-io drive0 "wriqemu-io drive0 "writqemu-io drive0 "writeqemu-io drive0 "write qemu-io drive0 "write -qemu-io drive0 "write -Pqemu-io drive0 "write -P qemu-io drive0 "write -P 0qemu-io drive0 "write -P 0xqemu-io drive0 "write -P 0x2qemu-io drive0 "write -P 0x22qemu-io drive0 "write -P 0x22 qemu-io drive0 "write -P 0x22 0qemu-io drive0 "write -P 0x22 0 qemu-io drive0 "write -P 0x22 0 4qemu-io drive0 "write -P 0x22 0 4kqemu-io drive0 "write -P 0x22 0 4k"
+(qemu) qemu-io drive0 "write -P 0x22 0 4k"
wrote 4096/4096 bytes at offset 0
4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
-(qemu) qququiquit
+(qemu) quit
read 4096/4096 bytes at offset 0
4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
Testing: -drive file=TEST_DIR/t.qcow2,snapshot=off,if=none,id=drive0
QEMU X.Y.Z monitor - type 'help' for more information
-(qemu) qqeqemqemuqemu-qemu-iqemu-ioqemu-io qemu-io dqemu-io drqemu-io driqemu-io drivqemu-io driveqemu-io drive0qemu-io drive0 qemu-io drive0 "qemu-io drive0 "wqemu-io drive0 "wrqemu-io drive0 "wriqemu-io drive0 "writqemu-io drive0 "writeqemu-io drive0 "write qemu-io drive0 "write -qemu-io drive0 "write -Pqemu-io drive0 "write -P qemu-io drive0 "write -P 0qemu-io drive0 "write -P 0xqemu-io drive0 "write -P 0x2qemu-io drive0 "write -P 0x22qemu-io drive0 "write -P 0x22 qemu-io drive0 "write -P 0x22 0qemu-io drive0 "write -P 0x22 0 qemu-io drive0 "write -P 0x22 0 4qemu-io drive0 "write -P 0x22 0 4kqemu-io drive0 "write -P 0x22 0 4k"
+(qemu) qemu-io drive0 "write -P 0x22 0 4k"
wrote 4096/4096 bytes at offset 0
4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
-(qemu) qququiquit
+(qemu) quit
read 4096/4096 bytes at offset 0
4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
Testing: -drive file=TEST_DIR/t.qcow2,snapshot=on,if=none,id=drive0
QEMU X.Y.Z monitor - type 'help' for more information
-(qemu) qqeqemqemuqemu-qemu-iqemu-ioqemu-io qemu-io dqemu-io drqemu-io driqemu-io drivqemu-io driveqemu-io drive0qemu-io drive0 qemu-io drive0 "qemu-io drive0 "wqemu-io drive0 "wrqemu-io drive0 "wriqemu-io drive0 "writqemu-io drive0 "writeqemu-io drive0 "write qemu-io drive0 "write -qemu-io drive0 "write -Pqemu-io drive0 "write -P qemu-io drive0 "write -P 0qemu-io drive0 "write -P 0xqemu-io drive0 "write -P 0x3qemu-io drive0 "write -P 0x33qemu-io drive0 "write -P 0x33 qemu-io drive0 "write -P 0x33 0qemu-io drive0 "write -P 0x33 0 qemu-io drive0 "write -P 0x33 0 4qemu-io drive0 "write -P 0x33 0 4kqemu-io drive0 "write -P 0x33 0 4k"
+(qemu) qemu-io drive0 "write -P 0x33 0 4k"
wrote 4096/4096 bytes at offset 0
4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
-(qemu) ccocomcommcommicommitcommit commit dcommit drcommit dricommit drivcommit drivecommit drive0
-(qemu) qququiquit
+(qemu) commit drive0
+(qemu) quit
read 4096/4096 bytes at offset 0
4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
diff --git a/tests/qemu-iotests/051.pc.out b/tests/qemu-iotests/051.pc.out
index c6f4eef..76d7205 100644
--- a/tests/qemu-iotests/051.pc.out
+++ b/tests/qemu-iotests/051.pc.out
@@ -58,12 +58,12 @@ QEMU X.Y.Z monitor - type 'help' for more information
Testing: -drive file=TEST_DIR/t.qcow2,driver=qcow2,backing.file.filename=TEST_DIR/t.qcow2.orig,if=none,id=drive0 -nodefaults
QEMU X.Y.Z monitor - type 'help' for more information
-(qemu) iininfinfoinfo info binfo blinfo bloinfo blocinfo block
+(qemu) info block
drive0 (NODE_NAME): TEST_DIR/t.qcow2 (qcow2)
Removable device: not locked, tray closed
Cache mode: writeback
Backing file: TEST_DIR/t.qcow2.orig (chain depth: 1)
-(qemu) qququiquit
+(qemu) quit
Testing: -drive file=TEST_DIR/t.qcow2,driver=raw,backing.file.filename=TEST_DIR/t.qcow2.orig
QEMU_PROG: -drive file=TEST_DIR/t.qcow2,driver=raw,backing.file.filename=TEST_DIR/t.qcow2.orig: Driver doesn't support backing files
@@ -79,11 +79,11 @@ QEMU_PROG: -drive file=TEST_DIR/t.qcow2,file.backing.driver=qcow2,file.backing.f
Testing: -drive file=TEST_DIR/t.qcow2,format=qcow2,lazy-refcounts=on
QEMU X.Y.Z monitor - type 'help' for more information
-(qemu) qququiquit
+(qemu) quit
Testing: -drive file=TEST_DIR/t.qcow2,format=qcow2,lazy-refcounts=off
QEMU X.Y.Z monitor - type 'help' for more information
-(qemu) qququiquit
+(qemu) quit
Testing: -drive file=TEST_DIR/t.qcow2,format=qcow2,lazy-refcounts=
QEMU_PROG: -drive file=TEST_DIR/t.qcow2,format=qcow2,lazy-refcounts=: Parameter 'lazy-refcounts' expects 'on' or 'off'
@@ -103,23 +103,23 @@ QEMU_PROG: -drive file=TEST_DIR/t.qcow2,format=qcow2,lazy-refcounts=on: Lazy ref
Testing: -drive file=TEST_DIR/t.qcow2,format=qcow2,lazy-refcounts=off
QEMU X.Y.Z monitor - type 'help' for more information
-(qemu) qququiquit
+(qemu) quit
=== No medium ===
Testing: -drive if=floppy
QEMU X.Y.Z monitor - type 'help' for more information
-(qemu) qququiquit
+(qemu) quit
Testing: -drive if=ide,media=cdrom
QEMU X.Y.Z monitor - type 'help' for more information
-(qemu) qququiquit
+(qemu) quit
Testing: -drive if=scsi,media=cdrom
QEMU X.Y.Z monitor - type 'help' for more information
(qemu) QEMU_PROG: -drive if=scsi,media=cdrom: warning: bus=0,unit=0 is deprecated with this machine type
-qququiquit
+quit
Testing: -drive if=ide
QEMU X.Y.Z monitor - type 'help' for more information
@@ -137,11 +137,11 @@ QEMU X.Y.Z monitor - type 'help' for more information
Testing: -drive if=none,id=disk -device ide-cd,drive=disk
QEMU X.Y.Z monitor - type 'help' for more information
-(qemu) qququiquit
+(qemu) quit
Testing: -drive if=none,id=disk -device lsi53c895a -device scsi-cd,drive=disk
QEMU X.Y.Z monitor - type 'help' for more information
-(qemu) qququiquit
+(qemu) quit
Testing: -drive if=none,id=disk -device ide-drive,drive=disk
QEMU X.Y.Z monitor - type 'help' for more information
@@ -166,16 +166,16 @@ QEMU X.Y.Z monitor - type 'help' for more information
Testing: -drive file=TEST_DIR/t.qcow2,if=floppy,readonly=on
QEMU X.Y.Z monitor - type 'help' for more information
-(qemu) qququiquit
+(qemu) quit
Testing: -drive file=TEST_DIR/t.qcow2,if=ide,media=cdrom,readonly=on
QEMU X.Y.Z monitor - type 'help' for more information
-(qemu) qququiquit
+(qemu) quit
Testing: -drive file=TEST_DIR/t.qcow2,if=scsi,media=cdrom,readonly=on
QEMU X.Y.Z monitor - type 'help' for more information
(qemu) QEMU_PROG: -drive file=TEST_DIR/t.qcow2,if=scsi,media=cdrom,readonly=on: warning: bus=0,unit=0 is deprecated with this machine type
-qququiquit
+quit
Testing: -drive file=TEST_DIR/t.qcow2,if=ide,readonly=on
QEMU X.Y.Z monitor - type 'help' for more information
@@ -185,19 +185,19 @@ QEMU_PROG: Initialization of device ide-hd failed: Device initialization failed.
Testing: -drive file=TEST_DIR/t.qcow2,if=scsi,readonly=on
QEMU X.Y.Z monitor - type 'help' for more information
(qemu) QEMU_PROG: -drive file=TEST_DIR/t.qcow2,if=scsi,readonly=on: warning: bus=0,unit=0 is deprecated with this machine type
-qququiquit
+quit
Testing: -drive file=TEST_DIR/t.qcow2,if=virtio,readonly=on
QEMU X.Y.Z monitor - type 'help' for more information
-(qemu) qququiquit
+(qemu) quit
Testing: -drive file=TEST_DIR/t.qcow2,if=none,id=disk,readonly=on -device ide-cd,drive=disk
QEMU X.Y.Z monitor - type 'help' for more information
-(qemu) qququiquit
+(qemu) quit
Testing: -drive file=TEST_DIR/t.qcow2,if=none,id=disk,readonly=on -device lsi53c895a -device scsi-cd,drive=disk
QEMU X.Y.Z monitor - type 'help' for more information
-(qemu) qququiquit
+(qemu) quit
Testing: -drive file=TEST_DIR/t.qcow2,if=none,id=disk,readonly=on -device ide-drive,drive=disk
QEMU X.Y.Z monitor - type 'help' for more information
@@ -211,97 +211,97 @@ QEMU_PROG: -device ide-hd,drive=disk: Device initialization failed.
Testing: -drive file=TEST_DIR/t.qcow2,if=none,id=disk,readonly=on -device lsi53c895a -device scsi-disk,drive=disk
QEMU X.Y.Z monitor - type 'help' for more information
-(qemu) qququiquit
+(qemu) quit
Testing: -drive file=TEST_DIR/t.qcow2,if=none,id=disk,readonly=on -device lsi53c895a -device scsi-hd,drive=disk
QEMU X.Y.Z monitor - type 'help' for more information
-(qemu) qququiquit
+(qemu) quit
=== Cache modes ===
Testing: -drive driver=null-co,cache=none
QEMU X.Y.Z monitor - type 'help' for more information
-(qemu) qququiquit
+(qemu) quit
Testing: -drive driver=null-co,cache=directsync
QEMU X.Y.Z monitor - type 'help' for more information
-(qemu) qququiquit
+(qemu) quit
Testing: -drive driver=null-co,cache=writeback
QEMU X.Y.Z monitor - type 'help' for more information
-(qemu) qququiquit
+(qemu) quit
Testing: -drive driver=null-co,cache=writethrough
QEMU X.Y.Z monitor - type 'help' for more information
-(qemu) qququiquit
+(qemu) quit
Testing: -drive driver=null-co,cache=unsafe
QEMU X.Y.Z monitor - type 'help' for more information
-(qemu) qququiquit
+(qemu) quit
Testing: -drive driver=null-co,cache=invalid_value
QEMU_PROG: -drive driver=null-co,cache=invalid_value: invalid cache option
Testing: -drive file=TEST_DIR/t.qcow2,cache=writeback,backing.file.filename=TEST_DIR/t.qcow2.base,backing.cache.no-flush=on,backing.node-name=backing,backing.file.node-name=backing-file,file.node-name=file,if=none,id=drive0 -nodefaults
QEMU X.Y.Z monitor - type 'help' for more information
-(qemu) iininfinfoinfo info binfo blinfo bloinfo blocinfo block
+(qemu) info block
drive0 (NODE_NAME): TEST_DIR/t.qcow2 (qcow2)
Removable device: not locked, tray closed
Cache mode: writeback
Backing file: TEST_DIR/t.qcow2.base (chain depth: 1)
-(qemu) iininfinfoinfo info binfo blinfo bloinfo blocinfo blockinfo block info block finfo block fiinfo block filinfo block file
+(qemu) info block file
file: TEST_DIR/t.qcow2 (file)
Cache mode: writeback
-(qemu) iininfinfoinfo info binfo blinfo bloinfo blocinfo blockinfo block info block binfo block bainfo block bacinfo block backinfo block backiinfo block backininfo block backing
+(qemu) info block backing
backing: TEST_DIR/t.qcow2.base (qcow2, read-only)
Cache mode: writeback, ignore flushes
-(qemu) iininfinfoinfo info binfo blinfo bloinfo blocinfo blockinfo block info block binfo block bainfo block bacinfo block backinfo block backiinfo block backininfo block backinginfo block backing-info block backing-finfo block backing-fiinfo block backing-filinfo block backing-file
+(qemu) info block backing-file
backing-file: TEST_DIR/t.qcow2.base (file, read-only)
Cache mode: writeback, ignore flushes
-(qemu) qququiquit
+(qemu) quit
Testing: -drive file=TEST_DIR/t.qcow2,cache=writethrough,backing.file.filename=TEST_DIR/t.qcow2.base,backing.cache.no-flush=on,backing.node-name=backing,backing.file.node-name=backing-file,file.node-name=file,if=none,id=drive0 -nodefaults
QEMU X.Y.Z monitor - type 'help' for more information
-(qemu) iininfinfoinfo info binfo blinfo bloinfo blocinfo block
+(qemu) info block
drive0 (NODE_NAME): TEST_DIR/t.qcow2 (qcow2)
Removable device: not locked, tray closed
Cache mode: writethrough
Backing file: TEST_DIR/t.qcow2.base (chain depth: 1)
-(qemu) iininfinfoinfo info binfo blinfo bloinfo blocinfo blockinfo block info block finfo block fiinfo block filinfo block file
+(qemu) info block file
file: TEST_DIR/t.qcow2 (file)
Cache mode: writeback
-(qemu) iininfinfoinfo info binfo blinfo bloinfo blocinfo blockinfo block info block binfo block bainfo block bacinfo block backinfo block backiinfo block backininfo block backing
+(qemu) info block backing
backing: TEST_DIR/t.qcow2.base (qcow2, read-only)
Cache mode: writeback, ignore flushes
-(qemu) iininfinfoinfo info binfo blinfo bloinfo blocinfo blockinfo block info block binfo block bainfo block bacinfo block backinfo block backiinfo block backininfo block backinginfo block backing-info block backing-finfo block backing-fiinfo block backing-filinfo block backing-file
+(qemu) info block backing-file
backing-file: TEST_DIR/t.qcow2.base (file, read-only)
Cache mode: writeback, ignore flushes
-(qemu) qququiquit
+(qemu) quit
Testing: -drive file=TEST_DIR/t.qcow2,cache=unsafe,backing.file.filename=TEST_DIR/t.qcow2.base,backing.cache.no-flush=on,backing.node-name=backing,backing.file.node-name=backing-file,file.node-name=file,if=none,id=drive0 -nodefaults
QEMU X.Y.Z monitor - type 'help' for more information
-(qemu) iininfinfoinfo info binfo blinfo bloinfo blocinfo block
+(qemu) info block
drive0 (NODE_NAME): TEST_DIR/t.qcow2 (qcow2)
Removable device: not locked, tray closed
Cache mode: writeback, ignore flushes
Backing file: TEST_DIR/t.qcow2.base (chain depth: 1)
-(qemu) iininfinfoinfo info binfo blinfo bloinfo blocinfo blockinfo block info block finfo block fiinfo block filinfo block file
+(qemu) info block file
file: TEST_DIR/t.qcow2 (file)
Cache mode: writeback, ignore flushes
-(qemu) iininfinfoinfo info binfo blinfo bloinfo blocinfo blockinfo block info block binfo block bainfo block bacinfo block backinfo block backiinfo block backininfo block backing
+(qemu) info block backing
backing: TEST_DIR/t.qcow2.base (qcow2, read-only)
Cache mode: writeback, ignore flushes
-(qemu) iininfinfoinfo info binfo blinfo bloinfo blocinfo blockinfo block info block binfo block bainfo block bacinfo block backinfo block backiinfo block backininfo block backinginfo block backing-info block backing-finfo block backing-fiinfo block backing-filinfo block backing-file
+(qemu) info block backing-file
backing-file: TEST_DIR/t.qcow2.base (file, read-only)
Cache mode: writeback, ignore flushes
-(qemu) qququiquit
+(qemu) quit
Testing: -drive file=TEST_DIR/t.qcow2,cache=invalid_value,backing.file.filename=TEST_DIR/t.qcow2.base,backing.cache.no-flush=on,backing.node-name=backing,backing.file.node-name=backing-file,file.node-name=file,if=none,id=drive0 -nodefaults
QEMU_PROG: -drive file=TEST_DIR/t.qcow2,cache=invalid_value,backing.file.filename=TEST_DIR/t.qcow2.base,backing.cache.no-flush=on,backing.node-name=backing,backing.file.node-name=backing-file,file.node-name=file,if=none,id=drive0: invalid cache option
@@ -311,7 +311,7 @@ QEMU_PROG: -drive file=TEST_DIR/t.qcow2,cache=invalid_value,backing.file.filenam
Testing: -drive file=TEST_DIR/t.qcow2,file.driver=file
QEMU X.Y.Z monitor - type 'help' for more information
-(qemu) qququiquit
+(qemu) quit
=== Leaving out required options ===
@@ -319,6 +319,9 @@ QEMU X.Y.Z monitor - type 'help' for more information
Testing: -drive driver=file
QEMU_PROG: -drive driver=file: The 'file' block driver requires a file name
+Testing: -drive driver=file,filename=
+QEMU_PROG: -drive driver=file,filename=: The 'file' block driver requires a file name
+
Testing: -drive driver=nbd
QEMU_PROG: -drive driver=nbd: NBD server address missing
@@ -405,15 +408,15 @@ QEMU_PROG: -drive file=TEST_DIR/t.qcow2,throttling.bps-total=-5: bps/iops/max va
Testing: -drive file=TEST_DIR/t.qcow2,bps=0
QEMU X.Y.Z monitor - type 'help' for more information
-(qemu) qququiquit
+(qemu) quit
Testing: -drive file=TEST_DIR/t.qcow2,bps=1
QEMU X.Y.Z monitor - type 'help' for more information
-(qemu) qququiquit
+(qemu) quit
Testing: -drive file=TEST_DIR/t.qcow2,bps=1000000000000000
QEMU X.Y.Z monitor - type 'help' for more information
-(qemu) qququiquit
+(qemu) quit
Testing: -drive file=TEST_DIR/t.qcow2,bps=1000000000000001
QEMU_PROG: -drive file=TEST_DIR/t.qcow2,bps=1000000000000001: bps/iops/max values must be within [0, 1000000000000000]
@@ -435,11 +438,11 @@ QEMU_PROG: -drive file.filename=foo:bar: Could not open 'foo:bar': No such file
Testing: -hda file:TEST_DIR/t.qcow2
QEMU X.Y.Z monitor - type 'help' for more information
-(qemu) qququiquit
+(qemu) quit
Testing: -drive file=file:TEST_DIR/t.qcow2
QEMU X.Y.Z monitor - type 'help' for more information
-(qemu) qququiquit
+(qemu) quit
Testing: -drive file.filename=file:TEST_DIR/t.qcow2
QEMU_PROG: -drive file.filename=file:TEST_DIR/t.qcow2: Could not open 'file:TEST_DIR/t.qcow2': No such file or directory
@@ -451,78 +454,78 @@ wrote 4096/4096 bytes at offset 0
4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
Testing: -drive file=TEST_DIR/t.qcow2,if=none,id=drive0 -snapshot
QEMU X.Y.Z monitor - type 'help' for more information
-(qemu) qqeqemqemuqemu-qemu-iqemu-ioqemu-io qemu-io dqemu-io drqemu-io driqemu-io drivqemu-io driveqemu-io drive0qemu-io drive0 qemu-io drive0 "qemu-io drive0 "wqemu-io drive0 "wrqemu-io drive0 "wriqemu-io drive0 "writqemu-io drive0 "writeqemu-io drive0 "write qemu-io drive0 "write -qemu-io drive0 "write -Pqemu-io drive0 "write -P qemu-io drive0 "write -P 0qemu-io drive0 "write -P 0xqemu-io drive0 "write -P 0x2qemu-io drive0 "write -P 0x22qemu-io drive0 "write -P 0x22 qemu-io drive0 "write -P 0x22 0qemu-io drive0 "write -P 0x22 0 qemu-io drive0 "write -P 0x22 0 4qemu-io drive0 "write -P 0x22 0 4kqemu-io drive0 "write -P 0x22 0 4k"
+(qemu) qemu-io drive0 "write -P 0x22 0 4k"
wrote 4096/4096 bytes at offset 0
4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
-(qemu) qququiquit
+(qemu) quit
Testing: -drive file=TEST_DIR/t.qcow2,snapshot=on,if=none,id=drive0
QEMU X.Y.Z monitor - type 'help' for more information
-(qemu) qqeqemqemuqemu-qemu-iqemu-ioqemu-io qemu-io dqemu-io drqemu-io driqemu-io drivqemu-io driveqemu-io drive0qemu-io drive0 qemu-io drive0 "qemu-io drive0 "wqemu-io drive0 "wrqemu-io drive0 "wriqemu-io drive0 "writqemu-io drive0 "writeqemu-io drive0 "write qemu-io drive0 "write -qemu-io drive0 "write -Pqemu-io drive0 "write -P qemu-io drive0 "write -P 0qemu-io drive0 "write -P 0xqemu-io drive0 "write -P 0x2qemu-io drive0 "write -P 0x22qemu-io drive0 "write -P 0x22 qemu-io drive0 "write -P 0x22 0qemu-io drive0 "write -P 0x22 0 qemu-io drive0 "write -P 0x22 0 4qemu-io drive0 "write -P 0x22 0 4kqemu-io drive0 "write -P 0x22 0 4k"
+(qemu) qemu-io drive0 "write -P 0x22 0 4k"
wrote 4096/4096 bytes at offset 0
4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
-(qemu) qququiquit
+(qemu) quit
Testing: -drive file.filename=TEST_DIR/t.qcow2,driver=qcow2,snapshot=on,if=none,id=drive0
QEMU X.Y.Z monitor - type 'help' for more information
-(qemu) qqeqemqemuqemu-qemu-iqemu-ioqemu-io qemu-io dqemu-io drqemu-io driqemu-io drivqemu-io driveqemu-io drive0qemu-io drive0 qemu-io drive0 "qemu-io drive0 "wqemu-io drive0 "wrqemu-io drive0 "wriqemu-io drive0 "writqemu-io drive0 "writeqemu-io drive0 "write qemu-io drive0 "write -qemu-io drive0 "write -Pqemu-io drive0 "write -P qemu-io drive0 "write -P 0qemu-io drive0 "write -P 0xqemu-io drive0 "write -P 0x2qemu-io drive0 "write -P 0x22qemu-io drive0 "write -P 0x22 qemu-io drive0 "write -P 0x22 0qemu-io drive0 "write -P 0x22 0 qemu-io drive0 "write -P 0x22 0 4qemu-io drive0 "write -P 0x22 0 4kqemu-io drive0 "write -P 0x22 0 4k"
+(qemu) qemu-io drive0 "write -P 0x22 0 4k"
wrote 4096/4096 bytes at offset 0
4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
-(qemu) qququiquit
+(qemu) quit
Testing: -drive file.filename=TEST_DIR/t.qcow2,driver=qcow2,if=none,id=drive0 -snapshot
QEMU X.Y.Z monitor - type 'help' for more information
-(qemu) qqeqemqemuqemu-qemu-iqemu-ioqemu-io qemu-io dqemu-io drqemu-io driqemu-io drivqemu-io driveqemu-io drive0qemu-io drive0 qemu-io drive0 "qemu-io drive0 "wqemu-io drive0 "wrqemu-io drive0 "wriqemu-io drive0 "writqemu-io drive0 "writeqemu-io drive0 "write qemu-io drive0 "write -qemu-io drive0 "write -Pqemu-io drive0 "write -P qemu-io drive0 "write -P 0qemu-io drive0 "write -P 0xqemu-io drive0 "write -P 0x2qemu-io drive0 "write -P 0x22qemu-io drive0 "write -P 0x22 qemu-io drive0 "write -P 0x22 0qemu-io drive0 "write -P 0x22 0 qemu-io drive0 "write -P 0x22 0 4qemu-io drive0 "write -P 0x22 0 4kqemu-io drive0 "write -P 0x22 0 4k"
+(qemu) qemu-io drive0 "write -P 0x22 0 4k"
wrote 4096/4096 bytes at offset 0
4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
-(qemu) qququiquit
+(qemu) quit
Testing: -drive file=file:TEST_DIR/t.qcow2,if=none,id=drive0 -snapshot
QEMU X.Y.Z monitor - type 'help' for more information
-(qemu) qqeqemqemuqemu-qemu-iqemu-ioqemu-io qemu-io dqemu-io drqemu-io driqemu-io drivqemu-io driveqemu-io drive0qemu-io drive0 qemu-io drive0 "qemu-io drive0 "wqemu-io drive0 "wrqemu-io drive0 "wriqemu-io drive0 "writqemu-io drive0 "writeqemu-io drive0 "write qemu-io drive0 "write -qemu-io drive0 "write -Pqemu-io drive0 "write -P qemu-io drive0 "write -P 0qemu-io drive0 "write -P 0xqemu-io drive0 "write -P 0x2qemu-io drive0 "write -P 0x22qemu-io drive0 "write -P 0x22 qemu-io drive0 "write -P 0x22 0qemu-io drive0 "write -P 0x22 0 qemu-io drive0 "write -P 0x22 0 4qemu-io drive0 "write -P 0x22 0 4kqemu-io drive0 "write -P 0x22 0 4k"
+(qemu) qemu-io drive0 "write -P 0x22 0 4k"
wrote 4096/4096 bytes at offset 0
4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
-(qemu) qququiquit
+(qemu) quit
Testing: -drive file=file:TEST_DIR/t.qcow2,snapshot=on,if=none,id=drive0
QEMU X.Y.Z monitor - type 'help' for more information
-(qemu) qqeqemqemuqemu-qemu-iqemu-ioqemu-io qemu-io dqemu-io drqemu-io driqemu-io drivqemu-io driveqemu-io drive0qemu-io drive0 qemu-io drive0 "qemu-io drive0 "wqemu-io drive0 "wrqemu-io drive0 "wriqemu-io drive0 "writqemu-io drive0 "writeqemu-io drive0 "write qemu-io drive0 "write -qemu-io drive0 "write -Pqemu-io drive0 "write -P qemu-io drive0 "write -P 0qemu-io drive0 "write -P 0xqemu-io drive0 "write -P 0x2qemu-io drive0 "write -P 0x22qemu-io drive0 "write -P 0x22 qemu-io drive0 "write -P 0x22 0qemu-io drive0 "write -P 0x22 0 qemu-io drive0 "write -P 0x22 0 4qemu-io drive0 "write -P 0x22 0 4kqemu-io drive0 "write -P 0x22 0 4k"
+(qemu) qemu-io drive0 "write -P 0x22 0 4k"
wrote 4096/4096 bytes at offset 0
4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
-(qemu) qququiquit
+(qemu) quit
Testing: -drive file=TEST_DIR/t.qcow2,if=none,id=drive0 -snapshot
QEMU X.Y.Z monitor - type 'help' for more information
-(qemu) qqeqemqemuqemu-qemu-iqemu-ioqemu-io qemu-io dqemu-io drqemu-io driqemu-io drivqemu-io driveqemu-io drive0qemu-io drive0 qemu-io drive0 "qemu-io drive0 "wqemu-io drive0 "wrqemu-io drive0 "wriqemu-io drive0 "writqemu-io drive0 "writeqemu-io drive0 "write qemu-io drive0 "write -qemu-io drive0 "write -Pqemu-io drive0 "write -P qemu-io drive0 "write -P 0qemu-io drive0 "write -P 0xqemu-io drive0 "write -P 0x2qemu-io drive0 "write -P 0x22qemu-io drive0 "write -P 0x22 qemu-io drive0 "write -P 0x22 0qemu-io drive0 "write -P 0x22 0 qemu-io drive0 "write -P 0x22 0 4qemu-io drive0 "write -P 0x22 0 4kqemu-io drive0 "write -P 0x22 0 4k"
+(qemu) qemu-io drive0 "write -P 0x22 0 4k"
wrote 4096/4096 bytes at offset 0
4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
-(qemu) qququiquit
+(qemu) quit
Testing: -drive file=TEST_DIR/t.qcow2,snapshot=on,if=none,id=drive0
QEMU X.Y.Z monitor - type 'help' for more information
-(qemu) qqeqemqemuqemu-qemu-iqemu-ioqemu-io qemu-io dqemu-io drqemu-io driqemu-io drivqemu-io driveqemu-io drive0qemu-io drive0 qemu-io drive0 "qemu-io drive0 "wqemu-io drive0 "wrqemu-io drive0 "wriqemu-io drive0 "writqemu-io drive0 "writeqemu-io drive0 "write qemu-io drive0 "write -qemu-io drive0 "write -Pqemu-io drive0 "write -P qemu-io drive0 "write -P 0qemu-io drive0 "write -P 0xqemu-io drive0 "write -P 0x2qemu-io drive0 "write -P 0x22qemu-io drive0 "write -P 0x22 qemu-io drive0 "write -P 0x22 0qemu-io drive0 "write -P 0x22 0 qemu-io drive0 "write -P 0x22 0 4qemu-io drive0 "write -P 0x22 0 4kqemu-io drive0 "write -P 0x22 0 4k"
+(qemu) qemu-io drive0 "write -P 0x22 0 4k"
wrote 4096/4096 bytes at offset 0
4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
-(qemu) qququiquit
+(qemu) quit
read 4096/4096 bytes at offset 0
4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
Testing: -drive file=TEST_DIR/t.qcow2,snapshot=off,if=none,id=drive0
QEMU X.Y.Z monitor - type 'help' for more information
-(qemu) qqeqemqemuqemu-qemu-iqemu-ioqemu-io qemu-io dqemu-io drqemu-io driqemu-io drivqemu-io driveqemu-io drive0qemu-io drive0 qemu-io drive0 "qemu-io drive0 "wqemu-io drive0 "wrqemu-io drive0 "wriqemu-io drive0 "writqemu-io drive0 "writeqemu-io drive0 "write qemu-io drive0 "write -qemu-io drive0 "write -Pqemu-io drive0 "write -P qemu-io drive0 "write -P 0qemu-io drive0 "write -P 0xqemu-io drive0 "write -P 0x2qemu-io drive0 "write -P 0x22qemu-io drive0 "write -P 0x22 qemu-io drive0 "write -P 0x22 0qemu-io drive0 "write -P 0x22 0 qemu-io drive0 "write -P 0x22 0 4qemu-io drive0 "write -P 0x22 0 4kqemu-io drive0 "write -P 0x22 0 4k"
+(qemu) qemu-io drive0 "write -P 0x22 0 4k"
wrote 4096/4096 bytes at offset 0
4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
-(qemu) qququiquit
+(qemu) quit
read 4096/4096 bytes at offset 0
4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
Testing: -drive file=TEST_DIR/t.qcow2,snapshot=on,if=none,id=drive0
QEMU X.Y.Z monitor - type 'help' for more information
-(qemu) qqeqemqemuqemu-qemu-iqemu-ioqemu-io qemu-io dqemu-io drqemu-io driqemu-io drivqemu-io driveqemu-io drive0qemu-io drive0 qemu-io drive0 "qemu-io drive0 "wqemu-io drive0 "wrqemu-io drive0 "wriqemu-io drive0 "writqemu-io drive0 "writeqemu-io drive0 "write qemu-io drive0 "write -qemu-io drive0 "write -Pqemu-io drive0 "write -P qemu-io drive0 "write -P 0qemu-io drive0 "write -P 0xqemu-io drive0 "write -P 0x3qemu-io drive0 "write -P 0x33qemu-io drive0 "write -P 0x33 qemu-io drive0 "write -P 0x33 0qemu-io drive0 "write -P 0x33 0 qemu-io drive0 "write -P 0x33 0 4qemu-io drive0 "write -P 0x33 0 4kqemu-io drive0 "write -P 0x33 0 4k"
+(qemu) qemu-io drive0 "write -P 0x33 0 4k"
wrote 4096/4096 bytes at offset 0
4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
-(qemu) ccocomcommcommicommitcommit commit dcommit drcommit dricommit drivcommit drivecommit drive0
-(qemu) qququiquit
+(qemu) commit drive0
+(qemu) quit
read 4096/4096 bytes at offset 0
4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
diff --git a/tests/qemu-iotests/066 b/tests/qemu-iotests/066
index 364166d..c2116a3 100755
--- a/tests/qemu-iotests/066
+++ b/tests/qemu-iotests/066
@@ -42,16 +42,18 @@ _supported_fmt qcow2
_supported_proto generic
_supported_os Linux
+# Intentionally create an unaligned image
IMGOPTS="compat=1.1"
-IMG_SIZE=64M
+IMG_SIZE=$((64 * 1024 * 1024 + 512))
echo
-echo "=== Testing snapshotting an image with zero clusters ==="
+echo "=== Testing cluster discards ==="
echo
_make_test_img $IMG_SIZE
-# Write some normal clusters, zero them (creating preallocated zero clusters)
-# and discard those
-$QEMU_IO -c "write 0 256k" -c "write -z 0 256k" -c "discard 0 256k" "$TEST_IMG" \
+# Write some normal clusters, zero some of them (creating preallocated
+# zero clusters) and discard everything. Everything should now read as 0.
+$QEMU_IO -c "write 0 256k" -c "write -z 0 256k" -c "write 64M 512" \
+ -c "discard 0 $IMG_SIZE" -c "read -P 0 0 $IMG_SIZE" "$TEST_IMG" \
| _filter_qemu_io
# Check the image (there shouldn't be any leaks)
_check_test_img
diff --git a/tests/qemu-iotests/066.out b/tests/qemu-iotests/066.out
index 7bc9a10..7c1f31a 100644
--- a/tests/qemu-iotests/066.out
+++ b/tests/qemu-iotests/066.out
@@ -1,13 +1,17 @@
QA output created by 066
-=== Testing snapshotting an image with zero clusters ===
+=== Testing cluster discards ===
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67109376
wrote 262144/262144 bytes at offset 0
256 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
wrote 262144/262144 bytes at offset 0
256 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
-discard 262144/262144 bytes at offset 0
-256 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+wrote 512/512 bytes at offset 67108864
+512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+discard 67109376/67109376 bytes at offset 0
+64 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+read 67109376/67109376 bytes at offset 0
+64 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
No errors were found on the image.
*** done
diff --git a/tests/qemu-iotests/068 b/tests/qemu-iotests/068
index 68f6e82..9c1687d 100755
--- a/tests/qemu-iotests/068
+++ b/tests/qemu-iotests/068
@@ -62,11 +62,11 @@ esac
# Give qemu some time to boot before saving the VM state
bash -c 'sleep 1; echo -e "savevm 0\nquit"' |\
$QEMU $platform_parm -nographic -monitor stdio -serial none -hda "$TEST_IMG" |\
- _filter_qemu
+ _filter_qemu | _filter_hmp
# Now try to continue from that VM state (this should just work)
echo quit |\
$QEMU $platform_parm -nographic -monitor stdio -serial none -hda "$TEST_IMG" -loadvm 0 |\
- _filter_qemu
+ _filter_qemu | _filter_hmp
# success, all done
echo "*** done"
diff --git a/tests/qemu-iotests/068.out b/tests/qemu-iotests/068.out
index 84f19b4..0fa5340 100644
--- a/tests/qemu-iotests/068.out
+++ b/tests/qemu-iotests/068.out
@@ -4,8 +4,8 @@ QA output created by 068
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=131072
QEMU X.Y.Z monitor - type 'help' for more information
-(qemu) ssasavsavesavevsavevmsavevm savevm 0
-(qemu) qququiquit
+(qemu) savevm 0
+(qemu) quit
QEMU X.Y.Z monitor - type 'help' for more information
-(qemu) qququiquit
+(qemu) quit
*** done
diff --git a/tests/qemu-iotests/109 b/tests/qemu-iotests/109
index 6161633..3b496a3 100755
--- a/tests/qemu-iotests/109
+++ b/tests/qemu-iotests/109
@@ -81,7 +81,8 @@ for fmt in qcow qcow2 qed vdi vmdk vpc; do
# This first test should fail: The image format was probed, we may not
# write an image header at the start of the image
- run_qemu "$TEST_IMG" "$TEST_IMG.src" "" "BLOCK_JOB_ERROR"
+ run_qemu "$TEST_IMG" "$TEST_IMG.src" "" "BLOCK_JOB_ERROR" |
+ _filter_block_job_len
$QEMU_IO -c 'read -P 0 0 64k' "$TEST_IMG" | _filter_qemu_io
@@ -104,7 +105,8 @@ for sample_img in empty.bochs iotest-dirtylog-10G-4M.vhdx parallels-v1 \
_make_test_img 64M
bzcat "$SAMPLE_IMG_DIR/$sample_img.bz2" > "$TEST_IMG.src"
- run_qemu "$TEST_IMG" "$TEST_IMG.src" "" "BLOCK_JOB_ERROR" | _filter_block_job_offset
+ run_qemu "$TEST_IMG" "$TEST_IMG.src" "" "BLOCK_JOB_ERROR" |
+ _filter_block_job_offset | _filter_block_job_len
$QEMU_IO -c 'read -P 0 0 64k' "$TEST_IMG" | _filter_qemu_io
run_qemu "$TEST_IMG" "$TEST_IMG.src" "'format': 'raw'," "BLOCK_JOB_READY"
diff --git a/tests/qemu-iotests/109.out b/tests/qemu-iotests/109.out
index 55fe536..dc02f9e 100644
--- a/tests/qemu-iotests/109.out
+++ b/tests/qemu-iotests/109.out
@@ -10,7 +10,7 @@ Automatically detecting the format is dangerous for raw images, write operations
Specify the 'raw' format explicitly to remove the restrictions.
{"return": {}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_ERROR", "data": {"device": "src", "operation": "write", "action": "report"}}
-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "src", "len": 65536, "offset": 0, "speed": 0, "type": "mirror", "error": "Operation not permitted"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "src", "len": LEN, "offset": 0, "speed": 0, "type": "mirror", "error": "Operation not permitted"}}
{"return": []}
read 65536/65536 bytes at offset 0
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
@@ -31,7 +31,7 @@ Automatically detecting the format is dangerous for raw images, write operations
Specify the 'raw' format explicitly to remove the restrictions.
{"return": {}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_ERROR", "data": {"device": "src", "operation": "write", "action": "report"}}
-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "src", "len": 197120, "offset": 512, "speed": 0, "type": "mirror", "error": "Operation not permitted"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "src", "len": LEN, "offset": 512, "speed": 0, "type": "mirror", "error": "Operation not permitted"}}
{"return": []}
read 65536/65536 bytes at offset 0
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
@@ -52,7 +52,7 @@ Automatically detecting the format is dangerous for raw images, write operations
Specify the 'raw' format explicitly to remove the restrictions.
{"return": {}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_ERROR", "data": {"device": "src", "operation": "write", "action": "report"}}
-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "src", "len": 327680, "offset": 262144, "speed": 0, "type": "mirror", "error": "Operation not permitted"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "src", "len": LEN, "offset": 262144, "speed": 0, "type": "mirror", "error": "Operation not permitted"}}
{"return": []}
read 65536/65536 bytes at offset 0
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
@@ -73,7 +73,7 @@ Automatically detecting the format is dangerous for raw images, write operations
Specify the 'raw' format explicitly to remove the restrictions.
{"return": {}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_ERROR", "data": {"device": "src", "operation": "write", "action": "report"}}
-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "src", "len": 65536, "offset": 0, "speed": 0, "type": "mirror", "error": "Operation not permitted"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "src", "len": LEN, "offset": 0, "speed": 0, "type": "mirror", "error": "Operation not permitted"}}
{"return": []}
read 65536/65536 bytes at offset 0
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
@@ -94,7 +94,7 @@ Automatically detecting the format is dangerous for raw images, write operations
Specify the 'raw' format explicitly to remove the restrictions.
{"return": {}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_ERROR", "data": {"device": "src", "operation": "write", "action": "report"}}
-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "src", "len": 65536, "offset": 0, "speed": 0, "type": "mirror", "error": "Operation not permitted"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "src", "len": LEN, "offset": 0, "speed": 0, "type": "mirror", "error": "Operation not permitted"}}
{"return": []}
read 65536/65536 bytes at offset 0
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
@@ -115,7 +115,7 @@ Automatically detecting the format is dangerous for raw images, write operations
Specify the 'raw' format explicitly to remove the restrictions.
{"return": {}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_ERROR", "data": {"device": "src", "operation": "write", "action": "report"}}
-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "src", "len": 65536, "offset": 0, "speed": 0, "type": "mirror", "error": "Operation not permitted"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "src", "len": LEN, "offset": 0, "speed": 0, "type": "mirror", "error": "Operation not permitted"}}
{"return": []}
read 65536/65536 bytes at offset 0
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
@@ -135,7 +135,7 @@ Automatically detecting the format is dangerous for raw images, write operations
Specify the 'raw' format explicitly to remove the restrictions.
{"return": {}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_ERROR", "data": {"device": "src", "operation": "write", "action": "report"}}
-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "src", "len": 65536, "offset": OFFSET, "speed": 0, "type": "mirror", "error": "Operation not permitted"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "src", "len": LEN, "offset": OFFSET, "speed": 0, "type": "mirror", "error": "Operation not permitted"}}
{"return": []}
read 65536/65536 bytes at offset 0
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
@@ -155,7 +155,7 @@ Automatically detecting the format is dangerous for raw images, write operations
Specify the 'raw' format explicitly to remove the restrictions.
{"return": {}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_ERROR", "data": {"device": "src", "operation": "write", "action": "report"}}
-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "src", "len": 31457280, "offset": OFFSET, "speed": 0, "type": "mirror", "error": "Operation not permitted"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "src", "len": LEN, "offset": OFFSET, "speed": 0, "type": "mirror", "error": "Operation not permitted"}}
{"return": []}
read 65536/65536 bytes at offset 0
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
@@ -175,7 +175,7 @@ Automatically detecting the format is dangerous for raw images, write operations
Specify the 'raw' format explicitly to remove the restrictions.
{"return": {}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_ERROR", "data": {"device": "src", "operation": "write", "action": "report"}}
-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "src", "len": 327680, "offset": OFFSET, "speed": 0, "type": "mirror", "error": "Operation not permitted"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "src", "len": LEN, "offset": OFFSET, "speed": 0, "type": "mirror", "error": "Operation not permitted"}}
{"return": []}
read 65536/65536 bytes at offset 0
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
@@ -195,7 +195,7 @@ Automatically detecting the format is dangerous for raw images, write operations
Specify the 'raw' format explicitly to remove the restrictions.
{"return": {}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_ERROR", "data": {"device": "src", "operation": "write", "action": "report"}}
-{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "src", "len": 65536, "offset": OFFSET, "speed": 0, "type": "mirror", "error": "Operation not permitted"}}
+{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "BLOCK_JOB_COMPLETED", "data": {"device": "src", "len": LEN, "offset": OFFSET, "speed": 0, "type": "mirror", "error": "Operation not permitted"}}
{"return": []}
read 65536/65536 bytes at offset 0
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
diff --git a/tests/qemu-iotests/122.out b/tests/qemu-iotests/122.out
index 98814de..9317d80 100644
--- a/tests/qemu-iotests/122.out
+++ b/tests/qemu-iotests/122.out
@@ -61,8 +61,8 @@ read 65536/65536 bytes at offset 4194304
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
read 65536/65536 bytes at offset 8388608
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
-qemu-img: -B makes no sense when concatenating multiple input images
-qemu-img: -B makes no sense when concatenating multiple input images
+qemu-img: Having a backing file for the target makes no sense when concatenating multiple input images
+qemu-img: Having a backing file for the target makes no sense when concatenating multiple input images
=== Compression with misaligned allocations and image sizes ===
diff --git a/tests/qemu-iotests/130.out b/tests/qemu-iotests/130.out
index ae95b50..93020c3 100644
--- a/tests/qemu-iotests/130.out
+++ b/tests/qemu-iotests/130.out
@@ -9,14 +9,14 @@ virtual size: 64M (67108864 bytes)
=== HMP commit ===
QEMU X.Y.Z monitor - type 'help' for more information
-(qemu) ccocomcommcommicommitcommit commit tcommit tecommit tescommit testcommit testdcommit testdicommit testdiscommit testdisk
+(qemu) commit testdisk
(qemu)
image: TEST_DIR/t.IMGFMT
file format: IMGFMT
virtual size: 64M (67108864 bytes)
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 backing_file=TEST_DIR/t.IMGFMT.orig backing_fmt=raw
QEMU X.Y.Z monitor - type 'help' for more information
-(qemu) ccocomcommcommicommitcommit commit tcommit tecommit tescommit testcommit testdcommit testdicommit testdiscommit testdisk
+(qemu) commit testdisk
(qemu)
image: TEST_DIR/t.IMGFMT
file format: IMGFMT
diff --git a/tests/qemu-iotests/142 b/tests/qemu-iotests/142
index 29c0606..9a5b713 100755
--- a/tests/qemu-iotests/142
+++ b/tests/qemu-iotests/142
@@ -62,7 +62,7 @@ function do_run_qemu()
function run_qemu()
{
- do_run_qemu "$@" 2>&1 | _filter_testdir | _filter_qemu
+ do_run_qemu "$@" 2>&1 | _filter_testdir | _filter_qemu | _filter_hmp
}
size=128M
diff --git a/tests/qemu-iotests/142.out b/tests/qemu-iotests/142.out
index 600beca..3667e38 100644
--- a/tests/qemu-iotests/142.out
+++ b/tests/qemu-iotests/142.out
@@ -7,23 +7,23 @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 backing_file=TEST_DIR/
Testing: -drive file=TEST_DIR/t.qcow2,cache=none
QEMU X.Y.Z monitor - type 'help' for more information
-(qemu) qququiquit
+(qemu) quit
Testing: -drive file=TEST_DIR/t.qcow2,cache=directsync
QEMU X.Y.Z monitor - type 'help' for more information
-(qemu) qququiquit
+(qemu) quit
Testing: -drive file=TEST_DIR/t.qcow2,cache=writeback
QEMU X.Y.Z monitor - type 'help' for more information
-(qemu) qququiquit
+(qemu) quit
Testing: -drive file=TEST_DIR/t.qcow2,cache=writethrough
QEMU X.Y.Z monitor - type 'help' for more information
-(qemu) qququiquit
+(qemu) quit
Testing: -drive file=TEST_DIR/t.qcow2,cache=unsafe
QEMU X.Y.Z monitor - type 'help' for more information
-(qemu) qququiquit
+(qemu) quit
Testing: -drive file=TEST_DIR/t.qcow2,cache=invalid_value
QEMU_PROG: -drive file=TEST_DIR/t.qcow2,cache=invalid_value: invalid cache option
diff --git a/tests/qemu-iotests/145 b/tests/qemu-iotests/145
index 1eca0e8..e6c6bc4 100755
--- a/tests/qemu-iotests/145
+++ b/tests/qemu-iotests/145
@@ -43,7 +43,8 @@ _supported_proto generic
_supported_os Linux
_make_test_img 1M
-echo quit | $QEMU -nographic -hda "$TEST_IMG" -incoming 'exec:true' -snapshot -serial none -monitor stdio | _filter_qemu
+echo quit | $QEMU -nographic -hda "$TEST_IMG" -incoming 'exec:true' -snapshot -serial none -monitor stdio |
+ _filter_qemu | _filter_hmp
# success, all done
echo "*** done"
diff --git a/tests/qemu-iotests/145.out b/tests/qemu-iotests/145.out
index 75b5c8a..9a90009 100644
--- a/tests/qemu-iotests/145.out
+++ b/tests/qemu-iotests/145.out
@@ -1,5 +1,5 @@
QA output created by 145
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1048576
QEMU X.Y.Z monitor - type 'help' for more information
-(qemu) qququiquit
+(qemu) quit
*** done
diff --git a/tests/qemu-iotests/181 b/tests/qemu-iotests/181
new file mode 100755
index 0000000..e969a2a
--- /dev/null
+++ b/tests/qemu-iotests/181
@@ -0,0 +1,119 @@
+#!/bin/bash
+#
+# Test postcopy live migration with shared storage
+#
+# Copyright (C) 2017 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=kwolf@redhat.com
+
+seq=`basename $0`
+echo "QA output created by $seq"
+
+here=`pwd`
+status=1 # failure is the default!
+
+MIG_SOCKET="${TEST_DIR}/migrate"
+
+_cleanup()
+{
+ rm -f "${MIG_SOCKET}"
+ _cleanup_test_img
+ _cleanup_qemu
+}
+trap "_cleanup; exit \$status" 0 1 2 3 15
+
+# get standard environment, filters and checks
+. ./common.rc
+. ./common.filter
+. ./common.qemu
+
+_supported_fmt generic
+_supported_proto generic
+_supported_os Linux
+
+size=64M
+_make_test_img $size
+
+echo
+echo === Starting VMs ===
+echo
+
+qemu_comm_method="monitor"
+
+_launch_qemu \
+ -drive file="${TEST_IMG}",cache=${CACHEMODE},driver=$IMGFMT,id=disk
+src=$QEMU_HANDLE
+
+_launch_qemu \
+ -drive file="${TEST_IMG}",cache=${CACHEMODE},driver=$IMGFMT,id=disk \
+ -incoming "unix:${MIG_SOCKET}"
+dest=$QEMU_HANDLE
+
+echo
+echo === Write something on the source ===
+echo
+
+silent=
+_send_qemu_cmd $src 'qemu-io disk "write -P 0x55 0 64k"' "(qemu)"
+_send_qemu_cmd $src "" "ops/sec"
+_send_qemu_cmd $src 'qemu-io disk "read -P 0x55 0 64k"' "(qemu)"
+_send_qemu_cmd $src "" "ops/sec"
+
+echo
+echo === Do postcopy migration to destination ===
+echo
+
+# Slow down migration so much that it definitely won't finish before we can
+# switch to postcopy
+silent=yes
+_send_qemu_cmd $src 'migrate_set_speed 4k' "(qemu)"
+_send_qemu_cmd $src 'migrate_set_capability postcopy-ram on' "(qemu)"
+_send_qemu_cmd $src "migrate -d unix:${MIG_SOCKET}" "(qemu)"
+_send_qemu_cmd $src 'migrate_start_postcopy' "(qemu)"
+
+QEMU_COMM_TIMEOUT=1 qemu_cmd_repeat=10 silent=yes \
+ _send_qemu_cmd $src "info migrate" "completed\|failed"
+silent=yes _send_qemu_cmd $src "" "(qemu)"
+
+echo
+echo === Do some I/O on the destination ===
+echo
+
+# It is important that we use the BlockBackend of the guest device here instead
+# of the node name, which would create a new BlockBackend and not test whether
+# the guest has the necessary permissions to access the image now
+silent=
+_send_qemu_cmd $dest 'qemu-io disk "read -P 0x55 0 64k"' "(qemu)"
+_send_qemu_cmd $dest "" "ops/sec"
+_send_qemu_cmd $dest 'qemu-io disk "write -P 0x66 1M 64k"' "(qemu)"
+_send_qemu_cmd $dest "" "ops/sec"
+
+echo
+echo === Shut down and check image ===
+echo
+
+_send_qemu_cmd $src 'quit' ""
+_send_qemu_cmd $dest 'quit' ""
+wait=1 _cleanup_qemu
+
+_check_test_img
+
+# success, all done
+echo "*** done"
+rm -f $seq.full
+status=0
diff --git a/tests/qemu-iotests/181.out b/tests/qemu-iotests/181.out
new file mode 100644
index 0000000..6534ba2
--- /dev/null
+++ b/tests/qemu-iotests/181.out
@@ -0,0 +1,38 @@
+QA output created by 181
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
+
+=== Starting VMs ===
+
+
+=== Write something on the source ===
+
+QEMU X.Y.Z monitor - type 'help' for more information
+(qemu) qemu-io disk "write -P 0x55 0 64k"
+wrote 65536/65536 bytes at offset 0
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+(qemu)
+(qemu) qemu-io disk "read -P 0x55 0 64k"
+read 65536/65536 bytes at offset 0
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+
+=== Do postcopy migration to destination ===
+
+
+=== Do some I/O on the destination ===
+
+QEMU X.Y.Z monitor - type 'help' for more information
+(qemu) qemu-io disk "read -P 0x55 0 64k"
+read 65536/65536 bytes at offset 0
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+(qemu)
+(qemu) qemu-io disk "write -P 0x66 1M 64k"
+wrote 65536/65536 bytes at offset 1048576
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+
+=== Shut down and check image ===
+
+(qemu) quit
+(qemu)
+(qemu) quit
+No errors were found on the image.
+*** done
diff --git a/tests/qemu-iotests/common b/tests/qemu-iotests/common
index 9c6f972..f2a7199 100644
--- a/tests/qemu-iotests/common
+++ b/tests/qemu-iotests/common
@@ -86,7 +86,8 @@ s/ .*//p
elif $xgroup
then
# arg after -x
- [ ! -s $tmp.list ] && ls [0-9][0-9][0-9] [0-9][0-9][0-9][0-9] >$tmp.list 2>/dev/null
+ # Populate $tmp.list with all tests
+ awk '/^[0-9]{3,}/ {print $1}' "${source_iotests}/group" > $tmp.list 2>/dev/null
group_list=`sed -n <"$source_iotests/group" -e 's/$/ /' -e "/^[0-9][0-9][0-9].* $r /"'{
s/ .*//p
}'`
@@ -138,7 +139,7 @@ common options
-v verbose
-d debug
-check options
+image format options
-raw test raw (default)
-bochs test bochs
-cloop test cloop
@@ -150,14 +151,18 @@ check options
-vpc test vpc
-vhdx test vhdx
-vmdk test vmdk
+ -luks test luks
+
+image protocol options
-file test file (default)
-rbd test rbd
-sheepdog test sheepdog
-nbd test nbd
-ssh test ssh
-nfs test nfs
- -luks test luks
-vxhs test vxhs
+
+other options
-xdiff graphical mode diff
-nocache use O_DIRECT on backing file
-misalign misalign memory allocations
diff --git a/tests/qemu-iotests/common.config b/tests/qemu-iotests/common.config
index c4b51b3..d1b45f5 100644
--- a/tests/qemu-iotests/common.config
+++ b/tests/qemu-iotests/common.config
@@ -75,18 +75,12 @@ _fatal()
exit 1
}
-export PERL_PROG="`set_prog_path perl`"
-[ "$PERL_PROG" = "" ] && _fatal "perl not found"
-
export AWK_PROG="`set_prog_path awk`"
[ "$AWK_PROG" = "" ] && _fatal "awk not found"
export SED_PROG="`set_prog_path sed`"
[ "$SED_PROG" = "" ] && _fatal "sed not found"
-export BC_PROG="`set_prog_path bc`"
-[ "$BC_PROG" = "" ] && _fatal "bc not found"
-
export PS_ALL_FLAGS="-ef"
if [ -z "$QEMU_PROG" ]; then
@@ -223,23 +217,5 @@ fi
export SAMPLE_IMG_DIR
-_readlink()
-{
- if [ $# -ne 1 ]; then
- echo "Usage: _readlink filename" 1>&2
- exit 1
- fi
-
- perl -e "\$in=\"$1\";" -e '
- $lnk = readlink($in);
- if ($lnk =~ m!^/.*!) {
- print "$lnk\n";
- }
- else {
- chomp($dir = `dirname $in`);
- print "$dir/$lnk\n";
- }'
-}
-
# make sure this script returns success
true
diff --git a/tests/qemu-iotests/common.filter b/tests/qemu-iotests/common.filter
index c9a2d5c..f58548d 100644
--- a/tests/qemu-iotests/common.filter
+++ b/tests/qemu-iotests/common.filter
@@ -86,12 +86,25 @@ _filter_qmp()
-e ' QMP_VERSION'
}
+# readline makes HMP command strings so long that git complains
+_filter_hmp()
+{
+ sed -e $'s/^\\((qemu) \\)\\?.*\e\\[D/\\1/g' \
+ -e $'s/\e\\[K//g'
+}
+
# replace block job offset
_filter_block_job_offset()
{
sed -e 's/, "offset": [0-9]\+,/, "offset": OFFSET,/'
}
+# replace block job len
+_filter_block_job_len()
+{
+ sed -e 's/, "len": [0-9]\+,/, "len": LEN,/g'
+}
+
# replace driver-specific options in the "Formatting..." line
_filter_img_create()
{
diff --git a/tests/qemu-iotests/common.qemu b/tests/qemu-iotests/common.qemu
index 4278789..7a78a00 100644
--- a/tests/qemu-iotests/common.qemu
+++ b/tests/qemu-iotests/common.qemu
@@ -59,7 +59,7 @@ function _timed_wait_for()
do
if [ -z "${silent}" ]; then
echo "${resp}" | _filter_testdir | _filter_qemu \
- | _filter_qemu_io | _filter_qmp
+ | _filter_qemu_io | _filter_qmp | _filter_hmp
fi
grep -q "${*}" < <(echo ${resp})
if [ $? -eq 0 ]; then
@@ -217,7 +217,7 @@ function _cleanup_qemu()
if [ -n "${wait}" ]; then
cat <&${QEMU_OUT[$i]} | _filter_testdir | _filter_qemu \
- | _filter_qemu_io | _filter_qmp
+ | _filter_qemu_io | _filter_qmp | _filter_hmp
fi
rm -f "${QEMU_FIFO_IN}_${i}" "${QEMU_FIFO_OUT}_${i}"
eval "exec ${QEMU_IN[$i]}<&-" # close file descriptors
diff --git a/tests/qemu-iotests/common.rc b/tests/qemu-iotests/common.rc
index 62529ee..9fd3130 100644
--- a/tests/qemu-iotests/common.rc
+++ b/tests/qemu-iotests/common.rc
@@ -171,7 +171,9 @@ _make_test_img()
# Start an NBD server on the image file, which is what we'll be talking to
if [ $IMGPROTO = "nbd" ]; then
- eval "$QEMU_NBD -v -t -b 127.0.0.1 -p 10810 -f $IMGFMT $TEST_IMG_FILE >/dev/null &"
+ # Pass a sufficiently high number to -e that should be enough for all
+ # tests
+ eval "$QEMU_NBD -v -t -b 127.0.0.1 -p 10810 -f $IMGFMT -e 42 $TEST_IMG_FILE >/dev/null &"
sleep 1 # FIXME: qemu-nbd needs to be listening before we continue
fi
diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group
index 43142dd..893962d 100644
--- a/tests/qemu-iotests/group
+++ b/tests/qemu-iotests/group
@@ -169,3 +169,4 @@
174 auto
175 auto quick
176 rw auto backing
+181 rw auto migration
diff --git a/tests/test-char.c b/tests/test-char.c
index da69f11..773a1c3 100644
--- a/tests/test-char.c
+++ b/tests/test-char.c
@@ -1,18 +1,35 @@
#include "qemu/osdep.h"
+#include <glib/gstdio.h>
#include "qemu-common.h"
#include "qemu/config-file.h"
+#include "qemu/sockets.h"
#include "sysemu/char.h"
#include "sysemu/sysemu.h"
#include "qapi/error.h"
+#include "qom/qom-qobject.h"
#include "qmp-commands.h"
+static bool quit;
+
typedef struct FeHandler {
int read_count;
int last_event;
char read_buf[128];
} FeHandler;
+static void main_loop(void)
+{
+ bool nonblocking;
+ int last_io = 0;
+
+ quit = false;
+ do {
+ nonblocking = last_io > 0;
+ last_io = main_loop_wait(nonblocking);
+ } while (!quit);
+}
+
static int fe_can_read(void *opaque)
{
FeHandler *h = opaque;
@@ -28,6 +45,7 @@ static void fe_read(void *opaque, const uint8_t *buf, int size)
memcpy(h->read_buf + h->read_count, buf, size);
h->read_count += size;
+ quit = true;
}
static void fe_event(void *opaque, int event)
@@ -35,9 +53,36 @@ static void fe_event(void *opaque, int event)
FeHandler *h = opaque;
h->last_event = event;
+ quit = true;
}
#ifdef CONFIG_HAS_GLIB_SUBPROCESS_TESTS
+#ifdef _WIN32
+static void char_console_test_subprocess(void)
+{
+ QemuOpts *opts;
+ Chardev *chr;
+
+ opts = qemu_opts_create(qemu_find_opts("chardev"), "console-label",
+ 1, &error_abort);
+ qemu_opt_set(opts, "backend", "console", &error_abort);
+
+ chr = qemu_chr_new_from_opts(opts, NULL);
+ g_assert_nonnull(chr);
+
+ qemu_chr_write_all(chr, (const uint8_t *)"CONSOLE", 7);
+
+ qemu_opts_del(opts);
+ object_unparent(OBJECT(chr));
+}
+
+static void char_console_test(void)
+{
+ g_test_trap_subprocess("/char/console/subprocess", 0, 0);
+ g_test_trap_assert_passed();
+ g_test_trap_assert_stdout("CONSOLE");
+}
+#endif
static void char_stdio_test_subprocess(void)
{
Chardev *chr;
@@ -53,7 +98,7 @@ static void char_stdio_test_subprocess(void)
g_assert_cmpint(ret, ==, 4);
qemu_chr_fe_deinit(&be);
- qemu_chr_delete(chr);
+ object_unparent(OBJECT(chr));
}
static void char_stdio_test(void)
@@ -64,7 +109,6 @@ static void char_stdio_test(void)
}
#endif
-
static void char_ringbuf_test(void)
{
QemuOpts *opts;
@@ -103,7 +147,17 @@ static void char_ringbuf_test(void)
g_free(data);
qemu_chr_fe_deinit(&be);
- qemu_chr_delete(chr);
+ object_unparent(OBJECT(chr));
+
+ /* check alias */
+ opts = qemu_opts_create(qemu_find_opts("chardev"), "memory-label",
+ 1, &error_abort);
+ qemu_opt_set(opts, "backend", "memory", &error_abort);
+ qemu_opt_set(opts, "size", "2", &error_abort);
+ chr = qemu_chr_new_from_opts(opts, NULL);
+ g_assert_nonnull(chr);
+ object_unparent(OBJECT(chr));
+ qemu_opts_del(opts);
}
static void char_mux_test(void)
@@ -179,7 +233,296 @@ static void char_mux_test(void)
qemu_chr_fe_deinit(&chr_be1);
qemu_chr_fe_deinit(&chr_be2);
- qemu_chr_delete(chr);
+ object_unparent(OBJECT(chr));
+}
+
+typedef struct SocketIdleData {
+ GMainLoop *loop;
+ Chardev *chr;
+ bool conn_expected;
+ CharBackend *be;
+ CharBackend *client_be;
+} SocketIdleData;
+
+static gboolean char_socket_test_idle(gpointer user_data)
+{
+ SocketIdleData *data = user_data;
+
+ if (object_property_get_bool(OBJECT(data->chr), "connected", NULL)
+ == data->conn_expected) {
+ quit = true;
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static void socket_read(void *opaque, const uint8_t *buf, int size)
+{
+ SocketIdleData *data = opaque;
+
+ g_assert_cmpint(size, ==, 1);
+ g_assert_cmpint(*buf, ==, 'Z');
+
+ size = qemu_chr_fe_write(data->be, (const uint8_t *)"hello", 5);
+ g_assert_cmpint(size, ==, 5);
+}
+
+static int socket_can_read(void *opaque)
+{
+ return 10;
+}
+
+static void socket_read_hello(void *opaque, const uint8_t *buf, int size)
+{
+ g_assert_cmpint(size, ==, 5);
+ g_assert(strncmp((char *)buf, "hello", 5) == 0);
+
+ quit = true;
+}
+
+static int socket_can_read_hello(void *opaque)
+{
+ return 10;
+}
+
+static void char_socket_test(void)
+{
+ Chardev *chr = qemu_chr_new("server", "tcp:127.0.0.1:0,server,nowait");
+ Chardev *chr_client;
+ QObject *addr;
+ QDict *qdict, *data;
+ const char *port;
+ SocketIdleData d = { .chr = chr };
+ CharBackend be;
+ CharBackend client_be;
+ char *tmp;
+
+ d.be = &be;
+ d.client_be = &be;
+
+ g_assert_nonnull(chr);
+ g_assert(!object_property_get_bool(OBJECT(chr), "connected", &error_abort));
+
+ addr = object_property_get_qobject(OBJECT(chr), "addr", &error_abort);
+ qdict = qobject_to_qdict(addr);
+ data = qdict_get_qdict(qdict, "data");
+ port = qdict_get_str(data, "port");
+ tmp = g_strdup_printf("tcp:127.0.0.1:%s", port);
+ QDECREF(qdict);
+
+ qemu_chr_fe_init(&be, chr, &error_abort);
+ qemu_chr_fe_set_handlers(&be, socket_can_read, socket_read,
+ NULL, &d, NULL, true);
+
+ chr_client = qemu_chr_new("client", tmp);
+ qemu_chr_fe_init(&client_be, chr_client, &error_abort);
+ qemu_chr_fe_set_handlers(&client_be, socket_can_read_hello,
+ socket_read_hello,
+ NULL, &d, NULL, true);
+ g_free(tmp);
+
+ d.conn_expected = true;
+ guint id = g_idle_add(char_socket_test_idle, &d);
+ g_source_set_name_by_id(id, "test-idle");
+ g_assert_cmpint(id, >, 0);
+ main_loop();
+
+ g_assert(object_property_get_bool(OBJECT(chr), "connected", &error_abort));
+ g_assert(object_property_get_bool(OBJECT(chr_client),
+ "connected", &error_abort));
+
+ qemu_chr_write_all(chr_client, (const uint8_t *)"Z", 1);
+ main_loop();
+
+ object_unparent(OBJECT(chr_client));
+
+ d.conn_expected = false;
+ g_idle_add(char_socket_test_idle, &d);
+ main_loop();
+
+ object_unparent(OBJECT(chr));
+}
+
+#ifndef _WIN32
+static void char_pipe_test(void)
+{
+ gchar *tmp_path = g_dir_make_tmp("qemu-test-char.XXXXXX", NULL);
+ gchar *tmp, *in, *out, *pipe = g_build_filename(tmp_path, "pipe", NULL);
+ Chardev *chr;
+ CharBackend be;
+ int ret, fd;
+ char buf[10];
+ FeHandler fe = { 0, };
+
+ in = g_strdup_printf("%s.in", pipe);
+ if (mkfifo(in, 0600) < 0) {
+ abort();
+ }
+ out = g_strdup_printf("%s.out", pipe);
+ if (mkfifo(out, 0600) < 0) {
+ abort();
+ }
+
+ tmp = g_strdup_printf("pipe:%s", pipe);
+ chr = qemu_chr_new("pipe", tmp);
+ g_assert_nonnull(chr);
+ g_free(tmp);
+
+ qemu_chr_fe_init(&be, chr, &error_abort);
+
+ ret = qemu_chr_fe_write(&be, (void *)"pipe-out", 9);
+ g_assert_cmpint(ret, ==, 9);
+
+ fd = open(out, O_RDWR);
+ ret = read(fd, buf, sizeof(buf));
+ g_assert_cmpint(ret, ==, 9);
+ g_assert_cmpstr(buf, ==, "pipe-out");
+ close(fd);
+
+ fd = open(in, O_WRONLY);
+ ret = write(fd, "pipe-in", 8);
+ g_assert_cmpint(ret, ==, 8);
+ close(fd);
+
+ qemu_chr_fe_set_handlers(&be,
+ fe_can_read,
+ fe_read,
+ fe_event,
+ &fe,
+ NULL, true);
+
+ main_loop();
+
+ g_assert_cmpint(fe.read_count, ==, 8);
+ g_assert_cmpstr(fe.read_buf, ==, "pipe-in");
+
+ qemu_chr_fe_deinit(&be);
+ object_unparent(OBJECT(chr));
+
+ g_assert(g_unlink(in) == 0);
+ g_assert(g_unlink(out) == 0);
+ g_assert(g_rmdir(tmp_path) == 0);
+ g_free(in);
+ g_free(out);
+ g_free(tmp_path);
+ g_free(pipe);
+}
+#endif
+
+static void char_udp_test(void)
+{
+ struct sockaddr_in addr = { 0, }, other;
+ SocketIdleData d = { 0, };
+ Chardev *chr;
+ CharBackend be;
+ socklen_t alen = sizeof(addr);
+ int ret, sock = qemu_socket(PF_INET, SOCK_DGRAM, 0);
+ char buf[10];
+ char *tmp;
+
+ g_assert_cmpint(sock, >, 0);
+ addr.sin_family = AF_INET ;
+ addr.sin_addr.s_addr = htonl(INADDR_ANY);
+ addr.sin_port = 0;
+ ret = bind(sock, (struct sockaddr *)&addr, sizeof(addr));
+ g_assert_cmpint(ret, ==, 0);
+ ret = getsockname(sock, (struct sockaddr *)&addr, &alen);
+ g_assert_cmpint(ret, ==, 0);
+
+ tmp = g_strdup_printf("udp:127.0.0.1:%d",
+ ntohs(addr.sin_port));
+ chr = qemu_chr_new("client", tmp);
+ g_assert_nonnull(chr);
+
+ d.chr = chr;
+ qemu_chr_fe_init(&be, chr, &error_abort);
+ qemu_chr_fe_set_handlers(&be, socket_can_read_hello, socket_read_hello,
+ NULL, &d, NULL, true);
+ ret = qemu_chr_write_all(chr, (uint8_t *)"hello", 5);
+ g_assert_cmpint(ret, ==, 5);
+
+ alen = sizeof(addr);
+ ret = recvfrom(sock, buf, sizeof(buf), 0,
+ (struct sockaddr *)&other, &alen);
+ g_assert_cmpint(ret, ==, 5);
+ ret = sendto(sock, buf, 5, 0, (struct sockaddr *)&other, alen);
+ g_assert_cmpint(ret, ==, 5);
+
+ main_loop();
+
+ close(sock);
+ g_free(tmp);
+}
+
+static void char_file_test(void)
+{
+ char *tmp_path = g_dir_make_tmp("qemu-test-char.XXXXXX", NULL);
+ char *out = g_build_filename(tmp_path, "out", NULL);
+ char *contents = NULL;
+ ChardevFile file = { .out = out };
+ ChardevBackend backend = { .type = CHARDEV_BACKEND_KIND_FILE,
+ .u.file.data = &file };
+ Chardev *chr;
+ gsize length;
+ int ret;
+
+ chr = qemu_chardev_new(NULL, TYPE_CHARDEV_FILE, &backend,
+ &error_abort);
+ ret = qemu_chr_write_all(chr, (uint8_t *)"hello!", 6);
+ g_assert_cmpint(ret, ==, 6);
+ object_unref(OBJECT(chr));
+
+ ret = g_file_get_contents(out, &contents, &length, NULL);
+ g_assert(ret == TRUE);
+ g_assert_cmpint(length, ==, 6);
+ g_assert(strncmp(contents, "hello!", 6) == 0);
+ g_free(contents);
+
+#ifndef _WIN32
+ {
+ CharBackend be;
+ FeHandler fe = { 0, };
+ char *fifo = g_build_filename(tmp_path, "fifo", NULL);
+ int fd;
+
+ if (mkfifo(fifo, 0600) < 0) {
+ abort();
+ }
+
+ fd = open(fifo, O_RDWR);
+ ret = write(fd, "fifo-in", 8);
+ g_assert_cmpint(ret, ==, 8);
+
+ file.in = fifo;
+ file.has_in = true;
+ chr = qemu_chardev_new(NULL, TYPE_CHARDEV_FILE, &backend,
+ &error_abort);
+
+ qemu_chr_fe_init(&be, chr, &error_abort);
+ qemu_chr_fe_set_handlers(&be,
+ fe_can_read,
+ fe_read,
+ fe_event,
+ &fe, NULL, true);
+
+ main_loop();
+
+ close(fd);
+
+ g_assert_cmpint(fe.read_count, ==, 8);
+ g_assert_cmpstr(fe.read_buf, ==, "fifo-in");
+ qemu_chr_fe_deinit(&be);
+ object_unref(OBJECT(chr));
+ g_unlink(fifo);
+ g_free(fifo);
+ }
+#endif
+
+ g_unlink(out);
+ g_rmdir(tmp_path);
+ g_free(tmp_path);
+ g_free(out);
}
static void char_null_test(void)
@@ -222,7 +565,7 @@ static void char_null_test(void)
g_assert_cmpint(ret, ==, 4);
qemu_chr_fe_deinit(&be);
- qemu_chr_delete(chr);
+ object_unparent(OBJECT(chr));
}
static void char_invalid_test(void)
@@ -235,6 +578,9 @@ static void char_invalid_test(void)
int main(int argc, char **argv)
{
+ qemu_init_main_loop(&error_abort);
+ socket_init();
+
g_test_init(&argc, &argv, NULL);
module_call_init(MODULE_INIT_QOM);
@@ -245,9 +591,19 @@ int main(int argc, char **argv)
g_test_add_func("/char/ringbuf", char_ringbuf_test);
g_test_add_func("/char/mux", char_mux_test);
#ifdef CONFIG_HAS_GLIB_SUBPROCESS_TESTS
+#ifdef _WIN32
+ g_test_add_func("/char/console/subprocess", char_console_test_subprocess);
+ g_test_add_func("/char/console", char_console_test);
+#endif
g_test_add_func("/char/stdio/subprocess", char_stdio_test_subprocess);
g_test_add_func("/char/stdio", char_stdio_test);
#endif
+#ifndef _WIN32
+ g_test_add_func("/char/pipe", char_pipe_test);
+#endif
+ g_test_add_func("/char/file", char_file_test);
+ g_test_add_func("/char/socket", char_socket_test);
+ g_test_add_func("/char/udp", char_udp_test);
return g_test_run();
}
diff --git a/tests/vhost-user-test.c b/tests/vhost-user-test.c
index a61896c..9095af2 100644
--- a/tests/vhost-user-test.c
+++ b/tests/vhost-user-test.c
@@ -491,7 +491,7 @@ static gboolean _test_server_free(TestServer *server)
Chardev *chr = qemu_chr_fe_get_driver(&server->chr);
qemu_chr_fe_deinit(&server->chr);
- qemu_chr_delete(chr);
+ object_unparent(OBJECT(chr));
for (i = 0; i < server->fds_num; i++) {
close(server->fds[i]);
diff --git a/ui/console.c b/ui/console.c
index 189eecf..ac66b3c 100644
--- a/ui/console.c
+++ b/ui/console.c
@@ -2076,7 +2076,7 @@ static void text_console_do_init(Chardev *chr, DisplayState *ds)
s->t_attrib = s->t_attrib_default;
}
- qemu_chr_be_generic_open(chr);
+ qemu_chr_be_event(chr, CHR_EVENT_OPENED);
}
static void vc_chr_open(Chardev *chr,
diff --git a/ui/gtk.c b/ui/gtk.c
index a86848f..7479cee 100644
--- a/ui/gtk.c
+++ b/ui/gtk.c
@@ -1868,7 +1868,7 @@ static GSList *gd_vc_vte_init(GtkDisplayState *s, VirtualConsole *vc,
gtk_notebook_append_page(GTK_NOTEBOOK(s->notebook), vc->tab_item,
gtk_label_new(vc->label));
- qemu_chr_be_generic_open(vc->vte.chr);
+ qemu_chr_be_event(vc->vte.chr, CHR_EVENT_OPENED);
return group;
}
diff --git a/ui/input.c b/ui/input.c
index ed88cda..830f912 100644
--- a/ui/input.c
+++ b/ui/input.c
@@ -41,6 +41,8 @@ static QTAILQ_HEAD(QemuInputEventQueueHead, QemuInputEventQueue) kbd_queue =
QTAILQ_HEAD_INITIALIZER(kbd_queue);
static QEMUTimer *kbd_timer;
static uint32_t kbd_default_delay_ms = 10;
+static uint32_t queue_count;
+static uint32_t queue_limit = 1024;
QemuInputHandlerState *qemu_input_handler_register(DeviceState *dev,
QemuInputHandler *handler)
@@ -268,6 +270,7 @@ static void qemu_input_queue_process(void *opaque)
break;
}
QTAILQ_REMOVE(queue, item, node);
+ queue_count--;
g_free(item);
}
}
@@ -282,6 +285,7 @@ static void qemu_input_queue_delay(struct QemuInputEventQueueHead *queue,
item->delay_ms = delay_ms;
item->timer = timer;
QTAILQ_INSERT_TAIL(queue, item, node);
+ queue_count++;
if (start_timer) {
timer_mod(item->timer, qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL)
@@ -298,6 +302,7 @@ static void qemu_input_queue_event(struct QemuInputEventQueueHead *queue,
item->src = src;
item->evt = evt;
QTAILQ_INSERT_TAIL(queue, item, node);
+ queue_count++;
}
static void qemu_input_queue_sync(struct QemuInputEventQueueHead *queue)
@@ -306,6 +311,7 @@ static void qemu_input_queue_sync(struct QemuInputEventQueueHead *queue)
item->type = QEMU_INPUT_QUEUE_SYNC;
QTAILQ_INSERT_TAIL(queue, item, node);
+ queue_count++;
}
void qemu_input_event_send_impl(QemuConsole *src, InputEvent *evt)
@@ -381,7 +387,7 @@ void qemu_input_event_send_key(QemuConsole *src, KeyValue *key, bool down)
qemu_input_event_send(src, evt);
qemu_input_event_sync();
qapi_free_InputEvent(evt);
- } else {
+ } else if (queue_count < queue_limit) {
qemu_input_queue_event(&kbd_queue, src, evt);
qemu_input_queue_sync(&kbd_queue);
}
@@ -405,12 +411,18 @@ void qemu_input_event_send_key_qcode(QemuConsole *src, QKeyCode q, bool down)
void qemu_input_event_send_key_delay(uint32_t delay_ms)
{
+ if (!runstate_is_running() && !runstate_check(RUN_STATE_SUSPENDED)) {
+ return;
+ }
+
if (!kbd_timer) {
kbd_timer = timer_new_ms(QEMU_CLOCK_VIRTUAL, qemu_input_queue_process,
&kbd_queue);
}
- qemu_input_queue_delay(&kbd_queue, kbd_timer,
- delay_ms ? delay_ms : kbd_default_delay_ms);
+ if (queue_count < queue_limit) {
+ qemu_input_queue_delay(&kbd_queue, kbd_timer,
+ delay_ms ? delay_ms : kbd_default_delay_ms);
+ }
}
InputEvent *qemu_input_event_new_btn(InputButton btn, bool down)
diff --git a/util/qemu-config.c b/util/qemu-config.c
index 5527100..405dd1a 100644
--- a/util/qemu-config.c
+++ b/util/qemu-config.c
@@ -227,6 +227,12 @@ static QemuOptsList machine_opts = {
.name = "dea-key-wrap",
.type = QEMU_OPT_BOOL,
.help = "enable/disable DEA key wrapping using the CPACF wrapping key",
+ },{
+ .name = "loadparm",
+ .type = QEMU_OPT_STRING,
+ .help = "Up to 8 chars in set of [A-Za-z0-9. ](lower case chars"
+ " converted to upper case) to pass to machine"
+ " loader, boot manager, and guest kernel",
},
{ /* End of list */ }
}
diff --git a/util/qemu-progress.c b/util/qemu-progress.c
index f745233..3c2223c 100644
--- a/util/qemu-progress.c
+++ b/util/qemu-progress.c
@@ -88,6 +88,9 @@ static void progress_dummy_init(void)
action.sa_handler = sigusr_print;
action.sa_flags = 0;
sigaction(SIGUSR1, &action, NULL);
+#ifdef SIGINFO
+ sigaction(SIGINFO, &action, NULL);
+#endif
/*
* SIGUSR1 is SIG_IPI and gets blocked in qemu_init_main_loop(). In the
diff --git a/vl.c b/vl.c
index f46e070..560288f 100644
--- a/vl.c
+++ b/vl.c
@@ -3231,6 +3231,8 @@ int main(int argc, char **argv, char **envp)
}
}
}
+ error_report("'-hdachs' is deprecated, please use '-device"
+ " ide-hd,cyls=c,heads=h,secs=s,...' instead");
break;
case QEMU_OPTION_numa:
opts = qemu_opts_parse_noisily(qemu_find_opts("numa"),
@@ -4727,6 +4729,7 @@ int main(int argc, char **argv, char **envp)
audio_cleanup();
monitor_cleanup();
qemu_chr_cleanup();
+ /* TODO: unref root container, check all devices are ok */
return 0;
}