All of lore.kernel.org
 help / color / mirror / Atom feed
* [Qemu-devel] [PATCH v4 0/7] new test infrastructure + qtest
@ 2012-03-28 13:42 Paolo Bonzini
  2012-03-28 13:42 ` [Qemu-devel] [PATCH v4 1/7] test makefile overhaul Paolo Bonzini
                   ` (8 more replies)
  0 siblings, 9 replies; 21+ messages in thread
From: Paolo Bonzini @ 2012-03-28 13:42 UTC (permalink / raw)
  To: qemu-devel

This is a rebase of qtest.  I split the gtester infrastructure into
its own patch, and reorganized the tests by moving everything into
tests/.

Also, libqtest now has bindings for the clock management commands, and
I am using them in rtc-test.  Finally, the accept is moved from qemu to
libqtest; tests need not sleep anymore until QEMU connects.

This is on top of Luiz's recent pull request.

Anthony Liguori (4):
  qtest: add test framework
  qtest: add C version of test infrastructure
  rtc: split out macros into a header file and use in test case
  qtest: add rtc-test test-case

Paolo Bonzini (3):
  test makefile overhaul
  qtest: IRQ interception infrastructure
  qtest: add clock management

 Makefile.objs                                      |    2 +
 cpu-exec.c                                         |    1 +
 cpus.c                                             |   82 ++++-
 cpus.h                                             |    2 +
 hw/irq.c                                           |   17 +
 hw/irq.h                                           |    5 +
 hw/mc146818rtc.c                                   |   33 --
 hw/mc146818rtc.h                                   |    3 +-
 hw/mc146818rtc_regs.h                              |   62 +++
 hw/pc_piix.c                                       |    5 +-
 osdep.h                                            |    2 +
 qemu-common.h                                      |    1 -
 qemu-options.hx                                    |    8 +
 qemu-timer.c                                       |    2 +-
 qemu-timer.h                                       |    1 +
 qtest.c                                            |  443 ++++++++++++++++++++
 qtest.h                                            |   35 ++
 rules.mak                                          |    2 +-
 scripts/gtester-cat                                |   26 ++
 scripts/qtest                                      |    5 +
 tests/Makefile                                     |  165 ++++++--
 check-qdict.c => tests/check-qdict.c               |    0
 check-qfloat.c => tests/check-qfloat.c             |    0
 check-qint.c => tests/check-qint.c                 |    0
 check-qjson.c => tests/check-qjson.c               |    0
 check-qlist.c => tests/check-qlist.c               |    0
 check-qstring.c => tests/check-qstring.c           |    0
 tests/libqtest.c                                   |  385 +++++++++++++++++
 tests/libqtest.h                                   |  333 +++++++++++++++
 tests/rtc-test.c                                   |  263 ++++++++++++
 test-coroutine.c => tests/test-coroutine.c         |    0
 test-qmp-commands.c => tests/test-qmp-commands.c   |    0
 .../test-qmp-input-strict.c                        |    0
 .../test-qmp-input-visitor.c                       |    0
 .../test-qmp-output-visitor.c                      |    0
 .../test-string-input-visitor.c                    |    0
 .../test-string-output-visitor.c                   |    0
 vl.c                                               |   10 +-
 38 files changed, 1806 insertions(+), 87 deletions(-)
 create mode 100644 hw/mc146818rtc_regs.h
 create mode 100644 qtest.c
 create mode 100644 qtest.h
 create mode 100755 scripts/gtester-cat
 create mode 100755 scripts/qtest
 rename check-qdict.c => tests/check-qdict.c (100%)
 rename check-qfloat.c => tests/check-qfloat.c (100%)
 rename check-qint.c => tests/check-qint.c (100%)
 rename check-qjson.c => tests/check-qjson.c (100%)
 rename check-qlist.c => tests/check-qlist.c (100%)
 rename check-qstring.c => tests/check-qstring.c (100%)
 create mode 100644 tests/libqtest.c
 create mode 100644 tests/libqtest.h
 create mode 100644 tests/rtc-test.c
 rename test-coroutine.c => tests/test-coroutine.c (100%)
 rename test-qmp-commands.c => tests/test-qmp-commands.c (100%)
 rename test-qmp-input-strict.c => tests/test-qmp-input-strict.c (100%)
 rename test-qmp-input-visitor.c => tests/test-qmp-input-visitor.c (100%)
 rename test-qmp-output-visitor.c => tests/test-qmp-output-visitor.c (100%)
 rename test-string-input-visitor.c => tests/test-string-input-visitor.c (100%)
 rename test-string-output-visitor.c => tests/test-string-output-visitor.c (100%)

-- 
1.7.9.1

^ permalink raw reply	[flat|nested] 21+ messages in thread

* [Qemu-devel] [PATCH v4 1/7] test makefile overhaul
  2012-03-28 13:42 [Qemu-devel] [PATCH v4 0/7] new test infrastructure + qtest Paolo Bonzini
@ 2012-03-28 13:42 ` Paolo Bonzini
  2012-03-28 13:42 ` [Qemu-devel] [PATCH v4 2/7] qtest: add test framework Paolo Bonzini
                   ` (7 subsequent siblings)
  8 siblings, 0 replies; 21+ messages in thread
From: Paolo Bonzini @ 2012-03-28 13:42 UTC (permalink / raw)
  To: qemu-devel; +Cc: Anthony Liguori

This introduces new test reporting infrastructure based on
gtester and gtester-report.

Also, all existing tests are moved to tests/, and tests/Makefile
is reorganized to factor out the commonalities in the rules.

Signed-off-by: Anthony Liguori <aliguori@linux.vnet.ibm.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 rules.mak                                          |    2 +-
 scripts/gtester-cat                                |   26 ++++
 tests/Makefile                                     |  140 +++++++++++++------
 check-qdict.c => tests/check-qdict.c               |    0
 check-qfloat.c => tests/check-qfloat.c             |    0
 check-qint.c => tests/check-qint.c                 |    0
 check-qjson.c => tests/check-qjson.c               |    0
 check-qlist.c => tests/check-qlist.c               |    0
 check-qstring.c => tests/check-qstring.c           |    0
 test-coroutine.c => tests/test-coroutine.c         |    0
 test-qmp-commands.c => tests/test-qmp-commands.c   |    0
 .../test-qmp-input-strict.c                        |    0
 .../test-qmp-input-visitor.c                       |    0
 .../test-qmp-output-visitor.c                      |    0
 .../test-string-input-visitor.c                    |    0
 .../test-string-output-visitor.c                   |    0
 16 files changed, 123 insertions(+), 45 deletions(-)
 create mode 100755 scripts/gtester-cat
 rename check-qdict.c => tests/check-qdict.c (100%)
 rename check-qfloat.c => tests/check-qfloat.c (100%)
 rename check-qint.c => tests/check-qint.c (100%)
 rename check-qjson.c => tests/check-qjson.c (100%)
 rename check-qlist.c => tests/check-qlist.c (100%)
 rename check-qstring.c => tests/check-qstring.c (100%)
 rename test-coroutine.c => tests/test-coroutine.c (100%)
 rename test-qmp-commands.c => tests/test-qmp-commands.c (100%)
 rename test-qmp-input-strict.c => tests/test-qmp-input-strict.c (100%)
 rename test-qmp-input-visitor.c => tests/test-qmp-input-visitor.c (100%)
 rename test-qmp-output-visitor.c => tests/test-qmp-output-visitor.c (100%)
 rename test-string-input-visitor.c => tests/test-string-input-visitor.c (100%)
 rename test-string-output-visitor.c => tests/test-string-output-visitor.c (100%)

diff --git a/rules.mak b/rules.mak
index 04a9198..c30093c 100644
--- a/rules.mak
+++ b/rules.mak
@@ -47,7 +47,7 @@ quiet-command = $(if $(V),$1,$(if $(2),@echo $2 && $1, @$1))
 cc-option = $(if $(shell $(CC) $1 $2 -S -o /dev/null -xc /dev/null \
               >/dev/null 2>&1 && echo OK), $2, $3)
 
-VPATH_SUFFIXES = %.c %.h %.S %.m %.mak %.texi
+VPATH_SUFFIXES = %.c %.h %.S %.m %.mak %.texi %.sh
 set-vpath = $(if $1,$(foreach PATTERN,$(VPATH_SUFFIXES),$(eval vpath $(PATTERN) $1)))
 
 # find-in-path
diff --git a/scripts/gtester-cat b/scripts/gtester-cat
new file mode 100755
index 0000000..5bcce50
--- /dev/null
+++ b/scripts/gtester-cat
@@ -0,0 +1,26 @@
+#!/bin/sh
+#
+# Copyright IBM, Corp. 2012
+#
+# Authors:
+#  Anthony Liguori <aliguori@us.ibm.com>
+#
+# This work is licensed under the terms of the GNU GPLv2 or later.
+# See the COPYING file in the top-level directory.
+
+cat <<EOF
+<?xml version="1.0"?>
+<gtester>
+ <info>
+  <package>qemu</package>
+  <version>0.0</version>
+  <revision>rev</revision>
+ </info>
+EOF
+
+sed \
+  -e '/<?xml/d' \
+  -e '/^<gtester>$/d' \
+  -e '/<info>/,/<\/info>/d' \
+  -e '$b' \
+  -e '/^<\/gtester>$/d' "$@"
diff --git a/tests/Makefile b/tests/Makefile
index 2a2fff7..249f972 100644
--- a/tests/Makefile
+++ b/tests/Makefile
@@ -1,61 +1,113 @@
 export SRC_PATH
 
-CHECKS = check-qdict check-qfloat check-qint check-qstring check-qlist
-CHECKS += check-qjson test-qmp-output-visitor test-qmp-input-visitor
-CHECKS += test-string-input-visitor test-string-output-visitor test-coroutine
-CHECKS += test-qmp-commands
-CHECKS += $(SRC_PATH)/tests/qemu-iotests-quick.sh
-
-check-qint.o check-qstring.o check-qdict.o check-qlist.o check-qfloat.o check-qjson.o test-coroutine.o: $(GENERATED_HEADERS)
-
-check-qint: check-qint.o qint.o $(tools-obj-y)
-check-qstring: check-qstring.o qstring.o $(tools-obj-y)
-check-qdict: check-qdict.o qdict.o qfloat.o qint.o qstring.o qbool.o qlist.o $(tools-obj-y)
-check-qlist: check-qlist.o qlist.o qint.o $(tools-obj-y)
-check-qfloat: check-qfloat.o qfloat.o $(tools-obj-y)
-check-qjson: check-qjson.o $(qobject-obj-y) $(tools-obj-y)
-test-coroutine: test-coroutine.o qemu-timer-common.o async.o $(coroutine-obj-y) $(tools-obj-y)
-
-test-qmp-input-visitor.o test-qmp-output-visitor.o test-qmp-input-strict.o \
-test-string-input-visitor.o test-string-output-visitor.o \
-	test-qmp-commands.o: QEMU_CFLAGS += -I $(qapi-dir)
-
-$(qapi-dir)/test-qapi-types.c $(qapi-dir)/test-qapi-types.h :\
+check-unit-y = tests/check-qdict$(EXESUF)
+check-unit-y += tests/check-qfloat$(EXESUF)
+check-unit-y += tests/check-qint$(EXESUF)
+check-unit-y += tests/check-qstring$(EXESUF)
+check-unit-y += tests/check-qlist$(EXESUF)
+check-unit-y += tests/check-qjson$(EXESUF)
+check-unit-y += tests/test-qmp-output-visitor$(EXESUF)
+check-unit-y += tests/test-qmp-input-visitor$(EXESUF)
+check-unit-y += tests/test-qmp-input-strict$(EXESUF)
+check-unit-y += tests/test-qmp-commands$(EXESUF)
+check-unit-y += tests/test-string-input-visitor$(EXESUF)
+check-unit-y += tests/test-string-output-visitor$(EXESUF)
+check-unit-y += tests/test-coroutine$(EXESUF)
+
+check-block-$(CONFIG_POSIX) += tests/qemu-iotests-quick.sh
+
+GENERATED_HEADERS += tests/test-qapi-types.h tests/test-qapi-visit.h tests/test-qmp-commands.h
+
+test-obj-y = tests/check-qint.o tests/check-qstring.o tests/check-qdict.o \
+	tests/check-qlist.o tests/check-qfloat.o tests/check-qjson.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
+
+test-qapi-obj-y =  $(qobject-obj-y) $(qapi-obj-y) $(tools-obj-y)
+test-qapi-obj-y += tests/test-qapi-visit.o tests/test-qapi-types.o
+test-qapi-obj-y += module.o
+
+$(test-obj-y): $(GENERATED_HEADERS)
+$(test-obj-y): QEMU_INCLUDES += -Itests
+
+tests/check-qint$(EXESUF): tests/check-qint.o qint.o $(tools-obj-y)
+tests/check-qstring$(EXESUF): tests/check-qstring.o qstring.o $(tools-obj-y)
+tests/check-qdict$(EXESUF): tests/check-qdict.o qdict.o qfloat.o qint.o qstring.o qbool.o qlist.o $(tools-obj-y)
+tests/check-qlist$(EXESUF): tests/check-qlist.o qlist.o qint.o $(tools-obj-y)
+tests/check-qfloat$(EXESUF): tests/check-qfloat.o qfloat.o $(tools-obj-y)
+tests/check-qjson$(EXESUF): tests/check-qjson.o $(qobject-obj-y) $(tools-obj-y)
+tests/test-coroutine$(EXESUF): tests/test-coroutine.o $(coroutine-obj-y) $(tools-obj-y)
+
+tests/test-qapi-types.c tests/test-qapi-types.h :\
 $(SRC_PATH)/qapi-schema-test.json $(SRC_PATH)/scripts/qapi-types.py
-	$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-types.py $(gen-out-type) -o "$(qapi-dir)" -p "test-" < $<, "  GEN   $@")
-$(qapi-dir)/test-qapi-visit.c $(qapi-dir)/test-qapi-visit.h :\
+	$(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
-	$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-visit.py $(gen-out-type) -o "$(qapi-dir)" -p "test-" < $<, "  GEN   $@")
-$(qapi-dir)/test-qmp-commands.h $(qapi-dir)/test-qmp-marshal.c :\
+	$(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
-	    $(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-commands.py $(gen-out-type) -o "$(qapi-dir)" -p "test-" < $<, "  GEN   $@")
+	$(call quiet-command,$(PYTHON) $(SRC_PATH)/scripts/qapi-commands.py $(gen-out-type) -o tests -p "test-" < $<, "  GEN   $@")
 
 
-test-string-output-visitor.o: $(addprefix $(qapi-dir)/, test-qapi-types.c test-qapi-types.h test-qapi-visit.c test-qapi-visit.h) $(qapi-obj-y)
-test-string-output-visitor: test-string-output-visitor.o $(qobject-obj-y) $(qapi-obj-y) $(tools-obj-y) $(qapi-dir)/test-qapi-visit.o $(qapi-dir)/test-qapi-types.o
+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)
 
-test-string-input-visitor.o: $(addprefix $(qapi-dir)/, test-qapi-types.c test-qapi-types.h test-qapi-visit.c test-qapi-visit.h) $(qapi-obj-y)
-test-string-input-visitor: test-string-input-visitor.o $(qobject-obj-y) $(qapi-obj-y) $(tools-obj-y) $(qapi-dir)/test-qapi-visit.o $(qapi-dir)/test-qapi-types.o
+.PHONY: check-help
+check-help:
+	@echo "Regression testing targets:"
+	@echo
+	@echo " make check                Run all tests"
+	@echo " make check-unit           Run qobject tests"
+	@echo " make check-block          Run block tests"
+	@echo " make check-report.html    Generates an HTML test report"
+	@echo
+	@echo "Please note that HTML reports do not regenerate if the unit tests"
+	@echo "has not changed."
+	@echo
+	@echo "The variable SPEED can be set to control the gtester speed setting."
+	@echo "Default options are -k and (for make V=1) --verbose; they can be"
+	@echo "changed with variable GTESTER_OPTIONS."
 
-test-qmp-input-strict.o: $(addprefix $(qapi-dir)/, test-qapi-types.c test-qapi-types.h test-qapi-visit.c test-qapi-visit.h) $(qapi-obj-y)
-test-qmp-input-strict: test-qmp-input-strict.o $(qobject-obj-y) $(qapi-obj-y) $(tools-obj-y) $(qapi-dir)/test-qapi-visit.o $(qapi-dir)/test-qapi-types.o
+.SECONDARY:
 
-test-qmp-output-visitor.o: $(addprefix $(qapi-dir)/, test-qapi-types.c test-qapi-types.h test-qapi-visit.c test-qapi-visit.h) $(qapi-obj-y)
-test-qmp-output-visitor: test-qmp-output-visitor.o $(qobject-obj-y) $(qapi-obj-y) $(tools-obj-y) $(qapi-dir)/test-qapi-visit.o $(qapi-dir)/test-qapi-types.o
+SPEED = quick
+GTESTER_OPTIONS = -k $(if $(V),--verbose,-q)
 
-test-qmp-input-visitor.o: $(addprefix $(qapi-dir)/, test-qapi-types.c test-qapi-types.h test-qapi-visit.c test-qapi-visit.h) $(qapi-obj-y)
-test-qmp-input-visitor: test-qmp-input-visitor.o $(qobject-obj-y) $(qapi-obj-y) $(tools-obj-y) $(qapi-dir)/test-qapi-visit.o $(qapi-dir)/test-qapi-types.o
+# gtester tests, possibly with verbose output
 
-test-qmp-commands.o: $(addprefix $(qapi-dir)/, test-qapi-types.c test-qapi-types.h test-qapi-visit.c test-qapi-visit.h test-qmp-marshal.c test-qmp-commands.h) $(qapi-obj-y)
-test-qmp-commands: test-qmp-commands.o $(qobject-obj-y) $(qapi-obj-y) $(tools-obj-y) $(qapi-dir)/test-qapi-visit.o $(qapi-dir)/test-qapi-types.o $(qapi-dir)/test-qmp-marshal.o module.o
+.PHONY: $(patsubst %, check-%, $(check-unit-y))
+$(patsubst %, check-%, $(check-unit-y)): check-%: %
+	$(call quiet-command,gtester $(GTESTER_OPTIONS) -m=$(SPEED) $*,"GTESTER $*")
 
-$(SRC_PATH)/tests/qemu-iotests-quick.sh: qemu-img qemu-io
+# gtester tests with XML output
 
+check-report-unit.xml: $(check-unit-y)
+	$(call quiet-command,gtester -q $(GTESTER_OPTIONS) -o $@ -m=$(SPEED) $^, "GTESTER $@")
 
-.PHONY: check check-block
+# Reports and overall runs
 
-check: $(CHECKS)
-	$(call quiet-command, gtester $(CHECKS), "  CHECK")
+check-report.xml: check-report-unit.xml
+	$(call quiet-command,$(SRC_PATH)/scripts/gtester-cat $^ > $@, "  GEN    $@")
 
-check-block:
-	$(call quiet-command, $(SHELL) $(SRC_PATH)/tests/check-block.sh , "  CHECK")
+check-report.html: check-report.xml
+	$(call quiet-command,gtester-report $< > $@, "  GEN    $@")
+
+
+# Other tests
+
+.PHONY: check-tests/qemu-iotests-quick.sh
+check-tests/qemu-iotests-quick.sh: tests/qemu-iotests-quick.sh qemu-img$(EXESUF) qemu-io$(EXESUF)
+	$<
+
+# Consolidated targets
+
+.PHONY: check-unit check
+check-unit: $(patsubst %,check-%, $(check-unit-y))
+check-block: $(patsubst %,check-%, $(check-block-y))
+check: check-unit
diff --git a/check-qdict.c b/tests/check-qdict.c
similarity index 100%
rename from check-qdict.c
rename to tests/check-qdict.c
diff --git a/check-qfloat.c b/tests/check-qfloat.c
similarity index 100%
rename from check-qfloat.c
rename to tests/check-qfloat.c
diff --git a/check-qint.c b/tests/check-qint.c
similarity index 100%
rename from check-qint.c
rename to tests/check-qint.c
diff --git a/check-qjson.c b/tests/check-qjson.c
similarity index 100%
rename from check-qjson.c
rename to tests/check-qjson.c
diff --git a/check-qlist.c b/tests/check-qlist.c
similarity index 100%
rename from check-qlist.c
rename to tests/check-qlist.c
diff --git a/check-qstring.c b/tests/check-qstring.c
similarity index 100%
rename from check-qstring.c
rename to tests/check-qstring.c
diff --git a/test-coroutine.c b/tests/test-coroutine.c
similarity index 100%
rename from test-coroutine.c
rename to tests/test-coroutine.c
diff --git a/test-qmp-commands.c b/tests/test-qmp-commands.c
similarity index 100%
rename from test-qmp-commands.c
rename to tests/test-qmp-commands.c
diff --git a/test-qmp-input-strict.c b/tests/test-qmp-input-strict.c
similarity index 100%
rename from test-qmp-input-strict.c
rename to tests/test-qmp-input-strict.c
diff --git a/test-qmp-input-visitor.c b/tests/test-qmp-input-visitor.c
similarity index 100%
rename from test-qmp-input-visitor.c
rename to tests/test-qmp-input-visitor.c
diff --git a/test-qmp-output-visitor.c b/tests/test-qmp-output-visitor.c
similarity index 100%
rename from test-qmp-output-visitor.c
rename to tests/test-qmp-output-visitor.c
diff --git a/test-string-input-visitor.c b/tests/test-string-input-visitor.c
similarity index 100%
rename from test-string-input-visitor.c
rename to tests/test-string-input-visitor.c
diff --git a/test-string-output-visitor.c b/tests/test-string-output-visitor.c
similarity index 100%
rename from test-string-output-visitor.c
rename to tests/test-string-output-visitor.c
-- 
1.7.9.1

^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [Qemu-devel] [PATCH v4 2/7] qtest: add test framework
  2012-03-28 13:42 [Qemu-devel] [PATCH v4 0/7] new test infrastructure + qtest Paolo Bonzini
  2012-03-28 13:42 ` [Qemu-devel] [PATCH v4 1/7] test makefile overhaul Paolo Bonzini
@ 2012-03-28 13:42 ` Paolo Bonzini
  2012-03-30 17:40   ` Stefan Weil
  2012-03-28 13:42 ` [Qemu-devel] [PATCH v4 3/7] qtest: IRQ interception infrastructure Paolo Bonzini
                   ` (6 subsequent siblings)
  8 siblings, 1 reply; 21+ messages in thread
From: Paolo Bonzini @ 2012-03-28 13:42 UTC (permalink / raw)
  To: qemu-devel; +Cc: Anthony Liguori

From: Anthony Liguori <aliguori@us.ibm.com>

The idea behind qtest is pretty simple.  Instead of executing a CPU via TCG or
KVM, rely on an external process to send events to the device model that the CPU
would normally generate.

qtest presents itself as an accelerator.  In addition, a new option is added to
establish a qtest server (-qtest) that takes a character device.  This is what
allows the external process to send CPU events to the device model.

qtest uses a simple line based protocol to send the events.  Documentation of
that protocol is in qtest.c.

I considered reusing the monitor for this job.  Adding interrupts would be a bit
difficult.  In addition, logging would also be difficult.

qtest has extensive logging support.  All protocol commands are logged with
time stamps using a new command line option (-qtest-log).  Logging is important
since ultimately, this is a feature for debugging.

Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 Makefile.objs   |    2 +
 cpu-exec.c      |    1 +
 cpus.c          |   62 +++++++++-
 qemu-options.hx |    8 ++
 qtest.c         |  354 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 qtest.h         |   35 ++++++
 scripts/qtest   |    5 +
 vl.c            |   10 ++-
 8 files changed, 473 insertions(+), 4 deletions(-)
 create mode 100644 qtest.c
 create mode 100644 qtest.h
 create mode 100755 scripts/qtest

diff --git a/Makefile.objs b/Makefile.objs
index 226b01d..e9842b0 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -322,6 +322,8 @@ hw-obj-$(CONFIG_DP8393X) += dp8393x.o
 hw-obj-$(CONFIG_DS1225Y) += ds1225y.o
 hw-obj-$(CONFIG_MIPSNET) += mipsnet.o
 
+hw-obj-y += qtest.o
+
 # Sound
 sound-obj-y =
 sound-obj-$(CONFIG_SB16) += sb16.o
diff --git a/cpu-exec.c b/cpu-exec.c
index 0fa8325..d153f97 100644
--- a/cpu-exec.c
+++ b/cpu-exec.c
@@ -21,6 +21,7 @@
 #include "disas.h"
 #include "tcg.h"
 #include "qemu-barrier.h"
+#include "qtest.h"
 
 int tb_invalidated_flag;
 
diff --git a/cpus.c b/cpus.c
index 25ba621..010047e 100644
--- a/cpus.c
+++ b/cpus.c
@@ -741,6 +741,48 @@ static void *qemu_kvm_cpu_thread_fn(void *arg)
     return NULL;
 }
 
+static void *qemu_dummy_cpu_thread_fn(void *arg)
+{
+#ifdef _WIN32
+    fprintf(stderr, "qtest is not supported under Windows\n");
+    exit(1);
+#else
+    CPUArchState *env = arg;
+    sigset_t waitset;
+    int r;
+
+    qemu_mutex_lock_iothread();
+    qemu_thread_get_self(env->thread);
+    env->thread_id = qemu_get_thread_id();
+
+    sigemptyset(&waitset);
+    sigaddset(&waitset, SIG_IPI);
+
+    /* signal CPU creation */
+    env->created = 1;
+    qemu_cond_signal(&qemu_cpu_cond);
+
+    cpu_single_env = env;
+    while (1) {
+        cpu_single_env = NULL;
+        qemu_mutex_unlock_iothread();
+        do {
+            int sig;
+            r = sigwait(&waitset, &sig);
+        } while (r == -1 && (errno == EAGAIN || errno == EINTR));
+        if (r == -1) {
+            perror("sigwait");
+            exit(1);
+        }
+        qemu_mutex_lock_iothread();
+        cpu_single_env = env;
+        qemu_wait_io_event_common(env);
+    }
+
+    return NULL;
+#endif
+}
+
 static void tcg_exec_all(void);
 
 static void *qemu_tcg_cpu_thread_fn(void *arg)
@@ -803,7 +845,7 @@ void qemu_cpu_kick(void *_env)
     CPUArchState *env = _env;
 
     qemu_cond_broadcast(env->halt_cond);
-    if (kvm_enabled() && !env->thread_kicked) {
+    if (!tcg_enabled() && !env->thread_kicked) {
         qemu_cpu_kick_thread(env);
         env->thread_kicked = true;
     }
@@ -832,7 +874,7 @@ int qemu_cpu_is_self(void *_env)
 
 void qemu_mutex_lock_iothread(void)
 {
-    if (kvm_enabled()) {
+    if (!tcg_enabled()) {
         qemu_mutex_lock(&qemu_global_mutex);
     } else {
         iothread_requesting_mutex = true;
@@ -947,6 +989,18 @@ static void qemu_kvm_start_vcpu(CPUArchState *env)
     }
 }
 
+static void qemu_dummy_start_vcpu(CPUArchState *env)
+{
+    env->thread = g_malloc0(sizeof(QemuThread));
+    env->halt_cond = g_malloc0(sizeof(QemuCond));
+    qemu_cond_init(env->halt_cond);
+    qemu_thread_create(env->thread, qemu_dummy_cpu_thread_fn, env,
+                       QEMU_THREAD_JOINABLE);
+    while (env->created == 0) {
+        qemu_cond_wait(&qemu_cpu_cond, &qemu_global_mutex);
+    }
+}
+
 void qemu_init_vcpu(void *_env)
 {
     CPUArchState *env = _env;
@@ -956,8 +1010,10 @@ void qemu_init_vcpu(void *_env)
     env->stopped = 1;
     if (kvm_enabled()) {
         qemu_kvm_start_vcpu(env);
-    } else {
+    } else if (tcg_enabled()) {
         qemu_tcg_init_vcpu(env);
+    } else {
+        qemu_dummy_start_vcpu(env);
     }
 }
 
diff --git a/qemu-options.hx b/qemu-options.hx
index 662f571..fe88939 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -2715,6 +2715,14 @@ the @var{simple} tracing backend.
 @end table
 ETEXI
 
+DEF("qtest", HAS_ARG, QEMU_OPTION_qtest,
+    "-qtest CHR      specify tracing options\n",
+    QEMU_ARCH_ALL)
+
+DEF("qtest-log", HAS_ARG, QEMU_OPTION_qtest_log,
+    "-qtest-log LOG  specify tracing options\n",
+    QEMU_ARCH_ALL)
+
 HXCOMM This is the last statement. Insert new options before this line!
 STEXI
 @end table
diff --git a/qtest.c b/qtest.c
new file mode 100644
index 0000000..46ebda1
--- /dev/null
+++ b/qtest.c
@@ -0,0 +1,354 @@
+/*
+ * Test Server
+ *
+ * Copyright IBM, Corp. 2011
+ *
+ * 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 "qtest.h"
+#include "qemu-char.h"
+#include "ioport.h"
+#include "memory.h"
+#include "hw/irq.h"
+#include "sysemu.h"
+
+#define MAX_IRQ 256
+
+const char *qtest_chrdev;
+const char *qtest_log;
+int qtest_allowed = 0;
+
+static FILE *qtest_log_fp;
+static CharDriverState *qtest_chr;
+static GString *inbuf;
+static int irq_levels[MAX_IRQ];
+static struct timeval start_time;
+static bool qtest_opened;
+
+#define FMT_timeval "%" PRId64 ".%06" PRId64
+
+/**
+ * QTest Protocol
+ *
+ * Line based protocol, request/response based.  Server can send async messages
+ * so clients should always handle many async messages before the response
+ * comes in.
+ *
+ * Valid requests
+ *
+ *  > outb ADDR VALUE
+ *  < OK
+ *
+ *  > outw ADDR VALUE
+ *  < OK
+ *
+ *  > outl ADDR VALUE
+ *  < OK
+ *
+ *  > inb ADDR
+ *  < OK VALUE
+ *
+ *  > inw ADDR
+ *  < OK VALUE
+ *
+ *  > inl ADDR
+ *  < OK VALUE
+ *
+ *  > read ADDR SIZE
+ *  < OK DATA
+ *
+ *  > write ADDR SIZE DATA
+ *  < OK
+ *
+ * Valid async messages:
+ *
+ *  IRQ raise NUM
+ *  IRQ lower NUM
+ *
+ * ADDR, SIZE, VALUE are all integers parsed with strtoul() with a base of 0.
+ *
+ * DATA is an arbitrarily long hex number prefixed with '0x'.  If it's smaller
+ * than the expected size, the value will be zero filled at the end of the data
+ * sequence.
+ *
+ * NUM is an IRQ number.
+ */
+
+static int hex2nib(char ch)
+{
+    if (ch >= '0' && ch <= '9') {
+        return ch - '0';
+    } else if (ch >= 'a' && ch <= 'f') {
+        return 10 + (ch - 'a');
+    } else if (ch >= 'A' && ch <= 'F') {
+        return 10 + (ch - 'a');
+    } else {
+        return -1;
+    }
+}
+
+static void qtest_get_time(struct timeval *tv)
+{
+    gettimeofday(tv, NULL);
+    tv->tv_sec -= start_time.tv_sec;
+    tv->tv_usec -= start_time.tv_usec;
+    if (tv->tv_usec < 0) {
+        tv->tv_usec += 1000000;
+        tv->tv_sec -= 1;
+    }
+}
+
+static void qtest_send_prefix(CharDriverState *chr)
+{
+    struct timeval tv;
+
+    if (!qtest_log_fp || !qtest_opened) {
+        return;
+    }
+
+    qtest_get_time(&tv);
+    fprintf(qtest_log_fp, "[S +" FMT_timeval "] ",
+            tv.tv_sec, tv.tv_usec);
+}
+
+static void qtest_send(CharDriverState *chr, const char *fmt, ...)
+{
+    va_list ap;
+    char buffer[1024];
+    size_t len;
+
+    va_start(ap, fmt);
+    len = vsnprintf(buffer, sizeof(buffer), fmt, ap);
+    va_end(ap);
+
+    qemu_chr_fe_write(chr, (uint8_t *)buffer, len);
+    if (qtest_log_fp && qtest_opened) {
+        fprintf(qtest_log_fp, "%s", buffer);
+    }
+}
+
+static void qtest_process_command(CharDriverState *chr, gchar **words)
+{
+    const gchar *command;
+
+    g_assert(words);
+
+    command = words[0];
+
+    if (qtest_log_fp) {
+        struct timeval tv;
+        int i;
+
+        qtest_get_time(&tv);
+        fprintf(qtest_log_fp, "[R +" FMT_timeval "]",
+                tv.tv_sec, tv.tv_usec);
+        for (i = 0; words[i]; i++) {
+            fprintf(qtest_log_fp, " %s", words[i]);
+        }
+        fprintf(qtest_log_fp, "\n");
+    }
+
+    g_assert(command);
+    if (strcmp(words[0], "outb") == 0 ||
+        strcmp(words[0], "outw") == 0 ||
+        strcmp(words[0], "outl") == 0) {
+        uint16_t addr;
+        uint32_t value;
+
+        g_assert(words[1] && words[2]);
+        addr = strtol(words[1], NULL, 0);
+        value = strtol(words[2], NULL, 0);
+
+        if (words[0][3] == 'b') {
+            cpu_outb(addr, value);
+        } else if (words[0][3] == 'w') {
+            cpu_outw(addr, value);
+        } else if (words[0][3] == 'l') {
+            cpu_outl(addr, value);
+        }
+        qtest_send_prefix(chr);
+        qtest_send(chr, "OK\n");
+    } else if (strcmp(words[0], "inb") == 0 ||
+        strcmp(words[0], "inw") == 0 ||
+        strcmp(words[0], "inl") == 0) {
+        uint16_t addr;
+        uint32_t value = -1U;
+
+        g_assert(words[1]);
+        addr = strtol(words[1], NULL, 0);
+
+        if (words[0][2] == 'b') {
+            value = cpu_inb(addr);
+        } else if (words[0][2] == 'w') {
+            value = cpu_inw(addr);
+        } else if (words[0][2] == 'l') {
+            value = cpu_inl(addr);
+        }
+        qtest_send_prefix(chr);
+        qtest_send(chr, "OK 0x%04x\n", value);
+    } else if (strcmp(words[0], "read") == 0) {
+        uint64_t addr, len, i;
+        uint8_t *data;
+
+        g_assert(words[1] && words[2]);
+        addr = strtoul(words[1], NULL, 0);
+        len = strtoul(words[2], NULL, 0);
+
+        data = g_malloc(len);
+        cpu_physical_memory_read(addr, data, len);
+
+        qtest_send_prefix(chr);
+        qtest_send(chr, "OK 0x");
+        for (i = 0; i < len; i++) {
+            qtest_send(chr, "%02x", data[i]);
+        }
+        qtest_send(chr, "\n");
+
+        g_free(data);
+    } else if (strcmp(words[0], "write") == 0) {
+        uint64_t addr, len, i;
+        uint8_t *data;
+        size_t data_len;
+
+        g_assert(words[1] && words[2] && words[3]);
+        addr = strtoul(words[1], NULL, 0);
+        len = strtoul(words[2], NULL, 0);
+
+        data_len = strlen(words[3]);
+        if (data_len < 3) {
+            qtest_send(chr, "ERR invalid argument size\n");
+            return;
+        }
+
+        data = g_malloc(len);
+        for (i = 0; i < len; i++) {
+            if ((i * 2 + 4) <= data_len) {
+                data[i] = hex2nib(words[3][i * 2 + 2]) << 4;
+                data[i] |= hex2nib(words[3][i * 2 + 3]);
+            } else {
+                data[i] = 0;
+            }
+        }
+        cpu_physical_memory_write(addr, data, len);
+        g_free(data);
+
+        qtest_send_prefix(chr);
+        qtest_send(chr, "OK\n");
+    } else {
+        qtest_send_prefix(chr);
+        qtest_send(chr, "FAIL Unknown command `%s'\n", words[0]);
+    }
+}
+
+static void qtest_process_inbuf(CharDriverState *chr, GString *inbuf)
+{
+    char *end;
+
+    while ((end = strchr(inbuf->str, '\n')) != NULL) {
+        size_t offset;
+        GString *cmd;
+        gchar **words;
+
+        offset = end - inbuf->str;
+
+        cmd = g_string_new_len(inbuf->str, offset);
+        g_string_erase(inbuf, 0, offset + 1);
+
+        words = g_strsplit(cmd->str, " ", 0);
+        qtest_process_command(chr, words);
+        g_strfreev(words);
+
+        g_string_free(cmd, TRUE);
+    }
+}
+
+static void qtest_read(void *opaque, const uint8_t *buf, int size)
+{
+    CharDriverState *chr = opaque;
+
+    g_string_append_len(inbuf, (const gchar *)buf, size);
+    qtest_process_inbuf(chr, inbuf);
+}
+
+static int qtest_can_read(void *opaque)
+{
+    return 1024;
+}
+
+static void qtest_event(void *opaque, int event)
+{
+    int i;
+
+    switch (event) {
+    case CHR_EVENT_OPENED:
+        qemu_system_reset(false);
+        for (i = 0; i < ARRAY_SIZE(irq_levels); i++) {
+            irq_levels[i] = 0;
+        }
+        gettimeofday(&start_time, NULL);
+        qtest_opened = true;
+        if (qtest_log_fp) {
+            fprintf(qtest_log_fp, "[I " FMT_timeval "] OPENED\n",
+                    start_time.tv_sec, start_time.tv_usec);
+        }
+        break;
+    case CHR_EVENT_CLOSED:
+        qtest_opened = false;
+        if (qtest_log_fp) {
+            struct timeval tv;
+            qtest_get_time(&tv);
+            fprintf(qtest_log_fp, "[I +" FMT_timeval "] CLOSED\n",
+                    tv.tv_sec, tv.tv_usec);
+        }
+        break;
+    default:
+        break;
+    }
+}
+
+static void qtest_set_irq(void *opaque, int irq, int level)
+{
+    CharDriverState *chr = qtest_chr;
+    bool changed;
+
+    changed = (irq_levels[irq] != level);
+    irq_levels[irq] = level;
+
+    if (changed) {
+        qtest_send_prefix(chr);
+        qtest_send(chr, "IRQ %s %d\n",
+                   level ? "raise" : "lower", irq);
+    }
+}
+
+int qtest_init(void)
+{
+    CharDriverState *chr;
+
+    g_assert(qtest_chrdev != NULL);
+
+    chr = qemu_chr_new("qtest", qtest_chrdev, NULL);
+
+    qemu_chr_add_handlers(chr, qtest_can_read, qtest_read, qtest_event, chr);
+    qemu_chr_fe_set_echo(chr, true);
+
+    inbuf = g_string_new("");
+
+    if (qtest_log) {
+        if (strcmp(qtest_log, "none") != 0) {
+            qtest_log_fp = fopen(qtest_log, "w+");
+        }
+    } else {
+        qtest_log_fp = stderr;
+    }
+
+    qtest_chr = chr;
+
+    return 0;
+}
diff --git a/qtest.h b/qtest.h
new file mode 100644
index 0000000..1478343
--- /dev/null
+++ b/qtest.h
@@ -0,0 +1,35 @@
+/*
+ * Test Server
+ *
+ * Copyright IBM, Corp. 2011
+ *
+ * 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 QTEST_H
+#define QTEST_H
+
+#include "qemu-common.h"
+
+extern int qtest_allowed;
+extern const char *qtest_chrdev;
+extern const char *qtest_log;
+
+static inline bool qtest_enabled(void)
+{
+    return qtest_allowed;
+}
+
+static inline int qtest_available(void)
+{
+    return 1;
+}
+
+int qtest_init(void);
+
+#endif
diff --git a/scripts/qtest b/scripts/qtest
new file mode 100755
index 0000000..4ef6c1c
--- /dev/null
+++ b/scripts/qtest
@@ -0,0 +1,5 @@
+#!/bin/sh
+
+export QTEST_QEMU_BINARY=$1
+shift
+"$@"
diff --git a/vl.c b/vl.c
index 0fccf50..e575401 100644
--- a/vl.c
+++ b/vl.c
@@ -152,6 +152,7 @@ int main(int argc, char **argv)
 #ifdef CONFIG_VIRTFS
 #include "fsdev/qemu-fsdev.h"
 #endif
+#include "qtest.h"
 
 #include "disas.h"
 
@@ -1312,7 +1313,7 @@ int qemu_shutdown_requested(void)
 
 void qemu_kill_report(void)
 {
-    if (shutdown_signal != -1) {
+    if (!qtest_enabled() && shutdown_signal != -1) {
         fprintf(stderr, "qemu: terminating on signal %d", shutdown_signal);
         if (shutdown_pid == 0) {
             /* This happens for eg ^C at the terminal, so it's worth
@@ -2098,6 +2099,7 @@ static struct {
     { "tcg", "tcg", tcg_available, tcg_init, &tcg_allowed },
     { "xen", "Xen", xen_available, xen_init, &xen_allowed },
     { "kvm", "KVM", kvm_available, kvm_init, &kvm_allowed },
+    { "qtest", "QTest", qtest_available, qtest_init, &qtest_allowed },
 };
 
 static int configure_accelerator(void)
@@ -3181,6 +3183,12 @@ int main(int argc, char **argv, char **envp)
                     fclose(fp);
                     break;
                 }
+            case QEMU_OPTION_qtest:
+                qtest_chrdev = optarg;
+                break;
+            case QEMU_OPTION_qtest_log:
+                qtest_log = optarg;
+                break;
             default:
                 os_parse_cmd_args(popt->index, optarg);
             }
-- 
1.7.9.1

^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [Qemu-devel] [PATCH v4 3/7] qtest: IRQ interception infrastructure
  2012-03-28 13:42 [Qemu-devel] [PATCH v4 0/7] new test infrastructure + qtest Paolo Bonzini
  2012-03-28 13:42 ` [Qemu-devel] [PATCH v4 1/7] test makefile overhaul Paolo Bonzini
  2012-03-28 13:42 ` [Qemu-devel] [PATCH v4 2/7] qtest: add test framework Paolo Bonzini
@ 2012-03-28 13:42 ` Paolo Bonzini
  2012-03-28 13:42 ` [Qemu-devel] [PATCH v4 4/7] qtest: add clock management Paolo Bonzini
                   ` (5 subsequent siblings)
  8 siblings, 0 replies; 21+ messages in thread
From: Paolo Bonzini @ 2012-03-28 13:42 UTC (permalink / raw)
  To: qemu-devel; +Cc: Anthony Liguori

Since /i440fx/piix3 is being removed from the composition tree, the
IO-APIC is placed under /i440fx.  This is wrong and should be changed
as soon as the /i440fx/piix3 path is put back.

Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
---
 hw/irq.c     |   17 +++++++++++
 hw/irq.h     |    5 +++
 hw/pc_piix.c |    5 ++-
 qtest.c      |   92 ++++++++++++++++++++++++++++++++++++++++++---------------
 4 files changed, 94 insertions(+), 25 deletions(-)

diff --git a/hw/irq.c b/hw/irq.c
index 62f766e..d413a0b 100644
--- a/hw/irq.c
+++ b/hw/irq.c
@@ -104,3 +104,20 @@ qemu_irq *qemu_irq_proxy(qemu_irq **target, int n)
 {
     return qemu_allocate_irqs(proxy_irq_handler, target, n);
 }
+
+void qemu_irq_intercept_in(qemu_irq *gpio_in, qemu_irq_handler handler, int n)
+{
+    int i;
+    qemu_irq *old_irqs = qemu_allocate_irqs(NULL, NULL, n);
+    for (i = 0; i < n; i++) {
+        *old_irqs[i] = *gpio_in[i];
+        gpio_in[i]->handler = handler;
+        gpio_in[i]->opaque = old_irqs;
+    }
+}
+
+void qemu_irq_intercept_out(qemu_irq **gpio_out, qemu_irq_handler handler, int n)
+{
+    qemu_irq *old_irqs = *gpio_out;
+    *gpio_out = qemu_allocate_irqs(handler, old_irqs, n);
+}
diff --git a/hw/irq.h b/hw/irq.h
index 64da2fd..56c55f0 100644
--- a/hw/irq.h
+++ b/hw/irq.h
@@ -38,4 +38,9 @@ qemu_irq qemu_irq_split(qemu_irq irq1, qemu_irq irq2);
  */
 qemu_irq *qemu_irq_proxy(qemu_irq **target, int n);
 
+/* For internal use in qtest.  Similar to qemu_irq_split, but operating
+   on an existing vector of qemu_irq.  */
+void qemu_irq_intercept_in(qemu_irq *gpio_in, qemu_irq_handler handler, int n);
+void qemu_irq_intercept_out(qemu_irq **gpio_out, qemu_irq_handler handler, int n);
+
 #endif
diff --git a/hw/pc_piix.c b/hw/pc_piix.c
index 3f99f9a..a5f9551 100644
--- a/hw/pc_piix.c
+++ b/hw/pc_piix.c
@@ -107,6 +107,9 @@ static void ioapic_init(GSIState *gsi_state)
     } else {
         dev = qdev_create(NULL, "ioapic");
     }
+    /* FIXME: this should be under the piix3.  */
+    object_property_add_child(object_resolve_path("i440fx", NULL),
+                              "ioapic", OBJECT(dev), NULL);
     qdev_init_nofail(dev);
     d = sysbus_from_qdev(dev);
     sysbus_mmio_map(d, 0, 0xfec00000);
diff --git a/qtest.c b/qtest.c
index 46ebda1..a1eca49 100644
--- a/qtest.c
+++ b/qtest.c
@@ -12,6 +12,7 @@
  */
 
 #include "qtest.h"
+#include "hw/qdev.h"
 #include "qemu-char.h"
 #include "ioport.h"
 #include "memory.h"
@@ -24,6 +25,7 @@ const char *qtest_chrdev;
 const char *qtest_log;
 int qtest_allowed = 0;
 
+static DeviceState *irq_intercept_dev;
 static FILE *qtest_log_fp;
 static CharDriverState *qtest_chr;
 static GString *inbuf;
@@ -66,18 +68,30 @@ static bool qtest_opened;
  *  > write ADDR SIZE DATA
  *  < OK
  *
- * Valid async messages:
- *
- *  IRQ raise NUM
- *  IRQ lower NUM
- *
  * ADDR, SIZE, VALUE are all integers parsed with strtoul() with a base of 0.
  *
  * DATA is an arbitrarily long hex number prefixed with '0x'.  If it's smaller
  * than the expected size, the value will be zero filled at the end of the data
  * sequence.
  *
- * NUM is an IRQ number.
+ * IRQ management:
+ *
+ *  > irq_intercept_in QOM-PATH
+ *  < OK
+ *
+ *  > irq_intercept_out QOM-PATH
+ *  < OK
+ *
+ * Attach to the gpio-in (resp. gpio-out) pins exported by the device at
+ * QOM-PATH.  When the pin is triggered, one of the following async messages
+ * will be printed to the qtest stream:
+ *
+ *  IRQ raise NUM
+ *  IRQ lower NUM
+ *
+ * where NUM is an IRQ number.  For the PC, interrupts can be intercepted
+ * simply with "irq_intercept_in ioapic" (note that IRQ0 comes out with
+ * NUM=0 even though it is remapped to GSI 2).
  */
 
 static int hex2nib(char ch)
@@ -133,6 +147,20 @@ static void qtest_send(CharDriverState *chr, const char *fmt, ...)
     }
 }
 
+static void qtest_irq_handler(void *opaque, int n, int level)
+{
+    qemu_irq *old_irqs = opaque;
+    qemu_set_irq(old_irqs[n], level);
+
+    if (irq_levels[n] != level) {
+        CharDriverState *chr = qtest_chr;
+        irq_levels[n] = level;
+        qtest_send_prefix(chr);
+        qtest_send(chr, "IRQ %s %d\n",
+                   level ? "raise" : "lower", n);
+    }
+}
+
 static void qtest_process_command(CharDriverState *chr, gchar **words)
 {
     const gchar *command;
@@ -155,9 +183,40 @@ static void qtest_process_command(CharDriverState *chr, gchar **words)
     }
 
     g_assert(command);
-    if (strcmp(words[0], "outb") == 0 ||
-        strcmp(words[0], "outw") == 0 ||
-        strcmp(words[0], "outl") == 0) {
+    if (strcmp(words[0], "irq_intercept_out") == 0
+        || strcmp(words[0], "irq_intercept_in") == 0) {
+	DeviceState *dev;
+
+        g_assert(words[1]);
+        dev = DEVICE(object_resolve_path(words[1], NULL));
+        if (!dev) {
+            qtest_send_prefix(chr);
+            qtest_send(chr, "FAIL Unknown device\n");
+	    return;
+        }
+
+        if (irq_intercept_dev) {
+            qtest_send_prefix(chr);
+            if (irq_intercept_dev != dev) {
+                qtest_send(chr, "FAIL IRQ intercept already enabled\n");
+            } else {
+                qtest_send(chr, "OK\n");
+            }
+	    return;
+        }
+
+        if (words[0][14] == 'o') {
+            qemu_irq_intercept_out(&dev->gpio_out, qtest_irq_handler, dev->num_gpio_out);
+        } else {
+            qemu_irq_intercept_in(dev->gpio_in, qtest_irq_handler, dev->num_gpio_in);
+        }
+        irq_intercept_dev = dev;
+        qtest_send_prefix(chr);
+        qtest_send(chr, "OK\n");
+
+    } else if (strcmp(words[0], "outb") == 0 ||
+               strcmp(words[0], "outw") == 0 ||
+               strcmp(words[0], "outl") == 0) {
         uint16_t addr;
         uint32_t value;
 
@@ -312,21 +371,6 @@ static void qtest_event(void *opaque, int event)
     }
 }
 
-static void qtest_set_irq(void *opaque, int irq, int level)
-{
-    CharDriverState *chr = qtest_chr;
-    bool changed;
-
-    changed = (irq_levels[irq] != level);
-    irq_levels[irq] = level;
-
-    if (changed) {
-        qtest_send_prefix(chr);
-        qtest_send(chr, "IRQ %s %d\n",
-                   level ? "raise" : "lower", irq);
-    }
-}
-
 int qtest_init(void)
 {
     CharDriverState *chr;
-- 
1.7.9.1

^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [Qemu-devel] [PATCH v4 4/7] qtest: add clock management
  2012-03-28 13:42 [Qemu-devel] [PATCH v4 0/7] new test infrastructure + qtest Paolo Bonzini
                   ` (2 preceding siblings ...)
  2012-03-28 13:42 ` [Qemu-devel] [PATCH v4 3/7] qtest: IRQ interception infrastructure Paolo Bonzini
@ 2012-03-28 13:42 ` Paolo Bonzini
  2012-03-28 13:42 ` [Qemu-devel] [PATCH v4 5/7] qtest: add C version of test infrastructure Paolo Bonzini
                   ` (4 subsequent siblings)
  8 siblings, 0 replies; 21+ messages in thread
From: Paolo Bonzini @ 2012-03-28 13:42 UTC (permalink / raw)
  To: qemu-devel; +Cc: Anthony Liguori

This patch combines qtest and -icount together to turn the vm_clock
into a source that can be fully managed by the client.  To this end new
commands clock_step and clock_set are added.  Hooking them with libqtest
is left as an exercise to the reader.

Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
---
 cpus.c       |   20 ++++++++++++++++++++
 cpus.h       |    2 ++
 qemu-timer.c |    2 +-
 qemu-timer.h |    1 +
 qtest.c      |   45 +++++++++++++++++++++++++++++++++++++++++++++
 5 files changed, 69 insertions(+), 1 deletions(-)

diff --git a/cpus.c b/cpus.c
index 010047e..107b2ca 100644
--- a/cpus.c
+++ b/cpus.c
@@ -34,6 +34,7 @@
 
 #include "qemu-thread.h"
 #include "cpus.h"
+#include "qtest.h"
 #include "main-loop.h"
 
 #ifndef _WIN32
@@ -238,6 +239,20 @@ static void icount_warp_rt(void *opaque)
     vm_clock_warp_start = -1;
 }
 
+void qtest_clock_warp(int64_t dest)
+{
+    int64_t clock = qemu_get_clock_ns(vm_clock);
+    assert(qtest_enabled());
+    while (clock < dest) {
+        int64_t deadline = qemu_clock_deadline(vm_clock);
+        int64_t warp = MIN(dest - clock, deadline);
+        qemu_icount_bias += warp;
+        qemu_run_timers(vm_clock);
+        clock = qemu_get_clock_ns(vm_clock);
+    }
+    qemu_notify_event();
+}
+
 void qemu_clock_warp(QEMUClock *clock)
 {
     int64_t deadline;
@@ -264,6 +279,11 @@ void qemu_clock_warp(QEMUClock *clock)
         return;
     }
 
+    if (qtest_enabled()) {
+        /* When testing, qtest commands advance icount.  */
+	return;
+    }
+
     vm_clock_warp_start = qemu_get_clock_ns(rt_clock);
     deadline = qemu_clock_deadline(vm_clock);
     if (deadline > 0) {
diff --git a/cpus.h b/cpus.h
index 4ea2fe2..81bd817 100644
--- a/cpus.h
+++ b/cpus.h
@@ -11,6 +11,8 @@ void cpu_synchronize_all_states(void);
 void cpu_synchronize_all_post_reset(void);
 void cpu_synchronize_all_post_init(void);
 
+void qtest_clock_warp(int64_t dest);
+
 /* vl.c */
 extern int smp_cores;
 extern int smp_threads;
diff --git a/qemu-timer.c b/qemu-timer.c
index d7f56e5..80bcc56 100644
--- a/qemu-timer.c
+++ b/qemu-timer.c
@@ -397,7 +397,7 @@ int qemu_timer_expired(QEMUTimer *timer_head, int64_t current_time)
     return qemu_timer_expired_ns(timer_head, current_time * timer_head->scale);
 }
 
-static void qemu_run_timers(QEMUClock *clock)
+void qemu_run_timers(QEMUClock *clock)
 {
     QEMUTimer **ptimer_head, *ts;
     int64_t current_time;
diff --git a/qemu-timer.h b/qemu-timer.h
index de17f3b..661bbe7 100644
--- a/qemu-timer.h
+++ b/qemu-timer.h
@@ -59,6 +59,7 @@ int qemu_timer_pending(QEMUTimer *ts);
 int qemu_timer_expired(QEMUTimer *timer_head, int64_t current_time);
 uint64_t qemu_timer_expire_time_ns(QEMUTimer *ts);
 
+void qemu_run_timers(QEMUClock *clock);
 void qemu_run_all_timers(void);
 int qemu_alarm_pending(void);
 void configure_alarms(char const *opt);
diff --git a/qtest.c b/qtest.c
index a1eca49..53e2b79 100644
--- a/qtest.c
+++ b/qtest.c
@@ -18,6 +18,7 @@
 #include "memory.h"
 #include "hw/irq.h"
 #include "sysemu.h"
+#include "cpus.h"
 
 #define MAX_IRQ 256
 
@@ -44,6 +45,30 @@ static bool qtest_opened;
  *
  * Valid requests
  *
+ * Clock management:
+ *
+ * The qtest client is completely in charge of the vm_clock.  qtest commands
+ * let you adjust the value of the clock (monotonically).  All the commands
+ * return the current value of the clock in nanoseconds.
+ *
+ *  > clock_step
+ *  < OK VALUE
+ *
+ *     Advance the clock to the next deadline.  Useful when waiting for
+ *     asynchronous events.
+ *
+ *  > clock_step NS
+ *  < OK VALUE
+ *
+ *     Advance the clock by NS nanoseconds.
+ *
+ *  > clock_set NS
+ *  < OK VALUE
+ *
+ *     Advance the clock to NS nanoseconds (do nothing if it's already past).
+ *
+ * PIO and memory access:
+ *
  *  > outb ADDR VALUE
  *  < OK
  *
@@ -299,6 +324,25 @@ static void qtest_process_command(CharDriverState *chr, gchar **words)
 
         qtest_send_prefix(chr);
         qtest_send(chr, "OK\n");
+    } else if (strcmp(words[0], "clock_step") == 0) {
+        int64_t ns;
+
+        if (words[1]) {
+            ns = strtoll(words[1], NULL, 0);
+        } else {
+            ns = qemu_clock_deadline(vm_clock);
+        }
+        qtest_clock_warp(qemu_get_clock_ns(vm_clock) + ns);
+        qtest_send_prefix(chr);
+        qtest_send(chr, "OK %"PRIi64"\n", (int64_t)qemu_get_clock_ns(vm_clock));
+    } else if (strcmp(words[0], "clock_set") == 0) {
+        int64_t ns;
+
+        g_assert(words[1]);
+        ns = strtoll(words[1], NULL, 0);
+        qtest_clock_warp(ns);
+        qtest_send_prefix(chr);
+        qtest_send(chr, "OK %"PRIi64"\n", (int64_t)qemu_get_clock_ns(vm_clock));
     } else {
         qtest_send_prefix(chr);
         qtest_send(chr, "FAIL Unknown command `%s'\n", words[0]);
@@ -377,6 +421,7 @@ int qtest_init(void)
 
     g_assert(qtest_chrdev != NULL);
 
+    configure_icount("0");
     chr = qemu_chr_new("qtest", qtest_chrdev, NULL);
 
     qemu_chr_add_handlers(chr, qtest_can_read, qtest_read, qtest_event, chr);
-- 
1.7.9.1

^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [Qemu-devel] [PATCH v4 5/7] qtest: add C version of test infrastructure
  2012-03-28 13:42 [Qemu-devel] [PATCH v4 0/7] new test infrastructure + qtest Paolo Bonzini
                   ` (3 preceding siblings ...)
  2012-03-28 13:42 ` [Qemu-devel] [PATCH v4 4/7] qtest: add clock management Paolo Bonzini
@ 2012-03-28 13:42 ` Paolo Bonzini
  2012-03-28 13:42 ` [Qemu-devel] [PATCH v4 6/7] rtc: split out macros into a header file and use in test case Paolo Bonzini
                   ` (3 subsequent siblings)
  8 siblings, 0 replies; 21+ messages in thread
From: Paolo Bonzini @ 2012-03-28 13:42 UTC (permalink / raw)
  To: qemu-devel; +Cc: Anthony Liguori

From: Anthony Liguori <aliguori@us.ibm.com>

This also includes a qtest wrapper script to make it easier to launch qtest
tests directly.

Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 osdep.h          |    2 +
 qemu-common.h    |    1 -
 tests/Makefile   |   26 ++++-
 tests/libqtest.c |  385 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 tests/libqtest.h |  333 ++++++++++++++++++++++++++++++++++++++++++++++
 5 files changed, 743 insertions(+), 4 deletions(-)
 create mode 100644 tests/libqtest.c
 create mode 100644 tests/libqtest.h

diff --git a/osdep.h b/osdep.h
index 156666e..428285c 100644
--- a/osdep.h
+++ b/osdep.h
@@ -140,4 +140,6 @@ static inline void qemu_timersub(const struct timeval *val1,
 #define qemu_timersub timersub
 #endif
 
+void qemu_set_cloexec(int fd);
+
 #endif
diff --git a/qemu-common.h b/qemu-common.h
index c9e96a8..4647dd9 100644
--- a/qemu-common.h
+++ b/qemu-common.h
@@ -190,7 +190,6 @@ ssize_t qemu_send_full(int fd, const void *buf, size_t count, int flags)
     QEMU_WARN_UNUSED_RESULT;
 ssize_t qemu_recv_full(int fd, void *buf, size_t count, int flags)
     QEMU_WARN_UNUSED_RESULT;
-void qemu_set_cloexec(int fd);
 
 #ifndef _WIN32
 int qemu_eventfd(int pipefd[2]);
diff --git a/tests/Makefile b/tests/Makefile
index 249f972..99ca308 100644
--- a/tests/Makefile
+++ b/tests/Makefile
@@ -58,11 +58,22 @@ tests/test-qmp-input-visitor$(EXESUF): tests/test-qmp-input-visitor.o $(test-qap
 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)
 
+# QTest rules
+
+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)
+$(check-qtest-y): $(qtest-obj-y)
+
 .PHONY: check-help
 check-help:
 	@echo "Regression testing targets:"
 	@echo
 	@echo " make check                Run all tests"
+	@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-block          Run block tests"
 	@echo " make check-report.html    Generates an HTML test report"
@@ -81,18 +91,27 @@ GTESTER_OPTIONS = -k $(if $(V),--verbose,-q)
 
 # gtester tests, possibly with verbose output
 
+.PHONY: $(patsubst %, check-qtest-%, $(QTEST_TARGETS))
+$(patsubst %, check-qtest-%, $(QTEST_TARGETS)): check-qtest-%: $(check-qtest-y)
+	$(call quiet-command,QTEST_QEMU_BINARY=$*-softmmu/qemu-system-$* \
+		gtester $(GTESTER_OPTIONS) -m=$(SPEED) $(check-qtest-$*-y),"GTESTER $@")
+
 .PHONY: $(patsubst %, check-%, $(check-unit-y))
 $(patsubst %, check-%, $(check-unit-y)): check-%: %
 	$(call quiet-command,gtester $(GTESTER_OPTIONS) -m=$(SPEED) $*,"GTESTER $*")
 
 # gtester tests with XML output
 
+$(patsubst %, check-report-qtest-%.xml, $(QTEST_TARGETS)): check-report-qtest-%.xml: $(check-qtest-y)
+	$(call quiet-command,QTEST_QEMU_BINARY=$*-softmmu/qemu-system-$* \
+	  gtester -q $(GTESTER_OPTIONS) -o $@ -m=$(SPEED) $(check-qtest-$*-y),"GTESTER $@")
+
 check-report-unit.xml: $(check-unit-y)
 	$(call quiet-command,gtester -q $(GTESTER_OPTIONS) -o $@ -m=$(SPEED) $^, "GTESTER $@")
 
 # Reports and overall runs
 
-check-report.xml: check-report-unit.xml
+check-report.xml: $(patsubst %,check-report-qtest-%.xml, $(QTEST_TARGETS)) check-report-unit.xml
 	$(call quiet-command,$(SRC_PATH)/scripts/gtester-cat $^ > $@, "  GEN    $@")
 
 check-report.html: check-report.xml
@@ -107,7 +126,8 @@ check-tests/qemu-iotests-quick.sh: tests/qemu-iotests-quick.sh qemu-img$(EXESUF)
 
 # Consolidated targets
 
-.PHONY: check-unit check
+.PHONY: check-qtest check-unit check
+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: check-unit check-qtest
diff --git a/tests/libqtest.c b/tests/libqtest.c
new file mode 100644
index 0000000..2e2b9de
--- /dev/null
+++ b/tests/libqtest.c
@@ -0,0 +1,387 @@
+/*
+ * QTest
+ *
+ * Copyright IBM, Corp. 2012
+ * Copyright Red Hat, Inc. 2012
+ *
+ * Authors:
+ *  Anthony Liguori   <aliguori@us.ibm.com>
+ *  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 <sys/types.h>
+#include <sys/socket.h>
+#include <sys/wait.h>
+#include <sys/un.h>
+#include <inttypes.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+
+#include "osdep.h"
+
+#define MAX_IRQ 256
+
+QTestState *global_qtest;
+
+struct QTestState
+{
+    int fd;
+    bool irq_level[MAX_IRQ];
+    GString *rx;
+    gchar *pid_file;
+};
+
+#define g_assert_no_errno(ret) do { \
+    g_assert_cmpint(ret, !=, -1); \
+} while (0)
+
+QTestState *qtest_init(const char *extra_args)
+{
+    QTestState *s;
+    struct sockaddr_un addr;
+    int sock, ret, i;
+    gchar *socket_path;
+    gchar *pid_file;
+    gchar *command;
+    const char *qemu_binary;
+    pid_t pid;
+    socklen_t addrlen;
+
+    qemu_binary = getenv("QTEST_QEMU_BINARY");
+    g_assert(qemu_binary != NULL);
+
+    socket_path = g_strdup_printf("/tmp/qtest-%d.sock", getpid());
+    pid_file = g_strdup_printf("/tmp/qtest-%d.pid", getpid());
+
+    s = g_malloc(sizeof(*s));
+
+    sock = socket(PF_UNIX, SOCK_STREAM, 0);
+    g_assert_no_errno(sock);
+
+    addr.sun_family = AF_UNIX;
+    snprintf(addr.sun_path, sizeof(addr.sun_path), "%s", socket_path);
+    qemu_set_cloexec(sock);
+
+    do {
+        ret = bind(sock, (struct sockaddr *)&addr, sizeof(addr));
+    } while (ret == -1 && errno == EINTR);
+    g_assert_no_errno(ret);
+    listen(sock, 1);
+
+    pid = fork();
+    if (pid == 0) {
+        command = g_strdup_printf("%s "
+                                  "-qtest unix:%s,nowait "
+                                  "-qtest-log /dev/null "
+                                  "-pidfile %s "
+                                  "-machine accel=qtest "
+                                  "%s", qemu_binary, socket_path,
+                                  pid_file,
+                                  extra_args ?: "");
+
+        ret = system(command);
+        exit(ret);
+        g_free(command);
+    }
+
+    do {
+        ret = accept(sock, (struct sockaddr *)&addr, &addrlen);
+    } while (ret == -1 && errno == EINTR);
+    g_assert_no_errno(ret);
+    close(sock);
+
+    s->fd = ret;
+    s->rx = g_string_new("");
+    s->pid_file = pid_file;
+    for (i = 0; i < MAX_IRQ; i++) {
+        s->irq_level[i] = false;
+    }
+
+    g_free(socket_path);
+
+    return s;
+}
+
+void qtest_quit(QTestState *s)
+{
+    FILE *f;
+    char buffer[1024];
+
+    f = fopen(s->pid_file, "r");
+    if (f) {
+        if (fgets(buffer, sizeof(buffer), f)) {
+            pid_t pid = atoi(buffer);
+            int status = 0;
+
+            kill(pid, SIGTERM);
+            waitpid(pid, &status, 0);
+        }
+
+        fclose(f);
+    }
+}
+
+static void qtest_sendf(QTestState *s, const char *fmt, ...)
+{
+    va_list ap;
+    gchar *str;
+    size_t size, offset;
+
+    va_start(ap, fmt);
+    str = g_strdup_vprintf(fmt, ap);
+    va_end(ap);
+    size = strlen(str);
+
+    offset = 0;
+    while (offset < size) {
+        ssize_t len;
+
+        len = write(s->fd, str + offset, size - offset);
+        if (len == -1 && errno == EINTR) {
+            continue;
+        }
+
+        g_assert_no_errno(len);
+        g_assert_cmpint(len, >, 0);
+
+        offset += len;
+    }
+}
+
+static GString *qtest_recv_line(QTestState *s)
+{
+    GString *line;
+    size_t offset;
+    char *eol;
+
+    while ((eol = strchr(s->rx->str, '\n')) == NULL) {
+        ssize_t len;
+        char buffer[1024];
+
+        len = read(s->fd, buffer, sizeof(buffer));
+        if (len == -1 && errno == EINTR) {
+            continue;
+        }
+
+        if (len == -1 || len == 0) {
+            fprintf(stderr, "Broken pipe\n");
+            exit(1);
+        }
+
+        g_string_append_len(s->rx, buffer, len);
+    }
+
+    offset = eol - s->rx->str;
+    line = g_string_new_len(s->rx->str, offset);
+    g_string_erase(s->rx, 0, offset + 1);
+
+    return line;
+}
+
+static gchar **qtest_rsp(QTestState *s, int expected_args)
+{
+    GString *line;
+    gchar **words;
+    int i;
+
+redo:
+    line = qtest_recv_line(s);
+    words = g_strsplit(line->str, " ", 0);
+    g_string_free(line, TRUE);
+
+    if (strcmp(words[0], "IRQ") == 0) {
+        int irq;
+
+        g_assert(words[1] != NULL);
+        g_assert(words[2] != NULL);
+
+        irq = strtoul(words[2], NULL, 0);
+        g_assert_cmpint(irq, >=, 0);
+        g_assert_cmpint(irq, <, MAX_IRQ);
+
+        if (strcmp(words[1], "raise") == 0) {
+            s->irq_level[irq] = true;
+        } else {
+            s->irq_level[irq] = false;
+        }
+
+        g_strfreev(words);
+        goto redo;
+    }
+
+    g_assert(words[0] != NULL);
+    g_assert_cmpstr(words[0], ==, "OK");
+
+    if (expected_args) {
+        for (i = 0; i < expected_args; i++) {
+            g_assert(words[i] != NULL);
+        }
+    } else {
+        g_strfreev(words);
+    }
+
+    return words;
+}
+
+const char *qtest_get_arch(void)
+{
+    const char *qemu = getenv("QTEST_QEMU_BINARY");
+    const char *end = strrchr(qemu, '/');
+
+    return end + strlen("/qemu-system-");
+}
+
+bool qtest_get_irq(QTestState *s, int num)
+{
+    /* dummy operation in order to make sure irq is up to date */
+    qtest_inb(s, 0);
+
+    return s->irq_level[num];
+}
+
+static int64_t qtest_clock_rsp(QTestState *s)
+{
+    gchar **words;
+    int64_t clock;
+    words = qtest_rsp(s, 2);
+    clock = g_ascii_strtoll(words[1], NULL, 0);
+    g_strfreev(words);
+    return clock;
+}
+
+int64_t qtest_clock_step_next(QTestState *s)
+{
+    qtest_sendf(s, "clock_step\n");
+    return qtest_clock_rsp(s);
+}
+
+int64_t qtest_clock_step(QTestState *s, int64_t step)
+{
+    qtest_sendf(s, "clock_step %"PRIi64"\n", step);
+    return qtest_clock_rsp(s);
+}
+
+int64_t qtest_clock_set(QTestState *s, int64_t val)
+{
+    qtest_sendf(s, "clock_set %"PRIi64"\n", val);
+    return qtest_clock_rsp(s);
+}
+
+void qtest_irq_intercept_out(QTestState *s, const char *qom_path)
+{
+    qtest_sendf(s, "irq_intercept_out %s\n", qom_path);
+    qtest_rsp(s, 0);
+}
+
+void qtest_irq_intercept_in(QTestState *s, const char *qom_path)
+{
+    qtest_sendf(s, "irq_intercept_in %s\n", qom_path);
+    qtest_rsp(s, 0);
+}
+
+static void qtest_out(QTestState *s, const char *cmd, uint16_t addr, uint32_t value)
+{
+    qtest_sendf(s, "%s 0x%x 0x%x\n", cmd, addr, value);
+    qtest_rsp(s, 0);
+}
+
+void qtest_outb(QTestState *s, uint16_t addr, uint8_t value)
+{
+    qtest_out(s, "outb", addr, value);
+}
+
+void qtest_outw(QTestState *s, uint16_t addr, uint16_t value)
+{
+    qtest_out(s, "outw", addr, value);
+}
+
+void qtest_outl(QTestState *s, uint16_t addr, uint32_t value)
+{
+    qtest_out(s, "outl", addr, value);
+}
+
+static uint32_t qtest_in(QTestState *s, const char *cmd, uint16_t addr)
+{
+    gchar **args;
+    uint32_t value;
+
+    qtest_sendf(s, "%s 0x%x\n", cmd, addr);
+    args = qtest_rsp(s, 2);
+    value = strtoul(args[1], NULL, 0);
+    g_strfreev(args);
+
+    return value;
+}
+
+uint8_t qtest_inb(QTestState *s, uint16_t addr)
+{
+    return qtest_in(s, "inb", addr);
+}
+
+uint16_t qtest_inw(QTestState *s, uint16_t addr)
+{
+    return qtest_in(s, "inw", addr);
+}
+
+uint32_t qtest_inl(QTestState *s, uint16_t addr)
+{
+    return qtest_in(s, "inl", addr);
+}
+
+static int hex2nib(char ch)
+{
+    if (ch >= '0' && ch <= '9') {
+        return ch - '0';
+    } else if (ch >= 'a' && ch <= 'f') {
+        return 10 + (ch - 'a');
+    } else if (ch >= 'A' && ch <= 'F') {
+        return 10 + (ch - 'a');
+    } else {
+        return -1;
+    }
+}
+
+void qtest_memread(QTestState *s, uint64_t addr, void *data, size_t size)
+{
+    uint8_t *ptr = data;
+    gchar **args;
+    size_t i;
+
+    qtest_sendf(s, "read 0x%x 0x%x\n", addr, size);
+    args = qtest_rsp(s, 2);
+
+    for (i = 0; i < size; i++) {
+        ptr[i] = hex2nib(args[1][2 + (i * 2)]) << 4;
+        ptr[i] |= hex2nib(args[1][2 + (i * 2) + 1]);
+    }
+
+    g_strfreev(args);
+}
+
+void qtest_add_func(const char *str, void (*fn))
+{
+    gchar *path = g_strdup_printf("/%s/%s", qtest_get_arch(), str);
+    g_test_add_func(path, fn);
+}
+
+void qtest_memwrite(QTestState *s, uint64_t addr, const void *data, size_t size)
+{
+    const uint8_t *ptr = data;
+    size_t i;
+
+    qtest_sendf(s, "write 0x%x 0x%x 0x", addr, size);
+    for (i = 0; i < size; i++) {
+        qtest_sendf(s, "%02x", ptr[i]);
+    }
+    qtest_sendf(s, "\n");
+    qtest_rsp(s, 0);
+}
diff --git a/tests/libqtest.h b/tests/libqtest.h
new file mode 100644
index 0000000..e35610f
--- /dev/null
+++ b/tests/libqtest.h
@@ -0,0 +1,335 @@
+/*
+ * QTest
+ *
+ * Copyright IBM, Corp. 2012
+ * Copyright Red Hat, Inc. 2012
+ *
+ * Authors:
+ *  Anthony Liguori   <aliguori@us.ibm.com>
+ *  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.
+ *
+ */
+#ifndef LIBQTEST_H
+#define LIBQTEST_H
+
+#include <stdint.h>
+#include <stdbool.h>
+#include <sys/types.h>
+
+typedef struct QTestState QTestState;
+
+extern QTestState *global_qtest;
+
+/**
+ * qtest_init:
+ * @extra_args: other arguments to pass to QEMU.
+ */
+QTestState *qtest_init(const char *extra_args);
+
+/**
+ * qtest_quit:
+ * @s: QTestState instance to operate on.
+ *
+ * Shut down the QEMU process associated to @s.
+ */
+void qtest_quit(QTestState *s);
+
+/**
+ * qtest_get_irq:
+ * @s: QTestState instance to operate on.
+ * @num: Interrupt to observe.
+ *
+ * Return the level of the @num interrupt.
+ */
+bool qtest_get_irq(QTestState *s, int num);
+
+/**
+ * qtest_irq_intercept_in:
+ * @s: QTestState instance to operate on.
+ * @string: QOM path of a device.
+ *
+ * Associate qtest irqs with the GPIO-in pins of the device
+ * whose path is specified by @string.
+ */
+void qtest_irq_intercept_in(QTestState *s, const char *string);
+
+/**
+ * qtest_irq_intercept_out:
+ * @s: QTestState instance to operate on.
+ * @string: QOM path of a device.
+ *
+ * Associate qtest irqs with the GPIO-out pins of the device
+ * whose path is specified by @string.
+ */
+void qtest_irq_intercept_out(QTestState *s, const char *string);
+
+/**
+ * qtest_outb:
+ * @s: QTestState instance to operate on.
+ * @addr: I/O port to write to.
+ * @value: Value being written.
+ *
+ * Write an 8-bit value to an I/O port.
+ */
+void qtest_outb(QTestState *s, uint16_t addr, uint8_t value);
+
+/**
+ * qtest_outw:
+ * @s: QTestState instance to operate on.
+ * @addr: I/O port to write to.
+ * @value: Value being written.
+ *
+ * Write a 16-bit value to an I/O port.
+ */
+void qtest_outw(QTestState *s, uint16_t addr, uint16_t value);
+
+/**
+ * qtest_outl:
+ * @s: QTestState instance to operate on.
+ * @addr: I/O port to write to.
+ * @value: Value being written.
+ *
+ * Write a 32-bit value to an I/O port.
+ */
+void qtest_outl(QTestState *s, uint16_t addr, uint32_t value);
+
+/**
+ * qtest_inb:
+ * @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.
+ */
+uint8_t qtest_inb(QTestState *s, uint16_t addr);
+
+/**
+ * qtest_inw:
+ * @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.
+ */
+uint16_t qtest_inw(QTestState *s, uint16_t addr);
+
+/**
+ * qtest_inl:
+ * @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_memread:
+ * @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.
+ *
+ * Read guest memory into a buffer.
+ */
+void qtest_memread(QTestState *s, uint64_t addr, void *data, size_t size);
+
+/**
+ * qtest_memwrite:
+ * @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.
+ *
+ * Write a buffer to guest memory.
+ */
+void qtest_memwrite(QTestState *s, uint64_t addr, const void *data, size_t size);
+
+/**
+ * qtest_clock_step_next:
+ * @s: QTestState instance to operate on.
+ *
+ * Advance the vm_clock to the next deadline.  Return the current
+ * value of the vm_clock in nanoseconds.
+ */
+int64_t qtest_clock_step_next(QTestState *s);
+
+/**
+ * qtest_clock_step:
+ * @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.
+ */
+int64_t qtest_clock_step(QTestState *s, int64_t step);
+
+/**
+ * qtest_clock_set:
+ * @s: QTestState instance to operate on.
+ * @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.
+ */
+int64_t qtest_clock_set(QTestState *s, int64_t val);
+
+/**
+ * qtest_get_arch:
+ *
+ * Returns the architecture for the QEMU executable under test.
+ */
+const char *qtest_get_arch(void);
+
+/**
+ * qtest_add_func:
+ * @str: Test case path.
+ * @fn: Test case function
+ *
+ * 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.
+ */
+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.
+ */
+#define qtest_start(args) (            \
+    global_qtest = qtest_init((args)) \
+        )
+
+/**
+ * get_irq:
+ * @num: Interrupt to observe.
+ *
+ * Return the level of the @num interrupt.
+ */
+#define get_irq(num) qtest_get_irq(global_qtest, num)
+
+/**
+ * irq_intercept_in:
+ * @string: QOM path of a device.
+ *
+ * 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)
+
+/**
+ * qtest_irq_intercept_out:
+ * @string: QOM path of a device.
+ *
+ * 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)
+
+/**
+ * outb:
+ * @addr: I/O port to write to.
+ * @value: Value being written.
+ *
+ * Write an 8-bit value to an I/O port.
+ */
+#define outb(addr, val) qtest_outb(global_qtest, addr, val)
+
+/**
+ * outw:
+ * @addr: I/O port to write to.
+ * @value: Value being written.
+ *
+ * Write a 16-bit value to an I/O port.
+ */
+#define outw(addr, val) qtest_outw(global_qtest, addr, val)
+
+/**
+ * outl:
+ * @addr: I/O port to write to.
+ * @value: Value being written.
+ *
+ * Write a 32-bit value to an I/O port.
+ */
+#define outl(addr, val) qtest_outl(global_qtest, addr, val)
+
+/**
+ * inb:
+ * @addr: I/O port to read from.
+ * @value: Value being written.
+ *
+ * Returns an 8-bit value from an I/O port.
+ */
+#define inb(addr) 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.
+ */
+#define inw(addr) qtest_inw(global_qtest, addr)
+
+/**
+ * inl:
+ * @addr: I/O port to read from.
+ * @value: Value being written.
+ *
+ * Returns a 32-bit value from an I/O port.
+ */
+#define inl(addr) qtest_inl(global_qtest, addr)
+
+/**
+ * memread:
+ * @addr: Guest address to read from.
+ * @data: Pointer to where memory contents will be stored.
+ * @size: Number of bytes to read.
+ *
+ * Read guest memory into a buffer.
+ */
+#define memread(addr, data, size) qtest_memread(global_qtest, addr, data, size)
+
+/**
+ * memwrite:
+ * @addr: Guest address to write to.
+ * @data: Pointer to the bytes that will be written to guest memory.
+ * @size: Number of bytes to write.
+ *
+ * Write a buffer to guest memory.
+ */
+#define memwrite(addr, data, 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.
+ */
+#define clock_step_next() 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.
+ */
+#define clock_step(step) 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.
+ */
+#define clock_set(val) qtest_clock_set(global_qtest, val)
+
+#endif
-- 
1.7.9.1

^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [Qemu-devel] [PATCH v4 6/7] rtc: split out macros into a header file and use in test case
  2012-03-28 13:42 [Qemu-devel] [PATCH v4 0/7] new test infrastructure + qtest Paolo Bonzini
                   ` (4 preceding siblings ...)
  2012-03-28 13:42 ` [Qemu-devel] [PATCH v4 5/7] qtest: add C version of test infrastructure Paolo Bonzini
@ 2012-03-28 13:42 ` Paolo Bonzini
  2012-03-28 13:42 ` [Qemu-devel] [PATCH v4 7/7] qtest: add rtc-test test-case Paolo Bonzini
                   ` (2 subsequent siblings)
  8 siblings, 0 replies; 21+ messages in thread
From: Paolo Bonzini @ 2012-03-28 13:42 UTC (permalink / raw)
  To: qemu-devel; +Cc: Anthony Liguori

From: Anthony Liguori <aliguori@us.ibm.com>

Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>

Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 hw/mc146818rtc.c      |   33 --------------------------
 hw/mc146818rtc.h      |    3 +-
 hw/mc146818rtc_regs.h |   62 +++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 63 insertions(+), 35 deletions(-)
 create mode 100644 hw/mc146818rtc_regs.h

diff --git a/hw/mc146818rtc.c b/hw/mc146818rtc.c
index 2b59c36..9c64e0a 100644
--- a/hw/mc146818rtc.c
+++ b/hw/mc146818rtc.c
@@ -47,39 +47,6 @@
 
 #define RTC_REINJECT_ON_ACK_COUNT 20
 
-#define RTC_SECONDS             0
-#define RTC_SECONDS_ALARM       1
-#define RTC_MINUTES             2
-#define RTC_MINUTES_ALARM       3
-#define RTC_HOURS               4
-#define RTC_HOURS_ALARM         5
-#define RTC_ALARM_DONT_CARE    0xC0
-
-#define RTC_DAY_OF_WEEK         6
-#define RTC_DAY_OF_MONTH        7
-#define RTC_MONTH               8
-#define RTC_YEAR                9
-
-#define RTC_REG_A               10
-#define RTC_REG_B               11
-#define RTC_REG_C               12
-#define RTC_REG_D               13
-
-#define REG_A_UIP 0x80
-
-#define REG_B_SET  0x80
-#define REG_B_PIE  0x40
-#define REG_B_AIE  0x20
-#define REG_B_UIE  0x10
-#define REG_B_SQWE 0x08
-#define REG_B_DM   0x04
-#define REG_B_24H  0x02
-
-#define REG_C_UF   0x10
-#define REG_C_IRQF 0x80
-#define REG_C_PF   0x40
-#define REG_C_AF   0x20
-
 typedef struct RTCState {
     ISADevice dev;
     MemoryRegion io;
diff --git a/hw/mc146818rtc.h b/hw/mc146818rtc.h
index f119930..f286b6a 100644
--- a/hw/mc146818rtc.h
+++ b/hw/mc146818rtc.h
@@ -2,8 +2,7 @@
 #define MC146818RTC_H
 
 #include "isa.h"
-
-#define RTC_ISA_IRQ 8
+#include "mc146818rtc_regs.h"
 
 ISADevice *rtc_init(ISABus *bus, int base_year, qemu_irq intercept_irq);
 void rtc_set_memory(ISADevice *dev, int addr, int val);
diff --git a/hw/mc146818rtc_regs.h b/hw/mc146818rtc_regs.h
new file mode 100644
index 0000000..3ab3770
--- /dev/null
+++ b/hw/mc146818rtc_regs.h
@@ -0,0 +1,62 @@
+/*
+ * QEMU MC146818 RTC emulation
+ *
+ * Copyright (c) 2003-2004 Fabrice Bellard
+ *
+ * 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.
+ */
+#ifndef RTC_REGS_H
+#define RTC_REGS_H
+
+#define RTC_ISA_IRQ 8
+
+#define RTC_SECONDS             0
+#define RTC_SECONDS_ALARM       1
+#define RTC_MINUTES             2
+#define RTC_MINUTES_ALARM       3
+#define RTC_HOURS               4
+#define RTC_HOURS_ALARM         5
+#define RTC_ALARM_DONT_CARE    0xC0
+
+#define RTC_DAY_OF_WEEK         6
+#define RTC_DAY_OF_MONTH        7
+#define RTC_MONTH               8
+#define RTC_YEAR                9
+
+#define RTC_REG_A               10
+#define RTC_REG_B               11
+#define RTC_REG_C               12
+#define RTC_REG_D               13
+
+#define REG_A_UIP 0x80
+
+#define REG_B_SET  0x80
+#define REG_B_PIE  0x40
+#define REG_B_AIE  0x20
+#define REG_B_UIE  0x10
+#define REG_B_SQWE 0x08
+#define REG_B_DM   0x04
+#define REG_B_24H  0x02
+
+#define REG_C_UF   0x10
+#define REG_C_IRQF 0x80
+#define REG_C_PF   0x40
+#define REG_C_AF   0x20
+
+#endif
-- 
1.7.9.1

^ permalink raw reply related	[flat|nested] 21+ messages in thread

* [Qemu-devel] [PATCH v4 7/7] qtest: add rtc-test test-case
  2012-03-28 13:42 [Qemu-devel] [PATCH v4 0/7] new test infrastructure + qtest Paolo Bonzini
                   ` (5 preceding siblings ...)
  2012-03-28 13:42 ` [Qemu-devel] [PATCH v4 6/7] rtc: split out macros into a header file and use in test case Paolo Bonzini
@ 2012-03-28 13:42 ` Paolo Bonzini
  2012-03-30 17:15   ` Blue Swirl
  2012-03-28 17:43 ` [Qemu-devel] [PATCH v4 0/7] new test infrastructure + qtest Anthony Liguori
  2012-03-30 14:45 ` Anthony Liguori
  8 siblings, 1 reply; 21+ messages in thread
From: Paolo Bonzini @ 2012-03-28 13:42 UTC (permalink / raw)
  To: qemu-devel; +Cc: Anthony Liguori

From: Anthony Liguori <aliguori@us.ibm.com>

Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 tests/Makefile   |    5 +
 tests/rtc-test.c |  263 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 268 insertions(+), 0 deletions(-)
 create mode 100644 tests/rtc-test.c

diff --git a/tests/Makefile b/tests/Makefile
index 99ca308..42ce2d7 100644
--- a/tests/Makefile
+++ b/tests/Makefile
@@ -16,6 +16,11 @@ check-unit-y += tests/test-coroutine$(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/rtc-test
+check-qtest-x86_64-y = $(check-qtest-i386-y)
+
 GENERATED_HEADERS += tests/test-qapi-types.h tests/test-qapi-visit.h tests/test-qmp-commands.h
 
 test-obj-y = tests/check-qint.o tests/check-qstring.o tests/check-qdict.o \
diff --git a/tests/rtc-test.c b/tests/rtc-test.c
new file mode 100644
index 0000000..22f807c
--- /dev/null
+++ b/tests/rtc-test.c
@@ -0,0 +1,263 @@
+/*
+ * QTest testcase for the MC146818 real-time clock
+ *
+ * Copyright IBM, Corp. 2012
+ *
+ * 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 "hw/mc146818rtc_regs.h"
+
+#include <glib.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+static uint8_t base = 0x70;
+
+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);
+    return inb(base + 1);
+}
+
+static void cmos_write(uint8_t reg, uint8_t val)
+{
+    outb(base + 0, reg);
+    outb(base + 1, val);
+}
+
+static int tm_cmp(struct tm *lhs, struct tm *rhs)
+{
+    time_t a, b;
+    struct tm d1, d2;
+
+    memcpy(&d1, lhs, sizeof(d1));
+    memcpy(&d2, rhs, sizeof(d2));
+
+    a = mktime(&d1);
+    b = mktime(&d2);
+
+    if (a < b) {
+        return -1;
+    } else if (a > b) {
+        return 1;
+    }
+
+    return 0;
+}
+
+#if 0
+static void print_tm(struct tm *tm)
+{
+    printf("%04d-%02d-%02d %02d:%02d:%02d\n",
+           tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
+           tm->tm_hour, tm->tm_min, tm->tm_sec, tm->tm_gmtoff);
+}
+#endif
+
+static void cmos_get_date_time(struct tm *date)
+{
+    int base_year = 2000, hour_offset;
+    int sec, min, hour, mday, mon, year;
+    time_t ts;
+    struct tm dummy;
+
+    sec = cmos_read(RTC_SECONDS);
+    min = cmos_read(RTC_MINUTES);
+    hour = cmos_read(RTC_HOURS);
+    mday = cmos_read(RTC_DAY_OF_MONTH);
+    mon = cmos_read(RTC_MONTH);
+    year = cmos_read(RTC_YEAR);
+
+    if ((cmos_read(RTC_REG_B) & REG_B_DM) == 0) {
+        sec = bcd2dec(sec);
+        min = bcd2dec(min);
+        hour = bcd2dec(hour);
+        mday = bcd2dec(mday);
+        mon = bcd2dec(mon);
+        year = bcd2dec(year);
+        hour_offset = 80;
+    } else {
+        hour_offset = 0x80;
+    }
+
+    if ((cmos_read(0x0B) & REG_B_24H) == 0) {
+        if (hour >= hour_offset) {
+            hour -= hour_offset;
+            hour += 12;
+        }
+    }
+
+    ts = time(NULL);
+    localtime_r(&ts, &dummy);
+
+    date->tm_isdst = dummy.tm_isdst;
+    date->tm_sec = sec;
+    date->tm_min = min;
+    date->tm_hour = hour;
+    date->tm_mday = mday;
+    date->tm_mon = mon - 1;
+    date->tm_year = base_year + year - 1900;
+    date->tm_gmtoff = 0;
+
+    ts = mktime(date);
+}
+
+static void check_time(int wiggle)
+{
+    struct tm start, date[4], end;
+    struct tm *datep;
+    time_t ts;
+
+    /*
+     * This check assumes a few things.  First, we cannot guarantee that we get
+     * a consistent reading from the wall clock because we may hit an edge of
+     * the clock while reading.  To work around this, we read four clock readings
+     * such that at least two of them should match.  We need to assume that one
+     * reading is corrupt so we need four readings to ensure that we have at
+     * least two consecutive identical readings
+     *
+     * It's also possible that we'll cross an edge reading the host clock so
+     * simply check to make sure that the clock reading is within the period of
+     * when we expect it to be.
+     */
+
+    ts = time(NULL);
+    gmtime_r(&ts, &start);
+
+    cmos_get_date_time(&date[0]);
+    cmos_get_date_time(&date[1]);
+    cmos_get_date_time(&date[2]);
+    cmos_get_date_time(&date[3]);
+
+    ts = time(NULL);
+    gmtime_r(&ts, &end);
+
+    if (tm_cmp(&date[0], &date[1]) == 0) {
+        datep = &date[0];
+    } else if (tm_cmp(&date[1], &date[2]) == 0) {
+        datep = &date[1];
+    } else if (tm_cmp(&date[2], &date[3]) == 0) {
+        datep = &date[2];
+    } else {
+        g_assert_not_reached();
+    }
+
+    if (!(tm_cmp(&start, datep) <= 0 && tm_cmp(datep, &end) <= 0)) {
+        time_t t, s;
+
+        start.tm_isdst = datep->tm_isdst;
+
+        t = mktime(datep);
+        s = mktime(&start);
+        if (t < s) {
+            g_test_message("RTC is %ld second(s) behind wall-clock\n", (s - t));
+        } else {
+            g_test_message("RTC is %ld second(s) ahead of wall-clock\n", (t - s));
+        }
+
+        g_assert_cmpint(ABS(t - s), <=, wiggle);
+    }
+}
+
+static int wiggle = 2;
+
+static void bcd_check_time(void)
+{
+    /* Set BCD mode */
+    cmos_write(RTC_REG_B, cmos_read(RTC_REG_B) & ~REG_B_DM);
+    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);
+    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;
+    time_t ts;
+    int i;
+
+    ts = time(NULL);
+    gmtime_r(&ts, &now);
+
+    /* set DEC mode */
+    cmos_write(RTC_REG_B, cmos_read(RTC_REG_B) | 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_REG_B, cmos_read(RTC_REG_B) | REG_B_AIE);
+
+    for (i = 0; i < 2 + wiggle; i++) {
+        if (get_irq(RTC_ISA_IRQ)) {
+            break;
+        }
+
+        clock_step(1000000000);
+    }
+
+    g_assert(get_irq(RTC_ISA_IRQ));
+    g_assert((cmos_read(RTC_REG_C) & REG_C_AF) != 0);
+    g_assert(cmos_read(RTC_REG_C) == 0);
+}
+
+int main(int argc, char **argv)
+{
+    QTestState *s = NULL;
+    int ret;
+
+    g_test_init(&argc, &argv, NULL);
+
+    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);
+    ret = g_test_run();
+
+    if (s) {
+        qtest_quit(s);
+    }
+
+    return ret;
+}
-- 
1.7.9.1

^ permalink raw reply related	[flat|nested] 21+ messages in thread

* Re: [Qemu-devel] [PATCH v4 0/7] new test infrastructure + qtest
  2012-03-28 13:42 [Qemu-devel] [PATCH v4 0/7] new test infrastructure + qtest Paolo Bonzini
                   ` (6 preceding siblings ...)
  2012-03-28 13:42 ` [Qemu-devel] [PATCH v4 7/7] qtest: add rtc-test test-case Paolo Bonzini
@ 2012-03-28 17:43 ` Anthony Liguori
  2012-03-30 14:45 ` Anthony Liguori
  8 siblings, 0 replies; 21+ messages in thread
From: Anthony Liguori @ 2012-03-28 17:43 UTC (permalink / raw)
  To: Paolo Bonzini; +Cc: qemu-devel

On 03/28/2012 08:42 AM, Paolo Bonzini wrote:
> This is a rebase of qtest.  I split the gtester infrastructure into
> its own patch, and reorganized the tests by moving everything into
> tests/.
>
> Also, libqtest now has bindings for the clock management commands, and
> I am using them in rtc-test.  Finally, the accept is moved from qemu to
> libqtest; tests need not sleep anymore until QEMU connects.
>
> This is on top of Luiz's recent pull request.

Thanks, I'll process and apply this ASAP.

Regards,

Anthony Liguori

>
> Anthony Liguori (4):
>    qtest: add test framework
>    qtest: add C version of test infrastructure
>    rtc: split out macros into a header file and use in test case
>    qtest: add rtc-test test-case
>
> Paolo Bonzini (3):
>    test makefile overhaul
>    qtest: IRQ interception infrastructure
>    qtest: add clock management
>
>   Makefile.objs                                      |    2 +
>   cpu-exec.c                                         |    1 +
>   cpus.c                                             |   82 ++++-
>   cpus.h                                             |    2 +
>   hw/irq.c                                           |   17 +
>   hw/irq.h                                           |    5 +
>   hw/mc146818rtc.c                                   |   33 --
>   hw/mc146818rtc.h                                   |    3 +-
>   hw/mc146818rtc_regs.h                              |   62 +++
>   hw/pc_piix.c                                       |    5 +-
>   osdep.h                                            |    2 +
>   qemu-common.h                                      |    1 -
>   qemu-options.hx                                    |    8 +
>   qemu-timer.c                                       |    2 +-
>   qemu-timer.h                                       |    1 +
>   qtest.c                                            |  443 ++++++++++++++++++++
>   qtest.h                                            |   35 ++
>   rules.mak                                          |    2 +-
>   scripts/gtester-cat                                |   26 ++
>   scripts/qtest                                      |    5 +
>   tests/Makefile                                     |  165 ++++++--
>   check-qdict.c =>  tests/check-qdict.c               |    0
>   check-qfloat.c =>  tests/check-qfloat.c             |    0
>   check-qint.c =>  tests/check-qint.c                 |    0
>   check-qjson.c =>  tests/check-qjson.c               |    0
>   check-qlist.c =>  tests/check-qlist.c               |    0
>   check-qstring.c =>  tests/check-qstring.c           |    0
>   tests/libqtest.c                                   |  385 +++++++++++++++++
>   tests/libqtest.h                                   |  333 +++++++++++++++
>   tests/rtc-test.c                                   |  263 ++++++++++++
>   test-coroutine.c =>  tests/test-coroutine.c         |    0
>   test-qmp-commands.c =>  tests/test-qmp-commands.c   |    0
>   .../test-qmp-input-strict.c                        |    0
>   .../test-qmp-input-visitor.c                       |    0
>   .../test-qmp-output-visitor.c                      |    0
>   .../test-string-input-visitor.c                    |    0
>   .../test-string-output-visitor.c                   |    0
>   vl.c                                               |   10 +-
>   38 files changed, 1806 insertions(+), 87 deletions(-)
>   create mode 100644 hw/mc146818rtc_regs.h
>   create mode 100644 qtest.c
>   create mode 100644 qtest.h
>   create mode 100755 scripts/gtester-cat
>   create mode 100755 scripts/qtest
>   rename check-qdict.c =>  tests/check-qdict.c (100%)
>   rename check-qfloat.c =>  tests/check-qfloat.c (100%)
>   rename check-qint.c =>  tests/check-qint.c (100%)
>   rename check-qjson.c =>  tests/check-qjson.c (100%)
>   rename check-qlist.c =>  tests/check-qlist.c (100%)
>   rename check-qstring.c =>  tests/check-qstring.c (100%)
>   create mode 100644 tests/libqtest.c
>   create mode 100644 tests/libqtest.h
>   create mode 100644 tests/rtc-test.c
>   rename test-coroutine.c =>  tests/test-coroutine.c (100%)
>   rename test-qmp-commands.c =>  tests/test-qmp-commands.c (100%)
>   rename test-qmp-input-strict.c =>  tests/test-qmp-input-strict.c (100%)
>   rename test-qmp-input-visitor.c =>  tests/test-qmp-input-visitor.c (100%)
>   rename test-qmp-output-visitor.c =>  tests/test-qmp-output-visitor.c (100%)
>   rename test-string-input-visitor.c =>  tests/test-string-input-visitor.c (100%)
>   rename test-string-output-visitor.c =>  tests/test-string-output-visitor.c (100%)
>

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [Qemu-devel] [PATCH v4 0/7] new test infrastructure + qtest
  2012-03-28 13:42 [Qemu-devel] [PATCH v4 0/7] new test infrastructure + qtest Paolo Bonzini
                   ` (7 preceding siblings ...)
  2012-03-28 17:43 ` [Qemu-devel] [PATCH v4 0/7] new test infrastructure + qtest Anthony Liguori
@ 2012-03-30 14:45 ` Anthony Liguori
  8 siblings, 0 replies; 21+ messages in thread
From: Anthony Liguori @ 2012-03-30 14:45 UTC (permalink / raw)
  To: Paolo Bonzini; +Cc: qemu-devel

On 03/28/2012 08:42 AM, Paolo Bonzini wrote:
> This is a rebase of qtest.  I split the gtester infrastructure into
> its own patch, and reorganized the tests by moving everything into
> tests/.
>
> Also, libqtest now has bindings for the clock management commands, and
> I am using them in rtc-test.  Finally, the accept is moved from qemu to
> libqtest; tests need not sleep anymore until QEMU connects.
>
> This is on top of Luiz's recent pull request.
>
> Anthony Liguori (4):
>    qtest: add test framework
>    qtest: add C version of test infrastructure
>    rtc: split out macros into a header file and use in test case
>    qtest: add rtc-test test-case
>
> Paolo Bonzini (3):
>    test makefile overhaul
>    qtest: IRQ interception infrastructure
>    qtest: add clock management

Applied.  Thanks!

Regards,

Anthony Liguori

>
>   Makefile.objs                                      |    2 +
>   cpu-exec.c                                         |    1 +
>   cpus.c                                             |   82 ++++-
>   cpus.h                                             |    2 +
>   hw/irq.c                                           |   17 +
>   hw/irq.h                                           |    5 +
>   hw/mc146818rtc.c                                   |   33 --
>   hw/mc146818rtc.h                                   |    3 +-
>   hw/mc146818rtc_regs.h                              |   62 +++
>   hw/pc_piix.c                                       |    5 +-
>   osdep.h                                            |    2 +
>   qemu-common.h                                      |    1 -
>   qemu-options.hx                                    |    8 +
>   qemu-timer.c                                       |    2 +-
>   qemu-timer.h                                       |    1 +
>   qtest.c                                            |  443 ++++++++++++++++++++
>   qtest.h                                            |   35 ++
>   rules.mak                                          |    2 +-
>   scripts/gtester-cat                                |   26 ++
>   scripts/qtest                                      |    5 +
>   tests/Makefile                                     |  165 ++++++--
>   check-qdict.c =>  tests/check-qdict.c               |    0
>   check-qfloat.c =>  tests/check-qfloat.c             |    0
>   check-qint.c =>  tests/check-qint.c                 |    0
>   check-qjson.c =>  tests/check-qjson.c               |    0
>   check-qlist.c =>  tests/check-qlist.c               |    0
>   check-qstring.c =>  tests/check-qstring.c           |    0
>   tests/libqtest.c                                   |  385 +++++++++++++++++
>   tests/libqtest.h                                   |  333 +++++++++++++++
>   tests/rtc-test.c                                   |  263 ++++++++++++
>   test-coroutine.c =>  tests/test-coroutine.c         |    0
>   test-qmp-commands.c =>  tests/test-qmp-commands.c   |    0
>   .../test-qmp-input-strict.c                        |    0
>   .../test-qmp-input-visitor.c                       |    0
>   .../test-qmp-output-visitor.c                      |    0
>   .../test-string-input-visitor.c                    |    0
>   .../test-string-output-visitor.c                   |    0
>   vl.c                                               |   10 +-
>   38 files changed, 1806 insertions(+), 87 deletions(-)
>   create mode 100644 hw/mc146818rtc_regs.h
>   create mode 100644 qtest.c
>   create mode 100644 qtest.h
>   create mode 100755 scripts/gtester-cat
>   create mode 100755 scripts/qtest
>   rename check-qdict.c =>  tests/check-qdict.c (100%)
>   rename check-qfloat.c =>  tests/check-qfloat.c (100%)
>   rename check-qint.c =>  tests/check-qint.c (100%)
>   rename check-qjson.c =>  tests/check-qjson.c (100%)
>   rename check-qlist.c =>  tests/check-qlist.c (100%)
>   rename check-qstring.c =>  tests/check-qstring.c (100%)
>   create mode 100644 tests/libqtest.c
>   create mode 100644 tests/libqtest.h
>   create mode 100644 tests/rtc-test.c
>   rename test-coroutine.c =>  tests/test-coroutine.c (100%)
>   rename test-qmp-commands.c =>  tests/test-qmp-commands.c (100%)
>   rename test-qmp-input-strict.c =>  tests/test-qmp-input-strict.c (100%)
>   rename test-qmp-input-visitor.c =>  tests/test-qmp-input-visitor.c (100%)
>   rename test-qmp-output-visitor.c =>  tests/test-qmp-output-visitor.c (100%)
>   rename test-string-input-visitor.c =>  tests/test-string-input-visitor.c (100%)
>   rename test-string-output-visitor.c =>  tests/test-string-output-visitor.c (100%)
>

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [Qemu-devel] [PATCH v4 7/7] qtest: add rtc-test test-case
  2012-03-28 13:42 ` [Qemu-devel] [PATCH v4 7/7] qtest: add rtc-test test-case Paolo Bonzini
@ 2012-03-30 17:15   ` Blue Swirl
  2012-03-30 17:22     ` Blue Swirl
  2012-03-30 17:29     ` Anthony Liguori
  0 siblings, 2 replies; 21+ messages in thread
From: Blue Swirl @ 2012-03-30 17:15 UTC (permalink / raw)
  To: Paolo Bonzini; +Cc: Anthony Liguori, qemu-devel

On Wed, Mar 28, 2012 at 13:42, Paolo Bonzini <pbonzini@redhat.com> wrote:
> From: Anthony Liguori <aliguori@us.ibm.com>
>
> Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
> ---
>  tests/Makefile   |    5 +
>  tests/rtc-test.c |  263 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
>  2 files changed, 268 insertions(+), 0 deletions(-)
>  create mode 100644 tests/rtc-test.c
>
> diff --git a/tests/Makefile b/tests/Makefile
> index 99ca308..42ce2d7 100644
> --- a/tests/Makefile
> +++ b/tests/Makefile
> @@ -16,6 +16,11 @@ check-unit-y += tests/test-coroutine$(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/rtc-test
> +check-qtest-x86_64-y = $(check-qtest-i386-y)

I get this error when trying 'make check':
GTESTER tests/test-string-output-visitor
GTESTER tests/test-coroutine
ccache gcc -O2 -g   -Wl,--warn-common -m64 -g
/src/qemu/tests/rtc-test.c tests/libqtest.o osdep.o oslib-posix.o
qemu-thread-posix.o   -o tests/rtc-test
/src/qemu/tests/rtc-test.c:14:33: error: hw/mc146818rtc_regs.h: No
such file or directory
/src/qemu/tests/rtc-test.c:16:18: error: glib.h: No such file or directory
/src/qemu/tests/rtc-test.c:46: warning: 'struct tm' declared inside
parameter list
/src/qemu/tests/rtc-test.c:46: warning: its scope is only this
definition or declaration, which is probably not what you want

It looks like the build rules are not correct. This is also an out of
tree build. Perhaps the patsubst rules in tests/Makefile do not match
rtc-test because it doesn't start with "qtest-"?

> +
>  GENERATED_HEADERS += tests/test-qapi-types.h tests/test-qapi-visit.h tests/test-qmp-commands.h
>
>  test-obj-y = tests/check-qint.o tests/check-qstring.o tests/check-qdict.o \
> diff --git a/tests/rtc-test.c b/tests/rtc-test.c
> new file mode 100644
> index 0000000..22f807c
> --- /dev/null
> +++ b/tests/rtc-test.c
> @@ -0,0 +1,263 @@
> +/*
> + * QTest testcase for the MC146818 real-time clock
> + *
> + * Copyright IBM, Corp. 2012
> + *
> + * 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 "hw/mc146818rtc_regs.h"
> +
> +#include <glib.h>
> +#include <stdio.h>
> +#include <string.h>
> +#include <stdlib.h>
> +#include <unistd.h>
> +
> +static uint8_t base = 0x70;
> +
> +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);
> +    return inb(base + 1);
> +}
> +
> +static void cmos_write(uint8_t reg, uint8_t val)
> +{
> +    outb(base + 0, reg);
> +    outb(base + 1, val);
> +}
> +
> +static int tm_cmp(struct tm *lhs, struct tm *rhs)
> +{
> +    time_t a, b;
> +    struct tm d1, d2;
> +
> +    memcpy(&d1, lhs, sizeof(d1));
> +    memcpy(&d2, rhs, sizeof(d2));
> +
> +    a = mktime(&d1);
> +    b = mktime(&d2);
> +
> +    if (a < b) {
> +        return -1;
> +    } else if (a > b) {
> +        return 1;
> +    }
> +
> +    return 0;
> +}
> +
> +#if 0
> +static void print_tm(struct tm *tm)
> +{
> +    printf("%04d-%02d-%02d %02d:%02d:%02d\n",
> +           tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
> +           tm->tm_hour, tm->tm_min, tm->tm_sec, tm->tm_gmtoff);
> +}
> +#endif
> +
> +static void cmos_get_date_time(struct tm *date)
> +{
> +    int base_year = 2000, hour_offset;
> +    int sec, min, hour, mday, mon, year;
> +    time_t ts;
> +    struct tm dummy;
> +
> +    sec = cmos_read(RTC_SECONDS);
> +    min = cmos_read(RTC_MINUTES);
> +    hour = cmos_read(RTC_HOURS);
> +    mday = cmos_read(RTC_DAY_OF_MONTH);
> +    mon = cmos_read(RTC_MONTH);
> +    year = cmos_read(RTC_YEAR);
> +
> +    if ((cmos_read(RTC_REG_B) & REG_B_DM) == 0) {
> +        sec = bcd2dec(sec);
> +        min = bcd2dec(min);
> +        hour = bcd2dec(hour);
> +        mday = bcd2dec(mday);
> +        mon = bcd2dec(mon);
> +        year = bcd2dec(year);
> +        hour_offset = 80;
> +    } else {
> +        hour_offset = 0x80;
> +    }
> +
> +    if ((cmos_read(0x0B) & REG_B_24H) == 0) {
> +        if (hour >= hour_offset) {
> +            hour -= hour_offset;
> +            hour += 12;
> +        }
> +    }
> +
> +    ts = time(NULL);
> +    localtime_r(&ts, &dummy);
> +
> +    date->tm_isdst = dummy.tm_isdst;
> +    date->tm_sec = sec;
> +    date->tm_min = min;
> +    date->tm_hour = hour;
> +    date->tm_mday = mday;
> +    date->tm_mon = mon - 1;
> +    date->tm_year = base_year + year - 1900;
> +    date->tm_gmtoff = 0;
> +
> +    ts = mktime(date);
> +}
> +
> +static void check_time(int wiggle)
> +{
> +    struct tm start, date[4], end;
> +    struct tm *datep;
> +    time_t ts;
> +
> +    /*
> +     * This check assumes a few things.  First, we cannot guarantee that we get
> +     * a consistent reading from the wall clock because we may hit an edge of
> +     * the clock while reading.  To work around this, we read four clock readings
> +     * such that at least two of them should match.  We need to assume that one
> +     * reading is corrupt so we need four readings to ensure that we have at
> +     * least two consecutive identical readings
> +     *
> +     * It's also possible that we'll cross an edge reading the host clock so
> +     * simply check to make sure that the clock reading is within the period of
> +     * when we expect it to be.
> +     */
> +
> +    ts = time(NULL);
> +    gmtime_r(&ts, &start);
> +
> +    cmos_get_date_time(&date[0]);
> +    cmos_get_date_time(&date[1]);
> +    cmos_get_date_time(&date[2]);
> +    cmos_get_date_time(&date[3]);
> +
> +    ts = time(NULL);
> +    gmtime_r(&ts, &end);
> +
> +    if (tm_cmp(&date[0], &date[1]) == 0) {
> +        datep = &date[0];
> +    } else if (tm_cmp(&date[1], &date[2]) == 0) {
> +        datep = &date[1];
> +    } else if (tm_cmp(&date[2], &date[3]) == 0) {
> +        datep = &date[2];
> +    } else {
> +        g_assert_not_reached();
> +    }
> +
> +    if (!(tm_cmp(&start, datep) <= 0 && tm_cmp(datep, &end) <= 0)) {
> +        time_t t, s;
> +
> +        start.tm_isdst = datep->tm_isdst;
> +
> +        t = mktime(datep);
> +        s = mktime(&start);
> +        if (t < s) {
> +            g_test_message("RTC is %ld second(s) behind wall-clock\n", (s - t));
> +        } else {
> +            g_test_message("RTC is %ld second(s) ahead of wall-clock\n", (t - s));
> +        }
> +
> +        g_assert_cmpint(ABS(t - s), <=, wiggle);
> +    }
> +}
> +
> +static int wiggle = 2;
> +
> +static void bcd_check_time(void)
> +{
> +    /* Set BCD mode */
> +    cmos_write(RTC_REG_B, cmos_read(RTC_REG_B) & ~REG_B_DM);
> +    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);
> +    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;
> +    time_t ts;
> +    int i;
> +
> +    ts = time(NULL);
> +    gmtime_r(&ts, &now);
> +
> +    /* set DEC mode */
> +    cmos_write(RTC_REG_B, cmos_read(RTC_REG_B) | 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_REG_B, cmos_read(RTC_REG_B) | REG_B_AIE);
> +
> +    for (i = 0; i < 2 + wiggle; i++) {
> +        if (get_irq(RTC_ISA_IRQ)) {
> +            break;
> +        }
> +
> +        clock_step(1000000000);
> +    }
> +
> +    g_assert(get_irq(RTC_ISA_IRQ));
> +    g_assert((cmos_read(RTC_REG_C) & REG_C_AF) != 0);
> +    g_assert(cmos_read(RTC_REG_C) == 0);
> +}
> +
> +int main(int argc, char **argv)
> +{
> +    QTestState *s = NULL;
> +    int ret;
> +
> +    g_test_init(&argc, &argv, NULL);
> +
> +    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);
> +    ret = g_test_run();
> +
> +    if (s) {
> +        qtest_quit(s);
> +    }
> +
> +    return ret;
> +}
> --
> 1.7.9.1
>
>

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [Qemu-devel] [PATCH v4 7/7] qtest: add rtc-test test-case
  2012-03-30 17:15   ` Blue Swirl
@ 2012-03-30 17:22     ` Blue Swirl
  2012-03-30 17:49       ` Anthony Liguori
  2012-03-30 17:29     ` Anthony Liguori
  1 sibling, 1 reply; 21+ messages in thread
From: Blue Swirl @ 2012-03-30 17:22 UTC (permalink / raw)
  To: Paolo Bonzini, Anthony Liguori; +Cc: qemu-devel

On Fri, Mar 30, 2012 at 17:15, Blue Swirl <blauwirbel@gmail.com> wrote:
> On Wed, Mar 28, 2012 at 13:42, Paolo Bonzini <pbonzini@redhat.com> wrote:
>> From: Anthony Liguori <aliguori@us.ibm.com>
>>
>> Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
>> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
>> ---
>>  tests/Makefile   |    5 +
>>  tests/rtc-test.c |  263 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
>>  2 files changed, 268 insertions(+), 0 deletions(-)
>>  create mode 100644 tests/rtc-test.c
>>
>> diff --git a/tests/Makefile b/tests/Makefile
>> index 99ca308..42ce2d7 100644
>> --- a/tests/Makefile
>> +++ b/tests/Makefile
>> @@ -16,6 +16,11 @@ check-unit-y += tests/test-coroutine$(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/rtc-test
>> +check-qtest-x86_64-y = $(check-qtest-i386-y)
>
> I get this error when trying 'make check':
> GTESTER tests/test-string-output-visitor
> GTESTER tests/test-coroutine
> ccache gcc -O2 -g   -Wl,--warn-common -m64 -g
> /src/qemu/tests/rtc-test.c tests/libqtest.o osdep.o oslib-posix.o
> qemu-thread-posix.o   -o tests/rtc-test
> /src/qemu/tests/rtc-test.c:14:33: error: hw/mc146818rtc_regs.h: No
> such file or directory
> /src/qemu/tests/rtc-test.c:16:18: error: glib.h: No such file or directory
> /src/qemu/tests/rtc-test.c:46: warning: 'struct tm' declared inside
> parameter list
> /src/qemu/tests/rtc-test.c:46: warning: its scope is only this
> definition or declaration, which is probably not what you want
>
> It looks like the build rules are not correct. This is also an out of
> tree build. Perhaps the patsubst rules in tests/Makefile do not match
> rtc-test because it doesn't start with "qtest-"?

This fixes 'make check'. Trace objects are also needed if tracing is enabled.

diff --git a/tests/Makefile b/tests/Makefile
index 29c1e51..a98a848 100644
--- a/tests/Makefile
+++ b/tests/Makefile
@@ -63,6 +63,8 @@ tests/test-qmp-input-visitor$(EXESUF):
tests/test-qmp-input-visitor.o $(test-qap
 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/rtc-test$(EXESUF): tests/rtc-test.o $(trace-obj-y)
+
 # QTest rules

 TARGETS=$(patsubst %-softmmu,%, $(filter %-softmmu,$(TARGET_DIRS)))

>> +
>>  GENERATED_HEADERS += tests/test-qapi-types.h tests/test-qapi-visit.h tests/test-qmp-commands.h
>>
>>  test-obj-y = tests/check-qint.o tests/check-qstring.o tests/check-qdict.o \
>> diff --git a/tests/rtc-test.c b/tests/rtc-test.c
>> new file mode 100644
>> index 0000000..22f807c
>> --- /dev/null
>> +++ b/tests/rtc-test.c
>> @@ -0,0 +1,263 @@
>> +/*
>> + * QTest testcase for the MC146818 real-time clock
>> + *
>> + * Copyright IBM, Corp. 2012
>> + *
>> + * 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 "hw/mc146818rtc_regs.h"
>> +
>> +#include <glib.h>
>> +#include <stdio.h>
>> +#include <string.h>
>> +#include <stdlib.h>
>> +#include <unistd.h>
>> +
>> +static uint8_t base = 0x70;
>> +
>> +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);
>> +    return inb(base + 1);
>> +}
>> +
>> +static void cmos_write(uint8_t reg, uint8_t val)
>> +{
>> +    outb(base + 0, reg);
>> +    outb(base + 1, val);
>> +}
>> +
>> +static int tm_cmp(struct tm *lhs, struct tm *rhs)
>> +{
>> +    time_t a, b;
>> +    struct tm d1, d2;
>> +
>> +    memcpy(&d1, lhs, sizeof(d1));
>> +    memcpy(&d2, rhs, sizeof(d2));
>> +
>> +    a = mktime(&d1);
>> +    b = mktime(&d2);
>> +
>> +    if (a < b) {
>> +        return -1;
>> +    } else if (a > b) {
>> +        return 1;
>> +    }
>> +
>> +    return 0;
>> +}
>> +
>> +#if 0
>> +static void print_tm(struct tm *tm)
>> +{
>> +    printf("%04d-%02d-%02d %02d:%02d:%02d\n",
>> +           tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
>> +           tm->tm_hour, tm->tm_min, tm->tm_sec, tm->tm_gmtoff);
>> +}
>> +#endif
>> +
>> +static void cmos_get_date_time(struct tm *date)
>> +{
>> +    int base_year = 2000, hour_offset;
>> +    int sec, min, hour, mday, mon, year;
>> +    time_t ts;
>> +    struct tm dummy;
>> +
>> +    sec = cmos_read(RTC_SECONDS);
>> +    min = cmos_read(RTC_MINUTES);
>> +    hour = cmos_read(RTC_HOURS);
>> +    mday = cmos_read(RTC_DAY_OF_MONTH);
>> +    mon = cmos_read(RTC_MONTH);
>> +    year = cmos_read(RTC_YEAR);
>> +
>> +    if ((cmos_read(RTC_REG_B) & REG_B_DM) == 0) {
>> +        sec = bcd2dec(sec);
>> +        min = bcd2dec(min);
>> +        hour = bcd2dec(hour);
>> +        mday = bcd2dec(mday);
>> +        mon = bcd2dec(mon);
>> +        year = bcd2dec(year);
>> +        hour_offset = 80;
>> +    } else {
>> +        hour_offset = 0x80;
>> +    }
>> +
>> +    if ((cmos_read(0x0B) & REG_B_24H) == 0) {
>> +        if (hour >= hour_offset) {
>> +            hour -= hour_offset;
>> +            hour += 12;
>> +        }
>> +    }
>> +
>> +    ts = time(NULL);
>> +    localtime_r(&ts, &dummy);
>> +
>> +    date->tm_isdst = dummy.tm_isdst;
>> +    date->tm_sec = sec;
>> +    date->tm_min = min;
>> +    date->tm_hour = hour;
>> +    date->tm_mday = mday;
>> +    date->tm_mon = mon - 1;
>> +    date->tm_year = base_year + year - 1900;
>> +    date->tm_gmtoff = 0;
>> +
>> +    ts = mktime(date);
>> +}
>> +
>> +static void check_time(int wiggle)
>> +{
>> +    struct tm start, date[4], end;
>> +    struct tm *datep;
>> +    time_t ts;
>> +
>> +    /*
>> +     * This check assumes a few things.  First, we cannot guarantee that we get
>> +     * a consistent reading from the wall clock because we may hit an edge of
>> +     * the clock while reading.  To work around this, we read four clock readings
>> +     * such that at least two of them should match.  We need to assume that one
>> +     * reading is corrupt so we need four readings to ensure that we have at
>> +     * least two consecutive identical readings
>> +     *
>> +     * It's also possible that we'll cross an edge reading the host clock so
>> +     * simply check to make sure that the clock reading is within the period of
>> +     * when we expect it to be.
>> +     */
>> +
>> +    ts = time(NULL);
>> +    gmtime_r(&ts, &start);
>> +
>> +    cmos_get_date_time(&date[0]);
>> +    cmos_get_date_time(&date[1]);
>> +    cmos_get_date_time(&date[2]);
>> +    cmos_get_date_time(&date[3]);
>> +
>> +    ts = time(NULL);
>> +    gmtime_r(&ts, &end);
>> +
>> +    if (tm_cmp(&date[0], &date[1]) == 0) {
>> +        datep = &date[0];
>> +    } else if (tm_cmp(&date[1], &date[2]) == 0) {
>> +        datep = &date[1];
>> +    } else if (tm_cmp(&date[2], &date[3]) == 0) {
>> +        datep = &date[2];
>> +    } else {
>> +        g_assert_not_reached();
>> +    }
>> +
>> +    if (!(tm_cmp(&start, datep) <= 0 && tm_cmp(datep, &end) <= 0)) {
>> +        time_t t, s;
>> +
>> +        start.tm_isdst = datep->tm_isdst;
>> +
>> +        t = mktime(datep);
>> +        s = mktime(&start);
>> +        if (t < s) {
>> +            g_test_message("RTC is %ld second(s) behind wall-clock\n", (s - t));
>> +        } else {
>> +            g_test_message("RTC is %ld second(s) ahead of wall-clock\n", (t - s));
>> +        }
>> +
>> +        g_assert_cmpint(ABS(t - s), <=, wiggle);
>> +    }
>> +}
>> +
>> +static int wiggle = 2;
>> +
>> +static void bcd_check_time(void)
>> +{
>> +    /* Set BCD mode */
>> +    cmos_write(RTC_REG_B, cmos_read(RTC_REG_B) & ~REG_B_DM);
>> +    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);
>> +    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;
>> +    time_t ts;
>> +    int i;
>> +
>> +    ts = time(NULL);
>> +    gmtime_r(&ts, &now);
>> +
>> +    /* set DEC mode */
>> +    cmos_write(RTC_REG_B, cmos_read(RTC_REG_B) | 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_REG_B, cmos_read(RTC_REG_B) | REG_B_AIE);
>> +
>> +    for (i = 0; i < 2 + wiggle; i++) {
>> +        if (get_irq(RTC_ISA_IRQ)) {
>> +            break;
>> +        }
>> +
>> +        clock_step(1000000000);
>> +    }
>> +
>> +    g_assert(get_irq(RTC_ISA_IRQ));
>> +    g_assert((cmos_read(RTC_REG_C) & REG_C_AF) != 0);
>> +    g_assert(cmos_read(RTC_REG_C) == 0);
>> +}
>> +
>> +int main(int argc, char **argv)
>> +{
>> +    QTestState *s = NULL;
>> +    int ret;
>> +
>> +    g_test_init(&argc, &argv, NULL);
>> +
>> +    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);
>> +    ret = g_test_run();
>> +
>> +    if (s) {
>> +        qtest_quit(s);
>> +    }
>> +
>> +    return ret;
>> +}
>> --
>> 1.7.9.1
>>
>>

^ permalink raw reply related	[flat|nested] 21+ messages in thread

* Re: [Qemu-devel] [PATCH v4 7/7] qtest: add rtc-test test-case
  2012-03-30 17:15   ` Blue Swirl
  2012-03-30 17:22     ` Blue Swirl
@ 2012-03-30 17:29     ` Anthony Liguori
  2012-03-30 17:37       ` Blue Swirl
  1 sibling, 1 reply; 21+ messages in thread
From: Anthony Liguori @ 2012-03-30 17:29 UTC (permalink / raw)
  To: Blue Swirl; +Cc: Paolo Bonzini, Anthony Liguori, qemu-devel

On 03/30/2012 12:15 PM, Blue Swirl wrote:
> On Wed, Mar 28, 2012 at 13:42, Paolo Bonzini<pbonzini@redhat.com>  wrote:
>> From: Anthony Liguori<aliguori@us.ibm.com>
>>
>> Signed-off-by: Anthony Liguori<aliguori@us.ibm.com>
>> Signed-off-by: Paolo Bonzini<pbonzini@redhat.com>
>> ---
>>   tests/Makefile   |    5 +
>>   tests/rtc-test.c |  263 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
>>   2 files changed, 268 insertions(+), 0 deletions(-)
>>   create mode 100644 tests/rtc-test.c
>>
>> diff --git a/tests/Makefile b/tests/Makefile
>> index 99ca308..42ce2d7 100644
>> --- a/tests/Makefile
>> +++ b/tests/Makefile
>> @@ -16,6 +16,11 @@ check-unit-y += tests/test-coroutine$(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/rtc-test
>> +check-qtest-x86_64-y = $(check-qtest-i386-y)
>
> I get this error when trying 'make check':
> GTESTER tests/test-string-output-visitor
> GTESTER tests/test-coroutine
> ccache gcc -O2 -g   -Wl,--warn-common -m64 -g
> /src/qemu/tests/rtc-test.c tests/libqtest.o osdep.o oslib-posix.o
> qemu-thread-posix.o   -o tests/rtc-test
> /src/qemu/tests/rtc-test.c:14:33: error: hw/mc146818rtc_regs.h: No
> such file or directory
> /src/qemu/tests/rtc-test.c:16:18: error: glib.h: No such file or directory
> /src/qemu/tests/rtc-test.c:46: warning: 'struct tm' declared inside
> parameter list
> /src/qemu/tests/rtc-test.c:46: warning: its scope is only this
> definition or declaration, which is probably not what you want
>
> It looks like the build rules are not correct. This is also an out of
> tree build. Perhaps the patsubst rules in tests/Makefile do not match
> rtc-test because it doesn't start with "qtest-"?

It works for me with an out of tree build.  I'm a bit surprised you don't have 
any LDFLAGS or LIBS set.

You are running make check at the top level, right?  And make check previously 
worked for you?

What's your host?

Regards,

Anthony Liguori

>> +
>>   GENERATED_HEADERS += tests/test-qapi-types.h tests/test-qapi-visit.h tests/test-qmp-commands.h
>>
>>   test-obj-y = tests/check-qint.o tests/check-qstring.o tests/check-qdict.o \
>> diff --git a/tests/rtc-test.c b/tests/rtc-test.c
>> new file mode 100644
>> index 0000000..22f807c
>> --- /dev/null
>> +++ b/tests/rtc-test.c
>> @@ -0,0 +1,263 @@
>> +/*
>> + * QTest testcase for the MC146818 real-time clock
>> + *
>> + * Copyright IBM, Corp. 2012
>> + *
>> + * 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 "hw/mc146818rtc_regs.h"
>> +
>> +#include<glib.h>
>> +#include<stdio.h>
>> +#include<string.h>
>> +#include<stdlib.h>
>> +#include<unistd.h>
>> +
>> +static uint8_t base = 0x70;
>> +
>> +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);
>> +    return inb(base + 1);
>> +}
>> +
>> +static void cmos_write(uint8_t reg, uint8_t val)
>> +{
>> +    outb(base + 0, reg);
>> +    outb(base + 1, val);
>> +}
>> +
>> +static int tm_cmp(struct tm *lhs, struct tm *rhs)
>> +{
>> +    time_t a, b;
>> +    struct tm d1, d2;
>> +
>> +    memcpy(&d1, lhs, sizeof(d1));
>> +    memcpy(&d2, rhs, sizeof(d2));
>> +
>> +    a = mktime(&d1);
>> +    b = mktime(&d2);
>> +
>> +    if (a<  b) {
>> +        return -1;
>> +    } else if (a>  b) {
>> +        return 1;
>> +    }
>> +
>> +    return 0;
>> +}
>> +
>> +#if 0
>> +static void print_tm(struct tm *tm)
>> +{
>> +    printf("%04d-%02d-%02d %02d:%02d:%02d\n",
>> +           tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
>> +           tm->tm_hour, tm->tm_min, tm->tm_sec, tm->tm_gmtoff);
>> +}
>> +#endif
>> +
>> +static void cmos_get_date_time(struct tm *date)
>> +{
>> +    int base_year = 2000, hour_offset;
>> +    int sec, min, hour, mday, mon, year;
>> +    time_t ts;
>> +    struct tm dummy;
>> +
>> +    sec = cmos_read(RTC_SECONDS);
>> +    min = cmos_read(RTC_MINUTES);
>> +    hour = cmos_read(RTC_HOURS);
>> +    mday = cmos_read(RTC_DAY_OF_MONTH);
>> +    mon = cmos_read(RTC_MONTH);
>> +    year = cmos_read(RTC_YEAR);
>> +
>> +    if ((cmos_read(RTC_REG_B)&  REG_B_DM) == 0) {
>> +        sec = bcd2dec(sec);
>> +        min = bcd2dec(min);
>> +        hour = bcd2dec(hour);
>> +        mday = bcd2dec(mday);
>> +        mon = bcd2dec(mon);
>> +        year = bcd2dec(year);
>> +        hour_offset = 80;
>> +    } else {
>> +        hour_offset = 0x80;
>> +    }
>> +
>> +    if ((cmos_read(0x0B)&  REG_B_24H) == 0) {
>> +        if (hour>= hour_offset) {
>> +            hour -= hour_offset;
>> +            hour += 12;
>> +        }
>> +    }
>> +
>> +    ts = time(NULL);
>> +    localtime_r(&ts,&dummy);
>> +
>> +    date->tm_isdst = dummy.tm_isdst;
>> +    date->tm_sec = sec;
>> +    date->tm_min = min;
>> +    date->tm_hour = hour;
>> +    date->tm_mday = mday;
>> +    date->tm_mon = mon - 1;
>> +    date->tm_year = base_year + year - 1900;
>> +    date->tm_gmtoff = 0;
>> +
>> +    ts = mktime(date);
>> +}
>> +
>> +static void check_time(int wiggle)
>> +{
>> +    struct tm start, date[4], end;
>> +    struct tm *datep;
>> +    time_t ts;
>> +
>> +    /*
>> +     * This check assumes a few things.  First, we cannot guarantee that we get
>> +     * a consistent reading from the wall clock because we may hit an edge of
>> +     * the clock while reading.  To work around this, we read four clock readings
>> +     * such that at least two of them should match.  We need to assume that one
>> +     * reading is corrupt so we need four readings to ensure that we have at
>> +     * least two consecutive identical readings
>> +     *
>> +     * It's also possible that we'll cross an edge reading the host clock so
>> +     * simply check to make sure that the clock reading is within the period of
>> +     * when we expect it to be.
>> +     */
>> +
>> +    ts = time(NULL);
>> +    gmtime_r(&ts,&start);
>> +
>> +    cmos_get_date_time(&date[0]);
>> +    cmos_get_date_time(&date[1]);
>> +    cmos_get_date_time(&date[2]);
>> +    cmos_get_date_time(&date[3]);
>> +
>> +    ts = time(NULL);
>> +    gmtime_r(&ts,&end);
>> +
>> +    if (tm_cmp(&date[0],&date[1]) == 0) {
>> +        datep =&date[0];
>> +    } else if (tm_cmp(&date[1],&date[2]) == 0) {
>> +        datep =&date[1];
>> +    } else if (tm_cmp(&date[2],&date[3]) == 0) {
>> +        datep =&date[2];
>> +    } else {
>> +        g_assert_not_reached();
>> +    }
>> +
>> +    if (!(tm_cmp(&start, datep)<= 0&&  tm_cmp(datep,&end)<= 0)) {
>> +        time_t t, s;
>> +
>> +        start.tm_isdst = datep->tm_isdst;
>> +
>> +        t = mktime(datep);
>> +        s = mktime(&start);
>> +        if (t<  s) {
>> +            g_test_message("RTC is %ld second(s) behind wall-clock\n", (s - t));
>> +        } else {
>> +            g_test_message("RTC is %ld second(s) ahead of wall-clock\n", (t - s));
>> +        }
>> +
>> +        g_assert_cmpint(ABS(t - s),<=, wiggle);
>> +    }
>> +}
>> +
>> +static int wiggle = 2;
>> +
>> +static void bcd_check_time(void)
>> +{
>> +    /* Set BCD mode */
>> +    cmos_write(RTC_REG_B, cmos_read(RTC_REG_B)&  ~REG_B_DM);
>> +    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);
>> +    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;
>> +    time_t ts;
>> +    int i;
>> +
>> +    ts = time(NULL);
>> +    gmtime_r(&ts,&now);
>> +
>> +    /* set DEC mode */
>> +    cmos_write(RTC_REG_B, cmos_read(RTC_REG_B) | 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_REG_B, cmos_read(RTC_REG_B) | REG_B_AIE);
>> +
>> +    for (i = 0; i<  2 + wiggle; i++) {
>> +        if (get_irq(RTC_ISA_IRQ)) {
>> +            break;
>> +        }
>> +
>> +        clock_step(1000000000);
>> +    }
>> +
>> +    g_assert(get_irq(RTC_ISA_IRQ));
>> +    g_assert((cmos_read(RTC_REG_C)&  REG_C_AF) != 0);
>> +    g_assert(cmos_read(RTC_REG_C) == 0);
>> +}
>> +
>> +int main(int argc, char **argv)
>> +{
>> +    QTestState *s = NULL;
>> +    int ret;
>> +
>> +    g_test_init(&argc,&argv, NULL);
>> +
>> +    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);
>> +    ret = g_test_run();
>> +
>> +    if (s) {
>> +        qtest_quit(s);
>> +    }
>> +
>> +    return ret;
>> +}
>> --
>> 1.7.9.1
>>
>>
>

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [Qemu-devel] [PATCH v4 7/7] qtest: add rtc-test test-case
  2012-03-30 17:29     ` Anthony Liguori
@ 2012-03-30 17:37       ` Blue Swirl
  0 siblings, 0 replies; 21+ messages in thread
From: Blue Swirl @ 2012-03-30 17:37 UTC (permalink / raw)
  To: Anthony Liguori; +Cc: Paolo Bonzini, Anthony Liguori, qemu-devel

On Fri, Mar 30, 2012 at 17:29, Anthony Liguori <anthony@codemonkey.ws> wrote:
> On 03/30/2012 12:15 PM, Blue Swirl wrote:
>>
>> On Wed, Mar 28, 2012 at 13:42, Paolo Bonzini<pbonzini@redhat.com>  wrote:
>>>
>>> From: Anthony Liguori<aliguori@us.ibm.com>
>>>
>>> Signed-off-by: Anthony Liguori<aliguori@us.ibm.com>
>>> Signed-off-by: Paolo Bonzini<pbonzini@redhat.com>
>>> ---
>>>  tests/Makefile   |    5 +
>>>  tests/rtc-test.c |  263
>>> ++++++++++++++++++++++++++++++++++++++++++++++++++++++
>>>  2 files changed, 268 insertions(+), 0 deletions(-)
>>>  create mode 100644 tests/rtc-test.c
>>>
>>> diff --git a/tests/Makefile b/tests/Makefile
>>> index 99ca308..42ce2d7 100644
>>> --- a/tests/Makefile
>>> +++ b/tests/Makefile
>>> @@ -16,6 +16,11 @@ check-unit-y += tests/test-coroutine$(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/rtc-test
>>> +check-qtest-x86_64-y = $(check-qtest-i386-y)
>>
>>
>> I get this error when trying 'make check':
>> GTESTER tests/test-string-output-visitor
>> GTESTER tests/test-coroutine
>> ccache gcc -O2 -g   -Wl,--warn-common -m64 -g
>> /src/qemu/tests/rtc-test.c tests/libqtest.o osdep.o oslib-posix.o
>> qemu-thread-posix.o   -o tests/rtc-test
>> /src/qemu/tests/rtc-test.c:14:33: error: hw/mc146818rtc_regs.h: No
>> such file or directory
>> /src/qemu/tests/rtc-test.c:16:18: error: glib.h: No such file or directory
>> /src/qemu/tests/rtc-test.c:46: warning: 'struct tm' declared inside
>> parameter list
>> /src/qemu/tests/rtc-test.c:46: warning: its scope is only this
>> definition or declaration, which is probably not what you want
>>
>> It looks like the build rules are not correct. This is also an out of
>> tree build. Perhaps the patsubst rules in tests/Makefile do not match
>> rtc-test because it doesn't start with "qtest-"?
>
>
> It works for me with an out of tree build.  I'm a bit surprised you don't
> have any LDFLAGS or LIBS set.
>
> You are running make check at the top level, right?  And make check
> previously worked for you?

Top of build tree, not source tree. I hadn't tested before.

> What's your host?

Debian stable x86_64.

> Regards,
>
> Anthony Liguori
>
>>> +
>>>  GENERATED_HEADERS += tests/test-qapi-types.h tests/test-qapi-visit.h
>>> tests/test-qmp-commands.h
>>>
>>>  test-obj-y = tests/check-qint.o tests/check-qstring.o
>>> tests/check-qdict.o \
>>> diff --git a/tests/rtc-test.c b/tests/rtc-test.c
>>> new file mode 100644
>>> index 0000000..22f807c
>>> --- /dev/null
>>> +++ b/tests/rtc-test.c
>>> @@ -0,0 +1,263 @@
>>> +/*
>>> + * QTest testcase for the MC146818 real-time clock
>>> + *
>>> + * Copyright IBM, Corp. 2012
>>> + *
>>> + * 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 "hw/mc146818rtc_regs.h"
>>> +
>>> +#include<glib.h>
>>> +#include<stdio.h>
>>> +#include<string.h>
>>> +#include<stdlib.h>
>>> +#include<unistd.h>
>>> +
>>> +static uint8_t base = 0x70;
>>> +
>>> +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);
>>> +    return inb(base + 1);
>>> +}
>>> +
>>> +static void cmos_write(uint8_t reg, uint8_t val)
>>> +{
>>> +    outb(base + 0, reg);
>>> +    outb(base + 1, val);
>>> +}
>>> +
>>> +static int tm_cmp(struct tm *lhs, struct tm *rhs)
>>> +{
>>> +    time_t a, b;
>>> +    struct tm d1, d2;
>>> +
>>> +    memcpy(&d1, lhs, sizeof(d1));
>>> +    memcpy(&d2, rhs, sizeof(d2));
>>> +
>>> +    a = mktime(&d1);
>>> +    b = mktime(&d2);
>>> +
>>> +    if (a<  b) {
>>> +        return -1;
>>> +    } else if (a>  b) {
>>> +        return 1;
>>> +    }
>>> +
>>> +    return 0;
>>> +}
>>> +
>>> +#if 0
>>> +static void print_tm(struct tm *tm)
>>> +{
>>> +    printf("%04d-%02d-%02d %02d:%02d:%02d\n",
>>> +           tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
>>> +           tm->tm_hour, tm->tm_min, tm->tm_sec, tm->tm_gmtoff);
>>> +}
>>> +#endif
>>> +
>>> +static void cmos_get_date_time(struct tm *date)
>>> +{
>>> +    int base_year = 2000, hour_offset;
>>> +    int sec, min, hour, mday, mon, year;
>>> +    time_t ts;
>>> +    struct tm dummy;
>>> +
>>> +    sec = cmos_read(RTC_SECONDS);
>>> +    min = cmos_read(RTC_MINUTES);
>>> +    hour = cmos_read(RTC_HOURS);
>>> +    mday = cmos_read(RTC_DAY_OF_MONTH);
>>> +    mon = cmos_read(RTC_MONTH);
>>> +    year = cmos_read(RTC_YEAR);
>>> +
>>> +    if ((cmos_read(RTC_REG_B)&  REG_B_DM) == 0) {
>>>
>>> +        sec = bcd2dec(sec);
>>> +        min = bcd2dec(min);
>>> +        hour = bcd2dec(hour);
>>> +        mday = bcd2dec(mday);
>>> +        mon = bcd2dec(mon);
>>> +        year = bcd2dec(year);
>>> +        hour_offset = 80;
>>> +    } else {
>>> +        hour_offset = 0x80;
>>> +    }
>>> +
>>> +    if ((cmos_read(0x0B)&  REG_B_24H) == 0) {
>>>
>>> +        if (hour>= hour_offset) {
>>> +            hour -= hour_offset;
>>> +            hour += 12;
>>> +        }
>>> +    }
>>> +
>>> +    ts = time(NULL);
>>> +    localtime_r(&ts,&dummy);
>>> +
>>> +    date->tm_isdst = dummy.tm_isdst;
>>> +    date->tm_sec = sec;
>>> +    date->tm_min = min;
>>> +    date->tm_hour = hour;
>>> +    date->tm_mday = mday;
>>> +    date->tm_mon = mon - 1;
>>> +    date->tm_year = base_year + year - 1900;
>>> +    date->tm_gmtoff = 0;
>>> +
>>> +    ts = mktime(date);
>>> +}
>>> +
>>> +static void check_time(int wiggle)
>>> +{
>>> +    struct tm start, date[4], end;
>>> +    struct tm *datep;
>>> +    time_t ts;
>>> +
>>> +    /*
>>> +     * This check assumes a few things.  First, we cannot guarantee that
>>> we get
>>> +     * a consistent reading from the wall clock because we may hit an
>>> edge of
>>> +     * the clock while reading.  To work around this, we read four clock
>>> readings
>>> +     * such that at least two of them should match.  We need to assume
>>> that one
>>> +     * reading is corrupt so we need four readings to ensure that we
>>> have at
>>> +     * least two consecutive identical readings
>>> +     *
>>> +     * It's also possible that we'll cross an edge reading the host
>>> clock so
>>> +     * simply check to make sure that the clock reading is within the
>>> period of
>>> +     * when we expect it to be.
>>> +     */
>>> +
>>> +    ts = time(NULL);
>>> +    gmtime_r(&ts,&start);
>>> +
>>> +    cmos_get_date_time(&date[0]);
>>> +    cmos_get_date_time(&date[1]);
>>> +    cmos_get_date_time(&date[2]);
>>> +    cmos_get_date_time(&date[3]);
>>> +
>>> +    ts = time(NULL);
>>> +    gmtime_r(&ts,&end);
>>> +
>>> +    if (tm_cmp(&date[0],&date[1]) == 0) {
>>> +        datep =&date[0];
>>> +    } else if (tm_cmp(&date[1],&date[2]) == 0) {
>>> +        datep =&date[1];
>>> +    } else if (tm_cmp(&date[2],&date[3]) == 0) {
>>> +        datep =&date[2];
>>>
>>> +    } else {
>>> +        g_assert_not_reached();
>>> +    }
>>> +
>>> +    if (!(tm_cmp(&start, datep)<= 0&&  tm_cmp(datep,&end)<= 0)) {
>>>
>>> +        time_t t, s;
>>> +
>>> +        start.tm_isdst = datep->tm_isdst;
>>> +
>>> +        t = mktime(datep);
>>> +        s = mktime(&start);
>>> +        if (t<  s) {
>>> +            g_test_message("RTC is %ld second(s) behind wall-clock\n",
>>> (s - t));
>>> +        } else {
>>> +            g_test_message("RTC is %ld second(s) ahead of wall-clock\n",
>>> (t - s));
>>> +        }
>>> +
>>> +        g_assert_cmpint(ABS(t - s),<=, wiggle);
>>> +    }
>>> +}
>>> +
>>> +static int wiggle = 2;
>>> +
>>> +static void bcd_check_time(void)
>>> +{
>>> +    /* Set BCD mode */
>>> +    cmos_write(RTC_REG_B, cmos_read(RTC_REG_B)&  ~REG_B_DM);
>>>
>>> +    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);
>>> +    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;
>>> +    time_t ts;
>>> +    int i;
>>> +
>>> +    ts = time(NULL);
>>> +    gmtime_r(&ts,&now);
>>> +
>>> +    /* set DEC mode */
>>> +    cmos_write(RTC_REG_B, cmos_read(RTC_REG_B) | 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_REG_B, cmos_read(RTC_REG_B) | REG_B_AIE);
>>> +
>>> +    for (i = 0; i<  2 + wiggle; i++) {
>>> +        if (get_irq(RTC_ISA_IRQ)) {
>>> +            break;
>>> +        }
>>> +
>>> +        clock_step(1000000000);
>>> +    }
>>> +
>>> +    g_assert(get_irq(RTC_ISA_IRQ));
>>> +    g_assert((cmos_read(RTC_REG_C)&  REG_C_AF) != 0);
>>>
>>> +    g_assert(cmos_read(RTC_REG_C) == 0);
>>> +}
>>> +
>>> +int main(int argc, char **argv)
>>> +{
>>> +    QTestState *s = NULL;
>>> +    int ret;
>>> +
>>> +    g_test_init(&argc,&argv, NULL);
>>>
>>> +
>>> +    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);
>>> +    ret = g_test_run();
>>> +
>>> +    if (s) {
>>> +        qtest_quit(s);
>>> +    }
>>> +
>>> +    return ret;
>>> +}
>>> --
>>> 1.7.9.1
>>>
>>>
>>
>

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [Qemu-devel] [PATCH v4 2/7] qtest: add test framework
  2012-03-28 13:42 ` [Qemu-devel] [PATCH v4 2/7] qtest: add test framework Paolo Bonzini
@ 2012-03-30 17:40   ` Stefan Weil
  2012-03-30 17:50     ` Anthony Liguori
  0 siblings, 1 reply; 21+ messages in thread
From: Stefan Weil @ 2012-03-30 17:40 UTC (permalink / raw)
  To: Paolo Bonzini, Anthony Liguori; +Cc: qemu-devel

Hi

this commit breaks builds on Linux i386:

CC libhw64/qtest.o
cc1: warnings being treated as errors
/home/stefan/src/qemu/qemu.org/qemu/qtest.c: In function 
‘qtest_send_prefix’:
/home/stefan/src/qemu/qemu.org/qemu/qtest.c:156: error: format ‘%lld’ 
expects type ‘long long int’, but argument 3 has type ‘__time_t’
/home/stefan/src/qemu/qemu.org/qemu/qtest.c:156: error: format ‘%06lld’ 
expects type ‘long long int’, but argument 4 has type ‘__suseconds_t’
(more follow)

The size of the timeval elements is only 32 bit on my Debian installation,
Therefore this format string in qtest.c does not work:

+#define FMT_timeval "%" PRId64 ".%06" PRId64

Regards,
Stefan W.

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [Qemu-devel] [PATCH v4 7/7] qtest: add rtc-test test-case
  2012-03-30 17:22     ` Blue Swirl
@ 2012-03-30 17:49       ` Anthony Liguori
  2012-03-30 17:53         ` Blue Swirl
  0 siblings, 1 reply; 21+ messages in thread
From: Anthony Liguori @ 2012-03-30 17:49 UTC (permalink / raw)
  To: Blue Swirl; +Cc: Paolo Bonzini, Anthony Liguori, qemu-devel

On 03/30/2012 12:22 PM, Blue Swirl wrote:
> On Fri, Mar 30, 2012 at 17:15, Blue Swirl<blauwirbel@gmail.com>  wrote:
>> On Wed, Mar 28, 2012 at 13:42, Paolo Bonzini<pbonzini@redhat.com>  wrote:
>>> From: Anthony Liguori<aliguori@us.ibm.com>
>>>
>>> Signed-off-by: Anthony Liguori<aliguori@us.ibm.com>
>>> Signed-off-by: Paolo Bonzini<pbonzini@redhat.com>
>>> ---
>>>   tests/Makefile   |    5 +
>>>   tests/rtc-test.c |  263 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
>>>   2 files changed, 268 insertions(+), 0 deletions(-)
>>>   create mode 100644 tests/rtc-test.c
>>>
>>> diff --git a/tests/Makefile b/tests/Makefile
>>> index 99ca308..42ce2d7 100644
>>> --- a/tests/Makefile
>>> +++ b/tests/Makefile
>>> @@ -16,6 +16,11 @@ check-unit-y += tests/test-coroutine$(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/rtc-test
>>> +check-qtest-x86_64-y = $(check-qtest-i386-y)
>>
>> I get this error when trying 'make check':
>> GTESTER tests/test-string-output-visitor
>> GTESTER tests/test-coroutine
>> ccache gcc -O2 -g   -Wl,--warn-common -m64 -g
>> /src/qemu/tests/rtc-test.c tests/libqtest.o osdep.o oslib-posix.o
>> qemu-thread-posix.o   -o tests/rtc-test
>> /src/qemu/tests/rtc-test.c:14:33: error: hw/mc146818rtc_regs.h: No
>> such file or directory
>> /src/qemu/tests/rtc-test.c:16:18: error: glib.h: No such file or directory
>> /src/qemu/tests/rtc-test.c:46: warning: 'struct tm' declared inside
>> parameter list
>> /src/qemu/tests/rtc-test.c:46: warning: its scope is only this
>> definition or declaration, which is probably not what you want
>>
>> It looks like the build rules are not correct. This is also an out of
>> tree build. Perhaps the patsubst rules in tests/Makefile do not match
>> rtc-test because it doesn't start with "qtest-"?
>
> This fixes 'make check'. Trace objects are also needed if tracing is enabled.
>
> diff --git a/tests/Makefile b/tests/Makefile
> index 29c1e51..a98a848 100644
> --- a/tests/Makefile
> +++ b/tests/Makefile
> @@ -63,6 +63,8 @@ tests/test-qmp-input-visitor$(EXESUF):
> tests/test-qmp-input-visitor.o $(test-qap
>   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/rtc-test$(EXESUF): tests/rtc-test.o $(trace-obj-y)
> +
>   # QTest rules
>
>   TARGETS=$(patsubst %-softmmu,%, $(filter %-softmmu,$(TARGET_DIRS)))

Reviewed-by: Anthony Liguori <aliguori@us.ibm.com>

Could you please add a SoB and apply Blue?  Thanks!

Regards,

Anthony Liguori

>
>>> +
>>>   GENERATED_HEADERS += tests/test-qapi-types.h tests/test-qapi-visit.h tests/test-qmp-commands.h
>>>
>>>   test-obj-y = tests/check-qint.o tests/check-qstring.o tests/check-qdict.o \
>>> diff --git a/tests/rtc-test.c b/tests/rtc-test.c
>>> new file mode 100644
>>> index 0000000..22f807c
>>> --- /dev/null
>>> +++ b/tests/rtc-test.c
>>> @@ -0,0 +1,263 @@
>>> +/*
>>> + * QTest testcase for the MC146818 real-time clock
>>> + *
>>> + * Copyright IBM, Corp. 2012
>>> + *
>>> + * 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 "hw/mc146818rtc_regs.h"
>>> +
>>> +#include<glib.h>
>>> +#include<stdio.h>
>>> +#include<string.h>
>>> +#include<stdlib.h>
>>> +#include<unistd.h>
>>> +
>>> +static uint8_t base = 0x70;
>>> +
>>> +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);
>>> +    return inb(base + 1);
>>> +}
>>> +
>>> +static void cmos_write(uint8_t reg, uint8_t val)
>>> +{
>>> +    outb(base + 0, reg);
>>> +    outb(base + 1, val);
>>> +}
>>> +
>>> +static int tm_cmp(struct tm *lhs, struct tm *rhs)
>>> +{
>>> +    time_t a, b;
>>> +    struct tm d1, d2;
>>> +
>>> +    memcpy(&d1, lhs, sizeof(d1));
>>> +    memcpy(&d2, rhs, sizeof(d2));
>>> +
>>> +    a = mktime(&d1);
>>> +    b = mktime(&d2);
>>> +
>>> +    if (a<  b) {
>>> +        return -1;
>>> +    } else if (a>  b) {
>>> +        return 1;
>>> +    }
>>> +
>>> +    return 0;
>>> +}
>>> +
>>> +#if 0
>>> +static void print_tm(struct tm *tm)
>>> +{
>>> +    printf("%04d-%02d-%02d %02d:%02d:%02d\n",
>>> +           tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
>>> +           tm->tm_hour, tm->tm_min, tm->tm_sec, tm->tm_gmtoff);
>>> +}
>>> +#endif
>>> +
>>> +static void cmos_get_date_time(struct tm *date)
>>> +{
>>> +    int base_year = 2000, hour_offset;
>>> +    int sec, min, hour, mday, mon, year;
>>> +    time_t ts;
>>> +    struct tm dummy;
>>> +
>>> +    sec = cmos_read(RTC_SECONDS);
>>> +    min = cmos_read(RTC_MINUTES);
>>> +    hour = cmos_read(RTC_HOURS);
>>> +    mday = cmos_read(RTC_DAY_OF_MONTH);
>>> +    mon = cmos_read(RTC_MONTH);
>>> +    year = cmos_read(RTC_YEAR);
>>> +
>>> +    if ((cmos_read(RTC_REG_B)&  REG_B_DM) == 0) {
>>> +        sec = bcd2dec(sec);
>>> +        min = bcd2dec(min);
>>> +        hour = bcd2dec(hour);
>>> +        mday = bcd2dec(mday);
>>> +        mon = bcd2dec(mon);
>>> +        year = bcd2dec(year);
>>> +        hour_offset = 80;
>>> +    } else {
>>> +        hour_offset = 0x80;
>>> +    }
>>> +
>>> +    if ((cmos_read(0x0B)&  REG_B_24H) == 0) {
>>> +        if (hour>= hour_offset) {
>>> +            hour -= hour_offset;
>>> +            hour += 12;
>>> +        }
>>> +    }
>>> +
>>> +    ts = time(NULL);
>>> +    localtime_r(&ts,&dummy);
>>> +
>>> +    date->tm_isdst = dummy.tm_isdst;
>>> +    date->tm_sec = sec;
>>> +    date->tm_min = min;
>>> +    date->tm_hour = hour;
>>> +    date->tm_mday = mday;
>>> +    date->tm_mon = mon - 1;
>>> +    date->tm_year = base_year + year - 1900;
>>> +    date->tm_gmtoff = 0;
>>> +
>>> +    ts = mktime(date);
>>> +}
>>> +
>>> +static void check_time(int wiggle)
>>> +{
>>> +    struct tm start, date[4], end;
>>> +    struct tm *datep;
>>> +    time_t ts;
>>> +
>>> +    /*
>>> +     * This check assumes a few things.  First, we cannot guarantee that we get
>>> +     * a consistent reading from the wall clock because we may hit an edge of
>>> +     * the clock while reading.  To work around this, we read four clock readings
>>> +     * such that at least two of them should match.  We need to assume that one
>>> +     * reading is corrupt so we need four readings to ensure that we have at
>>> +     * least two consecutive identical readings
>>> +     *
>>> +     * It's also possible that we'll cross an edge reading the host clock so
>>> +     * simply check to make sure that the clock reading is within the period of
>>> +     * when we expect it to be.
>>> +     */
>>> +
>>> +    ts = time(NULL);
>>> +    gmtime_r(&ts,&start);
>>> +
>>> +    cmos_get_date_time(&date[0]);
>>> +    cmos_get_date_time(&date[1]);
>>> +    cmos_get_date_time(&date[2]);
>>> +    cmos_get_date_time(&date[3]);
>>> +
>>> +    ts = time(NULL);
>>> +    gmtime_r(&ts,&end);
>>> +
>>> +    if (tm_cmp(&date[0],&date[1]) == 0) {
>>> +        datep =&date[0];
>>> +    } else if (tm_cmp(&date[1],&date[2]) == 0) {
>>> +        datep =&date[1];
>>> +    } else if (tm_cmp(&date[2],&date[3]) == 0) {
>>> +        datep =&date[2];
>>> +    } else {
>>> +        g_assert_not_reached();
>>> +    }
>>> +
>>> +    if (!(tm_cmp(&start, datep)<= 0&&  tm_cmp(datep,&end)<= 0)) {
>>> +        time_t t, s;
>>> +
>>> +        start.tm_isdst = datep->tm_isdst;
>>> +
>>> +        t = mktime(datep);
>>> +        s = mktime(&start);
>>> +        if (t<  s) {
>>> +            g_test_message("RTC is %ld second(s) behind wall-clock\n", (s - t));
>>> +        } else {
>>> +            g_test_message("RTC is %ld second(s) ahead of wall-clock\n", (t - s));
>>> +        }
>>> +
>>> +        g_assert_cmpint(ABS(t - s),<=, wiggle);
>>> +    }
>>> +}
>>> +
>>> +static int wiggle = 2;
>>> +
>>> +static void bcd_check_time(void)
>>> +{
>>> +    /* Set BCD mode */
>>> +    cmos_write(RTC_REG_B, cmos_read(RTC_REG_B)&  ~REG_B_DM);
>>> +    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);
>>> +    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;
>>> +    time_t ts;
>>> +    int i;
>>> +
>>> +    ts = time(NULL);
>>> +    gmtime_r(&ts,&now);
>>> +
>>> +    /* set DEC mode */
>>> +    cmos_write(RTC_REG_B, cmos_read(RTC_REG_B) | 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_REG_B, cmos_read(RTC_REG_B) | REG_B_AIE);
>>> +
>>> +    for (i = 0; i<  2 + wiggle; i++) {
>>> +        if (get_irq(RTC_ISA_IRQ)) {
>>> +            break;
>>> +        }
>>> +
>>> +        clock_step(1000000000);
>>> +    }
>>> +
>>> +    g_assert(get_irq(RTC_ISA_IRQ));
>>> +    g_assert((cmos_read(RTC_REG_C)&  REG_C_AF) != 0);
>>> +    g_assert(cmos_read(RTC_REG_C) == 0);
>>> +}
>>> +
>>> +int main(int argc, char **argv)
>>> +{
>>> +    QTestState *s = NULL;
>>> +    int ret;
>>> +
>>> +    g_test_init(&argc,&argv, NULL);
>>> +
>>> +    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);
>>> +    ret = g_test_run();
>>> +
>>> +    if (s) {
>>> +        qtest_quit(s);
>>> +    }
>>> +
>>> +    return ret;
>>> +}
>>> --
>>> 1.7.9.1
>>>
>>>
>

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [Qemu-devel] [PATCH v4 2/7] qtest: add test framework
  2012-03-30 17:40   ` Stefan Weil
@ 2012-03-30 17:50     ` Anthony Liguori
  2012-03-30 17:52       ` Stefan Weil
  0 siblings, 1 reply; 21+ messages in thread
From: Anthony Liguori @ 2012-03-30 17:50 UTC (permalink / raw)
  To: Stefan Weil; +Cc: Paolo Bonzini, Anthony Liguori, qemu-devel

On 03/30/2012 12:40 PM, Stefan Weil wrote:
> Hi
>
> this commit breaks builds on Linux i386:
>
> CC libhw64/qtest.o
> cc1: warnings being treated as errors
> /home/stefan/src/qemu/qemu.org/qemu/qtest.c: In function ‘qtest_send_prefix’:
> /home/stefan/src/qemu/qemu.org/qemu/qtest.c:156: error: format ‘%lld’ expects
> type ‘long long int’, but argument 3 has type ‘__time_t’
> /home/stefan/src/qemu/qemu.org/qemu/qtest.c:156: error: format ‘%06lld’ expects
> type ‘long long int’, but argument 4 has type ‘__suseconds_t’
> (more follow)
>
> The size of the timeval elements is only 32 bit on my Debian installation,
> Therefore this format string in qtest.c does not work:
>
> +#define FMT_timeval "%" PRId64 ".%06" PRId64

Does %ld work instead of PRId64?

Regards,

Anthony Liguori

>
> Regards,
> Stefan W.
>
>

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [Qemu-devel] [PATCH v4 2/7] qtest: add test framework
  2012-03-30 17:50     ` Anthony Liguori
@ 2012-03-30 17:52       ` Stefan Weil
  2012-03-30 17:53         ` Anthony Liguori
  0 siblings, 1 reply; 21+ messages in thread
From: Stefan Weil @ 2012-03-30 17:52 UTC (permalink / raw)
  To: Anthony Liguori; +Cc: Paolo Bonzini, Anthony Liguori, qemu-devel

Am 30.03.2012 19:50, schrieb Anthony Liguori:
> On 03/30/2012 12:40 PM, Stefan Weil wrote:
>> Hi
>>
>> this commit breaks builds on Linux i386:
>>
>> CC libhw64/qtest.o
>> cc1: warnings being treated as errors
>> /home/stefan/src/qemu/qemu.org/qemu/qtest.c: In function 
>> ‘qtest_send_prefix’:
>> /home/stefan/src/qemu/qemu.org/qemu/qtest.c:156: error: format ‘%lld’ 
>> expects
>> type ‘long long int’, but argument 3 has type ‘__time_t’
>> /home/stefan/src/qemu/qemu.org/qemu/qtest.c:156: error: format 
>> ‘%06lld’ expects
>> type ‘long long int’, but argument 4 has type ‘__suseconds_t’
>> (more follow)
>>
>> The size of the timeval elements is only 32 bit on my Debian 
>> installation,
>> Therefore this format string in qtest.c does not work:
>>
>> +#define FMT_timeval "%" PRId64 ".%06" PRId64
>
> Does %ld work instead of PRId64?

That works for my 32 bit Debian, but it would fail on 64 bit Linux.

>
> Regards,
>
> Anthony Liguori
>
>>
>> Regards,
>> Stefan W.
>>
>>
>
>

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [Qemu-devel] [PATCH v4 7/7] qtest: add rtc-test test-case
  2012-03-30 17:49       ` Anthony Liguori
@ 2012-03-30 17:53         ` Blue Swirl
  0 siblings, 0 replies; 21+ messages in thread
From: Blue Swirl @ 2012-03-30 17:53 UTC (permalink / raw)
  To: Anthony Liguori; +Cc: Paolo Bonzini, Anthony Liguori, qemu-devel

On Fri, Mar 30, 2012 at 17:49, Anthony Liguori <anthony@codemonkey.ws> wrote:
> On 03/30/2012 12:22 PM, Blue Swirl wrote:
>>
>> On Fri, Mar 30, 2012 at 17:15, Blue Swirl<blauwirbel@gmail.com>  wrote:
>>>
>>> On Wed, Mar 28, 2012 at 13:42, Paolo Bonzini<pbonzini@redhat.com>  wrote:
>>>>
>>>> From: Anthony Liguori<aliguori@us.ibm.com>
>>>>
>>>> Signed-off-by: Anthony Liguori<aliguori@us.ibm.com>
>>>> Signed-off-by: Paolo Bonzini<pbonzini@redhat.com>
>>>> ---
>>>>  tests/Makefile   |    5 +
>>>>  tests/rtc-test.c |  263
>>>> ++++++++++++++++++++++++++++++++++++++++++++++++++++++
>>>>  2 files changed, 268 insertions(+), 0 deletions(-)
>>>>  create mode 100644 tests/rtc-test.c
>>>>
>>>> diff --git a/tests/Makefile b/tests/Makefile
>>>> index 99ca308..42ce2d7 100644
>>>> --- a/tests/Makefile
>>>> +++ b/tests/Makefile
>>>> @@ -16,6 +16,11 @@ check-unit-y += tests/test-coroutine$(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/rtc-test
>>>> +check-qtest-x86_64-y = $(check-qtest-i386-y)
>>>
>>>
>>> I get this error when trying 'make check':
>>> GTESTER tests/test-string-output-visitor
>>> GTESTER tests/test-coroutine
>>> ccache gcc -O2 -g   -Wl,--warn-common -m64 -g
>>> /src/qemu/tests/rtc-test.c tests/libqtest.o osdep.o oslib-posix.o
>>> qemu-thread-posix.o   -o tests/rtc-test
>>> /src/qemu/tests/rtc-test.c:14:33: error: hw/mc146818rtc_regs.h: No
>>> such file or directory
>>> /src/qemu/tests/rtc-test.c:16:18: error: glib.h: No such file or
>>> directory
>>> /src/qemu/tests/rtc-test.c:46: warning: 'struct tm' declared inside
>>> parameter list
>>> /src/qemu/tests/rtc-test.c:46: warning: its scope is only this
>>> definition or declaration, which is probably not what you want
>>>
>>> It looks like the build rules are not correct. This is also an out of
>>> tree build. Perhaps the patsubst rules in tests/Makefile do not match
>>> rtc-test because it doesn't start with "qtest-"?
>>
>>
>> This fixes 'make check'. Trace objects are also needed if tracing is
>> enabled.
>>
>> diff --git a/tests/Makefile b/tests/Makefile
>> index 29c1e51..a98a848 100644
>> --- a/tests/Makefile
>> +++ b/tests/Makefile
>> @@ -63,6 +63,8 @@ tests/test-qmp-input-visitor$(EXESUF):
>> tests/test-qmp-input-visitor.o $(test-qap
>>  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/rtc-test$(EXESUF): tests/rtc-test.o $(trace-obj-y)
>> +
>>  # QTest rules
>>
>>  TARGETS=$(patsubst %-softmmu,%, $(filter %-softmmu,$(TARGET_DIRS)))
>
>
> Reviewed-by: Anthony Liguori <aliguori@us.ibm.com>
>
> Could you please add a SoB and apply Blue?  Thanks!

OK, pushed.

> Regards,
>
> Anthony Liguori
>
>>
>>>> +
>>>>  GENERATED_HEADERS += tests/test-qapi-types.h tests/test-qapi-visit.h
>>>> tests/test-qmp-commands.h
>>>>
>>>>  test-obj-y = tests/check-qint.o tests/check-qstring.o
>>>> tests/check-qdict.o \
>>>> diff --git a/tests/rtc-test.c b/tests/rtc-test.c
>>>> new file mode 100644
>>>> index 0000000..22f807c
>>>> --- /dev/null
>>>> +++ b/tests/rtc-test.c
>>>> @@ -0,0 +1,263 @@
>>>> +/*
>>>> + * QTest testcase for the MC146818 real-time clock
>>>> + *
>>>> + * Copyright IBM, Corp. 2012
>>>> + *
>>>> + * 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 "hw/mc146818rtc_regs.h"
>>>> +
>>>> +#include<glib.h>
>>>> +#include<stdio.h>
>>>> +#include<string.h>
>>>> +#include<stdlib.h>
>>>> +#include<unistd.h>
>>>> +
>>>> +static uint8_t base = 0x70;
>>>> +
>>>> +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);
>>>> +    return inb(base + 1);
>>>> +}
>>>> +
>>>> +static void cmos_write(uint8_t reg, uint8_t val)
>>>> +{
>>>> +    outb(base + 0, reg);
>>>> +    outb(base + 1, val);
>>>> +}
>>>> +
>>>> +static int tm_cmp(struct tm *lhs, struct tm *rhs)
>>>> +{
>>>> +    time_t a, b;
>>>> +    struct tm d1, d2;
>>>> +
>>>> +    memcpy(&d1, lhs, sizeof(d1));
>>>> +    memcpy(&d2, rhs, sizeof(d2));
>>>> +
>>>> +    a = mktime(&d1);
>>>> +    b = mktime(&d2);
>>>> +
>>>> +    if (a<  b) {
>>>> +        return -1;
>>>> +    } else if (a>  b) {
>>>> +        return 1;
>>>> +    }
>>>> +
>>>> +    return 0;
>>>> +}
>>>> +
>>>> +#if 0
>>>> +static void print_tm(struct tm *tm)
>>>> +{
>>>> +    printf("%04d-%02d-%02d %02d:%02d:%02d\n",
>>>> +           tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
>>>> +           tm->tm_hour, tm->tm_min, tm->tm_sec, tm->tm_gmtoff);
>>>> +}
>>>> +#endif
>>>> +
>>>> +static void cmos_get_date_time(struct tm *date)
>>>> +{
>>>> +    int base_year = 2000, hour_offset;
>>>> +    int sec, min, hour, mday, mon, year;
>>>> +    time_t ts;
>>>> +    struct tm dummy;
>>>> +
>>>> +    sec = cmos_read(RTC_SECONDS);
>>>> +    min = cmos_read(RTC_MINUTES);
>>>> +    hour = cmos_read(RTC_HOURS);
>>>> +    mday = cmos_read(RTC_DAY_OF_MONTH);
>>>> +    mon = cmos_read(RTC_MONTH);
>>>> +    year = cmos_read(RTC_YEAR);
>>>> +
>>>> +    if ((cmos_read(RTC_REG_B)&  REG_B_DM) == 0) {
>>>>
>>>> +        sec = bcd2dec(sec);
>>>> +        min = bcd2dec(min);
>>>> +        hour = bcd2dec(hour);
>>>> +        mday = bcd2dec(mday);
>>>> +        mon = bcd2dec(mon);
>>>> +        year = bcd2dec(year);
>>>> +        hour_offset = 80;
>>>> +    } else {
>>>> +        hour_offset = 0x80;
>>>> +    }
>>>> +
>>>> +    if ((cmos_read(0x0B)&  REG_B_24H) == 0) {
>>>>
>>>> +        if (hour>= hour_offset) {
>>>> +            hour -= hour_offset;
>>>> +            hour += 12;
>>>> +        }
>>>> +    }
>>>> +
>>>> +    ts = time(NULL);
>>>> +    localtime_r(&ts,&dummy);
>>>> +
>>>> +    date->tm_isdst = dummy.tm_isdst;
>>>> +    date->tm_sec = sec;
>>>> +    date->tm_min = min;
>>>> +    date->tm_hour = hour;
>>>> +    date->tm_mday = mday;
>>>> +    date->tm_mon = mon - 1;
>>>> +    date->tm_year = base_year + year - 1900;
>>>> +    date->tm_gmtoff = 0;
>>>> +
>>>> +    ts = mktime(date);
>>>> +}
>>>> +
>>>> +static void check_time(int wiggle)
>>>> +{
>>>> +    struct tm start, date[4], end;
>>>> +    struct tm *datep;
>>>> +    time_t ts;
>>>> +
>>>> +    /*
>>>> +     * This check assumes a few things.  First, we cannot guarantee
>>>> that we get
>>>> +     * a consistent reading from the wall clock because we may hit an
>>>> edge of
>>>> +     * the clock while reading.  To work around this, we read four
>>>> clock readings
>>>> +     * such that at least two of them should match.  We need to assume
>>>> that one
>>>> +     * reading is corrupt so we need four readings to ensure that we
>>>> have at
>>>> +     * least two consecutive identical readings
>>>> +     *
>>>> +     * It's also possible that we'll cross an edge reading the host
>>>> clock so
>>>> +     * simply check to make sure that the clock reading is within the
>>>> period of
>>>> +     * when we expect it to be.
>>>> +     */
>>>> +
>>>> +    ts = time(NULL);
>>>> +    gmtime_r(&ts,&start);
>>>> +
>>>> +    cmos_get_date_time(&date[0]);
>>>> +    cmos_get_date_time(&date[1]);
>>>> +    cmos_get_date_time(&date[2]);
>>>> +    cmos_get_date_time(&date[3]);
>>>> +
>>>> +    ts = time(NULL);
>>>> +    gmtime_r(&ts,&end);
>>>> +
>>>> +    if (tm_cmp(&date[0],&date[1]) == 0) {
>>>> +        datep =&date[0];
>>>> +    } else if (tm_cmp(&date[1],&date[2]) == 0) {
>>>> +        datep =&date[1];
>>>> +    } else if (tm_cmp(&date[2],&date[3]) == 0) {
>>>> +        datep =&date[2];
>>>>
>>>> +    } else {
>>>> +        g_assert_not_reached();
>>>> +    }
>>>> +
>>>> +    if (!(tm_cmp(&start, datep)<= 0&&  tm_cmp(datep,&end)<= 0)) {
>>>>
>>>> +        time_t t, s;
>>>> +
>>>> +        start.tm_isdst = datep->tm_isdst;
>>>> +
>>>> +        t = mktime(datep);
>>>> +        s = mktime(&start);
>>>> +        if (t<  s) {
>>>> +            g_test_message("RTC is %ld second(s) behind wall-clock\n",
>>>> (s - t));
>>>> +        } else {
>>>> +            g_test_message("RTC is %ld second(s) ahead of
>>>> wall-clock\n", (t - s));
>>>> +        }
>>>> +
>>>> +        g_assert_cmpint(ABS(t - s),<=, wiggle);
>>>> +    }
>>>> +}
>>>> +
>>>> +static int wiggle = 2;
>>>> +
>>>> +static void bcd_check_time(void)
>>>> +{
>>>> +    /* Set BCD mode */
>>>> +    cmos_write(RTC_REG_B, cmos_read(RTC_REG_B)&  ~REG_B_DM);
>>>>
>>>> +    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);
>>>> +    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;
>>>> +    time_t ts;
>>>> +    int i;
>>>> +
>>>> +    ts = time(NULL);
>>>> +    gmtime_r(&ts,&now);
>>>> +
>>>> +    /* set DEC mode */
>>>> +    cmos_write(RTC_REG_B, cmos_read(RTC_REG_B) | 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_REG_B, cmos_read(RTC_REG_B) | REG_B_AIE);
>>>> +
>>>> +    for (i = 0; i<  2 + wiggle; i++) {
>>>> +        if (get_irq(RTC_ISA_IRQ)) {
>>>> +            break;
>>>> +        }
>>>> +
>>>> +        clock_step(1000000000);
>>>> +    }
>>>> +
>>>> +    g_assert(get_irq(RTC_ISA_IRQ));
>>>> +    g_assert((cmos_read(RTC_REG_C)&  REG_C_AF) != 0);
>>>>
>>>> +    g_assert(cmos_read(RTC_REG_C) == 0);
>>>> +}
>>>> +
>>>> +int main(int argc, char **argv)
>>>> +{
>>>> +    QTestState *s = NULL;
>>>> +    int ret;
>>>> +
>>>> +    g_test_init(&argc,&argv, NULL);
>>>>
>>>> +
>>>> +    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);
>>>> +    ret = g_test_run();
>>>> +
>>>> +    if (s) {
>>>> +        qtest_quit(s);
>>>> +    }
>>>> +
>>>> +    return ret;
>>>> +}
>>>> --
>>>> 1.7.9.1
>>>>
>>>>
>>
>

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [Qemu-devel] [PATCH v4 2/7] qtest: add test framework
  2012-03-30 17:52       ` Stefan Weil
@ 2012-03-30 17:53         ` Anthony Liguori
  2012-03-30 18:37           ` Paolo Bonzini
  0 siblings, 1 reply; 21+ messages in thread
From: Anthony Liguori @ 2012-03-30 17:53 UTC (permalink / raw)
  To: Stefan Weil; +Cc: Paolo Bonzini, Anthony Liguori, qemu-devel

On 03/30/2012 12:52 PM, Stefan Weil wrote:
> Am 30.03.2012 19:50, schrieb Anthony Liguori:
>> On 03/30/2012 12:40 PM, Stefan Weil wrote:
>>> Hi
>>>
>>> this commit breaks builds on Linux i386:
>>>
>>> CC libhw64/qtest.o
>>> cc1: warnings being treated as errors
>>> /home/stefan/src/qemu/qemu.org/qemu/qtest.c: In function ‘qtest_send_prefix’:
>>> /home/stefan/src/qemu/qemu.org/qemu/qtest.c:156: error: format ‘%lld’ expects
>>> type ‘long long int’, but argument 3 has type ‘__time_t’
>>> /home/stefan/src/qemu/qemu.org/qemu/qtest.c:156: error: format ‘%06lld’ expects
>>> type ‘long long int’, but argument 4 has type ‘__suseconds_t’
>>> (more follow)
>>>
>>> The size of the timeval elements is only 32 bit on my Debian installation,
>>> Therefore this format string in qtest.c does not work:
>>>
>>> +#define FMT_timeval "%" PRId64 ".%06" PRId64
>>
>> Does %ld work instead of PRId64?
>
> That works for my 32 bit Debian, but it would fail on 64 bit Linux.

It works on my 64-bit Linux fwiw.

Regards,

Anthony Liguori

>>
>> Regards,
>>
>> Anthony Liguori
>>
>>>
>>> Regards,
>>> Stefan W.
>>>
>>>
>>
>>
>
>

^ permalink raw reply	[flat|nested] 21+ messages in thread

* Re: [Qemu-devel] [PATCH v4 2/7] qtest: add test framework
  2012-03-30 17:53         ` Anthony Liguori
@ 2012-03-30 18:37           ` Paolo Bonzini
  0 siblings, 0 replies; 21+ messages in thread
From: Paolo Bonzini @ 2012-03-30 18:37 UTC (permalink / raw)
  To: Anthony Liguori; +Cc: Stefan Weil, Anthony Liguori, qemu-devel

Il 30/03/2012 19:53, Anthony Liguori ha scritto:
>>>>
>>>> +#define FMT_timeval "%" PRId64 ".%06" PRId64
>>>
>>> Does %ld work instead of PRId64?
>>
>> That works for my 32 bit Debian, but it would fail on 64 bit Linux.
> 
> It works on my 64-bit Linux fwiw.

It would fail on x32, but it's a good start.  I could only fix it up
next Monday, so feel free to beat me to it.

Paolo

^ permalink raw reply	[flat|nested] 21+ messages in thread

end of thread, other threads:[~2012-03-30 18:37 UTC | newest]

Thread overview: 21+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2012-03-28 13:42 [Qemu-devel] [PATCH v4 0/7] new test infrastructure + qtest Paolo Bonzini
2012-03-28 13:42 ` [Qemu-devel] [PATCH v4 1/7] test makefile overhaul Paolo Bonzini
2012-03-28 13:42 ` [Qemu-devel] [PATCH v4 2/7] qtest: add test framework Paolo Bonzini
2012-03-30 17:40   ` Stefan Weil
2012-03-30 17:50     ` Anthony Liguori
2012-03-30 17:52       ` Stefan Weil
2012-03-30 17:53         ` Anthony Liguori
2012-03-30 18:37           ` Paolo Bonzini
2012-03-28 13:42 ` [Qemu-devel] [PATCH v4 3/7] qtest: IRQ interception infrastructure Paolo Bonzini
2012-03-28 13:42 ` [Qemu-devel] [PATCH v4 4/7] qtest: add clock management Paolo Bonzini
2012-03-28 13:42 ` [Qemu-devel] [PATCH v4 5/7] qtest: add C version of test infrastructure Paolo Bonzini
2012-03-28 13:42 ` [Qemu-devel] [PATCH v4 6/7] rtc: split out macros into a header file and use in test case Paolo Bonzini
2012-03-28 13:42 ` [Qemu-devel] [PATCH v4 7/7] qtest: add rtc-test test-case Paolo Bonzini
2012-03-30 17:15   ` Blue Swirl
2012-03-30 17:22     ` Blue Swirl
2012-03-30 17:49       ` Anthony Liguori
2012-03-30 17:53         ` Blue Swirl
2012-03-30 17:29     ` Anthony Liguori
2012-03-30 17:37       ` Blue Swirl
2012-03-28 17:43 ` [Qemu-devel] [PATCH v4 0/7] new test infrastructure + qtest Anthony Liguori
2012-03-30 14:45 ` Anthony Liguori

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.