summaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
Diffstat (limited to 'tests')
-rw-r--r--tests/.gitignore8
-rw-r--r--tests/Makefile186
-rw-r--r--tests/boot-order-test.c209
-rw-r--r--tests/check-qdict.c6
-rw-r--r--tests/check-qfloat.c2
-rw-r--r--tests/check-qint.c2
-rw-r--r--tests/check-qjson.c738
-rw-r--r--tests/check-qlist.c4
-rw-r--r--tests/check-qstring.c2
-rw-r--r--tests/endianness-test.c316
-rw-r--r--tests/fdc-test.c2
-rw-r--r--tests/fw_cfg-test.c141
-rw-r--r--tests/hd-geo-test.c8
-rw-r--r--tests/i440fx-test.c285
-rw-r--r--tests/ide-test.c506
-rw-r--r--tests/libqos/fw_cfg.c107
-rw-r--r--tests/libqos/fw_cfg.h43
-rw-r--r--tests/libqos/i2c-omap.c173
-rw-r--r--tests/libqos/i2c.c22
-rw-r--r--tests/libqos/i2c.h30
-rw-r--r--tests/libqos/malloc-pc.c71
-rw-r--r--tests/libqos/malloc-pc.h20
-rw-r--r--tests/libqos/malloc.h38
-rw-r--r--tests/libqos/pci-pc.c239
-rw-r--r--tests/libqos/pci-pc.h20
-rw-r--r--tests/libqos/pci.c151
-rw-r--r--tests/libqos/pci.h80
-rw-r--r--tests/libqtest.c98
-rw-r--r--tests/libqtest.h382
-rw-r--r--tests/m48t59-test.c14
-rw-r--r--tests/qapi-schema/comments.err0
-rw-r--r--tests/qapi-schema/comments.exit1
-rw-r--r--tests/qapi-schema/comments.json4
-rw-r--r--tests/qapi-schema/comments.out3
-rw-r--r--tests/qapi-schema/empty.err0
-rw-r--r--tests/qapi-schema/empty.exit1
-rw-r--r--tests/qapi-schema/empty.json0
-rw-r--r--tests/qapi-schema/empty.out3
-rw-r--r--tests/qapi-schema/funny-char.err1
-rw-r--r--tests/qapi-schema/funny-char.exit1
-rw-r--r--tests/qapi-schema/funny-char.json2
-rw-r--r--tests/qapi-schema/funny-char.out0
-rw-r--r--tests/qapi-schema/indented-expr.err0
-rw-r--r--tests/qapi-schema/indented-expr.exit1
-rw-r--r--tests/qapi-schema/indented-expr.json2
-rw-r--r--tests/qapi-schema/indented-expr.out3
-rw-r--r--tests/qapi-schema/missing-colon.err1
-rw-r--r--tests/qapi-schema/missing-colon.exit1
-rw-r--r--tests/qapi-schema/missing-colon.json2
-rw-r--r--tests/qapi-schema/missing-colon.out0
-rw-r--r--tests/qapi-schema/missing-comma-list.err1
-rw-r--r--tests/qapi-schema/missing-comma-list.exit1
-rw-r--r--tests/qapi-schema/missing-comma-list.json2
-rw-r--r--tests/qapi-schema/missing-comma-list.out0
-rw-r--r--tests/qapi-schema/missing-comma-object.err1
-rw-r--r--tests/qapi-schema/missing-comma-object.exit1
-rw-r--r--tests/qapi-schema/missing-comma-object.json2
-rw-r--r--tests/qapi-schema/missing-comma-object.out0
-rw-r--r--tests/qapi-schema/non-objects.err1
-rw-r--r--tests/qapi-schema/non-objects.exit1
-rw-r--r--tests/qapi-schema/non-objects.json2
-rw-r--r--tests/qapi-schema/non-objects.out0
-rw-r--r--tests/qapi-schema/qapi-schema-test.err0
-rw-r--r--tests/qapi-schema/qapi-schema-test.exit1
-rw-r--r--tests/qapi-schema/qapi-schema-test.json53
-rw-r--r--tests/qapi-schema/qapi-schema-test.out19
-rw-r--r--tests/qapi-schema/quoted-structural-chars.err1
-rw-r--r--tests/qapi-schema/quoted-structural-chars.exit1
-rw-r--r--tests/qapi-schema/quoted-structural-chars.json1
-rw-r--r--tests/qapi-schema/quoted-structural-chars.out0
-rw-r--r--tests/qapi-schema/test-qapi.py27
-rw-r--r--tests/qapi-schema/trailing-comma-list.err1
-rw-r--r--tests/qapi-schema/trailing-comma-list.exit1
-rw-r--r--tests/qapi-schema/trailing-comma-list.json2
-rw-r--r--tests/qapi-schema/trailing-comma-list.out0
-rw-r--r--tests/qapi-schema/trailing-comma-object.err1
-rw-r--r--tests/qapi-schema/trailing-comma-object.exit1
-rw-r--r--tests/qapi-schema/trailing-comma-object.json2
-rw-r--r--tests/qapi-schema/trailing-comma-object.out0
-rw-r--r--tests/qapi-schema/unclosed-list.err1
-rw-r--r--tests/qapi-schema/unclosed-list.exit1
-rw-r--r--tests/qapi-schema/unclosed-list.json1
-rw-r--r--tests/qapi-schema/unclosed-list.out0
-rw-r--r--tests/qapi-schema/unclosed-object.err1
-rw-r--r--tests/qapi-schema/unclosed-object.exit1
-rw-r--r--tests/qapi-schema/unclosed-object.json1
-rw-r--r--tests/qapi-schema/unclosed-object.out0
-rw-r--r--tests/qapi-schema/unclosed-string.err1
-rw-r--r--tests/qapi-schema/unclosed-string.exit1
-rw-r--r--tests/qapi-schema/unclosed-string.json2
-rw-r--r--tests/qapi-schema/unclosed-string.out0
-rwxr-xr-xtests/qemu-iotests/00213
-rw-r--r--tests/qemu-iotests/002.out26
-rwxr-xr-xtests/qemu-iotests/0077
-rwxr-xr-xtests/qemu-iotests/0174
-rw-r--r--tests/qemu-iotests/017.out2
-rwxr-xr-xtests/qemu-iotests/0184
-rw-r--r--tests/qemu-iotests/018.out2
-rwxr-xr-xtests/qemu-iotests/0266
-rwxr-xr-xtests/qemu-iotests/03099
-rwxr-xr-xtests/qemu-iotests/0363
-rw-r--r--tests/qemu-iotests/038.out10
-rwxr-xr-xtests/qemu-iotests/0392
-rwxr-xr-xtests/qemu-iotests/041298
-rw-r--r--tests/qemu-iotests/041.out4
-rwxr-xr-xtests/qemu-iotests/0422
-rwxr-xr-xtests/qemu-iotests/0432
-rw-r--r--tests/qemu-iotests/044.out2
-rwxr-xr-xtests/qemu-iotests/045129
-rw-r--r--tests/qemu-iotests/045.out5
-rwxr-xr-xtests/qemu-iotests/046262
-rw-r--r--tests/qemu-iotests/046.out239
-rwxr-xr-xtests/qemu-iotests/04775
-rw-r--r--tests/qemu-iotests/047.out22
-rwxr-xr-xtests/qemu-iotests/04878
-rw-r--r--tests/qemu-iotests/048.out31
-rwxr-xr-xtests/qemu-iotests/049123
-rw-r--r--tests/qemu-iotests/049.out212
-rwxr-xr-xtests/qemu-iotests/05075
-rw-r--r--tests/qemu-iotests/050.out17
-rwxr-xr-xtests/qemu-iotests/051167
-rw-r--r--tests/qemu-iotests/051.out229
-rwxr-xr-xtests/qemu-iotests/05261
-rw-r--r--tests/qemu-iotests/052.out13
-rwxr-xr-xtests/qemu-iotests/05373
-rw-r--r--tests/qemu-iotests/053.out17
-rwxr-xr-xtests/qemu-iotests/05458
-rw-r--r--tests/qemu-iotests/054.out10
-rwxr-xr-xtests/qemu-iotests/055294
-rw-r--r--tests/qemu-iotests/055.out5
-rwxr-xr-xtests/qemu-iotests/05694
-rw-r--r--tests/qemu-iotests/056.out5
-rwxr-xr-xtests/qemu-iotests/05972
-rw-r--r--tests/qemu-iotests/059.out20
-rwxr-xr-xtests/qemu-iotests/check3
-rw-r--r--tests/qemu-iotests/common5
-rw-r--r--tests/qemu-iotests/common.filter7
-rw-r--r--tests/qemu-iotests/common.rc19
-rw-r--r--tests/qemu-iotests/group13
-rw-r--r--tests/qemu-iotests/iotests.py72
-rwxr-xr-xtests/qemu-iotests/qcow2.py17
-rw-r--r--tests/rtc-test.c250
-rw-r--r--tests/tcg/cris/crisutils.h5
-rw-r--r--tests/tcg/linux-test.c1
-rw-r--r--tests/tcg/lm32/test_cmpgei.S15
-rw-r--r--tests/tcg/lm32/test_cmpgeui.S15
-rw-r--r--tests/tcg/lm32/test_cmpgi.S15
-rw-r--r--tests/tcg/lm32/test_cmpgui.S17
-rw-r--r--tests/tcg/mips/mips32-dsp/dpaq_sa_l_w.c64
-rw-r--r--tests/tcg/mips/mips32-dsp/dpsq_s_w_ph.c10
-rw-r--r--tests/tcg/mips/mips32-dsp/dpsq_sa_l_w.c4
-rw-r--r--tests/tcg/mips/mips32-dsp/extp.c18
-rw-r--r--tests/tcg/mips/mips32-dsp/extpdp.c18
-rw-r--r--tests/tcg/mips/mips32-dsp/extr_r_w.c46
-rw-r--r--tests/tcg/mips/mips32-dsp/extr_rs_w.c69
-rw-r--r--tests/tcg/mips/mips32-dsp/extr_s_h.c23
-rw-r--r--tests/tcg/mips/mips32-dsp/extr_w.c46
-rw-r--r--tests/tcg/mips/mips32-dsp/extrv_r_w.c25
-rw-r--r--tests/tcg/mips/mips32-dsp/extrv_rs_w.c25
-rw-r--r--tests/tcg/mips/mips32-dsp/extrv_s_h.c17
-rw-r--r--tests/tcg/mips/mips32-dsp/extrv_w.c26
-rw-r--r--tests/tcg/mips/mips32-dsp/insv.c15
-rw-r--r--tests/tcg/mips/mips32-dsp/maq_s_w_phl.c16
-rw-r--r--tests/tcg/mips/mips32-dsp/maq_s_w_phr.c24
-rw-r--r--tests/tcg/mips/mips32-dsp/maq_sa_w_phl.c12
-rw-r--r--tests/tcg/mips/mips32-dsp/maq_sa_w_phr.c24
-rw-r--r--tests/tcg/mips/mips32-dsp/mthlip.c2
-rw-r--r--tests/tcg/mips/mips32-dsp/mulq_rs_ph.c19
-rw-r--r--tests/tcg/mips/mips32-dsp/precrq_rs_ph_w.c24
-rw-r--r--tests/tcg/mips/mips32-dsp/rddsp.c32
-rw-r--r--tests/tcg/mips/mips32-dsp/shilo.c18
-rw-r--r--tests/tcg/mips/mips32-dsp/shilov.c20
-rw-r--r--tests/tcg/mips/mips32-dsp/shll_ph.c33
-rw-r--r--tests/tcg/mips/mips32-dsp/shll_qb.c23
-rw-r--r--tests/tcg/mips/mips32-dsp/subq_s_ph.c22
-rw-r--r--tests/tcg/mips/mips32-dsp/subq_s_w.c36
-rw-r--r--tests/tcg/mips/mips32-dsp/wrdsp.c32
-rw-r--r--tests/tcg/mips/mips32-dspr2/dpa_w_ph.c4
-rw-r--r--tests/tcg/mips/mips32-dspr2/dpaqx_sa_w_ph.c12
-rw-r--r--tests/tcg/mips/mips32-dspr2/dpax_w_ph.c17
-rw-r--r--tests/tcg/mips/mips32-dspr2/dps_w_ph.c17
-rw-r--r--tests/tcg/mips/mips32-dspr2/dpsqx_s_w_ph.c8
-rw-r--r--tests/tcg/mips/mips32-dspr2/dpsx_w_ph.c4
-rw-r--r--tests/tcg/mips/mips32-dspr2/mulq_rs_w.c2
-rw-r--r--tests/tcg/mips/mips32-dspr2/mulq_s_ph.c15
-rw-r--r--tests/tcg/mips/mips32-dspr2/mulq_s_w.c2
-rw-r--r--tests/tcg/test-i386-fprem.c4
-rw-r--r--tests/tcg/test-i386.c12
-rw-r--r--tests/tcg/xtensa/Makefile23
-rw-r--r--tests/tcg/xtensa/macros.inc2
-rw-r--r--tests/tcg/xtensa/test_extui.S26
-rw-r--r--tests/tcg/xtensa/test_s32c1i.S39
-rw-r--r--tests/tcg/xtensa/test_sr.S90
-rw-r--r--tests/test-aio.c37
-rw-r--r--tests/test-bitops.c75
-rw-r--r--tests/test-coroutine.c4
-rw-r--r--tests/test-cutils.c251
-rw-r--r--tests/test-hbitmap.c401
-rw-r--r--tests/test-int128.c212
-rw-r--r--tests/test-iov.c154
-rw-r--r--tests/test-mul64.c70
-rw-r--r--tests/test-qmp-commands.c7
-rw-r--r--tests/test-qmp-input-strict.c3
-rw-r--r--tests/test-qmp-input-visitor.c361
-rw-r--r--tests/test-qmp-output-visitor.c340
-rw-r--r--tests/test-string-input-visitor.c52
-rw-r--r--tests/test-string-output-visitor.c3
-rw-r--r--tests/test-thread-pool.c70
-rw-r--r--tests/test-visitor-serialization.c503
-rw-r--r--tests/test-x86-cpuid.c110
-rw-r--r--tests/test-xbzrle.c196
-rw-r--r--tests/tmp105-test.c76
212 files changed, 10706 insertions, 627 deletions
diff --git a/tests/.gitignore b/tests/.gitignore
index f9041f3d3..fb05c2ae8 100644
--- a/tests/.gitignore
+++ b/tests/.gitignore
@@ -4,10 +4,18 @@ check-qint
check-qjson
check-qlist
check-qstring
+test-aio
+test-cutils
+test-hbitmap
+test-iov
+test-mul64
test-qapi-types.[ch]
test-qapi-visit.[ch]
test-qmp-commands.h
test-qmp-commands
test-qmp-input-strict
test-qmp-marshal.c
+test-thread-pool
+test-x86-cpuid
+test-xbzrle
*-test
diff --git a/tests/Makefile b/tests/Makefile
index b60f0fb8f..d0449080b 100644
--- a/tests/Makefile
+++ b/tests/Makefile
@@ -1,33 +1,95 @@
export SRC_PATH
check-unit-y = tests/check-qdict$(EXESUF)
+gcov-files-check-qdict-y = qobject/qdict.c
check-unit-y += tests/check-qfloat$(EXESUF)
+gcov-files-check-qfloat-y = qobject/qfloat.c
check-unit-y += tests/check-qint$(EXESUF)
+gcov-files-check-qint-y = qobject/qint.c
check-unit-y += tests/check-qstring$(EXESUF)
+gcov-files-check-qstring-y = qobject/qstring.c
check-unit-y += tests/check-qlist$(EXESUF)
+gcov-files-check-qlist-y = qobject/qlist.c
check-unit-y += tests/check-qjson$(EXESUF)
+gcov-files-check-qjson-y = qobject/qjson.c
check-unit-y += tests/test-qmp-output-visitor$(EXESUF)
+gcov-files-test-qmp-output-visitor-y = qapi/qmp-output-visitor.c
check-unit-y += tests/test-qmp-input-visitor$(EXESUF)
+gcov-files-test-qmp-input-visitor-y = qapi/qmp-input-visitor.c
check-unit-y += tests/test-qmp-input-strict$(EXESUF)
check-unit-y += tests/test-qmp-commands$(EXESUF)
+gcov-files-test-qmp-commands-y = qapi/qmp-dispatch.c
check-unit-y += tests/test-string-input-visitor$(EXESUF)
+gcov-files-test-string-input-visitor-y = qapi/string-input-visitor.c
check-unit-y += tests/test-string-output-visitor$(EXESUF)
+gcov-files-test-string-output-visitor-y = qapi/string-output-visitor.c
check-unit-y += tests/test-coroutine$(EXESUF)
+gcov-files-test-coroutine-y = coroutine-$(CONFIG_COROUTINE_BACKEND).c
check-unit-y += tests/test-visitor-serialization$(EXESUF)
check-unit-y += tests/test-iov$(EXESUF)
+gcov-files-test-iov-y = util/iov.c
check-unit-y += tests/test-aio$(EXESUF)
+gcov-files-test-aio-$(CONFIG_WIN32) = aio-win32.c
+gcov-files-test-aio-$(CONFIG_POSIX) = aio-posix.c
check-unit-y += tests/test-thread-pool$(EXESUF)
+gcov-files-test-thread-pool-y = thread-pool.c
+gcov-files-test-hbitmap-y = util/hbitmap.c
+check-unit-y += tests/test-hbitmap$(EXESUF)
+check-unit-y += tests/test-x86-cpuid$(EXESUF)
+# all code tested by test-x86-cpuid is inside topology.h
+gcov-files-test-x86-cpuid-y =
+check-unit-y += tests/test-xbzrle$(EXESUF)
+gcov-files-test-xbzrle-y = xbzrle.c
+check-unit-y += tests/test-cutils$(EXESUF)
+gcov-files-test-cutils-y += util/cutils.c
+check-unit-y += tests/test-mul64$(EXESUF)
+gcov-files-test-mul64-y = util/host-utils.c
+check-unit-y += tests/test-int128$(EXESUF)
+# all code tested by test-int128 is inside int128.h
+gcov-files-test-int128-y =
+check-unit-y += tests/test-bitops$(EXESUF)
check-block-$(CONFIG_POSIX) += tests/qemu-iotests-quick.sh
# All QTests for now are POSIX-only, but the dependencies are
# really in libqtest, not in the testcases themselves.
-check-qtest-i386-y = tests/fdc-test$(EXESUF)
+check-qtest-i386-y = tests/endianness-test$(EXESUF)
+check-qtest-i386-y += tests/fdc-test$(EXESUF)
+gcov-files-i386-y = hw/fdc.c
+check-qtest-i386-y += tests/ide-test$(EXESUF)
check-qtest-i386-y += tests/hd-geo-test$(EXESUF)
+gcov-files-i386-y += hw/hd-geometry.c
+check-qtest-i386-y += tests/boot-order-test$(EXESUF)
check-qtest-i386-y += tests/rtc-test$(EXESUF)
+check-qtest-i386-y += tests/i440fx-test$(EXESUF)
+check-qtest-i386-y += tests/fw_cfg-test$(EXESUF)
check-qtest-x86_64-y = $(check-qtest-i386-y)
-check-qtest-sparc-y = tests/m48t59-test$(EXESUF)
-check-qtest-sparc64-y = tests/m48t59-test$(EXESUF)
+gcov-files-i386-y += i386-softmmu/hw/mc146818rtc.c
+gcov-files-x86_64-y = $(subst i386-softmmu/,x86_64-softmmu/,$(gcov-files-i386-y))
+check-qtest-mips-y = tests/endianness-test$(EXESUF)
+check-qtest-mips64-y = tests/endianness-test$(EXESUF)
+check-qtest-mips64el-y = tests/endianness-test$(EXESUF)
+check-qtest-ppc-y = tests/endianness-test$(EXESUF)
+check-qtest-ppc64-y = tests/endianness-test$(EXESUF)
+check-qtest-sh4-y = tests/endianness-test$(EXESUF)
+check-qtest-sh4eb-y = tests/endianness-test$(EXESUF)
+check-qtest-sparc64-y = tests/endianness-test$(EXESUF)
+#check-qtest-sparc-y = tests/m48t59-test$(EXESUF)
+#check-qtest-sparc64-y += tests/m48t59-test$(EXESUF)
+gcov-files-sparc-y += hw/m48t59.c
+gcov-files-sparc64-y += hw/m48t59.c
+check-qtest-arm-y = tests/tmp105-test$(EXESUF)
+gcov-files-arm-y += hw/tmp105.c
+check-qtest-ppc-y += tests/boot-order-test$(EXESUF)
+check-qtest-ppc64-y += tests/boot-order-test$(EXESUF)
+
+check-qapi-schema-y := $(addprefix tests/qapi-schema/, \
+ comments.json empty.json funny-char.json indented-expr.json \
+ missing-colon.json missing-comma-list.json \
+ missing-comma-object.json non-objects.json \
+ qapi-schema-test.json quoted-structural-chars.json \
+ trailing-comma-list.json trailing-comma-object.json \
+ unclosed-list.json unclosed-object.json unclosed-string.json)
GENERATED_HEADERS += tests/test-qapi-types.h tests/test-qapi-visit.h tests/test-qmp-commands.h
@@ -36,48 +98,69 @@ test-obj-y = tests/check-qint.o tests/check-qstring.o tests/check-qdict.o \
tests/test-coroutine.o tests/test-string-output-visitor.o \
tests/test-string-input-visitor.o tests/test-qmp-output-visitor.o \
tests/test-qmp-input-visitor.o tests/test-qmp-input-strict.o \
- tests/test-qmp-commands.o tests/test-visitor-serialization.o
+ tests/test-qmp-commands.o tests/test-visitor-serialization.o \
+ tests/test-x86-cpuid.o tests/test-mul64.o tests/test-int128.o
-test-qapi-obj-y = $(qobject-obj-y) $(qapi-obj-y) qemu-tool.o
-test-qapi-obj-y += tests/test-qapi-visit.o tests/test-qapi-types.o
-test-qapi-obj-y += module.o
+test-qapi-obj-y = tests/test-qapi-visit.o tests/test-qapi-types.o
$(test-obj-y): QEMU_INCLUDES += -Itests
-
-tests/check-qint$(EXESUF): tests/check-qint.o qint.o
-tests/check-qstring$(EXESUF): tests/check-qstring.o qstring.o
-tests/check-qdict$(EXESUF): tests/check-qdict.o qdict.o qfloat.o qint.o qstring.o qbool.o qlist.o
-tests/check-qlist$(EXESUF): tests/check-qlist.o qlist.o qint.o
-tests/check-qfloat$(EXESUF): tests/check-qfloat.o qfloat.o
-tests/check-qjson$(EXESUF): tests/check-qjson.o $(qobject-obj-y) qemu-tool.o
-tests/test-coroutine$(EXESUF): tests/test-coroutine.o $(coroutine-obj-y) $(tools-obj-y) $(block-obj-y) iov.o libqemustub.a
-tests/test-aio$(EXESUF): tests/test-aio.o $(coroutine-obj-y) $(tools-obj-y) $(block-obj-y) libqemustub.a
-tests/test-thread-pool$(EXESUF): tests/test-thread-pool.o $(coroutine-obj-y) $(tools-obj-y) $(block-obj-y) libqemustub.a
-tests/test-iov$(EXESUF): tests/test-iov.o iov.o
+QEMU_CFLAGS += -I$(SRC_PATH)/tests
+
+tests/test-x86-cpuid.o: QEMU_INCLUDES += -I$(SRC_PATH)/target-i386
+
+tests/check-qint$(EXESUF): tests/check-qint.o libqemuutil.a
+tests/check-qstring$(EXESUF): tests/check-qstring.o libqemuutil.a
+tests/check-qdict$(EXESUF): tests/check-qdict.o libqemuutil.a
+tests/check-qlist$(EXESUF): tests/check-qlist.o libqemuutil.a
+tests/check-qfloat$(EXESUF): tests/check-qfloat.o libqemuutil.a
+tests/check-qjson$(EXESUF): tests/check-qjson.o libqemuutil.a libqemustub.a
+tests/test-coroutine$(EXESUF): tests/test-coroutine.o $(block-obj-y) libqemuutil.a libqemustub.a
+tests/test-aio$(EXESUF): tests/test-aio.o $(block-obj-y) libqemuutil.a libqemustub.a
+tests/test-thread-pool$(EXESUF): tests/test-thread-pool.o $(block-obj-y) libqemuutil.a libqemustub.a
+tests/test-iov$(EXESUF): tests/test-iov.o libqemuutil.a
+tests/test-hbitmap$(EXESUF): tests/test-hbitmap.o libqemuutil.a libqemustub.a
+tests/test-x86-cpuid$(EXESUF): tests/test-x86-cpuid.o
+tests/test-xbzrle$(EXESUF): tests/test-xbzrle.o xbzrle.o page_cache.o libqemuutil.a
+tests/test-cutils$(EXESUF): tests/test-cutils.o util/cutils.o
+tests/test-int128$(EXESUF): tests/test-int128.o
tests/test-qapi-types.c tests/test-qapi-types.h :\
-$(SRC_PATH)/qapi-schema-test.json $(SRC_PATH)/scripts/qapi-types.py
+$(SRC_PATH)/tests/qapi-schema/qapi-schema-test.json $(SRC_PATH)/scripts/qapi-types.py
$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-types.py $(gen-out-type) -o tests -p "test-" < $<, " GEN $@")
tests/test-qapi-visit.c tests/test-qapi-visit.h :\
-$(SRC_PATH)/qapi-schema-test.json $(SRC_PATH)/scripts/qapi-visit.py
+$(SRC_PATH)/tests/qapi-schema/qapi-schema-test.json $(SRC_PATH)/scripts/qapi-visit.py
$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-visit.py $(gen-out-type) -o tests -p "test-" < $<, " GEN $@")
tests/test-qmp-commands.h tests/test-qmp-marshal.c :\
-$(SRC_PATH)/qapi-schema-test.json $(SRC_PATH)/scripts/qapi-commands.py
+$(SRC_PATH)/tests/qapi-schema/qapi-schema-test.json $(SRC_PATH)/scripts/qapi-commands.py
$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-commands.py $(gen-out-type) -o tests -p "test-" < $<, " GEN $@")
-
-tests/test-string-output-visitor$(EXESUF): tests/test-string-output-visitor.o $(test-qapi-obj-y)
-tests/test-string-input-visitor$(EXESUF): tests/test-string-input-visitor.o $(test-qapi-obj-y)
-tests/test-qmp-output-visitor$(EXESUF): tests/test-qmp-output-visitor.o $(test-qapi-obj-y)
-tests/test-qmp-input-visitor$(EXESUF): tests/test-qmp-input-visitor.o $(test-qapi-obj-y)
-tests/test-qmp-input-strict$(EXESUF): tests/test-qmp-input-strict.o $(test-qapi-obj-y)
-tests/test-qmp-commands$(EXESUF): tests/test-qmp-commands.o tests/test-qmp-marshal.o $(test-qapi-obj-y)
-tests/test-visitor-serialization$(EXESUF): tests/test-visitor-serialization.o $(test-qapi-obj-y)
-
-tests/rtc-test$(EXESUF): tests/rtc-test.o $(trace-obj-y)
-tests/m48t59-test$(EXESUF): tests/m48t59-test.o $(trace-obj-y)
-tests/fdc-test$(EXESUF): tests/fdc-test.o tests/libqtest.o $(trace-obj-y)
-tests/hd-geo-test$(EXESUF): tests/hd-geo-test.o tests/libqtest.o $(trace-obj-y)
+tests/test-string-output-visitor$(EXESUF): tests/test-string-output-visitor.o $(test-qapi-obj-y) libqemuutil.a libqemustub.a
+tests/test-string-input-visitor$(EXESUF): tests/test-string-input-visitor.o $(test-qapi-obj-y) libqemuutil.a libqemustub.a
+tests/test-qmp-output-visitor$(EXESUF): tests/test-qmp-output-visitor.o $(test-qapi-obj-y) libqemuutil.a libqemustub.a
+tests/test-qmp-input-visitor$(EXESUF): tests/test-qmp-input-visitor.o $(test-qapi-obj-y) libqemuutil.a libqemustub.a
+tests/test-qmp-input-strict$(EXESUF): tests/test-qmp-input-strict.o $(test-qapi-obj-y) libqemuutil.a libqemustub.a
+tests/test-qmp-commands$(EXESUF): tests/test-qmp-commands.o tests/test-qmp-marshal.o $(test-qapi-obj-y) qapi-types.o qapi-visit.o libqemuutil.a libqemustub.a
+tests/test-visitor-serialization$(EXESUF): tests/test-visitor-serialization.o $(test-qapi-obj-y) libqemuutil.a libqemustub.a
+
+tests/test-mul64$(EXESUF): tests/test-mul64.o libqemuutil.a
+tests/test-bitops$(EXESUF): tests/test-bitops.o libqemuutil.a
+
+libqos-obj-y = tests/libqos/pci.o tests/libqos/fw_cfg.o
+libqos-obj-y += tests/libqos/i2c.o
+libqos-pc-obj-y = $(libqos-obj-y) tests/libqos/pci-pc.o
+libqos-pc-obj-y += tests/libqos/malloc-pc.o
+libqos-omap-obj-y = $(libqos-obj-y) tests/libqos/i2c-omap.o
+
+tests/rtc-test$(EXESUF): tests/rtc-test.o
+tests/m48t59-test$(EXESUF): tests/m48t59-test.o
+tests/endianness-test$(EXESUF): tests/endianness-test.o
+tests/fdc-test$(EXESUF): tests/fdc-test.o
+tests/ide-test$(EXESUF): tests/ide-test.o $(libqos-pc-obj-y)
+tests/hd-geo-test$(EXESUF): tests/hd-geo-test.o
+tests/boot-order-test$(EXESUF): tests/boot-order-test.o $(libqos-obj-y)
+tests/tmp105-test$(EXESUF): tests/tmp105-test.o $(libqos-omap-obj-y)
+tests/i440fx-test$(EXESUF): tests/i440fx-test.o $(libqos-pc-obj-y)
+tests/fw_cfg-test$(EXESUF): tests/fw_cfg-test.o $(libqos-pc-obj-y)
# QTest rules
@@ -85,7 +168,7 @@ TARGETS=$(patsubst %-softmmu,%, $(filter %-softmmu,$(TARGET_DIRS)))
QTEST_TARGETS=$(foreach TARGET,$(TARGETS), $(if $(check-qtest-$(TARGET)-y), $(TARGET),))
check-qtest-$(CONFIG_POSIX)=$(foreach TARGET,$(TARGETS), $(check-qtest-$(TARGET)-y))
-qtest-obj-y = tests/libqtest.o $(oslib-obj-y) libqemustub.a
+qtest-obj-y = tests/libqtest.o libqemuutil.a libqemustub.a
$(check-qtest-y): $(qtest-obj-y)
.PHONY: check-help
@@ -96,6 +179,7 @@ check-help:
@echo " make check-qtest-TARGET Run qtest tests for given target"
@echo " make check-qtest Run qtest tests"
@echo " make check-unit Run qobject tests"
+ @echo " make check-qapi-schema Run QAPI schema tests"
@echo " make check-block Run block tests"
@echo " make check-report.html Generates an HTML test report"
@echo
@@ -108,17 +192,31 @@ check-help:
SPEED = quick
GTESTER_OPTIONS = -k $(if $(V),--verbose,-q)
+GCOV_OPTIONS = -n $(if $(V),-f,)
# gtester tests, possibly with verbose output
.PHONY: $(patsubst %, check-qtest-%, $(QTEST_TARGETS))
$(patsubst %, check-qtest-%, $(QTEST_TARGETS)): check-qtest-%: $(check-qtest-y)
+ $(if $(CONFIG_GCOV),@rm -f *.gcda */*.gcda */*/*.gcda */*/*/*.gcda,)
$(call quiet-command,QTEST_QEMU_BINARY=$*-softmmu/qemu-system-$* \
+ MALLOC_PERTURB_=$${MALLOC_PERTURB_:-$$((RANDOM % 255 + 1))} \
gtester $(GTESTER_OPTIONS) -m=$(SPEED) $(check-qtest-$*-y),"GTESTER $@")
+ $(if $(CONFIG_GCOV),@for f in $(gcov-files-$*-y); do \
+ echo Gcov report for $$f:;\
+ $(GCOV) $(GCOV_OPTIONS) $$f -o `dirname $$f`; \
+ done,)
.PHONY: $(patsubst %, check-%, $(check-unit-y))
$(patsubst %, check-%, $(check-unit-y)): check-%: %
- $(call quiet-command,gtester $(GTESTER_OPTIONS) -m=$(SPEED) $*,"GTESTER $*")
+ $(if $(CONFIG_GCOV),@rm -f *.gcda */*.gcda */*/*.gcda */*/*/*.gcda,)
+ $(call quiet-command, \
+ MALLOC_PERTURB_=$${MALLOC_PERTURB_:-$$((RANDOM % 255 + 1))} \
+ gtester $(GTESTER_OPTIONS) -m=$(SPEED) $*,"GTESTER $*")
+ $(if $(CONFIG_GCOV),@for f in $(gcov-files-$(subst tests/,,$*)-y); do \
+ echo Gcov report for $$f:;\
+ $(GCOV) $(GCOV_OPTIONS) $$f -o `dirname $$f`; \
+ done,)
# gtester tests with XML output
@@ -144,12 +242,24 @@ check-report.html: check-report.xml
check-tests/qemu-iotests-quick.sh: tests/qemu-iotests-quick.sh qemu-img$(EXESUF) qemu-io$(EXESUF)
$<
+.PHONY: check-tests/test-qapi.py
+check-tests/test-qapi.py: tests/test-qapi.py
+
+.PHONY: $(patsubst %, check-%, $(check-qapi-schema-y))
+$(patsubst %, check-%, $(check-qapi-schema-y)): check-%.json: $(SRC_PATH)/%.json
+ $(call quiet-command, PYTHONPATH=$(SRC_PATH)/scripts $(PYTHON) $(SRC_PATH)/tests/qapi-schema/test-qapi.py <$^ >$*.out 2>$*.err; echo $$? >$*.exit, " TEST $*.out")
+ @diff -q $(SRC_PATH)/$*.out $*.out
+ @diff -q $(SRC_PATH)/$*.err $*.err
+ @diff -q $(SRC_PATH)/$*.exit $*.exit
+
# Consolidated targets
-.PHONY: check-qtest check-unit check
+.PHONY: check-qapi-schema check-qtest check-unit check
+check-qapi-schema: $(patsubst %,check-%, $(check-qapi-schema-y))
check-qtest: $(patsubst %,check-qtest-%, $(QTEST_TARGETS))
check-unit: $(patsubst %,check-%, $(check-unit-y))
check-block: $(patsubst %,check-%, $(check-block-y))
-check: check-unit check-qtest
+check: check-qapi-schema check-unit check-qtest
-include $(wildcard tests/*.d)
+-include $(wildcard tests/libqos/*.d)
diff --git a/tests/boot-order-test.c b/tests/boot-order-test.c
new file mode 100644
index 000000000..4b233d0b2
--- /dev/null
+++ b/tests/boot-order-test.c
@@ -0,0 +1,209 @@
+/*
+ * Boot order test cases.
+ *
+ * Copyright (c) 2013 Red Hat Inc.
+ *
+ * Authors:
+ * Markus Armbruster <armbru@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 <string.h>
+#include <glib.h>
+#include "libqos/fw_cfg.h"
+#include "libqtest.h"
+
+#define NO_QEMU_PROTOS
+#include "hw/nvram/fw_cfg.h"
+#undef NO_QEMU_PROTOS
+
+typedef struct {
+ const char *args;
+ uint64_t expected_boot;
+ uint64_t expected_reboot;
+} boot_order_test;
+
+static void test_a_boot_order(const char *machine,
+ const char *test_args,
+ uint64_t (*read_boot_order)(void),
+ uint64_t expected_boot,
+ uint64_t expected_reboot)
+{
+ char *args;
+ uint64_t actual;
+
+ args = g_strdup_printf("-nodefaults -display none%s%s %s",
+ machine ? " -M " : "",
+ machine ?: "",
+ test_args);
+ qtest_start(args);
+ actual = read_boot_order();
+ g_assert_cmphex(actual, ==, expected_boot);
+ qmp("{ 'execute': 'system_reset' }");
+ /*
+ * system_reset only requests reset. We get a RESET event after
+ * the actual reset completes. Need to wait for that.
+ */
+ qmp(""); /* HACK: wait for event */
+ actual = read_boot_order();
+ g_assert_cmphex(actual, ==, expected_reboot);
+ qtest_quit(global_qtest);
+ g_free(args);
+}
+
+static void test_boot_orders(const char *machine,
+ uint64_t (*read_boot_order)(void),
+ const boot_order_test *tests)
+{
+ int i;
+
+ for (i = 0; tests[i].args; i++) {
+ test_a_boot_order(machine, tests[i].args,
+ read_boot_order,
+ tests[i].expected_boot,
+ tests[i].expected_reboot);
+ }
+}
+
+static uint8_t read_mc146818(uint16_t port, uint8_t reg)
+{
+ outb(port, reg);
+ return inb(port + 1);
+}
+
+static uint64_t read_boot_order_pc(void)
+{
+ uint8_t b1 = read_mc146818(0x70, 0x38);
+ uint8_t b2 = read_mc146818(0x70, 0x3d);
+
+ return b1 | (b2 << 8);
+}
+
+static const boot_order_test test_cases_pc[] = {
+ { "",
+ 0x1230, 0x1230 },
+ { "-no-fd-bootchk",
+ 0x1231, 0x1231 },
+ { "-boot c",
+ 0x0200, 0x0200 },
+ { "-boot nda",
+ 0x3410, 0x3410 },
+ { "-boot order=",
+ 0, 0 },
+ { "-boot order= -boot order=c",
+ 0x0200, 0x0200 },
+ { "-boot once=a",
+ 0x0100, 0x1230 },
+ { "-boot once=a -no-fd-bootchk",
+ 0x0101, 0x1231 },
+ { "-boot once=a,order=c",
+ 0x0100, 0x0200 },
+ { "-boot once=d -boot order=nda",
+ 0x0300, 0x3410 },
+ { "-boot once=a -boot once=b -boot once=c",
+ 0x0200, 0x1230 },
+ {}
+};
+
+static void test_pc_boot_order(void)
+{
+ test_boot_orders(NULL, read_boot_order_pc, test_cases_pc);
+}
+
+static uint8_t read_m48t59(uint64_t addr, uint16_t reg)
+{
+ writeb(addr, reg & 0xff);
+ writeb(addr + 1, reg >> 8);
+ return readb(addr + 3);
+}
+
+static uint64_t read_boot_order_prep(void)
+{
+ return read_m48t59(0x80000000 + 0x74, 0x34);
+}
+
+static const boot_order_test test_cases_prep[] = {
+ { "", 'c', 'c' },
+ { "-boot c", 'c', 'c' },
+ { "-boot d", 'd', 'd' },
+ {}
+};
+
+static void test_prep_boot_order(void)
+{
+ test_boot_orders("prep", read_boot_order_prep, test_cases_prep);
+}
+
+static uint64_t read_boot_order_pmac(void)
+{
+ QFWCFG *fw_cfg = mm_fw_cfg_init(0xf0000510);
+
+ return qfw_cfg_get_u16(fw_cfg, FW_CFG_BOOT_DEVICE);
+}
+
+static const boot_order_test test_cases_fw_cfg[] = {
+ { "", 'c', 'c' },
+ { "-boot c", 'c', 'c' },
+ { "-boot d", 'd', 'd' },
+ { "-boot once=d,order=c", 'd', 'c' },
+ {}
+};
+
+static void test_pmac_oldworld_boot_order(void)
+{
+ test_boot_orders("g3beige", read_boot_order_pmac, test_cases_fw_cfg);
+}
+
+static void test_pmac_newworld_boot_order(void)
+{
+ test_boot_orders("mac99", read_boot_order_pmac, test_cases_fw_cfg);
+}
+
+static uint64_t read_boot_order_sun4m(void)
+{
+ QFWCFG *fw_cfg = mm_fw_cfg_init(0xd00000510ULL);
+
+ return qfw_cfg_get_u16(fw_cfg, FW_CFG_BOOT_DEVICE);
+}
+
+static void test_sun4m_boot_order(void)
+{
+ test_boot_orders("SS-5", read_boot_order_sun4m, test_cases_fw_cfg);
+}
+
+static uint64_t read_boot_order_sun4u(void)
+{
+ QFWCFG *fw_cfg = io_fw_cfg_init(0x510);
+
+ return qfw_cfg_get_u16(fw_cfg, FW_CFG_BOOT_DEVICE);
+}
+
+static void test_sun4u_boot_order(void)
+{
+ test_boot_orders("sun4u", read_boot_order_sun4u, test_cases_fw_cfg);
+}
+
+int main(int argc, char *argv[])
+{
+ const char *arch = qtest_get_arch();
+
+ g_test_init(&argc, &argv, NULL);
+
+ if (strcmp(arch, "i386") == 0 || strcmp(arch, "x86_64") == 0) {
+ qtest_add_func("boot-order/pc", test_pc_boot_order);
+ } else if (strcmp(arch, "ppc") == 0 || strcmp(arch, "ppc64") == 0) {
+ qtest_add_func("boot-order/prep", test_prep_boot_order);
+ qtest_add_func("boot-order/pmac_oldworld",
+ test_pmac_oldworld_boot_order);
+ qtest_add_func("boot-order/pmac_newworld",
+ test_pmac_newworld_boot_order);
+ } else if (strcmp(arch, "sparc") == 0) {
+ qtest_add_func("boot-order/sun4m", test_sun4m_boot_order);
+ } else if (strcmp(arch, "sparc64") == 0) {
+ qtest_add_func("boot-order/sun4u", test_sun4u_boot_order);
+ }
+
+ return g_test_run();
+}
diff --git a/tests/check-qdict.c b/tests/check-qdict.c
index fc0d27653..dc5f05a85 100644
--- a/tests/check-qdict.c
+++ b/tests/check-qdict.c
@@ -11,9 +11,9 @@
*/
#include <glib.h>
-#include "qint.h"
-#include "qdict.h"
-#include "qstring.h"
+#include "qapi/qmp/qint.h"
+#include "qapi/qmp/qdict.h"
+#include "qapi/qmp/qstring.h"
#include "qemu-common.h"
/*
diff --git a/tests/check-qfloat.c b/tests/check-qfloat.c
index cdc66ea10..6404ac8df 100644
--- a/tests/check-qfloat.c
+++ b/tests/check-qfloat.c
@@ -12,7 +12,7 @@
*/
#include <glib.h>
-#include "qfloat.h"
+#include "qapi/qmp/qfloat.h"
#include "qemu-common.h"
/*
diff --git a/tests/check-qint.c b/tests/check-qint.c
index 5a27119ae..86868844a 100644
--- a/tests/check-qint.c
+++ b/tests/check-qint.c
@@ -11,7 +11,7 @@
*/
#include <glib.h>
-#include "qint.h"
+#include "qapi/qmp/qint.h"
#include "qemu-common.h"
/*
diff --git a/tests/check-qjson.c b/tests/check-qjson.c
index 3b896f5f9..4e7454810 100644
--- a/tests/check-qjson.c
+++ b/tests/check-qjson.c
@@ -1,8 +1,10 @@
/*
* Copyright IBM, Corp. 2009
+ * Copyright (c) 2013 Red Hat Inc.
*
* Authors:
* Anthony Liguori <aliguori@us.ibm.com>
+ * Markus Armbruster <armbru@redhat.com>
*
* 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.
@@ -10,13 +12,13 @@
*/
#include <glib.h>
-#include "qstring.h"
-#include "qint.h"
-#include "qdict.h"
-#include "qlist.h"
-#include "qfloat.h"
-#include "qbool.h"
-#include "qjson.h"
+#include "qapi/qmp/qstring.h"
+#include "qapi/qmp/qint.h"
+#include "qapi/qmp/qdict.h"
+#include "qapi/qmp/qlist.h"
+#include "qapi/qmp/qfloat.h"
+#include "qapi/qmp/qbool.h"
+#include "qapi/qmp/qjson.h"
#include "qemu-common.h"
@@ -131,6 +133,727 @@ static void single_quote_string(void)
}
}
+static void utf8_string(void)
+{
+ /*
+ * FIXME Current behavior for invalid UTF-8 sequences is
+ * incorrect. This test expects current, incorrect results.
+ * They're all marked "bug:" below, and are to be replaced by
+ * correct ones as the bugs get fixed.
+ *
+ * The JSON parser rejects some invalid sequences, but accepts
+ * others without correcting the problem.
+ *
+ * We should either reject all invalid sequences, or minimize
+ * overlong sequences and replace all other invalid sequences by a
+ * suitable replacement character. A common choice for
+ * replacement is U+FFFD.
+ *
+ * Problem: we can't easily deal with embedded U+0000. Parsing
+ * the JSON string "this \\u0000" is fun" yields "this \0 is fun",
+ * which gets misinterpreted as NUL-terminated "this ". We should
+ * consider using overlong encoding \xC0\x80 for U+0000 ("modified
+ * UTF-8").
+ *
+ * Most test cases are scraped from Markus Kuhn's UTF-8 decoder
+ * capability and stress test at
+ * http://www.cl.cam.ac.uk/~mgk25/ucs/examples/UTF-8-test.txt
+ */
+ static const struct {
+ const char *json_in;
+ const char *utf8_out;
+ const char *json_out; /* defaults to @json_in */
+ const char *utf8_in; /* defaults to @utf8_out */
+ } test_cases[] = {
+ /*
+ * Bug markers used here:
+ * - bug: not corrected
+ * JSON parser fails to correct invalid sequence(s)
+ * - bug: rejected
+ * JSON parser rejects invalid sequence(s)
+ * We may choose to define this as feature
+ * - bug: want "..."
+ * JSON parser produces incorrect result, this is the
+ * correct one, assuming replacement character U+FFFF
+ * We may choose to reject instead of replace
+ */
+
+ /* 1 Some correct UTF-8 text */
+ {
+ /* a bit of German */
+ "\"Falsches \xC3\x9C" "ben von Xylophonmusik qu\xC3\xA4lt"
+ " jeden gr\xC3\xB6\xC3\x9F" "eren Zwerg.\"",
+ "Falsches \xC3\x9C" "ben von Xylophonmusik qu\xC3\xA4lt"
+ " jeden gr\xC3\xB6\xC3\x9F" "eren Zwerg.",
+ "\"Falsches \\u00DCben von Xylophonmusik qu\\u00E4lt"
+ " jeden gr\\u00F6\\u00DFeren Zwerg.\"",
+ },
+ {
+ /* a bit of Greek */
+ "\"\xCE\xBA\xE1\xBD\xB9\xCF\x83\xCE\xBC\xCE\xB5\"",
+ "\xCE\xBA\xE1\xBD\xB9\xCF\x83\xCE\xBC\xCE\xB5",
+ "\"\\u03BA\\u1F79\\u03C3\\u03BC\\u03B5\"",
+ },
+ /* 2 Boundary condition test cases */
+ /* 2.1 First possible sequence of a certain length */
+ /* 2.1.1 1 byte U+0000 */
+ {
+ "\"\\u0000\"",
+ "", /* bug: want overlong "\xC0\x80" */
+ "\"\\u0000\"",
+ "\xC0\x80",
+ },
+ /* 2.1.2 2 bytes U+0080 */
+ {
+ "\"\xC2\x80\"",
+ "\xC2\x80",
+ "\"\\u0080\"",
+ },
+ /* 2.1.3 3 bytes U+0800 */
+ {
+ "\"\xE0\xA0\x80\"",
+ "\xE0\xA0\x80",
+ "\"\\u0800\"",
+ },
+ /* 2.1.4 4 bytes U+10000 */
+ {
+ "\"\xF0\x90\x80\x80\"",
+ "\xF0\x90\x80\x80",
+ "\"\\uD800\\uDC00\"",
+ },
+ /* 2.1.5 5 bytes U+200000 */
+ {
+ "\"\xF8\x88\x80\x80\x80\"",
+ NULL, /* bug: rejected */
+ "\"\\uFFFD\"",
+ "\xF8\x88\x80\x80\x80",
+ },
+ /* 2.1.6 6 bytes U+4000000 */
+ {
+ "\"\xFC\x84\x80\x80\x80\x80\"",
+ NULL, /* bug: rejected */
+ "\"\\uFFFD\"",
+ "\xFC\x84\x80\x80\x80\x80",
+ },
+ /* 2.2 Last possible sequence of a certain length */
+ /* 2.2.1 1 byte U+007F */
+ {
+ "\"\x7F\"",
+ "\x7F",
+ "\"\\u007F\"",
+ },
+ /* 2.2.2 2 bytes U+07FF */
+ {
+ "\"\xDF\xBF\"",
+ "\xDF\xBF",
+ "\"\\u07FF\"",
+ },
+ /*
+ * 2.2.3 3 bytes U+FFFC
+ * The last possible sequence is actually U+FFFF. But that's
+ * a noncharacter, and already covered by its own test case
+ * under 5.3. Same for U+FFFE. U+FFFD is the last character
+ * in the BMP, and covered under 2.3. Because of U+FFFD's
+ * special role as replacement character, it's worth testing
+ * U+FFFC here.
+ */
+ {
+ "\"\xEF\xBF\xBC\"",
+ "\xEF\xBF\xBC",
+ "\"\\uFFFC\"",
+ },
+ /* 2.2.4 4 bytes U+1FFFFF */
+ {
+ "\"\xF7\xBF\xBF\xBF\"",
+ NULL, /* bug: rejected */
+ "\"\\uFFFD\"",
+ "\xF7\xBF\xBF\xBF",
+ },
+ /* 2.2.5 5 bytes U+3FFFFFF */
+ {
+ "\"\xFB\xBF\xBF\xBF\xBF\"",
+ NULL, /* bug: rejected */
+ "\"\\uFFFD\"",
+ "\xFB\xBF\xBF\xBF\xBF",
+ },
+ /* 2.2.6 6 bytes U+7FFFFFFF */
+ {
+ "\"\xFD\xBF\xBF\xBF\xBF\xBF\"",
+ NULL, /* bug: rejected */
+ "\"\\uFFFD\"",
+ "\xFD\xBF\xBF\xBF\xBF\xBF",
+ },
+ /* 2.3 Other boundary conditions */
+ {
+ /* last one before surrogate range: U+D7FF */
+ "\"\xED\x9F\xBF\"",
+ "\xED\x9F\xBF",
+ "\"\\uD7FF\"",
+ },
+ {
+ /* first one after surrogate range: U+E000 */
+ "\"\xEE\x80\x80\"",
+ "\xEE\x80\x80",
+ "\"\\uE000\"",
+ },
+ {
+ /* last one in BMP: U+FFFD */
+ "\"\xEF\xBF\xBD\"",
+ "\xEF\xBF\xBD",
+ "\"\\uFFFD\"",
+ },
+ {
+ /* last one in last plane: U+10FFFD */
+ "\"\xF4\x8F\xBF\xBD\"",
+ "\xF4\x8F\xBF\xBD",
+ "\"\\uDBFF\\uDFFD\""
+ },
+ {
+ /* first one beyond Unicode range: U+110000 */
+ "\"\xF4\x90\x80\x80\"",
+ "\xF4\x90\x80\x80",
+ "\"\\uFFFD\"",
+ },
+ /* 3 Malformed sequences */
+ /* 3.1 Unexpected continuation bytes */
+ /* 3.1.1 First continuation byte */
+ {
+ "\"\x80\"",
+ "\x80", /* bug: not corrected */
+ "\"\\uFFFD\"",
+ },
+ /* 3.1.2 Last continuation byte */
+ {
+ "\"\xBF\"",
+ "\xBF", /* bug: not corrected */
+ "\"\\uFFFD\"",
+ },
+ /* 3.1.3 2 continuation bytes */
+ {
+ "\"\x80\xBF\"",
+ "\x80\xBF", /* bug: not corrected */
+ "\"\\uFFFD\\uFFFD\"",
+ },
+ /* 3.1.4 3 continuation bytes */
+ {
+ "\"\x80\xBF\x80\"",
+ "\x80\xBF\x80", /* bug: not corrected */
+ "\"\\uFFFD\\uFFFD\\uFFFD\"",
+ },
+ /* 3.1.5 4 continuation bytes */
+ {
+ "\"\x80\xBF\x80\xBF\"",
+ "\x80\xBF\x80\xBF", /* bug: not corrected */
+ "\"\\uFFFD\\uFFFD\\uFFFD\\uFFFD\"",
+ },
+ /* 3.1.6 5 continuation bytes */
+ {
+ "\"\x80\xBF\x80\xBF\x80\"",
+ "\x80\xBF\x80\xBF\x80", /* bug: not corrected */
+ "\"\\uFFFD\\uFFFD\\uFFFD\\uFFFD\\uFFFD\"",
+ },
+ /* 3.1.7 6 continuation bytes */
+ {
+ "\"\x80\xBF\x80\xBF\x80\xBF\"",
+ "\x80\xBF\x80\xBF\x80\xBF", /* bug: not corrected */
+ "\"\\uFFFD\\uFFFD\\uFFFD\\uFFFD\\uFFFD\\uFFFD\"",
+ },
+ /* 3.1.8 7 continuation bytes */
+ {
+ "\"\x80\xBF\x80\xBF\x80\xBF\x80\"",
+ "\x80\xBF\x80\xBF\x80\xBF\x80", /* bug: not corrected */
+ "\"\\uFFFD\\uFFFD\\uFFFD\\uFFFD\\uFFFD\\uFFFD\\uFFFD\"",
+ },
+ /* 3.1.9 Sequence of all 64 possible continuation bytes */
+ {
+ "\"\x80\x81\x82\x83\x84\x85\x86\x87"
+ "\x88\x89\x8A\x8B\x8C\x8D\x8E\x8F"
+ "\x90\x91\x92\x93\x94\x95\x96\x97"
+ "\x98\x99\x9A\x9B\x9C\x9D\x9E\x9F"
+ "\xA0\xA1\xA2\xA3\xA4\xA5\xA6\xA7"
+ "\xA8\xA9\xAA\xAB\xAC\xAD\xAE\xAF"
+ "\xB0\xB1\xB2\xB3\xB4\xB5\xB6\xB7"
+ "\xB8\xB9\xBA\xBB\xBC\xBD\xBE\xBF\"",
+ /* bug: not corrected */
+ "\x80\x81\x82\x83\x84\x85\x86\x87"
+ "\x88\x89\x8A\x8B\x8C\x8D\x8E\x8F"
+ "\x90\x91\x92\x93\x94\x95\x96\x97"
+ "\x98\x99\x9A\x9B\x9C\x9D\x9E\x9F"
+ "\xA0\xA1\xA2\xA3\xA4\xA5\xA6\xA7"
+ "\xA8\xA9\xAA\xAB\xAC\xAD\xAE\xAF"
+ "\xB0\xB1\xB2\xB3\xB4\xB5\xB6\xB7"
+ "\xB8\xB9\xBA\xBB\xBC\xBD\xBE\xBF",
+ "\"\\uFFFD\\uFFFD\\uFFFD\\uFFFD\\uFFFD\\uFFFD\\uFFFD\\uFFFD"
+ "\\uFFFD\\uFFFD\\uFFFD\\uFFFD\\uFFFD\\uFFFD\\uFFFD\\uFFFD"
+ "\\uFFFD\\uFFFD\\uFFFD\\uFFFD\\uFFFD\\uFFFD\\uFFFD\\uFFFD"
+ "\\uFFFD\\uFFFD\\uFFFD\\uFFFD\\uFFFD\\uFFFD\\uFFFD\\uFFFD"
+ "\\uFFFD\\uFFFD\\uFFFD\\uFFFD\\uFFFD\\uFFFD\\uFFFD\\uFFFD"
+ "\\uFFFD\\uFFFD\\uFFFD\\uFFFD\\uFFFD\\uFFFD\\uFFFD\\uFFFD"
+ "\\uFFFD\\uFFFD\\uFFFD\\uFFFD\\uFFFD\\uFFFD\\uFFFD\\uFFFD"
+ "\\uFFFD\\uFFFD\\uFFFD\\uFFFD\\uFFFD\\uFFFD\\uFFFD\\uFFFD\""
+ },
+ /* 3.2 Lonely start characters */
+ /* 3.2.1 All 32 first bytes of 2-byte sequences, followed by space */
+ {
+ "\"\xC0 \xC1 \xC2 \xC3 \xC4 \xC5 \xC6 \xC7 "
+ "\xC8 \xC9 \xCA \xCB \xCC \xCD \xCE \xCF "
+ "\xD0 \xD1 \xD2 \xD3 \xD4 \xD5 \xD6 \xD7 "
+ "\xD8 \xD9 \xDA \xDB \xDC \xDD \xDE \xDF \"",
+ NULL, /* bug: rejected */
+ "\"\\uFFFD \\uFFFD \\uFFFD \\uFFFD \\uFFFD \\uFFFD \\uFFFD \\uFFFD "
+ "\\uFFFD \\uFFFD \\uFFFD \\uFFFD \\uFFFD \\uFFFD \\uFFFD \\uFFFD "
+ "\\uFFFD \\uFFFD \\uFFFD \\uFFFD \\uFFFD \\uFFFD \\uFFFD \\uFFFD "
+ "\\uFFFD \\uFFFD \\uFFFD \\uFFFD \\uFFFD \\uFFFD \\uFFFD \\uFFFD \"",
+ "\xC0 \xC1 \xC2 \xC3 \xC4 \xC5 \xC6 \xC7 "
+ "\xC8 \xC9 \xCA \xCB \xCC \xCD \xCE \xCF "
+ "\xD0 \xD1 \xD2 \xD3 \xD4 \xD5 \xD6 \xD7 "
+ "\xD8 \xD9 \xDA \xDB \xDC \xDD \xDE \xDF ",
+ },
+ /* 3.2.2 All 16 first bytes of 3-byte sequences, followed by space */
+ {
+ "\"\xE0 \xE1 \xE2 \xE3 \xE4 \xE5 \xE6 \xE7 "
+ "\xE8 \xE9 \xEA \xEB \xEC \xED \xEE \xEF \"",
+ /* bug: not corrected */
+ "\xE0 \xE1 \xE2 \xE3 \xE4 \xE5 \xE6 \xE7 "
+ "\xE8 \xE9 \xEA \xEB \xEC \xED \xEE \xEF ",
+ "\"\\uFFFD \\uFFFD \\uFFFD \\uFFFD \\uFFFD \\uFFFD \\uFFFD \\uFFFD "
+ "\\uFFFD \\uFFFD \\uFFFD \\uFFFD \\uFFFD \\uFFFD \\uFFFD \\uFFFD \"",
+ },
+ /* 3.2.3 All 8 first bytes of 4-byte sequences, followed by space */
+ {
+ "\"\xF0 \xF1 \xF2 \xF3 \xF4 \xF5 \xF6 \xF7 \"",
+ NULL, /* bug: rejected */
+ "\"\\uFFFD \\uFFFD \\uFFFD \\uFFFD \\uFFFD \\uFFFD \\uFFFD \\uFFFD \"",
+ "\xF0 \xF1 \xF2 \xF3 \xF4 \xF5 \xF6 \xF7 ",
+ },
+ /* 3.2.4 All 4 first bytes of 5-byte sequences, followed by space */
+ {
+ "\"\xF8 \xF9 \xFA \xFB \"",
+ NULL, /* bug: rejected */
+ "\"\\uFFFD \\uFFFD \\uFFFD \\uFFFD \"",
+ "\xF8 \xF9 \xFA \xFB ",
+ },
+ /* 3.2.5 All 2 first bytes of 6-byte sequences, followed by space */
+ {
+ "\"\xFC \xFD \"",
+ NULL, /* bug: rejected */
+ "\"\\uFFFD \\uFFFD \"",
+ "\xFC \xFD ",
+ },
+ /* 3.3 Sequences with last continuation byte missing */
+ /* 3.3.1 2-byte sequence with last byte missing (U+0000) */
+ {
+ "\"\xC0\"",
+ NULL, /* bug: rejected */
+ "\"\\uFFFD\"",
+ "\xC0",
+ },
+ /* 3.3.2 3-byte sequence with last byte missing (U+0000) */
+ {
+ "\"\xE0\x80\"",
+ "\xE0\x80", /* bug: not corrected */
+ "\"\\uFFFD\"",
+ },
+ /* 3.3.3 4-byte sequence with last byte missing (U+0000) */
+ {
+ "\"\xF0\x80\x80\"",
+ "\xF0\x80\x80", /* bug: not corrected */
+ "\"\\uFFFD\"",
+ },
+ /* 3.3.4 5-byte sequence with last byte missing (U+0000) */
+ {
+ "\"\xF8\x80\x80\x80\"",
+ NULL, /* bug: rejected */
+ "\"\\uFFFD\"",
+ "\xF8\x80\x80\x80",
+ },
+ /* 3.3.5 6-byte sequence with last byte missing (U+0000) */
+ {
+ "\"\xFC\x80\x80\x80\x80\"",
+ NULL, /* bug: rejected */
+ "\"\\uFFFD\"",
+ "\xFC\x80\x80\x80\x80",
+ },
+ /* 3.3.6 2-byte sequence with last byte missing (U+07FF) */
+ {
+ "\"\xDF\"",
+ "\xDF", /* bug: not corrected */
+ "\"\\uFFFD\"",
+ },
+ /* 3.3.7 3-byte sequence with last byte missing (U+FFFF) */
+ {
+ "\"\xEF\xBF\"",
+ "\xEF\xBF", /* bug: not corrected */
+ "\"\\uFFFD\"",
+ },
+ /* 3.3.8 4-byte sequence with last byte missing (U+1FFFFF) */
+ {
+ "\"\xF7\xBF\xBF\"",
+ NULL, /* bug: rejected */
+ "\"\\uFFFD\"",
+ "\xF7\xBF\xBF",
+ },
+ /* 3.3.9 5-byte sequence with last byte missing (U+3FFFFFF) */
+ {
+ "\"\xFB\xBF\xBF\xBF\"",
+ NULL, /* bug: rejected */
+ "\"\\uFFFD\"",
+ "\xFB\xBF\xBF\xBF",
+ },
+ /* 3.3.10 6-byte sequence with last byte missing (U+7FFFFFFF) */
+ {
+ "\"\xFD\xBF\xBF\xBF\xBF\"",
+ NULL, /* bug: rejected */
+ "\"\\uFFFD\"",
+ "\xFD\xBF\xBF\xBF\xBF",
+ },
+ /* 3.4 Concatenation of incomplete sequences */
+ {
+ "\"\xC0\xE0\x80\xF0\x80\x80\xF8\x80\x80\x80\xFC\x80\x80\x80\x80"
+ "\xDF\xEF\xBF\xF7\xBF\xBF\xFB\xBF\xBF\xBF\xFD\xBF\xBF\xBF\xBF\"",
+ NULL, /* bug: rejected */
+ "\"\\uFFFD\\uFFFD\\uFFFD\\uFFFD\\uFFFD"
+ "\\uFFFD\\uFFFD\\uFFFD\\uFFFD\\uFFFD\"",
+ "\xC0\xE0\x80\xF0\x80\x80\xF8\x80\x80\x80\xFC\x80\x80\x80\x80"
+ "\xDF\xEF\xBF\xF7\xBF\xBF\xFB\xBF\xBF\xBF\xFD\xBF\xBF\xBF\xBF",
+ },
+ /* 3.5 Impossible bytes */
+ {
+ "\"\xFE\"",
+ NULL, /* bug: rejected */
+ "\"\\uFFFD\"",
+ "\xFE",
+ },
+ {
+ "\"\xFF\"",
+ NULL, /* bug: rejected */
+ "\"\\uFFFD\"",
+ "\xFF",
+ },
+ {
+ "\"\xFE\xFE\xFF\xFF\"",
+ NULL, /* bug: rejected */
+ "\"\\uFFFD\\uFFFD\\uFFFD\\uFFFD\"",
+ "\xFE\xFE\xFF\xFF",
+ },
+ /* 4 Overlong sequences */
+ /* 4.1 Overlong '/' */
+ {
+ "\"\xC0\xAF\"",
+ NULL, /* bug: rejected */
+ "\"\\uFFFD\"",
+ "\xC0\xAF",
+ },
+ {
+ "\"\xE0\x80\xAF\"",
+ "\xE0\x80\xAF", /* bug: not corrected */
+ "\"\\uFFFD\"",
+ },
+ {
+ "\"\xF0\x80\x80\xAF\"",
+ "\xF0\x80\x80\xAF", /* bug: not corrected */
+ "\"\\uFFFD\"",
+ },
+ {
+ "\"\xF8\x80\x80\x80\xAF\"",
+ NULL, /* bug: rejected */
+ "\"\\uFFFD\"",
+ "\xF8\x80\x80\x80\xAF",
+ },
+ {
+ "\"\xFC\x80\x80\x80\x80\xAF\"",
+ NULL, /* bug: rejected */
+ "\"\\uFFFD\"",
+ "\xFC\x80\x80\x80\x80\xAF",
+ },
+ /*
+ * 4.2 Maximum overlong sequences
+ * Highest Unicode value that is still resulting in an
+ * overlong sequence if represented with the given number of
+ * bytes. This is a boundary test for safe UTF-8 decoders.
+ */
+ {
+ /* \U+007F */
+ "\"\xC1\xBF\"",
+ NULL, /* bug: rejected */
+ "\"\\uFFFD\"",
+ "\xC1\xBF",
+ },
+ {
+ /* \U+07FF */
+ "\"\xE0\x9F\xBF\"",
+ "\xE0\x9F\xBF", /* bug: not corrected */
+ "\"\\uFFFD\"",
+ },
+ {
+ /*
+ * \U+FFFC
+ * The actual maximum would be U+FFFF, but that's a
+ * noncharacter. Testing U+FFFC seems more useful. See
+ * also 2.2.3
+ */
+ "\"\xF0\x8F\xBF\xBC\"",
+ "\xF0\x8F\xBF\xBC", /* bug: not corrected */
+ "\"\\uFFFD\"",
+ },
+ {
+ /* \U+1FFFFF */
+ "\"\xF8\x87\xBF\xBF\xBF\"",
+ NULL, /* bug: rejected */
+ "\"\\uFFFD\"",
+ "\xF8\x87\xBF\xBF\xBF",
+ },
+ {
+ /* \U+3FFFFFF */
+ "\"\xFC\x83\xBF\xBF\xBF\xBF\"",
+ NULL, /* bug: rejected */
+ "\"\\uFFFD\"",
+ "\xFC\x83\xBF\xBF\xBF\xBF",
+ },
+ /* 4.3 Overlong representation of the NUL character */
+ {
+ /* \U+0000 */
+ "\"\xC0\x80\"",
+ NULL, /* bug: rejected */
+ "\"\\u0000\"",
+ "\xC0\x80",
+ },
+ {
+ /* \U+0000 */
+ "\"\xE0\x80\x80\"",
+ "\xE0\x80\x80", /* bug: not corrected */
+ "\"\\uFFFD\"",
+ },
+ {
+ /* \U+0000 */
+ "\"\xF0\x80\x80\x80\"",
+ "\xF0\x80\x80\x80", /* bug: not corrected */
+ "\"\\uFFFD\"",
+ },
+ {
+ /* \U+0000 */
+ "\"\xF8\x80\x80\x80\x80\"",
+ NULL, /* bug: rejected */
+ "\"\\uFFFD\"",
+ "\xF8\x80\x80\x80\x80",
+ },
+ {
+ /* \U+0000 */
+ "\"\xFC\x80\x80\x80\x80\x80\"",
+ NULL, /* bug: rejected */
+ "\"\\uFFFD\"",
+ "\xFC\x80\x80\x80\x80\x80",
+ },
+ /* 5 Illegal code positions */
+ /* 5.1 Single UTF-16 surrogates */
+ {
+ /* \U+D800 */
+ "\"\xED\xA0\x80\"",
+ "\xED\xA0\x80", /* bug: not corrected */
+ "\"\\uFFFD\"",
+ },
+ {
+ /* \U+DB7F */
+ "\"\xED\xAD\xBF\"",
+ "\xED\xAD\xBF", /* bug: not corrected */
+ "\"\\uFFFD\"",
+ },
+ {
+ /* \U+DB80 */
+ "\"\xED\xAE\x80\"",
+ "\xED\xAE\x80", /* bug: not corrected */
+ "\"\\uFFFD\"",
+ },
+ {
+ /* \U+DBFF */
+ "\"\xED\xAF\xBF\"",
+ "\xED\xAF\xBF", /* bug: not corrected */
+ "\"\\uFFFD\"",
+ },
+ {
+ /* \U+DC00 */
+ "\"\xED\xB0\x80\"",
+ "\xED\xB0\x80", /* bug: not corrected */
+ "\"\\uFFFD\"",
+ },
+ {
+ /* \U+DF80 */
+ "\"\xED\xBE\x80\"",
+ "\xED\xBE\x80", /* bug: not corrected */
+ "\"\\uFFFD\"",
+ },
+ {
+ /* \U+DFFF */
+ "\"\xED\xBF\xBF\"",
+ "\xED\xBF\xBF", /* bug: not corrected */
+ "\"\\uFFFD\"",
+ },
+ /* 5.2 Paired UTF-16 surrogates */
+ {
+ /* \U+D800\U+DC00 */
+ "\"\xED\xA0\x80\xED\xB0\x80\"",
+ "\xED\xA0\x80\xED\xB0\x80", /* bug: not corrected */
+ "\"\\uFFFD\\uFFFD\"",
+ },
+ {
+ /* \U+D800\U+DFFF */
+ "\"\xED\xA0\x80\xED\xBF\xBF\"",
+ "\xED\xA0\x80\xED\xBF\xBF", /* bug: not corrected */
+ "\"\\uFFFD\\uFFFD\"",
+ },
+ {
+ /* \U+DB7F\U+DC00 */
+ "\"\xED\xAD\xBF\xED\xB0\x80\"",
+ "\xED\xAD\xBF\xED\xB0\x80", /* bug: not corrected */
+ "\"\\uFFFD\\uFFFD\"",
+ },
+ {
+ /* \U+DB7F\U+DFFF */
+ "\"\xED\xAD\xBF\xED\xBF\xBF\"",
+ "\xED\xAD\xBF\xED\xBF\xBF", /* bug: not corrected */
+ "\"\\uFFFD\\uFFFD\"",
+ },
+ {
+ /* \U+DB80\U+DC00 */
+ "\"\xED\xAE\x80\xED\xB0\x80\"",
+ "\xED\xAE\x80\xED\xB0\x80", /* bug: not corrected */
+ "\"\\uFFFD\\uFFFD\"",
+ },
+ {
+ /* \U+DB80\U+DFFF */
+ "\"\xED\xAE\x80\xED\xBF\xBF\"",
+ "\xED\xAE\x80\xED\xBF\xBF", /* bug: not corrected */
+ "\"\\uFFFD\\uFFFD\"",
+ },
+ {
+ /* \U+DBFF\U+DC00 */
+ "\"\xED\xAF\xBF\xED\xB0\x80\"",
+ "\xED\xAF\xBF\xED\xB0\x80", /* bug: not corrected */
+ "\"\\uFFFD\\uFFFD\"",
+ },
+ {
+ /* \U+DBFF\U+DFFF */
+ "\"\xED\xAF\xBF\xED\xBF\xBF\"",
+ "\xED\xAF\xBF\xED\xBF\xBF", /* bug: not corrected */
+ "\"\\uFFFD\\uFFFD\"",
+ },
+ /* 5.3 Other illegal code positions */
+ /* BMP noncharacters */
+ {
+ /* \U+FFFE */
+ "\"\xEF\xBF\xBE\"",
+ "\xEF\xBF\xBE", /* bug: not corrected */
+ "\"\\uFFFD\"",
+ },
+ {
+ /* \U+FFFF */
+ "\"\xEF\xBF\xBF\"",
+ "\xEF\xBF\xBF", /* bug: not corrected */
+ "\"\\uFFFD\"",
+ },
+ {
+ /* U+FDD0 */
+ "\"\xEF\xB7\x90\"",
+ "\xEF\xB7\x90", /* bug: not corrected */
+ "\"\\uFFFD\"",
+ },
+ {
+ /* U+FDEF */
+ "\"\xEF\xB7\xAF\"",
+ "\xEF\xB7\xAF", /* bug: not corrected */
+ "\"\\uFFFD\"",
+ },
+ /* Plane 1 .. 16 noncharacters */
+ {
+ /* U+1FFFE U+1FFFF U+2FFFE U+2FFFF ... U+10FFFE U+10FFFF */
+ "\"\xF0\x9F\xBF\xBE\xF0\x9F\xBF\xBF"
+ "\xF0\xAF\xBF\xBE\xF0\xAF\xBF\xBF"
+ "\xF0\xBF\xBF\xBE\xF0\xBF\xBF\xBF"
+ "\xF1\x8F\xBF\xBE\xF1\x8F\xBF\xBF"
+ "\xF1\x9F\xBF\xBE\xF1\x9F\xBF\xBF"
+ "\xF1\xAF\xBF\xBE\xF1\xAF\xBF\xBF"
+ "\xF1\xBF\xBF\xBE\xF1\xBF\xBF\xBF"
+ "\xF2\x8F\xBF\xBE\xF2\x8F\xBF\xBF"
+ "\xF2\x9F\xBF\xBE\xF2\x9F\xBF\xBF"
+ "\xF2\xAF\xBF\xBE\xF2\xAF\xBF\xBF"
+ "\xF2\xBF\xBF\xBE\xF2\xBF\xBF\xBF"
+ "\xF3\x8F\xBF\xBE\xF3\x8F\xBF\xBF"
+ "\xF3\x9F\xBF\xBE\xF3\x9F\xBF\xBF"
+ "\xF3\xAF\xBF\xBE\xF3\xAF\xBF\xBF"
+ "\xF3\xBF\xBF\xBE\xF3\xBF\xBF\xBF"
+ "\xF4\x8F\xBF\xBE\xF4\x8F\xBF\xBF\"",
+ /* bug: not corrected */
+ "\xF0\x9F\xBF\xBE\xF0\x9F\xBF\xBF"
+ "\xF0\xAF\xBF\xBE\xF0\xAF\xBF\xBF"
+ "\xF0\xBF\xBF\xBE\xF0\xBF\xBF\xBF"
+ "\xF1\x8F\xBF\xBE\xF1\x8F\xBF\xBF"
+ "\xF1\x9F\xBF\xBE\xF1\x9F\xBF\xBF"
+ "\xF1\xAF\xBF\xBE\xF1\xAF\xBF\xBF"
+ "\xF1\xBF\xBF\xBE\xF1\xBF\xBF\xBF"
+ "\xF2\x8F\xBF\xBE\xF2\x8F\xBF\xBF"
+ "\xF2\x9F\xBF\xBE\xF2\x9F\xBF\xBF"
+ "\xF2\xAF\xBF\xBE\xF2\xAF\xBF\xBF"
+ "\xF2\xBF\xBF\xBE\xF2\xBF\xBF\xBF"
+ "\xF3\x8F\xBF\xBE\xF3\x8F\xBF\xBF"
+ "\xF3\x9F\xBF\xBE\xF3\x9F\xBF\xBF"
+ "\xF3\xAF\xBF\xBE\xF3\xAF\xBF\xBF"
+ "\xF3\xBF\xBF\xBE\xF3\xBF\xBF\xBF"
+ "\xF4\x8F\xBF\xBE\xF4\x8F\xBF\xBF",
+ "\"\\uFFFD\\uFFFD\\uFFFD\\uFFFD\\uFFFD\\uFFFD\\uFFFD\\uFFFD"
+ "\\uFFFD\\uFFFD\\uFFFD\\uFFFD\\uFFFD\\uFFFD\\uFFFD\\uFFFD"
+ "\\uFFFD\\uFFFD\\uFFFD\\uFFFD\\uFFFD\\uFFFD\\uFFFD\\uFFFD"
+ "\\uFFFD\\uFFFD\\uFFFD\\uFFFD\\uFFFD\\uFFFD\\uFFFD\\uFFFD\"",
+ },
+ {}
+ };
+ int i;
+ QObject *obj;
+ QString *str;
+ const char *json_in, *utf8_out, *utf8_in, *json_out;
+
+ for (i = 0; test_cases[i].json_in; i++) {
+ json_in = test_cases[i].json_in;
+ utf8_out = test_cases[i].utf8_out;
+ utf8_in = test_cases[i].utf8_in ?: test_cases[i].utf8_out;
+ json_out = test_cases[i].json_out ?: test_cases[i].json_in;
+
+ obj = qobject_from_json(json_in);
+ if (utf8_out) {
+ g_assert(obj);
+ g_assert(qobject_type(obj) == QTYPE_QSTRING);
+ str = qobject_to_qstring(obj);
+ g_assert_cmpstr(qstring_get_str(str), ==, utf8_out);
+ } else {
+ g_assert(!obj);
+ }
+ qobject_decref(obj);
+
+ obj = QOBJECT(qstring_from_str(utf8_in));
+ str = qobject_to_json(obj);
+ if (json_out) {
+ g_assert(str);
+ g_assert_cmpstr(qstring_get_str(str), ==, json_out);
+ } else {
+ g_assert(!str);
+ }
+ QDECREF(str);
+ qobject_decref(obj);
+
+ /*
+ * Disabled, because qobject_from_json() is buggy, and I can't
+ * be bothered to add the expected incorrect results.
+ * FIXME Enable once these bugs have been fixed.
+ */
+ if (0 && json_out != json_in) {
+ obj = qobject_from_json(json_out);
+ g_assert(obj);
+ g_assert(qobject_type(obj) == QTYPE_QSTRING);
+ str = qobject_to_qstring(obj);
+ g_assert_cmpstr(qstring_get_str(str), ==, utf8_out);
+ }
+ }
+}
+
static void vararg_string(void)
{
int i;
@@ -748,6 +1471,7 @@ int main(int argc, char **argv)
g_test_add_func("/literals/string/simple", simple_string);
g_test_add_func("/literals/string/escaped", escaped_string);
+ g_test_add_func("/literals/string/utf8", utf8_string);
g_test_add_func("/literals/string/single_quote", single_quote_string);
g_test_add_func("/literals/string/vararg", vararg_string);
diff --git a/tests/check-qlist.c b/tests/check-qlist.c
index 501ba262d..b9c05d43f 100644
--- a/tests/check-qlist.c
+++ b/tests/check-qlist.c
@@ -11,8 +11,8 @@
*/
#include <glib.h>
-#include "qint.h"
-#include "qlist.h"
+#include "qapi/qmp/qint.h"
+#include "qapi/qmp/qlist.h"
/*
* Public Interface test-cases
diff --git a/tests/check-qstring.c b/tests/check-qstring.c
index addad6c67..95dc9e3e7 100644
--- a/tests/check-qstring.c
+++ b/tests/check-qstring.c
@@ -11,7 +11,7 @@
*/
#include <glib.h>
-#include "qstring.h"
+#include "qapi/qmp/qstring.h"
#include "qemu-common.h"
/*
diff --git a/tests/endianness-test.c b/tests/endianness-test.c
new file mode 100644
index 000000000..feb32a850
--- /dev/null
+++ b/tests/endianness-test.c
@@ -0,0 +1,316 @@
+/*
+ * QTest testcase for ISA endianness
+ *
+ * Copyright Red Hat, Inc. 2012
+ *
+ * Authors:
+ * Paolo Bonzini <pbonzini@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 "libqtest.h"
+
+#include <glib.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include "qemu/bswap.h"
+
+typedef struct TestCase TestCase;
+struct TestCase {
+ const char *arch;
+ const char *machine;
+ uint64_t isa_base;
+ bool bswap;
+ const char *superio;
+};
+
+static const TestCase test_cases[] = {
+ { "i386", "pc", -1 },
+ { "mips", "magnum", 0x90000000, .bswap = true },
+ { "mips", "pica61", 0x90000000, .bswap = true },
+ { "mips", "mips", 0x14000000, .bswap = true },
+ { "mips", "malta", 0x10000000, .bswap = true },
+ { "mips64", "magnum", 0x90000000, .bswap = true },
+ { "mips64", "pica61", 0x90000000, .bswap = true },
+ { "mips64", "mips", 0x14000000, .bswap = true },
+ { "mips64", "malta", 0x10000000, .bswap = true },
+ { "mips64el", "fulong2e", 0x1fd00000 },
+ { "ppc", "g3beige", 0xfe000000, .bswap = true, .superio = "i82378" },
+ { "ppc", "prep", 0x80000000, .bswap = true },
+ { "ppc", "bamboo", 0xe8000000, .bswap = true, .superio = "i82378" },
+ { "ppc64", "mac99", 0xf2000000, .bswap = true, .superio = "i82378" },
+ { "ppc64", "pseries", 0x10080000000, .bswap = true, .superio = "i82378" },
+ { "sh4", "r2d", 0xfe240000, .superio = "i82378" },
+ { "sh4eb", "r2d", 0xfe240000, .bswap = true, .superio = "i82378" },
+ { "sparc64", "sun4u", 0x1fe02000000LL, .bswap = true },
+ { "x86_64", "pc", -1 },
+ {}
+};
+
+static uint8_t isa_inb(const TestCase *test, uint16_t addr)
+{
+ uint8_t value;
+ if (test->isa_base == -1) {
+ value = inb(addr);
+ } else {
+ value = readb(test->isa_base + addr);
+ }
+ return value;
+}
+
+static uint16_t isa_inw(const TestCase *test, uint16_t addr)
+{
+ uint16_t value;
+ if (test->isa_base == -1) {
+ value = inw(addr);
+ } else {
+ value = readw(test->isa_base + addr);
+ }
+ return test->bswap ? bswap16(value) : value;
+}
+
+static uint32_t isa_inl(const TestCase *test, uint16_t addr)
+{
+ uint32_t value;
+ if (test->isa_base == -1) {
+ value = inl(addr);
+ } else {
+ value = readl(test->isa_base + addr);
+ }
+ return test->bswap ? bswap32(value) : value;
+}
+
+static void isa_outb(const TestCase *test, uint16_t addr, uint8_t value)
+{
+ if (test->isa_base == -1) {
+ outb(addr, value);
+ } else {
+ writeb(test->isa_base + addr, value);
+ }
+}
+
+static void isa_outw(const TestCase *test, uint16_t addr, uint16_t value)
+{
+ value = test->bswap ? bswap16(value) : value;
+ if (test->isa_base == -1) {
+ outw(addr, value);
+ } else {
+ writew(test->isa_base + addr, value);
+ }
+}
+
+static void isa_outl(const TestCase *test, uint16_t addr, uint32_t value)
+{
+ value = test->bswap ? bswap32(value) : value;
+ if (test->isa_base == -1) {
+ outl(addr, value);
+ } else {
+ writel(test->isa_base + addr, value);
+ }
+}
+
+
+static void test_endianness(gconstpointer data)
+{
+ const TestCase *test = data;
+ char *args;
+
+ args = g_strdup_printf("-display none -M %s%s%s -device pc-testdev",
+ test->machine,
+ test->superio ? " -device " : "",
+ test->superio ?: "");
+ qtest_start(args);
+ isa_outl(test, 0xe0, 0x87654321);
+ g_assert_cmphex(isa_inl(test, 0xe0), ==, 0x87654321);
+ g_assert_cmphex(isa_inw(test, 0xe2), ==, 0x8765);
+ g_assert_cmphex(isa_inw(test, 0xe0), ==, 0x4321);
+ g_assert_cmphex(isa_inb(test, 0xe3), ==, 0x87);
+ g_assert_cmphex(isa_inb(test, 0xe2), ==, 0x65);
+ g_assert_cmphex(isa_inb(test, 0xe1), ==, 0x43);
+ g_assert_cmphex(isa_inb(test, 0xe0), ==, 0x21);
+
+ isa_outw(test, 0xe2, 0x8866);
+ g_assert_cmphex(isa_inl(test, 0xe0), ==, 0x88664321);
+ g_assert_cmphex(isa_inw(test, 0xe2), ==, 0x8866);
+ g_assert_cmphex(isa_inw(test, 0xe0), ==, 0x4321);
+ g_assert_cmphex(isa_inb(test, 0xe3), ==, 0x88);
+ g_assert_cmphex(isa_inb(test, 0xe2), ==, 0x66);
+ g_assert_cmphex(isa_inb(test, 0xe1), ==, 0x43);
+ g_assert_cmphex(isa_inb(test, 0xe0), ==, 0x21);
+
+ isa_outw(test, 0xe0, 0x4422);
+ g_assert_cmphex(isa_inl(test, 0xe0), ==, 0x88664422);
+ g_assert_cmphex(isa_inw(test, 0xe2), ==, 0x8866);
+ g_assert_cmphex(isa_inw(test, 0xe0), ==, 0x4422);
+ g_assert_cmphex(isa_inb(test, 0xe3), ==, 0x88);
+ g_assert_cmphex(isa_inb(test, 0xe2), ==, 0x66);
+ g_assert_cmphex(isa_inb(test, 0xe1), ==, 0x44);
+ g_assert_cmphex(isa_inb(test, 0xe0), ==, 0x22);
+
+ isa_outb(test, 0xe3, 0x87);
+ g_assert_cmphex(isa_inl(test, 0xe0), ==, 0x87664422);
+ g_assert_cmphex(isa_inw(test, 0xe2), ==, 0x8766);
+ g_assert_cmphex(isa_inb(test, 0xe3), ==, 0x87);
+ g_assert_cmphex(isa_inb(test, 0xe2), ==, 0x66);
+ g_assert_cmphex(isa_inb(test, 0xe1), ==, 0x44);
+ g_assert_cmphex(isa_inb(test, 0xe0), ==, 0x22);
+
+ isa_outb(test, 0xe2, 0x65);
+ g_assert_cmphex(isa_inl(test, 0xe0), ==, 0x87654422);
+ g_assert_cmphex(isa_inw(test, 0xe2), ==, 0x8765);
+ g_assert_cmphex(isa_inw(test, 0xe0), ==, 0x4422);
+ g_assert_cmphex(isa_inb(test, 0xe3), ==, 0x87);
+ g_assert_cmphex(isa_inb(test, 0xe2), ==, 0x65);
+ g_assert_cmphex(isa_inb(test, 0xe1), ==, 0x44);
+ g_assert_cmphex(isa_inb(test, 0xe0), ==, 0x22);
+
+ isa_outb(test, 0xe1, 0x43);
+ g_assert_cmphex(isa_inl(test, 0xe0), ==, 0x87654322);
+ g_assert_cmphex(isa_inw(test, 0xe2), ==, 0x8765);
+ g_assert_cmphex(isa_inw(test, 0xe0), ==, 0x4322);
+ g_assert_cmphex(isa_inb(test, 0xe3), ==, 0x87);
+ g_assert_cmphex(isa_inb(test, 0xe2), ==, 0x65);
+ g_assert_cmphex(isa_inb(test, 0xe1), ==, 0x43);
+ g_assert_cmphex(isa_inb(test, 0xe0), ==, 0x22);
+
+ isa_outb(test, 0xe0, 0x21);
+ g_assert_cmphex(isa_inl(test, 0xe0), ==, 0x87654321);
+ g_assert_cmphex(isa_inw(test, 0xe2), ==, 0x8765);
+ g_assert_cmphex(isa_inw(test, 0xe0), ==, 0x4321);
+ g_assert_cmphex(isa_inb(test, 0xe3), ==, 0x87);
+ g_assert_cmphex(isa_inb(test, 0xe2), ==, 0x65);
+ g_assert_cmphex(isa_inb(test, 0xe1), ==, 0x43);
+ g_assert_cmphex(isa_inb(test, 0xe0), ==, 0x21);
+ qtest_quit(global_qtest);
+ g_free(args);
+}
+
+static void test_endianness_split(gconstpointer data)
+{
+ const TestCase *test = data;
+ char *args;
+
+ args = g_strdup_printf("-display none -M %s%s%s -device pc-testdev",
+ test->machine,
+ test->superio ? " -device " : "",
+ test->superio ?: "");
+ qtest_start(args);
+ isa_outl(test, 0xe8, 0x87654321);
+ g_assert_cmphex(isa_inl(test, 0xe0), ==, 0x87654321);
+ g_assert_cmphex(isa_inw(test, 0xe2), ==, 0x8765);
+ g_assert_cmphex(isa_inw(test, 0xe0), ==, 0x4321);
+
+ isa_outw(test, 0xea, 0x8866);
+ g_assert_cmphex(isa_inl(test, 0xe0), ==, 0x88664321);
+ g_assert_cmphex(isa_inw(test, 0xe2), ==, 0x8866);
+ g_assert_cmphex(isa_inw(test, 0xe0), ==, 0x4321);
+
+ isa_outw(test, 0xe8, 0x4422);
+ g_assert_cmphex(isa_inl(test, 0xe0), ==, 0x88664422);
+ g_assert_cmphex(isa_inw(test, 0xe2), ==, 0x8866);
+ g_assert_cmphex(isa_inw(test, 0xe0), ==, 0x4422);
+
+ isa_outb(test, 0xeb, 0x87);
+ g_assert_cmphex(isa_inl(test, 0xe0), ==, 0x87664422);
+ g_assert_cmphex(isa_inw(test, 0xe2), ==, 0x8766);
+
+ isa_outb(test, 0xea, 0x65);
+ g_assert_cmphex(isa_inl(test, 0xe0), ==, 0x87654422);
+ g_assert_cmphex(isa_inw(test, 0xe2), ==, 0x8765);
+ g_assert_cmphex(isa_inw(test, 0xe0), ==, 0x4422);
+
+ isa_outb(test, 0xe9, 0x43);
+ g_assert_cmphex(isa_inl(test, 0xe0), ==, 0x87654322);
+ g_assert_cmphex(isa_inw(test, 0xe2), ==, 0x8765);
+ g_assert_cmphex(isa_inw(test, 0xe0), ==, 0x4322);
+
+ isa_outb(test, 0xe8, 0x21);
+ g_assert_cmphex(isa_inl(test, 0xe0), ==, 0x87654321);
+ g_assert_cmphex(isa_inw(test, 0xe2), ==, 0x8765);
+ g_assert_cmphex(isa_inw(test, 0xe0), ==, 0x4321);
+ qtest_quit(global_qtest);
+ g_free(args);
+}
+
+static void test_endianness_combine(gconstpointer data)
+{
+ const TestCase *test = data;
+ char *args;
+
+ args = g_strdup_printf("-display none -M %s%s%s -device pc-testdev",
+ test->machine,
+ test->superio ? " -device " : "",
+ test->superio ?: "");
+ qtest_start(args);
+ isa_outl(test, 0xe0, 0x87654321);
+ g_assert_cmphex(isa_inl(test, 0xe8), ==, 0x87654321);
+ g_assert_cmphex(isa_inw(test, 0xea), ==, 0x8765);
+ g_assert_cmphex(isa_inw(test, 0xe8), ==, 0x4321);
+
+ isa_outw(test, 0xe2, 0x8866);
+ g_assert_cmphex(isa_inl(test, 0xe8), ==, 0x88664321);
+ g_assert_cmphex(isa_inw(test, 0xea), ==, 0x8866);
+ g_assert_cmphex(isa_inw(test, 0xe8), ==, 0x4321);
+
+ isa_outw(test, 0xe0, 0x4422);
+ g_assert_cmphex(isa_inl(test, 0xe8), ==, 0x88664422);
+ g_assert_cmphex(isa_inw(test, 0xea), ==, 0x8866);
+ g_assert_cmphex(isa_inw(test, 0xe8), ==, 0x4422);
+
+ isa_outb(test, 0xe3, 0x87);
+ g_assert_cmphex(isa_inl(test, 0xe8), ==, 0x87664422);
+ g_assert_cmphex(isa_inw(test, 0xea), ==, 0x8766);
+
+ isa_outb(test, 0xe2, 0x65);
+ g_assert_cmphex(isa_inl(test, 0xe8), ==, 0x87654422);
+ g_assert_cmphex(isa_inw(test, 0xea), ==, 0x8765);
+ g_assert_cmphex(isa_inw(test, 0xe8), ==, 0x4422);
+
+ isa_outb(test, 0xe1, 0x43);
+ g_assert_cmphex(isa_inl(test, 0xe8), ==, 0x87654322);
+ g_assert_cmphex(isa_inw(test, 0xea), ==, 0x8765);
+ g_assert_cmphex(isa_inw(test, 0xe8), ==, 0x4322);
+
+ isa_outb(test, 0xe0, 0x21);
+ g_assert_cmphex(isa_inl(test, 0xe8), ==, 0x87654321);
+ g_assert_cmphex(isa_inw(test, 0xea), ==, 0x8765);
+ g_assert_cmphex(isa_inw(test, 0xe8), ==, 0x4321);
+ qtest_quit(global_qtest);
+ g_free(args);
+}
+
+int main(int argc, char **argv)
+{
+ const char *arch = qtest_get_arch();
+ int ret;
+ int i;
+
+ g_test_init(&argc, &argv, NULL);
+
+ for (i = 0; test_cases[i].arch; i++) {
+ gchar *path;
+ if (strcmp(test_cases[i].arch, arch) != 0) {
+ continue;
+ }
+ path = g_strdup_printf("/%s/endianness/%s",
+ arch, test_cases[i].machine);
+ g_test_add_data_func(path, &test_cases[i], test_endianness);
+
+ path = g_strdup_printf("/%s/endianness/split/%s",
+ arch, test_cases[i].machine);
+ g_test_add_data_func(path, &test_cases[i], test_endianness_split);
+
+ path = g_strdup_printf("/%s/endianness/combine/%s",
+ arch, test_cases[i].machine);
+ g_test_add_data_func(path, &test_cases[i], test_endianness_combine);
+ }
+
+ ret = g_test_run();
+
+ return ret;
+}
diff --git a/tests/fdc-test.c b/tests/fdc-test.c
index 4b0301da4..fd198dcf8 100644
--- a/tests/fdc-test.c
+++ b/tests/fdc-test.c
@@ -556,7 +556,7 @@ int main(int argc, char **argv)
ret = g_test_run();
/* Cleanup */
- qtest_quit(global_qtest);
+ qtest_end();
unlink(test_image);
return ret;
diff --git a/tests/fw_cfg-test.c b/tests/fw_cfg-test.c
new file mode 100644
index 000000000..b86e49ab0
--- /dev/null
+++ b/tests/fw_cfg-test.c
@@ -0,0 +1,141 @@
+/*
+ * qtest fw_cfg test case
+ *
+ * Copyright IBM, Corp. 2012-2013
+ *
+ * Authors:
+ * Anthony Liguori <aliguori@us.ibm.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.
+ */
+
+#define NO_QEMU_PROTOS
+
+#include "libqtest.h"
+#include "hw/nvram/fw_cfg.h"
+#include "libqos/fw_cfg.h"
+
+#include <string.h>
+#include <glib.h>
+
+static uint64_t ram_size = 128 << 20;
+static uint16_t nb_cpus = 1;
+static uint16_t max_cpus = 1;
+static uint64_t nb_nodes = 0;
+static uint16_t boot_menu = 0;
+static QFWCFG *fw_cfg = NULL;
+
+static void test_fw_cfg_signature(void)
+{
+ char buf[5];
+
+ qfw_cfg_get(fw_cfg, FW_CFG_SIGNATURE, buf, 4);
+ buf[4] = 0;
+
+ g_assert_cmpstr(buf, ==, "QEMU");
+}
+
+static void test_fw_cfg_id(void)
+{
+ g_assert_cmpint(qfw_cfg_get_u32(fw_cfg, FW_CFG_ID), ==, 1);
+}
+
+static void test_fw_cfg_uuid(void)
+{
+ uint8_t buf[16];
+ static const uint8_t uuid[16] = {
+ 0x46, 0x00, 0xcb, 0x32, 0x38, 0xec, 0x4b, 0x2f,
+ 0x8a, 0xcb, 0x81, 0xc6, 0xea, 0x54, 0xf2, 0xd8,
+ };
+
+ qfw_cfg_get(fw_cfg, FW_CFG_UUID, buf, 16);
+ g_assert(memcmp(buf, uuid, sizeof(buf)) == 0);
+}
+
+static void test_fw_cfg_ram_size(void)
+{
+ g_assert_cmpint(qfw_cfg_get_u64(fw_cfg, FW_CFG_RAM_SIZE), ==, ram_size);
+}
+
+static void test_fw_cfg_nographic(void)
+{
+ g_assert_cmpint(qfw_cfg_get_u16(fw_cfg, FW_CFG_NOGRAPHIC), ==, 0);
+}
+
+static void test_fw_cfg_nb_cpus(void)
+{
+ g_assert_cmpint(qfw_cfg_get_u16(fw_cfg, FW_CFG_NB_CPUS), ==, nb_cpus);
+}
+
+static void test_fw_cfg_max_cpus(void)
+{
+ g_assert_cmpint(qfw_cfg_get_u16(fw_cfg, FW_CFG_MAX_CPUS), ==, max_cpus);
+}
+
+static void test_fw_cfg_numa(void)
+{
+ uint64_t *cpu_mask;
+ uint64_t *node_mask;
+
+ g_assert_cmpint(qfw_cfg_get_u64(fw_cfg, FW_CFG_NUMA), ==, nb_nodes);
+
+ cpu_mask = g_malloc0(sizeof(uint64_t) * max_cpus);
+ node_mask = g_malloc0(sizeof(uint64_t) * nb_nodes);
+
+ qfw_cfg_read_data(fw_cfg, cpu_mask, sizeof(uint64_t) * max_cpus);
+ qfw_cfg_read_data(fw_cfg, node_mask, sizeof(uint64_t) * nb_nodes);
+
+ if (nb_nodes) {
+ g_assert(cpu_mask[0] & 0x01);
+ g_assert_cmpint(node_mask[0], ==, ram_size);
+ }
+
+ g_free(node_mask);
+ g_free(cpu_mask);
+}
+
+static void test_fw_cfg_boot_menu(void)
+{
+ g_assert_cmpint(qfw_cfg_get_u16(fw_cfg, FW_CFG_BOOT_MENU), ==, boot_menu);
+}
+
+int main(int argc, char **argv)
+{
+ QTestState *s;
+ char *cmdline;
+ int ret;
+
+ g_test_init(&argc, &argv, NULL);
+
+ fw_cfg = pc_fw_cfg_init();
+
+ g_test_add_func("/fw_cfg/signature", test_fw_cfg_signature);
+ g_test_add_func("/fw_cfg/id", test_fw_cfg_id);
+ g_test_add_func("/fw_cfg/uuid", test_fw_cfg_uuid);
+ g_test_add_func("/fw_cfg/ram_size", test_fw_cfg_ram_size);
+ g_test_add_func("/fw_cfg/nographic", test_fw_cfg_nographic);
+ g_test_add_func("/fw_cfg/nb_cpus", test_fw_cfg_nb_cpus);
+#if 0
+ g_test_add_func("/fw_cfg/machine_id", test_fw_cfg_machine_id);
+ g_test_add_func("/fw_cfg/kernel", test_fw_cfg_kernel);
+ g_test_add_func("/fw_cfg/initrd", test_fw_cfg_initrd);
+ g_test_add_func("/fw_cfg/boot_device", test_fw_cfg_boot_device);
+#endif
+ g_test_add_func("/fw_cfg/max_cpus", test_fw_cfg_max_cpus);
+ g_test_add_func("/fw_cfg/numa", test_fw_cfg_numa);
+ g_test_add_func("/fw_cfg/boot_menu", test_fw_cfg_boot_menu);
+
+ cmdline = g_strdup_printf("-display none "
+ "-uuid 4600cb32-38ec-4b2f-8acb-81c6ea54f2d8 ");
+ s = qtest_start(cmdline);
+ g_free(cmdline);
+
+ ret = g_test_run();
+
+ if (s) {
+ qtest_quit(s);
+ }
+
+ return ret;
+}
diff --git a/tests/hd-geo-test.c b/tests/hd-geo-test.c
index 9a31e8587..b72042e59 100644
--- a/tests/hd-geo-test.c
+++ b/tests/hd-geo-test.c
@@ -244,7 +244,7 @@ static void test_ide_none(void)
setup_common(argv, ARRAY_SIZE(argv));
qtest_start(g_strjoinv(" ", argv));
test_cmos();
- qtest_quit(global_qtest);
+ qtest_end();
}
static void test_ide_mbr(bool use_device, MBRcontents mbr)
@@ -262,7 +262,7 @@ static void test_ide_mbr(bool use_device, MBRcontents mbr)
}
qtest_start(g_strjoinv(" ", argv));
test_cmos();
- qtest_quit(global_qtest);
+ qtest_end();
}
/*
@@ -334,7 +334,7 @@ static void test_ide_drive_user(const char *dev, bool trans)
g_free(opts);
qtest_start(g_strjoinv(" ", argv));
test_cmos();
- qtest_quit(global_qtest);
+ qtest_end();
}
/*
@@ -387,7 +387,7 @@ static void test_ide_drive_cd_0(void)
}
qtest_start(g_strjoinv(" ", argv));
test_cmos();
- qtest_quit(global_qtest);
+ qtest_end();
}
int main(int argc, char **argv)
diff --git a/tests/i440fx-test.c b/tests/i440fx-test.c
new file mode 100644
index 000000000..08ce820eb
--- /dev/null
+++ b/tests/i440fx-test.c
@@ -0,0 +1,285 @@
+/*
+ * qtest I440FX test case
+ *
+ * Copyright IBM, Corp. 2012-2013
+ *
+ * Authors:
+ * Anthony Liguori <aliguori@us.ibm.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 "libqos/pci.h"
+#include "libqos/pci-pc.h"
+#include "libqtest.h"
+
+#include "hw/pci/pci_regs.h"
+
+#include <glib.h>
+#include <string.h>
+
+#define BROKEN 1
+
+#define ARRAY_SIZE(array) (sizeof(array) / sizeof((array)[0]))
+
+typedef struct TestData
+{
+ int num_cpus;
+ QPCIBus *bus;
+} TestData;
+
+static void test_i440fx_defaults(gconstpointer opaque)
+{
+ const TestData *s = opaque;
+ QPCIDevice *dev;
+ uint32_t value;
+
+ dev = qpci_device_find(s->bus, QPCI_DEVFN(0, 0));
+ g_assert(dev != NULL);
+
+ /* 3.2.2 */
+ g_assert_cmpint(qpci_config_readw(dev, PCI_VENDOR_ID), ==, 0x8086);
+ /* 3.2.3 */
+ g_assert_cmpint(qpci_config_readw(dev, PCI_DEVICE_ID), ==, 0x1237);
+#ifndef BROKEN
+ /* 3.2.4 */
+ g_assert_cmpint(qpci_config_readw(dev, PCI_COMMAND), ==, 0x0006);
+ /* 3.2.5 */
+ g_assert_cmpint(qpci_config_readw(dev, PCI_STATUS), ==, 0x0280);
+#endif
+ /* 3.2.7 */
+ g_assert_cmpint(qpci_config_readb(dev, PCI_CLASS_PROG), ==, 0x00);
+ g_assert_cmpint(qpci_config_readw(dev, PCI_CLASS_DEVICE), ==, 0x0600);
+ /* 3.2.8 */
+ g_assert_cmpint(qpci_config_readb(dev, PCI_LATENCY_TIMER), ==, 0x00);
+ /* 3.2.9 */
+ g_assert_cmpint(qpci_config_readb(dev, PCI_HEADER_TYPE), ==, 0x00);
+ /* 3.2.10 */
+ g_assert_cmpint(qpci_config_readb(dev, PCI_BIST), ==, 0x00);
+
+ /* 3.2.11 */
+ value = qpci_config_readw(dev, 0x50); /* PMCCFG */
+ if (s->num_cpus == 1) { /* WPE */
+ g_assert(!(value & (1 << 15)));
+ } else {
+ g_assert((value & (1 << 15)));
+ }
+
+ g_assert(!(value & (1 << 6))); /* EPTE */
+
+ /* 3.2.12 */
+ g_assert_cmpint(qpci_config_readb(dev, 0x52), ==, 0x00); /* DETURBO */
+ /* 3.2.13 */
+#ifndef BROKEN
+ g_assert_cmpint(qpci_config_readb(dev, 0x53), ==, 0x80); /* DBC */
+#endif
+ /* 3.2.14 */
+ g_assert_cmpint(qpci_config_readb(dev, 0x54), ==, 0x00); /* AXC */
+ /* 3.2.15 */
+ g_assert_cmpint(qpci_config_readw(dev, 0x55), ==, 0x0000); /* DRT */
+#ifndef BROKEN
+ /* 3.2.16 */
+ g_assert_cmpint(qpci_config_readb(dev, 0x57), ==, 0x01); /* DRAMC */
+ /* 3.2.17 */
+ g_assert_cmpint(qpci_config_readb(dev, 0x58), ==, 0x10); /* DRAMT */
+#endif
+ /* 3.2.18 */
+ g_assert_cmpint(qpci_config_readb(dev, 0x59), ==, 0x00); /* PAM0 */
+ g_assert_cmpint(qpci_config_readb(dev, 0x5A), ==, 0x00); /* PAM1 */
+ g_assert_cmpint(qpci_config_readb(dev, 0x5B), ==, 0x00); /* PAM2 */
+ g_assert_cmpint(qpci_config_readb(dev, 0x5C), ==, 0x00); /* PAM3 */
+ g_assert_cmpint(qpci_config_readb(dev, 0x5D), ==, 0x00); /* PAM4 */
+ g_assert_cmpint(qpci_config_readb(dev, 0x5E), ==, 0x00); /* PAM5 */
+ g_assert_cmpint(qpci_config_readb(dev, 0x5F), ==, 0x00); /* PAM6 */
+#ifndef BROKEN
+ /* 3.2.19 */
+ g_assert_cmpint(qpci_config_readb(dev, 0x60), ==, 0x01); /* DRB0 */
+ g_assert_cmpint(qpci_config_readb(dev, 0x61), ==, 0x01); /* DRB1 */
+ g_assert_cmpint(qpci_config_readb(dev, 0x62), ==, 0x01); /* DRB2 */
+ g_assert_cmpint(qpci_config_readb(dev, 0x63), ==, 0x01); /* DRB3 */
+ g_assert_cmpint(qpci_config_readb(dev, 0x64), ==, 0x01); /* DRB4 */
+ g_assert_cmpint(qpci_config_readb(dev, 0x65), ==, 0x01); /* DRB5 */
+ g_assert_cmpint(qpci_config_readb(dev, 0x66), ==, 0x01); /* DRB6 */
+ g_assert_cmpint(qpci_config_readb(dev, 0x67), ==, 0x01); /* DRB7 */
+#endif
+ /* 3.2.20 */
+ g_assert_cmpint(qpci_config_readb(dev, 0x68), ==, 0x00); /* FDHC */
+ /* 3.2.21 */
+ g_assert_cmpint(qpci_config_readb(dev, 0x70), ==, 0x00); /* MTT */
+#ifndef BROKEN
+ /* 3.2.22 */
+ g_assert_cmpint(qpci_config_readb(dev, 0x71), ==, 0x10); /* CLT */
+#endif
+ /* 3.2.23 */
+ g_assert_cmpint(qpci_config_readb(dev, 0x72), ==, 0x02); /* SMRAM */
+ /* 3.2.24 */
+ g_assert_cmpint(qpci_config_readb(dev, 0x90), ==, 0x00); /* ERRCMD */
+ /* 3.2.25 */
+ g_assert_cmpint(qpci_config_readb(dev, 0x91), ==, 0x00); /* ERRSTS */
+ /* 3.2.26 */
+ g_assert_cmpint(qpci_config_readb(dev, 0x93), ==, 0x00); /* TRC */
+}
+
+#define PAM_RE 1
+#define PAM_WE 2
+
+static void pam_set(QPCIDevice *dev, int index, int flags)
+{
+ int regno = 0x59 + (index / 2);
+ uint8_t reg;
+
+ reg = qpci_config_readb(dev, regno);
+ if (index & 1) {
+ reg = (reg & 0x0F) | (flags << 4);
+ } else {
+ reg = (reg & 0xF0) | flags;
+ }
+ qpci_config_writeb(dev, regno, reg);
+}
+
+static gboolean verify_area(uint32_t start, uint32_t end, uint8_t value)
+{
+ uint32_t size = end - start + 1;
+ gboolean ret = TRUE;
+ uint8_t *data;
+ int i;
+
+ data = g_malloc0(size);
+ memread(start, data, size);
+
+ g_test_message("verify_area: data[0] = 0x%x", data[0]);
+
+ for (i = 0; i < size; i++) {
+ if (data[i] != value) {
+ ret = FALSE;
+ break;
+ }
+ }
+
+ g_free(data);
+
+ return ret;
+}
+
+static void write_area(uint32_t start, uint32_t end, uint8_t value)
+{
+ uint32_t size = end - start + 1;
+ uint8_t *data;
+
+ data = g_malloc0(size);
+ memset(data, value, size);
+ memwrite(start, data, size);
+
+ g_free(data);
+}
+
+static void test_i440fx_pam(gconstpointer opaque)
+{
+ const TestData *s = opaque;
+ QPCIDevice *dev;
+ int i;
+ static struct {
+ uint32_t start;
+ uint32_t end;
+ } pam_area[] = {
+ { 0, 0 }, /* Reserved */
+ { 0xF0000, 0xFFFFF }, /* BIOS Area */
+ { 0xC0000, 0xC3FFF }, /* Option ROM */
+ { 0xC4000, 0xC7FFF }, /* Option ROM */
+ { 0xC8000, 0xCBFFF }, /* Option ROM */
+ { 0xCC000, 0xCFFFF }, /* Option ROM */
+ { 0xD0000, 0xD3FFF }, /* Option ROM */
+ { 0xD4000, 0xD7FFF }, /* Option ROM */
+ { 0xD8000, 0xDBFFF }, /* Option ROM */
+ { 0xDC000, 0xDFFFF }, /* Option ROM */
+ { 0xE0000, 0xE3FFF }, /* BIOS Extension */
+ { 0xE4000, 0xE7FFF }, /* BIOS Extension */
+ { 0xE8000, 0xEBFFF }, /* BIOS Extension */
+ { 0xEC000, 0xEFFFF }, /* BIOS Extension */
+ };
+
+ dev = qpci_device_find(s->bus, QPCI_DEVFN(0, 0));
+ g_assert(dev != NULL);
+
+ for (i = 0; i < ARRAY_SIZE(pam_area); i++) {
+ if (pam_area[i].start == pam_area[i].end) {
+ continue;
+ }
+
+ g_test_message("Checking area 0x%05x..0x%05x",
+ pam_area[i].start, pam_area[i].end);
+ /* Switch to RE for the area */
+ pam_set(dev, i, PAM_RE);
+ /* Verify the RAM is all zeros */
+ g_assert(verify_area(pam_area[i].start, pam_area[i].end, 0));
+
+ /* Switch to WE for the area */
+ pam_set(dev, i, PAM_RE | PAM_WE);
+ /* Write out a non-zero mask to the full area */
+ write_area(pam_area[i].start, pam_area[i].end, 0x42);
+
+#ifndef BROKEN
+ /* QEMU only supports a limited form of PAM */
+
+ /* Switch to !RE for the area */
+ pam_set(dev, i, PAM_WE);
+ /* Verify the area is not our mask */
+ g_assert(!verify_area(pam_area[i].start, pam_area[i].end, 0x42));
+#endif
+
+ /* Verify the area is our new mask */
+ g_assert(verify_area(pam_area[i].start, pam_area[i].end, 0x42));
+
+ /* Write out a new mask */
+ write_area(pam_area[i].start, pam_area[i].end, 0x82);
+
+#ifndef BROKEN
+ /* QEMU only supports a limited form of PAM */
+
+ /* Verify the area is not our mask */
+ g_assert(!verify_area(pam_area[i].start, pam_area[i].end, 0x82));
+
+ /* Switch to RE for the area */
+ pam_set(dev, i, PAM_RE | PAM_WE);
+#endif
+ /* Verify the area is our new mask */
+ g_assert(verify_area(pam_area[i].start, pam_area[i].end, 0x82));
+
+ /* Reset area */
+ pam_set(dev, i, 0);
+
+ /* Verify the area is not our new mask */
+ g_assert(!verify_area(pam_area[i].start, pam_area[i].end, 0x82));
+ }
+}
+
+int main(int argc, char **argv)
+{
+ QTestState *s;
+ TestData data;
+ char *cmdline;
+ int ret;
+
+ g_test_init(&argc, &argv, NULL);
+
+ data.num_cpus = 1;
+
+ cmdline = g_strdup_printf("-display none -smp %d", data.num_cpus);
+ s = qtest_start(cmdline);
+ g_free(cmdline);
+
+ data.bus = qpci_init_pc();
+
+ g_test_add_data_func("/i440fx/defaults", &data, test_i440fx_defaults);
+ g_test_add_data_func("/i440fx/pam", &data, test_i440fx_pam);
+
+
+ ret = g_test_run();
+
+ if (s) {
+ qtest_quit(s);
+ }
+
+ return ret;
+}
diff --git a/tests/ide-test.c b/tests/ide-test.c
new file mode 100644
index 000000000..7307f1d33
--- /dev/null
+++ b/tests/ide-test.c
@@ -0,0 +1,506 @@
+/*
+ * IDE test cases
+ *
+ * Copyright (c) 2013 Kevin Wolf <kwolf@redhat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include <stdint.h>
+#include <string.h>
+#include <stdio.h>
+
+#include <glib.h>
+
+#include "libqtest.h"
+#include "libqos/pci-pc.h"
+#include "libqos/malloc-pc.h"
+
+#include "qemu-common.h"
+#include "hw/pci/pci_ids.h"
+#include "hw/pci/pci_regs.h"
+
+#define TEST_IMAGE_SIZE 64 * 1024 * 1024
+
+#define IDE_PCI_DEV 1
+#define IDE_PCI_FUNC 1
+
+#define IDE_BASE 0x1f0
+#define IDE_PRIMARY_IRQ 14
+
+enum {
+ reg_data = 0x0,
+ reg_nsectors = 0x2,
+ reg_lba_low = 0x3,
+ reg_lba_middle = 0x4,
+ reg_lba_high = 0x5,
+ reg_device = 0x6,
+ reg_status = 0x7,
+ reg_command = 0x7,
+};
+
+enum {
+ BSY = 0x80,
+ DRDY = 0x40,
+ DF = 0x20,
+ DRQ = 0x08,
+ ERR = 0x01,
+};
+
+enum {
+ DEV = 0x10,
+ LBA = 0x40,
+};
+
+enum {
+ bmreg_cmd = 0x0,
+ bmreg_status = 0x2,
+ bmreg_prdt = 0x4,
+};
+
+enum {
+ CMD_READ_DMA = 0xc8,
+ CMD_WRITE_DMA = 0xca,
+ CMD_FLUSH_CACHE = 0xe7,
+ CMD_IDENTIFY = 0xec,
+
+ CMDF_ABORT = 0x100,
+};
+
+enum {
+ BM_CMD_START = 0x1,
+ BM_CMD_WRITE = 0x8, /* write = from device to memory */
+};
+
+enum {
+ BM_STS_ACTIVE = 0x1,
+ BM_STS_ERROR = 0x2,
+ BM_STS_INTR = 0x4,
+};
+
+enum {
+ PRDT_EOT = 0x80000000,
+};
+
+#define assert_bit_set(data, mask) g_assert_cmphex((data) & (mask), ==, (mask))
+#define assert_bit_clear(data, mask) g_assert_cmphex((data) & (mask), ==, 0)
+
+static QPCIBus *pcibus = NULL;
+static QGuestAllocator *guest_malloc;
+
+static char tmp_path[] = "/tmp/qtest.XXXXXX";
+
+static void ide_test_start(const char *cmdline_fmt, ...)
+{
+ va_list ap;
+ char *cmdline;
+
+ va_start(ap, cmdline_fmt);
+ cmdline = g_strdup_vprintf(cmdline_fmt, ap);
+ va_end(ap);
+
+ qtest_start(cmdline);
+ qtest_irq_intercept_in(global_qtest, "ioapic");
+ guest_malloc = pc_alloc_init();
+}
+
+static void ide_test_quit(void)
+{
+ qtest_end();
+}
+
+static QPCIDevice *get_pci_device(uint16_t *bmdma_base)
+{
+ QPCIDevice *dev;
+ uint16_t vendor_id, device_id;
+
+ if (!pcibus) {
+ pcibus = qpci_init_pc();
+ }
+
+ /* Find PCI device and verify it's the right one */
+ dev = qpci_device_find(pcibus, QPCI_DEVFN(IDE_PCI_DEV, IDE_PCI_FUNC));
+ g_assert(dev != NULL);
+
+ vendor_id = qpci_config_readw(dev, PCI_VENDOR_ID);
+ device_id = qpci_config_readw(dev, PCI_DEVICE_ID);
+ g_assert(vendor_id == PCI_VENDOR_ID_INTEL);
+ g_assert(device_id == PCI_DEVICE_ID_INTEL_82371SB_1);
+
+ /* Map bmdma BAR */
+ *bmdma_base = (uint16_t)(uintptr_t) qpci_iomap(dev, 4);
+
+ qpci_device_enable(dev);
+
+ return dev;
+}
+
+static void free_pci_device(QPCIDevice *dev)
+{
+ /* libqos doesn't have a function for this, so free it manually */
+ g_free(dev);
+}
+
+typedef struct PrdtEntry {
+ uint32_t addr;
+ uint32_t size;
+} QEMU_PACKED PrdtEntry;
+
+#define assert_bit_set(data, mask) g_assert_cmphex((data) & (mask), ==, (mask))
+#define assert_bit_clear(data, mask) g_assert_cmphex((data) & (mask), ==, 0)
+
+static int send_dma_request(int cmd, uint64_t sector, int nb_sectors,
+ PrdtEntry *prdt, int prdt_entries)
+{
+ QPCIDevice *dev;
+ uint16_t bmdma_base;
+ uintptr_t guest_prdt;
+ size_t len;
+ bool from_dev;
+ uint8_t status;
+ int flags;
+
+ dev = get_pci_device(&bmdma_base);
+
+ flags = cmd & ~0xff;
+ cmd &= 0xff;
+
+ switch (cmd) {
+ case CMD_READ_DMA:
+ from_dev = true;
+ break;
+ case CMD_WRITE_DMA:
+ from_dev = false;
+ break;
+ default:
+ g_assert_not_reached();
+ }
+
+ /* Select device 0 */
+ outb(IDE_BASE + reg_device, 0 | LBA);
+
+ /* Stop any running transfer, clear any pending interrupt */
+ outb(bmdma_base + bmreg_cmd, 0);
+ outb(bmdma_base + bmreg_status, BM_STS_INTR);
+
+ /* Setup PRDT */
+ len = sizeof(*prdt) * prdt_entries;
+ guest_prdt = guest_alloc(guest_malloc, len);
+ memwrite(guest_prdt, prdt, len);
+ outl(bmdma_base + bmreg_prdt, guest_prdt);
+
+ /* ATA DMA command */
+ outb(IDE_BASE + reg_nsectors, nb_sectors);
+
+ outb(IDE_BASE + reg_lba_low, sector & 0xff);
+ outb(IDE_BASE + reg_lba_middle, (sector >> 8) & 0xff);
+ outb(IDE_BASE + reg_lba_high, (sector >> 16) & 0xff);
+
+ outb(IDE_BASE + reg_command, cmd);
+
+ /* Start DMA transfer */
+ outb(bmdma_base + bmreg_cmd, BM_CMD_START | (from_dev ? BM_CMD_WRITE : 0));
+
+ if (flags & CMDF_ABORT) {
+ outb(bmdma_base + bmreg_cmd, 0);
+ }
+
+ /* Wait for the DMA transfer to complete */
+ do {
+ status = inb(bmdma_base + bmreg_status);
+ } while ((status & (BM_STS_ACTIVE | BM_STS_INTR)) == BM_STS_ACTIVE);
+
+ g_assert_cmpint(get_irq(IDE_PRIMARY_IRQ), ==, !!(status & BM_STS_INTR));
+
+ /* Check IDE status code */
+ assert_bit_set(inb(IDE_BASE + reg_status), DRDY);
+ assert_bit_clear(inb(IDE_BASE + reg_status), BSY | DRQ);
+
+ /* Reading the status register clears the IRQ */
+ g_assert(!get_irq(IDE_PRIMARY_IRQ));
+
+ /* Stop DMA transfer if still active */
+ if (status & BM_STS_ACTIVE) {
+ outb(bmdma_base + bmreg_cmd, 0);
+ }
+
+ free_pci_device(dev);
+
+ return status;
+}
+
+static void test_bmdma_simple_rw(void)
+{
+ uint8_t status;
+ uint8_t *buf;
+ uint8_t *cmpbuf;
+ size_t len = 512;
+ uintptr_t guest_buf = guest_alloc(guest_malloc, len);
+
+ PrdtEntry prdt[] = {
+ {
+ .addr = cpu_to_le32(guest_buf),
+ .size = cpu_to_le32(len | PRDT_EOT),
+ },
+ };
+
+ buf = g_malloc(len);
+ cmpbuf = g_malloc(len);
+
+ /* Write 0x55 pattern to sector 0 */
+ memset(buf, 0x55, len);
+ memwrite(guest_buf, buf, len);
+
+ status = send_dma_request(CMD_WRITE_DMA, 0, 1, prdt, ARRAY_SIZE(prdt));
+ g_assert_cmphex(status, ==, BM_STS_INTR);
+ assert_bit_clear(inb(IDE_BASE + reg_status), DF | ERR);
+
+ /* Write 0xaa pattern to sector 1 */
+ memset(buf, 0xaa, len);
+ memwrite(guest_buf, buf, len);
+
+ status = send_dma_request(CMD_WRITE_DMA, 1, 1, prdt, ARRAY_SIZE(prdt));
+ g_assert_cmphex(status, ==, BM_STS_INTR);
+ assert_bit_clear(inb(IDE_BASE + reg_status), DF | ERR);
+
+ /* Read and verify 0x55 pattern in sector 0 */
+ memset(cmpbuf, 0x55, len);
+
+ status = send_dma_request(CMD_READ_DMA, 0, 1, prdt, ARRAY_SIZE(prdt));
+ g_assert_cmphex(status, ==, BM_STS_INTR);
+ assert_bit_clear(inb(IDE_BASE + reg_status), DF | ERR);
+
+ memread(guest_buf, buf, len);
+ g_assert(memcmp(buf, cmpbuf, len) == 0);
+
+ /* Read and verify 0xaa pattern in sector 1 */
+ memset(cmpbuf, 0xaa, len);
+
+ status = send_dma_request(CMD_READ_DMA, 1, 1, prdt, ARRAY_SIZE(prdt));
+ g_assert_cmphex(status, ==, BM_STS_INTR);
+ assert_bit_clear(inb(IDE_BASE + reg_status), DF | ERR);
+
+ memread(guest_buf, buf, len);
+ g_assert(memcmp(buf, cmpbuf, len) == 0);
+
+
+ g_free(buf);
+ g_free(cmpbuf);
+}
+
+static void test_bmdma_short_prdt(void)
+{
+ uint8_t status;
+
+ PrdtEntry prdt[] = {
+ {
+ .addr = 0,
+ .size = cpu_to_le32(0x10 | PRDT_EOT),
+ },
+ };
+
+ /* Normal request */
+ status = send_dma_request(CMD_READ_DMA, 0, 1,
+ prdt, ARRAY_SIZE(prdt));
+ g_assert_cmphex(status, ==, 0);
+ assert_bit_clear(inb(IDE_BASE + reg_status), DF | ERR);
+
+ /* Abort the request before it completes */
+ status = send_dma_request(CMD_READ_DMA | CMDF_ABORT, 0, 1,
+ prdt, ARRAY_SIZE(prdt));
+ g_assert_cmphex(status, ==, 0);
+ assert_bit_clear(inb(IDE_BASE + reg_status), DF | ERR);
+}
+
+static void test_bmdma_long_prdt(void)
+{
+ uint8_t status;
+
+ PrdtEntry prdt[] = {
+ {
+ .addr = 0,
+ .size = cpu_to_le32(0x1000 | PRDT_EOT),
+ },
+ };
+
+ /* Normal request */
+ status = send_dma_request(CMD_READ_DMA, 0, 1,
+ prdt, ARRAY_SIZE(prdt));
+ g_assert_cmphex(status, ==, BM_STS_ACTIVE | BM_STS_INTR);
+ assert_bit_clear(inb(IDE_BASE + reg_status), DF | ERR);
+
+ /* Abort the request before it completes */
+ status = send_dma_request(CMD_READ_DMA | CMDF_ABORT, 0, 1,
+ prdt, ARRAY_SIZE(prdt));
+ g_assert_cmphex(status, ==, BM_STS_INTR);
+ assert_bit_clear(inb(IDE_BASE + reg_status), DF | ERR);
+}
+
+static void test_bmdma_setup(void)
+{
+ ide_test_start(
+ "-vnc none "
+ "-drive file=%s,if=ide,serial=%s,cache=writeback "
+ "-global ide-hd.ver=%s",
+ tmp_path, "testdisk", "version");
+}
+
+static void test_bmdma_teardown(void)
+{
+ ide_test_quit();
+}
+
+static void string_cpu_to_be16(uint16_t *s, size_t bytes)
+{
+ g_assert((bytes & 1) == 0);
+ bytes /= 2;
+
+ while (bytes--) {
+ *s = cpu_to_be16(*s);
+ s++;
+ }
+}
+
+static void test_identify(void)
+{
+ uint8_t data;
+ uint16_t buf[256];
+ int i;
+ int ret;
+
+ ide_test_start(
+ "-vnc none "
+ "-drive file=%s,if=ide,serial=%s,cache=writeback "
+ "-global ide-hd.ver=%s",
+ tmp_path, "testdisk", "version");
+
+ /* IDENTIFY command on device 0*/
+ outb(IDE_BASE + reg_device, 0);
+ outb(IDE_BASE + reg_command, CMD_IDENTIFY);
+
+ /* Read in the IDENTIFY buffer and check registers */
+ data = inb(IDE_BASE + reg_device);
+ g_assert_cmpint(data & DEV, ==, 0);
+
+ for (i = 0; i < 256; i++) {
+ data = inb(IDE_BASE + reg_status);
+ assert_bit_set(data, DRDY | DRQ);
+ assert_bit_clear(data, BSY | DF | ERR);
+
+ ((uint16_t*) buf)[i] = inw(IDE_BASE + reg_data);
+ }
+
+ data = inb(IDE_BASE + reg_status);
+ assert_bit_set(data, DRDY);
+ assert_bit_clear(data, BSY | DF | ERR | DRQ);
+
+ /* Check serial number/version in the buffer */
+ string_cpu_to_be16(&buf[10], 20);
+ ret = memcmp(&buf[10], "testdisk ", 20);
+ g_assert(ret == 0);
+
+ string_cpu_to_be16(&buf[23], 8);
+ ret = memcmp(&buf[23], "version ", 8);
+ g_assert(ret == 0);
+
+ /* Write cache enabled bit */
+ assert_bit_set(buf[85], 0x20);
+
+ ide_test_quit();
+}
+
+static void test_flush(void)
+{
+ uint8_t data;
+
+ ide_test_start(
+ "-vnc none "
+ "-drive file=blkdebug::%s,if=ide,cache=writeback",
+ tmp_path);
+
+ /* Delay the completion of the flush request until we explicitly do it */
+ qmp("{'execute':'human-monitor-command', 'arguments': { "
+ "'command-line': 'qemu-io ide0-hd0 \"break flush_to_os A\"'} }");
+
+ /* FLUSH CACHE command on device 0*/
+ outb(IDE_BASE + reg_device, 0);
+ outb(IDE_BASE + reg_command, CMD_FLUSH_CACHE);
+
+ /* Check status while request is in flight*/
+ data = inb(IDE_BASE + reg_status);
+ assert_bit_set(data, BSY | DRDY);
+ assert_bit_clear(data, DF | ERR | DRQ);
+
+ /* Complete the command */
+ qmp("{'execute':'human-monitor-command', 'arguments': { "
+ "'command-line': 'qemu-io ide0-hd0 \"resume A\"'} }");
+
+ /* Check registers */
+ data = inb(IDE_BASE + reg_device);
+ g_assert_cmpint(data & DEV, ==, 0);
+
+ do {
+ data = inb(IDE_BASE + reg_status);
+ } while (data & BSY);
+
+ assert_bit_set(data, DRDY);
+ assert_bit_clear(data, BSY | DF | ERR | DRQ);
+
+ ide_test_quit();
+}
+
+int main(int argc, char **argv)
+{
+ const char *arch = qtest_get_arch();
+ int fd;
+ int ret;
+
+ /* Check architecture */
+ if (strcmp(arch, "i386") && strcmp(arch, "x86_64")) {
+ g_test_message("Skipping test for non-x86\n");
+ return 0;
+ }
+
+ /* Create a temporary raw image */
+ fd = mkstemp(tmp_path);
+ g_assert(fd >= 0);
+ ret = ftruncate(fd, TEST_IMAGE_SIZE);
+ g_assert(ret == 0);
+ close(fd);
+
+ /* Run the tests */
+ g_test_init(&argc, &argv, NULL);
+
+ qtest_add_func("/ide/identify", test_identify);
+
+ qtest_add_func("/ide/bmdma/setup", test_bmdma_setup);
+ qtest_add_func("/ide/bmdma/simple_rw", test_bmdma_simple_rw);
+ qtest_add_func("/ide/bmdma/short_prdt", test_bmdma_short_prdt);
+ qtest_add_func("/ide/bmdma/long_prdt", test_bmdma_long_prdt);
+ qtest_add_func("/ide/bmdma/teardown", test_bmdma_teardown);
+
+ qtest_add_func("/ide/flush", test_flush);
+
+ ret = g_test_run();
+
+ /* Cleanup */
+ unlink(tmp_path);
+
+ return ret;
+}
diff --git a/tests/libqos/fw_cfg.c b/tests/libqos/fw_cfg.c
new file mode 100644
index 000000000..ef00fedf1
--- /dev/null
+++ b/tests/libqos/fw_cfg.c
@@ -0,0 +1,107 @@
+/*
+ * libqos fw_cfg support
+ *
+ * Copyright IBM, Corp. 2012-2013
+ * Copyright (C) 2013 Red Hat Inc.
+ *
+ * Authors:
+ * Anthony Liguori <aliguori@us.ibm.com>
+ * Markus Armbruster <armbru@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 "libqos/fw_cfg.h"
+#include "libqtest.h"
+#include "qemu/bswap.h"
+
+void qfw_cfg_select(QFWCFG *fw_cfg, uint16_t key)
+{
+ fw_cfg->select(fw_cfg, key);
+}
+
+void qfw_cfg_read_data(QFWCFG *fw_cfg, void *data, size_t len)
+{
+ fw_cfg->read(fw_cfg, data, len);
+}
+
+void qfw_cfg_get(QFWCFG *fw_cfg, uint16_t key, void *data, size_t len)
+{
+ qfw_cfg_select(fw_cfg, key);
+ qfw_cfg_read_data(fw_cfg, data, len);
+}
+
+uint16_t qfw_cfg_get_u16(QFWCFG *fw_cfg, uint16_t key)
+{
+ uint16_t value;
+ qfw_cfg_get(fw_cfg, key, &value, sizeof(value));
+ return le16_to_cpu(value);
+}
+
+uint32_t qfw_cfg_get_u32(QFWCFG *fw_cfg, uint16_t key)
+{
+ uint32_t value;
+ qfw_cfg_get(fw_cfg, key, &value, sizeof(value));
+ return le32_to_cpu(value);
+}
+
+uint64_t qfw_cfg_get_u64(QFWCFG *fw_cfg, uint16_t key)
+{
+ uint64_t value;
+ qfw_cfg_get(fw_cfg, key, &value, sizeof(value));
+ return le64_to_cpu(value);
+}
+
+static void mm_fw_cfg_select(QFWCFG *fw_cfg, uint16_t key)
+{
+ writew(fw_cfg->base, key);
+}
+
+static void mm_fw_cfg_read(QFWCFG *fw_cfg, void *data, size_t len)
+{
+ uint8_t *ptr = data;
+ int i;
+
+ for (i = 0; i < len; i++) {
+ ptr[i] = readb(fw_cfg->base + 2);
+ }
+}
+
+QFWCFG *mm_fw_cfg_init(uint64_t base)
+{
+ QFWCFG *fw_cfg = g_malloc0(sizeof(*fw_cfg));
+
+ fw_cfg->base = base;
+ fw_cfg->select = mm_fw_cfg_select;
+ fw_cfg->read = mm_fw_cfg_read;
+
+ return fw_cfg;
+}
+
+static void io_fw_cfg_select(QFWCFG *fw_cfg, uint16_t key)
+{
+ outw(fw_cfg->base, key);
+}
+
+static void io_fw_cfg_read(QFWCFG *fw_cfg, void *data, size_t len)
+{
+ uint8_t *ptr = data;
+ int i;
+
+ for (i = 0; i < len; i++) {
+ ptr[i] = inb(fw_cfg->base + 1);
+ }
+}
+
+QFWCFG *io_fw_cfg_init(uint16_t base)
+{
+ QFWCFG *fw_cfg = g_malloc0(sizeof(*fw_cfg));
+
+ fw_cfg->base = base;
+ fw_cfg->select = io_fw_cfg_select;
+ fw_cfg->read = io_fw_cfg_read;
+
+ return fw_cfg;
+}
diff --git a/tests/libqos/fw_cfg.h b/tests/libqos/fw_cfg.h
new file mode 100644
index 000000000..61b1548b4
--- /dev/null
+++ b/tests/libqos/fw_cfg.h
@@ -0,0 +1,43 @@
+/*
+ * libqos fw_cfg support
+ *
+ * Copyright IBM, Corp. 2012-2013
+ *
+ * Authors:
+ * Anthony Liguori <aliguori@us.ibm.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.
+ */
+
+#ifndef LIBQOS_FW_CFG_H
+#define LIBQOS_FW_CFG_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+typedef struct QFWCFG QFWCFG;
+
+struct QFWCFG
+{
+ uint64_t base;
+ void (*select)(QFWCFG *fw_cfg, uint16_t key);
+ void (*read)(QFWCFG *fw_cfg, void *data, size_t len);
+};
+
+void qfw_cfg_select(QFWCFG *fw_cfg, uint16_t key);
+void qfw_cfg_read_data(QFWCFG *fw_cfg, void *data, size_t len);
+void qfw_cfg_get(QFWCFG *fw_cfg, uint16_t key, void *data, size_t len);
+uint16_t qfw_cfg_get_u16(QFWCFG *fw_cfg, uint16_t key);
+uint32_t qfw_cfg_get_u32(QFWCFG *fw_cfg, uint16_t key);
+uint64_t qfw_cfg_get_u64(QFWCFG *fw_cfg, uint16_t key);
+
+QFWCFG *mm_fw_cfg_init(uint64_t base);
+QFWCFG *io_fw_cfg_init(uint16_t base);
+
+static inline QFWCFG *pc_fw_cfg_init(void)
+{
+ return io_fw_cfg_init(0x510);
+}
+
+#endif
diff --git a/tests/libqos/i2c-omap.c b/tests/libqos/i2c-omap.c
new file mode 100644
index 000000000..3d4d45d84
--- /dev/null
+++ b/tests/libqos/i2c-omap.c
@@ -0,0 +1,173 @@
+/*
+ * QTest I2C driver
+ *
+ * Copyright (c) 2012 Andreas Färber
+ *
+ * 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 "libqos/i2c.h"
+
+#include <glib.h>
+#include <string.h>
+
+#include "qemu/osdep.h"
+#include "qemu/bswap.h"
+#include "libqtest.h"
+
+enum OMAPI2CRegisters {
+ OMAP_I2C_REV = 0x00,
+ OMAP_I2C_STAT = 0x08,
+ OMAP_I2C_CNT = 0x18,
+ OMAP_I2C_DATA = 0x1c,
+ OMAP_I2C_CON = 0x24,
+ OMAP_I2C_SA = 0x2c,
+};
+
+enum OMAPI2CSTATBits {
+ OMAP_I2C_STAT_NACK = 1 << 1,
+ OMAP_I2C_STAT_ARDY = 1 << 2,
+ OMAP_I2C_STAT_RRDY = 1 << 3,
+ OMAP_I2C_STAT_XRDY = 1 << 4,
+ OMAP_I2C_STAT_ROVR = 1 << 11,
+ OMAP_I2C_STAT_SBD = 1 << 15,
+};
+
+enum OMAPI2CCONBits {
+ OMAP_I2C_CON_STT = 1 << 0,
+ OMAP_I2C_CON_STP = 1 << 1,
+ OMAP_I2C_CON_TRX = 1 << 9,
+ OMAP_I2C_CON_MST = 1 << 10,
+ OMAP_I2C_CON_BE = 1 << 14,
+ OMAP_I2C_CON_I2C_EN = 1 << 15,
+};
+
+typedef struct OMAPI2C {
+ I2CAdapter parent;
+
+ uint64_t addr;
+} OMAPI2C;
+
+
+static void omap_i2c_set_slave_addr(OMAPI2C *s, uint8_t addr)
+{
+ uint16_t data = addr;
+
+ writew(s->addr + OMAP_I2C_SA, data);
+ data = readw(s->addr + OMAP_I2C_SA);
+ g_assert_cmphex(data, ==, addr);
+}
+
+static void omap_i2c_send(I2CAdapter *i2c, uint8_t addr,
+ const uint8_t *buf, uint16_t len)
+{
+ OMAPI2C *s = (OMAPI2C *)i2c;
+ uint16_t data;
+
+ omap_i2c_set_slave_addr(s, addr);
+
+ data = len;
+ writew(s->addr + OMAP_I2C_CNT, data);
+
+ data = OMAP_I2C_CON_I2C_EN |
+ OMAP_I2C_CON_TRX |
+ OMAP_I2C_CON_MST |
+ OMAP_I2C_CON_STT |
+ OMAP_I2C_CON_STP;
+ writew(s->addr + OMAP_I2C_CON, data);
+ data = readw(s->addr + OMAP_I2C_CON);
+ g_assert((data & OMAP_I2C_CON_STP) != 0);
+
+ data = readw(s->addr + OMAP_I2C_STAT);
+ g_assert((data & OMAP_I2C_STAT_NACK) == 0);
+
+ while (len > 1) {
+ data = readw(s->addr + OMAP_I2C_STAT);
+ g_assert((data & OMAP_I2C_STAT_XRDY) != 0);
+
+ data = buf[0] | ((uint16_t)buf[1] << 8);
+ writew(s->addr + OMAP_I2C_DATA, data);
+ buf = (uint8_t *)buf + 2;
+ len -= 2;
+ }
+ if (len == 1) {
+ data = readw(s->addr + OMAP_I2C_STAT);
+ g_assert((data & OMAP_I2C_STAT_XRDY) != 0);
+
+ data = buf[0];
+ writew(s->addr + OMAP_I2C_DATA, data);
+ }
+
+ data = readw(s->addr + OMAP_I2C_CON);
+ g_assert((data & OMAP_I2C_CON_STP) == 0);
+}
+
+static void omap_i2c_recv(I2CAdapter *i2c, uint8_t addr,
+ uint8_t *buf, uint16_t len)
+{
+ OMAPI2C *s = (OMAPI2C *)i2c;
+ uint16_t data, stat;
+
+ omap_i2c_set_slave_addr(s, addr);
+
+ data = len;
+ writew(s->addr + OMAP_I2C_CNT, data);
+
+ data = OMAP_I2C_CON_I2C_EN |
+ OMAP_I2C_CON_MST |
+ OMAP_I2C_CON_STT |
+ OMAP_I2C_CON_STP;
+ writew(s->addr + OMAP_I2C_CON, data);
+ data = readw(s->addr + OMAP_I2C_CON);
+ g_assert((data & OMAP_I2C_CON_STP) == 0);
+
+ data = readw(s->addr + OMAP_I2C_STAT);
+ g_assert((data & OMAP_I2C_STAT_NACK) == 0);
+
+ data = readw(s->addr + OMAP_I2C_CNT);
+ g_assert_cmpuint(data, ==, len);
+
+ while (len > 0) {
+ data = readw(s->addr + OMAP_I2C_STAT);
+ g_assert((data & OMAP_I2C_STAT_RRDY) != 0);
+ g_assert((data & OMAP_I2C_STAT_ROVR) == 0);
+
+ data = readw(s->addr + OMAP_I2C_DATA);
+
+ stat = readw(s->addr + OMAP_I2C_STAT);
+
+ if (unlikely(len == 1)) {
+ g_assert((stat & OMAP_I2C_STAT_SBD) != 0);
+
+ buf[0] = data & 0xff;
+ buf++;
+ len--;
+ } else {
+ buf[0] = data & 0xff;
+ buf[1] = data >> 8;
+ buf += 2;
+ len -= 2;
+ }
+ }
+
+ data = readw(s->addr + OMAP_I2C_CON);
+ g_assert((data & OMAP_I2C_CON_STP) == 0);
+}
+
+I2CAdapter *omap_i2c_create(uint64_t addr)
+{
+ OMAPI2C *s = g_malloc0(sizeof(*s));
+ I2CAdapter *i2c = (I2CAdapter *)s;
+ uint16_t data;
+
+ s->addr = addr;
+
+ i2c->send = omap_i2c_send;
+ i2c->recv = omap_i2c_recv;
+
+ /* verify the mmio address by looking for a known signature */
+ data = readw(addr + OMAP_I2C_REV);
+ g_assert_cmphex(data, ==, 0x34);
+
+ return i2c;
+}
diff --git a/tests/libqos/i2c.c b/tests/libqos/i2c.c
new file mode 100644
index 000000000..da7592f71
--- /dev/null
+++ b/tests/libqos/i2c.c
@@ -0,0 +1,22 @@
+/*
+ * QTest I2C driver
+ *
+ * Copyright (c) 2012 Andreas Färber
+ *
+ * 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 "libqos/i2c.h"
+#include "libqtest.h"
+
+void i2c_send(I2CAdapter *i2c, uint8_t addr,
+ const uint8_t *buf, uint16_t len)
+{
+ i2c->send(i2c, addr, buf, len);
+}
+
+void i2c_recv(I2CAdapter *i2c, uint8_t addr,
+ uint8_t *buf, uint16_t len)
+{
+ i2c->recv(i2c, addr, buf, len);
+}
diff --git a/tests/libqos/i2c.h b/tests/libqos/i2c.h
new file mode 100644
index 000000000..1ce9af405
--- /dev/null
+++ b/tests/libqos/i2c.h
@@ -0,0 +1,30 @@
+/*
+ * I2C libqos
+ *
+ * Copyright (c) 2012 Andreas Färber
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+#ifndef LIBQOS_I2C_H
+#define LIBQOS_I2C_H
+
+#include <stdint.h>
+
+typedef struct I2CAdapter I2CAdapter;
+struct I2CAdapter {
+ void (*send)(I2CAdapter *adapter, uint8_t addr,
+ const uint8_t *buf, uint16_t len);
+ void (*recv)(I2CAdapter *adapter, uint8_t addr,
+ uint8_t *buf, uint16_t len);
+};
+
+void i2c_send(I2CAdapter *i2c, uint8_t addr,
+ const uint8_t *buf, uint16_t len);
+void i2c_recv(I2CAdapter *i2c, uint8_t addr,
+ uint8_t *buf, uint16_t len);
+
+/* libi2c-omap.c */
+I2CAdapter *omap_i2c_create(uint64_t addr);
+
+#endif
diff --git a/tests/libqos/malloc-pc.c b/tests/libqos/malloc-pc.c
new file mode 100644
index 000000000..db1496c66
--- /dev/null
+++ b/tests/libqos/malloc-pc.c
@@ -0,0 +1,71 @@
+/*
+ * libqos malloc support for PC
+ *
+ * Copyright IBM, Corp. 2012-2013
+ *
+ * Authors:
+ * Anthony Liguori <aliguori@us.ibm.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 "libqos/malloc-pc.h"
+#include "libqos/fw_cfg.h"
+
+#define NO_QEMU_PROTOS
+#include "hw/nvram/fw_cfg.h"
+
+#include "qemu-common.h"
+#include <glib.h>
+
+#define PAGE_SIZE (4096)
+
+typedef struct PCAlloc
+{
+ QGuestAllocator alloc;
+
+ uint64_t start;
+ uint64_t end;
+} PCAlloc;
+
+static uint64_t pc_alloc(QGuestAllocator *allocator, size_t size)
+{
+ PCAlloc *s = container_of(allocator, PCAlloc, alloc);
+ uint64_t addr;
+
+
+ size += (PAGE_SIZE - 1);
+ size &= PAGE_SIZE;
+
+ g_assert_cmpint((s->start + size), <=, s->end);
+
+ addr = s->start;
+ s->start += size;
+
+ return addr;
+}
+
+static void pc_free(QGuestAllocator *allocator, uint64_t addr)
+{
+}
+
+QGuestAllocator *pc_alloc_init(void)
+{
+ PCAlloc *s = g_malloc0(sizeof(*s));
+ uint64_t ram_size;
+ QFWCFG *fw_cfg = pc_fw_cfg_init();
+
+ s->alloc.alloc = pc_alloc;
+ s->alloc.free = pc_free;
+
+ ram_size = qfw_cfg_get_u64(fw_cfg, FW_CFG_RAM_SIZE);
+
+ /* Start at 1MB */
+ s->start = 1 << 20;
+
+ /* Respect PCI hole */
+ s->end = MIN(ram_size, 0xE0000000);
+
+ return &s->alloc;
+}
diff --git a/tests/libqos/malloc-pc.h b/tests/libqos/malloc-pc.h
new file mode 100644
index 000000000..ff964abe5
--- /dev/null
+++ b/tests/libqos/malloc-pc.h
@@ -0,0 +1,20 @@
+/*
+ * libqos malloc support for PC
+ *
+ * Copyright IBM, Corp. 2012-2013
+ *
+ * Authors:
+ * Anthony Liguori <aliguori@us.ibm.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.
+ */
+
+#ifndef LIBQOS_MALLOC_PC_H
+#define LIBQOS_MALLOC_PC_H
+
+#include "libqos/malloc.h"
+
+QGuestAllocator *pc_alloc_init(void);
+
+#endif
diff --git a/tests/libqos/malloc.h b/tests/libqos/malloc.h
new file mode 100644
index 000000000..46f600076
--- /dev/null
+++ b/tests/libqos/malloc.h
@@ -0,0 +1,38 @@
+/*
+ * libqos malloc support
+ *
+ * Copyright IBM, Corp. 2012-2013
+ *
+ * Authors:
+ * Anthony Liguori <aliguori@us.ibm.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.
+ */
+
+#ifndef LIBQOS_MALLOC_H
+#define LIBQOS_MALLOC_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+typedef struct QGuestAllocator QGuestAllocator;
+
+struct QGuestAllocator
+{
+ uint64_t (*alloc)(QGuestAllocator *allocator, size_t size);
+ void (*free)(QGuestAllocator *allocator, uint64_t addr);
+};
+
+/* Always returns page aligned values */
+static inline uint64_t guest_alloc(QGuestAllocator *allocator, size_t size)
+{
+ return allocator->alloc(allocator, size);
+}
+
+static inline void guest_free(QGuestAllocator *allocator, uint64_t addr)
+{
+ allocator->alloc(allocator, addr);
+}
+
+#endif
diff --git a/tests/libqos/pci-pc.c b/tests/libqos/pci-pc.c
new file mode 100644
index 000000000..3bde8ab19
--- /dev/null
+++ b/tests/libqos/pci-pc.c
@@ -0,0 +1,239 @@
+/*
+ * libqos PCI bindings for PC
+ *
+ * Copyright IBM, Corp. 2012-2013
+ *
+ * Authors:
+ * Anthony Liguori <aliguori@us.ibm.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 "libqtest.h"
+#include "libqos/pci-pc.h"
+
+#include "hw/pci/pci_regs.h"
+
+#include "qemu-common.h"
+#include "qemu/host-utils.h"
+
+#include <glib.h>
+
+typedef struct QPCIBusPC
+{
+ QPCIBus bus;
+
+ uint32_t pci_hole_start;
+ uint32_t pci_hole_size;
+ uint32_t pci_hole_alloc;
+
+ uint16_t pci_iohole_start;
+ uint16_t pci_iohole_size;
+ uint16_t pci_iohole_alloc;
+} QPCIBusPC;
+
+static uint8_t qpci_pc_io_readb(QPCIBus *bus, void *addr)
+{
+ uintptr_t port = (uintptr_t)addr;
+ uint8_t value;
+
+ if (port < 0x10000) {
+ value = inb(port);
+ } else {
+ memread(port, &value, sizeof(value));
+ }
+
+ return value;
+}
+
+static uint16_t qpci_pc_io_readw(QPCIBus *bus, void *addr)
+{
+ uintptr_t port = (uintptr_t)addr;
+ uint16_t value;
+
+ if (port < 0x10000) {
+ value = inw(port);
+ } else {
+ memread(port, &value, sizeof(value));
+ }
+
+ return value;
+}
+
+static uint32_t qpci_pc_io_readl(QPCIBus *bus, void *addr)
+{
+ uintptr_t port = (uintptr_t)addr;
+ uint32_t value;
+
+ if (port < 0x10000) {
+ value = inl(port);
+ } else {
+ memread(port, &value, sizeof(value));
+ }
+
+ return value;
+}
+
+static void qpci_pc_io_writeb(QPCIBus *bus, void *addr, uint8_t value)
+{
+ uintptr_t port = (uintptr_t)addr;
+
+ if (port < 0x10000) {
+ outb(port, value);
+ } else {
+ memwrite(port, &value, sizeof(value));
+ }
+}
+
+static void qpci_pc_io_writew(QPCIBus *bus, void *addr, uint16_t value)
+{
+ uintptr_t port = (uintptr_t)addr;
+
+ if (port < 0x10000) {
+ outw(port, value);
+ } else {
+ memwrite(port, &value, sizeof(value));
+ }
+}
+
+static void qpci_pc_io_writel(QPCIBus *bus, void *addr, uint32_t value)
+{
+ uintptr_t port = (uintptr_t)addr;
+
+ if (port < 0x10000) {
+ outl(port, value);
+ } else {
+ memwrite(port, &value, sizeof(value));
+ }
+}
+
+static uint8_t qpci_pc_config_readb(QPCIBus *bus, int devfn, uint8_t offset)
+{
+ outl(0xcf8, (1 << 31) | (devfn << 8) | offset);
+ return inb(0xcfc);
+}
+
+static uint16_t qpci_pc_config_readw(QPCIBus *bus, int devfn, uint8_t offset)
+{
+ outl(0xcf8, (1 << 31) | (devfn << 8) | offset);
+ return inw(0xcfc);
+}
+
+static uint32_t qpci_pc_config_readl(QPCIBus *bus, int devfn, uint8_t offset)
+{
+ outl(0xcf8, (1 << 31) | (devfn << 8) | offset);
+ return inl(0xcfc);
+}
+
+static void qpci_pc_config_writeb(QPCIBus *bus, int devfn, uint8_t offset, uint8_t value)
+{
+ outl(0xcf8, (1 << 31) | (devfn << 8) | offset);
+ outb(0xcfc, value);
+}
+
+static void qpci_pc_config_writew(QPCIBus *bus, int devfn, uint8_t offset, uint16_t value)
+{
+ outl(0xcf8, (1 << 31) | (devfn << 8) | offset);
+ outw(0xcfc, value);
+}
+
+static void qpci_pc_config_writel(QPCIBus *bus, int devfn, uint8_t offset, uint32_t value)
+{
+ outl(0xcf8, (1 << 31) | (devfn << 8) | offset);
+ outl(0xcfc, value);
+}
+
+static void *qpci_pc_iomap(QPCIBus *bus, QPCIDevice *dev, int barno)
+{
+ QPCIBusPC *s = container_of(bus, QPCIBusPC, bus);
+ static const int bar_reg_map[] = {
+ PCI_BASE_ADDRESS_0, PCI_BASE_ADDRESS_1, PCI_BASE_ADDRESS_2,
+ PCI_BASE_ADDRESS_3, PCI_BASE_ADDRESS_4, PCI_BASE_ADDRESS_5,
+ };
+ int bar_reg;
+ uint32_t addr;
+ uint64_t size;
+ uint32_t io_type;
+
+ g_assert(barno >= 0 && barno <= 5);
+ bar_reg = bar_reg_map[barno];
+
+ qpci_config_writel(dev, bar_reg, 0xFFFFFFFF);
+ addr = qpci_config_readl(dev, bar_reg);
+
+ io_type = addr & PCI_BASE_ADDRESS_SPACE;
+ if (io_type == PCI_BASE_ADDRESS_SPACE_IO) {
+ addr &= PCI_BASE_ADDRESS_IO_MASK;
+ } else {
+ addr &= PCI_BASE_ADDRESS_MEM_MASK;
+ }
+
+ size = (1ULL << ctzl(addr));
+ if (size == 0) {
+ return NULL;
+ }
+
+ if (io_type == PCI_BASE_ADDRESS_SPACE_IO) {
+ uint16_t loc;
+
+ g_assert((s->pci_iohole_alloc + size) <= s->pci_iohole_size);
+ loc = s->pci_iohole_start + s->pci_iohole_alloc;
+ s->pci_iohole_alloc += size;
+
+ qpci_config_writel(dev, bar_reg, loc | PCI_BASE_ADDRESS_SPACE_IO);
+
+ return (void *)(intptr_t)loc;
+ } else {
+ uint64_t loc;
+
+ g_assert((s->pci_hole_alloc + size) <= s->pci_hole_size);
+ loc = s->pci_hole_start + s->pci_hole_alloc;
+ s->pci_hole_alloc += size;
+
+ qpci_config_writel(dev, bar_reg, loc);
+
+ return (void *)(intptr_t)loc;
+ }
+}
+
+static void qpci_pc_iounmap(QPCIBus *bus, void *data)
+{
+ /* FIXME */
+}
+
+QPCIBus *qpci_init_pc(void)
+{
+ QPCIBusPC *ret;
+
+ ret = g_malloc(sizeof(*ret));
+
+ ret->bus.io_readb = qpci_pc_io_readb;
+ ret->bus.io_readw = qpci_pc_io_readw;
+ ret->bus.io_readl = qpci_pc_io_readl;
+
+ ret->bus.io_writeb = qpci_pc_io_writeb;
+ ret->bus.io_writew = qpci_pc_io_writew;
+ ret->bus.io_writel = qpci_pc_io_writel;
+
+ ret->bus.config_readb = qpci_pc_config_readb;
+ ret->bus.config_readw = qpci_pc_config_readw;
+ ret->bus.config_readl = qpci_pc_config_readl;
+
+ ret->bus.config_writeb = qpci_pc_config_writeb;
+ ret->bus.config_writew = qpci_pc_config_writew;
+ ret->bus.config_writel = qpci_pc_config_writel;
+
+ ret->bus.iomap = qpci_pc_iomap;
+ ret->bus.iounmap = qpci_pc_iounmap;
+
+ ret->pci_hole_start = 0xE0000000;
+ ret->pci_hole_size = 0x20000000;
+ ret->pci_hole_alloc = 0;
+
+ ret->pci_iohole_start = 0xc000;
+ ret->pci_iohole_size = 0x4000;
+ ret->pci_iohole_alloc = 0;
+
+ return &ret->bus;
+}
diff --git a/tests/libqos/pci-pc.h b/tests/libqos/pci-pc.h
new file mode 100644
index 000000000..4f7475f6f
--- /dev/null
+++ b/tests/libqos/pci-pc.h
@@ -0,0 +1,20 @@
+/*
+ * libqos PCI bindings for PC
+ *
+ * Copyright IBM, Corp. 2012-2013
+ *
+ * Authors:
+ * Anthony Liguori <aliguori@us.ibm.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.
+ */
+
+#ifndef LIBQOS_PCI_PC_H
+#define LIBQOS_PCI_PC_H
+
+#include "libqos/pci.h"
+
+QPCIBus *qpci_init_pc(void);
+
+#endif
diff --git a/tests/libqos/pci.c b/tests/libqos/pci.c
new file mode 100644
index 000000000..7e0907b51
--- /dev/null
+++ b/tests/libqos/pci.c
@@ -0,0 +1,151 @@
+/*
+ * libqos PCI bindings
+ *
+ * Copyright IBM, Corp. 2012-2013
+ *
+ * Authors:
+ * Anthony Liguori <aliguori@us.ibm.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 "libqos/pci.h"
+
+#include "hw/pci/pci_regs.h"
+#include <glib.h>
+
+#include <stdio.h>
+
+void qpci_device_foreach(QPCIBus *bus, int vendor_id, int device_id,
+ void (*func)(QPCIDevice *dev, int devfn, void *data),
+ void *data)
+{
+ int slot;
+
+ for (slot = 0; slot < 32; slot++) {
+ int fn;
+
+ for (fn = 0; fn < 8; fn++) {
+ QPCIDevice *dev;
+
+ dev = qpci_device_find(bus, QPCI_DEVFN(slot, fn));
+ if (!dev) {
+ continue;
+ }
+
+ if (vendor_id != -1 &&
+ qpci_config_readw(dev, PCI_VENDOR_ID) != vendor_id) {
+ continue;
+ }
+
+ if (device_id != -1 &&
+ qpci_config_readw(dev, PCI_DEVICE_ID) != device_id) {
+ continue;
+ }
+
+ func(dev, QPCI_DEVFN(slot, fn), data);
+ }
+ }
+}
+
+QPCIDevice *qpci_device_find(QPCIBus *bus, int devfn)
+{
+ QPCIDevice *dev;
+
+ dev = g_malloc0(sizeof(*dev));
+ dev->bus = bus;
+ dev->devfn = devfn;
+
+ if (qpci_config_readw(dev, PCI_VENDOR_ID) == 0xFFFF) {
+ g_free(dev);
+ return NULL;
+ }
+
+ return dev;
+}
+
+void qpci_device_enable(QPCIDevice *dev)
+{
+ uint16_t cmd;
+
+ /* FIXME -- does this need to be a bus callout? */
+ cmd = qpci_config_readw(dev, PCI_COMMAND);
+ cmd |= PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER;
+ qpci_config_writew(dev, PCI_COMMAND, cmd);
+}
+
+uint8_t qpci_config_readb(QPCIDevice *dev, uint8_t offset)
+{
+ return dev->bus->config_readb(dev->bus, dev->devfn, offset);
+}
+
+uint16_t qpci_config_readw(QPCIDevice *dev, uint8_t offset)
+{
+ return dev->bus->config_readw(dev->bus, dev->devfn, offset);
+}
+
+uint32_t qpci_config_readl(QPCIDevice *dev, uint8_t offset)
+{
+ return dev->bus->config_readl(dev->bus, dev->devfn, offset);
+}
+
+
+void qpci_config_writeb(QPCIDevice *dev, uint8_t offset, uint8_t value)
+{
+ dev->bus->config_writeb(dev->bus, dev->devfn, offset, value);
+}
+
+void qpci_config_writew(QPCIDevice *dev, uint8_t offset, uint16_t value)
+{
+ dev->bus->config_writew(dev->bus, dev->devfn, offset, value);
+}
+
+void qpci_config_writel(QPCIDevice *dev, uint8_t offset, uint32_t value)
+{
+ dev->bus->config_writew(dev->bus, dev->devfn, offset, value);
+}
+
+
+uint8_t qpci_io_readb(QPCIDevice *dev, void *data)
+{
+ return dev->bus->io_readb(dev->bus, data);
+}
+
+uint16_t qpci_io_readw(QPCIDevice *dev, void *data)
+{
+ return dev->bus->io_readw(dev->bus, data);
+}
+
+uint32_t qpci_io_readl(QPCIDevice *dev, void *data)
+{
+ return dev->bus->io_readl(dev->bus, data);
+}
+
+
+void qpci_io_writeb(QPCIDevice *dev, void *data, uint8_t value)
+{
+ dev->bus->io_writeb(dev->bus, data, value);
+}
+
+void qpci_io_writew(QPCIDevice *dev, void *data, uint16_t value)
+{
+ dev->bus->io_writew(dev->bus, data, value);
+}
+
+void qpci_io_writel(QPCIDevice *dev, void *data, uint32_t value)
+{
+ dev->bus->io_writel(dev->bus, data, value);
+}
+
+void *qpci_iomap(QPCIDevice *dev, int barno)
+{
+ return dev->bus->iomap(dev->bus, dev, barno);
+}
+
+void qpci_iounmap(QPCIDevice *dev, void *data)
+{
+ dev->bus->iounmap(dev->bus, data);
+}
+
+
diff --git a/tests/libqos/pci.h b/tests/libqos/pci.h
new file mode 100644
index 000000000..343943154
--- /dev/null
+++ b/tests/libqos/pci.h
@@ -0,0 +1,80 @@
+/*
+ * libqos PCI bindings
+ *
+ * Copyright IBM, Corp. 2012-2013
+ *
+ * Authors:
+ * Anthony Liguori <aliguori@us.ibm.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.
+ */
+
+#ifndef LIBQOS_PCI_H
+#define LIBQOS_PCI_H
+
+#include <stdint.h>
+
+#define QPCI_DEVFN(dev, fn) (((dev) << 3) | (fn))
+
+typedef struct QPCIDevice QPCIDevice;
+typedef struct QPCIBus QPCIBus;
+
+struct QPCIBus
+{
+ uint8_t (*io_readb)(QPCIBus *bus, void *addr);
+ uint16_t (*io_readw)(QPCIBus *bus, void *addr);
+ uint32_t (*io_readl)(QPCIBus *bus, void *addr);
+
+ void (*io_writeb)(QPCIBus *bus, void *addr, uint8_t value);
+ void (*io_writew)(QPCIBus *bus, void *addr, uint16_t value);
+ void (*io_writel)(QPCIBus *bus, void *addr, uint32_t value);
+
+ uint8_t (*config_readb)(QPCIBus *bus, int devfn, uint8_t offset);
+ uint16_t (*config_readw)(QPCIBus *bus, int devfn, uint8_t offset);
+ uint32_t (*config_readl)(QPCIBus *bus, int devfn, uint8_t offset);
+
+ void (*config_writeb)(QPCIBus *bus, int devfn,
+ uint8_t offset, uint8_t value);
+ void (*config_writew)(QPCIBus *bus, int devfn,
+ uint8_t offset, uint16_t value);
+ void (*config_writel)(QPCIBus *bus, int devfn,
+ uint8_t offset, uint32_t value);
+
+ void *(*iomap)(QPCIBus *bus, QPCIDevice *dev, int barno);
+ void (*iounmap)(QPCIBus *bus, void *data);
+};
+
+struct QPCIDevice
+{
+ QPCIBus *bus;
+ int devfn;
+};
+
+void qpci_device_foreach(QPCIBus *bus, int vendor_id, int device_id,
+ void (*func)(QPCIDevice *dev, int devfn, void *data),
+ void *data);
+QPCIDevice *qpci_device_find(QPCIBus *bus, int devfn);
+
+void qpci_device_enable(QPCIDevice *dev);
+
+uint8_t qpci_config_readb(QPCIDevice *dev, uint8_t offset);
+uint16_t qpci_config_readw(QPCIDevice *dev, uint8_t offset);
+uint32_t qpci_config_readl(QPCIDevice *dev, uint8_t offset);
+
+void qpci_config_writeb(QPCIDevice *dev, uint8_t offset, uint8_t value);
+void qpci_config_writew(QPCIDevice *dev, uint8_t offset, uint16_t value);
+void qpci_config_writel(QPCIDevice *dev, uint8_t offset, uint32_t value);
+
+uint8_t qpci_io_readb(QPCIDevice *dev, void *data);
+uint16_t qpci_io_readw(QPCIDevice *dev, void *data);
+uint32_t qpci_io_readl(QPCIDevice *dev, void *data);
+
+void qpci_io_writeb(QPCIDevice *dev, void *data, uint8_t value);
+void qpci_io_writew(QPCIDevice *dev, void *data, uint16_t value);
+void qpci_io_writel(QPCIDevice *dev, void *data, uint32_t value);
+
+void *qpci_iomap(QPCIDevice *dev, int barno);
+void qpci_iounmap(QPCIDevice *dev, void *data);
+
+#endif
diff --git a/tests/libqtest.c b/tests/libqtest.c
index 71b84c12d..bb82069f5 100644
--- a/tests/libqtest.c
+++ b/tests/libqtest.c
@@ -3,10 +3,12 @@
*
* Copyright IBM, Corp. 2012
* Copyright Red Hat, Inc. 2012
+ * Copyright SUSE LINUX Products GmbH 2013
*
* Authors:
* Anthony Liguori <aliguori@us.ibm.com>
* Paolo Bonzini <pbonzini@redhat.com>
+ * Andreas Färber <afaerber@suse.de>
*
* This work is licensed under the terms of the GNU GPL, version 2 or later.
* See the COPYING file in the top-level directory.
@@ -26,8 +28,8 @@
#include <unistd.h>
#include <string.h>
-#include "compiler.h"
-#include "osdep.h"
+#include "qemu/compiler.h"
+#include "qemu/osdep.h"
#define MAX_IRQ 256
@@ -39,7 +41,8 @@ struct QTestState
int qmp_fd;
bool irq_level[MAX_IRQ];
GString *rx;
- gchar *pid_file;
+ gchar *pid_file; /* QEMU PID file */
+ int child_pid; /* Child process created to execute QEMU */
char *socket_path, *qmp_socket_path;
};
@@ -96,15 +99,15 @@ static pid_t qtest_qemu_pid(QTestState *s)
if (fgets(buffer, sizeof(buffer), f)) {
pid = atoi(buffer);
}
+ fclose(f);
}
- fclose(f);
return pid;
}
QTestState *qtest_init(const char *extra_args)
{
QTestState *s;
- int sock, qmpsock, ret, i;
+ int sock, qmpsock, i;
gchar *pid_file;
gchar *command;
const char *qemu_binary;
@@ -133,10 +136,8 @@ QTestState *qtest_init(const char *extra_args)
"%s", qemu_binary, s->socket_path,
s->qmp_socket_path, pid_file,
extra_args ?: "");
-
- ret = system(command);
- exit(ret);
- g_free(command);
+ execlp("/bin/sh", "sh", "-c", command, NULL);
+ exit(1);
}
s->fd = socket_accept(sock);
@@ -144,6 +145,7 @@ QTestState *qtest_init(const char *extra_args)
s->rx = g_string_new("");
s->pid_file = pid_file;
+ s->child_pid = pid;
for (i = 0; i < MAX_IRQ; i++) {
s->irq_level[i] = false;
}
@@ -169,12 +171,16 @@ void qtest_quit(QTestState *s)
waitpid(pid, &status, 0);
}
+ close(s->fd);
+ close(s->qmp_fd);
+ g_string_free(s->rx, true);
unlink(s->pid_file);
unlink(s->socket_path);
unlink(s->qmp_socket_path);
g_free(s->pid_file);
g_free(s->socket_path);
g_free(s->qmp_socket_path);
+ g_free(s);
}
static void socket_sendf(int fd, const char *fmt, va_list ap)
@@ -285,16 +291,13 @@ redo:
return words;
}
-void qtest_qmp(QTestState *s, const char *fmt, ...)
+void qtest_qmpv(QTestState *s, const char *fmt, va_list ap)
{
- va_list ap;
bool has_reply = false;
int nesting = 0;
/* Send QMP request */
- va_start(ap, fmt);
socket_sendf(s->qmp_fd, fmt, ap);
- va_end(ap);
/* Receive reply */
while (!has_reply || nesting > 0) {
@@ -323,6 +326,15 @@ void qtest_qmp(QTestState *s, const char *fmt, ...)
}
}
+void qtest_qmp(QTestState *s, const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ qtest_qmpv(s, fmt, ap);
+ va_end(ap);
+}
+
const char *qtest_get_arch(void)
{
const char *qemu = getenv("QTEST_QEMU_BINARY");
@@ -428,6 +440,66 @@ uint32_t qtest_inl(QTestState *s, uint16_t addr)
return qtest_in(s, "inl", addr);
}
+static void qtest_write(QTestState *s, const char *cmd, uint64_t addr,
+ uint64_t value)
+{
+ qtest_sendf(s, "%s 0x%" PRIx64 " 0x%" PRIx64 "\n", cmd, addr, value);
+ qtest_rsp(s, 0);
+}
+
+void qtest_writeb(QTestState *s, uint64_t addr, uint8_t value)
+{
+ qtest_write(s, "writeb", addr, value);
+}
+
+void qtest_writew(QTestState *s, uint64_t addr, uint16_t value)
+{
+ qtest_write(s, "writew", addr, value);
+}
+
+void qtest_writel(QTestState *s, uint64_t addr, uint32_t value)
+{
+ qtest_write(s, "writel", addr, value);
+}
+
+void qtest_writeq(QTestState *s, uint64_t addr, uint64_t value)
+{
+ qtest_write(s, "writeq", addr, value);
+}
+
+static uint64_t qtest_read(QTestState *s, const char *cmd, uint64_t addr)
+{
+ gchar **args;
+ uint64_t value;
+
+ qtest_sendf(s, "%s 0x%" PRIx64 "\n", cmd, addr);
+ args = qtest_rsp(s, 2);
+ value = strtoull(args[1], NULL, 0);
+ g_strfreev(args);
+
+ return value;
+}
+
+uint8_t qtest_readb(QTestState *s, uint64_t addr)
+{
+ return qtest_read(s, "readb", addr);
+}
+
+uint16_t qtest_readw(QTestState *s, uint64_t addr)
+{
+ return qtest_read(s, "readw", addr);
+}
+
+uint32_t qtest_readl(QTestState *s, uint64_t addr)
+{
+ return qtest_read(s, "readl", addr);
+}
+
+uint64_t qtest_readq(QTestState *s, uint64_t addr)
+{
+ return qtest_read(s, "readq", addr);
+}
+
static int hex2nib(char ch)
{
if (ch >= '0' && ch <= '9') {
diff --git a/tests/libqtest.h b/tests/libqtest.h
index c8ade856f..0f6aade09 100644
--- a/tests/libqtest.h
+++ b/tests/libqtest.h
@@ -3,10 +3,12 @@
*
* Copyright IBM, Corp. 2012
* Copyright Red Hat, Inc. 2012
+ * Copyright SUSE LINUX Products GmbH 2013
*
* Authors:
* Anthony Liguori <aliguori@us.ibm.com>
* Paolo Bonzini <pbonzini@redhat.com>
+ * Andreas Färber <afaerber@suse.de>
*
* This work is licensed under the terms of the GNU GPL, version 2 or later.
* See the COPYING file in the top-level directory.
@@ -15,8 +17,10 @@
#ifndef LIBQTEST_H
#define LIBQTEST_H
+#include <stddef.h>
#include <stdint.h>
#include <stdbool.h>
+#include <stdarg.h>
#include <sys/types.h>
typedef struct QTestState QTestState;
@@ -26,12 +30,14 @@ extern QTestState *global_qtest;
/**
* qtest_init:
* @extra_args: other arguments to pass to QEMU.
+ *
+ * Returns: #QTestState instance.
*/
QTestState *qtest_init(const char *extra_args);
/**
* qtest_quit:
- * @s: QTestState instance to operate on.
+ * @s: #QTestState instance to operate on.
*
* Shut down the QEMU process associated to @s.
*/
@@ -39,7 +45,7 @@ void qtest_quit(QTestState *s);
/**
* qtest_qmp:
- * @s: QTestState instance to operate on.
+ * @s: #QTestState instance to operate on.
* @fmt...: QMP message to send to qemu
*
* Sends a QMP message to QEMU
@@ -47,17 +53,27 @@ void qtest_quit(QTestState *s);
void qtest_qmp(QTestState *s, const char *fmt, ...);
/**
+ * qtest_qmpv:
+ * @s: #QTestState instance to operate on.
+ * @fmt: QMP message to send to QEMU
+ * @ap: QMP message arguments
+ *
+ * Sends a QMP message to QEMU.
+ */
+void qtest_qmpv(QTestState *s, const char *fmt, va_list ap);
+
+/**
* qtest_get_irq:
- * @s: QTestState instance to operate on.
+ * @s: #QTestState instance to operate on.
* @num: Interrupt to observe.
*
- * Return the level of the @num interrupt.
+ * Returns: The level of the @num interrupt.
*/
bool qtest_get_irq(QTestState *s, int num);
/**
* qtest_irq_intercept_in:
- * @s: QTestState instance to operate on.
+ * @s: #QTestState instance to operate on.
* @string: QOM path of a device.
*
* Associate qtest irqs with the GPIO-in pins of the device
@@ -67,7 +83,7 @@ void qtest_irq_intercept_in(QTestState *s, const char *string);
/**
* qtest_irq_intercept_out:
- * @s: QTestState instance to operate on.
+ * @s: #QTestState instance to operate on.
* @string: QOM path of a device.
*
* Associate qtest irqs with the GPIO-out pins of the device
@@ -77,7 +93,7 @@ void qtest_irq_intercept_out(QTestState *s, const char *string);
/**
* qtest_outb:
- * @s: QTestState instance to operate on.
+ * @s: #QTestState instance to operate on.
* @addr: I/O port to write to.
* @value: Value being written.
*
@@ -87,7 +103,7 @@ void qtest_outb(QTestState *s, uint16_t addr, uint8_t value);
/**
* qtest_outw:
- * @s: QTestState instance to operate on.
+ * @s: #QTestState instance to operate on.
* @addr: I/O port to write to.
* @value: Value being written.
*
@@ -97,7 +113,7 @@ void qtest_outw(QTestState *s, uint16_t addr, uint16_t value);
/**
* qtest_outl:
- * @s: QTestState instance to operate on.
+ * @s: #QTestState instance to operate on.
* @addr: I/O port to write to.
* @value: Value being written.
*
@@ -107,9 +123,8 @@ void qtest_outl(QTestState *s, uint16_t addr, uint32_t value);
/**
* qtest_inb:
- * @s: QTestState instance to operate on.
+ * @s: #QTestState instance to operate on.
* @addr: I/O port to read from.
- * @value: Value being written.
*
* Returns an 8-bit value from an I/O port.
*/
@@ -117,9 +132,8 @@ uint8_t qtest_inb(QTestState *s, uint16_t addr);
/**
* qtest_inw:
- * @s: QTestState instance to operate on.
+ * @s: #QTestState instance to operate on.
* @addr: I/O port to read from.
- * @value: Value being written.
*
* Returns a 16-bit value from an I/O port.
*/
@@ -127,17 +141,100 @@ uint16_t qtest_inw(QTestState *s, uint16_t addr);
/**
* qtest_inl:
- * @s: QTestState instance to operate on.
+ * @s: #QTestState instance to operate on.
* @addr: I/O port to read from.
- * @value: Value being written.
*
* Returns a 32-bit value from an I/O port.
*/
uint32_t qtest_inl(QTestState *s, uint16_t addr);
/**
+ * qtest_writeb:
+ * @s: #QTestState instance to operate on.
+ * @addr: Guest address to write to.
+ * @value: Value being written.
+ *
+ * Writes an 8-bit value to memory.
+ */
+void qtest_writeb(QTestState *s, uint64_t addr, uint8_t value);
+
+/**
+ * qtest_writew:
+ * @s: #QTestState instance to operate on.
+ * @addr: Guest address to write to.
+ * @value: Value being written.
+ *
+ * Writes a 16-bit value to memory.
+ */
+void qtest_writew(QTestState *s, uint64_t addr, uint16_t value);
+
+/**
+ * qtest_writel:
+ * @s: #QTestState instance to operate on.
+ * @addr: Guest address to write to.
+ * @value: Value being written.
+ *
+ * Writes a 32-bit value to memory.
+ */
+void qtest_writel(QTestState *s, uint64_t addr, uint32_t value);
+
+/**
+ * qtest_writeq:
+ * @s: #QTestState instance to operate on.
+ * @addr: Guest address to write to.
+ * @value: Value being written.
+ *
+ * Writes a 64-bit value to memory.
+ */
+void qtest_writeq(QTestState *s, uint64_t addr, uint64_t value);
+
+/**
+ * qtest_readb:
+ * @s: #QTestState instance to operate on.
+ * @addr: Guest address to read from.
+ *
+ * Reads an 8-bit value from memory.
+ *
+ * Returns: Value read.
+ */
+uint8_t qtest_readb(QTestState *s, uint64_t addr);
+
+/**
+ * qtest_readw:
+ * @s: #QTestState instance to operate on.
+ * @addr: Guest address to read from.
+ *
+ * Reads a 16-bit value from memory.
+ *
+ * Returns: Value read.
+ */
+uint16_t qtest_readw(QTestState *s, uint64_t addr);
+
+/**
+ * qtest_readl:
+ * @s: #QTestState instance to operate on.
+ * @addr: Guest address to read from.
+ *
+ * Reads a 32-bit value from memory.
+ *
+ * Returns: Value read.
+ */
+uint32_t qtest_readl(QTestState *s, uint64_t addr);
+
+/**
+ * qtest_readq:
+ * @s: #QTestState instance to operate on.
+ * @addr: Guest address to read from.
+ *
+ * Reads a 64-bit value from memory.
+ *
+ * Returns: Value read.
+ */
+uint64_t qtest_readq(QTestState *s, uint64_t addr);
+
+/**
* qtest_memread:
- * @s: QTestState instance to operate on.
+ * @s: #QTestState instance to operate on.
* @addr: Guest address to read from.
* @data: Pointer to where memory contents will be stored.
* @size: Number of bytes to read.
@@ -148,7 +245,7 @@ void qtest_memread(QTestState *s, uint64_t addr, void *data, size_t size);
/**
* qtest_memwrite:
- * @s: QTestState instance to operate on.
+ * @s: #QTestState instance to operate on.
* @addr: Guest address to write to.
* @data: Pointer to the bytes that will be written to guest memory.
* @size: Number of bytes to write.
@@ -159,10 +256,11 @@ void qtest_memwrite(QTestState *s, uint64_t addr, const void *data, size_t size)
/**
* qtest_clock_step_next:
- * @s: QTestState instance to operate on.
+ * @s: #QTestState instance to operate on.
+ *
+ * Advance the vm_clock to the next deadline.
*
- * Advance the vm_clock to the next deadline. Return the current
- * value of the vm_clock in nanoseconds.
+ * Returns: The current value of the vm_clock in nanoseconds.
*/
int64_t qtest_clock_step_next(QTestState *s);
@@ -171,8 +269,9 @@ int64_t qtest_clock_step_next(QTestState *s);
* @s: QTestState instance to operate on.
* @step: Number of nanoseconds to advance the clock by.
*
- * Advance the vm_clock by @step nanoseconds. Return the current
- * value of the vm_clock in nanoseconds.
+ * Advance the vm_clock by @step nanoseconds.
+ *
+ * Returns: The current value of the vm_clock in nanoseconds.
*/
int64_t qtest_clock_step(QTestState *s, int64_t step);
@@ -182,14 +281,15 @@ int64_t qtest_clock_step(QTestState *s, int64_t step);
* @val: Nanoseconds value to advance the clock to.
*
* Advance the vm_clock to @val nanoseconds since the VM was launched.
- * Return the current value of the vm_clock in nanoseconds.
+ *
+ * Returns: The current value of the vm_clock in nanoseconds.
*/
int64_t qtest_clock_set(QTestState *s, int64_t val);
/**
* qtest_get_arch:
*
- * Returns the architecture for the QEMU executable under test.
+ * Returns: The architecture for the QEMU executable under test.
*/
const char *qtest_get_arch(void);
@@ -200,7 +300,7 @@ const char *qtest_get_arch(void);
*
* Add a GTester testcase with the given name and function.
* The path is prefixed with the architecture under test, as
- * returned by qtest_get_arch.
+ * returned by qtest_get_arch().
*/
void qtest_add_func(const char *str, void (*fn));
@@ -208,12 +308,27 @@ void qtest_add_func(const char *str, void (*fn));
* qtest_start:
* @args: other arguments to pass to QEMU
*
- * Start QEMU and assign the resulting QTestState to a global variable.
- * The global variable is used by "shortcut" macros documented below.
+ * Start QEMU and assign the resulting #QTestState to a global variable.
+ * The global variable is used by "shortcut" functions documented below.
+ *
+ * Returns: #QTestState instance.
+ */
+static inline QTestState *qtest_start(const char *args)
+{
+ global_qtest = qtest_init(args);
+ return global_qtest;
+}
+
+/**
+ * qtest_end:
+ *
+ * Shut down the QEMU process started by qtest_start().
*/
-#define qtest_start(args) ( \
- global_qtest = qtest_init((args)) \
- )
+static inline void qtest_end(void)
+{
+ qtest_quit(global_qtest);
+ global_qtest = NULL;
+}
/**
* qmp:
@@ -221,15 +336,25 @@ void qtest_add_func(const char *str, void (*fn));
*
* Sends a QMP message to QEMU
*/
-#define qmp(fmt, ...) qtest_qmp(global_qtest, fmt, ## __VA_ARGS__)
+static inline void qmp(const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ qtest_qmpv(global_qtest, fmt, ap);
+ va_end(ap);
+}
/**
* get_irq:
* @num: Interrupt to observe.
*
- * Return the level of the @num interrupt.
+ * Returns: The level of the @num interrupt.
*/
-#define get_irq(num) qtest_get_irq(global_qtest, num)
+static inline bool get_irq(int num)
+{
+ return qtest_get_irq(global_qtest, num);
+}
/**
* irq_intercept_in:
@@ -238,7 +363,10 @@ void qtest_add_func(const char *str, void (*fn));
* Associate qtest irqs with the GPIO-in pins of the device
* whose path is specified by @string.
*/
-#define irq_intercept_in(string) qtest_irq_intercept_in(global_qtest, string)
+static inline void irq_intercept_in(const char *string)
+{
+ qtest_irq_intercept_in(global_qtest, string);
+}
/**
* qtest_irq_intercept_out:
@@ -247,7 +375,10 @@ void qtest_add_func(const char *str, void (*fn));
* Associate qtest irqs with the GPIO-out pins of the device
* whose path is specified by @string.
*/
-#define irq_intercept_out(string) qtest_irq_intercept_out(global_qtest, string)
+static inline void irq_intercept_out(const char *string)
+{
+ qtest_irq_intercept_out(global_qtest, string);
+}
/**
* outb:
@@ -256,7 +387,10 @@ void qtest_add_func(const char *str, void (*fn));
*
* Write an 8-bit value to an I/O port.
*/
-#define outb(addr, val) qtest_outb(global_qtest, addr, val)
+static inline void outb(uint16_t addr, uint8_t value)
+{
+ qtest_outb(global_qtest, addr, value);
+}
/**
* outw:
@@ -265,7 +399,10 @@ void qtest_add_func(const char *str, void (*fn));
*
* Write a 16-bit value to an I/O port.
*/
-#define outw(addr, val) qtest_outw(global_qtest, addr, val)
+static inline void outw(uint16_t addr, uint16_t value)
+{
+ qtest_outw(global_qtest, addr, value);
+}
/**
* outl:
@@ -274,34 +411,149 @@ void qtest_add_func(const char *str, void (*fn));
*
* Write a 32-bit value to an I/O port.
*/
-#define outl(addr, val) qtest_outl(global_qtest, addr, val)
+static inline void outl(uint16_t addr, uint32_t value)
+{
+ qtest_outl(global_qtest, addr, value);
+}
/**
* inb:
* @addr: I/O port to read from.
- * @value: Value being written.
*
- * Returns an 8-bit value from an I/O port.
+ * Reads an 8-bit value from an I/O port.
+ *
+ * Returns: Value read.
*/
-#define inb(addr) qtest_inb(global_qtest, addr)
+static inline uint8_t inb(uint16_t addr)
+{
+ return qtest_inb(global_qtest, addr);
+}
/**
* inw:
* @addr: I/O port to read from.
- * @value: Value being written.
*
- * Returns a 16-bit value from an I/O port.
+ * Reads a 16-bit value from an I/O port.
+ *
+ * Returns: Value read.
*/
-#define inw(addr) qtest_inw(global_qtest, addr)
+static inline uint16_t inw(uint16_t addr)
+{
+ return qtest_inw(global_qtest, addr);
+}
/**
* inl:
* @addr: I/O port to read from.
+ *
+ * Reads a 32-bit value from an I/O port.
+ *
+ * Returns: Value read.
+ */
+static inline uint32_t inl(uint16_t addr)
+{
+ return qtest_inl(global_qtest, addr);
+}
+
+/**
+ * writeb:
+ * @addr: Guest address to write to.
* @value: Value being written.
*
- * Returns a 32-bit value from an I/O port.
+ * Writes an 8-bit value to guest memory.
+ */
+static inline void writeb(uint64_t addr, uint8_t value)
+{
+ qtest_writeb(global_qtest, addr, value);
+}
+
+/**
+ * writew:
+ * @addr: Guest address to write to.
+ * @value: Value being written.
+ *
+ * Writes a 16-bit value to guest memory.
+ */
+static inline void writew(uint64_t addr, uint16_t value)
+{
+ qtest_writew(global_qtest, addr, value);
+}
+
+/**
+ * writel:
+ * @addr: Guest address to write to.
+ * @value: Value being written.
+ *
+ * Writes a 32-bit value to guest memory.
+ */
+static inline void writel(uint64_t addr, uint32_t value)
+{
+ qtest_writel(global_qtest, addr, value);
+}
+
+/**
+ * writeq:
+ * @addr: Guest address to write to.
+ * @value: Value being written.
+ *
+ * Writes a 64-bit value to guest memory.
+ */
+static inline void writeq(uint64_t addr, uint64_t value)
+{
+ qtest_writeq(global_qtest, addr, value);
+}
+
+/**
+ * readb:
+ * @addr: Guest address to read from.
+ *
+ * Reads an 8-bit value from guest memory.
+ *
+ * Returns: Value read.
+ */
+static inline uint8_t readb(uint64_t addr)
+{
+ return qtest_readb(global_qtest, addr);
+}
+
+/**
+ * readw:
+ * @addr: Guest address to read from.
+ *
+ * Reads a 16-bit value from guest memory.
+ *
+ * Returns: Value read.
*/
-#define inl(addr) qtest_inl(global_qtest, addr)
+static inline uint16_t readw(uint64_t addr)
+{
+ return qtest_readw(global_qtest, addr);
+}
+
+/**
+ * readl:
+ * @addr: Guest address to read from.
+ *
+ * Reads a 32-bit value from guest memory.
+ *
+ * Returns: Value read.
+ */
+static inline uint32_t readl(uint64_t addr)
+{
+ return qtest_readl(global_qtest, addr);
+}
+
+/**
+ * readq:
+ * @addr: Guest address to read from.
+ *
+ * Reads a 64-bit value from guest memory.
+ *
+ * Returns: Value read.
+ */
+static inline uint64_t readq(uint64_t addr)
+{
+ return qtest_readq(global_qtest, addr);
+}
/**
* memread:
@@ -311,7 +563,10 @@ void qtest_add_func(const char *str, void (*fn));
*
* Read guest memory into a buffer.
*/
-#define memread(addr, data, size) qtest_memread(global_qtest, addr, data, size)
+static inline void memread(uint64_t addr, void *data, size_t size)
+{
+ qtest_memread(global_qtest, addr, data, size);
+}
/**
* memwrite:
@@ -321,32 +576,47 @@ void qtest_add_func(const char *str, void (*fn));
*
* Write a buffer to guest memory.
*/
-#define memwrite(addr, data, size) qtest_memwrite(global_qtest, addr, data, size)
+static inline void memwrite(uint64_t addr, const void *data, size_t size)
+{
+ qtest_memwrite(global_qtest, addr, data, size);
+}
/**
* clock_step_next:
*
- * Advance the vm_clock to the next deadline. Return the current
- * value of the vm_clock in nanoseconds.
+ * Advance the vm_clock to the next deadline.
+ *
+ * Returns: The current value of the vm_clock in nanoseconds.
*/
-#define clock_step_next() qtest_clock_step_next(global_qtest)
+static inline int64_t clock_step_next(void)
+{
+ return qtest_clock_step_next(global_qtest);
+}
/**
* clock_step:
* @step: Number of nanoseconds to advance the clock by.
*
- * Advance the vm_clock by @step nanoseconds. Return the current
- * value of the vm_clock in nanoseconds.
+ * Advance the vm_clock by @step nanoseconds.
+ *
+ * Returns: The current value of the vm_clock in nanoseconds.
*/
-#define clock_step(step) qtest_clock_step(global_qtest, step)
+static inline int64_t clock_step(int64_t step)
+{
+ return qtest_clock_step(global_qtest, step);
+}
/**
* clock_set:
* @val: Nanoseconds value to advance the clock to.
*
* Advance the vm_clock to @val nanoseconds since the VM was launched.
- * Return the current value of the vm_clock in nanoseconds.
+ *
+ * Returns: The current value of the vm_clock in nanoseconds.
*/
-#define clock_set(val) qtest_clock_set(global_qtest, val)
+static inline int64_t clock_set(int64_t val)
+{
+ return qtest_clock_set(global_qtest, val);
+}
#endif
diff --git a/tests/m48t59-test.c b/tests/m48t59-test.c
index 5179681ca..4081a5fdb 100644
--- a/tests/m48t59-test.c
+++ b/tests/m48t59-test.c
@@ -35,17 +35,14 @@ static bool use_mmio;
static uint8_t cmos_read_mmio(uint8_t reg)
{
- uint8_t data;
-
- memread(base + (uint32_t)reg_base + (uint32_t)reg, &data, 1);
- return data;
+ return readb(base + (uint32_t)reg_base + (uint32_t)reg);
}
static void cmos_write_mmio(uint8_t reg, uint8_t val)
{
uint8_t data = val;
- memwrite(base + (uint32_t)reg_base + (uint32_t)reg, &data, 1);
+ writeb(base + (uint32_t)reg_base + (uint32_t)reg, data);
}
static uint8_t cmos_read_ioio(uint8_t reg)
@@ -142,7 +139,9 @@ static void cmos_get_date_time(struct tm *date)
date->tm_mday = mday;
date->tm_mon = mon - 1;
date->tm_year = base_year + year - 1900;
+#ifndef __sun__
date->tm_gmtoff = 0;
+#endif
ts = mktime(date);
}
@@ -233,6 +232,11 @@ static void fuzz_registers(void)
reg = (uint8_t)g_test_rand_int_range(0, 16);
val = (uint8_t)g_test_rand_int_range(0, 256);
+ if (reg == 7) {
+ /* watchdog setup register, may trigger system reset, skip */
+ continue;
+ }
+
cmos_write(reg, val);
cmos_read(reg);
}
diff --git a/tests/qapi-schema/comments.err b/tests/qapi-schema/comments.err
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/tests/qapi-schema/comments.err
diff --git a/tests/qapi-schema/comments.exit b/tests/qapi-schema/comments.exit
new file mode 100644
index 000000000..573541ac9
--- /dev/null
+++ b/tests/qapi-schema/comments.exit
@@ -0,0 +1 @@
+0
diff --git a/tests/qapi-schema/comments.json b/tests/qapi-schema/comments.json
new file mode 100644
index 000000000..e643f3a74
--- /dev/null
+++ b/tests/qapi-schema/comments.json
@@ -0,0 +1,4 @@
+# Unindented comment
+{ 'enum': 'Status', # Comment to the right of code
+ # Indented comment
+ 'data': [ 'good', 'bad', 'ugly' ] }
diff --git a/tests/qapi-schema/comments.out b/tests/qapi-schema/comments.out
new file mode 100644
index 000000000..e3bd90445
--- /dev/null
+++ b/tests/qapi-schema/comments.out
@@ -0,0 +1,3 @@
+[OrderedDict([('enum', 'Status'), ('data', ['good', 'bad', 'ugly'])])]
+['Status']
+[]
diff --git a/tests/qapi-schema/empty.err b/tests/qapi-schema/empty.err
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/tests/qapi-schema/empty.err
diff --git a/tests/qapi-schema/empty.exit b/tests/qapi-schema/empty.exit
new file mode 100644
index 000000000..573541ac9
--- /dev/null
+++ b/tests/qapi-schema/empty.exit
@@ -0,0 +1 @@
+0
diff --git a/tests/qapi-schema/empty.json b/tests/qapi-schema/empty.json
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/tests/qapi-schema/empty.json
diff --git a/tests/qapi-schema/empty.out b/tests/qapi-schema/empty.out
new file mode 100644
index 000000000..b7f89a45c
--- /dev/null
+++ b/tests/qapi-schema/empty.out
@@ -0,0 +1,3 @@
+[]
+[]
+[]
diff --git a/tests/qapi-schema/funny-char.err b/tests/qapi-schema/funny-char.err
new file mode 100644
index 000000000..d3dd293fa
--- /dev/null
+++ b/tests/qapi-schema/funny-char.err
@@ -0,0 +1 @@
+<stdin>:2:36: Stray ";"
diff --git a/tests/qapi-schema/funny-char.exit b/tests/qapi-schema/funny-char.exit
new file mode 100644
index 000000000..d00491fd7
--- /dev/null
+++ b/tests/qapi-schema/funny-char.exit
@@ -0,0 +1 @@
+1
diff --git a/tests/qapi-schema/funny-char.json b/tests/qapi-schema/funny-char.json
new file mode 100644
index 000000000..d4973a2cd
--- /dev/null
+++ b/tests/qapi-schema/funny-char.json
@@ -0,0 +1,2 @@
+{ 'enum': 'Status',
+ 'data': [ 'good', 'bad', 'ugly' ]; }
diff --git a/tests/qapi-schema/funny-char.out b/tests/qapi-schema/funny-char.out
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/tests/qapi-schema/funny-char.out
diff --git a/tests/qapi-schema/indented-expr.err b/tests/qapi-schema/indented-expr.err
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/tests/qapi-schema/indented-expr.err
diff --git a/tests/qapi-schema/indented-expr.exit b/tests/qapi-schema/indented-expr.exit
new file mode 100644
index 000000000..573541ac9
--- /dev/null
+++ b/tests/qapi-schema/indented-expr.exit
@@ -0,0 +1 @@
+0
diff --git a/tests/qapi-schema/indented-expr.json b/tests/qapi-schema/indented-expr.json
new file mode 100644
index 000000000..d80af6056
--- /dev/null
+++ b/tests/qapi-schema/indented-expr.json
@@ -0,0 +1,2 @@
+{ 'id' : 'eins' }
+ { 'id' : 'zwei' }
diff --git a/tests/qapi-schema/indented-expr.out b/tests/qapi-schema/indented-expr.out
new file mode 100644
index 000000000..98af89aa1
--- /dev/null
+++ b/tests/qapi-schema/indented-expr.out
@@ -0,0 +1,3 @@
+[OrderedDict([('id', 'eins')]), OrderedDict([('id', 'zwei')])]
+[]
+[]
diff --git a/tests/qapi-schema/missing-colon.err b/tests/qapi-schema/missing-colon.err
new file mode 100644
index 000000000..9f2a35515
--- /dev/null
+++ b/tests/qapi-schema/missing-colon.err
@@ -0,0 +1 @@
+<stdin>:1:10: Expected ":"
diff --git a/tests/qapi-schema/missing-colon.exit b/tests/qapi-schema/missing-colon.exit
new file mode 100644
index 000000000..d00491fd7
--- /dev/null
+++ b/tests/qapi-schema/missing-colon.exit
@@ -0,0 +1 @@
+1
diff --git a/tests/qapi-schema/missing-colon.json b/tests/qapi-schema/missing-colon.json
new file mode 100644
index 000000000..6fc27ce40
--- /dev/null
+++ b/tests/qapi-schema/missing-colon.json
@@ -0,0 +1,2 @@
+{ 'enum' 'Status',
+ 'data': [ 'good', 'bad', 'ugly' ] }
diff --git a/tests/qapi-schema/missing-colon.out b/tests/qapi-schema/missing-colon.out
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/tests/qapi-schema/missing-colon.out
diff --git a/tests/qapi-schema/missing-comma-list.err b/tests/qapi-schema/missing-comma-list.err
new file mode 100644
index 000000000..4fe070019
--- /dev/null
+++ b/tests/qapi-schema/missing-comma-list.err
@@ -0,0 +1 @@
+<stdin>:2:20: Expected "," or "]"
diff --git a/tests/qapi-schema/missing-comma-list.exit b/tests/qapi-schema/missing-comma-list.exit
new file mode 100644
index 000000000..d00491fd7
--- /dev/null
+++ b/tests/qapi-schema/missing-comma-list.exit
@@ -0,0 +1 @@
+1
diff --git a/tests/qapi-schema/missing-comma-list.json b/tests/qapi-schema/missing-comma-list.json
new file mode 100644
index 000000000..1af39b293
--- /dev/null
+++ b/tests/qapi-schema/missing-comma-list.json
@@ -0,0 +1,2 @@
+{ 'enum': 'Status',
+ 'data': [ 'good' 'bad', 'ugly' ] }
diff --git a/tests/qapi-schema/missing-comma-list.out b/tests/qapi-schema/missing-comma-list.out
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/tests/qapi-schema/missing-comma-list.out
diff --git a/tests/qapi-schema/missing-comma-object.err b/tests/qapi-schema/missing-comma-object.err
new file mode 100644
index 000000000..b0121b5f3
--- /dev/null
+++ b/tests/qapi-schema/missing-comma-object.err
@@ -0,0 +1 @@
+<stdin>:2:3: Expected "," or "}"
diff --git a/tests/qapi-schema/missing-comma-object.exit b/tests/qapi-schema/missing-comma-object.exit
new file mode 100644
index 000000000..d00491fd7
--- /dev/null
+++ b/tests/qapi-schema/missing-comma-object.exit
@@ -0,0 +1 @@
+1
diff --git a/tests/qapi-schema/missing-comma-object.json b/tests/qapi-schema/missing-comma-object.json
new file mode 100644
index 000000000..50f51786e
--- /dev/null
+++ b/tests/qapi-schema/missing-comma-object.json
@@ -0,0 +1,2 @@
+{ 'enum': 'Status'
+ 'data': [ 'good', 'bad', 'ugly' ] }
diff --git a/tests/qapi-schema/missing-comma-object.out b/tests/qapi-schema/missing-comma-object.out
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/tests/qapi-schema/missing-comma-object.out
diff --git a/tests/qapi-schema/non-objects.err b/tests/qapi-schema/non-objects.err
new file mode 100644
index 000000000..a6c2dc26a
--- /dev/null
+++ b/tests/qapi-schema/non-objects.err
@@ -0,0 +1 @@
+<stdin>:1:1: Expected "{"
diff --git a/tests/qapi-schema/non-objects.exit b/tests/qapi-schema/non-objects.exit
new file mode 100644
index 000000000..d00491fd7
--- /dev/null
+++ b/tests/qapi-schema/non-objects.exit
@@ -0,0 +1 @@
+1
diff --git a/tests/qapi-schema/non-objects.json b/tests/qapi-schema/non-objects.json
new file mode 100644
index 000000000..f3fa851d4
--- /dev/null
+++ b/tests/qapi-schema/non-objects.json
@@ -0,0 +1,2 @@
+'string'
+[ ]
diff --git a/tests/qapi-schema/non-objects.out b/tests/qapi-schema/non-objects.out
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/tests/qapi-schema/non-objects.out
diff --git a/tests/qapi-schema/qapi-schema-test.err b/tests/qapi-schema/qapi-schema-test.err
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/tests/qapi-schema/qapi-schema-test.err
diff --git a/tests/qapi-schema/qapi-schema-test.exit b/tests/qapi-schema/qapi-schema-test.exit
new file mode 100644
index 000000000..573541ac9
--- /dev/null
+++ b/tests/qapi-schema/qapi-schema-test.exit
@@ -0,0 +1 @@
+0
diff --git a/tests/qapi-schema/qapi-schema-test.json b/tests/qapi-schema/qapi-schema-test.json
new file mode 100644
index 000000000..4434fa396
--- /dev/null
+++ b/tests/qapi-schema/qapi-schema-test.json
@@ -0,0 +1,53 @@
+# *-*- Mode: Python -*-*
+
+# for testing enums
+{ 'enum': 'EnumOne',
+ 'data': [ 'value1', 'value2', 'value3' ] }
+{ 'type': 'NestedEnumsOne',
+ 'data': { 'enum1': 'EnumOne', '*enum2': 'EnumOne', 'enum3': 'EnumOne', '*enum4': 'EnumOne' } }
+
+# for testing nested structs
+{ 'type': 'UserDefOne',
+ 'data': { 'integer': 'int', 'string': 'str', '*enum1': 'EnumOne' } }
+
+{ 'type': 'UserDefTwo',
+ 'data': { 'string': 'str',
+ 'dict': { 'string': 'str',
+ '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' } } } }
+
+# for testing unions
+{ 'type': 'UserDefA',
+ 'data': { 'boolean': 'bool' } }
+
+{ 'type': 'UserDefB',
+ 'data': { 'integer': 'int' } }
+
+{ 'union': 'UserDefUnion',
+ 'data': { 'a' : 'UserDefA', 'b' : 'UserDefB' } }
+
+# for testing native lists
+{ 'union': 'UserDefNativeListUnion',
+ 'data': { 'integer': ['int'],
+ 's8': ['int8'],
+ 's16': ['int16'],
+ 's32': ['int32'],
+ 's64': ['int64'],
+ 'u8': ['uint8'],
+ 'u16': ['uint16'],
+ 'u32': ['uint32'],
+ 'u64': ['uint64'],
+ 'number': ['number'],
+ 'boolean': ['bool'],
+ 'string': ['str'] } }
+
+# testing commands
+{ 'command': 'user_def_cmd', 'data': {} }
+{ 'command': 'user_def_cmd1', 'data': {'ud1a': 'UserDefOne'} }
+{ 'command': 'user_def_cmd2', 'data': {'ud1a': 'UserDefOne', 'ud1b': 'UserDefOne'}, 'returns': 'UserDefTwo' }
diff --git a/tests/qapi-schema/qapi-schema-test.out b/tests/qapi-schema/qapi-schema-test.out
new file mode 100644
index 000000000..fb0034489
--- /dev/null
+++ b/tests/qapi-schema/qapi-schema-test.out
@@ -0,0 +1,19 @@
+[OrderedDict([('enum', 'EnumOne'), ('data', ['value1', 'value2', 'value3'])]),
+ OrderedDict([('type', 'NestedEnumsOne'), ('data', OrderedDict([('enum1', 'EnumOne'), ('*enum2', 'EnumOne'), ('enum3', 'EnumOne'), ('*enum4', 'EnumOne')]))]),
+ OrderedDict([('type', 'UserDefOne'), ('data', OrderedDict([('integer', 'int'), ('string', 'str'), ('*enum1', 'EnumOne')]))]),
+ OrderedDict([('type', 'UserDefTwo'), ('data', OrderedDict([('string', 'str'), ('dict', OrderedDict([('string', 'str'), ('dict', OrderedDict([('userdef', 'UserDefOne'), ('string', 'str')])), ('*dict2', OrderedDict([('userdef', 'UserDefOne'), ('string', 'str')]))]))]))]),
+ OrderedDict([('type', 'UserDefNested'), ('data', OrderedDict([('string0', 'str'), ('dict1', OrderedDict([('string1', 'str'), ('dict2', OrderedDict([('userdef1', 'UserDefOne'), ('string2', 'str')])), ('*dict3', OrderedDict([('userdef2', 'UserDefOne'), ('string3', 'str')]))]))]))]),
+ OrderedDict([('type', 'UserDefA'), ('data', OrderedDict([('boolean', 'bool')]))]),
+ OrderedDict([('type', 'UserDefB'), ('data', OrderedDict([('integer', 'int')]))]),
+ OrderedDict([('union', 'UserDefUnion'), ('data', OrderedDict([('a', 'UserDefA'), ('b', 'UserDefB')]))]),
+ OrderedDict([('union', 'UserDefNativeListUnion'), ('data', OrderedDict([('integer', ['int']), ('s8', ['int8']), ('s16', ['int16']), ('s32', ['int32']), ('s64', ['int64']), ('u8', ['uint8']), ('u16', ['uint16']), ('u32', ['uint32']), ('u64', ['uint64']), ('number', ['number']), ('boolean', ['bool']), ('string', ['str'])]))]),
+ OrderedDict([('command', 'user_def_cmd'), ('data', OrderedDict())]),
+ OrderedDict([('command', 'user_def_cmd1'), ('data', OrderedDict([('ud1a', 'UserDefOne')]))]),
+ OrderedDict([('command', 'user_def_cmd2'), ('data', OrderedDict([('ud1a', 'UserDefOne'), ('ud1b', 'UserDefOne')])), ('returns', 'UserDefTwo')])]
+['EnumOne', 'UserDefUnionKind', 'UserDefNativeListUnionKind']
+[OrderedDict([('type', 'NestedEnumsOne'), ('data', OrderedDict([('enum1', 'EnumOne'), ('*enum2', 'EnumOne'), ('enum3', 'EnumOne'), ('*enum4', 'EnumOne')]))]),
+ OrderedDict([('type', 'UserDefOne'), ('data', OrderedDict([('integer', 'int'), ('string', 'str'), ('*enum1', 'EnumOne')]))]),
+ OrderedDict([('type', 'UserDefTwo'), ('data', OrderedDict([('string', 'str'), ('dict', OrderedDict([('string', 'str'), ('dict', OrderedDict([('userdef', 'UserDefOne'), ('string', 'str')])), ('*dict2', OrderedDict([('userdef', 'UserDefOne'), ('string', 'str')]))]))]))]),
+ OrderedDict([('type', 'UserDefNested'), ('data', OrderedDict([('string0', 'str'), ('dict1', OrderedDict([('string1', 'str'), ('dict2', OrderedDict([('userdef1', 'UserDefOne'), ('string2', 'str')])), ('*dict3', OrderedDict([('userdef2', 'UserDefOne'), ('string3', 'str')]))]))]))]),
+ OrderedDict([('type', 'UserDefA'), ('data', OrderedDict([('boolean', 'bool')]))]),
+ OrderedDict([('type', 'UserDefB'), ('data', OrderedDict([('integer', 'int')]))])]
diff --git a/tests/qapi-schema/quoted-structural-chars.err b/tests/qapi-schema/quoted-structural-chars.err
new file mode 100644
index 000000000..a6c2dc26a
--- /dev/null
+++ b/tests/qapi-schema/quoted-structural-chars.err
@@ -0,0 +1 @@
+<stdin>:1:1: Expected "{"
diff --git a/tests/qapi-schema/quoted-structural-chars.exit b/tests/qapi-schema/quoted-structural-chars.exit
new file mode 100644
index 000000000..d00491fd7
--- /dev/null
+++ b/tests/qapi-schema/quoted-structural-chars.exit
@@ -0,0 +1 @@
+1
diff --git a/tests/qapi-schema/quoted-structural-chars.json b/tests/qapi-schema/quoted-structural-chars.json
new file mode 100644
index 000000000..9fe657ae9
--- /dev/null
+++ b/tests/qapi-schema/quoted-structural-chars.json
@@ -0,0 +1 @@
+'{' 'key1' ':' 'value1' ',' 'key2' ':' '[' ']' '}'
diff --git a/tests/qapi-schema/quoted-structural-chars.out b/tests/qapi-schema/quoted-structural-chars.out
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/tests/qapi-schema/quoted-structural-chars.out
diff --git a/tests/qapi-schema/test-qapi.py b/tests/qapi-schema/test-qapi.py
new file mode 100644
index 000000000..b3d1e1dbc
--- /dev/null
+++ b/tests/qapi-schema/test-qapi.py
@@ -0,0 +1,27 @@
+#
+# QAPI parser test harness
+#
+# Copyright (c) 2013 Red Hat Inc.
+#
+# Authors:
+# Markus Armbruster <armbru@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.
+#
+
+from qapi import *
+from pprint import pprint
+import sys
+
+try:
+ exprs = parse_schema(sys.stdin)
+except SystemExit:
+ raise
+except:
+ print >>sys.stderr, "Crashed:", sys.exc_info()[0]
+ exit(1)
+
+pprint(exprs)
+pprint(enum_types)
+pprint(struct_types)
diff --git a/tests/qapi-schema/trailing-comma-list.err b/tests/qapi-schema/trailing-comma-list.err
new file mode 100644
index 000000000..ff839a34e
--- /dev/null
+++ b/tests/qapi-schema/trailing-comma-list.err
@@ -0,0 +1 @@
+<stdin>:2:36: Expected "{", "[" or string
diff --git a/tests/qapi-schema/trailing-comma-list.exit b/tests/qapi-schema/trailing-comma-list.exit
new file mode 100644
index 000000000..d00491fd7
--- /dev/null
+++ b/tests/qapi-schema/trailing-comma-list.exit
@@ -0,0 +1 @@
+1
diff --git a/tests/qapi-schema/trailing-comma-list.json b/tests/qapi-schema/trailing-comma-list.json
new file mode 100644
index 000000000..9b0c8bd70
--- /dev/null
+++ b/tests/qapi-schema/trailing-comma-list.json
@@ -0,0 +1,2 @@
+{ 'enum': 'Status',
+ 'data': [ 'good', 'bad', 'ugly', ] }
diff --git a/tests/qapi-schema/trailing-comma-list.out b/tests/qapi-schema/trailing-comma-list.out
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/tests/qapi-schema/trailing-comma-list.out
diff --git a/tests/qapi-schema/trailing-comma-object.err b/tests/qapi-schema/trailing-comma-object.err
new file mode 100644
index 000000000..f5409627d
--- /dev/null
+++ b/tests/qapi-schema/trailing-comma-object.err
@@ -0,0 +1 @@
+<stdin>:2:38: Expected string
diff --git a/tests/qapi-schema/trailing-comma-object.exit b/tests/qapi-schema/trailing-comma-object.exit
new file mode 100644
index 000000000..d00491fd7
--- /dev/null
+++ b/tests/qapi-schema/trailing-comma-object.exit
@@ -0,0 +1 @@
+1
diff --git a/tests/qapi-schema/trailing-comma-object.json b/tests/qapi-schema/trailing-comma-object.json
new file mode 100644
index 000000000..bbaea550c
--- /dev/null
+++ b/tests/qapi-schema/trailing-comma-object.json
@@ -0,0 +1,2 @@
+{ 'enum': 'Status',
+ 'data': [ 'good', 'bad', 'ugly' ], }
diff --git a/tests/qapi-schema/trailing-comma-object.out b/tests/qapi-schema/trailing-comma-object.out
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/tests/qapi-schema/trailing-comma-object.out
diff --git a/tests/qapi-schema/unclosed-list.err b/tests/qapi-schema/unclosed-list.err
new file mode 100644
index 000000000..0e837a7fa
--- /dev/null
+++ b/tests/qapi-schema/unclosed-list.err
@@ -0,0 +1 @@
+<stdin>:1:20: Expected "," or "]"
diff --git a/tests/qapi-schema/unclosed-list.exit b/tests/qapi-schema/unclosed-list.exit
new file mode 100644
index 000000000..d00491fd7
--- /dev/null
+++ b/tests/qapi-schema/unclosed-list.exit
@@ -0,0 +1 @@
+1
diff --git a/tests/qapi-schema/unclosed-list.json b/tests/qapi-schema/unclosed-list.json
new file mode 100644
index 000000000..e3e956698
--- /dev/null
+++ b/tests/qapi-schema/unclosed-list.json
@@ -0,0 +1 @@
+{ 'key': [ 'value' }
diff --git a/tests/qapi-schema/unclosed-list.out b/tests/qapi-schema/unclosed-list.out
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/tests/qapi-schema/unclosed-list.out
diff --git a/tests/qapi-schema/unclosed-object.err b/tests/qapi-schema/unclosed-object.err
new file mode 100644
index 000000000..e6dc9501d
--- /dev/null
+++ b/tests/qapi-schema/unclosed-object.err
@@ -0,0 +1 @@
+<stdin>:1:21: Expected "," or "}"
diff --git a/tests/qapi-schema/unclosed-object.exit b/tests/qapi-schema/unclosed-object.exit
new file mode 100644
index 000000000..d00491fd7
--- /dev/null
+++ b/tests/qapi-schema/unclosed-object.exit
@@ -0,0 +1 @@
+1
diff --git a/tests/qapi-schema/unclosed-object.json b/tests/qapi-schema/unclosed-object.json
new file mode 100644
index 000000000..8ac069dce
--- /dev/null
+++ b/tests/qapi-schema/unclosed-object.json
@@ -0,0 +1 @@
+{ 'key': [ 'value' ]
diff --git a/tests/qapi-schema/unclosed-object.out b/tests/qapi-schema/unclosed-object.out
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/tests/qapi-schema/unclosed-object.out
diff --git a/tests/qapi-schema/unclosed-string.err b/tests/qapi-schema/unclosed-string.err
new file mode 100644
index 000000000..948d88339
--- /dev/null
+++ b/tests/qapi-schema/unclosed-string.err
@@ -0,0 +1 @@
+<stdin>:1:11: Missing terminating "'"
diff --git a/tests/qapi-schema/unclosed-string.exit b/tests/qapi-schema/unclosed-string.exit
new file mode 100644
index 000000000..d00491fd7
--- /dev/null
+++ b/tests/qapi-schema/unclosed-string.exit
@@ -0,0 +1 @@
+1
diff --git a/tests/qapi-schema/unclosed-string.json b/tests/qapi-schema/unclosed-string.json
new file mode 100644
index 000000000..8c16b6b6f
--- /dev/null
+++ b/tests/qapi-schema/unclosed-string.json
@@ -0,0 +1,2 @@
+{ 'text': 'lorem ips
+}
diff --git a/tests/qapi-schema/unclosed-string.out b/tests/qapi-schema/unclosed-string.out
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/tests/qapi-schema/unclosed-string.out
diff --git a/tests/qemu-iotests/002 b/tests/qemu-iotests/002
index bebed84fd..51d0a8f4a 100755
--- a/tests/qemu-iotests/002
+++ b/tests/qemu-iotests/002
@@ -61,10 +61,23 @@ $QEMU_IO -c "read -pP 0xa 0 $size" $TEST_IMG | _filter_qemu_io
echo
echo "unaligned pwrite"
$QEMU_IO -c 'write -pP 0xab 66 42' $TEST_IMG | _filter_qemu_io
+$QEMU_IO -c 'write -pP 0xac 512 288' $TEST_IMG | _filter_qemu_io
+$QEMU_IO -c 'write -pP 0xad 800 224' $TEST_IMG | _filter_qemu_io
+$QEMU_IO -c 'write -pP 0xae 66000 128k' $TEST_IMG | _filter_qemu_io
+$QEMU_IO -c 'write -pP 0xaf 256k 42' $TEST_IMG | _filter_qemu_io
echo
echo "verify pattern"
+$QEMU_IO -c 'read -pP 0xa 0 66' $TEST_IMG | _filter_qemu_io
$QEMU_IO -c 'read -pP 0xab 66 42' $TEST_IMG | _filter_qemu_io
+$QEMU_IO -c 'read -pP 0xa 108 404' $TEST_IMG | _filter_qemu_io
+$QEMU_IO -c 'read -pP 0xac 512 288' $TEST_IMG | _filter_qemu_io
+$QEMU_IO -c 'read -pP 0xad 800 224' $TEST_IMG | _filter_qemu_io
+$QEMU_IO -c 'read -pP 0xa 1k 64976' $TEST_IMG | _filter_qemu_io
+$QEMU_IO -c 'read -pP 0xae 66000 128k' $TEST_IMG | _filter_qemu_io
+$QEMU_IO -c 'read -pP 0xa 197072 65072' $TEST_IMG | _filter_qemu_io
+$QEMU_IO -c 'read -pP 0xaf 256k 42' $TEST_IMG | _filter_qemu_io
+$QEMU_IO -c 'read -pP 0xa 262186 470' $TEST_IMG | _filter_qemu_io
# success, all done
echo "*** done"
diff --git a/tests/qemu-iotests/002.out b/tests/qemu-iotests/002.out
index 75f5876e8..cd6aa0f9f 100644
--- a/tests/qemu-iotests/002.out
+++ b/tests/qemu-iotests/002.out
@@ -16,8 +16,34 @@ read 134217728/134217728 bytes at offset 0
unaligned pwrite
wrote 42/42 bytes at offset 66
42 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+wrote 288/288 bytes at offset 512
+288 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+wrote 224/224 bytes at offset 800
+224 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+wrote 131072/131072 bytes at offset 66000
+128 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+wrote 42/42 bytes at offset 262144
+42 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
verify pattern
+read 66/66 bytes at offset 0
+66 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
read 42/42 bytes at offset 66
42 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+read 404/404 bytes at offset 108
+404 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+read 288/288 bytes at offset 512
+288 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+read 224/224 bytes at offset 800
+224 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+read 64976/64976 bytes at offset 1024
+63.453 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+read 131072/131072 bytes at offset 66000
+128 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+read 65072/65072 bytes at offset 197072
+63.547 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+read 42/42 bytes at offset 262144
+42 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+read 470/470 bytes at offset 262186
+470 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
*** done
diff --git a/tests/qemu-iotests/007 b/tests/qemu-iotests/007
index 0139264c4..c454f2c8e 100755
--- a/tests/qemu-iotests/007
+++ b/tests/qemu-iotests/007
@@ -50,10 +50,9 @@ _make_test_img 1M
for i in `seq 1 10`; do
echo "savevm $i"
- # XXX(hch): adding -nographic would be good, but hangs the test
- $QEMU -hda $TEST_IMG -monitor stdio >/dev/null 2>&1 <<EOF
-savevm test-$i
-quit
+ $QEMU -nographic -hda $TEST_IMG -serial none -monitor stdio >/dev/null 2>&1 <<EOF
+savevm test-$i
+quit
EOF
done
diff --git a/tests/qemu-iotests/017 b/tests/qemu-iotests/017
index 66951eb1a..45f2c0b05 100755
--- a/tests/qemu-iotests/017
+++ b/tests/qemu-iotests/017
@@ -46,6 +46,8 @@ _supported_os Linux
TEST_OFFSETS="0 4294967296"
+TEST_IMG_SAVE=$TEST_IMG
+TEST_IMG=$TEST_IMG.base
_make_test_img 6G
echo "Filling base image"
@@ -63,7 +65,7 @@ _check_test_img
echo "Creating test image with backing file"
echo
-mv $TEST_IMG $TEST_IMG.base
+TEST_IMG=$TEST_IMG_SAVE
_make_test_img -b $TEST_IMG.base 6G
echo "Filling test image"
diff --git a/tests/qemu-iotests/017.out b/tests/qemu-iotests/017.out
index a861e5833..df34ee78c 100644
--- a/tests/qemu-iotests/017.out
+++ b/tests/qemu-iotests/017.out
@@ -1,5 +1,5 @@
QA output created by 017
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=6442450944
+Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=6442450944
Filling base image
=== IO: pattern 0
diff --git a/tests/qemu-iotests/018 b/tests/qemu-iotests/018
index bd2db7871..453ce61e7 100755
--- a/tests/qemu-iotests/018
+++ b/tests/qemu-iotests/018
@@ -46,6 +46,8 @@ _supported_os Linux
TEST_OFFSETS="0 4294967296"
+TEST_IMG_SAVE=$TEST_IMG
+TEST_IMG=$TEST_IMG.base
_make_test_img 6G
echo "Filling base image"
@@ -63,7 +65,7 @@ _check_test_img
echo "Creating test image with backing file"
echo
-mv $TEST_IMG $TEST_IMG.base
+TEST_IMG=$TEST_IMG_SAVE
_make_test_img -b $TEST_IMG.base 6G
echo "Filling test image"
diff --git a/tests/qemu-iotests/018.out b/tests/qemu-iotests/018.out
index 6bbd815ce..3ddb8d8f6 100644
--- a/tests/qemu-iotests/018.out
+++ b/tests/qemu-iotests/018.out
@@ -1,5 +1,5 @@
QA output created by 018
-Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=6442450944
+Formatting 'TEST_DIR/t.IMGFMT.base', fmt=IMGFMT size=6442450944
Filling base image
=== IO: pattern 0
diff --git a/tests/qemu-iotests/026 b/tests/qemu-iotests/026
index 1602ccd2a..107a3ff2f 100755
--- a/tests/qemu-iotests/026
+++ b/tests/qemu-iotests/026
@@ -102,7 +102,7 @@ if [ "$event" == "l2_load" ]; then
$QEMU_IO -c "read $vmstate 0 128k " $BLKDBG_TEST_IMG | _filter_qemu_io
fi
-$QEMU_IMG check $TEST_IMG 2>&1 | grep -v "refcount=1 reference=0"
+_check_test_img 2>&1 | grep -v "refcount=1 reference=0"
done
done
@@ -147,7 +147,7 @@ echo
echo "Event: $event; errno: $errno; imm: $imm; once: $once; write $vmstate"
$QEMU_IO -c "write $vmstate 0 64M" $BLKDBG_TEST_IMG | _filter_qemu_io
-$QEMU_IMG check $TEST_IMG 2>&1 | grep -v "refcount=1 reference=0"
+_check_test_img 2>&1 | grep -v "refcount=1 reference=0"
done
done
@@ -186,7 +186,7 @@ echo
echo "Event: $event; errno: $errno; imm: $imm; once: $once"
$QEMU_IO -c "write -b 0 64k" $BLKDBG_TEST_IMG | _filter_qemu_io
-$QEMU_IMG check $TEST_IMG 2>&1 | grep -v "refcount=1 reference=0"
+_check_test_img 2>&1 | grep -v "refcount=1 reference=0"
done
done
diff --git a/tests/qemu-iotests/030 b/tests/qemu-iotests/030
index dd4ef1199..ae56f3b80 100755
--- a/tests/qemu-iotests/030
+++ b/tests/qemu-iotests/030
@@ -22,49 +22,16 @@ import time
import os
import iotests
from iotests import qemu_img, qemu_io
-import struct
backing_img = os.path.join(iotests.test_dir, 'backing.img')
mid_img = os.path.join(iotests.test_dir, 'mid.img')
test_img = os.path.join(iotests.test_dir, 'test.img')
-class ImageStreamingTestCase(iotests.QMPTestCase):
- '''Abstract base class for image streaming test cases'''
-
- def assert_no_active_streams(self):
- result = self.vm.qmp('query-block-jobs')
- self.assert_qmp(result, 'return', [])
-
- def cancel_and_wait(self, drive='drive0'):
- '''Cancel a block job and wait for it to finish'''
- result = self.vm.qmp('block-job-cancel', device=drive)
- self.assert_qmp(result, 'return', {})
-
- cancelled = False
- while not cancelled:
- for event in self.vm.get_qmp_events(wait=True):
- if event['event'] == 'BLOCK_JOB_CANCELLED':
- self.assert_qmp(event, 'data/type', 'stream')
- self.assert_qmp(event, 'data/device', drive)
- cancelled = True
-
- self.assert_no_active_streams()
-
- def create_image(self, name, size):
- file = open(name, 'w')
- i = 0
- while i < size:
- sector = struct.pack('>l504xl', i / 512, i / 512)
- file.write(sector)
- i = i + 512
- file.close()
-
-
-class TestSingleDrive(ImageStreamingTestCase):
+class TestSingleDrive(iotests.QMPTestCase):
image_len = 1 * 1024 * 1024 # MB
def setUp(self):
- self.create_image(backing_img, TestSingleDrive.image_len)
+ iotests.create_image(backing_img, TestSingleDrive.image_len)
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)
self.vm = iotests.VM().add_drive(test_img)
@@ -77,7 +44,7 @@ class TestSingleDrive(ImageStreamingTestCase):
os.remove(backing_img)
def test_stream(self):
- self.assert_no_active_streams()
+ self.assert_no_active_block_jobs()
result = self.vm.qmp('block-stream', device='drive0')
self.assert_qmp(result, 'return', {})
@@ -92,7 +59,7 @@ class TestSingleDrive(ImageStreamingTestCase):
self.assert_qmp(event, 'data/len', self.image_len)
completed = True
- self.assert_no_active_streams()
+ self.assert_no_active_block_jobs()
self.vm.shutdown()
self.assertEqual(qemu_io('-c', 'map', backing_img),
@@ -100,7 +67,7 @@ class TestSingleDrive(ImageStreamingTestCase):
'image file map does not match backing file after streaming')
def test_stream_pause(self):
- self.assert_no_active_streams()
+ self.assert_no_active_block_jobs()
result = self.vm.qmp('block-stream', device='drive0')
self.assert_qmp(result, 'return', {})
@@ -129,7 +96,7 @@ class TestSingleDrive(ImageStreamingTestCase):
self.assert_qmp(event, 'data/len', self.image_len)
completed = True
- self.assert_no_active_streams()
+ self.assert_no_active_block_jobs()
self.vm.shutdown()
self.assertEqual(qemu_io('-c', 'map', backing_img),
@@ -137,7 +104,7 @@ class TestSingleDrive(ImageStreamingTestCase):
'image file map does not match backing file after streaming')
def test_stream_partial(self):
- self.assert_no_active_streams()
+ self.assert_no_active_block_jobs()
result = self.vm.qmp('block-stream', device='drive0', base=mid_img)
self.assert_qmp(result, 'return', {})
@@ -152,7 +119,7 @@ class TestSingleDrive(ImageStreamingTestCase):
self.assert_qmp(event, 'data/len', self.image_len)
completed = True
- self.assert_no_active_streams()
+ self.assert_no_active_block_jobs()
self.vm.shutdown()
self.assertEqual(qemu_io('-c', 'map', mid_img),
@@ -164,12 +131,12 @@ class TestSingleDrive(ImageStreamingTestCase):
self.assert_qmp(result, 'error/class', 'DeviceNotFound')
-class TestSmallerBackingFile(ImageStreamingTestCase):
+class TestSmallerBackingFile(iotests.QMPTestCase):
backing_len = 1 * 1024 * 1024 # MB
image_len = 2 * backing_len
def setUp(self):
- self.create_image(backing_img, self.backing_len)
+ iotests.create_image(backing_img, self.backing_len)
qemu_img('create', '-f', iotests.imgfmt, '-o', 'backing_file=%s' % backing_img, test_img, str(self.image_len))
self.vm = iotests.VM().add_drive(test_img)
self.vm.launch()
@@ -177,7 +144,7 @@ class TestSmallerBackingFile(ImageStreamingTestCase):
# If this hangs, then you are missing a fix to complete streaming when the
# end of the backing file is reached.
def test_stream(self):
- self.assert_no_active_streams()
+ self.assert_no_active_block_jobs()
result = self.vm.qmp('block-stream', device='drive0')
self.assert_qmp(result, 'return', {})
@@ -192,10 +159,10 @@ class TestSmallerBackingFile(ImageStreamingTestCase):
self.assert_qmp(event, 'data/len', self.image_len)
completed = True
- self.assert_no_active_streams()
+ self.assert_no_active_block_jobs()
self.vm.shutdown()
-class TestErrors(ImageStreamingTestCase):
+class TestErrors(iotests.QMPTestCase):
image_len = 2 * 1024 * 1024 # MB
# this should match STREAM_BUFFER_SIZE/512 in block/stream.c
@@ -227,7 +194,7 @@ new_state = "1"
class TestEIO(TestErrors):
def setUp(self):
self.blkdebug_file = backing_img + ".blkdebug"
- self.create_image(backing_img, TestErrors.image_len)
+ iotests.create_image(backing_img, TestErrors.image_len)
self.create_blkdebug_file(self.blkdebug_file, "read_aio", 5)
qemu_img('create', '-f', iotests.imgfmt,
'-o', 'backing_file=blkdebug:%s:%s,backing_fmt=raw'
@@ -243,7 +210,7 @@ class TestEIO(TestErrors):
os.remove(self.blkdebug_file)
def test_report(self):
- self.assert_no_active_streams()
+ self.assert_no_active_block_jobs()
result = self.vm.qmp('block-stream', device='drive0')
self.assert_qmp(result, 'return', {})
@@ -265,11 +232,11 @@ class TestEIO(TestErrors):
self.assert_qmp(event, 'data/len', self.image_len)
completed = True
- self.assert_no_active_streams()
+ self.assert_no_active_block_jobs()
self.vm.shutdown()
def test_ignore(self):
- self.assert_no_active_streams()
+ self.assert_no_active_block_jobs()
result = self.vm.qmp('block-stream', device='drive0', on_error='ignore')
self.assert_qmp(result, 'return', {})
@@ -293,11 +260,11 @@ class TestEIO(TestErrors):
self.assert_qmp(event, 'data/len', self.image_len)
completed = True
- self.assert_no_active_streams()
+ self.assert_no_active_block_jobs()
self.vm.shutdown()
def test_stop(self):
- self.assert_no_active_streams()
+ self.assert_no_active_block_jobs()
result = self.vm.qmp('block-stream', device='drive0', on_error='stop')
self.assert_qmp(result, 'return', {})
@@ -331,11 +298,11 @@ class TestEIO(TestErrors):
self.assert_qmp(event, 'data/len', self.image_len)
completed = True
- self.assert_no_active_streams()
+ self.assert_no_active_block_jobs()
self.vm.shutdown()
def test_enospc(self):
- self.assert_no_active_streams()
+ self.assert_no_active_block_jobs()
result = self.vm.qmp('block-stream', device='drive0', on_error='enospc')
self.assert_qmp(result, 'return', {})
@@ -357,13 +324,13 @@ class TestEIO(TestErrors):
self.assert_qmp(event, 'data/len', self.image_len)
completed = True
- self.assert_no_active_streams()
+ self.assert_no_active_block_jobs()
self.vm.shutdown()
class TestENOSPC(TestErrors):
def setUp(self):
self.blkdebug_file = backing_img + ".blkdebug"
- self.create_image(backing_img, TestErrors.image_len)
+ iotests.create_image(backing_img, TestErrors.image_len)
self.create_blkdebug_file(self.blkdebug_file, "read_aio", 28)
qemu_img('create', '-f', iotests.imgfmt,
'-o', 'backing_file=blkdebug:%s:%s,backing_fmt=raw'
@@ -379,7 +346,7 @@ class TestENOSPC(TestErrors):
os.remove(self.blkdebug_file)
def test_enospc(self):
- self.assert_no_active_streams()
+ self.assert_no_active_block_jobs()
result = self.vm.qmp('block-stream', device='drive0', on_error='enospc')
self.assert_qmp(result, 'return', {})
@@ -413,10 +380,10 @@ class TestENOSPC(TestErrors):
self.assert_qmp(event, 'data/len', self.image_len)
completed = True
- self.assert_no_active_streams()
+ self.assert_no_active_block_jobs()
self.vm.shutdown()
-class TestStreamStop(ImageStreamingTestCase):
+class TestStreamStop(iotests.QMPTestCase):
image_len = 8 * 1024 * 1024 * 1024 # GB
def setUp(self):
@@ -431,7 +398,7 @@ class TestStreamStop(ImageStreamingTestCase):
os.remove(backing_img)
def test_stream_stop(self):
- self.assert_no_active_streams()
+ self.assert_no_active_block_jobs()
result = self.vm.qmp('block-stream', device='drive0')
self.assert_qmp(result, 'return', {})
@@ -442,7 +409,7 @@ class TestStreamStop(ImageStreamingTestCase):
self.cancel_and_wait()
-class TestSetSpeed(ImageStreamingTestCase):
+class TestSetSpeed(iotests.QMPTestCase):
image_len = 80 * 1024 * 1024 # MB
def setUp(self):
@@ -459,7 +426,7 @@ class TestSetSpeed(ImageStreamingTestCase):
# This is a short performance test which is not run by default.
# Invoke "IMGFMT=qed ./030 TestSetSpeed.perf_test_throughput"
def perf_test_throughput(self):
- self.assert_no_active_streams()
+ self.assert_no_active_block_jobs()
result = self.vm.qmp('block-stream', device='drive0')
self.assert_qmp(result, 'return', {})
@@ -477,10 +444,10 @@ class TestSetSpeed(ImageStreamingTestCase):
self.assert_qmp(event, 'data/len', self.image_len)
completed = True
- self.assert_no_active_streams()
+ self.assert_no_active_block_jobs()
def test_set_speed(self):
- self.assert_no_active_streams()
+ self.assert_no_active_block_jobs()
result = self.vm.qmp('block-stream', device='drive0')
self.assert_qmp(result, 'return', {})
@@ -511,12 +478,12 @@ class TestSetSpeed(ImageStreamingTestCase):
self.cancel_and_wait()
def test_set_speed_invalid(self):
- self.assert_no_active_streams()
+ self.assert_no_active_block_jobs()
result = self.vm.qmp('block-stream', device='drive0', speed=-1)
self.assert_qmp(result, 'error/class', 'GenericError')
- self.assert_no_active_streams()
+ self.assert_no_active_block_jobs()
result = self.vm.qmp('block-stream', device='drive0')
self.assert_qmp(result, 'return', {})
diff --git a/tests/qemu-iotests/036 b/tests/qemu-iotests/036
index 329533e9e..4dbfc5724 100755
--- a/tests/qemu-iotests/036
+++ b/tests/qemu-iotests/036
@@ -59,7 +59,8 @@ _make_test_img 64M
echo
echo === Repair image ===
echo
-$QEMU_IMG check -r all $TEST_IMG
+_check_test_img -r all
+
./qcow2.py $TEST_IMG dump-header
# success, all done
diff --git a/tests/qemu-iotests/038.out b/tests/qemu-iotests/038.out
index acc762926..9cd0cd877 100644
--- a/tests/qemu-iotests/038.out
+++ b/tests/qemu-iotests/038.out
@@ -517,9 +517,7 @@ qemu-io> wrote 65536/65536 bytes at offset 16711680
qemu-io> Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=6442450944 backing_file='TEST_DIR/t.IMGFMT.base'
== Some concurrent requests touching the same cluster ==
-qemu-io> qemu-io> qemu-io> qemu-io> qemu-io> qemu-io> qemu-io> qemu-io> qemu-io> qemu-io> qemu-io> qemu-io> qemu-io> qemu-io> qemu-io> qemu-io> qemu-io> qemu-io> qemu-io> qemu-io> qemu-io> qemu-io> qemu-io> qemu-io> qemu-io> qemu-io> qemu-io> qemu-io> qemu-io> qemu-io> qemu-io> qemu-io> qemu-io> qemu-io> qemu-io> qemu-io> qemu-io> qemu-io> qemu-io> qemu-io> qemu-io> qemu-io> qemu-io> qemu-io> qemu-io> qemu-io> qemu-io> qemu-io> qemu-io> qemu-io> qemu-io> qemu-io> qemu-io> qemu-io> qemu-io> qemu-io> qemu-io> qemu-io> qemu-io> qemu-io> qemu-io> qemu-io> qemu-io> qemu-io> qemu-io> qemu-io> qemu-io> qemu-io> qemu-io> qemu-io> qemu-io> qemu-io> qemu-io> qemu-io> qemu-io> qemu-io> qemu-io> qemu-io> qemu-io> qemu-io> qemu-io> qemu-io> qemu-io> qemu-io> qemu-io> qemu-io> qemu-io> qemu-io> qemu-io> qemu-io> qemu-io> qemu-io> qemu-io> qemu-io> qemu-io> wrote 81920/81920 bytes at offset XXX
-80 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
-wrote 65536/65536 bytes at offset XXX
+qemu-io> qemu-io> qemu-io> qemu-io> qemu-io> qemu-io> qemu-io> qemu-io> qemu-io> qemu-io> qemu-io> qemu-io> qemu-io> qemu-io> qemu-io> qemu-io> qemu-io> qemu-io> qemu-io> qemu-io> qemu-io> qemu-io> qemu-io> qemu-io> qemu-io> qemu-io> qemu-io> qemu-io> qemu-io> qemu-io> qemu-io> qemu-io> qemu-io> qemu-io> qemu-io> qemu-io> qemu-io> qemu-io> qemu-io> qemu-io> qemu-io> qemu-io> qemu-io> qemu-io> qemu-io> qemu-io> qemu-io> qemu-io> qemu-io> qemu-io> qemu-io> qemu-io> qemu-io> qemu-io> qemu-io> qemu-io> qemu-io> qemu-io> qemu-io> qemu-io> qemu-io> qemu-io> qemu-io> qemu-io> qemu-io> qemu-io> qemu-io> qemu-io> qemu-io> qemu-io> qemu-io> qemu-io> qemu-io> qemu-io> qemu-io> qemu-io> qemu-io> qemu-io> qemu-io> qemu-io> qemu-io> qemu-io> qemu-io> qemu-io> qemu-io> qemu-io> qemu-io> qemu-io> qemu-io> qemu-io> qemu-io> qemu-io> qemu-io> qemu-io> qemu-io> wrote 65536/65536 bytes at offset XXX
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
wrote 65536/65536 bytes at offset XXX
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
@@ -579,6 +577,8 @@ wrote 65536/65536 bytes at offset XXX
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
wrote 65536/65536 bytes at offset XXX
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+wrote 81920/81920 bytes at offset XXX
+80 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
wrote 65536/65536 bytes at offset XXX
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
wrote 65536/65536 bytes at offset XXX
@@ -645,6 +645,8 @@ wrote 65536/65536 bytes at offset XXX
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
wrote 65536/65536 bytes at offset XXX
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+wrote 81920/81920 bytes at offset XXX
+80 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
wrote 65536/65536 bytes at offset XXX
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
wrote 65536/65536 bytes at offset XXX
@@ -703,8 +705,6 @@ wrote 65536/65536 bytes at offset XXX
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
wrote 65536/65536 bytes at offset XXX
64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
-wrote 81920/81920 bytes at offset XXX
-80 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
== Verify image content ==
qemu-io> read 4096/4096 bytes at offset 2064384
diff --git a/tests/qemu-iotests/039 b/tests/qemu-iotests/039
index c5ae806ec..ae3517575 100755
--- a/tests/qemu-iotests/039
+++ b/tests/qemu-iotests/039
@@ -86,7 +86,7 @@ $QEMU_IO -r -c "read -P 0x5a 0 512" $TEST_IMG | _filter_qemu_io
echo
echo "== Repairing the image file must succeed =="
-$QEMU_IMG check -r all $TEST_IMG
+_check_test_img -r all
# The dirty bit must not be set
./qcow2.py $TEST_IMG dump-header | grep incompatible_features
diff --git a/tests/qemu-iotests/041 b/tests/qemu-iotests/041
index c6eb85187..6661c0395 100755
--- a/tests/qemu-iotests/041
+++ b/tests/qemu-iotests/041
@@ -22,7 +22,6 @@ import time
import os
import iotests
from iotests import qemu_img, qemu_io
-import struct
backing_img = os.path.join(iotests.test_dir, 'backing.img')
target_backing_img = os.path.join(iotests.test_dir, 'target-backing.img')
@@ -32,102 +31,40 @@ target_img = os.path.join(iotests.test_dir, 'target.img')
class ImageMirroringTestCase(iotests.QMPTestCase):
'''Abstract base class for image mirroring test cases'''
- def assert_no_active_mirrors(self):
- result = self.vm.qmp('query-block-jobs')
- self.assert_qmp(result, 'return', [])
-
- def cancel_and_wait(self, drive='drive0', wait_ready=True):
- '''Cancel a block job and wait for it to finish'''
- if wait_ready:
- ready = False
- while not ready:
- for event in self.vm.get_qmp_events(wait=True):
- if event['event'] == 'BLOCK_JOB_READY':
- self.assert_qmp(event, 'data/type', 'mirror')
- self.assert_qmp(event, 'data/device', drive)
- ready = True
-
- result = self.vm.qmp('block-job-cancel', device=drive,
- force=not wait_ready)
- self.assert_qmp(result, 'return', {})
-
- cancelled = False
- while not cancelled:
+ def wait_ready(self, drive='drive0'):
+ '''Wait until a block job BLOCK_JOB_READY event'''
+ ready = False
+ while not ready:
for event in self.vm.get_qmp_events(wait=True):
- if event['event'] == 'BLOCK_JOB_COMPLETED' or \
- event['event'] == 'BLOCK_JOB_CANCELLED':
+ if event['event'] == 'BLOCK_JOB_READY':
self.assert_qmp(event, 'data/type', 'mirror')
self.assert_qmp(event, 'data/device', drive)
- if wait_ready:
- self.assertEquals(event['event'], 'BLOCK_JOB_COMPLETED')
- self.assert_qmp(event, 'data/offset', self.image_len)
- self.assert_qmp(event, 'data/len', self.image_len)
- cancelled = True
+ ready = True
- self.assert_no_active_mirrors()
+ def wait_ready_and_cancel(self, drive='drive0'):
+ self.wait_ready(drive)
+ event = self.cancel_and_wait()
+ self.assertEquals(event['event'], 'BLOCK_JOB_COMPLETED')
+ self.assert_qmp(event, 'data/type', 'mirror')
+ self.assert_qmp(event, 'data/offset', self.image_len)
+ self.assert_qmp(event, 'data/len', self.image_len)
def complete_and_wait(self, drive='drive0', wait_ready=True):
'''Complete a block job and wait for it to finish'''
if wait_ready:
- ready = False
- while not ready:
- for event in self.vm.get_qmp_events(wait=True):
- if event['event'] == 'BLOCK_JOB_READY':
- self.assert_qmp(event, 'data/type', 'mirror')
- self.assert_qmp(event, 'data/device', drive)
- ready = True
+ self.wait_ready()
result = self.vm.qmp('block-job-complete', device=drive)
self.assert_qmp(result, 'return', {})
- completed = False
- while not completed:
- for event in self.vm.get_qmp_events(wait=True):
- if event['event'] == 'BLOCK_JOB_COMPLETED':
- self.assert_qmp(event, 'data/type', 'mirror')
- self.assert_qmp(event, 'data/device', drive)
- self.assert_qmp_absent(event, 'data/error')
- self.assert_qmp(event, 'data/offset', self.image_len)
- self.assert_qmp(event, 'data/len', self.image_len)
- completed = True
-
- self.assert_no_active_mirrors()
-
- def create_image(self, name, size):
- file = open(name, 'w')
- i = 0
- while i < size:
- sector = struct.pack('>l504xl', i / 512, i / 512)
- file.write(sector)
- i = i + 512
- file.close()
-
- def compare_images(self, img1, img2):
- try:
- qemu_img('convert', '-f', iotests.imgfmt, '-O', 'raw', img1, img1 + '.raw')
- qemu_img('convert', '-f', iotests.imgfmt, '-O', 'raw', img2, img2 + '.raw')
- file1 = open(img1 + '.raw', 'r')
- file2 = open(img2 + '.raw', 'r')
- return file1.read() == file2.read()
- finally:
- if file1 is not None:
- file1.close()
- if file2 is not None:
- file2.close()
- try:
- os.remove(img1 + '.raw')
- except OSError:
- pass
- try:
- os.remove(img2 + '.raw')
- except OSError:
- pass
+ event = self.wait_until_completed()
+ self.assert_qmp(event, 'data/type', 'mirror')
class TestSingleDrive(ImageMirroringTestCase):
image_len = 1 * 1024 * 1024 # MB
def setUp(self):
- self.create_image(backing_img, TestSingleDrive.image_len)
+ iotests.create_image(backing_img, TestSingleDrive.image_len)
qemu_img('create', '-f', iotests.imgfmt, '-o', 'backing_file=%s' % backing_img, test_img)
self.vm = iotests.VM().add_drive(test_img)
self.vm.launch()
@@ -142,7 +79,7 @@ class TestSingleDrive(ImageMirroringTestCase):
pass
def test_complete(self):
- self.assert_no_active_mirrors()
+ self.assert_no_active_block_jobs()
result = self.vm.qmp('drive-mirror', device='drive0', sync='full',
target=target_img)
@@ -152,37 +89,37 @@ class TestSingleDrive(ImageMirroringTestCase):
result = self.vm.qmp('query-block')
self.assert_qmp(result, 'return[0]/inserted/file', target_img)
self.vm.shutdown()
- self.assertTrue(self.compare_images(test_img, target_img),
+ self.assertTrue(iotests.compare_images(test_img, target_img),
'target image does not match source after mirroring')
def test_cancel(self):
- self.assert_no_active_mirrors()
+ self.assert_no_active_block_jobs()
result = self.vm.qmp('drive-mirror', device='drive0', sync='full',
target=target_img)
self.assert_qmp(result, 'return', {})
- self.cancel_and_wait(wait_ready=False)
+ self.cancel_and_wait(force=True)
result = self.vm.qmp('query-block')
self.assert_qmp(result, 'return[0]/inserted/file', test_img)
self.vm.shutdown()
def test_cancel_after_ready(self):
- self.assert_no_active_mirrors()
+ self.assert_no_active_block_jobs()
result = self.vm.qmp('drive-mirror', device='drive0', sync='full',
target=target_img)
self.assert_qmp(result, 'return', {})
- self.cancel_and_wait()
+ self.wait_ready_and_cancel()
result = self.vm.qmp('query-block')
self.assert_qmp(result, 'return[0]/inserted/file', test_img)
self.vm.shutdown()
- self.assertTrue(self.compare_images(test_img, target_img),
+ self.assertTrue(iotests.compare_images(test_img, target_img),
'target image does not match source after mirroring')
def test_pause(self):
- self.assert_no_active_mirrors()
+ self.assert_no_active_block_jobs()
result = self.vm.qmp('drive-mirror', device='drive0', sync='full',
target=target_img)
@@ -204,11 +141,42 @@ class TestSingleDrive(ImageMirroringTestCase):
self.complete_and_wait()
self.vm.shutdown()
- self.assertTrue(self.compare_images(test_img, target_img),
+ self.assertTrue(iotests.compare_images(test_img, target_img),
+ 'target image does not match source after mirroring')
+
+ def test_small_buffer(self):
+ self.assert_no_active_block_jobs()
+
+ # A small buffer is rounded up automatically
+ result = self.vm.qmp('drive-mirror', device='drive0', sync='full',
+ buf_size=4096, target=target_img)
+ self.assert_qmp(result, 'return', {})
+
+ self.complete_and_wait()
+ result = self.vm.qmp('query-block')
+ self.assert_qmp(result, 'return[0]/inserted/file', target_img)
+ self.vm.shutdown()
+ self.assertTrue(iotests.compare_images(test_img, target_img),
+ 'target image does not match source after mirroring')
+
+ def test_small_buffer2(self):
+ self.assert_no_active_block_jobs()
+
+ qemu_img('create', '-f', iotests.imgfmt, '-o', 'cluster_size=%d,size=%d'
+ % (TestSingleDrive.image_len, TestSingleDrive.image_len), target_img)
+ result = self.vm.qmp('drive-mirror', device='drive0', sync='full',
+ buf_size=65536, mode='existing', target=target_img)
+ self.assert_qmp(result, 'return', {})
+
+ self.complete_and_wait()
+ result = self.vm.qmp('query-block')
+ self.assert_qmp(result, 'return[0]/inserted/file', target_img)
+ self.vm.shutdown()
+ self.assertTrue(iotests.compare_images(test_img, target_img),
'target image does not match source after mirroring')
def test_large_cluster(self):
- self.assert_no_active_mirrors()
+ self.assert_no_active_block_jobs()
qemu_img('create', '-f', iotests.imgfmt, '-o', 'cluster_size=%d,backing_file=%s'
% (TestSingleDrive.image_len, backing_img), target_img)
@@ -220,7 +188,7 @@ class TestSingleDrive(ImageMirroringTestCase):
result = self.vm.qmp('query-block')
self.assert_qmp(result, 'return[0]/inserted/file', target_img)
self.vm.shutdown()
- self.assertTrue(self.compare_images(test_img, target_img),
+ self.assertTrue(iotests.compare_images(test_img, target_img),
'target image does not match source after mirroring')
def test_medium_not_found(self):
@@ -242,15 +210,15 @@ class TestMirrorNoBacking(ImageMirroringTestCase):
image_len = 2 * 1024 * 1024 # MB
def complete_and_wait(self, drive='drive0', wait_ready=True):
- self.create_image(target_backing_img, TestMirrorNoBacking.image_len)
+ iotests.create_image(target_backing_img, TestMirrorNoBacking.image_len)
return ImageMirroringTestCase.complete_and_wait(self, drive, wait_ready)
def compare_images(self, img1, img2):
- self.create_image(target_backing_img, TestMirrorNoBacking.image_len)
- return ImageMirroringTestCase.compare_images(self, img1, img2)
+ iotests.create_image(target_backing_img, TestMirrorNoBacking.image_len)
+ return iotests.compare_images(img1, img2)
def setUp(self):
- self.create_image(backing_img, TestMirrorNoBacking.image_len)
+ iotests.create_image(backing_img, TestMirrorNoBacking.image_len)
qemu_img('create', '-f', iotests.imgfmt, '-o', 'backing_file=%s' % backing_img, test_img)
self.vm = iotests.VM().add_drive(test_img)
self.vm.launch()
@@ -263,7 +231,7 @@ class TestMirrorNoBacking(ImageMirroringTestCase):
os.remove(target_img)
def test_complete(self):
- self.assert_no_active_mirrors()
+ self.assert_no_active_block_jobs()
qemu_img('create', '-f', iotests.imgfmt, '-o', 'backing_file=%s' % backing_img, target_img)
result = self.vm.qmp('drive-mirror', device='drive0', sync='full',
@@ -278,20 +246,89 @@ class TestMirrorNoBacking(ImageMirroringTestCase):
'target image does not match source after mirroring')
def test_cancel(self):
- self.assert_no_active_mirrors()
+ self.assert_no_active_block_jobs()
qemu_img('create', '-f', iotests.imgfmt, '-o', 'backing_file=%s' % backing_img, target_img)
result = self.vm.qmp('drive-mirror', device='drive0', sync='full',
mode='existing', target=target_img)
self.assert_qmp(result, 'return', {})
- self.cancel_and_wait()
+ self.wait_ready_and_cancel()
result = self.vm.qmp('query-block')
self.assert_qmp(result, 'return[0]/inserted/file', test_img)
self.vm.shutdown()
self.assertTrue(self.compare_images(test_img, target_img),
'target image does not match source after mirroring')
+ def test_large_cluster(self):
+ self.assert_no_active_block_jobs()
+
+ # qemu-img create fails if the image is not there
+ qemu_img('create', '-f', iotests.imgfmt, '-o', 'size=%d'
+ %(TestMirrorNoBacking.image_len), target_backing_img)
+ qemu_img('create', '-f', iotests.imgfmt, '-o', 'cluster_size=%d,backing_file=%s'
+ % (TestMirrorNoBacking.image_len, target_backing_img), target_img)
+ os.remove(target_backing_img)
+
+ result = self.vm.qmp('drive-mirror', device='drive0', sync='full',
+ mode='existing', target=target_img)
+ self.assert_qmp(result, 'return', {})
+
+ self.complete_and_wait()
+ result = self.vm.qmp('query-block')
+ self.assert_qmp(result, 'return[0]/inserted/file', target_img)
+ self.vm.shutdown()
+ self.assertTrue(self.compare_images(test_img, target_img),
+ 'target image does not match source after mirroring')
+
+class TestMirrorResized(ImageMirroringTestCase):
+ backing_len = 1 * 1024 * 1024 # MB
+ image_len = 2 * 1024 * 1024 # MB
+
+ def setUp(self):
+ iotests.create_image(backing_img, TestMirrorResized.backing_len)
+ qemu_img('create', '-f', iotests.imgfmt, '-o', 'backing_file=%s' % backing_img, test_img)
+ qemu_img('resize', test_img, '2M')
+ self.vm = iotests.VM().add_drive(test_img)
+ self.vm.launch()
+
+ def tearDown(self):
+ self.vm.shutdown()
+ os.remove(test_img)
+ os.remove(backing_img)
+ try:
+ os.remove(target_img)
+ except OSError:
+ pass
+
+ def test_complete_top(self):
+ self.assert_no_active_block_jobs()
+
+ result = self.vm.qmp('drive-mirror', device='drive0', sync='top',
+ target=target_img)
+ self.assert_qmp(result, 'return', {})
+
+ self.complete_and_wait()
+ result = self.vm.qmp('query-block')
+ self.assert_qmp(result, 'return[0]/inserted/file', target_img)
+ self.vm.shutdown()
+ self.assertTrue(iotests.compare_images(test_img, target_img),
+ 'target image does not match source after mirroring')
+
+ def test_complete_full(self):
+ self.assert_no_active_block_jobs()
+
+ result = self.vm.qmp('drive-mirror', device='drive0', sync='full',
+ target=target_img)
+ self.assert_qmp(result, 'return', {})
+
+ self.complete_and_wait()
+ result = self.vm.qmp('query-block')
+ self.assert_qmp(result, 'return[0]/inserted/file', target_img)
+ self.vm.shutdown()
+ self.assertTrue(iotests.compare_images(test_img, target_img),
+ 'target image does not match source after mirroring')
+
class TestReadErrors(ImageMirroringTestCase):
image_len = 2 * 1024 * 1024 # MB
@@ -324,12 +361,15 @@ new_state = "1"
def setUp(self):
self.blkdebug_file = backing_img + ".blkdebug"
- self.create_image(backing_img, TestReadErrors.image_len)
+ iotests.create_image(backing_img, TestReadErrors.image_len)
self.create_blkdebug_file(self.blkdebug_file, "read_aio", 5)
qemu_img('create', '-f', iotests.imgfmt,
'-o', 'backing_file=blkdebug:%s:%s,backing_fmt=raw'
% (self.blkdebug_file, backing_img),
test_img)
+ # Write something for tests that use sync='top'
+ qemu_io('-c', 'write %d 512' % (self.MIRROR_GRANULARITY + 65536),
+ test_img)
self.vm = iotests.VM().add_drive(test_img)
self.vm.launch()
@@ -340,7 +380,7 @@ new_state = "1"
os.remove(self.blkdebug_file)
def test_report_read(self):
- self.assert_no_active_mirrors()
+ self.assert_no_active_block_jobs()
result = self.vm.qmp('drive-mirror', device='drive0', sync='full',
target=target_img)
@@ -364,11 +404,11 @@ new_state = "1"
self.assert_qmp(event, 'data/len', self.image_len)
completed = True
- self.assert_no_active_mirrors()
+ self.assert_no_active_block_jobs()
self.vm.shutdown()
def test_ignore_read(self):
- self.assert_no_active_mirrors()
+ self.assert_no_active_block_jobs()
result = self.vm.qmp('drive-mirror', device='drive0', sync='full',
target=target_img, on_source_error='ignore')
@@ -383,8 +423,34 @@ new_state = "1"
self.complete_and_wait()
self.vm.shutdown()
+ def test_large_cluster(self):
+ self.assert_no_active_block_jobs()
+
+ # Test COW into the target image. The first half of the
+ # cluster at MIRROR_GRANULARITY has to be copied from
+ # backing_img, even though sync='top'.
+ qemu_img('create', '-f', iotests.imgfmt, '-ocluster_size=131072,backing_file=%s' %(backing_img), target_img)
+ result = self.vm.qmp('drive-mirror', device='drive0', sync='top',
+ on_source_error='ignore',
+ mode='existing', target=target_img)
+ self.assert_qmp(result, 'return', {})
+
+ event = self.vm.get_qmp_event(wait=True)
+ self.assertEquals(event['event'], 'BLOCK_JOB_ERROR')
+ self.assert_qmp(event, 'data/device', 'drive0')
+ self.assert_qmp(event, 'data/operation', 'read')
+ result = self.vm.qmp('query-block-jobs')
+ self.assert_qmp(result, 'return[0]/paused', False)
+ self.complete_and_wait()
+ self.vm.shutdown()
+
+ # Detach blkdebug to compare images successfully
+ qemu_img('rebase', '-f', iotests.imgfmt, '-u', '-b', backing_img, test_img)
+ self.assertTrue(iotests.compare_images(test_img, target_img),
+ 'target image does not match source after mirroring')
+
def test_stop_read(self):
- self.assert_no_active_mirrors()
+ self.assert_no_active_block_jobs()
result = self.vm.qmp('drive-mirror', device='drive0', sync='full',
target=target_img, on_source_error='stop')
@@ -415,7 +481,7 @@ new_state = "1"
self.assert_qmp(result, 'return[0]/io-status', 'ok')
self.complete_and_wait(wait_ready=False)
- self.assert_no_active_mirrors()
+ self.assert_no_active_block_jobs()
self.vm.shutdown()
class TestWriteErrors(ImageMirroringTestCase):
@@ -450,7 +516,7 @@ new_state = "1"
def setUp(self):
self.blkdebug_file = target_img + ".blkdebug"
- self.create_image(backing_img, TestWriteErrors.image_len)
+ iotests.create_image(backing_img, TestWriteErrors.image_len)
self.create_blkdebug_file(self.blkdebug_file, "write_aio", 5)
qemu_img('create', '-f', iotests.imgfmt, '-obacking_file=%s' %(backing_img), test_img)
self.vm = iotests.VM().add_drive(test_img)
@@ -465,7 +531,7 @@ new_state = "1"
os.remove(self.blkdebug_file)
def test_report_write(self):
- self.assert_no_active_mirrors()
+ self.assert_no_active_block_jobs()
result = self.vm.qmp('drive-mirror', device='drive0', sync='full',
mode='existing', target=self.target_img)
@@ -489,11 +555,11 @@ new_state = "1"
self.assert_qmp(event, 'data/len', self.image_len)
completed = True
- self.assert_no_active_mirrors()
+ self.assert_no_active_block_jobs()
self.vm.shutdown()
def test_ignore_write(self):
- self.assert_no_active_mirrors()
+ self.assert_no_active_block_jobs()
result = self.vm.qmp('drive-mirror', device='drive0', sync='full',
mode='existing', target=self.target_img,
@@ -510,7 +576,7 @@ new_state = "1"
self.vm.shutdown()
def test_stop_write(self):
- self.assert_no_active_mirrors()
+ self.assert_no_active_block_jobs()
result = self.vm.qmp('drive-mirror', device='drive0', sync='full',
mode='existing', target=self.target_img,
@@ -542,7 +608,7 @@ new_state = "1"
ready = True
self.complete_and_wait(wait_ready=False)
- self.assert_no_active_mirrors()
+ self.assert_no_active_block_jobs()
self.vm.shutdown()
class TestSetSpeed(ImageMirroringTestCase):
@@ -561,7 +627,7 @@ class TestSetSpeed(ImageMirroringTestCase):
os.remove(target_img)
def test_set_speed(self):
- self.assert_no_active_mirrors()
+ self.assert_no_active_block_jobs()
result = self.vm.qmp('drive-mirror', device='drive0', sync='full',
target=target_img)
@@ -580,7 +646,7 @@ class TestSetSpeed(ImageMirroringTestCase):
self.assert_qmp(result, 'return[0]/device', 'drive0')
self.assert_qmp(result, 'return[0]/speed', 8 * 1024 * 1024)
- self.cancel_and_wait()
+ self.wait_ready_and_cancel()
# Check setting speed in drive-mirror works
result = self.vm.qmp('drive-mirror', device='drive0', sync='full',
@@ -591,16 +657,16 @@ class TestSetSpeed(ImageMirroringTestCase):
self.assert_qmp(result, 'return[0]/device', 'drive0')
self.assert_qmp(result, 'return[0]/speed', 4 * 1024 * 1024)
- self.cancel_and_wait()
+ self.wait_ready_and_cancel()
def test_set_speed_invalid(self):
- self.assert_no_active_mirrors()
+ self.assert_no_active_block_jobs()
result = self.vm.qmp('drive-mirror', device='drive0', sync='full',
target=target_img, speed=-1)
self.assert_qmp(result, 'error/class', 'GenericError')
- self.assert_no_active_mirrors()
+ self.assert_no_active_block_jobs()
result = self.vm.qmp('drive-mirror', device='drive0', sync='full',
target=target_img)
@@ -609,7 +675,7 @@ class TestSetSpeed(ImageMirroringTestCase):
result = self.vm.qmp('block-job-set-speed', device='drive0', speed=-1)
self.assert_qmp(result, 'error/class', 'GenericError')
- self.cancel_and_wait()
+ self.wait_ready_and_cancel()
if __name__ == '__main__':
iotests.main(supported_fmts=['qcow2', 'qed'])
diff --git a/tests/qemu-iotests/041.out b/tests/qemu-iotests/041.out
index 71009c239..42314e9c0 100644
--- a/tests/qemu-iotests/041.out
+++ b/tests/qemu-iotests/041.out
@@ -1,5 +1,5 @@
-..................
+........................
----------------------------------------------------------------------
-Ran 18 tests
+Ran 24 tests
OK
diff --git a/tests/qemu-iotests/042 b/tests/qemu-iotests/042
index c3c3ca8d0..16b2fdbd5 100755
--- a/tests/qemu-iotests/042
+++ b/tests/qemu-iotests/042
@@ -38,7 +38,7 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
. ./common.rc
. ./common.filter
-_supported_fmt qcow2 qcow qed vmdk
+_supported_fmt qcow2 qcow qed
_supported_proto file
_supported_os Linux
diff --git a/tests/qemu-iotests/043 b/tests/qemu-iotests/043
index 3ba08dc94..478773d10 100755
--- a/tests/qemu-iotests/043
+++ b/tests/qemu-iotests/043
@@ -40,7 +40,7 @@ trap "_cleanup; exit \$status" 0 1 2 3 15
. ./common.filter
# Any format supporting backing files
-_supported_fmt qcow qcow2 vmdk qed
+_supported_fmt qcow2 qed
_supported_proto generic
_supported_os Linux
diff --git a/tests/qemu-iotests/044.out b/tests/qemu-iotests/044.out
index 7a4007137..5c5aa929f 100644
--- a/tests/qemu-iotests/044.out
+++ b/tests/qemu-iotests/044.out
@@ -1,4 +1,6 @@
No errors were found on the image.
+7292415/33554432 = 21.73% allocated, 0.00% fragmented, 0.00% compressed clusters
+Image end offset: 4296448000
.
----------------------------------------------------------------------
Ran 1 tests
diff --git a/tests/qemu-iotests/045 b/tests/qemu-iotests/045
new file mode 100755
index 000000000..2b6f1af27
--- /dev/null
+++ b/tests/qemu-iotests/045
@@ -0,0 +1,129 @@
+#!/usr/bin/env python
+#
+# Tests for fdsets.
+#
+# Copyright (C) 2012 IBM Corp.
+#
+# 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/>.
+#
+
+import os
+import iotests
+from iotests import qemu_img
+
+image0 = os.path.join(iotests.test_dir, 'image0')
+image1 = os.path.join(iotests.test_dir, 'image1')
+image2 = os.path.join(iotests.test_dir, 'image2')
+image3 = os.path.join(iotests.test_dir, 'image3')
+image4 = os.path.join(iotests.test_dir, 'image4')
+
+class TestFdSets(iotests.QMPTestCase):
+
+ def setUp(self):
+ self.vm = iotests.VM()
+ qemu_img('create', '-f', iotests.imgfmt, image0, '128K')
+ qemu_img('create', '-f', iotests.imgfmt, image1, '128K')
+ qemu_img('create', '-f', iotests.imgfmt, image2, '128K')
+ qemu_img('create', '-f', iotests.imgfmt, image3, '128K')
+ qemu_img('create', '-f', iotests.imgfmt, image4, '128K')
+ self.file0 = open(image0, 'r')
+ self.file1 = open(image1, 'w+')
+ self.file2 = open(image2, 'r')
+ self.file3 = open(image3, 'r')
+ self.file4 = open(image4, 'r')
+ self.vm.add_fd(self.file0.fileno(), 1, 'image0:r')
+ self.vm.add_fd(self.file1.fileno(), 1, 'image1:w+')
+ self.vm.add_fd(self.file2.fileno(), 0, 'image2:r')
+ self.vm.add_fd(self.file3.fileno(), 2, 'image3:r')
+ self.vm.add_fd(self.file4.fileno(), 2, 'image4:r')
+ self.vm.add_drive("/dev/fdset/1")
+ self.vm.launch()
+
+ def tearDown(self):
+ self.vm.shutdown()
+ self.file0.close()
+ self.file1.close()
+ self.file2.close()
+ self.file3.close()
+ self.file4.close()
+ os.remove(image0)
+ os.remove(image1)
+ os.remove(image2)
+ os.remove(image3)
+ os.remove(image4)
+
+ def test_query_fdset(self):
+ result = self.vm.qmp('query-fdsets')
+ self.assert_qmp(result, 'return[0]/fdset-id', 2)
+ self.assert_qmp(result, 'return[1]/fdset-id', 1)
+ self.assert_qmp(result, 'return[2]/fdset-id', 0)
+ self.assert_qmp(result, 'return[0]/fds[0]/opaque', 'image3:r')
+ self.assert_qmp(result, 'return[0]/fds[1]/opaque', 'image4:r')
+ self.assert_qmp(result, 'return[1]/fds[0]/opaque', 'image0:r')
+ self.assert_qmp(result, 'return[1]/fds[1]/opaque', 'image1:w+')
+ self.assert_qmp(result, 'return[2]/fds[0]/opaque', 'image2:r')
+ self.vm.shutdown()
+
+ def test_remove_fdset(self):
+ result = self.vm.qmp('remove-fd', fdset_id=2)
+ self.assert_qmp(result, 'return', {})
+ result = self.vm.qmp('query-fdsets')
+ self.assert_qmp(result, 'return[0]/fdset-id', 1)
+ self.assert_qmp(result, 'return[1]/fdset-id', 0)
+ self.assert_qmp(result, 'return[0]/fds[0]/opaque', 'image0:r')
+ self.assert_qmp(result, 'return[0]/fds[1]/opaque', 'image1:w+')
+ self.assert_qmp(result, 'return[1]/fds[0]/opaque', 'image2:r')
+ self.vm.shutdown()
+
+ def test_remove_fd(self):
+ result = self.vm.qmp('query-fdsets')
+ fd_image3 = result['return'][0]['fds'][0]['fd']
+ result = self.vm.qmp('remove-fd', fdset_id=2, fd=fd_image3)
+ self.assert_qmp(result, 'return', {})
+ result = self.vm.qmp('query-fdsets')
+ self.assert_qmp(result, 'return[0]/fdset-id', 2)
+ self.assert_qmp(result, 'return[1]/fdset-id', 1)
+ self.assert_qmp(result, 'return[2]/fdset-id', 0)
+ self.assert_qmp(result, 'return[0]/fds[0]/opaque', 'image4:r')
+ self.assert_qmp(result, 'return[1]/fds[0]/opaque', 'image0:r')
+ self.assert_qmp(result, 'return[1]/fds[1]/opaque', 'image1:w+')
+ self.assert_qmp(result, 'return[2]/fds[0]/opaque', 'image2:r')
+ self.vm.shutdown()
+
+ def test_remove_fd_invalid_fdset(self):
+ result = self.vm.qmp('query-fdsets')
+ fd_image3 = result['return'][0]['fds'][0]['fd']
+ result = self.vm.qmp('remove-fd', fdset_id=3, fd=fd_image3)
+ self.assert_qmp(result, 'error/class', 'GenericError')
+ self.assert_qmp(result, 'error/desc',
+ 'File descriptor named \'fdset-id:3, fd:%d\' not found' % fd_image3)
+ self.vm.shutdown()
+
+ def test_remove_fd_invalid_fd(self):
+ result = self.vm.qmp('query-fdsets')
+ result = self.vm.qmp('remove-fd', fdset_id=2, fd=999)
+ self.assert_qmp(result, 'error/class', 'GenericError')
+ self.assert_qmp(result, 'error/desc',
+ 'File descriptor named \'fdset-id:2, fd:999\' not found')
+ self.vm.shutdown()
+
+ def test_add_fd_invalid_fd(self):
+ result = self.vm.qmp('add-fd', fdset_id=2)
+ self.assert_qmp(result, 'error/class', 'GenericError')
+ self.assert_qmp(result, 'error/desc',
+ 'No file descriptor supplied via SCM_RIGHTS')
+ self.vm.shutdown()
+
+if __name__ == '__main__':
+ iotests.main(supported_fmts=['raw'])
diff --git a/tests/qemu-iotests/045.out b/tests/qemu-iotests/045.out
new file mode 100644
index 000000000..3f8a935a0
--- /dev/null
+++ b/tests/qemu-iotests/045.out
@@ -0,0 +1,5 @@
+......
+----------------------------------------------------------------------
+Ran 6 tests
+
+OK
diff --git a/tests/qemu-iotests/046 b/tests/qemu-iotests/046
new file mode 100755
index 000000000..987bfff8f
--- /dev/null
+++ b/tests/qemu-iotests/046
@@ -0,0 +1,262 @@
+#!/bin/bash
+#
+# Test concurrent cluster allocations
+#
+# Copyright (C) 2012 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()
+{
+ _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 generic
+_supported_os Linux
+
+CLUSTER_SIZE=64k
+size=128M
+
+echo
+echo "== creating backing file for COW tests =="
+
+_make_test_img $size
+
+function backing_io()
+{
+ local offset=$1
+ local sectors=$2
+ local op=$3
+ local pattern=0
+ local cur_sec=0
+
+ for i in $(seq 0 $((sectors - 1))); do
+ cur_sec=$((offset / 65536 + i))
+ pattern=$(( ( (cur_sec % 128) + (cur_sec / 128)) % 128 ))
+
+ echo "$op -P $pattern $((cur_sec * 64))k 64k"
+ done
+}
+
+backing_io 0 32 write | $QEMU_IO $TEST_IMG | _filter_qemu_io
+
+mv $TEST_IMG $TEST_IMG.base
+
+_make_test_img -b $TEST_IMG.base 6G
+
+echo
+echo "== Some concurrent requests touching the same cluster =="
+
+function overlay_io()
+{
+# Allocate middle of cluster 1, then write to somewhere before and after it
+cat <<EOF
+break write_aio A
+aio_write -P 10 0x18000 0x2000
+wait_break A
+
+aio_write -P 11 0x12000 0x2000
+aio_write -P 12 0x1c000 0x2000
+
+resume A
+aio_flush
+EOF
+
+# Sequential write case: Alloc middle of cluster 2, then write overlapping
+# to next cluster
+cat <<EOF
+break write_aio A
+aio_write -P 20 0x28000 0x2000
+wait_break A
+aio_write -P 21 0x2a000 0x10000
+resume A
+aio_flush
+EOF
+
+# The same with a gap between both requests
+cat <<EOF
+break write_aio A
+aio_write -P 40 0x48000 0x2000
+wait_break A
+aio_write -P 41 0x4c000 0x10000
+resume A
+aio_flush
+EOF
+
+# Sequential write, but the next cluster is already allocated
+cat <<EOF
+write -P 70 0x76000 0x8000
+aio_flush
+break write_aio A
+aio_write -P 60 0x66000 0x2000
+wait_break A
+aio_write -P 61 0x6a000 0xe000
+resume A
+aio_flush
+EOF
+
+# Sequential write, but the next cluster is already allocated
+# and phyiscally in the right position
+cat <<EOF
+write -P 89 0x80000 0x1000
+write -P 90 0x96000 0x8000
+aio_flush
+discard 0x80000 0x10000
+aio_flush
+break write_aio A
+aio_write -P 80 0x86000 0x2000
+wait_break A
+aio_write -P 81 0x8a000 0xe000
+resume A
+aio_flush
+EOF
+
+# Sequential write, and the next cluster is compressed
+cat <<EOF
+write -P 109 0xa0000 0x1000
+write -c -P 110 0xb0000 0x10000
+aio_flush
+discard 0xa0000 0x10000
+aio_flush
+break write_aio A
+aio_write -P 100 0xa6000 0x2000
+wait_break A
+aio_write -P 101 0xaa000 0xe000
+resume A
+aio_flush
+EOF
+
+# Reverse sequential write
+cat <<EOF
+break write_aio A
+aio_write -P 121 0xdc000 0x2000
+wait_break A
+aio_write -P 120 0xc4000 0x18000
+resume A
+aio_flush
+EOF
+
+# Reverse sequential write with a gap
+cat <<EOF
+break write_aio A
+aio_write -P 141 0xfc000 0x2000
+wait_break A
+aio_write -P 140 0xe4000 0x14000
+resume A
+aio_flush
+EOF
+
+# Allocate an area in the middle and then overwrite with a larger request
+cat <<EOF
+break write_aio A
+aio_write -P 161 0x10c000 0x8000
+wait_break A
+aio_write -P 160 0x104000 0x18000
+resume A
+aio_flush
+EOF
+}
+
+overlay_io | $QEMU_IO blkdebug::$TEST_IMG | _filter_qemu_io |\
+ sed -e 's/bytes at offset [0-9]*/bytes at offset XXX/g'
+
+echo
+echo "== Verify image content =="
+
+function verify_io()
+{
+ echo read -P 0 0 0x10000
+
+ echo read -P 1 0x10000 0x2000
+ echo read -P 11 0x12000 0x2000
+ echo read -P 1 0x14000 0x4000
+ echo read -P 10 0x18000 0x2000
+ echo read -P 1 0x1a000 0x2000
+ echo read -P 12 0x1c000 0x2000
+ echo read -P 1 0x1e000 0x2000
+
+ echo read -P 2 0x20000 0x8000
+ echo read -P 20 0x28000 0x2000
+ echo read -P 21 0x2a000 0x10000
+ echo read -P 3 0x3a000 0x6000
+
+ echo read -P 4 0x40000 0x8000
+ echo read -P 40 0x48000 0x2000
+ echo read -P 4 0x4a000 0x2000
+ echo read -P 41 0x4c000 0x10000
+ echo read -P 5 0x5c000 0x4000
+
+ echo read -P 6 0x60000 0x6000
+ echo read -P 60 0x66000 0x2000
+ echo read -P 6 0x68000 0x2000
+ echo read -P 61 0x6a000 0xe000
+ echo read -P 70 0x78000 0x6000
+ echo read -P 7 0x7e000 0x2000
+
+ echo read -P 8 0x80000 0x6000
+ echo read -P 80 0x86000 0x2000
+ echo read -P 8 0x88000 0x2000
+ echo read -P 81 0x8a000 0xe000
+ echo read -P 90 0x98000 0x6000
+ echo read -P 9 0x9e000 0x2000
+
+ echo read -P 10 0xa0000 0x6000
+ echo read -P 100 0xa6000 0x2000
+ echo read -P 10 0xa8000 0x2000
+ echo read -P 101 0xaa000 0xe000
+ echo read -P 110 0xb8000 0x8000
+
+ echo read -P 12 0xc0000 0x4000
+ echo read -P 120 0xc4000 0x18000
+ echo read -P 121 0xdc000 0x2000
+ echo read -P 13 0xde000 0x2000
+
+ echo read -P 14 0xe0000 0x4000
+ echo read -P 140 0xe4000 0x14000
+ echo read -P 15 0xf8000 0x4000
+ echo read -P 141 0xfc000 0x2000
+ echo read -P 15 0xfe000 0x2000
+
+ echo read -P 16 0x100000 0x4000
+ echo read -P 160 0x104000 0x8000
+ # Undefined content for 0x10c000 0x8000
+ echo read -P 160 0x114000 0x8000
+ echo read -P 17 0x11c000 0x4000
+}
+
+verify_io | $QEMU_IO $TEST_IMG | _filter_qemu_io
+
+_check_test_img
+
+# success, all done
+echo "*** done"
+rm -f $seq.full
+status=0
diff --git a/tests/qemu-iotests/046.out b/tests/qemu-iotests/046.out
new file mode 100644
index 000000000..4b50a17ee
--- /dev/null
+++ b/tests/qemu-iotests/046.out
@@ -0,0 +1,239 @@
+QA output created by 046
+
+== creating backing file for COW tests ==
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728
+qemu-io> wrote 65536/65536 bytes at offset 0
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+qemu-io> wrote 65536/65536 bytes at offset 65536
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+qemu-io> wrote 65536/65536 bytes at offset 131072
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+qemu-io> wrote 65536/65536 bytes at offset 196608
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+qemu-io> wrote 65536/65536 bytes at offset 262144
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+qemu-io> wrote 65536/65536 bytes at offset 327680
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+qemu-io> wrote 65536/65536 bytes at offset 393216
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+qemu-io> wrote 65536/65536 bytes at offset 458752
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+qemu-io> wrote 65536/65536 bytes at offset 524288
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+qemu-io> wrote 65536/65536 bytes at offset 589824
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+qemu-io> wrote 65536/65536 bytes at offset 655360
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+qemu-io> wrote 65536/65536 bytes at offset 720896
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+qemu-io> wrote 65536/65536 bytes at offset 786432
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+qemu-io> wrote 65536/65536 bytes at offset 851968
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+qemu-io> wrote 65536/65536 bytes at offset 917504
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+qemu-io> wrote 65536/65536 bytes at offset 983040
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+qemu-io> wrote 65536/65536 bytes at offset 1048576
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+qemu-io> wrote 65536/65536 bytes at offset 1114112
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+qemu-io> wrote 65536/65536 bytes at offset 1179648
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+qemu-io> wrote 65536/65536 bytes at offset 1245184
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+qemu-io> wrote 65536/65536 bytes at offset 1310720
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+qemu-io> wrote 65536/65536 bytes at offset 1376256
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+qemu-io> wrote 65536/65536 bytes at offset 1441792
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+qemu-io> wrote 65536/65536 bytes at offset 1507328
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+qemu-io> wrote 65536/65536 bytes at offset 1572864
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+qemu-io> wrote 65536/65536 bytes at offset 1638400
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+qemu-io> wrote 65536/65536 bytes at offset 1703936
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+qemu-io> wrote 65536/65536 bytes at offset 1769472
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+qemu-io> wrote 65536/65536 bytes at offset 1835008
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+qemu-io> wrote 65536/65536 bytes at offset 1900544
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+qemu-io> wrote 65536/65536 bytes at offset 1966080
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+qemu-io> wrote 65536/65536 bytes at offset 2031616
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+qemu-io> Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=6442450944 backing_file='TEST_DIR/t.IMGFMT.base'
+
+== Some concurrent requests touching the same cluster ==
+qemu-io> qemu-io> qemu-io> blkdebug: Suspended request 'A'
+qemu-io> qemu-io> qemu-io> qemu-io> qemu-io> blkdebug: Resuming request 'A'
+qemu-io> wrote 8192/8192 bytes at offset XXX
+8 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+wrote 8192/8192 bytes at offset XXX
+8 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+wrote 8192/8192 bytes at offset XXX
+8 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+qemu-io> qemu-io> blkdebug: Suspended request 'A'
+qemu-io> qemu-io> qemu-io> blkdebug: Resuming request 'A'
+qemu-io> wrote 8192/8192 bytes at offset XXX
+8 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+wrote 65536/65536 bytes at offset XXX
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+qemu-io> qemu-io> blkdebug: Suspended request 'A'
+qemu-io> qemu-io> qemu-io> blkdebug: Resuming request 'A'
+qemu-io> wrote 8192/8192 bytes at offset XXX
+8 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+wrote 65536/65536 bytes at offset XXX
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+qemu-io> wrote 32768/32768 bytes at offset XXX
+32 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+qemu-io> qemu-io> qemu-io> blkdebug: Suspended request 'A'
+qemu-io> qemu-io> qemu-io> blkdebug: Resuming request 'A'
+qemu-io> wrote 8192/8192 bytes at offset XXX
+8 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+wrote 57344/57344 bytes at offset XXX
+56 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+qemu-io> wrote 4096/4096 bytes at offset XXX
+4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+qemu-io> wrote 32768/32768 bytes at offset XXX
+32 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+qemu-io> qemu-io> discard 65536/65536 bytes at offset XXX
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+qemu-io> qemu-io> qemu-io> blkdebug: Suspended request 'A'
+qemu-io> qemu-io> qemu-io> blkdebug: Resuming request 'A'
+qemu-io> wrote 8192/8192 bytes at offset XXX
+8 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+wrote 57344/57344 bytes at offset XXX
+56 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+qemu-io> wrote 4096/4096 bytes at offset XXX
+4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+qemu-io> wrote 65536/65536 bytes at offset XXX
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+qemu-io> qemu-io> discard 65536/65536 bytes at offset XXX
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+qemu-io> qemu-io> qemu-io> blkdebug: Suspended request 'A'
+qemu-io> qemu-io> qemu-io> blkdebug: Resuming request 'A'
+qemu-io> wrote 8192/8192 bytes at offset XXX
+8 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+wrote 57344/57344 bytes at offset XXX
+56 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+qemu-io> qemu-io> blkdebug: Suspended request 'A'
+qemu-io> qemu-io> qemu-io> blkdebug: Resuming request 'A'
+qemu-io> wrote 8192/8192 bytes at offset XXX
+8 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+wrote 98304/98304 bytes at offset XXX
+96 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+qemu-io> qemu-io> blkdebug: Suspended request 'A'
+qemu-io> qemu-io> qemu-io> blkdebug: Resuming request 'A'
+qemu-io> wrote 8192/8192 bytes at offset XXX
+8 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+wrote 81920/81920 bytes at offset XXX
+80 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+qemu-io> qemu-io> blkdebug: Suspended request 'A'
+qemu-io> qemu-io> qemu-io> blkdebug: Resuming request 'A'
+qemu-io> wrote 32768/32768 bytes at offset XXX
+32 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+wrote 98304/98304 bytes at offset XXX
+96 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+qemu-io>
+== Verify image content ==
+qemu-io> read 65536/65536 bytes at offset 0
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+qemu-io> read 8192/8192 bytes at offset 65536
+8 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+qemu-io> read 8192/8192 bytes at offset 73728
+8 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+qemu-io> read 16384/16384 bytes at offset 81920
+16 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+qemu-io> read 8192/8192 bytes at offset 98304
+8 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+qemu-io> read 8192/8192 bytes at offset 106496
+8 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+qemu-io> read 8192/8192 bytes at offset 114688
+8 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+qemu-io> read 8192/8192 bytes at offset 122880
+8 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+qemu-io> read 32768/32768 bytes at offset 131072
+32 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+qemu-io> read 8192/8192 bytes at offset 163840
+8 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+qemu-io> read 65536/65536 bytes at offset 172032
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+qemu-io> read 24576/24576 bytes at offset 237568
+24 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+qemu-io> read 32768/32768 bytes at offset 262144
+32 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+qemu-io> read 8192/8192 bytes at offset 294912
+8 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+qemu-io> read 8192/8192 bytes at offset 303104
+8 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+qemu-io> read 65536/65536 bytes at offset 311296
+64 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+qemu-io> read 16384/16384 bytes at offset 376832
+16 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+qemu-io> read 24576/24576 bytes at offset 393216
+24 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+qemu-io> read 8192/8192 bytes at offset 417792
+8 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+qemu-io> read 8192/8192 bytes at offset 425984
+8 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+qemu-io> read 57344/57344 bytes at offset 434176
+56 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+qemu-io> read 24576/24576 bytes at offset 491520
+24 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+qemu-io> read 8192/8192 bytes at offset 516096
+8 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+qemu-io> read 24576/24576 bytes at offset 524288
+24 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+qemu-io> read 8192/8192 bytes at offset 548864
+8 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+qemu-io> read 8192/8192 bytes at offset 557056
+8 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+qemu-io> read 57344/57344 bytes at offset 565248
+56 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+qemu-io> read 24576/24576 bytes at offset 622592
+24 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+qemu-io> read 8192/8192 bytes at offset 647168
+8 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+qemu-io> read 24576/24576 bytes at offset 655360
+24 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+qemu-io> read 8192/8192 bytes at offset 679936
+8 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+qemu-io> read 8192/8192 bytes at offset 688128
+8 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+qemu-io> read 57344/57344 bytes at offset 696320
+56 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+qemu-io> read 32768/32768 bytes at offset 753664
+32 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+qemu-io> read 16384/16384 bytes at offset 786432
+16 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+qemu-io> read 98304/98304 bytes at offset 802816
+96 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+qemu-io> read 8192/8192 bytes at offset 901120
+8 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+qemu-io> read 8192/8192 bytes at offset 909312
+8 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+qemu-io> read 16384/16384 bytes at offset 917504
+16 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+qemu-io> read 81920/81920 bytes at offset 933888
+80 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+qemu-io> read 16384/16384 bytes at offset 1015808
+16 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+qemu-io> read 8192/8192 bytes at offset 1032192
+8 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+qemu-io> read 8192/8192 bytes at offset 1040384
+8 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+qemu-io> read 16384/16384 bytes at offset 1048576
+16 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+qemu-io> read 32768/32768 bytes at offset 1064960
+32 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+qemu-io> read 32768/32768 bytes at offset 1130496
+32 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+qemu-io> read 16384/16384 bytes at offset 1163264
+16 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+qemu-io> No errors were found on the image.
+*** done
diff --git a/tests/qemu-iotests/047 b/tests/qemu-iotests/047
new file mode 100755
index 000000000..0cf36b434
--- /dev/null
+++ b/tests/qemu-iotests/047
@@ -0,0 +1,75 @@
+#!/bin/bash
+#
+# Regression test for commit b7ab0fea (which was a corruption fix,
+# despite the commit message claiming otherwise)
+#
+# Copyright (C) 2013 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()
+{
+ _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 generic
+_supported_os Linux
+
+size=128M
+
+_make_test_img $size
+
+function qemu_io_cmds()
+{
+cat <<EOF
+write -P 0x66 0 320k
+write 320k 128k
+write -P 0x55 1M 128k
+write -P 0x88 448k 128k
+discard 320k 128k
+aio_flush
+
+write -P 0x77 0 480k
+aio_flush
+
+read -P 0x77 0 480k
+read -P 0x88 480k 96k
+read -P 0x55 1M 128k
+EOF
+}
+
+qemu_io_cmds | $QEMU_IO $TEST_IMG | _filter_qemu_io
+_check_test_img
+
+# success, all done
+echo "*** done"
+rm -f $seq.full
+status=0
diff --git a/tests/qemu-iotests/047.out b/tests/qemu-iotests/047.out
new file mode 100644
index 000000000..81b2ff73b
--- /dev/null
+++ b/tests/qemu-iotests/047.out
@@ -0,0 +1,22 @@
+QA output created by 047
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728
+qemu-io> wrote 327680/327680 bytes at offset 0
+320 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+qemu-io> wrote 131072/131072 bytes at offset 327680
+128 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+qemu-io> wrote 131072/131072 bytes at offset 1048576
+128 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+qemu-io> wrote 131072/131072 bytes at offset 458752
+128 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+qemu-io> discard 131072/131072 bytes at offset 327680
+128 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+qemu-io> qemu-io> qemu-io> wrote 491520/491520 bytes at offset 0
+480 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+qemu-io> qemu-io> qemu-io> read 491520/491520 bytes at offset 0
+480 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+qemu-io> read 98304/98304 bytes at offset 491520
+96 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+qemu-io> read 131072/131072 bytes at offset 1048576
+128 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+qemu-io> No errors were found on the image.
+*** done
diff --git a/tests/qemu-iotests/048 b/tests/qemu-iotests/048
new file mode 100755
index 000000000..7cce049d2
--- /dev/null
+++ b/tests/qemu-iotests/048
@@ -0,0 +1,78 @@
+#!/bin/bash
+##
+## qemu-img compare test
+##
+##
+## Copyright (C) 2013 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=mrezanin@redhat.com
+
+seq=`basename $0`
+echo "QA output created by $seq"
+
+status=1 # failure is the default!
+
+_cleanup()
+{
+ echo "Cleanup"
+ _cleanup_test_img
+ rm ${TEST_IMG2}
+}
+trap "_cleanup; exit \$status" 0 1 2 3 15
+
+_compare()
+{
+ $QEMU_IMG compare "$@" $TEST_IMG ${TEST_IMG2}
+ echo $?
+}
+
+# get standard environment, filters and checks
+. ./common.rc
+. ./common.filter
+. ./common.pattern
+
+_supported_fmt raw qcow qcow2 qed
+_supported_proto file
+_supported_os Linux
+
+# Setup test basic parameters
+TEST_IMG2=$TEST_IMG.2
+CLUSTER_SIZE=4096
+size=1024M
+
+_make_test_img $size
+io_pattern write 524288 $CLUSTER_SIZE $CLUSTER_SIZE 4 45
+
+# Compare identical images
+cp $TEST_IMG ${TEST_IMG2}
+_compare
+_compare -q
+
+# Compare images with different size
+$QEMU_IMG resize $TEST_IMG +512M
+_compare
+_compare -s
+
+# Compare images with different content
+io_pattern write 1228800 $CLUSTER_SIZE 0 1 67
+_compare
+io_pattern write 0 $CLUSTER_SIZE 0 1 123
+_compare
+
+# Cleanup
+status=0
diff --git a/tests/qemu-iotests/048.out b/tests/qemu-iotests/048.out
new file mode 100644
index 000000000..68f65d5e1
--- /dev/null
+++ b/tests/qemu-iotests/048.out
@@ -0,0 +1,31 @@
+QA output created by 048
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1073741824
+=== IO: pattern 45
+qemu-io> wrote 4096/4096 bytes at offset 524288
+4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+qemu-io> wrote 4096/4096 bytes at offset 528384
+4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+qemu-io> wrote 4096/4096 bytes at offset 532480
+4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+qemu-io> wrote 4096/4096 bytes at offset 536576
+4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+qemu-io> Images are identical.
+0
+0
+Image resized.
+Warning: Image size mismatch!
+Images are identical.
+0
+Strict mode: Image size mismatch!
+1
+=== IO: pattern 67
+qemu-io> wrote 4096/4096 bytes at offset 1228800
+4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+qemu-io> Content mismatch at offset 1228800!
+1
+=== IO: pattern 123
+qemu-io> wrote 4096/4096 bytes at offset 0
+4 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+qemu-io> Content mismatch at offset 0!
+1
+Cleanup
diff --git a/tests/qemu-iotests/049 b/tests/qemu-iotests/049
new file mode 100755
index 000000000..6c6017e2d
--- /dev/null
+++ b/tests/qemu-iotests/049
@@ -0,0 +1,123 @@
+#!/bin/bash
+#
+# Check qemu-img option parsing
+#
+# Copyright (C) 2013 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()
+{
+ _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
+
+function filter_test_dir()
+{
+ sed -e "s#$IMGPROTO:$TEST_DIR#TEST_DIR#g" \
+ -e "s#$TEST_DIR#TEST_DIR#g"
+}
+
+function test_qemu_img()
+{
+ echo qemu-img "$@" | filter_test_dir
+ $QEMU_IMG "$@" 2>&1 | filter_test_dir
+ echo
+}
+
+echo "=== Check correct interpretation of suffixes for image size ==="
+echo
+sizes="1024 1024b 1k 1K 1M 1G 1T "
+sizes+="1024.0 1024.0b 1.5k 1.5K 1.5M 1.5G 1.5T"
+
+echo "== 1. Traditional size parameter =="
+echo
+for s in $sizes; do
+ test_qemu_img create -f $IMGFMT $TEST_IMG $s
+done
+
+echo "== 2. Specifying size via -o =="
+echo
+for s in $sizes; do
+ test_qemu_img create -f $IMGFMT -o size=$s $TEST_IMG
+done
+
+echo "== 3. Invalid sizes =="
+echo
+sizes="-1024 -1k 1kilobyte foobar"
+
+for s in $sizes; do
+ test_qemu_img create -f $IMGFMT $TEST_IMG -- $s
+ test_qemu_img create -f $IMGFMT -o size=$s $TEST_IMG
+done
+
+echo "== Check correct interpretation of suffixes for cluster size =="
+echo
+sizes="1024 1024b 1k 1K 1M "
+sizes+="1024.0 1024.0b 0.5k 0.5K 0.5M"
+
+for s in $sizes; do
+ test_qemu_img create -f $IMGFMT -o cluster_size=$s $TEST_IMG 64M
+done
+
+echo "== Check compat level option =="
+echo
+test_qemu_img create -f $IMGFMT -o compat=0.10 $TEST_IMG 64M
+test_qemu_img create -f $IMGFMT -o compat=1.1 $TEST_IMG 64M
+
+test_qemu_img create -f $IMGFMT -o compat=0.42 $TEST_IMG 64M
+test_qemu_img create -f $IMGFMT -o compat=foobar $TEST_IMG 64M
+
+echo "== Check preallocation option =="
+echo
+test_qemu_img create -f $IMGFMT -o preallocation=off $TEST_IMG 64M
+test_qemu_img create -f $IMGFMT -o preallocation=metadata $TEST_IMG 64M
+test_qemu_img create -f $IMGFMT -o preallocation=1234 $TEST_IMG 64M
+
+echo "== Check encryption option =="
+echo
+test_qemu_img create -f $IMGFMT -o encryption=off $TEST_IMG 64M
+test_qemu_img create -f $IMGFMT -o encryption=on $TEST_IMG 64M
+
+echo "== Check lazy_refcounts option (only with v3) =="
+echo
+test_qemu_img create -f $IMGFMT -o compat=1.1,lazy_refcounts=off $TEST_IMG 64M
+test_qemu_img create -f $IMGFMT -o compat=1.1,lazy_refcounts=on $TEST_IMG 64M
+
+test_qemu_img create -f $IMGFMT -o compat=0.10,lazy_refcounts=off $TEST_IMG 64M
+test_qemu_img create -f $IMGFMT -o compat=0.10,lazy_refcounts=on $TEST_IMG 64M
+
+# success, all done
+echo "*** done"
+rm -f $seq.full
+status=0
diff --git a/tests/qemu-iotests/049.out b/tests/qemu-iotests/049.out
new file mode 100644
index 000000000..d2f0efe16
--- /dev/null
+++ b/tests/qemu-iotests/049.out
@@ -0,0 +1,212 @@
+QA output created by 049
+=== Check correct interpretation of suffixes for image size ===
+
+== 1. Traditional size parameter ==
+
+qemu-img create -f qcow2 TEST_DIR/t.qcow2 1024
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1024 encryption=off cluster_size=65536 lazy_refcounts=off
+
+qemu-img create -f qcow2 TEST_DIR/t.qcow2 1024b
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1024 encryption=off cluster_size=65536 lazy_refcounts=off
+
+qemu-img create -f qcow2 TEST_DIR/t.qcow2 1k
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1024 encryption=off cluster_size=65536 lazy_refcounts=off
+
+qemu-img create -f qcow2 TEST_DIR/t.qcow2 1K
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1024 encryption=off cluster_size=65536 lazy_refcounts=off
+
+qemu-img create -f qcow2 TEST_DIR/t.qcow2 1M
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1048576 encryption=off cluster_size=65536 lazy_refcounts=off
+
+qemu-img create -f qcow2 TEST_DIR/t.qcow2 1G
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1073741824 encryption=off cluster_size=65536 lazy_refcounts=off
+
+qemu-img create -f qcow2 TEST_DIR/t.qcow2 1T
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1099511627776 encryption=off cluster_size=65536 lazy_refcounts=off
+
+qemu-img create -f qcow2 TEST_DIR/t.qcow2 1024.0
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1024 encryption=off cluster_size=65536 lazy_refcounts=off
+
+qemu-img create -f qcow2 TEST_DIR/t.qcow2 1024.0b
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1024 encryption=off cluster_size=65536 lazy_refcounts=off
+
+qemu-img create -f qcow2 TEST_DIR/t.qcow2 1.5k
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1536 encryption=off cluster_size=65536 lazy_refcounts=off
+
+qemu-img create -f qcow2 TEST_DIR/t.qcow2 1.5K
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1536 encryption=off cluster_size=65536 lazy_refcounts=off
+
+qemu-img create -f qcow2 TEST_DIR/t.qcow2 1.5M
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1572864 encryption=off cluster_size=65536 lazy_refcounts=off
+
+qemu-img create -f qcow2 TEST_DIR/t.qcow2 1.5G
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1610612736 encryption=off cluster_size=65536 lazy_refcounts=off
+
+qemu-img create -f qcow2 TEST_DIR/t.qcow2 1.5T
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1649267441664 encryption=off cluster_size=65536 lazy_refcounts=off
+
+== 2. Specifying size via -o ==
+
+qemu-img create -f qcow2 -o size=1024 TEST_DIR/t.qcow2
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1024 encryption=off cluster_size=65536 lazy_refcounts=off
+
+qemu-img create -f qcow2 -o size=1024b TEST_DIR/t.qcow2
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1024 encryption=off cluster_size=65536 lazy_refcounts=off
+
+qemu-img create -f qcow2 -o size=1k TEST_DIR/t.qcow2
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1024 encryption=off cluster_size=65536 lazy_refcounts=off
+
+qemu-img create -f qcow2 -o size=1K TEST_DIR/t.qcow2
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1024 encryption=off cluster_size=65536 lazy_refcounts=off
+
+qemu-img create -f qcow2 -o size=1M TEST_DIR/t.qcow2
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1048576 encryption=off cluster_size=65536 lazy_refcounts=off
+
+qemu-img create -f qcow2 -o size=1G TEST_DIR/t.qcow2
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1073741824 encryption=off cluster_size=65536 lazy_refcounts=off
+
+qemu-img create -f qcow2 -o size=1T TEST_DIR/t.qcow2
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1099511627776 encryption=off cluster_size=65536 lazy_refcounts=off
+
+qemu-img create -f qcow2 -o size=1024.0 TEST_DIR/t.qcow2
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1024 encryption=off cluster_size=65536 lazy_refcounts=off
+
+qemu-img create -f qcow2 -o size=1024.0b TEST_DIR/t.qcow2
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1024 encryption=off cluster_size=65536 lazy_refcounts=off
+
+qemu-img create -f qcow2 -o size=1.5k TEST_DIR/t.qcow2
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1536 encryption=off cluster_size=65536 lazy_refcounts=off
+
+qemu-img create -f qcow2 -o size=1.5K TEST_DIR/t.qcow2
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1536 encryption=off cluster_size=65536 lazy_refcounts=off
+
+qemu-img create -f qcow2 -o size=1.5M TEST_DIR/t.qcow2
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1572864 encryption=off cluster_size=65536 lazy_refcounts=off
+
+qemu-img create -f qcow2 -o size=1.5G TEST_DIR/t.qcow2
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1610612736 encryption=off cluster_size=65536 lazy_refcounts=off
+
+qemu-img create -f qcow2 -o size=1.5T TEST_DIR/t.qcow2
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1649267441664 encryption=off cluster_size=65536 lazy_refcounts=off
+
+== 3. Invalid sizes ==
+
+qemu-img create -f qcow2 TEST_DIR/t.qcow2 -- -1024
+qemu-img: Image size must be less than 8 EiB!
+
+qemu-img create -f qcow2 -o size=-1024 TEST_DIR/t.qcow2
+qemu-img: qcow2 doesn't support shrinking images yet
+qemu-img: Formatting or formatting option not supported for file format 'qcow2'
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=-1024 encryption=off cluster_size=65536 lazy_refcounts=off
+
+qemu-img create -f qcow2 TEST_DIR/t.qcow2 -- -1k
+qemu-img: Image size must be less than 8 EiB!
+
+qemu-img create -f qcow2 -o size=-1k TEST_DIR/t.qcow2
+qemu-img: qcow2 doesn't support shrinking images yet
+qemu-img: Formatting or formatting option not supported for file format 'qcow2'
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=-1024 encryption=off cluster_size=65536 lazy_refcounts=off
+
+qemu-img create -f qcow2 TEST_DIR/t.qcow2 -- 1kilobyte
+qemu-img: Invalid image size specified! You may use k, M, G, T, P or E suffixes for
+qemu-img: kilobytes, megabytes, gigabytes, terabytes, petabytes and exabytes.
+
+qemu-img create -f qcow2 -o size=1kilobyte TEST_DIR/t.qcow2
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=1024 encryption=off cluster_size=65536 lazy_refcounts=off
+
+qemu-img create -f qcow2 TEST_DIR/t.qcow2 -- foobar
+qemu-img: Invalid image size specified! You may use k, M, G, T, P or E suffixes for
+qemu-img: kilobytes, megabytes, gigabytes, terabytes, petabytes and exabytes.
+
+qemu-img create -f qcow2 -o size=foobar TEST_DIR/t.qcow2
+qemu-img: Parameter 'size' expects a size
+qemu-img: Invalid options for file format 'qcow2'.
+
+== Check correct interpretation of suffixes for cluster size ==
+
+qemu-img create -f qcow2 -o cluster_size=1024 TEST_DIR/t.qcow2 64M
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 encryption=off cluster_size=1024 lazy_refcounts=off
+
+qemu-img create -f qcow2 -o cluster_size=1024b TEST_DIR/t.qcow2 64M
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 encryption=off cluster_size=1024 lazy_refcounts=off
+
+qemu-img create -f qcow2 -o cluster_size=1k TEST_DIR/t.qcow2 64M
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 encryption=off cluster_size=1024 lazy_refcounts=off
+
+qemu-img create -f qcow2 -o cluster_size=1K TEST_DIR/t.qcow2 64M
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 encryption=off cluster_size=1024 lazy_refcounts=off
+
+qemu-img create -f qcow2 -o cluster_size=1M TEST_DIR/t.qcow2 64M
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 encryption=off cluster_size=1048576 lazy_refcounts=off
+
+qemu-img create -f qcow2 -o cluster_size=1024.0 TEST_DIR/t.qcow2 64M
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 encryption=off cluster_size=1024 lazy_refcounts=off
+
+qemu-img create -f qcow2 -o cluster_size=1024.0b TEST_DIR/t.qcow2 64M
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 encryption=off cluster_size=1024 lazy_refcounts=off
+
+qemu-img create -f qcow2 -o cluster_size=0.5k TEST_DIR/t.qcow2 64M
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 encryption=off cluster_size=512 lazy_refcounts=off
+
+qemu-img create -f qcow2 -o cluster_size=0.5K TEST_DIR/t.qcow2 64M
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 encryption=off cluster_size=512 lazy_refcounts=off
+
+qemu-img create -f qcow2 -o cluster_size=0.5M TEST_DIR/t.qcow2 64M
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 encryption=off cluster_size=524288 lazy_refcounts=off
+
+== Check compat level option ==
+
+qemu-img create -f qcow2 -o compat=0.10 TEST_DIR/t.qcow2 64M
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 compat='0.10' encryption=off cluster_size=65536 lazy_refcounts=off
+
+qemu-img create -f qcow2 -o compat=1.1 TEST_DIR/t.qcow2 64M
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 compat='1.1' encryption=off cluster_size=65536 lazy_refcounts=off
+
+qemu-img create -f qcow2 -o compat=0.42 TEST_DIR/t.qcow2 64M
+Invalid compatibility level: '0.42'
+qemu-img: TEST_DIR/t.qcow2: error while creating qcow2: Invalid argument
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 compat='0.42' encryption=off cluster_size=65536 lazy_refcounts=off
+
+qemu-img create -f qcow2 -o compat=foobar TEST_DIR/t.qcow2 64M
+Invalid compatibility level: 'foobar'
+qemu-img: TEST_DIR/t.qcow2: error while creating qcow2: Invalid argument
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 compat='foobar' encryption=off cluster_size=65536 lazy_refcounts=off
+
+== Check preallocation option ==
+
+qemu-img create -f qcow2 -o preallocation=off TEST_DIR/t.qcow2 64M
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 encryption=off cluster_size=65536 preallocation='off' lazy_refcounts=off
+
+qemu-img create -f qcow2 -o preallocation=metadata TEST_DIR/t.qcow2 64M
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 encryption=off cluster_size=65536 preallocation='metadata' lazy_refcounts=off
+
+qemu-img create -f qcow2 -o preallocation=1234 TEST_DIR/t.qcow2 64M
+Invalid preallocation mode: '1234'
+qemu-img: TEST_DIR/t.qcow2: error while creating qcow2: Invalid argument
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 encryption=off cluster_size=65536 preallocation='1234' lazy_refcounts=off
+
+== Check encryption option ==
+
+qemu-img create -f qcow2 -o encryption=off TEST_DIR/t.qcow2 64M
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 encryption=off cluster_size=65536 lazy_refcounts=off
+
+qemu-img create -f qcow2 -o encryption=on TEST_DIR/t.qcow2 64M
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 encryption=on cluster_size=65536 lazy_refcounts=off
+
+== Check lazy_refcounts option (only with v3) ==
+
+qemu-img create -f qcow2 -o compat=1.1,lazy_refcounts=off TEST_DIR/t.qcow2 64M
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 compat='1.1' encryption=off cluster_size=65536 lazy_refcounts=off
+
+qemu-img create -f qcow2 -o compat=1.1,lazy_refcounts=on TEST_DIR/t.qcow2 64M
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 compat='1.1' encryption=off cluster_size=65536 lazy_refcounts=on
+
+qemu-img create -f qcow2 -o compat=0.10,lazy_refcounts=off TEST_DIR/t.qcow2 64M
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 compat='0.10' encryption=off cluster_size=65536 lazy_refcounts=off
+
+qemu-img create -f qcow2 -o compat=0.10,lazy_refcounts=on TEST_DIR/t.qcow2 64M
+Lazy refcounts only supported with compatibility level 1.1 and above (use compat=1.1 or greater)
+qemu-img: TEST_DIR/t.qcow2: error while creating qcow2: Invalid argument
+Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 compat='0.10' encryption=off cluster_size=65536 lazy_refcounts=on
+
+*** done
diff --git a/tests/qemu-iotests/050 b/tests/qemu-iotests/050
new file mode 100755
index 000000000..05793e2d4
--- /dev/null
+++ b/tests/qemu-iotests/050
@@ -0,0 +1,75 @@
+#!/bin/bash
+#
+# Test qemu-img rebase with zero clusters
+#
+# Copyright (C) 2013 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=pbonzini@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
+ rm -f $TEST_IMG.old
+ rm -f $TEST_IMG.new
+}
+trap "_cleanup; exit \$status" 0 1 2 3 15
+
+# get standard environment, filters and checks
+. ./common.rc
+. ./common.filter
+
+_supported_fmt qcow2 qed
+_supported_proto file
+_supported_os Linux
+
+if test "$IMGFMT" = qcow2 && test $IMGOPTS = ""; then
+ IMGOPTS=compat=1.1
+fi
+
+echo
+echo "== Creating images =="
+
+size=10M
+_make_test_img $size
+$QEMU_IO -c "write -P 0x40 0 1048576" $TEST_IMG | _filter_qemu_io
+mv $TEST_IMG $TEST_IMG.old
+
+_make_test_img $size
+$QEMU_IO -c "write -P 0x5a 0 1048576" $TEST_IMG | _filter_qemu_io
+mv $TEST_IMG $TEST_IMG.new
+
+_make_test_img -b $TEST_IMG.old $size
+$QEMU_IO -c "write -z 0 1048576" $TEST_IMG | _filter_qemu_io
+
+echo
+echo "== Rebasing the image =="
+
+$QEMU_IMG rebase -b $TEST_IMG.new $TEST_IMG
+$QEMU_IO -c "read -P 0x00 0 1048576" $TEST_IMG | _filter_qemu_io
+
+# success, all done
+echo "*** done"
+rm -f $seq.full
+status=0
diff --git a/tests/qemu-iotests/050.out b/tests/qemu-iotests/050.out
new file mode 100644
index 000000000..3f5f7e1e7
--- /dev/null
+++ b/tests/qemu-iotests/050.out
@@ -0,0 +1,17 @@
+QA output created by 050
+
+== Creating images ==
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=10485760
+wrote 1048576/1048576 bytes at offset 0
+1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=10485760
+wrote 1048576/1048576 bytes at offset 0
+1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=10485760 backing_file='TEST_DIR/t.IMGFMT.old'
+wrote 1048576/1048576 bytes at offset 0
+1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+
+== Rebasing the image ==
+read 1048576/1048576 bytes at offset 0
+1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+*** done
diff --git a/tests/qemu-iotests/051 b/tests/qemu-iotests/051
new file mode 100755
index 000000000..1f39c6ad2
--- /dev/null
+++ b/tests/qemu-iotests/051
@@ -0,0 +1,167 @@
+#!/bin/bash
+#
+# Test command line configuration of block devices and driver-specific options
+#
+# Copyright (C) 2013 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()
+{
+ _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
+
+function do_run_qemu()
+{
+ echo Testing: "$@"
+ echo quit | $QEMU -nographic -monitor stdio -serial none "$@"
+ echo
+}
+
+function run_qemu()
+{
+ do_run_qemu "$@" 2>&1 | _filter_testdir | _filter_qemu
+}
+
+size=128M
+
+_make_test_img $size
+
+echo
+echo === Unknown option ===
+echo
+
+run_qemu -drive file=$TEST_IMG,format=qcow2,unknown_opt=
+run_qemu -drive file=$TEST_IMG,format=qcow2,unknown_opt=on
+run_qemu -drive file=$TEST_IMG,format=qcow2,unknown_opt=1234
+run_qemu -drive file=$TEST_IMG,format=qcow2,unknown_opt=foo
+
+
+echo
+echo === Enable and disable lazy refcounting on the command line, plus some invalid values ===
+echo
+
+run_qemu -drive file=$TEST_IMG,format=qcow2,lazy-refcounts=on
+run_qemu -drive file=$TEST_IMG,format=qcow2,lazy-refcounts=off
+run_qemu -drive file=$TEST_IMG,format=qcow2,lazy-refcounts=
+run_qemu -drive file=$TEST_IMG,format=qcow2,lazy-refcounts=42
+run_qemu -drive file=$TEST_IMG,format=qcow2,lazy-refcounts=foo
+
+
+echo
+echo === With version 2 images enabling lazy refcounts must fail ===
+echo
+
+_make_test_img -ocompat=0.10 $size
+
+run_qemu -drive file=$TEST_IMG,format=qcow2,lazy-refcounts=on
+run_qemu -drive file=$TEST_IMG,format=qcow2,lazy-refcounts=off
+
+echo
+echo === No medium ===
+echo
+
+run_qemu -drive if=floppy
+run_qemu -drive if=ide,media=cdrom
+run_qemu -drive if=scsi,media=cdrom
+
+run_qemu -drive if=ide
+run_qemu -drive if=virtio
+run_qemu -drive if=scsi
+
+run_qemu -drive if=none,id=disk -device ide-cd,drive=disk
+run_qemu -drive if=none,id=disk -device lsi53c895a -device scsi-cd,drive=disk
+
+run_qemu -drive if=none,id=disk -device ide-drive,drive=disk
+run_qemu -drive if=none,id=disk -device ide-hd,drive=disk
+run_qemu -drive if=none,id=disk -device lsi53c895a -device scsi-disk,drive=disk
+run_qemu -drive if=none,id=disk -device lsi53c895a -device scsi-hd,drive=disk
+
+echo
+echo === Read-only ===
+echo
+
+run_qemu -drive file=$TEST_IMG,if=floppy,readonly=on
+run_qemu -drive file=$TEST_IMG,if=ide,media=cdrom,readonly=on
+run_qemu -drive file=$TEST_IMG,if=scsi,media=cdrom,readonly=on
+
+run_qemu -drive file=$TEST_IMG,if=ide,readonly=on
+run_qemu -drive file=$TEST_IMG,if=virtio,readonly=on
+run_qemu -drive file=$TEST_IMG,if=scsi,readonly=on
+
+run_qemu -drive file=$TEST_IMG,if=none,id=disk,readonly=on -device ide-cd,drive=disk
+run_qemu -drive file=$TEST_IMG,if=none,id=disk,readonly=on -device lsi53c895a -device scsi-cd,drive=disk
+
+run_qemu -drive file=$TEST_IMG,if=none,id=disk,readonly=on -device ide-drive,drive=disk
+run_qemu -drive file=$TEST_IMG,if=none,id=disk,readonly=on -device ide-hd,drive=disk
+run_qemu -drive file=$TEST_IMG,if=none,id=disk,readonly=on -device lsi53c895a -device scsi-disk,drive=disk
+run_qemu -drive file=$TEST_IMG,if=none,id=disk,readonly=on -device lsi53c895a -device scsi-hd,drive=disk
+
+echo
+echo === Cache modes ===
+echo
+
+# Cannot use the test image because cache=none might not work on the host FS
+# Use cdrom so that we won't get errors about missing media
+
+run_qemu -drive media=cdrom,cache=none
+run_qemu -drive media=cdrom,cache=directsync
+run_qemu -drive media=cdrom,cache=writeback
+run_qemu -drive media=cdrom,cache=writethrough
+run_qemu -drive media=cdrom,cache=unsafe
+run_qemu -drive media=cdrom,cache=invalid_value
+
+echo
+echo === Specifying the protocol layer ===
+echo
+
+run_qemu -drive file=$TEST_IMG,file.driver=file
+run_qemu -drive file=$TEST_IMG,file.driver=qcow2
+
+echo
+echo === Parsing protocol from file name ===
+echo
+
+# Protocol strings are supposed to be parsed from traditional option strings,
+# but not when using driver-specific options. We can distinguish them by the
+# error message for non-existing files.
+
+run_qemu -hda foo:bar
+run_qemu -drive file=foo:bar
+run_qemu -drive file.filename=foo:bar
+
+# success, all done
+echo "*** done"
+rm -f $seq.full
+status=0
diff --git a/tests/qemu-iotests/051.out b/tests/qemu-iotests/051.out
new file mode 100644
index 000000000..5582ed365
--- /dev/null
+++ b/tests/qemu-iotests/051.out
@@ -0,0 +1,229 @@
+QA output created by 051
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728
+
+=== Unknown option ===
+
+Testing: -drive file=TEST_DIR/t.qcow2,format=qcow2,unknown_opt=
+QEMU_PROG: -drive file=TEST_DIR/t.qcow2,format=qcow2,unknown_opt=: Block format 'qcow2' used by device 'ide0-hd0' doesn't support the option 'unknown_opt'
+QEMU_PROG: -drive file=TEST_DIR/t.qcow2,format=qcow2,unknown_opt=: could not open disk image TEST_DIR/t.qcow2: Invalid argument
+
+Testing: -drive file=TEST_DIR/t.qcow2,format=qcow2,unknown_opt=on
+QEMU_PROG: -drive file=TEST_DIR/t.qcow2,format=qcow2,unknown_opt=on: Block format 'qcow2' used by device 'ide0-hd0' doesn't support the option 'unknown_opt'
+QEMU_PROG: -drive file=TEST_DIR/t.qcow2,format=qcow2,unknown_opt=on: could not open disk image TEST_DIR/t.qcow2: Invalid argument
+
+Testing: -drive file=TEST_DIR/t.qcow2,format=qcow2,unknown_opt=1234
+QEMU_PROG: -drive file=TEST_DIR/t.qcow2,format=qcow2,unknown_opt=1234: Block format 'qcow2' used by device 'ide0-hd0' doesn't support the option 'unknown_opt'
+QEMU_PROG: -drive file=TEST_DIR/t.qcow2,format=qcow2,unknown_opt=1234: could not open disk image TEST_DIR/t.qcow2: Invalid argument
+
+Testing: -drive file=TEST_DIR/t.qcow2,format=qcow2,unknown_opt=foo
+QEMU_PROG: -drive file=TEST_DIR/t.qcow2,format=qcow2,unknown_opt=foo: Block format 'qcow2' used by device 'ide0-hd0' doesn't support the option 'unknown_opt'
+QEMU_PROG: -drive file=TEST_DIR/t.qcow2,format=qcow2,unknown_opt=foo: could not open disk image TEST_DIR/t.qcow2: Invalid argument
+
+
+=== Enable and disable lazy refcounting on the command line, plus some invalid values ===
+
+Testing: -drive file=TEST_DIR/t.qcow2,format=qcow2,lazy-refcounts=on
+QEMU X.Y.Z monitor - type 'help' for more information
+(qemu) qququiquit
+
+Testing: -drive file=TEST_DIR/t.qcow2,format=qcow2,lazy-refcounts=off
+QEMU X.Y.Z monitor - type 'help' for more information
+(qemu) qququiquit
+
+Testing: -drive file=TEST_DIR/t.qcow2,format=qcow2,lazy-refcounts=
+QEMU_PROG: -drive file=TEST_DIR/t.qcow2,format=qcow2,lazy-refcounts=: Parameter 'lazy-refcounts' expects 'on' or 'off'
+QEMU_PROG: -drive file=TEST_DIR/t.qcow2,format=qcow2,lazy-refcounts=: could not open disk image TEST_DIR/t.qcow2: Invalid argument
+
+Testing: -drive file=TEST_DIR/t.qcow2,format=qcow2,lazy-refcounts=42
+QEMU_PROG: -drive file=TEST_DIR/t.qcow2,format=qcow2,lazy-refcounts=42: Parameter 'lazy-refcounts' expects 'on' or 'off'
+QEMU_PROG: -drive file=TEST_DIR/t.qcow2,format=qcow2,lazy-refcounts=42: could not open disk image TEST_DIR/t.qcow2: Invalid argument
+
+Testing: -drive file=TEST_DIR/t.qcow2,format=qcow2,lazy-refcounts=foo
+QEMU_PROG: -drive file=TEST_DIR/t.qcow2,format=qcow2,lazy-refcounts=foo: Parameter 'lazy-refcounts' expects 'on' or 'off'
+QEMU_PROG: -drive file=TEST_DIR/t.qcow2,format=qcow2,lazy-refcounts=foo: could not open disk image TEST_DIR/t.qcow2: Invalid argument
+
+
+=== With version 2 images enabling lazy refcounts must fail ===
+
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728
+Testing: -drive file=TEST_DIR/t.qcow2,format=qcow2,lazy-refcounts=on
+QEMU_PROG: -drive file=TEST_DIR/t.qcow2,format=qcow2,lazy-refcounts=on: Lazy refcounts require a qcow2 image with at least qemu 1.1 compatibility level
+QEMU_PROG: -drive file=TEST_DIR/t.qcow2,format=qcow2,lazy-refcounts=on: could not open disk image TEST_DIR/t.qcow2: Invalid argument
+
+Testing: -drive file=TEST_DIR/t.qcow2,format=qcow2,lazy-refcounts=off
+QEMU X.Y.Z monitor - type 'help' for more information
+(qemu) qququiquit
+
+
+=== No medium ===
+
+Testing: -drive if=floppy
+QEMU X.Y.Z monitor - type 'help' for more information
+(qemu) qququiquit
+
+Testing: -drive if=ide,media=cdrom
+QEMU X.Y.Z monitor - type 'help' for more information
+(qemu) qququiquit
+
+Testing: -drive if=scsi,media=cdrom
+QEMU X.Y.Z monitor - type 'help' for more information
+(qemu) qququiquit
+
+Testing: -drive if=ide
+QEMU X.Y.Z monitor - type 'help' for more information
+(qemu) QEMU_PROG: Device needs media, but drive is empty
+QEMU_PROG: Device initialization failed.
+QEMU_PROG: Initialization of device ide-hd failed
+
+Testing: -drive if=virtio
+QEMU X.Y.Z monitor - type 'help' for more information
+(qemu) QEMU_PROG: -drive if=virtio: Device needs media, but drive is empty
+QEMU_PROG: -drive if=virtio: Device initialization failed.
+QEMU_PROG: -drive if=virtio: Device initialization failed.
+QEMU_PROG: -drive if=virtio: Device 'virtio-blk-pci' could not be initialized
+
+Testing: -drive if=scsi
+QEMU X.Y.Z monitor - type 'help' for more information
+(qemu) QEMU_PROG: -drive if=scsi: Device needs media, but drive is empty
+QEMU_PROG: -drive if=scsi: Device initialization failed.
+QEMU_PROG: Device initialization failed.
+QEMU_PROG: Initialization of device lsi53c895a failed
+
+Testing: -drive if=none,id=disk -device ide-cd,drive=disk
+QEMU X.Y.Z monitor - type 'help' for more information
+(qemu) qququiquit
+
+Testing: -drive if=none,id=disk -device lsi53c895a -device scsi-cd,drive=disk
+QEMU X.Y.Z monitor - type 'help' for more information
+(qemu) qququiquit
+
+Testing: -drive if=none,id=disk -device ide-drive,drive=disk
+QEMU X.Y.Z monitor - type 'help' for more information
+(qemu) QEMU_PROG: -device ide-drive,drive=disk: Device needs media, but drive is empty
+QEMU_PROG: -device ide-drive,drive=disk: Device initialization failed.
+QEMU_PROG: -device ide-drive,drive=disk: Device 'ide-drive' could not be initialized
+
+Testing: -drive if=none,id=disk -device ide-hd,drive=disk
+QEMU X.Y.Z monitor - type 'help' for more information
+(qemu) QEMU_PROG: -device ide-hd,drive=disk: Device needs media, but drive is empty
+QEMU_PROG: -device ide-hd,drive=disk: Device initialization failed.
+QEMU_PROG: -device ide-hd,drive=disk: Device 'ide-hd' could not be initialized
+
+Testing: -drive if=none,id=disk -device lsi53c895a -device scsi-disk,drive=disk
+QEMU X.Y.Z monitor - type 'help' for more information
+(qemu) QEMU_PROG: -device scsi-disk,drive=disk: Device needs media, but drive is empty
+QEMU_PROG: -device scsi-disk,drive=disk: Device initialization failed.
+QEMU_PROG: -device scsi-disk,drive=disk: Device 'scsi-disk' could not be initialized
+
+Testing: -drive if=none,id=disk -device lsi53c895a -device scsi-hd,drive=disk
+QEMU X.Y.Z monitor - type 'help' for more information
+(qemu) QEMU_PROG: -device scsi-hd,drive=disk: Device needs media, but drive is empty
+QEMU_PROG: -device scsi-hd,drive=disk: Device initialization failed.
+QEMU_PROG: -device scsi-hd,drive=disk: Device 'scsi-hd' could not be initialized
+
+
+=== Read-only ===
+
+Testing: -drive file=TEST_DIR/t.qcow2,if=floppy,readonly=on
+QEMU X.Y.Z monitor - type 'help' for more information
+(qemu) qququiquit
+
+Testing: -drive file=TEST_DIR/t.qcow2,if=ide,media=cdrom,readonly=on
+QEMU X.Y.Z monitor - type 'help' for more information
+(qemu) qququiquit
+
+Testing: -drive file=TEST_DIR/t.qcow2,if=scsi,media=cdrom,readonly=on
+QEMU X.Y.Z monitor - type 'help' for more information
+(qemu) qququiquit
+
+Testing: -drive file=TEST_DIR/t.qcow2,if=ide,readonly=on
+QEMU_PROG: -drive file=TEST_DIR/t.qcow2,if=ide,readonly=on: read-only not supported by this bus type
+
+Testing: -drive file=TEST_DIR/t.qcow2,if=virtio,readonly=on
+QEMU X.Y.Z monitor - type 'help' for more information
+(qemu) qququiquit
+
+Testing: -drive file=TEST_DIR/t.qcow2,if=scsi,readonly=on
+QEMU X.Y.Z monitor - type 'help' for more information
+(qemu) qququiquit
+
+Testing: -drive file=TEST_DIR/t.qcow2,if=none,id=disk,readonly=on -device ide-cd,drive=disk
+QEMU X.Y.Z monitor - type 'help' for more information
+(qemu) qququiquit
+
+Testing: -drive file=TEST_DIR/t.qcow2,if=none,id=disk,readonly=on -device lsi53c895a -device scsi-cd,drive=disk
+QEMU X.Y.Z monitor - type 'help' for more information
+(qemu) qququiquit
+
+Testing: -drive file=TEST_DIR/t.qcow2,if=none,id=disk,readonly=on -device ide-drive,drive=disk
+QEMU X.Y.Z monitor - type 'help' for more information
+(qemu) QEMU_PROG: -device ide-drive,drive=disk: Can't use a read-only drive
+QEMU_PROG: -device ide-drive,drive=disk: Device initialization failed.
+QEMU_PROG: -device ide-drive,drive=disk: Device 'ide-drive' could not be initialized
+
+Testing: -drive file=TEST_DIR/t.qcow2,if=none,id=disk,readonly=on -device ide-hd,drive=disk
+QEMU X.Y.Z monitor - type 'help' for more information
+(qemu) QEMU_PROG: -device ide-hd,drive=disk: Can't use a read-only drive
+QEMU_PROG: -device ide-hd,drive=disk: Device initialization failed.
+QEMU_PROG: -device ide-hd,drive=disk: Device 'ide-hd' could not be initialized
+
+Testing: -drive file=TEST_DIR/t.qcow2,if=none,id=disk,readonly=on -device lsi53c895a -device scsi-disk,drive=disk
+QEMU X.Y.Z monitor - type 'help' for more information
+(qemu) qququiquit
+
+Testing: -drive file=TEST_DIR/t.qcow2,if=none,id=disk,readonly=on -device lsi53c895a -device scsi-hd,drive=disk
+QEMU X.Y.Z monitor - type 'help' for more information
+(qemu) qququiquit
+
+
+=== Cache modes ===
+
+Testing: -drive media=cdrom,cache=none
+QEMU X.Y.Z monitor - type 'help' for more information
+(qemu) qququiquit
+
+Testing: -drive media=cdrom,cache=directsync
+QEMU X.Y.Z monitor - type 'help' for more information
+(qemu) qququiquit
+
+Testing: -drive media=cdrom,cache=writeback
+QEMU X.Y.Z monitor - type 'help' for more information
+(qemu) qququiquit
+
+Testing: -drive media=cdrom,cache=writethrough
+QEMU X.Y.Z monitor - type 'help' for more information
+(qemu) qququiquit
+
+Testing: -drive media=cdrom,cache=unsafe
+QEMU X.Y.Z monitor - type 'help' for more information
+(qemu) qququiquit
+
+Testing: -drive media=cdrom,cache=invalid_value
+QEMU_PROG: -drive media=cdrom,cache=invalid_value: invalid cache option
+
+
+=== Specifying the protocol layer ===
+
+Testing: -drive file=TEST_DIR/t.qcow2,file.driver=file
+QEMU X.Y.Z monitor - type 'help' for more information
+(qemu) qququiquit
+
+Testing: -drive file=TEST_DIR/t.qcow2,file.driver=qcow2
+QEMU_PROG: -drive file=TEST_DIR/t.qcow2,file.driver=qcow2: Can't use 'qcow2' as a block driver for the protocol level
+QEMU_PROG: -drive file=TEST_DIR/t.qcow2,file.driver=qcow2: could not open disk image TEST_DIR/t.qcow2: Invalid argument
+
+
+=== Parsing protocol from file name ===
+
+Testing: -hda foo:bar
+QEMU_PROG: -hda foo:bar: Unknown protocol
+QEMU_PROG: -hda foo:bar: could not open disk image foo:bar: No such file or directory
+
+Testing: -drive file=foo:bar
+QEMU_PROG: -drive file=foo:bar: Unknown protocol
+QEMU_PROG: -drive file=foo:bar: could not open disk image foo:bar: No such file or directory
+
+Testing: -drive file.filename=foo:bar
+QEMU_PROG: -drive file.filename=foo:bar: could not open disk image ide0-hd0: No such file or directory
+
+*** done
diff --git a/tests/qemu-iotests/052 b/tests/qemu-iotests/052
new file mode 100755
index 000000000..14a512663
--- /dev/null
+++ b/tests/qemu-iotests/052
@@ -0,0 +1,61 @@
+#!/bin/bash
+#
+# Test bdrv_read/bdrv_write using BDRV_O_SNAPSHOT
+#
+# Copyright (C) 2013 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=stefanha@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 generic
+_supported_proto generic
+_supported_os Linux
+
+
+size=128M
+_make_test_img $size
+
+echo
+echo "== reading whole image =="
+$QEMU_IO -s -c "read 0 $size" $TEST_IMG | _filter_qemu_io
+
+echo
+echo "== writing whole image does not modify image =="
+$QEMU_IO -s -c "write -P 0xa 0 $size" $TEST_IMG | _filter_qemu_io
+$QEMU_IO -c "read -P 0 0 $size" $TEST_IMG | _filter_qemu_io
+
+# success, all done
+echo "*** done"
+rm -f $seq.full
+status=0
diff --git a/tests/qemu-iotests/052.out b/tests/qemu-iotests/052.out
new file mode 100644
index 000000000..8617aa2a9
--- /dev/null
+++ b/tests/qemu-iotests/052.out
@@ -0,0 +1,13 @@
+QA output created by 052
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728
+
+== reading whole image ==
+read 134217728/134217728 bytes at offset 0
+128 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+
+== writing whole image does not modify image ==
+wrote 134217728/134217728 bytes at offset 0
+128 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+read 134217728/134217728 bytes at offset 0
+128 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+*** done
diff --git a/tests/qemu-iotests/053 b/tests/qemu-iotests/053
new file mode 100755
index 000000000..bc5699258
--- /dev/null
+++ b/tests/qemu-iotests/053
@@ -0,0 +1,73 @@
+#!/bin/bash
+#
+# Test qemu-img convert when image length is not a multiple of cluster size
+#
+# Copyright (C) 2013 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=stefanha@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.orig
+ _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 qcow
+_supported_proto file
+_supported_os Linux
+
+echo
+echo "== Creating single sector image =="
+
+_make_test_img 512
+$QEMU_IO -c "write -P0xa 0 512" $TEST_IMG | _filter_qemu_io
+mv $TEST_IMG $TEST_IMG.orig
+
+echo
+echo "== Converting the image, compressed =="
+
+$QEMU_IMG convert -c -O $IMGFMT $TEST_IMG.orig $TEST_IMG
+_check_test_img
+
+echo
+echo "== Checking compressed image virtual disk size =="
+
+_img_info | grep '^virtual size:'
+
+echo
+echo "== Verifying the compressed image =="
+
+$QEMU_IO -c "read -P0xa 0 512" $TEST_IMG | _filter_qemu_io
+
+# success, all done
+echo "*** done"
+rm -f $seq.full
+status=0
+
diff --git a/tests/qemu-iotests/053.out b/tests/qemu-iotests/053.out
new file mode 100644
index 000000000..16464e6dd
--- /dev/null
+++ b/tests/qemu-iotests/053.out
@@ -0,0 +1,17 @@
+QA output created by 053
+
+== Creating single sector image ==
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=512
+wrote 512/512 bytes at offset 0
+512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+
+== Converting the image, compressed ==
+No errors were found on the image.
+
+== Checking compressed image virtual disk size ==
+virtual size: 512 (512 bytes)
+
+== Verifying the compressed image ==
+read 512/512 bytes at offset 0
+512 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+*** done
diff --git a/tests/qemu-iotests/054 b/tests/qemu-iotests/054
new file mode 100755
index 000000000..b36042958
--- /dev/null
+++ b/tests/qemu-iotests/054
@@ -0,0 +1,58 @@
+#!/bin/bash
+#
+# Test huge qcow2 images
+#
+# Copyright (C) 2013 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()
+{
+ _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 generic
+_supported_os Linux
+
+echo
+echo "creating too large image (1 EB)"
+_make_test_img $((1024*1024))T
+
+echo
+echo "creating too large image (1 EB) using qcow2.py"
+_make_test_img 4G
+./qcow2.py $TEST_IMG set-header size $((1024 ** 6))
+_check_test_img
+
+# success, all done
+echo "*** done"
+rm -f $seq.full
+status=0
diff --git a/tests/qemu-iotests/054.out b/tests/qemu-iotests/054.out
new file mode 100644
index 000000000..2f357c271
--- /dev/null
+++ b/tests/qemu-iotests/054.out
@@ -0,0 +1,10 @@
+QA output created by 054
+
+creating too large image (1 EB)
+qemu-img: The image size is too large for file format 'qcow2' (try using a larger cluster size)
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=1152921504606846976
+
+creating too large image (1 EB) using qcow2.py
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=4294967296
+qemu-img: Could not open 'TEST_DIR/t.qcow2': File too large
+*** done
diff --git a/tests/qemu-iotests/055 b/tests/qemu-iotests/055
new file mode 100755
index 000000000..44bb02568
--- /dev/null
+++ b/tests/qemu-iotests/055
@@ -0,0 +1,294 @@
+#!/usr/bin/env python
+#
+# Tests for drive-backup
+#
+# Copyright (C) 2013 Red Hat, Inc.
+#
+# Based on 041.
+#
+# 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/>.
+#
+
+import time
+import os
+import iotests
+from iotests import qemu_img, qemu_io
+
+test_img = os.path.join(iotests.test_dir, 'test.img')
+target_img = os.path.join(iotests.test_dir, 'target.img')
+
+class TestSingleDrive(iotests.QMPTestCase):
+ image_len = 64 * 1024 * 1024 # MB
+
+ def setUp(self):
+ # Write data to the image so we can compare later
+ qemu_img('create', '-f', iotests.imgfmt, test_img, str(TestSingleDrive.image_len))
+ qemu_io('-c', 'write -P0x5d 0 64k', test_img)
+ qemu_io('-c', 'write -P0xd5 1M 32k', test_img)
+ qemu_io('-c', 'write -P0xdc 32M 124k', test_img)
+ qemu_io('-c', 'write -P0xdc 67043328 64k', test_img)
+
+ self.vm = iotests.VM().add_drive(test_img)
+ self.vm.launch()
+
+ def tearDown(self):
+ self.vm.shutdown()
+ os.remove(test_img)
+ try:
+ os.remove(target_img)
+ except OSError:
+ pass
+
+ def test_cancel(self):
+ self.assert_no_active_block_jobs()
+
+ result = self.vm.qmp('drive-backup', device='drive0',
+ target=target_img, sync='full')
+ self.assert_qmp(result, 'return', {})
+
+ event = self.cancel_and_wait()
+ self.assert_qmp(event, 'data/type', 'backup')
+
+ def test_pause(self):
+ self.assert_no_active_block_jobs()
+
+ result = self.vm.qmp('drive-backup', device='drive0',
+ target=target_img, sync='full')
+ self.assert_qmp(result, 'return', {})
+
+ result = self.vm.qmp('block-job-pause', device='drive0')
+ self.assert_qmp(result, 'return', {})
+
+ time.sleep(1)
+ result = self.vm.qmp('query-block-jobs')
+ offset = self.dictpath(result, 'return[0]/offset')
+
+ time.sleep(1)
+ result = self.vm.qmp('query-block-jobs')
+ self.assert_qmp(result, 'return[0]/offset', offset)
+
+ result = self.vm.qmp('block-job-resume', device='drive0')
+ self.assert_qmp(result, 'return', {})
+
+ self.wait_until_completed()
+
+ self.vm.shutdown()
+ self.assertTrue(iotests.compare_images(test_img, target_img),
+ 'target image does not match source after backup')
+
+ def test_medium_not_found(self):
+ result = self.vm.qmp('drive-backup', device='ide1-cd0',
+ target=target_img, sync='full')
+ self.assert_qmp(result, 'error/class', 'GenericError')
+
+ def test_image_not_found(self):
+ result = self.vm.qmp('drive-backup', device='drive0',
+ target=target_img, sync='full', mode='existing')
+ self.assert_qmp(result, 'error/class', 'GenericError')
+
+ def test_invalid_format(self):
+ result = self.vm.qmp('drive-backup', device='drive0',
+ target=target_img, sync='full',
+ format='spaghetti-noodles')
+ self.assert_qmp(result, 'error/class', 'GenericError')
+
+ def test_device_not_found(self):
+ result = self.vm.qmp('drive-backup', device='nonexistent',
+ target=target_img, sync='full')
+ self.assert_qmp(result, 'error/class', 'DeviceNotFound')
+
+class TestSetSpeed(iotests.QMPTestCase):
+ image_len = 80 * 1024 * 1024 # MB
+
+ def setUp(self):
+ qemu_img('create', '-f', iotests.imgfmt, test_img, str(TestSetSpeed.image_len))
+ self.vm = iotests.VM().add_drive(test_img)
+ self.vm.launch()
+
+ def tearDown(self):
+ self.vm.shutdown()
+ os.remove(test_img)
+ os.remove(target_img)
+
+ def test_set_speed(self):
+ self.assert_no_active_block_jobs()
+
+ result = self.vm.qmp('drive-backup', device='drive0',
+ target=target_img, sync='full')
+ self.assert_qmp(result, 'return', {})
+
+ # Default speed is 0
+ result = self.vm.qmp('query-block-jobs')
+ self.assert_qmp(result, 'return[0]/device', 'drive0')
+ self.assert_qmp(result, 'return[0]/speed', 0)
+
+ result = self.vm.qmp('block-job-set-speed', device='drive0', speed=8 * 1024 * 1024)
+ self.assert_qmp(result, 'return', {})
+
+ # Ensure the speed we set was accepted
+ result = self.vm.qmp('query-block-jobs')
+ self.assert_qmp(result, 'return[0]/device', 'drive0')
+ self.assert_qmp(result, 'return[0]/speed', 8 * 1024 * 1024)
+
+ event = self.cancel_and_wait()
+ self.assert_qmp(event, 'data/type', 'backup')
+
+ # Check setting speed in drive-backup works
+ result = self.vm.qmp('drive-backup', device='drive0',
+ target=target_img, sync='full', speed=4*1024*1024)
+ self.assert_qmp(result, 'return', {})
+
+ result = self.vm.qmp('query-block-jobs')
+ self.assert_qmp(result, 'return[0]/device', 'drive0')
+ self.assert_qmp(result, 'return[0]/speed', 4 * 1024 * 1024)
+
+ event = self.cancel_and_wait()
+ self.assert_qmp(event, 'data/type', 'backup')
+
+ def test_set_speed_invalid(self):
+ self.assert_no_active_block_jobs()
+
+ result = self.vm.qmp('drive-backup', device='drive0',
+ target=target_img, sync='full', speed=-1)
+ self.assert_qmp(result, 'error/class', 'GenericError')
+
+ self.assert_no_active_block_jobs()
+
+ result = self.vm.qmp('drive-backup', device='drive0',
+ target=target_img, sync='full')
+ self.assert_qmp(result, 'return', {})
+
+ result = self.vm.qmp('block-job-set-speed', device='drive0', speed=-1)
+ self.assert_qmp(result, 'error/class', 'GenericError')
+
+ event = self.cancel_and_wait()
+ self.assert_qmp(event, 'data/type', 'backup')
+
+class TestSingleTransaction(iotests.QMPTestCase):
+ image_len = 64 * 1024 * 1024 # MB
+
+ def setUp(self):
+ qemu_img('create', '-f', iotests.imgfmt, test_img, str(TestSingleTransaction.image_len))
+ qemu_io('-c', 'write -P0x5d 0 64k', test_img)
+ qemu_io('-c', 'write -P0xd5 1M 32k', test_img)
+ qemu_io('-c', 'write -P0xdc 32M 124k', test_img)
+ qemu_io('-c', 'write -P0xdc 67043328 64k', test_img)
+
+ self.vm = iotests.VM().add_drive(test_img)
+ self.vm.launch()
+
+ def tearDown(self):
+ self.vm.shutdown()
+ os.remove(test_img)
+ try:
+ os.remove(target_img)
+ except OSError:
+ pass
+
+ def test_cancel(self):
+ self.assert_no_active_block_jobs()
+
+ result = self.vm.qmp('transaction', actions=[{
+ 'type': 'drive-backup',
+ 'data': { 'device': 'drive0',
+ 'target': target_img,
+ 'sync': 'full' },
+ }
+ ])
+ self.assert_qmp(result, 'return', {})
+
+ event = self.cancel_and_wait()
+ self.assert_qmp(event, 'data/type', 'backup')
+
+ def test_pause(self):
+ self.assert_no_active_block_jobs()
+
+ result = self.vm.qmp('transaction', actions=[{
+ 'type': 'drive-backup',
+ 'data': { 'device': 'drive0',
+ 'target': target_img,
+ 'sync': 'full' },
+ }
+ ])
+ self.assert_qmp(result, 'return', {})
+
+ result = self.vm.qmp('block-job-pause', device='drive0')
+ self.assert_qmp(result, 'return', {})
+
+ time.sleep(1)
+ result = self.vm.qmp('query-block-jobs')
+ offset = self.dictpath(result, 'return[0]/offset')
+
+ time.sleep(1)
+ result = self.vm.qmp('query-block-jobs')
+ self.assert_qmp(result, 'return[0]/offset', offset)
+
+ result = self.vm.qmp('block-job-resume', device='drive0')
+ self.assert_qmp(result, 'return', {})
+
+ self.wait_until_completed()
+
+ self.vm.shutdown()
+ self.assertTrue(iotests.compare_images(test_img, target_img),
+ 'target image does not match source after backup')
+
+ def test_medium_not_found(self):
+ result = self.vm.qmp('transaction', actions=[{
+ 'type': 'drive-backup',
+ 'data': { 'device': 'ide1-cd0',
+ 'target': target_img,
+ 'sync': 'full' },
+ }
+ ])
+ self.assert_qmp(result, 'error/class', 'GenericError')
+
+ def test_image_not_found(self):
+ result = self.vm.qmp('transaction', actions=[{
+ 'type': 'drive-backup',
+ 'data': { 'device': 'drive0',
+ 'mode': 'existing',
+ 'target': target_img,
+ 'sync': 'full' },
+ }
+ ])
+ self.assert_qmp(result, 'error/class', 'GenericError')
+
+ def test_device_not_found(self):
+ result = self.vm.qmp('transaction', actions=[{
+ 'type': 'drive-backup',
+ 'data': { 'device': 'nonexistent',
+ 'mode': 'existing',
+ 'target': target_img,
+ 'sync': 'full' },
+ }
+ ])
+ self.assert_qmp(result, 'error/class', 'DeviceNotFound')
+
+ def test_abort(self):
+ result = self.vm.qmp('transaction', actions=[{
+ 'type': 'drive-backup',
+ 'data': { 'device': 'nonexistent',
+ 'mode': 'existing',
+ 'target': target_img,
+ 'sync': 'full' },
+ }, {
+ 'type': 'Abort',
+ 'data': {},
+ }
+ ])
+ self.assert_qmp(result, 'error/class', 'GenericError')
+ self.assert_no_active_block_jobs()
+
+if __name__ == '__main__':
+ iotests.main(supported_fmts=['raw', 'qcow2'])
diff --git a/tests/qemu-iotests/055.out b/tests/qemu-iotests/055.out
new file mode 100644
index 000000000..6323079e0
--- /dev/null
+++ b/tests/qemu-iotests/055.out
@@ -0,0 +1,5 @@
+..............
+----------------------------------------------------------------------
+Ran 14 tests
+
+OK
diff --git a/tests/qemu-iotests/056 b/tests/qemu-iotests/056
new file mode 100755
index 000000000..63893423c
--- /dev/null
+++ b/tests/qemu-iotests/056
@@ -0,0 +1,94 @@
+#!/usr/bin/env python
+#
+# Tests for drive-backup
+#
+# Copyright (C) 2013 Red Hat, Inc.
+#
+# Based on 041.
+#
+# 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/>.
+#
+
+import time
+import os
+import iotests
+from iotests import qemu_img, qemu_io, create_image
+
+backing_img = os.path.join(iotests.test_dir, 'backing.img')
+test_img = os.path.join(iotests.test_dir, 'test.img')
+target_img = os.path.join(iotests.test_dir, 'target.img')
+
+class TestSyncModesNoneAndTop(iotests.QMPTestCase):
+ image_len = 64 * 1024 * 1024 # MB
+
+ def setUp(self):
+ create_image(backing_img, TestSyncModesNoneAndTop.image_len)
+ qemu_img('create', '-f', iotests.imgfmt, '-o', 'backing_file=%s' % backing_img, test_img)
+ qemu_io('-c', 'write -P0x41 0 512', test_img)
+ qemu_io('-c', 'write -P0xd5 1M 32k', test_img)
+ qemu_io('-c', 'write -P0xdc 32M 124k', test_img)
+ qemu_io('-c', 'write -P0xdc 67043328 64k', test_img)
+ self.vm = iotests.VM().add_drive(test_img)
+ self.vm.launch()
+
+ def tearDown(self):
+ self.vm.shutdown()
+ os.remove(test_img)
+ os.remove(backing_img)
+ try:
+ os.remove(target_img)
+ except OSError:
+ pass
+
+ def test_complete_top(self):
+ self.assert_no_active_block_jobs()
+ result = self.vm.qmp('drive-backup', device='drive0', sync='top',
+ format=iotests.imgfmt, target=target_img)
+ self.assert_qmp(result, 'return', {})
+
+ # Custom completed check as we are not copying all data.
+ completed = False
+ while not completed:
+ for event in self.vm.get_qmp_events(wait=True):
+ if event['event'] == 'BLOCK_JOB_COMPLETED':
+ self.assert_qmp(event, 'data/device', 'drive0')
+ self.assert_qmp_absent(event, 'data/error')
+ completed = True
+
+ self.assert_no_active_block_jobs()
+ self.vm.shutdown()
+ self.assertTrue(iotests.compare_images(test_img, target_img),
+ 'target image does not match source after backup')
+
+ def test_cancel_sync_none(self):
+ self.assert_no_active_block_jobs()
+
+ result = self.vm.qmp('drive-backup', device='drive0',
+ sync='none', target=target_img)
+ self.assert_qmp(result, 'return', {})
+ time.sleep(1)
+ self.vm.hmp_qemu_io('drive0', 'write -P0x5e 0 512')
+ self.vm.hmp_qemu_io('drive0', 'aio_flush')
+ # Verify that the original contents exist in the target image.
+
+ event = self.cancel_and_wait()
+ self.assert_qmp(event, 'data/type', 'backup')
+
+ self.vm.shutdown()
+ time.sleep(1)
+ self.assertEqual(-1, qemu_io('-c', 'read -P0x41 0 512', target_img).find("verification failed"))
+
+
+if __name__ == '__main__':
+ iotests.main(supported_fmts=['qcow2', 'qed'])
diff --git a/tests/qemu-iotests/056.out b/tests/qemu-iotests/056.out
new file mode 100644
index 000000000..fbc63e62f
--- /dev/null
+++ b/tests/qemu-iotests/056.out
@@ -0,0 +1,5 @@
+..
+----------------------------------------------------------------------
+Ran 2 tests
+
+OK
diff --git a/tests/qemu-iotests/059 b/tests/qemu-iotests/059
new file mode 100755
index 000000000..b03429dd0
--- /dev/null
+++ b/tests/qemu-iotests/059
@@ -0,0 +1,72 @@
+#!/bin/bash
+#
+# Test case for vmdk
+#
+# Copyright (C) 2013 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=famz@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
+
+# This tests vmdk-specific low-level functionality
+_supported_fmt vmdk
+_supported_proto generic
+_supported_os Linux
+
+capacity_offset=16
+granularity_offset=20
+grain_table_size_offset=44
+
+echo "=== Testing invalid granularity ==="
+echo
+_make_test_img 64M
+poke_file "$TEST_IMG" "$granularity_offset" "\xff\xff\xff\xff\xff\xff\xff\xff"
+{ $QEMU_IO -c "read 0 512" $TEST_IMG; } 2>&1 | _filter_qemu_io | _filter_testdir
+
+echo "=== Testing too big L2 table size ==="
+echo
+_make_test_img 64M
+poke_file "$TEST_IMG" "$grain_table_size_offset" "\xff\xff\xff\xff"
+{ $QEMU_IO -c "read 0 512" $TEST_IMG; } 2>&1 | _filter_qemu_io | _filter_testdir
+
+echo "=== Testing too big L1 table size ==="
+echo
+_make_test_img 64M
+poke_file "$TEST_IMG" "$capacity_offset" "\xff\xff\xff\xff"
+poke_file "$TEST_IMG" "$grain_table_size_offset" "\x01\x00\x00\x00"
+{ $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/059.out b/tests/qemu-iotests/059.out
new file mode 100644
index 000000000..9e715e5a9
--- /dev/null
+++ b/tests/qemu-iotests/059.out
@@ -0,0 +1,20 @@
+QA output created by 059
+=== Testing invalid granularity ===
+
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
+invalid granularity, image may be corrupt
+qemu-io: can't open device TEST_DIR/t.vmdk
+no file open, try 'help open'
+=== Testing too big L2 table size ===
+
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
+L2 table size too big
+qemu-io: can't open device TEST_DIR/t.vmdk
+no file open, try 'help open'
+=== Testing too big L1 table size ===
+
+Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=67108864
+L1 size too big
+qemu-io: can't open device TEST_DIR/t.vmdk
+no file open, try 'help open'
+*** done
diff --git a/tests/qemu-iotests/check b/tests/qemu-iotests/check
index 432732cfc..74628ae63 100755
--- a/tests/qemu-iotests/check
+++ b/tests/qemu-iotests/check
@@ -214,7 +214,8 @@ do
start=`_wallclock`
$timestamp && echo -n " ["`date "+%T"`"]"
[ ! -x $seq ] && chmod u+x $seq # ensure we can run it
- ./$seq >$tmp.out 2>&1
+ MALLOC_PERTURB_=${MALLOC_PERTURB_:-$(($RANDOM % 255 + 1))} \
+ ./$seq >$tmp.out 2>&1
sts=$?
$timestamp && _timestamp
stop=`_wallclock`
diff --git a/tests/qemu-iotests/common b/tests/qemu-iotests/common
index b3aad89e2..6826ea72f 100644
--- a/tests/qemu-iotests/common
+++ b/tests/qemu-iotests/common
@@ -137,6 +137,7 @@ check options
-rbd test rbd
-sheepdog test sheepdog
-nbd test nbd
+ -ssh test ssh
-xdiff graphical mode diff
-nocache use O_DIRECT on backing file
-misalign misalign memory allocations
@@ -206,6 +207,10 @@ testlist options
IMGPROTO=nbd
xpand=false
;;
+ -ssh)
+ IMGPROTO=ssh
+ xpand=false
+ ;;
-nocache)
QEMU_IO_OPTIONS="$QEMU_IO_OPTIONS --nocache"
xpand=false
diff --git a/tests/qemu-iotests/common.filter b/tests/qemu-iotests/common.filter
index fa26b62dd..97a31ff0b 100644
--- a/tests/qemu-iotests/common.filter
+++ b/tests/qemu-iotests/common.filter
@@ -152,5 +152,12 @@ _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)/"
}
+# replace occurrences of QEMU_PROG with "qemu"
+_filter_qemu()
+{
+ sed -e "s#\\(^\\|(qemu) \\)$(basename $QEMU_PROG):#\1QEMU_PROG:#" \
+ -e 's#^QEMU [0-9]\+\.[0-9]\+\.[0-9]\+ monitor#QEMU X.Y.Z monitor#'
+}
+
# make sure this script returns success
/bin/true
diff --git a/tests/qemu-iotests/common.rc b/tests/qemu-iotests/common.rc
index aef5f52b4..5e077c357 100644
--- a/tests/qemu-iotests/common.rc
+++ b/tests/qemu-iotests/common.rc
@@ -34,6 +34,12 @@ dd()
fi
}
+# poke_file 'test.img' 512 '\xff\xfe'
+poke_file()
+{
+ printf "$3" | dd "of=$1" bs=1 "seek=$2" conv=notrunc &>/dev/null
+}
+
# we need common.config
if [ "$iam" != "check" ]
then
@@ -52,6 +58,9 @@ if [ "$IMGPROTO" = "file" ]; then
elif [ "$IMGPROTO" = "nbd" ]; then
TEST_IMG_FILE=$TEST_DIR/t.$IMGFMT
TEST_IMG="nbd:127.0.0.1:10810"
+elif [ "$IMGPROTO" = "ssh" ]; then
+ TEST_IMG_FILE=$TEST_DIR/t.$IMGFMT
+ TEST_IMG="ssh://127.0.0.1$TEST_IMG_FILE"
else
TEST_IMG=$IMGPROTO:$TEST_DIR/t.$IMGFMT
fi
@@ -124,6 +133,9 @@ _make_test_img()
-e "s# compat='[^']*'##g" \
-e "s# compat6=\\(on\\|off\\)##g" \
-e "s# static=\\(on\\|off\\)##g" \
+ -e "s# zeroed_grain=\\(on\\|off\\)##g" \
+ -e "s# subformat='[^']*'##g" \
+ -e "s# adapter_type='[^']*'##g" \
-e "s# lazy_refcounts=\\(on\\|off\\)##g"
# Start an NBD server on the image file, which is what we'll be talking to
@@ -161,9 +173,10 @@ _cleanup_test_img()
_check_test_img()
{
- $QEMU_IMG check -f $IMGFMT $TEST_IMG 2>&1 | \
- grep -v "fragmented$" | \
- sed -e 's/qemu-img\: This image format does not support checks/No errors were found on the image./'
+ $QEMU_IMG check "$@" -f $IMGFMT $TEST_IMG 2>&1 | _filter_testdir | \
+ sed -e '/allocated.*fragmented.*compressed clusters/d' \
+ -e 's/qemu-img: This image format does not support checks/No errors were found on the image./' \
+ -e '/Image end offset: [0-9]\+/d'
}
_img_info()
diff --git a/tests/qemu-iotests/group b/tests/qemu-iotests/group
index a4a9044f2..43c05d6f5 100644
--- a/tests/qemu-iotests/group
+++ b/tests/qemu-iotests/group
@@ -51,3 +51,16 @@
042 rw auto quick
043 rw auto backing
044 rw auto
+045 rw auto
+046 rw auto aio
+047 rw auto
+048 img auto quick
+049 rw auto
+050 rw auto backing quick
+#051 rw auto
+052 rw auto backing
+053 rw auto
+054 rw auto
+055 rw auto
+056 rw auto backing
+059 rw auto
diff --git a/tests/qemu-iotests/iotests.py b/tests/qemu-iotests/iotests.py
index b2eaf20f0..33ad0ecb9 100644
--- a/tests/qemu-iotests/iotests.py
+++ b/tests/qemu-iotests/iotests.py
@@ -23,6 +23,7 @@ import string
import unittest
import sys; sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..', 'QMP'))
import qmp
+import struct
__all__ = ['imgfmt', 'imgproto', 'test_dir' 'qemu_img', 'qemu_io',
'VM', 'QMPTestCase', 'notrun', 'main']
@@ -43,7 +44,7 @@ def qemu_img(*args):
return subprocess.call(qemu_img_args + list(args), stdin=devnull, stdout=devnull)
def qemu_img_verbose(*args):
- '''Run qemu-img without supressing its output and return the exit code'''
+ '''Run qemu-img without suppressing its output and return the exit code'''
return subprocess.call(qemu_img_args + list(args))
def qemu_io(*args):
@@ -51,6 +52,21 @@ def qemu_io(*args):
args = qemu_io_args + list(args)
return subprocess.Popen(args, stdout=subprocess.PIPE).communicate()[0]
+def compare_images(img1, img2):
+ '''Return True if two image files are identical'''
+ return qemu_img('compare', '-f', imgfmt,
+ '-F', imgfmt, img1, img2) == 0
+
+def create_image(name, size):
+ '''Create a fully-allocated raw image with sector markers'''
+ file = open(name, 'w')
+ i = 0
+ while i < size:
+ sector = struct.pack('>l504xl', i / 512, i / 512)
+ file.write(sector)
+ i = i + 512
+ file.close()
+
class VM(object):
'''A QEMU VM'''
@@ -79,6 +95,23 @@ class VM(object):
self._num_drives += 1
return self
+ def hmp_qemu_io(self, drive, cmd):
+ '''Write to a given drive using an HMP command'''
+ return self.qmp('human-monitor-command',
+ command_line='qemu-io %s "%s"' % (drive, cmd))
+
+ def add_fd(self, fd, fdset, opaque, opts=''):
+ '''Pass a file descriptor to the VM'''
+ options = ['fd=%d' % fd,
+ 'set=%d' % fdset,
+ 'opaque=%s' % opaque]
+ if opts:
+ options.append(opts)
+
+ self._args.append('-add-fd')
+ self._args.append(','.join(options))
+ return self
+
def launch(self):
'''Launch the VM and establish a QMP connection'''
devnull = open('/dev/null', 'rb')
@@ -158,6 +191,43 @@ class QMPTestCase(unittest.TestCase):
result = self.dictpath(d, path)
self.assertEqual(result, value, 'values not equal "%s" and "%s"' % (str(result), str(value)))
+ def assert_no_active_block_jobs(self):
+ result = self.vm.qmp('query-block-jobs')
+ self.assert_qmp(result, 'return', [])
+
+ def cancel_and_wait(self, drive='drive0', force=False):
+ '''Cancel a block job and wait for it to finish, returning the event'''
+ result = self.vm.qmp('block-job-cancel', device=drive, force=force)
+ self.assert_qmp(result, 'return', {})
+
+ cancelled = False
+ result = None
+ while not cancelled:
+ for event in self.vm.get_qmp_events(wait=True):
+ if event['event'] == 'BLOCK_JOB_COMPLETED' or \
+ event['event'] == 'BLOCK_JOB_CANCELLED':
+ self.assert_qmp(event, 'data/device', drive)
+ result = event
+ cancelled = True
+
+ self.assert_no_active_block_jobs()
+ return result
+
+ def wait_until_completed(self, drive='drive0'):
+ '''Wait for a block job to finish, returning the event'''
+ completed = False
+ while not completed:
+ for event in self.vm.get_qmp_events(wait=True):
+ if event['event'] == 'BLOCK_JOB_COMPLETED':
+ self.assert_qmp(event, 'data/device', drive)
+ self.assert_qmp_absent(event, 'data/error')
+ self.assert_qmp(event, 'data/offset', self.image_len)
+ self.assert_qmp(event, 'data/len', self.image_len)
+ completed = True
+
+ self.assert_no_active_block_jobs()
+ return event
+
def notrun(reason):
'''Skip this test suite'''
# Each test in qemu-iotests has a number ("seq")
diff --git a/tests/qemu-iotests/qcow2.py b/tests/qemu-iotests/qcow2.py
index fecf5b9a5..44a2b4564 100755
--- a/tests/qemu-iotests/qcow2.py
+++ b/tests/qemu-iotests/qcow2.py
@@ -149,6 +149,22 @@ def cmd_dump_header(fd):
h.dump()
h.dump_extensions()
+def cmd_set_header(fd, name, value):
+ try:
+ value = int(value, 0)
+ except:
+ print "'%s' is not a valid number" % value
+ sys.exit(1)
+
+ fields = (field[2] for field in QcowHeader.fields)
+ if not name in fields:
+ print "'%s' is not a known header field" % name
+ sys.exit(1)
+
+ h = QcowHeader(fd)
+ h.__dict__[name] = value
+ h.update(fd)
+
def cmd_add_header_ext(fd, magic, data):
try:
magic = int(magic, 0)
@@ -205,6 +221,7 @@ def cmd_set_feature_bit(fd, group, bit):
cmds = [
[ 'dump-header', cmd_dump_header, 0, 'Dump image header and header extensions' ],
+ [ 'set-header', cmd_set_header, 2, 'Set a field in the header'],
[ 'add-header-ext', cmd_add_header_ext, 2, 'Add a header extension' ],
[ 'del-header-ext', cmd_del_header_ext, 1, 'Delete a header extension' ],
[ 'set-feature-bit', cmd_set_feature_bit, 2, 'Set a feature bit'],
diff --git a/tests/rtc-test.c b/tests/rtc-test.c
index 02edbf572..3395d7f50 100644
--- a/tests/rtc-test.c
+++ b/tests/rtc-test.c
@@ -11,7 +11,7 @@
*
*/
#include "libqtest.h"
-#include "hw/mc146818rtc_regs.h"
+#include "hw/timer/mc146818rtc_regs.h"
#include <glib.h>
#include <stdio.h>
@@ -26,11 +26,6 @@ static int bcd2dec(int value)
return (((value >> 4) & 0x0F) * 10) + (value & 0x0F);
}
-static int dec2bcd(int value)
-{
- return ((value / 10) << 4) | (value % 10);
-}
-
static uint8_t cmos_read(uint8_t reg)
{
outb(base + 0, reg);
@@ -115,7 +110,9 @@ static void cmos_get_date_time(struct tm *date)
date->tm_mday = mday;
date->tm_mon = mon - 1;
date->tm_year = base_year + year - 1900;
+#ifndef __sun__
date->tm_gmtoff = 0;
+#endif
ts = mktime(date);
}
@@ -182,7 +179,7 @@ static int wiggle = 2;
static void set_year_20xx(void)
{
/* Set BCD mode */
- cmos_write(RTC_REG_B, cmos_read(RTC_REG_B) & ~REG_B_DM);
+ cmos_write(RTC_REG_B, REG_B_24H);
cmos_write(RTC_REG_A, 0x76);
cmos_write(RTC_YEAR, 0x11);
cmos_write(RTC_CENTURY, 0x20);
@@ -201,6 +198,10 @@ static void set_year_20xx(void)
g_assert_cmpint(cmos_read(RTC_YEAR), ==, 0x11);
g_assert_cmpint(cmos_read(RTC_CENTURY), ==, 0x20);
+ if (sizeof(time_t) == 4) {
+ return;
+ }
+
/* Set a date in 2080 to ensure there is no year-2038 overflow. */
cmos_write(RTC_REG_A, 0x76);
cmos_write(RTC_YEAR, 0x80);
@@ -230,7 +231,7 @@ static void set_year_20xx(void)
static void set_year_1980(void)
{
/* Set BCD mode */
- cmos_write(RTC_REG_B, cmos_read(RTC_REG_B) & ~REG_B_DM);
+ cmos_write(RTC_REG_B, REG_B_24H);
cmos_write(RTC_REG_A, 0x76);
cmos_write(RTC_YEAR, 0x80);
cmos_write(RTC_CENTURY, 0x19);
@@ -253,32 +254,17 @@ static void set_year_1980(void)
static void bcd_check_time(void)
{
/* Set BCD mode */
- cmos_write(RTC_REG_B, cmos_read(RTC_REG_B) & ~REG_B_DM);
+ cmos_write(RTC_REG_B, REG_B_24H);
check_time(wiggle);
}
static void dec_check_time(void)
{
/* Set DEC mode */
- cmos_write(RTC_REG_B, cmos_read(RTC_REG_B) | REG_B_DM);
+ cmos_write(RTC_REG_B, REG_B_24H | REG_B_DM);
check_time(wiggle);
}
-static void set_alarm_time(struct tm *tm)
-{
- int sec;
-
- sec = tm->tm_sec;
-
- if ((cmos_read(RTC_REG_B) & REG_B_DM) == 0) {
- sec = dec2bcd(sec);
- }
-
- cmos_write(RTC_SECONDS_ALARM, sec);
- cmos_write(RTC_MINUTES_ALARM, RTC_ALARM_DONT_CARE);
- cmos_write(RTC_HOURS_ALARM, RTC_ALARM_DONT_CARE);
-}
-
static void alarm_time(void)
{
struct tm now;
@@ -289,13 +275,15 @@ static void alarm_time(void)
gmtime_r(&ts, &now);
/* set DEC mode */
- cmos_write(RTC_REG_B, cmos_read(RTC_REG_B) | REG_B_DM);
+ cmos_write(RTC_REG_B, REG_B_24H | REG_B_DM);
g_assert(!get_irq(RTC_ISA_IRQ));
cmos_read(RTC_REG_C);
now.tm_sec = (now.tm_sec + 2) % 60;
- set_alarm_time(&now);
+ cmos_write(RTC_SECONDS_ALARM, now.tm_sec);
+ cmos_write(RTC_MINUTES_ALARM, RTC_ALARM_DONT_CARE);
+ cmos_write(RTC_HOURS_ALARM, RTC_ALARM_DONT_CARE);
cmos_write(RTC_REG_B, cmos_read(RTC_REG_B) | REG_B_AIE);
for (i = 0; i < 2 + wiggle; i++) {
@@ -311,6 +299,197 @@ static void alarm_time(void)
g_assert(cmos_read(RTC_REG_C) == 0);
}
+static void set_time(int mode, int h, int m, int s)
+{
+ /* set BCD 12 hour mode */
+ cmos_write(RTC_REG_B, mode);
+
+ cmos_write(RTC_REG_A, 0x76);
+ cmos_write(RTC_HOURS, h);
+ cmos_write(RTC_MINUTES, m);
+ cmos_write(RTC_SECONDS, s);
+ cmos_write(RTC_REG_A, 0x26);
+}
+
+#define assert_time(h, m, s) \
+ do { \
+ g_assert_cmpint(cmos_read(RTC_HOURS), ==, h); \
+ g_assert_cmpint(cmos_read(RTC_MINUTES), ==, m); \
+ g_assert_cmpint(cmos_read(RTC_SECONDS), ==, s); \
+ } while(0)
+
+static void basic_12h_bcd(void)
+{
+ /* set BCD 12 hour mode */
+ set_time(0, 0x81, 0x59, 0x00);
+ clock_step(1000000000LL);
+ assert_time(0x81, 0x59, 0x01);
+ clock_step(59000000000LL);
+ assert_time(0x82, 0x00, 0x00);
+
+ /* test BCD wraparound */
+ set_time(0, 0x09, 0x59, 0x59);
+ clock_step(60000000000LL);
+ assert_time(0x10, 0x00, 0x59);
+
+ /* 12 AM -> 1 AM */
+ set_time(0, 0x12, 0x59, 0x59);
+ clock_step(1000000000LL);
+ assert_time(0x01, 0x00, 0x00);
+
+ /* 12 PM -> 1 PM */
+ set_time(0, 0x92, 0x59, 0x59);
+ clock_step(1000000000LL);
+ assert_time(0x81, 0x00, 0x00);
+
+ /* 11 AM -> 12 PM */
+ set_time(0, 0x11, 0x59, 0x59);
+ clock_step(1000000000LL);
+ assert_time(0x92, 0x00, 0x00);
+ /* TODO: test day wraparound */
+
+ /* 11 PM -> 12 AM */
+ set_time(0, 0x91, 0x59, 0x59);
+ clock_step(1000000000LL);
+ assert_time(0x12, 0x00, 0x00);
+ /* TODO: test day wraparound */
+}
+
+static void basic_12h_dec(void)
+{
+ /* set decimal 12 hour mode */
+ set_time(REG_B_DM, 0x81, 59, 0);
+ clock_step(1000000000LL);
+ assert_time(0x81, 59, 1);
+ clock_step(59000000000LL);
+ assert_time(0x82, 0, 0);
+
+ /* 12 PM -> 1 PM */
+ set_time(REG_B_DM, 0x8c, 59, 59);
+ clock_step(1000000000LL);
+ assert_time(0x81, 0, 0);
+
+ /* 12 AM -> 1 AM */
+ set_time(REG_B_DM, 0x0c, 59, 59);
+ clock_step(1000000000LL);
+ assert_time(0x01, 0, 0);
+
+ /* 11 AM -> 12 PM */
+ set_time(REG_B_DM, 0x0b, 59, 59);
+ clock_step(1000000000LL);
+ assert_time(0x8c, 0, 0);
+
+ /* 11 PM -> 12 AM */
+ set_time(REG_B_DM, 0x8b, 59, 59);
+ clock_step(1000000000LL);
+ assert_time(0x0c, 0, 0);
+ /* TODO: test day wraparound */
+}
+
+static void basic_24h_bcd(void)
+{
+ /* set BCD 24 hour mode */
+ set_time(REG_B_24H, 0x09, 0x59, 0x00);
+ clock_step(1000000000LL);
+ assert_time(0x09, 0x59, 0x01);
+ clock_step(59000000000LL);
+ assert_time(0x10, 0x00, 0x00);
+
+ /* test BCD wraparound */
+ set_time(REG_B_24H, 0x09, 0x59, 0x00);
+ clock_step(60000000000LL);
+ assert_time(0x10, 0x00, 0x00);
+
+ /* TODO: test day wraparound */
+ set_time(REG_B_24H, 0x23, 0x59, 0x00);
+ clock_step(60000000000LL);
+ assert_time(0x00, 0x00, 0x00);
+}
+
+static void basic_24h_dec(void)
+{
+ /* set decimal 24 hour mode */
+ set_time(REG_B_24H | REG_B_DM, 9, 59, 0);
+ clock_step(1000000000LL);
+ assert_time(9, 59, 1);
+ clock_step(59000000000LL);
+ assert_time(10, 0, 0);
+
+ /* test BCD wraparound */
+ set_time(REG_B_24H | REG_B_DM, 9, 59, 0);
+ clock_step(60000000000LL);
+ assert_time(10, 0, 0);
+
+ /* TODO: test day wraparound */
+ set_time(REG_B_24H | REG_B_DM, 23, 59, 0);
+ clock_step(60000000000LL);
+ assert_time(0, 0, 0);
+}
+
+static void am_pm_alarm(void)
+{
+ cmos_write(RTC_MINUTES_ALARM, 0xC0);
+ cmos_write(RTC_SECONDS_ALARM, 0xC0);
+
+ /* set BCD 12 hour mode */
+ cmos_write(RTC_REG_B, 0);
+
+ /* Set time and alarm hour. */
+ cmos_write(RTC_REG_A, 0x76);
+ cmos_write(RTC_HOURS_ALARM, 0x82);
+ cmos_write(RTC_HOURS, 0x81);
+ cmos_write(RTC_MINUTES, 0x59);
+ cmos_write(RTC_SECONDS, 0x00);
+ cmos_read(RTC_REG_C);
+ cmos_write(RTC_REG_A, 0x26);
+
+ /* Check that alarm triggers when AM/PM is set. */
+ clock_step(60000000000LL);
+ g_assert(cmos_read(RTC_HOURS) == 0x82);
+ g_assert((cmos_read(RTC_REG_C) & REG_C_AF) != 0);
+
+ /*
+ * Each of the following two tests takes over 60 seconds due to the time
+ * needed to report the PIT interrupts. Unfortunately, our PIT device
+ * model keeps counting even when GATE=0, so we cannot simply disable
+ * it in main().
+ */
+ if (g_test_quick()) {
+ return;
+ }
+
+ /* set DEC 12 hour mode */
+ cmos_write(RTC_REG_B, REG_B_DM);
+
+ /* Set time and alarm hour. */
+ cmos_write(RTC_REG_A, 0x76);
+ cmos_write(RTC_HOURS_ALARM, 0x82);
+ cmos_write(RTC_HOURS, 3);
+ cmos_write(RTC_MINUTES, 0);
+ cmos_write(RTC_SECONDS, 0);
+ cmos_read(RTC_REG_C);
+ cmos_write(RTC_REG_A, 0x26);
+
+ /* Check that alarm triggers. */
+ clock_step(3600 * 11 * 1000000000LL);
+ g_assert(cmos_read(RTC_HOURS) == 0x82);
+ g_assert((cmos_read(RTC_REG_C) & REG_C_AF) != 0);
+
+ /* Same as above, with inverted HOURS and HOURS_ALARM. */
+ cmos_write(RTC_REG_A, 0x76);
+ cmos_write(RTC_HOURS_ALARM, 2);
+ cmos_write(RTC_HOURS, 3);
+ cmos_write(RTC_MINUTES, 0);
+ cmos_write(RTC_SECONDS, 0);
+ cmos_read(RTC_REG_C);
+ cmos_write(RTC_REG_A, 0x26);
+
+ /* Check that alarm does not trigger if hours differ only by AM/PM. */
+ clock_step(3600 * 11 * 1000000000LL);
+ g_assert(cmos_read(RTC_HOURS) == 0x82);
+ g_assert((cmos_read(RTC_REG_C) & REG_C_AF) == 0);
+}
+
/* success if no crash or abort */
static void fuzz_registers(void)
{
@@ -330,7 +509,7 @@ static void fuzz_registers(void)
static void register_b_set_flag(void)
{
/* Enable binary-coded decimal (BCD) mode and SET flag in Register B*/
- cmos_write(RTC_REG_B, (cmos_read(RTC_REG_B) & ~REG_B_DM) | REG_B_SET);
+ cmos_write(RTC_REG_B, REG_B_24H | REG_B_SET);
cmos_write(RTC_REG_A, 0x76);
cmos_write(RTC_YEAR, 0x11);
@@ -376,13 +555,18 @@ int main(int argc, char **argv)
s = qtest_start("-display none -rtc clock=vm");
qtest_irq_intercept_in(s, "ioapic");
- qtest_add_func("/rtc/bcd/check-time", bcd_check_time);
- qtest_add_func("/rtc/dec/check-time", dec_check_time);
- qtest_add_func("/rtc/alarm-time", alarm_time);
+ qtest_add_func("/rtc/check-time/bcd", bcd_check_time);
+ qtest_add_func("/rtc/check-time/dec", dec_check_time);
+ qtest_add_func("/rtc/alarm/interrupt", alarm_time);
+ qtest_add_func("/rtc/alarm/am-pm", am_pm_alarm);
+ qtest_add_func("/rtc/basic/dec-24h", basic_24h_dec);
+ qtest_add_func("/rtc/basic/bcd-24h", basic_24h_bcd);
+ qtest_add_func("/rtc/basic/dec-12h", basic_12h_dec);
+ qtest_add_func("/rtc/basic/bcd-12h", basic_12h_bcd);
qtest_add_func("/rtc/set-year/20xx", set_year_20xx);
qtest_add_func("/rtc/set-year/1980", set_year_1980);
- qtest_add_func("/rtc/register_b_set_flag", register_b_set_flag);
- qtest_add_func("/rtc/fuzz-registers", fuzz_registers);
+ qtest_add_func("/rtc/misc/register_b_set_flag", register_b_set_flag);
+ qtest_add_func("/rtc/misc/fuzz-registers", fuzz_registers);
ret = g_test_run();
if (s) {
diff --git a/tests/tcg/cris/crisutils.h b/tests/tcg/cris/crisutils.h
index 29b71cd7b..3456b9d50 100644
--- a/tests/tcg/cris/crisutils.h
+++ b/tests/tcg/cris/crisutils.h
@@ -1,3 +1,6 @@
+#ifndef CRISUTILS_H
+#define CRISUTILS_H 1
+
static char *tst_cc_loc = NULL;
#define cris_tst_cc_init() \
@@ -69,3 +72,5 @@ static inline void cris_tst_cc(const int n, const int z,
if (c) cris_tst_cc_c1(); else cris_tst_cc_c0();
asm volatile ("" : : "g" (_err));
}
+
+#endif
diff --git a/tests/tcg/linux-test.c b/tests/tcg/linux-test.c
index 83cb32ddb..1c6c01318 100644
--- a/tests/tcg/linux-test.c
+++ b/tests/tcg/linux-test.c
@@ -39,7 +39,6 @@
#include <dirent.h>
#include <setjmp.h>
#include <sys/shm.h>
-#include <sched.h>
#define TESTPATH "/tmp/linux-test.tmp"
#define TESTPORT 7654
diff --git a/tests/tcg/lm32/test_cmpgei.S b/tests/tcg/lm32/test_cmpgei.S
index 6a8870f4c..6e388a2a3 100644
--- a/tests/tcg/lm32/test_cmpgei.S
+++ b/tests/tcg/lm32/test_cmpgei.S
@@ -52,4 +52,19 @@ mvi r3, 0
cmpgei r3, r3, 0
check_r3 1
+test_name CMPGEI_11
+mvi r1, 0
+cmpgei r3, r1, -32768
+check_r3 1
+
+test_name CMPGEI_12
+mvi r1, -1
+cmpgei r3, r1, -32768
+check_r3 1
+
+test_name CMPGEI_13
+mvi r1, -32768
+cmpgei r3, r1, -32768
+check_r3 1
+
end
diff --git a/tests/tcg/lm32/test_cmpgeui.S b/tests/tcg/lm32/test_cmpgeui.S
index b9d1755e2..3866d96cb 100644
--- a/tests/tcg/lm32/test_cmpgeui.S
+++ b/tests/tcg/lm32/test_cmpgeui.S
@@ -52,4 +52,19 @@ mvi r3, 0
cmpgeui r3, r3, 0
check_r3 1
+test_name CMPGEUI_11
+mvi r1, 0
+cmpgeui r3, r1, 0x8000
+check_r3 0
+
+test_name CMPGEUI_12
+mvi r1, -1
+cmpgeui r3, r1, 0x8000
+check_r3 1
+
+test_name CMPGEUI_13
+ori r1, r0, 0x8000
+cmpgeui r3, r1, 0x8000
+check_r3 1
+
end
diff --git a/tests/tcg/lm32/test_cmpgi.S b/tests/tcg/lm32/test_cmpgi.S
index 1f622d290..21695f97a 100644
--- a/tests/tcg/lm32/test_cmpgi.S
+++ b/tests/tcg/lm32/test_cmpgi.S
@@ -52,4 +52,19 @@ mvi r3, 0
cmpgi r3, r3, 0
check_r3 0
+test_name CMPGI_11
+mvi r1, 0
+cmpgi r3, r1, -32768
+check_r3 1
+
+test_name CMPGI_12
+mvi r1, -1
+cmpgi r3, r1, -32768
+check_r3 1
+
+test_name CMPGI_13
+mvi r1, -32768
+cmpgi r3, r1, -32768
+check_r3 0
+
end
diff --git a/tests/tcg/lm32/test_cmpgui.S b/tests/tcg/lm32/test_cmpgui.S
index 759bb64b3..dd9400149 100644
--- a/tests/tcg/lm32/test_cmpgui.S
+++ b/tests/tcg/lm32/test_cmpgui.S
@@ -35,7 +35,7 @@ check_r3 1
test_name CMPGUI_7
mvi r1, -1
cmpgui r3, r1, 0xffff
-check_r3 0
+check_r3 1
test_name CMPGUI_8
mvi r3, 0
@@ -52,4 +52,19 @@ mvi r3, 0
cmpgui r3, r3, 0
check_r3 0
+test_name CMPGUI_11
+mvi r1, 0
+cmpgui r3, r1, 0x8000
+check_r3 0
+
+test_name CMPGUI_12
+mvi r1, -1
+cmpgui r3, r1, 0x8000
+check_r3 1
+
+test_name CMPGUI_13
+ori r1, r0, 0x8000
+cmpgui r3, r1, 0x8000
+check_r3 0
+
end
diff --git a/tests/tcg/mips/mips32-dsp/dpaq_sa_l_w.c b/tests/tcg/mips/mips32-dsp/dpaq_sa_l_w.c
index ce864844d..cbf900713 100644
--- a/tests/tcg/mips/mips32-dsp/dpaq_sa_l_w.c
+++ b/tests/tcg/mips/mips32-dsp/dpaq_sa_l_w.c
@@ -14,7 +14,7 @@ int main()
resultdsp = 0x01;
__asm
("mthi %0, $ac1\n\t"
- "mtlo %0, $ac1\n\t"
+ "mtlo %1, $ac1\n\t"
"dpaq_sa.l.w $ac1, %3, %4\n\t"
"mfhi %0, $ac1\n\t"
"mflo %1, $ac1\n\t"
@@ -27,8 +27,8 @@ int main()
assert(ach == resulth);
assert(acl == resultl);
- ach = 0x12;
- acl = 0x48;
+ ach = 0x00000012;
+ acl = 0x00000048;
rs = 0x80000000;
rt = 0x80000000;
@@ -37,7 +37,7 @@ int main()
resultdsp = 0x01;
__asm
("mthi %0, $ac1\n\t"
- "mtlo %0, $ac1\n\t"
+ "mtlo %1, $ac1\n\t"
"dpaq_sa.l.w $ac1, %3, %4\n\t"
"mfhi %0, $ac1\n\t"
"mflo %1, $ac1\n\t"
@@ -51,16 +51,64 @@ int main()
assert(acl == resultl);
ach = 0x741532A0;
- acl = 0xfceabb08;
+ acl = 0xFCEABB08;
rs = 0x80000000;
rt = 0x80000000;
- resulth = 0x7fffffff;
- resultl = 0xffffffff;
+ resulth = 0x7FFFFFFF;
+ resultl = 0xFFFFFFFF;
resultdsp = 0x01;
__asm
("mthi %0, $ac1\n\t"
- "mtlo %0, $ac1\n\t"
+ "mtlo %1, $ac1\n\t"
+ "dpaq_sa.l.w $ac1, %3, %4\n\t"
+ "mfhi %0, $ac1\n\t"
+ "mflo %1, $ac1\n\t"
+ "rddsp %2\n\t"
+ : "+r"(ach), "+r"(acl), "=r"(dsp)
+ : "r"(rs), "r"(rt)
+ );
+ dsp = (dsp >> 17) & 0x01;
+ assert(dsp == resultdsp);
+ assert(ach == resulth);
+ assert(acl == resultl);
+
+ ach = 0;
+ acl = 0;
+ rs = 0xC0000000;
+ rt = 0x7FFFFFFF;
+
+ resulth = 0xC0000000;
+ resultl = 0x80000000;
+ resultdsp = 0;
+ __asm
+ ("wrdsp $0\n\t"
+ "mthi %0, $ac1\n\t"
+ "mtlo %1, $ac1\n\t"
+ "dpaq_sa.l.w $ac1, %3, %4\n\t"
+ "mfhi %0, $ac1\n\t"
+ "mflo %1, $ac1\n\t"
+ "rddsp %2\n\t"
+ : "+r"(ach), "+r"(acl), "=r"(dsp)
+ : "r"(rs), "r"(rt)
+ );
+ dsp = (dsp >> 17) & 0x01;
+ assert(dsp == resultdsp);
+ assert(ach == resulth);
+ assert(acl == resultl);
+
+ ach = 0x20000000;
+ acl = 0;
+ rs = 0xE0000000;
+ rt = 0x7FFFFFFF;
+
+ resulth = 0;
+ resultl = 0x40000000;
+ resultdsp = 0;
+ __asm
+ ("wrdsp $0\n\t"
+ "mthi %0, $ac1\n\t"
+ "mtlo %1, $ac1\n\t"
"dpaq_sa.l.w $ac1, %3, %4\n\t"
"mfhi %0, $ac1\n\t"
"mflo %1, $ac1\n\t"
diff --git a/tests/tcg/mips/mips32-dsp/dpsq_s_w_ph.c b/tests/tcg/mips/mips32-dsp/dpsq_s_w_ph.c
index 22ab4d57b..74058fe7e 100644
--- a/tests/tcg/mips/mips32-dsp/dpsq_s_w_ph.c
+++ b/tests/tcg/mips/mips32-dsp/dpsq_s_w_ph.c
@@ -9,8 +9,8 @@ int main()
rs = 0xBC0123AD;
rt = 0x01643721;
- resulth = 0x04;
- resultl = 0xEE9794A3;
+ resulth = 0x00000004;
+ resultl = 0xF15F94A3;
__asm
("mthi %0, $ac1\n\t"
"mtlo %1, $ac1\n\t"
@@ -23,12 +23,12 @@ int main()
assert(ach == resulth);
assert(acl == resultl);
- ach = 0x1424Ef1f;
+ ach = 0x1424EF1F;
acl = 0x1035219A;
rs = 0x800083AD;
rt = 0x80003721;
- resulth = 0x1424ef1e;
- resultl = 0x577ed901;
+ resulth = 0x1424EF1E;
+ resultl = 0xC5C0D901;
__asm
("mthi %0, $ac1\n\t"
"mtlo %1, $ac1\n\t"
diff --git a/tests/tcg/mips/mips32-dsp/dpsq_sa_l_w.c b/tests/tcg/mips/mips32-dsp/dpsq_sa_l_w.c
index b7b73fdb6..eda3b14e2 100644
--- a/tests/tcg/mips/mips32-dsp/dpsq_sa_l_w.c
+++ b/tests/tcg/mips/mips32-dsp/dpsq_sa_l_w.c
@@ -9,8 +9,8 @@ int main()
rs = 0xBC0123AD;
rt = 0x01643721;
- resulth = 0xfdf4cbe0;
- resultl = 0xd138776b;
+ resulth = 0x00BD3A22;
+ resultl = 0xD138776B;
resultdsp = 0x00;
__asm
("mthi %0, $ac1\n\t"
diff --git a/tests/tcg/mips/mips32-dsp/extp.c b/tests/tcg/mips/mips32-dsp/extp.c
index 21a67af21..b18bdb34c 100644
--- a/tests/tcg/mips/mips32-dsp/extp.c
+++ b/tests/tcg/mips/mips32-dsp/extp.c
@@ -40,5 +40,23 @@ int main()
dsp = (dsp >> 14) & 0x01;
assert(dsp == 1);
+ ach = 0;
+ acl = 0x80000001;
+ dsp = 0x1F;
+ result = 0x80000001;
+
+ __asm
+ ("wrdsp %1\n\t"
+ "mthi %2, $ac2\n\t"
+ "mtlo %3, $ac2\n\t"
+ "extp %0, $ac2, 0x1F\n\t"
+ "rddsp %1\n\t"
+ : "=r"(rt), "+r"(dsp)
+ : "r"(ach), "r"(acl)
+ );
+ dsp = (dsp >> 14) & 0x01;
+ assert(dsp == 0);
+ assert(result == rt);
+
return 0;
}
diff --git a/tests/tcg/mips/mips32-dsp/extpdp.c b/tests/tcg/mips/mips32-dsp/extpdp.c
index 15ba0828f..79ee16e8b 100644
--- a/tests/tcg/mips/mips32-dsp/extpdp.c
+++ b/tests/tcg/mips/mips32-dsp/extpdp.c
@@ -42,5 +42,23 @@ int main()
efi = (dsp >> 14) & 0x01;
assert(efi == 1);
+
+ ach = 0;
+ acl = 0;
+ dsp = 0;
+ result = 0;
+
+ __asm
+ ("wrdsp %1\n\t"
+ "mthi %2, $ac1\n\t"
+ "mtlo %3, $ac1\n\t"
+ "extpdp %0, $ac1, 0x00\n\t"
+ "rddsp %1\n\t"
+ : "=r"(rt), "+r"(dsp)
+ : "r"(ach), "r"(acl)
+ );
+ assert(dsp == 0x3F);
+ assert(result == rt);
+
return 0;
}
diff --git a/tests/tcg/mips/mips32-dsp/extr_r_w.c b/tests/tcg/mips/mips32-dsp/extr_r_w.c
index 0beeefd36..489c1931b 100644
--- a/tests/tcg/mips/mips32-dsp/extr_r_w.c
+++ b/tests/tcg/mips/mips32-dsp/extr_r_w.c
@@ -44,5 +44,51 @@ int main()
assert(dsp == 0);
assert(result == rt);
+ /* Clear dspcontrol */
+ dsp = 0;
+ __asm
+ ("wrdsp %0\n\t"
+ :
+ : "r"(dsp)
+ );
+
+ ach = 0x3fffffff;
+ acl = 0x2bcdef01;
+ result = 0x7ffffffe;
+ __asm
+ ("mthi %2, $ac1\n\t"
+ "mtlo %3, $ac1\n\t"
+ "extr_r.w %0, $ac1, 0x1F\n\t"
+ "rddsp %1\n\t"
+ : "=r"(rt), "=r"(dsp)
+ : "r"(ach), "r"(acl)
+ );
+ dsp = (dsp >> 23) & 0x01;
+ assert(dsp == 0);
+ assert(result == rt);
+
+ /* Clear dspcontrol */
+ dsp = 0;
+ __asm
+ ("wrdsp %0\n\t"
+ :
+ : "r"(dsp)
+ );
+
+ ach = 0xFFFFFFFF;
+ acl = 0xFFFFFFFF;
+ result = 0;
+ __asm
+ ("mthi %2, $ac1\n\t"
+ "mtlo %3, $ac1\n\t"
+ "extr_r.w %0, $ac1, 0x1F\n\t"
+ "rddsp %1\n\t"
+ : "=r"(rt), "=r"(dsp)
+ : "r"(ach), "r"(acl)
+ );
+ dsp = (dsp >> 23) & 0x01;
+ assert(dsp == 0);
+ assert(result == rt);
+
return 0;
}
diff --git a/tests/tcg/mips/mips32-dsp/extr_rs_w.c b/tests/tcg/mips/mips32-dsp/extr_rs_w.c
index 24c748db2..f9d2ed646 100644
--- a/tests/tcg/mips/mips32-dsp/extr_rs_w.c
+++ b/tests/tcg/mips/mips32-dsp/extr_rs_w.c
@@ -44,5 +44,74 @@ int main()
assert(dsp == 0);
assert(result == rt);
+ /* Clear dspcontrol */
+ dsp = 0;
+ __asm
+ ("wrdsp %0\n\t"
+ :
+ : "r"(dsp)
+ );
+
+ ach = 0x3fffffff;
+ acl = 0x2bcdef01;
+ result = 0x7ffffffe;
+ __asm
+ ("mthi %2, $ac1\n\t"
+ "mtlo %3, $ac1\n\t"
+ "extr_rs.w %0, $ac1, 0x1F\n\t"
+ "rddsp %1\n\t"
+ : "=r"(rt), "=r"(dsp)
+ : "r"(ach), "r"(acl)
+ );
+ dsp = (dsp >> 23) & 0x01;
+ assert(dsp == 0);
+ assert(result == rt);
+
+ /* Clear dspcontrol */
+ dsp = 0;
+ __asm
+ ("wrdsp %0\n\t"
+ :
+ : "r"(dsp)
+ );
+
+ ach = 0x80000000;
+ acl = 0x00000000;
+ result = 0x80000000;
+ __asm
+ ("mthi %2, $ac1\n\t"
+ "mtlo %3, $ac1\n\t"
+ "extr_rs.w %0, $ac1, 0x1F\n\t"
+ "rddsp %1\n\t"
+ : "=r"(rt), "=r"(dsp)
+ : "r"(ach), "r"(acl)
+ );
+ dsp = (dsp >> 23) & 0x01;
+ assert(dsp == 1);
+ assert(result == rt);
+
+ /* Clear dspcontrol */
+ dsp = 0;
+ __asm
+ ("wrdsp %0\n\t"
+ :
+ : "r"(dsp)
+ );
+
+ ach = 0xFFFFFFFF;
+ acl = 0xFFFFFFFF;
+ result = 0;
+ __asm
+ ("mthi %2, $ac1\n\t"
+ "mtlo %3, $ac1\n\t"
+ "extr_rs.w %0, $ac1, 0x1F\n\t"
+ "rddsp %1\n\t"
+ : "=r"(rt), "=r"(dsp)
+ : "r"(ach), "r"(acl)
+ );
+ dsp = (dsp >> 23) & 0x01;
+ assert(dsp == 0);
+ assert(result == rt);
+
return 0;
}
diff --git a/tests/tcg/mips/mips32-dsp/extr_s_h.c b/tests/tcg/mips/mips32-dsp/extr_s_h.c
index b2129134c..9bc2a63cc 100644
--- a/tests/tcg/mips/mips32-dsp/extr_s_h.c
+++ b/tests/tcg/mips/mips32-dsp/extr_s_h.c
@@ -59,5 +59,28 @@ int main()
assert(dsp == 0);
assert(result == rt);
+ /* Clear dsp */
+ dsp = 0;
+ __asm
+ ("wrdsp %0\n\t"
+ :
+ : "r"(dsp)
+ );
+
+ ach = 0x123;
+ acl = 0x87654321;
+ result = 0x1238;
+ __asm
+ ("mthi %2, $ac1\n\t"
+ "mtlo %3, $ac1\n\t"
+ "extr_s.h %0, $ac1, 28\n\t"
+ "rddsp %1\n\t"
+ : "=r"(rt), "=r"(dsp)
+ : "r"(ach), "r"(acl)
+ );
+ dsp = (dsp >> 23) & 0x01;
+ assert(dsp == 0);
+ assert(result == rt);
+
return 0;
}
diff --git a/tests/tcg/mips/mips32-dsp/extr_w.c b/tests/tcg/mips/mips32-dsp/extr_w.c
index 02ab9ecaa..cf926146d 100644
--- a/tests/tcg/mips/mips32-dsp/extr_w.c
+++ b/tests/tcg/mips/mips32-dsp/extr_w.c
@@ -44,5 +44,51 @@ int main()
assert(dsp == 0);
assert(result == rt);
+ /* Clear dspcontrol */
+ dsp = 0;
+ __asm
+ ("wrdsp %0\n\t"
+ :
+ : "r"(dsp)
+ );
+
+ ach = 0x3fffffff;
+ acl = 0x2bcdef01;
+ result = 0x7ffffffe;
+ __asm
+ ("mthi %2, $ac1\n\t"
+ "mtlo %3, $ac1\n\t"
+ "extr.w %0, $ac1, 0x1F\n\t"
+ "rddsp %1\n\t"
+ : "=r"(rt), "=r"(dsp)
+ : "r"(ach), "r"(acl)
+ );
+ dsp = (dsp >> 23) & 0x01;
+ assert(dsp == 0);
+ assert(result == rt);
+
+ /* Clear dspcontrol */
+ dsp = 0;
+ __asm
+ ("wrdsp %0\n\t"
+ :
+ : "r"(dsp)
+ );
+
+ ach = 0xFFFFFFFF;
+ acl = 0xFFFFFFFF;
+ result = 0xFFFFFFFF;
+ __asm
+ ("mthi %2, $ac1\n\t"
+ "mtlo %3, $ac1\n\t"
+ "extr.w %0, $ac1, 0x1F\n\t"
+ "rddsp %1\n\t"
+ : "=r"(rt), "=r"(dsp)
+ : "r"(ach), "r"(acl)
+ );
+ dsp = (dsp >> 23) & 0x01;
+ assert(dsp == 0);
+ assert(result == rt);
+
return 0;
}
diff --git a/tests/tcg/mips/mips32-dsp/extrv_r_w.c b/tests/tcg/mips/mips32-dsp/extrv_r_w.c
index 005807b14..2403b3afe 100644
--- a/tests/tcg/mips/mips32-dsp/extrv_r_w.c
+++ b/tests/tcg/mips/mips32-dsp/extrv_r_w.c
@@ -50,5 +50,30 @@ int main()
assert(dsp == 0);
assert(result == rt);
+ /* Clear dspcontrol */
+ dsp = 0;
+ __asm
+ ("wrdsp %0\n\t"
+ :
+ : "r"(dsp)
+ );
+
+ rs = 31;
+ ach = 0x3fffffff;
+ acl = 0x2bcdef01;
+ result = 0x7ffffffe;
+ __asm
+ ("wrdsp %1, 0x01\n\t"
+ "mthi %3, $ac1\n\t"
+ "mtlo %4, $ac1\n\t"
+ "extrv_r.w %0, $ac1, %2\n\t"
+ "rddsp %1\n\t"
+ : "=r"(rt), "+r"(dsp)
+ : "r"(rs), "r"(ach), "r"(acl)
+ );
+ dsp = (dsp >> 23) & 0x01;
+ assert(dsp == 0);
+ assert(result == rt);
+
return 0;
}
diff --git a/tests/tcg/mips/mips32-dsp/extrv_rs_w.c b/tests/tcg/mips/mips32-dsp/extrv_rs_w.c
index c2d8513bb..ccceeb9f4 100644
--- a/tests/tcg/mips/mips32-dsp/extrv_rs_w.c
+++ b/tests/tcg/mips/mips32-dsp/extrv_rs_w.c
@@ -48,5 +48,30 @@ int main()
assert(dsp == 0);
assert(result == rt);
+ /* Clear dspcontrol */
+ dsp = 0;
+ __asm
+ ("wrdsp %0\n\t"
+ :
+ : "r"(dsp)
+ );
+
+ rs = 0x1F;
+ ach = 0x3fffffff;
+ acl = 0x2bcdef01;
+ result = 0x7ffffffe;
+ __asm
+ ("wrdsp %1, 0x01\n\t"
+ "mthi %3, $ac1\n\t"
+ "mtlo %4, $ac1\n\t"
+ "extrv_rs.w %0, $ac1, %2\n\t"
+ "rddsp %1\n\t"
+ : "=r"(rt), "+r"(dsp)
+ : "r"(rs), "r"(ach), "r"(acl)
+ );
+ dsp = (dsp >> 23) & 0x01;
+ assert(dsp == 0);
+ assert(result == rt);
+
return 0;
}
diff --git a/tests/tcg/mips/mips32-dsp/extrv_s_h.c b/tests/tcg/mips/mips32-dsp/extrv_s_h.c
index 8c13b5eda..feac3e2e3 100644
--- a/tests/tcg/mips/mips32-dsp/extrv_s_h.c
+++ b/tests/tcg/mips/mips32-dsp/extrv_s_h.c
@@ -67,5 +67,22 @@ int main()
assert(dsp == 0);
assert(result == rt);
+ rs = 0x1C;
+ ach = 0x123;
+ acl = 0x87654321;
+ result = 0x1238;
+ __asm
+ ("wrdsp %1, 0x01\n\t"
+ "mthi %3, $ac1\n\t"
+ "mtlo %4, $ac1\n\t"
+ "extrv_s.h %0, $ac1, %2\n\t"
+ "rddsp %1\n\t"
+ : "=r"(rt), "+r"(dsp)
+ : "r"(rs), "r"(ach), "r"(acl)
+ );
+ dsp = (dsp >> 23) & 0x01;
+ assert(dsp == 0);
+ assert(result == rt);
+
return 0;
}
diff --git a/tests/tcg/mips/mips32-dsp/extrv_w.c b/tests/tcg/mips/mips32-dsp/extrv_w.c
index 9cb493df3..9e8b238a0 100644
--- a/tests/tcg/mips/mips32-dsp/extrv_w.c
+++ b/tests/tcg/mips/mips32-dsp/extrv_w.c
@@ -50,5 +50,31 @@ int main()
assert(dsp == 0);
assert(result == rt);
+ /* Clear dspcontrol */
+ dsp = 0;
+ __asm
+ ("wrdsp %0\n\t"
+ :
+ : "r"(dsp)
+ );
+
+ rs = 31;
+ ach = 0x3fffffff;
+ acl = 0x2bcdef01;
+ result = 0x7ffffffe;
+ __asm
+ ("wrdsp %1, 0x01\n\t"
+ "mthi %3, $ac1\n\t"
+ "mtlo %4, $ac1\n\t"
+ "extrv.w %0, $ac1, %2\n\t"
+ "rddsp %1\n\t"
+ : "=r"(rt), "+r"(dsp)
+ : "r"(rs), "r"(ach), "r"(acl)
+ );
+ dsp = (dsp >> 23) & 0x01;
+ assert(dsp == 0);
+ assert(result == rt);
+
+
return 0;
}
diff --git a/tests/tcg/mips/mips32-dsp/insv.c b/tests/tcg/mips/mips32-dsp/insv.c
index 7e3b04760..9d674697c 100644
--- a/tests/tcg/mips/mips32-dsp/insv.c
+++ b/tests/tcg/mips/mips32-dsp/insv.c
@@ -10,7 +10,7 @@ int main()
dsp = 0x305;
rt = 0x12345678;
rs = 0x87654321;
- result = 0x12345338;
+ result = 0x12345438;
__asm
("wrdsp %2, 0x03\n\t"
"insv %0, %1\n\t"
@@ -19,5 +19,18 @@ int main()
);
assert(rt == result);
+ dsp = 0x1000;
+ rt = 0xF0F0F0F0;
+ rs = 0xA5A5A5A5;
+ result = 0xA5A5A5A5;
+
+ __asm
+ ("wrdsp %2\n\t"
+ "insv %0, %1\n\t"
+ : "+r"(rt)
+ : "r"(rs), "r"(dsp)
+ );
+ assert(rt == result);
+
return 0;
}
diff --git a/tests/tcg/mips/mips32-dsp/maq_s_w_phl.c b/tests/tcg/mips/mips32-dsp/maq_s_w_phl.c
index 292d68566..0f7c07015 100644
--- a/tests/tcg/mips/mips32-dsp/maq_s_w_phl.c
+++ b/tests/tcg/mips/mips32-dsp/maq_s_w_phl.c
@@ -10,12 +10,12 @@ int main()
int resulth, resultl;
int resdsp;
- achi = 0x05;
- acli = 0xB4CB;
+ achi = 0x00000005;
+ acli = 0x0000B4CB;
rs = 0xFF060000;
rt = 0xCB000000;
- resulth = 0x04;
- resultl = 0x947438CB;
+ resulth = 0x00000005;
+ resultl = 0x006838CB;
__asm
("mthi %2, $ac1\n\t"
@@ -29,12 +29,12 @@ int main()
assert(resulth == acho);
assert(resultl == aclo);
- achi = 0x06;
- acli = 0xB4CB;
+ achi = 0x00000006;
+ acli = 0x0000B4CB;
rs = 0x80000000;
rt = 0x80000000;
- resulth = 0x6;
- resultl = 0x8000b4ca;
+ resulth = 0x00000006;
+ resultl = 0x8000B4CA;
resdsp = 1;
__asm
diff --git a/tests/tcg/mips/mips32-dsp/maq_s_w_phr.c b/tests/tcg/mips/mips32-dsp/maq_s_w_phr.c
index 7b2ef2ab7..942722a53 100644
--- a/tests/tcg/mips/mips32-dsp/maq_s_w_phr.c
+++ b/tests/tcg/mips/mips32-dsp/maq_s_w_phr.c
@@ -10,12 +10,12 @@ int main()
int resulth, resultl;
int resdsp;
- achi = 0x05;
- acli = 0xB4CB;
- rs = 0xFF06;
- rt = 0xCB00;
- resulth = 0x04;
- resultl = 0x947438CB;
+ achi = 0x00000005;
+ acli = 0x0000B4CB;
+ rs = 0x0000FF06;
+ rt = 0x0000CB00;
+ resulth = 0x00000005;
+ resultl = 0x006838CB;
__asm
("mthi %2, $ac1\n\t"
@@ -29,12 +29,12 @@ int main()
assert(resulth == acho);
assert(resultl == aclo);
- achi = 0x06;
- acli = 0xB4CB;
- rs = 0x8000;
- rt = 0x8000;
- resulth = 0x6;
- resultl = 0x8000b4ca;
+ achi = 0x00000006;
+ acli = 0x0000B4CB;
+ rs = 0x00008000;
+ rt = 0x00008000;
+ resulth = 0x00000006;
+ resultl = 0x8000B4CA;
resdsp = 1;
__asm
diff --git a/tests/tcg/mips/mips32-dsp/maq_sa_w_phl.c b/tests/tcg/mips/mips32-dsp/maq_sa_w_phl.c
index a75699172..d83dce6f3 100644
--- a/tests/tcg/mips/mips32-dsp/maq_sa_w_phl.c
+++ b/tests/tcg/mips/mips32-dsp/maq_sa_w_phl.c
@@ -10,12 +10,12 @@ int main()
int resulth, resultl;
int resdsp;
- achi = 0x05;
- acli = 0xB4CB;
+ achi = 0x00000000;
+ acli = 0x0000B4CB;
rs = 0xFF060000;
rt = 0xCB000000;
- resulth = 0x00;
- resultl = 0x7FFFFFFF;
+ resulth = 0x00000000;
+ resultl = 0x006838CB;
__asm
("mthi %2, $ac1\n\t"
@@ -29,8 +29,8 @@ int main()
assert(resulth == acho);
assert(resultl == aclo);
- achi = 0x06;
- acli = 0xB4CB;
+ achi = 0x00000000;
+ acli = 0x0000B4CB;
rs = 0x80000000;
rt = 0x80000000;
resulth = 0x00;
diff --git a/tests/tcg/mips/mips32-dsp/maq_sa_w_phr.c b/tests/tcg/mips/mips32-dsp/maq_sa_w_phr.c
index d6498f8df..d2331118a 100644
--- a/tests/tcg/mips/mips32-dsp/maq_sa_w_phr.c
+++ b/tests/tcg/mips/mips32-dsp/maq_sa_w_phr.c
@@ -10,12 +10,12 @@ int main()
int resulth, resultl;
int resdsp;
- achi = 0x05;
- acli = 0xB4CB;
- rs = 0xFF06;
- rt = 0xCB00;
- resulth = 0x00;
- resultl = 0x7FFFFFFF;
+ achi = 0x00000000;
+ acli = 0x0000B4CB;
+ rs = 0x0000FF06;
+ rt = 0x0000CB00;
+ resulth = 0x00000000;
+ resultl = 0x006838CB;
__asm
("mthi %2, $ac1\n\t"
@@ -29,12 +29,12 @@ int main()
assert(resulth == acho);
assert(resultl == aclo);
- achi = 0x06;
- acli = 0xB4CB;
- rs = 0x8000;
- rt = 0x8000;
- resulth = 0x00;
- resultl = 0x7fffffff;
+ achi = 0x00000000;
+ acli = 0x0000B4CB;
+ rs = 0x00008000;
+ rt = 0x00008000;
+ resulth = 0x00000000;
+ resultl = 0x7FFFFFFF;
resdsp = 0x01;
__asm
diff --git a/tests/tcg/mips/mips32-dsp/mthlip.c b/tests/tcg/mips/mips32-dsp/mthlip.c
index 9549aae36..85f94d845 100644
--- a/tests/tcg/mips/mips32-dsp/mthlip.c
+++ b/tests/tcg/mips/mips32-dsp/mthlip.c
@@ -30,7 +30,7 @@ int main()
assert(ach == resulth);
assert(acl == resultl);
- dsp = 0x3f;
+ dsp = 0x1f;
ach = 0x05;
acl = 0xB4CB;
rs = 0x00FFBBAA;
diff --git a/tests/tcg/mips/mips32-dsp/mulq_rs_ph.c b/tests/tcg/mips/mips32-dsp/mulq_rs_ph.c
index c7206039e..370c2a801 100644
--- a/tests/tcg/mips/mips32-dsp/mulq_rs_ph.c
+++ b/tests/tcg/mips/mips32-dsp/mulq_rs_ph.c
@@ -12,7 +12,24 @@ int main()
resultdsp = 1;
__asm
- ("mulq_rs.ph %0, %2, %3\n\t"
+ ("wrdsp $0\n\t"
+ "mulq_rs.ph %0, %2, %3\n\t"
+ "rddsp %1\n\t"
+ : "=r"(rd), "=r"(dsp)
+ : "r"(rs), "r"(rt)
+ );
+ dsp = (dsp >> 21) & 0x01;
+ assert(rd == result);
+ assert(dsp == resultdsp);
+
+ rs = 0x80011234;
+ rt = 0x80024321;
+ result = 0x7FFD098C;
+ resultdsp = 0;
+
+ __asm
+ ("wrdsp $0\n\t"
+ "mulq_rs.ph %0, %2, %3\n\t"
"rddsp %1\n\t"
: "=r"(rd), "=r"(dsp)
: "r"(rs), "r"(rt)
diff --git a/tests/tcg/mips/mips32-dsp/precrq_rs_ph_w.c b/tests/tcg/mips/mips32-dsp/precrq_rs_ph_w.c
index 3535b37a5..da6845bf2 100644
--- a/tests/tcg/mips/mips32-dsp/precrq_rs_ph_w.c
+++ b/tests/tcg/mips/mips32-dsp/precrq_rs_ph_w.c
@@ -12,18 +12,34 @@ int main()
result = 0x12348765;
__asm
- ("precrq_rs.ph.w %0, %1, %2\n\t"
+ ("wrdsp $0\n\t"
+ "precrq_rs.ph.w %0, %1, %2\n\t"
: "=r"(rd)
: "r"(rs), "r"(rt)
);
assert(result == rd);
- rs = 0x7fffC678;
+ rs = 0x7FFFC678;
rt = 0x865432A0;
- result = 0x7fff8654;
+ result = 0x7FFF8654;
__asm
- ("precrq_rs.ph.w %0, %2, %3\n\t"
+ ("wrdsp $0\n\t"
+ "precrq_rs.ph.w %0, %2, %3\n\t"
+ "rddsp %1\n\t"
+ : "=r"(rd), "=r"(dsp)
+ : "r"(rs), "r"(rt)
+ );
+ assert(((dsp >> 22) & 0x01) == 1);
+ assert(result == rd);
+
+ rs = 0xBEEFFEED;
+ rt = 0x7FFF8000;
+ result = 0xBEF07FFF;
+
+ __asm
+ ("wrdsp $0\n\t"
+ "precrq_rs.ph.w %0, %2, %3\n\t"
"rddsp %1\n\t"
: "=r"(rd), "=r"(dsp)
: "r"(rs), "r"(rt)
diff --git a/tests/tcg/mips/mips32-dsp/rddsp.c b/tests/tcg/mips/mips32-dsp/rddsp.c
index e8948ec1d..2f3028503 100644
--- a/tests/tcg/mips/mips32-dsp/rddsp.c
+++ b/tests/tcg/mips/mips32-dsp/rddsp.c
@@ -6,14 +6,13 @@ int main()
int dsp_i, dsp_o;
int ccond_i, outflag_i, efi_i, c_i, scount_i, pos_i;
int ccond_o, outflag_o, efi_o, c_o, scount_o, pos_o;
- int ccond_r, outflag_r, efi_r, c_r, scount_r, pos_r;
- ccond_i = 0x000000BC;/* 4 */
- outflag_i = 0x0000001B;/* 3 */
- efi_i = 0x00000001;/* 5 */
- c_i = 0x00000001;/* 2 */
- scount_i = 0x0000000F;/* 1 */
- pos_i = 0x0000000C;/* 0 */
+ ccond_i = 0x0000000C; /* 4 */
+ outflag_i = 0x0000001B; /* 3 */
+ efi_i = 0x00000001; /* 5 */
+ c_i = 0x00000001; /* 2 */
+ scount_i = 0x0000000F; /* 1 */
+ pos_i = 0x0000000C; /* 0 */
dsp_i = (ccond_i << 24) | \
(outflag_i << 16) | \
@@ -22,13 +21,6 @@ int main()
(scount_i << 7) | \
pos_i;
- ccond_r = ccond_i;
- outflag_r = outflag_i;
- efi_r = efi_i;
- c_r = c_i;
- scount_r = scount_i;
- pos_r = pos_i;
-
__asm
("wrdsp %1, 0x3F\n\t"
"rddsp %0, 0x3F\n\t"
@@ -43,12 +35,12 @@ int main()
scount_o = (dsp_o >> 7) & 0x3F;
pos_o = dsp_o & 0x1F;
- assert(ccond_o == ccond_r);
- assert(outflag_o == outflag_r);
- assert(efi_o == efi_r);
- assert(c_o == c_r);
- assert(scount_o == scount_r);
- assert(pos_o == pos_r);
+ assert(ccond_o == ccond_i);
+ assert(outflag_o == outflag_i);
+ assert(efi_o == efi_i);
+ assert(c_o == c_i);
+ assert(scount_o == scount_i);
+ assert(pos_o == pos_i);
return 0;
}
diff --git a/tests/tcg/mips/mips32-dsp/shilo.c b/tests/tcg/mips/mips32-dsp/shilo.c
index b686616d8..ce8ebc69c 100644
--- a/tests/tcg/mips/mips32-dsp/shilo.c
+++ b/tests/tcg/mips/mips32-dsp/shilo.c
@@ -23,5 +23,23 @@ int main()
assert(ach == resulth);
assert(acl == resultl);
+
+ ach = 0x1;
+ acl = 0x80000000;
+
+ resulth = 0x3;
+ resultl = 0x0;
+
+ __asm
+ ("mthi %0, $ac1\n\t"
+ "mtlo %1, $ac1\n\t"
+ "shilo $ac1, -1\n\t"
+ "mfhi %0, $ac1\n\t"
+ "mflo %1, $ac1\n\t"
+ : "+r"(ach), "+r"(acl)
+ );
+ assert(ach == resulth);
+ assert(acl == resultl);
+
return 0;
}
diff --git a/tests/tcg/mips/mips32-dsp/shilov.c b/tests/tcg/mips/mips32-dsp/shilov.c
index f186032a1..e1d6cea4b 100644
--- a/tests/tcg/mips/mips32-dsp/shilov.c
+++ b/tests/tcg/mips/mips32-dsp/shilov.c
@@ -25,5 +25,25 @@ int main()
assert(ach == resulth);
assert(acl == resultl);
+
+ rs = 0xffffffff;
+ ach = 0x1;
+ acl = 0x80000000;
+
+ resulth = 0x3;
+ resultl = 0x0;
+
+ __asm
+ ("mthi %0, $ac1\n\t"
+ "mtlo %1, $ac1\n\t"
+ "shilov $ac1, %2\n\t"
+ "mfhi %0, $ac1\n\t"
+ "mflo %1, $ac1\n\t"
+ : "+r"(ach), "+r"(acl)
+ : "r"(rs)
+ );
+ assert(ach == resulth);
+ assert(acl == resultl);
+
return 0;
}
diff --git a/tests/tcg/mips/mips32-dsp/shll_ph.c b/tests/tcg/mips/mips32-dsp/shll_ph.c
index b8f1ff528..5fa58ccf6 100644
--- a/tests/tcg/mips/mips32-dsp/shll_ph.c
+++ b/tests/tcg/mips/mips32-dsp/shll_ph.c
@@ -11,7 +11,38 @@ int main()
resultdsp = 1;
__asm
- ("shll.ph %0, %2, 0x0B\n\t"
+ ("wrdsp $0\n\t"
+ "shll.ph %0, %2, 0x0B\n\t"
+ "rddsp %1\n\t"
+ : "=r"(rd), "=r"(dsp)
+ : "r"(rt)
+ );
+ dsp = (dsp >> 22) & 0x01;
+ assert(dsp == resultdsp);
+ assert(rd == result);
+
+ rt = 0x7fff8000;
+ result = 0xfffe0000;
+ resultdsp = 1;
+
+ __asm
+ ("wrdsp $0\n\t"
+ "shll.ph %0, %2, 0x01\n\t"
+ "rddsp %1\n\t"
+ : "=r"(rd), "=r"(dsp)
+ : "r"(rt)
+ );
+ dsp = (dsp >> 22) & 0x01;
+ assert(dsp == resultdsp);
+ assert(rd == result);
+
+ rt = 0x00000001;
+ result = 0x00008000;
+ resultdsp = 1;
+
+ __asm
+ ("wrdsp $0\n\t"
+ "shll.ph %0, %2, 0x0F\n\t"
"rddsp %1\n\t"
: "=r"(rd), "=r"(dsp)
: "r"(rt)
diff --git a/tests/tcg/mips/mips32-dsp/shll_qb.c b/tests/tcg/mips/mips32-dsp/shll_qb.c
index 8c1b91c63..729716d62 100644
--- a/tests/tcg/mips/mips32-dsp/shll_qb.c
+++ b/tests/tcg/mips/mips32-dsp/shll_qb.c
@@ -11,12 +11,14 @@ int main()
resultdsp = 0x00;
__asm
- ("shll.qb %0, %2, 0x00\n\t"
+ ("wrdsp $0\n\t"
+ "shll.qb %0, %2, 0x00\n\t"
"rddsp %1\n\t"
: "=r"(rd), "=r"(dsp)
: "r"(rt)
);
dsp = (dsp >> 22) & 0x01;
+ assert(dsp == resultdsp);
assert(rd == result);
rt = 0x87654321;
@@ -24,12 +26,29 @@ int main()
resultdsp = 0x01;
__asm
- ("shll.qb %0, %2, 0x03\n\t"
+ ("wrdsp $0\n\t"
+ "shll.qb %0, %2, 0x03\n\t"
"rddsp %1\n\t"
: "=r"(rd), "=r"(dsp)
: "r"(rt)
);
dsp = (dsp >> 22) & 0x01;
+ assert(dsp == resultdsp);
+ assert(rd == result);
+
+ rt = 0x00000001;
+ result = 0x00000080;
+ resultdsp = 0x00;
+
+ __asm
+ ("wrdsp $0\n\t"
+ "shll.qb %0, %2, 0x07\n\t"
+ "rddsp %1\n\t"
+ : "=r"(rd), "=r"(dsp)
+ : "r"(rt)
+ );
+ dsp = (dsp >> 22) & 0x01;
+ assert(dsp == resultdsp);
assert(rd == result);
return 0;
diff --git a/tests/tcg/mips/mips32-dsp/subq_s_ph.c b/tests/tcg/mips/mips32-dsp/subq_s_ph.c
index 8e36dadef..64c89ebd5 100644
--- a/tests/tcg/mips/mips32-dsp/subq_s_ph.c
+++ b/tests/tcg/mips/mips32-dsp/subq_s_ph.c
@@ -12,7 +12,8 @@ int main()
resultdsp = 0x01;
__asm
- ("subq_s.ph %0, %2, %3\n\t"
+ ("wrdsp $0\n\t"
+ "subq_s.ph %0, %2, %3\n\t"
"rddsp %1\n\t"
: "=r"(rd), "=r"(dsp)
: "r"(rs), "r"(rt)
@@ -27,7 +28,24 @@ int main()
resultdsp = 0x01;
__asm
- ("subq_s.ph %0, %2, %3\n\t"
+ ("wrdsp $0\n\t"
+ "subq_s.ph %0, %2, %3\n\t"
+ "rddsp %1\n\t"
+ : "=r"(rd), "=r"(dsp)
+ : "r"(rs), "r"(rt)
+ );
+ dsp = (dsp >> 20) & 0x01;
+ assert(dsp == resultdsp);
+ assert(rd == result);
+
+ rs = 0x12340000;
+ rt = 0x87658000;
+ result = 0x7FFF7FFF;
+ resultdsp = 0x01;
+
+ __asm
+ ("wrdsp $0\n\t"
+ "subq_s.ph %0, %2, %3\n\t"
"rddsp %1\n\t"
: "=r"(rd), "=r"(dsp)
: "r"(rs), "r"(rt)
diff --git a/tests/tcg/mips/mips32-dsp/subq_s_w.c b/tests/tcg/mips/mips32-dsp/subq_s_w.c
index 09022e9c8..9d456a90f 100644
--- a/tests/tcg/mips/mips32-dsp/subq_s_w.c
+++ b/tests/tcg/mips/mips32-dsp/subq_s_w.c
@@ -12,7 +12,8 @@ int main()
resultdsp = 0x01;
__asm
- ("subq_s.w %0, %2, %3\n\t"
+ ("wrdsp $0\n\t"
+ "subq_s.w %0, %2, %3\n\t"
"rddsp %1\n\t"
: "=r"(rd), "=r"(dsp)
: "r"(rs), "r"(rt)
@@ -24,10 +25,11 @@ int main()
rs = 0x66666;
rt = 0x55555;
result = 0x11111;
- resultdsp = 0x01;
+ resultdsp = 0x0;
__asm
- ("subq_s.w %0, %2, %3\n\t"
+ ("wrdsp $0\n\t"
+ "subq_s.w %0, %2, %3\n\t"
"rddsp %1\n\t"
: "=r"(rd), "=r"(dsp)
: "r"(rs), "r"(rt)
@@ -36,23 +38,37 @@ int main()
assert(dsp == resultdsp);
assert(rd == result);
-
-#if 0
- rs = 0x35555555;
- rt = 0xf5555555;
- result = 0x80000000;
+ rs = 0x0;
+ rt = 0x80000000;
+ result = 0x7FFFFFFF;
resultdsp = 0x01;
__asm
- ("subq_s.w %0, %2, %3\n\t"
+ ("wrdsp $0\n\t"
+ "subq_s.w %0, %2, %3\n\t"
"rddsp %1\n\t"
: "=r"(rd), "=r"(dsp)
: "r"(rs), "r"(rt)
);
+ dsp = (dsp >> 20) & 0x01;
+ assert(dsp == resultdsp);
+ assert(rd == result);
+
+ rs = 0x80000000;
+ rt = 0x80000000;
+ result = 0;
+ resultdsp = 0x00;
+ __asm
+ ("wrdsp $0\n\t"
+ "subq_s.w %0, %2, %3\n\t"
+ "rddsp %1\n\t"
+ : "=r"(rd), "=r"(dsp)
+ : "r"(rs), "r"(rt)
+ );
dsp = (dsp >> 20) & 0x01;
assert(dsp == resultdsp);
assert(rd == result);
-#endif
+
return 0;
}
diff --git a/tests/tcg/mips/mips32-dsp/wrdsp.c b/tests/tcg/mips/mips32-dsp/wrdsp.c
index e8948ec1d..dc54943a9 100644
--- a/tests/tcg/mips/mips32-dsp/wrdsp.c
+++ b/tests/tcg/mips/mips32-dsp/wrdsp.c
@@ -6,14 +6,13 @@ int main()
int dsp_i, dsp_o;
int ccond_i, outflag_i, efi_i, c_i, scount_i, pos_i;
int ccond_o, outflag_o, efi_o, c_o, scount_o, pos_o;
- int ccond_r, outflag_r, efi_r, c_r, scount_r, pos_r;
- ccond_i = 0x000000BC;/* 4 */
- outflag_i = 0x0000001B;/* 3 */
- efi_i = 0x00000001;/* 5 */
- c_i = 0x00000001;/* 2 */
- scount_i = 0x0000000F;/* 1 */
- pos_i = 0x0000000C;/* 0 */
+ ccond_i = 0x000000BC; /* 4 */
+ outflag_i = 0x0000001B; /* 3 */
+ efi_i = 0x00000001; /* 5 */
+ c_i = 0x00000001; /* 2 */
+ scount_i = 0x0000000F; /* 1 */
+ pos_i = 0x0000000C; /* 0 */
dsp_i = (ccond_i << 24) | \
(outflag_i << 16) | \
@@ -22,13 +21,6 @@ int main()
(scount_i << 7) | \
pos_i;
- ccond_r = ccond_i;
- outflag_r = outflag_i;
- efi_r = efi_i;
- c_r = c_i;
- scount_r = scount_i;
- pos_r = pos_i;
-
__asm
("wrdsp %1, 0x3F\n\t"
"rddsp %0, 0x3F\n\t"
@@ -43,12 +35,12 @@ int main()
scount_o = (dsp_o >> 7) & 0x3F;
pos_o = dsp_o & 0x1F;
- assert(ccond_o == ccond_r);
- assert(outflag_o == outflag_r);
- assert(efi_o == efi_r);
- assert(c_o == c_r);
- assert(scount_o == scount_r);
- assert(pos_o == pos_r);
+ assert(ccond_o == (ccond_i & 0x0F));
+ assert(outflag_o == outflag_i);
+ assert(efi_o == efi_i);
+ assert(c_o == c_i);
+ assert(scount_o == scount_i);
+ assert(pos_o == pos_i);
return 0;
}
diff --git a/tests/tcg/mips/mips32-dspr2/dpa_w_ph.c b/tests/tcg/mips/mips32-dspr2/dpa_w_ph.c
index 1cfbdb080..fae49f10e 100644
--- a/tests/tcg/mips/mips32-dspr2/dpa_w_ph.c
+++ b/tests/tcg/mips/mips32-dspr2/dpa_w_ph.c
@@ -26,8 +26,8 @@ int main()
ach = 6, acl = 7;
rs = 0xFFFF00FF;
rt = 0xFFFF0002;
- resulth = 0x05;
- resultl = 0xfffe0206;
+ resulth = 0x06;
+ resultl = 0x206;
__asm
("mthi %0, $ac1\n\t"
"mtlo %1, $ac1\n\t"
diff --git a/tests/tcg/mips/mips32-dspr2/dpaqx_sa_w_ph.c b/tests/tcg/mips/mips32-dspr2/dpaqx_sa_w_ph.c
index 798c4da5c..d551d64ae 100644
--- a/tests/tcg/mips/mips32-dspr2/dpaqx_sa_w_ph.c
+++ b/tests/tcg/mips/mips32-dspr2/dpaqx_sa_w_ph.c
@@ -4,14 +4,17 @@
int main()
{
int rs, rt, dsp;
- int ach = 5, acl = 5;
+ int ach, acl;
int resulth, resultl, resultdsp;
+ ach = 0x00000005;
+ acl = 0x00000005;
rs = 0x00FF00FF;
rt = 0x00010002;
resulth = 0x00;
resultl = 0x7FFFFFFF;
resultdsp = 0x01;
+ dsp = 0;
__asm
("wrdsp %2\n\t"
"mthi %0, $ac1\n\t"
@@ -27,13 +30,14 @@ int main()
assert(ach == resulth);
assert(acl == resultl);
- ach = 9;
- acl = 0xb;
+ ach = 0x00000009;
+ acl = 0x0000000B;
rs = 0x800000FF;
rt = 0x00018000;
resulth = 0x00;
- resultl = 0x7fffffff;
+ resultl = 0x7FFFFFFF;
resultdsp = 0x01;
+ dsp = 0;
__asm
("wrdsp %2\n\t"
"mthi %0, $ac1\n\t"
diff --git a/tests/tcg/mips/mips32-dspr2/dpax_w_ph.c b/tests/tcg/mips/mips32-dspr2/dpax_w_ph.c
index f75699755..514797cfd 100644
--- a/tests/tcg/mips/mips32-dspr2/dpax_w_ph.c
+++ b/tests/tcg/mips/mips32-dspr2/dpax_w_ph.c
@@ -23,5 +23,22 @@ int main()
assert(ach == resulth);
assert(acl == resultl);
+ ach = 6, acl = 7;
+ rs = 0xFFFF00FF;
+ rt = 0xFFFF0002;
+ resulth = 0x05;
+ resultl = 0xFFFFFF06;
+ __asm
+ ("mthi %0, $ac1\n\t"
+ "mtlo %1, $ac1\n\t"
+ "dpax.w.ph $ac1, %2, %3\n\t"
+ "mfhi %0, $ac1\n\t"
+ "mflo %1, $ac1\n\t"
+ : "+r"(ach), "+r"(acl)
+ : "r"(rs), "r"(rt)
+ );
+ assert(ach == resulth);
+ assert(acl == resultl);
+
return 0;
}
diff --git a/tests/tcg/mips/mips32-dspr2/dps_w_ph.c b/tests/tcg/mips/mips32-dspr2/dps_w_ph.c
index 8303643d1..f51f9b9d1 100644
--- a/tests/tcg/mips/mips32-dspr2/dps_w_ph.c
+++ b/tests/tcg/mips/mips32-dspr2/dps_w_ph.c
@@ -23,5 +23,22 @@ int main()
assert(ach == resulth);
assert(acl == resultl);
+ ach = 6, acl = 7;
+ rs = 0xFFFF00FF;
+ rt = 0xFFFF0002;
+ resulth = 0x05;
+ resultl = 0xFFFFFE08;
+ __asm
+ ("mthi %0, $ac1\n\t"
+ "mtlo %1, $ac1\n\t"
+ "dps.w.ph $ac1, %2, %3\n\t"
+ "mfhi %0, $ac1\n\t"
+ "mflo %1, $ac1\n\t"
+ : "+r"(ach), "+r"(acl)
+ : "r"(rs), "r"(rt)
+ );
+ assert(ach == resulth);
+ assert(acl == resultl);
+
return 0;
}
diff --git a/tests/tcg/mips/mips32-dspr2/dpsqx_s_w_ph.c b/tests/tcg/mips/mips32-dspr2/dpsqx_s_w_ph.c
index 14cdd7c0f..e40543fd8 100644
--- a/tests/tcg/mips/mips32-dspr2/dpsqx_s_w_ph.c
+++ b/tests/tcg/mips/mips32-dspr2/dpsqx_s_w_ph.c
@@ -9,8 +9,8 @@ int main()
rs = 0xBC0123AD;
rt = 0x01643721;
- resulth = 0x04;
- resultl = 0xAEA3E09B;
+ resulth = 0x00000005;
+ resultl = 0x1CE5E09B;
resultdsp = 0x00;
__asm
("mthi %0, $ac1\n\t"
@@ -27,12 +27,12 @@ int main()
assert(ach == resulth);
assert(acl == resultl);
- ach = 0x99f13005;
+ ach = 0x99F13005;
acl = 0x51730062;
rs = 0x80008000;
rt = 0x80008000;
- resulth = 0x99f13004;
+ resulth = 0x99F13004;
resultl = 0x51730064;
resultdsp = 0x01;
__asm
diff --git a/tests/tcg/mips/mips32-dspr2/dpsx_w_ph.c b/tests/tcg/mips/mips32-dspr2/dpsx_w_ph.c
index 6db59a4cc..bb49a4031 100644
--- a/tests/tcg/mips/mips32-dspr2/dpsx_w_ph.c
+++ b/tests/tcg/mips/mips32-dspr2/dpsx_w_ph.c
@@ -9,8 +9,8 @@ int main()
rs = 0xBC0123AD;
rt = 0x01643721;
- resulth = 0x04;
- resultl = 0xD751F050;
+ resulth = 0x05;
+ resultl = 0xE72F050;
__asm
("mthi %0, $ac1\n\t"
"mtlo %1, $ac1\n\t"
diff --git a/tests/tcg/mips/mips32-dspr2/mulq_rs_w.c b/tests/tcg/mips/mips32-dspr2/mulq_rs_w.c
index 669405faf..7ba633bc1 100644
--- a/tests/tcg/mips/mips32-dspr2/mulq_rs_w.c
+++ b/tests/tcg/mips/mips32-dspr2/mulq_rs_w.c
@@ -8,7 +8,7 @@ int main()
rs = 0x80001234;
rt = 0x80004321;
- result = 0x80005555;
+ result = 0x7FFFAAAB;
__asm
("mulq_rs.w %0, %1, %2\n\t"
diff --git a/tests/tcg/mips/mips32-dspr2/mulq_s_ph.c b/tests/tcg/mips/mips32-dspr2/mulq_s_ph.c
index d0f7674a3..00e015542 100644
--- a/tests/tcg/mips/mips32-dspr2/mulq_s_ph.c
+++ b/tests/tcg/mips/mips32-dspr2/mulq_s_ph.c
@@ -6,6 +6,21 @@ int main()
int rd, rs, rt, dsp;
int result, resultdsp;
+ rs = 0x80000000;
+ rt = 0x0ffc0000;
+ result = 0xF0040000;
+ resultdsp = 0;
+
+ __asm
+ ("mulq_s.ph %0, %2, %3\n\t"
+ "rddsp %1\n\t"
+ : "=r"(rd), "=r"(dsp)
+ : "r"(rs), "r"(rt)
+ );
+ dsp = (dsp >> 21) & 0x01;
+ assert(rd == result);
+ assert(dsp == resultdsp);
+
rs = 0x80001234;
rt = 0x80004321;
result = 0x7FFF098B;
diff --git a/tests/tcg/mips/mips32-dspr2/mulq_s_w.c b/tests/tcg/mips/mips32-dspr2/mulq_s_w.c
index df148b7ff..9c2be06cc 100644
--- a/tests/tcg/mips/mips32-dspr2/mulq_s_w.c
+++ b/tests/tcg/mips/mips32-dspr2/mulq_s_w.c
@@ -8,7 +8,7 @@ int main()
rs = 0x80001234;
rt = 0x80004321;
- result = 0x80005555;
+ result = 0x7FFFAAAB;
__asm
("mulq_s.w %0, %1, %2\n\t"
diff --git a/tests/tcg/test-i386-fprem.c b/tests/tcg/test-i386-fprem.c
index 8c7a4d1ff..e91fb1ae9 100644
--- a/tests/tcg/test-i386-fprem.c
+++ b/tests/tcg/test-i386-fprem.c
@@ -22,8 +22,8 @@
* 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 "compiler.h"
-#include "osdep.h"
+#include "qemu/compiler.h"
+#include "qemu/osdep.h"
#include <stdio.h>
#include <inttypes.h>
diff --git a/tests/tcg/test-i386.c b/tests/tcg/test-i386.c
index 40392ac51..b05572b73 100644
--- a/tests/tcg/test-i386.c
+++ b/tests/tcg/test-i386.c
@@ -17,7 +17,7 @@
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#define _GNU_SOURCE
-#include "compiler.h"
+#include "qemu/compiler.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
@@ -209,7 +209,7 @@ static inline long i2l(long v)
#define TEST_LEA16(STR)\
{\
asm(".code16 ; .byte 0x67 ; leal " STR ", %0 ; .code32"\
- : "=wq" (res)\
+ : "=r" (res)\
: "a" (eax), "b" (ebx), "c" (ecx), "d" (edx), "S" (esi), "D" (edi));\
printf("lea %s = %08lx\n", STR, res);\
}
@@ -925,7 +925,7 @@ void test_fbcd(double a)
void test_fenv(void)
{
- struct QEMU_PACKED {
+ struct __attribute__((__packed__)) {
uint16_t fpuc;
uint16_t dummy1;
uint16_t fpus;
@@ -935,7 +935,7 @@ void test_fenv(void)
uint32_t ignored[4];
long double fpregs[8];
} float_env32;
- struct QEMU_PACKED {
+ struct __attribute__((__packed__)) {
uint16_t fpuc;
uint16_t fpus;
uint16_t fptag;
@@ -1280,7 +1280,7 @@ void test_segs(void)
struct {
uint32_t offset;
uint16_t seg;
- } QEMU_PACKED segoff;
+ } __attribute__((__packed__)) segoff;
ldt.entry_number = 1;
ldt.base_addr = (unsigned long)&seg_data1;
@@ -1828,7 +1828,7 @@ void test_exceptions(void)
printf("lock nop exception:\n");
if (setjmp(jmp_env) == 0) {
/* now execute an invalid instruction */
- asm volatile(".byte 0xf0, 0x90"); /* lock nop */
+ asm volatile(".byte 0xf0, 0x90");
}
printf("INT exception:\n");
diff --git a/tests/tcg/xtensa/Makefile b/tests/tcg/xtensa/Makefile
index 0ff0ccfb8..1b519cae4 100644
--- a/tests/tcg/xtensa/Makefile
+++ b/tests/tcg/xtensa/Makefile
@@ -1,9 +1,9 @@
--include ../../config-host.mak
+-include ../../../config-host.mak
CROSS=xtensa-dc232b-elf-
ifndef XT
-SIM = qemu-system-xtensa
+SIM = ../../../xtensa-softmmu/qemu-system-xtensa
SIMFLAGS = -M sim -cpu dc232b -nographic -semihosting $(EXTFLAGS) -kernel
SIMDEBUG = -s -S
else
@@ -13,10 +13,12 @@ SIMDEBUG = --gdbserve=0
endif
CC = $(CROSS)gcc
-AS = $(CROSS)gcc -x assembler
+AS = $(CROSS)gcc -x assembler-with-cpp
LD = $(CROSS)ld
-LDFLAGS = -Tlinker.ld
+XTENSA_SRC_PATH = $(SRC_PATH)/tests/tcg/xtensa
+
+LDFLAGS = -T$(XTENSA_SRC_PATH)/linker.ld
CRT = crt.o vectors.o
@@ -26,6 +28,7 @@ TESTCASES += test_bi.tst
TESTCASES += test_break.tst
TESTCASES += test_bz.tst
TESTCASES += test_clamps.tst
+TESTCASES += test_extui.tst
TESTCASES += test_fail.tst
TESTCASES += test_interrupt.tst
TESTCASES += test_loop.tst
@@ -42,21 +45,23 @@ endif
TESTCASES += test_quo.tst
TESTCASES += test_rem.tst
TESTCASES += test_rst0.tst
+TESTCASES += test_s32c1i.tst
TESTCASES += test_sar.tst
TESTCASES += test_sext.tst
TESTCASES += test_shift.tst
+TESTCASES += test_sr.tst
TESTCASES += test_timer.tst
TESTCASES += test_windowed.tst
all: build
-%.o: $(SRC_PATH)/tests/xtensa/%.c
- $(CC) $(CFLAGS) -c $< -o $@
+%.o: $(XTENSA_SRC_PATH)/%.c
+ $(CC) -I$(XTENSA_SRC_PATH) $(CFLAGS) -c $< -o $@
-%.o: $(SRC_PATH)/tests/xtensa/%.S
- $(AS) $(ASFLAGS) -c $< -o $@
+%.o: $(XTENSA_SRC_PATH)/%.S
+ $(AS) -Wa,-I,$(XTENSA_SRC_PATH) $(ASFLAGS) -c $< -o $@
-%.tst: %.o macros.inc $(CRT) Makefile
+%.tst: %.o $(XTENSA_SRC_PATH)/macros.inc $(CRT) Makefile
$(LD) $(LDFLAGS) $(NOSTDFLAGS) $(CRT) $< -o $@
build: $(TESTCASES)
diff --git a/tests/tcg/xtensa/macros.inc b/tests/tcg/xtensa/macros.inc
index 23bf3e96c..c9be1ce51 100644
--- a/tests/tcg/xtensa/macros.inc
+++ b/tests/tcg/xtensa/macros.inc
@@ -1,7 +1,7 @@
.macro test_suite name
.data
status: .word result
-result: .space 20
+result: .space 256
.text
.global main
.align 4
diff --git a/tests/tcg/xtensa/test_extui.S b/tests/tcg/xtensa/test_extui.S
new file mode 100644
index 000000000..5d5545170
--- /dev/null
+++ b/tests/tcg/xtensa/test_extui.S
@@ -0,0 +1,26 @@
+.include "macros.inc"
+
+test_suite extui
+
+.macro test_extui v, shiftimm, maskimm
+ .if \shiftimm + \maskimm <= 32
+ movi a2, \v
+ extui a3, a2, \shiftimm, \maskimm
+ movi a4, ((\v) >> (\shiftimm)) & ((1 << (\maskimm)) - 1)
+ assert eq, a3, a4
+ .endif
+.endm
+
+test extui
+ .set shiftimm, 0
+ .rept 32
+ .set maskimm, 1
+ .rept 16
+ test_extui 0xc8df1370, shiftimm, maskimm
+ .set maskimm, maskimm + 1
+ .endr
+ .set shiftimm, shiftimm + 1
+ .endr
+test_end
+
+test_suite_end
diff --git a/tests/tcg/xtensa/test_s32c1i.S b/tests/tcg/xtensa/test_s32c1i.S
new file mode 100644
index 000000000..4536015a8
--- /dev/null
+++ b/tests/tcg/xtensa/test_s32c1i.S
@@ -0,0 +1,39 @@
+.include "macros.inc"
+
+test_suite s32c1i
+
+test s32c1i_nowrite
+ movi a2, 1f
+ movi a3, 1
+ wsr a3, scompare1
+ movi a1, 2
+ s32c1i a1, a2, 0
+ assert ne, a1, a3
+ l32i a1, a2, 0
+ assert eqi, a1, 3
+
+.data
+.align 4
+1:
+ .word 3
+.text
+test_end
+
+test s32c1i_write
+ movi a2, 1f
+ movi a3, 3
+ wsr a3, scompare1
+ movi a1, 2
+ s32c1i a1, a2, 0
+ assert eq, a1, a3
+ l32i a1, a2, 0
+ assert eqi, a1, 2
+
+.data
+.align 4
+1:
+ .word 3
+.text
+test_end
+
+test_suite_end
diff --git a/tests/tcg/xtensa/test_sr.S b/tests/tcg/xtensa/test_sr.S
new file mode 100644
index 000000000..470c03dae
--- /dev/null
+++ b/tests/tcg/xtensa/test_sr.S
@@ -0,0 +1,90 @@
+.include "macros.inc"
+
+test_suite sr
+
+.macro sr_op sym, op_sym, op_byte, sr
+ .if \sym
+ \op_sym a4, \sr
+ .else
+ .byte 0x40, \sr, \op_byte
+ .endif
+.endm
+
+.macro test_sr_op sym, mask, op, op_byte, sr
+ movi a4, 0
+ .if (\mask)
+ set_vector kernel, 0
+ sr_op \sym, \op, \op_byte, \sr
+ .else
+ set_vector kernel, 2f
+1:
+ sr_op \sym, \op, \op_byte, \sr
+ test_fail
+2:
+ reset_ps
+ rsr a2, exccause
+ assert eqi, a2, 0
+ rsr a2, epc1
+ movi a3, 1b
+ assert eq, a2, a3
+ .endif
+.endm
+
+.macro test_sr_mask sr, sym, mask
+test \sr
+ test_sr_op \sym, \mask & 1, rsr, 0x03, \sr
+ test_sr_op \sym, \mask & 2, wsr, 0x13, \sr
+ test_sr_op \sym, \mask & 4, xsr, 0x61, \sr
+test_end
+.endm
+
+.macro test_sr sr, conf
+ test_sr_mask \sr, \conf, 7
+.endm
+
+test_sr acchi, 1
+test_sr acclo, 1
+test_sr_mask /*atomctl*/99, 0, 0
+test_sr_mask /*br*/4, 0, 0
+test_sr_mask /*cacheattr*/98, 0, 0
+test_sr ccompare0, 1
+test_sr ccount, 1
+test_sr cpenable, 1
+test_sr dbreaka0, 1
+test_sr dbreakc0, 1
+test_sr_mask debugcause, 1, 1
+test_sr depc, 1
+test_sr dtlbcfg, 1
+test_sr epc1, 1
+test_sr epc2, 1
+test_sr eps2, 1
+test_sr exccause, 1
+test_sr excsave1, 1
+test_sr excsave2, 1
+test_sr excvaddr, 1
+test_sr ibreaka0, 1
+test_sr ibreakenable, 1
+test_sr icount, 1
+test_sr icountlevel, 1
+test_sr_mask /*intclear*/227, 0, 2
+test_sr_mask /*interrupt*/226, 0, 3
+test_sr intenable, 1
+test_sr itlbcfg, 1
+test_sr lbeg, 1
+test_sr lcount, 1
+test_sr lend, 1
+test_sr litbase, 1
+test_sr m0, 1
+test_sr misc0, 1
+test_sr_mask /*prefctl*/40, 0, 0
+test_sr_mask /*prid*/235, 0, 1
+test_sr ps, 1
+test_sr ptevaddr, 1
+test_sr rasid, 1
+test_sr sar, 1
+test_sr scompare1, 1
+test_sr vecbase, 1
+test_sr windowbase, 1
+test_sr windowstart, 1
+
+test_suite_end
diff --git a/tests/test-aio.c b/tests/test-aio.c
index f53c90870..c1738706c 100644
--- a/tests/test-aio.c
+++ b/tests/test-aio.c
@@ -11,10 +11,18 @@
*/
#include <glib.h>
-#include "qemu-aio.h"
+#include "block/aio.h"
AioContext *ctx;
+/* Wait until there are no more BHs or AIO requests */
+static void wait_for_aio(void)
+{
+ while (aio_poll(ctx, true)) {
+ /* Do nothing */
+ }
+}
+
/* Simple callbacks for testing. */
typedef struct {
@@ -78,14 +86,6 @@ static void test_notify(void)
g_assert(!aio_poll(ctx, false));
}
-static void test_flush(void)
-{
- g_assert(!aio_poll(ctx, false));
- aio_notify(ctx);
- aio_flush(ctx);
- g_assert(!aio_poll(ctx, false));
-}
-
static void test_bh_schedule(void)
{
BHTestData data = { .n = 0 };
@@ -116,7 +116,7 @@ static void test_bh_schedule10(void)
g_assert(aio_poll(ctx, true));
g_assert_cmpint(data.n, ==, 2);
- aio_flush(ctx);
+ wait_for_aio();
g_assert_cmpint(data.n, ==, 10);
g_assert(!aio_poll(ctx, false));
@@ -164,7 +164,7 @@ static void test_bh_delete_from_cb(void)
qemu_bh_schedule(data1.bh);
g_assert_cmpint(data1.n, ==, 0);
- aio_flush(ctx);
+ wait_for_aio();
g_assert_cmpint(data1.n, ==, data1.max);
g_assert(data1.bh == NULL);
@@ -200,7 +200,7 @@ static void test_bh_delete_from_cb_many(void)
g_assert_cmpint(data4.n, ==, 1);
g_assert(data1.bh == NULL);
- aio_flush(ctx);
+ wait_for_aio();
g_assert_cmpint(data1.n, ==, data1.max);
g_assert_cmpint(data2.n, ==, data2.max);
g_assert_cmpint(data3.n, ==, data3.max);
@@ -219,7 +219,7 @@ static void test_bh_flush(void)
qemu_bh_schedule(data.bh);
g_assert_cmpint(data.n, ==, 0);
- aio_flush(ctx);
+ wait_for_aio();
g_assert_cmpint(data.n, ==, 1);
g_assert(!aio_poll(ctx, false));
@@ -281,7 +281,7 @@ static void test_flush_event_notifier(void)
g_assert_cmpint(data.active, ==, 9);
g_assert(aio_poll(ctx, false));
- aio_flush(ctx);
+ wait_for_aio();
g_assert_cmpint(data.n, ==, 10);
g_assert_cmpint(data.active, ==, 0);
g_assert(!aio_poll(ctx, false));
@@ -315,17 +315,17 @@ static void test_wait_event_notifier_noflush(void)
event_notifier_set(&data.e);
g_assert(aio_poll(ctx, false));
g_assert_cmpint(data.n, ==, 1);
- g_assert(!aio_poll(ctx, false));
+ g_assert(aio_poll(ctx, false));
g_assert_cmpint(data.n, ==, 1);
event_notifier_set(&data.e);
g_assert(aio_poll(ctx, false));
g_assert_cmpint(data.n, ==, 2);
- g_assert(!aio_poll(ctx, false));
+ g_assert(aio_poll(ctx, false));
g_assert_cmpint(data.n, ==, 2);
event_notifier_set(&dummy.e);
- aio_flush(ctx);
+ wait_for_aio();
g_assert_cmpint(data.n, ==, 2);
g_assert_cmpint(dummy.n, ==, 1);
g_assert_cmpint(dummy.active, ==, 0);
@@ -346,7 +346,7 @@ static void test_wait_event_notifier_noflush(void)
* - sometimes both the AioContext and the glib main loop wake
* themselves up. Hence, some "g_assert(!aio_poll(ctx, false));"
* are replaced by "while (g_main_context_iteration(NULL, false));".
- * - there is no exact replacement for aio_flush's blocking wait.
+ * - there is no exact replacement for a blocking wait.
* "while (g_main_context_iteration(NULL, true)" seems to work,
* but it is not documented _why_ it works. For these tests a
* non-blocking loop like "while (g_main_context_iteration(NULL, false)"
@@ -637,7 +637,6 @@ int main(int argc, char **argv)
g_test_init(&argc, &argv, NULL);
g_test_add_func("/aio/notify", test_notify);
- g_test_add_func("/aio/flush", test_flush);
g_test_add_func("/aio/bh/schedule", test_bh_schedule);
g_test_add_func("/aio/bh/schedule10", test_bh_schedule10);
g_test_add_func("/aio/bh/cancel", test_bh_cancel);
diff --git a/tests/test-bitops.c b/tests/test-bitops.c
new file mode 100644
index 000000000..4e713e4e0
--- /dev/null
+++ b/tests/test-bitops.c
@@ -0,0 +1,75 @@
+/*
+ * Test bitops routines
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2 or later.
+ * See the COPYING.LIB file in the top-level directory.
+ *
+ */
+
+#include <glib.h>
+#include <stdint.h>
+#include "qemu/bitops.h"
+
+typedef struct {
+ uint32_t value;
+ int start;
+ int length;
+ int32_t result;
+} S32Test;
+
+typedef struct {
+ uint64_t value;
+ int start;
+ int length;
+ int64_t result;
+} S64Test;
+
+static const S32Test test_s32_data[] = {
+ { 0x38463983, 4, 4, -8 },
+ { 0x38463983, 12, 8, 0x63 },
+ { 0x38463983, 0, 32, 0x38463983 },
+};
+
+static const S64Test test_s64_data[] = {
+ { 0x8459826734967223, 60, 4, -8 },
+ { 0x8459826734967223, 0, 64, 0x8459826734967223 },
+};
+
+static void test_sextract32(void)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(test_s32_data); i++) {
+ const S32Test *test = &test_s32_data[i];
+ int32_t r = sextract32(test->value, test->start, test->length);
+
+ g_assert_cmpint(r, ==, test->result);
+ }
+}
+
+static void test_sextract64(void)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(test_s32_data); i++) {
+ const S32Test *test = &test_s32_data[i];
+ int64_t r = sextract64(test->value, test->start, test->length);
+
+ g_assert_cmpint(r, ==, test->result);
+ }
+
+ for (i = 0; i < ARRAY_SIZE(test_s64_data); i++) {
+ const S64Test *test = &test_s64_data[i];
+ int64_t r = sextract64(test->value, test->start, test->length);
+
+ g_assert_cmpint(r, ==, test->result);
+ }
+}
+
+int main(int argc, char **argv)
+{
+ g_test_init(&argc, &argv, NULL);
+ g_test_add_func("/bitops/sextract32", test_sextract32);
+ g_test_add_func("/bitops/sextract64", test_sextract64);
+ return g_test_run();
+}
diff --git a/tests/test-coroutine.c b/tests/test-coroutine.c
index e5d14eb69..39be046ec 100644
--- a/tests/test-coroutine.c
+++ b/tests/test-coroutine.c
@@ -12,7 +12,7 @@
*/
#include <glib.h>
-#include "qemu-coroutine.h"
+#include "block/coroutine.h"
/*
* Check that qemu_in_coroutine() works
@@ -183,7 +183,7 @@ static void perf_nesting(void)
double duration;
maxcycles = 100000000;
- maxnesting = 20000;
+ maxnesting = 1000;
Coroutine *root;
NestData nd = {
.n_enter = 0,
diff --git a/tests/test-cutils.c b/tests/test-cutils.c
new file mode 100644
index 000000000..2a4556d3a
--- /dev/null
+++ b/tests/test-cutils.c
@@ -0,0 +1,251 @@
+/*
+ * cutils.c unit-tests
+ *
+ * Copyright (C) 2013 Red Hat Inc.
+ *
+ * Authors:
+ * Eduardo Habkost <ehabkost@redhat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include <glib.h>
+#include <errno.h>
+#include <string.h>
+
+#include "qemu-common.h"
+
+
+static void test_parse_uint_null(void)
+{
+ unsigned long long i = 999;
+ char f = 'X';
+ char *endptr = &f;
+ int r;
+
+ r = parse_uint(NULL, &i, &endptr, 0);
+
+ g_assert_cmpint(r, ==, -EINVAL);
+ g_assert_cmpint(i, ==, 0);
+ g_assert(endptr == NULL);
+}
+
+static void test_parse_uint_empty(void)
+{
+ unsigned long long i = 999;
+ char f = 'X';
+ char *endptr = &f;
+ const char *str = "";
+ int r;
+
+ r = parse_uint(str, &i, &endptr, 0);
+
+ g_assert_cmpint(r, ==, -EINVAL);
+ g_assert_cmpint(i, ==, 0);
+ g_assert(endptr == str);
+}
+
+static void test_parse_uint_whitespace(void)
+{
+ unsigned long long i = 999;
+ char f = 'X';
+ char *endptr = &f;
+ const char *str = " \t ";
+ int r;
+
+ r = parse_uint(str, &i, &endptr, 0);
+
+ g_assert_cmpint(r, ==, -EINVAL);
+ g_assert_cmpint(i, ==, 0);
+ g_assert(endptr == str);
+}
+
+
+static void test_parse_uint_invalid(void)
+{
+ unsigned long long i = 999;
+ char f = 'X';
+ char *endptr = &f;
+ const char *str = " \t xxx";
+ int r;
+
+ r = parse_uint(str, &i, &endptr, 0);
+
+ g_assert_cmpint(r, ==, -EINVAL);
+ g_assert_cmpint(i, ==, 0);
+ g_assert(endptr == str);
+}
+
+
+static void test_parse_uint_trailing(void)
+{
+ unsigned long long i = 999;
+ char f = 'X';
+ char *endptr = &f;
+ const char *str = "123xxx";
+ int r;
+
+ r = parse_uint(str, &i, &endptr, 0);
+
+ g_assert_cmpint(r, ==, 0);
+ g_assert_cmpint(i, ==, 123);
+ g_assert(endptr == str + 3);
+}
+
+static void test_parse_uint_correct(void)
+{
+ unsigned long long i = 999;
+ char f = 'X';
+ char *endptr = &f;
+ const char *str = "123";
+ int r;
+
+ r = parse_uint(str, &i, &endptr, 0);
+
+ g_assert_cmpint(r, ==, 0);
+ g_assert_cmpint(i, ==, 123);
+ g_assert(endptr == str + strlen(str));
+}
+
+static void test_parse_uint_octal(void)
+{
+ unsigned long long i = 999;
+ char f = 'X';
+ char *endptr = &f;
+ const char *str = "0123";
+ int r;
+
+ r = parse_uint(str, &i, &endptr, 0);
+
+ g_assert_cmpint(r, ==, 0);
+ g_assert_cmpint(i, ==, 0123);
+ g_assert(endptr == str + strlen(str));
+}
+
+static void test_parse_uint_decimal(void)
+{
+ unsigned long long i = 999;
+ char f = 'X';
+ char *endptr = &f;
+ const char *str = "0123";
+ int r;
+
+ r = parse_uint(str, &i, &endptr, 10);
+
+ g_assert_cmpint(r, ==, 0);
+ g_assert_cmpint(i, ==, 123);
+ g_assert(endptr == str + strlen(str));
+}
+
+
+static void test_parse_uint_llong_max(void)
+{
+ unsigned long long i = 999;
+ char f = 'X';
+ char *endptr = &f;
+ char *str = g_strdup_printf("%llu", (unsigned long long)LLONG_MAX + 1);
+ int r;
+
+ r = parse_uint(str, &i, &endptr, 0);
+
+ g_assert_cmpint(r, ==, 0);
+ g_assert_cmpint(i, ==, (unsigned long long)LLONG_MAX + 1);
+ g_assert(endptr == str + strlen(str));
+
+ g_free(str);
+}
+
+static void test_parse_uint_overflow(void)
+{
+ unsigned long long i = 999;
+ char f = 'X';
+ char *endptr = &f;
+ const char *str = "99999999999999999999999999999999999999";
+ int r;
+
+ r = parse_uint(str, &i, &endptr, 0);
+
+ g_assert_cmpint(r, ==, -ERANGE);
+ g_assert_cmpint(i, ==, ULLONG_MAX);
+ g_assert(endptr == str + strlen(str));
+}
+
+static void test_parse_uint_negative(void)
+{
+ unsigned long long i = 999;
+ char f = 'X';
+ char *endptr = &f;
+ const char *str = " \t -321";
+ int r;
+
+ r = parse_uint(str, &i, &endptr, 0);
+
+ g_assert_cmpint(r, ==, -ERANGE);
+ g_assert_cmpint(i, ==, 0);
+ g_assert(endptr == str + strlen(str));
+}
+
+
+static void test_parse_uint_full_trailing(void)
+{
+ unsigned long long i = 999;
+ const char *str = "123xxx";
+ int r;
+
+ r = parse_uint_full(str, &i, 0);
+
+ g_assert_cmpint(r, ==, -EINVAL);
+ g_assert_cmpint(i, ==, 0);
+}
+
+static void test_parse_uint_full_correct(void)
+{
+ unsigned long long i = 999;
+ const char *str = "123";
+ int r;
+
+ r = parse_uint_full(str, &i, 0);
+
+ g_assert_cmpint(r, ==, 0);
+ g_assert_cmpint(i, ==, 123);
+}
+
+int main(int argc, char **argv)
+{
+ g_test_init(&argc, &argv, NULL);
+
+ g_test_add_func("/cutils/parse_uint/null", test_parse_uint_null);
+ g_test_add_func("/cutils/parse_uint/empty", test_parse_uint_empty);
+ g_test_add_func("/cutils/parse_uint/whitespace",
+ test_parse_uint_whitespace);
+ g_test_add_func("/cutils/parse_uint/invalid", test_parse_uint_invalid);
+ g_test_add_func("/cutils/parse_uint/trailing", test_parse_uint_trailing);
+ g_test_add_func("/cutils/parse_uint/correct", test_parse_uint_correct);
+ g_test_add_func("/cutils/parse_uint/octal", test_parse_uint_octal);
+ g_test_add_func("/cutils/parse_uint/decimal", test_parse_uint_decimal);
+ g_test_add_func("/cutils/parse_uint/llong_max", test_parse_uint_llong_max);
+ g_test_add_func("/cutils/parse_uint/overflow", test_parse_uint_overflow);
+ g_test_add_func("/cutils/parse_uint/negative", test_parse_uint_negative);
+ g_test_add_func("/cutils/parse_uint_full/trailing",
+ test_parse_uint_full_trailing);
+ g_test_add_func("/cutils/parse_uint_full/correct",
+ test_parse_uint_full_correct);
+
+ return g_test_run();
+}
diff --git a/tests/test-hbitmap.c b/tests/test-hbitmap.c
new file mode 100644
index 000000000..8c902f205
--- /dev/null
+++ b/tests/test-hbitmap.c
@@ -0,0 +1,401 @@
+/*
+ * Hierarchical bitmap unit-tests.
+ *
+ * Copyright (C) 2012 Red Hat Inc.
+ *
+ * Author: Paolo Bonzini <pbonzini@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 "qemu/hbitmap.h"
+
+#define LOG_BITS_PER_LONG (BITS_PER_LONG == 32 ? 5 : 6)
+
+#define L1 BITS_PER_LONG
+#define L2 (BITS_PER_LONG * L1)
+#define L3 (BITS_PER_LONG * L2)
+
+typedef struct TestHBitmapData {
+ HBitmap *hb;
+ unsigned long *bits;
+ size_t size;
+ int granularity;
+} TestHBitmapData;
+
+
+/* Check that the HBitmap and the shadow bitmap contain the same data,
+ * ignoring the same "first" bits.
+ */
+static void hbitmap_test_check(TestHBitmapData *data,
+ uint64_t first)
+{
+ uint64_t count = 0;
+ size_t pos;
+ int bit;
+ HBitmapIter hbi;
+ int64_t i, next;
+
+ hbitmap_iter_init(&hbi, data->hb, first);
+
+ i = first;
+ for (;;) {
+ next = hbitmap_iter_next(&hbi);
+ if (next < 0) {
+ next = data->size;
+ }
+
+ while (i < next) {
+ pos = i >> LOG_BITS_PER_LONG;
+ bit = i & (BITS_PER_LONG - 1);
+ i++;
+ g_assert_cmpint(data->bits[pos] & (1UL << bit), ==, 0);
+ }
+
+ if (next == data->size) {
+ break;
+ }
+
+ pos = i >> LOG_BITS_PER_LONG;
+ bit = i & (BITS_PER_LONG - 1);
+ i++;
+ count++;
+ g_assert_cmpint(data->bits[pos] & (1UL << bit), !=, 0);
+ }
+
+ if (first == 0) {
+ g_assert_cmpint(count << data->granularity, ==, hbitmap_count(data->hb));
+ }
+}
+
+/* This is provided instead of a test setup function so that the sizes
+ are kept in the test functions (and not in main()) */
+static void hbitmap_test_init(TestHBitmapData *data,
+ uint64_t size, int granularity)
+{
+ size_t n;
+ data->hb = hbitmap_alloc(size, granularity);
+
+ n = (size + BITS_PER_LONG - 1) / BITS_PER_LONG;
+ if (n == 0) {
+ n = 1;
+ }
+ data->bits = g_new0(unsigned long, n);
+ data->size = size;
+ data->granularity = granularity;
+ if (size) {
+ hbitmap_test_check(data, 0);
+ }
+}
+
+static void hbitmap_test_teardown(TestHBitmapData *data,
+ const void *unused)
+{
+ if (data->hb) {
+ hbitmap_free(data->hb);
+ data->hb = NULL;
+ }
+ if (data->bits) {
+ g_free(data->bits);
+ data->bits = NULL;
+ }
+}
+
+/* Set a range in the HBitmap and in the shadow "simple" bitmap.
+ * The two bitmaps are then tested against each other.
+ */
+static void hbitmap_test_set(TestHBitmapData *data,
+ uint64_t first, uint64_t count)
+{
+ hbitmap_set(data->hb, first, count);
+ while (count-- != 0) {
+ size_t pos = first >> LOG_BITS_PER_LONG;
+ int bit = first & (BITS_PER_LONG - 1);
+ first++;
+
+ data->bits[pos] |= 1UL << bit;
+ }
+
+ if (data->granularity == 0) {
+ hbitmap_test_check(data, 0);
+ }
+}
+
+/* Reset a range in the HBitmap and in the shadow "simple" bitmap.
+ */
+static void hbitmap_test_reset(TestHBitmapData *data,
+ uint64_t first, uint64_t count)
+{
+ hbitmap_reset(data->hb, first, count);
+ while (count-- != 0) {
+ size_t pos = first >> LOG_BITS_PER_LONG;
+ int bit = first & (BITS_PER_LONG - 1);
+ first++;
+
+ data->bits[pos] &= ~(1UL << bit);
+ }
+
+ if (data->granularity == 0) {
+ hbitmap_test_check(data, 0);
+ }
+}
+
+static void hbitmap_test_check_get(TestHBitmapData *data)
+{
+ uint64_t count = 0;
+ uint64_t i;
+
+ for (i = 0; i < data->size; i++) {
+ size_t pos = i >> LOG_BITS_PER_LONG;
+ int bit = i & (BITS_PER_LONG - 1);
+ unsigned long val = data->bits[pos] & (1UL << bit);
+ count += hbitmap_get(data->hb, i);
+ g_assert_cmpint(hbitmap_get(data->hb, i), ==, val != 0);
+ }
+ g_assert_cmpint(count, ==, hbitmap_count(data->hb));
+}
+
+static void test_hbitmap_zero(TestHBitmapData *data,
+ const void *unused)
+{
+ hbitmap_test_init(data, 0, 0);
+}
+
+static void test_hbitmap_unaligned(TestHBitmapData *data,
+ const void *unused)
+{
+ hbitmap_test_init(data, L3 + 23, 0);
+ hbitmap_test_set(data, 0, 1);
+ hbitmap_test_set(data, L3 + 22, 1);
+}
+
+static void test_hbitmap_iter_empty(TestHBitmapData *data,
+ const void *unused)
+{
+ hbitmap_test_init(data, L1, 0);
+}
+
+static void test_hbitmap_iter_partial(TestHBitmapData *data,
+ const void *unused)
+{
+ hbitmap_test_init(data, L3, 0);
+ hbitmap_test_set(data, 0, L3);
+ hbitmap_test_check(data, 1);
+ hbitmap_test_check(data, L1 - 1);
+ hbitmap_test_check(data, L1);
+ hbitmap_test_check(data, L1 * 2 - 1);
+ hbitmap_test_check(data, L2 - 1);
+ hbitmap_test_check(data, L2);
+ hbitmap_test_check(data, L2 + 1);
+ hbitmap_test_check(data, L2 + L1);
+ hbitmap_test_check(data, L2 + L1 * 2 - 1);
+ hbitmap_test_check(data, L2 * 2 - 1);
+ hbitmap_test_check(data, L2 * 2);
+ hbitmap_test_check(data, L2 * 2 + 1);
+ hbitmap_test_check(data, L2 * 2 + L1);
+ hbitmap_test_check(data, L2 * 2 + L1 * 2 - 1);
+ hbitmap_test_check(data, L3 / 2);
+}
+
+static void test_hbitmap_set_all(TestHBitmapData *data,
+ const void *unused)
+{
+ hbitmap_test_init(data, L3, 0);
+ hbitmap_test_set(data, 0, L3);
+}
+
+static void test_hbitmap_get_all(TestHBitmapData *data,
+ const void *unused)
+{
+ hbitmap_test_init(data, L3, 0);
+ hbitmap_test_set(data, 0, L3);
+ hbitmap_test_check_get(data);
+}
+
+static void test_hbitmap_get_some(TestHBitmapData *data,
+ const void *unused)
+{
+ hbitmap_test_init(data, 2 * L2, 0);
+ hbitmap_test_set(data, 10, 1);
+ hbitmap_test_check_get(data);
+ hbitmap_test_set(data, L1 - 1, 1);
+ hbitmap_test_check_get(data);
+ hbitmap_test_set(data, L1, 1);
+ hbitmap_test_check_get(data);
+ hbitmap_test_set(data, L2 - 1, 1);
+ hbitmap_test_check_get(data);
+ hbitmap_test_set(data, L2, 1);
+ hbitmap_test_check_get(data);
+}
+
+static void test_hbitmap_set_one(TestHBitmapData *data,
+ const void *unused)
+{
+ hbitmap_test_init(data, 2 * L2, 0);
+ hbitmap_test_set(data, 10, 1);
+ hbitmap_test_set(data, L1 - 1, 1);
+ hbitmap_test_set(data, L1, 1);
+ hbitmap_test_set(data, L2 - 1, 1);
+ hbitmap_test_set(data, L2, 1);
+}
+
+static void test_hbitmap_set_two_elem(TestHBitmapData *data,
+ const void *unused)
+{
+ hbitmap_test_init(data, 2 * L2, 0);
+ hbitmap_test_set(data, L1 - 1, 2);
+ hbitmap_test_set(data, L1 * 2 - 1, 4);
+ hbitmap_test_set(data, L1 * 4, L1 + 1);
+ hbitmap_test_set(data, L1 * 8 - 1, L1 + 1);
+ hbitmap_test_set(data, L2 - 1, 2);
+ hbitmap_test_set(data, L2 + L1 - 1, 8);
+ hbitmap_test_set(data, L2 + L1 * 4, L1 + 1);
+ hbitmap_test_set(data, L2 + L1 * 8 - 1, L1 + 1);
+}
+
+static void test_hbitmap_set(TestHBitmapData *data,
+ const void *unused)
+{
+ hbitmap_test_init(data, L3 * 2, 0);
+ hbitmap_test_set(data, L1 - 1, L1 + 2);
+ hbitmap_test_set(data, L1 * 3 - 1, L1 + 2);
+ hbitmap_test_set(data, L1 * 5, L1 * 2 + 1);
+ hbitmap_test_set(data, L1 * 8 - 1, L1 * 2 + 1);
+ hbitmap_test_set(data, L2 - 1, L1 + 2);
+ hbitmap_test_set(data, L2 + L1 * 2 - 1, L1 + 2);
+ hbitmap_test_set(data, L2 + L1 * 4, L1 * 2 + 1);
+ hbitmap_test_set(data, L2 + L1 * 7 - 1, L1 * 2 + 1);
+ hbitmap_test_set(data, L2 * 2 - 1, L3 * 2 - L2 * 2);
+}
+
+static void test_hbitmap_set_twice(TestHBitmapData *data,
+ const void *unused)
+{
+ hbitmap_test_init(data, L1 * 3, 0);
+ hbitmap_test_set(data, 0, L1 * 3);
+ hbitmap_test_set(data, L1, 1);
+}
+
+static void test_hbitmap_set_overlap(TestHBitmapData *data,
+ const void *unused)
+{
+ hbitmap_test_init(data, L3 * 2, 0);
+ hbitmap_test_set(data, L1 - 1, L1 + 2);
+ hbitmap_test_set(data, L1 * 2 - 1, L1 * 2 + 2);
+ hbitmap_test_set(data, 0, L1 * 3);
+ hbitmap_test_set(data, L1 * 8 - 1, L2);
+ hbitmap_test_set(data, L2, L1);
+ hbitmap_test_set(data, L2 - L1 - 1, L1 * 8 + 2);
+ hbitmap_test_set(data, L2, L3 - L2 + 1);
+ hbitmap_test_set(data, L3 - L1, L1 * 3);
+ hbitmap_test_set(data, L3 - 1, 3);
+ hbitmap_test_set(data, L3 - 1, L2);
+}
+
+static void test_hbitmap_reset_empty(TestHBitmapData *data,
+ const void *unused)
+{
+ hbitmap_test_init(data, L3, 0);
+ hbitmap_test_reset(data, 0, L3);
+}
+
+static void test_hbitmap_reset(TestHBitmapData *data,
+ const void *unused)
+{
+ hbitmap_test_init(data, L3 * 2, 0);
+ hbitmap_test_set(data, L1 - 1, L1 + 2);
+ hbitmap_test_reset(data, L1 * 2 - 1, L1 * 2 + 2);
+ hbitmap_test_set(data, 0, L1 * 3);
+ hbitmap_test_reset(data, L1 * 8 - 1, L2);
+ hbitmap_test_set(data, L2, L1);
+ hbitmap_test_reset(data, L2 - L1 - 1, L1 * 8 + 2);
+ hbitmap_test_set(data, L2, L3 - L2 + 1);
+ hbitmap_test_reset(data, L3 - L1, L1 * 3);
+ hbitmap_test_set(data, L3 - 1, 3);
+ hbitmap_test_reset(data, L3 - 1, L2);
+ hbitmap_test_set(data, 0, L3 * 2);
+ hbitmap_test_reset(data, 0, L1);
+ hbitmap_test_reset(data, 0, L2);
+ hbitmap_test_reset(data, L3, L3);
+ hbitmap_test_set(data, L3 / 2, L3);
+}
+
+static void test_hbitmap_granularity(TestHBitmapData *data,
+ const void *unused)
+{
+ /* Note that hbitmap_test_check has to be invoked manually in this test. */
+ hbitmap_test_init(data, L1, 1);
+ hbitmap_test_set(data, 0, 1);
+ g_assert_cmpint(hbitmap_count(data->hb), ==, 2);
+ hbitmap_test_check(data, 0);
+ hbitmap_test_set(data, 2, 1);
+ g_assert_cmpint(hbitmap_count(data->hb), ==, 4);
+ hbitmap_test_check(data, 0);
+ hbitmap_test_set(data, 0, 3);
+ g_assert_cmpint(hbitmap_count(data->hb), ==, 4);
+ hbitmap_test_reset(data, 0, 1);
+ g_assert_cmpint(hbitmap_count(data->hb), ==, 2);
+}
+
+static void test_hbitmap_iter_granularity(TestHBitmapData *data,
+ const void *unused)
+{
+ HBitmapIter hbi;
+
+ /* Note that hbitmap_test_check has to be invoked manually in this test. */
+ hbitmap_test_init(data, 131072 << 7, 7);
+ hbitmap_iter_init(&hbi, data->hb, 0);
+ g_assert_cmpint(hbitmap_iter_next(&hbi), <, 0);
+
+ hbitmap_test_set(data, ((L2 + L1 + 1) << 7) + 8, 8);
+ hbitmap_iter_init(&hbi, data->hb, 0);
+ g_assert_cmpint(hbitmap_iter_next(&hbi), ==, (L2 + L1 + 1) << 7);
+ g_assert_cmpint(hbitmap_iter_next(&hbi), <, 0);
+
+ hbitmap_iter_init(&hbi, data->hb, (L2 + L1 + 2) << 7);
+ g_assert_cmpint(hbitmap_iter_next(&hbi), <, 0);
+
+ hbitmap_test_set(data, (131072 << 7) - 8, 8);
+ hbitmap_iter_init(&hbi, data->hb, 0);
+ g_assert_cmpint(hbitmap_iter_next(&hbi), ==, (L2 + L1 + 1) << 7);
+ g_assert_cmpint(hbitmap_iter_next(&hbi), ==, 131071 << 7);
+ g_assert_cmpint(hbitmap_iter_next(&hbi), <, 0);
+
+ hbitmap_iter_init(&hbi, data->hb, (L2 + L1 + 2) << 7);
+ g_assert_cmpint(hbitmap_iter_next(&hbi), ==, 131071 << 7);
+ g_assert_cmpint(hbitmap_iter_next(&hbi), <, 0);
+}
+
+static void hbitmap_test_add(const char *testpath,
+ void (*test_func)(TestHBitmapData *data, const void *user_data))
+{
+ g_test_add(testpath, TestHBitmapData, NULL, NULL, test_func,
+ hbitmap_test_teardown);
+}
+
+int main(int argc, char **argv)
+{
+ g_test_init(&argc, &argv, NULL);
+ hbitmap_test_add("/hbitmap/size/0", test_hbitmap_zero);
+ hbitmap_test_add("/hbitmap/size/unaligned", test_hbitmap_unaligned);
+ hbitmap_test_add("/hbitmap/iter/empty", test_hbitmap_iter_empty);
+ hbitmap_test_add("/hbitmap/iter/partial", test_hbitmap_iter_partial);
+ hbitmap_test_add("/hbitmap/iter/granularity", test_hbitmap_iter_granularity);
+ hbitmap_test_add("/hbitmap/get/all", test_hbitmap_get_all);
+ hbitmap_test_add("/hbitmap/get/some", test_hbitmap_get_some);
+ hbitmap_test_add("/hbitmap/set/all", test_hbitmap_set_all);
+ hbitmap_test_add("/hbitmap/set/one", test_hbitmap_set_one);
+ hbitmap_test_add("/hbitmap/set/two-elem", test_hbitmap_set_two_elem);
+ hbitmap_test_add("/hbitmap/set/general", test_hbitmap_set);
+ hbitmap_test_add("/hbitmap/set/twice", test_hbitmap_set_twice);
+ hbitmap_test_add("/hbitmap/set/overlap", test_hbitmap_set_overlap);
+ hbitmap_test_add("/hbitmap/reset/empty", test_hbitmap_reset_empty);
+ hbitmap_test_add("/hbitmap/reset/general", test_hbitmap_reset);
+ hbitmap_test_add("/hbitmap/granularity", test_hbitmap_granularity);
+ g_test_run();
+
+ return 0;
+}
diff --git a/tests/test-int128.c b/tests/test-int128.c
new file mode 100644
index 000000000..5aca032e0
--- /dev/null
+++ b/tests/test-int128.c
@@ -0,0 +1,212 @@
+/*
+ * Test Int128 arithmetic
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2 or later.
+ * See the COPYING.LIB file in the top-level directory.
+ *
+ */
+
+#include <glib.h>
+#include <stdio.h>
+#include "qemu/int128.h"
+#include "qemu/osdep.h"
+
+static uint32_t tests[8] = {
+ 0x00000000, 0x00000001, 0x7FFFFFFE, 0x7FFFFFFF,
+ 0x80000000, 0x80000001, 0xFFFFFFFE, 0xFFFFFFFF,
+};
+
+#define LOW 3ULL
+#define HIGH (1ULL << 63)
+#define MIDDLE (-1ULL & ~LOW & ~HIGH)
+
+static uint64_t expand16(unsigned x)
+{
+ return (x & LOW) | ((x & 4) ? MIDDLE : 0) | (x & 0x8000 ? HIGH : 0);
+}
+
+static Int128 expand(uint32_t x)
+{
+ uint64_t l, h;
+ l = expand16(x & 65535);
+ h = expand16(x >> 16);
+ return (Int128) {l, h};
+};
+
+static void test_and(void)
+{
+ int i, j;
+
+ for (i = 0; i < ARRAY_SIZE(tests); ++i) {
+ for (j = 0; j < ARRAY_SIZE(tests); ++j) {
+ Int128 a = expand(tests[i]);
+ Int128 b = expand(tests[j]);
+ Int128 r = expand(tests[i] & tests[j]);
+ Int128 s = int128_and(a, b);
+ g_assert_cmpuint(r.lo, ==, s.lo);
+ g_assert_cmpuint(r.hi, ==, s.hi);
+ }
+ }
+}
+
+static void test_add(void)
+{
+ int i, j;
+
+ for (i = 0; i < ARRAY_SIZE(tests); ++i) {
+ for (j = 0; j < ARRAY_SIZE(tests); ++j) {
+ Int128 a = expand(tests[i]);
+ Int128 b = expand(tests[j]);
+ Int128 r = expand(tests[i] + tests[j]);
+ Int128 s = int128_add(a, b);
+ g_assert_cmpuint(r.lo, ==, s.lo);
+ g_assert_cmpuint(r.hi, ==, s.hi);
+ }
+ }
+}
+
+static void test_sub(void)
+{
+ int i, j;
+
+ for (i = 0; i < ARRAY_SIZE(tests); ++i) {
+ for (j = 0; j < ARRAY_SIZE(tests); ++j) {
+ Int128 a = expand(tests[i]);
+ Int128 b = expand(tests[j]);
+ Int128 r = expand(tests[i] - tests[j]);
+ Int128 s = int128_sub(a, b);
+ g_assert_cmpuint(r.lo, ==, s.lo);
+ g_assert_cmpuint(r.hi, ==, s.hi);
+ }
+ }
+}
+
+static void test_neg(void)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(tests); ++i) {
+ Int128 a = expand(tests[i]);
+ Int128 r = expand(-tests[i]);
+ Int128 s = int128_neg(a);
+ g_assert_cmpuint(r.lo, ==, s.lo);
+ g_assert_cmpuint(r.hi, ==, s.hi);
+ }
+}
+
+static void test_nz(void)
+{
+ int i, j;
+
+ for (i = 0; i < ARRAY_SIZE(tests); ++i) {
+ for (j = 0; j < ARRAY_SIZE(tests); ++j) {
+ Int128 a = expand(tests[i]);
+ g_assert_cmpuint(int128_nz(a), ==, tests[i] != 0);
+ }
+ }
+}
+
+static void test_le(void)
+{
+ int i, j;
+
+ for (i = 0; i < ARRAY_SIZE(tests); ++i) {
+ for (j = 0; j < ARRAY_SIZE(tests); ++j) {
+ /* Signed comparison */
+ int32_t a = (int32_t) tests[i];
+ int32_t b = (int32_t) tests[j];
+ g_assert_cmpuint(int128_le(expand(a), expand(b)), ==, a <= b);
+ }
+ }
+}
+
+static void test_lt(void)
+{
+ int i, j;
+
+ for (i = 0; i < ARRAY_SIZE(tests); ++i) {
+ for (j = 0; j < ARRAY_SIZE(tests); ++j) {
+ /* Signed comparison */
+ int32_t a = (int32_t) tests[i];
+ int32_t b = (int32_t) tests[j];
+ g_assert_cmpuint(int128_lt(expand(a), expand(b)), ==, a < b);
+ }
+ }
+}
+
+static void test_ge(void)
+{
+ int i, j;
+
+ for (i = 0; i < ARRAY_SIZE(tests); ++i) {
+ for (j = 0; j < ARRAY_SIZE(tests); ++j) {
+ /* Signed comparison */
+ int32_t a = (int32_t) tests[i];
+ int32_t b = (int32_t) tests[j];
+ g_assert_cmpuint(int128_ge(expand(a), expand(b)), ==, a >= b);
+ }
+ }
+}
+
+static void test_gt(void)
+{
+ int i, j;
+
+ for (i = 0; i < ARRAY_SIZE(tests); ++i) {
+ for (j = 0; j < ARRAY_SIZE(tests); ++j) {
+ /* Signed comparison */
+ int32_t a = (int32_t) tests[i];
+ int32_t b = (int32_t) tests[j];
+ g_assert_cmpuint(int128_gt(expand(a), expand(b)), ==, a > b);
+ }
+ }
+}
+
+/* Make sure to test undefined behavior at runtime! */
+
+static void __attribute__((__noinline__, __noclone__))
+test_rshift_one(uint32_t x, int n, uint64_t h, uint64_t l)
+{
+ Int128 a = expand(x);
+ Int128 r = int128_rshift(a, n);
+ g_assert_cmpuint(r.lo, ==, l);
+ g_assert_cmpuint(r.hi, ==, h);
+}
+
+static void test_rshift(void)
+{
+ test_rshift_one(0x00010000U, 64, 0x0000000000000000ULL, 0x0000000000000001ULL);
+ test_rshift_one(0x80010000U, 64, 0xFFFFFFFFFFFFFFFFULL, 0x8000000000000001ULL);
+ test_rshift_one(0x7FFE0000U, 64, 0x0000000000000000ULL, 0x7FFFFFFFFFFFFFFEULL);
+ test_rshift_one(0xFFFE0000U, 64, 0xFFFFFFFFFFFFFFFFULL, 0xFFFFFFFFFFFFFFFEULL);
+ test_rshift_one(0x00010000U, 60, 0x0000000000000000ULL, 0x0000000000000010ULL);
+ test_rshift_one(0x80010000U, 60, 0xFFFFFFFFFFFFFFF8ULL, 0x0000000000000010ULL);
+ test_rshift_one(0x00018000U, 60, 0x0000000000000000ULL, 0x0000000000000018ULL);
+ test_rshift_one(0x80018000U, 60, 0xFFFFFFFFFFFFFFF8ULL, 0x0000000000000018ULL);
+ test_rshift_one(0x7FFE0000U, 60, 0x0000000000000007ULL, 0xFFFFFFFFFFFFFFE0ULL);
+ test_rshift_one(0xFFFE0000U, 60, 0xFFFFFFFFFFFFFFFFULL, 0xFFFFFFFFFFFFFFE0ULL);
+ test_rshift_one(0x7FFE8000U, 60, 0x0000000000000007ULL, 0xFFFFFFFFFFFFFFE8ULL);
+ test_rshift_one(0xFFFE8000U, 60, 0xFFFFFFFFFFFFFFFFULL, 0xFFFFFFFFFFFFFFE8ULL);
+ test_rshift_one(0x00018000U, 0, 0x0000000000000001ULL, 0x8000000000000000ULL);
+ test_rshift_one(0x80018000U, 0, 0x8000000000000001ULL, 0x8000000000000000ULL);
+ test_rshift_one(0x7FFE0000U, 0, 0x7FFFFFFFFFFFFFFEULL, 0x0000000000000000ULL);
+ test_rshift_one(0xFFFE0000U, 0, 0xFFFFFFFFFFFFFFFEULL, 0x0000000000000000ULL);
+ test_rshift_one(0x7FFE8000U, 0, 0x7FFFFFFFFFFFFFFEULL, 0x8000000000000000ULL);
+ test_rshift_one(0xFFFE8000U, 0, 0xFFFFFFFFFFFFFFFEULL, 0x8000000000000000ULL);
+}
+
+int main(int argc, char **argv)
+{
+ g_test_init(&argc, &argv, NULL);
+ g_test_add_func("/int128/int128_and", test_and);
+ g_test_add_func("/int128/int128_add", test_add);
+ g_test_add_func("/int128/int128_sub", test_sub);
+ g_test_add_func("/int128/int128_neg", test_neg);
+ g_test_add_func("/int128/int128_nz", test_nz);
+ g_test_add_func("/int128/int128_le", test_le);
+ g_test_add_func("/int128/int128_lt", test_lt);
+ g_test_add_func("/int128/int128_ge", test_ge);
+ g_test_add_func("/int128/int128_gt", test_gt);
+ g_test_add_func("/int128/int128_rshift", test_rshift);
+ return g_test_run();
+}
diff --git a/tests/test-iov.c b/tests/test-iov.c
index cbe7a8955..46e4dddc5 100644
--- a/tests/test-iov.c
+++ b/tests/test-iov.c
@@ -1,7 +1,7 @@
#include <glib.h>
#include "qemu-common.h"
-#include "iov.h"
-#include "qemu_socket.h"
+#include "qemu/iov.h"
+#include "qemu/sockets.h"
/* create a randomly-sized iovec with random vectors */
static void iov_random(struct iovec **iovp, unsigned *iov_cntp)
@@ -250,11 +250,161 @@ static void test_io(void)
#endif
}
+static void test_discard_front(void)
+{
+ struct iovec *iov;
+ struct iovec *iov_tmp;
+ unsigned int iov_cnt;
+ unsigned int iov_cnt_tmp;
+ void *old_base;
+ size_t size;
+ size_t ret;
+
+ /* Discard zero bytes */
+ iov_random(&iov, &iov_cnt);
+ iov_tmp = iov;
+ iov_cnt_tmp = iov_cnt;
+ ret = iov_discard_front(&iov_tmp, &iov_cnt_tmp, 0);
+ g_assert(ret == 0);
+ g_assert(iov_tmp == iov);
+ g_assert(iov_cnt_tmp == iov_cnt);
+ iov_free(iov, iov_cnt);
+
+ /* Discard more bytes than vector size */
+ iov_random(&iov, &iov_cnt);
+ iov_tmp = iov;
+ iov_cnt_tmp = iov_cnt;
+ size = iov_size(iov, iov_cnt);
+ ret = iov_discard_front(&iov_tmp, &iov_cnt_tmp, size + 1);
+ g_assert(ret == size);
+ g_assert(iov_cnt_tmp == 0);
+ iov_free(iov, iov_cnt);
+
+ /* Discard entire vector */
+ iov_random(&iov, &iov_cnt);
+ iov_tmp = iov;
+ iov_cnt_tmp = iov_cnt;
+ size = iov_size(iov, iov_cnt);
+ ret = iov_discard_front(&iov_tmp, &iov_cnt_tmp, size);
+ g_assert(ret == size);
+ g_assert(iov_cnt_tmp == 0);
+ iov_free(iov, iov_cnt);
+
+ /* Discard within first element */
+ iov_random(&iov, &iov_cnt);
+ iov_tmp = iov;
+ iov_cnt_tmp = iov_cnt;
+ old_base = iov->iov_base;
+ size = g_test_rand_int_range(1, iov->iov_len);
+ ret = iov_discard_front(&iov_tmp, &iov_cnt_tmp, size);
+ g_assert(ret == size);
+ g_assert(iov_tmp == iov);
+ g_assert(iov_cnt_tmp == iov_cnt);
+ g_assert(iov_tmp->iov_base == old_base + size);
+ iov_tmp->iov_base = old_base; /* undo before g_free() */
+ iov_free(iov, iov_cnt);
+
+ /* Discard entire first element */
+ iov_random(&iov, &iov_cnt);
+ iov_tmp = iov;
+ iov_cnt_tmp = iov_cnt;
+ ret = iov_discard_front(&iov_tmp, &iov_cnt_tmp, iov->iov_len);
+ g_assert(ret == iov->iov_len);
+ g_assert(iov_tmp == iov + 1);
+ g_assert(iov_cnt_tmp == iov_cnt - 1);
+ iov_free(iov, iov_cnt);
+
+ /* Discard within second element */
+ iov_random(&iov, &iov_cnt);
+ iov_tmp = iov;
+ iov_cnt_tmp = iov_cnt;
+ old_base = iov[1].iov_base;
+ size = iov->iov_len + g_test_rand_int_range(1, iov[1].iov_len);
+ ret = iov_discard_front(&iov_tmp, &iov_cnt_tmp, size);
+ g_assert(ret == size);
+ g_assert(iov_tmp == iov + 1);
+ g_assert(iov_cnt_tmp == iov_cnt - 1);
+ g_assert(iov_tmp->iov_base == old_base + (size - iov->iov_len));
+ iov_tmp->iov_base = old_base; /* undo before g_free() */
+ iov_free(iov, iov_cnt);
+}
+
+static void test_discard_back(void)
+{
+ struct iovec *iov;
+ unsigned int iov_cnt;
+ unsigned int iov_cnt_tmp;
+ void *old_base;
+ size_t size;
+ size_t ret;
+
+ /* Discard zero bytes */
+ iov_random(&iov, &iov_cnt);
+ iov_cnt_tmp = iov_cnt;
+ ret = iov_discard_back(iov, &iov_cnt_tmp, 0);
+ g_assert(ret == 0);
+ g_assert(iov_cnt_tmp == iov_cnt);
+ iov_free(iov, iov_cnt);
+
+ /* Discard more bytes than vector size */
+ iov_random(&iov, &iov_cnt);
+ iov_cnt_tmp = iov_cnt;
+ size = iov_size(iov, iov_cnt);
+ ret = iov_discard_back(iov, &iov_cnt_tmp, size + 1);
+ g_assert(ret == size);
+ g_assert(iov_cnt_tmp == 0);
+ iov_free(iov, iov_cnt);
+
+ /* Discard entire vector */
+ iov_random(&iov, &iov_cnt);
+ iov_cnt_tmp = iov_cnt;
+ size = iov_size(iov, iov_cnt);
+ ret = iov_discard_back(iov, &iov_cnt_tmp, size);
+ g_assert(ret == size);
+ g_assert(iov_cnt_tmp == 0);
+ iov_free(iov, iov_cnt);
+
+ /* Discard within last element */
+ iov_random(&iov, &iov_cnt);
+ iov_cnt_tmp = iov_cnt;
+ old_base = iov[iov_cnt - 1].iov_base;
+ size = g_test_rand_int_range(1, iov[iov_cnt - 1].iov_len);
+ ret = iov_discard_back(iov, &iov_cnt_tmp, size);
+ g_assert(ret == size);
+ g_assert(iov_cnt_tmp == iov_cnt);
+ g_assert(iov[iov_cnt - 1].iov_base == old_base);
+ iov_free(iov, iov_cnt);
+
+ /* Discard entire last element */
+ iov_random(&iov, &iov_cnt);
+ iov_cnt_tmp = iov_cnt;
+ old_base = iov[iov_cnt - 1].iov_base;
+ size = iov[iov_cnt - 1].iov_len;
+ ret = iov_discard_back(iov, &iov_cnt_tmp, size);
+ g_assert(ret == size);
+ g_assert(iov_cnt_tmp == iov_cnt - 1);
+ iov_free(iov, iov_cnt);
+
+ /* Discard within second-to-last element */
+ iov_random(&iov, &iov_cnt);
+ iov_cnt_tmp = iov_cnt;
+ old_base = iov[iov_cnt - 2].iov_base;
+ size = iov[iov_cnt - 1].iov_len +
+ g_test_rand_int_range(1, iov[iov_cnt - 2].iov_len);
+ ret = iov_discard_back(iov, &iov_cnt_tmp, size);
+ g_assert(ret == size);
+ g_assert(iov_cnt_tmp == iov_cnt - 1);
+ g_assert(iov[iov_cnt - 2].iov_base == old_base);
+ iov_free(iov, iov_cnt);
+}
+
int main(int argc, char **argv)
{
g_test_init(&argc, &argv, NULL);
g_test_rand_int();
g_test_add_func("/basic/iov/from-to-buf", test_to_from_buf);
g_test_add_func("/basic/iov/io", test_io);
+ g_test_add_func("/basic/iov/discard-front", test_discard_front);
+ g_test_add_func("/basic/iov/discard-back", test_discard_back);
return g_test_run();
}
diff --git a/tests/test-mul64.c b/tests/test-mul64.c
new file mode 100644
index 000000000..a0a17f777
--- /dev/null
+++ b/tests/test-mul64.c
@@ -0,0 +1,70 @@
+/*
+ * Test 64x64 -> 128 multiply subroutines
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2 or later.
+ * See the COPYING.LIB file in the top-level directory.
+ *
+ */
+
+#include <glib.h>
+#include <stdint.h>
+#include "qemu/host-utils.h"
+#include "qemu/osdep.h"
+
+
+typedef struct {
+ uint64_t a, b;
+ uint64_t rh, rl;
+} Test;
+
+static const Test test_u_data[] = {
+ { 1, 1, 0, 1 },
+ { 10000, 10000, 0, 100000000 },
+ { 0xffffffffffffffffULL, 2, 1, 0xfffffffffffffffeULL },
+ { 0xffffffffffffffffULL, 0xffffffffffffffffULL,
+ 0xfffffffffffffffeULL, 0x0000000000000001ULL },
+ { 0x1122334455667788ull, 0x8877665544332211ull,
+ 0x092228fb777ae38full, 0x0a3e963337c60008ull },
+};
+
+static const Test test_s_data[] = {
+ { 1, 1, 0, 1 },
+ { 1, -1, -1, -1 },
+ { -10, -10, 0, 100 },
+ { 10000, 10000, 0, 100000000 },
+ { -1, 2, -1, -2 },
+ { 0x1122334455667788ULL, 0x1122334455667788ULL,
+ 0x01258f60bbc2975cULL, 0x1eace4a3c82fb840ULL },
+};
+
+static void test_u(void)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(test_u_data); ++i) {
+ uint64_t rl, rh;
+ mulu64(&rl, &rh, test_u_data[i].a, test_u_data[i].b);
+ g_assert_cmpuint(rl, ==, test_u_data[i].rl);
+ g_assert_cmpuint(rh, ==, test_u_data[i].rh);
+ }
+}
+
+static void test_s(void)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(test_s_data); ++i) {
+ uint64_t rl, rh;
+ muls64(&rl, &rh, test_s_data[i].a, test_s_data[i].b);
+ g_assert_cmpuint(rl, ==, test_s_data[i].rl);
+ g_assert_cmpint(rh, ==, test_s_data[i].rh);
+ }
+}
+
+int main(int argc, char **argv)
+{
+ g_test_init(&argc, &argv, NULL);
+ g_test_add_func("/host-utils/mulu64", test_u);
+ g_test_add_func("/host-utils/muls64", test_s);
+ return g_test_run();
+}
diff --git a/tests/test-qmp-commands.c b/tests/test-qmp-commands.c
index dc3c507f2..5a3e82a85 100644
--- a/tests/test-qmp-commands.c
+++ b/tests/test-qmp-commands.c
@@ -1,8 +1,9 @@
#include <glib.h>
-#include "qemu-objects.h"
+#include "qemu-common.h"
+#include "qapi/qmp/types.h"
#include "test-qmp-commands.h"
-#include "qapi/qmp-core.h"
-#include "module.h"
+#include "qapi/qmp/dispatch.h"
+#include "qemu/module.h"
#include "qapi/qmp-input-visitor.h"
#include "tests/test-qapi-types.h"
#include "tests/test-qapi-visit.h"
diff --git a/tests/test-qmp-input-strict.c b/tests/test-qmp-input-strict.c
index f6df8cbe1..6f68963a3 100644
--- a/tests/test-qmp-input-strict.c
+++ b/tests/test-qmp-input-strict.c
@@ -14,10 +14,11 @@
#include <glib.h>
#include <stdarg.h>
+#include "qemu-common.h"
#include "qapi/qmp-input-visitor.h"
#include "test-qapi-types.h"
#include "test-qapi-visit.h"
-#include "qemu-objects.h"
+#include "qapi/qmp/types.h"
typedef struct TestInputVisitorData {
QObject *obj;
diff --git a/tests/test-qmp-input-visitor.c b/tests/test-qmp-input-visitor.c
index 8f5a50958..0beb8fbfd 100644
--- a/tests/test-qmp-input-visitor.c
+++ b/tests/test-qmp-input-visitor.c
@@ -13,10 +13,11 @@
#include <glib.h>
#include <stdarg.h>
+#include "qemu-common.h"
#include "qapi/qmp-input-visitor.h"
#include "test-qapi-types.h"
#include "test-qapi-visit.h"
-#include "qemu-objects.h"
+#include "qapi/qmp/types.h"
typedef struct TestInputVisitorData {
QObject *obj;
@@ -60,6 +61,31 @@ Visitor *visitor_input_test_init(TestInputVisitorData *data,
return v;
}
+/* similar to visitor_input_test_init(), but does not expect a string
+ * literal/format json_string argument and so can be used for
+ * programatically generated strings (and we can't pass in programatically
+ * generated strings via %s format parameters since qobject_from_jsonv()
+ * will wrap those in double-quotes and treat the entire object as a
+ * string)
+ */
+static Visitor *visitor_input_test_init_raw(TestInputVisitorData *data,
+ const char *json_string)
+{
+ Visitor *v;
+
+ data->obj = qobject_from_json(json_string);
+
+ 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)
{
@@ -74,6 +100,24 @@ static void test_visitor_in_int(TestInputVisitorData *data,
g_assert_cmpint(res, ==, value);
}
+static void test_visitor_in_int_overflow(TestInputVisitorData *data,
+ const void *unused)
+{
+ int64_t res = 0;
+ Error *errp = NULL;
+ Visitor *v;
+
+ /* this will overflow a Qint/int64, so should be deserialized into
+ * a QFloat/double field instead, leading to an error if we pass it
+ * to visit_type_int. confirm this.
+ */
+ v = visitor_input_test_init(data, "%f", DBL_MAX);
+
+ visit_type_int(v, &res, NULL, &errp);
+ g_assert(error_is_set(&errp));
+ error_free(errp);
+}
+
static void test_visitor_in_bool(TestInputVisitorData *data,
const void *unused)
{
@@ -258,6 +302,287 @@ static void test_visitor_in_union(TestInputVisitorData *data,
qapi_free_UserDefUnion(tmp);
}
+static void test_native_list_integer_helper(TestInputVisitorData *data,
+ const void *unused,
+ UserDefNativeListUnionKind kind)
+{
+ UserDefNativeListUnion *cvalue = NULL;
+ Error *err = NULL;
+ Visitor *v;
+ GString *gstr_list = g_string_new("");
+ GString *gstr_union = g_string_new("");
+ int i;
+
+ for (i = 0; i < 32; i++) {
+ g_string_append_printf(gstr_list, "%d", i);
+ if (i != 31) {
+ g_string_append(gstr_list, ", ");
+ }
+ }
+ g_string_append_printf(gstr_union, "{ 'type': '%s', 'data': [ %s ] }",
+ UserDefNativeListUnionKind_lookup[kind],
+ gstr_list->str);
+ v = visitor_input_test_init_raw(data, gstr_union->str);
+
+ visit_type_UserDefNativeListUnion(v, &cvalue, NULL, &err);
+ g_assert(err == NULL);
+ g_assert(cvalue != NULL);
+ g_assert_cmpint(cvalue->kind, ==, kind);
+
+ switch (kind) {
+ case USER_DEF_NATIVE_LIST_UNION_KIND_INTEGER: {
+ intList *elem = NULL;
+ for (i = 0, elem = cvalue->integer; elem; elem = elem->next, i++) {
+ g_assert_cmpint(elem->value, ==, i);
+ }
+ break;
+ }
+ case USER_DEF_NATIVE_LIST_UNION_KIND_S8: {
+ int8List *elem = NULL;
+ for (i = 0, elem = cvalue->s8; elem; elem = elem->next, i++) {
+ g_assert_cmpint(elem->value, ==, i);
+ }
+ break;
+ }
+ case USER_DEF_NATIVE_LIST_UNION_KIND_S16: {
+ int16List *elem = NULL;
+ for (i = 0, elem = cvalue->s16; elem; elem = elem->next, i++) {
+ g_assert_cmpint(elem->value, ==, i);
+ }
+ break;
+ }
+ case USER_DEF_NATIVE_LIST_UNION_KIND_S32: {
+ int32List *elem = NULL;
+ for (i = 0, elem = cvalue->s32; elem; elem = elem->next, i++) {
+ g_assert_cmpint(elem->value, ==, i);
+ }
+ break;
+ }
+ case USER_DEF_NATIVE_LIST_UNION_KIND_S64: {
+ int64List *elem = NULL;
+ for (i = 0, elem = cvalue->s64; elem; elem = elem->next, i++) {
+ g_assert_cmpint(elem->value, ==, i);
+ }
+ break;
+ }
+ case USER_DEF_NATIVE_LIST_UNION_KIND_U8: {
+ uint8List *elem = NULL;
+ for (i = 0, elem = cvalue->u8; elem; elem = elem->next, i++) {
+ g_assert_cmpint(elem->value, ==, i);
+ }
+ break;
+ }
+ case USER_DEF_NATIVE_LIST_UNION_KIND_U16: {
+ uint16List *elem = NULL;
+ for (i = 0, elem = cvalue->u16; elem; elem = elem->next, i++) {
+ g_assert_cmpint(elem->value, ==, i);
+ }
+ break;
+ }
+ case USER_DEF_NATIVE_LIST_UNION_KIND_U32: {
+ uint32List *elem = NULL;
+ for (i = 0, elem = cvalue->u32; elem; elem = elem->next, i++) {
+ g_assert_cmpint(elem->value, ==, i);
+ }
+ break;
+ }
+ case USER_DEF_NATIVE_LIST_UNION_KIND_U64: {
+ uint64List *elem = NULL;
+ for (i = 0, elem = cvalue->u64; elem; elem = elem->next, i++) {
+ g_assert_cmpint(elem->value, ==, i);
+ }
+ break;
+ }
+ default:
+ g_assert_not_reached();
+ }
+
+ g_string_free(gstr_union, true);
+ g_string_free(gstr_list, true);
+ qapi_free_UserDefNativeListUnion(cvalue);
+}
+
+static void test_visitor_in_native_list_int(TestInputVisitorData *data,
+ const void *unused)
+{
+ test_native_list_integer_helper(data, unused,
+ USER_DEF_NATIVE_LIST_UNION_KIND_INTEGER);
+}
+
+static void test_visitor_in_native_list_int8(TestInputVisitorData *data,
+ const void *unused)
+{
+ test_native_list_integer_helper(data, unused,
+ USER_DEF_NATIVE_LIST_UNION_KIND_S8);
+}
+
+static void test_visitor_in_native_list_int16(TestInputVisitorData *data,
+ const void *unused)
+{
+ test_native_list_integer_helper(data, unused,
+ USER_DEF_NATIVE_LIST_UNION_KIND_S16);
+}
+
+static void test_visitor_in_native_list_int32(TestInputVisitorData *data,
+ const void *unused)
+{
+ test_native_list_integer_helper(data, unused,
+ USER_DEF_NATIVE_LIST_UNION_KIND_S32);
+}
+
+static void test_visitor_in_native_list_int64(TestInputVisitorData *data,
+ const void *unused)
+{
+ test_native_list_integer_helper(data, unused,
+ USER_DEF_NATIVE_LIST_UNION_KIND_S64);
+}
+
+static void test_visitor_in_native_list_uint8(TestInputVisitorData *data,
+ const void *unused)
+{
+ test_native_list_integer_helper(data, unused,
+ USER_DEF_NATIVE_LIST_UNION_KIND_U8);
+}
+
+static void test_visitor_in_native_list_uint16(TestInputVisitorData *data,
+ const void *unused)
+{
+ test_native_list_integer_helper(data, unused,
+ USER_DEF_NATIVE_LIST_UNION_KIND_U16);
+}
+
+static void test_visitor_in_native_list_uint32(TestInputVisitorData *data,
+ const void *unused)
+{
+ test_native_list_integer_helper(data, unused,
+ USER_DEF_NATIVE_LIST_UNION_KIND_U32);
+}
+
+static void test_visitor_in_native_list_uint64(TestInputVisitorData *data,
+ const void *unused)
+{
+ test_native_list_integer_helper(data, unused,
+ USER_DEF_NATIVE_LIST_UNION_KIND_U64);
+}
+
+static void test_visitor_in_native_list_bool(TestInputVisitorData *data,
+ const void *unused)
+{
+ UserDefNativeListUnion *cvalue = NULL;
+ boolList *elem = NULL;
+ Error *err = NULL;
+ Visitor *v;
+ GString *gstr_list = g_string_new("");
+ GString *gstr_union = g_string_new("");
+ int i;
+
+ for (i = 0; i < 32; i++) {
+ g_string_append_printf(gstr_list, "%s",
+ (i % 3 == 0) ? "true" : "false");
+ if (i != 31) {
+ g_string_append(gstr_list, ", ");
+ }
+ }
+ g_string_append_printf(gstr_union, "{ 'type': 'boolean', 'data': [ %s ] }",
+ gstr_list->str);
+ v = visitor_input_test_init_raw(data, gstr_union->str);
+
+ visit_type_UserDefNativeListUnion(v, &cvalue, NULL, &err);
+ g_assert(err == NULL);
+ g_assert(cvalue != NULL);
+ g_assert_cmpint(cvalue->kind, ==, USER_DEF_NATIVE_LIST_UNION_KIND_BOOLEAN);
+
+ for (i = 0, elem = cvalue->boolean; elem; elem = elem->next, i++) {
+ g_assert_cmpint(elem->value, ==, (i % 3 == 0) ? 1 : 0);
+ }
+
+ g_string_free(gstr_union, true);
+ g_string_free(gstr_list, true);
+ qapi_free_UserDefNativeListUnion(cvalue);
+}
+
+static void test_visitor_in_native_list_string(TestInputVisitorData *data,
+ const void *unused)
+{
+ UserDefNativeListUnion *cvalue = NULL;
+ strList *elem = NULL;
+ Error *err = NULL;
+ Visitor *v;
+ GString *gstr_list = g_string_new("");
+ GString *gstr_union = g_string_new("");
+ int i;
+
+ for (i = 0; i < 32; i++) {
+ g_string_append_printf(gstr_list, "'%d'", i);
+ if (i != 31) {
+ g_string_append(gstr_list, ", ");
+ }
+ }
+ g_string_append_printf(gstr_union, "{ 'type': 'string', 'data': [ %s ] }",
+ gstr_list->str);
+ v = visitor_input_test_init_raw(data, gstr_union->str);
+
+ visit_type_UserDefNativeListUnion(v, &cvalue, NULL, &err);
+ g_assert(err == NULL);
+ g_assert(cvalue != NULL);
+ g_assert_cmpint(cvalue->kind, ==, USER_DEF_NATIVE_LIST_UNION_KIND_STRING);
+
+ for (i = 0, elem = cvalue->string; elem; elem = elem->next, i++) {
+ gchar str[8];
+ sprintf(str, "%d", i);
+ g_assert_cmpstr(elem->value, ==, str);
+ }
+
+ g_string_free(gstr_union, true);
+ g_string_free(gstr_list, true);
+ qapi_free_UserDefNativeListUnion(cvalue);
+}
+
+#define DOUBLE_STR_MAX 16
+
+static void test_visitor_in_native_list_number(TestInputVisitorData *data,
+ const void *unused)
+{
+ UserDefNativeListUnion *cvalue = NULL;
+ numberList *elem = NULL;
+ Error *err = NULL;
+ Visitor *v;
+ GString *gstr_list = g_string_new("");
+ GString *gstr_union = g_string_new("");
+ int i;
+
+ for (i = 0; i < 32; i++) {
+ g_string_append_printf(gstr_list, "%f", (double)i / 3);
+ if (i != 31) {
+ g_string_append(gstr_list, ", ");
+ }
+ }
+ g_string_append_printf(gstr_union, "{ 'type': 'number', 'data': [ %s ] }",
+ gstr_list->str);
+ v = visitor_input_test_init_raw(data, gstr_union->str);
+
+ visit_type_UserDefNativeListUnion(v, &cvalue, NULL, &err);
+ g_assert(err == NULL);
+ g_assert(cvalue != NULL);
+ g_assert_cmpint(cvalue->kind, ==, USER_DEF_NATIVE_LIST_UNION_KIND_NUMBER);
+
+ for (i = 0, elem = cvalue->number; elem; elem = elem->next, i++) {
+ GString *double_expected = g_string_new("");
+ GString *double_actual = g_string_new("");
+
+ g_string_printf(double_expected, "%.6f", (double)i / 3);
+ g_string_printf(double_actual, "%.6f", elem->value);
+ g_assert_cmpstr(double_expected->str, ==, double_actual->str);
+
+ g_string_free(double_expected, true);
+ g_string_free(double_actual, true);
+ }
+
+ g_string_free(gstr_union, true);
+ g_string_free(gstr_list, true);
+ qapi_free_UserDefNativeListUnion(cvalue);
+}
+
static void input_visitor_test_add(const char *testpath,
TestInputVisitorData *data,
void (*test_func)(TestInputVisitorData *data, const void *user_data))
@@ -291,6 +616,8 @@ int main(int argc, char **argv)
input_visitor_test_add("/visitor/input/int",
&in_visitor_data, test_visitor_in_int);
+ input_visitor_test_add("/visitor/input/int_overflow",
+ &in_visitor_data, test_visitor_in_int_overflow);
input_visitor_test_add("/visitor/input/bool",
&in_visitor_data, test_visitor_in_bool);
input_visitor_test_add("/visitor/input/number",
@@ -309,6 +636,38 @@ int main(int argc, char **argv)
&in_visitor_data, test_visitor_in_union);
input_visitor_test_add("/visitor/input/errors",
&in_visitor_data, test_visitor_in_errors);
+ input_visitor_test_add("/visitor/input/native_list/int",
+ &in_visitor_data,
+ test_visitor_in_native_list_int);
+ input_visitor_test_add("/visitor/input/native_list/int8",
+ &in_visitor_data,
+ test_visitor_in_native_list_int8);
+ input_visitor_test_add("/visitor/input/native_list/int16",
+ &in_visitor_data,
+ test_visitor_in_native_list_int16);
+ input_visitor_test_add("/visitor/input/native_list/int32",
+ &in_visitor_data,
+ test_visitor_in_native_list_int32);
+ input_visitor_test_add("/visitor/input/native_list/int64",
+ &in_visitor_data,
+ test_visitor_in_native_list_int64);
+ input_visitor_test_add("/visitor/input/native_list/uint8",
+ &in_visitor_data,
+ test_visitor_in_native_list_uint8);
+ input_visitor_test_add("/visitor/input/native_list/uint16",
+ &in_visitor_data,
+ test_visitor_in_native_list_uint16);
+ input_visitor_test_add("/visitor/input/native_list/uint32",
+ &in_visitor_data,
+ test_visitor_in_native_list_uint32);
+ input_visitor_test_add("/visitor/input/native_list/uint64",
+ &in_visitor_data, test_visitor_in_native_list_uint64);
+ input_visitor_test_add("/visitor/input/native_list/bool",
+ &in_visitor_data, test_visitor_in_native_list_bool);
+ input_visitor_test_add("/visitor/input/native_list/str",
+ &in_visitor_data, test_visitor_in_native_list_string);
+ input_visitor_test_add("/visitor/input/native_list/number",
+ &in_visitor_data, test_visitor_in_native_list_number);
g_test_run();
diff --git a/tests/test-qmp-output-visitor.c b/tests/test-qmp-output-visitor.c
index 24a635950..e073d833b 100644
--- a/tests/test-qmp-output-visitor.c
+++ b/tests/test-qmp-output-visitor.c
@@ -12,10 +12,11 @@
#include <glib.h>
+#include "qemu-common.h"
#include "qapi/qmp-output-visitor.h"
#include "test-qapi-types.h"
#include "test-qapi-visit.h"
-#include "qemu-objects.h"
+#include "qapi/qmp/types.h"
typedef struct TestOutputVisitorData {
QmpOutputVisitor *qov;
@@ -294,7 +295,10 @@ static void test_visitor_out_struct_errors(TestOutputVisitorData *data,
typedef struct TestStructList
{
- TestStruct *value;
+ union {
+ TestStruct *value;
+ uint64_t padding;
+ };
struct TestStructList *next;
} TestStructList;
@@ -430,6 +434,314 @@ static void test_visitor_out_union(TestOutputVisitorData *data,
QDECREF(qdict);
}
+static void init_native_list(UserDefNativeListUnion *cvalue)
+{
+ int i;
+ switch (cvalue->kind) {
+ case USER_DEF_NATIVE_LIST_UNION_KIND_INTEGER: {
+ intList **list = &cvalue->integer;
+ for (i = 0; i < 32; i++) {
+ *list = g_new0(intList, 1);
+ (*list)->value = i;
+ (*list)->next = NULL;
+ list = &(*list)->next;
+ }
+ break;
+ }
+ case USER_DEF_NATIVE_LIST_UNION_KIND_S8: {
+ int8List **list = &cvalue->s8;
+ for (i = 0; i < 32; i++) {
+ *list = g_new0(int8List, 1);
+ (*list)->value = i;
+ (*list)->next = NULL;
+ list = &(*list)->next;
+ }
+ break;
+ }
+ case USER_DEF_NATIVE_LIST_UNION_KIND_S16: {
+ int16List **list = &cvalue->s16;
+ for (i = 0; i < 32; i++) {
+ *list = g_new0(int16List, 1);
+ (*list)->value = i;
+ (*list)->next = NULL;
+ list = &(*list)->next;
+ }
+ break;
+ }
+ case USER_DEF_NATIVE_LIST_UNION_KIND_S32: {
+ int32List **list = &cvalue->s32;
+ for (i = 0; i < 32; i++) {
+ *list = g_new0(int32List, 1);
+ (*list)->value = i;
+ (*list)->next = NULL;
+ list = &(*list)->next;
+ }
+ break;
+ }
+ case USER_DEF_NATIVE_LIST_UNION_KIND_S64: {
+ int64List **list = &cvalue->s64;
+ for (i = 0; i < 32; i++) {
+ *list = g_new0(int64List, 1);
+ (*list)->value = i;
+ (*list)->next = NULL;
+ list = &(*list)->next;
+ }
+ break;
+ }
+ case USER_DEF_NATIVE_LIST_UNION_KIND_U8: {
+ uint8List **list = &cvalue->u8;
+ for (i = 0; i < 32; i++) {
+ *list = g_new0(uint8List, 1);
+ (*list)->value = i;
+ (*list)->next = NULL;
+ list = &(*list)->next;
+ }
+ break;
+ }
+ case USER_DEF_NATIVE_LIST_UNION_KIND_U16: {
+ uint16List **list = &cvalue->u16;
+ for (i = 0; i < 32; i++) {
+ *list = g_new0(uint16List, 1);
+ (*list)->value = i;
+ (*list)->next = NULL;
+ list = &(*list)->next;
+ }
+ break;
+ }
+ case USER_DEF_NATIVE_LIST_UNION_KIND_U32: {
+ uint32List **list = &cvalue->u32;
+ for (i = 0; i < 32; i++) {
+ *list = g_new0(uint32List, 1);
+ (*list)->value = i;
+ (*list)->next = NULL;
+ list = &(*list)->next;
+ }
+ break;
+ }
+ case USER_DEF_NATIVE_LIST_UNION_KIND_U64: {
+ uint64List **list = &cvalue->u64;
+ for (i = 0; i < 32; i++) {
+ *list = g_new0(uint64List, 1);
+ (*list)->value = i;
+ (*list)->next = NULL;
+ list = &(*list)->next;
+ }
+ break;
+ }
+ case USER_DEF_NATIVE_LIST_UNION_KIND_BOOLEAN: {
+ boolList **list = &cvalue->boolean;
+ for (i = 0; i < 32; i++) {
+ *list = g_new0(boolList, 1);
+ (*list)->value = (i % 3 == 0);
+ (*list)->next = NULL;
+ list = &(*list)->next;
+ }
+ break;
+ }
+ case USER_DEF_NATIVE_LIST_UNION_KIND_STRING: {
+ strList **list = &cvalue->string;
+ for (i = 0; i < 32; i++) {
+ *list = g_new0(strList, 1);
+ (*list)->value = g_strdup_printf("%d", i);
+ (*list)->next = NULL;
+ list = &(*list)->next;
+ }
+ break;
+ }
+ case USER_DEF_NATIVE_LIST_UNION_KIND_NUMBER: {
+ numberList **list = &cvalue->number;
+ for (i = 0; i < 32; i++) {
+ *list = g_new0(numberList, 1);
+ (*list)->value = (double)i / 3;
+ (*list)->next = NULL;
+ list = &(*list)->next;
+ }
+ break;
+ }
+ default:
+ g_assert_not_reached();
+ }
+}
+
+static void check_native_list(QObject *qobj,
+ UserDefNativeListUnionKind kind)
+{
+ QDict *qdict;
+ QList *qlist;
+ int i;
+
+ g_assert(qobj);
+ g_assert(qobject_type(qobj) == QTYPE_QDICT);
+ qdict = qobject_to_qdict(qobj);
+ g_assert(qdict);
+ g_assert(qdict_haskey(qdict, "data"));
+ qlist = qlist_copy(qobject_to_qlist(qdict_get(qdict, "data")));
+
+ switch (kind) {
+ case USER_DEF_NATIVE_LIST_UNION_KIND_S8:
+ case USER_DEF_NATIVE_LIST_UNION_KIND_S16:
+ case USER_DEF_NATIVE_LIST_UNION_KIND_S32:
+ case USER_DEF_NATIVE_LIST_UNION_KIND_S64:
+ case USER_DEF_NATIVE_LIST_UNION_KIND_U8:
+ case USER_DEF_NATIVE_LIST_UNION_KIND_U16:
+ case USER_DEF_NATIVE_LIST_UNION_KIND_U32:
+ case USER_DEF_NATIVE_LIST_UNION_KIND_U64:
+ /* all integer elements in JSON arrays get stored into QInts when
+ * we convert to QObjects, so we can check them all in the same
+ * fashion, so simply fall through here
+ */
+ case USER_DEF_NATIVE_LIST_UNION_KIND_INTEGER:
+ for (i = 0; i < 32; i++) {
+ QObject *tmp;
+ QInt *qvalue;
+ tmp = qlist_peek(qlist);
+ g_assert(tmp);
+ qvalue = qobject_to_qint(tmp);
+ g_assert_cmpint(qint_get_int(qvalue), ==, i);
+ qobject_decref(qlist_pop(qlist));
+ }
+ break;
+ case USER_DEF_NATIVE_LIST_UNION_KIND_BOOLEAN:
+ for (i = 0; i < 32; i++) {
+ QObject *tmp;
+ QBool *qvalue;
+ tmp = qlist_peek(qlist);
+ g_assert(tmp);
+ qvalue = qobject_to_qbool(tmp);
+ g_assert_cmpint(qbool_get_int(qvalue), ==, (i % 3 == 0) ? 1 : 0);
+ qobject_decref(qlist_pop(qlist));
+ }
+ break;
+ case USER_DEF_NATIVE_LIST_UNION_KIND_STRING:
+ for (i = 0; i < 32; i++) {
+ QObject *tmp;
+ QString *qvalue;
+ gchar str[8];
+ tmp = qlist_peek(qlist);
+ g_assert(tmp);
+ qvalue = qobject_to_qstring(tmp);
+ sprintf(str, "%d", i);
+ g_assert_cmpstr(qstring_get_str(qvalue), ==, str);
+ qobject_decref(qlist_pop(qlist));
+ }
+ break;
+ case USER_DEF_NATIVE_LIST_UNION_KIND_NUMBER:
+ for (i = 0; i < 32; i++) {
+ QObject *tmp;
+ QFloat *qvalue;
+ GString *double_expected = g_string_new("");
+ GString *double_actual = g_string_new("");
+
+ tmp = qlist_peek(qlist);
+ g_assert(tmp);
+ qvalue = qobject_to_qfloat(tmp);
+ g_string_printf(double_expected, "%.6f", (double)i / 3);
+ g_string_printf(double_actual, "%.6f", qfloat_get_double(qvalue));
+ g_assert_cmpstr(double_actual->str, ==, double_expected->str);
+
+ qobject_decref(qlist_pop(qlist));
+ g_string_free(double_expected, true);
+ g_string_free(double_actual, true);
+ }
+ break;
+ default:
+ g_assert_not_reached();
+ }
+ QDECREF(qlist);
+}
+
+static void test_native_list(TestOutputVisitorData *data,
+ const void *unused,
+ UserDefNativeListUnionKind kind)
+{
+ UserDefNativeListUnion *cvalue = g_new0(UserDefNativeListUnion, 1);
+ Error *err = NULL;
+ QObject *obj;
+
+ cvalue->kind = kind;
+ init_native_list(cvalue);
+
+ visit_type_UserDefNativeListUnion(data->ov, &cvalue, NULL, &err);
+ g_assert(err == NULL);
+
+ obj = qmp_output_get_qobject(data->qov);
+ check_native_list(obj, cvalue->kind);
+ qapi_free_UserDefNativeListUnion(cvalue);
+ qobject_decref(obj);
+}
+
+static void test_visitor_out_native_list_int(TestOutputVisitorData *data,
+ const void *unused)
+{
+ test_native_list(data, unused, USER_DEF_NATIVE_LIST_UNION_KIND_INTEGER);
+}
+
+static void test_visitor_out_native_list_int8(TestOutputVisitorData *data,
+ const void *unused)
+{
+ test_native_list(data, unused, USER_DEF_NATIVE_LIST_UNION_KIND_S8);
+}
+
+static void test_visitor_out_native_list_int16(TestOutputVisitorData *data,
+ const void *unused)
+{
+ test_native_list(data, unused, USER_DEF_NATIVE_LIST_UNION_KIND_S16);
+}
+
+static void test_visitor_out_native_list_int32(TestOutputVisitorData *data,
+ const void *unused)
+{
+ test_native_list(data, unused, USER_DEF_NATIVE_LIST_UNION_KIND_S32);
+}
+
+static void test_visitor_out_native_list_int64(TestOutputVisitorData *data,
+ const void *unused)
+{
+ test_native_list(data, unused, USER_DEF_NATIVE_LIST_UNION_KIND_S64);
+}
+
+static void test_visitor_out_native_list_uint8(TestOutputVisitorData *data,
+ const void *unused)
+{
+ test_native_list(data, unused, USER_DEF_NATIVE_LIST_UNION_KIND_U8);
+}
+
+static void test_visitor_out_native_list_uint16(TestOutputVisitorData *data,
+ const void *unused)
+{
+ test_native_list(data, unused, USER_DEF_NATIVE_LIST_UNION_KIND_U16);
+}
+
+static void test_visitor_out_native_list_uint32(TestOutputVisitorData *data,
+ const void *unused)
+{
+ test_native_list(data, unused, USER_DEF_NATIVE_LIST_UNION_KIND_U32);
+}
+
+static void test_visitor_out_native_list_uint64(TestOutputVisitorData *data,
+ const void *unused)
+{
+ test_native_list(data, unused, USER_DEF_NATIVE_LIST_UNION_KIND_U64);
+}
+
+static void test_visitor_out_native_list_bool(TestOutputVisitorData *data,
+ const void *unused)
+{
+ test_native_list(data, unused, USER_DEF_NATIVE_LIST_UNION_KIND_BOOLEAN);
+}
+
+static void test_visitor_out_native_list_str(TestOutputVisitorData *data,
+ const void *unused)
+{
+ test_native_list(data, unused, USER_DEF_NATIVE_LIST_UNION_KIND_STRING);
+}
+
+static void test_visitor_out_native_list_number(TestOutputVisitorData *data,
+ const void *unused)
+{
+ test_native_list(data, unused, USER_DEF_NATIVE_LIST_UNION_KIND_NUMBER);
+}
+
static void output_visitor_test_add(const char *testpath,
TestOutputVisitorData *data,
void (*test_func)(TestOutputVisitorData *data, const void *user_data))
@@ -470,6 +782,30 @@ int main(int argc, char **argv)
&out_visitor_data, test_visitor_out_list_qapi_free);
output_visitor_test_add("/visitor/output/union",
&out_visitor_data, test_visitor_out_union);
+ 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",
+ &out_visitor_data, test_visitor_out_native_list_int8);
+ output_visitor_test_add("/visitor/output/native_list/int16",
+ &out_visitor_data, test_visitor_out_native_list_int16);
+ output_visitor_test_add("/visitor/output/native_list/int32",
+ &out_visitor_data, test_visitor_out_native_list_int32);
+ output_visitor_test_add("/visitor/output/native_list/int64",
+ &out_visitor_data, test_visitor_out_native_list_int64);
+ output_visitor_test_add("/visitor/output/native_list/uint8",
+ &out_visitor_data, test_visitor_out_native_list_uint8);
+ output_visitor_test_add("/visitor/output/native_list/uint16",
+ &out_visitor_data, test_visitor_out_native_list_uint16);
+ output_visitor_test_add("/visitor/output/native_list/uint32",
+ &out_visitor_data, test_visitor_out_native_list_uint32);
+ output_visitor_test_add("/visitor/output/native_list/uint64",
+ &out_visitor_data, test_visitor_out_native_list_uint64);
+ output_visitor_test_add("/visitor/output/native_list/bool",
+ &out_visitor_data, test_visitor_out_native_list_bool);
+ output_visitor_test_add("/visitor/output/native_list/string",
+ &out_visitor_data, test_visitor_out_native_list_str);
+ output_visitor_test_add("/visitor/output/native_list/number",
+ &out_visitor_data, test_visitor_out_native_list_number);
g_test_run();
diff --git a/tests/test-string-input-visitor.c b/tests/test-string-input-visitor.c
index 5370e3204..5989f8118 100644
--- a/tests/test-string-input-visitor.c
+++ b/tests/test-string-input-visitor.c
@@ -13,10 +13,11 @@
#include <glib.h>
#include <stdarg.h>
+#include "qemu-common.h"
#include "qapi/string-input-visitor.h"
#include "test-qapi-types.h"
#include "test-qapi-visit.h"
-#include "qemu-objects.h"
+#include "qapi/qmp/types.h"
typedef struct TestInputVisitorData {
StringInputVisitor *siv;
@@ -164,6 +165,53 @@ static void test_visitor_in_enum(TestInputVisitorData *data,
data->siv = NULL;
}
+/* Try to crash the visitors */
+static void test_visitor_in_fuzz(TestInputVisitorData *data,
+ const void *unused)
+{
+ int64_t ires;
+ bool bres;
+ double nres;
+ char *sres;
+ EnumOne eres;
+ Visitor *v;
+ unsigned int i;
+ char buf[10000];
+
+ for (i = 0; i < 100; i++) {
+ unsigned int j;
+
+ j = g_test_rand_int_range(0, sizeof(buf) - 1);
+
+ buf[j] = '\0';
+
+ if (j != 0) {
+ for (j--; j != 0; j--) {
+ buf[j - 1] = (char)g_test_rand_int_range(0, 256);
+ }
+ }
+
+ v = visitor_input_test_init(data, buf);
+ visit_type_int(v, &ires, NULL, NULL);
+
+ v = visitor_input_test_init(data, buf);
+ visit_type_bool(v, &bres, NULL, NULL);
+ visitor_input_teardown(data, NULL);
+
+ v = visitor_input_test_init(data, buf);
+ visit_type_number(v, &nres, NULL, NULL);
+
+ v = visitor_input_test_init(data, buf);
+ sres = NULL;
+ visit_type_str(v, &sres, NULL, NULL);
+ g_free(sres);
+
+ v = visitor_input_test_init(data, buf);
+ visit_type_EnumOne(v, &eres, NULL, NULL);
+ visitor_input_teardown(data, NULL);
+ }
+}
+
static void input_visitor_test_add(const char *testpath,
TestInputVisitorData *data,
void (*test_func)(TestInputVisitorData *data, const void *user_data))
@@ -188,6 +236,8 @@ int main(int argc, char **argv)
&in_visitor_data, test_visitor_in_string);
input_visitor_test_add("/string-visitor/input/enum",
&in_visitor_data, test_visitor_in_enum);
+ input_visitor_test_add("/string-visitor/input/fuzz",
+ &in_visitor_data, test_visitor_in_fuzz);
g_test_run();
diff --git a/tests/test-string-output-visitor.c b/tests/test-string-output-visitor.c
index 608f14a5d..79d815f88 100644
--- a/tests/test-string-output-visitor.c
+++ b/tests/test-string-output-visitor.c
@@ -12,10 +12,11 @@
#include <glib.h>
+#include "qemu-common.h"
#include "qapi/string-output-visitor.h"
#include "test-qapi-types.h"
#include "test-qapi-visit.h"
-#include "qemu-objects.h"
+#include "qapi/qmp/types.h"
typedef struct TestOutputVisitorData {
StringOutputVisitor *sov;
diff --git a/tests/test-thread-pool.c b/tests/test-thread-pool.c
index fea0445fb..b62338f37 100644
--- a/tests/test-thread-pool.c
+++ b/tests/test-thread-pool.c
@@ -1,9 +1,11 @@
#include <glib.h>
#include "qemu-common.h"
-#include "qemu-aio.h"
-#include "thread-pool.h"
-#include "block.h"
+#include "block/aio.h"
+#include "block/thread-pool.h"
+#include "block/block.h"
+static AioContext *ctx;
+static ThreadPool *pool;
static int active;
typedef struct {
@@ -15,15 +17,15 @@ typedef struct {
static int worker_cb(void *opaque)
{
WorkerTestData *data = opaque;
- return __sync_fetch_and_add(&data->n, 1);
+ return atomic_fetch_inc(&data->n);
}
static int long_cb(void *opaque)
{
WorkerTestData *data = opaque;
- __sync_fetch_and_add(&data->n, 1);
+ atomic_inc(&data->n);
g_usleep(2000000);
- __sync_fetch_and_add(&data->n, 1);
+ atomic_inc(&data->n);
return 0;
}
@@ -38,32 +40,32 @@ static void done_cb(void *opaque, int ret)
active--;
}
-/* A non-blocking poll of the main AIO context (we cannot use aio_poll
- * because we do not know the AioContext).
- */
-static void qemu_aio_wait_nonblocking(void)
+/* Wait until all aio and bh activity has finished */
+static void qemu_aio_wait_all(void)
{
- qemu_notify_event();
- qemu_aio_wait();
+ while (aio_poll(ctx, true)) {
+ /* Do nothing */
+ }
}
static void test_submit(void)
{
WorkerTestData data = { .n = 0 };
- thread_pool_submit(worker_cb, &data);
- qemu_aio_flush();
+ thread_pool_submit(pool, worker_cb, &data);
+ qemu_aio_wait_all();
g_assert_cmpint(data.n, ==, 1);
}
static void test_submit_aio(void)
{
WorkerTestData data = { .n = 0, .ret = -EINPROGRESS };
- data.aiocb = thread_pool_submit_aio(worker_cb, &data, done_cb, &data);
+ data.aiocb = thread_pool_submit_aio(pool, worker_cb, &data,
+ done_cb, &data);
/* The callbacks are not called until after the first wait. */
active = 1;
g_assert_cmpint(data.ret, ==, -EINPROGRESS);
- qemu_aio_flush();
+ qemu_aio_wait_all();
g_assert_cmpint(active, ==, 0);
g_assert_cmpint(data.n, ==, 1);
g_assert_cmpint(data.ret, ==, 0);
@@ -76,7 +78,7 @@ static void co_test_cb(void *opaque)
active = 1;
data->n = 0;
data->ret = -EINPROGRESS;
- thread_pool_submit_co(worker_cb, data);
+ thread_pool_submit_co(pool, worker_cb, data);
/* The test continues in test_submit_co, after qemu_coroutine_enter... */
@@ -84,7 +86,7 @@ static void co_test_cb(void *opaque)
data->ret = 0;
active--;
- /* The test continues in test_submit_co, after qemu_aio_flush... */
+ /* The test continues in test_submit_co, after qemu_aio_wait_all... */
}
static void test_submit_co(void)
@@ -99,9 +101,9 @@ static void test_submit_co(void)
g_assert_cmpint(active, ==, 1);
g_assert_cmpint(data.ret, ==, -EINPROGRESS);
- /* qemu_aio_flush will execute the rest of the coroutine. */
+ /* qemu_aio_wait_all will execute the rest of the coroutine. */
- qemu_aio_flush();
+ qemu_aio_wait_all();
/* Back here after the coroutine has finished. */
@@ -118,12 +120,12 @@ static void test_submit_many(void)
for (i = 0; i < 100; i++) {
data[i].n = 0;
data[i].ret = -EINPROGRESS;
- thread_pool_submit_aio(worker_cb, &data[i], done_cb, &data[i]);
+ thread_pool_submit_aio(pool, worker_cb, &data[i], done_cb, &data[i]);
}
active = 100;
while (active > 0) {
- qemu_aio_wait();
+ aio_poll(ctx, true);
}
for (i = 0; i < 100; i++) {
g_assert_cmpint(data[i].n, ==, 1);
@@ -146,7 +148,7 @@ static void test_cancel(void)
for (i = 0; i < 100; i++) {
data[i].n = 0;
data[i].ret = -EINPROGRESS;
- data[i].aiocb = thread_pool_submit_aio(long_cb, &data[i],
+ data[i].aiocb = thread_pool_submit_aio(pool, long_cb, &data[i],
done_cb, &data[i]);
}
@@ -154,7 +156,8 @@ static void test_cancel(void)
* run, but do not waste too much time...
*/
active = 100;
- qemu_aio_wait_nonblocking();
+ aio_notify(ctx);
+ aio_poll(ctx, false);
/* Wait some time for the threads to start, with some sanity
* testing on the behavior of the scheduler...
@@ -166,7 +169,7 @@ static void test_cancel(void)
/* Cancel the jobs that haven't been started yet. */
num_canceled = 0;
for (i = 0; i < 100; i++) {
- if (__sync_val_compare_and_swap(&data[i].n, 0, 3) == 0) {
+ if (atomic_cmpxchg(&data[i].n, 0, 3) == 0) {
data[i].ret = -ECANCELED;
bdrv_aio_cancel(data[i].aiocb);
active--;
@@ -184,7 +187,7 @@ static void test_cancel(void)
}
/* Finish execution and execute any remaining callbacks. */
- qemu_aio_flush();
+ qemu_aio_wait_all();
g_assert_cmpint(active, ==, 0);
for (i = 0; i < 100; i++) {
if (data[i].n == 3) {
@@ -200,11 +203,10 @@ static void test_cancel(void)
int main(int argc, char **argv)
{
- /* These should be removed once each AioContext has its thread pool.
- * The test should create its own AioContext.
- */
- qemu_init_main_loop();
- bdrv_init();
+ int ret;
+
+ ctx = aio_context_new();
+ pool = aio_get_thread_pool(ctx);
g_test_init(&argc, &argv, NULL);
g_test_add_func("/thread-pool/submit", test_submit);
@@ -212,5 +214,9 @@ int main(int argc, char **argv)
g_test_add_func("/thread-pool/submit-co", test_submit_co);
g_test_add_func("/thread-pool/submit-many", test_submit_many);
g_test_add_func("/thread-pool/cancel", test_cancel);
- return g_test_run();
+
+ ret = g_test_run();
+
+ aio_context_unref(ctx);
+ return ret;
}
diff --git a/tests/test-visitor-serialization.c b/tests/test-visitor-serialization.c
index b8ad16fc9..9aaa5872e 100644
--- a/tests/test-visitor-serialization.c
+++ b/tests/test-visitor-serialization.c
@@ -14,13 +14,34 @@
#include <stdlib.h>
#include <stdint.h>
#include <float.h>
+
+#include "qemu-common.h"
#include "test-qapi-types.h"
#include "test-qapi-visit.h"
-#include "qemu-objects.h"
+#include "qapi/qmp/types.h"
#include "qapi/qmp-input-visitor.h"
#include "qapi/qmp-output-visitor.h"
#include "qapi/string-input-visitor.h"
#include "qapi/string-output-visitor.h"
+#include "qapi-types.h"
+#include "qapi-visit.h"
+#include "qapi/dealloc-visitor.h"
+
+enum PrimitiveTypeKind {
+ PTYPE_STRING = 0,
+ PTYPE_BOOLEAN,
+ PTYPE_NUMBER,
+ PTYPE_INTEGER,
+ PTYPE_U8,
+ PTYPE_U16,
+ PTYPE_U32,
+ PTYPE_U64,
+ PTYPE_S8,
+ PTYPE_S16,
+ PTYPE_S32,
+ PTYPE_S64,
+ PTYPE_EOL,
+};
typedef struct PrimitiveType {
union {
@@ -38,26 +59,42 @@ typedef struct PrimitiveType {
int64_t s64;
intmax_t max;
} value;
- enum {
- PTYPE_STRING = 0,
- PTYPE_BOOLEAN,
- PTYPE_NUMBER,
- PTYPE_INTEGER,
- PTYPE_U8,
- PTYPE_U16,
- PTYPE_U32,
- PTYPE_U64,
- PTYPE_S8,
- PTYPE_S16,
- PTYPE_S32,
- PTYPE_S64,
- PTYPE_EOL,
- } type;
+ enum PrimitiveTypeKind type;
const char *description;
} PrimitiveType;
+typedef struct PrimitiveList {
+ union {
+ strList *strings;
+ boolList *booleans;
+ numberList *numbers;
+ intList *integers;
+ int8List *s8_integers;
+ int16List *s16_integers;
+ int32List *s32_integers;
+ int64List *s64_integers;
+ uint8List *u8_integers;
+ uint16List *u16_integers;
+ uint32List *u32_integers;
+ uint64List *u64_integers;
+ } value;
+ enum PrimitiveTypeKind type;
+ const char *description;
+} PrimitiveList;
+
/* test helpers */
+typedef void (*VisitorFunc)(Visitor *v, void **native, Error **errp);
+
+static void dealloc_helper(void *native_in, VisitorFunc visit, Error **errp)
+{
+ QapiDeallocVisitor *qdv = qapi_dealloc_visitor_new();
+
+ visit(qapi_dealloc_get_visitor(qdv), &native_in, errp);
+
+ qapi_dealloc_visitor_cleanup(qdv);
+}
+
static void visit_primitive_type(Visitor *v, void **native, Error **errp)
{
PrimitiveType *pt = *native;
@@ -99,7 +136,52 @@ static void visit_primitive_type(Visitor *v, void **native, Error **errp)
visit_type_int64(v, &pt->value.s64, NULL, errp);
break;
case PTYPE_EOL:
- g_assert(false);
+ g_assert_not_reached();
+ }
+}
+
+static void visit_primitive_list(Visitor *v, void **native, Error **errp)
+{
+ PrimitiveList *pl = *native;
+ switch (pl->type) {
+ case PTYPE_STRING:
+ visit_type_strList(v, &pl->value.strings, NULL, errp);
+ break;
+ case PTYPE_BOOLEAN:
+ visit_type_boolList(v, &pl->value.booleans, NULL, errp);
+ break;
+ case PTYPE_NUMBER:
+ visit_type_numberList(v, &pl->value.numbers, NULL, errp);
+ break;
+ case PTYPE_INTEGER:
+ visit_type_intList(v, &pl->value.integers, NULL, errp);
+ break;
+ case PTYPE_S8:
+ visit_type_int8List(v, &pl->value.s8_integers, NULL, errp);
+ break;
+ case PTYPE_S16:
+ visit_type_int16List(v, &pl->value.s16_integers, NULL, errp);
+ break;
+ case PTYPE_S32:
+ visit_type_int32List(v, &pl->value.s32_integers, NULL, errp);
+ break;
+ case PTYPE_S64:
+ visit_type_int64List(v, &pl->value.s64_integers, NULL, errp);
+ break;
+ case PTYPE_U8:
+ visit_type_uint8List(v, &pl->value.u8_integers, NULL, errp);
+ break;
+ case PTYPE_U16:
+ visit_type_uint16List(v, &pl->value.u16_integers, NULL, errp);
+ break;
+ case PTYPE_U32:
+ visit_type_uint32List(v, &pl->value.u32_integers, NULL, errp);
+ break;
+ case PTYPE_U64:
+ visit_type_uint64List(v, &pl->value.u64_integers, NULL, errp);
+ break;
+ default:
+ g_assert_not_reached();
}
}
@@ -204,12 +286,11 @@ static void visit_nested_struct_list(Visitor *v, void **native, Error **errp)
/* test cases */
-typedef void (*VisitorFunc)(Visitor *v, void **native, Error **errp);
-
typedef enum VisitorCapabilities {
VCAP_PRIMITIVES = 1,
VCAP_STRUCTURES = 2,
VCAP_LISTS = 4,
+ VCAP_PRIMITIVE_LISTS = 8,
} VisitorCapabilities;
typedef struct SerializeOps {
@@ -227,17 +308,6 @@ typedef struct TestArgs {
void *test_data;
} TestArgs;
-#define FLOAT_STRING_PRECISION 6 /* corresponding to n in %.nf formatting */
-static gsize calc_float_string_storage(double value)
-{
- int whole_value = value;
- gsize i = 0;
- do {
- i++;
- } while (whole_value /= 10);
- return i + 2 + FLOAT_STRING_PRECISION;
-}
-
static void test_primitives(gconstpointer opaque)
{
TestArgs *args = (TestArgs *) opaque;
@@ -246,7 +316,6 @@ static void test_primitives(gconstpointer opaque)
PrimitiveType *pt_copy = g_malloc0(sizeof(*pt_copy));
Error *err = NULL;
void *serialize_data;
- char *double1, *double2;
pt_copy->type = pt->type;
ops->serialize(pt, &serialize_data, visit_primitive_type, &err);
@@ -256,15 +325,19 @@ static void test_primitives(gconstpointer opaque)
g_assert(pt_copy != NULL);
if (pt->type == PTYPE_STRING) {
g_assert_cmpstr(pt->value.string, ==, pt_copy->value.string);
+ g_free((char *)pt_copy->value.string);
} else if (pt->type == PTYPE_NUMBER) {
+ GString *double_expected = g_string_new("");
+ GString *double_actual = g_string_new("");
/* we serialize with %f for our reference visitors, so rather than fuzzy
* floating math to test "equality", just compare the formatted values
*/
- double1 = g_malloc0(calc_float_string_storage(pt->value.number));
- double2 = g_malloc0(calc_float_string_storage(pt_copy->value.number));
- g_assert_cmpstr(double1, ==, double2);
- g_free(double1);
- g_free(double2);
+ g_string_printf(double_expected, "%.6f", pt->value.number);
+ g_string_printf(double_actual, "%.6f", pt_copy->value.number);
+ g_assert_cmpstr(double_actual->str, ==, double_expected->str);
+
+ g_string_free(double_expected, true);
+ g_string_free(double_actual, true);
} else if (pt->type == PTYPE_BOOLEAN) {
g_assert_cmpint(!!pt->value.max, ==, !!pt->value.max);
} else {
@@ -273,6 +346,329 @@ static void test_primitives(gconstpointer opaque)
ops->cleanup(serialize_data);
g_free(args);
+ g_free(pt_copy);
+}
+
+static void test_primitive_lists(gconstpointer opaque)
+{
+ TestArgs *args = (TestArgs *) opaque;
+ const SerializeOps *ops = args->ops;
+ PrimitiveType *pt = args->test_data;
+ PrimitiveList pl = { .value = { 0 } };
+ PrimitiveList pl_copy = { .value = { 0 } };
+ PrimitiveList *pl_copy_ptr = &pl_copy;
+ Error *err = NULL;
+ void *serialize_data;
+ void *cur_head = NULL;
+ int i;
+
+ pl.type = pl_copy.type = pt->type;
+
+ /* build up our list of primitive types */
+ for (i = 0; i < 32; i++) {
+ switch (pl.type) {
+ case PTYPE_STRING: {
+ strList *tmp = g_new0(strList, 1);
+ tmp->value = g_strdup(pt->value.string);
+ if (pl.value.strings == NULL) {
+ pl.value.strings = tmp;
+ } else {
+ tmp->next = pl.value.strings;
+ pl.value.strings = tmp;
+ }
+ break;
+ }
+ case PTYPE_INTEGER: {
+ intList *tmp = g_new0(intList, 1);
+ tmp->value = pt->value.integer;
+ if (pl.value.integers == NULL) {
+ pl.value.integers = tmp;
+ } else {
+ tmp->next = pl.value.integers;
+ pl.value.integers = tmp;
+ }
+ break;
+ }
+ case PTYPE_S8: {
+ int8List *tmp = g_new0(int8List, 1);
+ tmp->value = pt->value.s8;
+ if (pl.value.s8_integers == NULL) {
+ pl.value.s8_integers = tmp;
+ } else {
+ tmp->next = pl.value.s8_integers;
+ pl.value.s8_integers = tmp;
+ }
+ break;
+ }
+ case PTYPE_S16: {
+ int16List *tmp = g_new0(int16List, 1);
+ tmp->value = pt->value.s16;
+ if (pl.value.s16_integers == NULL) {
+ pl.value.s16_integers = tmp;
+ } else {
+ tmp->next = pl.value.s16_integers;
+ pl.value.s16_integers = tmp;
+ }
+ break;
+ }
+ case PTYPE_S32: {
+ int32List *tmp = g_new0(int32List, 1);
+ tmp->value = pt->value.s32;
+ if (pl.value.s32_integers == NULL) {
+ pl.value.s32_integers = tmp;
+ } else {
+ tmp->next = pl.value.s32_integers;
+ pl.value.s32_integers = tmp;
+ }
+ break;
+ }
+ case PTYPE_S64: {
+ int64List *tmp = g_new0(int64List, 1);
+ tmp->value = pt->value.s64;
+ if (pl.value.s64_integers == NULL) {
+ pl.value.s64_integers = tmp;
+ } else {
+ tmp->next = pl.value.s64_integers;
+ pl.value.s64_integers = tmp;
+ }
+ break;
+ }
+ case PTYPE_U8: {
+ uint8List *tmp = g_new0(uint8List, 1);
+ tmp->value = pt->value.u8;
+ if (pl.value.u8_integers == NULL) {
+ pl.value.u8_integers = tmp;
+ } else {
+ tmp->next = pl.value.u8_integers;
+ pl.value.u8_integers = tmp;
+ }
+ break;
+ }
+ case PTYPE_U16: {
+ uint16List *tmp = g_new0(uint16List, 1);
+ tmp->value = pt->value.u16;
+ if (pl.value.u16_integers == NULL) {
+ pl.value.u16_integers = tmp;
+ } else {
+ tmp->next = pl.value.u16_integers;
+ pl.value.u16_integers = tmp;
+ }
+ break;
+ }
+ case PTYPE_U32: {
+ uint32List *tmp = g_new0(uint32List, 1);
+ tmp->value = pt->value.u32;
+ if (pl.value.u32_integers == NULL) {
+ pl.value.u32_integers = tmp;
+ } else {
+ tmp->next = pl.value.u32_integers;
+ pl.value.u32_integers = tmp;
+ }
+ break;
+ }
+ case PTYPE_U64: {
+ uint64List *tmp = g_new0(uint64List, 1);
+ tmp->value = pt->value.u64;
+ if (pl.value.u64_integers == NULL) {
+ pl.value.u64_integers = tmp;
+ } else {
+ tmp->next = pl.value.u64_integers;
+ pl.value.u64_integers = tmp;
+ }
+ break;
+ }
+ case PTYPE_NUMBER: {
+ numberList *tmp = g_new0(numberList, 1);
+ tmp->value = pt->value.number;
+ if (pl.value.numbers == NULL) {
+ pl.value.numbers = tmp;
+ } else {
+ tmp->next = pl.value.numbers;
+ pl.value.numbers = tmp;
+ }
+ break;
+ }
+ case PTYPE_BOOLEAN: {
+ boolList *tmp = g_new0(boolList, 1);
+ tmp->value = pt->value.boolean;
+ if (pl.value.booleans == NULL) {
+ pl.value.booleans = tmp;
+ } else {
+ tmp->next = pl.value.booleans;
+ pl.value.booleans = tmp;
+ }
+ break;
+ }
+ default:
+ g_assert_not_reached();
+ }
+ }
+
+ ops->serialize((void **)&pl, &serialize_data, visit_primitive_list, &err);
+ ops->deserialize((void **)&pl_copy_ptr, serialize_data, visit_primitive_list, &err);
+
+ g_assert(err == NULL);
+ i = 0;
+
+ /* compare our deserialized list of primitives to the original */
+ do {
+ switch (pl_copy.type) {
+ case PTYPE_STRING: {
+ strList *ptr;
+ if (cur_head) {
+ ptr = cur_head;
+ cur_head = ptr->next;
+ } else {
+ cur_head = ptr = pl_copy.value.strings;
+ }
+ g_assert_cmpstr(pt->value.string, ==, ptr->value);
+ break;
+ }
+ case PTYPE_INTEGER: {
+ intList *ptr;
+ if (cur_head) {
+ ptr = cur_head;
+ cur_head = ptr->next;
+ } else {
+ cur_head = ptr = pl_copy.value.integers;
+ }
+ g_assert_cmpint(pt->value.integer, ==, ptr->value);
+ break;
+ }
+ case PTYPE_S8: {
+ int8List *ptr;
+ if (cur_head) {
+ ptr = cur_head;
+ cur_head = ptr->next;
+ } else {
+ cur_head = ptr = pl_copy.value.s8_integers;
+ }
+ g_assert_cmpint(pt->value.s8, ==, ptr->value);
+ break;
+ }
+ case PTYPE_S16: {
+ int16List *ptr;
+ if (cur_head) {
+ ptr = cur_head;
+ cur_head = ptr->next;
+ } else {
+ cur_head = ptr = pl_copy.value.s16_integers;
+ }
+ g_assert_cmpint(pt->value.s16, ==, ptr->value);
+ break;
+ }
+ case PTYPE_S32: {
+ int32List *ptr;
+ if (cur_head) {
+ ptr = cur_head;
+ cur_head = ptr->next;
+ } else {
+ cur_head = ptr = pl_copy.value.s32_integers;
+ }
+ g_assert_cmpint(pt->value.s32, ==, ptr->value);
+ break;
+ }
+ case PTYPE_S64: {
+ int64List *ptr;
+ if (cur_head) {
+ ptr = cur_head;
+ cur_head = ptr->next;
+ } else {
+ cur_head = ptr = pl_copy.value.s64_integers;
+ }
+ g_assert_cmpint(pt->value.s64, ==, ptr->value);
+ break;
+ }
+ case PTYPE_U8: {
+ uint8List *ptr;
+ if (cur_head) {
+ ptr = cur_head;
+ cur_head = ptr->next;
+ } else {
+ cur_head = ptr = pl_copy.value.u8_integers;
+ }
+ g_assert_cmpint(pt->value.u8, ==, ptr->value);
+ break;
+ }
+ case PTYPE_U16: {
+ uint16List *ptr;
+ if (cur_head) {
+ ptr = cur_head;
+ cur_head = ptr->next;
+ } else {
+ cur_head = ptr = pl_copy.value.u16_integers;
+ }
+ g_assert_cmpint(pt->value.u16, ==, ptr->value);
+ break;
+ }
+ case PTYPE_U32: {
+ uint32List *ptr;
+ if (cur_head) {
+ ptr = cur_head;
+ cur_head = ptr->next;
+ } else {
+ cur_head = ptr = pl_copy.value.u32_integers;
+ }
+ g_assert_cmpint(pt->value.u32, ==, ptr->value);
+ break;
+ }
+ case PTYPE_U64: {
+ uint64List *ptr;
+ if (cur_head) {
+ ptr = cur_head;
+ cur_head = ptr->next;
+ } else {
+ cur_head = ptr = pl_copy.value.u64_integers;
+ }
+ g_assert_cmpint(pt->value.u64, ==, ptr->value);
+ break;
+ }
+ case PTYPE_NUMBER: {
+ numberList *ptr;
+ GString *double_expected = g_string_new("");
+ GString *double_actual = g_string_new("");
+ if (cur_head) {
+ ptr = cur_head;
+ cur_head = ptr->next;
+ } else {
+ cur_head = ptr = pl_copy.value.numbers;
+ }
+ /* we serialize with %f for our reference visitors, so rather than
+ * fuzzy floating math to test "equality", just compare the
+ * formatted values
+ */
+ g_string_printf(double_expected, "%.6f", pt->value.number);
+ g_string_printf(double_actual, "%.6f", ptr->value);
+ g_assert_cmpstr(double_actual->str, ==, double_expected->str);
+ g_string_free(double_expected, true);
+ g_string_free(double_actual, true);
+ break;
+ }
+ case PTYPE_BOOLEAN: {
+ boolList *ptr;
+ if (cur_head) {
+ ptr = cur_head;
+ cur_head = ptr->next;
+ } else {
+ cur_head = ptr = pl_copy.value.booleans;
+ }
+ g_assert_cmpint(!!pt->value.boolean, ==, !!ptr->value);
+ break;
+ }
+ default:
+ g_assert_not_reached();
+ }
+ i++;
+ } while (cur_head);
+
+ g_assert_cmpint(i, ==, 33);
+
+ ops->cleanup(serialize_data);
+ dealloc_helper(&pl, visit_primitive_list, &err);
+ g_assert(!err);
+ dealloc_helper(&pl_copy, visit_primitive_list, &err);
+ g_assert(!err);
+ g_free(args);
}
static void test_struct(gconstpointer opaque)
@@ -653,11 +1049,17 @@ static void qmp_deserialize(void **native_out, void *datap,
VisitorFunc visit, Error **errp)
{
QmpSerializeData *d = datap;
- QString *output_json = qobject_to_json(qmp_output_get_qobject(d->qov));
- QObject *obj = qobject_from_json(qstring_get_str(output_json));
+ QString *output_json;
+ QObject *obj_orig, *obj;
+
+ obj_orig = qmp_output_get_qobject(d->qov);
+ output_json = qobject_to_json(obj_orig);
+ obj = qobject_from_json(qstring_get_str(output_json));
QDECREF(output_json);
d->qiv = qmp_input_visitor_new(obj);
+ qobject_decref(obj_orig);
+ qobject_decref(obj);
visit(qmp_input_get_visitor(d->qiv), native_out, errp);
}
@@ -666,9 +1068,12 @@ static void qmp_cleanup(void *datap)
QmpSerializeData *d = datap;
qmp_output_visitor_cleanup(d->qov);
qmp_input_visitor_cleanup(d->qiv);
+
+ g_free(d);
}
typedef struct StringSerializeData {
+ char *string;
StringOutputVisitor *sov;
StringInputVisitor *siv;
} StringSerializeData;
@@ -688,15 +1093,19 @@ static void string_deserialize(void **native_out, void *datap,
{
StringSerializeData *d = datap;
- d->siv = string_input_visitor_new(string_output_get_string(d->sov));
+ d->string = string_output_get_string(d->sov);
+ d->siv = string_input_visitor_new(d->string);
visit(string_input_get_visitor(d->siv), native_out, errp);
}
static void string_cleanup(void *datap)
{
StringSerializeData *d = datap;
+
string_output_visitor_cleanup(d->sov);
string_input_visitor_cleanup(d->siv);
+ g_free(d->string);
+ g_free(d);
}
/* visitor registration, test harness */
@@ -711,7 +1120,8 @@ static const SerializeOps visitors[] = {
.serialize = qmp_serialize,
.deserialize = qmp_deserialize,
.cleanup = qmp_cleanup,
- .caps = VCAP_PRIMITIVES | VCAP_STRUCTURES | VCAP_LISTS
+ .caps = VCAP_PRIMITIVES | VCAP_STRUCTURES | VCAP_LISTS |
+ VCAP_PRIMITIVE_LISTS
},
{
.type = "String",
@@ -765,6 +1175,19 @@ static void add_visitor_type(const SerializeOps *ops)
args->test_data = NULL;
g_test_add_data_func(testname, args, test_nested_struct_list);
}
+
+ if (ops->caps & VCAP_PRIMITIVE_LISTS) {
+ i = 0;
+ while (pt_values[i].type != PTYPE_EOL) {
+ sprintf(testname, "%s/primitive_list/%s", testname_prefix,
+ pt_values[i].description);
+ args = g_malloc0(sizeof(*args));
+ args->ops = ops;
+ args->test_data = &pt_values[i];
+ g_test_add_data_func(testname, args, test_primitive_lists);
+ i++;
+ }
+ }
}
int main(int argc, char **argv)
diff --git a/tests/test-x86-cpuid.c b/tests/test-x86-cpuid.c
new file mode 100644
index 000000000..8d9f96a11
--- /dev/null
+++ b/tests/test-x86-cpuid.c
@@ -0,0 +1,110 @@
+/*
+ * Test code for x86 CPUID and Topology functions
+ *
+ * Copyright (c) 2012 Red Hat Inc.
+ *
+ * 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 <glib.h>
+
+#include "topology.h"
+
+static void test_topo_bits(void)
+{
+ /* simple tests for 1 thread per core, 1 core per socket */
+ g_assert_cmpuint(apicid_smt_width(1, 1), ==, 0);
+ g_assert_cmpuint(apicid_core_width(1, 1), ==, 0);
+
+ g_assert_cmpuint(x86_apicid_from_cpu_idx(1, 1, 0), ==, 0);
+ g_assert_cmpuint(x86_apicid_from_cpu_idx(1, 1, 1), ==, 1);
+ g_assert_cmpuint(x86_apicid_from_cpu_idx(1, 1, 2), ==, 2);
+ g_assert_cmpuint(x86_apicid_from_cpu_idx(1, 1, 3), ==, 3);
+
+
+ /* Test field width calculation for multiple values
+ */
+ g_assert_cmpuint(apicid_smt_width(1, 2), ==, 1);
+ g_assert_cmpuint(apicid_smt_width(1, 3), ==, 2);
+ g_assert_cmpuint(apicid_smt_width(1, 4), ==, 2);
+
+ g_assert_cmpuint(apicid_smt_width(1, 14), ==, 4);
+ g_assert_cmpuint(apicid_smt_width(1, 15), ==, 4);
+ g_assert_cmpuint(apicid_smt_width(1, 16), ==, 4);
+ g_assert_cmpuint(apicid_smt_width(1, 17), ==, 5);
+
+
+ g_assert_cmpuint(apicid_core_width(30, 2), ==, 5);
+ g_assert_cmpuint(apicid_core_width(31, 2), ==, 5);
+ g_assert_cmpuint(apicid_core_width(32, 2), ==, 5);
+ g_assert_cmpuint(apicid_core_width(33, 2), ==, 6);
+
+
+ /* build a weird topology and see if IDs are calculated correctly
+ */
+
+ /* This will use 2 bits for thread ID and 3 bits for core ID
+ */
+ g_assert_cmpuint(apicid_smt_width(6, 3), ==, 2);
+ g_assert_cmpuint(apicid_core_width(6, 3), ==, 3);
+ g_assert_cmpuint(apicid_pkg_offset(6, 3), ==, 5);
+
+ g_assert_cmpuint(x86_apicid_from_cpu_idx(6, 3, 0), ==, 0);
+ g_assert_cmpuint(x86_apicid_from_cpu_idx(6, 3, 1), ==, 1);
+ g_assert_cmpuint(x86_apicid_from_cpu_idx(6, 3, 2), ==, 2);
+
+ g_assert_cmpuint(x86_apicid_from_cpu_idx(6, 3, 1 * 3 + 0), ==,
+ (1 << 2) | 0);
+ g_assert_cmpuint(x86_apicid_from_cpu_idx(6, 3, 1 * 3 + 1), ==,
+ (1 << 2) | 1);
+ g_assert_cmpuint(x86_apicid_from_cpu_idx(6, 3, 1 * 3 + 2), ==,
+ (1 << 2) | 2);
+
+ g_assert_cmpuint(x86_apicid_from_cpu_idx(6, 3, 2 * 3 + 0), ==,
+ (2 << 2) | 0);
+ g_assert_cmpuint(x86_apicid_from_cpu_idx(6, 3, 2 * 3 + 1), ==,
+ (2 << 2) | 1);
+ g_assert_cmpuint(x86_apicid_from_cpu_idx(6, 3, 2 * 3 + 2), ==,
+ (2 << 2) | 2);
+
+ g_assert_cmpuint(x86_apicid_from_cpu_idx(6, 3, 5 * 3 + 0), ==,
+ (5 << 2) | 0);
+ g_assert_cmpuint(x86_apicid_from_cpu_idx(6, 3, 5 * 3 + 1), ==,
+ (5 << 2) | 1);
+ g_assert_cmpuint(x86_apicid_from_cpu_idx(6, 3, 5 * 3 + 2), ==,
+ (5 << 2) | 2);
+
+ g_assert_cmpuint(x86_apicid_from_cpu_idx(6, 3, 1 * 6 * 3 + 0 * 3 + 0), ==,
+ (1 << 5));
+ g_assert_cmpuint(x86_apicid_from_cpu_idx(6, 3, 1 * 6 * 3 + 1 * 3 + 1), ==,
+ (1 << 5) | (1 << 2) | 1);
+ g_assert_cmpuint(x86_apicid_from_cpu_idx(6, 3, 3 * 6 * 3 + 5 * 3 + 2), ==,
+ (3 << 5) | (5 << 2) | 2);
+}
+
+int main(int argc, char **argv)
+{
+ g_test_init(&argc, &argv, NULL);
+
+ g_test_add_func("/cpuid/topology/basic", test_topo_bits);
+
+ g_test_run();
+
+ return 0;
+}
diff --git a/tests/test-xbzrle.c b/tests/test-xbzrle.c
new file mode 100644
index 000000000..db93b0a3d
--- /dev/null
+++ b/tests/test-xbzrle.c
@@ -0,0 +1,196 @@
+/*
+ * Xor Based Zero Run Length Encoding unit tests.
+ *
+ * Copyright 2013 Red Hat, Inc. and/or its affiliates
+ *
+ * Authors:
+ * Orit Wasserman <owasserm@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 <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <strings.h>
+#include <string.h>
+#include <sys/time.h>
+#include <assert.h>
+#include "qemu-common.h"
+#include "include/migration/migration.h"
+
+#define PAGE_SIZE 4096
+
+static void test_uleb(void)
+{
+ uint32_t i, val;
+ uint8_t buf[2];
+ int encode_ret, decode_ret;
+
+ for (i = 0; i <= 0x3fff; i++) {
+ encode_ret = uleb128_encode_small(&buf[0], i);
+ decode_ret = uleb128_decode_small(&buf[0], &val);
+ g_assert(encode_ret == decode_ret);
+ g_assert(i == val);
+ }
+
+ /* decode invalid value */
+ buf[0] = 0x80;
+ buf[1] = 0x80;
+
+ decode_ret = uleb128_decode_small(&buf[0], &val);
+ g_assert(decode_ret == -1);
+ g_assert(val == 0);
+}
+
+static void test_encode_decode_zero(void)
+{
+ uint8_t *buffer = g_malloc0(PAGE_SIZE);
+ uint8_t *compressed = g_malloc0(PAGE_SIZE);
+ int i = 0;
+ int dlen = 0;
+ int diff_len = g_test_rand_int_range(0, PAGE_SIZE - 1006);
+
+ for (i = diff_len; i > 0; i--) {
+ buffer[1000 + i] = i;
+ }
+
+ buffer[1000 + diff_len + 3] = 103;
+ buffer[1000 + diff_len + 5] = 105;
+
+ /* encode zero page */
+ dlen = xbzrle_encode_buffer(buffer, buffer, PAGE_SIZE, compressed,
+ PAGE_SIZE);
+ g_assert(dlen == 0);
+
+ g_free(buffer);
+ g_free(compressed);
+}
+
+static void test_encode_decode_unchanged(void)
+{
+ uint8_t *compressed = g_malloc0(PAGE_SIZE);
+ uint8_t *test = g_malloc0(PAGE_SIZE);
+ int i = 0;
+ int dlen = 0;
+ int diff_len = g_test_rand_int_range(0, PAGE_SIZE - 1006);
+
+ for (i = diff_len; i > 0; i--) {
+ test[1000 + i] = i + 4;
+ }
+
+ test[1000 + diff_len + 3] = 107;
+ test[1000 + diff_len + 5] = 109;
+
+ /* test unchanged buffer */
+ dlen = xbzrle_encode_buffer(test, test, PAGE_SIZE, compressed,
+ PAGE_SIZE);
+ g_assert(dlen == 0);
+
+ g_free(test);
+ g_free(compressed);
+}
+
+static void test_encode_decode_1_byte(void)
+{
+ uint8_t *buffer = g_malloc0(PAGE_SIZE);
+ uint8_t *test = g_malloc0(PAGE_SIZE);
+ uint8_t *compressed = g_malloc(PAGE_SIZE);
+ int dlen = 0, rc = 0;
+ uint8_t buf[2];
+
+ test[PAGE_SIZE - 1] = 1;
+
+ dlen = xbzrle_encode_buffer(buffer, test, PAGE_SIZE, compressed,
+ PAGE_SIZE);
+ g_assert(dlen == (uleb128_encode_small(&buf[0], 4095) + 2));
+
+ rc = xbzrle_decode_buffer(compressed, dlen, buffer, PAGE_SIZE);
+ g_assert(rc == PAGE_SIZE);
+ g_assert(memcmp(test, buffer, PAGE_SIZE) == 0);
+
+ g_free(buffer);
+ g_free(compressed);
+ g_free(test);
+}
+
+static void test_encode_decode_overflow(void)
+{
+ uint8_t *compressed = g_malloc0(PAGE_SIZE);
+ uint8_t *test = g_malloc0(PAGE_SIZE);
+ uint8_t *buffer = g_malloc0(PAGE_SIZE);
+ int i = 0, rc = 0;
+
+ for (i = 0; i < PAGE_SIZE / 2 - 1; i++) {
+ test[i * 2] = 1;
+ }
+
+ /* encode overflow */
+ rc = xbzrle_encode_buffer(buffer, test, PAGE_SIZE, compressed,
+ PAGE_SIZE);
+ g_assert(rc == -1);
+
+ g_free(buffer);
+ g_free(compressed);
+ g_free(test);
+}
+
+static void encode_decode_range(void)
+{
+ uint8_t *buffer = g_malloc0(PAGE_SIZE);
+ uint8_t *compressed = g_malloc(PAGE_SIZE);
+ uint8_t *test = g_malloc0(PAGE_SIZE);
+ int i = 0, rc = 0;
+ int dlen = 0;
+
+ int diff_len = g_test_rand_int_range(0, PAGE_SIZE - 1006);
+
+ for (i = diff_len; i > 0; i--) {
+ buffer[1000 + i] = i;
+ test[1000 + i] = i + 4;
+ }
+
+ buffer[1000 + diff_len + 3] = 103;
+ test[1000 + diff_len + 3] = 107;
+
+ buffer[1000 + diff_len + 5] = 105;
+ test[1000 + diff_len + 5] = 109;
+
+ /* test encode/decode */
+ dlen = xbzrle_encode_buffer(test, buffer, PAGE_SIZE, compressed,
+ PAGE_SIZE);
+
+ rc = xbzrle_decode_buffer(compressed, dlen, test, PAGE_SIZE);
+ g_assert(rc < PAGE_SIZE);
+ g_assert(memcmp(test, buffer, PAGE_SIZE) == 0);
+
+ g_free(buffer);
+ g_free(compressed);
+ g_free(test);
+}
+
+static void test_encode_decode(void)
+{
+ int i;
+
+ for (i = 0; i < 10000; i++) {
+ encode_decode_range();
+ }
+}
+
+int main(int argc, char **argv)
+{
+ g_test_init(&argc, &argv, NULL);
+ g_test_rand_int();
+ g_test_add_func("/xbzrle/uleb", test_uleb);
+ g_test_add_func("/xbzrle/encode_decode_zero", test_encode_decode_zero);
+ g_test_add_func("/xbzrle/encode_decode_unchanged",
+ test_encode_decode_unchanged);
+ g_test_add_func("/xbzrle/encode_decode_1_byte", test_encode_decode_1_byte);
+ g_test_add_func("/xbzrle/encode_decode_overflow",
+ test_encode_decode_overflow);
+ g_test_add_func("/xbzrle/encode_decode", test_encode_decode);
+
+ return g_test_run();
+}
diff --git a/tests/tmp105-test.c b/tests/tmp105-test.c
new file mode 100644
index 000000000..fecd6dcd7
--- /dev/null
+++ b/tests/tmp105-test.c
@@ -0,0 +1,76 @@
+/*
+ * QTest testcase for the TMP105 temperature sensor
+ *
+ * Copyright (c) 2012 Andreas Färber
+ *
+ * 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 "libqtest.h"
+#include "libqos/i2c.h"
+#include "hw/misc/tmp105_regs.h"
+
+#include <glib.h>
+
+#define OMAP2_I2C_1_BASE 0x48070000
+
+#define N8X0_ADDR 0x48
+
+static I2CAdapter *i2c;
+static uint8_t addr;
+
+static void send_and_receive(void)
+{
+ uint8_t cmd[3];
+ uint8_t resp[2];
+
+ cmd[0] = TMP105_REG_TEMPERATURE;
+ i2c_send(i2c, addr, cmd, 1);
+ i2c_recv(i2c, addr, resp, 2);
+ g_assert_cmpuint(((uint16_t)resp[0] << 8) | resp[1], ==, 0);
+
+ cmd[0] = TMP105_REG_CONFIG;
+ cmd[1] = 0x0; /* matches the reset value */
+ i2c_send(i2c, addr, cmd, 2);
+ i2c_recv(i2c, addr, resp, 1);
+ g_assert_cmphex(resp[0], ==, cmd[1]);
+
+ cmd[0] = TMP105_REG_T_LOW;
+ cmd[1] = 0x12;
+ cmd[2] = 0x34;
+ i2c_send(i2c, addr, cmd, 3);
+ i2c_recv(i2c, addr, resp, 2);
+ g_assert_cmphex(resp[0], ==, cmd[1]);
+ g_assert_cmphex(resp[1], ==, cmd[2]);
+
+ cmd[0] = TMP105_REG_T_HIGH;
+ cmd[1] = 0x42;
+ cmd[2] = 0x31;
+ i2c_send(i2c, addr, cmd, 3);
+ i2c_recv(i2c, addr, resp, 2);
+ g_assert_cmphex(resp[0], ==, cmd[1]);
+ g_assert_cmphex(resp[1], ==, cmd[2]);
+}
+
+int main(int argc, char **argv)
+{
+ QTestState *s = NULL;
+ int ret;
+
+ g_test_init(&argc, &argv, NULL);
+
+ s = qtest_start("-display none -machine n800");
+ i2c = omap_i2c_create(OMAP2_I2C_1_BASE);
+ addr = N8X0_ADDR;
+
+ qtest_add_func("/tmp105/tx-rx", send_and_receive);
+
+ ret = g_test_run();
+
+ if (s) {
+ qtest_quit(s);
+ }
+ g_free(i2c);
+
+ return ret;
+}