summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--MAINTAINERS17
-rw-r--r--Makefile5
-rw-r--r--backends/hostmem.c8
-rw-r--r--block/parallels.c2
-rw-r--r--block/qapi.c8
-rw-r--r--block/raw-posix.c15
-rwxr-xr-xconfigure17
-rw-r--r--cpus.c2
-rw-r--r--default-configs/aarch64-linux-user.mak2
-rw-r--r--exec.c6
-rw-r--r--hw/arm/xlnx-ep108.c2
-rw-r--r--hw/block/nand.c2
-rw-r--r--hw/block/virtio-blk.c7
-rw-r--r--hw/block/xen_disk.c8
-rw-r--r--hw/ide/atapi.c8
-rw-r--r--hw/misc/ivshmem.c9
-rw-r--r--hw/scsi/virtio-scsi.c2
-rw-r--r--hw/xenpv/xen_domainbuild.c2
-rw-r--r--include/hw/xen/xen_common.h16
-rw-r--r--include/qapi/qmp/json-lexer.h16
-rw-r--r--include/qapi/qmp/json-parser.h4
-rw-r--r--include/qapi/qmp/json-streamer.h16
-rw-r--r--migration/block.c7
-rw-r--r--migration/postcopy-ram.c10
-rw-r--r--monitor.c3
-rw-r--r--qemu-doc.texi10
-rw-r--r--qga/commands-posix.c56
-rw-r--r--qga/commands-win32.c20
-rw-r--r--qga/guest-agent-core.h7
-rw-r--r--qga/installer/qemu-ga.wxs18
-rw-r--r--qga/main.c2
-rw-r--r--qga/qapi-schema.json4
-rw-r--r--qobject/json-lexer.c48
-rw-r--r--qobject/json-parser.c330
-rw-r--r--qobject/json-streamer.c91
-rw-r--r--qobject/qjson.c2
-rw-r--r--target-arm/helper.c12
-rw-r--r--target-arm/translate-a64.c15
-rw-r--r--target-i386/cpu.h2
-rw-r--r--target-i386/kvm.c22
-rw-r--r--target-mips/cpu.h18
-rw-r--r--target-mips/helper.c12
-rw-r--r--target-mips/op_helper.c13
-rw-r--r--target-sparc/vis_helper.c2
-rw-r--r--tcg/tcg.c2
-rw-r--r--tests/Makefile3
-rw-r--r--tests/check-qjson.c25
-rw-r--r--tests/ide-test.c32
-rw-r--r--tests/ivshmem-test.c3
-rw-r--r--tests/libqtest.c2
-rwxr-xr-xtests/qemu-iotests/1192
-rwxr-xr-xtests/qemu-iotests/1202
-rw-r--r--tests/test-aio.c1
-rw-r--r--tests/test-qga.c98
-rw-r--r--ui/vnc.c5
-rw-r--r--vl.c28
56 files changed, 625 insertions, 456 deletions
diff --git a/MAINTAINERS b/MAINTAINERS
index 28f0139..bb1f3e4 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -62,14 +62,22 @@ Guest CPU cores (TCG):
----------------------
Overall
L: qemu-devel@nongnu.org
-S: Odd fixes
+M: Paolo Bonzini <pbonzini@redhat.com>
+M: Peter Crosthwaite <crosthwaite.peter@gmail.com>
+M: Richard Henderson <rth@twiddle.net>
+S: Maintained
F: cpu-exec.c
+F: cpu-exec-common.c
+F: cpus.c
F: cputlb.c
+F: exec.c
F: softmmu_template.h
-F: translate-all.c
-F: include/exec/cpu_ldst.h
-F: include/exec/cpu_ldst_template.h
+F: translate-all.*
+F: translate-common.c
+F: include/exec/cpu*.h
+F: include/exec/exec-all.h
F: include/exec/helper*.h
+F: include/exec/tb-hash.h
Alpha
M: Richard Henderson <rth@twiddle.net>
@@ -1042,6 +1050,7 @@ S: Supported
F: include/exec/ioport.h
F: ioport.c
F: include/exec/memory.h
+F: include/exec/ram_addr.h
F: memory.c
F: include/exec/memory-internal.h
F: exec.c
diff --git a/Makefile b/Makefile
index c7fa427..930ac27 100644
--- a/Makefile
+++ b/Makefile
@@ -440,10 +440,7 @@ endif
install: all $(if $(BUILD_DOCS),install-doc) \
install-datadir install-localstatedir
ifneq ($(TOOLS),)
- $(call install-prog,$(filter-out qemu-ga,$(TOOLS)),$(DESTDIR)$(bindir))
-ifneq (,$(findstring qemu-ga,$(TOOLS)))
- $(call install-prog,qemu-ga$(EXESUF),$(DESTDIR)$(bindir))
-endif
+ $(call install-prog,$(subst qemu-ga,qemu-ga$(EXESUF),$(TOOLS)),$(DESTDIR)$(bindir))
endif
ifneq ($(CONFIG_MODULES),)
$(INSTALL_DIR) "$(DESTDIR)$(qemu_moddir)"
diff --git a/backends/hostmem.c b/backends/hostmem.c
index 41ba2af..1b4eb45 100644
--- a/backends/hostmem.c
+++ b/backends/hostmem.c
@@ -313,9 +313,11 @@ host_memory_backend_memory_complete(UserCreatable *uc, Error **errp)
assert(maxnode <= MAX_NODES);
if (mbind(ptr, sz, backend->policy,
maxnode ? backend->host_nodes : NULL, maxnode + 1, flags)) {
- error_setg_errno(errp, errno,
- "cannot bind memory to host NUMA nodes");
- return;
+ if (backend->policy != MPOL_DEFAULT || errno != ENOSYS) {
+ error_setg_errno(errp, errno,
+ "cannot bind memory to host NUMA nodes");
+ return;
+ }
}
#endif
/* Preallocate memory after the NUMA policy has been instantiated.
diff --git a/block/parallels.c b/block/parallels.c
index 4f79293..f689fde 100644
--- a/block/parallels.c
+++ b/block/parallels.c
@@ -220,7 +220,7 @@ static int64_t allocate_clusters(BlockDriverState *bs, int64_t sector_num,
s->bat_bitmap[idx + i] = cpu_to_le32(s->data_end / s->off_multiplier);
s->data_end += s->tracks;
bitmap_set(s->bat_dirty_bmap,
- bat_entry_off(idx) / s->bat_dirty_block, 1);
+ bat_entry_off(idx + i) / s->bat_dirty_block, 1);
}
return bat2sect(s, idx) + sector_num % s->tracks;
diff --git a/block/qapi.c b/block/qapi.c
index d20262d..267f147 100644
--- a/block/qapi.c
+++ b/block/qapi.c
@@ -436,7 +436,9 @@ BlockInfoList *qmp_query_block(Error **errp)
bdrv_query_info(blk, &info->value, &local_err);
if (local_err) {
error_propagate(errp, local_err);
- goto err;
+ g_free(info);
+ qapi_free_BlockInfoList(head);
+ return NULL;
}
*p_next = info;
@@ -444,10 +446,6 @@ BlockInfoList *qmp_query_block(Error **errp)
}
return head;
-
- err:
- qapi_free_BlockInfoList(head);
- return NULL;
}
BlockStatsList *qmp_query_blockstats(bool has_query_nodes,
diff --git a/block/raw-posix.c b/block/raw-posix.c
index aec9ec6..d9162fd 100644
--- a/block/raw-posix.c
+++ b/block/raw-posix.c
@@ -1976,8 +1976,8 @@ BlockDriver bdrv_file = {
#if defined(__APPLE__) && defined(__MACH__)
static kern_return_t FindEjectableCDMedia( io_iterator_t *mediaIterator );
-static kern_return_t GetBSDPath( io_iterator_t mediaIterator, char *bsdPath, CFIndex maxPathSize );
-
+static kern_return_t GetBSDPath(io_iterator_t mediaIterator, char *bsdPath,
+ CFIndex maxPathSize, int flags);
kern_return_t FindEjectableCDMedia( io_iterator_t *mediaIterator )
{
kern_return_t kernResult;
@@ -2004,7 +2004,8 @@ kern_return_t FindEjectableCDMedia( io_iterator_t *mediaIterator )
return kernResult;
}
-kern_return_t GetBSDPath( io_iterator_t mediaIterator, char *bsdPath, CFIndex maxPathSize )
+kern_return_t GetBSDPath(io_iterator_t mediaIterator, char *bsdPath,
+ CFIndex maxPathSize, int flags)
{
io_object_t nextMedia;
kern_return_t kernResult = KERN_FAILURE;
@@ -2017,7 +2018,9 @@ kern_return_t GetBSDPath( io_iterator_t mediaIterator, char *bsdPath, CFIndex ma
if ( bsdPathAsCFString ) {
size_t devPathLength;
strcpy( bsdPath, _PATH_DEV );
- strcat( bsdPath, "r" );
+ if (flags & BDRV_O_NOCACHE) {
+ strcat(bsdPath, "r");
+ }
devPathLength = strlen( bsdPath );
if ( CFStringGetCString( bsdPathAsCFString, bsdPath + devPathLength, maxPathSize - devPathLength, kCFStringEncodingASCII ) ) {
kernResult = KERN_SUCCESS;
@@ -2129,8 +2132,8 @@ static int hdev_open(BlockDriverState *bs, QDict *options, int flags,
int fd;
kernResult = FindEjectableCDMedia( &mediaIterator );
- kernResult = GetBSDPath( mediaIterator, bsdPath, sizeof( bsdPath ) );
-
+ kernResult = GetBSDPath(mediaIterator, bsdPath, sizeof(bsdPath),
+ flags);
if ( bsdPath[ 0 ] != '\0' ) {
strcat(bsdPath,"s0");
/* some CDs don't have a partition 0 */
diff --git a/configure b/configure
index 71d6cbc..979bc55 100755
--- a/configure
+++ b/configure
@@ -1946,6 +1946,23 @@ EOF
elif
cat > $TMPC <<EOF &&
#include <xenctrl.h>
+#include <stdint.h>
+int main(void) {
+ xc_interface *xc = NULL;
+ xen_domain_handle_t handle;
+ xc_domain_create(xc, 0, handle, 0, NULL, NULL);
+ return 0;
+}
+EOF
+ compile_prog "" "$xen_libs"
+ then
+ xen_ctrl_version=470
+ xen=yes
+
+ # Xen 4.6
+ elif
+ cat > $TMPC <<EOF &&
+#include <xenctrl.h>
#include <xenstore.h>
#include <stdint.h>
#include <xen/hvm/hvm_info_table.h>
diff --git a/cpus.c b/cpus.c
index 877bd70..43676fa 100644
--- a/cpus.c
+++ b/cpus.c
@@ -1415,6 +1415,8 @@ int vm_stop_force_state(RunState state)
return vm_stop(state);
} else {
runstate_set(state);
+
+ bdrv_drain_all();
/* Make sure to return an error if the flush in a previous vm_stop()
* failed. */
return bdrv_flush_all();
diff --git a/default-configs/aarch64-linux-user.mak b/default-configs/aarch64-linux-user.mak
index 3df7de5..0a5b08a 100644
--- a/default-configs/aarch64-linux-user.mak
+++ b/default-configs/aarch64-linux-user.mak
@@ -1,3 +1 @@
# Default configuration for aarch64-linux-user
-
-CONFIG_GDBSTUB_XML=y
diff --git a/exec.c b/exec.c
index acbd4a2..de1cf19 100644
--- a/exec.c
+++ b/exec.c
@@ -51,7 +51,6 @@
#include "qemu/main-loop.h"
#include "translate-all.h"
#include "sysemu/replay.h"
-#include "sysemu/qtest.h"
#include "exec/memory-internal.h"
#include "exec/ram_addr.h"
@@ -1197,11 +1196,6 @@ static long gethugepagesize(const char *path, Error **errp)
return 0;
}
- if (!qtest_driver() &&
- fs.f_type != HUGETLBFS_MAGIC) {
- fprintf(stderr, "Warning: path not on HugeTLBFS: %s\n", path);
- }
-
return fs.f_bsize;
}
diff --git a/hw/arm/xlnx-ep108.c b/hw/arm/xlnx-ep108.c
index 2899698..85b978f 100644
--- a/hw/arm/xlnx-ep108.c
+++ b/hw/arm/xlnx-ep108.c
@@ -51,7 +51,7 @@ static void xlnx_ep108_init(MachineState *machine)
machine->ram_size = EP108_MAX_RAM_SIZE;
}
- if (machine->ram_size <= 0x08000000) {
+ if (machine->ram_size < 0x08000000) {
qemu_log("WARNING: RAM size " RAM_ADDR_FMT " is small for EP108",
machine->ram_size);
}
diff --git a/hw/block/nand.c b/hw/block/nand.c
index a68266f..f0e3413 100644
--- a/hw/block/nand.c
+++ b/hw/block/nand.c
@@ -712,7 +712,7 @@ static void glue(nand_blk_erase_, PAGE_SIZE)(NANDFlashState *s)
memset(s->storage + (PAGE(addr) << OOB_SHIFT),
0xff, OOB_SIZE << s->erase_shift);
i = SECTOR(addr);
- page = SECTOR(addr + (ADDR_SHIFT + s->erase_shift));
+ page = SECTOR(addr + (1 << (ADDR_SHIFT + s->erase_shift)));
for (; i < page; i ++)
if (blk_write(s->blk, i, iobuf, 1) < 0) {
printf("%s: write error in sector %" PRIu64 "\n", __func__, i);
diff --git a/hw/block/virtio-blk.c b/hw/block/virtio-blk.c
index 848f3fe..756ae5c 100644
--- a/hw/block/virtio-blk.c
+++ b/hw/block/virtio-blk.c
@@ -72,6 +72,9 @@ static int virtio_blk_handle_rw_error(VirtIOBlockReq *req, int error,
VirtIOBlock *s = req->dev;
if (action == BLOCK_ERROR_ACTION_STOP) {
+ /* Break the link as the next request is going to be parsed from the
+ * ring again. Otherwise we may end up doing a double completion! */
+ req->mr_next = NULL;
req->next = s->rq;
s->rq = req;
} else if (action == BLOCK_ERROR_ACTION_REPORT) {
@@ -112,10 +115,6 @@ static void virtio_blk_rw_complete(void *opaque, int ret)
* happen on the other side of the migration).
*/
if (virtio_blk_handle_rw_error(req, -ret, is_read)) {
- /* Break the link in case the next request is added to the
- * restart queue and is going to be parsed from the ring again.
- */
- req->mr_next = NULL;
continue;
}
}
diff --git a/hw/block/xen_disk.c b/hw/block/xen_disk.c
index 02eda6e..8146650 100644
--- a/hw/block/xen_disk.c
+++ b/hw/block/xen_disk.c
@@ -75,7 +75,6 @@ struct ioreq {
off_t start;
QEMUIOVector v;
int presync;
- int postsync;
uint8_t mapped;
/* grant mapping */
@@ -144,7 +143,6 @@ static void ioreq_reset(struct ioreq *ioreq)
ioreq->status = 0;
ioreq->start = 0;
ioreq->presync = 0;
- ioreq->postsync = 0;
ioreq->mapped = 0;
memset(ioreq->domids, 0, sizeof(ioreq->domids));
@@ -520,12 +518,6 @@ static void qemu_aio_complete(void *opaque, int ret)
if (ioreq->aio_inflight > 0) {
return;
}
- if (ioreq->postsync) {
- ioreq->postsync = 0;
- ioreq->aio_inflight++;
- blk_aio_flush(ioreq->blkdev->blk, qemu_aio_complete, ioreq);
- return;
- }
ioreq->status = ioreq->aio_errors ? BLKIF_RSP_ERROR : BLKIF_RSP_OKAY;
ioreq_unmap(ioreq);
diff --git a/hw/ide/atapi.c b/hw/ide/atapi.c
index 7b9f74c..65f8dd4 100644
--- a/hw/ide/atapi.c
+++ b/hw/ide/atapi.c
@@ -148,17 +148,18 @@ static void cd_read_sector_cb(void *opaque, int ret)
{
IDEState *s = opaque;
- block_acct_done(blk_get_stats(s->blk), &s->acct);
-
#ifdef DEBUG_IDE_ATAPI
printf("cd_read_sector_cb: lba=%d ret=%d\n", s->lba, ret);
#endif
if (ret < 0) {
+ block_acct_failed(blk_get_stats(s->blk), &s->acct);
ide_atapi_io_error(s, ret);
return;
}
+ block_acct_done(blk_get_stats(s->blk), &s->acct);
+
if (s->cd_sector_size == 2352) {
cd_data_to_raw(s->io_buffer, s->lba);
}
@@ -173,6 +174,7 @@ static void cd_read_sector_cb(void *opaque, int ret)
static int cd_read_sector(IDEState *s)
{
if (s->cd_sector_size != 2048 && s->cd_sector_size != 2352) {
+ block_acct_invalid(blk_get_stats(s->blk), BLOCK_ACCT_READ);
return -EINVAL;
}
@@ -441,7 +443,7 @@ eot:
if (ret < 0) {
block_acct_failed(blk_get_stats(s->blk), &s->acct);
} else {
- block_acct_done(blk_get_stats(s->blk), &s->acct);
+ block_acct_done(blk_get_stats(s->blk), &s->acct);
}
ide_set_inactive(s, false);
}
diff --git a/hw/misc/ivshmem.c b/hw/misc/ivshmem.c
index 83d7bd3..f73f0c2 100644
--- a/hw/misc/ivshmem.c
+++ b/hw/misc/ivshmem.c
@@ -60,8 +60,6 @@
#define IVSHMEM(obj) \
OBJECT_CHECK(IVShmemState, (obj), TYPE_IVSHMEM)
-#define IVSHMEM_MEMDEV_PROP "memdev"
-
typedef struct Peer {
int nb_eventfds;
EventNotifier *eventfds;
@@ -857,8 +855,8 @@ static void pci_ivshmem_realize(PCIDevice *dev, Error **errp)
PCI_BASE_ADDRESS_MEM_PREFETCH;
if (!!s->server_chr + !!s->shmobj + !!s->hostmem != 1) {
- error_setg(errp, "You must specify either a shmobj, a chardev"
- " or a hostmem");
+ error_setg(errp,
+ "You must specify either 'shm', 'chardev' or 'x-memdev'");
return;
}
@@ -939,6 +937,7 @@ static void pci_ivshmem_realize(PCIDevice *dev, Error **errp)
memory_region_add_subregion(&s->bar, 0, mr);
pci_register_bar(PCI_DEVICE(s), 2, attr, &s->bar);
} else if (s->server_chr != NULL) {
+ /* FIXME do not rely on what chr drivers put into filename */
if (strncmp(s->server_chr->filename, "unix:", 5)) {
error_setg(errp, "chardev is not a unix client socket");
return;
@@ -1181,7 +1180,7 @@ static void ivshmem_init(Object *obj)
{
IVShmemState *s = IVSHMEM(obj);
- object_property_add_link(obj, IVSHMEM_MEMDEV_PROP, TYPE_MEMORY_BACKEND,
+ object_property_add_link(obj, "x-memdev", TYPE_MEMORY_BACKEND,
(Object **)&s->hostmem,
ivshmem_check_memdev_is_busy,
OBJ_PROP_LINK_UNREF_ON_RELEASE,
diff --git a/hw/scsi/virtio-scsi.c b/hw/scsi/virtio-scsi.c
index 7655401..3a4f520 100644
--- a/hw/scsi/virtio-scsi.c
+++ b/hw/scsi/virtio-scsi.c
@@ -250,7 +250,7 @@ static int virtio_scsi_do_tmf(VirtIOSCSI *s, VirtIOSCSIReq *req)
int target;
int ret = 0;
- if (s->dataplane_started) {
+ if (s->dataplane_started && d) {
assert(blk_get_aio_context(d->conf.blk) == s->ctx);
}
/* Here VIRTIO_SCSI_S_OK means "FUNCTION COMPLETE". */
diff --git a/hw/xenpv/xen_domainbuild.c b/hw/xenpv/xen_domainbuild.c
index c0ab753..ac0e5ac 100644
--- a/hw/xenpv/xen_domainbuild.c
+++ b/hw/xenpv/xen_domainbuild.c
@@ -234,7 +234,7 @@ int xen_domain_build_pv(const char *kernel, const char *ramdisk,
int rc;
memcpy(uuid, qemu_uuid, sizeof(uuid));
- rc = xc_domain_create(xen_xc, ssidref, uuid, flags, &xen_domid);
+ rc = xen_domain_create(xen_xc, ssidref, uuid, flags, &xen_domid);
if (rc < 0) {
fprintf(stderr, "xen: xc_domain_create() failed\n");
goto err;
diff --git a/include/hw/xen/xen_common.h b/include/hw/xen/xen_common.h
index d7fa6a4..4ac0c6f 100644
--- a/include/hw/xen/xen_common.h
+++ b/include/hw/xen/xen_common.h
@@ -439,4 +439,20 @@ static inline int xen_xc_domain_add_to_physmap(XenXC xch, uint32_t domid,
}
#endif
+#if CONFIG_XEN_CTRL_INTERFACE_VERSION < 470
+static inline int xen_domain_create(XenXC xc, uint32_t ssidref,
+ xen_domain_handle_t handle, uint32_t flags,
+ uint32_t *pdomid)
+{
+ return xc_domain_create(xc, ssidref, handle, flags, pdomid);
+}
+#else
+static inline int xen_domain_create(XenXC xc, uint32_t ssidref,
+ xen_domain_handle_t handle, uint32_t flags,
+ uint32_t *pdomid)
+{
+ return xc_domain_create(xc, ssidref, handle, flags, pdomid, NULL);
+}
+#endif
+
#endif /* QEMU_HW_XEN_COMMON_H */
diff --git a/include/qapi/qmp/json-lexer.h b/include/qapi/qmp/json-lexer.h
index cdff046..cb456d5 100644
--- a/include/qapi/qmp/json-lexer.h
+++ b/include/qapi/qmp/json-lexer.h
@@ -14,11 +14,16 @@
#ifndef QEMU_JSON_LEXER_H
#define QEMU_JSON_LEXER_H
-#include "qapi/qmp/qstring.h"
-#include "qapi/qmp/qlist.h"
+#include "glib-compat.h"
typedef enum json_token_type {
- JSON_OPERATOR = 100,
+ JSON_MIN = 100,
+ JSON_LCURLY = JSON_MIN,
+ JSON_RCURLY,
+ JSON_LSQUARE,
+ JSON_RSQUARE,
+ JSON_COLON,
+ JSON_COMMA,
JSON_INTEGER,
JSON_FLOAT,
JSON_KEYWORD,
@@ -30,13 +35,14 @@ typedef enum json_token_type {
typedef struct JSONLexer JSONLexer;
-typedef void (JSONLexerEmitter)(JSONLexer *, QString *, JSONTokenType, int x, int y);
+typedef void (JSONLexerEmitter)(JSONLexer *, GString *,
+ JSONTokenType, int x, int y);
struct JSONLexer
{
JSONLexerEmitter *emit;
int state;
- QString *token;
+ GString *token;
int x, y;
};
diff --git a/include/qapi/qmp/json-parser.h b/include/qapi/qmp/json-parser.h
index 44d88f3..fea89f8 100644
--- a/include/qapi/qmp/json-parser.h
+++ b/include/qapi/qmp/json-parser.h
@@ -18,7 +18,7 @@
#include "qapi/qmp/qlist.h"
#include "qapi/error.h"
-QObject *json_parser_parse(QList *tokens, va_list *ap);
-QObject *json_parser_parse_err(QList *tokens, va_list *ap, Error **errp);
+QObject *json_parser_parse(GQueue *tokens, va_list *ap);
+QObject *json_parser_parse_err(GQueue *tokens, va_list *ap, Error **errp);
#endif
diff --git a/include/qapi/qmp/json-streamer.h b/include/qapi/qmp/json-streamer.h
index 823f7d7..09b3d3e 100644
--- a/include/qapi/qmp/json-streamer.h
+++ b/include/qapi/qmp/json-streamer.h
@@ -14,21 +14,29 @@
#ifndef QEMU_JSON_STREAMER_H
#define QEMU_JSON_STREAMER_H
-#include "qapi/qmp/qlist.h"
+#include <stdint.h>
+#include "glib-compat.h"
#include "qapi/qmp/json-lexer.h"
+typedef struct JSONToken {
+ int type;
+ int x;
+ int y;
+ char str[];
+} JSONToken;
+
typedef struct JSONMessageParser
{
- void (*emit)(struct JSONMessageParser *parser, QList *tokens);
+ void (*emit)(struct JSONMessageParser *parser, GQueue *tokens);
JSONLexer lexer;
int brace_count;
int bracket_count;
- QList *tokens;
+ GQueue *tokens;
uint64_t token_size;
} JSONMessageParser;
void json_message_parser_init(JSONMessageParser *parser,
- void (*func)(JSONMessageParser *, QList *));
+ void (*func)(JSONMessageParser *, GQueue *));
int json_message_parser_feed(JSONMessageParser *parser,
const char *buffer, size_t size);
diff --git a/migration/block.c b/migration/block.c
index 310e2b3..656f38f 100644
--- a/migration/block.c
+++ b/migration/block.c
@@ -36,6 +36,8 @@
#define MAX_IS_ALLOCATED_SEARCH 65536
+#define MAX_INFLIGHT_IO 512
+
//#define DEBUG_BLK_MIGRATION
#ifdef DEBUG_BLK_MIGRATION
@@ -665,7 +667,10 @@ static int block_save_iterate(QEMUFile *f, void *opaque)
blk_mig_lock();
while ((block_mig_state.submitted +
block_mig_state.read_done) * BLOCK_SIZE <
- qemu_file_get_rate_limit(f)) {
+ qemu_file_get_rate_limit(f) &&
+ (block_mig_state.submitted +
+ block_mig_state.read_done) <
+ MAX_INFLIGHT_IO) {
blk_mig_unlock();
if (block_mig_state.bulk_completed == 0) {
/* first finish the bulk phase */
diff --git a/migration/postcopy-ram.c b/migration/postcopy-ram.c
index 22d6b18..3946aa9 100644
--- a/migration/postcopy-ram.c
+++ b/migration/postcopy-ram.c
@@ -241,10 +241,7 @@ static int cleanup_range(const char *block_name, void *host_addr,
* We turned off hugepage for the precopy stage with postcopy enabled
* we can turn it back on now.
*/
- if (qemu_madvise(host_addr, length, QEMU_MADV_HUGEPAGE)) {
- error_report("%s HUGEPAGE: %s", __func__, strerror(errno));
- return -1;
- }
+ qemu_madvise(host_addr, length, QEMU_MADV_HUGEPAGE);
/*
* We can also turn off userfault now since we should have all the
@@ -345,10 +342,7 @@ static int nhp_range(const char *block_name, void *host_addr,
* do delete areas of the page, even if THP thinks a hugepage would
* be a good idea, so force hugepages off.
*/
- if (qemu_madvise(host_addr, length, QEMU_MADV_NOHUGEPAGE)) {
- error_report("%s: NOHUGEPAGE: %s", __func__, strerror(errno));
- return -1;
- }
+ qemu_madvise(host_addr, length, QEMU_MADV_NOHUGEPAGE);
return 0;
}
diff --git a/monitor.c b/monitor.c
index e4cf34e..9a35d72 100644
--- a/monitor.c
+++ b/monitor.c
@@ -3849,7 +3849,7 @@ static QDict *qmp_check_input_obj(QObject *input_obj, Error **errp)
return input_dict;
}
-static void handle_qmp_command(JSONMessageParser *parser, QList *tokens)
+static void handle_qmp_command(JSONMessageParser *parser, GQueue *tokens)
{
Error *local_err = NULL;
QObject *obj, *data;
@@ -3907,6 +3907,7 @@ static void handle_qmp_command(JSONMessageParser *parser, QList *tokens)
err_out:
monitor_protocol_emitter(mon, data, local_err);
qobject_decref(data);
+ error_free(local_err);
QDECREF(input);
QDECREF(args);
}
diff --git a/qemu-doc.texi b/qemu-doc.texi
index 460ab71..ffc3e50 100644
--- a/qemu-doc.texi
+++ b/qemu-doc.texi
@@ -1256,7 +1256,7 @@ zero-copy communication to the application level of the guests. The basic
syntax is:
@example
-qemu-system-i386 -device ivshmem,size=<size in format accepted by -m>[,shm=<shm name>]
+qemu-system-i386 -device ivshmem,size=@var{size},shm=@var{shm-name}
@end example
If desired, interrupts can be sent between guest VMs accessing the same shared
@@ -1267,12 +1267,12 @@ memory server is:
@example
# First start the ivshmem server once and for all
-ivshmem-server -p <pidfile> -S <path> -m <shm name> -l <shm size> -n <vectors n>
+ivshmem-server -p @var{pidfile} -S @var{path} -m @var{shm-name} -l @var{shm-size} -n @var{vectors}
# Then start your qemu instances with matching arguments
-qemu-system-i386 -device ivshmem,size=<shm size>,vectors=<vectors n>,chardev=<id>
+qemu-system-i386 -device ivshmem,size=@var{shm-size},vectors=@var{vectors},chardev=@var{id}
[,msi=on][,ioeventfd=on][,role=peer|master]
- -chardev socket,path=<path>,id=<id>
+ -chardev socket,path=@var{path},id=@var{id}
@end example
When using the server, the guest will be assigned a VM ID (>=0) that allows guests
@@ -1300,7 +1300,7 @@ a memory backend that has hugepage support:
@example
qemu-system-i386 -object memory-backend-file,size=1G,mem-path=/mnt/hugepages/my-shmem-file,id=mb1
- -device ivshmem,memdev=mb1
+ -device ivshmem,x-memdev=mb1
@end example
ivshmem-server also supports hugepages mount points with the
diff --git a/qga/commands-posix.c b/qga/commands-posix.c
index 0ebd473..c2ff970 100644
--- a/qga/commands-posix.c
+++ b/qga/commands-posix.c
@@ -216,9 +216,16 @@ void qmp_guest_set_time(bool has_time, int64_t time_ns, Error **errp)
}
}
+typedef enum {
+ RW_STATE_NEW,
+ RW_STATE_READING,
+ RW_STATE_WRITING,
+} RwState;
+
typedef struct GuestFileHandle {
uint64_t id;
FILE *fh;
+ RwState state;
QTAILQ_ENTRY(GuestFileHandle) next;
} GuestFileHandle;
@@ -460,6 +467,17 @@ struct GuestFileRead *qmp_guest_file_read(int64_t handle, bool has_count,
}
fh = gfh->fh;
+
+ /* explicitly flush when switching from writing to reading */
+ if (gfh->state == RW_STATE_WRITING) {
+ int ret = fflush(fh);
+ if (ret == EOF) {
+ error_setg_errno(errp, errno, "failed to flush file");
+ return NULL;
+ }
+ gfh->state = RW_STATE_NEW;
+ }
+
buf = g_malloc0(count+1);
read_count = fread(buf, 1, count, fh);
if (ferror(fh)) {
@@ -473,6 +491,7 @@ struct GuestFileRead *qmp_guest_file_read(int64_t handle, bool has_count,
if (read_count) {
read_data->buf_b64 = g_base64_encode(buf, read_count);
}
+ gfh->state = RW_STATE_READING;
}
g_free(buf);
clearerr(fh);
@@ -496,6 +515,16 @@ GuestFileWrite *qmp_guest_file_write(int64_t handle, const char *buf_b64,
}
fh = gfh->fh;
+
+ if (gfh->state == RW_STATE_READING) {
+ int ret = fseek(fh, 0, SEEK_CUR);
+ if (ret == -1) {
+ error_setg_errno(errp, errno, "failed to seek file");
+ return NULL;
+ }
+ gfh->state = RW_STATE_NEW;
+ }
+
buf = g_base64_decode(buf_b64, &buf_len);
if (!has_count) {
@@ -515,6 +544,7 @@ GuestFileWrite *qmp_guest_file_write(int64_t handle, const char *buf_b64,
write_data = g_new0(GuestFileWrite, 1);
write_data->count = write_count;
write_data->eof = feof(fh);
+ gfh->state = RW_STATE_WRITING;
}
g_free(buf);
clearerr(fh);
@@ -523,25 +553,47 @@ GuestFileWrite *qmp_guest_file_write(int64_t handle, const char *buf_b64,
}
struct GuestFileSeek *qmp_guest_file_seek(int64_t handle, int64_t offset,
- int64_t whence, Error **errp)
+ int64_t whence_code, Error **errp)
{
GuestFileHandle *gfh = guest_file_handle_find(handle, errp);
GuestFileSeek *seek_data = NULL;
FILE *fh;
int ret;
+ int whence;
if (!gfh) {
return NULL;
}
+ /* We stupidly exposed 'whence':'int' in our qapi */
+ switch (whence_code) {
+ case QGA_SEEK_SET:
+ whence = SEEK_SET;
+ break;
+ case QGA_SEEK_CUR:
+ whence = SEEK_CUR;
+ break;
+ case QGA_SEEK_END:
+ whence = SEEK_END;
+ break;
+ default:
+ error_setg(errp, "invalid whence code %"PRId64, whence_code);
+ return NULL;
+ }
+
fh = gfh->fh;
ret = fseek(fh, offset, whence);
if (ret == -1) {
error_setg_errno(errp, errno, "failed to seek file");
+ if (errno == ESPIPE) {
+ /* file is non-seekable, stdio shouldn't be buffering anyways */
+ gfh->state = RW_STATE_NEW;
+ }
} else {
seek_data = g_new0(GuestFileSeek, 1);
seek_data->position = ftell(fh);
seek_data->eof = feof(fh);
+ gfh->state = RW_STATE_NEW;
}
clearerr(fh);
@@ -562,6 +614,8 @@ void qmp_guest_file_flush(int64_t handle, Error **errp)
ret = fflush(fh);
if (ret == EOF) {
error_setg_errno(errp, errno, "failed to flush file");
+ } else {
+ gfh->state = RW_STATE_NEW;
}
}
diff --git a/qga/commands-win32.c b/qga/commands-win32.c
index 41f6dd9..0654fe4 100644
--- a/qga/commands-win32.c
+++ b/qga/commands-win32.c
@@ -382,7 +382,7 @@ done:
}
GuestFileSeek *qmp_guest_file_seek(int64_t handle, int64_t offset,
- int64_t whence, Error **errp)
+ int64_t whence_code, Error **errp)
{
GuestFileHandle *gfh;
GuestFileSeek *seek_data;
@@ -390,11 +390,29 @@ GuestFileSeek *qmp_guest_file_seek(int64_t handle, int64_t offset,
LARGE_INTEGER new_pos, off_pos;
off_pos.QuadPart = offset;
BOOL res;
+ int whence;
+
gfh = guest_file_handle_find(handle, errp);
if (!gfh) {
return NULL;
}
+ /* We stupidly exposed 'whence':'int' in our qapi */
+ switch (whence_code) {
+ case QGA_SEEK_SET:
+ whence = SEEK_SET;
+ break;
+ case QGA_SEEK_CUR:
+ whence = SEEK_CUR;
+ break;
+ case QGA_SEEK_END:
+ whence = SEEK_END;
+ break;
+ default:
+ error_setg(errp, "invalid whence code %"PRId64, whence_code);
+ return NULL;
+ }
+
fh = gfh->fh;
res = SetFilePointerEx(fh, off_pos, &new_pos, whence);
if (!res) {
diff --git a/qga/guest-agent-core.h b/qga/guest-agent-core.h
index e92c6ab..238dc6b 100644
--- a/qga/guest-agent-core.h
+++ b/qga/guest-agent-core.h
@@ -15,6 +15,13 @@
#define QGA_READ_COUNT_DEFAULT 4096
+/* Mapping of whence codes used by guest-file-seek. */
+enum {
+ QGA_SEEK_SET = 0,
+ QGA_SEEK_CUR = 1,
+ QGA_SEEK_END = 2,
+};
+
typedef struct GAState GAState;
typedef struct GACommandState GACommandState;
extern GAState *ga_state;
diff --git a/qga/installer/qemu-ga.wxs b/qga/installer/qemu-ga.wxs
index 6804f02..9473875 100644
--- a/qga/installer/qemu-ga.wxs
+++ b/qga/installer/qemu-ga.wxs
@@ -91,6 +91,22 @@
<File Id="qga_vss.tlb" Name="qga-vss.tlb" Source="$(env.BUILD_DIR)/qga/vss-win32/qga-vss.tlb" KeyPath="yes" DiskId="1"/>
</Component>
<?endif?>
+ <?if $(var.Arch) = "32"?>
+ <Component Id="gspawn-helper-console" Guid="{446185B3-87BE-43D2-96B8-0FEFD9E8696D}">
+ <File Id="gspawn-win32-helper-console.exe" Name="gspawn-win32-helper-console.exe" Source="$(var.Mingw_bin)/gspawn-win32-helper-console.exe" KeyPath="yes" DiskId="1"/>
+ </Component>
+ <Component Id="gspawn-helper" Guid="{CD67A5A3-2DB1-4DA1-A67A-8D71E797B466}">
+ <File Id="gspawn-win32-helper.exe" Name="gspawn-win32-helper.exe" Source="$(var.Mingw_bin)/gspawn-win32-helper.exe" KeyPath="yes" DiskId="1"/>
+ </Component>
+ <?endif?>
+ <?if $(var.Arch) = "64"?>
+ <Component Id="gspawn-helper-console" Guid="{9E615A9F-349A-4992-A5C2-C10BAD173660}">
+ <File Id="gspawn-win64-helper-console.exe" Name="gspawn-win64-helper-console.exe" Source="$(var.Mingw_bin)/gspawn-win64-helper-console.exe" KeyPath="yes" DiskId="1"/>
+ </Component>
+ <Component Id="gspawn-helper" Guid="{D201AD22-1846-4E4F-B6E1-C7A908ED2457}">
+ <File Id="gspawn-win64-helper.exe" Name="gspawn-win64-helper.exe" Source="$(var.Mingw_bin)/gspawn-win64-helper.exe" KeyPath="yes" DiskId="1"/>
+ </Component>
+ <?endif?>
<Component Id="iconv" Guid="{35EE3558-D34B-4F0A-B8BD-430FF0775246}">
<File Id="iconv.dll" Name="iconv.dll" Source="$(var.Mingw_bin)/iconv.dll" KeyPath="yes" DiskId="1"/>
</Component>
@@ -148,6 +164,8 @@
<ComponentRef Id="qga_vss_dll" />
<ComponentRef Id="qga_vss_tlb" />
<?endif?>
+ <ComponentRef Id="gspawn-helper-console" />
+ <ComponentRef Id="gspawn-helper" />
<ComponentRef Id="iconv" />
<ComponentRef Id="libgcc_arch_lib" />
<ComponentRef Id="libglib" />
diff --git a/qga/main.c b/qga/main.c
index d2a0ffc..f83a97d 100644
--- a/qga/main.c
+++ b/qga/main.c
@@ -570,7 +570,7 @@ static void process_command(GAState *s, QDict *req)
}
/* handle requests/control events coming in over the channel */
-static void process_event(JSONMessageParser *parser, QList *tokens)
+static void process_event(JSONMessageParser *parser, GQueue *tokens)
{
GAState *s = container_of(parser, GAState, parser);
QDict *qdict;
diff --git a/qga/qapi-schema.json b/qga/qapi-schema.json
index 78362e0..01c9ee4 100644
--- a/qga/qapi-schema.json
+++ b/qga/qapi-schema.json
@@ -318,13 +318,13 @@
#
# Seek to a position in the file, as with fseek(), and return the
# current file position afterward. Also encapsulates ftell()'s
-# functionality, just Set offset=0, whence=SEEK_CUR.
+# functionality, with offset=0 and whence=1.
#
# @handle: filehandle returned by guest-file-open
#
# @offset: bytes to skip over in the file stream
#
-# @whence: SEEK_SET, SEEK_CUR, or SEEK_END, as with fseek()
+# @whence: 0 for SEEK_SET, 1 for SEEK_CUR, or 2 for SEEK_END
#
# Returns: @GuestFileSeek on success.
#
diff --git a/qobject/json-lexer.c b/qobject/json-lexer.c
index b19623e..92798ae 100644
--- a/qobject/json-lexer.c
+++ b/qobject/json-lexer.c
@@ -11,12 +11,9 @@
*
*/
-#include "qapi/qmp/qstring.h"
-#include "qapi/qmp/qlist.h"
-#include "qapi/qmp/qdict.h"
-#include "qapi/qmp/qint.h"
#include "qemu-common.h"
#include "qapi/qmp/json-lexer.h"
+#include <stdint.h>
#define MAX_TOKEN_SIZE (64ULL << 20)
@@ -30,7 +27,7 @@
*/
enum json_lexer_state {
- IN_ERROR = 0,
+ IN_ERROR = 0, /* must really be 0, see json_lexer[] */
IN_DQ_UCODE3,
IN_DQ_UCODE2,
IN_DQ_UCODE1,
@@ -62,6 +59,8 @@ enum json_lexer_state {
IN_START,
};
+QEMU_BUILD_BUG_ON((int)JSON_MIN <= (int)IN_START);
+
#define TERMINAL(state) [0 ... 0x7F] = (state)
/* Return whether TERMINAL is a terminal state and the transition to it
@@ -71,6 +70,8 @@ enum json_lexer_state {
(json_lexer[(old_state)][0] == (terminal))
static const uint8_t json_lexer[][256] = {
+ /* Relies on default initialization to IN_ERROR! */
+
/* double quote string */
[IN_DQ_UCODE3] = {
['0' ... '9'] = IN_DQ_STRING,
@@ -253,12 +254,12 @@ static const uint8_t json_lexer[][256] = {
['0'] = IN_ZERO,
['1' ... '9'] = IN_NONZERO_NUMBER,
['-'] = IN_NEG_NONZERO_NUMBER,
- ['{'] = JSON_OPERATOR,
- ['}'] = JSON_OPERATOR,
- ['['] = JSON_OPERATOR,
- [']'] = JSON_OPERATOR,
- [','] = JSON_OPERATOR,
- [':'] = JSON_OPERATOR,
+ ['{'] = JSON_LCURLY,
+ ['}'] = JSON_RCURLY,
+ ['['] = JSON_LSQUARE,
+ [']'] = JSON_RSQUARE,
+ [','] = JSON_COMMA,
+ [':'] = JSON_COLON,
['a' ... 'z'] = IN_KEYWORD,
['%'] = IN_ESCAPE,
[' '] = IN_WHITESPACE,
@@ -272,7 +273,7 @@ void json_lexer_init(JSONLexer *lexer, JSONLexerEmitter func)
{
lexer->emit = func;
lexer->state = IN_START;
- lexer->token = qstring_new();
+ lexer->token = g_string_sized_new(3);
lexer->x = lexer->y = 0;
}
@@ -287,14 +288,20 @@ static int json_lexer_feed_char(JSONLexer *lexer, char ch, bool flush)
}
do {
+ assert(lexer->state <= ARRAY_SIZE(json_lexer));
new_state = json_lexer[lexer->state][(uint8_t)ch];
char_consumed = !TERMINAL_NEEDED_LOOKAHEAD(lexer->state, new_state);
if (char_consumed) {
- qstring_append_chr(lexer->token, ch);
+ g_string_append_c(lexer->token, ch);
}
switch (new_state) {
- case JSON_OPERATOR:
+ case JSON_LCURLY:
+ case JSON_RCURLY:
+ case JSON_LSQUARE:
+ case JSON_RSQUARE:
+ case JSON_COLON:
+ case JSON_COMMA:
case JSON_ESCAPE:
case JSON_INTEGER:
case JSON_FLOAT:
@@ -303,8 +310,7 @@ static int json_lexer_feed_char(JSONLexer *lexer, char ch, bool flush)
lexer->emit(lexer, lexer->token, new_state, lexer->x, lexer->y);
/* fall through */
case JSON_SKIP:
- QDECREF(lexer->token);
- lexer->token = qstring_new();
+ g_string_truncate(lexer->token, 0);
new_state = IN_START;
break;
case IN_ERROR:
@@ -322,8 +328,7 @@ static int json_lexer_feed_char(JSONLexer *lexer, char ch, bool flush)
* induce an error/flush state.
*/
lexer->emit(lexer, lexer->token, JSON_ERROR, lexer->x, lexer->y);
- QDECREF(lexer->token);
- lexer->token = qstring_new();
+ g_string_truncate(lexer->token, 0);
new_state = IN_START;
lexer->state = new_state;
return 0;
@@ -336,10 +341,9 @@ static int json_lexer_feed_char(JSONLexer *lexer, char ch, bool flush)
/* Do not let a single token grow to an arbitrarily large size,
* this is a security consideration.
*/
- if (lexer->token->length > MAX_TOKEN_SIZE) {
+ if (lexer->token->len > MAX_TOKEN_SIZE) {
lexer->emit(lexer, lexer->token, lexer->state, lexer->x, lexer->y);
- QDECREF(lexer->token);
- lexer->token = qstring_new();
+ g_string_truncate(lexer->token, 0);
lexer->state = IN_START;
}
@@ -369,5 +373,5 @@ int json_lexer_flush(JSONLexer *lexer)
void json_lexer_destroy(JSONLexer *lexer)
{
- QDECREF(lexer->token);
+ g_string_free(lexer->token, true);
}
diff --git a/qobject/json-parser.c b/qobject/json-parser.c
index ac991ba..3c5d35d 100644
--- a/qobject/json-parser.c
+++ b/qobject/json-parser.c
@@ -22,15 +22,13 @@
#include "qapi/qmp/qbool.h"
#include "qapi/qmp/json-parser.h"
#include "qapi/qmp/json-lexer.h"
+#include "qapi/qmp/json-streamer.h"
typedef struct JSONParserContext
{
Error *err;
- struct {
- QObject **buf;
- size_t pos;
- size_t count;
- } tokens;
+ JSONToken *current;
+ GQueue *buf;
} JSONParserContext;
#define BUG_ON(cond) assert(!(cond))
@@ -47,58 +45,10 @@ typedef struct JSONParserContext
static QObject *parse_value(JSONParserContext *ctxt, va_list *ap);
/**
- * Token manipulators
- *
- * tokens are dictionaries that contain a type, a string value, and geometry information
- * about a token identified by the lexer. These are routines that make working with
- * these objects a bit easier.
- */
-static const char *token_get_value(QObject *obj)
-{
- return qdict_get_str(qobject_to_qdict(obj), "token");
-}
-
-static JSONTokenType token_get_type(QObject *obj)
-{
- return qdict_get_int(qobject_to_qdict(obj), "type");
-}
-
-static int token_is_operator(QObject *obj, char op)
-{
- const char *val;
-
- if (token_get_type(obj) != JSON_OPERATOR) {
- return 0;
- }
-
- val = token_get_value(obj);
-
- return (val[0] == op) && (val[1] == 0);
-}
-
-static int token_is_keyword(QObject *obj, const char *value)
-{
- if (token_get_type(obj) != JSON_KEYWORD) {
- return 0;
- }
-
- return strcmp(token_get_value(obj), value) == 0;
-}
-
-static int token_is_escape(QObject *obj, const char *value)
-{
- if (token_get_type(obj) != JSON_ESCAPE) {
- return 0;
- }
-
- return (strcmp(token_get_value(obj), value) == 0);
-}
-
-/**
* Error handler
*/
static void GCC_FMT_ATTR(3, 4) parse_error(JSONParserContext *ctxt,
- QObject *token, const char *msg, ...)
+ JSONToken *token, const char *msg, ...)
{
va_list ap;
char message[1024];
@@ -176,9 +126,10 @@ static int hex2decimal(char ch)
* \t
* \u four-hex-digits
*/
-static QString *qstring_from_escaped_str(JSONParserContext *ctxt, QObject *token)
+static QString *qstring_from_escaped_str(JSONParserContext *ctxt,
+ JSONToken *token)
{
- const char *ptr = token_get_value(token);
+ const char *ptr = token->str;
QString *str;
int double_quote = 1;
@@ -274,73 +225,34 @@ out:
return NULL;
}
-static QObject *parser_context_pop_token(JSONParserContext *ctxt)
-{
- QObject *token;
- g_assert(ctxt->tokens.pos < ctxt->tokens.count);
- token = ctxt->tokens.buf[ctxt->tokens.pos];
- ctxt->tokens.pos++;
- return token;
-}
-
-/* Note: parser_context_{peek|pop}_token do not increment the
- * token object's refcount. In both cases the references will continue
- * to be tracked and cleaned up in parser_context_free(), so do not
- * attempt to free the token object.
+/* Note: the token object returned by parser_context_peek_token or
+ * parser_context_pop_token is deleted as soon as parser_context_pop_token
+ * is called again.
*/
-static QObject *parser_context_peek_token(JSONParserContext *ctxt)
-{
- QObject *token;
- g_assert(ctxt->tokens.pos < ctxt->tokens.count);
- token = ctxt->tokens.buf[ctxt->tokens.pos];
- return token;
-}
-
-static JSONParserContext parser_context_save(JSONParserContext *ctxt)
-{
- JSONParserContext saved_ctxt = {0};
- saved_ctxt.tokens.pos = ctxt->tokens.pos;
- saved_ctxt.tokens.count = ctxt->tokens.count;
- saved_ctxt.tokens.buf = ctxt->tokens.buf;
- return saved_ctxt;
-}
-
-static void parser_context_restore(JSONParserContext *ctxt,
- JSONParserContext saved_ctxt)
+static JSONToken *parser_context_pop_token(JSONParserContext *ctxt)
{
- ctxt->tokens.pos = saved_ctxt.tokens.pos;
- ctxt->tokens.count = saved_ctxt.tokens.count;
- ctxt->tokens.buf = saved_ctxt.tokens.buf;
+ g_free(ctxt->current);
+ assert(!g_queue_is_empty(ctxt->buf));
+ ctxt->current = g_queue_pop_head(ctxt->buf);
+ return ctxt->current;
}
-static void tokens_append_from_iter(QObject *obj, void *opaque)
+static JSONToken *parser_context_peek_token(JSONParserContext *ctxt)
{
- JSONParserContext *ctxt = opaque;
- g_assert(ctxt->tokens.pos < ctxt->tokens.count);
- ctxt->tokens.buf[ctxt->tokens.pos++] = obj;
- qobject_incref(obj);
+ assert(!g_queue_is_empty(ctxt->buf));
+ return g_queue_peek_head(ctxt->buf);
}
-static JSONParserContext *parser_context_new(QList *tokens)
+static JSONParserContext *parser_context_new(GQueue *tokens)
{
JSONParserContext *ctxt;
- size_t count;
if (!tokens) {
return NULL;
}
- count = qlist_size(tokens);
- if (count == 0) {
- return NULL;
- }
-
ctxt = g_malloc0(sizeof(JSONParserContext));
- ctxt->tokens.pos = 0;
- ctxt->tokens.count = count;
- ctxt->tokens.buf = g_malloc(count * sizeof(QObject *));
- qlist_iter(tokens, tokens_append_from_iter, ctxt);
- ctxt->tokens.pos = 0;
+ ctxt->buf = tokens;
return ctxt;
}
@@ -348,12 +260,12 @@ static JSONParserContext *parser_context_new(QList *tokens)
/* to support error propagation, ctxt->err must be freed separately */
static void parser_context_free(JSONParserContext *ctxt)
{
- int i;
if (ctxt) {
- for (i = 0; i < ctxt->tokens.count; i++) {
- qobject_decref(ctxt->tokens.buf[i]);
+ while (!g_queue_is_empty(ctxt->buf)) {
+ parser_context_pop_token(ctxt);
}
- g_free(ctxt->tokens.buf);
+ g_free(ctxt->current);
+ g_queue_free(ctxt->buf);
g_free(ctxt);
}
}
@@ -363,8 +275,8 @@ static void parser_context_free(JSONParserContext *ctxt)
*/
static int parse_pair(JSONParserContext *ctxt, QDict *dict, va_list *ap)
{
- QObject *key = NULL, *token = NULL, *value, *peek;
- JSONParserContext saved_ctxt = parser_context_save(ctxt);
+ QObject *key = NULL, *value;
+ JSONToken *peek, *token;
peek = parser_context_peek_token(ctxt);
if (peek == NULL) {
@@ -384,7 +296,7 @@ static int parse_pair(JSONParserContext *ctxt, QDict *dict, va_list *ap)
goto out;
}
- if (!token_is_operator(token, ':')) {
+ if (token->type != JSON_COLON) {
parse_error(ctxt, token, "missing : in object pair");
goto out;
}
@@ -402,7 +314,6 @@ static int parse_pair(JSONParserContext *ctxt, QDict *dict, va_list *ap)
return 0;
out:
- parser_context_restore(ctxt, saved_ctxt);
qobject_decref(key);
return -1;
@@ -411,17 +322,10 @@ out:
static QObject *parse_object(JSONParserContext *ctxt, va_list *ap)
{
QDict *dict = NULL;
- QObject *token, *peek;
- JSONParserContext saved_ctxt = parser_context_save(ctxt);
+ JSONToken *token, *peek;
token = parser_context_pop_token(ctxt);
- if (token == NULL) {
- goto out;
- }
-
- if (!token_is_operator(token, '{')) {
- goto out;
- }
+ assert(token && token->type == JSON_LCURLY);
dict = qdict_new();
@@ -431,7 +335,7 @@ static QObject *parse_object(JSONParserContext *ctxt, va_list *ap)
goto out;
}
- if (!token_is_operator(peek, '}')) {
+ if (peek->type != JSON_RCURLY) {
if (parse_pair(ctxt, dict, ap) == -1) {
goto out;
}
@@ -442,8 +346,8 @@ static QObject *parse_object(JSONParserContext *ctxt, va_list *ap)
goto out;
}
- while (!token_is_operator(token, '}')) {
- if (!token_is_operator(token, ',')) {
+ while (token->type != JSON_RCURLY) {
+ if (token->type != JSON_COMMA) {
parse_error(ctxt, token, "expected separator in dict");
goto out;
}
@@ -465,7 +369,6 @@ static QObject *parse_object(JSONParserContext *ctxt, va_list *ap)
return QOBJECT(dict);
out:
- parser_context_restore(ctxt, saved_ctxt);
QDECREF(dict);
return NULL;
}
@@ -473,17 +376,10 @@ out:
static QObject *parse_array(JSONParserContext *ctxt, va_list *ap)
{
QList *list = NULL;
- QObject *token, *peek;
- JSONParserContext saved_ctxt = parser_context_save(ctxt);
+ JSONToken *token, *peek;
token = parser_context_pop_token(ctxt);
- if (token == NULL) {
- goto out;
- }
-
- if (!token_is_operator(token, '[')) {
- goto out;
- }
+ assert(token && token->type == JSON_LSQUARE);
list = qlist_new();
@@ -493,7 +389,7 @@ static QObject *parse_array(JSONParserContext *ctxt, va_list *ap)
goto out;
}
- if (!token_is_operator(peek, ']')) {
+ if (peek->type != JSON_RSQUARE) {
QObject *obj;
obj = parse_value(ctxt, ap);
@@ -510,8 +406,8 @@ static QObject *parse_array(JSONParserContext *ctxt, va_list *ap)
goto out;
}
- while (!token_is_operator(token, ']')) {
- if (!token_is_operator(token, ',')) {
+ while (token->type != JSON_RSQUARE) {
+ if (token->type != JSON_COMMA) {
parse_error(ctxt, token, "expected separator in list");
goto out;
}
@@ -537,99 +433,68 @@ static QObject *parse_array(JSONParserContext *ctxt, va_list *ap)
return QOBJECT(list);
out:
- parser_context_restore(ctxt, saved_ctxt);
QDECREF(list);
return NULL;
}
static QObject *parse_keyword(JSONParserContext *ctxt)
{
- QObject *token, *ret;
- JSONParserContext saved_ctxt = parser_context_save(ctxt);
+ JSONToken *token;
token = parser_context_pop_token(ctxt);
- if (token == NULL) {
- goto out;
- }
-
- if (token_get_type(token) != JSON_KEYWORD) {
- goto out;
- }
+ assert(token && token->type == JSON_KEYWORD);
- if (token_is_keyword(token, "true")) {
- ret = QOBJECT(qbool_from_bool(true));
- } else if (token_is_keyword(token, "false")) {
- ret = QOBJECT(qbool_from_bool(false));
- } else if (token_is_keyword(token, "null")) {
- ret = qnull();
- } else {
- parse_error(ctxt, token, "invalid keyword `%s'", token_get_value(token));
- goto out;
+ if (!strcmp(token->str, "true")) {
+ return QOBJECT(qbool_from_bool(true));
+ } else if (!strcmp(token->str, "false")) {
+ return QOBJECT(qbool_from_bool(false));
+ } else if (!strcmp(token->str, "null")) {
+ return qnull();
}
-
- return ret;
-
-out:
- parser_context_restore(ctxt, saved_ctxt);
-
+ parse_error(ctxt, token, "invalid keyword '%s'", token->str);
return NULL;
}
static QObject *parse_escape(JSONParserContext *ctxt, va_list *ap)
{
- QObject *token = NULL, *obj;
- JSONParserContext saved_ctxt = parser_context_save(ctxt);
+ JSONToken *token;
if (ap == NULL) {
- goto out;
+ return NULL;
}
token = parser_context_pop_token(ctxt);
- if (token == NULL) {
- goto out;
- }
-
- if (token_is_escape(token, "%p")) {
- obj = va_arg(*ap, QObject *);
- } else if (token_is_escape(token, "%i")) {
- obj = QOBJECT(qbool_from_bool(va_arg(*ap, int)));
- } else if (token_is_escape(token, "%d")) {
- obj = QOBJECT(qint_from_int(va_arg(*ap, int)));
- } else if (token_is_escape(token, "%ld")) {
- obj = QOBJECT(qint_from_int(va_arg(*ap, long)));
- } else if (token_is_escape(token, "%lld") ||
- token_is_escape(token, "%I64d")) {
- obj = QOBJECT(qint_from_int(va_arg(*ap, long long)));
- } else if (token_is_escape(token, "%s")) {
- obj = QOBJECT(qstring_from_str(va_arg(*ap, const char *)));
- } else if (token_is_escape(token, "%f")) {
- obj = QOBJECT(qfloat_from_double(va_arg(*ap, double)));
- } else {
- goto out;
+ assert(token && token->type == JSON_ESCAPE);
+
+ if (!strcmp(token->str, "%p")) {
+ return va_arg(*ap, QObject *);
+ } else if (!strcmp(token->str, "%i")) {
+ return QOBJECT(qbool_from_bool(va_arg(*ap, int)));
+ } else if (!strcmp(token->str, "%d")) {
+ return QOBJECT(qint_from_int(va_arg(*ap, int)));
+ } else if (!strcmp(token->str, "%ld")) {
+ return QOBJECT(qint_from_int(va_arg(*ap, long)));
+ } else if (!strcmp(token->str, "%lld") ||
+ !strcmp(token->str, "%I64d")) {
+ return QOBJECT(qint_from_int(va_arg(*ap, long long)));
+ } else if (!strcmp(token->str, "%s")) {
+ return QOBJECT(qstring_from_str(va_arg(*ap, const char *)));
+ } else if (!strcmp(token->str, "%f")) {
+ return QOBJECT(qfloat_from_double(va_arg(*ap, double)));
}
-
- return obj;
-
-out:
- parser_context_restore(ctxt, saved_ctxt);
-
return NULL;
}
static QObject *parse_literal(JSONParserContext *ctxt)
{
- QObject *token, *obj;
- JSONParserContext saved_ctxt = parser_context_save(ctxt);
+ JSONToken *token;
token = parser_context_pop_token(ctxt);
- if (token == NULL) {
- goto out;
- }
+ assert(token);
- switch (token_get_type(token)) {
+ switch (token->type) {
case JSON_STRING:
- obj = QOBJECT(qstring_from_escaped_str(ctxt, token));
- break;
+ return QOBJECT(qstring_from_escaped_str(ctxt, token));
case JSON_INTEGER: {
/* A possibility exists that this is a whole-valued float where the
* fractional part was left out due to being 0 (.0). It's not a big
@@ -646,56 +511,55 @@ static QObject *parse_literal(JSONParserContext *ctxt)
int64_t value;
errno = 0; /* strtoll doesn't set errno on success */
- value = strtoll(token_get_value(token), NULL, 10);
+ value = strtoll(token->str, NULL, 10);
if (errno != ERANGE) {
- obj = QOBJECT(qint_from_int(value));
- break;
+ return QOBJECT(qint_from_int(value));
}
/* fall through to JSON_FLOAT */
}
case JSON_FLOAT:
/* FIXME dependent on locale */
- obj = QOBJECT(qfloat_from_double(strtod(token_get_value(token), NULL)));
- break;
+ return QOBJECT(qfloat_from_double(strtod(token->str, NULL)));
default:
- goto out;
+ abort();
}
-
- return obj;
-
-out:
- parser_context_restore(ctxt, saved_ctxt);
-
- return NULL;
}
static QObject *parse_value(JSONParserContext *ctxt, va_list *ap)
{
- QObject *obj;
+ JSONToken *token;
- obj = parse_object(ctxt, ap);
- if (obj == NULL) {
- obj = parse_array(ctxt, ap);
- }
- if (obj == NULL) {
- obj = parse_escape(ctxt, ap);
- }
- if (obj == NULL) {
- obj = parse_keyword(ctxt);
- }
- if (obj == NULL) {
- obj = parse_literal(ctxt);
+ token = parser_context_peek_token(ctxt);
+ if (token == NULL) {
+ parse_error(ctxt, NULL, "premature EOI");
+ return NULL;
}
- return obj;
+ switch (token->type) {
+ case JSON_LCURLY:
+ return parse_object(ctxt, ap);
+ case JSON_LSQUARE:
+ return parse_array(ctxt, ap);
+ case JSON_ESCAPE:
+ return parse_escape(ctxt, ap);
+ case JSON_INTEGER:
+ case JSON_FLOAT:
+ case JSON_STRING:
+ return parse_literal(ctxt);
+ case JSON_KEYWORD:
+ return parse_keyword(ctxt);
+ default:
+ parse_error(ctxt, token, "expecting value");
+ return NULL;
+ }
}
-QObject *json_parser_parse(QList *tokens, va_list *ap)
+QObject *json_parser_parse(GQueue *tokens, va_list *ap)
{
return json_parser_parse_err(tokens, ap, NULL);
}
-QObject *json_parser_parse_err(QList *tokens, va_list *ap, Error **errp)
+QObject *json_parser_parse_err(GQueue *tokens, va_list *ap, Error **errp)
{
JSONParserContext *ctxt = parser_context_new(tokens);
QObject *result;
diff --git a/qobject/json-streamer.c b/qobject/json-streamer.c
index 1b2f9b1..a4db4b8 100644
--- a/qobject/json-streamer.c
+++ b/qobject/json-streamer.c
@@ -11,50 +11,55 @@
*
*/
-#include "qapi/qmp/qlist.h"
-#include "qapi/qmp/qint.h"
-#include "qapi/qmp/qdict.h"
#include "qemu-common.h"
#include "qapi/qmp/json-lexer.h"
#include "qapi/qmp/json-streamer.h"
#define MAX_TOKEN_SIZE (64ULL << 20)
+#define MAX_TOKEN_COUNT (2ULL << 20)
#define MAX_NESTING (1ULL << 10)
-static void json_message_process_token(JSONLexer *lexer, QString *token, JSONTokenType type, int x, int y)
+static void json_message_free_tokens(JSONMessageParser *parser)
+{
+ if (parser->tokens) {
+ g_queue_free(parser->tokens);
+ parser->tokens = NULL;
+ }
+}
+
+static void json_message_process_token(JSONLexer *lexer, GString *input,
+ JSONTokenType type, int x, int y)
{
JSONMessageParser *parser = container_of(lexer, JSONMessageParser, lexer);
- QDict *dict;
-
- if (type == JSON_OPERATOR) {
- switch (qstring_get_str(token)[0]) {
- case '{':
- parser->brace_count++;
- break;
- case '}':
- parser->brace_count--;
- break;
- case '[':
- parser->bracket_count++;
- break;
- case ']':
- parser->bracket_count--;
- break;
- default:
- break;
- }
+ JSONToken *token;
+
+ switch (type) {
+ case JSON_LCURLY:
+ parser->brace_count++;
+ break;
+ case JSON_RCURLY:
+ parser->brace_count--;
+ break;
+ case JSON_LSQUARE:
+ parser->bracket_count++;
+ break;
+ case JSON_RSQUARE:
+ parser->bracket_count--;
+ break;
+ default:
+ break;
}
- dict = qdict_new();
- qdict_put(dict, "type", qint_from_int(type));
- QINCREF(token);
- qdict_put(dict, "token", token);
- qdict_put(dict, "x", qint_from_int(x));
- qdict_put(dict, "y", qint_from_int(y));
+ token = g_malloc(sizeof(JSONToken) + input->len + 1);
+ token->type = type;
+ memcpy(token->str, input->str, input->len);
+ token->str[input->len] = 0;
+ token->x = x;
+ token->y = y;
- parser->token_size += token->length;
+ parser->token_size += input->len;
- qlist_append(parser->tokens, dict);
+ g_queue_push_tail(parser->tokens, token);
if (type == JSON_ERROR) {
goto out_emit_bad;
@@ -64,41 +69,39 @@ static void json_message_process_token(JSONLexer *lexer, QString *token, JSONTok
parser->bracket_count == 0)) {
goto out_emit;
} else if (parser->token_size > MAX_TOKEN_SIZE ||
- parser->bracket_count > MAX_NESTING ||
- parser->brace_count > MAX_NESTING) {
+ g_queue_get_length(parser->tokens) > MAX_TOKEN_COUNT ||
+ parser->bracket_count + parser->brace_count > MAX_NESTING) {
/* Security consideration, we limit total memory allocated per object
* and the maximum recursion depth that a message can force.
*/
- goto out_emit;
+ goto out_emit_bad;
}
return;
out_emit_bad:
- /* clear out token list and tell the parser to emit and error
+ /*
+ * Clear out token list and tell the parser to emit an error
* indication by passing it a NULL list
*/
- QDECREF(parser->tokens);
- parser->tokens = NULL;
+ json_message_free_tokens(parser);
out_emit:
/* send current list of tokens to parser and reset tokenizer */
parser->brace_count = 0;
parser->bracket_count = 0;
+ /* parser->emit takes ownership of parser->tokens. */
parser->emit(parser, parser->tokens);
- if (parser->tokens) {
- QDECREF(parser->tokens);
- }
- parser->tokens = qlist_new();
+ parser->tokens = g_queue_new();
parser->token_size = 0;
}
void json_message_parser_init(JSONMessageParser *parser,
- void (*func)(JSONMessageParser *, QList *))
+ void (*func)(JSONMessageParser *, GQueue *))
{
parser->emit = func;
parser->brace_count = 0;
parser->bracket_count = 0;
- parser->tokens = qlist_new();
+ parser->tokens = g_queue_new();
parser->token_size = 0;
json_lexer_init(&parser->lexer, json_message_process_token);
@@ -118,5 +121,5 @@ int json_message_parser_flush(JSONMessageParser *parser)
void json_message_parser_destroy(JSONMessageParser *parser)
{
json_lexer_destroy(&parser->lexer);
- QDECREF(parser->tokens);
+ json_message_free_tokens(parser);
}
diff --git a/qobject/qjson.c b/qobject/qjson.c
index 33f8ef5..a3e6a7c 100644
--- a/qobject/qjson.c
+++ b/qobject/qjson.c
@@ -28,7 +28,7 @@ typedef struct JSONParsingState
QObject *result;
} JSONParsingState;
-static void parse_json(JSONMessageParser *parser, QList *tokens)
+static void parse_json(JSONMessageParser *parser, GQueue *tokens)
{
JSONParsingState *s = container_of(parser, JSONParsingState, parser);
s->result = json_parser_parse(tokens, s->ap);
diff --git a/target-arm/helper.c b/target-arm/helper.c
index 4ecae61..afc4163 100644
--- a/target-arm/helper.c
+++ b/target-arm/helper.c
@@ -6642,6 +6642,7 @@ static bool get_phys_addr_lpae(CPUARMState *env, target_ulong address,
int ap, ns, xn, pxn;
uint32_t el = regime_el(env, mmu_idx);
bool ttbr1_valid = true;
+ uint64_t descaddrmask;
/* TODO:
* This code does not handle the different format TCR for VTCR_EL2.
@@ -6831,6 +6832,15 @@ static bool get_phys_addr_lpae(CPUARMState *env, target_ulong address,
descaddr = extract64(ttbr, 0, 48);
descaddr &= ~((1ULL << (inputsize - (stride * (4 - level)))) - 1);
+ /* The address field in the descriptor goes up to bit 39 for ARMv7
+ * but up to bit 47 for ARMv8.
+ */
+ if (arm_feature(env, ARM_FEATURE_V8)) {
+ descaddrmask = 0xfffffffff000ULL;
+ } else {
+ descaddrmask = 0xfffffff000ULL;
+ }
+
/* Secure accesses start with the page table in secure memory and
* can be downgraded to non-secure at any step. Non-secure accesses
* remain non-secure. We implement this by just ORing in the NSTable/NS
@@ -6854,7 +6864,7 @@ static bool get_phys_addr_lpae(CPUARMState *env, target_ulong address,
/* Invalid, or the Reserved level 3 encoding */
goto do_fault;
}
- descaddr = descriptor & 0xfffffff000ULL;
+ descaddr = descriptor & descaddrmask;
if ((descriptor & 2) && (level < 3)) {
/* Table entry. The top five bits are attributes which may
diff --git a/target-arm/translate-a64.c b/target-arm/translate-a64.c
index fe485a4..14e8131 100644
--- a/target-arm/translate-a64.c
+++ b/target-arm/translate-a64.c
@@ -1816,9 +1816,6 @@ static void gen_store_exclusive(DisasContext *s, int rd, int rt, int rt2,
* o2: 0 -> exclusive, 1 -> not
* o1: 0 -> single register, 1 -> register pair
* o0: 1 -> load-acquire/store-release, 0 -> not
- *
- * o0 == 0 AND o2 == 1 is un-allocated
- * o1 == 1 is un-allocated except for 32 and 64 bit sizes
*/
static void disas_ldst_excl(DisasContext *s, uint32_t insn)
{
@@ -1833,7 +1830,8 @@ static void disas_ldst_excl(DisasContext *s, uint32_t insn)
int size = extract32(insn, 30, 2);
TCGv_i64 tcg_addr;
- if ((!is_excl && !is_lasr) ||
+ if ((!is_excl && !is_pair && !is_lasr) ||
+ (!is_excl && is_pair) ||
(is_pair && size < 2)) {
unallocated_encoding(s);
return;
@@ -1862,15 +1860,6 @@ static void disas_ldst_excl(DisasContext *s, uint32_t insn)
} else {
do_gpr_ld(s, tcg_rt, tcg_addr, size, false, false);
}
- if (is_pair) {
- TCGv_i64 tcg_rt2 = cpu_reg(s, rt);
- tcg_gen_addi_i64(tcg_addr, tcg_addr, 1 << size);
- if (is_store) {
- do_gpr_st(s, tcg_rt2, tcg_addr, size);
- } else {
- do_gpr_ld(s, tcg_rt2, tcg_addr, size, false, false);
- }
- }
}
}
diff --git a/target-i386/cpu.h b/target-i386/cpu.h
index fc4a605..84edfd0 100644
--- a/target-i386/cpu.h
+++ b/target-i386/cpu.h
@@ -286,6 +286,8 @@
#define MCE_CAP_DEF (MCG_CTL_P|MCG_SER_P)
#define MCE_BANKS_DEF 10
+#define MCG_CAP_BANKS_MASK 0xff
+
#define MCG_STATUS_RIPV (1ULL<<0) /* restart ip valid */
#define MCG_STATUS_EIPV (1ULL<<1) /* ip points to correct instruction */
#define MCG_STATUS_MCIP (1ULL<<2) /* machine check in progress */
diff --git a/target-i386/kvm.c b/target-i386/kvm.c
index 2a9953b..6dc9846 100644
--- a/target-i386/kvm.c
+++ b/target-i386/kvm.c
@@ -774,7 +774,7 @@ int kvm_arch_init_vcpu(CPUState *cs)
&& (env->features[FEAT_1_EDX] & (CPUID_MCE | CPUID_MCA)) ==
(CPUID_MCE | CPUID_MCA)
&& kvm_check_extension(cs->kvm_state, KVM_CAP_MCE) > 0) {
- uint64_t mcg_cap;
+ uint64_t mcg_cap, unsupported_caps;
int banks;
int ret;
@@ -784,18 +784,24 @@ int kvm_arch_init_vcpu(CPUState *cs)
return ret;
}
- if (banks > MCE_BANKS_DEF) {
- banks = MCE_BANKS_DEF;
+ if (banks < (env->mcg_cap & MCG_CAP_BANKS_MASK)) {
+ error_report("kvm: Unsupported MCE bank count (QEMU = %d, KVM = %d)",
+ (int)(env->mcg_cap & MCG_CAP_BANKS_MASK), banks);
+ return -ENOTSUP;
}
- mcg_cap &= MCE_CAP_DEF;
- mcg_cap |= banks;
- ret = kvm_vcpu_ioctl(cs, KVM_X86_SETUP_MCE, &mcg_cap);
+
+ unsupported_caps = env->mcg_cap & ~(mcg_cap | MCG_CAP_BANKS_MASK);
+ if (unsupported_caps) {
+ error_report("warning: Unsupported MCG_CAP bits: 0x%" PRIx64,
+ unsupported_caps);
+ }
+
+ env->mcg_cap &= mcg_cap | MCG_CAP_BANKS_MASK;
+ ret = kvm_vcpu_ioctl(cs, KVM_X86_SETUP_MCE, &env->mcg_cap);
if (ret < 0) {
fprintf(stderr, "KVM_X86_SETUP_MCE: %s", strerror(-ret));
return ret;
}
-
- env->mcg_cap = mcg_cap;
}
qemu_add_vm_change_state_handler(cpu_update_state, env);
diff --git a/target-mips/cpu.h b/target-mips/cpu.h
index fa919c1..89c01f7 100644
--- a/target-mips/cpu.h
+++ b/target-mips/cpu.h
@@ -961,6 +961,15 @@ static inline void compute_hflags(CPUMIPSState *env)
}
#ifndef CONFIG_USER_ONLY
+static inline void cpu_mips_tlb_flush(CPUMIPSState *env, int flush_global)
+{
+ MIPSCPU *cpu = mips_env_get_cpu(env);
+
+ /* Flush qemu's TLB and discard all shadowed entries. */
+ tlb_flush(CPU(cpu), flush_global);
+ env->tlb->tlb_in_use = env->tlb->nb_tlb;
+}
+
/* Called for updates to CP0_Status. */
static inline void sync_c0_status(CPUMIPSState *env, CPUMIPSState *cpu, int tc)
{
@@ -999,6 +1008,7 @@ static inline void sync_c0_status(CPUMIPSState *env, CPUMIPSState *cpu, int tc)
static inline void cpu_mips_store_status(CPUMIPSState *env, target_ulong val)
{
uint32_t mask = env->CP0_Status_rw_bitmask;
+ target_ulong old = env->CP0_Status;
if (env->insn_flags & ISA_MIPS32R6) {
bool has_supervisor = extract32(mask, CP0St_KSU, 2) == 0x3;
@@ -1014,7 +1024,13 @@ static inline void cpu_mips_store_status(CPUMIPSState *env, target_ulong val)
mask &= ~(((1 << CP0St_SR) | (1 << CP0St_NMI)) & val);
}
- env->CP0_Status = (env->CP0_Status & ~mask) | (val & mask);
+ env->CP0_Status = (old & ~mask) | (val & mask);
+#if defined(TARGET_MIPS64)
+ if ((env->CP0_Status ^ old) & (old & (7 << CP0St_UX))) {
+ /* Access to at least one of the 64-bit segments has been disabled */
+ cpu_mips_tlb_flush(env, 1);
+ }
+#endif
if (env->CP0_Config3 & (1 << CP0C3_MT)) {
sync_c0_status(env, env, env->current_tc);
} else {
diff --git a/target-mips/helper.c b/target-mips/helper.c
index b3fe816..118072a 100644
--- a/target-mips/helper.c
+++ b/target-mips/helper.c
@@ -524,6 +524,10 @@ void mips_cpu_do_interrupt(CPUState *cs)
enter_debug_mode:
if (env->insn_flags & ISA_MIPS3) {
env->hflags |= MIPS_HFLAG_64;
+ if (!(env->insn_flags & ISA_MIPS64R6) ||
+ env->CP0_Status & (1 << CP0St_KX)) {
+ env->hflags &= ~MIPS_HFLAG_AWRAP;
+ }
}
env->hflags |= MIPS_HFLAG_DM | MIPS_HFLAG_CP0;
env->hflags &= ~(MIPS_HFLAG_KSU);
@@ -548,6 +552,10 @@ void mips_cpu_do_interrupt(CPUState *cs)
env->CP0_Status |= (1 << CP0St_ERL) | (1 << CP0St_BEV);
if (env->insn_flags & ISA_MIPS3) {
env->hflags |= MIPS_HFLAG_64;
+ if (!(env->insn_flags & ISA_MIPS64R6) ||
+ env->CP0_Status & (1 << CP0St_KX)) {
+ env->hflags &= ~MIPS_HFLAG_AWRAP;
+ }
}
env->hflags |= MIPS_HFLAG_CP0;
env->hflags &= ~(MIPS_HFLAG_KSU);
@@ -725,6 +733,10 @@ void mips_cpu_do_interrupt(CPUState *cs)
env->CP0_Status |= (1 << CP0St_EXL);
if (env->insn_flags & ISA_MIPS3) {
env->hflags |= MIPS_HFLAG_64;
+ if (!(env->insn_flags & ISA_MIPS64R6) ||
+ env->CP0_Status & (1 << CP0St_KX)) {
+ env->hflags &= ~MIPS_HFLAG_AWRAP;
+ }
}
env->hflags |= MIPS_HFLAG_CP0;
env->hflags &= ~(MIPS_HFLAG_KSU);
diff --git a/target-mips/op_helper.c b/target-mips/op_helper.c
index 056d53b..d2c98c9 100644
--- a/target-mips/op_helper.c
+++ b/target-mips/op_helper.c
@@ -23,10 +23,6 @@
#include "exec/cpu_ldst.h"
#include "sysemu/kvm.h"
-#ifndef CONFIG_USER_ONLY
-static inline void cpu_mips_tlb_flush (CPUMIPSState *env, int flush_global);
-#endif
-
/*****************************************************************************/
/* Exceptions processing helpers */
@@ -1846,15 +1842,6 @@ target_ulong helper_yield(CPUMIPSState *env, target_ulong arg)
#ifndef CONFIG_USER_ONLY
/* TLB management */
-static void cpu_mips_tlb_flush (CPUMIPSState *env, int flush_global)
-{
- MIPSCPU *cpu = mips_env_get_cpu(env);
-
- /* Flush qemu's TLB and discard all shadowed entries. */
- tlb_flush(CPU(cpu), flush_global);
- env->tlb->tlb_in_use = env->tlb->nb_tlb;
-}
-
static void r4k_mips_tlb_flush_extra (CPUMIPSState *env, int first)
{
/* Discard entries from env->tlb[first] onwards. */
diff --git a/target-sparc/vis_helper.c b/target-sparc/vis_helper.c
index 383cc8b..45fc7db 100644
--- a/target-sparc/vis_helper.c
+++ b/target-sparc/vis_helper.c
@@ -447,7 +447,7 @@ uint32_t helper_fpackfix(uint64_t gsr, uint64_t rs2)
for (word = 0; word < 2; word++) {
uint32_t val;
int32_t src = rs2 >> (word * 32);
- int64_t scaled = src << scale;
+ int64_t scaled = (int64_t)src << scale;
int64_t from_fixed = scaled >> 16;
val = (from_fixed < -32768 ? -32768 :
diff --git a/tcg/tcg.c b/tcg/tcg.c
index 682af8a..b20ed19 100644
--- a/tcg/tcg.c
+++ b/tcg/tcg.c
@@ -2443,7 +2443,7 @@ int tcg_gen_code(TCGContext *s, tcg_insn_unit *gen_code_buf)
one operation beginning below the high water mark cannot overrun
the buffer completely. Thus we can test for overflow after
generating code without having to check during generation. */
- if (unlikely(s->code_gen_ptr > s->code_gen_highwater)) {
+ if (unlikely((void *)s->code_ptr > s->code_gen_highwater)) {
return -1;
}
}
diff --git a/tests/Makefile b/tests/Makefile
index b937984..0ef00a1 100644
--- a/tests/Makefile
+++ b/tests/Makefile
@@ -415,8 +415,7 @@ tests/test-vmstate$(EXESUF): tests/test-vmstate.o \
migration/qemu-file-unix.o qjson.o \
$(test-qom-obj-y)
tests/test-timed-average$(EXESUF): tests/test-timed-average.o qemu-timer.o \
- libqemuutil.a stubs/clock-warp.o stubs/cpu-get-icount.o \
- stubs/notify-event.o stubs/replay.o
+ $(test-util-obj-y)
tests/test-qapi-types.c tests/test-qapi-types.h :\
$(SRC_PATH)/tests/qapi-schema/qapi-schema-test.json $(SRC_PATH)/scripts/qapi-types.py $(qapi-py)
diff --git a/tests/check-qjson.c b/tests/check-qjson.c
index 1cfffa5..61e9bfb 100644
--- a/tests/check-qjson.c
+++ b/tests/check-qjson.c
@@ -1484,6 +1484,30 @@ static void unterminated_literal(void)
g_assert(obj == NULL);
}
+static char *make_nest(char *buf, size_t cnt)
+{
+ memset(buf, '[', cnt - 1);
+ buf[cnt - 1] = '{';
+ buf[cnt] = '}';
+ memset(buf + cnt + 1, ']', cnt - 1);
+ buf[2 * cnt] = 0;
+ return buf;
+}
+
+static void limits_nesting(void)
+{
+ enum { max_nesting = 1024 }; /* see qobject/json-streamer.c */
+ char buf[2 * (max_nesting + 1) + 1];
+ QObject *obj;
+
+ obj = qobject_from_json(make_nest(buf, max_nesting));
+ g_assert(obj != NULL);
+ qobject_decref(obj);
+
+ obj = qobject_from_json(make_nest(buf, max_nesting + 1));
+ g_assert(obj == NULL);
+}
+
int main(int argc, char **argv)
{
g_test_init(&argc, &argv, NULL);
@@ -1519,6 +1543,7 @@ int main(int argc, char **argv)
g_test_add_func("/errors/invalid_array_comma", invalid_array_comma);
g_test_add_func("/errors/invalid_dict_comma", invalid_dict_comma);
g_test_add_func("/errors/unterminated/literal", unterminated_literal);
+ g_test_add_func("/errors/limits/nesting", limits_nesting);
return g_test_run();
}
diff --git a/tests/ide-test.c b/tests/ide-test.c
index fc1ce52..c3aacd2 100644
--- a/tests/ide-test.c
+++ b/tests/ide-test.c
@@ -642,15 +642,19 @@ static void nsleep(int64_t nsecs)
static uint8_t ide_wait_clear(uint8_t flag)
{
- int i;
uint8_t data;
+ time_t st;
/* Wait with a 5 second timeout */
- for (i = 0; i <= 12500000; i++) {
+ time(&st);
+ while (true) {
data = inb(IDE_BASE + reg_status);
if (!(data & flag)) {
return data;
}
+ if (difftime(time(NULL), st) > 5.0) {
+ break;
+ }
nsleep(400);
}
g_assert_not_reached();
@@ -658,14 +662,18 @@ static uint8_t ide_wait_clear(uint8_t flag)
static void ide_wait_intr(int irq)
{
- int i;
+ time_t st;
bool intr;
- for (i = 0; i <= 12500000; i++) {
+ time(&st);
+ while (true) {
intr = get_irq(irq);
if (intr) {
return;
}
+ if (difftime(time(NULL), st) > 5.0) {
+ break;
+ }
nsleep(400);
}
@@ -709,9 +717,6 @@ static void cdrom_pio_impl(int nblocks)
/* SCSI CDB (READ10) -- read n*2048 bytes from block 0 */
send_scsi_cdb_read10(0, nblocks);
- /* HP3: INTRQ_Wait */
- ide_wait_intr(IDE_PRIMARY_IRQ);
-
/* Read data back: occurs in bursts of 'BYTE_COUNT_LIMIT' bytes.
* If BYTE_COUNT_LIMIT is odd, we transfer BYTE_COUNT_LIMIT - 1 bytes.
* We allow an odd limit only when the remaining transfer size is
@@ -723,16 +728,25 @@ static void cdrom_pio_impl(int nblocks)
for (i = 0; i < DIV_ROUND_UP(rxsize, limit); i++) {
size_t offset = i * (limit / 2);
size_t rem = (rxsize / 2) - offset;
- /* HP2: Check_Status_B */
+
+ /* HP3: INTRQ_Wait */
+ ide_wait_intr(IDE_PRIMARY_IRQ);
+
+ /* HP2: Check_Status_B (and clear IRQ) */
data = ide_wait_clear(BSY);
assert_bit_set(data, DRQ | DRDY);
assert_bit_clear(data, ERR | DF | BSY);
+
/* HP4: Transfer_Data */
for (j = 0; j < MIN((limit / 2), rem); j++) {
rx[offset + j] = le16_to_cpu(inw(IDE_BASE + reg_data));
}
- ide_wait_intr(IDE_PRIMARY_IRQ);
}
+
+ /* Check for final completion IRQ */
+ ide_wait_intr(IDE_PRIMARY_IRQ);
+
+ /* Sanity check final state */
data = ide_wait_clear(DRQ);
assert_bit_set(data, DRDY);
assert_bit_clear(data, DRQ | ERR | DF | BSY);
diff --git a/tests/ivshmem-test.c b/tests/ivshmem-test.c
index f1793ba..03c7b96 100644
--- a/tests/ivshmem-test.c
+++ b/tests/ivshmem-test.c
@@ -40,6 +40,7 @@ static QPCIDevice *get_device(void)
QPCIBus *pcibus;
pcibus = qpci_init_pc();
+ dev = NULL;
qpci_device_foreach(pcibus, 0x1af4, 0x1110, save_fn, &dev);
g_assert(dev != NULL);
@@ -392,7 +393,7 @@ static void test_ivshmem_memdev(void)
/* just for the sake of checking memory-backend property */
setup_vm_cmd(&state, "-object memory-backend-ram,size=1M,id=mb1"
- " -device ivshmem,memdev=mb1", false);
+ " -device ivshmem,x-memdev=mb1", false);
qtest_quit(state.qtest);
}
diff --git a/tests/libqtest.c b/tests/libqtest.c
index f6f3d7a..9753161 100644
--- a/tests/libqtest.c
+++ b/tests/libqtest.c
@@ -351,7 +351,7 @@ typedef struct {
QDict *response;
} QMPResponseParser;
-static void qmp_response(JSONMessageParser *parser, QList *tokens)
+static void qmp_response(JSONMessageParser *parser, GQueue *tokens)
{
QMPResponseParser *qmp = container_of(parser, QMPResponseParser, parser);
QObject *obj;
diff --git a/tests/qemu-iotests/119 b/tests/qemu-iotests/119
index 9a11f1b..cc6ec07 100755
--- a/tests/qemu-iotests/119
+++ b/tests/qemu-iotests/119
@@ -49,7 +49,7 @@ echo "{'execute': 'qmp_capabilities'}
{'execute': 'human-monitor-command',
'arguments': {'command-line': 'qemu-io drv \"read -P 0 0 64k\"'}}
{'execute': 'quit'}" \
- | $QEMU -drive id=drv,if=none,file="$TEST_IMG",driver=nbd \
+ | $QEMU -nographic -drive id=drv,if=none,file="$TEST_IMG",driver=nbd \
-qmp stdio -nodefaults \
| _filter_qmp | _filter_qemu_io
diff --git a/tests/qemu-iotests/120 b/tests/qemu-iotests/120
index 9f13078..d899a3f 100755
--- a/tests/qemu-iotests/120
+++ b/tests/qemu-iotests/120
@@ -49,7 +49,7 @@ echo "{'execute': 'qmp_capabilities'}
{'execute': 'human-monitor-command',
'arguments': {'command-line': 'qemu-io drv \"write -P 42 0 64k\"'}}
{'execute': 'quit'}" \
- | $QEMU -qmp stdio -nodefaults \
+ | $QEMU -qmp stdio -nographic -nodefaults \
-drive id=drv,if=none,file="$TEST_IMG",driver=raw,file.driver=$IMGFMT \
| _filter_qmp | _filter_qemu_io
$QEMU_IO -c 'read -P 42 0 64k' "$TEST_IMG" | _filter_qemu_io
diff --git a/tests/test-aio.c b/tests/test-aio.c
index 1623803..e188d8c 100644
--- a/tests/test-aio.c
+++ b/tests/test-aio.c
@@ -393,6 +393,7 @@ static void test_aio_external_client(void)
aio_enable_external(ctx);
}
assert(aio_poll(ctx, false));
+ set_event_notifier(ctx, &data.e, NULL);
event_notifier_cleanup(&data.e);
}
}
diff --git a/tests/test-qga.c b/tests/test-qga.c
index 6473846..e6a84d1 100644
--- a/tests/test-qga.c
+++ b/tests/test-qga.c
@@ -13,6 +13,7 @@
#include "libqtest.h"
#include "config-host.h"
+#include "qga/guest-agent-core.h"
typedef struct {
char *test_dir;
@@ -352,10 +353,10 @@ static void test_qga_network_get_interfaces(gconstpointer fix)
static void test_qga_file_ops(gconstpointer fix)
{
const TestFixture *fixture = fix;
- const guchar helloworld[] = "Hello World!\n";
+ const unsigned char helloworld[] = "Hello World!\n";
const char *b64;
gchar *cmd, *path, *enc;
- guchar *dec;
+ unsigned char *dec;
QDict *ret, *val;
int64_t id, eof;
gsize count;
@@ -457,7 +458,7 @@ static void test_qga_file_ops(gconstpointer fix)
cmd = g_strdup_printf("{'execute': 'guest-file-seek',"
" 'arguments': { 'handle': %" PRId64 ", "
" 'offset': %d, 'whence': %d } }",
- id, 6, SEEK_SET);
+ id, 6, QGA_SEEK_SET);
ret = qmp_fd(fixture->fd, cmd);
qmp_assert_no_error(ret);
val = qdict_get_qdict(ret, "return");
@@ -496,6 +497,96 @@ static void test_qga_file_ops(gconstpointer fix)
g_free(cmd);
}
+static void test_qga_file_write_read(gconstpointer fix)
+{
+ const TestFixture *fixture = fix;
+ const unsigned char helloworld[] = "Hello World!\n";
+ const char *b64;
+ gchar *cmd, *enc;
+ QDict *ret, *val;
+ int64_t id, eof;
+ gsize count;
+
+ /* open */
+ ret = qmp_fd(fixture->fd, "{'execute': 'guest-file-open',"
+ " 'arguments': { 'path': 'foo', 'mode': 'w+' } }");
+ g_assert_nonnull(ret);
+ qmp_assert_no_error(ret);
+ id = qdict_get_int(ret, "return");
+ QDECREF(ret);
+
+ enc = g_base64_encode(helloworld, sizeof(helloworld));
+ /* write */
+ cmd = g_strdup_printf("{'execute': 'guest-file-write',"
+ " 'arguments': { 'handle': %" PRId64 ","
+ " 'buf-b64': '%s' } }", id, enc);
+ ret = qmp_fd(fixture->fd, cmd);
+ g_assert_nonnull(ret);
+ qmp_assert_no_error(ret);
+
+ val = qdict_get_qdict(ret, "return");
+ count = qdict_get_int(val, "count");
+ eof = qdict_get_bool(val, "eof");
+ g_assert_cmpint(count, ==, sizeof(helloworld));
+ g_assert_cmpint(eof, ==, 0);
+ QDECREF(ret);
+ g_free(cmd);
+
+ /* read (check implicit flush) */
+ cmd = g_strdup_printf("{'execute': 'guest-file-read',"
+ " 'arguments': { 'handle': %" PRId64 "} }",
+ id);
+ ret = qmp_fd(fixture->fd, cmd);
+ val = qdict_get_qdict(ret, "return");
+ count = qdict_get_int(val, "count");
+ eof = qdict_get_bool(val, "eof");
+ b64 = qdict_get_str(val, "buf-b64");
+ g_assert_cmpint(count, ==, 0);
+ g_assert(eof);
+ g_assert_cmpstr(b64, ==, "");
+ QDECREF(ret);
+ g_free(cmd);
+
+ /* seek to 0 */
+ cmd = g_strdup_printf("{'execute': 'guest-file-seek',"
+ " 'arguments': { 'handle': %" PRId64 ", "
+ " 'offset': %d, 'whence': %d } }",
+ id, 0, QGA_SEEK_SET);
+ ret = qmp_fd(fixture->fd, cmd);
+ qmp_assert_no_error(ret);
+ val = qdict_get_qdict(ret, "return");
+ count = qdict_get_int(val, "position");
+ eof = qdict_get_bool(val, "eof");
+ g_assert_cmpint(count, ==, 0);
+ g_assert(!eof);
+ QDECREF(ret);
+ g_free(cmd);
+
+ /* read */
+ cmd = g_strdup_printf("{'execute': 'guest-file-read',"
+ " 'arguments': { 'handle': %" PRId64 "} }",
+ id);
+ ret = qmp_fd(fixture->fd, cmd);
+ val = qdict_get_qdict(ret, "return");
+ count = qdict_get_int(val, "count");
+ eof = qdict_get_bool(val, "eof");
+ b64 = qdict_get_str(val, "buf-b64");
+ g_assert_cmpint(count, ==, sizeof(helloworld));
+ g_assert(eof);
+ g_assert_cmpstr(b64, ==, enc);
+ QDECREF(ret);
+ g_free(cmd);
+ g_free(enc);
+
+ /* close */
+ cmd = g_strdup_printf("{'execute': 'guest-file-close',"
+ " 'arguments': {'handle': %" PRId64 "} }",
+ id);
+ ret = qmp_fd(fixture->fd, cmd);
+ QDECREF(ret);
+ g_free(cmd);
+}
+
static void test_qga_get_time(gconstpointer fix)
{
const TestFixture *fixture = fix;
@@ -762,6 +853,7 @@ int main(int argc, char **argv)
g_test_add_data_func("/qga/get-memory-blocks", &fix,
test_qga_get_memory_blocks);
g_test_add_data_func("/qga/file-ops", &fix, test_qga_file_ops);
+ g_test_add_data_func("/qga/file-write-read", &fix, test_qga_file_write_read);
g_test_add_data_func("/qga/get-time", &fix, test_qga_get_time);
g_test_add_data_func("/qga/invalid-cmd", &fix, test_qga_invalid_cmd);
g_test_add_data_func("/qga/fsfreeze-status", &fix,
diff --git a/ui/vnc.c b/ui/vnc.c
index c9f2fed..7538405 100644
--- a/ui/vnc.c
+++ b/ui/vnc.c
@@ -931,6 +931,11 @@ static void vnc_dpy_copy(DisplayChangeListener *dcl,
int i, x, y, pitch, inc, w_lim, s;
int cmp_bytes;
+ if (!vd->server) {
+ /* no client connected */
+ return;
+ }
+
vnc_refresh_server_surface(vd);
QTAILQ_FOREACH_SAFE(vs, &vd->clients, next, vn) {
if (vnc_has_feature(vs, VNC_FEATURE_COPYRECT)) {
diff --git a/vl.c b/vl.c
index 525929b..4211ff1 100644
--- a/vl.c
+++ b/vl.c
@@ -4291,26 +4291,17 @@ int main(int argc, char **argv, char **envp)
page_size_init();
socket_init();
- if (qemu_opts_foreach(qemu_find_opts("chardev"),
- chardev_init_func, NULL, NULL)) {
- exit(1);
- }
-
- if (qtest_chrdev) {
- Error *local_err = NULL;
- qtest_init(qtest_chrdev, qtest_log, &local_err);
- if (local_err) {
- error_report_err(local_err);
- exit(1);
- }
- }
-
if (qemu_opts_foreach(qemu_find_opts("object"),
object_create,
object_create_initial, NULL)) {
exit(1);
}
+ if (qemu_opts_foreach(qemu_find_opts("chardev"),
+ chardev_init_func, NULL, NULL)) {
+ exit(1);
+ }
+
#ifdef CONFIG_VIRTFS
if (qemu_opts_foreach(qemu_find_opts("fsdev"),
fsdev_init_func, NULL, NULL)) {
@@ -4337,6 +4328,15 @@ int main(int argc, char **argv, char **envp)
configure_accelerator(current_machine);
+ if (qtest_chrdev) {
+ Error *local_err = NULL;
+ qtest_init(qtest_chrdev, qtest_log, &local_err);
+ if (local_err) {
+ error_report_err(local_err);
+ exit(1);
+ }
+ }
+
machine_opts = qemu_get_machine_opts();
kernel_filename = qemu_opt_get(machine_opts, "kernel");
initrd_filename = qemu_opt_get(machine_opts, "initrd");
OpenPOWER on IntegriCloud