Merge remote-tracking branch 'remotes/vivier2/tags/linux-user-for-3.1-pull-request' into staging
- gdb signal handling fix
- add SO_REUSEPORT
- remove dead-code
# gpg: Signature made Mon 12 Nov 2018 20:48:23 GMT
# gpg: using RSA key F30C38BD3F2FBE3C
# gpg: Good signature from "Laurent Vivier <lvivier@redhat.com>"
# gpg: aka "Laurent Vivier <laurent@vivier.eu>"
# gpg: aka "Laurent Vivier (Red Hat) <lvivier@redhat.com>"
# Primary key fingerprint: CD2F 75DD C8E3 A4DC 2E4F 5173 F30C 38BD 3F2F BE3C
* remotes/vivier2/tags/linux-user-for-3.1-pull-request:
linux-user: Add support for SO_REUSEPORT
linux-user: Clean up nios2 main loop signal handling
linux-user: Don't call gdb_handlesig() before queue_signal()
linux-user: Remove dead error-checking code
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
diff --git a/MAINTAINERS b/MAINTAINERS
index c076758..4b8db61 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -591,6 +591,13 @@
F: hw/misc/mst_fpga.c
F: include/hw/arm/pxa.h
+Sharp SL-5500 (Collie) PDA
+M: Peter Maydell <peter.maydell@linaro.org>
+L: qemu-arm@nongnu.org
+S: Odd Fixes
+F: hw/arm/collie.c
+F: hw/arm/strongarm*
+
Stellaris
M: Peter Maydell <peter.maydell@linaro.org>
L: qemu-arm@nongnu.org
diff --git a/audio/paaudio.c b/audio/paaudio.c
index 9497697..4c100bc 100644
--- a/audio/paaudio.c
+++ b/audio/paaudio.c
@@ -227,7 +227,7 @@
}
}
- decr = to_mix = audio_MIN (pa->live, pa->g->conf.samples >> 2);
+ decr = to_mix = audio_MIN(pa->live, pa->g->conf.samples >> 5);
rpos = pa->rpos;
if (audio_pt_unlock(&pa->pt, __func__)) {
@@ -319,7 +319,7 @@
}
}
- incr = to_grab = audio_MIN (pa->dead, pa->g->conf.samples >> 2);
+ incr = to_grab = audio_MIN(pa->dead, pa->g->conf.samples >> 5);
wpos = pa->wpos;
if (audio_pt_unlock(&pa->pt, __func__)) {
diff --git a/block/Makefile.objs b/block/Makefile.objs
index c8337bf..46d585c 100644
--- a/block/Makefile.objs
+++ b/block/Makefile.objs
@@ -1,10 +1,18 @@
-block-obj-y += raw-format.o qcow.o vdi.o vmdk.o cloop.o bochs.o vpc.o vvfat.o dmg.o
+block-obj-y += raw-format.o vmdk.o vpc.o
+block-obj-$(CONFIG_QCOW1) += qcow.o
+block-obj-$(CONFIG_VDI) += vdi.o
+block-obj-$(CONFIG_CLOOP) += cloop.o
+block-obj-$(CONFIG_BOCHS) += bochs.o
+block-obj-$(CONFIG_VVFAT) += vvfat.o
+block-obj-$(CONFIG_DMG) += dmg.o
+
block-obj-y += qcow2.o qcow2-refcount.o qcow2-cluster.o qcow2-snapshot.o qcow2-cache.o qcow2-bitmap.o
-block-obj-y += qed.o qed-l2-cache.o qed-table.o qed-cluster.o
-block-obj-y += qed-check.o
+block-obj-$(CONFIG_QED) += qed.o qed-l2-cache.o qed-table.o qed-cluster.o
+block-obj-$(CONFIG_QED) += qed-check.o
block-obj-y += vhdx.o vhdx-endian.o vhdx-log.o
block-obj-y += quorum.o
-block-obj-y += parallels.o blkdebug.o blkverify.o blkreplay.o
+block-obj-y += blkdebug.o blkverify.o blkreplay.o
+block-obj-$(CONFIG_PARALLELS) += parallels.o
block-obj-y += blklogwrites.o
block-obj-y += block-backend.o snapshot.o qapi.o
block-obj-$(CONFIG_WIN32) += file-win32.o win32-aio.o
@@ -14,7 +22,8 @@
block-obj-y += throttle-groups.o
block-obj-$(CONFIG_LINUX) += nvme.o
-block-obj-y += nbd.o nbd-client.o sheepdog.o
+block-obj-y += nbd.o nbd-client.o
+block-obj-$(CONFIG_SHEEPDOG) += sheepdog.o
block-obj-$(CONFIG_LIBISCSI) += iscsi.o
block-obj-$(if $(CONFIG_LIBISCSI),y,n) += iscsi-opts.o
block-obj-$(CONFIG_LIBNFS) += nfs.o
@@ -45,7 +54,8 @@
vxhs.o-libs := $(VXHS_LIBS)
ssh.o-cflags := $(LIBSSH2_CFLAGS)
ssh.o-libs := $(LIBSSH2_LIBS)
-block-obj-$(if $(CONFIG_BZIP2),m,n) += dmg-bz2.o
+block-obj-dmg-bz2-$(CONFIG_BZIP2) += dmg-bz2.o
+block-obj-$(if $(CONFIG_DMG),m,n) += $(block-obj-dmg-bz2-y)
dmg-bz2.o-libs := $(BZIP2_LIBS)
qcow.o-libs := -lz
linux-aio.o-libs := -laio
diff --git a/block/block-backend.c b/block/block-backend.c
index 2a8f3b5..60d37a0 100644
--- a/block/block-backend.c
+++ b/block/block-backend.c
@@ -918,7 +918,8 @@
} else if (dev->id) {
return g_strdup(dev->id);
}
- return object_get_canonical_path(OBJECT(dev));
+
+ return object_get_canonical_path(OBJECT(dev)) ?: g_strdup("");
}
/*
diff --git a/block/file-posix.c b/block/file-posix.c
index 0c1b81c..58c86a0 100644
--- a/block/file-posix.c
+++ b/block/file-posix.c
@@ -142,7 +142,6 @@
typedef struct BDRVRawState {
int fd;
- int lock_fd;
bool use_lock;
int type;
int open_flags;
@@ -152,6 +151,11 @@
uint64_t perm;
uint64_t shared_perm;
+ /* The perms bits whose corresponding bytes are already locked in
+ * s->fd. */
+ uint64_t locked_perm;
+ uint64_t locked_shared_perm;
+
#ifdef CONFIG_XFS
bool is_xfs:1;
#endif
@@ -205,7 +209,7 @@
#endif
#if defined(__NetBSD__)
-static int raw_normalize_devicepath(const char **filename)
+static int raw_normalize_devicepath(const char **filename, Error **errp)
{
static char namebuf[PATH_MAX];
const char *dp, *fname;
@@ -214,8 +218,7 @@
fname = *filename;
dp = strrchr(fname, '/');
if (lstat(fname, &sb) < 0) {
- fprintf(stderr, "%s: stat failed: %s\n",
- fname, strerror(errno));
+ error_setg_errno(errp, errno, "%s: stat failed", fname);
return -errno;
}
@@ -229,14 +232,13 @@
snprintf(namebuf, PATH_MAX, "%.*s/r%s",
(int)(dp - fname), fname, dp + 1);
}
- fprintf(stderr, "%s is a block device", fname);
*filename = namebuf;
- fprintf(stderr, ", using %s\n", *filename);
+ warn_report("%s is a block device, using %s", fname, *filename);
return 0;
}
#else
-static int raw_normalize_devicepath(const char **filename)
+static int raw_normalize_devicepath(const char **filename, Error **errp)
{
return 0;
}
@@ -461,9 +463,8 @@
filename = qemu_opt_get(opts, "filename");
- ret = raw_normalize_devicepath(&filename);
+ ret = raw_normalize_devicepath(&filename, errp);
if (ret != 0) {
- error_setg_errno(errp, -ret, "Could not normalize device path");
goto fail;
}
@@ -492,11 +493,10 @@
case ON_OFF_AUTO_ON:
s->use_lock = true;
if (!qemu_has_ofd_lock()) {
- fprintf(stderr,
- "File lock requested but OFD locking syscall is "
- "unavailable, falling back to POSIX file locks.\n"
- "Due to the implementation, locks can be lost "
- "unexpectedly.\n");
+ warn_report("File lock requested but OFD locking syscall is "
+ "unavailable, falling back to POSIX file locks");
+ error_printf("Due to the implementation, locks can be lost "
+ "unexpectedly.\n");
}
break;
case ON_OFF_AUTO_OFF:
@@ -550,18 +550,6 @@
}
s->fd = fd;
- s->lock_fd = -1;
- if (s->use_lock) {
- fd = qemu_open(filename, s->open_flags);
- if (fd < 0) {
- ret = -errno;
- error_setg_errno(errp, errno, "Could not open '%s' for locking",
- filename);
- qemu_close(s->fd);
- goto fail;
- }
- s->lock_fd = fd;
- }
s->perm = 0;
s->shared_perm = BLK_PERM_ALL;
@@ -693,43 +681,72 @@
* file; if @unlock == true, also unlock the unneeded bytes.
* @shared_perm_lock_bits is the mask of all permissions that are NOT shared.
*/
-static int raw_apply_lock_bytes(int fd,
+static int raw_apply_lock_bytes(BDRVRawState *s, int fd,
uint64_t perm_lock_bits,
uint64_t shared_perm_lock_bits,
bool unlock, Error **errp)
{
int ret;
int i;
+ uint64_t locked_perm, locked_shared_perm;
+
+ if (s) {
+ locked_perm = s->locked_perm;
+ locked_shared_perm = s->locked_shared_perm;
+ } else {
+ /*
+ * We don't have the previous bits, just lock/unlock for each of the
+ * requested bits.
+ */
+ if (unlock) {
+ locked_perm = BLK_PERM_ALL;
+ locked_shared_perm = BLK_PERM_ALL;
+ } else {
+ locked_perm = 0;
+ locked_shared_perm = 0;
+ }
+ }
PERM_FOREACH(i) {
int off = RAW_LOCK_PERM_BASE + i;
- if (perm_lock_bits & (1ULL << i)) {
+ uint64_t bit = (1ULL << i);
+ if ((perm_lock_bits & bit) && !(locked_perm & bit)) {
ret = qemu_lock_fd(fd, off, 1, false);
if (ret) {
error_setg(errp, "Failed to lock byte %d", off);
return ret;
+ } else if (s) {
+ s->locked_perm |= bit;
}
- } else if (unlock) {
+ } else if (unlock && (locked_perm & bit) && !(perm_lock_bits & bit)) {
ret = qemu_unlock_fd(fd, off, 1);
if (ret) {
error_setg(errp, "Failed to unlock byte %d", off);
return ret;
+ } else if (s) {
+ s->locked_perm &= ~bit;
}
}
}
PERM_FOREACH(i) {
int off = RAW_LOCK_SHARED_BASE + i;
- if (shared_perm_lock_bits & (1ULL << i)) {
+ uint64_t bit = (1ULL << i);
+ if ((shared_perm_lock_bits & bit) && !(locked_shared_perm & bit)) {
ret = qemu_lock_fd(fd, off, 1, false);
if (ret) {
error_setg(errp, "Failed to lock byte %d", off);
return ret;
+ } else if (s) {
+ s->locked_shared_perm |= bit;
}
- } else if (unlock) {
+ } else if (unlock && (locked_shared_perm & bit) &&
+ !(shared_perm_lock_bits & bit)) {
ret = qemu_unlock_fd(fd, off, 1);
if (ret) {
error_setg(errp, "Failed to unlock byte %d", off);
return ret;
+ } else if (s) {
+ s->locked_shared_perm &= ~bit;
}
}
}
@@ -793,15 +810,13 @@
return 0;
}
- assert(s->lock_fd > 0);
-
switch (op) {
case RAW_PL_PREPARE:
- ret = raw_apply_lock_bytes(s->lock_fd, s->perm | new_perm,
+ ret = raw_apply_lock_bytes(s, s->fd, s->perm | new_perm,
~s->shared_perm | ~new_shared,
false, errp);
if (!ret) {
- ret = raw_check_lock_bytes(s->lock_fd, new_perm, new_shared, errp);
+ ret = raw_check_lock_bytes(s->fd, new_perm, new_shared, errp);
if (!ret) {
return 0;
}
@@ -812,23 +827,23 @@
op = RAW_PL_ABORT;
/* fall through to unlock bytes. */
case RAW_PL_ABORT:
- raw_apply_lock_bytes(s->lock_fd, s->perm, ~s->shared_perm,
+ raw_apply_lock_bytes(s, s->fd, s->perm, ~s->shared_perm,
true, &local_err);
if (local_err) {
/* Theoretically the above call only unlocks bytes and it cannot
* fail. Something weird happened, report it.
*/
- error_report_err(local_err);
+ warn_report_err(local_err);
}
break;
case RAW_PL_COMMIT:
- raw_apply_lock_bytes(s->lock_fd, new_perm, ~new_shared,
+ raw_apply_lock_bytes(s, s->fd, new_perm, ~new_shared,
true, &local_err);
if (local_err) {
/* Theoretically the above call only unlocks bytes and it cannot
* fail. Something weird happened, report it.
*/
- error_report_err(local_err);
+ warn_report_err(local_err);
}
break;
}
@@ -905,10 +920,8 @@
/* If we cannot use fcntl, or fcntl failed, fall back to qemu_open() */
if (rs->fd == -1) {
const char *normalized_filename = state->bs->filename;
- ret = raw_normalize_devicepath(&normalized_filename);
- if (ret < 0) {
- error_setg_errno(errp, -ret, "Could not normalize device path");
- } else {
+ ret = raw_normalize_devicepath(&normalized_filename, errp);
+ if (ret >= 0) {
assert(!(rs->open_flags & O_CREAT));
rs->fd = qemu_open(normalized_filename, rs->open_flags);
if (rs->fd == -1) {
@@ -939,10 +952,18 @@
{
BDRVRawReopenState *rs = state->opaque;
BDRVRawState *s = state->bs->opaque;
+ Error *local_err = NULL;
s->check_cache_dropped = rs->check_cache_dropped;
s->open_flags = rs->open_flags;
+ /* Copy locks to the new fd before closing the old one. */
+ raw_apply_lock_bytes(NULL, rs->fd, s->locked_perm,
+ ~s->locked_shared_perm, false, &local_err);
+ if (local_err) {
+ /* shouldn't fail in a sane host, but report it just in case. */
+ error_report_err(local_err);
+ }
qemu_close(s->fd);
s->fd = rs->fd;
@@ -1788,7 +1809,7 @@
ret = handle_aiocb_truncate(aiocb);
break;
default:
- fprintf(stderr, "invalid aio request (0x%x)\n", aiocb->aio_type);
+ error_report("invalid aio request (0x%x)", aiocb->aio_type);
ret = -EINVAL;
break;
}
@@ -1935,10 +1956,6 @@
qemu_close(s->fd);
s->fd = -1;
}
- if (s->lock_fd >= 0) {
- qemu_close(s->lock_fd);
- s->lock_fd = -1;
- }
}
/**
@@ -2226,7 +2243,7 @@
shared = BLK_PERM_ALL & ~BLK_PERM_RESIZE;
/* Step one: Take locks */
- result = raw_apply_lock_bytes(fd, perm, ~shared, false, errp);
+ result = raw_apply_lock_bytes(NULL, fd, perm, ~shared, false, errp);
if (result < 0) {
goto out_close;
}
@@ -2270,13 +2287,13 @@
}
out_unlock:
- raw_apply_lock_bytes(fd, 0, 0, true, &local_err);
+ raw_apply_lock_bytes(NULL, fd, 0, 0, true, &local_err);
if (local_err) {
/* The above call should not fail, and if it does, that does
* not mean the whole creation operation has failed. So
* report it the user for their convenience, but do not report
* it to the caller. */
- error_report_err(local_err);
+ warn_report_err(local_err);
}
out_close:
@@ -3141,9 +3158,8 @@
(void)has_prefix;
- ret = raw_normalize_devicepath(&filename);
+ ret = raw_normalize_devicepath(&filename, errp);
if (ret < 0) {
- error_setg_errno(errp, -ret, "Could not normalize device path");
return ret;
}
diff --git a/block/qcow2-refcount.c b/block/qcow2-refcount.c
index 3c539f0..46082ae 100644
--- a/block/qcow2-refcount.c
+++ b/block/qcow2-refcount.c
@@ -2719,15 +2719,17 @@
}
static const char *metadata_ol_names[] = {
- [QCOW2_OL_MAIN_HEADER_BITNR] = "qcow2_header",
- [QCOW2_OL_ACTIVE_L1_BITNR] = "active L1 table",
- [QCOW2_OL_ACTIVE_L2_BITNR] = "active L2 table",
- [QCOW2_OL_REFCOUNT_TABLE_BITNR] = "refcount table",
- [QCOW2_OL_REFCOUNT_BLOCK_BITNR] = "refcount block",
- [QCOW2_OL_SNAPSHOT_TABLE_BITNR] = "snapshot table",
- [QCOW2_OL_INACTIVE_L1_BITNR] = "inactive L1 table",
- [QCOW2_OL_INACTIVE_L2_BITNR] = "inactive L2 table",
+ [QCOW2_OL_MAIN_HEADER_BITNR] = "qcow2_header",
+ [QCOW2_OL_ACTIVE_L1_BITNR] = "active L1 table",
+ [QCOW2_OL_ACTIVE_L2_BITNR] = "active L2 table",
+ [QCOW2_OL_REFCOUNT_TABLE_BITNR] = "refcount table",
+ [QCOW2_OL_REFCOUNT_BLOCK_BITNR] = "refcount block",
+ [QCOW2_OL_SNAPSHOT_TABLE_BITNR] = "snapshot table",
+ [QCOW2_OL_INACTIVE_L1_BITNR] = "inactive L1 table",
+ [QCOW2_OL_INACTIVE_L2_BITNR] = "inactive L2 table",
+ [QCOW2_OL_BITMAP_DIRECTORY_BITNR] = "bitmap directory",
};
+QEMU_BUILD_BUG_ON(QCOW2_OL_MAX_BITNR != ARRAY_SIZE(metadata_ol_names));
/*
* First performs a check for metadata overlaps (through
diff --git a/block/vvfat.c b/block/vvfat.c
index e4df255..1de5de1 100644
--- a/block/vvfat.c
+++ b/block/vvfat.c
@@ -100,30 +100,26 @@
/* does not automatically grow */
static inline void* array_get(array_t* array,unsigned int index) {
assert(index < array->next);
+ assert(array->pointer);
return array->pointer + index * array->item_size;
}
-static inline int array_ensure_allocated(array_t* array, int index)
+static inline void array_ensure_allocated(array_t *array, int index)
{
if((index + 1) * array->item_size > array->size) {
int new_size = (index + 32) * array->item_size;
array->pointer = g_realloc(array->pointer, new_size);
- if (!array->pointer)
- return -1;
+ assert(array->pointer);
memset(array->pointer + array->size, 0, new_size - array->size);
array->size = new_size;
array->next = index + 1;
}
-
- return 0;
}
static inline void* array_get_next(array_t* array) {
unsigned int next = array->next;
- if (array_ensure_allocated(array, next) < 0)
- return NULL;
-
+ array_ensure_allocated(array, next);
array->next = next + 1;
return array_get(array, next);
}
@@ -2422,16 +2418,13 @@
direntry_t* direntry = array_get(&(s->directory), dir_index);
uint32_t first_cluster = dir_index == 0 ? 0 : begin_of_direntry(direntry);
mapping_t* mapping = find_mapping_for_cluster(s, first_cluster);
-
int factor = 0x10 * s->sectors_per_cluster;
int old_cluster_count, new_cluster_count;
- int current_dir_index = mapping->info.dir.first_dir_index;
- int first_dir_index = current_dir_index;
+ int current_dir_index;
+ int first_dir_index;
int ret, i;
uint32_t c;
-DLOG(fprintf(stderr, "commit_direntries for %s, parent_mapping_index %d\n", mapping->path, parent_mapping_index));
-
assert(direntry);
assert(mapping);
assert(mapping->begin == first_cluster);
@@ -2439,6 +2432,11 @@
assert(mapping->mode & MODE_DIRECTORY);
assert(dir_index == 0 || is_directory(direntry));
+ DLOG(fprintf(stderr, "commit_direntries for %s, parent_mapping_index %d\n",
+ mapping->path, parent_mapping_index));
+
+ current_dir_index = mapping->info.dir.first_dir_index;
+ first_dir_index = current_dir_index;
mapping->info.dir.parent_mapping_index = parent_mapping_index;
if (first_cluster == 0) {
@@ -2488,6 +2486,9 @@
direntry = array_get(&(s->directory), first_dir_index + i);
if (is_directory(direntry) && !is_dot(direntry)) {
mapping = find_mapping_for_cluster(s, first_cluster);
+ if (mapping == NULL) {
+ return -1;
+ }
assert(mapping->mode & MODE_DIRECTORY);
ret = commit_direntries(s, first_dir_index + i,
array_index(&(s->mapping), mapping));
@@ -2516,6 +2517,10 @@
assert(offset < size);
assert((offset % s->cluster_size) == 0);
+ if (mapping == NULL) {
+ return -1;
+ }
+
for (i = s->cluster_size; i < offset; i += s->cluster_size)
c = modified_fat_get(s, c);
@@ -2662,8 +2667,12 @@
if (commit->action == ACTION_RENAME) {
mapping_t* mapping = find_mapping_for_cluster(s,
commit->param.rename.cluster);
- char* old_path = mapping->path;
+ char *old_path;
+ if (mapping == NULL) {
+ return -1;
+ }
+ old_path = mapping->path;
assert(commit->path);
mapping->path = commit->path;
if (rename(old_path, mapping->path))
@@ -2684,10 +2693,15 @@
direntry_t* d = direntry + i;
if (is_file(d) || (is_directory(d) && !is_dot(d))) {
+ int l;
+ char *new_path;
mapping_t* m = find_mapping_for_cluster(s,
begin_of_direntry(d));
- int l = strlen(m->path);
- char* new_path = g_malloc(l + diff + 1);
+ if (m == NULL) {
+ return -1;
+ }
+ l = strlen(m->path);
+ new_path = g_malloc(l + diff + 1);
assert(!strncmp(m->path, mapping->path, l2));
diff --git a/blockdev.c b/blockdev.c
index e5b5eb4..81f95d9 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -1640,7 +1640,7 @@
}
options = qdict_new();
- if (s->has_snapshot_node_name) {
+ if (snapshot_node_name) {
qdict_put_str(options, "node-name", snapshot_node_name);
}
qdict_put_str(options, "driver", format);
@@ -4413,6 +4413,7 @@
{
BlockBackend *blk = blk_by_name(device);
BlockAcctStats *stats;
+ int ret;
if (!blk) {
error_setg(errp, "Device '%s' not found", device);
@@ -4428,21 +4429,33 @@
}
if (has_boundaries || has_boundaries_read) {
- block_latency_histogram_set(
+ ret = block_latency_histogram_set(
stats, BLOCK_ACCT_READ,
has_boundaries_read ? boundaries_read : boundaries);
+ if (ret) {
+ error_setg(errp, "Device '%s' set read boundaries fail", device);
+ return;
+ }
}
if (has_boundaries || has_boundaries_write) {
- block_latency_histogram_set(
+ ret = block_latency_histogram_set(
stats, BLOCK_ACCT_WRITE,
has_boundaries_write ? boundaries_write : boundaries);
+ if (ret) {
+ error_setg(errp, "Device '%s' set write boundaries fail", device);
+ return;
+ }
}
if (has_boundaries || has_boundaries_flush) {
- block_latency_histogram_set(
+ ret = block_latency_histogram_set(
stats, BLOCK_ACCT_FLUSH,
has_boundaries_flush ? boundaries_flush : boundaries);
+ if (ret) {
+ error_setg(errp, "Device '%s' set flush boundaries fail", device);
+ return;
+ }
}
}
diff --git a/configure b/configure
index 74e313a..5b1d83e 100755
--- a/configure
+++ b/configure
@@ -470,6 +470,15 @@
jemalloc="no"
replication="yes"
vxhs=""
+bochs="yes"
+cloop="yes"
+dmg="yes"
+qcow1="yes"
+vdi="yes"
+vvfat="yes"
+qed="yes"
+parallels="yes"
+sheepdog="yes"
libxml2=""
docker="no"
debug_mutex="no"
@@ -1416,6 +1425,42 @@
;;
--enable-vxhs) vxhs="yes"
;;
+ --disable-bochs) bochs="no"
+ ;;
+ --enable-bochs) bochs="yes"
+ ;;
+ --disable-cloop) cloop="no"
+ ;;
+ --enable-cloop) cloop="yes"
+ ;;
+ --disable-dmg) dmg="no"
+ ;;
+ --enable-dmg) dmg="yes"
+ ;;
+ --disable-qcow1) qcow1="no"
+ ;;
+ --enable-qcow1) qcow1="yes"
+ ;;
+ --disable-vdi) vdi="no"
+ ;;
+ --enable-vdi) vdi="yes"
+ ;;
+ --disable-vvfat) vvfat="no"
+ ;;
+ --enable-vvfat) vvfat="yes"
+ ;;
+ --disable-qed) qed="no"
+ ;;
+ --enable-qed) qed="yes"
+ ;;
+ --disable-parallels) parallels="no"
+ ;;
+ --enable-parallels) parallels="yes"
+ ;;
+ --disable-sheepdog) sheepdog="no"
+ ;;
+ --enable-sheepdog) sheepdog="yes"
+ ;;
--disable-vhost-user) vhost_user="no"
;;
--enable-vhost-user)
@@ -1718,6 +1763,15 @@
qom-cast-debug cast debugging support
tools build qemu-io, qemu-nbd and qemu-image tools
vxhs Veritas HyperScale vDisk backend support
+ bochs bochs image format support
+ cloop cloop image format support
+ dmg dmg image format support
+ qcow1 qcow v1 image format support
+ vdi vdi image format support
+ vvfat vvfat image format support
+ qed qed image format support
+ parallels parallels image format support
+ sheepdog sheepdog block driver support
crypto-afalg Linux AF_ALG crypto backend driver
vhost-user vhost-user support
capstone capstone disassembler support
@@ -6043,6 +6097,15 @@
echo "avx2 optimization $avx2_opt"
echo "replication support $replication"
echo "VxHS block device $vxhs"
+echo "bochs support $bochs"
+echo "cloop support $cloop"
+echo "dmg support $dmg"
+echo "qcow v1 support $qcow1"
+echo "vdi support $vdi"
+echo "vvfat support $vvfat"
+echo "qed support $qed"
+echo "parallels support $parallels"
+echo "sheepdog support $sheepdog"
echo "capstone $capstone"
echo "docker $docker"
echo "libpmem support $libpmem"
@@ -6799,6 +6862,34 @@
echo "CONFIG_LIBPMEM=y" >> $config_host_mak
fi
+if test "$bochs" = "yes" ; then
+ echo "CONFIG_BOCHS=y" >> $config_host_mak
+fi
+if test "$cloop" = "yes" ; then
+ echo "CONFIG_CLOOP=y" >> $config_host_mak
+fi
+if test "$dmg" = "yes" ; then
+ echo "CONFIG_DMG=y" >> $config_host_mak
+fi
+if test "$qcow1" = "yes" ; then
+ echo "CONFIG_QCOW1=y" >> $config_host_mak
+fi
+if test "$vdi" = "yes" ; then
+ echo "CONFIG_VDI=y" >> $config_host_mak
+fi
+if test "$vvfat" = "yes" ; then
+ echo "CONFIG_VVFAT=y" >> $config_host_mak
+fi
+if test "$qed" = "yes" ; then
+ echo "CONFIG_QED=y" >> $config_host_mak
+fi
+if test "$parallels" = "yes" ; then
+ echo "CONFIG_PARALLELS=y" >> $config_host_mak
+fi
+if test "$sheepdog" = "yes" ; then
+ echo "CONFIG_SHEEPDOG=y" >> $config_host_mak
+fi
+
if test "$tcg_interpreter" = "yes"; then
QEMU_INCLUDES="-iquote \$(SRC_PATH)/tcg/tci $QEMU_INCLUDES"
elif test "$ARCH" = "sparc64" ; then
diff --git a/hw/acpi/nvdimm.c b/hw/acpi/nvdimm.c
index 27eeb66..e53b2cb 100644
--- a/hw/acpi/nvdimm.c
+++ b/hw/acpi/nvdimm.c
@@ -581,7 +581,7 @@
int size;
read_fit = (NvdimmFuncReadFITIn *)in->arg3;
- le32_to_cpus(&read_fit->offset);
+ read_fit->offset = le32_to_cpu(read_fit->offset);
fit = fit_buf->fit;
@@ -742,8 +742,8 @@
int size;
get_label_data = (NvdimmFuncGetLabelDataIn *)in->arg3;
- le32_to_cpus(&get_label_data->offset);
- le32_to_cpus(&get_label_data->length);
+ get_label_data->offset = le32_to_cpu(get_label_data->offset);
+ get_label_data->length = le32_to_cpu(get_label_data->length);
nvdimm_debug("Read Label Data: offset %#x length %#x.\n",
get_label_data->offset, get_label_data->length);
@@ -781,8 +781,8 @@
set_label_data = (NvdimmFuncSetLabelDataIn *)in->arg3;
- le32_to_cpus(&set_label_data->offset);
- le32_to_cpus(&set_label_data->length);
+ set_label_data->offset = le32_to_cpu(set_label_data->offset);
+ set_label_data->length = le32_to_cpu(set_label_data->length);
nvdimm_debug("Write Label Data: offset %#x length %#x.\n",
set_label_data->offset, set_label_data->length);
@@ -877,9 +877,9 @@
in = g_new(NvdimmDsmIn, 1);
cpu_physical_memory_read(dsm_mem_addr, in, sizeof(*in));
- le32_to_cpus(&in->revision);
- le32_to_cpus(&in->function);
- le32_to_cpus(&in->handle);
+ in->revision = le32_to_cpu(in->revision);
+ in->function = le32_to_cpu(in->function);
+ in->handle = le32_to_cpu(in->handle);
nvdimm_debug("Revision %#x Handler %#x Function %#x.\n", in->revision,
in->handle, in->function);
diff --git a/hw/arm/sysbus-fdt.c b/hw/arm/sysbus-fdt.c
index 0e24c80..ad698d4 100644
--- a/hw/arm/sysbus-fdt.c
+++ b/hw/arm/sysbus-fdt.c
@@ -449,7 +449,7 @@
return !strcmp(object_get_typename(OBJECT(sbdev)), entry->typename);
}
-#define TYPE_BINDING(type, add_fn) {(type), NULL, (add_fn), type_match}
+#define TYPE_BINDING(type, add_fn) {(type), NULL, (add_fn), NULL}
/* list of supported dynamic sysbus bindings */
static const BindingEntry bindings[] = {
@@ -481,10 +481,12 @@
for (i = 0; i < ARRAY_SIZE(bindings); i++) {
const BindingEntry *iter = &bindings[i];
- if (iter->match_fn(sbdev, iter)) {
- ret = iter->add_fn(sbdev, opaque);
- assert(!ret);
- return;
+ if (type_match(sbdev, iter)) {
+ if (!iter->match_fn || iter->match_fn(sbdev, iter)) {
+ ret = iter->add_fn(sbdev, opaque);
+ assert(!ret);
+ return;
+ }
}
}
error_report("Device %s can not be dynamically instantiated",
diff --git a/hw/block/nvme.c b/hw/block/nvme.c
index fc7dacb..09d7c90 100644
--- a/hw/block/nvme.c
+++ b/hw/block/nvme.c
@@ -1331,10 +1331,10 @@
g_free(n->namespaces);
g_free(n->cq);
g_free(n->sq);
- if (n->cmbsz) {
- memory_region_unref(&n->ctrl_mem);
- }
+ if (n->cmb_size_mb) {
+ g_free(n->cmbuf);
+ }
msix_uninit_exclusive_bar(pci_dev);
}
diff --git a/hw/display/edid-generate.c b/hw/display/edid-generate.c
index bdf5e1d..77d9127 100644
--- a/hw/display/edid-generate.c
+++ b/hw/display/edid-generate.c
@@ -165,7 +165,7 @@
if (len > 12) {
len = 12;
}
- strncpy((char *)(desc + 5), text, len);
+ memcpy(desc + 5, text, len);
desc[5 + len] = '\n';
}
diff --git a/job.c b/job.c
index c65e01b..da8e4b7 100644
--- a/job.c
+++ b/job.c
@@ -159,7 +159,7 @@
static void job_state_transition(Job *job, JobStatus s1)
{
JobStatus s0 = job->status;
- assert(s1 >= 0 && s1 <= JOB_STATUS__MAX);
+ assert(s1 >= 0 && s1 < JOB_STATUS__MAX);
trace_job_state_transition(job, job->ret,
JobSTT[s0][s1] ? "allowed" : "disallowed",
JobStatus_str(s0), JobStatus_str(s1));
@@ -174,7 +174,7 @@
int job_apply_verb(Job *job, JobVerb verb, Error **errp)
{
JobStatus s0 = job->status;
- assert(verb >= 0 && verb <= JOB_VERB__MAX);
+ assert(verb >= 0 && verb < JOB_VERB__MAX);
trace_job_apply_verb(job, JobStatus_str(s0), JobVerb_str(verb),
JobVerbTable[verb][s0] ? "allowed" : "prohibited");
if (JobVerbTable[verb][s0]) {
diff --git a/qemu-deprecated.texi b/qemu-deprecated.texi
index 5d2d7a3..cb4291f 100644
--- a/qemu-deprecated.texi
+++ b/qemu-deprecated.texi
@@ -128,6 +128,13 @@
The ``ivshmem'' device type is replaced by either the ``ivshmem-plain''
or ``ivshmem-doorbell`` device types.
+@subsection bluetooth (since 3.1)
+
+The bluetooth subsystem is unmaintained since many years and likely bitrotten
+quite a bit. It will be removed without replacement unless some users speaks
+up at the @email{qemu-devel@@nongnu.org} mailing list with information about
+their usecases.
+
@section System emulator machines
@subsection pc-0.10 and pc-0.11 (since 3.0)
diff --git a/qemu-img.c b/qemu-img.c
index 4c96db7..13a6ca3 100644
--- a/qemu-img.c
+++ b/qemu-img.c
@@ -1029,6 +1029,7 @@
}
job = block_job_get("commit");
+ assert(job);
run_block_job(job, &local_err);
if (local_err) {
goto unref_backing;
diff --git a/qemu-options.hx b/qemu-options.hx
index 38c7a97..ee379b3 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -2772,6 +2772,10 @@
the machines @code{n800} and @code{n810} have one HCI and all other
machines have none.
+Note: This option and the whole bluetooth subsystem is considered as deprecated.
+If you still use it, please send a mail to @email{qemu-devel@@nongnu.org} where
+you describe your usecase.
+
@anchor{bt-hcis}
The following three types are recognized:
diff --git a/target/arm/cpu.c b/target/arm/cpu.c
index 784a4c2..60411f6 100644
--- a/target/arm/cpu.c
+++ b/target/arm/cpu.c
@@ -436,6 +436,48 @@
}
#endif
+void arm_cpu_update_virq(ARMCPU *cpu)
+{
+ /*
+ * Update the interrupt level for VIRQ, which is the logical OR of
+ * the HCR_EL2.VI bit and the input line level from the GIC.
+ */
+ CPUARMState *env = &cpu->env;
+ CPUState *cs = CPU(cpu);
+
+ bool new_state = (env->cp15.hcr_el2 & HCR_VI) ||
+ (env->irq_line_state & CPU_INTERRUPT_VIRQ);
+
+ if (new_state != ((cs->interrupt_request & CPU_INTERRUPT_VIRQ) != 0)) {
+ if (new_state) {
+ cpu_interrupt(cs, CPU_INTERRUPT_VIRQ);
+ } else {
+ cpu_reset_interrupt(cs, CPU_INTERRUPT_VIRQ);
+ }
+ }
+}
+
+void arm_cpu_update_vfiq(ARMCPU *cpu)
+{
+ /*
+ * Update the interrupt level for VFIQ, which is the logical OR of
+ * the HCR_EL2.VF bit and the input line level from the GIC.
+ */
+ CPUARMState *env = &cpu->env;
+ CPUState *cs = CPU(cpu);
+
+ bool new_state = (env->cp15.hcr_el2 & HCR_VF) ||
+ (env->irq_line_state & CPU_INTERRUPT_VFIQ);
+
+ if (new_state != ((cs->interrupt_request & CPU_INTERRUPT_VFIQ) != 0)) {
+ if (new_state) {
+ cpu_interrupt(cs, CPU_INTERRUPT_VFIQ);
+ } else {
+ cpu_reset_interrupt(cs, CPU_INTERRUPT_VFIQ);
+ }
+ }
+}
+
#ifndef CONFIG_USER_ONLY
static void arm_cpu_set_irq(void *opaque, int irq, int level)
{
@@ -449,11 +491,21 @@
[ARM_CPU_VFIQ] = CPU_INTERRUPT_VFIQ
};
+ if (level) {
+ env->irq_line_state |= mask[irq];
+ } else {
+ env->irq_line_state &= ~mask[irq];
+ }
+
switch (irq) {
case ARM_CPU_VIRQ:
+ assert(arm_feature(env, ARM_FEATURE_EL2));
+ arm_cpu_update_virq(cpu);
+ break;
case ARM_CPU_VFIQ:
assert(arm_feature(env, ARM_FEATURE_EL2));
- /* fall through */
+ arm_cpu_update_vfiq(cpu);
+ break;
case ARM_CPU_IRQ:
case ARM_CPU_FIQ:
if (level) {
@@ -471,19 +523,30 @@
{
#ifdef CONFIG_KVM
ARMCPU *cpu = opaque;
+ CPUARMState *env = &cpu->env;
CPUState *cs = CPU(cpu);
int kvm_irq = KVM_ARM_IRQ_TYPE_CPU << KVM_ARM_IRQ_TYPE_SHIFT;
+ uint32_t linestate_bit;
switch (irq) {
case ARM_CPU_IRQ:
kvm_irq |= KVM_ARM_IRQ_CPU_IRQ;
+ linestate_bit = CPU_INTERRUPT_HARD;
break;
case ARM_CPU_FIQ:
kvm_irq |= KVM_ARM_IRQ_CPU_FIQ;
+ linestate_bit = CPU_INTERRUPT_FIQ;
break;
default:
g_assert_not_reached();
}
+
+ if (level) {
+ env->irq_line_state |= linestate_bit;
+ } else {
+ env->irq_line_state &= ~linestate_bit;
+ }
+
kvm_irq |= cs->cpu_index << KVM_ARM_IRQ_VCPU_SHIFT;
kvm_set_irq(kvm_state, kvm_irq, level ? 1 : 0);
#endif
@@ -1587,6 +1650,7 @@
set_feature(&cpu->env, ARM_FEATURE_GENERIC_TIMER);
set_feature(&cpu->env, ARM_FEATURE_DUMMY_C15_REGS);
set_feature(&cpu->env, ARM_FEATURE_CBAR_RO);
+ set_feature(&cpu->env, ARM_FEATURE_EL2);
set_feature(&cpu->env, ARM_FEATURE_EL3);
cpu->kvm_target = QEMU_KVM_ARM_TARGET_CORTEX_A7;
cpu->midr = 0x410fc075;
@@ -1633,6 +1697,7 @@
set_feature(&cpu->env, ARM_FEATURE_GENERIC_TIMER);
set_feature(&cpu->env, ARM_FEATURE_DUMMY_C15_REGS);
set_feature(&cpu->env, ARM_FEATURE_CBAR_RO);
+ set_feature(&cpu->env, ARM_FEATURE_EL2);
set_feature(&cpu->env, ARM_FEATURE_EL3);
cpu->kvm_target = QEMU_KVM_ARM_TARGET_CORTEX_A15;
cpu->midr = 0x412fc0f1;
diff --git a/target/arm/cpu.h b/target/arm/cpu.h
index b5eff79..2a73fed 100644
--- a/target/arm/cpu.h
+++ b/target/arm/cpu.h
@@ -538,6 +538,9 @@
uint64_t esr;
} serror;
+ /* State of our input IRQ/FIQ/VIRQ/VFIQ lines */
+ uint32_t irq_line_state;
+
/* Thumb-2 EE state. */
uint32_t teecr;
uint32_t teehbr;
@@ -2743,7 +2746,7 @@
if (arm_feature(env, ARM_FEATURE_EL2) && !secure) {
route_to_el2 = env->cp15.hcr_el2 & HCR_TGE ||
- env->cp15.mdcr_el2 & (1 << 8);
+ env->cp15.mdcr_el2 & MDCR_TDE;
}
if (route_to_el2) {
@@ -2764,23 +2767,35 @@
return (cpu->clidr & R_V7M_CLIDR_CTYPE_ALL_MASK) != 0;
}
+/* See AArch64.GenerateDebugExceptionsFrom() in ARM ARM pseudocode */
static inline bool aa64_generate_debug_exceptions(CPUARMState *env)
{
- if (arm_is_secure(env)) {
- /* MDCR_EL3.SDD disables debug events from Secure state */
- if (extract32(env->cp15.mdcr_el3, 16, 1) != 0
- || arm_current_el(env) == 3) {
- return false;
- }
+ int cur_el = arm_current_el(env);
+ int debug_el;
+
+ if (cur_el == 3) {
+ return false;
}
- if (arm_current_el(env) == arm_debug_target_el(env)) {
- if ((extract32(env->cp15.mdscr_el1, 13, 1) == 0)
- || (env->daif & PSTATE_D)) {
- return false;
- }
+ /* MDCR_EL3.SDD disables debug events from Secure state */
+ if (arm_is_secure_below_el3(env)
+ && extract32(env->cp15.mdcr_el3, 16, 1)) {
+ return false;
}
- return true;
+
+ /*
+ * Same EL to same EL debug exceptions need MDSCR_KDE enabled
+ * while not masking the (D)ebug bit in DAIF.
+ */
+ debug_el = arm_debug_target_el(env);
+
+ if (cur_el == debug_el) {
+ return extract32(env->cp15.mdscr_el1, 13, 1)
+ && !(env->daif & PSTATE_D);
+ }
+
+ /* Otherwise the debug target needs to be a higher EL */
+ return debug_el > cur_el;
}
static inline bool aa32_generate_debug_exceptions(CPUARMState *env)
@@ -2833,9 +2848,6 @@
* since the pseudocode has it at all callsites except for the one in
* CheckSoftwareStep(), where it is elided because both branches would
* always return the same value.
- *
- * Parts of the pseudocode relating to EL2 and EL3 are omitted because we
- * don't yet implement those exception levels or their associated trap bits.
*/
static inline bool arm_generate_debug_exceptions(CPUARMState *env)
{
diff --git a/target/arm/helper.c b/target/arm/helper.c
index 9630193..0da1424f 100644
--- a/target/arm/helper.c
+++ b/target/arm/helper.c
@@ -3155,7 +3155,7 @@
CPUState *cs = ENV_GET_CPU(env);
if (tlb_force_broadcast(env)) {
- tlbi_aa64_vmalle1_write(env, NULL, value);
+ tlbi_aa64_vmalle1is_write(env, NULL, value);
return;
}
@@ -3931,7 +3931,6 @@
static void hcr_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value)
{
ARMCPU *cpu = arm_env_get_cpu(env);
- CPUState *cs = ENV_GET_CPU(env);
uint64_t valid_mask = HCR_MASK;
if (arm_feature(env, ARM_FEATURE_EL3)) {
@@ -3950,28 +3949,6 @@
/* Clear RES0 bits. */
value &= valid_mask;
- /*
- * VI and VF are kept in cs->interrupt_request. Modifying that
- * requires that we have the iothread lock, which is done by
- * marking the reginfo structs as ARM_CP_IO.
- * Note that if a write to HCR pends a VIRQ or VFIQ it is never
- * possible for it to be taken immediately, because VIRQ and
- * VFIQ are masked unless running at EL0 or EL1, and HCR
- * can only be written at EL2.
- */
- g_assert(qemu_mutex_iothread_locked());
- if (value & HCR_VI) {
- cs->interrupt_request |= CPU_INTERRUPT_VIRQ;
- } else {
- cs->interrupt_request &= ~CPU_INTERRUPT_VIRQ;
- }
- if (value & HCR_VF) {
- cs->interrupt_request |= CPU_INTERRUPT_VFIQ;
- } else {
- cs->interrupt_request &= ~CPU_INTERRUPT_VFIQ;
- }
- value &= ~(HCR_VI | HCR_VF);
-
/* These bits change the MMU setup:
* HCR_VM enables stage 2 translation
* HCR_PTW forbids certain page-table setups
@@ -3981,6 +3958,21 @@
tlb_flush(CPU(cpu));
}
env->cp15.hcr_el2 = value;
+
+ /*
+ * Updates to VI and VF require us to update the status of
+ * virtual interrupts, which are the logical OR of these bits
+ * and the state of the input lines from the GIC. (This requires
+ * that we have the iothread lock, which is done by marking the
+ * reginfo structs as ARM_CP_IO.)
+ * Note that if a write to HCR pends a VIRQ or VFIQ it is never
+ * possible for it to be taken immediately, because VIRQ and
+ * VFIQ are masked unless running at EL0 or EL1, and HCR
+ * can only be written at EL2.
+ */
+ g_assert(qemu_mutex_iothread_locked());
+ arm_cpu_update_virq(cpu);
+ arm_cpu_update_vfiq(cpu);
}
static void hcr_writehigh(CPUARMState *env, const ARMCPRegInfo *ri,
@@ -3999,32 +3991,17 @@
hcr_write(env, NULL, value);
}
-static uint64_t hcr_read(CPUARMState *env, const ARMCPRegInfo *ri)
-{
- /* The VI and VF bits live in cs->interrupt_request */
- uint64_t ret = env->cp15.hcr_el2 & ~(HCR_VI | HCR_VF);
- CPUState *cs = ENV_GET_CPU(env);
-
- if (cs->interrupt_request & CPU_INTERRUPT_VIRQ) {
- ret |= HCR_VI;
- }
- if (cs->interrupt_request & CPU_INTERRUPT_VFIQ) {
- ret |= HCR_VF;
- }
- return ret;
-}
-
static const ARMCPRegInfo el2_cp_reginfo[] = {
{ .name = "HCR_EL2", .state = ARM_CP_STATE_AA64,
.type = ARM_CP_IO,
.opc0 = 3, .opc1 = 4, .crn = 1, .crm = 1, .opc2 = 0,
.access = PL2_RW, .fieldoffset = offsetof(CPUARMState, cp15.hcr_el2),
- .writefn = hcr_write, .readfn = hcr_read },
+ .writefn = hcr_write },
{ .name = "HCR", .state = ARM_CP_STATE_AA32,
.type = ARM_CP_ALIAS | ARM_CP_IO,
.cp = 15, .opc1 = 4, .crn = 1, .crm = 1, .opc2 = 0,
.access = PL2_RW, .fieldoffset = offsetof(CPUARMState, cp15.hcr_el2),
- .writefn = hcr_writelow, .readfn = hcr_read },
+ .writefn = hcr_writelow },
{ .name = "ELR_EL2", .state = ARM_CP_STATE_AA64,
.type = ARM_CP_ALIAS,
.opc0 = 3, .opc1 = 4, .crn = 4, .crm = 0, .opc2 = 1,
@@ -6455,13 +6432,14 @@
i = bank_number(old_mode);
env->banked_r13[i] = env->regs[13];
- env->banked_r14[i] = env->regs[14];
env->banked_spsr[i] = env->spsr;
i = bank_number(mode);
env->regs[13] = env->banked_r13[i];
- env->regs[14] = env->banked_r14[i];
env->spsr = env->banked_spsr[i];
+
+ env->banked_r14[r14_bank_number(old_mode)] = env->regs[14];
+ env->regs[14] = env->banked_r14[r14_bank_number(mode)];
}
/* Physical Interrupt Target EL Lookup Table
@@ -8040,7 +8018,7 @@
if (mode == ARM_CPU_MODE_HYP) {
env->xregs[14] = env->regs[14];
} else {
- env->xregs[14] = env->banked_r14[bank_number(ARM_CPU_MODE_USR)];
+ env->xregs[14] = env->banked_r14[r14_bank_number(ARM_CPU_MODE_USR)];
}
}
@@ -8054,7 +8032,7 @@
env->xregs[16] = env->regs[14];
env->xregs[17] = env->regs[13];
} else {
- env->xregs[16] = env->banked_r14[bank_number(ARM_CPU_MODE_IRQ)];
+ env->xregs[16] = env->banked_r14[r14_bank_number(ARM_CPU_MODE_IRQ)];
env->xregs[17] = env->banked_r13[bank_number(ARM_CPU_MODE_IRQ)];
}
@@ -8062,7 +8040,7 @@
env->xregs[18] = env->regs[14];
env->xregs[19] = env->regs[13];
} else {
- env->xregs[18] = env->banked_r14[bank_number(ARM_CPU_MODE_SVC)];
+ env->xregs[18] = env->banked_r14[r14_bank_number(ARM_CPU_MODE_SVC)];
env->xregs[19] = env->banked_r13[bank_number(ARM_CPU_MODE_SVC)];
}
@@ -8070,7 +8048,7 @@
env->xregs[20] = env->regs[14];
env->xregs[21] = env->regs[13];
} else {
- env->xregs[20] = env->banked_r14[bank_number(ARM_CPU_MODE_ABT)];
+ env->xregs[20] = env->banked_r14[r14_bank_number(ARM_CPU_MODE_ABT)];
env->xregs[21] = env->banked_r13[bank_number(ARM_CPU_MODE_ABT)];
}
@@ -8078,7 +8056,7 @@
env->xregs[22] = env->regs[14];
env->xregs[23] = env->regs[13];
} else {
- env->xregs[22] = env->banked_r14[bank_number(ARM_CPU_MODE_UND)];
+ env->xregs[22] = env->banked_r14[r14_bank_number(ARM_CPU_MODE_UND)];
env->xregs[23] = env->banked_r13[bank_number(ARM_CPU_MODE_UND)];
}
@@ -8095,7 +8073,7 @@
env->xregs[i] = env->fiq_regs[i - 24];
}
env->xregs[29] = env->banked_r13[bank_number(ARM_CPU_MODE_FIQ)];
- env->xregs[30] = env->banked_r14[bank_number(ARM_CPU_MODE_FIQ)];
+ env->xregs[30] = env->banked_r14[r14_bank_number(ARM_CPU_MODE_FIQ)];
}
env->pc = env->regs[15];
@@ -8145,7 +8123,7 @@
if (mode == ARM_CPU_MODE_HYP) {
env->regs[14] = env->xregs[14];
} else {
- env->banked_r14[bank_number(ARM_CPU_MODE_USR)] = env->xregs[14];
+ env->banked_r14[r14_bank_number(ARM_CPU_MODE_USR)] = env->xregs[14];
}
}
@@ -8159,7 +8137,7 @@
env->regs[14] = env->xregs[16];
env->regs[13] = env->xregs[17];
} else {
- env->banked_r14[bank_number(ARM_CPU_MODE_IRQ)] = env->xregs[16];
+ env->banked_r14[r14_bank_number(ARM_CPU_MODE_IRQ)] = env->xregs[16];
env->banked_r13[bank_number(ARM_CPU_MODE_IRQ)] = env->xregs[17];
}
@@ -8167,7 +8145,7 @@
env->regs[14] = env->xregs[18];
env->regs[13] = env->xregs[19];
} else {
- env->banked_r14[bank_number(ARM_CPU_MODE_SVC)] = env->xregs[18];
+ env->banked_r14[r14_bank_number(ARM_CPU_MODE_SVC)] = env->xregs[18];
env->banked_r13[bank_number(ARM_CPU_MODE_SVC)] = env->xregs[19];
}
@@ -8175,7 +8153,7 @@
env->regs[14] = env->xregs[20];
env->regs[13] = env->xregs[21];
} else {
- env->banked_r14[bank_number(ARM_CPU_MODE_ABT)] = env->xregs[20];
+ env->banked_r14[r14_bank_number(ARM_CPU_MODE_ABT)] = env->xregs[20];
env->banked_r13[bank_number(ARM_CPU_MODE_ABT)] = env->xregs[21];
}
@@ -8183,7 +8161,7 @@
env->regs[14] = env->xregs[22];
env->regs[13] = env->xregs[23];
} else {
- env->banked_r14[bank_number(ARM_CPU_MODE_UND)] = env->xregs[22];
+ env->banked_r14[r14_bank_number(ARM_CPU_MODE_UND)] = env->xregs[22];
env->banked_r13[bank_number(ARM_CPU_MODE_UND)] = env->xregs[23];
}
@@ -8200,7 +8178,7 @@
env->fiq_regs[i - 24] = env->xregs[i];
}
env->banked_r13[bank_number(ARM_CPU_MODE_FIQ)] = env->xregs[29];
- env->banked_r14[bank_number(ARM_CPU_MODE_FIQ)] = env->xregs[30];
+ env->banked_r14[r14_bank_number(ARM_CPU_MODE_FIQ)] = env->xregs[30];
}
env->regs[15] = env->pc;
@@ -8378,7 +8356,6 @@
return;
}
- /* TODO: Vectored interrupt controller. */
switch (cs->exception_index) {
case EXCP_UDEF:
new_mode = ARM_CPU_MODE_UND;
@@ -10560,18 +10537,6 @@
ret = pmsav8_mpu_lookup(env, address, access_type, mmu_idx, phys_ptr,
txattrs, prot, &mpu_is_subpage, fi, NULL);
- /*
- * TODO: this is a temporary hack to ignore the fact that the SAU region
- * is smaller than a page if this is an executable region. We never
- * supported small MPU regions, but we did (accidentally) allow small
- * SAU regions, and if we now made small SAU regions not be executable
- * then this would break previously working guest code. We can't
- * remove this until/unless we implement support for execution from
- * small regions.
- */
- if (*prot & PAGE_EXEC) {
- sattrs.subpage = false;
- }
*page_size = sattrs.subpage || mpu_is_subpage ? 1 : TARGET_PAGE_SIZE;
return ret;
}
diff --git a/target/arm/internals.h b/target/arm/internals.h
index 6c2bb2d..d208b70 100644
--- a/target/arm/internals.h
+++ b/target/arm/internals.h
@@ -145,6 +145,22 @@
g_assert_not_reached();
}
+/**
+ * r14_bank_number: Map CPU mode onto register bank for r14
+ *
+ * Given an AArch32 CPU mode, return the index into the saved register
+ * banks to use for the R14 (LR) in that mode. This is the same as
+ * bank_number(), except for the special case of Hyp mode, where
+ * R14 is shared with USR and SYS, unlike its R13 and SPSR.
+ * This should be used as the index into env->banked_r14[], and
+ * bank_number() used for the index into env->banked_r13[] and
+ * env->banked_spsr[].
+ */
+static inline int r14_bank_number(int mode)
+{
+ return (mode == ARM_CPU_MODE_HYP) ? BANK_USRSYS : bank_number(mode);
+}
+
void arm_cpu_register_gdb_regs_for_features(ARMCPU *cpu);
void arm_translate_init(void);
@@ -871,4 +887,22 @@
return cpu_mode_names[psr & 0xf];
}
+/**
+ * arm_cpu_update_virq: Update CPU_INTERRUPT_VIRQ bit in cs->interrupt_request
+ *
+ * Update the CPU_INTERRUPT_VIRQ bit in cs->interrupt_request, following
+ * a change to either the input VIRQ line from the GIC or the HCR_EL2.VI bit.
+ * Must be called with the iothread lock held.
+ */
+void arm_cpu_update_virq(ARMCPU *cpu);
+
+/**
+ * arm_cpu_update_vfiq: Update CPU_INTERRUPT_VFIQ bit in cs->interrupt_request
+ *
+ * Update the CPU_INTERRUPT_VFIQ bit in cs->interrupt_request, following
+ * a change to either the input VFIQ line from the GIC or the HCR_EL2.VF bit.
+ * Must be called with the iothread lock held.
+ */
+void arm_cpu_update_vfiq(ARMCPU *cpu);
+
#endif
diff --git a/target/arm/kvm32.c b/target/arm/kvm32.c
index 0f1e94c..cb3fb73 100644
--- a/target/arm/kvm32.c
+++ b/target/arm/kvm32.c
@@ -318,8 +318,8 @@
memcpy(env->usr_regs, env->regs + 8, 5 * sizeof(uint32_t));
}
env->banked_r13[bn] = env->regs[13];
- env->banked_r14[bn] = env->regs[14];
env->banked_spsr[bn] = env->spsr;
+ env->banked_r14[r14_bank_number(mode)] = env->regs[14];
/* Now we can safely copy stuff down to the kernel */
for (i = 0; i < ARRAY_SIZE(regs); i++) {
@@ -430,8 +430,8 @@
memcpy(env->regs + 8, env->usr_regs, 5 * sizeof(uint32_t));
}
env->regs[13] = env->banked_r13[bn];
- env->regs[14] = env->banked_r14[bn];
env->spsr = env->banked_spsr[bn];
+ env->regs[14] = env->banked_r14[r14_bank_number(mode)];
/* VFP registers */
r.id = KVM_REG_ARM | KVM_REG_SIZE_U64 | KVM_REG_ARM_VFP;
diff --git a/target/arm/kvm64.c b/target/arm/kvm64.c
index 5de8ff0..46fbe6d 100644
--- a/target/arm/kvm64.c
+++ b/target/arm/kvm64.c
@@ -103,7 +103,7 @@
* capable of fancier matching but that will require exposing that
* fanciness to GDB's interface
*
- * D7.3.2 DBGBCR<n>_EL1, Debug Breakpoint Control Registers
+ * DBGBCR<n>_EL1, Debug Breakpoint Control Registers
*
* 31 24 23 20 19 16 15 14 13 12 9 8 5 4 3 2 1 0
* +------+------+-------+-----+----+------+-----+------+-----+---+
@@ -115,12 +115,25 @@
* SSC/HMC/PMC: Security, Higher and Priv access control (Table D-12)
* BAS: Byte Address Select (RES1 for AArch64)
* E: Enable bit
+ *
+ * DBGBVR<n>_EL1, Debug Breakpoint Value Registers
+ *
+ * 63 53 52 49 48 2 1 0
+ * +------+-----------+----------+-----+
+ * | RESS | VA[52:49] | VA[48:2] | 0 0 |
+ * +------+-----------+----------+-----+
+ *
+ * Depending on the addressing mode bits the top bits of the register
+ * are a sign extension of the highest applicable VA bit. Some
+ * versions of GDB don't do it correctly so we ensure they are correct
+ * here so future PC comparisons will work properly.
*/
+
static int insert_hw_breakpoint(target_ulong addr)
{
HWBreakpoint brk = {
.bcr = 0x1, /* BCR E=1, enable */
- .bvr = addr
+ .bvr = sextract64(addr, 0, 53)
};
if (cur_hw_bps >= max_hw_bps) {
@@ -987,7 +1000,10 @@
cs->exception_index = EXCP_BKPT;
env->exception.syndrome = debug_exit->hsr;
env->exception.vaddress = debug_exit->far;
+ env->exception.target_el = 1;
+ qemu_mutex_lock_iothread();
cc->do_interrupt(cs);
+ qemu_mutex_unlock_iothread();
return false;
}
diff --git a/target/arm/machine.c b/target/arm/machine.c
index 239fe4e..2033816 100644
--- a/target/arm/machine.c
+++ b/target/arm/machine.c
@@ -192,6 +192,22 @@
}
};
+static bool irq_line_state_needed(void *opaque)
+{
+ return true;
+}
+
+static const VMStateDescription vmstate_irq_line_state = {
+ .name = "cpu/irq-line-state",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .needed = irq_line_state_needed,
+ .fields = (VMStateField[]) {
+ VMSTATE_UINT32(env.irq_line_state, ARMCPU),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
static bool m_needed(void *opaque)
{
ARMCPU *cpu = opaque;
@@ -625,11 +641,44 @@
return 0;
}
+static int cpu_pre_load(void *opaque)
+{
+ ARMCPU *cpu = opaque;
+ CPUARMState *env = &cpu->env;
+
+ /*
+ * Pre-initialize irq_line_state to a value that's never valid as
+ * real data, so cpu_post_load() can tell whether we've seen the
+ * irq-line-state subsection in the incoming migration state.
+ */
+ env->irq_line_state = UINT32_MAX;
+
+ return 0;
+}
+
static int cpu_post_load(void *opaque, int version_id)
{
ARMCPU *cpu = opaque;
+ CPUARMState *env = &cpu->env;
int i, v;
+ /*
+ * Handle migration compatibility from old QEMU which didn't
+ * send the irq-line-state subsection. A QEMU without it did not
+ * implement the HCR_EL2.{VI,VF} bits as generating interrupts,
+ * so for TCG the line state matches the bits set in cs->interrupt_request.
+ * For KVM the line state is not stored in cs->interrupt_request
+ * and so this will leave irq_line_state as 0, but this is OK because
+ * we only need to care about it for TCG.
+ */
+ if (env->irq_line_state == UINT32_MAX) {
+ CPUState *cs = CPU(cpu);
+
+ env->irq_line_state = cs->interrupt_request &
+ (CPU_INTERRUPT_HARD | CPU_INTERRUPT_FIQ |
+ CPU_INTERRUPT_VIRQ | CPU_INTERRUPT_VFIQ);
+ }
+
/* Update the values list from the incoming migration data.
* Anything in the incoming data which we don't know about is
* a migration failure; anything we know about but the incoming
@@ -680,6 +729,7 @@
.version_id = 22,
.minimum_version_id = 22,
.pre_save = cpu_pre_save,
+ .pre_load = cpu_pre_load,
.post_load = cpu_post_load,
.fields = (VMStateField[]) {
VMSTATE_UINT32_ARRAY(env.regs, ARMCPU, 16),
@@ -747,6 +797,7 @@
&vmstate_sve,
#endif
&vmstate_serror,
+ &vmstate_irq_line_state,
NULL
}
};
diff --git a/target/arm/op_helper.c b/target/arm/op_helper.c
index 90741f6..eb6fb82 100644
--- a/target/arm/op_helper.c
+++ b/target/arm/op_helper.c
@@ -694,7 +694,7 @@
env->banked_r13[bank_number(tgtmode)] = value;
break;
case 14:
- env->banked_r14[bank_number(tgtmode)] = value;
+ env->banked_r14[r14_bank_number(tgtmode)] = value;
break;
case 8 ... 12:
switch (tgtmode) {
@@ -725,7 +725,7 @@
case 13:
return env->banked_r13[bank_number(tgtmode)];
case 14:
- return env->banked_r14[bank_number(tgtmode)];
+ return env->banked_r14[r14_bank_number(tgtmode)];
case 8 ... 12:
switch (tgtmode) {
case ARM_CPU_MODE_USR:
diff --git a/tests/Makefile.include b/tests/Makefile.include
index 074eece..613242b 100644
--- a/tests/Makefile.include
+++ b/tests/Makefile.include
@@ -70,6 +70,7 @@
check-unit-y += tests/test-blockjob$(EXESUF)
check-unit-y += tests/test-blockjob-txn$(EXESUF)
check-unit-y += tests/test-block-backend$(EXESUF)
+check-unit-y += tests/test-image-locking$(EXESUF)
check-unit-y += tests/test-x86-cpuid$(EXESUF)
# all code tested by test-x86-cpuid is inside topology.h
ifeq ($(CONFIG_SOFTMMU),y)
@@ -537,6 +538,7 @@
tests/test-blockjob$(EXESUF): tests/test-blockjob.o $(test-block-obj-y) $(test-util-obj-y)
tests/test-blockjob-txn$(EXESUF): tests/test-blockjob-txn.o $(test-block-obj-y) $(test-util-obj-y)
tests/test-block-backend$(EXESUF): tests/test-block-backend.o $(test-block-obj-y) $(test-util-obj-y)
+tests/test-image-locking$(EXESUF): tests/test-image-locking.o $(test-block-obj-y) $(test-util-obj-y)
tests/test-thread-pool$(EXESUF): tests/test-thread-pool.o $(test-block-obj-y)
tests/test-iov$(EXESUF): tests/test-iov.o $(test-util-obj-y)
tests/test-hbitmap$(EXESUF): tests/test-hbitmap.o $(test-util-obj-y) $(test-crypto-obj-y)
diff --git a/tests/guest-debug/test-gdbstub.py b/tests/guest-debug/test-gdbstub.py
index 0e4ac01..c7e3986 100644
--- a/tests/guest-debug/test-gdbstub.py
+++ b/tests/guest-debug/test-gdbstub.py
@@ -16,6 +16,7 @@
print ("PASS: %s" % (msg))
else:
print ("FAIL: %s" % (msg))
+ global failcount
failcount += 1
diff --git a/tests/test-image-locking.c b/tests/test-image-locking.c
new file mode 100644
index 0000000..7614cbf
--- /dev/null
+++ b/tests/test-image-locking.c
@@ -0,0 +1,157 @@
+/*
+ * Image locking tests
+ *
+ * Copyright (c) 2018 Red Hat Inc.
+ *
+ * Author: Fam Zheng <famz@redhat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "qemu/osdep.h"
+#include "block/block.h"
+#include "sysemu/block-backend.h"
+#include "qapi/error.h"
+#include "qapi/qmp/qdict.h"
+
+static BlockBackend *open_image(const char *path,
+ uint64_t perm, uint64_t shared_perm,
+ Error **errp)
+{
+ Error *local_err = NULL;
+ BlockBackend *blk;
+ QDict *options = qdict_new();
+
+ qdict_put_str(options, "driver", "raw");
+ blk = blk_new_open(path, NULL, options, BDRV_O_RDWR, &local_err);
+ if (blk) {
+ g_assert_null(local_err);
+ if (blk_set_perm(blk, perm, shared_perm, errp)) {
+ blk_unref(blk);
+ blk = NULL;
+ }
+ } else {
+ error_propagate(errp, local_err);
+ }
+ return blk;
+}
+
+static void check_locked_bytes(int fd, uint64_t perm_locks,
+ uint64_t shared_perm_locks)
+{
+ int i;
+
+ if (!perm_locks && !shared_perm_locks) {
+ g_assert(!qemu_lock_fd_test(fd, 0, 0, true));
+ return;
+ }
+ for (i = 0; (1ULL << i) <= BLK_PERM_ALL; i++) {
+ uint64_t bit = (1ULL << i);
+ bool perm_expected = !!(bit & perm_locks);
+ bool shared_perm_expected = !!(bit & shared_perm_locks);
+ g_assert_cmpint(perm_expected, ==,
+ !!qemu_lock_fd_test(fd, 100 + i, 1, true));
+ g_assert_cmpint(shared_perm_expected, ==,
+ !!qemu_lock_fd_test(fd, 200 + i, 1, true));
+ }
+}
+
+static void test_image_locking_basic(void)
+{
+ BlockBackend *blk1, *blk2, *blk3;
+ char img_path[] = "/tmp/qtest.XXXXXX";
+ uint64_t perm, shared_perm;
+
+ int fd = mkstemp(img_path);
+ assert(fd >= 0);
+
+ perm = BLK_PERM_WRITE | BLK_PERM_CONSISTENT_READ;
+ shared_perm = BLK_PERM_ALL;
+ blk1 = open_image(img_path, perm, shared_perm, &error_abort);
+ g_assert(blk1);
+
+ check_locked_bytes(fd, perm, ~shared_perm);
+
+ /* compatible perm between blk1 and blk2 */
+ blk2 = open_image(img_path, perm | BLK_PERM_RESIZE, shared_perm, NULL);
+ g_assert(blk2);
+ check_locked_bytes(fd, perm | BLK_PERM_RESIZE, ~shared_perm);
+
+ /* incompatible perm with already open blk1 and blk2 */
+ blk3 = open_image(img_path, perm, BLK_PERM_WRITE_UNCHANGED, NULL);
+ g_assert_null(blk3);
+
+ blk_unref(blk2);
+
+ /* Check that extra bytes in blk2 are correctly unlocked */
+ check_locked_bytes(fd, perm, ~shared_perm);
+
+ blk_unref(blk1);
+
+ /* Image is unused, no lock there */
+ check_locked_bytes(fd, 0, 0);
+ blk3 = open_image(img_path, perm, BLK_PERM_WRITE_UNCHANGED, &error_abort);
+ g_assert(blk3);
+ blk_unref(blk3);
+ close(fd);
+ unlink(img_path);
+}
+
+static void test_set_perm_abort(void)
+{
+ BlockBackend *blk1, *blk2;
+ char img_path[] = "/tmp/qtest.XXXXXX";
+ uint64_t perm, shared_perm;
+ int r;
+ int fd = mkstemp(img_path);
+ assert(fd >= 0);
+
+ perm = BLK_PERM_WRITE | BLK_PERM_CONSISTENT_READ;
+ shared_perm = BLK_PERM_ALL;
+ blk1 = open_image(img_path, perm, shared_perm, &error_abort);
+ g_assert(blk1);
+
+ blk2 = open_image(img_path, perm, shared_perm, &error_abort);
+ g_assert(blk2);
+
+ check_locked_bytes(fd, perm, ~shared_perm);
+
+ /* A failed blk_set_perm mustn't change perm status (locked bytes) */
+ r = blk_set_perm(blk2, perm | BLK_PERM_RESIZE, BLK_PERM_WRITE_UNCHANGED,
+ NULL);
+ g_assert_cmpint(r, !=, 0);
+ check_locked_bytes(fd, perm, ~shared_perm);
+ blk_unref(blk1);
+ blk_unref(blk2);
+}
+
+int main(int argc, char **argv)
+{
+ bdrv_init();
+ qemu_init_main_loop(&error_abort);
+
+ g_test_init(&argc, &argv, NULL);
+
+ if (qemu_has_ofd_lock()) {
+ g_test_add_func("/image-locking/basic", test_image_locking_basic);
+ g_test_add_func("/image-locking/set-perm-abort", test_set_perm_abort);
+ }
+
+ return g_test_run();
+}
diff --git a/ui/gtk-egl.c b/ui/gtk-egl.c
index a77c25b..5420c23 100644
--- a/ui/gtk-egl.c
+++ b/ui/gtk-egl.c
@@ -68,8 +68,15 @@
return;
}
+ window = gtk_widget_get_window(vc->gfx.drawing_area);
+ ww = gdk_window_get_width(window);
+ wh = gdk_window_get_height(window);
+
if (vc->gfx.scanout_mode) {
gd_egl_scanout_flush(&vc->gfx.dcl, 0, 0, vc->gfx.w, vc->gfx.h);
+
+ vc->gfx.scale_x = (double)ww / vc->gfx.w;
+ vc->gfx.scale_y = (double)wh / vc->gfx.h;
} else {
if (!vc->gfx.ds) {
return;
@@ -77,13 +84,13 @@
eglMakeCurrent(qemu_egl_display, vc->gfx.esurface,
vc->gfx.esurface, vc->gfx.ectx);
- window = gtk_widget_get_window(vc->gfx.drawing_area);
- ww = gdk_window_get_width(window);
- wh = gdk_window_get_height(window);
surface_gl_setup_viewport(vc->gfx.gls, vc->gfx.ds, ww, wh);
surface_gl_render_texture(vc->gfx.gls, vc->gfx.ds);
eglSwapBuffers(qemu_egl_display, vc->gfx.esurface);
+
+ vc->gfx.scale_x = (double)ww / surface_width(vc->gfx.ds);
+ vc->gfx.scale_y = (double)wh / surface_height(vc->gfx.ds);
}
}
@@ -232,8 +239,8 @@
{
VirtualConsole *vc = container_of(dcl, VirtualConsole, gfx.dcl);
- vc->gfx.cursor_x = pos_x;
- vc->gfx.cursor_y = pos_y;
+ vc->gfx.cursor_x = pos_x * vc->gfx.scale_x;
+ vc->gfx.cursor_y = pos_y * vc->gfx.scale_y;
}
void gd_egl_release_dmabuf(DisplayChangeListener *dcl,
diff --git a/vl.c b/vl.c
index 55bab00..fa25d1a 100644
--- a/vl.c
+++ b/vl.c
@@ -3269,6 +3269,10 @@
break;
#endif
case QEMU_OPTION_bt:
+ warn_report("The bluetooth subsystem is deprecated and will "
+ "be removed soon. If the bluetooth subsystem is "
+ "still useful for you, please send a mail to "
+ "qemu-devel@nongnu.org with your usecase.");
add_device_config(DEV_BT, optarg);
break;
case QEMU_OPTION_audio_help: