summary refs log tree commit diff stats
path: root/tests
diff options
context:
space:
mode:
Diffstat (limited to 'tests')
-rw-r--r--tests/Makefile7
-rw-r--r--tests/check-qdict.c87
-rw-r--r--tests/libqos/pci.c2
-rwxr-xr-xtests/qemu-iotests/0302
-rwxr-xr-xtests/qemu-iotests/03920
-rw-r--r--tests/qemu-iotests/039.out3
-rw-r--r--tests/qemu-iotests/067.out10
-rwxr-xr-xtests/qemu-iotests/0707
-rw-r--r--tests/qemu-iotests/070.out7
-rwxr-xr-xtests/qemu-iotests/089129
-rw-r--r--tests/qemu-iotests/089.out50
-rwxr-xr-xtests/qemu-iotests/0916
-rwxr-xr-xtests/qemu-iotests/09298
-rw-r--r--tests/qemu-iotests/092.out38
-rw-r--r--tests/qemu-iotests/common.filter1
-rw-r--r--tests/qemu-iotests/group2
-rw-r--r--tests/qemu-iotests/sample_images/test-disk2vhd.vhdx.bz2bin0 -> 1424 bytes
-rw-r--r--tests/qom-test.c15
-rw-r--r--tests/tcg/lm32/Makefile15
-rw-r--r--tests/tcg/lm32/crt.S4
-rw-r--r--tests/tcg/lm32/helper.S65
-rw-r--r--tests/tcg/lm32/macros.inc37
-rw-r--r--tests/tcg/lm32/test_lb.S4
-rw-r--r--tests/tcg/lm32/test_lbu.S4
-rw-r--r--tests/tcg/lm32/test_lh.S4
-rw-r--r--tests/tcg/lm32/test_lhu.S4
-rw-r--r--tests/tcg/lm32/test_lw.S2
-rw-r--r--tests/tcg/lm32/test_sb.S2
-rw-r--r--tests/tcg/lm32/test_scall.S4
-rw-r--r--tests/tcg/lm32/test_sh.S2
-rw-r--r--tests/tcg/lm32/test_sw.S3
-rw-r--r--tests/tcg/xtensa/test_mmu.S246
-rw-r--r--tests/test-qemu-opts.c441
-rw-r--r--tests/test-qmp-output-visitor.c11
-rw-r--r--tests/test-thread-pool.c2
-rw-r--r--tests/usb-hcd-ehci-test.c153
36 files changed, 1427 insertions, 60 deletions
diff --git a/tests/Makefile b/tests/Makefile
index ba93e8a1d4..361bb7b6e3 100644
--- a/tests/Makefile
+++ b/tests/Makefile
@@ -60,6 +60,8 @@ check-unit-y += tests/test-qdev-global-props$(EXESUF)
 check-unit-y += tests/check-qom-interface$(EXESUF)
 gcov-files-check-qom-interface-y = qom/object.c
 check-unit-$(CONFIG_POSIX) += tests/test-vmstate$(EXESUF)
+check-unit-y += tests/test-qemu-opts$(EXESUF)
+gcov-files-test-qemu-opts-y = qom/test-qemu-opts.c
 
 check-block-$(CONFIG_POSIX) += tests/qemu-iotests-quick.sh
 
@@ -152,6 +154,8 @@ gcov-files-i386-y += hw/pci-bridge/ioh3420.c
 check-qtest-i386-y += tests/usb-hcd-ehci-test$(EXESUF)
 gcov-files-i386-y += hw/usb/hcd-ehci.c
 gcov-files-i386-y += hw/usb/hcd-uhci.c
+gcov-files-i386-y += hw/usb/dev-hid.c
+gcov-files-i386-y += hw/usb/dev-storage.c
 check-qtest-x86_64-y = $(check-qtest-i386-y)
 gcov-files-i386-y += i386-softmmu/hw/timer/mc146818rtc.c
 gcov-files-x86_64-y = $(subst i386-softmmu/,x86_64-softmmu/,$(gcov-files-i386-y))
@@ -317,8 +321,9 @@ tests/ac97-test$(EXESUF): tests/ac97-test.o
 tests/es1370-test$(EXESUF): tests/es1370-test.o
 tests/intel-hda-test$(EXESUF): tests/intel-hda-test.o
 tests/ioh3420-test$(EXESUF): tests/ioh3420-test.o
-tests/usb-hcd-ehci-test$(EXESUF): tests/usb-hcd-ehci-test.o
+tests/usb-hcd-ehci-test$(EXESUF): tests/usb-hcd-ehci-test.o $(libqos-pc-obj-y)
 tests/qemu-iotests/socket_scm_helper$(EXESUF): tests/qemu-iotests/socket_scm_helper.o
+tests/test-qemu-opts$(EXESUF): tests/test-qemu-opts.o libqemuutil.a libqemustub.a
 
 # QTest rules
 
diff --git a/tests/check-qdict.c b/tests/check-qdict.c
index 2ad0f7827e..a9296f0833 100644
--- a/tests/check-qdict.c
+++ b/tests/check-qdict.c
@@ -444,6 +444,92 @@ static void qdict_array_split_test(void)
     QDECREF(test_dict);
 }
 
+static void qdict_join_test(void)
+{
+    QDict *dict1, *dict2;
+    bool overwrite = false;
+    int i;
+
+    dict1 = qdict_new();
+    dict2 = qdict_new();
+
+
+    /* Test everything once without overwrite and once with */
+    do
+    {
+        /* Test empty dicts */
+        qdict_join(dict1, dict2, overwrite);
+
+        g_assert(qdict_size(dict1) == 0);
+        g_assert(qdict_size(dict2) == 0);
+
+
+        /* First iteration: Test movement */
+        /* Second iteration: Test empty source and non-empty destination */
+        qdict_put(dict2, "foo", qint_from_int(42));
+
+        for (i = 0; i < 2; i++) {
+            qdict_join(dict1, dict2, overwrite);
+
+            g_assert(qdict_size(dict1) == 1);
+            g_assert(qdict_size(dict2) == 0);
+
+            g_assert(qdict_get_int(dict1, "foo") == 42);
+        }
+
+
+        /* Test non-empty source and destination without conflict */
+        qdict_put(dict2, "bar", qint_from_int(23));
+
+        qdict_join(dict1, dict2, overwrite);
+
+        g_assert(qdict_size(dict1) == 2);
+        g_assert(qdict_size(dict2) == 0);
+
+        g_assert(qdict_get_int(dict1, "foo") == 42);
+        g_assert(qdict_get_int(dict1, "bar") == 23);
+
+
+        /* Test conflict */
+        qdict_put(dict2, "foo", qint_from_int(84));
+
+        qdict_join(dict1, dict2, overwrite);
+
+        g_assert(qdict_size(dict1) == 2);
+        g_assert(qdict_size(dict2) == !overwrite);
+
+        g_assert(qdict_get_int(dict1, "foo") == overwrite ? 84 : 42);
+        g_assert(qdict_get_int(dict1, "bar") == 23);
+
+        if (!overwrite) {
+            g_assert(qdict_get_int(dict2, "foo") == 84);
+        }
+
+
+        /* Check the references */
+        g_assert(qdict_get(dict1, "foo")->refcnt == 1);
+        g_assert(qdict_get(dict1, "bar")->refcnt == 1);
+
+        if (!overwrite) {
+            g_assert(qdict_get(dict2, "foo")->refcnt == 1);
+        }
+
+
+        /* Clean up */
+        qdict_del(dict1, "foo");
+        qdict_del(dict1, "bar");
+
+        if (!overwrite) {
+            qdict_del(dict2, "foo");
+        }
+    }
+    while (overwrite ^= true);
+
+
+    QDECREF(dict1);
+    QDECREF(dict2);
+}
+
 /*
  * Errors test-cases
  */
@@ -584,6 +670,7 @@ int main(int argc, char **argv)
     g_test_add_func("/public/iterapi", qdict_iterapi_test);
     g_test_add_func("/public/flatten", qdict_flatten_test);
     g_test_add_func("/public/array_split", qdict_array_split_test);
+    g_test_add_func("/public/join", qdict_join_test);
 
     g_test_add_func("/errors/put_exists", qdict_put_exists_test);
     g_test_add_func("/errors/get_not_exists", qdict_get_not_exists_test);
diff --git a/tests/libqos/pci.c b/tests/libqos/pci.c
index 7e0907b514..c9a0b9134a 100644
--- a/tests/libqos/pci.c
+++ b/tests/libqos/pci.c
@@ -103,7 +103,7 @@ void qpci_config_writew(QPCIDevice *dev, uint8_t offset, uint16_t value)
 
 void qpci_config_writel(QPCIDevice *dev, uint8_t offset, uint32_t value)
 {
-    dev->bus->config_writew(dev->bus, dev->devfn, offset, value);
+    dev->bus->config_writel(dev->bus, dev->devfn, offset, value);
 }
 
 
diff --git a/tests/qemu-iotests/030 b/tests/qemu-iotests/030
index 8cb61fd7ec..8ce2373cf5 100755
--- a/tests/qemu-iotests/030
+++ b/tests/qemu-iotests/030
@@ -35,7 +35,7 @@ class TestSingleDrive(iotests.QMPTestCase):
         qemu_img('create', '-f', iotests.imgfmt, '-o', 'backing_file=%s' % backing_img, mid_img)
         qemu_img('create', '-f', iotests.imgfmt, '-o', 'backing_file=%s' % mid_img, test_img)
         qemu_io('-c', 'write -P 0x1 0 512', backing_img)
-        self.vm = iotests.VM().add_drive(test_img)
+        self.vm = iotests.VM().add_drive("blkdebug::" + test_img)
         self.vm.launch()
 
     def tearDown(self):
diff --git a/tests/qemu-iotests/039 b/tests/qemu-iotests/039
index b9cbe99560..27fe4bdacc 100755
--- a/tests/qemu-iotests/039
+++ b/tests/qemu-iotests/039
@@ -47,6 +47,11 @@ _supported_os Linux
 _default_cache_mode "writethrough"
 _supported_cache_modes "writethrough"
 
+_no_dump_exec()
+{
+    (ulimit -c 0; exec "$@")
+}
+
 size=128M
 
 echo
@@ -67,10 +72,7 @@ echo "== Creating a dirty image file =="
 IMGOPTS="compat=1.1,lazy_refcounts=on"
 _make_test_img $size
 
-old_ulimit=$(ulimit -c)
-ulimit -c 0 # do not produce a core dump on abort(3)
-$QEMU_IO -c "write -P 0x5a 0 512" -c "abort" "$TEST_IMG" | _filter_qemu_io
-ulimit -c "$old_ulimit"
+_no_dump_exec $QEMU_IO -c "write -P 0x5a 0 512" -c "abort" "$TEST_IMG" 2>&1 | _filter_qemu_io
 
 # The dirty bit must be set
 ./qcow2.py "$TEST_IMG" dump-header | grep incompatible_features
@@ -103,10 +105,7 @@ echo "== Opening a dirty image read/write should repair it =="
 IMGOPTS="compat=1.1,lazy_refcounts=on"
 _make_test_img $size
 
-old_ulimit=$(ulimit -c)
-ulimit -c 0 # do not produce a core dump on abort(3)
-$QEMU_IO -c "write -P 0x5a 0 512" -c "abort" "$TEST_IMG" | _filter_qemu_io
-ulimit -c "$old_ulimit"
+_no_dump_exec $QEMU_IO -c "write -P 0x5a 0 512" -c "abort" "$TEST_IMG" 2>&1 | _filter_qemu_io
 
 # The dirty bit must be set
 ./qcow2.py "$TEST_IMG" dump-header | grep incompatible_features
@@ -122,10 +121,7 @@ echo "== Creating an image file with lazy_refcounts=off =="
 IMGOPTS="compat=1.1,lazy_refcounts=off"
 _make_test_img $size
 
-old_ulimit=$(ulimit -c)
-ulimit -c 0 # do not produce a core dump on abort(3)
-$QEMU_IO -c "write -P 0x5a 0 512" -c "abort" "$TEST_IMG" | _filter_qemu_io
-ulimit -c "$old_ulimit"
+_no_dump_exec $QEMU_IO -c "write -P 0x5a 0 512" -c "abort" "$TEST_IMG" 2>&1 | _filter_qemu_io
 
 # The dirty bit must not be set since lazy_refcounts=off
 ./qcow2.py "$TEST_IMG" dump-header | grep incompatible_features
diff --git a/tests/qemu-iotests/039.out b/tests/qemu-iotests/039.out
index fb31ae0624..67e774430f 100644
--- a/tests/qemu-iotests/039.out
+++ b/tests/qemu-iotests/039.out
@@ -11,6 +11,7 @@ No errors were found on the image.
 Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 
 wrote 512/512 bytes at offset 0
 512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+./039: Aborted                 ( ulimit -c 0; exec "$@" )
 incompatible_features     0x1
 ERROR cluster 5 refcount=0 reference=1
 ERROR OFLAG_COPIED data cluster: l2_entry=8000000000050000 refcount=0
@@ -42,6 +43,7 @@ read 512/512 bytes at offset 0
 Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 
 wrote 512/512 bytes at offset 0
 512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+./039: Aborted                 ( ulimit -c 0; exec "$@" )
 incompatible_features     0x1
 Repairing cluster 5 refcount=0 reference=1
 wrote 512/512 bytes at offset 0
@@ -52,6 +54,7 @@ incompatible_features     0x0
 Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 
 wrote 512/512 bytes at offset 0
 512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+./039: Aborted                 ( ulimit -c 0; exec "$@" )
 incompatible_features     0x0
 No errors were found on the image.
 
diff --git a/tests/qemu-iotests/067.out b/tests/qemu-iotests/067.out
index 8d271cc41a..7e090b95ab 100644
--- a/tests/qemu-iotests/067.out
+++ b/tests/qemu-iotests/067.out
@@ -6,7 +6,7 @@ Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728
 Testing: -drive file=TEST_DIR/t.qcow2,format=qcow2,if=none,id=disk -device virtio-blk-pci,drive=disk,id=virtio0
 QMP_VERSION
 {"return": {}}
-{"return": [{"io-status": "ok", "device": "disk", "locked": false, "removable": false, "inserted": {"iops_rd": 0, "image": {"virtual-size": 134217728, "filename": "TEST_DIR/t.qcow2", "cluster-size": 65536, "format": "qcow2", "actual-size": SIZE, "format-specific": {"type": "qcow2", "data": {"compat": "1.1", "lazy-refcounts": false}}, "dirty-flag": false}, "iops_wr": 0, "ro": false, "backing_file_depth": 0, "drv": "qcow2", "iops": 0, "bps_wr": 0, "encrypted": false, "bps": 0, "bps_rd": 0, "file": "TEST_DIR/t.qcow2", "encryption_key_missing": false}, "type": "unknown"}, {"io-status": "ok", "device": "ide1-cd0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"device": "floppy0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"device": "sd0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}]}
+{"return": [{"io-status": "ok", "device": "disk", "locked": false, "removable": false, "inserted": {"iops_rd": 0, "detect_zeroes": "off", "image": {"virtual-size": 134217728, "filename": "TEST_DIR/t.qcow2", "cluster-size": 65536, "format": "qcow2", "actual-size": SIZE, "format-specific": {"type": "qcow2", "data": {"compat": "1.1", "lazy-refcounts": false}}, "dirty-flag": false}, "iops_wr": 0, "ro": false, "backing_file_depth": 0, "drv": "qcow2", "iops": 0, "bps_wr": 0, "encrypted": false, "bps": 0, "bps_rd": 0, "file": "TEST_DIR/t.qcow2", "encryption_key_missing": false}, "type": "unknown"}, {"io-status": "ok", "device": "ide1-cd0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"device": "floppy0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"device": "sd0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}]}
 {"return": {}}
 {"return": {}}
 {"timestamp": {"seconds":  TIMESTAMP, "microseconds":  TIMESTAMP}, "event": "DEVICE_DELETED", "data": {"path": "/machine/peripheral/virtio0/virtio-backend"}}
@@ -24,7 +24,7 @@ QMP_VERSION
 Testing: -drive file=TEST_DIR/t.qcow2,format=qcow2,if=none,id=disk
 QMP_VERSION
 {"return": {}}
-{"return": [{"device": "disk", "locked": false, "removable": true, "inserted": {"iops_rd": 0, "image": {"virtual-size": 134217728, "filename": "TEST_DIR/t.qcow2", "cluster-size": 65536, "format": "qcow2", "actual-size": SIZE, "format-specific": {"type": "qcow2", "data": {"compat": "1.1", "lazy-refcounts": false}}, "dirty-flag": false}, "iops_wr": 0, "ro": false, "backing_file_depth": 0, "drv": "qcow2", "iops": 0, "bps_wr": 0, "encrypted": false, "bps": 0, "bps_rd": 0, "file": "TEST_DIR/t.qcow2", "encryption_key_missing": false}, "tray_open": false, "type": "unknown"}, {"io-status": "ok", "device": "ide1-cd0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"device": "floppy0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"device": "sd0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}]}
+{"return": [{"device": "disk", "locked": false, "removable": true, "inserted": {"iops_rd": 0, "detect_zeroes": "off", "image": {"virtual-size": 134217728, "filename": "TEST_DIR/t.qcow2", "cluster-size": 65536, "format": "qcow2", "actual-size": SIZE, "format-specific": {"type": "qcow2", "data": {"compat": "1.1", "lazy-refcounts": false}}, "dirty-flag": false}, "iops_wr": 0, "ro": false, "backing_file_depth": 0, "drv": "qcow2", "iops": 0, "bps_wr": 0, "encrypted": false, "bps": 0, "bps_rd": 0, "file": "TEST_DIR/t.qcow2", "encryption_key_missing": false}, "tray_open": false, "type": "unknown"}, {"io-status": "ok", "device": "ide1-cd0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"device": "floppy0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"device": "sd0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}]}
 {"return": {}}
 {"return": {}}
 {"return": {}}
@@ -44,7 +44,7 @@ Testing:
 QMP_VERSION
 {"return": {}}
 {"return": "OK\r\n"}
-{"return": [{"io-status": "ok", "device": "ide1-cd0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"device": "floppy0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"device": "sd0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"device": "disk", "locked": false, "removable": true, "inserted": {"iops_rd": 0, "image": {"virtual-size": 134217728, "filename": "TEST_DIR/t.qcow2", "cluster-size": 65536, "format": "qcow2", "actual-size": SIZE, "format-specific": {"type": "qcow2", "data": {"compat": "1.1", "lazy-refcounts": false}}, "dirty-flag": false}, "iops_wr": 0, "ro": false, "backing_file_depth": 0, "drv": "qcow2", "iops": 0, "bps_wr": 0, "encrypted": false, "bps": 0, "bps_rd": 0, "file": "TEST_DIR/t.qcow2", "encryption_key_missing": false}, "tray_open": false, "type": "unknown"}]}
+{"return": [{"io-status": "ok", "device": "ide1-cd0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"device": "floppy0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"device": "sd0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"device": "disk", "locked": false, "removable": true, "inserted": {"iops_rd": 0, "detect_zeroes": "off", "image": {"virtual-size": 134217728, "filename": "TEST_DIR/t.qcow2", "cluster-size": 65536, "format": "qcow2", "actual-size": SIZE, "format-specific": {"type": "qcow2", "data": {"compat": "1.1", "lazy-refcounts": false}}, "dirty-flag": false}, "iops_wr": 0, "ro": false, "backing_file_depth": 0, "drv": "qcow2", "iops": 0, "bps_wr": 0, "encrypted": false, "bps": 0, "bps_rd": 0, "file": "TEST_DIR/t.qcow2", "encryption_key_missing": false}, "tray_open": false, "type": "unknown"}]}
 {"return": {}}
 {"return": {}}
 {"return": {}}
@@ -64,14 +64,14 @@ Testing:
 QMP_VERSION
 {"return": {}}
 {"return": {}}
-{"return": [{"io-status": "ok", "device": "ide1-cd0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"device": "floppy0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"device": "sd0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"device": "disk", "locked": false, "removable": true, "inserted": {"iops_rd": 0, "image": {"virtual-size": 134217728, "filename": "TEST_DIR/t.qcow2", "cluster-size": 65536, "format": "qcow2", "actual-size": SIZE, "format-specific": {"type": "qcow2", "data": {"compat": "1.1", "lazy-refcounts": false}}, "dirty-flag": false}, "iops_wr": 0, "ro": false, "backing_file_depth": 0, "drv": "qcow2", "iops": 0, "bps_wr": 0, "encrypted": false, "bps": 0, "bps_rd": 0, "file": "TEST_DIR/t.qcow2", "encryption_key_missing": false}, "tray_open": false, "type": "unknown"}]}
+{"return": [{"io-status": "ok", "device": "ide1-cd0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"device": "floppy0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"device": "sd0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"device": "disk", "locked": false, "removable": true, "inserted": {"iops_rd": 0, "detect_zeroes": "off", "image": {"virtual-size": 134217728, "filename": "TEST_DIR/t.qcow2", "cluster-size": 65536, "format": "qcow2", "actual-size": SIZE, "format-specific": {"type": "qcow2", "data": {"compat": "1.1", "lazy-refcounts": false}}, "dirty-flag": false}, "iops_wr": 0, "ro": false, "backing_file_depth": 0, "drv": "qcow2", "iops": 0, "bps_wr": 0, "encrypted": false, "bps": 0, "bps_rd": 0, "file": "TEST_DIR/t.qcow2", "encryption_key_missing": false}, "tray_open": false, "type": "unknown"}]}
 {"return": {}}
 {"return": {}}
 {"return": {}}
 {"timestamp": {"seconds":  TIMESTAMP, "microseconds":  TIMESTAMP}, "event": "DEVICE_DELETED", "data": {"path": "/machine/peripheral/virtio0/virtio-backend"}}
 {"timestamp": {"seconds":  TIMESTAMP, "microseconds":  TIMESTAMP}, "event": "DEVICE_DELETED", "data": {"device": "virtio0", "path": "/machine/peripheral/virtio0"}}
 {"timestamp": {"seconds":  TIMESTAMP, "microseconds":  TIMESTAMP}, "event": "RESET"}
-{"return": [{"io-status": "ok", "device": "ide1-cd0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"device": "floppy0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"device": "sd0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"io-status": "ok", "device": "disk", "locked": false, "removable": true, "inserted": {"iops_rd": 0, "image": {"virtual-size": 134217728, "filename": "TEST_DIR/t.qcow2", "cluster-size": 65536, "format": "qcow2", "actual-size": SIZE, "format-specific": {"type": "qcow2", "data": {"compat": "1.1", "lazy-refcounts": false}}, "dirty-flag": false}, "iops_wr": 0, "ro": false, "backing_file_depth": 0, "drv": "qcow2", "iops": 0, "bps_wr": 0, "encrypted": false, "bps": 0, "bps_rd": 0, "file": "TEST_DIR/t.qcow2", "encryption_key_missing": false}, "tray_open": false, "type": "unknown"}]}
+{"return": [{"io-status": "ok", "device": "ide1-cd0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"device": "floppy0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"device": "sd0", "locked": false, "removable": true, "tray_open": false, "type": "unknown"}, {"io-status": "ok", "device": "disk", "locked": false, "removable": true, "inserted": {"iops_rd": 0, "detect_zeroes": "off", "image": {"virtual-size": 134217728, "filename": "TEST_DIR/t.qcow2", "cluster-size": 65536, "format": "qcow2", "actual-size": SIZE, "format-specific": {"type": "qcow2", "data": {"compat": "1.1", "lazy-refcounts": false}}, "dirty-flag": false}, "iops_wr": 0, "ro": false, "backing_file_depth": 0, "drv": "qcow2", "iops": 0, "bps_wr": 0, "encrypted": false, "bps": 0, "bps_rd": 0, "file": "TEST_DIR/t.qcow2", "encryption_key_missing": false}, "tray_open": false, "type": "unknown"}]}
 {"return": {}}
 {"timestamp": {"seconds":  TIMESTAMP, "microseconds":  TIMESTAMP}, "event": "SHUTDOWN"}
 {"timestamp": {"seconds":  TIMESTAMP, "microseconds":  TIMESTAMP}, "event": "DEVICE_TRAY_MOVED", "data": {"device": "ide1-cd0", "tray-open": true}}
diff --git a/tests/qemu-iotests/070 b/tests/qemu-iotests/070
index ce71fa4a22..ea0dae7e9c 100755
--- a/tests/qemu-iotests/070
+++ b/tests/qemu-iotests/070
@@ -72,6 +72,13 @@ echo "=== Verify open image read-only succeeds after log replay ==="
 $QEMU_IO -r -c "read -pP 0xa5 0 18M" "$TEST_IMG" 2>&1 | _filter_testdir \
                                                       | _filter_qemu_io
 
+_cleanup_test_img
+_use_sample_img test-disk2vhd.vhdx.bz2
+
+echo
+echo "=== Verify image created by Disk2VHD can be opened ==="
+$QEMU_IMG info "$TEST_IMG" 2>&1 | _filter_testdir | _filter_qemu
+
 # success, all done
 echo "*** done"
 rm -f $seq.full
diff --git a/tests/qemu-iotests/070.out b/tests/qemu-iotests/070.out
index 922d62cb51..15f1fc1471 100644
--- a/tests/qemu-iotests/070.out
+++ b/tests/qemu-iotests/070.out
@@ -18,4 +18,11 @@ No errors were found on the image.
 === Verify open image read-only succeeds after log replay ===
 read 18874368/18874368 bytes at offset 0
 18 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+
+=== Verify image created by Disk2VHD can be opened ===
+image: TEST_DIR/test-disk2vhd.vhdx
+file format: vhdx
+virtual size: 256M (268435456 bytes)
+disk size: 260M
+cluster_size: 2097152
 *** done
diff --git a/tests/qemu-iotests/089 b/tests/qemu-iotests/089
new file mode 100755
index 0000000000..dffc977e1c
--- /dev/null
+++ b/tests/qemu-iotests/089
@@ -0,0 +1,129 @@
+#!/bin/bash
+#
+# Test case for support of JSON filenames
+#
+# Copyright (C) 2014 Red Hat, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+
+# creator
+owner=mreitz@redhat.com
+
+seq="$(basename $0)"
+echo "QA output created by $seq"
+
+here="$PWD"
+tmp=/tmp/$$
+status=1	# failure is the default!
+
+_cleanup()
+{
+	_cleanup_test_img
+}
+trap "_cleanup; exit \$status" 0 1 2 3 15
+
+# get standard environment, filters and checks
+. ./common.rc
+. ./common.filter
+
+_supported_fmt qcow2
+_supported_proto file
+_supported_os Linux
+
+# Using an image filename containing quotation marks will render the JSON data
+# below invalid. In that case, we have little choice but simply not to run this
+# test.
+case $TEST_IMG in
+    *'"'*)
+        _notrun "image filename may not contain quotation marks"
+        ;;
+esac
+
+IMG_SIZE=64M
+
+# Taken from test 072
+echo
+echo "=== Testing nested image formats ==="
+echo
+
+TEST_IMG="$TEST_IMG.base" _make_test_img $IMG_SIZE
+
+$QEMU_IO -c 'write -P 42 0 512' -c 'write -P 23 512 512' \
+         -c 'write -P 66 1024 512' "$TEST_IMG.base" | _filter_qemu_io
+
+$QEMU_IMG convert -f raw -O $IMGFMT "$TEST_IMG.base" "$TEST_IMG"
+
+$QEMU_IO -c 'read -P 42 0 512' -c 'read -P 23 512 512' \
+         -c 'read -P 66 1024 512' "json:{
+    \"driver\": \"$IMGFMT\",
+    \"file\": {
+        \"driver\": \"$IMGFMT\",
+        \"file\": {
+            \"filename\": \"$TEST_IMG\"
+        }
+    }
+}" | _filter_qemu_io
+
+# This should fail (see test 072)
+$QEMU_IO -c 'read -P 42 0 512' "$TEST_IMG" | _filter_qemu_io
+
+
+# Taken from test 071
+echo
+echo "=== Testing blkdebug ==="
+echo
+
+_make_test_img $IMG_SIZE
+
+$QEMU_IO -c 'write -P 42 0x38000 512' "$TEST_IMG" | _filter_qemu_io
+
+# The "image.filename" part tests whether "a": { "b": "c" } and "a.b": "c" do
+# the same (which they should).
+$QEMU_IO -c 'read -P 42 0x38000 512' "json:{
+    \"driver\": \"$IMGFMT\",
+    \"file\": {
+        \"driver\": \"blkdebug\",
+        \"inject-error\": [{
+            \"event\": \"l2_load\"
+        }],
+        \"image.filename\": \"$TEST_IMG\"
+    }
+}" | _filter_qemu_io
+
+
+echo
+echo "=== Testing qemu-img info output ==="
+echo
+
+TEST_IMG="json:{\"driver\":\"qcow2\",\"file.filename\":\"$TEST_IMG\"}" _img_info
+
+
+echo
+echo "=== Testing option merging ==="
+echo
+
+# Both options given directly and those given in the filename should be used
+$QEMU_IO -c "open -o driver=qcow2 json:{\"file.filename\":\"$TEST_IMG\"}" \
+         -c "info" 2>&1 | _filter_testdir | _filter_imgfmt
+
+# Options given directly should be prioritized over those given in the filename
+$QEMU_IO -c "open -o driver=qcow2 json:{\"driver\":\"raw\",\"file.filename\":\"$TEST_IMG\"}" \
+         -c "info" 2>&1 | _filter_testdir | _filter_imgfmt
+
+
+# success, all done
+echo "*** done"
+rm -f $seq.full
+status=0
diff --git a/tests/qemu-iotests/089.out b/tests/qemu-iotests/089.out
new file mode 100644
index 0000000000..4ca2f88e6a
--- /dev/null
+++ b/tests/qemu-iotests/089.out
@@ -0,0 +1,50 @@
+QA output created by 089
+
+=== Testing nested image formats ===
+
+Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=67108864 
+wrote 512/512 bytes at offset 0
+512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+wrote 512/512 bytes at offset 512
+512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+wrote 512/512 bytes at offset 1024
+512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+read 512/512 bytes at offset 0
+512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+read 512/512 bytes at offset 512
+512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+read 512/512 bytes at offset 1024
+512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+Pattern verification failed at offset 0, 512 bytes
+read 512/512 bytes at offset 0
+512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+
+=== Testing blkdebug ===
+
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 
+wrote 512/512 bytes at offset 229376
+512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+read failed: Input/output error
+
+=== Testing qemu-img info output ===
+
+image: TEST_DIR/t.IMGFMT
+file format: IMGFMT
+virtual size: 64M (67108864 bytes)
+cluster_size: 65536
+
+=== Testing option merging ===
+
+format name: IMGFMT
+cluster size: 64 KiB
+vm state offset: 512 MiB
+Format specific information:
+    compat: 1.1
+    lazy refcounts: false
+format name: IMGFMT
+cluster size: 64 KiB
+vm state offset: 512 MiB
+Format specific information:
+    compat: 1.1
+    lazy refcounts: false
+*** done
diff --git a/tests/qemu-iotests/091 b/tests/qemu-iotests/091
index 384b3ace54..32bbd56975 100755
--- a/tests/qemu-iotests/091
+++ b/tests/qemu-iotests/091
@@ -47,6 +47,8 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
 _supported_fmt qcow2
 _supported_proto file
 _supported_os Linux
+_default_cache_mode "none"
+_supported_cache_modes "writethrough" "none" "writeback"
 
 size=1G
 
@@ -59,13 +61,13 @@ echo === Starting QEMU VM1 ===
 echo
 
 qemu_comm_method="monitor"
-_launch_qemu -drive file="${TEST_IMG}",cache=none,id=disk
+_launch_qemu -drive file="${TEST_IMG}",cache=${CACHEMODE},id=disk
 h1=$QEMU_HANDLE
 
 echo
 echo === Starting QEMU VM2 ===
 echo
-_launch_qemu -drive file="${TEST_IMG}",cache=none,id=disk \
+_launch_qemu -drive file="${TEST_IMG}",cache=${CACHEMODE},id=disk \
              -incoming "exec: cat '${MIG_FIFO}'"
 h2=$QEMU_HANDLE
 
diff --git a/tests/qemu-iotests/092 b/tests/qemu-iotests/092
new file mode 100755
index 0000000000..a8c0c9ca2b
--- /dev/null
+++ b/tests/qemu-iotests/092
@@ -0,0 +1,98 @@
+#!/bin/bash
+#
+# qcow1 format input validation tests
+#
+# Copyright (C) 2014 Red Hat, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+
+# creator
+owner=kwolf@redhat.com
+
+seq=`basename $0`
+echo "QA output created by $seq"
+
+here=`pwd`
+tmp=/tmp/$$
+status=1	# failure is the default!
+
+_cleanup()
+{
+    rm -f $TEST_IMG.snap
+    _cleanup_test_img
+}
+trap "_cleanup; exit \$status" 0 1 2 3 15
+
+# get standard environment, filters and checks
+. ./common.rc
+. ./common.filter
+
+_supported_fmt qcow
+_supported_proto generic
+_supported_os Linux
+
+offset_backing_file_offset=8
+offset_backing_file_size=16
+offset_size=24
+offset_cluster_bits=32
+offset_l2_bits=33
+
+echo
+echo "== Invalid cluster size =="
+_make_test_img 64M
+poke_file "$TEST_IMG" "$offset_cluster_bits" "\xff"
+{ $QEMU_IO -c "read 0 512" $TEST_IMG; } 2>&1 | _filter_qemu_io | _filter_testdir
+poke_file "$TEST_IMG" "$offset_cluster_bits" "\x1f"
+{ $QEMU_IO -c "read 0 512" $TEST_IMG; } 2>&1 | _filter_qemu_io | _filter_testdir
+poke_file "$TEST_IMG" "$offset_cluster_bits" "\x08"
+{ $QEMU_IO -c "read 0 512" $TEST_IMG; } 2>&1 | _filter_qemu_io | _filter_testdir
+poke_file "$TEST_IMG" "$offset_cluster_bits" "\x11"
+{ $QEMU_IO -c "read 0 512" $TEST_IMG; } 2>&1 | _filter_qemu_io | _filter_testdir
+
+echo
+echo "== Invalid L2 table size =="
+_make_test_img 64M
+poke_file "$TEST_IMG" "$offset_l2_bits" "\xff"
+{ $QEMU_IO -c "read 0 512" $TEST_IMG; } 2>&1 | _filter_qemu_io | _filter_testdir
+poke_file "$TEST_IMG" "$offset_l2_bits" "\x05"
+{ $QEMU_IO -c "read 0 512" $TEST_IMG; } 2>&1 | _filter_qemu_io | _filter_testdir
+poke_file "$TEST_IMG" "$offset_l2_bits" "\x0e"
+{ $QEMU_IO -c "read 0 512" $TEST_IMG; } 2>&1 | _filter_qemu_io | _filter_testdir
+
+# 1 << 0x1b = 2^31 / L2_CACHE_SIZE
+poke_file "$TEST_IMG" "$offset_l2_bits" "\x1b"
+{ $QEMU_IO -c "read 0 512" $TEST_IMG; } 2>&1 | _filter_qemu_io | _filter_testdir
+
+echo
+echo "== Invalid size =="
+_make_test_img 64M
+poke_file "$TEST_IMG" "$offset_size" "\xee\xee\xee\xee\xee\xee\xee\xee"
+{ $QEMU_IO -c "read 0 512" $TEST_IMG; } 2>&1 | _filter_qemu_io | _filter_testdir
+poke_file "$TEST_IMG" "$offset_size" "\x7f\xff\xff\xff\xff\xff\xff\xff"
+{ $QEMU_IO -c "write 0 64M" $TEST_IMG; } 2>&1 | _filter_qemu_io | _filter_testdir
+
+echo
+echo "== Invalid backing file length =="
+_make_test_img 64M
+poke_file "$TEST_IMG" "$offset_backing_file_offset" "\x00\x00\x00\xff"
+poke_file "$TEST_IMG" "$offset_backing_file_size" "\xff\xff\xff\xff"
+{ $QEMU_IO -c "read 0 512" $TEST_IMG; } 2>&1 | _filter_qemu_io | _filter_testdir
+poke_file "$TEST_IMG" "$offset_backing_file_size" "\x7f\xff\xff\xff"
+{ $QEMU_IO -c "read 0 512" $TEST_IMG; } 2>&1 | _filter_qemu_io | _filter_testdir
+
+# success, all done
+echo "*** done"
+rm -f $seq.full
+status=0
diff --git a/tests/qemu-iotests/092.out b/tests/qemu-iotests/092.out
new file mode 100644
index 0000000000..496d8f0a63
--- /dev/null
+++ b/tests/qemu-iotests/092.out
@@ -0,0 +1,38 @@
+QA output created by 092
+
+== Invalid cluster size ==
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 
+qemu-io: can't open device TEST_DIR/t.qcow: Cluster size must be between 512 and 64k
+no file open, try 'help open'
+qemu-io: can't open device TEST_DIR/t.qcow: Cluster size must be between 512 and 64k
+no file open, try 'help open'
+qemu-io: can't open device TEST_DIR/t.qcow: Cluster size must be between 512 and 64k
+no file open, try 'help open'
+qemu-io: can't open device TEST_DIR/t.qcow: Cluster size must be between 512 and 64k
+no file open, try 'help open'
+
+== Invalid L2 table size ==
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 
+qemu-io: can't open device TEST_DIR/t.qcow: L2 table size must be between 512 and 64k
+no file open, try 'help open'
+qemu-io: can't open device TEST_DIR/t.qcow: L2 table size must be between 512 and 64k
+no file open, try 'help open'
+qemu-io: can't open device TEST_DIR/t.qcow: L2 table size must be between 512 and 64k
+no file open, try 'help open'
+qemu-io: can't open device TEST_DIR/t.qcow: L2 table size must be between 512 and 64k
+no file open, try 'help open'
+
+== Invalid size ==
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 
+qemu-io: can't open device TEST_DIR/t.qcow: Image too large
+no file open, try 'help open'
+qemu-io: can't open device TEST_DIR/t.qcow: Image too large
+no file open, try 'help open'
+
+== Invalid backing file length ==
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864 
+qemu-io: can't open device TEST_DIR/t.qcow: Backing file name too long
+no file open, try 'help open'
+qemu-io: can't open device TEST_DIR/t.qcow: Backing file name too long
+no file open, try 'help open'
+*** done
diff --git a/tests/qemu-iotests/common.filter b/tests/qemu-iotests/common.filter
index 776985d15e..a04df7f6dc 100644
--- a/tests/qemu-iotests/common.filter
+++ b/tests/qemu-iotests/common.filter
@@ -150,6 +150,7 @@ _filter_win32()
 _filter_qemu_io()
 {
     _filter_win32 | sed -e "s/[0-9]* ops\; [0-9/:. sec]* ([0-9/.inf]* [EPTGMKiBbytes]*\/sec and [0-9/.inf]* ops\/sec)/X ops\; XX:XX:XX.X (XXX YYY\/sec and XXX ops\/sec)/" \
+        -e "s/: line [0-9][0-9]*:  *[0-9][0-9]*\( Aborted\)/:\1/" \
         -e "s/qemu-io> //g"
 }
 
diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group
index cd3e4d2c27..0f074403ae 100644
--- a/tests/qemu-iotests/group
+++ b/tests/qemu-iotests/group
@@ -95,5 +95,7 @@
 086 rw auto quick
 087 rw auto
 088 rw auto
+089 rw auto quick
 090 rw auto quick
 091 rw auto
+092 rw auto quick
diff --git a/tests/qemu-iotests/sample_images/test-disk2vhd.vhdx.bz2 b/tests/qemu-iotests/sample_images/test-disk2vhd.vhdx.bz2
new file mode 100644
index 0000000000..2891c9a6d6
--- /dev/null
+++ b/tests/qemu-iotests/sample_images/test-disk2vhd.vhdx.bz2
Binary files differdiff --git a/tests/qom-test.c b/tests/qom-test.c
index 6d9a00b448..d8d1d8d9ff 100644
--- a/tests/qom-test.c
+++ b/tests/qom-test.c
@@ -44,7 +44,7 @@ static bool is_blacklisted(const char *arch, const char *mach)
     return false;
 }
 
-static void test_properties(const char *path)
+static void test_properties(const char *path, bool recurse)
 {
     char *child_path;
     QDict *response, *tuple;
@@ -56,14 +56,21 @@ static void test_properties(const char *path)
                    "  'arguments': { 'path': '%s' } }", path);
     g_assert(response);
 
+    if (!recurse) {
+        return;
+    }
+
     g_assert(qdict_haskey(response, "return"));
     list = qobject_to_qlist(qdict_get(response, "return"));
     QLIST_FOREACH_ENTRY(list, entry) {
         tuple = qobject_to_qdict(qlist_entry_obj(entry));
-        if (strstart(qdict_get_str(tuple, "type"), "child<", NULL)) {
+        bool is_child = strstart(qdict_get_str(tuple, "type"), "child<", NULL);
+        bool is_link = strstart(qdict_get_str(tuple, "type"), "link<", NULL);
+
+        if (is_child || is_link) {
             child_path = g_strdup_printf("%s/%s",
                                          path, qdict_get_str(tuple, "name"));
-            test_properties(child_path);
+            test_properties(child_path, is_child);
             g_free(child_path);
         } else {
             const char *prop = qdict_get_str(tuple, "name");
@@ -87,7 +94,7 @@ static void test_machine(gconstpointer data)
     args = g_strdup_printf("-machine %s", machine);
     qtest_start(args);
 
-    test_properties("/machine");
+    test_properties("/machine", true);
 
     response = qmp("{ 'execute': 'quit' }");
     g_assert(qdict_haskey(response, "return"));
diff --git a/tests/tcg/lm32/Makefile b/tests/tcg/lm32/Makefile
index 8e5d405459..57e7363b2c 100644
--- a/tests/tcg/lm32/Makefile
+++ b/tests/tcg/lm32/Makefile
@@ -3,7 +3,7 @@
 CROSS=lm32-elf-
 
 SIM = qemu-system-lm32
-SIMFLAGS = -M lm32-evr -nographic -device lm32-sys -net none -kernel
+SIMFLAGS = -M lm32-evr -nographic -semihosting -net none -kernel
 
 CC      = $(CROSS)gcc
 AS      = $(CROSS)as
@@ -18,6 +18,7 @@ LDFLAGS = -T$(TSRC_PATH)/linker.ld
 ASFLAGS += -Wa,-I,$(TSRC_PATH)/
 
 CRT        = crt.o
+HELPER     = helper.o
 TESTCASES += test_add.tst
 TESTCASES += test_addi.tst
 TESTCASES += test_and.tst
@@ -91,15 +92,15 @@ all: build
 %.o: $(TSRC_PATH)/%.S
 	$(AS) $(ASFLAGS) -c $< -o $@
 
-%.tst: %.o $(TSRC_PATH)/macros.inc $(CRT)
-	$(LD) $(LDFLAGS) $(NOSTDFLAGS) $(CRT) $< -o $@
+%.tst: %.o $(TSRC_PATH)/macros.inc $(CRT) $(HELPER)
+	$(LD) $(LDFLAGS) $(NOSTDFLAGS) $(CRT) $(HELPER) $< -o $@
 
-build: $(CRT) $(TESTCASES)
+build: $(TESTCASES)
 
 check: $(TESTCASES:test_%.tst=check_%)
 
-check_%: test_%.tst $(CRT) $(SYS)
-	$(SIM) $(SIMFLAGS) $<
+check_%: test_%.tst
+	@$(SIM) $(SIMFLAGS) $<
 
 clean:
-	$(RM) -fr $(TESTCASES) $(CRT)
+	$(RM) -fr $(TESTCASES) $(CRT) $(HELPER)
diff --git a/tests/tcg/lm32/crt.S b/tests/tcg/lm32/crt.S
index 5f9cfd95d3..fc437a3de1 100644
--- a/tests/tcg/lm32/crt.S
+++ b/tests/tcg/lm32/crt.S
@@ -8,9 +8,9 @@ _reset_handler:
 	ori r1, r1, lo(_start)
 	wcsr eba, r1
 	wcsr deba, r1
+	mvhi sp, hi(_fstack)
+	ori sp, sp, lo(_fstack)
 	bi _main
-	nop
-	nop
 
 _breakpoint_handler:
 	ori r25, r25, 1
diff --git a/tests/tcg/lm32/helper.S b/tests/tcg/lm32/helper.S
new file mode 100644
index 0000000000..3351d41e84
--- /dev/null
+++ b/tests/tcg/lm32/helper.S
@@ -0,0 +1,65 @@
+.text
+.global _start, _write, _exit
+.global _tc_fail, _tc_pass
+
+_write:
+	addi sp, sp, -4
+	sw (sp+4), r8
+	mvi r8, 5
+	scall
+	lw r8, (sp+4)
+	addi sp, sp, 4
+	ret
+
+_exit:
+	mvi r8, 1
+	scall
+1:
+	bi 1b
+
+_tc_pass:
+.data
+1:
+	.ascii "OK\n"
+2:
+.text
+	addi sp, sp, -16
+	sw (sp+4), ra
+	sw (sp+8), r1
+	sw (sp+12), r2
+	sw (sp+16), r3
+	mvi r1, 1
+	mvhi r2, hi(1b)
+	ori r2, r2, lo(1b)
+	mvi r3, (2b - 1b)
+	calli _write
+	lw r3, (sp+16)
+	lw r2, (sp+12)
+	lw r1, (sp+8)
+	lw ra, (sp+4)
+	addi sp, sp, 16
+	ret
+
+_tc_fail:
+.data
+1:
+	.ascii "FAILED\n"
+2:
+.text
+	addi sp, sp, -16
+	sw (sp+4), ra
+	sw (sp+8), r1
+	sw (sp+12), r2
+	sw (sp+16), r3
+	sw (sp+4), ra
+	mvi r1, 1
+	mvhi r2, hi(1b)
+	ori r2, r2, lo(1b)
+	mvi r3, (2b - 1b)
+	calli _write
+	lw r3, (sp+16)
+	lw r2, (sp+12)
+	lw r1, (sp+8)
+	lw ra, (sp+4)
+	addi sp, sp, 16
+	ret
diff --git a/tests/tcg/lm32/macros.inc b/tests/tcg/lm32/macros.inc
index 367c7c50d8..360ad53c9f 100644
--- a/tests/tcg/lm32/macros.inc
+++ b/tests/tcg/lm32/macros.inc
@@ -1,12 +1,26 @@
 
+.equ MAX_TESTNAME_LEN, 32
 .macro test_name name
 	.data
 tn_\name:
-	.asciz "\name"
+	.ascii "\name"
+	.space MAX_TESTNAME_LEN - (. - tn_\name), ' '
 	.text
-	mvhi r13, hi(tn_\name)
-	ori r13, r13, lo(tn_\name)
-	sw (r12+8), r13
+	.global \name
+\name:
+	addi sp, sp, -12
+	sw (sp+4), r1
+	sw (sp+8), r2
+	sw (sp+12), r3
+	mvi r1, 1
+	mvhi r2, hi(tn_\name)
+	ori r2, r2, lo(tn_\name)
+	mvi r3, MAX_TESTNAME_LEN
+	calli _write
+	lw r3, (sp+12)
+	lw r2, (sp+8)
+	lw r1, (sp+4)
+	addi sp, sp, 12
 .endm
 
 .macro load reg val
@@ -15,13 +29,12 @@ tn_\name:
 .endm
 
 .macro tc_pass
-	mvi r13, 0
-	sw (r12+4), r13
+	calli _tc_pass
 .endm
 
 .macro tc_fail
-	mvi r13, 1
-	sw (r12+4), r13
+	addi r12, r12, 1
+	calli _tc_fail
 .endm
 
 .macro check_r3 val
@@ -63,14 +76,12 @@ tn_\name:
 	.global _main
 	.text
 _main:
-	mvhi r12, hi(0xffff0000)      # base address of test block
-	ori r12, r12, lo(0xffff0000)
+	mvi r12, 0
 .endm
 
 .macro end
-	sw (r12+0), r0
-1:
-	bi 1b
+	mv r1, r12
+	calli _exit
 .endm
 
 # base +
diff --git a/tests/tcg/lm32/test_lb.S b/tests/tcg/lm32/test_lb.S
index f84d21ead9..d677eea4c4 100644
--- a/tests/tcg/lm32/test_lb.S
+++ b/tests/tcg/lm32/test_lb.S
@@ -8,10 +8,12 @@ lb r3, (r1+0)
 check_r3 0x7e
 
 test_name LB_2
+load r1 data
 lb r3, (r1+1)
 check_r3 0x7f
 
 test_name LB_3
+load r1 data
 lb r3, (r1+-1)
 check_r3 0x7d
 
@@ -21,10 +23,12 @@ lb r3, (r1+0)
 check_r3 0xfffffffe
 
 test_name LB_5
+load r1 data_msb
 lb r3, (r1+1)
 check_r3 0xffffffff
 
 test_name LB_6
+load r1 data_msb
 lb r3, (r1+-1)
 check_r3 0xfffffffd
 
diff --git a/tests/tcg/lm32/test_lbu.S b/tests/tcg/lm32/test_lbu.S
index 4c1786ad71..dc5d5f67d3 100644
--- a/tests/tcg/lm32/test_lbu.S
+++ b/tests/tcg/lm32/test_lbu.S
@@ -8,10 +8,12 @@ lbu r3, (r1+0)
 check_r3 0x7e
 
 test_name LBU_2
+load r1 data
 lbu r3, (r1+1)
 check_r3 0x7f
 
 test_name LBU_3
+load r1 data
 lbu r3, (r1+-1)
 check_r3 0x7d
 
@@ -21,10 +23,12 @@ lbu r3, (r1+0)
 check_r3 0xfe
 
 test_name LBU_5
+load r1 data_msb
 lbu r3, (r1+1)
 check_r3 0xff
 
 test_name LBU_6
+load r1 data_msb
 lbu r3, (r1+-1)
 check_r3 0xfd
 
diff --git a/tests/tcg/lm32/test_lh.S b/tests/tcg/lm32/test_lh.S
index e57d9e35cf..397996bddd 100644
--- a/tests/tcg/lm32/test_lh.S
+++ b/tests/tcg/lm32/test_lh.S
@@ -8,10 +8,12 @@ lh r3, (r1+0)
 check_r3 0x7e7f
 
 test_name LH_2
+load r1 data
 lh r3, (r1+2)
 check_r3 0x7071
 
 test_name LH_3
+load r1 data
 lh r3, (r1+-2)
 check_r3 0x7c7d
 
@@ -21,10 +23,12 @@ lh r3, (r1+0)
 check_r3 0xfffffeff
 
 test_name LH_5
+load r1 data_msb
 lh r3, (r1+2)
 check_r3 0xfffff0f1
 
 test_name LH_6
+load r1 data_msb
 lh r3, (r1+-2)
 check_r3 0xfffffcfd
 
diff --git a/tests/tcg/lm32/test_lhu.S b/tests/tcg/lm32/test_lhu.S
index e648775d94..8de7c52560 100644
--- a/tests/tcg/lm32/test_lhu.S
+++ b/tests/tcg/lm32/test_lhu.S
@@ -8,10 +8,12 @@ lhu r3, (r1+0)
 check_r3 0x7e7f
 
 test_name LHU_2
+load r1 data
 lhu r3, (r1+2)
 check_r3 0x7071
 
 test_name LHU_3
+load r1 data
 lhu r3, (r1+-2)
 check_r3 0x7c7d
 
@@ -21,10 +23,12 @@ lhu r3, (r1+0)
 check_r3 0xfeff
 
 test_name LHU_5
+load r1 data_msb
 lhu r3, (r1+2)
 check_r3 0xf0f1
 
 test_name LHU_6
+load r1 data_msb
 lhu r3, (r1+-2)
 check_r3 0xfcfd
 
diff --git a/tests/tcg/lm32/test_lw.S b/tests/tcg/lm32/test_lw.S
index f8c919d2b8..996e5f8c88 100644
--- a/tests/tcg/lm32/test_lw.S
+++ b/tests/tcg/lm32/test_lw.S
@@ -8,10 +8,12 @@ lw r3, (r1+0)
 check_r3 0x7e7f7071
 
 test_name LW_2
+load r1 data
 lw r3, (r1+4)
 check_r3 0x72737475
 
 test_name LW_3
+load r1 data
 lw r3, (r1+-4)
 check_r3 0x7a7b7c7d
 
diff --git a/tests/tcg/lm32/test_sb.S b/tests/tcg/lm32/test_sb.S
index 89e39d621d..b15a89d342 100644
--- a/tests/tcg/lm32/test_sb.S
+++ b/tests/tcg/lm32/test_sb.S
@@ -9,11 +9,13 @@ sb (r1+0), r2
 check_mem data 0xaa000000
 
 test_name SB_2
+load r1 data
 load r2 0xf0f1f2bb
 sb (r1+1), r2
 check_mem data 0xaabb0000
 
 test_name SB_3
+load r1 data
 load r2 0xf0f1f2cc
 sb (r1+-1), r2
 check_mem data0 0x000000cc
diff --git a/tests/tcg/lm32/test_scall.S b/tests/tcg/lm32/test_scall.S
index b442e32374..46032f841d 100644
--- a/tests/tcg/lm32/test_scall.S
+++ b/tests/tcg/lm32/test_scall.S
@@ -5,6 +5,10 @@ start
 test_name SCALL_1
 mvi r1, 1
 wcsr IE, r1
+# we are running in a semi hosted environment
+# therefore we have to set r8 to some unused system
+# call
+mvi r8, 0
 insn:
 scall
 check_excp 64
diff --git a/tests/tcg/lm32/test_sh.S b/tests/tcg/lm32/test_sh.S
index ea8b3f2067..bba10224f6 100644
--- a/tests/tcg/lm32/test_sh.S
+++ b/tests/tcg/lm32/test_sh.S
@@ -9,11 +9,13 @@ sh (r1+0), r2
 check_mem data 0xaaaa0000
 
 test_name SH_2
+load r1 data
 load r2 0xf0f1bbbb
 sh (r1+2), r2
 check_mem data 0xaaaabbbb
 
 test_name SH_3
+load r1 data
 load r2 0xf0f1cccc
 sh (r1+-2), r2
 check_mem data0 0x0000cccc
diff --git a/tests/tcg/lm32/test_sw.S b/tests/tcg/lm32/test_sw.S
index d1fdadce61..2b1c017e7b 100644
--- a/tests/tcg/lm32/test_sw.S
+++ b/tests/tcg/lm32/test_sw.S
@@ -9,16 +9,19 @@ sw (r1+0), r2
 check_mem data 0xaabbccdd
 
 test_name SW_2
+load r1 data
 load r2 0x00112233
 sw (r1+4), r2
 check_mem data1 0x00112233
 
 test_name SW_3
+load r1 data
 load r2 0x44556677
 sw (r1+-4), r2
 check_mem data0 0x44556677
 
 test_name SW_4
+load r1 data
 sw (r1+0), r1
 lw r3, (r1+0)
 check_r3 data
diff --git a/tests/tcg/xtensa/test_mmu.S b/tests/tcg/xtensa/test_mmu.S
index 099031fd14..58c5bca30e 100644
--- a/tests/tcg/xtensa/test_mmu.S
+++ b/tests/tcg/xtensa/test_mmu.S
@@ -4,16 +4,28 @@ test_suite mmu
 
 .purgem test_init
 
-.macro test_init
-    movi    a2, 0x00000004
-    idtlb   a2
-    movi    a2, 0x00100004
+.macro clean_tlb_way way, page_size, n_entries
+    movi    a2, \way
+    movi    a3, \page_size
+    movi    a4, \n_entries
+    loop    a4, 1f
     idtlb   a2
-    movi    a2, 0x00200004
+    iitlb   a2
+    add     a2, a2, a3
+1:
+.endm
+
+.macro test_init
+    clean_tlb_way 0, 0x00001000, 4
+    clean_tlb_way 1, 0x00001000, 4
+    clean_tlb_way 2, 0x00001000, 4
+    clean_tlb_way 3, 0x00001000, 4
+    clean_tlb_way 4, 0x00100000, 4
+    movi    a2, 0x00000007
     idtlb   a2
-    movi    a2, 0x00300004
+    movi    a2, 0x00000008
     idtlb   a2
-    movi    a2, 0x00000007
+    movi    a2, 0x00000009
     idtlb   a2
 .endm
 
@@ -508,4 +520,224 @@ test autoload_3_level_pt
     assert_sr exccause, 24
 test_end
 
+test cross_page_insn
+    set_vector kernel, 2f
+
+    movi    a2, 0x04000003 /* PPN */
+    movi    a3, 0x00007000 /* VPN */
+    witlb   a2, a3
+    wdtlb   a2, a3
+    movi    a3, 0x00008000 /* VPN */
+    witlb   a2, a3
+    wdtlb   a2, a3
+
+    movi    a2, 0x00007fff
+    movi    a3, 20f
+    movi    a4, 21f
+    sub     a4, a4, a3
+    loop    a4, 1f
+    l8ui    a5, a3, 0
+    s8i     a5, a2, 0
+    addi    a2, a2, 1
+    addi    a3, a3, 1
+1:
+    movi    a2, 0x00007fff
+    movi    a3, 0x00008000
+    /* DTLB: OK, ITLB: OK */
+    jx      a2
+
+    .begin  no-transform
+20:
+    l32i    a2, a3, 0
+    syscall
+21:
+    .end    no-transform
+
+2:
+    rsr     a2, exccause
+    movi    a3, 1
+    assert  eq, a2, a3
+    rsr     a2, epc1
+    movi    a3, 0x8002
+    assert  eq, a2, a3
+    rsr     a2, excsave1
+    movi    a3, 0x00007fff
+    assert  ne, a2, a3
+
+    reset_ps
+    set_vector kernel, 3f
+
+    movi    a2, 0x0400000c /* PPN */
+    movi    a3, 0x00008000 /* VPN */
+    wdtlb   a2, a3
+    movi    a2, 0x00007fff
+    movi    a3, 0x00008000
+    /* DTLB: FAIL, ITLB: OK */
+    jx      a2
+3:
+    rsr     a2, exccause
+    movi    a3, 28
+    assert  eq, a2, a3
+    rsr     a2, epc1
+    movi    a3, 0x7fff
+    assert  eq, a2, a3
+    rsr     a2, excsave1
+    movi    a3, 0x00007fff
+    assert  eq, a2, a3
+
+    reset_ps
+    set_vector kernel, 4f
+
+    movi    a2, 0x0400000c /* PPN */
+    movi    a3, 0x00008000 /* VPN */
+    witlb   a2, a3
+    movi    a2, 0x04000003 /* PPN */
+    wdtlb   a2, a3
+    movi    a2, 0x00007fff
+    movi    a3, 0x00008000
+    /* DTLB: OK, ITLB: FAIL */
+    jx      a2
+4:
+    rsr     a2, exccause
+    movi    a3, 20
+    assert  eq, a2, a3
+    rsr     a2, epc1
+    movi    a3, 0x7fff
+    assert  eq, a2, a3
+    rsr     a2, excsave1
+    movi    a3, 0x00007fff
+    assert  eq, a2, a3
+
+    reset_ps
+    set_vector kernel, 5f
+
+    movi    a2, 0x0400000c /* PPN */
+    movi    a3, 0x00008000 /* VPN */
+    wdtlb   a2, a3
+    movi    a2, 0x00007fff
+    movi    a3, 0x00008000
+    /* DTLB: FAIL, ITLB: FAIL */
+    jx      a2
+5:
+    rsr     a2, exccause
+    movi    a3, 20
+    assert  eq, a2, a3
+    rsr     a2, epc1
+    movi    a3, 0x7fff
+    assert  eq, a2, a3
+    rsr     a2, excsave1
+    movi    a3, 0x00007fff
+    assert  eq, a2, a3
+test_end
+
+test cross_page_tb
+    set_vector kernel, 2f
+
+    movi    a2, 0x04000003 /* PPN */
+    movi    a3, 0x00007000 /* VPN */
+    witlb   a2, a3
+    wdtlb   a2, a3
+    movi    a3, 0x00008000 /* VPN */
+    witlb   a2, a3
+    wdtlb   a2, a3
+
+    movi    a2, 0x00007ffd
+    movi    a3, 20f
+    movi    a4, 21f
+    sub     a4, a4, a3
+    loop    a4, 1f
+    l8ui    a5, a3, 0
+    s8i     a5, a2, 0
+    addi    a2, a2, 1
+    addi    a3, a3, 1
+1:
+    movi    a2, 0x00007ffd
+    movi    a3, 0x00008000
+    /* DTLB: OK, ITLB: OK */
+    jx      a2
+
+    .begin  no-transform
+20:
+    l32i    a2, a3, 0
+    syscall
+21:
+    .end    no-transform
+
+2:
+    rsr     a2, exccause
+    movi    a3, 1
+    assert  eq, a2, a3
+    rsr     a2, epc1
+    movi    a3, 0x8000
+    assert  eq, a2, a3
+    rsr     a2, excsave1
+    movi    a3, 0x00007ffd
+    assert  ne, a2, a3
+
+    reset_ps
+    set_vector kernel, 3f
+
+    movi    a2, 0x0400000c /* PPN */
+    movi    a3, 0x00008000 /* VPN */
+    wdtlb   a2, a3
+    movi    a2, 0x00007ffd
+    movi    a3, 0x00008000
+    /* DTLB: FAIL, ITLB: OK */
+    jx      a2
+3:
+    rsr     a2, exccause
+    movi    a3, 28
+    assert  eq, a2, a3
+    rsr     a2, epc1
+    movi    a3, 0x7ffd
+    assert  eq, a2, a3
+    rsr     a2, excsave1
+    movi    a3, 0x00007ffd
+    assert  eq, a2, a3
+
+    reset_ps
+    set_vector kernel, 4f
+
+    movi    a2, 0x0400000c /* PPN */
+    movi    a3, 0x00008000 /* VPN */
+    witlb   a2, a3
+    movi    a2, 0x04000003 /* PPN */
+    wdtlb   a2, a3
+    movi    a2, 0x00007ffd
+    movi    a3, 0x00008000
+    /* DTLB: OK, ITLB: FAIL */
+    jx      a2
+4:
+    rsr     a2, exccause
+    movi    a3, 20
+    assert  eq, a2, a3
+    rsr     a2, epc1
+    movi    a3, 0x8000
+    assert  eq, a2, a3
+    rsr     a2, excsave1
+    movi    a3, 0x00007ffd
+    assert  ne, a2, a3
+
+    reset_ps
+    set_vector kernel, 5f
+
+    movi    a2, 0x0400000c /* PPN */
+    movi    a3, 0x00008000 /* VPN */
+    wdtlb   a2, a3
+    movi    a2, 0x00007ffd
+    movi    a3, 0x00008000
+    /* DTLB: FAIL, ITLB: FAIL */
+    jx      a2
+5:
+    rsr     a2, exccause
+    movi    a3, 28
+    assert  eq, a2, a3
+    rsr     a2, epc1
+    movi    a3, 0x7ffd
+    assert  eq, a2, a3
+    rsr     a2, excsave1
+    movi    a3, 0x00007ffd
+    assert  eq, a2, a3
+test_end
+
 test_suite_end
diff --git a/tests/test-qemu-opts.c b/tests/test-qemu-opts.c
new file mode 100644
index 0000000000..3653507f56
--- /dev/null
+++ b/tests/test-qemu-opts.c
@@ -0,0 +1,441 @@
+/*
+ * QemuOpts unit-tests.
+ *
+ * Copyright (C) 2014 Leandro Dorileo <l@dorileo.org>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
+ * See the COPYING.LIB file in the top-level directory.
+ */
+
+#include "qapi/error.h"
+#include "qapi/qmp/qstring.h"
+#include "qemu/config-file.h"
+
+#include <glib.h>
+#include <string.h>
+
+static QemuOptsList opts_list_01 = {
+    .name = "opts_list_01",
+    .head = QTAILQ_HEAD_INITIALIZER(opts_list_01.head),
+    .desc = {
+        {
+            .name = "str1",
+            .type = QEMU_OPT_STRING,
+        },{
+            .name = "str2",
+            .type = QEMU_OPT_STRING,
+        },{
+            .name = "str3",
+            .type = QEMU_OPT_STRING,
+        },{
+            .name = "number1",
+            .type = QEMU_OPT_NUMBER,
+        },
+        { /* end of list */ }
+    },
+};
+
+static QemuOptsList opts_list_02 = {
+    .name = "opts_list_02",
+    .head = QTAILQ_HEAD_INITIALIZER(opts_list_02.head),
+    .desc = {
+        {
+            .name = "str1",
+            .type = QEMU_OPT_STRING,
+        },{
+            .name = "bool1",
+            .type = QEMU_OPT_BOOL,
+        },{
+            .name = "str2",
+            .type = QEMU_OPT_STRING,
+        },{
+            .name = "size1",
+            .type = QEMU_OPT_SIZE,
+        },
+        { /* end of list */ }
+    },
+};
+
+QemuOptsList opts_list_03 = {
+    .name = "opts_list_03",
+    .head = QTAILQ_HEAD_INITIALIZER(opts_list_03.head),
+    .desc = {
+        /* no elements => accept any params */
+        { /* end of list */ }
+    },
+};
+
+static void register_opts(void)
+{
+    qemu_add_opts(&opts_list_01);
+    qemu_add_opts(&opts_list_02);
+    qemu_add_opts(&opts_list_03);
+}
+
+static void test_find_unknown_opts(void)
+{
+    QemuOptsList *list;
+    Error *err = NULL;
+
+    /* should not return anything, we don't have an "unknown" option */
+    list = qemu_find_opts_err("unknown", &err);
+    g_assert(list == NULL);
+    g_assert(err);
+    error_free(err);
+}
+
+static void test_qemu_find_opts(void)
+{
+    QemuOptsList *list;
+
+    /* we have an "opts_list_01" option, should return it */
+    list = qemu_find_opts("opts_list_01");
+    g_assert(list != NULL);
+    g_assert_cmpstr(list->name, ==, "opts_list_01");
+}
+
+static void test_qemu_opts_create(void)
+{
+    QemuOptsList *list;
+    QemuOpts *opts;
+
+    list = qemu_find_opts("opts_list_01");
+    g_assert(list != NULL);
+    g_assert(QTAILQ_EMPTY(&list->head));
+    g_assert_cmpstr(list->name, ==, "opts_list_01");
+
+    /* should not find anything at this point */
+    opts = qemu_opts_find(list, NULL);
+    g_assert(opts == NULL);
+
+    /* create the opts */
+    opts = qemu_opts_create(list, NULL, 0, &error_abort);
+    g_assert(opts != NULL);
+    g_assert(!QTAILQ_EMPTY(&list->head));
+
+    /* now we've create the opts, must find it */
+    opts = qemu_opts_find(list, NULL);
+    g_assert(opts != NULL);
+
+    qemu_opts_del(opts);
+
+    /* should not find anything at this point */
+    opts = qemu_opts_find(list, NULL);
+    g_assert(opts == NULL);
+}
+
+static void test_qemu_opt_get(void)
+{
+    QemuOptsList *list;
+    QemuOpts *opts;
+    const char *opt = NULL;
+
+    list = qemu_find_opts("opts_list_01");
+    g_assert(list != NULL);
+    g_assert(QTAILQ_EMPTY(&list->head));
+    g_assert_cmpstr(list->name, ==, "opts_list_01");
+
+    /* should not find anything at this point */
+    opts = qemu_opts_find(list, NULL);
+    g_assert(opts == NULL);
+
+    /* create the opts */
+    opts = qemu_opts_create(list, NULL, 0, &error_abort);
+    g_assert(opts != NULL);
+    g_assert(!QTAILQ_EMPTY(&list->head));
+
+    /* haven't set anything to str2 yet */
+    opt = qemu_opt_get(opts, "str2");
+    g_assert(opt == NULL);
+
+    qemu_opt_set(opts, "str2", "value");
+
+    /* now we have set str2, should know about it */
+    opt = qemu_opt_get(opts, "str2");
+    g_assert_cmpstr(opt, ==, "value");
+
+    qemu_opt_set(opts, "str2", "value2");
+
+    /* having reset the value, the returned should be the reset one */
+    opt = qemu_opt_get(opts, "str2");
+    g_assert_cmpstr(opt, ==, "value2");
+
+    qemu_opts_del(opts);
+
+    /* should not find anything at this point */
+    opts = qemu_opts_find(list, NULL);
+    g_assert(opts == NULL);
+}
+
+static void test_qemu_opt_get_bool(void)
+{
+    QemuOptsList *list;
+    QemuOpts *opts;
+    bool opt;
+    int ret;
+
+    list = qemu_find_opts("opts_list_02");
+    g_assert(list != NULL);
+    g_assert(QTAILQ_EMPTY(&list->head));
+    g_assert_cmpstr(list->name, ==, "opts_list_02");
+
+    /* should not find anything at this point */
+    opts = qemu_opts_find(list, NULL);
+    g_assert(opts == NULL);
+
+    /* create the opts */
+    opts = qemu_opts_create(list, NULL, 0, &error_abort);
+    g_assert(opts != NULL);
+    g_assert(!QTAILQ_EMPTY(&list->head));
+
+    /* haven't set anything to bool1 yet, so defval should be returned */
+    opt = qemu_opt_get_bool(opts, "bool1", false);
+    g_assert(opt == false);
+
+    ret = qemu_opt_set_bool(opts, "bool1", true);
+    g_assert(ret == 0);
+
+    /* now we have set bool1, should know about it */
+    opt = qemu_opt_get_bool(opts, "bool1", false);
+    g_assert(opt == true);
+
+    /* having reset the value, opt should be the reset one not defval */
+    ret = qemu_opt_set_bool(opts, "bool1", false);
+    g_assert(ret == 0);
+
+    opt = qemu_opt_get_bool(opts, "bool1", true);
+    g_assert(opt == false);
+
+    qemu_opts_del(opts);
+
+    /* should not find anything at this point */
+    opts = qemu_opts_find(list, NULL);
+    g_assert(opts == NULL);
+}
+
+static void test_qemu_opt_get_number(void)
+{
+    QemuOptsList *list;
+    QemuOpts *opts;
+    uint64_t opt;
+    int ret;
+
+    list = qemu_find_opts("opts_list_01");
+    g_assert(list != NULL);
+    g_assert(QTAILQ_EMPTY(&list->head));
+    g_assert_cmpstr(list->name, ==, "opts_list_01");
+
+    /* should not find anything at this point */
+    opts = qemu_opts_find(list, NULL);
+    g_assert(opts == NULL);
+
+    /* create the opts */
+    opts = qemu_opts_create(list, NULL, 0, &error_abort);
+    g_assert(opts != NULL);
+    g_assert(!QTAILQ_EMPTY(&list->head));
+
+    /* haven't set anything to number1 yet, so defval should be returned */
+    opt = qemu_opt_get_number(opts, "number1", 5);
+    g_assert(opt == 5);
+
+    ret = qemu_opt_set_number(opts, "number1", 10);
+    g_assert(ret == 0);
+
+    /* now we have set number1, should know about it */
+    opt = qemu_opt_get_number(opts, "number1", 5);
+    g_assert(opt == 10);
+
+    /* having reset it, the returned should be the reset one not defval */
+    ret = qemu_opt_set_number(opts, "number1", 15);
+    g_assert(ret == 0);
+
+    opt = qemu_opt_get_number(opts, "number1", 5);
+    g_assert(opt == 15);
+
+    qemu_opts_del(opts);
+
+    /* should not find anything at this point */
+    opts = qemu_opts_find(list, NULL);
+    g_assert(opts == NULL);
+}
+
+static void test_qemu_opt_get_size(void)
+{
+    QemuOptsList *list;
+    QemuOpts *opts;
+    uint64_t opt;
+    QDict *dict;
+
+    list = qemu_find_opts("opts_list_02");
+    g_assert(list != NULL);
+    g_assert(QTAILQ_EMPTY(&list->head));
+    g_assert_cmpstr(list->name, ==, "opts_list_02");
+
+    /* should not find anything at this point */
+    opts = qemu_opts_find(list, NULL);
+    g_assert(opts == NULL);
+
+    /* create the opts */
+    opts = qemu_opts_create(list, NULL, 0, &error_abort);
+    g_assert(opts != NULL);
+    g_assert(!QTAILQ_EMPTY(&list->head));
+
+    /* haven't set anything to size1 yet, so defval should be returned */
+    opt = qemu_opt_get_size(opts, "size1", 5);
+    g_assert(opt == 5);
+
+    dict = qdict_new();
+    g_assert(dict != NULL);
+
+    qdict_put(dict, "size1", qstring_from_str("10"));
+
+    qemu_opts_absorb_qdict(opts, dict, &error_abort);
+    g_assert(error_abort == NULL);
+
+    /* now we have set size1, should know about it */
+    opt = qemu_opt_get_size(opts, "size1", 5);
+    g_assert(opt == 10);
+
+    /* reset value */
+    qdict_put(dict, "size1", qstring_from_str("15"));
+
+    qemu_opts_absorb_qdict(opts, dict, &error_abort);
+    g_assert(error_abort == NULL);
+
+    /* test the reset value */
+    opt = qemu_opt_get_size(opts, "size1", 5);
+    g_assert(opt == 15);
+
+    qdict_del(dict, "size1");
+    g_free(dict);
+
+    qemu_opts_del(opts);
+
+    /* should not find anything at this point */
+    opts = qemu_opts_find(list, NULL);
+    g_assert(opts == NULL);
+}
+
+static void test_qemu_opt_unset(void)
+{
+    QemuOpts *opts;
+    const char *value;
+    int ret;
+
+    /* dynamically initialized (parsed) opts */
+    opts = qemu_opts_parse(&opts_list_03, "key=value", 0);
+    g_assert(opts != NULL);
+
+    /* check default/parsed value */
+    value = qemu_opt_get(opts, "key");
+    g_assert_cmpstr(value, ==, "value");
+
+    /* reset it to value2 */
+    qemu_opt_set(opts, "key", "value2");
+
+    value = qemu_opt_get(opts, "key");
+    g_assert_cmpstr(value, ==, "value2");
+
+    /* unset, valid only for "accept any" */
+    ret = qemu_opt_unset(opts, "key");
+    g_assert(ret == 0);
+
+    /* after reset the value should be the parsed/default one */
+    value = qemu_opt_get(opts, "key");
+    g_assert_cmpstr(value, ==, "value");
+
+    qemu_opts_del(opts);
+}
+
+static void test_qemu_opts_reset(void)
+{
+    QemuOptsList *list;
+    QemuOpts *opts;
+    uint64_t opt;
+    int ret;
+
+    list = qemu_find_opts("opts_list_01");
+    g_assert(list != NULL);
+    g_assert(QTAILQ_EMPTY(&list->head));
+    g_assert_cmpstr(list->name, ==, "opts_list_01");
+
+    /* should not find anything at this point */
+    opts = qemu_opts_find(list, NULL);
+    g_assert(opts == NULL);
+
+    /* create the opts */
+    opts = qemu_opts_create(list, NULL, 0, &error_abort);
+    g_assert(opts != NULL);
+    g_assert(!QTAILQ_EMPTY(&list->head));
+
+    /* haven't set anything to number1 yet, so defval should be returned */
+    opt = qemu_opt_get_number(opts, "number1", 5);
+    g_assert(opt == 5);
+
+    ret = qemu_opt_set_number(opts, "number1", 10);
+    g_assert(ret == 0);
+
+    /* now we have set number1, should know about it */
+    opt = qemu_opt_get_number(opts, "number1", 5);
+    g_assert(opt == 10);
+
+    qemu_opts_reset(list);
+
+    /* should not find anything at this point */
+    opts = qemu_opts_find(list, NULL);
+    g_assert(opts == NULL);
+}
+
+static void test_qemu_opts_set(void)
+{
+    QemuOptsList *list;
+    QemuOpts *opts;
+    int ret;
+    const char *opt;
+
+    list = qemu_find_opts("opts_list_01");
+    g_assert(list != NULL);
+    g_assert(QTAILQ_EMPTY(&list->head));
+    g_assert_cmpstr(list->name, ==, "opts_list_01");
+
+    /* should not find anything at this point */
+    opts = qemu_opts_find(list, NULL);
+    g_assert(opts == NULL);
+
+    /* implicitly create opts and set str3 value */
+    ret = qemu_opts_set(list, NULL, "str3", "value");
+    g_assert(ret == 0);
+    g_assert(!QTAILQ_EMPTY(&list->head));
+
+    /* get the just created opts */
+    opts = qemu_opts_find(list, NULL);
+    g_assert(opts != NULL);
+
+    /* check the str3 value */
+    opt = qemu_opt_get(opts, "str3");
+    g_assert_cmpstr(opt, ==, "value");
+
+    qemu_opts_del(opts);
+
+    /* should not find anything at this point */
+    opts = qemu_opts_find(list, NULL);
+    g_assert(opts == NULL);
+}
+
+int main(int argc, char *argv[])
+{
+    register_opts();
+    g_test_init(&argc, &argv, NULL);
+    g_test_add_func("/qemu-opts/find_unknown_opts", test_find_unknown_opts);
+    g_test_add_func("/qemu-opts/find_opts", test_qemu_find_opts);
+    g_test_add_func("/qemu-opts/opts_create", test_qemu_opts_create);
+    g_test_add_func("/qemu-opts/opt_get", test_qemu_opt_get);
+    g_test_add_func("/qemu-opts/opt_get_bool", test_qemu_opt_get_bool);
+    g_test_add_func("/qemu-opts/opt_get_number", test_qemu_opt_get_number);
+    g_test_add_func("/qemu-opts/opt_get_size", test_qemu_opt_get_size);
+    g_test_add_func("/qemu-opts/opt_unset", test_qemu_opt_unset);
+    g_test_add_func("/qemu-opts/opts_reset", test_qemu_opts_reset);
+    g_test_add_func("/qemu-opts/opts_set", test_qemu_opts_set);
+    g_test_run();
+    return 0;
+}
diff --git a/tests/test-qmp-output-visitor.c b/tests/test-qmp-output-visitor.c
index 9c154581d7..74020de5e7 100644
--- a/tests/test-qmp-output-visitor.c
+++ b/tests/test-qmp-output-visitor.c
@@ -507,6 +507,15 @@ static void test_visitor_out_union_anon(TestOutputVisitorData *data,
     qapi_free_UserDefAnonUnion(tmp);
 }
 
+static void test_visitor_out_empty(TestOutputVisitorData *data,
+                                   const void *unused)
+{
+    QObject *arg;
+
+    arg = qmp_output_get_qobject(data->qov);
+    g_assert(!arg);
+}
+
 static void init_native_list(UserDefNativeListUnion *cvalue)
 {
     int i;
@@ -859,6 +868,8 @@ int main(int argc, char **argv)
                             &out_visitor_data, test_visitor_out_union_flat);
     output_visitor_test_add("/visitor/output/union-anon",
                             &out_visitor_data, test_visitor_out_union_anon);
+    output_visitor_test_add("/visitor/output/empty",
+                            &out_visitor_data, test_visitor_out_empty);
     output_visitor_test_add("/visitor/output/native_list/int",
                             &out_visitor_data, test_visitor_out_native_list_int);
     output_visitor_test_add("/visitor/output/native_list/int8",
diff --git a/tests/test-thread-pool.c b/tests/test-thread-pool.c
index c1f8e13a9f..aa156bcd32 100644
--- a/tests/test-thread-pool.c
+++ b/tests/test-thread-pool.c
@@ -180,7 +180,7 @@ static void test_cancel(void)
 
     /* Canceling the others will be a blocking operation.  */
     for (i = 0; i < 100; i++) {
-        if (data[i].n != 3) {
+        if (data[i].aiocb && data[i].n != 3) {
             bdrv_aio_cancel(data[i].aiocb);
         }
     }
diff --git a/tests/usb-hcd-ehci-test.c b/tests/usb-hcd-ehci-test.c
index bc56ba7707..bcdf62fc3b 100644
--- a/tests/usb-hcd-ehci-test.c
+++ b/tests/usb-hcd-ehci-test.c
@@ -9,12 +9,149 @@
 
 #include <glib.h>
 #include <string.h>
+#include <stdio.h>
 #include "libqtest.h"
+#include "libqos/pci-pc.h"
 #include "qemu/osdep.h"
+#include "hw/usb/uhci-regs.h"
+#include "hw/usb/ehci-regs.h"
 
-/* Tests only initialization so far. TODO: Replace with functional tests */
-static void pci_nop(void)
+struct qhc {
+    QPCIDevice *dev;
+    void *base;
+};
+
+static QPCIBus *pcibus;
+static struct qhc uhci1;
+static struct qhc uhci2;
+static struct qhc uhci3;
+static struct qhc ehci1;
+
+/* helpers */
+
+static void pci_init_one(struct qhc *hc, uint32_t devfn, int bar)
+{
+    hc->dev = qpci_device_find(pcibus, devfn);
+    g_assert(hc->dev != NULL);
+    qpci_device_enable(hc->dev);
+    hc->base = qpci_iomap(hc->dev, bar);
+    g_assert(hc->base != NULL);
+}
+
+#if 0
+static void uhci_port_update(struct qhc *hc, int port,
+                             uint16_t set, uint16_t clear)
 {
+    void *addr = hc->base + 0x10 + 2 * port;
+    uint16_t value;
+
+    value = qpci_io_readw(hc->dev, addr);
+    value |= set;
+    value &= ~clear;
+    qpci_io_writew(hc->dev, addr, value);
+}
+#endif
+
+static void uhci_port_test(struct qhc *hc, int port, uint16_t expect)
+{
+    void *addr = hc->base + 0x10 + 2 * port;
+    uint16_t value = qpci_io_readw(hc->dev, addr);
+    uint16_t mask = ~(UHCI_PORT_WRITE_CLEAR | UHCI_PORT_RSVD1);
+
+#if 0
+    fprintf(stderr, "%s: %d, have 0x%04x, want 0x%04x\n",
+            __func__, port, value & mask, expect & mask);
+#endif
+    g_assert((value & mask) == (expect & mask));
+}
+
+static void ehci_port_test(struct qhc *hc, int port, uint32_t expect)
+{
+    void *addr = hc->base + 0x64 + 4 * port;
+    uint32_t value = qpci_io_readl(hc->dev, addr);
+    uint16_t mask = ~(PORTSC_CSC | PORTSC_PEDC | PORTSC_OCC);
+
+#if 0
+    fprintf(stderr, "%s: %d, have 0x%08x, want 0x%08x\n",
+            __func__, port, value & mask, expect & mask);
+#endif
+    g_assert((value & mask) == (expect & mask));
+}
+
+/* tests */
+
+static void pci_init(void)
+{
+    if (pcibus) {
+        return;
+    }
+    pcibus = qpci_init_pc();
+    g_assert(pcibus != NULL);
+
+    pci_init_one(&uhci1, QPCI_DEVFN(0x1d, 0), 4);
+    pci_init_one(&uhci2, QPCI_DEVFN(0x1d, 1), 4);
+    pci_init_one(&uhci3, QPCI_DEVFN(0x1d, 2), 4);
+    pci_init_one(&ehci1, QPCI_DEVFN(0x1d, 7), 0);
+}
+
+static void pci_uhci_port_1(void)
+{
+    g_assert(pcibus != NULL);
+
+    uhci_port_test(&uhci1, 0, UHCI_PORT_CCS); /* usb-tablet  */
+    uhci_port_test(&uhci1, 1, UHCI_PORT_CCS); /* usb-storage */
+    uhci_port_test(&uhci2, 0, 0);
+    uhci_port_test(&uhci2, 1, 0);
+    uhci_port_test(&uhci3, 0, 0);
+    uhci_port_test(&uhci3, 1, 0);
+}
+
+static void pci_ehci_port_1(void)
+{
+    int i;
+
+    g_assert(pcibus != NULL);
+
+    for (i = 0; i < 6; i++) {
+        ehci_port_test(&ehci1, i, PORTSC_POWNER | PORTSC_PPOWER);
+    }
+}
+
+static void pci_ehci_config(void)
+{
+    /* hands over all ports from companion uhci to ehci */
+    qpci_io_writew(ehci1.dev, ehci1.base + 0x60, 1);
+}
+
+static void pci_uhci_port_2(void)
+{
+    g_assert(pcibus != NULL);
+
+    uhci_port_test(&uhci1, 0, 0); /* usb-tablet,  @ehci */
+    uhci_port_test(&uhci1, 1, 0); /* usb-storage, @ehci */
+    uhci_port_test(&uhci2, 0, 0);
+    uhci_port_test(&uhci2, 1, 0);
+    uhci_port_test(&uhci3, 0, 0);
+    uhci_port_test(&uhci3, 1, 0);
+}
+
+static void pci_ehci_port_2(void)
+{
+    static uint32_t expect[] = {
+        PORTSC_PPOWER | PORTSC_CONNECT, /* usb-tablet  */
+        PORTSC_PPOWER | PORTSC_CONNECT, /* usb-storage */
+        PORTSC_PPOWER,
+        PORTSC_PPOWER,
+        PORTSC_PPOWER,
+        PORTSC_PPOWER,
+    };
+    int i;
+
+    g_assert(pcibus != NULL);
+
+    for (i = 0; i < 6; i++) {
+        ehci_port_test(&ehci1, i, expect[i]);
+    }
 }
 
 int main(int argc, char **argv)
@@ -22,7 +159,12 @@ int main(int argc, char **argv)
     int ret;
 
     g_test_init(&argc, &argv, NULL);
-    qtest_add_func("/ehci/pci/nop", pci_nop);
+    qtest_add_func("/ehci/pci/init", pci_init);
+    qtest_add_func("/ehci/pci/uhci-port-1", pci_uhci_port_1);
+    qtest_add_func("/ehci/pci/ehci-port-1", pci_ehci_port_1);
+    qtest_add_func("/ehci/pci/ehci-config", pci_ehci_config);
+    qtest_add_func("/ehci/pci/uhci-port-2", pci_uhci_port_2);
+    qtest_add_func("/ehci/pci/ehci-port-2", pci_ehci_port_2);
 
     qtest_start("-machine q35 -device ich9-usb-ehci1,bus=pcie.0,addr=1d.7,"
                 "multifunction=on,id=ich9-ehci-1 "
@@ -31,7 +173,10 @@ int main(int argc, char **argv)
                 "-device ich9-usb-uhci2,bus=pcie.0,addr=1d.1,"
                 "multifunction=on,masterbus=ich9-ehci-1.0,firstport=2 "
                 "-device ich9-usb-uhci3,bus=pcie.0,addr=1d.2,"
-                "multifunction=on,masterbus=ich9-ehci-1.0,firstport=4");
+                "multifunction=on,masterbus=ich9-ehci-1.0,firstport=4 "
+                "-drive if=none,id=usbcdrom,media=cdrom "
+                "-device usb-tablet,bus=ich9-ehci-1.0,port=1,usb_version=1 "
+                "-device usb-storage,bus=ich9-ehci-1.0,port=2,drive=usbcdrom ");
     ret = g_test_run();
 
     qtest_end();