qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
* [Qemu-devel] [PATCH 00/10] qtest: a testing framework for devices (v2)
@ 2012-02-25 19:42 Anthony Liguori
  2012-02-25 19:42 ` [Qemu-devel] [PATCH 01/10] qtest: add test framework (v2) Anthony Liguori
                   ` (9 more replies)
  0 siblings, 10 replies; 24+ messages in thread
From: Anthony Liguori @ 2012-02-25 19:42 UTC (permalink / raw)
  To: qemu-devel; +Cc: Kevin Wolf

Hi,

This is an updated version of the qtest patches I posted about a month ago.
I've included the RFC that Paolo posted in this series too.

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

* [Qemu-devel] [PATCH 01/10] qtest: add test framework (v2)
  2012-02-25 19:42 [Qemu-devel] [PATCH 00/10] qtest: a testing framework for devices (v2) Anthony Liguori
@ 2012-02-25 19:42 ` Anthony Liguori
  2012-02-25 20:19   ` Paolo Bonzini
  2012-02-25 19:42 ` [Qemu-devel] [PATCH 02/10] qtest: add support for -M pc Anthony Liguori
                   ` (8 subsequent siblings)
  9 siblings, 1 reply; 24+ messages in thread
From: Anthony Liguori @ 2012-02-25 19:42 UTC (permalink / raw)
  To: qemu-devel; +Cc: Kevin Wolf, Paolo Bonzini, Anthony Liguori

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.

This is currently modelled after Xen since the Xen device model does something
very similar.  Instead of hooking cpu_exec, Xen sticks the CPU in the halted
state making sure it never gets to execute.  In addition, Xen replaces the LAPIC
with a dummy interrupt controller that forwards interrupt requests.

qtest does the exact same thing and 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>
---
v1 -> v2
 - always send a response (Paolo)
 - enable echo (Paolo)
 - do not use TCG CPU threads (Paolo)
---
 Makefile.objs   |    2 +
 cpu-exec.c      |    1 +
 cpus.c          |   62 +++++++++-
 qemu-options.hx |    8 ++
 qtest.c         |  359 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 qtest.h         |   37 ++++++
 vl.c            |    8 ++
 7 files changed, 474 insertions(+), 3 deletions(-)
 create mode 100644 qtest.c
 create mode 100644 qtest.h

diff --git a/Makefile.objs b/Makefile.objs
index 808de6a..3372d9b 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -302,6 +302,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 2c2d24e..d476616 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 f45a438..c77e649 100644
--- a/cpus.c
+++ b/cpus.c
@@ -740,6 +740,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
+    CPUState *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)
@@ -797,7 +839,7 @@ void qemu_cpu_kick(void *_env)
     CPUState *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;
     }
@@ -826,7 +868,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;
@@ -929,6 +971,18 @@ static void qemu_kvm_start_vcpu(CPUState *env)
     }
 }
 
+static void qemu_dummy_start_vcpu(CPUState *env)
+{
+    env->thread = g_malloc0(sizeof(QemuThread));
+    env->halt_cond = g_malloc0(sizeof(QemuCond));
+    qemu_cond_init(env->halt_cond);
+    qemu_thread_create(env->thread, qemu_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)
 {
     CPUState *env = _env;
@@ -938,8 +992,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 b129996..3dca2dc 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -2698,6 +2698,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..c2fbf50
--- /dev/null
+++ b/qtest.c
@@ -0,0 +1,359 @@
+/*
+ * 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);
+    }
+}
+
+qemu_irq *qtest_interrupt_controller_init(void)
+{
+    return qemu_allocate_irqs(qtest_set_irq, NULL, MAX_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..f0e1377
--- /dev/null
+++ b/qtest.h
@@ -0,0 +1,37 @@
+/*
+ * 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);
+
+qemu_irq *qtest_interrupt_controller_init(void);
+
+#endif
diff --git a/vl.c b/vl.c
index 1d4c350..1473016 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"
 
@@ -2097,6 +2098,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)
@@ -3180,6 +3182,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.4.1

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

* [Qemu-devel] [PATCH 02/10] qtest: add support for -M pc
  2012-02-25 19:42 [Qemu-devel] [PATCH 00/10] qtest: a testing framework for devices (v2) Anthony Liguori
  2012-02-25 19:42 ` [Qemu-devel] [PATCH 01/10] qtest: add test framework (v2) Anthony Liguori
@ 2012-02-25 19:42 ` Anthony Liguori
  2012-02-25 20:19   ` Paolo Bonzini
  2012-02-25 19:42 ` [Qemu-devel] [PATCH 03/10] qtest: add C version of test infrastructure Anthony Liguori
                   ` (7 subsequent siblings)
  9 siblings, 1 reply; 24+ messages in thread
From: Anthony Liguori @ 2012-02-25 19:42 UTC (permalink / raw)
  To: qemu-devel; +Cc: Kevin Wolf, Anthony Liguori

This involves replacing the local APIC with the qtest interrupt controller.

It should be pretty straight forward to do the same for other machine types.

Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
---
 hw/pc_piix.c |    3 +++
 1 files changed, 3 insertions(+), 0 deletions(-)

diff --git a/hw/pc_piix.c b/hw/pc_piix.c
index 5e11d15..2c0881e 100644
--- a/hw/pc_piix.c
+++ b/hw/pc_piix.c
@@ -46,6 +46,7 @@
 #ifdef CONFIG_XEN
 #  include <xen/hvm/hvm_info_table.h>
 #endif
+#include "qtest.h"
 
 #define MAX_IDE_BUS 2
 
@@ -212,6 +213,8 @@ static void pc_init1(MemoryRegion *system_memory,
         i8259 = kvm_i8259_init(isa_bus);
     } else if (xen_enabled()) {
         i8259 = xen_interrupt_controller_init();
+    } else if (qtest_enabled()) {
+        i8259 = qtest_interrupt_controller_init();
     } else {
         cpu_irq = pc_allocate_cpu_irq();
         i8259 = i8259_init(isa_bus, cpu_irq[0]);
-- 
1.7.4.1

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

* [Qemu-devel] [PATCH 03/10] qtest: add C version of test infrastructure
  2012-02-25 19:42 [Qemu-devel] [PATCH 00/10] qtest: a testing framework for devices (v2) Anthony Liguori
  2012-02-25 19:42 ` [Qemu-devel] [PATCH 01/10] qtest: add test framework (v2) Anthony Liguori
  2012-02-25 19:42 ` [Qemu-devel] [PATCH 02/10] qtest: add support for -M pc Anthony Liguori
@ 2012-02-25 19:42 ` Anthony Liguori
  2012-03-02 22:17   ` Eduardo Habkost
  2012-02-25 19:42 ` [Qemu-devel] [PATCH 04/10] make: add check targets based on gtester (v2) Anthony Liguori
                   ` (6 subsequent siblings)
  9 siblings, 1 reply; 24+ messages in thread
From: Anthony Liguori @ 2012-02-25 19:42 UTC (permalink / raw)
  To: qemu-devel; +Cc: Kevin Wolf, Anthony Liguori

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>
---
 scripts/qtest    |    5 +
 tests/Makefile   |    2 +
 tests/libqtest.c |  334 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 tests/libqtest.h |   63 ++++++++++
 4 files changed, 404 insertions(+), 0 deletions(-)
 create mode 100644 scripts/qtest
 create mode 100644 tests/libqtest.c
 create mode 100644 tests/libqtest.h

diff --git a/scripts/qtest b/scripts/qtest
new file mode 100644
index 0000000..5cff3d4
--- /dev/null
+++ b/scripts/qtest
@@ -0,0 +1,5 @@
+#!/bin/sh
+
+export QTEST_QEMU_BINARY=$1
+shift
+eval "$@"
diff --git a/tests/Makefile b/tests/Makefile
index 74b29dc..3c554f0 100644
--- a/tests/Makefile
+++ b/tests/Makefile
@@ -42,6 +42,8 @@ test-qmp-input-visitor: test-qmp-input-visitor.o $(qobject-obj-y) $(qapi-obj-y)
 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
 
+tests/rtc-test: tests/rtc-test.o tests/libqtest.o
+
 .PHONY: check
 check: $(CHECKS)
 	$(call quiet-command, gtester $(CHECKS), "  CHECK")
diff --git a/tests/libqtest.c b/tests/libqtest.c
new file mode 100644
index 0000000..dd07b07
--- /dev/null
+++ b/tests/libqtest.c
@@ -0,0 +1,334 @@
+/*
+ * QTest
+ *
+ * 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 <glib.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/wait.h>
+#include <sys/un.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.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;
+
+    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);
+
+    pid = fork();
+    if (pid == 0) {
+        command = g_strdup_printf("%s "
+                                  "-qtest unix:%s,server,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 {
+        sleep(1);
+        ret = connect(sock, (struct sockaddr *)&addr, sizeof(addr));
+    } while (ret == -1);
+    g_assert_no_errno(ret);
+
+    s->fd = sock;
+    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 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..dd82926
--- /dev/null
+++ b/tests/libqtest.h
@@ -0,0 +1,63 @@
+/*
+ * QTest
+ *
+ * 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.
+ *
+ */
+#ifndef LIBQTEST_H
+#define LIBQTEST_H
+
+#include <stdint.h>
+#include <stdbool.h>
+#include <sys/types.h>
+
+typedef struct QTestState QTestState;
+
+extern QTestState *global_qtest;
+
+QTestState *qtest_init(const char *extra_args);
+void qtest_quit(QTestState *s);
+
+bool qtest_get_irq(QTestState *s, int num);
+
+void qtest_outb(QTestState *s, uint16_t addr, uint8_t value);
+
+void qtest_outw(QTestState *s, uint16_t addr, uint16_t value);
+
+void qtest_outl(QTestState *s, uint16_t addr, uint32_t value);
+
+uint8_t qtest_inb(QTestState *s, uint16_t addr);
+
+uint16_t qtest_inw(QTestState *s, uint16_t addr);
+
+uint32_t qtest_inl(QTestState *s, uint16_t addr);
+
+void qtest_memread(QTestState *s, uint64_t addr, void *data, size_t size);
+
+void qtest_memwrite(QTestState *s, uint64_t addr, const void *data, size_t size);
+
+const char *qtest_get_arch(void);
+
+void qtest_add_func(const char *str, void (*fn));
+
+#define qtest_start(args) (            \
+    global_qtest = qtest_init((args)) \
+        )
+
+#define get_irq(num) qtest_get_irq(global_qtest, (num))
+#define outb(addr, val) qtest_outb(global_qtest, (addr), (val))
+#define outw(addr, val) qtest_outw(global_qtest, (addr), (val))
+#define outl(addr, val) qtest_outl(global_qtest, (addr), (val))
+#define inb(addr) qtest_inb(global_qtest, (addr))
+#define inw(addr) qtest_inw(global_qtest, (addr))
+#define inl(addr) qtest_inl(global_qtest, (addr))
+#define memread(addr, data, size) qtest_memread(global_qtest, (addr), (data), (size))
+#define memwrite(addr, data, size) qtest_memwrite(global_qtest, (addr), (data), (size))
+
+#endif
-- 
1.7.4.1

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

* [Qemu-devel] [PATCH 04/10] make: add check targets based on gtester (v2)
  2012-02-25 19:42 [Qemu-devel] [PATCH 00/10] qtest: a testing framework for devices (v2) Anthony Liguori
                   ` (2 preceding siblings ...)
  2012-02-25 19:42 ` [Qemu-devel] [PATCH 03/10] qtest: add C version of test infrastructure Anthony Liguori
@ 2012-02-25 19:42 ` Anthony Liguori
  2012-02-25 19:42 ` [Qemu-devel] [PATCH 05/10] rtc: split out macros into a header file and use in test case Anthony Liguori
                   ` (5 subsequent siblings)
  9 siblings, 0 replies; 24+ messages in thread
From: Anthony Liguori @ 2012-02-25 19:42 UTC (permalink / raw)
  To: qemu-devel; +Cc: Kevin Wolf, Paolo Bonzini, Anthony Liguori

This will run all tests through gtester.  The main targets are:

$ make check

Which will run each unit test and:

$ make check-report.html

Which will generate a nice HTML report of the test status.

Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
v1 -> v2
 - fix Makefile (Paolo)
---
 scripts/gtester-cat |   32 ++++++++++++++++++++++++++++
 tests/Makefile      |   58 ++++++++++++++++++++++++++++++++++++++++++++++++--
 2 files changed, 87 insertions(+), 3 deletions(-)
 create mode 100644 scripts/gtester-cat

diff --git a/scripts/gtester-cat b/scripts/gtester-cat
new file mode 100644
index 0000000..afd8c3e
--- /dev/null
+++ b/scripts/gtester-cat
@@ -0,0 +1,32 @@
+#!/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>
+EOF
+
+for file in "$@"; do
+    first="yes"
+    cat $file | while read LINE; do
+	if test "$first" = "yes"; then
+	    first="no"
+	    continue
+	fi
+	if test "$LINE" = "<gtester>" -o "$LINE" = "</gtester>"; then
+	    continue
+	fi
+	echo $LINE
+    done
+done
+
+cat<<EOF
+</gtester>
+EOF
diff --git a/tests/Makefile b/tests/Makefile
index 3c554f0..f41a00b 100644
--- a/tests/Makefile
+++ b/tests/Makefile
@@ -2,6 +2,10 @@ 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
 
+HW_TESTS=
+
+TARGETS=$(patsubst %-softmmu,%, $(filter %-softmmu,$(TARGET_DIRS)))
+
 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)
@@ -44,6 +48,54 @@ test-qmp-commands: test-qmp-commands.o $(qobject-obj-y) $(qapi-obj-y) $(tools-ob
 
 tests/rtc-test: tests/rtc-test.o tests/libqtest.o
 
-.PHONY: check
-check: $(CHECKS)
-	$(call quiet-command, gtester $(CHECKS), "  CHECK")
+check-help:
+	@echo "Regression targets:"
+	@echo
+	@echo " make check                Run all tests"
+	@echo " make check-qtest          Run qtest tests"
+	@echo " make check-unit           Run qobject 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"
+
+.SECONDARY:
+
+SPEED ?= quick
+
+# Reports
+check-report-qtest-%.log: $(HW_TESTS)
+	$(call quiet-command,QTEST_QEMU_BINARY=`basename $@ .log | cut -f4 -d-`-softmmu/qemu-system-`basename $@ .log | cut -f4 -d-` \
+	  gtester -k -q -o $@ -m=$(SPEED) $(HW_TESTS),"  TEST   $^ (`basename $@ .log | cut -f4 -d-`)")
+
+check-report-unit.log: $(CHECKS)
+	$(call quiet-command,gtester -k -q -m=$(SPEED) -o $@ $^, "  TEST   $^")
+
+check-report.log: check-report-unit.log $(patsubst %,check-report-qtest-%.log, $(TARGETS))
+	$(call quiet-command,$(SRC_PATH)/scripts/gtester-cat $^ > $@, "  GEN    $@")
+
+check-report.html: check-report.log
+	$(call quiet-command,gtester-report $< > $@, "  GEN    $@")
+
+# Check tests
+
+check-qtest-%: $(HW_TESTS)
+	@for test in $^; do \
+	    arch=`echo $@ | cut -f3- -d-`; \
+	    echo "Running '$$test' with qemu-system-$$arch..."; \
+	    $(SRC_PATH)/scripts/qtest $$arch-softmmu/qemu-system-$$arch $$test || exit $$?; \
+	done
+
+check-qtest: $(patsubst %,check-qtest-%, $(TARGETS))
+
+check-unit: $(CHECKS)
+	@for test in $^; do \
+	    echo "Running '$$test'..."; \
+	    ./$$test || exit $?; \
+	done
+
+check: check-unit check-qtest
+
+.PHONY: check-help check-qtest check-unit check
-- 
1.7.4.1

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

* [Qemu-devel] [PATCH 05/10] rtc: split out macros into a header file and use in test case
  2012-02-25 19:42 [Qemu-devel] [PATCH 00/10] qtest: a testing framework for devices (v2) Anthony Liguori
                   ` (3 preceding siblings ...)
  2012-02-25 19:42 ` [Qemu-devel] [PATCH 04/10] make: add check targets based on gtester (v2) Anthony Liguori
@ 2012-02-25 19:42 ` Anthony Liguori
  2012-02-25 19:42 ` [Qemu-devel] [PATCH 06/10] qtest: add rtc-test test-case (v2) Anthony Liguori
                   ` (4 subsequent siblings)
  9 siblings, 0 replies; 24+ messages in thread
From: Anthony Liguori @ 2012-02-25 19:42 UTC (permalink / raw)
  To: qemu-devel; +Cc: Kevin Wolf, Anthony Liguori

Signed-off-by: Anthony Liguori <aliguori@us.ibm.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 a46fdfc..e7c080c 100644
--- a/hw/mc146818rtc.c
+++ b/hw/mc146818rtc.c
@@ -46,39 +46,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.4.1

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

* [Qemu-devel] [PATCH 06/10] qtest: add rtc-test test-case (v2)
  2012-02-25 19:42 [Qemu-devel] [PATCH 00/10] qtest: a testing framework for devices (v2) Anthony Liguori
                   ` (4 preceding siblings ...)
  2012-02-25 19:42 ` [Qemu-devel] [PATCH 05/10] rtc: split out macros into a header file and use in test case Anthony Liguori
@ 2012-02-25 19:42 ` Anthony Liguori
  2012-02-25 20:20   ` Paolo Bonzini
  2012-02-25 20:41   ` Stefan Weil
  2012-02-25 19:42 ` [Qemu-devel] [PATCH 07/10] qtest: IRQ interception infrastructure (v2) Anthony Liguori
                   ` (3 subsequent siblings)
  9 siblings, 2 replies; 24+ messages in thread
From: Anthony Liguori @ 2012-02-25 19:42 UTC (permalink / raw)
  To: qemu-devel; +Cc: Kevin Wolf, Paolo Bonzini, Anthony Liguori

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

diff --git a/tests/Makefile b/tests/Makefile
index f41a00b..feacbf0 100644
--- a/tests/Makefile
+++ b/tests/Makefile
@@ -2,7 +2,7 @@ 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
 
-HW_TESTS=
+HW_TESTS=tests/rtc-test
 
 TARGETS=$(patsubst %-softmmu,%, $(filter %-softmmu,$(TARGET_DIRS)))
 
diff --git a/tests/rtc-test.c b/tests/rtc-test.c
new file mode 100644
index 0000000..1645b34
--- /dev/null
+++ b/tests/rtc-test.c
@@ -0,0 +1,267 @@
+/*
+ * QTest
+ *
+ * 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));
+
+    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;
+        }
+
+        sleep(1);
+    }
+
+    g_assert(get_irq(RTC_ISA_IRQ));
+}
+
+int main(int argc, char **argv)
+{
+    const char *arch;
+    QTestState *s = NULL;
+    int ret;
+
+    g_test_init(&argc, &argv, NULL);
+
+    arch = qtest_get_arch();
+    /* These tests only work on i386 and x86_64 */
+    if (strcmp(arch, "i386") == 0 || strcmp(arch, "x86_64") == 0) {
+        s = qtest_start("-vnc none");
+
+        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);
+    } else {
+        g_test_message("Skipping unsupported arch `%s'\n", arch);
+    }
+
+    ret = g_test_run();
+
+    if (s) {
+        qtest_quit(s);
+    }
+
+    return ret;
+}
-- 
1.7.4.1

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

* [Qemu-devel] [PATCH 07/10] qtest: IRQ interception infrastructure (v2)
  2012-02-25 19:42 [Qemu-devel] [PATCH 00/10] qtest: a testing framework for devices (v2) Anthony Liguori
                   ` (5 preceding siblings ...)
  2012-02-25 19:42 ` [Qemu-devel] [PATCH 06/10] qtest: add rtc-test test-case (v2) Anthony Liguori
@ 2012-02-25 19:42 ` Anthony Liguori
  2012-02-25 20:20   ` Paolo Bonzini
  2012-02-25 19:42 ` [Qemu-devel] [PATCH 08/10] libqtest: add IRQ intercept commands Anthony Liguori
                   ` (2 subsequent siblings)
  9 siblings, 1 reply; 24+ messages in thread
From: Anthony Liguori @ 2012-02-25 19:42 UTC (permalink / raw)
  To: qemu-devel; +Cc: Kevin Wolf, Paolo Bonzini, Anthony Liguori

From: Paolo Bonzini <pbonzini@redhat.com>

Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
---
v1 -> v2
 - rebased to latest (aliguori)
---
 hw/irq.c     |   17 ++++++++++
 hw/irq.h     |    5 +++
 hw/pc_piix.c |    9 +++--
 qtest.c      |   97 ++++++++++++++++++++++++++++++++++++++++-----------------
 qtest.h      |    2 -
 5 files changed, 95 insertions(+), 35 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 2c0881e..36c06d5 100644
--- a/hw/pc_piix.c
+++ b/hw/pc_piix.c
@@ -99,7 +99,7 @@ static void kvm_piix3_gsi_handler(void *opaque, int n, int level)
     }
 }
 
-static void ioapic_init(GSIState *gsi_state)
+static DeviceState *ioapic_init(GSIState *gsi_state)
 {
     DeviceState *dev;
     SysBusDevice *d;
@@ -117,6 +117,7 @@ static void ioapic_init(GSIState *gsi_state)
     for (i = 0; i < IOAPIC_NUM_PINS; i++) {
         gsi_state->ioapic_irq[i] = qdev_get_gpio_in(dev, i);
     }
+    return dev;
 }
 
 /* PC hardware initialisation */
@@ -213,8 +214,6 @@ static void pc_init1(MemoryRegion *system_memory,
         i8259 = kvm_i8259_init(isa_bus);
     } else if (xen_enabled()) {
         i8259 = xen_interrupt_controller_init();
-    } else if (qtest_enabled()) {
-        i8259 = qtest_interrupt_controller_init();
     } else {
         cpu_irq = pc_allocate_cpu_irq();
         i8259 = i8259_init(isa_bus, cpu_irq[0]);
@@ -224,7 +223,9 @@ static void pc_init1(MemoryRegion *system_memory,
         gsi_state->i8259_irq[i] = i8259[i];
     }
     if (pci_enabled) {
-        ioapic_init(gsi_state);
+        dev = ioapic_init(gsi_state);
+        object_property_add_child(object_resolve_path("/i440fx/piix3", NULL),
+                                  "ioapic", OBJECT(dev), NULL);
     }
 
     pc_register_ferr_irq(gsi[13]);
diff --git a/qtest.c b/qtest.c
index c2fbf50..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,26 +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);
-    }
-}
-
-qemu_irq *qtest_interrupt_controller_init(void)
-{
-    return qemu_allocate_irqs(qtest_set_irq, NULL, MAX_IRQ);
-}
-
 int qtest_init(void)
 {
     CharDriverState *chr;
diff --git a/qtest.h b/qtest.h
index f0e1377..1478343 100644
--- a/qtest.h
+++ b/qtest.h
@@ -32,6 +32,4 @@ static inline int qtest_available(void)
 
 int qtest_init(void);
 
-qemu_irq *qtest_interrupt_controller_init(void);
-
 #endif
-- 
1.7.4.1

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

* [Qemu-devel] [PATCH 08/10] libqtest: add IRQ intercept commands
  2012-02-25 19:42 [Qemu-devel] [PATCH 00/10] qtest: a testing framework for devices (v2) Anthony Liguori
                   ` (6 preceding siblings ...)
  2012-02-25 19:42 ` [Qemu-devel] [PATCH 07/10] qtest: IRQ interception infrastructure (v2) Anthony Liguori
@ 2012-02-25 19:42 ` Anthony Liguori
  2012-02-25 19:42 ` [Qemu-devel] [PATCH 09/10] rtc-test: add IRQ intercept Anthony Liguori
  2012-02-25 19:42 ` [Qemu-devel] [PATCH 10/10] qtest: add clock management Anthony Liguori
  9 siblings, 0 replies; 24+ messages in thread
From: Anthony Liguori @ 2012-02-25 19:42 UTC (permalink / raw)
  To: qemu-devel; +Cc: Kevin Wolf, Paolo Bonzini, Anthony Liguori

From: Paolo Bonzini <pbonzini@redhat.com>

Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
---
 tests/libqtest.c |   12 ++++++++++++
 tests/libqtest.h |    6 ++++++
 2 files changed, 18 insertions(+), 0 deletions(-)

diff --git a/tests/libqtest.c b/tests/libqtest.c
index dd07b07..1d1b06e 100644
--- a/tests/libqtest.c
+++ b/tests/libqtest.c
@@ -235,6 +235,18 @@ bool qtest_get_irq(QTestState *s, int num)
     return s->irq_level[num];
 }
 
+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);
diff --git a/tests/libqtest.h b/tests/libqtest.h
index dd82926..b5ca04e 100644
--- a/tests/libqtest.h
+++ b/tests/libqtest.h
@@ -26,6 +26,10 @@ void qtest_quit(QTestState *s);
 
 bool qtest_get_irq(QTestState *s, int num);
 
+void qtest_irq_intercept_in(QTestState *s, const char *string);
+
+void qtest_irq_intercept_out(QTestState *s, const char *string);
+
 void qtest_outb(QTestState *s, uint16_t addr, uint8_t value);
 
 void qtest_outw(QTestState *s, uint16_t addr, uint16_t value);
@@ -51,6 +55,8 @@ void qtest_add_func(const char *str, void (*fn));
         )
 
 #define get_irq(num) qtest_get_irq(global_qtest, (num))
+#define irq_intercept_in(num) qtest_irq_intercept_in(global_qtest, (num))
+#define irq_intercept_out(num) qtest_irq_intercept_out(global_qtest, (num))
 #define outb(addr, val) qtest_outb(global_qtest, (addr), (val))
 #define outw(addr, val) qtest_outw(global_qtest, (addr), (val))
 #define outl(addr, val) qtest_outl(global_qtest, (addr), (val))
-- 
1.7.4.1

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

* [Qemu-devel] [PATCH 09/10] rtc-test: add IRQ intercept
  2012-02-25 19:42 [Qemu-devel] [PATCH 00/10] qtest: a testing framework for devices (v2) Anthony Liguori
                   ` (7 preceding siblings ...)
  2012-02-25 19:42 ` [Qemu-devel] [PATCH 08/10] libqtest: add IRQ intercept commands Anthony Liguori
@ 2012-02-25 19:42 ` Anthony Liguori
  2012-02-25 19:42 ` [Qemu-devel] [PATCH 10/10] qtest: add clock management Anthony Liguori
  9 siblings, 0 replies; 24+ messages in thread
From: Anthony Liguori @ 2012-02-25 19:42 UTC (permalink / raw)
  To: qemu-devel; +Cc: Kevin Wolf, Paolo Bonzini, Anthony Liguori

From: Paolo Bonzini <pbonzini@redhat.com>

Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
---
 tests/rtc-test.c |    1 +
 1 files changed, 1 insertions(+), 0 deletions(-)

diff --git a/tests/rtc-test.c b/tests/rtc-test.c
index 1645b34..8280f45 100644
--- a/tests/rtc-test.c
+++ b/tests/rtc-test.c
@@ -249,6 +249,7 @@ int main(int argc, char **argv)
     /* These tests only work on i386 and x86_64 */
     if (strcmp(arch, "i386") == 0 || strcmp(arch, "x86_64") == 0) {
         s = qtest_start("-vnc none");
+        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);
-- 
1.7.4.1

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

* [Qemu-devel] [PATCH 10/10] qtest: add clock management
  2012-02-25 19:42 [Qemu-devel] [PATCH 00/10] qtest: a testing framework for devices (v2) Anthony Liguori
                   ` (8 preceding siblings ...)
  2012-02-25 19:42 ` [Qemu-devel] [PATCH 09/10] rtc-test: add IRQ intercept Anthony Liguori
@ 2012-02-25 19:42 ` Anthony Liguori
  9 siblings, 0 replies; 24+ messages in thread
From: Anthony Liguori @ 2012-02-25 19:42 UTC (permalink / raw)
  To: qemu-devel; +Cc: Kevin Wolf, Paolo Bonzini, Anthony Liguori

From: Paolo Bonzini <pbonzini@redhat.com>

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 c77e649..875984a 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.4.1

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

* Re: [Qemu-devel] [PATCH 02/10] qtest: add support for -M pc
  2012-02-25 19:42 ` [Qemu-devel] [PATCH 02/10] qtest: add support for -M pc Anthony Liguori
@ 2012-02-25 20:19   ` Paolo Bonzini
  2012-02-25 21:12     ` Anthony Liguori
  0 siblings, 1 reply; 24+ messages in thread
From: Paolo Bonzini @ 2012-02-25 20:19 UTC (permalink / raw)
  To: qemu-devel

On 02/25/2012 08:42 PM, Anthony Liguori wrote:
> This involves replacing the local APIC with the qtest interrupt controller.
> 
> It should be pretty straight forward to do the same for other machine types.
> 
> Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
> ---
>  hw/pc_piix.c |    3 +++
>  1 files changed, 3 insertions(+), 0 deletions(-)
> 
> diff --git a/hw/pc_piix.c b/hw/pc_piix.c
> index 5e11d15..2c0881e 100644
> --- a/hw/pc_piix.c
> +++ b/hw/pc_piix.c
> @@ -46,6 +46,7 @@
>  #ifdef CONFIG_XEN
>  #  include <xen/hvm/hvm_info_table.h>
>  #endif
> +#include "qtest.h"
>  
>  #define MAX_IDE_BUS 2
>  
> @@ -212,6 +213,8 @@ static void pc_init1(MemoryRegion *system_memory,
>          i8259 = kvm_i8259_init(isa_bus);
>      } else if (xen_enabled()) {
>          i8259 = xen_interrupt_controller_init();
> +    } else if (qtest_enabled()) {
> +        i8259 = qtest_interrupt_controller_init();
>      } else {
>          cpu_irq = pc_allocate_cpu_irq();
>          i8259 = i8259_init(isa_bus, cpu_irq[0]);

This is not needed anymore.

Paolo

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

* Re: [Qemu-devel] [PATCH 01/10] qtest: add test framework (v2)
  2012-02-25 19:42 ` [Qemu-devel] [PATCH 01/10] qtest: add test framework (v2) Anthony Liguori
@ 2012-02-25 20:19   ` Paolo Bonzini
  0 siblings, 0 replies; 24+ messages in thread
From: Paolo Bonzini @ 2012-02-25 20:19 UTC (permalink / raw)
  To: qemu-devel

On 02/25/2012 08:42 PM, Anthony Liguori wrote:
> +
> +qemu_irq *qtest_interrupt_controller_init(void)
> +{
> +    return qemu_allocate_irqs(qtest_set_irq, NULL, MAX_IRQ);
> +}

This should not be needed anymore.

Paolo

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

* Re: [Qemu-devel] [PATCH 07/10] qtest: IRQ interception infrastructure (v2)
  2012-02-25 19:42 ` [Qemu-devel] [PATCH 07/10] qtest: IRQ interception infrastructure (v2) Anthony Liguori
@ 2012-02-25 20:20   ` Paolo Bonzini
  2012-02-25 21:16     ` Anthony Liguori
  0 siblings, 1 reply; 24+ messages in thread
From: Paolo Bonzini @ 2012-02-25 20:20 UTC (permalink / raw)
  To: qemu-devel

On 02/25/2012 08:42 PM, Anthony Liguori wrote:
> @@ -224,7 +223,9 @@ static void pc_init1(MemoryRegion *system_memory,
>          gsi_state->i8259_irq[i] = i8259[i];
>      }
>      if (pci_enabled) {
> -        ioapic_init(gsi_state);
> +        dev = ioapic_init(gsi_state);
> +        object_property_add_child(object_resolve_path("/i440fx/piix3", NULL),
> +                                  "ioapic", OBJECT(dev), NULL);
>      }
>  
>      pc_register_ferr_irq(gsi[13]);

Jan objected to putting this under /i440fx/piix3.

Paolo

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

* Re: [Qemu-devel] [PATCH 06/10] qtest: add rtc-test test-case (v2)
  2012-02-25 19:42 ` [Qemu-devel] [PATCH 06/10] qtest: add rtc-test test-case (v2) Anthony Liguori
@ 2012-02-25 20:20   ` Paolo Bonzini
  2012-02-25 20:41   ` Stefan Weil
  1 sibling, 0 replies; 24+ messages in thread
From: Paolo Bonzini @ 2012-02-25 20:20 UTC (permalink / raw)
  To: qemu-devel

On 02/25/2012 08:42 PM, Anthony Liguori wrote:
> Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
> ---
> v1 -> v2
>  - fix set_alarm_time (Paolo)
> ---
>  tests/Makefile   |    2 +-
>  tests/rtc-test.c |  267 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
>  2 files changed, 268 insertions(+), 1 deletions(-)
>  create mode 100644 tests/rtc-test.c
> 
> diff --git a/tests/Makefile b/tests/Makefile
> index f41a00b..feacbf0 100644
> --- a/tests/Makefile
> +++ b/tests/Makefile
> @@ -2,7 +2,7 @@ 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
>  
> -HW_TESTS=
> +HW_TESTS=tests/rtc-test
>  
>  TARGETS=$(patsubst %-softmmu,%, $(filter %-softmmu,$(TARGET_DIRS)))
>  
> diff --git a/tests/rtc-test.c b/tests/rtc-test.c
> new file mode 100644
> index 0000000..1645b34
> --- /dev/null
> +++ b/tests/rtc-test.c
> @@ -0,0 +1,267 @@
> +/*
> + * QTest
> + *
> + * 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));
> +
> +    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;
> +        }
> +
> +        sleep(1);
> +    }
> +
> +    g_assert(get_irq(RTC_ISA_IRQ));
> +}
> +
> +int main(int argc, char **argv)
> +{
> +    const char *arch;
> +    QTestState *s = NULL;
> +    int ret;
> +
> +    g_test_init(&argc, &argv, NULL);
> +
> +    arch = qtest_get_arch();
> +    /* These tests only work on i386 and x86_64 */
> +    if (strcmp(arch, "i386") == 0 || strcmp(arch, "x86_64") == 0) {
> +        s = qtest_start("-vnc none");
> +
> +        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);
> +    } else {
> +        g_test_message("Skipping unsupported arch `%s'\n", arch);
> +    }
> +
> +    ret = g_test_run();
> +
> +    if (s) {
> +        qtest_quit(s);
> +    }
> +
> +    return ret;
> +}

Please squash this into patch 9 (i.e. move it after 7 and 8).

Paolo

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

* Re: [Qemu-devel] [PATCH 06/10] qtest: add rtc-test test-case (v2)
  2012-02-25 19:42 ` [Qemu-devel] [PATCH 06/10] qtest: add rtc-test test-case (v2) Anthony Liguori
  2012-02-25 20:20   ` Paolo Bonzini
@ 2012-02-25 20:41   ` Stefan Weil
  1 sibling, 0 replies; 24+ messages in thread
From: Stefan Weil @ 2012-02-25 20:41 UTC (permalink / raw)
  To: Anthony Liguori; +Cc: Kevin Wolf, Paolo Bonzini, qemu-devel

Am 25.02.2012 20:42, schrieb Anthony Liguori:
> Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
> ---
> v1 -> v2
> - fix set_alarm_time (Paolo)
> ---
> tests/Makefile | 2 +-
> tests/rtc-test.c | 267 
> ++++++++++++++++++++++++++++++++++++++++++++++++++++++
> 2 files changed, 268 insertions(+), 1 deletions(-)
> create mode 100644 tests/rtc-test.c
>
> diff --git a/tests/Makefile b/tests/Makefile
> index f41a00b..feacbf0 100644
> --- a/tests/Makefile
> +++ b/tests/Makefile
> @@ -2,7 +2,7 @@ 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
>
> -HW_TESTS=
> +HW_TESTS=tests/rtc-test

Would you mind adding $(EXESUF) to all new executables?
And could you please apply my patch which adds $(EXESUF)
to the existing test executables? Otherwise I'd have to
rebase it again. See
http://lists.nongnu.org/archive/html/qemu-devel/2012-02/msg03096.html

Running the tests on w32 hosts is required because there are
w32 specific implementations for coroutines, timers, ...
whichneed tests, too.

Thanks,

Stefan Weil

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

* Re: [Qemu-devel] [PATCH 02/10] qtest: add support for -M pc
  2012-02-25 20:19   ` Paolo Bonzini
@ 2012-02-25 21:12     ` Anthony Liguori
  2012-02-25 21:21       ` Andreas Färber
  2012-02-25 21:39       ` Paolo Bonzini
  0 siblings, 2 replies; 24+ messages in thread
From: Anthony Liguori @ 2012-02-25 21:12 UTC (permalink / raw)
  To: Paolo Bonzini; +Cc: qemu-devel

On 02/25/2012 02:19 PM, Paolo Bonzini wrote:
> On 02/25/2012 08:42 PM, Anthony Liguori wrote:
>> This involves replacing the local APIC with the qtest interrupt controller.
>>
>> It should be pretty straight forward to do the same for other machine types.
>>
>> Signed-off-by: Anthony Liguori<aliguori@us.ibm.com>
>> ---
>>   hw/pc_piix.c |    3 +++
>>   1 files changed, 3 insertions(+), 0 deletions(-)
>>
>> diff --git a/hw/pc_piix.c b/hw/pc_piix.c
>> index 5e11d15..2c0881e 100644
>> --- a/hw/pc_piix.c
>> +++ b/hw/pc_piix.c
>> @@ -46,6 +46,7 @@
>>   #ifdef CONFIG_XEN
>>   #  include<xen/hvm/hvm_info_table.h>
>>   #endif
>> +#include "qtest.h"
>>
>>   #define MAX_IDE_BUS 2
>>
>> @@ -212,6 +213,8 @@ static void pc_init1(MemoryRegion *system_memory,
>>           i8259 = kvm_i8259_init(isa_bus);
>>       } else if (xen_enabled()) {
>>           i8259 = xen_interrupt_controller_init();
>> +    } else if (qtest_enabled()) {
>> +        i8259 = qtest_interrupt_controller_init();
>>       } else {
>>           cpu_irq = pc_allocate_cpu_irq();
>>           i8259 = i8259_init(isa_bus, cpu_irq[0]);
>
> This is not needed anymore.

Why?  This is necessary for IRQ to work.

You mean, if you use irq_intercept, this isn't needed?

Regards,

Anthony Liguori

>
> Paolo
>
>

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

* Re: [Qemu-devel] [PATCH 07/10] qtest: IRQ interception infrastructure (v2)
  2012-02-25 20:20   ` Paolo Bonzini
@ 2012-02-25 21:16     ` Anthony Liguori
  2012-02-26  1:31       ` Andreas Färber
  0 siblings, 1 reply; 24+ messages in thread
From: Anthony Liguori @ 2012-02-25 21:16 UTC (permalink / raw)
  To: Paolo Bonzini; +Cc: Jan Kiszka, qemu-devel

On 02/25/2012 02:20 PM, Paolo Bonzini wrote:
> On 02/25/2012 08:42 PM, Anthony Liguori wrote:
>> @@ -224,7 +223,9 @@ static void pc_init1(MemoryRegion *system_memory,
>>           gsi_state->i8259_irq[i] = i8259[i];
>>       }
>>       if (pci_enabled) {
>> -        ioapic_init(gsi_state);
>> +        dev = ioapic_init(gsi_state);
>> +        object_property_add_child(object_resolve_path("/i440fx/piix3", NULL),
>> +                                  "ioapic", OBJECT(dev), NULL);
>>       }
>>
>>       pc_register_ferr_irq(gsi[13]);
>
> Jan objected to putting this under /i440fx/piix3.

It's not technically part of the PIIX3 packaging, but the I/O APIC is attached 
to the PIIX3 and it's I/O requests propagate through the I/O APIC.  See section 
8.12 of the PIIX4 manual.

I think for our model, having it as a child property makes quite a lot of sense.

Regards,

Anthony Liguori

> Paolo
>
>

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

* Re: [Qemu-devel] [PATCH 02/10] qtest: add support for -M pc
  2012-02-25 21:12     ` Anthony Liguori
@ 2012-02-25 21:21       ` Andreas Färber
  2012-02-25 21:29         ` Anthony Liguori
  2012-02-25 21:39       ` Paolo Bonzini
  1 sibling, 1 reply; 24+ messages in thread
From: Andreas Färber @ 2012-02-25 21:21 UTC (permalink / raw)
  To: Anthony Liguori; +Cc: Paolo Bonzini, qemu-devel

Am 25.02.2012 22:12, schrieb Anthony Liguori:
> On 02/25/2012 02:19 PM, Paolo Bonzini wrote:
>> On 02/25/2012 08:42 PM, Anthony Liguori wrote:
>>> This involves replacing the local APIC with the qtest interrupt
>>> controller.
>>>
>>> It should be pretty straight forward to do the same for other machine
>>> types.
>>>
>>> Signed-off-by: Anthony Liguori<aliguori@us.ibm.com>
>>> ---
>>>   hw/pc_piix.c |    3 +++
>>>   1 files changed, 3 insertions(+), 0 deletions(-)
>>>
>>> diff --git a/hw/pc_piix.c b/hw/pc_piix.c
>>> index 5e11d15..2c0881e 100644
>>> --- a/hw/pc_piix.c
>>> +++ b/hw/pc_piix.c
>>> @@ -46,6 +46,7 @@
>>>   #ifdef CONFIG_XEN
>>>   #  include<xen/hvm/hvm_info_table.h>
>>>   #endif
>>> +#include "qtest.h"
>>>
>>>   #define MAX_IDE_BUS 2
>>>
>>> @@ -212,6 +213,8 @@ static void pc_init1(MemoryRegion *system_memory,
>>>           i8259 = kvm_i8259_init(isa_bus);
>>>       } else if (xen_enabled()) {
>>>           i8259 = xen_interrupt_controller_init();
>>> +    } else if (qtest_enabled()) {
>>> +        i8259 = qtest_interrupt_controller_init();
>>>       } else {
>>>           cpu_irq = pc_allocate_cpu_irq();
>>>           i8259 = i8259_init(isa_bus, cpu_irq[0]);
>>
>> This is not needed anymore.
> 
> Why?  This is necessary for IRQ to work.
> 
> You mean, if you use irq_intercept, this isn't needed?

The reason for Paolo's RFC was to _avoid_ having to touch every target
with code such as the above, no?

Andreas

-- 
SUSE LINUX Products GmbH, Maxfeldstr. 5, 90409 Nürnberg, Germany
GF: Jeff Hawn, Jennifer Guild, Felix Imendörffer; HRB 16746 AG Nürnberg

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

* Re: [Qemu-devel] [PATCH 02/10] qtest: add support for -M pc
  2012-02-25 21:21       ` Andreas Färber
@ 2012-02-25 21:29         ` Anthony Liguori
  0 siblings, 0 replies; 24+ messages in thread
From: Anthony Liguori @ 2012-02-25 21:29 UTC (permalink / raw)
  To: Andreas Färber; +Cc: Paolo Bonzini, qemu-devel

On 02/25/2012 03:21 PM, Andreas Färber wrote:
> Am 25.02.2012 22:12, schrieb Anthony Liguori:
>> On 02/25/2012 02:19 PM, Paolo Bonzini wrote:
>>> On 02/25/2012 08:42 PM, Anthony Liguori wrote:
>>>> This involves replacing the local APIC with the qtest interrupt
>>>> controller.
>>>>
>>>> It should be pretty straight forward to do the same for other machine
>>>> types.
>>>>
>>>> Signed-off-by: Anthony Liguori<aliguori@us.ibm.com>
>>>> ---
>>>>    hw/pc_piix.c |    3 +++
>>>>    1 files changed, 3 insertions(+), 0 deletions(-)
>>>>
>>>> diff --git a/hw/pc_piix.c b/hw/pc_piix.c
>>>> index 5e11d15..2c0881e 100644
>>>> --- a/hw/pc_piix.c
>>>> +++ b/hw/pc_piix.c
>>>> @@ -46,6 +46,7 @@
>>>>    #ifdef CONFIG_XEN
>>>>    #  include<xen/hvm/hvm_info_table.h>
>>>>    #endif
>>>> +#include "qtest.h"
>>>>
>>>>    #define MAX_IDE_BUS 2
>>>>
>>>> @@ -212,6 +213,8 @@ static void pc_init1(MemoryRegion *system_memory,
>>>>            i8259 = kvm_i8259_init(isa_bus);
>>>>        } else if (xen_enabled()) {
>>>>            i8259 = xen_interrupt_controller_init();
>>>> +    } else if (qtest_enabled()) {
>>>> +        i8259 = qtest_interrupt_controller_init();
>>>>        } else {
>>>>            cpu_irq = pc_allocate_cpu_irq();
>>>>            i8259 = i8259_init(isa_bus, cpu_irq[0]);
>>>
>>> This is not needed anymore.
>>
>> Why?  This is necessary for IRQ to work.
>>
>> You mean, if you use irq_intercept, this isn't needed?
>
> The reason for Paolo's RFC was to _avoid_ having to touch every target
> with code such as the above, no?

I misunderstood.  I thought irq_intercept was intercepting the RTC IRQ.  I now 
see it's intercepting the I/O APIC irqs.

Regards,

Anthony Liguori

>
> Andreas
>

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

* Re: [Qemu-devel] [PATCH 02/10] qtest: add support for -M pc
  2012-02-25 21:12     ` Anthony Liguori
  2012-02-25 21:21       ` Andreas Färber
@ 2012-02-25 21:39       ` Paolo Bonzini
  1 sibling, 0 replies; 24+ messages in thread
From: Paolo Bonzini @ 2012-02-25 21:39 UTC (permalink / raw)
  To: qemu-devel

On 02/25/2012 10:12 PM, Anthony Liguori wrote:
> 
> Why?  This is necessary for IRQ to work.

Actually it's reverted later on in the series, so if you want to commit
it as is the end result is surely fine by me. :)

Paolo

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

* Re: [Qemu-devel] [PATCH 07/10] qtest: IRQ interception infrastructure (v2)
  2012-02-25 21:16     ` Anthony Liguori
@ 2012-02-26  1:31       ` Andreas Färber
  2012-02-26  1:34         ` Anthony Liguori
  0 siblings, 1 reply; 24+ messages in thread
From: Andreas Färber @ 2012-02-26  1:31 UTC (permalink / raw)
  To: Anthony Liguori; +Cc: Paolo Bonzini, qemu-devel, Jan Kiszka

Am 25.02.2012 22:16, schrieb Anthony Liguori:
> On 02/25/2012 02:20 PM, Paolo Bonzini wrote:
>> On 02/25/2012 08:42 PM, Anthony Liguori wrote:
>>> +       
>>> object_property_add_child(object_resolve_path("/i440fx/piix3", NULL),
>>> +                                  "ioapic", OBJECT(dev), NULL);
>>
>> Jan objected to putting this under /i440fx/piix3.
> 
> I think for our model, having it as a child property makes quite a lot
> of sense.

Weren't you discussing rearranging the tree so that devices are under a
separate node from block devices etc. (e.g., /devices)? Would be a good
idea to introduce a (dummy) object_resolve_device_path() to avoid having
to change hardcoded absolute string paths like the above later.
Or do that change first so that new paths like this one at least don't
need to be touched again.

Andreas

-- 
SUSE LINUX Products GmbH, Maxfeldstr. 5, 90409 Nürnberg, Germany
GF: Jeff Hawn, Jennifer Guild, Felix Imendörffer; HRB 16746 AG Nürnberg

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

* Re: [Qemu-devel] [PATCH 07/10] qtest: IRQ interception infrastructure (v2)
  2012-02-26  1:31       ` Andreas Färber
@ 2012-02-26  1:34         ` Anthony Liguori
  0 siblings, 0 replies; 24+ messages in thread
From: Anthony Liguori @ 2012-02-26  1:34 UTC (permalink / raw)
  To: Andreas Färber; +Cc: Paolo Bonzini, qemu-devel, Jan Kiszka

On 02/25/2012 07:31 PM, Andreas Färber wrote:
> Am 25.02.2012 22:16, schrieb Anthony Liguori:
>> On 02/25/2012 02:20 PM, Paolo Bonzini wrote:
>>> On 02/25/2012 08:42 PM, Anthony Liguori wrote:
>>>> +
>>>> object_property_add_child(object_resolve_path("/i440fx/piix3", NULL),
>>>> +                                  "ioapic", OBJECT(dev), NULL);
>>>
>>> Jan objected to putting this under /i440fx/piix3.
>>
>> I think for our model, having it as a child property makes quite a lot
>> of sense.
>
> Weren't you discussing rearranging the tree so that devices are under a
> separate node from block devices etc. (e.g., /devices)? Would be a good
> idea to introduce a (dummy) object_resolve_device_path() to avoid having
> to change hardcoded absolute string paths like the above later.

No need.  object_resolve_path("i440fx/piix3", NULL) would have the same effect.

But I also don't think it's necessary.  Direct calls to object_resolve_path 
almost always indicates the need to refactor code.

Regards,

Anthony Liguori

> Or do that change first so that new paths like this one at least don't
> need to be touched again.
>
> Andreas
>

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

* Re: [Qemu-devel] [PATCH 03/10] qtest: add C version of test infrastructure
  2012-02-25 19:42 ` [Qemu-devel] [PATCH 03/10] qtest: add C version of test infrastructure Anthony Liguori
@ 2012-03-02 22:17   ` Eduardo Habkost
  0 siblings, 0 replies; 24+ messages in thread
From: Eduardo Habkost @ 2012-03-02 22:17 UTC (permalink / raw)
  To: Anthony Liguori; +Cc: Kevin Wolf, qemu-devel

On Sat, Feb 25, 2012 at 01:42:42PM -0600, Anthony Liguori wrote:
> 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>
> ---
>  scripts/qtest    |    5 +
>  tests/Makefile   |    2 +
>  tests/libqtest.c |  334 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
>  tests/libqtest.h |   63 ++++++++++
>  4 files changed, 404 insertions(+), 0 deletions(-)
>  create mode 100644 scripts/qtest
>  create mode 100644 tests/libqtest.c
>  create mode 100644 tests/libqtest.h
> 
> diff --git a/scripts/qtest b/scripts/qtest
> new file mode 100644
> index 0000000..5cff3d4
> --- /dev/null
> +++ b/scripts/qtest

The script is missing the executable bit. When trying to run 'make check' after
applying this series, I get:

Running 'tests/rtc-test' with qemu-system-x86_64...
/bin/sh: line 3: /home/ehabkost/pessoal/proj/virt/qemu/scripts/qtest: Permission denied
make: *** [check-qtest-x86_64] Error 126

-- 
Eduardo

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

end of thread, other threads:[~2012-03-02 22:17 UTC | newest]

Thread overview: 24+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2012-02-25 19:42 [Qemu-devel] [PATCH 00/10] qtest: a testing framework for devices (v2) Anthony Liguori
2012-02-25 19:42 ` [Qemu-devel] [PATCH 01/10] qtest: add test framework (v2) Anthony Liguori
2012-02-25 20:19   ` Paolo Bonzini
2012-02-25 19:42 ` [Qemu-devel] [PATCH 02/10] qtest: add support for -M pc Anthony Liguori
2012-02-25 20:19   ` Paolo Bonzini
2012-02-25 21:12     ` Anthony Liguori
2012-02-25 21:21       ` Andreas Färber
2012-02-25 21:29         ` Anthony Liguori
2012-02-25 21:39       ` Paolo Bonzini
2012-02-25 19:42 ` [Qemu-devel] [PATCH 03/10] qtest: add C version of test infrastructure Anthony Liguori
2012-03-02 22:17   ` Eduardo Habkost
2012-02-25 19:42 ` [Qemu-devel] [PATCH 04/10] make: add check targets based on gtester (v2) Anthony Liguori
2012-02-25 19:42 ` [Qemu-devel] [PATCH 05/10] rtc: split out macros into a header file and use in test case Anthony Liguori
2012-02-25 19:42 ` [Qemu-devel] [PATCH 06/10] qtest: add rtc-test test-case (v2) Anthony Liguori
2012-02-25 20:20   ` Paolo Bonzini
2012-02-25 20:41   ` Stefan Weil
2012-02-25 19:42 ` [Qemu-devel] [PATCH 07/10] qtest: IRQ interception infrastructure (v2) Anthony Liguori
2012-02-25 20:20   ` Paolo Bonzini
2012-02-25 21:16     ` Anthony Liguori
2012-02-26  1:31       ` Andreas Färber
2012-02-26  1:34         ` Anthony Liguori
2012-02-25 19:42 ` [Qemu-devel] [PATCH 08/10] libqtest: add IRQ intercept commands Anthony Liguori
2012-02-25 19:42 ` [Qemu-devel] [PATCH 09/10] rtc-test: add IRQ intercept Anthony Liguori
2012-02-25 19:42 ` [Qemu-devel] [PATCH 10/10] qtest: add clock management Anthony Liguori

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).