summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.mailmap16
-rw-r--r--Makefile9
-rw-r--r--Makefile.target4
-rwxr-xr-xQMP/qmp126
-rw-r--r--README4
-rw-r--r--balloon.c28
-rw-r--r--balloon.h3
-rw-r--r--blockdev.c89
-rw-r--r--blockdev.h4
-rw-r--r--bsd-user/bsdload.c2
-rw-r--r--bsd-user/elfload.c5
-rwxr-xr-xconfigure10
-rw-r--r--console.h2
-rw-r--r--cpus.c96
-rw-r--r--docs/writing-qmp-commands.txt642
-rw-r--r--exec.c6
-rw-r--r--hmp-commands.hx36
-rw-r--r--hmp.c148
-rw-r--r--hmp.h12
-rw-r--r--hw/a9mpcore.c189
-rw-r--r--hw/arm11mpcore.c130
-rw-r--r--hw/arm_gic.c75
-rw-r--r--hw/arm_mptimer.c332
-rw-r--r--hw/arm_timer.c41
-rw-r--r--hw/ccid-card-emulated.c25
-rw-r--r--hw/e1000.c11
-rw-r--r--hw/eepro100.c7
-rw-r--r--hw/hw.h8
-rw-r--r--hw/ide/pci.c4
-rw-r--r--hw/lsi53c895a.c4
-rw-r--r--hw/mpcore.c283
-rw-r--r--hw/realview_gic.c25
-rw-r--r--hw/rtl8139.c8
-rw-r--r--hw/syborg.c113
-rw-r--r--hw/syborg.h18
-rw-r--r--hw/syborg_fb.c554
-rw-r--r--hw/syborg_interrupt.c233
-rw-r--r--hw/syborg_keyboard.c215
-rw-r--r--hw/syborg_pointer.c220
-rw-r--r--hw/syborg_rtc.c134
-rw-r--r--hw/syborg_serial.c329
-rw-r--r--hw/syborg_timer.c224
-rw-r--r--hw/syborg_virtio.c307
-rw-r--r--hw/usb-ehci.c6
-rw-r--r--hw/usb-net.c5
-rw-r--r--hw/usb-uhci.c17
-rw-r--r--migration-exec.c9
-rw-r--r--migration-tcp.c7
-rw-r--r--migration-unix.c7
-rw-r--r--migration.c32
-rw-r--r--migration.h7
-rw-r--r--monitor.c201
-rw-r--r--monitor.h3
-rw-r--r--net.c10
-rw-r--r--net.h1
-rw-r--r--net/socket.c88
-rw-r--r--qapi-schema-guest.json6
-rw-r--r--qapi-schema-test.json6
-rw-r--r--qapi-schema.json267
-rw-r--r--qapi/qmp-core.h4
-rw-r--r--qapi/qmp-dispatch.c4
-rw-r--r--qapi/qmp-registry.c56
-rw-r--r--qemu-ga.c37
-rw-r--r--qemu-thread-posix.c33
-rw-r--r--qemu-thread-win32.c107
-rw-r--r--qemu-thread-win32.h5
-rw-r--r--qemu-thread.h8
-rw-r--r--qerror.c8
-rw-r--r--qerror.h6
-rw-r--r--qga/guest-agent-commands.c24
-rw-r--r--qmp-commands.hx77
-rw-r--r--qmp.c37
-rw-r--r--savevm.c65
-rw-r--r--target-cris/cpu.h2
-rw-r--r--target-cris/helper.c1
-rw-r--r--target-cris/translate_v10.c72
-rw-r--r--target-i386/translate.c11
-rw-r--r--test-qmp-input-visitor.c270
-rw-r--r--test-qmp-output-visitor.c423
-rw-r--r--test-visitor.c338
-rw-r--r--ui/vnc-jobs-async.c2
81 files changed, 3413 insertions, 3580 deletions
diff --git a/.mailmap b/.mailmap
new file mode 100644
index 0000000000..9797802aaa
--- /dev/null
+++ b/.mailmap
@@ -0,0 +1,16 @@
+# This mailmap just translates the weird addresses from the original import into git
+# into proper addresses so that they are counted properly in git shortlog output.
+#
+Andrzej Zaborowski <balrogg@gmail.com> balrog <balrog@c046a42c-6fe2-441c-8c8c-71466251a162>
+Anthony Liguori <aliguori@us.ibm.com> aliguori <aliguori@c046a42c-6fe2-441c-8c8c-71466251a162>
+Aurelien Jarno <aurelien@aurel32.net> aurel32 <aurel32@c046a42c-6fe2-441c-8c8c-71466251a162>
+Blue Swirl <blauwirbel@gmail.com> blueswir1 <blueswir1@c046a42c-6fe2-441c-8c8c-71466251a162>
+Edgar E. Iglesias <edgar.iglesias@gmail.com> edgar_igl <edgar_igl@c046a42c-6fe2-441c-8c8c-71466251a162>
+Fabrice Bellard <fabrice@bellard.org> bellard <bellard@c046a42c-6fe2-441c-8c8c-71466251a162>
+Jocelyn Mayer <l_indien@magic.fr> j_mayer <j_mayer@c046a42c-6fe2-441c-8c8c-71466251a162>
+Paul Brook <paul@codesourcery.com> pbrook <pbrook@c046a42c-6fe2-441c-8c8c-71466251a162>
+Thiemo Seufer <ths@networkno.de> ths <ths@c046a42c-6fe2-441c-8c8c-71466251a162>
+malc <av1474@comtv.ru> malc <malc@c046a42c-6fe2-441c-8c8c-71466251a162>
+# There is also a:
+# (no author) <(no author)@c046a42c-6fe2-441c-8c8c-71466251a162>
+# for the cvs2svn initialization commit e63c3dc74bf.
diff --git a/Makefile b/Makefile
index 301c75e7e5..2c030552a1 100644
--- a/Makefile
+++ b/Makefile
@@ -169,7 +169,7 @@ test-coroutine: test-coroutine.o qemu-timer-common.o async.o $(coroutine-obj-y)
$(qapi-obj-y): $(GENERATED_HEADERS)
qapi-dir := $(BUILD_DIR)/qapi-generated
-test-visitor.o test-qmp-commands.o qemu-ga$(EXESUF): QEMU_CFLAGS += -I $(qapi-dir)
+test-qmp-input-visitor.o test-qmp-output-visitor.o test-qmp-commands.o qemu-ga$(EXESUF): QEMU_CFLAGS += -I $(qapi-dir)
qemu-ga$(EXESUF): LIBS = $(LIBS_QGA)
$(qapi-dir)/test-qapi-types.c $(qapi-dir)/test-qapi-types.h :\
@@ -202,8 +202,11 @@ qmp-commands.h qmp-marshal.c :\
$(SRC_PATH)/qapi-schema.json $(SRC_PATH)/scripts/qapi-commands.py
$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-commands.py -m -o "." < $<, " GEN $@")
-test-visitor.o: $(addprefix $(qapi-dir)/, test-qapi-types.c test-qapi-types.h test-qapi-visit.c test-qapi-visit.h) $(qapi-obj-y)
-test-visitor: test-visitor.o $(qobject-obj-y) $(qapi-obj-y) $(tools-obj-y) $(qapi-dir)/test-qapi-visit.o $(qapi-dir)/test-qapi-types.o
+test-qmp-output-visitor.o: $(addprefix $(qapi-dir)/, test-qapi-types.c test-qapi-types.h test-qapi-visit.c test-qapi-visit.h) $(qapi-obj-y)
+test-qmp-output-visitor: test-qmp-output-visitor.o $(qobject-obj-y) $(qapi-obj-y) $(tools-obj-y) $(qapi-dir)/test-qapi-visit.o $(qapi-dir)/test-qapi-types.o
+
+test-qmp-input-visitor.o: $(addprefix $(qapi-dir)/, test-qapi-types.c test-qapi-types.h test-qapi-visit.c test-qapi-visit.h) $(qapi-obj-y)
+test-qmp-input-visitor: test-qmp-input-visitor.o $(qobject-obj-y) $(qapi-obj-y) $(tools-obj-y) $(qapi-dir)/test-qapi-visit.o $(qapi-dir)/test-qapi-types.o
test-qmp-commands.o: $(addprefix $(qapi-dir)/, test-qapi-types.c test-qapi-types.h test-qapi-visit.c test-qapi-visit.h test-qmp-marshal.c test-qmp-commands.h) $(qapi-obj-y)
test-qmp-commands: test-qmp-commands.o $(qobject-obj-y) $(qapi-obj-y) $(tools-obj-y) $(qapi-dir)/test-qapi-visit.o $(qapi-dir)/test-qapi-types.o $(qapi-dir)/test-qmp-marshal.o module.o
diff --git a/Makefile.target b/Makefile.target
index 7369a89e55..8be9b9a596 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -342,6 +342,7 @@ obj-arm-y = integratorcp.o versatilepb.o arm_pic.o arm_timer.o
obj-arm-y += arm_boot.o pl011.o pl031.o pl050.o pl080.o pl110.o pl181.o pl190.o
obj-arm-y += versatile_pci.o
obj-arm-y += realview_gic.o realview.o arm_sysctl.o arm11mpcore.o a9mpcore.o
+obj-arm-y += arm_mptimer.o
obj-arm-y += armv7m.o armv7m_nvic.o stellaris.o pl022.o stellaris_enet.o
obj-arm-y += pl061.o
obj-arm-y += arm-semi.o
@@ -359,9 +360,6 @@ obj-arm-y += mst_fpga.o mainstone.o
obj-arm-y += z2.o
obj-arm-y += musicpal.o bitbang_i2c.o marvell_88w8618_audio.o
obj-arm-y += framebuffer.o
-obj-arm-y += syborg.o syborg_fb.o syborg_interrupt.o syborg_keyboard.o
-obj-arm-y += syborg_serial.o syborg_timer.o syborg_pointer.o syborg_rtc.o
-obj-arm-y += syborg_virtio.o
obj-arm-y += vexpress.o
obj-arm-y += strongarm.o
obj-arm-y += collie.o
diff --git a/QMP/qmp b/QMP/qmp
new file mode 100755
index 0000000000..1db3c7ffeb
--- /dev/null
+++ b/QMP/qmp
@@ -0,0 +1,126 @@
+#!/usr/bin/python
+#
+# QMP command line tool
+#
+# Copyright IBM, Corp. 2011
+#
+# Authors:
+# Anthony Liguori <aliguori@us.ibm.com>
+#
+# This work is licensed under the terms of the GNU GPLv2 or later.
+# See the COPYING file in the top-level directory.
+
+import sys, os
+from qmp import QEMUMonitorProtocol
+
+def print_response(rsp, prefix=[]):
+ if type(rsp) == list:
+ i = 0
+ for item in rsp:
+ if prefix == []:
+ prefix = ['item']
+ print_response(item, prefix[:-1] + ['%s[%d]' % (prefix[-1], i)])
+ i += 1
+ elif type(rsp) == dict:
+ for key in rsp.keys():
+ print_response(rsp[key], prefix + [key])
+ else:
+ if len(prefix):
+ print '%s: %s' % ('.'.join(prefix), rsp)
+ else:
+ print '%s' % (rsp)
+
+def main(args):
+ path = None
+
+ # Use QMP_PATH if it's set
+ if os.environ.has_key('QMP_PATH'):
+ path = os.environ['QMP_PATH']
+
+ while len(args):
+ arg = args[0]
+
+ if arg.startswith('--'):
+ arg = arg[2:]
+ if arg.find('=') == -1:
+ value = True
+ else:
+ arg, value = arg.split('=', 1)
+
+ if arg in ['path']:
+ if type(value) == str:
+ path = value
+ elif arg in ['help']:
+ os.execlp('man', 'man', 'qmp')
+ else:
+ print 'Unknown argument "%s"' % arg
+
+ args = args[1:]
+ else:
+ break
+
+ if not path:
+ print "QMP path isn't set, use --path=qmp-monitor-address or set QMP_PATH"
+ return 1
+
+ if len(args):
+ command, args = args[0], args[1:]
+ else:
+ print 'No command found'
+ print 'Usage: "qmp [--path=qmp-monitor-address] qmp-cmd arguments"'
+ return 1
+
+ if command in ['help']:
+ os.execlp('man', 'man', 'qmp')
+
+ srv = QEMUMonitorProtocol(path)
+ srv.connect()
+
+ def do_command(srv, cmd, **kwds):
+ rsp = srv.cmd(cmd, kwds)
+ if rsp.has_key('error'):
+ raise Exception(rsp['error']['desc'])
+ return rsp['return']
+
+ commands = map(lambda x: x['name'], do_command(srv, 'query-commands'))
+
+ srv.close()
+
+ if command not in commands:
+ fullcmd = 'qmp-%s' % command
+ try:
+ os.environ['QMP_PATH'] = path
+ os.execvp(fullcmd, [fullcmd] + args)
+ except OSError, (errno, msg):
+ if errno == 2:
+ print 'Command "%s" not found.' % (fullcmd)
+ return 1
+ raise
+ return 0
+
+ srv = QEMUMonitorProtocol(path)
+ srv.connect()
+
+ arguments = {}
+ for arg in args:
+ if not arg.startswith('--'):
+ print 'Unknown argument "%s"' % arg
+ return 1
+
+ arg = arg[2:]
+ if arg.find('=') == -1:
+ value = True
+ else:
+ arg, value = arg.split('=', 1)
+
+ if arg in ['help']:
+ os.execlp('man', 'man', 'qmp-%s' % command)
+ return 1
+
+ arguments[arg] = value
+
+ rsp = do_command(srv, command, **arguments)
+ print_response(rsp)
+
+if __name__ == '__main__':
+ sys.exit(main(sys.argv[1:]))
diff --git a/README b/README
index dfd56f24bb..c77d12642d 100644
--- a/README
+++ b/README
@@ -1,3 +1,3 @@
-Read the documentation in qemu-doc.html.
+Read the documentation in qemu-doc.html or on http://wiki.qemu.org
-Fabrice Bellard.
+- QEMU team
diff --git a/balloon.c b/balloon.c
index e1cd5fac4c..0166744aa8 100644
--- a/balloon.c
+++ b/balloon.c
@@ -100,31 +100,19 @@ BalloonInfo *qmp_query_balloon(Error **errp)
return info;
}
-/**
- * do_balloon(): Request VM to change its memory allocation
- */
-int do_balloon(Monitor *mon, const QDict *params,
- MonitorCompletion cb, void *opaque)
+void qmp_balloon(int64_t value, Error **errp)
{
- int64_t target;
- int ret;
-
if (kvm_enabled() && !kvm_has_sync_mmu()) {
- qerror_report(QERR_KVM_MISSING_CAP, "synchronous MMU", "balloon");
- return -1;
+ error_set(errp, QERR_KVM_MISSING_CAP, "synchronous MMU", "balloon");
+ return;
}
- target = qdict_get_int(params, "value");
- if (target <= 0) {
+ if (value <= 0) {
qerror_report(QERR_INVALID_PARAMETER_VALUE, "target", "a size");
- return -1;
+ return;
}
- ret = qemu_balloon(target);
- if (ret == 0) {
- qerror_report(QERR_DEVICE_NOT_ACTIVE, "balloon");
- return -1;
+
+ if (qemu_balloon(value) == 0) {
+ error_set(errp, QERR_DEVICE_NOT_ACTIVE, "balloon");
}
-
- cb(opaque, NULL);
- return 0;
}
diff --git a/balloon.h b/balloon.h
index b36abeadf0..b60fd5d9f2 100644
--- a/balloon.h
+++ b/balloon.h
@@ -24,7 +24,4 @@ int qemu_add_balloon_handler(QEMUBalloonEvent *event_func,
QEMUBalloonStatus *stat_func, void *opaque);
void qemu_remove_balloon_handler(void *opaque);
-int do_balloon(Monitor *mon, const QDict *params,
- MonitorCompletion cb, void *opaque);
-
#endif
diff --git a/blockdev.c b/blockdev.c
index dbf0251a77..c832782d03 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -15,6 +15,7 @@
#include "qemu-config.h"
#include "sysemu.h"
#include "block_int.h"
+#include "qmp-commands.h"
static QTAILQ_HEAD(drivelist, DriveInfo) drives = QTAILQ_HEAD_INITIALIZER(drives);
@@ -600,28 +601,20 @@ void do_commit(Monitor *mon, const QDict *qdict)
}
}
-int do_snapshot_blkdev(Monitor *mon, const QDict *qdict, QObject **ret_data)
+void qmp_blockdev_snapshot_sync(const char *device, const char *snapshot_file,
+ bool has_format, const char *format,
+ Error **errp)
{
- const char *device = qdict_get_str(qdict, "device");
- const char *filename = qdict_get_try_str(qdict, "snapshot-file");
- const char *format = qdict_get_try_str(qdict, "format");
BlockDriverState *bs;
BlockDriver *drv, *old_drv, *proto_drv;
int ret = 0;
int flags;
char old_filename[1024];
- if (!filename) {
- qerror_report(QERR_MISSING_PARAMETER, "snapshot-file");
- ret = -1;
- goto out;
- }
-
bs = bdrv_find(device);
if (!bs) {
- qerror_report(QERR_DEVICE_NOT_FOUND, device);
- ret = -1;
- goto out;
+ error_set(errp, QERR_DEVICE_NOT_FOUND, device);
+ return;
}
pstrcpy(old_filename, sizeof(old_filename), bs->filename);
@@ -629,35 +622,34 @@ int do_snapshot_blkdev(Monitor *mon, const QDict *qdict, QObject **ret_data)
old_drv = bs->drv;
flags = bs->open_flags;
- if (!format) {
+ if (!has_format) {
format = "qcow2";
}
drv = bdrv_find_format(format);
if (!drv) {
- qerror_report(QERR_INVALID_BLOCK_FORMAT, format);
- ret = -1;
- goto out;
+ error_set(errp, QERR_INVALID_BLOCK_FORMAT, format);
+ return;
}
- proto_drv = bdrv_find_protocol(filename);
+ proto_drv = bdrv_find_protocol(snapshot_file);
if (!proto_drv) {
- qerror_report(QERR_INVALID_BLOCK_FORMAT, format);
- ret = -1;
- goto out;
+ error_set(errp, QERR_INVALID_BLOCK_FORMAT, format);
+ return;
}
- ret = bdrv_img_create(filename, format, bs->filename,
+ ret = bdrv_img_create(snapshot_file, format, bs->filename,
bs->drv->format_name, NULL, -1, flags);
if (ret) {
- goto out;
+ error_set(errp, QERR_UNDEFINED_ERROR);
+ return;
}
bdrv_drain_all();
bdrv_flush(bs);
bdrv_close(bs);
- ret = bdrv_open(bs, filename, flags, drv);
+ ret = bdrv_open(bs, snapshot_file, flags, drv);
/*
* If reopening the image file we just created fails, fall back
* and try to re-open the original image. If that fails too, we
@@ -666,17 +658,11 @@ int do_snapshot_blkdev(Monitor *mon, const QDict *qdict, QObject **ret_data)
if (ret != 0) {
ret = bdrv_open(bs, old_filename, flags, old_drv);
if (ret != 0) {
- qerror_report(QERR_OPEN_FILE_FAILED, old_filename);
+ error_set(errp, QERR_OPEN_FILE_FAILED, old_filename);
} else {
- qerror_report(QERR_OPEN_FILE_FAILED, filename);
+ error_set(errp, QERR_OPEN_FILE_FAILED, snapshot_file);
}
}
-out:
- if (ret) {
- ret = -1;
- }
-
- return ret;
}
static int eject_device(Monitor *mon, BlockDriverState *bs, int force)
@@ -710,28 +696,25 @@ int do_eject(Monitor *mon, const QDict *qdict, QObject **ret_data)
return eject_device(mon, bs, force);
}
-int do_block_set_passwd(Monitor *mon, const QDict *qdict,
- QObject **ret_data)
+void qmp_block_passwd(const char *device, const char *password, Error **errp)
{
BlockDriverState *bs;
int err;
- bs = bdrv_find(qdict_get_str(qdict, "device"));
+ bs = bdrv_find(device);
if (!bs) {
- qerror_report(QERR_DEVICE_NOT_FOUND, qdict_get_str(qdict, "device"));
- return -1;
+ error_set(errp, QERR_DEVICE_NOT_FOUND, device);
+ return;
}
- err = bdrv_set_key(bs, qdict_get_str(qdict, "password"));
+ err = bdrv_set_key(bs, password);
if (err == -EINVAL) {
- qerror_report(QERR_DEVICE_NOT_ENCRYPTED, bdrv_get_device_name(bs));
- return -1;
+ error_set(errp, QERR_DEVICE_NOT_ENCRYPTED, bdrv_get_device_name(bs));
+ return;
} else if (err < 0) {
- qerror_report(QERR_INVALID_PASSWORD);
- return -1;
+ error_set(errp, QERR_INVALID_PASSWORD);
+ return;
}
-
- return 0;
}
int do_change_block(Monitor *mon, const char *device,
@@ -863,27 +846,23 @@ int do_drive_del(Monitor *mon, const QDict *qdict, QObject **ret_data)
* existing QERR_ macro mess is cleaned up. A good example for better
* error reports can be found in the qemu-img resize code.
*/
-int do_block_resize(Monitor *mon, const QDict *qdict, QObject **ret_data)
+void qmp_block_resize(const char *device, int64_t size, Error **errp)
{
- const char *device = qdict_get_str(qdict, "device");
- int64_t size = qdict_get_int(qdict, "size");
BlockDriverState *bs;
bs = bdrv_find(device);
if (!bs) {
- qerror_report(QERR_DEVICE_NOT_FOUND, device);
- return -1;
+ error_set(errp, QERR_DEVICE_NOT_FOUND, device);
+ return;
}
if (size < 0) {
- qerror_report(QERR_UNDEFINED_ERROR);
- return -1;
+ error_set(errp, QERR_UNDEFINED_ERROR);
+ return;
}
if (bdrv_truncate(bs, size)) {
- qerror_report(QERR_UNDEFINED_ERROR);
- return -1;
+ error_set(errp, QERR_UNDEFINED_ERROR);
+ return;
}
-
- return 0;
}
diff --git a/blockdev.h b/blockdev.h
index 1b48a75499..f1b639660d 100644
--- a/blockdev.h
+++ b/blockdev.h
@@ -59,13 +59,9 @@ DriveInfo *add_init_drive(const char *opts);
void do_commit(Monitor *mon, const QDict *qdict);
int do_eject(Monitor *mon, const QDict *qdict, QObject **ret_data);
-int do_block_set_passwd(Monitor *mon, const QDict *qdict, QObject **ret_data);
int do_change_block(Monitor *mon, const char *device,
const char *filename, const char *fmt);
int do_drive_del(Monitor *mon, const QDict *qdict, QObject **ret_data);
int do_block_set_io_throttle(Monitor *mon,
const QDict *qdict, QObject **ret_data);
-int do_snapshot_blkdev(Monitor *mon, const QDict *qdict, QObject **ret_data);
-int do_block_resize(Monitor *mon, const QDict *qdict, QObject **ret_data);
-
#endif
diff --git a/bsd-user/bsdload.c b/bsd-user/bsdload.c
index 6d9bb6fb4e..2abc7136e0 100644
--- a/bsd-user/bsdload.c
+++ b/bsd-user/bsdload.c
@@ -196,7 +196,7 @@ int loader_exec(const char * filename, char ** argv, char ** envp,
/* Something went wrong, return the inode and free the argument pages*/
for (i=0 ; i<MAX_ARG_PAGES ; i++) {
- free(bprm.page[i]);
+ g_free(bprm.page[i]);
}
return(retval);
}
diff --git a/bsd-user/elfload.c b/bsd-user/elfload.c
index 1ef1f972fc..12888840a4 100644
--- a/bsd-user/elfload.c
+++ b/bsd-user/elfload.c
@@ -641,8 +641,7 @@ static abi_ulong copy_elf_strings(int argc,char ** argv, void **page,
offset = p % TARGET_PAGE_SIZE;
pag = (char *)page[p/TARGET_PAGE_SIZE];
if (!pag) {
- pag = (char *)malloc(TARGET_PAGE_SIZE);
- memset(pag, 0, TARGET_PAGE_SIZE);
+ pag = g_try_malloc0(TARGET_PAGE_SIZE);
page[p/TARGET_PAGE_SIZE] = pag;
if (!pag)
return 0;
@@ -696,7 +695,7 @@ static abi_ulong setup_arg_pages(abi_ulong p, struct linux_binprm *bprm,
info->rss++;
/* FIXME - check return value of memcpy_to_target() for failure */
memcpy_to_target(stack_base, bprm->page[i], TARGET_PAGE_SIZE);
- free(bprm->page[i]);
+ g_free(bprm->page[i]);
}
stack_base += TARGET_PAGE_SIZE;
}
diff --git a/configure b/configure
index 4bcb8efe29..6fd580e3a6 100755
--- a/configure
+++ b/configure
@@ -1116,7 +1116,7 @@ fi
if test "$pie" = ""; then
case "$cpu-$targetos" in
- i386-Linux|x86_64-Linux)
+ i386-Linux|x86_64-Linux|i386-OpenBSD|x86_64-OpenBSD)
;;
*)
pie="no"
@@ -1528,9 +1528,6 @@ EOF
if compile_prog "$sdl_cflags" "$sdl_libs" ; then
sdl_libs="$sdl_libs -lX11"
fi
- if test "$mingw32" = "yes" ; then
- sdl_libs="`echo $sdl_libs | sed s/-mwindows//g` -mconsole"
- fi
libs_softmmu="$sdl_libs $libs_softmmu"
fi
@@ -2748,8 +2745,9 @@ if test "$softmmu" = yes ; then
fi
if [ "$check_utests" = "yes" ]; then
checks="check-qint check-qstring check-qdict check-qlist"
- checks="check-qfloat check-qjson test-coroutine $checks"
+ checks="check-qfloat check-qjson $checks"
fi
+ test_progs="$checks test-coroutine test-qmp-output-visitor test-qmp-input-visitor"
fi
fi
@@ -3235,7 +3233,7 @@ if test "$trace_default" = "yes"; then
fi
echo "TOOLS=$tools" >> $config_host_mak
-echo "CHECKS=$checks" >> $config_host_mak
+echo "CHECKS=$test_progs" >> $config_host_mak
echo "ROMS=$roms" >> $config_host_mak
echo "MAKE=$make" >> $config_host_mak
echo "INSTALL=$install" >> $config_host_mak
diff --git a/console.h b/console.h
index 6ac4ed31ec..9466886b59 100644
--- a/console.h
+++ b/console.h
@@ -74,8 +74,6 @@ struct MouseTransformInfo {
int a[7];
};
-void do_info_mice_print(Monitor *mon, const QObject *data);
-void do_info_mice(Monitor *mon, QObject **ret_data);
void do_mouse_set(Monitor *mon, const QDict *qdict);
/* keysym is a unicode code except for special keys (see QEMU_KEY_xxx
diff --git a/cpus.c b/cpus.c
index a53276ac32..a060c6056e 100644
--- a/cpus.c
+++ b/cpus.c
@@ -910,7 +910,8 @@ static void qemu_tcg_init_vcpu(void *_env)
env->halt_cond = g_malloc0(sizeof(QemuCond));
qemu_cond_init(env->halt_cond);
tcg_halt_cond = env->halt_cond;
- qemu_thread_create(env->thread, qemu_tcg_cpu_thread_fn, env);
+ qemu_thread_create(env->thread, qemu_tcg_cpu_thread_fn, env,
+ QEMU_THREAD_DETACHED);
while (env->created == 0) {
qemu_cond_wait(&qemu_cpu_cond, &qemu_global_mutex);
}
@@ -926,7 +927,8 @@ static void qemu_kvm_start_vcpu(CPUState *env)
env->thread = g_malloc0(sizeof(QemuThread));
env->halt_cond = g_malloc0(sizeof(QemuCond));
qemu_cond_init(env->halt_cond);
- qemu_thread_create(env->thread, qemu_kvm_cpu_thread_fn, env);
+ qemu_thread_create(env->thread, qemu_kvm_cpu_thread_fn, env,
+ QEMU_THREAD_DETACHED);
while (env->created == 0) {
qemu_cond_wait(&qemu_cpu_cond, &qemu_global_mutex);
}
@@ -1136,3 +1138,93 @@ CpuInfoList *qmp_query_cpus(Error **errp)
return head;
}
+
+void qmp_memsave(int64_t addr, int64_t size, const char *filename,
+ bool has_cpu, int64_t cpu_index, Error **errp)
+{
+ FILE *f;
+ uint32_t l;
+ CPUState *env;
+ uint8_t buf[1024];
+
+ if (!has_cpu) {
+ cpu_index = 0;
+ }
+
+ for (env = first_cpu; env; env = env->next_cpu) {
+ if (cpu_index == env->cpu_index) {
+ break;
+ }
+ }
+
+ if (env == NULL) {
+ error_set(errp, QERR_INVALID_PARAMETER_VALUE, "cpu-index",
+ "a CPU number");
+ return;
+ }
+
+ f = fopen(filename, "wb");
+ if (!f) {
+ error_set(errp, QERR_OPEN_FILE_FAILED, filename);
+ return;
+ }
+
+ while (size != 0) {
+ l = sizeof(buf);
+ if (l > size)
+ l = size;
+ cpu_memory_rw_debug(env, addr, buf, l, 0);
+ if (fwrite(buf, 1, l, f) != l) {
+ error_set(errp, QERR_IO_ERROR);
+ goto exit;
+ }
+ addr += l;
+ size -= l;
+ }
+
+exit:
+ fclose(f);
+}
+
+void qmp_pmemsave(int64_t addr, int64_t size, const char *filename,
+ Error **errp)
+{
+ FILE *f;
+ uint32_t l;
+ uint8_t buf[1024];
+
+ f = fopen(filename, "wb");
+ if (!f) {
+ error_set(errp, QERR_OPEN_FILE_FAILED, filename);
+ return;
+ }
+
+ while (size != 0) {
+ l = sizeof(buf);
+ if (l > size)
+ l = size;
+ cpu_physical_memory_rw(addr, buf, l, 0);
+ if (fwrite(buf, 1, l, f) != l) {
+ error_set(errp, QERR_IO_ERROR);
+ goto exit;
+ }
+ addr += l;
+ size -= l;
+ }
+
+exit:
+ fclose(f);
+}
+
+void qmp_inject_nmi(Error **errp)
+{
+#if defined(TARGET_I386)
+ CPUState *env;
+
+ for (env = first_cpu; env != NULL; env = env->next_cpu) {
+ cpu_interrupt(env, CPU_INTERRUPT_NMI);
+ }
+#else
+ error_set(errp, QERR_UNSUPPORTED);
+#endif
+}
diff --git a/docs/writing-qmp-commands.txt b/docs/writing-qmp-commands.txt
new file mode 100644
index 0000000000..0472fc3914
--- /dev/null
+++ b/docs/writing-qmp-commands.txt
@@ -0,0 +1,642 @@
+= How to write QMP commands using the QAPI framework =
+
+This document is a step-by-step guide on how to write new QMP commands using
+the QAPI framework. It also shows how to implement new style HMP commands.
+
+This document doesn't discuss QMP protocol level details, nor does it dive
+into the QAPI framework implementation.
+
+For an in-depth introduction to the QAPI framework, please refer to
+docs/qapi-code-gen.txt. For documentation about the QMP protocol, please
+check the files in QMP/.
+
+== Overview ==
+
+Generally speaking, the following steps should be taken in order to write a
+new QMP command.
+
+1. Write the command's and type(s) specification in the QAPI schema file
+ (qapi-schema.json in the root source directory)
+
+2. Write the QMP command itself, which is a regular C function. Preferably,
+ the command should be exported by some QEMU subsystem. But it can also be
+ added to the qmp.c file
+
+3. At this point the command can be tested under the QMP protocol
+
+4. Write the HMP command equivalent. This is not required and should only be
+ done if it does make sense to have the functionality in HMP. The HMP command
+ is implemented in terms of the QMP command
+
+The following sections will demonstrate each of the steps above. We will start
+very simple and get more complex as we progress.
+
+=== Testing ===
+
+For all the examples in the next sections, the test setup is the same and is
+shown here.
+
+First, QEMU should be started as:
+
+# /path/to/your/source/qemu [...] \
+ -chardev socket,id=qmp,port=4444,host=localhost,server \
+ -mon chardev=qmp,mode=control,pretty=on
+
+Then, in a different terminal:
+
+$ telnet localhost 4444
+Trying 127.0.0.1...
+Connected to localhost.
+Escape character is '^]'.
+{
+ "QMP": {
+ "version": {
+ "qemu": {
+ "micro": 50,
+ "minor": 15,
+ "major": 0
+ },
+ "package": ""
+ },
+ "capabilities": [
+ ]
+ }
+}
+
+The above output is the QMP server saying you're connected. The server is
+actually in capabilities negotiation mode. To enter in command mode type:
+
+{ "execute": "qmp_capabilities" }
+
+Then the server should respond:
+
+{
+ "return": {
+ }
+}
+
+Which is QMP's way of saying "the latest command executed OK and didn't return
+any data". Now you're ready to enter the QMP example commands as explained in
+the following sections.
+
+== Writing a command that doesn't return data ==
+
+That's the most simple QMP command that can be written. Usually, this kind of
+command carries some meaningful action in QEMU but here it will just print
+"Hello, world" to the standard output.
+
+Our command will be called "hello-world". It takes no arguments, nor does it
+return any data.
+
+The first step is to add the following line to the bottom of the
+qapi-schema.json file:
+
+{ 'command': 'hello-world' }
+
+The "command" keyword defines a new QMP command. It's an JSON object. All
+schema entries are JSON objects. The line above will instruct the QAPI to
+generate any prototypes and the necessary code to marshal and unmarshal
+protocol data.
+
+The next step is to write the "hello-world" implementation. As explained
+earlier, it's preferable for commands to live in QEMU subsystems. But
+"hello-world" doesn't pertain to any, so we put its implementation in qmp.c:
+
+void qmp_hello_world(Error **errp)
+{
+ printf("Hello, world!\n");
+}
+
+There are a few things to be noticed:
+
+1. QMP command implementation functions must be prefixed with "qmp_"
+2. qmp_hello_world() returns void, this is in accordance with the fact that the
+ command doesn't return any data
+3. It takes an "Error **" argument. This is required. Later we will see how to
+ return errors and take additional arguments. The Error argument should not
+ be touched if the command doesn't return errors
+4. We won't add the function's prototype. That's automatically done by the QAPI
+5. Printing to the terminal is discouraged for QMP commands, we do it here
+ because it's the easiest way to demonstrate a QMP command
+
+Now a little hack is needed. As we're still using the old QMP server we need
+to add the new command to its internal dispatch table. This step won't be
+required in the near future. Open the qmp-commands.hx file and add the
+following in the botton:
+
+ {
+ .name = "hello-world",
+ .args_type = "",
+ .mhandler.cmd_new = qmp_marshal_input_hello_world,
+ },
+
+You're done. Now build qemu, run it as suggested in the "Testing" section,
+and then type the following QMP command:
+
+{ "execute": "hello-world" }
+
+Then check the terminal running qemu and look for the "Hello, world" string. If
+you don't see it then something went wrong.
+
+=== Arguments ===
+
+Let's add an argument called "message" to our "hello-world" command. The new
+argument will contain the string to be printed to stdout. It's an optional
+argument, if it's not present we print our default "Hello, World" string.
+
+The first change we have to do is to modify the command specification in the
+schema file to the following:
+
+{ 'command': 'hello-world', 'data': { '*message': 'str' } }
+
+Notice the new 'data' member in the schema. It's an JSON object whose each
+element is an argument to the command in question. Also notice the asterisk,
+it's used to mark the argument optional (that means that you shouldn't use it
+for mandatory arguments). Finally, 'str' is the argument's type, which
+stands for "string". The QAPI also supports integers, booleans, enumerations
+and user defined types.
+
+Now, let's update our C implementation in qmp.c:
+
+void qmp_hello_world(bool has_message, const char *message, Error **errp)
+{
+ if (has_message) {
+ printf("%s\n", message);
+ } else {
+ printf("Hello, world\n");
+ }
+}
+
+There are two important details to be noticed:
+
+1. All optional arguments are accompanied by a 'has_' boolean, which is set
+ if the optional argument is present or false otherwise
+2. The C implementation signature must follow the schema's argument ordering,
+ which is defined by the "data" member
+
+The last step is to update the qmp-commands.hx file:
+
+ {
+ .name = "hello-world",
+ .args_type = "message:s?",
+ .mhandler.cmd_new = qmp_marshal_input_hello_world,
+ },
+
+Notice that the "args_type" member got our "message" argument. The character
+"s" stands for "string" and "?" means it's optional. This too must be ordered
+according to the C implementation and schema file. You can look for more
+examples in the qmp-commands.hx file if you need to define more arguments.
+
+Again, this step won't be required in the future.
+
+Time to test our new version of the "hello-world" command. Build qemu, run it as
+described in the "Testing" section and then send two commands:
+
+{ "execute": "hello-world" }
+{
+ "return": {
+ }
+}
+
+{ "execute": "hello-world", "arguments": { "message": "We love qemu" } }
+{
+ "return": {
+ }
+}
+
+You should see "Hello, world" and "we love qemu" in the terminal running qemu,
+if you don't see these strings, then something went wrong.
+
+=== Errors ===
+
+QMP commands should use the error interface exported by the error.h header
+file. The basic function used to set an error is the error_set() one.
+
+Let's say we don't accept the string "message" to contain the word "love". If
+it does contain it, we want the "hello-world" command to the return the
+InvalidParameter error.
+
+Only one change is required, and it's in the C implementation:
+
+void qmp_hello_world(bool has_message, const char *message, Error **errp)
+{
+ if (has_message) {
+ if (strstr(message, "love")) {
+ error_set(errp, QERR_INVALID_PARAMETER, "message");
+ return;
+ }
+ printf("%s\n", message);
+ } else {
+ printf("Hello, world\n");
+ }
+}
+
+Let's test it. Build qemu, run it as defined in the "Testing" section, and
+then issue the following command:
+
+{ "execute": "hello-world", "arguments": { "message": "we love qemu" } }
+
+The QMP server's response should be:
+
+{
+ "error": {
+ "class": "InvalidParameter",
+ "desc": "Invalid parameter 'message'",
+ "data": {
+ "name": "message"
+ }
+ }
+}
+
+Which is the InvalidParameter error.
+
+When you have to return an error but you're unsure what error to return or
+which arguments an error takes, you should look at the qerror.h file. Note
+that you might be required to add new errors if needed.
+
+FIXME: describe better the error API and how to add new errors.
+
+=== Command Documentation ===
+
+There's only one step missing to make "hello-world"'s implementation complete,
+and that's its documentation in the schema file.
+
+This is very important. No QMP command will be accepted in QEMU without proper
+documentation.
+
+There are many examples of such documentation in the schema file already, but
+here goes "hello-world"'s new entry for the qapi-schema.json file:
+
+##
+# @hello-world
+#
+# Print a client provided string to the standard output stream.
+#
+# @message: #optional string to be printed
+#
+# Returns: Nothing on success.
+# If @message contains "love", InvalidParameter
+#
+# Notes: if @message is not provided, the "Hello, world" string will
+# be printed instead
+#
+# Since: <next qemu stable release, eg. 1.0>
+##
+{ 'command': 'hello-world', 'data': { '*message': 'str' } }
+
+Please, note that the "Returns" clause is optional if a command doesn't return
+any data nor any errors.
+
+=== Implementing the HMP command ===
+
+Now that the QMP command is in place, we can also make it available in the human
+monitor (HMP).
+
+With the introduction of the QAPI, HMP commands make QMP calls. Most of the
+time HMP commands are simple wrappers. All HMP commands implementation exist in
+the hmp.c file.
+
+Here's the implementation of the "hello-world" HMP command:
+
+void hmp_hello_world(Monitor *mon, const QDict *qdict)
+{
+ const char *message = qdict_get_try_str(qdict, "message");
+ Error *errp = NULL;
+
+ qmp_hello_world(!!message, message, &errp);
+ if (error_is_set(&errp)) {
+ monitor_printf(mon, "%s\n", error_get_pretty(errp));
+ error_free(errp);
+ return;
+ }
+}
+
+Also, you have to add the function's prototype to the hmp.h file.
+
+There are three important points to be noticed:
+
+1. The "mon" and "qdict" arguments are mandatory for all HMP functions. The
+ former is the monitor object. The latter is how the monitor passes
+ arguments entered by the user to the command implementation
+2. hmp_hello_world() performs error checking. In this example we just print
+ the error description to the user, but we could do more, like taking
+ different actions depending on the error qmp_hello_world() returns
+3. The "errp" variable must be initialized to NULL before performing the
+ QMP call
+
+There's one last step to actually make the command available to monitor users,
+we should add it to the hmp-commands.hx file:
+
+ {
+ .name = "hello-world",
+ .args_type = "message:s?",
+ .params = "hello-world [message]",
+ .help = "Print message to the standard output",
+ .mhandler.cmd = hmp_hello_world,
+ },
+
+STEXI
+@item hello_world @var{message}
+@findex hello_world
+Print message to the standard output
+ETEXI
+
+To test this you have to open a user monitor and issue the "hello-world"
+command. It might be instructive to check the command's documentation with
+HMP's "help" command.
+
+Please, check the "-monitor" command-line option to know how to open a user
+monitor.
+
+== Writing a command that returns data ==
+
+A QMP command is capable of returning any data the QAPI supports like integers,
+strings, booleans, enumerations and user defined types.
+
+In this section we will focus on user defined types. Please, check the QAPI
+documentation for information about the other types.
+
+=== User Defined Types ===
+
+For this example we will write the query-alarm-clock command, which returns
+information about QEMU's timer alarm. For more information about it, please
+check the "-clock" command-line option.
+
+We want to return two pieces of information. The first one is the alarm clock's
+name. The second one is when the next alarm will fire. The former information is
+returned as a string, the latter is an integer in nanoseconds (which is not
+very useful in practice, as the timer has probably already fired when the
+information reaches the client).
+
+The best way to return that data is to create a new QAPI type, as shown below:
+
+##
+# @QemuAlarmClock
+#
+# QEMU alarm clock information.
+#
+# @clock-name: The alarm clock method's name.
+#
+# @next-deadline: #optional The time (in nanoseconds) the next alarm will fire.
+#
+# Since: 1.0
+##
+{ 'type': 'QemuAlarmClock',
+ 'data': { 'clock-name': 'str', '*next-deadline': 'int' } }
+
+The "type" keyword defines a new QAPI type. Its "data" member contains the
+type's members. In this example our members are the "clock-name" and the
+"next-deadline" one, which is optional.
+
+Now let's define the query-alarm-clock command:
+
+##
+# @query-alarm-clock
+#
+# Return information about QEMU's alarm clock.
+#
+# Returns a @QemuAlarmClock instance describing the alarm clock method
+# being currently used by QEMU (this is usually set by the '-clock'
+# command-line option).
+#
+# Since: 1.0
+##
+{ 'command': 'query-alarm-clock', 'returns': 'QemuAlarmClock' }
+
+Notice the "returns" keyword. As its name suggests, it's used to define the
+data returned by a command.
+
+It's time to implement the qmp_query_alarm_clock() function, you can put it
+in the qemu-timer.c file:
+
+QemuAlarmClock *qmp_query_alarm_clock(Error **errp)
+{
+ QemuAlarmClock *clock;
+ int64_t deadline;
+
+ clock = g_malloc0(sizeof(*clock));
+
+ deadline = qemu_next_alarm_deadline();
+ if (deadline > 0) {
+ clock->has_next_deadline = true;
+ clock->next_deadline = deadline;
+ }
+ clock->clock_name = g_strdup(alarm_timer->name);
+
+ return clock;
+}
+
+There are a number of things to be noticed:
+
+1. The QemuAlarmClock type is automatically generated by the QAPI framework,
+ its members correspond to the type's specification in the schema file
+2. As specified in the schema file, the function returns a QemuAlarmClock
+ instance and takes no arguments (besides the "errp" one, which is mandatory
+ for all QMP functions)
+3. The "clock" variable (which will point to our QAPI type instance) is
+ allocated by the regular g_malloc0() function. Note that we chose to
+ initialize the memory to zero. This is recomended for all QAPI types, as
+ it helps avoiding bad surprises (specially with booleans)
+4. Remember that "next_deadline" is optional? All optional members have a
+ 'has_TYPE_NAME' member that should be properly set by the implementation,
+ as shown above
+5. Even static strings, such as "alarm_timer->name", should be dynamically
+ allocated by the implementation. This is so because the QAPI also generates
+ a function to free its types and it cannot distinguish between dynamically
+ or statically allocated strings
+6. You have to include the "qmp-commands.h" header file in qemu-timer.c,
+ otherwise qemu won't build
+
+The last step is to add the correspoding entry in the qmp-commands.hx file:
+
+ {
+ .name = "query-alarm-clock",
+ .args_type = "",
+ .mhandler.cmd_new = qmp_marshal_input_query_alarm_clock,
+ },
+
+Time to test the new command. Build qemu, run it as described in the "Testing"
+section and try this:
+
+{ "execute": "query-alarm-clock" }
+{
+ "return": {
+ "next-deadline": 2368219,
+ "clock-name": "dynticks"
+ }
+}
+
+==== The HMP command ====
+
+Here's the HMP counterpart of the query-alarm-clock command:
+
+void hmp_info_alarm_clock(Monitor *mon)
+{
+ QemuAlarmClock *clock;
+ Error *errp = NULL;
+
+ clock = qmp_query_alarm_clock(&errp);
+ if (error_is_set(&errp)) {
+ monitor_printf(mon, "Could not query alarm clock information\n");
+ error_free(errp);
+ return;
+ }
+
+ monitor_printf(mon, "Alarm clock method in use: '%s'\n", clock->clock_name);
+ if (clock->has_next_deadline) {
+ monitor_printf(mon, "Next alarm will fire in %" PRId64 " nanoseconds\n",
+ clock->next_deadline);
+ }
+
+ qapi_free_QemuAlarmClock(clock);
+}
+
+It's important to notice that hmp_info_alarm_clock() calls
+qapi_free_QemuAlarmClock() to free the data returned by qmp_query_alarm_clock().
+For user defined types, the QAPI will generate a qapi_free_QAPI_TYPE_NAME()
+function and that's what you have to use to free the types you define and
+qapi_free_QAPI_TYPE_NAMEList() for list types (explained in the next section).
+If the QMP call returns a string, then you should g_free() to free it.
+
+Also note that hmp_info_alarm_clock() performs error handling. That's not
+strictly required if you're sure the QMP function doesn't return errors, but
+it's good practice to always check for errors.
+
+Another important detail is that HMP's "info" commands don't go into the
+hmp-commands.hx. Instead, they go into the info_cmds[] table, which is defined
+in the monitor.c file. The entry for the "info alarmclock" follows:
+
+ {
+ .name = "alarmclock",
+ .args_type = "",
+ .params = "",
+ .help = "show information about the alarm clock",
+ .mhandler.info = hmp_info_alarm_clock,
+ },
+
+To test this, run qemu and type "info alarmclock" in the user monitor.
+
+=== Returning Lists ===
+
+For this example, we're going to return all available methods for the timer
+alarm, which is pretty much what the command-line option "-clock ?" does,
+except that we're also going to inform which method is in use.
+
+This first step is to define a new type:
+
+##
+# @TimerAlarmMethod
+#
+# Timer alarm method information.
+#
+# @method-name: The method's name.
+#
+# @current: true if this alarm method is currently in use, false otherwise
+#
+# Since: 1.0
+##
+{ 'type': 'TimerAlarmMethod',
+ 'data': { 'method-name': 'str', 'current': 'bool' } }
+
+The command will be called "query-alarm-methods", here is its schema
+specification:
+
+##
+# @query-alarm-methods
+#
+# Returns information about available alarm methods.
+#
+# Returns: a list of @TimerAlarmMethod for each method
+#
+# Since: 1.0
+##
+{ 'command': 'query-alarm-methods', 'returns': ['TimerAlarmMethod'] }
+
+Notice the syntax for returning lists "'returns': ['TimerAlarmMethod']", this
+should be read as "returns a list of TimerAlarmMethod instances".
+
+The C implementation follows:
+
+TimerAlarmMethodList *qmp_query_alarm_methods(Error **errp)
+{
+ TimerAlarmMethodList *method_list = NULL;
+ const struct qemu_alarm_timer *p;
+ bool current = true;
+
+ for (p = alarm_timers; p->name; p++) {
+ TimerAlarmMethodList *info = g_malloc0(sizeof(*info));
+ info->value = g_malloc0(sizeof(*info->value));
+ info->value->method_name = g_strdup(p->name);
+ info->value->current = current;
+
+ current = false;
+
+ info->next = method_list;
+ method_list = info;
+ }
+
+ return method_list;
+}
+
+The most important difference from the previous examples is the
+TimerAlarmMethodList type, which is automatically generated by the QAPI from
+the TimerAlarmMethod type.
+
+Each list node is represented by a TimerAlarmMethodList instance. We have to
+allocate it, and that's done inside the for loop: the "info" pointer points to
+an allocated node. We also have to allocate the node's contents, which is
+stored in its "value" member. In our example, the "value" member is a pointer
+to an TimerAlarmMethod instance.
+
+Notice that the "current" variable is used as "true" only in the first
+interation of the loop. That's because the alarm timer method in use is the
+first element of the alarm_timers array. Also notice that QAPI lists are handled
+by hand and we return the head of the list.
+
+To test this you have to add the corresponding qmp-commands.hx entry:
+
+ {
+ .name = "query-alarm-methods",
+ .args_type = "",
+ .mhandler.cmd_new = qmp_marshal_input_query_alarm_methods,
+ },
+
+Now Build qemu, run it as explained in the "Testing" section and try our new
+command:
+
+{ "execute": "query-alarm-methods" }
+{
+ "return": [
+ {
+ "current": false,
+ "method-name": "unix"
+ },
+ {
+ "current": true,
+ "method-name": "dynticks"
+ }
+ ]
+}
+
+The HMP counterpart is a bit more complex than previous examples because it
+has to traverse the list, it's shown below for reference:
+
+void hmp_info_alarm_methods(Monitor *mon)
+{
+ TimerAlarmMethodList *method_list, *method;
+ Error *errp = NULL;
+
+ method_list = qmp_query_alarm_methods(&errp);
+ if (error_is_set(&errp)) {
+ monitor_printf(mon, "Could not query alarm methods\n");
+ error_free(errp);
+ return;
+ }
+
+ for (method = method_list; method; method = method->next) {
+ monitor_printf(mon, "%c %s\n", method->value->current ? '*' : ' ',
+ method->value->method_name);
+ }
+
+ qapi_free_TimerAlarmMethodList(method_list);
+}
diff --git a/exec.c b/exec.c
index 6b92198e62..d8b2180170 100644
--- a/exec.c
+++ b/exec.c
@@ -1603,8 +1603,10 @@ void cpu_set_log(int log_flags)
static char logfile_buf[4096];
setvbuf(logfile, logfile_buf, _IOLBF, sizeof(logfile_buf));
}
-#elif !defined(_WIN32)
- /* Win32 doesn't support line-buffering and requires size >= 2 */
+#elif defined(_WIN32)
+ /* Win32 doesn't support line-buffering, so use unbuffered output. */
+ setvbuf(logfile, NULL, _IONBF, 0);
+#else
setvbuf(logfile, NULL, _IOLBF, 0);
#endif
log_append = 1;
diff --git a/hmp-commands.hx b/hmp-commands.hx
index 54b2abf458..14838b7fae 100644
--- a/hmp-commands.hx
+++ b/hmp-commands.hx
@@ -57,8 +57,7 @@ ETEXI
.args_type = "device:B,size:o",
.params = "device size",
.help = "resize a block image",
- .user_print = monitor_user_noop,
- .mhandler.cmd_new = do_block_resize,
+ .mhandler.cmd = hmp_block_resize,
},
STEXI
@@ -304,8 +303,7 @@ ETEXI
.args_type = "",
.params = "",
.help = "resume emulation",
- .user_print = monitor_user_noop,
- .mhandler.cmd_new = do_cont,
+ .mhandler.cmd = hmp_cont,
},
STEXI
@@ -689,8 +687,7 @@ ETEXI
.args_type = "val:l,size:i,filename:s",
.params = "addr size file",
.help = "save to disk virtual memory dump starting at 'addr' of size 'size'",
- .user_print = monitor_user_noop,
- .mhandler.cmd_new = do_memory_save,
+ .mhandler.cmd = hmp_memsave,
},
STEXI
@@ -704,8 +701,7 @@ ETEXI
.args_type = "val:l,size:i,filename:s",
.params = "addr size file",
.help = "save to disk physical memory dump starting at 'addr' of size 'size'",
- .user_print = monitor_user_noop,
- .mhandler.cmd_new = do_physical_memory_save,
+ .mhandler.cmd = hmp_pmemsave,
},
STEXI
@@ -739,8 +735,7 @@ ETEXI
.args_type = "",
.params = "",
.help = "inject an NMI on all guest's CPUs",
- .user_print = monitor_user_noop,
- .mhandler.cmd_new = do_inject_nmi,
+ .mhandler.cmd = hmp_inject_nmi,
},
#endif
STEXI
@@ -776,8 +771,7 @@ ETEXI
.args_type = "",
.params = "",
.help = "cancel the current VM migration",
- .user_print = monitor_user_noop,
- .mhandler.cmd_new = do_migrate_cancel,
+ .mhandler.cmd = hmp_migrate_cancel,
},
STEXI
@@ -792,8 +786,7 @@ ETEXI
.params = "value",
.help = "set maximum speed (in bytes) for migrations. "
"Defaults to MB if no size suffix is specified, ie. B/K/M/G/T",
- .user_print = monitor_user_noop,
- .mhandler.cmd_new = do_migrate_set_speed,
+ .mhandler.cmd = hmp_migrate_set_speed,
},
STEXI
@@ -807,8 +800,7 @@ ETEXI
.args_type = "value:T",
.params = "value",
.help = "set maximum tolerated downtime (in seconds) for migrations",
- .user_print = monitor_user_noop,
- .mhandler.cmd_new = do_migrate_set_downtime,
+ .mhandler.cmd = hmp_migrate_set_downtime,
},
STEXI
@@ -845,7 +837,7 @@ ETEXI
"If format is specified, the snapshot file will\n\t\t\t"
"be created in that format. Otherwise the\n\t\t\t"
"snapshot will be internal! (currently unsupported)",
- .mhandler.cmd_new = do_snapshot_blkdev,
+ .mhandler.cmd = hmp_snapshot_blkdev,
},
STEXI
@@ -1026,9 +1018,7 @@ ETEXI
.args_type = "value:M",
.params = "target",
.help = "request VM to change its memory allocation (in MB)",
- .user_print = monitor_user_noop,
- .mhandler.cmd_async = do_balloon,
- .flags = MONITOR_CMD_ASYNC,
+ .mhandler.cmd = hmp_balloon,
},
STEXI
@@ -1042,8 +1032,7 @@ ETEXI
.args_type = "name:s,up:b",
.params = "name on|off",
.help = "change the link status of a network adapter",
- .user_print = monitor_user_noop,
- .mhandler.cmd_new = do_set_link,
+ .mhandler.cmd = hmp_set_link,
},
STEXI
@@ -1203,8 +1192,7 @@ ETEXI
.args_type = "device:B,password:s",
.params = "block_passwd device password",
.help = "set the password of encrypted block devices",
- .user_print = monitor_user_noop,
- .mhandler.cmd_new = do_block_set_passwd,
+ .mhandler.cmd = hmp_block_passwd,
},
STEXI
diff --git a/hmp.c b/hmp.c
index dfab7ad9bb..e7659d5ffc 100644
--- a/hmp.c
+++ b/hmp.c
@@ -14,6 +14,14 @@
#include "hmp.h"
#include "qmp-commands.h"
+static void hmp_handle_error(Monitor *mon, Error **errp)
+{
+ if (error_is_set(errp)) {
+ monitor_printf(mon, "%s\n", error_get_pretty(*errp));
+ error_free(*errp);
+ }
+}
+
void hmp_info_name(Monitor *mon)
{
NameInfo *info;
@@ -531,3 +539,143 @@ void hmp_cpu(Monitor *mon, const QDict *qdict)
monitor_printf(mon, "invalid CPU index\n");
}
}
+
+void hmp_memsave(Monitor *mon, const QDict *qdict)
+{
+ uint32_t size = qdict_get_int(qdict, "size");
+ const char *filename = qdict_get_str(qdict, "filename");
+ uint64_t addr = qdict_get_int(qdict, "val");
+ Error *errp = NULL;
+
+ qmp_memsave(addr, size, filename, true, monitor_get_cpu_index(), &errp);
+ hmp_handle_error(mon, &errp);
+}
+
+void hmp_pmemsave(Monitor *mon, const QDict *qdict)
+{
+ uint32_t size = qdict_get_int(qdict, "size");
+ const char *filename = qdict_get_str(qdict, "filename");
+ uint64_t addr = qdict_get_int(qdict, "val");
+ Error *errp = NULL;
+
+ qmp_pmemsave(addr, size, filename, &errp);
+ hmp_handle_error(mon, &errp);
+}
+
+static void hmp_cont_cb(void *opaque, int err)
+{
+ Monitor *mon = opaque;
+
+ if (!err) {
+ hmp_cont(mon, NULL);
+ }
+}
+
+void hmp_cont(Monitor *mon, const QDict *qdict)
+{
+ Error *errp = NULL;
+
+ qmp_cont(&errp);
+ if (error_is_set(&errp)) {
+ if (error_is_type(errp, QERR_DEVICE_ENCRYPTED)) {
+ const char *device;
+
+ /* The device is encrypted. Ask the user for the password
+ and retry */
+
+ device = error_get_field(errp, "device");
+ assert(device != NULL);
+
+ monitor_read_block_device_key(mon, device, hmp_cont_cb, mon);
+ error_free(errp);
+ return;
+ }
+ hmp_handle_error(mon, &errp);
+ }
+}
+
+void hmp_inject_nmi(Monitor *mon, const QDict *qdict)
+{
+ Error *errp = NULL;
+
+ qmp_inject_nmi(&errp);
+ hmp_handle_error(mon, &errp);
+}
+
+void hmp_set_link(Monitor *mon, const QDict *qdict)
+{
+ const char *name = qdict_get_str(qdict, "name");
+ int up = qdict_get_bool(qdict, "up");
+ Error *errp = NULL;
+
+ qmp_set_link(name, up, &errp);
+ hmp_handle_error(mon, &errp);
+}
+
+void hmp_block_passwd(Monitor *mon, const QDict *qdict)
+{
+ const char *device = qdict_get_str(qdict, "device");
+ const char *password = qdict_get_str(qdict, "password");
+ Error *errp = NULL;
+
+ qmp_block_passwd(device, password, &errp);
+ hmp_handle_error(mon, &errp);
+}
+
+void hmp_balloon(Monitor *mon, const QDict *qdict)
+{
+ int64_t value = qdict_get_int(qdict, "value");
+ Error *errp = NULL;
+
+ qmp_balloon(value, &errp);
+ if (error_is_set(&errp)) {
+ monitor_printf(mon, "balloon: %s\n", error_get_pretty(errp));
+ error_free(errp);
+ }
+}
+
+void hmp_block_resize(Monitor *mon, const QDict *qdict)
+{
+ const char *device = qdict_get_str(qdict, "device");
+ int64_t size = qdict_get_int(qdict, "size");
+ Error *errp = NULL;
+
+ qmp_block_resize(device, size, &errp);
+ hmp_handle_error(mon, &errp);
+}
+
+void hmp_snapshot_blkdev(Monitor *mon, const QDict *qdict)
+{
+ const char *device = qdict_get_str(qdict, "device");
+ const char *filename = qdict_get_try_str(qdict, "snapshot-file");
+ const char *format = qdict_get_try_str(qdict, "format");
+ Error *errp = NULL;
+
+ if (!filename) {
+ /* In the future, if 'snapshot-file' is not specified, the snapshot
+ will be taken internally. Today it's actually required. */
+ error_set(&errp, QERR_MISSING_PARAMETER, "snapshot-file");
+ hmp_handle_error(mon, &errp);
+ return;
+ }
+
+ qmp_blockdev_snapshot_sync(device, filename, !!format, format, &errp);
+ hmp_handle_error(mon, &errp);
+}
+
+void hmp_migrate_cancel(Monitor *mon, const QDict *qdict)
+{
+ qmp_migrate_cancel(NULL);
+}
+
+void hmp_migrate_set_downtime(Monitor *mon, const QDict *qdict)
+{
+ double value = qdict_get_double(qdict, "value");
+ qmp_migrate_set_downtime(value, NULL);
+}
+
+void hmp_migrate_set_speed(Monitor *mon, const QDict *qdict)
+{
+ int64_t value = qdict_get_int(qdict, "value");
+ qmp_migrate_set_speed(value, NULL);
+}
diff --git a/hmp.h b/hmp.h
index 4422578448..093242d626 100644
--- a/hmp.h
+++ b/hmp.h
@@ -37,5 +37,17 @@ void hmp_stop(Monitor *mon, const QDict *qdict);
void hmp_system_reset(Monitor *mon, const QDict *qdict);
void hmp_system_powerdown(Monitor *mon, const QDict *qdict);
void hmp_cpu(Monitor *mon, const QDict *qdict);
+void hmp_memsave(Monitor *mon, const QDict *qdict);
+void hmp_pmemsave(Monitor *mon, const QDict *qdict);
+void hmp_cont(Monitor *mon, const QDict *qdict);
+void hmp_inject_nmi(Monitor *mon, const QDict *qdict);
+void hmp_set_link(Monitor *mon, const QDict *qdict);
+void hmp_block_passwd(Monitor *mon, const QDict *qdict);
+void hmp_balloon(Monitor *mon, const QDict *qdict);
+void hmp_block_resize(Monitor *mon, const QDict *qdict);
+void hmp_snapshot_blkdev(Monitor *mon, const QDict *qdict);
+void hmp_migrate_cancel(Monitor *mon, const QDict *qdict);
+void hmp_migrate_set_downtime(Monitor *mon, const QDict *qdict);
+void hmp_migrate_set_speed(Monitor *mon, const QDict *qdict);
#endif
diff --git a/hw/a9mpcore.c b/hw/a9mpcore.c
index 6f108f4ce2..cd2985f421 100644
--- a/hw/a9mpcore.c
+++ b/hw/a9mpcore.c
@@ -2,28 +2,197 @@
* Cortex-A9MPCore internal peripheral emulation.
*
* Copyright (c) 2009 CodeSourcery.
- * Written by Paul Brook
+ * Copyright (c) 2011 Linaro Limited.
+ * Written by Paul Brook, Peter Maydell.
*
* This code is licensed under the GPL.
*/
-/* 64 external IRQ lines. */
+#include "sysbus.h"
+
+/* Configuration for arm_gic.c:
+ * number of external IRQ lines, max number of CPUs, how to ID current CPU
+ */
#define GIC_NIRQ 96
-#include "mpcore.c"
+#define NCPU 4
+
+static inline int
+gic_get_current_cpu(void)
+{
+ return cpu_single_env->cpu_index;
+}
+
+#include "arm_gic.c"
+
+/* A9MP private memory region. */
+
+typedef struct a9mp_priv_state {
+ gic_state gic;
+ uint32_t scu_control;
+ uint32_t old_timer_status[8];
+ uint32_t num_cpu;
+ qemu_irq *timer_irq;
+ MemoryRegion scu_iomem;
+ MemoryRegion ptimer_iomem;
+ MemoryRegion container;
+ DeviceState *mptimer;
+} a9mp_priv_state;
+
+static uint64_t a9_scu_read(void *opaque, target_phys_addr_t offset,
+ unsigned size)
+{
+ a9mp_priv_state *s = (a9mp_priv_state *)opaque;
+ switch (offset) {
+ case 0x00: /* Control */
+ return s->scu_control;
+ case 0x04: /* Configuration */
+ return (((1 << s->num_cpu) - 1) << 4) | (s->num_cpu - 1);
+ case 0x08: /* CPU Power Status */
+ return 0;
+ case 0x0c: /* Invalidate All Registers In Secure State */
+ return 0;
+ case 0x40: /* Filtering Start Address Register */
+ case 0x44: /* Filtering End Address Register */
+ /* RAZ/WI, like an implementation with only one AXI master */
+ return 0;
+ case 0x50: /* SCU Access Control Register */
+ case 0x54: /* SCU Non-secure Access Control Register */
+ /* unimplemented, fall through */
+ default:
+ return 0;
+ }
+}
+
+static void a9_scu_write(void *opaque, target_phys_addr_t offset,
+ uint64_t value, unsigned size)
+{
+ a9mp_priv_state *s = (a9mp_priv_state *)opaque;
+ switch (offset) {
+ case 0x00: /* Control */
+ s->scu_control = value & 1;
+ break;
+ case 0x4: /* Configuration: RO */
+ break;
+ case 0x0c: /* Invalidate All Registers In Secure State */
+ /* no-op as we do not implement caches */
+ break;
+ case 0x40: /* Filtering Start Address Register */
+ case 0x44: /* Filtering End Address Register */
+ /* RAZ/WI, like an implementation with only one AXI master */
+ break;
+ case 0x8: /* CPU Power Status */
+ case 0x50: /* SCU Access Control Register */
+ case 0x54: /* SCU Non-secure Access Control Register */
+ /* unimplemented, fall through */
+ default:
+ break;
+ }
+}
+
+static const MemoryRegionOps a9_scu_ops = {
+ .read = a9_scu_read,
+ .write = a9_scu_write,
+ .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static void a9mpcore_timer_irq_handler(void *opaque, int irq, int level)
+{
+ a9mp_priv_state *s = (a9mp_priv_state *)opaque;
+ if (level && !s->old_timer_status[irq]) {
+ gic_set_pending_private(&s->gic, irq >> 1, 29 + (irq & 1));
+ }
+ s->old_timer_status[irq] = level;
+}
+
+static void a9mp_priv_reset(DeviceState *dev)
+{
+ a9mp_priv_state *s = FROM_SYSBUSGIC(a9mp_priv_state, sysbus_from_qdev(dev));
+ int i;
+ s->scu_control = 0;
+ for (i = 0; i < ARRAY_SIZE(s->old_timer_status); i++) {
+ s->old_timer_status[i] = 0;
+ }
+}
+
+static int a9mp_priv_init(SysBusDevice *dev)
+{
+ a9mp_priv_state *s = FROM_SYSBUSGIC(a9mp_priv_state, dev);
+ SysBusDevice *busdev;
+ int i;
+
+ if (s->num_cpu > NCPU) {
+ hw_error("a9mp_priv_init: num-cpu may not be more than %d\n", NCPU);
+ }
+
+ gic_init(&s->gic, s->num_cpu);
+
+ s->mptimer = qdev_create(NULL, "arm_mptimer");
+ qdev_prop_set_uint32(s->mptimer, "num-cpu", s->num_cpu);
+ qdev_init_nofail(s->mptimer);
+ busdev = sysbus_from_qdev(s->mptimer);
+
+ /* Memory map (addresses are offsets from PERIPHBASE):
+ * 0x0000-0x00ff -- Snoop Control Unit
+ * 0x0100-0x01ff -- GIC CPU interface
+ * 0x0200-0x02ff -- Global Timer
+ * 0x0300-0x05ff -- nothing
+ * 0x0600-0x06ff -- private timers and watchdogs
+ * 0x0700-0x0fff -- nothing
+ * 0x1000-0x1fff -- GIC Distributor
+ *
+ * We should implement the global timer but don't currently do so.
+ */
+ memory_region_init(&s->container, "a9mp-priv-container", 0x2000);
+ memory_region_init_io(&s->scu_iomem, &a9_scu_ops, s, "a9mp-scu", 0x100);
+ memory_region_add_subregion(&s->container, 0, &s->scu_iomem);
+ /* GIC CPU interface */
+ memory_region_add_subregion(&s->container, 0x100, &s->gic.cpuiomem[0]);
+ /* Note that the A9 exposes only the "timer/watchdog for this core"
+ * memory region, not the "timer/watchdog for core X" ones 11MPcore has.
+ */
+ memory_region_add_subregion(&s->container, 0x600,
+ sysbus_mmio_get_region(busdev, 0));
+ memory_region_add_subregion(&s->container, 0x620,
+ sysbus_mmio_get_region(busdev, 1));
+ memory_region_add_subregion(&s->container, 0x1000, &s->gic.iomem);
+
+ sysbus_init_mmio(dev, &s->container);
+
+ /* Wire up the interrupt from each watchdog and timer. */
+ s->timer_irq = qemu_allocate_irqs(a9mpcore_timer_irq_handler,
+ s, (s->num_cpu + 1) * 2);
+ for (i = 0; i < s->num_cpu * 2; i++) {
+ sysbus_connect_irq(busdev, i, s->timer_irq[i]);
+ }
+ return 0;
+}
+
+static const VMStateDescription vmstate_a9mp_priv = {
+ .name = "a9mpcore_priv",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .fields = (VMStateField[]) {
+ VMSTATE_UINT32(scu_control, a9mp_priv_state),
+ VMSTATE_UINT32_ARRAY(old_timer_status, a9mp_priv_state, 8),
+ VMSTATE_END_OF_LIST()
+ }
+};
-static SysBusDeviceInfo mpcore_priv_info = {
- .init = mpcore_priv_init,
+static SysBusDeviceInfo a9mp_priv_info = {
+ .init = a9mp_priv_init,
.qdev.name = "a9mpcore_priv",
- .qdev.size = sizeof(mpcore_priv_state),
+ .qdev.size = sizeof(a9mp_priv_state),
+ .qdev.vmsd = &vmstate_a9mp_priv,
+ .qdev.reset = a9mp_priv_reset,
.qdev.props = (Property[]) {
- DEFINE_PROP_UINT32("num-cpu", mpcore_priv_state, num_cpu, 1),
+ DEFINE_PROP_UINT32("num-cpu", a9mp_priv_state, num_cpu, 1),
DEFINE_PROP_END_OF_LIST(),
}
};
-static void a9mpcore_register_devices(void)
+static void a9mp_register_devices(void)
{
- sysbus_register_withprop(&mpcore_priv_info);
+ sysbus_register_withprop(&a9mp_priv_info);
}
-device_init(a9mpcore_register_devices)
+device_init(a9mp_register_devices)
diff --git a/hw/arm11mpcore.c b/hw/arm11mpcore.c
index 32ecf98309..bc0457e58b 100644
--- a/hw/arm11mpcore.c
+++ b/hw/arm11mpcore.c
@@ -7,11 +7,139 @@
* This code is licensed under the GPL.
*/
+#include "sysbus.h"
+#include "qemu-timer.h"
+
/* ??? The MPCore TRM says the on-chip controller has 224 external IRQ lines
(+ 32 internal). However my test chip only exposes/reports 32.
More importantly Linux falls over if more than 32 are present! */
#define GIC_NIRQ 64
-#include "mpcore.c"
+
+#define NCPU 4
+
+static inline int
+gic_get_current_cpu(void)
+{
+ return cpu_single_env->cpu_index;
+}
+
+#include "arm_gic.c"
+
+/* MPCore private memory region. */
+
+typedef struct mpcore_priv_state {
+ gic_state gic;
+ uint32_t scu_control;
+ int iomemtype;
+ uint32_t old_timer_status[8];
+ uint32_t num_cpu;
+ qemu_irq *timer_irq;
+ MemoryRegion iomem;
+ MemoryRegion container;
+ DeviceState *mptimer;
+} mpcore_priv_state;
+
+/* Per-CPU private memory mapped IO. */
+
+static uint64_t mpcore_scu_read(void *opaque, target_phys_addr_t offset,
+ unsigned size)
+{
+ mpcore_priv_state *s = (mpcore_priv_state *)opaque;
+ int id;
+ offset &= 0xff;
+ /* SCU */
+ switch (offset) {
+ case 0x00: /* Control. */
+ return s->scu_control;
+ case 0x04: /* Configuration. */
+ id = ((1 << s->num_cpu) - 1) << 4;
+ return id | (s->num_cpu - 1);
+ case 0x08: /* CPU status. */
+ return 0;
+ case 0x0c: /* Invalidate all. */
+ return 0;
+ default:
+ hw_error("mpcore_priv_read: Bad offset %x\n", (int)offset);
+ }
+}
+
+static void mpcore_scu_write(void *opaque, target_phys_addr_t offset,
+ uint64_t value, unsigned size)
+{
+ mpcore_priv_state *s = (mpcore_priv_state *)opaque;
+ offset &= 0xff;
+ /* SCU */
+ switch (offset) {
+ case 0: /* Control register. */
+ s->scu_control = value & 1;
+ break;
+ case 0x0c: /* Invalidate all. */
+ /* This is a no-op as cache is not emulated. */
+ break;
+ default:
+ hw_error("mpcore_priv_read: Bad offset %x\n", (int)offset);
+ }
+}
+
+static const MemoryRegionOps mpcore_scu_ops = {
+ .read = mpcore_scu_read,
+ .write = mpcore_scu_write,
+ .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static void mpcore_timer_irq_handler(void *opaque, int irq, int level)
+{
+ mpcore_priv_state *s = (mpcore_priv_state *)opaque;
+ if (level && !s->old_timer_status[irq]) {
+ gic_set_pending_private(&s->gic, irq >> 1, 29 + (irq & 1));
+ }
+ s->old_timer_status[irq] = level;
+}
+
+static void mpcore_priv_map_setup(mpcore_priv_state *s)
+{
+ int i;
+ SysBusDevice *busdev = sysbus_from_qdev(s->mptimer);
+ memory_region_init(&s->container, "mpcode-priv-container", 0x2000);
+ memory_region_init_io(&s->iomem, &mpcore_scu_ops, s, "mpcore-scu", 0x100);
+ memory_region_add_subregion(&s->container, 0, &s->iomem);
+ /* GIC CPU interfaces: "current CPU" at 0x100, then specific CPUs
+ * at 0x200, 0x300...
+ */
+ for (i = 0; i < (s->num_cpu + 1); i++) {
+ target_phys_addr_t offset = 0x100 + (i * 0x100);
+ memory_region_add_subregion(&s->container, offset, &s->gic.cpuiomem[i]);
+ }
+ /* Add the regions for timer and watchdog for "current CPU" and
+ * for each specific CPU.
+ */
+ s->timer_irq = qemu_allocate_irqs(mpcore_timer_irq_handler,
+ s, (s->num_cpu + 1) * 2);
+ for (i = 0; i < (s->num_cpu + 1) * 2; i++) {
+ /* Timers at 0x600, 0x700, ...; watchdogs at 0x620, 0x720, ... */
+ target_phys_addr_t offset = 0x600 + (i >> 1) * 0x100 + (i & 1) * 0x20;
+ memory_region_add_subregion(&s->container, offset,
+ sysbus_mmio_get_region(busdev, i));
+ }
+ memory_region_add_subregion(&s->container, 0x1000, &s->gic.iomem);
+ /* Wire up the interrupt from each watchdog and timer. */
+ for (i = 0; i < s->num_cpu * 2; i++) {
+ sysbus_connect_irq(busdev, i, s->timer_irq[i]);
+ }
+}
+
+static int mpcore_priv_init(SysBusDevice *dev)
+{
+ mpcore_priv_state *s = FROM_SYSBUSGIC(mpcore_priv_state, dev);
+
+ gic_init(&s->gic, s->num_cpu);
+ s->mptimer = qdev_create(NULL, "arm_mptimer");
+ qdev_prop_set_uint32(s->mptimer, "num-cpu", s->num_cpu);
+ qdev_init_nofail(s->mptimer);
+ mpcore_priv_map_setup(s);
+ sysbus_init_mmio(dev, &s->container);
+ return 0;
+}
/* Dummy PIC to route IRQ lines. The baseboard has 4 independent IRQ
controllers. The output of these, plus some of the raw input lines
diff --git a/hw/arm_gic.c b/hw/arm_gic.c
index 1a896fbcb3..9b521195a5 100644
--- a/hw/arm_gic.c
+++ b/hw/arm_gic.c
@@ -103,7 +103,14 @@ typedef struct gic_state
int num_cpu;
#endif
- MemoryRegion iomem;
+ MemoryRegion iomem; /* Distributor */
+#ifndef NVIC
+ /* This is just so we can have an opaque pointer which identifies
+ * both this GIC and which CPU interface we should be accessing.
+ */
+ struct gic_state *backref[NCPU];
+ MemoryRegion cpuiomem[NCPU+1]; /* CPU interfaces */
+#endif
} gic_state;
/* TODO: Many places that call this routine could be optimized. */
@@ -633,6 +640,54 @@ static void gic_cpu_write(gic_state *s, int cpu, int offset, uint32_t value)
}
gic_update(s);
}
+
+/* Wrappers to read/write the GIC CPU interface for the current CPU */
+static uint64_t gic_thiscpu_read(void *opaque, target_phys_addr_t addr,
+ unsigned size)
+{
+ gic_state *s = (gic_state *)opaque;
+ return gic_cpu_read(s, gic_get_current_cpu(), addr & 0xff);
+}
+
+static void gic_thiscpu_write(void *opaque, target_phys_addr_t addr,
+ uint64_t value, unsigned size)
+{
+ gic_state *s = (gic_state *)opaque;
+ gic_cpu_write(s, gic_get_current_cpu(), addr & 0xff, value);
+}
+
+/* Wrappers to read/write the GIC CPU interface for a specific CPU.
+ * These just decode the opaque pointer into gic_state* + cpu id.
+ */
+static uint64_t gic_do_cpu_read(void *opaque, target_phys_addr_t addr,
+ unsigned size)
+{
+ gic_state **backref = (gic_state **)opaque;
+ gic_state *s = *backref;
+ int id = (backref - s->backref);
+ return gic_cpu_read(s, id, addr & 0xff);
+}
+
+static void gic_do_cpu_write(void *opaque, target_phys_addr_t addr,
+ uint64_t value, unsigned size)
+{
+ gic_state **backref = (gic_state **)opaque;
+ gic_state *s = *backref;
+ int id = (backref - s->backref);
+ gic_cpu_write(s, id, addr & 0xff, value);
+}
+
+static const MemoryRegionOps gic_thiscpu_ops = {
+ .read = gic_thiscpu_read,
+ .write = gic_thiscpu_write,
+ .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static const MemoryRegionOps gic_cpu_ops = {
+ .read = gic_do_cpu_read,
+ .write = gic_do_cpu_write,
+ .endianness = DEVICE_NATIVE_ENDIAN,
+};
#endif
static void gic_reset(gic_state *s)
@@ -752,6 +807,24 @@ static void gic_init(gic_state *s)
sysbus_init_irq(&s->busdev, &s->parent_irq[i]);
}
memory_region_init_io(&s->iomem, &gic_dist_ops, s, "gic_dist", 0x1000);
+#ifndef NVIC
+ /* Memory regions for the CPU interfaces (NVIC doesn't have these):
+ * a region for "CPU interface for this core", then a region for
+ * "CPU interface for core 0", "for core 1", ...
+ * NB that the memory region size of 0x100 applies for the 11MPCore
+ * and also cores following the GIC v1 spec (ie A9).
+ * GIC v2 defines a larger memory region (0x1000) so this will need
+ * to be extended when we implement A15.
+ */
+ memory_region_init_io(&s->cpuiomem[0], &gic_thiscpu_ops, s,
+ "gic_cpu", 0x100);
+ for (i = 0; i < NUM_CPU(s); i++) {
+ s->backref[i] = s;
+ memory_region_init_io(&s->cpuiomem[i+1], &gic_cpu_ops, &s->backref[i],
+ "gic_cpu", 0x100);
+ }
+#endif
+
gic_reset(s);
register_savevm(NULL, "arm_gic", -1, 2, gic_save, gic_load, s);
}
diff --git a/hw/arm_mptimer.c b/hw/arm_mptimer.c
new file mode 100644
index 0000000000..455a0aa55a
--- /dev/null
+++ b/hw/arm_mptimer.c
@@ -0,0 +1,332 @@
+/*
+ * Private peripheral timer/watchdog blocks for ARM 11MPCore and A9MP
+ *
+ * Copyright (c) 2006-2007 CodeSourcery.
+ * Copyright (c) 2011 Linaro Limited
+ * Written by Paul Brook, Peter Maydell
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "sysbus.h"
+#include "qemu-timer.h"
+
+/* This device implements the per-cpu private timer and watchdog block
+ * which is used in both the ARM11MPCore and Cortex-A9MP.
+ */
+
+#define MAX_CPUS 4
+
+/* State of a single timer or watchdog block */
+typedef struct {
+ uint32_t count;
+ uint32_t load;
+ uint32_t control;
+ uint32_t status;
+ int64_t tick;
+ QEMUTimer *timer;
+ qemu_irq irq;
+ MemoryRegion iomem;
+} timerblock;
+
+typedef struct {
+ SysBusDevice busdev;
+ uint32_t num_cpu;
+ timerblock timerblock[MAX_CPUS * 2];
+ MemoryRegion iomem[2];
+} arm_mptimer_state;
+
+static inline int get_current_cpu(arm_mptimer_state *s)
+{
+ if (cpu_single_env->cpu_index >= s->num_cpu) {
+ hw_error("arm_mptimer: num-cpu %d but this cpu is %d!\n",
+ s->num_cpu, cpu_single_env->cpu_index);
+ }
+ return cpu_single_env->cpu_index;
+}
+
+static inline void timerblock_update_irq(timerblock *tb)
+{
+ qemu_set_irq(tb->irq, tb->status);
+}
+
+/* Return conversion factor from mpcore timer ticks to qemu timer ticks. */
+static inline uint32_t timerblock_scale(timerblock *tb)
+{
+ return (((tb->control >> 8) & 0xff) + 1) * 10;
+}
+
+static void timerblock_reload(timerblock *tb, int restart)
+{
+ if (tb->count == 0) {
+ return;
+ }
+ if (restart) {
+ tb->tick = qemu_get_clock_ns(vm_clock);
+ }
+ tb->tick += (int64_t)tb->count * timerblock_scale(tb);
+ qemu_mod_timer(tb->timer, tb->tick);
+}
+
+static void timerblock_tick(void *opaque)
+{
+ timerblock *tb = (timerblock *)opaque;
+ tb->status = 1;
+ if (tb->control & 2) {
+ tb->count = tb->load;
+ timerblock_reload(tb, 0);
+ } else {
+ tb->count = 0;
+ }
+ timerblock_update_irq(tb);
+}
+
+static uint64_t timerblock_read(void *opaque, target_phys_addr_t addr,
+ unsigned size)
+{
+ timerblock *tb = (timerblock *)opaque;
+ int64_t val;
+ addr &= 0x1f;
+ switch (addr) {
+ case 0: /* Load */
+ return tb->load;
+ case 4: /* Counter. */
+ if (((tb->control & 1) == 0) || (tb->count == 0)) {
+ return 0;
+ }
+ /* Slow and ugly, but hopefully won't happen too often. */
+ val = tb->tick - qemu_get_clock_ns(vm_clock);
+ val /= timerblock_scale(tb);
+ if (val < 0) {
+ val = 0;
+ }
+ return val;
+ case 8: /* Control. */
+ return tb->control;
+ case 12: /* Interrupt status. */
+ return tb->status;
+ default:
+ return 0;
+ }
+}
+
+static void timerblock_write(void *opaque, target_phys_addr_t addr,
+ uint64_t value, unsigned size)
+{
+ timerblock *tb = (timerblock *)opaque;
+ int64_t old;
+ addr &= 0x1f;
+ switch (addr) {
+ case 0: /* Load */
+ tb->load = value;
+ /* Fall through. */
+ case 4: /* Counter. */
+ if ((tb->control & 1) && tb->count) {
+ /* Cancel the previous timer. */
+ qemu_del_timer(tb->timer);
+ }
+ tb->count = value;
+ if (tb->control & 1) {
+ timerblock_reload(tb, 1);
+ }
+ break;
+ case 8: /* Control. */
+ old = tb->control;
+ tb->control = value;
+ if (((old & 1) == 0) && (value & 1)) {
+ if (tb->count == 0 && (tb->control & 2)) {
+ tb->count = tb->load;
+ }
+ timerblock_reload(tb, 1);
+ }
+ break;
+ case 12: /* Interrupt status. */
+ tb->status &= ~value;
+ timerblock_update_irq(tb);
+ break;
+ }
+}
+
+/* Wrapper functions to implement the "read timer/watchdog for
+ * the current CPU" memory regions.
+ */
+static uint64_t arm_thistimer_read(void *opaque, target_phys_addr_t addr,
+ unsigned size)
+{
+ arm_mptimer_state *s = (arm_mptimer_state *)opaque;
+ int id = get_current_cpu(s);
+ return timerblock_read(&s->timerblock[id * 2], addr, size);
+}
+
+static void arm_thistimer_write(void *opaque, target_phys_addr_t addr,
+ uint64_t value, unsigned size)
+{
+ arm_mptimer_state *s = (arm_mptimer_state *)opaque;
+ int id = get_current_cpu(s);
+ timerblock_write(&s->timerblock[id * 2], addr, value, size);
+}
+
+static uint64_t arm_thiswdog_read(void *opaque, target_phys_addr_t addr,
+ unsigned size)
+{
+ arm_mptimer_state *s = (arm_mptimer_state *)opaque;
+ int id = get_current_cpu(s);
+ return timerblock_read(&s->timerblock[id * 2 + 1], addr, size);
+}
+
+static void arm_thiswdog_write(void *opaque, target_phys_addr_t addr,
+ uint64_t value, unsigned size)
+{
+ arm_mptimer_state *s = (arm_mptimer_state *)opaque;
+ int id = get_current_cpu(s);
+ timerblock_write(&s->timerblock[id * 2 + 1], addr, value, size);
+}
+
+static const MemoryRegionOps arm_thistimer_ops = {
+ .read = arm_thistimer_read,
+ .write = arm_thistimer_write,
+ .valid = {
+ .min_access_size = 4,
+ .max_access_size = 4,
+ },
+ .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static const MemoryRegionOps arm_thiswdog_ops = {
+ .read = arm_thiswdog_read,
+ .write = arm_thiswdog_write,
+ .valid = {
+ .min_access_size = 4,
+ .max_access_size = 4,
+ },
+ .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static const MemoryRegionOps timerblock_ops = {
+ .read = timerblock_read,
+ .write = timerblock_write,
+ .valid = {
+ .min_access_size = 4,
+ .max_access_size = 4,
+ },
+ .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static void timerblock_reset(timerblock *tb)
+{
+ tb->count = 0;
+ tb->load = 0;
+ tb->control = 0;
+ tb->status = 0;
+ tb->tick = 0;
+}
+
+static void arm_mptimer_reset(DeviceState *dev)
+{
+ arm_mptimer_state *s =
+ FROM_SYSBUS(arm_mptimer_state, sysbus_from_qdev(dev));
+ int i;
+ /* We reset every timer in the array, not just the ones we're using,
+ * because vmsave will look at every array element.
+ */
+ for (i = 0; i < ARRAY_SIZE(s->timerblock); i++) {
+ timerblock_reset(&s->timerblock[i]);
+ }
+}
+
+static int arm_mptimer_init(SysBusDevice *dev)
+{
+ arm_mptimer_state *s = FROM_SYSBUS(arm_mptimer_state, dev);
+ int i;
+ if (s->num_cpu < 1 || s->num_cpu > MAX_CPUS) {
+ hw_error("%s: num-cpu must be between 1 and %d\n", __func__, MAX_CPUS);
+ }
+ /* We implement one timer and one watchdog block per CPU, and
+ * expose multiple MMIO regions:
+ * * region 0 is "timer for this core"
+ * * region 1 is "watchdog for this core"
+ * * region 2 is "timer for core 0"
+ * * region 3 is "watchdog for core 0"
+ * * region 4 is "timer for core 1"
+ * * region 5 is "watchdog for core 1"
+ * and so on.
+ * The outgoing interrupt lines are
+ * * timer for core 0
+ * * watchdog for core 0
+ * * timer for core 1
+ * * watchdog for core 1
+ * and so on.
+ */
+ memory_region_init_io(&s->iomem[0], &arm_thistimer_ops, s,
+ "arm_mptimer_timer", 0x20);
+ sysbus_init_mmio(dev, &s->iomem[0]);
+ memory_region_init_io(&s->iomem[1], &arm_thiswdog_ops, s,
+ "arm_mptimer_wdog", 0x20);
+ sysbus_init_mmio(dev, &s->iomem[1]);
+ for (i = 0; i < (s->num_cpu * 2); i++) {
+ timerblock *tb = &s->timerblock[i];
+ tb->timer = qemu_new_timer_ns(vm_clock, timerblock_tick, tb);
+ sysbus_init_irq(dev, &tb->irq);
+ memory_region_init_io(&tb->iomem, &timerblock_ops, tb,
+ "arm_mptimer_timerblock", 0x20);
+ sysbus_init_mmio(dev, &tb->iomem);
+ }
+
+ return 0;
+}
+
+static const VMStateDescription vmstate_timerblock = {
+ .name = "arm_mptimer_timerblock",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .fields = (VMStateField[]) {
+ VMSTATE_UINT32(count, timerblock),
+ VMSTATE_UINT32(load, timerblock),
+ VMSTATE_UINT32(control, timerblock),
+ VMSTATE_UINT32(status, timerblock),
+ VMSTATE_INT64(tick, timerblock),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static const VMStateDescription vmstate_arm_mptimer = {
+ .name = "arm_mptimer",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .fields = (VMStateField[]) {
+ VMSTATE_STRUCT_ARRAY(timerblock, arm_mptimer_state, (MAX_CPUS * 2),
+ 1, vmstate_timerblock, timerblock),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static SysBusDeviceInfo arm_mptimer_info = {
+ .init = arm_mptimer_init,
+ .qdev.name = "arm_mptimer",
+ .qdev.size = sizeof(arm_mptimer_state),
+ .qdev.vmsd = &vmstate_arm_mptimer,
+ .qdev.reset = arm_mptimer_reset,
+ .qdev.no_user = 1,
+ .qdev.props = (Property[]) {
+ DEFINE_PROP_UINT32("num-cpu", arm_mptimer_state, num_cpu, 0),
+ DEFINE_PROP_END_OF_LIST()
+ }
+};
+
+static void arm_mptimer_register_devices(void)
+{
+ sysbus_register_withprop(&arm_mptimer_info);
+}
+
+device_init(arm_mptimer_register_devices)
diff --git a/hw/arm_timer.c b/hw/arm_timer.c
index 518bad20ae..0a5b9d2cd3 100644
--- a/hw/arm_timer.c
+++ b/hw/arm_timer.c
@@ -170,9 +170,9 @@ static arm_timer_state *arm_timer_init(uint32_t freq)
}
/* ARM PrimeCell SP804 dual timer module.
- Docs for this device don't seem to be publicly available. This
- implementation is based on guesswork, the linux kernel sources and the
- Integrator/CP timer modules. */
+ * Docs at
+ * http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0271d/index.html
+*/
typedef struct {
SysBusDevice busdev;
@@ -182,6 +182,13 @@ typedef struct {
qemu_irq irq;
} sp804_state;
+static const uint8_t sp804_ids[] = {
+ /* Timer ID */
+ 0x04, 0x18, 0x14, 0,
+ /* PrimeCell ID */
+ 0xd, 0xf0, 0x05, 0xb1
+};
+
/* Merge the IRQs from the two component devices. */
static void sp804_set_irq(void *opaque, int irq, int level)
{
@@ -196,12 +203,27 @@ static uint64_t sp804_read(void *opaque, target_phys_addr_t offset,
{
sp804_state *s = (sp804_state *)opaque;
- /* ??? Don't know the PrimeCell ID for this device. */
if (offset < 0x20) {
return arm_timer_read(s->timer[0], offset);
- } else {
+ }
+ if (offset < 0x40) {
return arm_timer_read(s->timer[1], offset - 0x20);
}
+
+ /* TimerPeriphID */
+ if (offset >= 0xfe0 && offset <= 0xffc) {
+ return sp804_ids[(offset - 0xfe0) >> 2];
+ }
+
+ switch (offset) {
+ /* Integration Test control registers, which we won't support */
+ case 0xf00: /* TimerITCR */
+ case 0xf04: /* TimerITOP (strictly write only but..) */
+ return 0;
+ }
+
+ hw_error("%s: Bad offset %x\n", __func__, (int)offset);
+ return 0;
}
static void sp804_write(void *opaque, target_phys_addr_t offset,
@@ -211,9 +233,16 @@ static void sp804_write(void *opaque, target_phys_addr_t offset,
if (offset < 0x20) {
arm_timer_write(s->timer[0], offset, value);
- } else {
+ return;
+ }
+
+ if (offset < 0x40) {
arm_timer_write(s->timer[1], offset - 0x20, value);
+ return;
}
+
+ /* Technically we could be writing to the Test Registers, but not likely */
+ hw_error("%s: Bad offset %x\n", __func__, (int)offset);
}
static const MemoryRegionOps sp804_ops = {
diff --git a/hw/ccid-card-emulated.c b/hw/ccid-card-emulated.c
index 092301b541..2d2ebce852 100644
--- a/hw/ccid-card-emulated.c
+++ b/hw/ccid-card-emulated.c
@@ -120,6 +120,7 @@ struct EmulatedState {
uint8_t atr_length;
QSIMPLEQ_HEAD(event_list, EmulEvent) event_list;
QemuMutex event_list_mutex;
+ QemuThread event_thread_id;
VReader *reader;
QSIMPLEQ_HEAD(guest_apdu_list, EmulEvent) guest_apdu_list;
QemuMutex vreader_mutex; /* and guest_apdu_list mutex */
@@ -127,8 +128,7 @@ struct EmulatedState {
QemuCond handle_apdu_cond;
int pipe[2];
int quit_apdu_thread;
- QemuMutex apdu_thread_quit_mutex;
- QemuCond apdu_thread_quit_cond;
+ QemuThread apdu_thread_id;
};
static void emulated_apdu_from_guest(CCIDCardState *base,
@@ -271,9 +271,6 @@ static void *handle_apdu_thread(void* arg)
}
qemu_mutex_unlock(&card->vreader_mutex);
}
- qemu_mutex_lock(&card->apdu_thread_quit_mutex);
- qemu_cond_signal(&card->apdu_thread_quit_cond);
- qemu_mutex_unlock(&card->apdu_thread_quit_mutex);
return NULL;
}
@@ -489,7 +486,6 @@ static uint32_t parse_enumeration(char *str,
static int emulated_initfn(CCIDCardState *base)
{
EmulatedState *card = DO_UPCAST(EmulatedState, base, base);
- QemuThread thread_id;
VCardEmulError ret;
EnumTable *ptable;
@@ -541,8 +537,10 @@ static int emulated_initfn(CCIDCardState *base)
printf("%s: failed to initialize vcard\n", EMULATED_DEV_NAME);
return -1;
}
- qemu_thread_create(&thread_id, event_thread, card);
- qemu_thread_create(&thread_id, handle_apdu_thread, card);
+ qemu_thread_create(&card->event_thread_id, event_thread, card,
+ QEMU_THREAD_JOINABLE);
+ qemu_thread_create(&card->apdu_thread_id, handle_apdu_thread, card,
+ QEMU_THREAD_JOINABLE);
return 0;
}
@@ -552,15 +550,14 @@ static int emulated_exitfn(CCIDCardState *base)
VEvent *vevent = vevent_new(VEVENT_LAST, NULL, NULL);
vevent_queue_vevent(vevent); /* stop vevent thread */
- qemu_mutex_lock(&card->apdu_thread_quit_mutex);
+ qemu_thread_join(&card->event_thread_id);
+
card->quit_apdu_thread = 1; /* stop handle_apdu thread */
qemu_cond_signal(&card->handle_apdu_cond);
- qemu_cond_wait(&card->apdu_thread_quit_cond,
- &card->apdu_thread_quit_mutex);
- /* handle_apdu thread stopped, can destroy all of it's mutexes */
+ qemu_thread_join(&card->apdu_thread_id);
+
+ /* threads exited, can destroy all condvars/mutexes */
qemu_cond_destroy(&card->handle_apdu_cond);
- qemu_cond_destroy(&card->apdu_thread_quit_cond);
- qemu_mutex_destroy(&card->apdu_thread_quit_mutex);
qemu_mutex_destroy(&card->handle_apdu_mutex);
qemu_mutex_destroy(&card->vreader_mutex);
qemu_mutex_destroy(&card->event_list_mutex);
diff --git a/hw/e1000.c b/hw/e1000.c
index 986ed9cf79..a29c944df4 100644
--- a/hw/e1000.c
+++ b/hw/e1000.c
@@ -507,7 +507,7 @@ txdesc_writeback(E1000State *s, dma_addr_t base, struct e1000_tx_desc *dp)
~(E1000_TXD_STAT_EC | E1000_TXD_STAT_LC | E1000_TXD_STAT_TU);
dp->upper.data = cpu_to_le32(txd_upper);
pci_dma_write(&s->dev, base + ((char *)&dp->upper - (char *)dp),
- (void *)&dp->upper, sizeof(dp->upper));
+ &dp->upper, sizeof(dp->upper));
return E1000_ICR_TXDW;
}
@@ -534,7 +534,7 @@ start_xmit(E1000State *s)
while (s->mac_reg[TDH] != s->mac_reg[TDT]) {
base = tx_desc_base(s) +
sizeof(struct e1000_tx_desc) * s->mac_reg[TDH];
- pci_dma_read(&s->dev, base, (void *)&desc, sizeof(desc));
+ pci_dma_read(&s->dev, base, &desc, sizeof(desc));
DBGOUT(TX, "index %d: %p : %x %x\n", s->mac_reg[TDH],
(void *)(intptr_t)desc.buffer_addr, desc.lower.data,
@@ -714,7 +714,7 @@ e1000_receive(VLANClientState *nc, const uint8_t *buf, size_t size)
desc_size = s->rxbuf_size;
}
base = rx_desc_base(s) + sizeof(desc) * s->mac_reg[RDH];
- pci_dma_read(&s->dev, base, (void *)&desc, sizeof(desc));
+ pci_dma_read(&s->dev, base, &desc, sizeof(desc));
desc.special = vlan_special;
desc.status |= (vlan_status | E1000_RXD_STAT_DD);
if (desc.buffer_addr) {
@@ -724,8 +724,7 @@ e1000_receive(VLANClientState *nc, const uint8_t *buf, size_t size)
copy_size = s->rxbuf_size;
}
pci_dma_write(&s->dev, le64_to_cpu(desc.buffer_addr),
- (void *)(buf + desc_offset + vlan_offset),
- copy_size);
+ buf + desc_offset + vlan_offset, copy_size);
}
desc_offset += desc_size;
desc.length = cpu_to_le16(desc_size);
@@ -739,7 +738,7 @@ e1000_receive(VLANClientState *nc, const uint8_t *buf, size_t size)
} else { // as per intel docs; skip descriptors with null buf addr
DBGOUT(RX, "Null RX descriptor!!\n");
}
- pci_dma_write(&s->dev, base, (void *)&desc, sizeof(desc));
+ pci_dma_write(&s->dev, base, &desc, sizeof(desc));
if (++s->mac_reg[RDH] * sizeof(desc) >= s->mac_reg[RDLEN])
s->mac_reg[RDH] = 0;
diff --git a/hw/eepro100.c b/hw/eepro100.c
index e430f56b29..6a162f607f 100644
--- a/hw/eepro100.c
+++ b/hw/eepro100.c
@@ -713,8 +713,7 @@ static void dump_statistics(EEPRO100State * s)
* values which really matter.
* Number of data should check configuration!!!
*/
- pci_dma_write(&s->dev, s->statsaddr,
- (uint8_t *) &s->statistics, s->stats_size);
+ pci_dma_write(&s->dev, s->statsaddr, &s->statistics, s->stats_size);
stl_le_pci_dma(&s->dev, s->statsaddr + 0,
s->statistics.tx_good_frames);
stl_le_pci_dma(&s->dev, s->statsaddr + 36,
@@ -732,7 +731,7 @@ static void dump_statistics(EEPRO100State * s)
static void read_cb(EEPRO100State *s)
{
- pci_dma_read(&s->dev, s->cb_address, (uint8_t *) &s->tx, sizeof(s->tx));
+ pci_dma_read(&s->dev, s->cb_address, &s->tx, sizeof(s->tx));
s->tx.status = le16_to_cpu(s->tx.status);
s->tx.command = le16_to_cpu(s->tx.command);
s->tx.link = le32_to_cpu(s->tx.link);
@@ -1715,7 +1714,7 @@ static ssize_t nic_receive(VLANClientState *nc, const uint8_t * buf, size_t size
/* !!! */
eepro100_rx_t rx;
pci_dma_read(&s->dev, s->ru_base + s->ru_offset,
- (uint8_t *) &rx, sizeof(eepro100_rx_t));
+ &rx, sizeof(eepro100_rx_t));
uint16_t rfd_command = le16_to_cpu(rx.command);
uint16_t rfd_size = le16_to_cpu(rx.size);
diff --git a/hw/hw.h b/hw/hw.h
index ed20f5a27a..efa04d1340 100644
--- a/hw/hw.h
+++ b/hw/hw.h
@@ -27,7 +27,13 @@ typedef int (QEMUFilePutBufferFunc)(void *opaque, const uint8_t *buf,
typedef int (QEMUFileGetBufferFunc)(void *opaque, uint8_t *buf,
int64_t pos, int size);
-/* Close a file and return an error code */
+/* Close a file
+ *
+ * Return negative error number on error, 0 or positive value on success.
+ *
+ * The meaning of return value on success depends on the specific back-end being
+ * used.
+ */
typedef int (QEMUFileCloseFunc)(void *opaque);
/* Called to determine if the file has exceeded it's bandwidth allocation. The
diff --git a/hw/ide/pci.c b/hw/ide/pci.c
index 5078c0b565..cb3de6537b 100644
--- a/hw/ide/pci.c
+++ b/hw/ide/pci.c
@@ -71,7 +71,7 @@ static int bmdma_prepare_buf(IDEDMA *dma, int is_write)
if (bm->cur_prd_last ||
(bm->cur_addr - bm->addr) >= BMDMA_PAGE_SIZE)
return s->io_buffer_size != 0;
- pci_dma_read(&bm->pci_dev->dev, bm->cur_addr, (uint8_t *)&prd, 8);
+ pci_dma_read(&bm->pci_dev->dev, bm->cur_addr, &prd, 8);
bm->cur_addr += 8;
prd.addr = le32_to_cpu(prd.addr);
prd.size = le32_to_cpu(prd.size);
@@ -113,7 +113,7 @@ static int bmdma_rw_buf(IDEDMA *dma, int is_write)
if (bm->cur_prd_last ||
(bm->cur_addr - bm->addr) >= BMDMA_PAGE_SIZE)
return 0;
- pci_dma_read(&bm->pci_dev->dev, bm->cur_addr, (uint8_t *)&prd, 8);
+ pci_dma_read(&bm->pci_dev->dev, bm->cur_addr, &prd, 8);
bm->cur_addr += 8;
prd.addr = le32_to_cpu(prd.addr);
prd.size = le32_to_cpu(prd.size);
diff --git a/hw/lsi53c895a.c b/hw/lsi53c895a.c
index fcc27d726f..0d3a1016df 100644
--- a/hw/lsi53c895a.c
+++ b/hw/lsi53c895a.c
@@ -392,7 +392,7 @@ static inline uint32_t read_dword(LSIState *s, uint32_t addr)
{
uint32_t buf;
- pci_dma_read(&s->dev, addr, (uint8_t *)&buf, 4);
+ pci_dma_read(&s->dev, addr, &buf, 4);
return cpu_to_le32(buf);
}
@@ -1079,7 +1079,7 @@ again:
/* 32-bit Table indirect */
offset = sxt24(addr);
- pci_dma_read(&s->dev, s->dsa + offset, (uint8_t *)buf, 8);
+ pci_dma_read(&s->dev, s->dsa + offset, buf, 8);
/* byte count is stored in bits 0:23 only */
s->dbc = cpu_to_le32(buf[0]) & 0xffffff;
s->rbc = s->dbc;
diff --git a/hw/mpcore.c b/hw/mpcore.c
deleted file mode 100644
index 4357d12217..0000000000
--- a/hw/mpcore.c
+++ /dev/null
@@ -1,283 +0,0 @@
-/*
- * ARM MPCore internal peripheral emulation (common code).
- *
- * Copyright (c) 2006-2007 CodeSourcery.
- * Written by Paul Brook
- *
- * This code is licensed under the GPL.
- */
-
-#include "sysbus.h"
-#include "qemu-timer.h"
-
-#define NCPU 4
-
-static inline int
-gic_get_current_cpu(void)
-{
- return cpu_single_env->cpu_index;
-}
-
-#include "arm_gic.c"
-
-/* MPCore private memory region. */
-
-typedef struct {
- uint32_t count;
- uint32_t load;
- uint32_t control;
- uint32_t status;
- uint32_t old_status;
- int64_t tick;
- QEMUTimer *timer;
- struct mpcore_priv_state *mpcore;
- int id; /* Encodes both timer/watchdog and CPU. */
-} mpcore_timer_state;
-
-typedef struct mpcore_priv_state {
- gic_state gic;
- uint32_t scu_control;
- int iomemtype;
- mpcore_timer_state timer[8];
- uint32_t num_cpu;
- MemoryRegion iomem;
- MemoryRegion container;
-} mpcore_priv_state;
-
-/* Per-CPU Timers. */
-
-static inline void mpcore_timer_update_irq(mpcore_timer_state *s)
-{
- if (s->status & ~s->old_status) {
- gic_set_pending_private(&s->mpcore->gic, s->id >> 1, 29 + (s->id & 1));
- }
- s->old_status = s->status;
-}
-
-/* Return conversion factor from mpcore timer ticks to qemu timer ticks. */
-static inline uint32_t mpcore_timer_scale(mpcore_timer_state *s)
-{
- return (((s->control >> 8) & 0xff) + 1) * 10;
-}
-
-static void mpcore_timer_reload(mpcore_timer_state *s, int restart)
-{
- if (s->count == 0)
- return;
- if (restart)
- s->tick = qemu_get_clock_ns(vm_clock);
- s->tick += (int64_t)s->count * mpcore_timer_scale(s);
- qemu_mod_timer(s->timer, s->tick);
-}
-
-static void mpcore_timer_tick(void *opaque)
-{
- mpcore_timer_state *s = (mpcore_timer_state *)opaque;
- s->status = 1;
- if (s->control & 2) {
- s->count = s->load;
- mpcore_timer_reload(s, 0);
- } else {
- s->count = 0;
- }
- mpcore_timer_update_irq(s);
-}
-
-static uint32_t mpcore_timer_read(mpcore_timer_state *s, int offset)
-{
- int64_t val;
- switch (offset) {
- case 0: /* Load */
- return s->load;
- /* Fall through. */
- case 4: /* Counter. */
- if (((s->control & 1) == 0) || (s->count == 0))
- return 0;
- /* Slow and ugly, but hopefully won't happen too often. */
- val = s->tick - qemu_get_clock_ns(vm_clock);
- val /= mpcore_timer_scale(s);
- if (val < 0)
- val = 0;
- return val;
- case 8: /* Control. */
- return s->control;
- case 12: /* Interrupt status. */
- return s->status;
- default:
- return 0;
- }
-}
-
-static void mpcore_timer_write(mpcore_timer_state *s, int offset,
- uint32_t value)
-{
- int64_t old;
- switch (offset) {
- case 0: /* Load */
- s->load = value;
- /* Fall through. */
- case 4: /* Counter. */
- if ((s->control & 1) && s->count) {
- /* Cancel the previous timer. */
- qemu_del_timer(s->timer);
- }
- s->count = value;
- if (s->control & 1) {
- mpcore_timer_reload(s, 1);
- }
- break;
- case 8: /* Control. */
- old = s->control;
- s->control = value;
- if (((old & 1) == 0) && (value & 1)) {
- if (s->count == 0 && (s->control & 2))
- s->count = s->load;
- mpcore_timer_reload(s, 1);
- }
- break;
- case 12: /* Interrupt status. */
- s->status &= ~value;
- mpcore_timer_update_irq(s);
- break;
- }
-}
-
-static void mpcore_timer_init(mpcore_priv_state *mpcore,
- mpcore_timer_state *s, int id)
-{
- s->id = id;
- s->mpcore = mpcore;
- s->timer = qemu_new_timer_ns(vm_clock, mpcore_timer_tick, s);
-}
-
-
-/* Per-CPU private memory mapped IO. */
-
-static uint64_t mpcore_priv_read(void *opaque, target_phys_addr_t offset,
- unsigned size)
-{
- mpcore_priv_state *s = (mpcore_priv_state *)opaque;
- int id;
- offset &= 0xfff;
- if (offset < 0x100) {
- /* SCU */
- switch (offset) {
- case 0x00: /* Control. */
- return s->scu_control;
- case 0x04: /* Configuration. */
- id = ((1 << s->num_cpu) - 1) << 4;
- return id | (s->num_cpu - 1);
- case 0x08: /* CPU status. */
- return 0;
- case 0x0c: /* Invalidate all. */
- return 0;
- default:
- goto bad_reg;
- }
- } else if (offset < 0x600) {
- /* Interrupt controller. */
- if (offset < 0x200) {
- id = gic_get_current_cpu();
- } else {
- id = (offset - 0x200) >> 8;
- if (id >= s->num_cpu) {
- return 0;
- }
- }
- return gic_cpu_read(&s->gic, id, offset & 0xff);
- } else if (offset < 0xb00) {
- /* Timers. */
- if (offset < 0x700) {
- id = gic_get_current_cpu();
- } else {
- id = (offset - 0x700) >> 8;
- if (id >= s->num_cpu) {
- return 0;
- }
- }
- id <<= 1;
- if (offset & 0x20)
- id++;
- return mpcore_timer_read(&s->timer[id], offset & 0xf);
- }
-bad_reg:
- hw_error("mpcore_priv_read: Bad offset %x\n", (int)offset);
- return 0;
-}
-
-static void mpcore_priv_write(void *opaque, target_phys_addr_t offset,
- uint64_t value, unsigned size)
-{
- mpcore_priv_state *s = (mpcore_priv_state *)opaque;
- int id;
- offset &= 0xfff;
- if (offset < 0x100) {
- /* SCU */
- switch (offset) {
- case 0: /* Control register. */
- s->scu_control = value & 1;
- break;
- case 0x0c: /* Invalidate all. */
- /* This is a no-op as cache is not emulated. */
- break;
- default:
- goto bad_reg;
- }
- } else if (offset < 0x600) {
- /* Interrupt controller. */
- if (offset < 0x200) {
- id = gic_get_current_cpu();
- } else {
- id = (offset - 0x200) >> 8;
- }
- if (id < s->num_cpu) {
- gic_cpu_write(&s->gic, id, offset & 0xff, value);
- }
- } else if (offset < 0xb00) {
- /* Timers. */
- if (offset < 0x700) {
- id = gic_get_current_cpu();
- } else {
- id = (offset - 0x700) >> 8;
- }
- if (id < s->num_cpu) {
- id <<= 1;
- if (offset & 0x20)
- id++;
- mpcore_timer_write(&s->timer[id], offset & 0xf, value);
- }
- return;
- }
- return;
-bad_reg:
- hw_error("mpcore_priv_read: Bad offset %x\n", (int)offset);
-}
-
-static const MemoryRegionOps mpcore_priv_ops = {
- .read = mpcore_priv_read,
- .write = mpcore_priv_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static void mpcore_priv_map_setup(mpcore_priv_state *s)
-{
- memory_region_init(&s->container, "mpcode-priv-container", 0x2000);
- memory_region_init_io(&s->iomem, &mpcore_priv_ops, s, "mpcode-priv",
- 0x1000);
- memory_region_add_subregion(&s->container, 0, &s->iomem);
- memory_region_add_subregion(&s->container, 0x1000, &s->gic.iomem);
-}
-
-static int mpcore_priv_init(SysBusDevice *dev)
-{
- mpcore_priv_state *s = FROM_SYSBUSGIC(mpcore_priv_state, dev);
- int i;
-
- gic_init(&s->gic, s->num_cpu);
- mpcore_priv_map_setup(s);
- sysbus_init_mmio(dev, &s->container);
- for (i = 0; i < s->num_cpu * 2; i++) {
- mpcore_timer_init(s, &s->timer[i], i);
- }
- return 0;
-}
diff --git a/hw/realview_gic.c b/hw/realview_gic.c
index 479f939553..8c4d509ee7 100644
--- a/hw/realview_gic.c
+++ b/hw/realview_gic.c
@@ -23,36 +23,13 @@ gic_get_current_cpu(void)
typedef struct {
gic_state gic;
- MemoryRegion iomem;
MemoryRegion container;
} RealViewGICState;
-static uint64_t realview_gic_cpu_read(void *opaque, target_phys_addr_t offset,
- unsigned size)
-{
- gic_state *s = (gic_state *)opaque;
- return gic_cpu_read(s, gic_get_current_cpu(), offset);
-}
-
-static void realview_gic_cpu_write(void *opaque, target_phys_addr_t offset,
- uint64_t value, unsigned size)
-{
- gic_state *s = (gic_state *)opaque;
- gic_cpu_write(s, gic_get_current_cpu(), offset, value);
-}
-
-static const MemoryRegionOps realview_gic_cpu_ops = {
- .read = realview_gic_cpu_read,
- .write = realview_gic_cpu_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
static void realview_gic_map_setup(RealViewGICState *s)
{
memory_region_init(&s->container, "realview-gic-container", 0x2000);
- memory_region_init_io(&s->iomem, &realview_gic_cpu_ops, &s->gic,
- "realview-gic", 0x1000);
- memory_region_add_subregion(&s->container, 0, &s->iomem);
+ memory_region_add_subregion(&s->container, 0, &s->gic.cpuiomem[0]);
memory_region_add_subregion(&s->container, 0x1000, &s->gic.iomem);
}
diff --git a/hw/rtl8139.c b/hw/rtl8139.c
index 8aace9a4ec..0ae9f5774b 100644
--- a/hw/rtl8139.c
+++ b/hw/rtl8139.c
@@ -991,13 +991,13 @@ static ssize_t rtl8139_do_receive(VLANClientState *nc, const uint8_t *buf, size_
uint32_t val, rxdw0,rxdw1,rxbufLO,rxbufHI;
- pci_dma_read(&s->dev, cplus_rx_ring_desc, (uint8_t *)&val, 4);
+ pci_dma_read(&s->dev, cplus_rx_ring_desc, &val, 4);
rxdw0 = le32_to_cpu(val);
- pci_dma_read(&s->dev, cplus_rx_ring_desc+4, (uint8_t *)&val, 4);
+ pci_dma_read(&s->dev, cplus_rx_ring_desc+4, &val, 4);
rxdw1 = le32_to_cpu(val);
- pci_dma_read(&s->dev, cplus_rx_ring_desc+8, (uint8_t *)&val, 4);
+ pci_dma_read(&s->dev, cplus_rx_ring_desc+8, &val, 4);
rxbufLO = le32_to_cpu(val);
- pci_dma_read(&s->dev, cplus_rx_ring_desc+12, (uint8_t *)&val, 4);
+ pci_dma_read(&s->dev, cplus_rx_ring_desc+12, &val, 4);
rxbufHI = le32_to_cpu(val);
DPRINTF("+++ C+ mode RX descriptor %d %08x %08x %08x %08x\n",
diff --git a/hw/syborg.c b/hw/syborg.c
deleted file mode 100644
index 248de54c4e..0000000000
--- a/hw/syborg.c
+++ /dev/null
@@ -1,113 +0,0 @@
-/*
- * Syborg (Symbian Virtual Platform) reference board
- *
- * Copyright (c) 2009 CodeSourcery
- *
- * 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 "sysbus.h"
-#include "boards.h"
-#include "arm-misc.h"
-#include "net.h"
-#include "exec-memory.h"
-
-static struct arm_boot_info syborg_binfo;
-
-static void syborg_init(ram_addr_t ram_size,
- const char *boot_device,
- const char *kernel_filename, const char *kernel_cmdline,
- const char *initrd_filename, const char *cpu_model)
-{
- CPUState *env;
- MemoryRegion *sysmem = get_system_memory();
- MemoryRegion *ram = g_new(MemoryRegion, 1);
- qemu_irq *cpu_pic;
- qemu_irq pic[64];
- DeviceState *dev;
- int i;
-
- if (!cpu_model)
- cpu_model = "cortex-a8";
- env = cpu_init(cpu_model);
- if (!env) {
- fprintf(stderr, "Unable to find CPU definition\n");
- exit(1);
- }
-
- /* RAM at address zero. */
- memory_region_init_ram(ram, NULL, "syborg.ram", ram_size);
- memory_region_add_subregion(sysmem, 0, ram);
-
- cpu_pic = arm_pic_init_cpu(env);
- dev = sysbus_create_simple("syborg,interrupt", 0xC0000000,
- cpu_pic[ARM_PIC_CPU_IRQ]);
- for (i = 0; i < 64; i++) {
- pic[i] = qdev_get_gpio_in(dev, i);
- }
-
- sysbus_create_simple("syborg,rtc", 0xC0001000, NULL);
-
- dev = qdev_create(NULL, "syborg,timer");
- qdev_prop_set_uint32(dev, "frequency", 1000000);
- qdev_init_nofail(dev);
- sysbus_mmio_map(sysbus_from_qdev(dev), 0, 0xC0002000);
- sysbus_connect_irq(sysbus_from_qdev(dev), 0, pic[1]);
-
- sysbus_create_simple("syborg,keyboard", 0xC0003000, pic[2]);
- sysbus_create_simple("syborg,pointer", 0xC0004000, pic[3]);
- sysbus_create_simple("syborg,framebuffer", 0xC0005000, pic[4]);
- sysbus_create_simple("syborg,serial", 0xC0006000, pic[5]);
- sysbus_create_simple("syborg,serial", 0xC0007000, pic[6]);
- sysbus_create_simple("syborg,serial", 0xC0008000, pic[7]);
- sysbus_create_simple("syborg,serial", 0xC0009000, pic[8]);
-
- if (nd_table[0].vlan || nd_table[0].netdev) {
- DeviceState *dev;
- SysBusDevice *s;
-
- qemu_check_nic_model(&nd_table[0], "virtio");
- dev = qdev_create(NULL, "syborg,virtio-net");
- qdev_set_nic_properties(dev, &nd_table[0]);
- qdev_init_nofail(dev);
- s = sysbus_from_qdev(dev);
- sysbus_mmio_map(s, 0, 0xc000c000);
- sysbus_connect_irq(s, 0, pic[9]);
- }
-
- syborg_binfo.ram_size = ram_size;
- syborg_binfo.kernel_filename = kernel_filename;
- syborg_binfo.kernel_cmdline = kernel_cmdline;
- syborg_binfo.initrd_filename = initrd_filename;
- syborg_binfo.board_id = 0;
- arm_load_kernel(env, &syborg_binfo);
-}
-
-static QEMUMachine syborg_machine = {
- .name = "syborg",
- .desc = "Syborg (Symbian Virtual Platform)",
- .init = syborg_init,
-};
-
-static void syborg_machine_init(void)
-{
- qemu_register_machine(&syborg_machine);
-}
-
-machine_init(syborg_machine_init);
diff --git a/hw/syborg.h b/hw/syborg.h
deleted file mode 100644
index b82ce4a502..0000000000
--- a/hw/syborg.h
+++ /dev/null
@@ -1,18 +0,0 @@
-#ifndef _SYBORG_H
-#define _SYBORG_H
-
-#define SYBORG_ID_PLATFORM 0xc51d1000
-#define SYBORG_ID_INT 0xc51d0000
-#define SYBORG_ID_SERIAL 0xc51d0001
-#define SYBORG_ID_KEYBOARD 0xc51d0002
-#define SYBORG_ID_TIMER 0xc51d0003
-#define SYBORG_ID_RTC 0xc51d0004
-#define SYBORG_ID_MOUSE 0xc51d0005
-#define SYBORG_ID_TOUCHSCREEN 0xc51d0006
-#define SYBORG_ID_FRAMEBUFFER 0xc51d0007
-#define SYBORG_ID_HOSTFS 0xc51d0008
-#define SYBORG_ID_SNAPSHOT 0xc51d0009
-#define SYBORG_ID_VIRTIO 0xc51d000a
-#define SYBORG_ID_NAND 0xc51d000b
-
-#endif
diff --git a/hw/syborg_fb.c b/hw/syborg_fb.c
deleted file mode 100644
index b87d7e6d10..0000000000
--- a/hw/syborg_fb.c
+++ /dev/null
@@ -1,554 +0,0 @@
-/*
- * Syborg Framebuffer
- *
- * Copyright (c) 2009 CodeSourcery
- *
- * 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 "sysbus.h"
-#include "console.h"
-#include "syborg.h"
-#include "framebuffer.h"
-
-//#define DEBUG_SYBORG_FB
-
-#ifdef DEBUG_SYBORG_FB
-#define DPRINTF(fmt, ...) \
-do { printf("syborg_fb: " fmt , ## __VA_ARGS__); } while (0)
-#define BADF(fmt, ...) \
-do { fprintf(stderr, "syborg_fb: error: " fmt , ## __VA_ARGS__); \
- exit(1);} while (0)
-#else
-#define DPRINTF(fmt, ...) do {} while(0)
-#define BADF(fmt, ...) \
-do { fprintf(stderr, "syborg_fb: error: " fmt , ## __VA_ARGS__);} while (0)
-#endif
-
-enum {
- FB_ID = 0,
- FB_BASE = 1,
- FB_HEIGHT = 2,
- FB_WIDTH = 3,
- FB_ORIENTATION = 4,
- FB_BLANK = 5,
- FB_INT_MASK = 6,
- FB_INTERRUPT_CAUSE = 7,
- FB_BPP = 8,
- FB_COLOR_ORDER = 9,
- FB_BYTE_ORDER = 10,
- FB_PIXEL_ORDER = 11,
- FB_ROW_PITCH = 12,
- FB_ENABLED = 13,
- FB_PALETTE_START = 0x400 >> 2,
- FB_PALETTE_END = FB_PALETTE_START+256-1,
-};
-
-#define FB_INT_VSYNC (1U << 0)
-#define FB_INT_BASE_UPDATE_DONE (1U << 1)
-
-typedef struct {
- SysBusDevice busdev;
- MemoryRegion iomem;
- DisplayState *ds;
- /*QEMUConsole *console;*/
- uint32_t need_update : 1;
- uint32_t need_int : 1;
- uint32_t enabled : 1;
- uint32_t int_status;
- uint32_t int_enable;
- qemu_irq irq;
-
- uint32_t base;
- uint32_t pitch;
- uint32_t rows;
- uint32_t cols;
- int blank;
- int bpp;
- int rgb; /* 0 = BGR, 1 = RGB */
- int endian; /* 0 = Little, 1 = Big */
- uint32_t raw_palette[256];
- uint32_t palette[256];
-} SyborgFBState;
-
-enum {
- BPP_SRC_1,
- BPP_SRC_2,
- BPP_SRC_4,
- BPP_SRC_8,
- BPP_SRC_16,
- BPP_SRC_32,
- /* TODO: Implement these. */
- BPP_SRC_15 = -1,
- BPP_SRC_24 = -2
-};
-
-#include "pixel_ops.h"
-
-#define BITS 8
-#include "pl110_template.h"
-#define BITS 15
-#include "pl110_template.h"
-#define BITS 16
-#include "pl110_template.h"
-#define BITS 24
-#include "pl110_template.h"
-#define BITS 32
-#include "pl110_template.h"
-
-/* Update interrupts. */
-static void syborg_fb_update(SyborgFBState *s)
-{
- if ((s->int_status & s->int_enable) != 0) {
- DPRINTF("Raise IRQ\n");
- qemu_irq_raise(s->irq);
- } else {
- DPRINTF("Lower IRQ\n");
- qemu_irq_lower(s->irq);
- }
-}
-
-static int syborg_fb_enabled(const SyborgFBState *s)
-{
- return s->enabled;
-}
-
-static void syborg_fb_update_palette(SyborgFBState *s)
-{
- int n, i;
- uint32_t raw;
- unsigned int r, g, b;
-
- switch (s->bpp) {
- case BPP_SRC_1: n = 2; break;
- case BPP_SRC_2: n = 4; break;
- case BPP_SRC_4: n = 16; break;
- case BPP_SRC_8: n = 256; break;
- default: return;
- }
-
- for (i = 0; i < n; i++) {
- raw = s->raw_palette[i];
- r = (raw >> 16) & 0xff;
- g = (raw >> 8) & 0xff;
- b = raw & 0xff;
- switch (ds_get_bits_per_pixel(s->ds)) {
- case 8:
- s->palette[i] = rgb_to_pixel8(r, g, b);
- break;
- case 15:
- s->palette[i] = rgb_to_pixel15(r, g, b);
- break;
- case 16:
- s->palette[i] = rgb_to_pixel16(r, g, b);
- break;
- case 24:
- case 32:
- s->palette[i] = rgb_to_pixel32(r, g, b);
- break;
- default:
- abort();
- }
- }
-
-}
-
-static void syborg_fb_update_display(void *opaque)
-{
- SyborgFBState *s = (SyborgFBState *)opaque;
- drawfn* fntable;
- drawfn fn;
- int dest_width;
- int src_width;
- int bpp_offset;
- int first;
- int last;
-
- if (!syborg_fb_enabled(s))
- return;
-
- switch (ds_get_bits_per_pixel(s->ds)) {
- case 0:
- return;
- case 8:
- fntable = pl110_draw_fn_8;
- dest_width = 1;
- break;
- case 15:
- fntable = pl110_draw_fn_15;
- dest_width = 2;
- break;
- case 16:
- fntable = pl110_draw_fn_16;
- dest_width = 2;
- break;
- case 24:
- fntable = pl110_draw_fn_24;
- dest_width = 3;
- break;
- case 32:
- fntable = pl110_draw_fn_32;
- dest_width = 4;
- break;
- default:
- fprintf(stderr, "syborg_fb: Bad color depth\n");
- exit(1);
- }
-
- if (s->need_int) {
- s->int_status |= FB_INT_BASE_UPDATE_DONE;
- syborg_fb_update(s);
- s->need_int = 0;
- }
-
- if (s->rgb) {
- bpp_offset = 24;
- } else {
- bpp_offset = 0;
- }
- if (s->endian) {
- bpp_offset += 8;
- }
- /* Our bpp constants mostly match the PL110/PL111 but
- * not for the 16 bit case
- */
- switch (s->bpp) {
- case BPP_SRC_16:
- bpp_offset += 6;
- break;
- default:
- bpp_offset += s->bpp;
- }
- fn = fntable[bpp_offset];
-
- if (s->pitch) {
- src_width = s->pitch;
- } else {
- src_width = s->cols;
- switch (s->bpp) {
- case BPP_SRC_1:
- src_width >>= 3;
- break;
- case BPP_SRC_2:
- src_width >>= 2;
- break;
- case BPP_SRC_4:
- src_width >>= 1;
- break;
- case BPP_SRC_8:
- break;
- case BPP_SRC_15:
- case BPP_SRC_16:
- src_width <<= 1;
- break;
- case BPP_SRC_24:
- src_width *= 3;
- break;
- case BPP_SRC_32:
- src_width <<= 2;
- break;
- }
- }
- dest_width *= s->cols;
- first = 0;
- /* TODO: Implement blanking. */
- if (!s->blank) {
- if (s->need_update && s->bpp <= BPP_SRC_8) {
- syborg_fb_update_palette(s);
- }
- framebuffer_update_display(s->ds,
- s->base, s->cols, s->rows,
- src_width, dest_width, 0,
- s->need_update,
- fn, s->palette,
- &first, &last);
- if (first >= 0) {
- dpy_update(s->ds, 0, first, s->cols, last - first + 1);
- }
-
- s->int_status |= FB_INT_VSYNC;
- syborg_fb_update(s);
- }
-
- s->need_update = 0;
-}
-
-static void syborg_fb_invalidate_display(void * opaque)
-{
- SyborgFBState *s = (SyborgFBState *)opaque;
- s->need_update = 1;
-}
-
-static uint64_t syborg_fb_read(void *opaque, target_phys_addr_t offset,
- unsigned size)
-{
- SyborgFBState *s = opaque;
-
- DPRINTF("read reg %d\n", (int)offset);
- offset &= 0xfff;
- switch (offset >> 2) {
- case FB_ID:
- return SYBORG_ID_FRAMEBUFFER;
-
- case FB_BASE:
- return s->base;
-
- case FB_HEIGHT:
- return s->rows;
-
- case FB_WIDTH:
- return s->cols;
-
- case FB_ORIENTATION:
- return 0;
-
- case FB_BLANK:
- return s->blank;
-
- case FB_INT_MASK:
- return s->int_enable;
-
- case FB_INTERRUPT_CAUSE:
- return s->int_status;
-
- case FB_BPP:
- switch (s->bpp) {
- case BPP_SRC_1: return 1;
- case BPP_SRC_2: return 2;
- case BPP_SRC_4: return 4;
- case BPP_SRC_8: return 8;
- case BPP_SRC_15: return 15;
- case BPP_SRC_16: return 16;
- case BPP_SRC_24: return 24;
- case BPP_SRC_32: return 32;
- default: return 0;
- }
-
- case FB_COLOR_ORDER:
- return s->rgb;
-
- case FB_BYTE_ORDER:
- return s->endian;
-
- case FB_PIXEL_ORDER:
- return 0;
-
- case FB_ROW_PITCH:
- return s->pitch;
-
- case FB_ENABLED:
- return s->enabled;
-
- default:
- if ((offset >> 2) >= FB_PALETTE_START
- && (offset >> 2) <= FB_PALETTE_END) {
- return s->raw_palette[(offset >> 2) - FB_PALETTE_START];
- } else {
- cpu_abort (cpu_single_env, "syborg_fb_read: Bad offset %x\n",
- (int)offset);
- }
- return 0;
- }
-}
-
-static void syborg_fb_write(void *opaque, target_phys_addr_t offset,
- uint64_t val, unsigned size)
-{
- SyborgFBState *s = opaque;
-
- DPRINTF("write reg %d = %d\n", (int)offset, val);
- s->need_update = 1;
- offset &= 0xfff;
- switch (offset >> 2) {
- case FB_BASE:
- s->base = val;
- s->need_int = 1;
- s->need_update = 1;
- syborg_fb_update(s);
- break;
-
- case FB_HEIGHT:
- s->rows = val;
- break;
-
- case FB_WIDTH:
- s->cols = val;
- break;
-
- case FB_ORIENTATION:
- /* TODO: Implement rotation. */
- break;
-
- case FB_BLANK:
- s->blank = val & 1;
- break;
-
- case FB_INT_MASK:
- s->int_enable = val;
- syborg_fb_update(s);
- break;
-
- case FB_INTERRUPT_CAUSE:
- s->int_status &= ~val;
- syborg_fb_update(s);
- break;
-
- case FB_BPP:
- switch (val) {
- case 1: val = BPP_SRC_1; break;
- case 2: val = BPP_SRC_2; break;
- case 4: val = BPP_SRC_4; break;
- case 8: val = BPP_SRC_8; break;
- /* case 15: val = BPP_SRC_15; break; */
- case 16: val = BPP_SRC_16; break;
- /* case 24: val = BPP_SRC_24; break; */
- case 32: val = BPP_SRC_32; break;
- default: val = s->bpp; break;
- }
- s->bpp = val;
- break;
-
- case FB_COLOR_ORDER:
- s->rgb = (val != 0);
- break;
-
- case FB_BYTE_ORDER:
- s->endian = (val != 0);
- break;
-
- case FB_PIXEL_ORDER:
- /* TODO: Implement this. */
- break;
-
- case FB_ROW_PITCH:
- s->pitch = val;
- break;
-
- case FB_ENABLED:
- s->enabled = val;
- break;
-
- default:
- if ((offset >> 2) >= FB_PALETTE_START
- && (offset >> 2) <= FB_PALETTE_END) {
- s->raw_palette[(offset >> 2) - FB_PALETTE_START] = val;
- } else {
- cpu_abort (cpu_single_env, "syborg_fb_write: Bad offset %x\n",
- (int)offset);
- }
- break;
- }
-}
-
-static const MemoryRegionOps syborg_fb_ops = {
- .read = syborg_fb_read,
- .write = syborg_fb_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static void syborg_fb_save(QEMUFile *f, void *opaque)
-{
- SyborgFBState *s = opaque;
- int i;
-
- qemu_put_be32(f, s->need_int);
- qemu_put_be32(f, s->int_status);
- qemu_put_be32(f, s->int_enable);
- qemu_put_be32(f, s->enabled);
- qemu_put_be32(f, s->base);
- qemu_put_be32(f, s->pitch);
- qemu_put_be32(f, s->rows);
- qemu_put_be32(f, s->cols);
- qemu_put_be32(f, s->bpp);
- qemu_put_be32(f, s->rgb);
- for (i = 0; i < 256; i++) {
- qemu_put_be32(f, s->raw_palette[i]);
- }
-}
-
-static int syborg_fb_load(QEMUFile *f, void *opaque, int version_id)
-{
- SyborgFBState *s = opaque;
- int i;
-
- if (version_id != 1)
- return -EINVAL;
-
- s->need_int = qemu_get_be32(f);
- s->int_status = qemu_get_be32(f);
- s->int_enable = qemu_get_be32(f);
- s->enabled = qemu_get_be32(f);
- s->base = qemu_get_be32(f);
- s->pitch = qemu_get_be32(f);
- s->rows = qemu_get_be32(f);
- s->cols = qemu_get_be32(f);
- s->bpp = qemu_get_be32(f);
- s->rgb = qemu_get_be32(f);
- for (i = 0; i < 256; i++) {
- s->raw_palette[i] = qemu_get_be32(f);
- }
- s->need_update = 1;
-
- return 0;
-}
-
-static int syborg_fb_init(SysBusDevice *dev)
-{
- SyborgFBState *s = FROM_SYSBUS(SyborgFBState, dev);
-
- sysbus_init_irq(dev, &s->irq);
- memory_region_init_io(&s->iomem, &syborg_fb_ops, s,
- "framebuffer", 0x1000);
- sysbus_init_mmio(dev, &s->iomem);
-
- s->ds = graphic_console_init(syborg_fb_update_display,
- syborg_fb_invalidate_display,
- NULL, NULL, s);
-
- if (s->cols != 0 && s->rows != 0) {
- qemu_console_resize(s->ds, s->cols, s->rows);
- }
-
- if (!s->cols)
- s->cols = ds_get_width(s->ds);
- if (!s->rows)
- s->rows = ds_get_height(s->ds);
-
- register_savevm(&dev->qdev, "syborg_framebuffer", -1, 1,
- syborg_fb_save, syborg_fb_load, s);
- return 0;
-}
-
-static SysBusDeviceInfo syborg_fb_info = {
- .init = syborg_fb_init,
- .qdev.name = "syborg,framebuffer",
- .qdev.size = sizeof(SyborgFBState),
- .qdev.props = (Property[]) {
- DEFINE_PROP_UINT32("width", SyborgFBState, cols, 0),
- DEFINE_PROP_UINT32("height", SyborgFBState, rows, 0),
- DEFINE_PROP_END_OF_LIST(),
- }
-};
-
-static void syborg_fb_register_devices(void)
-{
- sysbus_register_withprop(&syborg_fb_info);
-}
-
-device_init(syborg_fb_register_devices)
diff --git a/hw/syborg_interrupt.c b/hw/syborg_interrupt.c
deleted file mode 100644
index 93e81c8660..0000000000
--- a/hw/syborg_interrupt.c
+++ /dev/null
@@ -1,233 +0,0 @@
-/*
- * Syborg interrupt controller.
- *
- * Copyright (c) 2008 CodeSourcery
- *
- * 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 "sysbus.h"
-#include "syborg.h"
-
-//#define DEBUG_SYBORG_INT
-
-#ifdef DEBUG_SYBORG_INT
-#define DPRINTF(fmt, ...) \
-do { printf("syborg_int: " fmt , ## __VA_ARGS__); } while (0)
-#define BADF(fmt, ...) \
-do { fprintf(stderr, "syborg_int: error: " fmt , ## __VA_ARGS__); \
- exit(1);} while (0)
-#else
-#define DPRINTF(fmt, ...) do {} while(0)
-#define BADF(fmt, ...) \
-do { fprintf(stderr, "syborg_int: error: " fmt , ## __VA_ARGS__);} while (0)
-#endif
-enum {
- INT_ID = 0,
- INT_STATUS = 1, /* number of pending interrupts */
- INT_CURRENT = 2, /* next interrupt to be serviced */
- INT_DISABLE_ALL = 3,
- INT_DISABLE = 4,
- INT_ENABLE = 5,
- INT_TOTAL = 6
-};
-
-typedef struct {
- unsigned level:1;
- unsigned enabled:1;
-} syborg_int_flags;
-
-typedef struct {
- SysBusDevice busdev;
- MemoryRegion iomem;
- int pending_count;
- uint32_t num_irqs;
- syborg_int_flags *flags;
- qemu_irq parent_irq;
-} SyborgIntState;
-
-static void syborg_int_update(SyborgIntState *s)
-{
- DPRINTF("pending %d\n", s->pending_count);
- qemu_set_irq(s->parent_irq, s->pending_count > 0);
-}
-
-static void syborg_int_set_irq(void *opaque, int irq, int level)
-{
- SyborgIntState *s = (SyborgIntState *)opaque;
-
- if (s->flags[irq].level == level)
- return;
-
- s->flags[irq].level = level;
- if (s->flags[irq].enabled) {
- if (level)
- s->pending_count++;
- else
- s->pending_count--;
- syborg_int_update(s);
- }
-}
-
-static uint64_t syborg_int_read(void *opaque, target_phys_addr_t offset,
- unsigned size)
-{
- SyborgIntState *s = (SyborgIntState *)opaque;
- int i;
-
- offset &= 0xfff;
- switch (offset >> 2) {
- case INT_ID:
- return SYBORG_ID_INT;
- case INT_STATUS:
- DPRINTF("read status=%d\n", s->pending_count);
- return s->pending_count;
-
- case INT_CURRENT:
- for (i = 0; i < s->num_irqs; i++) {
- if (s->flags[i].level & s->flags[i].enabled) {
- DPRINTF("read current=%d\n", i);
- return i;
- }
- }
- DPRINTF("read current=none\n");
- return 0xffffffffu;
-
- default:
- cpu_abort(cpu_single_env, "syborg_int_read: Bad offset %x\n",
- (int)offset);
- return 0;
- }
-}
-
-static void syborg_int_write(void *opaque, target_phys_addr_t offset,
- uint64_t value, unsigned size)
-{
- SyborgIntState *s = (SyborgIntState *)opaque;
- int i;
- offset &= 0xfff;
-
- DPRINTF("syborg_int_write offset=%d val=%d\n", (int)offset, (int)value);
- switch (offset >> 2) {
- case INT_DISABLE_ALL:
- s->pending_count = 0;
- for (i = 0; i < s->num_irqs; i++)
- s->flags[i].enabled = 0;
- break;
-
- case INT_DISABLE:
- if (value >= s->num_irqs)
- break;
- if (s->flags[value].enabled) {
- if (s->flags[value].enabled)
- s->pending_count--;
- s->flags[value].enabled = 0;
- }
- break;
-
- case INT_ENABLE:
- if (value >= s->num_irqs)
- break;
- if (!(s->flags[value].enabled)) {
- if(s->flags[value].level)
- s->pending_count++;
- s->flags[value].enabled = 1;
- }
- break;
-
- default:
- cpu_abort(cpu_single_env, "syborg_int_write: Bad offset %x\n",
- (int)offset);
- return;
- }
- syborg_int_update(s);
-}
-
-static const MemoryRegionOps syborg_int_ops = {
- .read = syborg_int_read,
- .write = syborg_int_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static void syborg_int_save(QEMUFile *f, void *opaque)
-{
- SyborgIntState *s = (SyborgIntState *)opaque;
- int i;
-
- qemu_put_be32(f, s->num_irqs);
- qemu_put_be32(f, s->pending_count);
- for (i = 0; i < s->num_irqs; i++) {
- qemu_put_be32(f, s->flags[i].enabled
- | ((unsigned)s->flags[i].level << 1));
- }
-}
-
-static int syborg_int_load(QEMUFile *f, void *opaque, int version_id)
-{
- SyborgIntState *s = (SyborgIntState *)opaque;
- uint32_t val;
- int i;
-
- if (version_id != 1)
- return -EINVAL;
-
- val = qemu_get_be32(f);
- if (val != s->num_irqs)
- return -EINVAL;
- s->pending_count = qemu_get_be32(f);
- for (i = 0; i < s->num_irqs; i++) {
- val = qemu_get_be32(f);
- s->flags[i].enabled = val & 1;
- s->flags[i].level = (val >> 1) & 1;
- }
- return 0;
-}
-
-static int syborg_int_init(SysBusDevice *dev)
-{
- SyborgIntState *s = FROM_SYSBUS(SyborgIntState, dev);
-
- sysbus_init_irq(dev, &s->parent_irq);
- qdev_init_gpio_in(&dev->qdev, syborg_int_set_irq, s->num_irqs);
- memory_region_init_io(&s->iomem, &syborg_int_ops, s,
- "interrupt", 0x1000);
- sysbus_init_mmio(dev, &s->iomem);
- s->flags = g_malloc0(s->num_irqs * sizeof(syborg_int_flags));
-
- register_savevm(&dev->qdev, "syborg_int", -1, 1, syborg_int_save,
- syborg_int_load, s);
- return 0;
-}
-
-static SysBusDeviceInfo syborg_int_info = {
- .init = syborg_int_init,
- .qdev.name = "syborg,interrupt",
- .qdev.size = sizeof(SyborgIntState),
- .qdev.props = (Property[]) {
- DEFINE_PROP_UINT32("num-interrupts", SyborgIntState, num_irqs, 64),
- DEFINE_PROP_END_OF_LIST(),
- }
-};
-
-static void syborg_interrupt_register_devices(void)
-{
- sysbus_register_withprop(&syborg_int_info);
-}
-
-device_init(syborg_interrupt_register_devices)
diff --git a/hw/syborg_keyboard.c b/hw/syborg_keyboard.c
deleted file mode 100644
index 942a7dc800..0000000000
--- a/hw/syborg_keyboard.c
+++ /dev/null
@@ -1,215 +0,0 @@
-/*
- * Syborg keyboard controller.
- *
- * Copyright (c) 2008 CodeSourcery
- *
- * 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 "sysbus.h"
-#include "console.h"
-#include "syborg.h"
-
-//#define DEBUG_SYBORG_KEYBOARD
-
-#ifdef DEBUG_SYBORG_KEYBOARD
-#define DPRINTF(fmt, ...) \
-do { printf("syborg_keyboard: " fmt , ##args); } while (0)
-#define BADF(fmt, ...) \
-do { fprintf(stderr, "syborg_keyboard: error: " fmt , ## __VA_ARGS__); \
- exit(1);} while (0)
-#else
-#define DPRINTF(fmt, ...) do {} while(0)
-#define BADF(fmt, ...) \
-do { fprintf(stderr, "syborg_keyboard: error: " fmt , ## __VA_ARGS__); \
-} while (0)
-#endif
-
-enum {
- KBD_ID = 0,
- KBD_DATA = 1,
- KBD_FIFO_COUNT = 2,
- KBD_INT_ENABLE = 3,
- KBD_FIFO_SIZE = 4
-};
-
-typedef struct {
- SysBusDevice busdev;
- MemoryRegion iomem;
- uint32_t int_enabled;
- int extension_bit;
- uint32_t fifo_size;
- uint32_t *key_fifo;
- uint32_t read_pos, read_count;
- qemu_irq irq;
-} SyborgKeyboardState;
-
-static void syborg_keyboard_update(SyborgKeyboardState *s)
-{
- int level = s->read_count && s->int_enabled;
- DPRINTF("Update IRQ %d\n", level);
- qemu_set_irq(s->irq, level);
-}
-
-static uint64_t syborg_keyboard_read(void *opaque, target_phys_addr_t offset,
- unsigned size)
-{
- SyborgKeyboardState *s = (SyborgKeyboardState *)opaque;
- int c;
-
- DPRINTF("reg read %d\n", (int)offset);
- offset &= 0xfff;
- switch (offset >> 2) {
- case KBD_ID:
- return SYBORG_ID_KEYBOARD;
- case KBD_FIFO_COUNT:
- return s->read_count;
- case KBD_DATA:
- if (s->read_count == 0) {
- c = -1;
- DPRINTF("FIFO underflow\n");
- } else {
- c = s->key_fifo[s->read_pos];
- DPRINTF("FIFO read 0x%x\n", c);
- s->read_count--;
- s->read_pos++;
- if (s->read_pos == s->fifo_size)
- s->read_pos = 0;
- }
- syborg_keyboard_update(s);
- return c;
- case KBD_INT_ENABLE:
- return s->int_enabled;
- case KBD_FIFO_SIZE:
- return s->fifo_size;
- default:
- cpu_abort(cpu_single_env, "syborg_keyboard_read: Bad offset %x\n",
- (int)offset);
- return 0;
- }
-}
-
-static void syborg_keyboard_write(void *opaque, target_phys_addr_t offset,
- uint64_t value, unsigned size)
-{
- SyborgKeyboardState *s = (SyborgKeyboardState *)opaque;
-
- DPRINTF("reg write %d\n", (int)offset);
- offset &= 0xfff;
- switch (offset >> 2) {
- case KBD_INT_ENABLE:
- s->int_enabled = value;
- syborg_keyboard_update(s);
- break;
- default:
- cpu_abort(cpu_single_env, "syborg_keyboard_write: Bad offset %x\n",
- (int)offset);
- }
-}
-
-static const MemoryRegionOps syborg_keyboard_ops = {
- .read = syborg_keyboard_read,
- .write = syborg_keyboard_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static void syborg_keyboard_event(void *opaque, int keycode)
-{
- SyborgKeyboardState *s = (SyborgKeyboardState *)opaque;
- int slot;
- uint32_t val;
-
- /* Strip off 0xe0 prefixes and reconstruct the full scancode. */
- if (keycode == 0xe0 && !s->extension_bit) {
- DPRINTF("Extension bit\n");
- s->extension_bit = 0x80;
- return;
- }
- val = (keycode & 0x7f) | s->extension_bit;
- if (keycode & 0x80)
- val |= 0x80000000u;
- s->extension_bit = 0;
-
- DPRINTF("FIFO push 0x%x\n", val);
- slot = s->read_pos + s->read_count;
- if (slot >= s->fifo_size)
- slot -= s->fifo_size;
-
- if (s->read_count < s->fifo_size) {
- s->read_count++;
- s->key_fifo[slot] = val;
- } else {
- fprintf(stderr, "syborg_keyboard error! FIFO overflow\n");
- }
-
- syborg_keyboard_update(s);
-}
-
-static const VMStateDescription vmstate_syborg_keyboard = {
- .name = "syborg_keyboard",
- .version_id = 1,
- .minimum_version_id = 1,
- .minimum_version_id_old = 1,
- .fields = (VMStateField[]) {
- VMSTATE_UINT32_EQUAL(fifo_size, SyborgKeyboardState),
- VMSTATE_UINT32(int_enabled, SyborgKeyboardState),
- VMSTATE_UINT32(read_pos, SyborgKeyboardState),
- VMSTATE_UINT32(read_count, SyborgKeyboardState),
- VMSTATE_VARRAY_UINT32(key_fifo, SyborgKeyboardState, fifo_size, 1,
- vmstate_info_uint32, uint32),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static int syborg_keyboard_init(SysBusDevice *dev)
-{
- SyborgKeyboardState *s = FROM_SYSBUS(SyborgKeyboardState, dev);
-
- sysbus_init_irq(dev, &s->irq);
- memory_region_init_io(&s->iomem, &syborg_keyboard_ops, s,
- "keyboard", 0x1000);
- sysbus_init_mmio(dev, &s->iomem);
- if (s->fifo_size <= 0) {
- fprintf(stderr, "syborg_keyboard: fifo too small\n");
- s->fifo_size = 16;
- }
- s->key_fifo = g_malloc0(s->fifo_size * sizeof(s->key_fifo[0]));
-
- qemu_add_kbd_event_handler(syborg_keyboard_event, s);
-
- vmstate_register(&dev->qdev, -1, &vmstate_syborg_keyboard, s);
- return 0;
-}
-
-static SysBusDeviceInfo syborg_keyboard_info = {
- .init = syborg_keyboard_init,
- .qdev.name = "syborg,keyboard",
- .qdev.size = sizeof(SyborgKeyboardState),
- .qdev.props = (Property[]) {
- DEFINE_PROP_UINT32("fifo-size", SyborgKeyboardState, fifo_size, 16),
- DEFINE_PROP_END_OF_LIST(),
- }
-};
-
-static void syborg_keyboard_register_devices(void)
-{
- sysbus_register_withprop(&syborg_keyboard_info);
-}
-
-device_init(syborg_keyboard_register_devices)
diff --git a/hw/syborg_pointer.c b/hw/syborg_pointer.c
deleted file mode 100644
index bb75fa42c8..0000000000
--- a/hw/syborg_pointer.c
+++ /dev/null
@@ -1,220 +0,0 @@
-/*
- * Syborg pointing device (mouse/touchscreen)
- *
- * Copyright (c) 2008 CodeSourcery
- *
- * 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 "sysbus.h"
-#include "console.h"
-#include "syborg.h"
-
-enum {
- POINTER_ID = 0,
- POINTER_LATCH = 1,
- POINTER_FIFO_COUNT = 2,
- POINTER_X = 3,
- POINTER_Y = 4,
- POINTER_Z = 5,
- POINTER_BUTTONS = 6,
- POINTER_INT_ENABLE = 7,
- POINTER_FIFO_SIZE = 8
-};
-
-typedef struct {
- int x, y, z, pointer_buttons;
-} event_data;
-
-typedef struct {
- SysBusDevice busdev;
- MemoryRegion iomem;
- int int_enabled;
- uint32_t fifo_size;
- event_data *event_fifo;
- int read_pos, read_count;
- qemu_irq irq;
- uint32_t absolute;
-} SyborgPointerState;
-
-static void syborg_pointer_update(SyborgPointerState *s)
-{
- qemu_set_irq(s->irq, s->read_count && s->int_enabled);
-}
-
-static uint64_t syborg_pointer_read(void *opaque, target_phys_addr_t offset,
- unsigned size)
-{
- SyborgPointerState *s = (SyborgPointerState *)opaque;
-
- offset &= 0xfff;
- switch (offset >> 2) {
- case POINTER_ID:
- return s->absolute ? SYBORG_ID_TOUCHSCREEN : SYBORG_ID_MOUSE;
- case POINTER_FIFO_COUNT:
- return s->read_count;
- case POINTER_X:
- return s->event_fifo[s->read_pos].x;
- case POINTER_Y:
- return s->event_fifo[s->read_pos].y;
- case POINTER_Z:
- return s->event_fifo[s->read_pos].z;
- case POINTER_BUTTONS:
- return s->event_fifo[s->read_pos].pointer_buttons;
- case POINTER_INT_ENABLE:
- return s->int_enabled;
- case POINTER_FIFO_SIZE:
- return s->fifo_size;
- default:
- cpu_abort(cpu_single_env, "syborg_pointer_read: Bad offset %x\n",
- (int)offset);
- return 0;
- }
-}
-
-static void syborg_pointer_write(void *opaque, target_phys_addr_t offset,
- uint64_t value, unsigned size)
-{
- SyborgPointerState *s = (SyborgPointerState *)opaque;
-
- offset &= 0xfff;
- switch (offset >> 2) {
- case POINTER_LATCH:
- if (s->read_count > 0) {
- s->read_count--;
- if (++s->read_pos == s->fifo_size)
- s->read_pos = 0;
- }
- break;
- case POINTER_INT_ENABLE:
- s->int_enabled = value;
- break;
- default:
- cpu_abort(cpu_single_env, "syborg_pointer_write: Bad offset %x\n",
- (int)offset);
- }
- syborg_pointer_update(s);
-}
-
-static const MemoryRegionOps syborg_pointer_ops = {
- .read = syborg_pointer_read,
- .write = syborg_pointer_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static void syborg_pointer_event(void *opaque, int dx, int dy, int dz,
- int buttons_state)
-{
- SyborgPointerState *s = (SyborgPointerState *)opaque;
- int slot = s->read_pos + s->read_count;
-
- /* This first FIFO entry is used to store current register state. */
- if (s->read_count < s->fifo_size - 1) {
- s->read_count++;
- slot++;
- }
-
- if (slot >= s->fifo_size)
- slot -= s->fifo_size;
-
- if (s->read_count == s->fifo_size && !s->absolute) {
- /* Merge existing entries. */
- s->event_fifo[slot].x += dx;
- s->event_fifo[slot].y += dy;
- s->event_fifo[slot].z += dz;
- } else {
- s->event_fifo[slot].x = dx;
- s->event_fifo[slot].y = dy;
- s->event_fifo[slot].z = dz;
- }
- s->event_fifo[slot].pointer_buttons = buttons_state;
-
- syborg_pointer_update(s);
-}
-
-static const VMStateDescription vmstate_event_data = {
- .name = "dbma_channel",
- .version_id = 0,
- .minimum_version_id = 0,
- .minimum_version_id_old = 0,
- .fields = (VMStateField[]) {
- VMSTATE_INT32(x, event_data),
- VMSTATE_INT32(y, event_data),
- VMSTATE_INT32(z, event_data),
- VMSTATE_INT32(pointer_buttons, event_data),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static const VMStateDescription vmstate_syborg_pointer = {
- .name = "syborg_pointer",
- .version_id = 1,
- .minimum_version_id = 1,
- .minimum_version_id_old = 1,
- .fields = (VMStateField[]) {
- VMSTATE_UINT32_EQUAL(fifo_size, SyborgPointerState),
- VMSTATE_UINT32_EQUAL(absolute, SyborgPointerState),
- VMSTATE_INT32(int_enabled, SyborgPointerState),
- VMSTATE_INT32(read_pos, SyborgPointerState),
- VMSTATE_INT32(read_count, SyborgPointerState),
- VMSTATE_STRUCT_VARRAY_UINT32(event_fifo, SyborgPointerState, fifo_size,
- 1, vmstate_event_data, event_data),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static int syborg_pointer_init(SysBusDevice *dev)
-{
- SyborgPointerState *s = FROM_SYSBUS(SyborgPointerState, dev);
-
- sysbus_init_irq(dev, &s->irq);
- memory_region_init_io(&s->iomem, &syborg_pointer_ops, s,
- "pointer", 0x1000);
- sysbus_init_mmio(dev, &s->iomem);
-
- if (s->fifo_size <= 0) {
- fprintf(stderr, "syborg_pointer: fifo too small\n");
- s->fifo_size = 16;
- }
- s->event_fifo = g_malloc0(s->fifo_size * sizeof(s->event_fifo[0]));
-
- qemu_add_mouse_event_handler(syborg_pointer_event, s, s->absolute,
- "Syborg Pointer");
-
- vmstate_register(&dev->qdev, -1, &vmstate_syborg_pointer, s);
- return 0;
-}
-
-static SysBusDeviceInfo syborg_pointer_info = {
- .init = syborg_pointer_init,
- .qdev.name = "syborg,pointer",
- .qdev.size = sizeof(SyborgPointerState),
- .qdev.props = (Property[]) {
- DEFINE_PROP_UINT32("fifo-size", SyborgPointerState, fifo_size, 16),
- DEFINE_PROP_UINT32("absolute", SyborgPointerState, absolute, 1),
- DEFINE_PROP_END_OF_LIST(),
- }
-};
-
-static void syborg_pointer_register_devices(void)
-{
- sysbus_register_withprop(&syborg_pointer_info);
-}
-
-device_init(syborg_pointer_register_devices)
diff --git a/hw/syborg_rtc.c b/hw/syborg_rtc.c
deleted file mode 100644
index b5f34798b6..0000000000
--- a/hw/syborg_rtc.c
+++ /dev/null
@@ -1,134 +0,0 @@
-/*
- * Syborg RTC
- *
- * Copyright (c) 2008 CodeSourcery
- *
- * 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 "sysbus.h"
-#include "qemu-timer.h"
-#include "syborg.h"
-
-enum {
- RTC_ID = 0,
- RTC_LATCH = 1,
- RTC_DATA_LOW = 2,
- RTC_DATA_HIGH = 3
-};
-
-typedef struct {
- SysBusDevice busdev;
- MemoryRegion iomem;
- int64_t offset;
- int64_t data;
- qemu_irq irq;
-} SyborgRTCState;
-
-static uint64_t syborg_rtc_read(void *opaque, target_phys_addr_t offset,
- unsigned size)
-{
- SyborgRTCState *s = (SyborgRTCState *)opaque;
- offset &= 0xfff;
- switch (offset >> 2) {
- case RTC_ID:
- return SYBORG_ID_RTC;
- case RTC_DATA_LOW:
- return (uint32_t)s->data;
- case RTC_DATA_HIGH:
- return (uint32_t)(s->data >> 32);
- default:
- cpu_abort(cpu_single_env, "syborg_rtc_read: Bad offset %x\n",
- (int)offset);
- return 0;
- }
-}
-
-static void syborg_rtc_write(void *opaque, target_phys_addr_t offset,
- uint64_t value, unsigned size)
-{
- SyborgRTCState *s = (SyborgRTCState *)opaque;
- uint64_t now;
-
- offset &= 0xfff;
- switch (offset >> 2) {
- case RTC_LATCH:
- now = qemu_get_clock_ns(vm_clock);
- if (value >= 4) {
- s->offset = s->data - now;
- } else {
- s->data = now + s->offset;
- while (value) {
- s->data /= 1000;
- value--;
- }
- }
- break;
- case RTC_DATA_LOW:
- s->data = (s->data & ~(uint64_t)0xffffffffu) | value;
- break;
- case RTC_DATA_HIGH:
- s->data = (s->data & 0xffffffffu) | ((uint64_t)value << 32);
- break;
- default:
- cpu_abort(cpu_single_env, "syborg_rtc_write: Bad offset %x\n",
- (int)offset);
- break;
- }
-}
-
-static const MemoryRegionOps syborg_rtc_ops = {
- .read = syborg_rtc_read,
- .write = syborg_rtc_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static const VMStateDescription vmstate_syborg_rtc = {
- .name = "syborg_keyboard",
- .version_id = 1,
- .minimum_version_id = 1,
- .minimum_version_id_old = 1,
- .fields = (VMStateField[]) {
- VMSTATE_INT64(offset, SyborgRTCState),
- VMSTATE_INT64(data, SyborgRTCState),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static int syborg_rtc_init(SysBusDevice *dev)
-{
- SyborgRTCState *s = FROM_SYSBUS(SyborgRTCState, dev);
- struct tm tm;
-
- memory_region_init_io(&s->iomem, &syborg_rtc_ops, s, "rtc", 0x1000);
- sysbus_init_mmio(dev, &s->iomem);
-
- qemu_get_timedate(&tm, 0);
- s->offset = (uint64_t)mktime(&tm) * 1000000000;
-
- vmstate_register(&dev->qdev, -1, &vmstate_syborg_rtc, s);
- return 0;
-}
-
-static void syborg_rtc_register_devices(void)
-{
- sysbus_register_dev("syborg,rtc", sizeof(SyborgRTCState), syborg_rtc_init);
-}
-
-device_init(syborg_rtc_register_devices)
diff --git a/hw/syborg_serial.c b/hw/syborg_serial.c
deleted file mode 100644
index 6f339fa7a6..0000000000
--- a/hw/syborg_serial.c
+++ /dev/null
@@ -1,329 +0,0 @@
-/*
- * Syborg serial port
- *
- * Copyright (c) 2008 CodeSourcery
- *
- * 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 "sysbus.h"
-#include "qemu-char.h"
-#include "syborg.h"
-
-//#define DEBUG_SYBORG_SERIAL
-
-#ifdef DEBUG_SYBORG_SERIAL
-#define DPRINTF(fmt, ...) \
-do { printf("syborg_serial: " fmt , ##args); } while (0)
-#define BADF(fmt, ...) \
-do { fprintf(stderr, "syborg_serial: error: " fmt , ## __VA_ARGS__); \
- exit(1);} while (0)
-#else
-#define DPRINTF(fmt, ...) do {} while(0)
-#define BADF(fmt, ...) \
-do { fprintf(stderr, "syborg_serial: error: " fmt , ## __VA_ARGS__);} while (0)
-#endif
-
-enum {
- SERIAL_ID = 0,
- SERIAL_DATA = 1,
- SERIAL_FIFO_COUNT = 2,
- SERIAL_INT_ENABLE = 3,
- SERIAL_DMA_TX_ADDR = 4,
- SERIAL_DMA_TX_COUNT = 5, /* triggers dma */
- SERIAL_DMA_RX_ADDR = 6,
- SERIAL_DMA_RX_COUNT = 7, /* triggers dma */
- SERIAL_FIFO_SIZE = 8
-};
-
-#define SERIAL_INT_FIFO (1u << 0)
-#define SERIAL_INT_DMA_TX (1u << 1)
-#define SERIAL_INT_DMA_RX (1u << 2)
-
-typedef struct {
- SysBusDevice busdev;
- MemoryRegion iomem;
- uint32_t int_enable;
- uint32_t fifo_size;
- uint32_t *read_fifo;
- int read_pos;
- int read_count;
- CharDriverState *chr;
- qemu_irq irq;
- uint32_t dma_tx_ptr;
- uint32_t dma_rx_ptr;
- uint32_t dma_rx_size;
-} SyborgSerialState;
-
-static void syborg_serial_update(SyborgSerialState *s)
-{
- int level;
- level = 0;
- if ((s->int_enable & SERIAL_INT_FIFO) && s->read_count)
- level = 1;
- if (s->int_enable & SERIAL_INT_DMA_TX)
- level = 1;
- if ((s->int_enable & SERIAL_INT_DMA_RX) && s->dma_rx_size == 0)
- level = 1;
-
- qemu_set_irq(s->irq, level);
-}
-
-static uint32_t fifo_pop(SyborgSerialState *s)
-{
- const uint32_t c = s->read_fifo[s->read_pos];
- s->read_count--;
- s->read_pos++;
- if (s->read_pos == s->fifo_size)
- s->read_pos = 0;
-
- DPRINTF("FIFO pop %x (%d)\n", c, s->read_count);
- return c;
-}
-
-static void fifo_push(SyborgSerialState *s, uint32_t new_value)
-{
- int slot;
-
- DPRINTF("FIFO push %x (%d)\n", new_value, s->read_count);
- slot = s->read_pos + s->read_count;
- if (slot >= s->fifo_size)
- slot -= s->fifo_size;
- s->read_fifo[slot] = new_value;
- s->read_count++;
-}
-
-static void do_dma_tx(SyborgSerialState *s, uint32_t count)
-{
- unsigned char ch;
-
- if (count == 0)
- return;
-
- if (s->chr != NULL) {
- /* optimize later. Now, 1 byte per iteration */
- while (count--) {
- cpu_physical_memory_read(s->dma_tx_ptr, &ch, 1);
- qemu_chr_fe_write(s->chr, &ch, 1);
- s->dma_tx_ptr++;
- }
- } else {
- s->dma_tx_ptr += count;
- }
- /* QEMU char backends do not have a nonblocking mode, so we transmit all
- the data immediately and the interrupt status will be unchanged. */
-}
-
-/* Initiate RX DMA, and transfer data from the FIFO. */
-static void dma_rx_start(SyborgSerialState *s, uint32_t len)
-{
- uint32_t dest;
- unsigned char ch;
-
- dest = s->dma_rx_ptr;
- if (s->read_count < len) {
- s->dma_rx_size = len - s->read_count;
- len = s->read_count;
- } else {
- s->dma_rx_size = 0;
- }
-
- while (len--) {
- ch = fifo_pop(s);
- cpu_physical_memory_write(dest, &ch, 1);
- dest++;
- }
- s->dma_rx_ptr = dest;
- syborg_serial_update(s);
-}
-
-static uint64_t syborg_serial_read(void *opaque, target_phys_addr_t offset,
- unsigned size)
-{
- SyborgSerialState *s = (SyborgSerialState *)opaque;
- uint32_t c;
-
- offset &= 0xfff;
- DPRINTF("read 0x%x\n", (int)offset);
- switch(offset >> 2) {
- case SERIAL_ID:
- return SYBORG_ID_SERIAL;
- case SERIAL_DATA:
- if (s->read_count > 0)
- c = fifo_pop(s);
- else
- c = -1;
- syborg_serial_update(s);
- return c;
- case SERIAL_FIFO_COUNT:
- return s->read_count;
- case SERIAL_INT_ENABLE:
- return s->int_enable;
- case SERIAL_DMA_TX_ADDR:
- return s->dma_tx_ptr;
- case SERIAL_DMA_TX_COUNT:
- return 0;
- case SERIAL_DMA_RX_ADDR:
- return s->dma_rx_ptr;
- case SERIAL_DMA_RX_COUNT:
- return s->dma_rx_size;
- case SERIAL_FIFO_SIZE:
- return s->fifo_size;
-
- default:
- cpu_abort(cpu_single_env, "syborg_serial_read: Bad offset %x\n",
- (int)offset);
- return 0;
- }
-}
-
-static void syborg_serial_write(void *opaque, target_phys_addr_t offset,
- uint64_t value, unsigned size)
-{
- SyborgSerialState *s = (SyborgSerialState *)opaque;
- unsigned char ch;
-
- offset &= 0xfff;
- DPRINTF("Write 0x%x=0x%x\n", (int)offset, value);
- switch (offset >> 2) {
- case SERIAL_DATA:
- ch = value;
- if (s->chr)
- qemu_chr_fe_write(s->chr, &ch, 1);
- break;
- case SERIAL_INT_ENABLE:
- s->int_enable = value;
- syborg_serial_update(s);
- break;
- case SERIAL_DMA_TX_ADDR:
- s->dma_tx_ptr = value;
- break;
- case SERIAL_DMA_TX_COUNT:
- do_dma_tx(s, value);
- break;
- case SERIAL_DMA_RX_ADDR:
- /* For safety, writes to this register cancel any pending DMA. */
- s->dma_rx_size = 0;
- s->dma_rx_ptr = value;
- break;
- case SERIAL_DMA_RX_COUNT:
- dma_rx_start(s, value);
- break;
- default:
- cpu_abort(cpu_single_env, "syborg_serial_write: Bad offset %x\n",
- (int)offset);
- break;
- }
-}
-
-static int syborg_serial_can_receive(void *opaque)
-{
- SyborgSerialState *s = (SyborgSerialState *)opaque;
-
- if (s->dma_rx_size)
- return s->dma_rx_size;
- return s->fifo_size - s->read_count;
-}
-
-static void syborg_serial_receive(void *opaque, const uint8_t *buf, int size)
-{
- SyborgSerialState *s = (SyborgSerialState *)opaque;
-
- if (s->dma_rx_size) {
- /* Place it in the DMA buffer. */
- cpu_physical_memory_write(s->dma_rx_ptr, buf, size);
- s->dma_rx_size -= size;
- s->dma_rx_ptr += size;
- } else {
- while (size--)
- fifo_push(s, *buf);
- }
-
- syborg_serial_update(s);
-}
-
-static void syborg_serial_event(void *opaque, int event)
-{
- /* TODO: Report BREAK events? */
-}
-
-static const MemoryRegionOps syborg_serial_ops = {
- .read = syborg_serial_read,
- .write = syborg_serial_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static const VMStateDescription vmstate_syborg_serial = {
- .name = "syborg_serial",
- .version_id = 1,
- .minimum_version_id = 1,
- .minimum_version_id_old = 1,
- .fields = (VMStateField[]) {
- VMSTATE_UINT32_EQUAL(fifo_size, SyborgSerialState),
- VMSTATE_UINT32(int_enable, SyborgSerialState),
- VMSTATE_INT32(read_pos, SyborgSerialState),
- VMSTATE_INT32(read_count, SyborgSerialState),
- VMSTATE_UINT32(dma_tx_ptr, SyborgSerialState),
- VMSTATE_UINT32(dma_rx_ptr, SyborgSerialState),
- VMSTATE_UINT32(dma_rx_size, SyborgSerialState),
- VMSTATE_VARRAY_UINT32(read_fifo, SyborgSerialState, fifo_size, 1,
- vmstate_info_uint32, uint32),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static int syborg_serial_init(SysBusDevice *dev)
-{
- SyborgSerialState *s = FROM_SYSBUS(SyborgSerialState, dev);
-
- sysbus_init_irq(dev, &s->irq);
- memory_region_init_io(&s->iomem, &syborg_serial_ops, s,
- "serial", 0x1000);
- sysbus_init_mmio(dev, &s->iomem);
- s->chr = qdev_init_chardev(&dev->qdev);
- if (s->chr) {
- qemu_chr_add_handlers(s->chr, syborg_serial_can_receive,
- syborg_serial_receive, syborg_serial_event, s);
- }
- if (s->fifo_size <= 0) {
- fprintf(stderr, "syborg_serial: fifo too small\n");
- s->fifo_size = 16;
- }
- s->read_fifo = g_malloc0(s->fifo_size * sizeof(s->read_fifo[0]));
-
- return 0;
-}
-
-static SysBusDeviceInfo syborg_serial_info = {
- .init = syborg_serial_init,
- .qdev.name = "syborg,serial",
- .qdev.size = sizeof(SyborgSerialState),
- .qdev.vmsd = &vmstate_syborg_serial,
- .qdev.props = (Property[]) {
- DEFINE_PROP_UINT32("fifo-size", SyborgSerialState, fifo_size, 16),
- DEFINE_PROP_END_OF_LIST(),
- }
-};
-
-static void syborg_serial_register_devices(void)
-{
- sysbus_register_withprop(&syborg_serial_info);
-}
-
-device_init(syborg_serial_register_devices)
diff --git a/hw/syborg_timer.c b/hw/syborg_timer.c
deleted file mode 100644
index 1498f01a62..0000000000
--- a/hw/syborg_timer.c
+++ /dev/null
@@ -1,224 +0,0 @@
-/*
- * Syborg Interval Timer.
- *
- * Copyright (c) 2008 CodeSourcery
- *
- * 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 "sysbus.h"
-#include "qemu-timer.h"
-#include "syborg.h"
-
-//#define DEBUG_SYBORG_TIMER
-
-#ifdef DEBUG_SYBORG_TIMER
-#define DPRINTF(fmt, ...) \
-do { printf("syborg_timer: " fmt , ##args); } while (0)
-#define BADF(fmt, ...) \
-do { fprintf(stderr, "syborg_timer: error: " fmt , ## __VA_ARGS__); \
- exit(1);} while (0)
-#else
-#define DPRINTF(fmt, ...) do {} while(0)
-#define BADF(fmt, ...) \
-do { fprintf(stderr, "syborg_timer: error: " fmt , ## __VA_ARGS__);} while (0)
-#endif
-
-enum {
- TIMER_ID = 0,
- TIMER_RUNNING = 1,
- TIMER_ONESHOT = 2,
- TIMER_LIMIT = 3,
- TIMER_VALUE = 4,
- TIMER_INT_ENABLE = 5,
- TIMER_INT_STATUS = 6,
- TIMER_FREQ = 7
-};
-
-typedef struct {
- SysBusDevice busdev;
- MemoryRegion iomem;
- ptimer_state *timer;
- int running;
- int oneshot;
- uint32_t limit;
- uint32_t freq;
- uint32_t int_level;
- uint32_t int_enabled;
- qemu_irq irq;
-} SyborgTimerState;
-
-static void syborg_timer_update(SyborgTimerState *s)
-{
- /* Update interrupt. */
- if (s->int_level && s->int_enabled) {
- qemu_irq_raise(s->irq);
- } else {
- qemu_irq_lower(s->irq);
- }
-}
-
-static void syborg_timer_tick(void *opaque)
-{
- SyborgTimerState *s = (SyborgTimerState *)opaque;
- //DPRINTF("Timer Tick\n");
- s->int_level = 1;
- if (s->oneshot)
- s->running = 0;
- syborg_timer_update(s);
-}
-
-static uint64_t syborg_timer_read(void *opaque, target_phys_addr_t offset,
- unsigned size)
-{
- SyborgTimerState *s = (SyborgTimerState *)opaque;
-
- DPRINTF("Reg read %d\n", (int)offset);
- offset &= 0xfff;
- switch (offset >> 2) {
- case TIMER_ID:
- return SYBORG_ID_TIMER;
- case TIMER_RUNNING:
- return s->running;
- case TIMER_ONESHOT:
- return s->oneshot;
- case TIMER_LIMIT:
- return s->limit;
- case TIMER_VALUE:
- return ptimer_get_count(s->timer);
- case TIMER_INT_ENABLE:
- return s->int_enabled;
- case TIMER_INT_STATUS:
- return s->int_level;
- case TIMER_FREQ:
- return s->freq;
- default:
- cpu_abort(cpu_single_env, "syborg_timer_read: Bad offset %x\n",
- (int)offset);
- return 0;
- }
-}
-
-static void syborg_timer_write(void *opaque, target_phys_addr_t offset,
- uint64_t value, unsigned size)
-{
- SyborgTimerState *s = (SyborgTimerState *)opaque;
-
- DPRINTF("Reg write %d\n", (int)offset);
- offset &= 0xfff;
- switch (offset >> 2) {
- case TIMER_RUNNING:
- if (value == s->running)
- break;
- s->running = value;
- if (value) {
- ptimer_run(s->timer, s->oneshot);
- } else {
- ptimer_stop(s->timer);
- }
- break;
- case TIMER_ONESHOT:
- if (s->running) {
- ptimer_stop(s->timer);
- }
- s->oneshot = value;
- if (s->running) {
- ptimer_run(s->timer, s->oneshot);
- }
- break;
- case TIMER_LIMIT:
- s->limit = value;
- ptimer_set_limit(s->timer, value, 1);
- break;
- case TIMER_VALUE:
- ptimer_set_count(s->timer, value);
- break;
- case TIMER_INT_ENABLE:
- s->int_enabled = value;
- syborg_timer_update(s);
- break;
- case TIMER_INT_STATUS:
- s->int_level &= ~value;
- syborg_timer_update(s);
- break;
- default:
- cpu_abort(cpu_single_env, "syborg_timer_write: Bad offset %x\n",
- (int)offset);
- break;
- }
-}
-
-static const MemoryRegionOps syborg_timer_ops = {
- .read = syborg_timer_read,
- .write = syborg_timer_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static const VMStateDescription vmstate_syborg_timer = {
- .name = "syborg_timer",
- .version_id = 1,
- .minimum_version_id = 1,
- .minimum_version_id_old = 1,
- .fields = (VMStateField[]) {
- VMSTATE_INT32(running, SyborgTimerState),
- VMSTATE_INT32(oneshot, SyborgTimerState),
- VMSTATE_UINT32(limit, SyborgTimerState),
- VMSTATE_UINT32(int_level, SyborgTimerState),
- VMSTATE_UINT32(int_enabled, SyborgTimerState),
- VMSTATE_PTIMER(timer, SyborgTimerState),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static int syborg_timer_init(SysBusDevice *dev)
-{
- SyborgTimerState *s = FROM_SYSBUS(SyborgTimerState, dev);
- QEMUBH *bh;
-
- if (s->freq == 0) {
- fprintf(stderr, "syborg_timer: Zero/unset frequency\n");
- exit(1);
- }
- sysbus_init_irq(dev, &s->irq);
- memory_region_init_io(&s->iomem, &syborg_timer_ops, s, "timer", 0x1000);
- sysbus_init_mmio(dev, &s->iomem);
-
- bh = qemu_bh_new(syborg_timer_tick, s);
- s->timer = ptimer_init(bh);
- ptimer_set_freq(s->timer, s->freq);
- vmstate_register(&dev->qdev, -1, &vmstate_syborg_timer, s);
- return 0;
-}
-
-static SysBusDeviceInfo syborg_timer_info = {
- .init = syborg_timer_init,
- .qdev.name = "syborg,timer",
- .qdev.size = sizeof(SyborgTimerState),
- .qdev.props = (Property[]) {
- DEFINE_PROP_UINT32("frequency",SyborgTimerState, freq, 0),
- DEFINE_PROP_END_OF_LIST(),
- }
-};
-
-static void syborg_timer_register_devices(void)
-{
- sysbus_register_withprop(&syborg_timer_info);
-}
-
-device_init(syborg_timer_register_devices)
diff --git a/hw/syborg_virtio.c b/hw/syborg_virtio.c
deleted file mode 100644
index 96a0ee651f..0000000000
--- a/hw/syborg_virtio.c
+++ /dev/null
@@ -1,307 +0,0 @@
-/*
- * Virtio Syborg bindings
- *
- * Copyright (c) 2009 CodeSourcery
- *
- * 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 "syborg.h"
-#include "sysbus.h"
-#include "virtio.h"
-#include "virtio-net.h"
-
-//#define DEBUG_SYBORG_VIRTIO
-
-#ifdef DEBUG_SYBORG_VIRTIO
-#define DPRINTF(fmt, ...) \
-do { printf("syborg_virtio: " fmt , ## __VA_ARGS__); } while (0)
-#define BADF(fmt, ...) \
-do { fprintf(stderr, "syborg_virtio: error: " fmt , ## __VA_ARGS__); \
- exit(1);} while (0)
-#else
-#define DPRINTF(fmt, ...) do {} while(0)
-#define BADF(fmt, ...) \
-do { fprintf(stderr, "syborg_virtio: error: " fmt , ## __VA_ARGS__);} while (0)
-#endif
-
-enum {
- SYBORG_VIRTIO_ID = 0,
- SYBORG_VIRTIO_DEVTYPE = 1,
- SYBORG_VIRTIO_HOST_FEATURES = 2,
- SYBORG_VIRTIO_GUEST_FEATURES = 3,
- SYBORG_VIRTIO_QUEUE_BASE = 4,
- SYBORG_VIRTIO_QUEUE_NUM = 5,
- SYBORG_VIRTIO_QUEUE_SEL = 6,
- SYBORG_VIRTIO_QUEUE_NOTIFY = 7,
- SYBORG_VIRTIO_STATUS = 8,
- SYBORG_VIRTIO_INT_ENABLE = 9,
- SYBORG_VIRTIO_INT_STATUS = 10
-};
-
-#define SYBORG_VIRTIO_CONFIG 0x100
-
-/* Device independent interface. */
-
-typedef struct {
- SysBusDevice busdev;
- VirtIODevice *vdev;
- MemoryRegion iomem;
- qemu_irq irq;
- uint32_t int_enable;
- uint32_t id;
- NICConf nic;
- uint32_t host_features;
- virtio_net_conf net;
-} SyborgVirtIOProxy;
-
-static uint32_t syborg_virtio_readl(void *opaque, target_phys_addr_t offset)
-{
- SyborgVirtIOProxy *s = opaque;
- VirtIODevice *vdev = s->vdev;
- uint32_t ret;
-
- DPRINTF("readl 0x%x\n", (int)offset);
- if (offset >= SYBORG_VIRTIO_CONFIG) {
- return virtio_config_readl(vdev, offset - SYBORG_VIRTIO_CONFIG);
- }
- switch(offset >> 2) {
- case SYBORG_VIRTIO_ID:
- ret = SYBORG_ID_VIRTIO;
- break;
- case SYBORG_VIRTIO_DEVTYPE:
- ret = s->id;
- break;
- case SYBORG_VIRTIO_HOST_FEATURES:
- ret = s->host_features;
- break;
- case SYBORG_VIRTIO_GUEST_FEATURES:
- ret = vdev->guest_features;
- break;
- case SYBORG_VIRTIO_QUEUE_BASE:
- ret = virtio_queue_get_addr(vdev, vdev->queue_sel);
- break;
- case SYBORG_VIRTIO_QUEUE_NUM:
- ret = virtio_queue_get_num(vdev, vdev->queue_sel);
- break;
- case SYBORG_VIRTIO_QUEUE_SEL:
- ret = vdev->queue_sel;
- break;
- case SYBORG_VIRTIO_STATUS:
- ret = vdev->status;
- break;
- case SYBORG_VIRTIO_INT_ENABLE:
- ret = s->int_enable;
- break;
- case SYBORG_VIRTIO_INT_STATUS:
- ret = vdev->isr;
- break;
- default:
- BADF("Bad read offset 0x%x\n", (int)offset);
- return 0;
- }
- return ret;
-}
-
-static void syborg_virtio_writel(void *opaque, target_phys_addr_t offset,
- uint32_t value)
-{
- SyborgVirtIOProxy *s = opaque;
- VirtIODevice *vdev = s->vdev;
-
- DPRINTF("writel 0x%x = 0x%x\n", (int)offset, value);
- if (offset >= SYBORG_VIRTIO_CONFIG) {
- return virtio_config_writel(vdev, offset - SYBORG_VIRTIO_CONFIG,
- value);
- }
- switch (offset >> 2) {
- case SYBORG_VIRTIO_GUEST_FEATURES:
- virtio_set_features(vdev, value);
- break;
- case SYBORG_VIRTIO_QUEUE_BASE:
- if (value == 0)
- virtio_reset(vdev);
- else
- virtio_queue_set_addr(vdev, vdev->queue_sel, value);
- break;
- case SYBORG_VIRTIO_QUEUE_SEL:
- if (value < VIRTIO_PCI_QUEUE_MAX)
- vdev->queue_sel = value;
- break;
- case SYBORG_VIRTIO_QUEUE_NOTIFY:
- if (value < VIRTIO_PCI_QUEUE_MAX) {
- virtio_queue_notify(vdev, value);
- }
- break;
- case SYBORG_VIRTIO_STATUS:
- virtio_set_status(vdev, value & 0xFF);
- if (vdev->status == 0)
- virtio_reset(vdev);
- break;
- case SYBORG_VIRTIO_INT_ENABLE:
- s->int_enable = value;
- virtio_update_irq(vdev);
- break;
- case SYBORG_VIRTIO_INT_STATUS:
- vdev->isr &= ~value;
- virtio_update_irq(vdev);
- break;
- default:
- BADF("Bad write offset 0x%x\n", (int)offset);
- break;
- }
-}
-
-static uint32_t syborg_virtio_readw(void *opaque, target_phys_addr_t offset)
-{
- SyborgVirtIOProxy *s = opaque;
- VirtIODevice *vdev = s->vdev;
-
- DPRINTF("readw 0x%x\n", (int)offset);
- if (offset >= SYBORG_VIRTIO_CONFIG) {
- return virtio_config_readw(vdev, offset - SYBORG_VIRTIO_CONFIG);
- }
- BADF("Bad halfword read offset 0x%x\n", (int)offset);
- return -1;
-}
-
-static void syborg_virtio_writew(void *opaque, target_phys_addr_t offset,
- uint32_t value)
-{
- SyborgVirtIOProxy *s = opaque;
- VirtIODevice *vdev = s->vdev;
-
- DPRINTF("writew 0x%x = 0x%x\n", (int)offset, value);
- if (offset >= SYBORG_VIRTIO_CONFIG) {
- return virtio_config_writew(vdev, offset - SYBORG_VIRTIO_CONFIG,
- value);
- }
- BADF("Bad halfword write offset 0x%x\n", (int)offset);
-}
-
-static uint32_t syborg_virtio_readb(void *opaque, target_phys_addr_t offset)
-{
- SyborgVirtIOProxy *s = opaque;
- VirtIODevice *vdev = s->vdev;
-
- DPRINTF("readb 0x%x\n", (int)offset);
- if (offset >= SYBORG_VIRTIO_CONFIG) {
- return virtio_config_readb(vdev, offset - SYBORG_VIRTIO_CONFIG);
- }
- BADF("Bad byte read offset 0x%x\n", (int)offset);
- return -1;
-}
-
-static void syborg_virtio_writeb(void *opaque, target_phys_addr_t offset,
- uint32_t value)
-{
- SyborgVirtIOProxy *s = opaque;
- VirtIODevice *vdev = s->vdev;
-
- DPRINTF("writeb 0x%x = 0x%x\n", (int)offset, value);
- if (offset >= SYBORG_VIRTIO_CONFIG) {
- return virtio_config_writeb(vdev, offset - SYBORG_VIRTIO_CONFIG,
- value);
- }
- BADF("Bad byte write offset 0x%x\n", (int)offset);
-}
-
-static const MemoryRegionOps syborg_virtio_ops = {
- .old_mmio = {
- .read = { syborg_virtio_readb, syborg_virtio_readw, syborg_virtio_readl },
- .write = { syborg_virtio_writeb, syborg_virtio_writew, syborg_virtio_writel },
- },
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static void syborg_virtio_update_irq(void *opaque, uint16_t vector)
-{
- SyborgVirtIOProxy *proxy = opaque;
- int level;
-
- level = proxy->int_enable & proxy->vdev->isr;
- DPRINTF("IRQ %d\n", level);
- qemu_set_irq(proxy->irq, level != 0);
-}
-
-static unsigned syborg_virtio_get_features(void *opaque)
-{
- SyborgVirtIOProxy *proxy = opaque;
- return proxy->host_features;
-}
-
-static VirtIOBindings syborg_virtio_bindings = {
- .notify = syborg_virtio_update_irq,
- .get_features = syborg_virtio_get_features,
-};
-
-static int syborg_virtio_init(SyborgVirtIOProxy *proxy, VirtIODevice *vdev)
-{
- proxy->vdev = vdev;
-
- /* Don't support multiple vectors */
- proxy->vdev->nvectors = 0;
- sysbus_init_irq(&proxy->busdev, &proxy->irq);
- memory_region_init_io(&proxy->iomem, &syborg_virtio_ops, proxy,
- "virtio", 0x1000);
- sysbus_init_mmio(&proxy->busdev, &proxy->iomem);
-
- proxy->id = ((uint32_t)0x1af4 << 16) | vdev->device_id;
-
- qemu_register_reset(virtio_reset, vdev);
-
- virtio_bind_device(vdev, &syborg_virtio_bindings, proxy);
- proxy->host_features |= (0x1 << VIRTIO_F_NOTIFY_ON_EMPTY);
- proxy->host_features = vdev->get_features(vdev, proxy->host_features);
- return 0;
-}
-
-/* Device specific bindings. */
-
-static int syborg_virtio_net_init(SysBusDevice *dev)
-{
- VirtIODevice *vdev;
- SyborgVirtIOProxy *proxy = FROM_SYSBUS(SyborgVirtIOProxy, dev);
-
- vdev = virtio_net_init(&dev->qdev, &proxy->nic, &proxy->net);
- return syborg_virtio_init(proxy, vdev);
-}
-
-static SysBusDeviceInfo syborg_virtio_net_info = {
- .init = syborg_virtio_net_init,
- .qdev.name = "syborg,virtio-net",
- .qdev.size = sizeof(SyborgVirtIOProxy),
- .qdev.props = (Property[]) {
- DEFINE_NIC_PROPERTIES(SyborgVirtIOProxy, nic),
- DEFINE_VIRTIO_NET_FEATURES(SyborgVirtIOProxy, host_features),
- DEFINE_PROP_UINT32("x-txtimer", SyborgVirtIOProxy,
- net.txtimer, TX_TIMER_INTERVAL),
- DEFINE_PROP_INT32("x-txburst", SyborgVirtIOProxy,
- net.txburst, TX_BURST),
- DEFINE_PROP_STRING("tx", SyborgVirtIOProxy, net.tx),
- DEFINE_PROP_END_OF_LIST(),
- }
-};
-
-static void syborg_virtio_register_devices(void)
-{
- sysbus_register_withprop(&syborg_virtio_net_info);
-}
-
-device_init(syborg_virtio_register_devices)
diff --git a/hw/usb-ehci.c b/hw/usb-ehci.c
index a946e1d1fd..7c926c0d47 100644
--- a/hw/usb-ehci.c
+++ b/hw/usb-ehci.c
@@ -1109,7 +1109,7 @@ static inline int get_dwords(EHCIState *ehci, uint32_t addr,
int i;
for(i = 0; i < num; i++, buf++, addr += sizeof(*buf)) {
- pci_dma_read(&ehci->dev, addr, (uint8_t *)buf, sizeof(*buf));
+ pci_dma_read(&ehci->dev, addr, buf, sizeof(*buf));
*buf = le32_to_cpu(*buf);
}
@@ -1124,7 +1124,7 @@ static inline int put_dwords(EHCIState *ehci, uint32_t addr,
for(i = 0; i < num; i++, buf++, addr += sizeof(*buf)) {
uint32_t tmp = cpu_to_le32(*buf);
- pci_dma_write(&ehci->dev, addr, (uint8_t *)&tmp, sizeof(tmp));
+ pci_dma_write(&ehci->dev, addr, &tmp, sizeof(tmp));
}
return 1;
@@ -2157,7 +2157,7 @@ static void ehci_advance_periodic_state(EHCIState *ehci)
}
list |= ((ehci->frindex & 0x1ff8) >> 1);
- pci_dma_read(&ehci->dev, list, (uint8_t *) &entry, sizeof entry);
+ pci_dma_read(&ehci->dev, list, &entry, sizeof entry);
entry = le32_to_cpu(entry);
DPRINTF("PERIODIC state adv fr=%d. [%08X] -> %08X\n",
diff --git a/hw/usb-net.c b/hw/usb-net.c
index a8b7c8dd76..f91fa32334 100644
--- a/hw/usb-net.c
+++ b/hw/usb-net.c
@@ -1268,8 +1268,9 @@ static ssize_t usbnet_receive(VLANClientState *nc, const uint8_t *buf, size_t si
if (is_rndis(s)) {
msg = (struct rndis_packet_msg_type *) s->in_buf;
- if (!s->rndis_state == RNDIS_DATA_INITIALIZED)
+ if (s->rndis_state != RNDIS_DATA_INITIALIZED) {
return -1;
+ }
if (size + sizeof(struct rndis_packet_msg_type) > sizeof(s->in_buf))
return -1;
@@ -1302,7 +1303,7 @@ static int usbnet_can_receive(VLANClientState *nc)
{
USBNetState *s = DO_UPCAST(NICState, nc, nc)->opaque;
- if (is_rndis(s) && !s->rndis_state == RNDIS_DATA_INITIALIZED) {
+ if (is_rndis(s) && s->rndis_state != RNDIS_DATA_INITIALIZED) {
return 1;
}
diff --git a/hw/usb-uhci.c b/hw/usb-uhci.c
index f9e3ea5bfc..f8912e2b0b 100644
--- a/hw/usb-uhci.c
+++ b/hw/usb-uhci.c
@@ -876,7 +876,7 @@ static void uhci_async_complete(USBPort *port, USBPacket *packet)
uint32_t link = async->td;
uint32_t int_mask = 0, val;
- pci_dma_read(&s->dev, link & ~0xf, (uint8_t *) &td, sizeof(td));
+ pci_dma_read(&s->dev, link & ~0xf, &td, sizeof(td));
le32_to_cpus(&td.link);
le32_to_cpus(&td.ctrl);
le32_to_cpus(&td.token);
@@ -888,8 +888,7 @@ static void uhci_async_complete(USBPort *port, USBPacket *packet)
/* update the status bits of the TD */
val = cpu_to_le32(td.ctrl);
- pci_dma_write(&s->dev, (link & ~0xf) + 4,
- (const uint8_t *)&val, sizeof(val));
+ pci_dma_write(&s->dev, (link & ~0xf) + 4, &val, sizeof(val));
uhci_async_free(s, async);
} else {
async->done = 1;
@@ -952,7 +951,7 @@ static void uhci_process_frame(UHCIState *s)
DPRINTF("uhci: processing frame %d addr 0x%x\n" , s->frnum, frame_addr);
- pci_dma_read(&s->dev, frame_addr, (uint8_t *)&link, 4);
+ pci_dma_read(&s->dev, frame_addr, &link, 4);
le32_to_cpus(&link);
int_mask = 0;
@@ -976,7 +975,7 @@ static void uhci_process_frame(UHCIState *s)
break;
}
- pci_dma_read(&s->dev, link & ~0xf, (uint8_t *) &qh, sizeof(qh));
+ pci_dma_read(&s->dev, link & ~0xf, &qh, sizeof(qh));
le32_to_cpus(&qh.link);
le32_to_cpus(&qh.el_link);
@@ -996,7 +995,7 @@ static void uhci_process_frame(UHCIState *s)
}
/* TD */
- pci_dma_read(&s->dev, link & ~0xf, (uint8_t *) &td, sizeof(td));
+ pci_dma_read(&s->dev, link & ~0xf, &td, sizeof(td));
le32_to_cpus(&td.link);
le32_to_cpus(&td.ctrl);
le32_to_cpus(&td.token);
@@ -1010,8 +1009,7 @@ static void uhci_process_frame(UHCIState *s)
if (old_td_ctrl != td.ctrl) {
/* update the status bits of the TD */
val = cpu_to_le32(td.ctrl);
- pci_dma_write(&s->dev, (link & ~0xf) + 4,
- (const uint8_t *)&val, sizeof(val));
+ pci_dma_write(&s->dev, (link & ~0xf) + 4, &val, sizeof(val));
}
if (ret < 0) {
@@ -1039,8 +1037,7 @@ static void uhci_process_frame(UHCIState *s)
/* update QH element link */
qh.el_link = link;
val = cpu_to_le32(qh.el_link);
- pci_dma_write(&s->dev, (curr_qh & ~0xf) + 4,
- (const uint8_t *)&val, sizeof(val));
+ pci_dma_write(&s->dev, (curr_qh & ~0xf) + 4, &val, sizeof(val));
if (!depth_first(link)) {
/* done with this QH */
diff --git a/migration-exec.c b/migration-exec.c
index b7b1055e88..e14552ec01 100644
--- a/migration-exec.c
+++ b/migration-exec.c
@@ -50,12 +50,9 @@ static int exec_close(MigrationState *s)
ret = qemu_fclose(s->opaque);
s->opaque = NULL;
s->fd = -1;
- if (ret != -1 &&
- WIFEXITED(ret)
- && WEXITSTATUS(ret) == 0) {
- ret = 0;
- } else {
- ret = -1;
+ if (ret >= 0 && !(WIFEXITED(ret) && WEXITSTATUS(ret) == 0)) {
+ /* close succeeded, but non-zero exit code: */
+ ret = -EIO; /* fake errno value */
}
}
return ret;
diff --git a/migration-tcp.c b/migration-tcp.c
index 5aa742c34b..cf6a9b83d6 100644
--- a/migration-tcp.c
+++ b/migration-tcp.c
@@ -40,12 +40,15 @@ static int socket_write(MigrationState *s, const void * buf, size_t size)
static int tcp_close(MigrationState *s)
{
+ int r = 0;
DPRINTF("tcp_close\n");
if (s->fd != -1) {
- close(s->fd);
+ if (close(s->fd) < 0) {
+ r = -errno;
+ }
s->fd = -1;
}
- return 0;
+ return r;
}
static void tcp_wait_for_connect(void *opaque)
diff --git a/migration-unix.c b/migration-unix.c
index 8596353d7d..dfcf2033c6 100644
--- a/migration-unix.c
+++ b/migration-unix.c
@@ -40,12 +40,15 @@ static int unix_write(MigrationState *s, const void * buf, size_t size)
static int unix_close(MigrationState *s)
{
+ int r = 0;
DPRINTF("unix_close\n");
if (s->fd != -1) {
- close(s->fd);
+ if (close(s->fd) < 0) {
+ r = -errno;
+ }
s->fd = -1;
}
- return 0;
+ return r;
}
static void unix_wait_for_connect(void *opaque)
diff --git a/migration.c b/migration.c
index 8280d7189a..412fdfe5bf 100644
--- a/migration.c
+++ b/migration.c
@@ -174,9 +174,7 @@ static int migrate_fd_cleanup(MigrationState *s)
if (s->file) {
DPRINTF("closing file\n");
- if (qemu_fclose(s->file) != 0) {
- ret = -1;
- }
+ ret = qemu_fclose(s->file);
s->file = NULL;
} else {
if (s->mon) {
@@ -468,37 +466,27 @@ int do_migrate(Monitor *mon, const QDict *qdict, QObject **ret_data)
return 0;
}
-int do_migrate_cancel(Monitor *mon, const QDict *qdict, QObject **ret_data)
+void qmp_migrate_cancel(Error **errp)
{
migrate_fd_cancel(migrate_get_current());
- return 0;
}
-int do_migrate_set_speed(Monitor *mon, const QDict *qdict, QObject **ret_data)
+void qmp_migrate_set_speed(int64_t value, Error **errp)
{
- int64_t d;
MigrationState *s;
- d = qdict_get_int(qdict, "value");
- if (d < 0) {
- d = 0;
+ if (value < 0) {
+ value = 0;
}
s = migrate_get_current();
- s->bandwidth_limit = d;
+ s->bandwidth_limit = value;
qemu_file_set_rate_limit(s->file, s->bandwidth_limit);
-
- return 0;
}
-int do_migrate_set_downtime(Monitor *mon, const QDict *qdict,
- QObject **ret_data)
+void qmp_migrate_set_downtime(double value, Error **errp)
{
- double d;
-
- d = qdict_get_double(qdict, "value") * 1e9;
- d = MAX(0, MIN(UINT64_MAX, d));
- max_downtime = (uint64_t)d;
-
- return 0;
+ value *= 1e9;
+ value = MAX(0, MIN(UINT64_MAX, value));
+ max_downtime = (uint64_t)value;
}
diff --git a/migration.h b/migration.h
index 78a50d31ac..372b066b48 100644
--- a/migration.h
+++ b/migration.h
@@ -42,15 +42,8 @@ int qemu_start_incoming_migration(const char *uri);
int do_migrate(Monitor *mon, const QDict *qdict, QObject **ret_data);
-int do_migrate_cancel(Monitor *mon, const QDict *qdict, QObject **ret_data);
-
-int do_migrate_set_speed(Monitor *mon, const QDict *qdict, QObject **ret_data);
-
uint64_t migrate_max_downtime(void);
-int do_migrate_set_downtime(Monitor *mon, const QDict *qdict,
- QObject **ret_data);
-
void do_info_migrate_print(Monitor *mon, const QObject *data);
void do_info_migrate(Monitor *mon, QObject **ret_data);
diff --git a/monitor.c b/monitor.c
index 1be222ee18..733440115f 100644
--- a/monitor.c
+++ b/monitor.c
@@ -513,10 +513,10 @@ static int do_qmp_capabilities(Monitor *mon, const QDict *params,
static void handle_user_command(Monitor *mon, const char *cmdline);
-static int do_hmp_passthrough(Monitor *mon, const QDict *params,
- QObject **ret_data)
+char *qmp_human_monitor_command(const char *command_line, bool has_cpu_index,
+ int64_t cpu_index, Error **errp)
{
- int ret = 0;
+ char *output = NULL;
Monitor *old_mon, hmp;
CharDriverState mchar;
@@ -527,25 +527,30 @@ static int do_hmp_passthrough(Monitor *mon, const QDict *params,
old_mon = cur_mon;
cur_mon = &hmp;
- if (qdict_haskey(params, "cpu-index")) {
- ret = monitor_set_cpu(qdict_get_int(params, "cpu-index"));
+ if (has_cpu_index) {
+ int ret = monitor_set_cpu(cpu_index);
if (ret < 0) {
cur_mon = old_mon;
- qerror_report(QERR_INVALID_PARAMETER_VALUE, "cpu-index", "a CPU number");
+ error_set(errp, QERR_INVALID_PARAMETER_VALUE, "cpu-index",
+ "a CPU number");
goto out;
}
}
- handle_user_command(&hmp, qdict_get_str(params, "command-line"));
+ handle_user_command(&hmp, command_line);
cur_mon = old_mon;
if (qemu_chr_mem_osize(hmp.chr) > 0) {
- *ret_data = QOBJECT(qemu_chr_mem_to_qs(hmp.chr));
+ QString *str = qemu_chr_mem_to_qs(hmp.chr);
+ output = g_strdup(qstring_get_str(str));
+ QDECREF(str);
+ } else {
+ output = g_strdup("");
}
out:
qemu_chr_close_mem(hmp.chr);
- return ret;
+ return output;
}
static int compare_cmd(const char *name, const char *list)
@@ -1073,65 +1078,6 @@ static void do_singlestep(Monitor *mon, const QDict *qdict)
}
}
-static void encrypted_bdrv_it(void *opaque, BlockDriverState *bs);
-
-struct bdrv_iterate_context {
- Monitor *mon;
- int err;
-};
-
-static void iostatus_bdrv_it(void *opaque, BlockDriverState *bs)
-{
- bdrv_iostatus_reset(bs);
-}
-
-/**
- * do_cont(): Resume emulation.
- */
-static int do_cont(Monitor *mon, const QDict *qdict, QObject **ret_data)
-{
- struct bdrv_iterate_context context = { mon, 0 };
-
- if (runstate_check(RUN_STATE_INMIGRATE)) {
- qerror_report(QERR_MIGRATION_EXPECTED);
- return -1;
- } else if (runstate_check(RUN_STATE_INTERNAL_ERROR) ||
- runstate_check(RUN_STATE_SHUTDOWN)) {
- qerror_report(QERR_RESET_REQUIRED);
- return -1;
- }
-
- bdrv_iterate(iostatus_bdrv_it, NULL);
- bdrv_iterate(encrypted_bdrv_it, &context);
- /* only resume the vm if all keys are set and valid */
- if (!context.err) {
- vm_start();
- return 0;
- } else {
- return -1;
- }
-}
-
-static void bdrv_key_cb(void *opaque, int err)
-{
- Monitor *mon = opaque;
-
- /* another key was set successfully, retry to continue */
- if (!err)
- do_cont(mon, NULL, NULL);
-}
-
-static void encrypted_bdrv_it(void *opaque, BlockDriverState *bs)
-{
- struct bdrv_iterate_context *context = opaque;
-
- if (!context->err && bdrv_key_required(bs)) {
- context->err = -EBUSY;
- monitor_read_bdrv_key_start(context->mon, bs, bdrv_key_cb,
- context->mon);
- }
-}
-
static void do_gdbserver(Monitor *mon, const QDict *qdict)
{
const char *device = qdict_get_try_str(qdict, "device");
@@ -1370,81 +1316,6 @@ static void do_print(Monitor *mon, const QDict *qdict)
monitor_printf(mon, "\n");
}
-static int do_memory_save(Monitor *mon, const QDict *qdict, QObject **ret_data)
-{
- FILE *f;
- uint32_t size = qdict_get_int(qdict, "size");
- const char *filename = qdict_get_str(qdict, "filename");
- target_long addr = qdict_get_int(qdict, "val");
- uint32_t l;
- CPUState *env;
- uint8_t buf[1024];
- int ret = -1;
-
- env = mon_get_cpu();
-
- f = fopen(filename, "wb");
- if (!f) {
- qerror_report(QERR_OPEN_FILE_FAILED, filename);
- return -1;
- }
- while (size != 0) {
- l = sizeof(buf);
- if (l > size)
- l = size;
- cpu_memory_rw_debug(env, addr, buf, l, 0);
- if (fwrite(buf, 1, l, f) != l) {
- monitor_printf(mon, "fwrite() error in do_memory_save\n");
- goto exit;
- }
- addr += l;
- size -= l;
- }
-
- ret = 0;
-
-exit:
- fclose(f);
- return ret;
-}
-
-static int do_physical_memory_save(Monitor *mon, const QDict *qdict,
- QObject **ret_data)
-{
- FILE *f;
- uint32_t l;
- uint8_t buf[1024];
- uint32_t size = qdict_get_int(qdict, "size");
- const char *filename = qdict_get_str(qdict, "filename");
- target_phys_addr_t addr = qdict_get_int(qdict, "val");
- int ret = -1;
-
- f = fopen(filename, "wb");
- if (!f) {
- qerror_report(QERR_OPEN_FILE_FAILED, filename);
- return -1;
- }
- while (size != 0) {
- l = sizeof(buf);
- if (l > size)
- l = size;
- cpu_physical_memory_read(addr, buf, l);
- if (fwrite(buf, 1, l, f) != l) {
- monitor_printf(mon, "fwrite() error in do_physical_memory_save\n");
- goto exit;
- }
- fflush(f);
- addr += l;
- size -= l;
- }
-
- ret = 0;
-
-exit:
- fclose(f);
- return ret;
-}
-
static void do_sum(Monitor *mon, const QDict *qdict)
{
uint32_t addr;
@@ -1796,16 +1667,6 @@ static void do_boot_set(Monitor *mon, const QDict *qdict)
}
}
-/**
- * do_system_powerdown(): Issue a machine powerdown
- */
-static int do_system_powerdown(Monitor *mon, const QDict *qdict,
- QObject **ret_data)
-{
- qemu_system_powerdown_request();
- return 0;
-}
-
#if defined(TARGET_I386)
static void print_pte(Monitor *mon, target_phys_addr_t addr,
target_phys_addr_t pte,
@@ -2348,25 +2209,6 @@ static void do_wav_capture(Monitor *mon, const QDict *qdict)
}
#endif
-#if defined(TARGET_I386)
-static int do_inject_nmi(Monitor *mon, const QDict *qdict, QObject **ret_data)
-{
- CPUState *env;
-
- for (env = first_cpu; env != NULL; env = env->next_cpu) {
- cpu_interrupt(env, CPU_INTERRUPT_NMI);
- }
-
- return 0;
-}
-#else
-static int do_inject_nmi(Monitor *mon, const QDict *qdict, QObject **ret_data)
-{
- qerror_report(QERR_UNSUPPORTED);
- return -1;
-}
-#endif
-
static qemu_acl *find_acl(Monitor *mon, const char *name)
{
qemu_acl *acl = qemu_acl_find(name);
@@ -4943,3 +4785,18 @@ int monitor_read_bdrv_key_start(Monitor *mon, BlockDriverState *bs,
return err;
}
+
+int monitor_read_block_device_key(Monitor *mon, const char *device,
+ BlockDriverCompletionFunc *completion_cb,
+ void *opaque)
+{
+ BlockDriverState *bs;
+
+ bs = bdrv_find(device);
+ if (!bs) {
+ monitor_printf(mon, "Device not found %s\n", device);
+ return -1;
+ }
+
+ return monitor_read_bdrv_key_start(mon, bs, completion_cb, opaque);
+}
diff --git a/monitor.h b/monitor.h
index e76795f1f3..052f1cb244 100644
--- a/monitor.h
+++ b/monitor.h
@@ -49,6 +49,9 @@ void monitor_resume(Monitor *mon);
int monitor_read_bdrv_key_start(Monitor *mon, BlockDriverState *bs,
BlockDriverCompletionFunc *completion_cb,
void *opaque);
+int monitor_read_block_device_key(Monitor *mon, const char *device,
+ BlockDriverCompletionFunc *completion_cb,
+ void *opaque);
int monitor_get_fd(Monitor *mon, const char *fdname);
diff --git a/net.c b/net.c
index cb52050bfd..f7bebf8cc4 100644
--- a/net.c
+++ b/net.c
@@ -34,6 +34,7 @@
#include "monitor.h"
#include "qemu-common.h"
#include "qemu_socket.h"
+#include "qmp-commands.h"
#include "hw/qdev.h"
#include "iov.h"
@@ -1258,12 +1259,10 @@ void do_info_network(Monitor *mon)
}
}
-int do_set_link(Monitor *mon, const QDict *qdict, QObject **ret_data)
+void qmp_set_link(const char *name, bool up, Error **errp)
{
VLANState *vlan;
VLANClientState *vc = NULL;
- const char *name = qdict_get_str(qdict, "name");
- int up = qdict_get_bool(qdict, "up");
QTAILQ_FOREACH(vlan, &vlans, next) {
QTAILQ_FOREACH(vc, &vlan->clients, next) {
@@ -1280,8 +1279,8 @@ int do_set_link(Monitor *mon, const QDict *qdict, QObject **ret_data)
done:
if (!vc) {
- qerror_report(QERR_DEVICE_NOT_FOUND, name);
- return -1;
+ error_set(errp, QERR_DEVICE_NOT_FOUND, name);
+ return;
}
vc->link_down = !up;
@@ -1300,7 +1299,6 @@ done:
if (vc->peer && vc->peer->info->link_status_changed) {
vc->peer->info->link_status_changed(vc->peer);
}
- return 0;
}
void net_cleanup(void)
diff --git a/net.h b/net.h
index 9f633f8432..c6b41905af 100644
--- a/net.h
+++ b/net.h
@@ -122,7 +122,6 @@ int qemu_find_nic_model(NICInfo *nd, const char * const *models,
const char *default_model);
void do_info_network(Monitor *mon);
-int do_set_link(Monitor *mon, const QDict *qdict, QObject **ret_data);
/* NIC info */
diff --git a/net/socket.c b/net/socket.c
index 0f091645ed..aaf9be48e2 100644
--- a/net/socket.c
+++ b/net/socket.c
@@ -161,10 +161,11 @@ static int net_socket_mcast_create(struct sockaddr_in *mcastaddr, struct in_addr
#endif
if (!IN_MULTICAST(ntohl(mcastaddr->sin_addr.s_addr))) {
- fprintf(stderr, "qemu: error: specified mcastaddr \"%s\" (0x%08x) does not contain a multicast address\n",
- inet_ntoa(mcastaddr->sin_addr),
+ fprintf(stderr, "qemu: error: specified mcastaddr \"%s\" (0x%08x) "
+ "does not contain a multicast address\n",
+ inet_ntoa(mcastaddr->sin_addr),
(int)ntohl(mcastaddr->sin_addr.s_addr));
- return -1;
+ return -1;
}
fd = qemu_socket(PF_INET, SOCK_DGRAM, 0);
@@ -177,8 +178,8 @@ static int net_socket_mcast_create(struct sockaddr_in *mcastaddr, struct in_addr
ret=setsockopt(fd, SOL_SOCKET, SO_REUSEADDR,
(const char *)&val, sizeof(val));
if (ret < 0) {
- perror("setsockopt(SOL_SOCKET, SO_REUSEADDR)");
- goto fail;
+ perror("setsockopt(SOL_SOCKET, SO_REUSEADDR)");
+ goto fail;
}
ret = bind(fd, (struct sockaddr *)mcastaddr, sizeof(*mcastaddr));
@@ -198,8 +199,8 @@ static int net_socket_mcast_create(struct sockaddr_in *mcastaddr, struct in_addr
ret = setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP,
(const char *)&imr, sizeof(struct ip_mreq));
if (ret < 0) {
- perror("setsockopt(IP_ADD_MEMBERSHIP)");
- goto fail;
+ perror("setsockopt(IP_ADD_MEMBERSHIP)");
+ goto fail;
}
/* Force mcast msgs to loopback (eg. several QEMUs in same host */
@@ -207,8 +208,8 @@ static int net_socket_mcast_create(struct sockaddr_in *mcastaddr, struct in_addr
ret=setsockopt(fd, IPPROTO_IP, IP_MULTICAST_LOOP,
(const char *)&loop, sizeof(loop));
if (ret < 0) {
- perror("setsockopt(SOL_IP, IP_MULTICAST_LOOP)");
- goto fail;
+ perror("setsockopt(SOL_IP, IP_MULTICAST_LOOP)");
+ goto fail;
}
/* If a bind address is given, only send packets from that address */
@@ -260,37 +261,37 @@ static NetSocketState *net_socket_fd_init_dgram(VLANState *vlan,
*/
if (is_connected) {
- if (getsockname(fd, (struct sockaddr *) &saddr, &saddr_len) == 0) {
- /* must be bound */
- if (saddr.sin_addr.s_addr==0) {
- fprintf(stderr, "qemu: error: init_dgram: fd=%d unbound, cannot setup multicast dst addr\n",
- fd);
- return NULL;
- }
- /* clone dgram socket */
- newfd = net_socket_mcast_create(&saddr, NULL);
- if (newfd < 0) {
- /* error already reported by net_socket_mcast_create() */
- close(fd);
- return NULL;
- }
- /* clone newfd to fd, close newfd */
- dup2(newfd, fd);
- close(newfd);
-
- } else {
- fprintf(stderr, "qemu: error: init_dgram: fd=%d failed getsockname(): %s\n",
- fd, strerror(errno));
- return NULL;
- }
+ if (getsockname(fd, (struct sockaddr *) &saddr, &saddr_len) == 0) {
+ /* must be bound */
+ if (saddr.sin_addr.s_addr == 0) {
+ fprintf(stderr, "qemu: error: init_dgram: fd=%d unbound, "
+ "cannot setup multicast dst addr\n", fd);
+ goto err;
+ }
+ /* clone dgram socket */
+ newfd = net_socket_mcast_create(&saddr, NULL);
+ if (newfd < 0) {
+ /* error already reported by net_socket_mcast_create() */
+ goto err;
+ }
+ /* clone newfd to fd, close newfd */
+ dup2(newfd, fd);
+ close(newfd);
+
+ } else {
+ fprintf(stderr,
+ "qemu: error: init_dgram: fd=%d failed getsockname(): %s\n",
+ fd, strerror(errno));
+ goto err;
+ }
}
nc = qemu_new_net_client(&net_dgram_socket_info, vlan, NULL, model, name);
snprintf(nc->info_str, sizeof(nc->info_str),
- "socket: fd=%d (%s mcast=%s:%d)",
- fd, is_connected ? "cloned" : "",
- inet_ntoa(saddr.sin_addr), ntohs(saddr.sin_port));
+ "socket: fd=%d (%s mcast=%s:%d)",
+ fd, is_connected ? "cloned" : "",
+ inet_ntoa(saddr.sin_addr), ntohs(saddr.sin_port));
s = DO_UPCAST(NetSocketState, nc, nc);
@@ -302,6 +303,10 @@ static NetSocketState *net_socket_fd_init_dgram(VLANState *vlan,
if (is_connected) s->dgram_dst=saddr;
return s;
+
+err:
+ closesocket(fd);
+ return NULL;
}
static void net_socket_connect(void *opaque)
@@ -349,8 +354,10 @@ static NetSocketState *net_socket_fd_init(VLANState *vlan,
if(getsockopt(fd, SOL_SOCKET, SO_TYPE, (char *)&so_type,
(socklen_t *)&optlen)< 0) {
- fprintf(stderr, "qemu: error: getsockopt(SO_TYPE) for fd=%d failed\n", fd);
- return NULL;
+ fprintf(stderr, "qemu: error: getsockopt(SO_TYPE) for fd=%d failed\n",
+ fd);
+ closesocket(fd);
+ return NULL;
}
switch(so_type) {
case SOCK_DGRAM:
@@ -383,9 +390,7 @@ static void net_socket_accept(void *opaque)
}
}
s1 = net_socket_fd_init(s->vlan, s->model, s->name, fd, 1);
- if (!s1) {
- closesocket(fd);
- } else {
+ if (s1) {
snprintf(s1->nc.info_str, sizeof(s1->nc.info_str),
"socket: connection from %s:%d",
inet_ntoa(saddr.sin_addr), ntohs(saddr.sin_port));
@@ -512,7 +517,7 @@ static int net_socket_mcast_init(VLANState *vlan,
fd = net_socket_mcast_create(&saddr, param_localaddr);
if (fd < 0)
- return -1;
+ return -1;
s = net_socket_fd_init(vlan, model, name, fd, 0);
if (!s)
@@ -549,7 +554,6 @@ int net_init_socket(QemuOpts *opts,
}
if (!net_socket_fd_init(vlan, "socket", name, fd, 1)) {
- close(fd);
return -1;
}
} else if (qemu_opt_get(opts, "listen")) {
diff --git a/qapi-schema-guest.json b/qapi-schema-guest.json
index f4bcd1a532..5f8a18d4d8 100644
--- a/qapi-schema-guest.json
+++ b/qapi-schema-guest.json
@@ -43,7 +43,11 @@
#
# Since: 0.15.0
##
-{ 'type': 'GuestAgentInfo', 'data': {'version': 'str'} }
+{ 'type': 'GuestAgentCommandInfo',
+ 'data': { 'name': 'str', 'enabled': 'bool' } }
+{ 'type': 'GuestAgentInfo',
+ 'data': { 'version': 'str',
+ 'supported_commands': ['GuestAgentCommandInfo'] } }
{ 'command': 'guest-info',
'returns': 'GuestAgentInfo' }
diff --git a/qapi-schema-test.json b/qapi-schema-test.json
index 3acedad7ee..2b38919001 100644
--- a/qapi-schema-test.json
+++ b/qapi-schema-test.json
@@ -16,6 +16,12 @@
'dict': { 'userdef': 'UserDefOne', 'string': 'str' },
'*dict2': { 'userdef': 'UserDefOne', 'string': 'str' } } } }
+{ 'type': 'UserDefNested',
+ 'data': { 'string0': 'str',
+ 'dict1': { 'string1': 'str',
+ 'dict2': { 'userdef1': 'UserDefOne', 'string2': 'str' },
+ '*dict3': { 'userdef2': 'UserDefOne', 'string3': 'str' } } } }
+
# testing commands
{ 'command': 'user_def_cmd', 'data': {} }
{ 'command': 'user_def_cmd1', 'data': {'ud1a': 'UserDefOne'} }
diff --git a/qapi-schema.json b/qapi-schema.json
index fbbdbe0914..f358b490b0 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -901,3 +901,270 @@
# Notes: Do not use this command.
##
{ 'command': 'cpu', 'data': {'index': 'int'} }
+
+##
+# @memsave:
+#
+# Save a portion of guest memory to a file.
+#
+# @val: the virtual address of the guest to start from
+#
+# @size: the size of memory region to save
+#
+# @filename: the file to save the memory to as binary data
+#
+# @cpu-index: #optional the index of the virtual CPU to use for translating the
+# virtual address (defaults to CPU 0)
+#
+# Returns: Nothing on success
+# If @cpu is not a valid VCPU, InvalidParameterValue
+# If @filename cannot be opened, OpenFileFailed
+# If an I/O error occurs while writing the file, IOError
+#
+# Since: 0.14.0
+#
+# Notes: Errors were not reliably returned until 1.1
+##
+{ 'command': 'memsave',
+ 'data': {'val': 'int', 'size': 'int', 'filename': 'str', '*cpu-index': 'int'} }
+
+##
+# @pmemsave:
+#
+# Save a portion of guest physical memory to a file.
+#
+# @val: the physical address of the guest to start from
+#
+# @size: the size of memory region to save
+#
+# @filename: the file to save the memory to as binary data
+#
+# Returns: Nothing on success
+# If @filename cannot be opened, OpenFileFailed
+# If an I/O error occurs while writing the file, IOError
+#
+# Since: 0.14.0
+#
+# Notes: Errors were not reliably returned until 1.1
+##
+{ 'command': 'pmemsave',
+ 'data': {'val': 'int', 'size': 'int', 'filename': 'str'} }
+
+##
+# @cont:
+#
+# Resume guest VCPU execution.
+#
+# Since: 0.14.0
+#
+# Returns: If successful, nothing
+# If the QEMU is waiting for an incoming migration, MigrationExpected
+# If QEMU was started with an encrypted block device and a key has
+# not yet been set, DeviceEncrypted.
+#
+# Notes: This command will succeed if the guest is currently running.
+##
+{ 'command': 'cont' }
+
+##
+# @inject-nmi:
+#
+# Injects an Non-Maskable Interrupt into all guest's VCPUs.
+#
+# Returns: If successful, nothing
+# If the Virtual Machine doesn't support NMI injection, Unsupported
+#
+# Since: 0.14.0
+#
+# Notes: Only x86 Virtual Machines support this command.
+##
+{ 'command': 'inject-nmi' }
+
+##
+# @set_link:
+#
+# Sets the link status of a virtual network adapter.
+#
+# @name: the device name of the virtual network adapter
+#
+# @up: true to set the link status to be up
+#
+# Returns: Nothing on success
+# If @name is not a valid network device, DeviceNotFound
+#
+# Since: 0.14.0
+#
+# Notes: Not all network adapters support setting link status. This command
+# will succeed even if the network adapter does not support link status
+# notification.
+##
+{ 'command': 'set_link', 'data': {'name': 'str', 'up': 'bool'} }
+
+##
+# @block_passwd:
+#
+# This command sets the password of a block device that has not been open
+# with a password and requires one.
+#
+# The two cases where this can happen are a block device is created through
+# QEMU's initial command line or a block device is changed through the legacy
+# @change interface.
+#
+# In the event that the block device is created through the initial command
+# line, the VM will start in the stopped state regardless of whether '-S' is
+# used. The intention is for a management tool to query the block devices to
+# determine which ones are encrypted, set the passwords with this command, and
+# then start the guest with the @cont command.
+#
+# @device: the name of the device to set the password on
+#
+# @password: the password to use for the device
+#
+# Returns: nothing on success
+# If @device is not a valid block device, DeviceNotFound
+# If @device is not encrypted, DeviceNotEncrypted
+# If @password is not valid for this device, InvalidPassword
+#
+# Notes: Not all block formats support encryption and some that do are not
+# able to validate that a password is correct. Disk corruption may
+# occur if an invalid password is specified.
+#
+# Since: 0.14.0
+##
+{ 'command': 'block_passwd', 'data': {'device': 'str', 'password': 'str'} }
+
+##
+# @balloon:
+#
+# Request the balloon driver to change its balloon size.
+#
+# @value: the target size of the balloon in bytes
+#
+# Returns: Nothing on success
+# If the balloon driver is enabled but not functional because the KVM
+# kernel module cannot support it, KvmMissingCap
+# If no balloon device is present, DeviceNotActive
+#
+# Notes: This command just issues a request to the guest. When it returns,
+# the balloon size may not have changed. A guest can change the balloon
+# size independent of this command.
+#
+# Since: 0.14.0
+##
+{ 'command': 'balloon', 'data': {'value': 'int'} }
+
+##
+# @block_resize
+#
+# Resize a block image while a guest is running.
+#
+# @device: the name of the device to get the image resized
+#
+# @size: new image size in bytes
+#
+# Returns: nothing on success
+# If @device is not a valid block device, DeviceNotFound
+#
+# Notes: This command returns UndefinedError in a number of error conditions.
+#
+# Since: 0.14.0
+##
+{ 'command': 'block_resize', 'data': { 'device': 'str', 'size': 'int' }}
+
+##
+# @blockdev-snapshot-sync
+#
+# Generates a synchronous snapshot of a block device.
+#
+# @device: the name of the device to generate the snapshot from.
+#
+# @snapshot-file: the target of the new image. If the file exists, or if it
+# is a device, the snapshot will be created in the existing
+# file/device. If does not exist, a new file will be created.
+#
+# @format: #optional the format of the snapshot image, default is 'qcow2'.
+#
+# Returns: nothing on success
+# If @device is not a valid block device, DeviceNotFound
+# If @snapshot-file can't be opened, OpenFileFailed
+# If @format is invalid, InvalidBlockFormat
+#
+# Notes: One of the last steps taken by this command is to close the current
+# image being used by @device and open the @snapshot-file one. If that
+# fails, the command will try to reopen the original image file. If
+# that also fails OpenFileFailed will be returned and the guest may get
+# unexpected errors.
+#
+# Since 0.14.0
+##
+{ 'command': 'blockdev-snapshot-sync',
+ 'data': { 'device': 'str', 'snapshot-file': 'str', '*format': 'str' } }
+
+##
+# @human-monitor-command:
+#
+# Execute a command on the human monitor and return the output.
+#
+# @command-line: the command to execute in the human monitor
+#
+# @cpu-index: #optional The CPU to use for commands that require an implicit CPU
+#
+# Returns: the output of the command as a string
+#
+# Since: 0.14.0
+#
+# Notes: This command only exists as a stop-gap. It's use is highly
+# discouraged. The semantics of this command are not guaranteed.
+#
+# Known limitations:
+#
+# o This command is stateless, this means that commands that depend
+# on state information (such as getfd) might not work
+#
+# o Commands that prompt the user for data (eg. 'cont' when the block
+# device is encrypted) don't currently work
+##
+{ 'command': 'human-monitor-command',
+ 'data': {'command-line': 'str', '*cpu-index': 'int'},
+ 'returns': 'str' }
+
+##
+# @migrate_cancel
+#
+# Cancel the current executing migration process.
+#
+# Returns: nothing on success
+#
+# Notes: This command succeeds even if there is no migration process running.
+#
+# Since: 0.14.0
+##
+{ 'command': 'migrate_cancel' }
+
+##
+# @migrate_set_downtime
+#
+# Set maximum tolerated downtime for migration.
+#
+# @value: maximum downtime in seconds
+#
+# Returns: nothing on success
+#
+# Since: 0.14.0
+##
+{ 'command': 'migrate_set_downtime', 'data': {'value': 'number'} }
+
+##
+# @migrate_set_speed
+#
+# Set maximum speed for migration.
+#
+# @value: maximum speed in bytes.
+#
+# Returns: nothing on success
+#
+# Notes: A value lesser than zero will be automatically round up to zero.
+#
+# Since: 0.14.0
+##
+{ 'command': 'migrate_set_speed', 'data': {'value': 'int'} }
diff --git a/qapi/qmp-core.h b/qapi/qmp-core.h
index f1c26e4b2e..3bb3acb589 100644
--- a/qapi/qmp-core.h
+++ b/qapi/qmp-core.h
@@ -31,11 +31,15 @@ typedef struct QmpCommand
QmpCommandType type;
QmpCommandFunc *fn;
QTAILQ_ENTRY(QmpCommand) node;
+ bool enabled;
} QmpCommand;
void qmp_register_command(const char *name, QmpCommandFunc *fn);
QmpCommand *qmp_find_command(const char *name);
QObject *qmp_dispatch(QObject *request);
+void qmp_disable_command(const char *name);
+bool qmp_command_is_enabled(const char *name);
+char **qmp_get_command_list(void);
#endif
diff --git a/qapi/qmp-dispatch.c b/qapi/qmp-dispatch.c
index 558469325c..43f640a95e 100644
--- a/qapi/qmp-dispatch.c
+++ b/qapi/qmp-dispatch.c
@@ -79,6 +79,10 @@ static QObject *do_qmp_dispatch(QObject *request, Error **errp)
error_set(errp, QERR_COMMAND_NOT_FOUND, command);
return NULL;
}
+ if (!cmd->enabled) {
+ error_set(errp, QERR_COMMAND_DISABLED, command);
+ return NULL;
+ }
if (!qdict_haskey(dict, "arguments")) {
args = qdict_new();
diff --git a/qapi/qmp-registry.c b/qapi/qmp-registry.c
index 5ff99cff14..25c89ad098 100644
--- a/qapi/qmp-registry.c
+++ b/qapi/qmp-registry.c
@@ -14,7 +14,7 @@
#include "qapi/qmp-core.h"
-static QTAILQ_HEAD(, QmpCommand) qmp_commands =
+static QTAILQ_HEAD(QmpCommandList, QmpCommand) qmp_commands =
QTAILQ_HEAD_INITIALIZER(qmp_commands);
void qmp_register_command(const char *name, QmpCommandFunc *fn)
@@ -24,17 +24,63 @@ void qmp_register_command(const char *name, QmpCommandFunc *fn)
cmd->name = name;
cmd->type = QCT_NORMAL;
cmd->fn = fn;
+ cmd->enabled = true;
QTAILQ_INSERT_TAIL(&qmp_commands, cmd, node);
}
QmpCommand *qmp_find_command(const char *name)
{
- QmpCommand *i;
+ QmpCommand *cmd;
- QTAILQ_FOREACH(i, &qmp_commands, node) {
- if (strcmp(i->name, name) == 0) {
- return i;
+ QTAILQ_FOREACH(cmd, &qmp_commands, node) {
+ if (strcmp(cmd->name, name) == 0) {
+ return cmd;
}
}
return NULL;
}
+
+void qmp_disable_command(const char *name)
+{
+ QmpCommand *cmd;
+
+ QTAILQ_FOREACH(cmd, &qmp_commands, node) {
+ if (strcmp(cmd->name, name) == 0) {
+ cmd->enabled = false;
+ return;
+ }
+ }
+}
+
+bool qmp_command_is_enabled(const char *name)
+{
+ QmpCommand *cmd;
+
+ QTAILQ_FOREACH(cmd, &qmp_commands, node) {
+ if (strcmp(cmd->name, name) == 0) {
+ return cmd->enabled;
+ }
+ }
+
+ return false;
+}
+
+char **qmp_get_command_list(void)
+{
+ QmpCommand *cmd;
+ int count = 1;
+ char **list_head, **list;
+
+ QTAILQ_FOREACH(cmd, &qmp_commands, node) {
+ count++;
+ }
+
+ list_head = list = g_malloc0(count * sizeof(char *));
+
+ QTAILQ_FOREACH(cmd, &qmp_commands, node) {
+ *list = strdup(cmd->name);
+ list++;
+ }
+
+ return list_head;
+}
diff --git a/qemu-ga.c b/qemu-ga.c
index 49320133c6..200bb1585f 100644
--- a/qemu-ga.c
+++ b/qemu-ga.c
@@ -27,6 +27,7 @@
#include "signal.h"
#include "qerror.h"
#include "error_int.h"
+#include "qapi/qmp-core.h"
#define QGA_VIRTIO_PATH_DEFAULT "/dev/virtio-ports/org.qemu.guest_agent.0"
#define QGA_PIDFILE_DEFAULT "/var/run/qemu-ga.pid"
@@ -91,6 +92,8 @@ static void usage(const char *cmd)
" -v, --verbose log extra debugging information\n"
" -V, --version print version information and exit\n"
" -d, --daemonize become a daemon\n"
+" -b, --blacklist comma-seperated list of RPCs to disable (no spaces, \"?\""
+" to list available RPCs)\n"
" -h, --help display this help and exit\n"
"\n"
"Report bugs to <mdroth@linux.vnet.ibm.com>\n"
@@ -548,7 +551,7 @@ static void init_guest_agent(GAState *s)
int main(int argc, char **argv)
{
- const char *sopt = "hVvdm:p:l:f:";
+ const char *sopt = "hVvdm:p:l:f:b:";
const char *method = NULL, *path = NULL, *pidfile = QGA_PIDFILE_DEFAULT;
const struct option lopt[] = {
{ "help", 0, NULL, 'h' },
@@ -559,13 +562,16 @@ int main(int argc, char **argv)
{ "method", 0, NULL, 'm' },
{ "path", 0, NULL, 'p' },
{ "daemonize", 0, NULL, 'd' },
+ { "blacklist", 0, NULL, 'b' },
{ NULL, 0, NULL, 0 }
};
- int opt_ind = 0, ch, daemonize = 0;
+ int opt_ind = 0, ch, daemonize = 0, i, j, len;
GLogLevelFlags log_level = G_LOG_LEVEL_ERROR | G_LOG_LEVEL_CRITICAL;
FILE *log_file = stderr;
GAState *s;
+ module_call_init(MODULE_INIT_QAPI);
+
while ((ch = getopt_long(argc, argv, sopt, lopt, &opt_ind)) != -1) {
switch (ch) {
case 'm':
@@ -595,6 +601,32 @@ int main(int argc, char **argv)
case 'd':
daemonize = 1;
break;
+ case 'b': {
+ char **list_head, **list;
+ if (*optarg == '?') {
+ list_head = list = qmp_get_command_list();
+ while (*list != NULL) {
+ printf("%s\n", *list);
+ g_free(*list);
+ list++;
+ }
+ g_free(list_head);
+ return 0;
+ }
+ for (j = 0, i = 0, len = strlen(optarg); i < len; i++) {
+ if (optarg[i] == ',') {
+ optarg[i] = 0;
+ qmp_disable_command(&optarg[j]);
+ g_debug("disabling command: %s", &optarg[j]);
+ j = i + 1;
+ }
+ }
+ if (j < i) {
+ qmp_disable_command(&optarg[j]);
+ g_debug("disabling command: %s", &optarg[j]);
+ }
+ break;
+ }
case 'h':
usage(argv[0]);
return 0;
@@ -624,7 +656,6 @@ int main(int argc, char **argv)
ga_command_state_init_all(s->command_state);
ga_state = s;
- module_call_init(MODULE_INIT_QAPI);
init_guest_agent(ga_state);
register_signal_handlers();
diff --git a/qemu-thread-posix.c b/qemu-thread-posix.c
index ac3c0c9d14..9e1b5fbdaa 100644
--- a/qemu-thread-posix.c
+++ b/qemu-thread-posix.c
@@ -117,20 +117,33 @@ void qemu_cond_wait(QemuCond *cond, QemuMutex *mutex)
void qemu_thread_create(QemuThread *thread,
void *(*start_routine)(void*),
- void *arg)
+ void *arg, int mode)
{
+ sigset_t set, oldset;
int err;
+ pthread_attr_t attr;
- /* Leave signal handling to the iothread. */
- sigset_t set, oldset;
+ err = pthread_attr_init(&attr);
+ if (err) {
+ error_exit(err, __func__);
+ }
+ if (mode == QEMU_THREAD_DETACHED) {
+ err = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
+ if (err) {
+ error_exit(err, __func__);
+ }
+ }
+ /* Leave signal handling to the iothread. */
sigfillset(&set);
pthread_sigmask(SIG_SETMASK, &set, &oldset);
- err = pthread_create(&thread->thread, NULL, start_routine, arg);
+ err = pthread_create(&thread->thread, &attr, start_routine, arg);
if (err)
error_exit(err, __func__);
pthread_sigmask(SIG_SETMASK, &oldset, NULL);
+
+ pthread_attr_destroy(&attr);
}
void qemu_thread_get_self(QemuThread *thread)
@@ -147,3 +160,15 @@ void qemu_thread_exit(void *retval)
{
pthread_exit(retval);
}
+
+void *qemu_thread_join(QemuThread *thread)
+{
+ int err;
+ void *ret;
+
+ err = pthread_join(thread->thread, &ret);
+ if (err) {
+ error_exit(err, __func__);
+ }
+ return ret;
+}
diff --git a/qemu-thread-win32.c b/qemu-thread-win32.c
index db8e744729..a13ffcca69 100644
--- a/qemu-thread-win32.c
+++ b/qemu-thread-win32.c
@@ -193,41 +193,78 @@ void qemu_cond_wait(QemuCond *cond, QemuMutex *mutex)
}
struct QemuThreadData {
- QemuThread *thread;
- void *(*start_routine)(void *);
- void *arg;
+ /* Passed to win32_start_routine. */
+ void *(*start_routine)(void *);
+ void *arg;
+ short mode;
+
+ /* Only used for joinable threads. */
+ bool exited;
+ void *ret;
+ CRITICAL_SECTION cs;
};
static int qemu_thread_tls_index = TLS_OUT_OF_INDEXES;
static unsigned __stdcall win32_start_routine(void *arg)
{
- struct QemuThreadData data = *(struct QemuThreadData *) arg;
- QemuThread *thread = data.thread;
-
- free(arg);
- TlsSetValue(qemu_thread_tls_index, thread);
-
- /*
- * Use DuplicateHandle instead of assigning thread->thread in the
- * creating thread to avoid races. It's simpler this way than with
- * synchronization.
- */
- DuplicateHandle(GetCurrentProcess(), GetCurrentThread(),
- GetCurrentProcess(), &thread->thread,
- 0, FALSE, DUPLICATE_SAME_ACCESS);
-
- qemu_thread_exit(data.start_routine(data.arg));
+ QemuThreadData *data = (QemuThreadData *) arg;
+ void *(*start_routine)(void *) = data->start_routine;
+ void *thread_arg = data->arg;
+
+ if (data->mode == QEMU_THREAD_DETACHED) {
+ g_free(data);
+ data = NULL;
+ } else {
+ InitializeCriticalSection(&data->cs);
+ }
+ TlsSetValue(qemu_thread_tls_index, data);
+ qemu_thread_exit(start_routine(thread_arg));
abort();
}
void qemu_thread_exit(void *arg)
{
- QemuThread *thread = TlsGetValue(qemu_thread_tls_index);
- thread->ret = arg;
- CloseHandle(thread->thread);
- thread->thread = NULL;
- ExitThread(0);
+ QemuThreadData *data = TlsGetValue(qemu_thread_tls_index);
+ if (data) {
+ data->ret = arg;
+ EnterCriticalSection(&data->cs);
+ data->exited = true;
+ LeaveCriticalSection(&data->cs);
+ }
+ _endthreadex(0);
+}
+
+void *qemu_thread_join(QemuThread *thread)
+{
+ QemuThreadData *data;
+ void *ret;
+ HANDLE handle;
+
+ data = thread->data;
+ if (!data) {
+ return NULL;
+ }
+ /*
+ * Because multiple copies of the QemuThread can exist via
+ * qemu_thread_get_self, we need to store a value that cannot
+ * leak there. The simplest, non racy way is to store the TID,
+ * discard the handle that _beginthreadex gives back, and
+ * get another copy of the handle here.
+ */
+ EnterCriticalSection(&data->cs);
+ if (!data->exited) {
+ handle = OpenThread(SYNCHRONIZE, FALSE, thread->tid);
+ LeaveCriticalSection(&data->cs);
+ WaitForSingleObject(handle, INFINITE);
+ CloseHandle(handle);
+ } else {
+ LeaveCriticalSection(&data->cs);
+ }
+ ret = data->ret;
+ DeleteCriticalSection(&data->cs);
+ g_free(data);
+ return ret;
}
static inline void qemu_thread_init(void)
@@ -243,39 +280,35 @@ static inline void qemu_thread_init(void)
void qemu_thread_create(QemuThread *thread,
void *(*start_routine)(void *),
- void *arg)
+ void *arg, int mode)
{
HANDLE hThread;
struct QemuThreadData *data;
qemu_thread_init();
data = g_malloc(sizeof *data);
- data->thread = thread;
data->start_routine = start_routine;
data->arg = arg;
+ data->mode = mode;
+ data->exited = false;
hThread = (HANDLE) _beginthreadex(NULL, 0, win32_start_routine,
- data, 0, NULL);
+ data, 0, &thread->tid);
if (!hThread) {
error_exit(GetLastError(), __func__);
}
CloseHandle(hThread);
+ thread->data = (mode == QEMU_THREAD_DETACHED) ? NULL : data;
}
void qemu_thread_get_self(QemuThread *thread)
{
- if (!thread->thread) {
- /* In the main thread of the process. Initialize the QemuThread
- pointer in TLS, and use the dummy GetCurrentThread handle as
- the identifier for qemu_thread_is_self. */
- qemu_thread_init();
- TlsSetValue(qemu_thread_tls_index, thread);
- thread->thread = GetCurrentThread();
- }
+ qemu_thread_init();
+ thread->data = TlsGetValue(qemu_thread_tls_index);
+ thread->tid = GetCurrentThreadId();
}
int qemu_thread_is_self(QemuThread *thread)
{
- QemuThread *this_thread = TlsGetValue(qemu_thread_tls_index);
- return this_thread->thread == thread->thread;
+ return GetCurrentThreadId() == thread->tid;
}
diff --git a/qemu-thread-win32.h b/qemu-thread-win32.h
index 878f86a910..2983490a58 100644
--- a/qemu-thread-win32.h
+++ b/qemu-thread-win32.h
@@ -13,9 +13,10 @@ struct QemuCond {
HANDLE continue_event;
};
+typedef struct QemuThreadData QemuThreadData;
struct QemuThread {
- HANDLE thread;
- void *ret;
+ QemuThreadData *data;
+ unsigned tid;
};
#endif
diff --git a/qemu-thread.h b/qemu-thread.h
index e008b60028..a78a8f2524 100644
--- a/qemu-thread.h
+++ b/qemu-thread.h
@@ -13,6 +13,9 @@ typedef struct QemuThread QemuThread;
#include "qemu-thread-posix.h"
#endif
+#define QEMU_THREAD_JOINABLE 0
+#define QEMU_THREAD_DETACHED 1
+
void qemu_mutex_init(QemuMutex *mutex);
void qemu_mutex_destroy(QemuMutex *mutex);
void qemu_mutex_lock(QemuMutex *mutex);
@@ -35,8 +38,9 @@ void qemu_cond_broadcast(QemuCond *cond);
void qemu_cond_wait(QemuCond *cond, QemuMutex *mutex);
void qemu_thread_create(QemuThread *thread,
- void *(*start_routine)(void*),
- void *arg);
+ void *(*start_routine)(void *),
+ void *arg, int mode);
+void *qemu_thread_join(QemuThread *thread);
void qemu_thread_get_self(QemuThread *thread);
int qemu_thread_is_self(QemuThread *thread);
void qemu_thread_exit(void *retval);
diff --git a/qerror.c b/qerror.c
index d9ab3969d2..830c9c3ddf 100644
--- a/qerror.c
+++ b/qerror.c
@@ -65,6 +65,10 @@ static const QErrorStringTable qerror_table[] = {
.desc = "The command %(name) has not been found",
},
{
+ .error_fmt = QERR_COMMAND_DISABLED,
+ .desc = "The command %(name) has been disabled for this instance",
+ },
+ {
.error_fmt = QERR_DEVICE_ENCRYPTED,
.desc = "Device '%(device)' is encrypted",
},
@@ -149,6 +153,10 @@ static const QErrorStringTable qerror_table[] = {
.desc = "Password incorrect",
},
{
+ .error_fmt = QERR_IO_ERROR,
+ .desc = "An IO error has occurred",
+ },
+ {
.error_fmt = QERR_JSON_PARSING,
.desc = "Invalid JSON syntax",
},
diff --git a/qerror.h b/qerror.h
index 161d654b75..688e700223 100644
--- a/qerror.h
+++ b/qerror.h
@@ -66,6 +66,9 @@ QError *qobject_to_qerror(const QObject *obj);
#define QERR_COMMAND_NOT_FOUND \
"{ 'class': 'CommandNotFound', 'data': { 'name': %s } }"
+#define QERR_COMMAND_DISABLED \
+ "{ 'class': 'CommandDisabled', 'data': { 'name': %s } }"
+
#define QERR_DEVICE_ENCRYPTED \
"{ 'class': 'DeviceEncrypted', 'data': { 'device': %s } }"
@@ -126,6 +129,9 @@ QError *qobject_to_qerror(const QObject *obj);
#define QERR_INVALID_PASSWORD \
"{ 'class': 'InvalidPassword', 'data': {} }"
+#define QERR_IO_ERROR \
+ "{ 'class': 'IOError', 'data': {} }"
+
#define QERR_JSON_PARSING \
"{ 'class': 'JSONParsing', 'data': {} }"
diff --git a/qga/guest-agent-commands.c b/qga/guest-agent-commands.c
index 6da9904819..a09c8ca230 100644
--- a/qga/guest-agent-commands.c
+++ b/qga/guest-agent-commands.c
@@ -57,9 +57,33 @@ void qmp_guest_ping(Error **err)
struct GuestAgentInfo *qmp_guest_info(Error **err)
{
GuestAgentInfo *info = g_malloc0(sizeof(GuestAgentInfo));
+ GuestAgentCommandInfo *cmd_info;
+ GuestAgentCommandInfoList *cmd_info_list;
+ char **cmd_list_head, **cmd_list;
info->version = g_strdup(QGA_VERSION);
+ cmd_list_head = cmd_list = qmp_get_command_list();
+ if (*cmd_list_head == NULL) {
+ goto out;
+ }
+
+ while (*cmd_list) {
+ cmd_info = g_malloc0(sizeof(GuestAgentCommandInfo));
+ cmd_info->name = strdup(*cmd_list);
+ cmd_info->enabled = qmp_command_is_enabled(cmd_info->name);
+
+ cmd_info_list = g_malloc0(sizeof(GuestAgentCommandInfoList));
+ cmd_info_list->value = cmd_info;
+ cmd_info_list->next = info->supported_commands;
+ info->supported_commands = cmd_info_list;
+
+ g_free(*cmd_list);
+ cmd_list++;
+ }
+
+out:
+ g_free(cmd_list_head);
return info;
}
diff --git a/qmp-commands.hx b/qmp-commands.hx
index 94da2a8ef2..002e7e8bd9 100644
--- a/qmp-commands.hx
+++ b/qmp-commands.hx
@@ -199,10 +199,7 @@ EQMP
{
.name = "cont",
.args_type = "",
- .params = "",
- .help = "resume emulation",
- .user_print = monitor_user_noop,
- .mhandler.cmd_new = do_cont,
+ .mhandler.cmd_new = qmp_marshal_input_cont,
},
SQMP
@@ -244,10 +241,7 @@ EQMP
{
.name = "system_powerdown",
.args_type = "",
- .params = "",
- .help = "send system power down event",
- .user_print = monitor_user_noop,
- .mhandler.cmd_new = do_system_powerdown,
+ .mhandler.cmd_new = qmp_marshal_input_system_powerdown,
},
SQMP
@@ -355,11 +349,8 @@ EQMP
{
.name = "memsave",
- .args_type = "val:l,size:i,filename:s",
- .params = "addr size file",
- .help = "save to disk virtual memory dump starting at 'addr' of size 'size'",
- .user_print = monitor_user_noop,
- .mhandler.cmd_new = do_memory_save,
+ .args_type = "val:l,size:i,filename:s,cpu:i?",
+ .mhandler.cmd_new = qmp_marshal_input_memsave,
},
SQMP
@@ -373,6 +364,7 @@ Arguments:
- "val": the starting address (json-int)
- "size": the memory size, in bytes (json-int)
- "filename": file path (json-string)
+- "cpu": virtual CPU index (json-int, optional)
Example:
@@ -382,17 +374,12 @@ Example:
"filename": "/tmp/virtual-mem-dump" } }
<- { "return": {} }
-Note: Depends on the current CPU.
-
EQMP
{
.name = "pmemsave",
.args_type = "val:l,size:i,filename:s",
- .params = "addr size file",
- .help = "save to disk physical memory dump starting at 'addr' of size 'size'",
- .user_print = monitor_user_noop,
- .mhandler.cmd_new = do_physical_memory_save,
+ .mhandler.cmd_new = qmp_marshal_input_pmemsave,
},
SQMP
@@ -420,10 +407,7 @@ EQMP
{
.name = "inject-nmi",
.args_type = "",
- .params = "",
- .help = "",
- .user_print = monitor_user_noop,
- .mhandler.cmd_new = do_inject_nmi,
+ .mhandler.cmd_new = qmp_marshal_input_inject_nmi,
},
SQMP
@@ -487,10 +471,7 @@ EQMP
{
.name = "migrate_cancel",
.args_type = "",
- .params = "",
- .help = "cancel the current VM migration",
- .user_print = monitor_user_noop,
- .mhandler.cmd_new = do_migrate_cancel,
+ .mhandler.cmd_new = qmp_marshal_input_migrate_cancel,
},
SQMP
@@ -511,10 +492,7 @@ EQMP
{
.name = "migrate_set_speed",
.args_type = "value:o",
- .params = "value",
- .help = "set maximum speed (in bytes) for migrations",
- .user_print = monitor_user_noop,
- .mhandler.cmd_new = do_migrate_set_speed,
+ .mhandler.cmd_new = qmp_marshal_input_migrate_set_speed,
},
SQMP
@@ -537,10 +515,7 @@ EQMP
{
.name = "migrate_set_downtime",
.args_type = "value:T",
- .params = "value",
- .help = "set maximum tolerated downtime (in seconds) for migrations",
- .user_print = monitor_user_noop,
- .mhandler.cmd_new = do_migrate_set_downtime,
+ .mhandler.cmd_new = qmp_marshal_input_migrate_set_downtime,
},
SQMP
@@ -658,10 +633,7 @@ EQMP
{
.name = "block_resize",
.args_type = "device:B,size:o",
- .params = "device size",
- .help = "resize a block image",
- .user_print = monitor_user_noop,
- .mhandler.cmd_new = do_block_resize,
+ .mhandler.cmd_new = qmp_marshal_input_block_resize,
},
SQMP
@@ -684,10 +656,8 @@ EQMP
{
.name = "blockdev-snapshot-sync",
- .args_type = "device:B,snapshot-file:s?,format:s?",
- .params = "device [new-image-file] [format]",
- .user_print = monitor_user_noop,
- .mhandler.cmd_new = do_snapshot_blkdev,
+ .args_type = "device:B,snapshot-file:s,format:s?",
+ .mhandler.cmd_new = qmp_marshal_input_blockdev_snapshot_sync,
},
SQMP
@@ -719,11 +689,7 @@ EQMP
{
.name = "balloon",
.args_type = "value:M",
- .params = "target",
- .help = "request VM to change its memory allocation (in MB)",
- .user_print = monitor_user_noop,
- .mhandler.cmd_async = do_balloon,
- .flags = MONITOR_CMD_ASYNC,
+ .mhandler.cmd_new = qmp_marshal_input_balloon,
},
SQMP
@@ -746,10 +712,7 @@ EQMP
{
.name = "set_link",
.args_type = "name:s,up:b",
- .params = "name on|off",
- .help = "change the link status of a network adapter",
- .user_print = monitor_user_noop,
- .mhandler.cmd_new = do_set_link,
+ .mhandler.cmd_new = qmp_marshal_input_set_link,
},
SQMP
@@ -825,10 +788,7 @@ EQMP
{
.name = "block_passwd",
.args_type = "device:B,password:s",
- .params = "block_passwd device password",
- .help = "set the password of encrypted block devices",
- .user_print = monitor_user_noop,
- .mhandler.cmd_new = do_block_set_passwd,
+ .mhandler.cmd_new = qmp_marshal_input_block_passwd,
},
SQMP
@@ -1001,10 +961,7 @@ EQMP
{
.name = "human-monitor-command",
.args_type = "command-line:s,cpu-index:i?",
- .params = "",
- .help = "",
- .user_print = monitor_user_noop,
- .mhandler.cmd_new = do_hmp_passthrough,
+ .mhandler.cmd_new = qmp_marshal_input_human_monitor_command,
},
SQMP
diff --git a/qmp.c b/qmp.c
index 511dd624b5..d71ceb4e4d 100644
--- a/qmp.c
+++ b/qmp.c
@@ -117,3 +117,40 @@ SpiceInfo *qmp_query_spice(Error **errp)
return NULL;
};
#endif
+
+static void iostatus_bdrv_it(void *opaque, BlockDriverState *bs)
+{
+ bdrv_iostatus_reset(bs);
+}
+
+static void encrypted_bdrv_it(void *opaque, BlockDriverState *bs)
+{
+ Error **err = opaque;
+
+ if (!error_is_set(err) && bdrv_key_required(bs)) {
+ error_set(err, QERR_DEVICE_ENCRYPTED, bdrv_get_device_name(bs));
+ }
+}
+
+void qmp_cont(Error **errp)
+{
+ Error *local_err = NULL;
+
+ if (runstate_check(RUN_STATE_INMIGRATE)) {
+ error_set(errp, QERR_MIGRATION_EXPECTED);
+ return;
+ } else if (runstate_check(RUN_STATE_INTERNAL_ERROR) ||
+ runstate_check(RUN_STATE_SHUTDOWN)) {
+ error_set(errp, QERR_RESET_REQUIRED);
+ return;
+ }
+
+ bdrv_iterate(iostatus_bdrv_it, NULL);
+ bdrv_iterate(encrypted_bdrv_it, &local_err);
+ if (local_err) {
+ error_propagate(errp, local_err);
+ return;
+ }
+
+ vm_start();
+}
diff --git a/savevm.c b/savevm.c
index 1a21ab441f..b72f6c0d17 100644
--- a/savevm.c
+++ b/savevm.c
@@ -235,6 +235,9 @@ static int stdio_pclose(void *opaque)
QEMUFileStdio *s = opaque;
int ret;
ret = pclose(s->stdio_file);
+ if (ret == -1) {
+ ret = -errno;
+ }
g_free(s);
return ret;
}
@@ -242,9 +245,12 @@ static int stdio_pclose(void *opaque)
static int stdio_fclose(void *opaque)
{
QEMUFileStdio *s = opaque;
- fclose(s->stdio_file);
+ int ret = 0;
+ if (fclose(s->stdio_file) == EOF) {
+ ret = -errno;
+ }
g_free(s);
- return 0;
+ return ret;
}
QEMUFile *qemu_popen(FILE *stdio_file, const char *mode)
@@ -436,6 +442,22 @@ void qemu_file_set_error(QEMUFile *f, int ret)
f->last_error = ret;
}
+/** Sets last_error conditionally
+ *
+ * Sets last_error only if ret is negative _and_ no error
+ * was set before.
+ */
+static void qemu_file_set_if_error(QEMUFile *f, int ret)
+{
+ if (ret < 0 && !f->last_error) {
+ qemu_file_set_error(f, ret);
+ }
+}
+
+/** Flushes QEMUFile buffer
+ *
+ * In case of error, last_error is set.
+ */
void qemu_fflush(QEMUFile *f)
{
if (!f->put_buffer)
@@ -448,7 +470,7 @@ void qemu_fflush(QEMUFile *f)
if (len > 0)
f->buf_offset += f->buf_index;
else
- f->last_error = -EINVAL;
+ qemu_file_set_error(f, -EINVAL);
f->buf_index = 0;
}
}
@@ -479,15 +501,44 @@ static void qemu_fill_buffer(QEMUFile *f)
} else if (len == 0) {
f->last_error = -EIO;
} else if (len != -EAGAIN)
- f->last_error = len;
+ qemu_file_set_error(f, len);
}
-int qemu_fclose(QEMUFile *f)
+/** Calls close function and set last_error if needed
+ *
+ * Internal function. qemu_fflush() must be called before this.
+ *
+ * Returns f->close() return value, or 0 if close function is not set.
+ */
+static int qemu_close(QEMUFile *f)
{
int ret = 0;
- qemu_fflush(f);
- if (f->close)
+ if (f->close) {
ret = f->close(f->opaque);
+ qemu_file_set_if_error(f, ret);
+ }
+ return ret;
+}
+
+/** Closes the file
+ *
+ * Returns negative error value if any error happened on previous operations or
+ * while closing the file. Returns 0 or positive number on success.
+ *
+ * The meaning of return value on success depends on the specific backend
+ * being used.
+ */
+int qemu_fclose(QEMUFile *f)
+{
+ int ret;
+ qemu_fflush(f);
+ ret = qemu_close(f);
+ /* If any error was spotted before closing, we should report it
+ * instead of the close() return value.
+ */
+ if (f->last_error) {
+ ret = f->last_error;
+ }
g_free(f);
return ret;
}
diff --git a/target-cris/cpu.h b/target-cris/cpu.h
index 8ae0ce3ef3..453afbb66e 100644
--- a/target-cris/cpu.h
+++ b/target-cris/cpu.h
@@ -67,6 +67,8 @@
#define Q_FLAG 0x80000000
#define M_FLAG 0x40000000
#define PFIX_FLAG 0x800 /* CRISv10 Only. */
+#define F_FLAG_V10 0x400
+#define P_FLAG_V10 0x200
#define S_FLAG 0x200
#define R_FLAG 0x100
#define P_FLAG 0x80
diff --git a/target-cris/helper.c b/target-cris/helper.c
index 75f0035e6e..5bc6d810cb 100644
--- a/target-cris/helper.c
+++ b/target-cris/helper.c
@@ -157,6 +157,7 @@ static void do_interruptv10(CPUState *env)
/* Now that we are in kernel mode, load the handlers address. */
env->pc = ldl_code(env->pregs[PR_EBP] + ex_vec * 4);
env->locked_irq = 1;
+ env->pregs[PR_CCS] |= F_FLAG_V10; /* set F. */
qemu_log_mask(CPU_LOG_INT, "%s isr=%x vec=%x ccs=%x pid=%d erp=%x\n",
__func__, env->pc, ex_vec,
diff --git a/target-cris/translate_v10.c b/target-cris/translate_v10.c
index 637ac2084a..95053b64fb 100644
--- a/target-cris/translate_v10.c
+++ b/target-cris/translate_v10.c
@@ -62,6 +62,65 @@ static inline void cris_illegal_insn(DisasContext *dc)
t_gen_raise_exception(EXCP_BREAK);
}
+static void gen_store_v10_conditional(DisasContext *dc, TCGv addr, TCGv val,
+ unsigned int size, int mem_index)
+{
+ int l1 = gen_new_label();
+ TCGv taddr = tcg_temp_local_new();
+ TCGv tval = tcg_temp_local_new();
+ TCGv t1 = tcg_temp_local_new();
+ dc->postinc = 0;
+ cris_evaluate_flags(dc);
+
+ tcg_gen_mov_tl(taddr, addr);
+ tcg_gen_mov_tl(tval, val);
+
+ /* Store only if F flag isn't set */
+ tcg_gen_andi_tl(t1, cpu_PR[PR_CCS], F_FLAG_V10);
+ tcg_gen_brcondi_tl(TCG_COND_NE, t1, 0, l1);
+ if (size == 1) {
+ tcg_gen_qemu_st8(tval, taddr, mem_index);
+ } else if (size == 2) {
+ tcg_gen_qemu_st16(tval, taddr, mem_index);
+ } else {
+ tcg_gen_qemu_st32(tval, taddr, mem_index);
+ }
+ gen_set_label(l1);
+ tcg_gen_shri_tl(t1, t1, 1); /* shift F to P position */
+ tcg_gen_or_tl(cpu_PR[PR_CCS], cpu_PR[PR_CCS], t1); /*P=F*/
+ tcg_temp_free(t1);
+ tcg_temp_free(tval);
+ tcg_temp_free(taddr);
+}
+
+static void gen_store_v10(DisasContext *dc, TCGv addr, TCGv val,
+ unsigned int size)
+{
+ int mem_index = cpu_mmu_index(dc->env);
+
+ /* If we get a fault on a delayslot we must keep the jmp state in
+ the cpu-state to be able to re-execute the jmp. */
+ if (dc->delayed_branch == 1) {
+ cris_store_direct_jmp(dc);
+ }
+
+ /* Conditional writes. We only support the kind were X is known
+ at translation time. */
+ if (dc->flagx_known && dc->flags_x) {
+ gen_store_v10_conditional(dc, addr, val, size, mem_index);
+ return;
+ }
+
+ if (size == 1) {
+ tcg_gen_qemu_st8(val, addr, mem_index);
+ } else if (size == 2) {
+ tcg_gen_qemu_st16(val, addr, mem_index);
+ } else {
+ tcg_gen_qemu_st32(val, addr, mem_index);
+ }
+}
+
+
/* Prefix flag and register are used to handle the more complex
addressing modes. */
static void cris_set_prefix(DisasContext *dc)
@@ -313,7 +372,8 @@ static unsigned int dec10_setclrf(DisasContext *dc)
if (set) {
tcg_gen_ori_tl(cpu_PR[PR_CCS], cpu_PR[PR_CCS], flags);
} else {
- tcg_gen_andi_tl(cpu_PR[PR_CCS], cpu_PR[PR_CCS], ~flags);
+ tcg_gen_andi_tl(cpu_PR[PR_CCS], cpu_PR[PR_CCS],
+ ~(flags|F_FLAG_V10|P_FLAG_V10));
}
dc->flags_uptodate = 1;
@@ -723,7 +783,7 @@ static unsigned int dec10_ind_move_r_m(DisasContext *dc, unsigned int size)
LOG_DIS("move.%d $r%d, [$r%d]\n", dc->size, dc->src, dc->dst);
addr = tcg_temp_new();
crisv10_prepare_memaddr(dc, addr, size);
- gen_store(dc, addr, cpu_R[dc->dst], size);
+ gen_store_v10(dc, addr, cpu_R[dc->dst], size);
insn_len += crisv10_post_memaddr(dc, size);
return insn_len;
@@ -767,10 +827,10 @@ static unsigned int dec10_ind_move_pr_m(DisasContext *dc)
t0 = tcg_temp_new();
cris_evaluate_flags(dc);
tcg_gen_andi_tl(t0, cpu_PR[PR_CCS], ~PFIX_FLAG);
- gen_store(dc, addr, t0, size);
+ gen_store_v10(dc, addr, t0, size);
tcg_temp_free(t0);
} else {
- gen_store(dc, addr, cpu_PR[dc->dst], size);
+ gen_store_v10(dc, addr, cpu_PR[dc->dst], size);
}
t0 = tcg_temp_new();
insn_len += crisv10_post_memaddr(dc, size);
@@ -793,9 +853,9 @@ static void dec10_movem_r_m(DisasContext *dc)
tcg_gen_mov_tl(t0, addr);
for (i = dc->dst; i >= 0; i--) {
if ((pfix && dc->mode == CRISV10_MODE_AUTOINC) && dc->src == i) {
- gen_store(dc, addr, t0, 4);
+ gen_store_v10(dc, addr, t0, 4);
} else {
- gen_store(dc, addr, cpu_R[i], 4);
+ gen_store_v10(dc, addr, cpu_R[i], 4);
}
tcg_gen_addi_tl(addr, addr, 4);
}
diff --git a/target-i386/translate.c b/target-i386/translate.c
index 1ef8d16ac7..8321bf39a5 100644
--- a/target-i386/translate.c
+++ b/target-i386/translate.c
@@ -4870,20 +4870,23 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start)
tcg_gen_sub_tl(t2, cpu_regs[R_EAX], t0);
gen_extu(ot, t2);
tcg_gen_brcondi_tl(TCG_COND_EQ, t2, 0, label1);
+ label2 = gen_new_label();
if (mod == 3) {
- label2 = gen_new_label();
gen_op_mov_reg_v(ot, R_EAX, t0);
tcg_gen_br(label2);
gen_set_label(label1);
gen_op_mov_reg_v(ot, rm, t1);
- gen_set_label(label2);
} else {
- tcg_gen_mov_tl(t1, t0);
+ /* perform no-op store cycle like physical cpu; must be
+ before changing accumulator to ensure idempotency if
+ the store faults and the instruction is restarted */
+ gen_op_st_v(ot + s->mem_index, t0, a0);
gen_op_mov_reg_v(ot, R_EAX, t0);
+ tcg_gen_br(label2);
gen_set_label(label1);
- /* always store */
gen_op_st_v(ot + s->mem_index, t1, a0);
}
+ gen_set_label(label2);
tcg_gen_mov_tl(cpu_cc_src, t0);
tcg_gen_mov_tl(cpu_cc_dst, t2);
s->cc_op = CC_OP_SUBB + ot;
diff --git a/test-qmp-input-visitor.c b/test-qmp-input-visitor.c
new file mode 100644
index 0000000000..1f3ab031f7
--- /dev/null
+++ b/test-qmp-input-visitor.c
@@ -0,0 +1,270 @@
+/*
+ * QMP Input Visitor unit-tests.
+ *
+ * Copyright (C) 2011 Red Hat Inc.
+ *
+ * Authors:
+ * Luiz Capitulino <lcapitulino@redhat.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#include <glib.h>
+#include <stdarg.h>
+
+#include "qapi/qmp-input-visitor.h"
+#include "test-qapi-types.h"
+#include "test-qapi-visit.h"
+#include "qemu-objects.h"
+
+typedef struct TestInputVisitorData {
+ QObject *obj;
+ QmpInputVisitor *qiv;
+} TestInputVisitorData;
+
+static void visitor_input_teardown(TestInputVisitorData *data,
+ const void *unused)
+{
+ qobject_decref(data->obj);
+ data->obj = NULL;
+
+ if (data->qiv) {
+ qmp_input_visitor_cleanup(data->qiv);
+ data->qiv = NULL;
+ }
+}
+
+/* This is provided instead of a test setup function so that the JSON
+ string used by the tests are kept in the test functions (and not
+ int main()) */
+static Visitor *visitor_input_test_init(TestInputVisitorData *data,
+ const char *json_string, ...)
+{
+ Visitor *v;
+ va_list ap;
+
+ va_start(ap, json_string);
+ data->obj = qobject_from_jsonv(json_string, &ap);
+ va_end(ap);
+
+ g_assert(data->obj != NULL);
+
+ data->qiv = qmp_input_visitor_new(data->obj);
+ g_assert(data->qiv != NULL);
+
+ v = qmp_input_get_visitor(data->qiv);
+ g_assert(v != NULL);
+
+ return v;
+}
+
+static void test_visitor_in_int(TestInputVisitorData *data,
+ const void *unused)
+{
+ int64_t res = 0, value = -42;
+ Error *errp = NULL;
+ Visitor *v;
+
+ v = visitor_input_test_init(data, "%d", value);
+
+ visit_type_int(v, &res, NULL, &errp);
+ g_assert(!error_is_set(&errp));
+ g_assert_cmpint(res, ==, value);
+}
+
+static void test_visitor_in_bool(TestInputVisitorData *data,
+ const void *unused)
+{
+ Error *errp = NULL;
+ bool res = false;
+ Visitor *v;
+
+ v = visitor_input_test_init(data, "true");
+
+ visit_type_bool(v, &res, NULL, &errp);
+ g_assert(!error_is_set(&errp));
+ g_assert_cmpint(res, ==, true);
+}
+
+static void test_visitor_in_number(TestInputVisitorData *data,
+ const void *unused)
+{
+ double res = 0, value = 3.14;
+ Error *errp = NULL;
+ Visitor *v;
+
+ v = visitor_input_test_init(data, "%f", value);
+
+ visit_type_number(v, &res, NULL, &errp);
+ g_assert(!error_is_set(&errp));
+ g_assert_cmpfloat(res, ==, value);
+}
+
+static void test_visitor_in_string(TestInputVisitorData *data,
+ const void *unused)
+{
+ char *res = NULL, *value = (char *) "Q E M U";
+ Error *errp = NULL;
+ Visitor *v;
+
+ v = visitor_input_test_init(data, "%s", value);
+
+ visit_type_str(v, &res, NULL, &errp);
+ g_assert(!error_is_set(&errp));
+ g_assert_cmpstr(res, ==, value);
+
+ g_free(res);
+}
+
+static void test_visitor_in_enum(TestInputVisitorData *data,
+ const void *unused)
+{
+ Error *errp = NULL;
+ Visitor *v;
+ EnumOne i;
+
+ for (i = 0; EnumOne_lookup[i]; i++) {
+ EnumOne res = -1;
+
+ v = visitor_input_test_init(data, "%s", EnumOne_lookup[i]);
+
+ visit_type_EnumOne(v, &res, NULL, &errp);
+ g_assert(!error_is_set(&errp));
+ g_assert_cmpint(i, ==, res);
+
+ visitor_input_teardown(data, NULL);
+ }
+
+ data->obj = NULL;
+ data->qiv = NULL;
+}
+
+typedef struct TestStruct
+{
+ int64_t integer;
+ bool boolean;
+ char *string;
+} TestStruct;
+
+static void visit_type_TestStruct(Visitor *v, TestStruct **obj,
+ const char *name, Error **errp)
+{
+ visit_start_struct(v, (void **)obj, "TestStruct", name, sizeof(TestStruct),
+ errp);
+
+ visit_type_int(v, &(*obj)->integer, "integer", errp);
+ visit_type_bool(v, &(*obj)->boolean, "boolean", errp);
+ visit_type_str(v, &(*obj)->string, "string", errp);
+
+ visit_end_struct(v, errp);
+}
+
+static void test_visitor_in_struct(TestInputVisitorData *data,
+ const void *unused)
+{
+ TestStruct *p = NULL;
+ Error *errp = NULL;
+ Visitor *v;
+
+ v = visitor_input_test_init(data, "{ 'integer': -42, 'boolean': true, 'string': 'foo' }");
+
+ visit_type_TestStruct(v, &p, NULL, &errp);
+ g_assert(!error_is_set(&errp));
+ g_assert_cmpint(p->integer, ==, -42);
+ g_assert(p->boolean == true);
+ g_assert_cmpstr(p->string, ==, "foo");
+
+ g_free(p->string);
+ g_free(p);
+}
+
+static void check_and_free_str(char *str, const char *cmp)
+{
+ g_assert_cmpstr(str, ==, cmp);
+ g_free(str);
+}
+
+static void test_visitor_in_struct_nested(TestInputVisitorData *data,
+ const void *unused)
+{
+ UserDefNested *udp = NULL;
+ Error *errp = NULL;
+ Visitor *v;
+
+ v = visitor_input_test_init(data, "{ 'string0': 'string0', 'dict1': { 'string1': 'string1', 'dict2': { 'userdef1': { 'integer': 42, 'string': 'string' }, 'string2': 'string2'}}}");
+
+ visit_type_UserDefNested(v, &udp, NULL, &errp);
+ g_assert(!error_is_set(&errp));
+
+ check_and_free_str(udp->string0, "string0");
+ check_and_free_str(udp->dict1.string1, "string1");
+ g_assert_cmpint(udp->dict1.dict2.userdef1->integer, ==, 42);
+ check_and_free_str(udp->dict1.dict2.userdef1->string, "string");
+ check_and_free_str(udp->dict1.dict2.string2, "string2");
+ g_assert(udp->dict1.has_dict3 == false);
+
+ g_free(udp->dict1.dict2.userdef1);
+ g_free(udp);
+}
+
+static void test_visitor_in_list(TestInputVisitorData *data,
+ const void *unused)
+{
+ UserDefOneList *item, *head = NULL;
+ Error *errp = NULL;
+ Visitor *v;
+ int i;
+
+ v = visitor_input_test_init(data, "[ { 'string': 'string0', 'integer': 42 }, { 'string': 'string1', 'integer': 43 }, { 'string': 'string2', 'integer': 44 } ]");
+
+ visit_type_UserDefOneList(v, &head, NULL, &errp);
+ g_assert(!error_is_set(&errp));
+ g_assert(head != NULL);
+
+ for (i = 0, item = head; item; item = item->next, i++) {
+ char string[12];
+
+ snprintf(string, sizeof(string), "string%d", i);
+ g_assert_cmpstr(item->value->string, ==, string);
+ g_assert_cmpint(item->value->integer, ==, 42 + i);
+ }
+
+ qapi_free_UserDefOneList(head);
+}
+
+static void input_visitor_test_add(const char *testpath,
+ TestInputVisitorData *data,
+ void (*test_func)(TestInputVisitorData *data, const void *user_data))
+{
+ g_test_add(testpath, TestInputVisitorData, data, NULL, test_func,
+ visitor_input_teardown);
+}
+
+int main(int argc, char **argv)
+{
+ TestInputVisitorData in_visitor_data;
+
+ g_test_init(&argc, &argv, NULL);
+
+ input_visitor_test_add("/visitor/input/int",
+ &in_visitor_data, test_visitor_in_int);
+ input_visitor_test_add("/visitor/input/bool",
+ &in_visitor_data, test_visitor_in_bool);
+ input_visitor_test_add("/visitor/input/number",
+ &in_visitor_data, test_visitor_in_number);
+ input_visitor_test_add("/visitor/input/string",
+ &in_visitor_data, test_visitor_in_string);
+ input_visitor_test_add("/visitor/input/enum",
+ &in_visitor_data, test_visitor_in_enum);
+ input_visitor_test_add("/visitor/input/struct",
+ &in_visitor_data, test_visitor_in_struct);
+ input_visitor_test_add("/visitor/input/struct-nested",
+ &in_visitor_data, test_visitor_in_struct_nested);
+ input_visitor_test_add("/visitor/input/list",
+ &in_visitor_data, test_visitor_in_list);
+
+ g_test_run();
+
+ return 0;
+}
diff --git a/test-qmp-output-visitor.c b/test-qmp-output-visitor.c
new file mode 100644
index 0000000000..c94c208125
--- /dev/null
+++ b/test-qmp-output-visitor.c
@@ -0,0 +1,423 @@
+/*
+ * QMP Output Visitor unit-tests.
+ *
+ * Copyright (C) 2011 Red Hat Inc.
+ *
+ * Authors:
+ * Luiz Capitulino <lcapitulino@redhat.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#include <glib.h>
+
+#include "qapi/qmp-output-visitor.h"
+#include "test-qapi-types.h"
+#include "test-qapi-visit.h"
+#include "qemu-objects.h"
+
+typedef struct TestOutputVisitorData {
+ QmpOutputVisitor *qov;
+ Visitor *ov;
+} TestOutputVisitorData;
+
+static void visitor_output_setup(TestOutputVisitorData *data,
+ const void *unused)
+{
+ data->qov = qmp_output_visitor_new();
+ g_assert(data->qov != NULL);
+
+ data->ov = qmp_output_get_visitor(data->qov);
+ g_assert(data->ov != NULL);
+}
+
+static void visitor_output_teardown(TestOutputVisitorData *data,
+ const void *unused)
+{
+ qmp_output_visitor_cleanup(data->qov);
+ data->qov = NULL;
+ data->ov = NULL;
+}
+
+static void test_visitor_out_int(TestOutputVisitorData *data,
+ const void *unused)
+{
+ int64_t value = -42;
+ Error *errp = NULL;
+ QObject *obj;
+
+ visit_type_int(data->ov, &value, NULL, &errp);
+ g_assert(error_is_set(&errp) == 0);
+
+ obj = qmp_output_get_qobject(data->qov);
+ g_assert(obj != NULL);
+ g_assert(qobject_type(obj) == QTYPE_QINT);
+ g_assert_cmpint(qint_get_int(qobject_to_qint(obj)), ==, value);
+
+ qobject_decref(obj);
+}
+
+static void test_visitor_out_bool(TestOutputVisitorData *data,
+ const void *unused)
+{
+ Error *errp = NULL;
+ bool value = true;
+ QObject *obj;
+
+ visit_type_bool(data->ov, &value, NULL, &errp);
+ g_assert(error_is_set(&errp) == 0);
+
+ obj = qmp_output_get_qobject(data->qov);
+ g_assert(obj != NULL);
+ g_assert(qobject_type(obj) == QTYPE_QBOOL);
+ g_assert(qbool_get_int(qobject_to_qbool(obj)) == value);
+
+ qobject_decref(obj);
+}
+
+static void test_visitor_out_number(TestOutputVisitorData *data,
+ const void *unused)
+{
+ double value = 3.14;
+ Error *errp = NULL;
+ QObject *obj;
+
+ visit_type_number(data->ov, &value, NULL, &errp);
+ g_assert(error_is_set(&errp) == 0);
+
+ obj = qmp_output_get_qobject(data->qov);
+ g_assert(obj != NULL);
+ g_assert(qobject_type(obj) == QTYPE_QFLOAT);
+ g_assert(qfloat_get_double(qobject_to_qfloat(obj)) == value);
+
+ qobject_decref(obj);
+}
+
+static void test_visitor_out_string(TestOutputVisitorData *data,
+ const void *unused)
+{
+ char *string = (char *) "Q E M U";
+ Error *errp = NULL;
+ QObject *obj;
+
+ visit_type_str(data->ov, &string, NULL, &errp);
+ g_assert(error_is_set(&errp) == 0);
+
+ obj = qmp_output_get_qobject(data->qov);
+ g_assert(obj != NULL);
+ g_assert(qobject_type(obj) == QTYPE_QSTRING);
+ g_assert_cmpstr(qstring_get_str(qobject_to_qstring(obj)), ==, string);
+
+ qobject_decref(obj);
+}
+
+static void test_visitor_out_no_string(TestOutputVisitorData *data,
+ const void *unused)
+{
+ char *string = NULL;
+ Error *errp = NULL;
+ QObject *obj;
+
+ /* A null string should return "" */
+ visit_type_str(data->ov, &string, NULL, &errp);
+ g_assert(error_is_set(&errp) == 0);
+
+ obj = qmp_output_get_qobject(data->qov);
+ g_assert(obj != NULL);
+ g_assert(qobject_type(obj) == QTYPE_QSTRING);
+ g_assert_cmpstr(qstring_get_str(qobject_to_qstring(obj)), ==, "");
+
+ qobject_decref(obj);
+}
+
+static void test_visitor_out_enum(TestOutputVisitorData *data,
+ const void *unused)
+{
+ Error *errp = NULL;
+ QObject *obj;
+ EnumOne i;
+
+ for (i = 0; i < ENUM_ONE_MAX; i++) {
+ visit_type_EnumOne(data->ov, &i, "unused", &errp);
+ g_assert(!error_is_set(&errp));
+
+ obj = qmp_output_get_qobject(data->qov);
+ g_assert(obj != NULL);
+ g_assert(qobject_type(obj) == QTYPE_QSTRING);
+ g_assert_cmpstr(qstring_get_str(qobject_to_qstring(obj)), ==,
+ EnumOne_lookup[i]);
+ qobject_decref(obj);
+ }
+}
+
+static void test_visitor_out_enum_errors(TestOutputVisitorData *data,
+ const void *unused)
+{
+ EnumOne i, bad_values[] = { ENUM_ONE_MAX, -1 };
+ Error *errp;
+
+ for (i = 0; i < ARRAY_SIZE(bad_values) ; i++) {
+ errp = NULL;
+ visit_type_EnumOne(data->ov, &bad_values[i], "unused", &errp);
+ g_assert(error_is_set(&errp) == true);
+ error_free(errp);
+ }
+}
+
+typedef struct TestStruct
+{
+ int64_t integer;
+ bool boolean;
+ char *string;
+} TestStruct;
+
+static void visit_type_TestStruct(Visitor *v, TestStruct **obj,
+ const char *name, Error **errp)
+{
+ visit_start_struct(v, (void **)obj, "TestStruct", name, sizeof(TestStruct),
+ errp);
+
+ visit_type_int(v, &(*obj)->integer, "integer", errp);
+ visit_type_bool(v, &(*obj)->boolean, "boolean", errp);
+ visit_type_str(v, &(*obj)->string, "string", errp);
+
+ visit_end_struct(v, errp);
+}
+
+static void test_visitor_out_struct(TestOutputVisitorData *data,
+ const void *unused)
+{
+ TestStruct test_struct = { .integer = 42,
+ .boolean = false,
+ .string = (char *) "foo"};
+ TestStruct *p = &test_struct;
+ Error *errp = NULL;
+ QObject *obj;
+ QDict *qdict;
+
+ visit_type_TestStruct(data->ov, &p, NULL, &errp);
+ g_assert(!error_is_set(&errp));
+
+ obj = qmp_output_get_qobject(data->qov);
+ g_assert(obj != NULL);
+ g_assert(qobject_type(obj) == QTYPE_QDICT);
+
+ qdict = qobject_to_qdict(obj);
+ g_assert_cmpint(qdict_size(qdict), ==, 3);
+ g_assert_cmpint(qdict_get_int(qdict, "integer"), ==, 42);
+ g_assert_cmpint(qdict_get_bool(qdict, "boolean"), ==, 0);
+ g_assert_cmpstr(qdict_get_str(qdict, "string"), ==, "foo");
+
+ QDECREF(qdict);
+}
+
+static void test_visitor_out_struct_nested(TestOutputVisitorData *data,
+ const void *unused)
+{
+ int64_t value = 42;
+ Error *errp = NULL;
+ UserDefNested *ud2;
+ QObject *obj;
+ QDict *qdict, *dict1, *dict2, *dict3, *userdef;
+ const char *string = "user def string";
+ const char *strings[] = { "fourty two", "fourty three", "fourty four",
+ "fourty five" };
+
+ ud2 = g_malloc0(sizeof(*ud2));
+ ud2->string0 = g_strdup(strings[0]);
+
+ ud2->dict1.string1 = g_strdup(strings[1]);
+ ud2->dict1.dict2.userdef1 = g_malloc0(sizeof(UserDefOne));
+ ud2->dict1.dict2.userdef1->string = g_strdup(string);
+ ud2->dict1.dict2.userdef1->integer = value;
+ ud2->dict1.dict2.string2 = g_strdup(strings[2]);
+
+ ud2->dict1.has_dict3 = true;
+ ud2->dict1.dict3.userdef2 = g_malloc0(sizeof(UserDefOne));
+ ud2->dict1.dict3.userdef2->string = g_strdup(string);
+ ud2->dict1.dict3.userdef2->integer = value;
+ ud2->dict1.dict3.string3 = g_strdup(strings[3]);
+
+ visit_type_UserDefNested(data->ov, &ud2, "unused", &errp);
+ g_assert(!error_is_set(&errp));
+
+ obj = qmp_output_get_qobject(data->qov);
+ g_assert(obj != NULL);
+ g_assert(qobject_type(obj) == QTYPE_QDICT);
+
+ qdict = qobject_to_qdict(obj);
+ g_assert_cmpint(qdict_size(qdict), ==, 2);
+ g_assert_cmpstr(qdict_get_str(qdict, "string0"), ==, strings[0]);
+
+ dict1 = qdict_get_qdict(qdict, "dict1");
+ g_assert_cmpint(qdict_size(dict1), ==, 3);
+ g_assert_cmpstr(qdict_get_str(dict1, "string1"), ==, strings[1]);
+
+ dict2 = qdict_get_qdict(dict1, "dict2");
+ g_assert_cmpint(qdict_size(dict2), ==, 2);
+ g_assert_cmpstr(qdict_get_str(dict2, "string2"), ==, strings[2]);
+ userdef = qdict_get_qdict(dict2, "userdef1");
+ g_assert_cmpint(qdict_size(userdef), ==, 2);
+ g_assert_cmpint(qdict_get_int(userdef, "integer"), ==, value);
+ g_assert_cmpstr(qdict_get_str(userdef, "string"), ==, string);
+
+ dict3 = qdict_get_qdict(dict1, "dict3");
+ g_assert_cmpint(qdict_size(dict3), ==, 2);
+ g_assert_cmpstr(qdict_get_str(dict3, "string3"), ==, strings[3]);
+ userdef = qdict_get_qdict(dict3, "userdef2");
+ g_assert_cmpint(qdict_size(userdef), ==, 2);
+ g_assert_cmpint(qdict_get_int(userdef, "integer"), ==, value);
+ g_assert_cmpstr(qdict_get_str(userdef, "string"), ==, string);
+
+ QDECREF(qdict);
+ qapi_free_UserDefNested(ud2);
+}
+
+typedef struct TestStructList
+{
+ TestStruct *value;
+ struct TestStructList *next;
+} TestStructList;
+
+static void visit_type_TestStructList(Visitor *v, TestStructList **obj,
+ const char *name, Error **errp)
+{
+ GenericList *i, **head = (GenericList **)obj;
+
+ visit_start_list(v, name, errp);
+
+ for (*head = i = visit_next_list(v, head, errp); i; i = visit_next_list(v, &i, errp)) {
+ TestStructList *native_i = (TestStructList *)i;
+ visit_type_TestStruct(v, &native_i->value, NULL, errp);
+ }
+
+ visit_end_list(v, errp);
+}
+
+static void test_visitor_out_list(TestOutputVisitorData *data,
+ const void *unused)
+{
+ char *value_str = (char *) "list value";
+ TestStructList *p, *head = NULL;
+ const int max_items = 10;
+ bool value_bool = true;
+ int value_int = 10;
+ Error *errp = NULL;
+ QListEntry *entry;
+ QObject *obj;
+ QList *qlist;
+ int i;
+
+ for (i = 0; i < max_items; i++) {
+ p = g_malloc0(sizeof(*p));
+ p->value = g_malloc0(sizeof(*p->value));
+ p->value->integer = value_int;
+ p->value->boolean = value_bool;
+ p->value->string = value_str;
+
+ p->next = head;
+ head = p;
+ }
+
+ visit_type_TestStructList(data->ov, &head, NULL, &errp);
+ g_assert(!error_is_set(&errp));
+
+ obj = qmp_output_get_qobject(data->qov);
+ g_assert(obj != NULL);
+ g_assert(qobject_type(obj) == QTYPE_QLIST);
+
+ qlist = qobject_to_qlist(obj);
+ g_assert(!qlist_empty(qlist));
+
+ i = 0;
+ QLIST_FOREACH_ENTRY(qlist, entry) {
+ QDict *qdict;
+
+ g_assert(qobject_type(entry->value) == QTYPE_QDICT);
+ qdict = qobject_to_qdict(entry->value);
+ g_assert_cmpint(qdict_size(qdict), ==, 3);
+ g_assert_cmpint(qdict_get_int(qdict, "integer"), ==, value_int);
+ g_assert_cmpint(qdict_get_bool(qdict, "boolean"), ==, value_bool);
+ g_assert_cmpstr(qdict_get_str(qdict, "string"), ==, value_str);
+ i++;
+ }
+ g_assert_cmpint(i, ==, max_items);
+
+ QDECREF(qlist);
+
+ for (p = head; p;) {
+ TestStructList *tmp = p->next;
+ g_free(p->value);
+ g_free(p);
+ p = tmp;
+ }
+}
+
+static void test_visitor_out_list_qapi_free(TestOutputVisitorData *data,
+ const void *unused)
+{
+ UserDefNestedList *p, *head = NULL;
+ const char string[] = "foo bar";
+ int i, max_count = 1024;
+
+ for (i = 0; i < max_count; i++) {
+ p = g_malloc0(sizeof(*p));
+ p->value = g_malloc0(sizeof(*p->value));
+
+ p->value->string0 = g_strdup(string);
+ p->value->dict1.string1 = g_strdup(string);
+ p->value->dict1.dict2.userdef1 = g_malloc0(sizeof(UserDefOne));
+ p->value->dict1.dict2.userdef1->string = g_strdup(string);
+ p->value->dict1.dict2.userdef1->integer = 42;
+ p->value->dict1.dict2.string2 = g_strdup(string);
+ p->value->dict1.has_dict3 = false;
+
+ p->next = head;
+ head = p;
+ }
+
+ qapi_free_UserDefNestedList(head);
+}
+
+static void output_visitor_test_add(const char *testpath,
+ TestOutputVisitorData *data,
+ void (*test_func)(TestOutputVisitorData *data, const void *user_data))
+{
+ g_test_add(testpath, TestOutputVisitorData, data, visitor_output_setup,
+ test_func, visitor_output_teardown);
+}
+
+int main(int argc, char **argv)
+{
+ TestOutputVisitorData out_visitor_data;
+
+ g_test_init(&argc, &argv, NULL);
+
+ output_visitor_test_add("/visitor/output/int",
+ &out_visitor_data, test_visitor_out_int);
+ output_visitor_test_add("/visitor/output/bool",
+ &out_visitor_data, test_visitor_out_bool);
+ output_visitor_test_add("/visitor/output/number",
+ &out_visitor_data, test_visitor_out_number);
+ output_visitor_test_add("/visitor/output/string",
+ &out_visitor_data, test_visitor_out_string);
+ output_visitor_test_add("/visitor/output/no-string",
+ &out_visitor_data, test_visitor_out_no_string);
+ output_visitor_test_add("/visitor/output/enum",
+ &out_visitor_data, test_visitor_out_enum);
+ output_visitor_test_add("/visitor/output/enum-errors",
+ &out_visitor_data, test_visitor_out_enum_errors);
+ output_visitor_test_add("/visitor/output/struct",
+ &out_visitor_data, test_visitor_out_struct);
+ output_visitor_test_add("/visitor/output/struct-nested",
+ &out_visitor_data, test_visitor_out_struct_nested);
+ output_visitor_test_add("/visitor/output/list",
+ &out_visitor_data, test_visitor_out_list);
+ output_visitor_test_add("/visitor/output/list-qapi-free",
+ &out_visitor_data, test_visitor_out_list_qapi_free);
+
+ g_test_run();
+
+ return 0;
+}
diff --git a/test-visitor.c b/test-visitor.c
deleted file mode 100644
index f90b711883..0000000000
--- a/test-visitor.c
+++ /dev/null
@@ -1,338 +0,0 @@
-#include <glib.h>
-#include "qapi/qmp-output-visitor.h"
-#include "qapi/qmp-input-visitor.h"
-#include "test-qapi-types.h"
-#include "test-qapi-visit.h"
-#include "qemu-objects.h"
-
-typedef struct TestStruct
-{
- int64_t x;
- int64_t y;
-} TestStruct;
-
-typedef struct TestStructList
-{
- TestStruct *value;
- struct TestStructList *next;
-} TestStructList;
-
-static void visit_type_TestStruct(Visitor *v, TestStruct **obj, const char *name, Error **errp)
-{
- visit_start_struct(v, (void **)obj, "TestStruct", name, sizeof(TestStruct), errp);
- visit_type_int(v, &(*obj)->x, "x", errp);
- visit_type_int(v, &(*obj)->y, "y", errp);
- visit_end_struct(v, errp);
-}
-
-static void visit_type_TestStructList(Visitor *m, TestStructList ** obj, const char *name, Error **errp)
-{
- GenericList *i, **head = (GenericList **)obj;
-
- visit_start_list(m, name, errp);
-
- for (*head = i = visit_next_list(m, head, errp); i; i = visit_next_list(m, &i, errp)) {
- TestStructList *native_i = (TestStructList *)i;
- visit_type_TestStruct(m, &native_i->value, NULL, errp);
- }
-
- visit_end_list(m, errp);
-}
-
-/* test core visitor methods */
-static void test_visitor_core(void)
-{
- QmpOutputVisitor *mo;
- QmpInputVisitor *mi;
- Visitor *v;
- TestStruct ts = { 42, 82 };
- TestStruct *pts = &ts;
- TestStructList *lts = NULL;
- Error *err = NULL;
- QObject *obj;
- QList *qlist;
- QDict *qdict;
- QString *str;
- int64_t value = 0;
-
- mo = qmp_output_visitor_new();
- v = qmp_output_get_visitor(mo);
-
- visit_type_TestStruct(v, &pts, NULL, &err);
-
- obj = qmp_output_get_qobject(mo);
-
- str = qobject_to_json(obj);
-
- printf("%s\n", qstring_get_str(str));
-
- QDECREF(str);
-
- obj = QOBJECT(qint_from_int(0x42));
-
- mi = qmp_input_visitor_new(obj);
- v = qmp_input_get_visitor(mi);
-
- visit_type_int(v, &value, NULL, &err);
- if (err) {
- g_error("%s", error_get_pretty(err));
- }
-
- g_assert(value == 0x42);
-
- qobject_decref(obj);
-
- obj = qobject_from_json("{'x': 42, 'y': 84}");
- mi = qmp_input_visitor_new(obj);
- v = qmp_input_get_visitor(mi);
-
- pts = NULL;
-
- visit_type_TestStruct(v, &pts, NULL, &err);
- if (err) {
- g_error("%s", error_get_pretty(err));
- }
-
- g_assert(pts != NULL);
- g_assert(pts->x == 42);
- g_assert(pts->y == 84);
-
- qobject_decref(obj);
- g_free(pts);
-
- /* test list input visitor */
- obj = qobject_from_json("[{'x': 42, 'y': 84}, {'x': 12, 'y': 24}]");
- mi = qmp_input_visitor_new(obj);
- v = qmp_input_get_visitor(mi);
-
- visit_type_TestStructList(v, &lts, NULL, &err);
- if (err) {
- g_error("%s", error_get_pretty(err));
- }
-
- g_assert(lts != NULL);
- g_assert(lts->value->x == 42);
- g_assert(lts->value->y == 84);
-
- g_assert(lts->next != NULL);
- g_assert(lts->next->value->x == 12);
- g_assert(lts->next->value->y == 24);
- g_assert(lts->next->next == NULL);
-
- qobject_decref(obj);
-
- /* test list output visitor */
- mo = qmp_output_visitor_new();
- v = qmp_output_get_visitor(mo);
- visit_type_TestStructList(v, &lts, NULL, &err);
- if (err) {
- g_error("%s", error_get_pretty(err));
- }
- obj = qmp_output_get_qobject(mo);
- g_print("obj: %s\n", qstring_get_str(qobject_to_json(obj)));
-
- qlist = qobject_to_qlist(obj);
- assert(qlist);
- obj = qlist_pop(qlist);
- qdict = qobject_to_qdict(obj);
- assert(qdict);
- assert(qdict_get_int(qdict, "x") == 42);
- assert(qdict_get_int(qdict, "y") == 84);
- qobject_decref(obj);
-
- obj = qlist_pop(qlist);
- qdict = qobject_to_qdict(obj);
- assert(qdict);
- assert(qdict_get_int(qdict, "x") == 12);
- assert(qdict_get_int(qdict, "y") == 24);
- qobject_decref(obj);
-
- qmp_output_visitor_cleanup(mo);
- QDECREF(qlist);
-}
-
-/* test deep nesting with refs to other user-defined types */
-static void test_nested_structs(void)
-{
- QmpOutputVisitor *mo;
- QmpInputVisitor *mi;
- Visitor *v;
- UserDefOne ud1;
- UserDefOne *ud1_p = &ud1, *ud1c_p = NULL;
- UserDefTwo ud2;
- UserDefTwo *ud2_p = &ud2, *ud2c_p = NULL;
- Error *err = NULL;
- QObject *obj;
- QString *str;
-
- ud1.integer = 42;
- ud1.string = strdup("forty two");
-
- /* sanity check */
- mo = qmp_output_visitor_new();
- v = qmp_output_get_visitor(mo);
- visit_type_UserDefOne(v, &ud1_p, "o_O", &err);
- if (err) {
- g_error("%s", error_get_pretty(err));
- }
- obj = qmp_output_get_qobject(mo);
- g_assert(obj);
- qobject_decref(obj);
-
- ud2.string = strdup("forty three");
- ud2.dict.string = strdup("forty four");
- ud2.dict.dict.userdef = ud1_p;
- ud2.dict.dict.string = strdup("forty five");
- ud2.dict.has_dict2 = true;
- ud2.dict.dict2.userdef = ud1_p;
- ud2.dict.dict2.string = strdup("forty six");
-
- /* c type -> qobject */
- mo = qmp_output_visitor_new();
- v = qmp_output_get_visitor(mo);
- visit_type_UserDefTwo(v, &ud2_p, "unused", &err);
- if (err) {
- g_error("%s", error_get_pretty(err));
- }
- obj = qmp_output_get_qobject(mo);
- g_assert(obj);
- str = qobject_to_json_pretty(obj);
- g_print("%s\n", qstring_get_str(str));
- QDECREF(str);
-
- /* qobject -> c type, should match original struct */
- mi = qmp_input_visitor_new(obj);
- v = qmp_input_get_visitor(mi);
- visit_type_UserDefTwo(v, &ud2c_p, NULL, &err);
- if (err) {
- g_error("%s", error_get_pretty(err));
- }
-
- g_assert(!g_strcmp0(ud2c_p->string, ud2.string));
- g_assert(!g_strcmp0(ud2c_p->dict.string, ud2.dict.string));
-
- ud1c_p = ud2c_p->dict.dict.userdef;
- g_assert(ud1c_p->integer == ud1_p->integer);
- g_assert(!g_strcmp0(ud1c_p->string, ud1_p->string));
-
- g_assert(!g_strcmp0(ud2c_p->dict.dict.string, ud2.dict.dict.string));
-
- ud1c_p = ud2c_p->dict.dict2.userdef;
- g_assert(ud1c_p->integer == ud1_p->integer);
- g_assert(!g_strcmp0(ud1c_p->string, ud1_p->string));
-
- g_assert(!g_strcmp0(ud2c_p->dict.dict2.string, ud2.dict.dict2.string));
- g_free(ud1.string);
- g_free(ud2.string);
- g_free(ud2.dict.string);
- g_free(ud2.dict.dict.string);
- g_free(ud2.dict.dict2.string);
-
- qapi_free_UserDefTwo(ud2c_p);
-
- qobject_decref(obj);
-}
-
-/* test enum values */
-static void test_enums(void)
-{
- QmpOutputVisitor *mo;
- QmpInputVisitor *mi;
- Visitor *v;
- EnumOne enum1 = ENUM_ONE_VALUE2, enum1_cpy = ENUM_ONE_VALUE1;
- Error *err = NULL;
- QObject *obj;
- QString *str;
-
- /* C type -> QObject */
- mo = qmp_output_visitor_new();
- v = qmp_output_get_visitor(mo);
- visit_type_EnumOne(v, &enum1, "unused", &err);
- if (err) {
- g_error("%s", error_get_pretty(err));
- }
- obj = qmp_output_get_qobject(mo);
- g_assert(obj);
- str = qobject_to_json_pretty(obj);
- g_print("%s\n", qstring_get_str(str));
- QDECREF(str);
- g_assert(g_strcmp0(qstring_get_str(qobject_to_qstring(obj)), "value2") == 0);
-
- /* QObject -> C type */
- mi = qmp_input_visitor_new(obj);
- v = qmp_input_get_visitor(mi);
- visit_type_EnumOne(v, &enum1_cpy, "unused", &err);
- if (err) {
- g_error("%s", error_get_pretty(err));
- }
- g_debug("enum1_cpy, enum1: %d, %d", enum1_cpy, enum1);
- g_assert(enum1_cpy == enum1);
-
- qobject_decref(obj);
-}
-
-/* test enum values nested in schema-defined structs */
-static void test_nested_enums(void)
-{
- QmpOutputVisitor *mo;
- QmpInputVisitor *mi;
- Visitor *v;
- NestedEnumsOne *nested_enums, *nested_enums_cpy = NULL;
- Error *err = NULL;
- QObject *obj;
- QString *str;
-
- nested_enums = g_malloc0(sizeof(NestedEnumsOne));
- nested_enums->enum1 = ENUM_ONE_VALUE1;
- nested_enums->enum2 = ENUM_ONE_VALUE2;
- nested_enums->enum3 = ENUM_ONE_VALUE3;
- nested_enums->enum4 = ENUM_ONE_VALUE3;
- nested_enums->has_enum2 = false;
- nested_enums->has_enum4 = true;
-
- /* C type -> QObject */
- mo = qmp_output_visitor_new();
- v = qmp_output_get_visitor(mo);
- visit_type_NestedEnumsOne(v, &nested_enums, NULL, &err);
- if (err) {
- g_error("%s", error_get_pretty(err));
- }
- obj = qmp_output_get_qobject(mo);
- g_assert(obj);
- str = qobject_to_json_pretty(obj);
- g_print("%s\n", qstring_get_str(str));
- QDECREF(str);
-
- /* QObject -> C type */
- mi = qmp_input_visitor_new(obj);
- v = qmp_input_get_visitor(mi);
- visit_type_NestedEnumsOne(v, &nested_enums_cpy, NULL, &err);
- if (err) {
- g_error("%s", error_get_pretty(err));
- }
- g_assert(nested_enums_cpy);
- g_assert(nested_enums_cpy->enum1 == nested_enums->enum1);
- g_assert(nested_enums_cpy->enum3 == nested_enums->enum3);
- g_assert(nested_enums_cpy->enum4 == nested_enums->enum4);
- g_assert(nested_enums_cpy->has_enum2 == false);
- g_assert(nested_enums_cpy->has_enum4 == true);
-
- qmp_output_visitor_cleanup(mo);
- qmp_input_visitor_cleanup(mi);
- qapi_free_NestedEnumsOne(nested_enums);
- qapi_free_NestedEnumsOne(nested_enums_cpy);
-}
-
-int main(int argc, char **argv)
-{
- g_test_init(&argc, &argv, NULL);
-
- g_test_add_func("/0.15/visitor_core", test_visitor_core);
- g_test_add_func("/0.15/nested_structs", test_nested_structs);
- g_test_add_func("/0.15/enums", test_enums);
- g_test_add_func("/0.15/nested_enums", test_nested_enums);
-
- g_test_run();
-
- return 0;
-}
diff --git a/ui/vnc-jobs-async.c b/ui/vnc-jobs-async.c
index de5ea6b5d8..9b3016c129 100644
--- a/ui/vnc-jobs-async.c
+++ b/ui/vnc-jobs-async.c
@@ -318,7 +318,7 @@ void vnc_start_worker_thread(void)
return ;
q = vnc_queue_init();
- qemu_thread_create(&q->thread, vnc_worker_thread, q);
+ qemu_thread_create(&q->thread, vnc_worker_thread, q, QEMU_THREAD_DETACHED);
queue = q; /* Set global queue */
}