All of lore.kernel.org
 help / color / mirror / Atom feed
* [Qemu-devel] [PATCH v6 0/3] tests: add RTAS protocol
@ 2016-09-08 19:00 Laurent Vivier
  2016-09-08 19:00 ` [Qemu-devel] [PATCH v6 1/3] qtest: replace strtoXX() by qemu_strtoXX() Laurent Vivier
                   ` (2 more replies)
  0 siblings, 3 replies; 10+ messages in thread
From: Laurent Vivier @ 2016-09-08 19:00 UTC (permalink / raw)
  To: david; +Cc: thuth, lvivier, qemu-ppc, qemu-devel, groug

This series allows to call RTAS commands from the qtest framework,
and defines a first test to call RTAS command "get-time-of-day"
to validate the protocol and test RTAS.

RTAS command parameters are passed to the guest via the
guest memory, so we also need to implement the guest memory
management functions for SPAPR target.

RTAS commands will be needed later to test PCI from the qtest framework
with SPAPR virtual machines: PCI configuration is read/written with
RTAS commands "ibm,read-pci-config", "ibm,write-pci-config".

v6:
- rebase
- remove useless include

v5:
- replace "ppc64" by "spapr"
- define and use qtest_spapr_vboot()/qtest_spapr_boot()/qtest_spapr_shutdown()

v4:
- use qemu_strtoXXX() instead strtoXX(),
  add a patch in the series to change all strtoXX() in qtest.c

v3:
- use mktimegm() instead of timegm()

v2:
- remove useless parenthesis, inline
- add a missing space in qrtas_call() prototype

Laurent Vivier (3):
  qtest: replace strtoXX() by qemu_strtoXX()
  libqos: define SPAPR libqos functions
  tests: add RTAS command in the protocol

 hw/ppc/spapr_rtas.c         | 19 ++++++++++++
 include/hw/ppc/spapr_rtas.h | 10 +++++++
 qtest.c                     | 66 ++++++++++++++++++++++++++---------------
 tests/Makefile.include      |  5 ++++
 tests/libqos/libqos-pc.c    |  2 ++
 tests/libqos/libqos-spapr.c | 30 +++++++++++++++++++
 tests/libqos/libqos-spapr.h | 10 +++++++
 tests/libqos/libqos.c       |  1 -
 tests/libqos/malloc-spapr.c | 38 ++++++++++++++++++++++++
 tests/libqos/malloc-spapr.h | 17 +++++++++++
 tests/libqos/rtas.c         | 71 +++++++++++++++++++++++++++++++++++++++++++++
 tests/libqos/rtas.h         | 11 +++++++
 tests/libqtest.c            | 10 +++++++
 tests/libqtest.h            | 15 ++++++++++
 tests/rtas-test.c           | 40 +++++++++++++++++++++++++
 15 files changed, 321 insertions(+), 24 deletions(-)
 create mode 100644 include/hw/ppc/spapr_rtas.h
 create mode 100644 tests/libqos/libqos-spapr.c
 create mode 100644 tests/libqos/libqos-spapr.h
 create mode 100644 tests/libqos/malloc-spapr.c
 create mode 100644 tests/libqos/malloc-spapr.h
 create mode 100644 tests/libqos/rtas.c
 create mode 100644 tests/libqos/rtas.h
 create mode 100644 tests/rtas-test.c

-- 
2.5.5

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

* [Qemu-devel] [PATCH v6 1/3] qtest: replace strtoXX() by qemu_strtoXX()
  2016-09-08 19:00 [Qemu-devel] [PATCH v6 0/3] tests: add RTAS protocol Laurent Vivier
@ 2016-09-08 19:00 ` Laurent Vivier
  2016-09-08 19:00 ` [Qemu-devel] [PATCH v6 2/3] libqos: define SPAPR libqos functions Laurent Vivier
  2016-09-08 19:00 ` [Qemu-devel] [PATCH v6 3/3] tests: add RTAS command in the protocol Laurent Vivier
  2 siblings, 0 replies; 10+ messages in thread
From: Laurent Vivier @ 2016-09-08 19:00 UTC (permalink / raw)
  To: david; +Cc: thuth, lvivier, qemu-ppc, qemu-devel, groug

Check the result of qemu_strtoXX() and assert
if the string cannot be converted.

Signed-off-by: Laurent Vivier <lvivier@redhat.com>
Reviewed-by: David Gibson <david@gibson.dropbear.id.au>
Reviewed-by: Greg Kurz <groug@kaod.org>
---
v6:
- rebase and add Greg's Rb

v5:
- update log message about result checking
- add David's Rb

v4:
- add this patch in the series to change all strtoXX() in qtest.c

 qtest.c | 49 ++++++++++++++++++++++++++-----------------------
 1 file changed, 26 insertions(+), 23 deletions(-)

diff --git a/qtest.c b/qtest.c
index da4826c..4c94708 100644
--- a/qtest.c
+++ b/qtest.c
@@ -27,6 +27,7 @@
 #include "qemu/config-file.h"
 #include "qemu/option.h"
 #include "qemu/error-report.h"
+#include "qemu/cutils.h"
 
 #define MAX_IRQ 256
 
@@ -324,12 +325,13 @@ static void qtest_process_command(CharDriverState *chr, gchar **words)
     } else if (strcmp(words[0], "outb") == 0 ||
                strcmp(words[0], "outw") == 0 ||
                strcmp(words[0], "outl") == 0) {
-        uint16_t addr;
-        uint32_t value;
+        unsigned long addr;
+        unsigned long value;
 
         g_assert(words[1] && words[2]);
-        addr = strtoul(words[1], NULL, 0);
-        value = strtoul(words[2], NULL, 0);
+        g_assert(qemu_strtoul(words[1], NULL, 0, &addr) == 0);
+        g_assert(qemu_strtoul(words[2], NULL, 0, &value) == 0);
+        g_assert(addr <= 0xffff);
 
         if (words[0][3] == 'b') {
             cpu_outb(addr, value);
@@ -343,11 +345,12 @@ static void qtest_process_command(CharDriverState *chr, gchar **words)
     } else if (strcmp(words[0], "inb") == 0 ||
         strcmp(words[0], "inw") == 0 ||
         strcmp(words[0], "inl") == 0) {
-        uint16_t addr;
+        unsigned long addr;
         uint32_t value = -1U;
 
         g_assert(words[1]);
-        addr = strtoul(words[1], NULL, 0);
+        g_assert(qemu_strtoul(words[1], NULL, 0, &addr) == 0);
+        g_assert(addr <= 0xffff);
 
         if (words[0][2] == 'b') {
             value = cpu_inb(addr);
@@ -366,8 +369,8 @@ static void qtest_process_command(CharDriverState *chr, gchar **words)
         uint64_t value;
 
         g_assert(words[1] && words[2]);
-        addr = strtoull(words[1], NULL, 0);
-        value = strtoull(words[2], NULL, 0);
+        g_assert(qemu_strtoull(words[1], NULL, 0, &addr) == 0);
+        g_assert(qemu_strtoull(words[2], NULL, 0, &value) == 0);
 
         if (words[0][5] == 'b') {
             uint8_t data = value;
@@ -395,7 +398,7 @@ static void qtest_process_command(CharDriverState *chr, gchar **words)
         uint64_t value = UINT64_C(-1);
 
         g_assert(words[1]);
-        addr = strtoull(words[1], NULL, 0);
+        g_assert(qemu_strtoull(words[1], NULL, 0, &addr) == 0);
 
         if (words[0][4] == 'b') {
             uint8_t data;
@@ -421,8 +424,8 @@ static void qtest_process_command(CharDriverState *chr, gchar **words)
         char *enc;
 
         g_assert(words[1] && words[2]);
-        addr = strtoull(words[1], NULL, 0);
-        len = strtoull(words[2], NULL, 0);
+        g_assert(qemu_strtoull(words[1], NULL, 0, &addr) == 0);
+        g_assert(qemu_strtoull(words[2], NULL, 0, &len) == 0);
 
         data = g_malloc(len);
         cpu_physical_memory_read(addr, data, len);
@@ -443,8 +446,8 @@ static void qtest_process_command(CharDriverState *chr, gchar **words)
         gchar *b64_data;
 
         g_assert(words[1] && words[2]);
-        addr = strtoull(words[1], NULL, 0);
-        len = strtoull(words[2], NULL, 0);
+        g_assert(qemu_strtoull(words[1], NULL, 0, &addr) == 0);
+        g_assert(qemu_strtoull(words[2], NULL, 0, &len) == 0);
 
         data = g_malloc(len);
         cpu_physical_memory_read(addr, data, len);
@@ -460,8 +463,8 @@ static void qtest_process_command(CharDriverState *chr, gchar **words)
         size_t data_len;
 
         g_assert(words[1] && words[2] && words[3]);
-        addr = strtoull(words[1], NULL, 0);
-        len = strtoull(words[2], NULL, 0);
+        g_assert(qemu_strtoull(words[1], NULL, 0, &addr) == 0);
+        g_assert(qemu_strtoull(words[2], NULL, 0, &len) == 0);
 
         data_len = strlen(words[3]);
         if (data_len < 3) {
@@ -486,12 +489,12 @@ static void qtest_process_command(CharDriverState *chr, gchar **words)
     } else if (strcmp(words[0], "memset") == 0) {
         uint64_t addr, len;
         uint8_t *data;
-        uint8_t pattern;
+        unsigned long pattern;
 
         g_assert(words[1] && words[2] && words[3]);
-        addr = strtoull(words[1], NULL, 0);
-        len = strtoull(words[2], NULL, 0);
-        pattern = strtoull(words[3], NULL, 0);
+        g_assert(qemu_strtoull(words[1], NULL, 0, &addr) == 0);
+        g_assert(qemu_strtoull(words[2], NULL, 0, &len) == 0);
+        g_assert(qemu_strtoul(words[3], NULL, 0, &pattern) == 0);
 
         data = g_malloc(len);
         memset(data, pattern, len);
@@ -507,8 +510,8 @@ static void qtest_process_command(CharDriverState *chr, gchar **words)
         gsize out_len;
 
         g_assert(words[1] && words[2] && words[3]);
-        addr = strtoull(words[1], NULL, 0);
-        len = strtoull(words[2], NULL, 0);
+        g_assert(qemu_strtoull(words[1], NULL, 0, &addr) == 0);
+        g_assert(qemu_strtoull(words[2], NULL, 0, &len) == 0);
 
         data_len = strlen(words[3]);
         if (data_len < 3) {
@@ -532,7 +535,7 @@ static void qtest_process_command(CharDriverState *chr, gchar **words)
         int64_t ns;
 
         if (words[1]) {
-            ns = strtoll(words[1], NULL, 0);
+            g_assert(qemu_strtoll(words[1], NULL, 0, &ns) == 0);
         } else {
             ns = qemu_clock_deadline_ns_all(QEMU_CLOCK_VIRTUAL);
         }
@@ -544,7 +547,7 @@ static void qtest_process_command(CharDriverState *chr, gchar **words)
         int64_t ns;
 
         g_assert(words[1]);
-        ns = strtoll(words[1], NULL, 0);
+        g_assert(qemu_strtoll(words[1], NULL, 0, &ns) == 0);
         qtest_clock_warp(ns);
         qtest_send_prefix(chr);
         qtest_sendf(chr, "OK %"PRIi64"\n",
-- 
2.5.5

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

* [Qemu-devel] [PATCH v6 2/3] libqos: define SPAPR libqos functions
  2016-09-08 19:00 [Qemu-devel] [PATCH v6 0/3] tests: add RTAS protocol Laurent Vivier
  2016-09-08 19:00 ` [Qemu-devel] [PATCH v6 1/3] qtest: replace strtoXX() by qemu_strtoXX() Laurent Vivier
@ 2016-09-08 19:00 ` Laurent Vivier
  2016-09-12  4:08   ` David Gibson
  2016-09-08 19:00 ` [Qemu-devel] [PATCH v6 3/3] tests: add RTAS command in the protocol Laurent Vivier
  2 siblings, 1 reply; 10+ messages in thread
From: Laurent Vivier @ 2016-09-08 19:00 UTC (permalink / raw)
  To: david; +Cc: thuth, lvivier, qemu-ppc, qemu-devel, groug

Define spapr_alloc_init()/spapr_alloc_init_flags()/spapr_alloc_uninit()

  to allocate and use SPAPR guest memory

Define qtest_spapr_vboot()/qtest_spapr_boot()/qtest_spapr_shutdown()

  to start SPAPR guest with QOSState initialized for it (memory management)

Move qtest_irq_intercept_in() from generic part to PC part.

Signed-off-by: Laurent Vivier <lvivier@redhat.com>
Reviewed-by: Greg Kurz <groug@kaod.org>
---
v6:
- rebase
- remove added include in tests/libqos/libqos.h
- add Greg's Rb

v5:
- replace "ppc64" by "spapr"
- Add test_spapr_vboot()/qtest_spapr_boot()/qtest_spapr_shutdown()
  and remove machine_alloc_XXX() fuctions

 tests/Makefile.include      |  2 ++
 tests/libqos/libqos-pc.c    |  2 ++
 tests/libqos/libqos-spapr.c | 30 ++++++++++++++++++++++++++++++
 tests/libqos/libqos-spapr.h | 10 ++++++++++
 tests/libqos/libqos.c       |  1 -
 tests/libqos/malloc-spapr.c | 38 ++++++++++++++++++++++++++++++++++++++
 tests/libqos/malloc-spapr.h | 17 +++++++++++++++++
 7 files changed, 99 insertions(+), 1 deletion(-)
 create mode 100644 tests/libqos/libqos-spapr.c
 create mode 100644 tests/libqos/libqos-spapr.h
 create mode 100644 tests/libqos/malloc-spapr.c
 create mode 100644 tests/libqos/malloc-spapr.h

diff --git a/tests/Makefile.include b/tests/Makefile.include
index e3a3266..91df9f2 100644
--- a/tests/Makefile.include
+++ b/tests/Makefile.include
@@ -576,6 +576,8 @@ tests/test-crypto-block$(EXESUF): tests/test-crypto-block.o $(test-crypto-obj-y)
 
 libqos-obj-y = tests/libqos/pci.o tests/libqos/fw_cfg.o tests/libqos/malloc.o
 libqos-obj-y += tests/libqos/i2c.o tests/libqos/libqos.o
+libqos-spapr-obj-y = $(libqos-obj-y) tests/libqos/malloc-spapr.o
+libqos-spapr-obj-y += tests/libqos/libqos-spapr.o
 libqos-pc-obj-y = $(libqos-obj-y) tests/libqos/pci-pc.o
 libqos-pc-obj-y += tests/libqos/malloc-pc.o tests/libqos/libqos-pc.o
 libqos-pc-obj-y += tests/libqos/ahci.o
diff --git a/tests/libqos/libqos-pc.c b/tests/libqos/libqos-pc.c
index 72b5e3b..df34092 100644
--- a/tests/libqos/libqos-pc.c
+++ b/tests/libqos/libqos-pc.c
@@ -21,6 +21,8 @@ QOSState *qtest_pc_boot(const char *cmdline_fmt, ...)
     qs = qtest_vboot(&qos_ops, cmdline_fmt, ap);
     va_end(ap);
 
+    qtest_irq_intercept_in(global_qtest, "ioapic");
+
     return qs;
 }
 
diff --git a/tests/libqos/libqos-spapr.c b/tests/libqos/libqos-spapr.c
new file mode 100644
index 0000000..f19408b
--- /dev/null
+++ b/tests/libqos/libqos-spapr.c
@@ -0,0 +1,30 @@
+#include "qemu/osdep.h"
+#include "libqos/libqos-spapr.h"
+#include "libqos/malloc-spapr.h"
+
+static QOSOps qos_ops = {
+    .init_allocator = spapr_alloc_init_flags,
+    .uninit_allocator = spapr_alloc_uninit
+};
+
+QOSState *qtest_spapr_vboot(const char *cmdline_fmt, va_list ap)
+{
+    return qtest_vboot(&qos_ops, cmdline_fmt, ap);
+}
+
+QOSState *qtest_spapr_boot(const char *cmdline_fmt, ...)
+{
+    QOSState *qs;
+    va_list ap;
+
+    va_start(ap, cmdline_fmt);
+    qs = qtest_vboot(&qos_ops, cmdline_fmt, ap);
+    va_end(ap);
+
+    return qs;
+}
+
+void qtest_spapr_shutdown(QOSState *qs)
+{
+    return qtest_shutdown(qs);
+}
diff --git a/tests/libqos/libqos-spapr.h b/tests/libqos/libqos-spapr.h
new file mode 100644
index 0000000..dcb5c43
--- /dev/null
+++ b/tests/libqos/libqos-spapr.h
@@ -0,0 +1,10 @@
+#ifndef LIBQOS_SPAPR_H
+#define LIBQOS_SPAPR_H
+
+#include "libqos/libqos.h"
+
+QOSState *qtest_spapr_vboot(const char *cmdline_fmt, va_list ap);
+QOSState *qtest_spapr_boot(const char *cmdline_fmt, ...);
+void qtest_spapr_shutdown(QOSState *qs);
+
+#endif
diff --git a/tests/libqos/libqos.c b/tests/libqos/libqos.c
index c7ba441..a852dc5 100644
--- a/tests/libqos/libqos.c
+++ b/tests/libqos/libqos.c
@@ -20,7 +20,6 @@ QOSState *qtest_vboot(QOSOps *ops, const char *cmdline_fmt, va_list ap)
     cmdline = g_strdup_vprintf(cmdline_fmt, ap);
     qs->qts = qtest_start(cmdline);
     qs->ops = ops;
-    qtest_irq_intercept_in(global_qtest, "ioapic");
     if (ops && ops->init_allocator) {
         qs->alloc = ops->init_allocator(ALLOC_NO_FLAGS);
     }
diff --git a/tests/libqos/malloc-spapr.c b/tests/libqos/malloc-spapr.c
new file mode 100644
index 0000000..006404a
--- /dev/null
+++ b/tests/libqos/malloc-spapr.c
@@ -0,0 +1,38 @@
+/*
+ * libqos malloc support for SPAPR
+ *
+ * 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 "qemu/osdep.h"
+#include "libqos/malloc-spapr.h"
+
+#include "qemu-common.h"
+
+#define PAGE_SIZE 4096
+
+/* Memory must be a multiple of 256 MB,
+ * so we have at least 256MB
+ */
+#define SPAPR_MIN_SIZE 0x10000000
+
+void spapr_alloc_uninit(QGuestAllocator *allocator)
+{
+    alloc_uninit(allocator);
+}
+
+QGuestAllocator *spapr_alloc_init_flags(QAllocOpts flags)
+{
+    QGuestAllocator *s;
+
+    s = alloc_init_flags(flags, 1 << 20, SPAPR_MIN_SIZE);
+    alloc_set_page_size(s, PAGE_SIZE);
+
+    return s;
+}
+
+QGuestAllocator *spapr_alloc_init(void)
+{
+    return spapr_alloc_init_flags(ALLOC_NO_FLAGS);
+}
diff --git a/tests/libqos/malloc-spapr.h b/tests/libqos/malloc-spapr.h
new file mode 100644
index 0000000..64d0e77
--- /dev/null
+++ b/tests/libqos/malloc-spapr.h
@@ -0,0 +1,17 @@
+/*
+ * libqos malloc support for SPAPR
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#ifndef LIBQOS_MALLOC_SPAPR_H
+#define LIBQOS_MALLOC_SPAPR_H
+
+#include "libqos/malloc.h"
+
+QGuestAllocator *spapr_alloc_init(void);
+QGuestAllocator *spapr_alloc_init_flags(QAllocOpts flags);
+void spapr_alloc_uninit(QGuestAllocator *allocator);
+
+#endif
-- 
2.5.5

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

* [Qemu-devel] [PATCH v6 3/3] tests: add RTAS command in the protocol
  2016-09-08 19:00 [Qemu-devel] [PATCH v6 0/3] tests: add RTAS protocol Laurent Vivier
  2016-09-08 19:00 ` [Qemu-devel] [PATCH v6 1/3] qtest: replace strtoXX() by qemu_strtoXX() Laurent Vivier
  2016-09-08 19:00 ` [Qemu-devel] [PATCH v6 2/3] libqos: define SPAPR libqos functions Laurent Vivier
@ 2016-09-08 19:00 ` Laurent Vivier
  2016-09-09 16:49   ` Greg Kurz
  2016-09-12  4:17   ` David Gibson
  2 siblings, 2 replies; 10+ messages in thread
From: Laurent Vivier @ 2016-09-08 19:00 UTC (permalink / raw)
  To: david; +Cc: thuth, lvivier, qemu-ppc, qemu-devel, groug

Add a first test to validate the protocol:

- rtas/get-time-of-day compares the time
  from the guest with the time from the host.

Signed-off-by: Laurent Vivier <lvivier@redhat.com>
---
v6:
- rebase

v5:
- use qtest_spapr_boot() instead of machine_alloc_init()

v4:
- use qemu_strtoXXX() instead strtoXX()

v3:
- use mktimegm() instead of timegm()

v2:
- add a missing space in qrtas_call() prototype

 hw/ppc/spapr_rtas.c         | 19 ++++++++++++
 include/hw/ppc/spapr_rtas.h | 10 +++++++
 qtest.c                     | 17 +++++++++++
 tests/Makefile.include      |  3 ++
 tests/libqos/rtas.c         | 71 +++++++++++++++++++++++++++++++++++++++++++++
 tests/libqos/rtas.h         | 11 +++++++
 tests/libqtest.c            | 10 +++++++
 tests/libqtest.h            | 15 ++++++++++
 tests/rtas-test.c           | 40 +++++++++++++++++++++++++
 9 files changed, 196 insertions(+)
 create mode 100644 include/hw/ppc/spapr_rtas.h
 create mode 100644 tests/libqos/rtas.c
 create mode 100644 tests/libqos/rtas.h
 create mode 100644 tests/rtas-test.c

diff --git a/hw/ppc/spapr_rtas.c b/hw/ppc/spapr_rtas.c
index 27b5ad4..b80c1db 100644
--- a/hw/ppc/spapr_rtas.c
+++ b/hw/ppc/spapr_rtas.c
@@ -37,6 +37,7 @@
 
 #include "hw/ppc/spapr.h"
 #include "hw/ppc/spapr_vio.h"
+#include "hw/ppc/spapr_rtas.h"
 #include "hw/ppc/ppc.h"
 #include "qapi-event.h"
 #include "hw/boards.h"
@@ -692,6 +693,24 @@ target_ulong spapr_rtas_call(PowerPCCPU *cpu, sPAPRMachineState *spapr,
     return H_PARAMETER;
 }
 
+uint64_t qtest_rtas_call(char *cmd, uint32_t nargs, uint64_t args,
+                         uint32_t nret, uint64_t rets)
+{
+    int token;
+
+    for (token = 0; token < RTAS_TOKEN_MAX - RTAS_TOKEN_BASE; token++) {
+        if (strcmp(cmd, rtas_table[token].name) == 0) {
+            sPAPRMachineState *spapr = SPAPR_MACHINE(qdev_get_machine());
+            PowerPCCPU *cpu = POWERPC_CPU(first_cpu);
+
+            rtas_table[token].fn(cpu, spapr, token + RTAS_TOKEN_BASE,
+                                 nargs, args, nret, rets);
+            return H_SUCCESS;
+        }
+    }
+    return H_PARAMETER;
+}
+
 void spapr_rtas_register(int token, const char *name, spapr_rtas_fn fn)
 {
     assert((token >= RTAS_TOKEN_BASE) && (token < RTAS_TOKEN_MAX));
diff --git a/include/hw/ppc/spapr_rtas.h b/include/hw/ppc/spapr_rtas.h
new file mode 100644
index 0000000..383611f
--- /dev/null
+++ b/include/hw/ppc/spapr_rtas.h
@@ -0,0 +1,10 @@
+#ifndef HW_SPAPR_RTAS_H
+#define HW_SPAPR_RTAS_H
+/*
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+uint64_t qtest_rtas_call(char *cmd, uint32_t nargs, uint64_t args,
+                         uint32_t nret, uint64_t rets);
+#endif /* HW_SPAPR_RTAS_H */
diff --git a/qtest.c b/qtest.c
index 4c94708..beb62b4 100644
--- a/qtest.c
+++ b/qtest.c
@@ -28,6 +28,9 @@
 #include "qemu/option.h"
 #include "qemu/error-report.h"
 #include "qemu/cutils.h"
+#ifdef TARGET_PPC64
+#include "hw/ppc/spapr_rtas.h"
+#endif
 
 #define MAX_IRQ 256
 
@@ -531,6 +534,20 @@ static void qtest_process_command(CharDriverState *chr, gchar **words)
 
         qtest_send_prefix(chr);
         qtest_send(chr, "OK\n");
+#ifdef TARGET_PPC64
+    } else if (strcmp(words[0], "rtas") == 0) {
+        uint64_t res, args, ret;
+        unsigned long nargs, nret;
+
+        g_assert(qemu_strtoul(words[2], NULL, 0, &nargs) == 0);
+        g_assert(qemu_strtoull(words[3], NULL, 0, &args) == 0);
+        g_assert(qemu_strtoul(words[4], NULL, 0, &nret) == 0);
+        g_assert(qemu_strtoull(words[5], NULL, 0, &ret) == 0);
+        res = qtest_rtas_call(words[1], nargs, args, nret, ret);
+
+        qtest_send_prefix(chr);
+        qtest_sendf(chr, "OK %"PRIu64"\n", res);
+#endif
     } else if (qtest_enabled() && strcmp(words[0], "clock_step") == 0) {
         int64_t ns;
 
diff --git a/tests/Makefile.include b/tests/Makefile.include
index 91df9f2..fd61f97 100644
--- a/tests/Makefile.include
+++ b/tests/Makefile.include
@@ -265,6 +265,7 @@ check-qtest-ppc64-y += tests/prom-env-test$(EXESUF)
 check-qtest-ppc64-y += tests/drive_del-test$(EXESUF)
 check-qtest-ppc64-y += tests/postcopy-test$(EXESUF)
 check-qtest-ppc64-y += tests/boot-serial-test$(EXESUF)
+check-qtest-ppc64-y += tests/rtas-test$(EXESUF)
 
 check-qtest-sh4-y = tests/endianness-test$(EXESUF)
 
@@ -578,6 +579,7 @@ libqos-obj-y = tests/libqos/pci.o tests/libqos/fw_cfg.o tests/libqos/malloc.o
 libqos-obj-y += tests/libqos/i2c.o tests/libqos/libqos.o
 libqos-spapr-obj-y = $(libqos-obj-y) tests/libqos/malloc-spapr.o
 libqos-spapr-obj-y += tests/libqos/libqos-spapr.o
+libqos-spapr-obj-y += tests/libqos/rtas.o
 libqos-pc-obj-y = $(libqos-obj-y) tests/libqos/pci-pc.o
 libqos-pc-obj-y += tests/libqos/malloc-pc.o tests/libqos/libqos-pc.o
 libqos-pc-obj-y += tests/libqos/ahci.o
@@ -592,6 +594,7 @@ tests/m48t59-test$(EXESUF): tests/m48t59-test.o
 tests/endianness-test$(EXESUF): tests/endianness-test.o
 tests/spapr-phb-test$(EXESUF): tests/spapr-phb-test.o $(libqos-obj-y)
 tests/prom-env-test$(EXESUF): tests/prom-env-test.o $(libqos-obj-y)
+tests/rtas-test$(EXESUF): tests/rtas-test.o $(libqos-spapr-obj-y)
 tests/fdc-test$(EXESUF): tests/fdc-test.o
 tests/ide-test$(EXESUF): tests/ide-test.o $(libqos-pc-obj-y)
 tests/ahci-test$(EXESUF): tests/ahci-test.o $(libqos-pc-obj-y)
diff --git a/tests/libqos/rtas.c b/tests/libqos/rtas.c
new file mode 100644
index 0000000..d5f4ced
--- /dev/null
+++ b/tests/libqos/rtas.c
@@ -0,0 +1,71 @@
+/*
+ * 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 "qemu/osdep.h"
+#include "libqtest.h"
+#include "libqos/rtas.h"
+
+static void qrtas_copy_args(uint64_t target_args, uint32_t nargs,
+                            uint32_t *args)
+{
+    int i;
+
+    for (i = 0; i < nargs; i++) {
+        writel(target_args + i * sizeof(uint32_t), args[i]);
+    }
+}
+
+static void qrtas_copy_ret(uint64_t target_ret, uint32_t nret, uint32_t *ret)
+{
+    int i;
+
+    for (i = 0; i < nret; i++) {
+        ret[i] = readl(target_ret + i * sizeof(uint32_t));
+    }
+}
+
+static uint64_t qrtas_call(QGuestAllocator *alloc, const char *name,
+                           uint32_t nargs, uint32_t *args,
+                           uint32_t nret, uint32_t *ret)
+{
+    uint64_t res;
+    uint64_t target_args, target_ret;
+
+    target_args = guest_alloc(alloc, (nargs + nret) * sizeof(uint32_t));
+    target_ret = guest_alloc(alloc, nret * sizeof(uint32_t));
+
+    qrtas_copy_args(target_args, nargs, args);
+    res = qtest_rtas_call(global_qtest, name,
+                          nargs, target_args, nret, target_ret);
+    qrtas_copy_ret(target_ret, nret, ret);
+
+    guest_free(alloc, target_ret);
+    guest_free(alloc, target_args);
+
+    return res;
+}
+
+int qrtas_get_time_of_day(QGuestAllocator *alloc, struct tm *tm, uint32_t *ns)
+{
+    int res;
+    uint32_t ret[8];
+
+    res = qrtas_call(alloc, "get-time-of-day", 0, NULL, 8, ret);
+    if (res != 0) {
+        return res;
+    }
+
+    res = ret[0];
+    memset(tm, 0, sizeof(*tm));
+    tm->tm_year = ret[1] - 1900;
+    tm->tm_mon = ret[2] - 1;
+    tm->tm_mday = ret[3];
+    tm->tm_hour = ret[4];
+    tm->tm_min = ret[5];
+    tm->tm_sec = ret[6];
+    *ns = ret[7];
+
+    return res;
+}
diff --git a/tests/libqos/rtas.h b/tests/libqos/rtas.h
new file mode 100644
index 0000000..a1b60a8
--- /dev/null
+++ b/tests/libqos/rtas.h
@@ -0,0 +1,11 @@
+/*
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#ifndef LIBQOS_RTAS_H
+#define LIBQOS_RTAS_H
+#include "libqos/malloc.h"
+
+int qrtas_get_time_of_day(QGuestAllocator *alloc, struct tm *tm, uint32_t *ns);
+#endif /* LIBQOS_RTAS_H */
diff --git a/tests/libqtest.c b/tests/libqtest.c
index eb00f13..c9dd57b 100644
--- a/tests/libqtest.c
+++ b/tests/libqtest.c
@@ -751,6 +751,16 @@ void qtest_memread(QTestState *s, uint64_t addr, void *data, size_t size)
     g_strfreev(args);
 }
 
+uint64_t qtest_rtas_call(QTestState *s, const char *name,
+                         uint32_t nargs, uint64_t args,
+                         uint32_t nret, uint64_t ret)
+{
+    qtest_sendf(s, "rtas %s %u 0x%"PRIx64" %u 0x%"PRIx64"\n",
+                name, nargs, args, nret, ret);
+    qtest_rsp(s, 0);
+    return 0;
+}
+
 void qtest_add_func(const char *str, void (*fn)(void))
 {
     gchar *path = g_strdup_printf("/%s/%s", qtest_get_arch(), str);
diff --git a/tests/libqtest.h b/tests/libqtest.h
index 37f37ad..1badb76 100644
--- a/tests/libqtest.h
+++ b/tests/libqtest.h
@@ -318,6 +318,21 @@ uint64_t qtest_readq(QTestState *s, uint64_t addr);
 void qtest_memread(QTestState *s, uint64_t addr, void *data, size_t size);
 
 /**
+ * qtest_rtas_call:
+ * @s: #QTestState instance to operate on.
+ * @name: name of the command to call.
+ * @nargs: Number of args.
+ * @args: Guest address to read args from.
+ * @nret: Number of return value.
+ * @ret: Guest address to write return values to.
+ *
+ * Call an RTAS function
+ */
+uint64_t qtest_rtas_call(QTestState *s, const char *name,
+                         uint32_t nargs, uint64_t args,
+                         uint32_t nret, uint64_t ret);
+
+/**
  * qtest_bufread:
  * @s: #QTestState instance to operate on.
  * @addr: Guest address to read from.
diff --git a/tests/rtas-test.c b/tests/rtas-test.c
new file mode 100644
index 0000000..3bca36b
--- /dev/null
+++ b/tests/rtas-test.c
@@ -0,0 +1,40 @@
+#include "qemu/osdep.h"
+#include "qemu/cutils.h"
+#include "libqtest.h"
+
+#include "libqos/libqos-spapr.h"
+#include "libqos/rtas.h"
+
+static void test_rtas_get_time_of_day(void)
+{
+    QOSState *qs;
+    struct tm tm;
+    uint32_t ns;
+    uint64_t ret;
+    time_t t1, t2;
+
+    qs = qtest_spapr_boot("");
+
+    t1 = time(NULL);
+    ret = qrtas_get_time_of_day(qs->alloc, &tm, &ns);
+    g_assert_cmpint(ret, ==, 0);
+    t2 = mktimegm(&tm);
+    g_assert(t2 - t1 < 5); /* 5 sec max to run the test */
+
+    qtest_spapr_shutdown(qs);
+}
+
+int main(int argc, char *argv[])
+{
+    const char *arch = qtest_get_arch();
+
+    g_test_init(&argc, &argv, NULL);
+
+    if (strcmp(arch, "ppc64") == 0) {
+        qtest_add_func("rtas/get-time-of-day", test_rtas_get_time_of_day);
+    } else {
+        g_assert_not_reached();
+    }
+
+    return g_test_run();
+}
-- 
2.5.5

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

* Re: [Qemu-devel] [PATCH v6 3/3] tests: add RTAS command in the protocol
  2016-09-08 19:00 ` [Qemu-devel] [PATCH v6 3/3] tests: add RTAS command in the protocol Laurent Vivier
@ 2016-09-09 16:49   ` Greg Kurz
  2016-09-12 15:41     ` Laurent Vivier
  2016-09-12  4:17   ` David Gibson
  1 sibling, 1 reply; 10+ messages in thread
From: Greg Kurz @ 2016-09-09 16:49 UTC (permalink / raw)
  To: Laurent Vivier; +Cc: david, thuth, qemu-ppc, qemu-devel

On Thu,  8 Sep 2016 21:00:07 +0200
Laurent Vivier <lvivier@redhat.com> wrote:

> Add a first test to validate the protocol:
> 
> - rtas/get-time-of-day compares the time
>   from the guest with the time from the host.
> 
> Signed-off-by: Laurent Vivier <lvivier@redhat.com>
> ---
> v6:
> - rebase
> 
> v5:
> - use qtest_spapr_boot() instead of machine_alloc_init()
> 
> v4:
> - use qemu_strtoXXX() instead strtoXX()
> 
> v3:
> - use mktimegm() instead of timegm()
> 
> v2:
> - add a missing space in qrtas_call() prototype
> 
>  hw/ppc/spapr_rtas.c         | 19 ++++++++++++
>  include/hw/ppc/spapr_rtas.h | 10 +++++++
>  qtest.c                     | 17 +++++++++++
>  tests/Makefile.include      |  3 ++
>  tests/libqos/rtas.c         | 71 +++++++++++++++++++++++++++++++++++++++++++++
>  tests/libqos/rtas.h         | 11 +++++++
>  tests/libqtest.c            | 10 +++++++
>  tests/libqtest.h            | 15 ++++++++++
>  tests/rtas-test.c           | 40 +++++++++++++++++++++++++
>  9 files changed, 196 insertions(+)
>  create mode 100644 include/hw/ppc/spapr_rtas.h
>  create mode 100644 tests/libqos/rtas.c
>  create mode 100644 tests/libqos/rtas.h
>  create mode 100644 tests/rtas-test.c
> 
> diff --git a/hw/ppc/spapr_rtas.c b/hw/ppc/spapr_rtas.c
> index 27b5ad4..b80c1db 100644
> --- a/hw/ppc/spapr_rtas.c
> +++ b/hw/ppc/spapr_rtas.c
> @@ -37,6 +37,7 @@
>  
>  #include "hw/ppc/spapr.h"
>  #include "hw/ppc/spapr_vio.h"
> +#include "hw/ppc/spapr_rtas.h"
>  #include "hw/ppc/ppc.h"
>  #include "qapi-event.h"
>  #include "hw/boards.h"
> @@ -692,6 +693,24 @@ target_ulong spapr_rtas_call(PowerPCCPU *cpu, sPAPRMachineState *spapr,
>      return H_PARAMETER;
>  }
>  
> +uint64_t qtest_rtas_call(char *cmd, uint32_t nargs, uint64_t args,
> +                         uint32_t nret, uint64_t rets)
> +{
> +    int token;
> +
> +    for (token = 0; token < RTAS_TOKEN_MAX - RTAS_TOKEN_BASE; token++) {
> +        if (strcmp(cmd, rtas_table[token].name) == 0) {
> +            sPAPRMachineState *spapr = SPAPR_MACHINE(qdev_get_machine());

I'm now realizing that the above will abort if QEMU is started with a
non-pseries machine...

As long as pseries is the default for ppc64, this isn't an issue,
since  it would require to pass an explicit non-pseries machine to
qtest_spapr_boot() (aka. write a buggy test program).

qtest_spapr_boot() could also double-check the machine is indeed a pseries
with QMP. Makes sense ?

> +            PowerPCCPU *cpu = POWERPC_CPU(first_cpu);
> +
> +            rtas_table[token].fn(cpu, spapr, token + RTAS_TOKEN_BASE,
> +                                 nargs, args, nret, rets);
> +            return H_SUCCESS;
> +        }
> +    }
> +    return H_PARAMETER;
> +}
> +
>  void spapr_rtas_register(int token, const char *name, spapr_rtas_fn fn)
>  {
>      assert((token >= RTAS_TOKEN_BASE) && (token < RTAS_TOKEN_MAX));
> diff --git a/include/hw/ppc/spapr_rtas.h b/include/hw/ppc/spapr_rtas.h
> new file mode 100644
> index 0000000..383611f
> --- /dev/null
> +++ b/include/hw/ppc/spapr_rtas.h
> @@ -0,0 +1,10 @@
> +#ifndef HW_SPAPR_RTAS_H
> +#define HW_SPAPR_RTAS_H
> +/*
> + * This work is licensed under the terms of the GNU GPL, version 2 or later.
> + * See the COPYING file in the top-level directory.
> + */
> +
> +uint64_t qtest_rtas_call(char *cmd, uint32_t nargs, uint64_t args,
> +                         uint32_t nret, uint64_t rets);
> +#endif /* HW_SPAPR_RTAS_H */
> diff --git a/qtest.c b/qtest.c
> index 4c94708..beb62b4 100644
> --- a/qtest.c
> +++ b/qtest.c
> @@ -28,6 +28,9 @@
>  #include "qemu/option.h"
>  #include "qemu/error-report.h"
>  #include "qemu/cutils.h"
> +#ifdef TARGET_PPC64
> +#include "hw/ppc/spapr_rtas.h"
> +#endif
>  
>  #define MAX_IRQ 256
>  
> @@ -531,6 +534,20 @@ static void qtest_process_command(CharDriverState *chr, gchar **words)
>  
>          qtest_send_prefix(chr);
>          qtest_send(chr, "OK\n");
> +#ifdef TARGET_PPC64
> +    } else if (strcmp(words[0], "rtas") == 0) {
> +        uint64_t res, args, ret;
> +        unsigned long nargs, nret;
> +
> +        g_assert(qemu_strtoul(words[2], NULL, 0, &nargs) == 0);
> +        g_assert(qemu_strtoull(words[3], NULL, 0, &args) == 0);
> +        g_assert(qemu_strtoul(words[4], NULL, 0, &nret) == 0);
> +        g_assert(qemu_strtoull(words[5], NULL, 0, &ret) == 0);
> +        res = qtest_rtas_call(words[1], nargs, args, nret, ret);
> +
> +        qtest_send_prefix(chr);
> +        qtest_sendf(chr, "OK %"PRIu64"\n", res);
> +#endif
>      } else if (qtest_enabled() && strcmp(words[0], "clock_step") == 0) {
>          int64_t ns;
>  
> diff --git a/tests/Makefile.include b/tests/Makefile.include
> index 91df9f2..fd61f97 100644
> --- a/tests/Makefile.include
> +++ b/tests/Makefile.include
> @@ -265,6 +265,7 @@ check-qtest-ppc64-y += tests/prom-env-test$(EXESUF)
>  check-qtest-ppc64-y += tests/drive_del-test$(EXESUF)
>  check-qtest-ppc64-y += tests/postcopy-test$(EXESUF)
>  check-qtest-ppc64-y += tests/boot-serial-test$(EXESUF)
> +check-qtest-ppc64-y += tests/rtas-test$(EXESUF)
>  
>  check-qtest-sh4-y = tests/endianness-test$(EXESUF)
>  
> @@ -578,6 +579,7 @@ libqos-obj-y = tests/libqos/pci.o tests/libqos/fw_cfg.o tests/libqos/malloc.o
>  libqos-obj-y += tests/libqos/i2c.o tests/libqos/libqos.o
>  libqos-spapr-obj-y = $(libqos-obj-y) tests/libqos/malloc-spapr.o
>  libqos-spapr-obj-y += tests/libqos/libqos-spapr.o
> +libqos-spapr-obj-y += tests/libqos/rtas.o
>  libqos-pc-obj-y = $(libqos-obj-y) tests/libqos/pci-pc.o
>  libqos-pc-obj-y += tests/libqos/malloc-pc.o tests/libqos/libqos-pc.o
>  libqos-pc-obj-y += tests/libqos/ahci.o
> @@ -592,6 +594,7 @@ tests/m48t59-test$(EXESUF): tests/m48t59-test.o
>  tests/endianness-test$(EXESUF): tests/endianness-test.o
>  tests/spapr-phb-test$(EXESUF): tests/spapr-phb-test.o $(libqos-obj-y)
>  tests/prom-env-test$(EXESUF): tests/prom-env-test.o $(libqos-obj-y)
> +tests/rtas-test$(EXESUF): tests/rtas-test.o $(libqos-spapr-obj-y)
>  tests/fdc-test$(EXESUF): tests/fdc-test.o
>  tests/ide-test$(EXESUF): tests/ide-test.o $(libqos-pc-obj-y)
>  tests/ahci-test$(EXESUF): tests/ahci-test.o $(libqos-pc-obj-y)
> diff --git a/tests/libqos/rtas.c b/tests/libqos/rtas.c
> new file mode 100644
> index 0000000..d5f4ced
> --- /dev/null
> +++ b/tests/libqos/rtas.c
> @@ -0,0 +1,71 @@
> +/*
> + * 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 "qemu/osdep.h"
> +#include "libqtest.h"
> +#include "libqos/rtas.h"
> +
> +static void qrtas_copy_args(uint64_t target_args, uint32_t nargs,
> +                            uint32_t *args)
> +{
> +    int i;
> +
> +    for (i = 0; i < nargs; i++) {
> +        writel(target_args + i * sizeof(uint32_t), args[i]);
> +    }
> +}
> +
> +static void qrtas_copy_ret(uint64_t target_ret, uint32_t nret, uint32_t *ret)
> +{
> +    int i;
> +
> +    for (i = 0; i < nret; i++) {
> +        ret[i] = readl(target_ret + i * sizeof(uint32_t));
> +    }
> +}
> +
> +static uint64_t qrtas_call(QGuestAllocator *alloc, const char *name,
> +                           uint32_t nargs, uint32_t *args,
> +                           uint32_t nret, uint32_t *ret)
> +{
> +    uint64_t res;
> +    uint64_t target_args, target_ret;
> +
> +    target_args = guest_alloc(alloc, (nargs + nret) * sizeof(uint32_t));
> +    target_ret = guest_alloc(alloc, nret * sizeof(uint32_t));
> +
> +    qrtas_copy_args(target_args, nargs, args);
> +    res = qtest_rtas_call(global_qtest, name,
> +                          nargs, target_args, nret, target_ret);
> +    qrtas_copy_ret(target_ret, nret, ret);
> +
> +    guest_free(alloc, target_ret);
> +    guest_free(alloc, target_args);
> +
> +    return res;
> +}
> +
> +int qrtas_get_time_of_day(QGuestAllocator *alloc, struct tm *tm, uint32_t *ns)
> +{
> +    int res;
> +    uint32_t ret[8];
> +
> +    res = qrtas_call(alloc, "get-time-of-day", 0, NULL, 8, ret);
> +    if (res != 0) {
> +        return res;
> +    }
> +
> +    res = ret[0];
> +    memset(tm, 0, sizeof(*tm));
> +    tm->tm_year = ret[1] - 1900;
> +    tm->tm_mon = ret[2] - 1;
> +    tm->tm_mday = ret[3];
> +    tm->tm_hour = ret[4];
> +    tm->tm_min = ret[5];
> +    tm->tm_sec = ret[6];
> +    *ns = ret[7];
> +
> +    return res;
> +}
> diff --git a/tests/libqos/rtas.h b/tests/libqos/rtas.h
> new file mode 100644
> index 0000000..a1b60a8
> --- /dev/null
> +++ b/tests/libqos/rtas.h
> @@ -0,0 +1,11 @@
> +/*
> + * This work is licensed under the terms of the GNU GPL, version 2 or later.
> + * See the COPYING file in the top-level directory.
> + */
> +
> +#ifndef LIBQOS_RTAS_H
> +#define LIBQOS_RTAS_H
> +#include "libqos/malloc.h"
> +
> +int qrtas_get_time_of_day(QGuestAllocator *alloc, struct tm *tm, uint32_t *ns);
> +#endif /* LIBQOS_RTAS_H */
> diff --git a/tests/libqtest.c b/tests/libqtest.c
> index eb00f13..c9dd57b 100644
> --- a/tests/libqtest.c
> +++ b/tests/libqtest.c
> @@ -751,6 +751,16 @@ void qtest_memread(QTestState *s, uint64_t addr, void *data, size_t size)
>      g_strfreev(args);
>  }
>  
> +uint64_t qtest_rtas_call(QTestState *s, const char *name,
> +                         uint32_t nargs, uint64_t args,
> +                         uint32_t nret, uint64_t ret)
> +{
> +    qtest_sendf(s, "rtas %s %u 0x%"PRIx64" %u 0x%"PRIx64"\n",
> +                name, nargs, args, nret, ret);
> +    qtest_rsp(s, 0);
> +    return 0;
> +}
> +
>  void qtest_add_func(const char *str, void (*fn)(void))
>  {
>      gchar *path = g_strdup_printf("/%s/%s", qtest_get_arch(), str);
> diff --git a/tests/libqtest.h b/tests/libqtest.h
> index 37f37ad..1badb76 100644
> --- a/tests/libqtest.h
> +++ b/tests/libqtest.h
> @@ -318,6 +318,21 @@ uint64_t qtest_readq(QTestState *s, uint64_t addr);
>  void qtest_memread(QTestState *s, uint64_t addr, void *data, size_t size);
>  
>  /**
> + * qtest_rtas_call:
> + * @s: #QTestState instance to operate on.
> + * @name: name of the command to call.
> + * @nargs: Number of args.
> + * @args: Guest address to read args from.
> + * @nret: Number of return value.
> + * @ret: Guest address to write return values to.
> + *
> + * Call an RTAS function
> + */
> +uint64_t qtest_rtas_call(QTestState *s, const char *name,
> +                         uint32_t nargs, uint64_t args,
> +                         uint32_t nret, uint64_t ret);
> +
> +/**
>   * qtest_bufread:
>   * @s: #QTestState instance to operate on.
>   * @addr: Guest address to read from.
> diff --git a/tests/rtas-test.c b/tests/rtas-test.c
> new file mode 100644
> index 0000000..3bca36b
> --- /dev/null
> +++ b/tests/rtas-test.c
> @@ -0,0 +1,40 @@
> +#include "qemu/osdep.h"
> +#include "qemu/cutils.h"
> +#include "libqtest.h"
> +
> +#include "libqos/libqos-spapr.h"
> +#include "libqos/rtas.h"
> +
> +static void test_rtas_get_time_of_day(void)
> +{
> +    QOSState *qs;
> +    struct tm tm;
> +    uint32_t ns;
> +    uint64_t ret;
> +    time_t t1, t2;
> +
> +    qs = qtest_spapr_boot("");
> +
> +    t1 = time(NULL);
> +    ret = qrtas_get_time_of_day(qs->alloc, &tm, &ns);
> +    g_assert_cmpint(ret, ==, 0);
> +    t2 = mktimegm(&tm);
> +    g_assert(t2 - t1 < 5); /* 5 sec max to run the test */
> +
> +    qtest_spapr_shutdown(qs);
> +}
> +
> +int main(int argc, char *argv[])
> +{
> +    const char *arch = qtest_get_arch();
> +
> +    g_test_init(&argc, &argv, NULL);
> +
> +    if (strcmp(arch, "ppc64") == 0) {
> +        qtest_add_func("rtas/get-time-of-day", test_rtas_get_time_of_day);
> +    } else {
> +        g_assert_not_reached();

Since this is not supposed to happen when run from the makefile, but rather
when run by hand, maybe is is better to print an error with g_test_message()
and exit.

> +    }
> +
> +    return g_test_run();
> +}

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

* Re: [Qemu-devel] [PATCH v6 2/3] libqos: define SPAPR libqos functions
  2016-09-08 19:00 ` [Qemu-devel] [PATCH v6 2/3] libqos: define SPAPR libqos functions Laurent Vivier
@ 2016-09-12  4:08   ` David Gibson
  0 siblings, 0 replies; 10+ messages in thread
From: David Gibson @ 2016-09-12  4:08 UTC (permalink / raw)
  To: Laurent Vivier; +Cc: thuth, qemu-ppc, qemu-devel, groug

[-- Attachment #1: Type: text/plain, Size: 6551 bytes --]

On Thu, Sep 08, 2016 at 09:00:06PM +0200, Laurent Vivier wrote:
> Define spapr_alloc_init()/spapr_alloc_init_flags()/spapr_alloc_uninit()
> 
>   to allocate and use SPAPR guest memory
> 
> Define qtest_spapr_vboot()/qtest_spapr_boot()/qtest_spapr_shutdown()
> 
>   to start SPAPR guest with QOSState initialized for it (memory management)
> 
> Move qtest_irq_intercept_in() from generic part to PC part.
> 
> Signed-off-by: Laurent Vivier <lvivier@redhat.com>
> Reviewed-by: Greg Kurz <groug@kaod.org>

Reviewed-by: David Gibson <david@gibson.dropbear.id.au>


> ---
> v6:
> - rebase
> - remove added include in tests/libqos/libqos.h
> - add Greg's Rb
> 
> v5:
> - replace "ppc64" by "spapr"
> - Add test_spapr_vboot()/qtest_spapr_boot()/qtest_spapr_shutdown()
>   and remove machine_alloc_XXX() fuctions
> 
>  tests/Makefile.include      |  2 ++
>  tests/libqos/libqos-pc.c    |  2 ++
>  tests/libqos/libqos-spapr.c | 30 ++++++++++++++++++++++++++++++
>  tests/libqos/libqos-spapr.h | 10 ++++++++++
>  tests/libqos/libqos.c       |  1 -
>  tests/libqos/malloc-spapr.c | 38 ++++++++++++++++++++++++++++++++++++++
>  tests/libqos/malloc-spapr.h | 17 +++++++++++++++++
>  7 files changed, 99 insertions(+), 1 deletion(-)
>  create mode 100644 tests/libqos/libqos-spapr.c
>  create mode 100644 tests/libqos/libqos-spapr.h
>  create mode 100644 tests/libqos/malloc-spapr.c
>  create mode 100644 tests/libqos/malloc-spapr.h
> 
> diff --git a/tests/Makefile.include b/tests/Makefile.include
> index e3a3266..91df9f2 100644
> --- a/tests/Makefile.include
> +++ b/tests/Makefile.include
> @@ -576,6 +576,8 @@ tests/test-crypto-block$(EXESUF): tests/test-crypto-block.o $(test-crypto-obj-y)
>  
>  libqos-obj-y = tests/libqos/pci.o tests/libqos/fw_cfg.o tests/libqos/malloc.o
>  libqos-obj-y += tests/libqos/i2c.o tests/libqos/libqos.o
> +libqos-spapr-obj-y = $(libqos-obj-y) tests/libqos/malloc-spapr.o
> +libqos-spapr-obj-y += tests/libqos/libqos-spapr.o
>  libqos-pc-obj-y = $(libqos-obj-y) tests/libqos/pci-pc.o
>  libqos-pc-obj-y += tests/libqos/malloc-pc.o tests/libqos/libqos-pc.o
>  libqos-pc-obj-y += tests/libqos/ahci.o
> diff --git a/tests/libqos/libqos-pc.c b/tests/libqos/libqos-pc.c
> index 72b5e3b..df34092 100644
> --- a/tests/libqos/libqos-pc.c
> +++ b/tests/libqos/libqos-pc.c
> @@ -21,6 +21,8 @@ QOSState *qtest_pc_boot(const char *cmdline_fmt, ...)
>      qs = qtest_vboot(&qos_ops, cmdline_fmt, ap);
>      va_end(ap);
>  
> +    qtest_irq_intercept_in(global_qtest, "ioapic");
> +
>      return qs;
>  }
>  
> diff --git a/tests/libqos/libqos-spapr.c b/tests/libqos/libqos-spapr.c
> new file mode 100644
> index 0000000..f19408b
> --- /dev/null
> +++ b/tests/libqos/libqos-spapr.c
> @@ -0,0 +1,30 @@
> +#include "qemu/osdep.h"
> +#include "libqos/libqos-spapr.h"
> +#include "libqos/malloc-spapr.h"
> +
> +static QOSOps qos_ops = {
> +    .init_allocator = spapr_alloc_init_flags,
> +    .uninit_allocator = spapr_alloc_uninit
> +};
> +
> +QOSState *qtest_spapr_vboot(const char *cmdline_fmt, va_list ap)
> +{
> +    return qtest_vboot(&qos_ops, cmdline_fmt, ap);
> +}
> +
> +QOSState *qtest_spapr_boot(const char *cmdline_fmt, ...)
> +{
> +    QOSState *qs;
> +    va_list ap;
> +
> +    va_start(ap, cmdline_fmt);
> +    qs = qtest_vboot(&qos_ops, cmdline_fmt, ap);
> +    va_end(ap);
> +
> +    return qs;
> +}
> +
> +void qtest_spapr_shutdown(QOSState *qs)
> +{
> +    return qtest_shutdown(qs);
> +}
> diff --git a/tests/libqos/libqos-spapr.h b/tests/libqos/libqos-spapr.h
> new file mode 100644
> index 0000000..dcb5c43
> --- /dev/null
> +++ b/tests/libqos/libqos-spapr.h
> @@ -0,0 +1,10 @@
> +#ifndef LIBQOS_SPAPR_H
> +#define LIBQOS_SPAPR_H
> +
> +#include "libqos/libqos.h"
> +
> +QOSState *qtest_spapr_vboot(const char *cmdline_fmt, va_list ap);
> +QOSState *qtest_spapr_boot(const char *cmdline_fmt, ...);
> +void qtest_spapr_shutdown(QOSState *qs);
> +
> +#endif
> diff --git a/tests/libqos/libqos.c b/tests/libqos/libqos.c
> index c7ba441..a852dc5 100644
> --- a/tests/libqos/libqos.c
> +++ b/tests/libqos/libqos.c
> @@ -20,7 +20,6 @@ QOSState *qtest_vboot(QOSOps *ops, const char *cmdline_fmt, va_list ap)
>      cmdline = g_strdup_vprintf(cmdline_fmt, ap);
>      qs->qts = qtest_start(cmdline);
>      qs->ops = ops;
> -    qtest_irq_intercept_in(global_qtest, "ioapic");
>      if (ops && ops->init_allocator) {
>          qs->alloc = ops->init_allocator(ALLOC_NO_FLAGS);
>      }
> diff --git a/tests/libqos/malloc-spapr.c b/tests/libqos/malloc-spapr.c
> new file mode 100644
> index 0000000..006404a
> --- /dev/null
> +++ b/tests/libqos/malloc-spapr.c
> @@ -0,0 +1,38 @@
> +/*
> + * libqos malloc support for SPAPR
> + *
> + * 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 "qemu/osdep.h"
> +#include "libqos/malloc-spapr.h"
> +
> +#include "qemu-common.h"
> +
> +#define PAGE_SIZE 4096
> +
> +/* Memory must be a multiple of 256 MB,
> + * so we have at least 256MB
> + */
> +#define SPAPR_MIN_SIZE 0x10000000
> +
> +void spapr_alloc_uninit(QGuestAllocator *allocator)
> +{
> +    alloc_uninit(allocator);
> +}
> +
> +QGuestAllocator *spapr_alloc_init_flags(QAllocOpts flags)
> +{
> +    QGuestAllocator *s;
> +
> +    s = alloc_init_flags(flags, 1 << 20, SPAPR_MIN_SIZE);
> +    alloc_set_page_size(s, PAGE_SIZE);
> +
> +    return s;
> +}
> +
> +QGuestAllocator *spapr_alloc_init(void)
> +{
> +    return spapr_alloc_init_flags(ALLOC_NO_FLAGS);
> +}
> diff --git a/tests/libqos/malloc-spapr.h b/tests/libqos/malloc-spapr.h
> new file mode 100644
> index 0000000..64d0e77
> --- /dev/null
> +++ b/tests/libqos/malloc-spapr.h
> @@ -0,0 +1,17 @@
> +/*
> + * libqos malloc support for SPAPR
> + *
> + * This work is licensed under the terms of the GNU GPL, version 2 or later.
> + * See the COPYING file in the top-level directory.
> + */
> +
> +#ifndef LIBQOS_MALLOC_SPAPR_H
> +#define LIBQOS_MALLOC_SPAPR_H
> +
> +#include "libqos/malloc.h"
> +
> +QGuestAllocator *spapr_alloc_init(void);
> +QGuestAllocator *spapr_alloc_init_flags(QAllocOpts flags);
> +void spapr_alloc_uninit(QGuestAllocator *allocator);
> +
> +#endif

-- 
David Gibson			| I'll have my music baroque, and my code
david AT gibson.dropbear.id.au	| minimalist, thank you.  NOT _the_ _other_
				| _way_ _around_!
http://www.ozlabs.org/~dgibson

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 801 bytes --]

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

* Re: [Qemu-devel] [PATCH v6 3/3] tests: add RTAS command in the protocol
  2016-09-08 19:00 ` [Qemu-devel] [PATCH v6 3/3] tests: add RTAS command in the protocol Laurent Vivier
  2016-09-09 16:49   ` Greg Kurz
@ 2016-09-12  4:17   ` David Gibson
  2016-09-12 17:09     ` Laurent Vivier
  1 sibling, 1 reply; 10+ messages in thread
From: David Gibson @ 2016-09-12  4:17 UTC (permalink / raw)
  To: Laurent Vivier; +Cc: thuth, qemu-ppc, qemu-devel, groug

[-- Attachment #1: Type: text/plain, Size: 12245 bytes --]

On Thu, Sep 08, 2016 at 09:00:07PM +0200, Laurent Vivier wrote:
> Add a first test to validate the protocol:
> 
> - rtas/get-time-of-day compares the time
>   from the guest with the time from the host.
> 
> Signed-off-by: Laurent Vivier <lvivier@redhat.com>
> ---
> v6:
> - rebase
> 
> v5:
> - use qtest_spapr_boot() instead of machine_alloc_init()
> 
> v4:
> - use qemu_strtoXXX() instead strtoXX()
> 
> v3:
> - use mktimegm() instead of timegm()
> 
> v2:
> - add a missing space in qrtas_call() prototype
> 
>  hw/ppc/spapr_rtas.c         | 19 ++++++++++++
>  include/hw/ppc/spapr_rtas.h | 10 +++++++
>  qtest.c                     | 17 +++++++++++
>  tests/Makefile.include      |  3 ++
>  tests/libqos/rtas.c         | 71 +++++++++++++++++++++++++++++++++++++++++++++
>  tests/libqos/rtas.h         | 11 +++++++
>  tests/libqtest.c            | 10 +++++++
>  tests/libqtest.h            | 15 ++++++++++
>  tests/rtas-test.c           | 40 +++++++++++++++++++++++++
>  9 files changed, 196 insertions(+)
>  create mode 100644 include/hw/ppc/spapr_rtas.h
>  create mode 100644 tests/libqos/rtas.c
>  create mode 100644 tests/libqos/rtas.h
>  create mode 100644 tests/rtas-test.c
> 
> diff --git a/hw/ppc/spapr_rtas.c b/hw/ppc/spapr_rtas.c
> index 27b5ad4..b80c1db 100644
> --- a/hw/ppc/spapr_rtas.c
> +++ b/hw/ppc/spapr_rtas.c
> @@ -37,6 +37,7 @@
>  
>  #include "hw/ppc/spapr.h"
>  #include "hw/ppc/spapr_vio.h"
> +#include "hw/ppc/spapr_rtas.h"
>  #include "hw/ppc/ppc.h"
>  #include "qapi-event.h"
>  #include "hw/boards.h"
> @@ -692,6 +693,24 @@ target_ulong spapr_rtas_call(PowerPCCPU *cpu, sPAPRMachineState *spapr,
>      return H_PARAMETER;
>  }
>  
> +uint64_t qtest_rtas_call(char *cmd, uint32_t nargs, uint64_t args,
> +                         uint32_t nret, uint64_t rets)
> +{
> +    int token;
> +
> +    for (token = 0; token < RTAS_TOKEN_MAX - RTAS_TOKEN_BASE; token++) {
> +        if (strcmp(cmd, rtas_table[token].name) == 0) {
> +            sPAPRMachineState *spapr = SPAPR_MACHINE(qdev_get_machine());
> +            PowerPCCPU *cpu = POWERPC_CPU(first_cpu);
> +
> +            rtas_table[token].fn(cpu, spapr, token + RTAS_TOKEN_BASE,
> +                                 nargs, args, nret, rets);
> +            return H_SUCCESS;
> +        }
> +    }
> +    return H_PARAMETER;
> +}

I may be misunderstanding how qtest works here.  But wouldn't it test
a bit more of the common code paths if rather than doing your own
token lookup here, you actually generated a full guest style rtas
parameter buffer (token + args + rets in one structure), then dispatch
through h_rtas, or spapr_rtas_call?

> +
>  void spapr_rtas_register(int token, const char *name, spapr_rtas_fn fn)
>  {
>      assert((token >= RTAS_TOKEN_BASE) && (token < RTAS_TOKEN_MAX));
> diff --git a/include/hw/ppc/spapr_rtas.h b/include/hw/ppc/spapr_rtas.h
> new file mode 100644
> index 0000000..383611f
> --- /dev/null
> +++ b/include/hw/ppc/spapr_rtas.h
> @@ -0,0 +1,10 @@
> +#ifndef HW_SPAPR_RTAS_H
> +#define HW_SPAPR_RTAS_H
> +/*
> + * This work is licensed under the terms of the GNU GPL, version 2 or later.
> + * See the COPYING file in the top-level directory.
> + */
> +
> +uint64_t qtest_rtas_call(char *cmd, uint32_t nargs, uint64_t args,
> +                         uint32_t nret, uint64_t rets);
> +#endif /* HW_SPAPR_RTAS_H */
> diff --git a/qtest.c b/qtest.c
> index 4c94708..beb62b4 100644
> --- a/qtest.c
> +++ b/qtest.c
> @@ -28,6 +28,9 @@
>  #include "qemu/option.h"
>  #include "qemu/error-report.h"
>  #include "qemu/cutils.h"
> +#ifdef TARGET_PPC64
> +#include "hw/ppc/spapr_rtas.h"
> +#endif
>  
>  #define MAX_IRQ 256
>  
> @@ -531,6 +534,20 @@ static void qtest_process_command(CharDriverState *chr, gchar **words)
>  
>          qtest_send_prefix(chr);
>          qtest_send(chr, "OK\n");
> +#ifdef TARGET_PPC64
> +    } else if (strcmp(words[0], "rtas") == 0) {
> +        uint64_t res, args, ret;
> +        unsigned long nargs, nret;
> +
> +        g_assert(qemu_strtoul(words[2], NULL, 0, &nargs) == 0);
> +        g_assert(qemu_strtoull(words[3], NULL, 0, &args) == 0);
> +        g_assert(qemu_strtoul(words[4], NULL, 0, &nret) == 0);
> +        g_assert(qemu_strtoull(words[5], NULL, 0, &ret) == 0);
> +        res = qtest_rtas_call(words[1], nargs, args, nret, ret);
> +
> +        qtest_send_prefix(chr);
> +        qtest_sendf(chr, "OK %"PRIu64"\n", res);
> +#endif
>      } else if (qtest_enabled() && strcmp(words[0], "clock_step") == 0) {
>          int64_t ns;
>  
> diff --git a/tests/Makefile.include b/tests/Makefile.include
> index 91df9f2..fd61f97 100644
> --- a/tests/Makefile.include
> +++ b/tests/Makefile.include
> @@ -265,6 +265,7 @@ check-qtest-ppc64-y += tests/prom-env-test$(EXESUF)
>  check-qtest-ppc64-y += tests/drive_del-test$(EXESUF)
>  check-qtest-ppc64-y += tests/postcopy-test$(EXESUF)
>  check-qtest-ppc64-y += tests/boot-serial-test$(EXESUF)
> +check-qtest-ppc64-y += tests/rtas-test$(EXESUF)
>  
>  check-qtest-sh4-y = tests/endianness-test$(EXESUF)
>  
> @@ -578,6 +579,7 @@ libqos-obj-y = tests/libqos/pci.o tests/libqos/fw_cfg.o tests/libqos/malloc.o
>  libqos-obj-y += tests/libqos/i2c.o tests/libqos/libqos.o
>  libqos-spapr-obj-y = $(libqos-obj-y) tests/libqos/malloc-spapr.o
>  libqos-spapr-obj-y += tests/libqos/libqos-spapr.o
> +libqos-spapr-obj-y += tests/libqos/rtas.o
>  libqos-pc-obj-y = $(libqos-obj-y) tests/libqos/pci-pc.o
>  libqos-pc-obj-y += tests/libqos/malloc-pc.o tests/libqos/libqos-pc.o
>  libqos-pc-obj-y += tests/libqos/ahci.o
> @@ -592,6 +594,7 @@ tests/m48t59-test$(EXESUF): tests/m48t59-test.o
>  tests/endianness-test$(EXESUF): tests/endianness-test.o
>  tests/spapr-phb-test$(EXESUF): tests/spapr-phb-test.o $(libqos-obj-y)
>  tests/prom-env-test$(EXESUF): tests/prom-env-test.o $(libqos-obj-y)
> +tests/rtas-test$(EXESUF): tests/rtas-test.o $(libqos-spapr-obj-y)
>  tests/fdc-test$(EXESUF): tests/fdc-test.o
>  tests/ide-test$(EXESUF): tests/ide-test.o $(libqos-pc-obj-y)
>  tests/ahci-test$(EXESUF): tests/ahci-test.o $(libqos-pc-obj-y)
> diff --git a/tests/libqos/rtas.c b/tests/libqos/rtas.c
> new file mode 100644
> index 0000000..d5f4ced
> --- /dev/null
> +++ b/tests/libqos/rtas.c
> @@ -0,0 +1,71 @@
> +/*
> + * 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 "qemu/osdep.h"
> +#include "libqtest.h"
> +#include "libqos/rtas.h"
> +
> +static void qrtas_copy_args(uint64_t target_args, uint32_t nargs,
> +                            uint32_t *args)
> +{
> +    int i;
> +
> +    for (i = 0; i < nargs; i++) {
> +        writel(target_args + i * sizeof(uint32_t), args[i]);
> +    }
> +}
> +
> +static void qrtas_copy_ret(uint64_t target_ret, uint32_t nret, uint32_t *ret)
> +{
> +    int i;
> +
> +    for (i = 0; i < nret; i++) {
> +        ret[i] = readl(target_ret + i * sizeof(uint32_t));
> +    }
> +}
> +
> +static uint64_t qrtas_call(QGuestAllocator *alloc, const char *name,
> +                           uint32_t nargs, uint32_t *args,
> +                           uint32_t nret, uint32_t *ret)
> +{
> +    uint64_t res;
> +    uint64_t target_args, target_ret;
> +
> +    target_args = guest_alloc(alloc, (nargs + nret) * sizeof(uint32_t));
> +    target_ret = guest_alloc(alloc, nret * sizeof(uint32_t));

Again, possibly I'm misunderstanding something, but it looks like
you're over-allocating here - target_args seems to get enough space
for both args and rets, then target_ret gets additional space for the
rets as well.

> +    qrtas_copy_args(target_args, nargs, args);
> +    res = qtest_rtas_call(global_qtest, name,
> +                          nargs, target_args, nret, target_ret);
> +    qrtas_copy_ret(target_ret, nret, ret);
> +
> +    guest_free(alloc, target_ret);
> +    guest_free(alloc, target_args);
> +
> +    return res;
> +}
> +
> +int qrtas_get_time_of_day(QGuestAllocator *alloc, struct tm *tm, uint32_t *ns)
> +{
> +    int res;
> +    uint32_t ret[8];
> +
> +    res = qrtas_call(alloc, "get-time-of-day", 0, NULL, 8, ret);
> +    if (res != 0) {
> +        return res;
> +    }
> +
> +    res = ret[0];
> +    memset(tm, 0, sizeof(*tm));
> +    tm->tm_year = ret[1] - 1900;
> +    tm->tm_mon = ret[2] - 1;
> +    tm->tm_mday = ret[3];
> +    tm->tm_hour = ret[4];
> +    tm->tm_min = ret[5];
> +    tm->tm_sec = ret[6];
> +    *ns = ret[7];
> +
> +    return res;
> +}
> diff --git a/tests/libqos/rtas.h b/tests/libqos/rtas.h
> new file mode 100644
> index 0000000..a1b60a8
> --- /dev/null
> +++ b/tests/libqos/rtas.h
> @@ -0,0 +1,11 @@
> +/*
> + * This work is licensed under the terms of the GNU GPL, version 2 or later.
> + * See the COPYING file in the top-level directory.
> + */
> +
> +#ifndef LIBQOS_RTAS_H
> +#define LIBQOS_RTAS_H
> +#include "libqos/malloc.h"
> +
> +int qrtas_get_time_of_day(QGuestAllocator *alloc, struct tm *tm, uint32_t *ns);
> +#endif /* LIBQOS_RTAS_H */
> diff --git a/tests/libqtest.c b/tests/libqtest.c
> index eb00f13..c9dd57b 100644
> --- a/tests/libqtest.c
> +++ b/tests/libqtest.c
> @@ -751,6 +751,16 @@ void qtest_memread(QTestState *s, uint64_t addr, void *data, size_t size)
>      g_strfreev(args);
>  }
>  
> +uint64_t qtest_rtas_call(QTestState *s, const char *name,
> +                         uint32_t nargs, uint64_t args,
> +                         uint32_t nret, uint64_t ret)
> +{
> +    qtest_sendf(s, "rtas %s %u 0x%"PRIx64" %u 0x%"PRIx64"\n",
> +                name, nargs, args, nret, ret);
> +    qtest_rsp(s, 0);
> +    return 0;
> +}
> +
>  void qtest_add_func(const char *str, void (*fn)(void))
>  {
>      gchar *path = g_strdup_printf("/%s/%s", qtest_get_arch(), str);
> diff --git a/tests/libqtest.h b/tests/libqtest.h
> index 37f37ad..1badb76 100644
> --- a/tests/libqtest.h
> +++ b/tests/libqtest.h
> @@ -318,6 +318,21 @@ uint64_t qtest_readq(QTestState *s, uint64_t addr);
>  void qtest_memread(QTestState *s, uint64_t addr, void *data, size_t size);
>  
>  /**
> + * qtest_rtas_call:
> + * @s: #QTestState instance to operate on.
> + * @name: name of the command to call.
> + * @nargs: Number of args.
> + * @args: Guest address to read args from.
> + * @nret: Number of return value.
> + * @ret: Guest address to write return values to.
> + *
> + * Call an RTAS function
> + */
> +uint64_t qtest_rtas_call(QTestState *s, const char *name,
> +                         uint32_t nargs, uint64_t args,
> +                         uint32_t nret, uint64_t ret);
> +
> +/**
>   * qtest_bufread:
>   * @s: #QTestState instance to operate on.
>   * @addr: Guest address to read from.
> diff --git a/tests/rtas-test.c b/tests/rtas-test.c
> new file mode 100644
> index 0000000..3bca36b
> --- /dev/null
> +++ b/tests/rtas-test.c
> @@ -0,0 +1,40 @@
> +#include "qemu/osdep.h"
> +#include "qemu/cutils.h"
> +#include "libqtest.h"
> +
> +#include "libqos/libqos-spapr.h"
> +#include "libqos/rtas.h"
> +
> +static void test_rtas_get_time_of_day(void)
> +{
> +    QOSState *qs;
> +    struct tm tm;
> +    uint32_t ns;
> +    uint64_t ret;
> +    time_t t1, t2;
> +
> +    qs = qtest_spapr_boot("");
> +
> +    t1 = time(NULL);
> +    ret = qrtas_get_time_of_day(qs->alloc, &tm, &ns);
> +    g_assert_cmpint(ret, ==, 0);
> +    t2 = mktimegm(&tm);
> +    g_assert(t2 - t1 < 5); /* 5 sec max to run the test */
> +
> +    qtest_spapr_shutdown(qs);
> +}
> +
> +int main(int argc, char *argv[])
> +{
> +    const char *arch = qtest_get_arch();
> +
> +    g_test_init(&argc, &argv, NULL);
> +
> +    if (strcmp(arch, "ppc64") == 0) {
> +        qtest_add_func("rtas/get-time-of-day", test_rtas_get_time_of_day);
> +    } else {
> +        g_assert_not_reached();
> +    }
> +
> +    return g_test_run();
> +}

-- 
David Gibson			| I'll have my music baroque, and my code
david AT gibson.dropbear.id.au	| minimalist, thank you.  NOT _the_ _other_
				| _way_ _around_!
http://www.ozlabs.org/~dgibson

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 801 bytes --]

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

* Re: [Qemu-devel] [PATCH v6 3/3] tests: add RTAS command in the protocol
  2016-09-09 16:49   ` Greg Kurz
@ 2016-09-12 15:41     ` Laurent Vivier
  0 siblings, 0 replies; 10+ messages in thread
From: Laurent Vivier @ 2016-09-12 15:41 UTC (permalink / raw)
  To: Greg Kurz; +Cc: david, thuth, qemu-ppc, qemu-devel



On 09/09/2016 18:49, Greg Kurz wrote:
> On Thu,  8 Sep 2016 21:00:07 +0200
> Laurent Vivier <lvivier@redhat.com> wrote:
> 
>> Add a first test to validate the protocol:
>>
>> - rtas/get-time-of-day compares the time
>>   from the guest with the time from the host.
>>
>> Signed-off-by: Laurent Vivier <lvivier@redhat.com>
>> ---
>> v6:
>> - rebase
>>
>> v5:
>> - use qtest_spapr_boot() instead of machine_alloc_init()
>>
>> v4:
>> - use qemu_strtoXXX() instead strtoXX()
>>
>> v3:
>> - use mktimegm() instead of timegm()
>>
>> v2:
>> - add a missing space in qrtas_call() prototype
>>
>>  hw/ppc/spapr_rtas.c         | 19 ++++++++++++
>>  include/hw/ppc/spapr_rtas.h | 10 +++++++
>>  qtest.c                     | 17 +++++++++++
>>  tests/Makefile.include      |  3 ++
>>  tests/libqos/rtas.c         | 71 +++++++++++++++++++++++++++++++++++++++++++++
>>  tests/libqos/rtas.h         | 11 +++++++
>>  tests/libqtest.c            | 10 +++++++
>>  tests/libqtest.h            | 15 ++++++++++
>>  tests/rtas-test.c           | 40 +++++++++++++++++++++++++
>>  9 files changed, 196 insertions(+)
>>  create mode 100644 include/hw/ppc/spapr_rtas.h
>>  create mode 100644 tests/libqos/rtas.c
>>  create mode 100644 tests/libqos/rtas.h
>>  create mode 100644 tests/rtas-test.c
>>
>> diff --git a/hw/ppc/spapr_rtas.c b/hw/ppc/spapr_rtas.c
>> index 27b5ad4..b80c1db 100644
>> --- a/hw/ppc/spapr_rtas.c
>> +++ b/hw/ppc/spapr_rtas.c
>> @@ -37,6 +37,7 @@
>>  
>>  #include "hw/ppc/spapr.h"
>>  #include "hw/ppc/spapr_vio.h"
>> +#include "hw/ppc/spapr_rtas.h"
>>  #include "hw/ppc/ppc.h"
>>  #include "qapi-event.h"
>>  #include "hw/boards.h"
>> @@ -692,6 +693,24 @@ target_ulong spapr_rtas_call(PowerPCCPU *cpu, sPAPRMachineState *spapr,
>>      return H_PARAMETER;
>>  }
>>  
>> +uint64_t qtest_rtas_call(char *cmd, uint32_t nargs, uint64_t args,
>> +                         uint32_t nret, uint64_t rets)
>> +{
>> +    int token;
>> +
>> +    for (token = 0; token < RTAS_TOKEN_MAX - RTAS_TOKEN_BASE; token++) {
>> +        if (strcmp(cmd, rtas_table[token].name) == 0) {
>> +            sPAPRMachineState *spapr = SPAPR_MACHINE(qdev_get_machine());
> 
> I'm now realizing that the above will abort if QEMU is started with a
> non-pseries machine...
> 
> As long as pseries is the default for ppc64, this isn't an issue,
> since  it would require to pass an explicit non-pseries machine to
> qtest_spapr_boot() (aka. write a buggy test program).
> 
> qtest_spapr_boot() could also double-check the machine is indeed a pseries
> with QMP. Makes sense ?

It could be a first step to introduce the QMP call, then later we can
configure the framework according to the result.

>> +            PowerPCCPU *cpu = POWERPC_CPU(first_cpu);
>> +
>> +            rtas_table[token].fn(cpu, spapr, token + RTAS_TOKEN_BASE,
>> +                                 nargs, args, nret, rets);
>> +            return H_SUCCESS;
>> +        }
>> +    }
>> +    return H_PARAMETER;
>> +}
>> +
>>  void spapr_rtas_register(int token, const char *name, spapr_rtas_fn fn)
>>  {
>>      assert((token >= RTAS_TOKEN_BASE) && (token < RTAS_TOKEN_MAX));
>> diff --git a/include/hw/ppc/spapr_rtas.h b/include/hw/ppc/spapr_rtas.h
>> new file mode 100644
>> index 0000000..383611f
>> --- /dev/null
>> +++ b/include/hw/ppc/spapr_rtas.h
>> @@ -0,0 +1,10 @@
>> +#ifndef HW_SPAPR_RTAS_H
>> +#define HW_SPAPR_RTAS_H
>> +/*
>> + * This work is licensed under the terms of the GNU GPL, version 2 or later.
>> + * See the COPYING file in the top-level directory.
>> + */
>> +
>> +uint64_t qtest_rtas_call(char *cmd, uint32_t nargs, uint64_t args,
>> +                         uint32_t nret, uint64_t rets);
>> +#endif /* HW_SPAPR_RTAS_H */
>> diff --git a/qtest.c b/qtest.c
>> index 4c94708..beb62b4 100644
>> --- a/qtest.c
>> +++ b/qtest.c
>> @@ -28,6 +28,9 @@
>>  #include "qemu/option.h"
>>  #include "qemu/error-report.h"
>>  #include "qemu/cutils.h"
>> +#ifdef TARGET_PPC64
>> +#include "hw/ppc/spapr_rtas.h"
>> +#endif
>>  
>>  #define MAX_IRQ 256
>>  
>> @@ -531,6 +534,20 @@ static void qtest_process_command(CharDriverState *chr, gchar **words)
>>  
>>          qtest_send_prefix(chr);
>>          qtest_send(chr, "OK\n");
>> +#ifdef TARGET_PPC64
>> +    } else if (strcmp(words[0], "rtas") == 0) {
>> +        uint64_t res, args, ret;
>> +        unsigned long nargs, nret;
>> +
>> +        g_assert(qemu_strtoul(words[2], NULL, 0, &nargs) == 0);
>> +        g_assert(qemu_strtoull(words[3], NULL, 0, &args) == 0);
>> +        g_assert(qemu_strtoul(words[4], NULL, 0, &nret) == 0);
>> +        g_assert(qemu_strtoull(words[5], NULL, 0, &ret) == 0);
>> +        res = qtest_rtas_call(words[1], nargs, args, nret, ret);
>> +
>> +        qtest_send_prefix(chr);
>> +        qtest_sendf(chr, "OK %"PRIu64"\n", res);
>> +#endif
>>      } else if (qtest_enabled() && strcmp(words[0], "clock_step") == 0) {
>>          int64_t ns;
>>  
>> diff --git a/tests/Makefile.include b/tests/Makefile.include
>> index 91df9f2..fd61f97 100644
>> --- a/tests/Makefile.include
>> +++ b/tests/Makefile.include
>> @@ -265,6 +265,7 @@ check-qtest-ppc64-y += tests/prom-env-test$(EXESUF)
>>  check-qtest-ppc64-y += tests/drive_del-test$(EXESUF)
>>  check-qtest-ppc64-y += tests/postcopy-test$(EXESUF)
>>  check-qtest-ppc64-y += tests/boot-serial-test$(EXESUF)
>> +check-qtest-ppc64-y += tests/rtas-test$(EXESUF)
>>  
>>  check-qtest-sh4-y = tests/endianness-test$(EXESUF)
>>  
>> @@ -578,6 +579,7 @@ libqos-obj-y = tests/libqos/pci.o tests/libqos/fw_cfg.o tests/libqos/malloc.o
>>  libqos-obj-y += tests/libqos/i2c.o tests/libqos/libqos.o
>>  libqos-spapr-obj-y = $(libqos-obj-y) tests/libqos/malloc-spapr.o
>>  libqos-spapr-obj-y += tests/libqos/libqos-spapr.o
>> +libqos-spapr-obj-y += tests/libqos/rtas.o
>>  libqos-pc-obj-y = $(libqos-obj-y) tests/libqos/pci-pc.o
>>  libqos-pc-obj-y += tests/libqos/malloc-pc.o tests/libqos/libqos-pc.o
>>  libqos-pc-obj-y += tests/libqos/ahci.o
>> @@ -592,6 +594,7 @@ tests/m48t59-test$(EXESUF): tests/m48t59-test.o
>>  tests/endianness-test$(EXESUF): tests/endianness-test.o
>>  tests/spapr-phb-test$(EXESUF): tests/spapr-phb-test.o $(libqos-obj-y)
>>  tests/prom-env-test$(EXESUF): tests/prom-env-test.o $(libqos-obj-y)
>> +tests/rtas-test$(EXESUF): tests/rtas-test.o $(libqos-spapr-obj-y)
>>  tests/fdc-test$(EXESUF): tests/fdc-test.o
>>  tests/ide-test$(EXESUF): tests/ide-test.o $(libqos-pc-obj-y)
>>  tests/ahci-test$(EXESUF): tests/ahci-test.o $(libqos-pc-obj-y)
>> diff --git a/tests/libqos/rtas.c b/tests/libqos/rtas.c
>> new file mode 100644
>> index 0000000..d5f4ced
>> --- /dev/null
>> +++ b/tests/libqos/rtas.c
>> @@ -0,0 +1,71 @@
>> +/*
>> + * 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 "qemu/osdep.h"
>> +#include "libqtest.h"
>> +#include "libqos/rtas.h"
>> +
>> +static void qrtas_copy_args(uint64_t target_args, uint32_t nargs,
>> +                            uint32_t *args)
>> +{
>> +    int i;
>> +
>> +    for (i = 0; i < nargs; i++) {
>> +        writel(target_args + i * sizeof(uint32_t), args[i]);
>> +    }
>> +}
>> +
>> +static void qrtas_copy_ret(uint64_t target_ret, uint32_t nret, uint32_t *ret)
>> +{
>> +    int i;
>> +
>> +    for (i = 0; i < nret; i++) {
>> +        ret[i] = readl(target_ret + i * sizeof(uint32_t));
>> +    }
>> +}
>> +
>> +static uint64_t qrtas_call(QGuestAllocator *alloc, const char *name,
>> +                           uint32_t nargs, uint32_t *args,
>> +                           uint32_t nret, uint32_t *ret)
>> +{
>> +    uint64_t res;
>> +    uint64_t target_args, target_ret;
>> +
>> +    target_args = guest_alloc(alloc, (nargs + nret) * sizeof(uint32_t));
>> +    target_ret = guest_alloc(alloc, nret * sizeof(uint32_t));
>> +
>> +    qrtas_copy_args(target_args, nargs, args);
>> +    res = qtest_rtas_call(global_qtest, name,
>> +                          nargs, target_args, nret, target_ret);
>> +    qrtas_copy_ret(target_ret, nret, ret);
>> +
>> +    guest_free(alloc, target_ret);
>> +    guest_free(alloc, target_args);
>> +
>> +    return res;
>> +}
>> +
>> +int qrtas_get_time_of_day(QGuestAllocator *alloc, struct tm *tm, uint32_t *ns)
>> +{
>> +    int res;
>> +    uint32_t ret[8];
>> +
>> +    res = qrtas_call(alloc, "get-time-of-day", 0, NULL, 8, ret);
>> +    if (res != 0) {
>> +        return res;
>> +    }
>> +
>> +    res = ret[0];
>> +    memset(tm, 0, sizeof(*tm));
>> +    tm->tm_year = ret[1] - 1900;
>> +    tm->tm_mon = ret[2] - 1;
>> +    tm->tm_mday = ret[3];
>> +    tm->tm_hour = ret[4];
>> +    tm->tm_min = ret[5];
>> +    tm->tm_sec = ret[6];
>> +    *ns = ret[7];
>> +
>> +    return res;
>> +}
>> diff --git a/tests/libqos/rtas.h b/tests/libqos/rtas.h
>> new file mode 100644
>> index 0000000..a1b60a8
>> --- /dev/null
>> +++ b/tests/libqos/rtas.h
>> @@ -0,0 +1,11 @@
>> +/*
>> + * This work is licensed under the terms of the GNU GPL, version 2 or later.
>> + * See the COPYING file in the top-level directory.
>> + */
>> +
>> +#ifndef LIBQOS_RTAS_H
>> +#define LIBQOS_RTAS_H
>> +#include "libqos/malloc.h"
>> +
>> +int qrtas_get_time_of_day(QGuestAllocator *alloc, struct tm *tm, uint32_t *ns);
>> +#endif /* LIBQOS_RTAS_H */
>> diff --git a/tests/libqtest.c b/tests/libqtest.c
>> index eb00f13..c9dd57b 100644
>> --- a/tests/libqtest.c
>> +++ b/tests/libqtest.c
>> @@ -751,6 +751,16 @@ void qtest_memread(QTestState *s, uint64_t addr, void *data, size_t size)
>>      g_strfreev(args);
>>  }
>>  
>> +uint64_t qtest_rtas_call(QTestState *s, const char *name,
>> +                         uint32_t nargs, uint64_t args,
>> +                         uint32_t nret, uint64_t ret)
>> +{
>> +    qtest_sendf(s, "rtas %s %u 0x%"PRIx64" %u 0x%"PRIx64"\n",
>> +                name, nargs, args, nret, ret);
>> +    qtest_rsp(s, 0);
>> +    return 0;
>> +}
>> +
>>  void qtest_add_func(const char *str, void (*fn)(void))
>>  {
>>      gchar *path = g_strdup_printf("/%s/%s", qtest_get_arch(), str);
>> diff --git a/tests/libqtest.h b/tests/libqtest.h
>> index 37f37ad..1badb76 100644
>> --- a/tests/libqtest.h
>> +++ b/tests/libqtest.h
>> @@ -318,6 +318,21 @@ uint64_t qtest_readq(QTestState *s, uint64_t addr);
>>  void qtest_memread(QTestState *s, uint64_t addr, void *data, size_t size);
>>  
>>  /**
>> + * qtest_rtas_call:
>> + * @s: #QTestState instance to operate on.
>> + * @name: name of the command to call.
>> + * @nargs: Number of args.
>> + * @args: Guest address to read args from.
>> + * @nret: Number of return value.
>> + * @ret: Guest address to write return values to.
>> + *
>> + * Call an RTAS function
>> + */
>> +uint64_t qtest_rtas_call(QTestState *s, const char *name,
>> +                         uint32_t nargs, uint64_t args,
>> +                         uint32_t nret, uint64_t ret);
>> +
>> +/**
>>   * qtest_bufread:
>>   * @s: #QTestState instance to operate on.
>>   * @addr: Guest address to read from.
>> diff --git a/tests/rtas-test.c b/tests/rtas-test.c
>> new file mode 100644
>> index 0000000..3bca36b
>> --- /dev/null
>> +++ b/tests/rtas-test.c
>> @@ -0,0 +1,40 @@
>> +#include "qemu/osdep.h"
>> +#include "qemu/cutils.h"
>> +#include "libqtest.h"
>> +
>> +#include "libqos/libqos-spapr.h"
>> +#include "libqos/rtas.h"
>> +
>> +static void test_rtas_get_time_of_day(void)
>> +{
>> +    QOSState *qs;
>> +    struct tm tm;
>> +    uint32_t ns;
>> +    uint64_t ret;
>> +    time_t t1, t2;
>> +
>> +    qs = qtest_spapr_boot("");
>> +
>> +    t1 = time(NULL);
>> +    ret = qrtas_get_time_of_day(qs->alloc, &tm, &ns);
>> +    g_assert_cmpint(ret, ==, 0);
>> +    t2 = mktimegm(&tm);
>> +    g_assert(t2 - t1 < 5); /* 5 sec max to run the test */
>> +
>> +    qtest_spapr_shutdown(qs);
>> +}
>> +
>> +int main(int argc, char *argv[])
>> +{
>> +    const char *arch = qtest_get_arch();
>> +
>> +    g_test_init(&argc, &argv, NULL);
>> +
>> +    if (strcmp(arch, "ppc64") == 0) {
>> +        qtest_add_func("rtas/get-time-of-day", test_rtas_get_time_of_day);
>> +    } else {
>> +        g_assert_not_reached();
> 
> Since this is not supposed to happen when run from the makefile, but rather
> when run by hand, maybe is is better to print an error with g_test_message()
> and exit.

I've tested g_test_message() but it doesn't display anything when run by
hand.

https://developer.gnome.org/glib/stable/glib-Testing.html#g-test-message

I have only something when run with "gtester -o mylog", and then "mylog"
contains something like:

<?xml version="1.0"?>
<gtester>
  <testbinary path="tests/rtas-test">
    <binary file="tests/rtas-test"/>
    <random-seed>R02S12bea59d6ecbbc8f9212dd4536bd7e35</random-seed>
    <message>
Skipping test for non-ppc64

    </message>

<error>ERROR:/home/lvivier/Projects/qemu-upstream/tests/rtas-test.c:35:main:
assertion failed: (0)</error>
    <duration>0.049494</duration>
  </testbinary>

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

* Re: [Qemu-devel] [PATCH v6 3/3] tests: add RTAS command in the protocol
  2016-09-12  4:17   ` David Gibson
@ 2016-09-12 17:09     ` Laurent Vivier
  2016-09-13  5:36       ` David Gibson
  0 siblings, 1 reply; 10+ messages in thread
From: Laurent Vivier @ 2016-09-12 17:09 UTC (permalink / raw)
  To: David Gibson; +Cc: thuth, qemu-ppc, qemu-devel, groug



On 12/09/2016 06:17, David Gibson wrote:
> On Thu, Sep 08, 2016 at 09:00:07PM +0200, Laurent Vivier wrote:
>> Add a first test to validate the protocol:
>>
>> - rtas/get-time-of-day compares the time
>>   from the guest with the time from the host.
>>
>> Signed-off-by: Laurent Vivier <lvivier@redhat.com>
>> ---
>> v6:
>> - rebase
>>
>> v5:
>> - use qtest_spapr_boot() instead of machine_alloc_init()
>>
>> v4:
>> - use qemu_strtoXXX() instead strtoXX()
>>
>> v3:
>> - use mktimegm() instead of timegm()
>>
>> v2:
>> - add a missing space in qrtas_call() prototype
>>
>>  hw/ppc/spapr_rtas.c         | 19 ++++++++++++
>>  include/hw/ppc/spapr_rtas.h | 10 +++++++
>>  qtest.c                     | 17 +++++++++++
>>  tests/Makefile.include      |  3 ++
>>  tests/libqos/rtas.c         | 71 +++++++++++++++++++++++++++++++++++++++++++++
>>  tests/libqos/rtas.h         | 11 +++++++
>>  tests/libqtest.c            | 10 +++++++
>>  tests/libqtest.h            | 15 ++++++++++
>>  tests/rtas-test.c           | 40 +++++++++++++++++++++++++
>>  9 files changed, 196 insertions(+)
>>  create mode 100644 include/hw/ppc/spapr_rtas.h
>>  create mode 100644 tests/libqos/rtas.c
>>  create mode 100644 tests/libqos/rtas.h
>>  create mode 100644 tests/rtas-test.c
>>
>> diff --git a/hw/ppc/spapr_rtas.c b/hw/ppc/spapr_rtas.c
>> index 27b5ad4..b80c1db 100644
>> --- a/hw/ppc/spapr_rtas.c
>> +++ b/hw/ppc/spapr_rtas.c
>> @@ -37,6 +37,7 @@
>>  
>>  #include "hw/ppc/spapr.h"
>>  #include "hw/ppc/spapr_vio.h"
>> +#include "hw/ppc/spapr_rtas.h"
>>  #include "hw/ppc/ppc.h"
>>  #include "qapi-event.h"
>>  #include "hw/boards.h"
>> @@ -692,6 +693,24 @@ target_ulong spapr_rtas_call(PowerPCCPU *cpu, sPAPRMachineState *spapr,
>>      return H_PARAMETER;
>>  }
>>  
>> +uint64_t qtest_rtas_call(char *cmd, uint32_t nargs, uint64_t args,
>> +                         uint32_t nret, uint64_t rets)
>> +{
>> +    int token;
>> +
>> +    for (token = 0; token < RTAS_TOKEN_MAX - RTAS_TOKEN_BASE; token++) {
>> +        if (strcmp(cmd, rtas_table[token].name) == 0) {
>> +            sPAPRMachineState *spapr = SPAPR_MACHINE(qdev_get_machine());
>> +            PowerPCCPU *cpu = POWERPC_CPU(first_cpu);
>> +
>> +            rtas_table[token].fn(cpu, spapr, token + RTAS_TOKEN_BASE,
>> +                                 nargs, args, nret, rets);
>> +            return H_SUCCESS;
>> +        }
>> +    }
>> +    return H_PARAMETER;
>> +}
> 
> I may be misunderstanding how qtest works here.  But wouldn't it test

>From the point of view of the machine, qtest is an accelerator: so the
CPU is stopped, and the qtest accelerator open a socket allowing another
process to read/write/in/out/... the memory of the machine.
This allows to test the machine hardware or the hypervisor, not the CPU
or the firmware. kvm-unit-tests is better for this kind of test.

The qtest protocol is human readable: the second process sends strings
like "read 0x1000" and the qtest accelerator answers something like "OK
0" or "ERROR". This is why, from my point of view, using the name of the
service rather than the token number seems better.

> a bit more of the common code paths if rather than doing your own
> token lookup here, you actually generated a full guest style rtas
> parameter buffer (token + args + rets in one structure), then dispatch

We can't do the token lookup at the level of the second process as the
token is extracted from the OF device tree and for the moment we don't
have the functions in this process to scan the OF device tree. It is
possible as we can read the guest memory, but the functions are not
here. I plan to add this kind of feature, for instance to read the
memory size, but for the moment nothing is done.

> through h_rtas, or spapr_rtas_call?
> 
>> +
>>  void spapr_rtas_register(int token, const char *name, spapr_rtas_fn fn)
>>  {
>>      assert((token >= RTAS_TOKEN_BASE) && (token < RTAS_TOKEN_MAX));
>> diff --git a/include/hw/ppc/spapr_rtas.h b/include/hw/ppc/spapr_rtas.h
>> new file mode 100644
>> index 0000000..383611f
>> --- /dev/null
>> +++ b/include/hw/ppc/spapr_rtas.h
>> @@ -0,0 +1,10 @@
>> +#ifndef HW_SPAPR_RTAS_H
>> +#define HW_SPAPR_RTAS_H
>> +/*
>> + * This work is licensed under the terms of the GNU GPL, version 2 or later.
>> + * See the COPYING file in the top-level directory.
>> + */
>> +
>> +uint64_t qtest_rtas_call(char *cmd, uint32_t nargs, uint64_t args,
>> +                         uint32_t nret, uint64_t rets);
>> +#endif /* HW_SPAPR_RTAS_H */
>> diff --git a/qtest.c b/qtest.c
>> index 4c94708..beb62b4 100644
>> --- a/qtest.c
>> +++ b/qtest.c
>> @@ -28,6 +28,9 @@
>>  #include "qemu/option.h"
>>  #include "qemu/error-report.h"
>>  #include "qemu/cutils.h"
>> +#ifdef TARGET_PPC64
>> +#include "hw/ppc/spapr_rtas.h"
>> +#endif
>>  
>>  #define MAX_IRQ 256
>>  
>> @@ -531,6 +534,20 @@ static void qtest_process_command(CharDriverState *chr, gchar **words)
>>  
>>          qtest_send_prefix(chr);
>>          qtest_send(chr, "OK\n");
>> +#ifdef TARGET_PPC64
>> +    } else if (strcmp(words[0], "rtas") == 0) {
>> +        uint64_t res, args, ret;
>> +        unsigned long nargs, nret;
>> +
>> +        g_assert(qemu_strtoul(words[2], NULL, 0, &nargs) == 0);
>> +        g_assert(qemu_strtoull(words[3], NULL, 0, &args) == 0);
>> +        g_assert(qemu_strtoul(words[4], NULL, 0, &nret) == 0);
>> +        g_assert(qemu_strtoull(words[5], NULL, 0, &ret) == 0);
>> +        res = qtest_rtas_call(words[1], nargs, args, nret, ret);
>> +
>> +        qtest_send_prefix(chr);
>> +        qtest_sendf(chr, "OK %"PRIu64"\n", res);
>> +#endif
>>      } else if (qtest_enabled() && strcmp(words[0], "clock_step") == 0) {
>>          int64_t ns;
>>  
>> diff --git a/tests/Makefile.include b/tests/Makefile.include
>> index 91df9f2..fd61f97 100644
>> --- a/tests/Makefile.include
>> +++ b/tests/Makefile.include
>> @@ -265,6 +265,7 @@ check-qtest-ppc64-y += tests/prom-env-test$(EXESUF)
>>  check-qtest-ppc64-y += tests/drive_del-test$(EXESUF)
>>  check-qtest-ppc64-y += tests/postcopy-test$(EXESUF)
>>  check-qtest-ppc64-y += tests/boot-serial-test$(EXESUF)
>> +check-qtest-ppc64-y += tests/rtas-test$(EXESUF)
>>  
>>  check-qtest-sh4-y = tests/endianness-test$(EXESUF)
>>  
>> @@ -578,6 +579,7 @@ libqos-obj-y = tests/libqos/pci.o tests/libqos/fw_cfg.o tests/libqos/malloc.o
>>  libqos-obj-y += tests/libqos/i2c.o tests/libqos/libqos.o
>>  libqos-spapr-obj-y = $(libqos-obj-y) tests/libqos/malloc-spapr.o
>>  libqos-spapr-obj-y += tests/libqos/libqos-spapr.o
>> +libqos-spapr-obj-y += tests/libqos/rtas.o
>>  libqos-pc-obj-y = $(libqos-obj-y) tests/libqos/pci-pc.o
>>  libqos-pc-obj-y += tests/libqos/malloc-pc.o tests/libqos/libqos-pc.o
>>  libqos-pc-obj-y += tests/libqos/ahci.o
>> @@ -592,6 +594,7 @@ tests/m48t59-test$(EXESUF): tests/m48t59-test.o
>>  tests/endianness-test$(EXESUF): tests/endianness-test.o
>>  tests/spapr-phb-test$(EXESUF): tests/spapr-phb-test.o $(libqos-obj-y)
>>  tests/prom-env-test$(EXESUF): tests/prom-env-test.o $(libqos-obj-y)
>> +tests/rtas-test$(EXESUF): tests/rtas-test.o $(libqos-spapr-obj-y)
>>  tests/fdc-test$(EXESUF): tests/fdc-test.o
>>  tests/ide-test$(EXESUF): tests/ide-test.o $(libqos-pc-obj-y)
>>  tests/ahci-test$(EXESUF): tests/ahci-test.o $(libqos-pc-obj-y)
>> diff --git a/tests/libqos/rtas.c b/tests/libqos/rtas.c
>> new file mode 100644
>> index 0000000..d5f4ced
>> --- /dev/null
>> +++ b/tests/libqos/rtas.c
>> @@ -0,0 +1,71 @@
>> +/*
>> + * 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 "qemu/osdep.h"
>> +#include "libqtest.h"
>> +#include "libqos/rtas.h"
>> +
>> +static void qrtas_copy_args(uint64_t target_args, uint32_t nargs,
>> +                            uint32_t *args)
>> +{
>> +    int i;
>> +
>> +    for (i = 0; i < nargs; i++) {
>> +        writel(target_args + i * sizeof(uint32_t), args[i]);
>> +    }
>> +}
>> +
>> +static void qrtas_copy_ret(uint64_t target_ret, uint32_t nret, uint32_t *ret)
>> +{
>> +    int i;
>> +
>> +    for (i = 0; i < nret; i++) {
>> +        ret[i] = readl(target_ret + i * sizeof(uint32_t));
>> +    }
>> +}
>> +
>> +static uint64_t qrtas_call(QGuestAllocator *alloc, const char *name,
>> +                           uint32_t nargs, uint32_t *args,
>> +                           uint32_t nret, uint32_t *ret)
>> +{
>> +    uint64_t res;
>> +    uint64_t target_args, target_ret;
>> +
>> +    target_args = guest_alloc(alloc, (nargs + nret) * sizeof(uint32_t));
>> +    target_ret = guest_alloc(alloc, nret * sizeof(uint32_t));
> 
> Again, possibly I'm misunderstanding something, but it looks like
> you're over-allocating here - target_args seems to get enough space
> for both args and rets, then target_ret gets additional space for the
> rets as well.

You're right.

>> +    qrtas_copy_args(target_args, nargs, args);
>> +    res = qtest_rtas_call(global_qtest, name,
>> +                          nargs, target_args, nret, target_ret);
>> +    qrtas_copy_ret(target_ret, nret, ret);
>> +
>> +    guest_free(alloc, target_ret);
>> +    guest_free(alloc, target_args);
>> +
>> +    return res;
>> +}
>> +
>> +int qrtas_get_time_of_day(QGuestAllocator *alloc, struct tm *tm, uint32_t *ns)
>> +{
>> +    int res;
>> +    uint32_t ret[8];
>> +
>> +    res = qrtas_call(alloc, "get-time-of-day", 0, NULL, 8, ret);
>> +    if (res != 0) {
>> +        return res;
>> +    }
>> +
>> +    res = ret[0];
>> +    memset(tm, 0, sizeof(*tm));
>> +    tm->tm_year = ret[1] - 1900;
>> +    tm->tm_mon = ret[2] - 1;
>> +    tm->tm_mday = ret[3];
>> +    tm->tm_hour = ret[4];
>> +    tm->tm_min = ret[5];
>> +    tm->tm_sec = ret[6];
>> +    *ns = ret[7];
>> +
>> +    return res;
>> +}
>> diff --git a/tests/libqos/rtas.h b/tests/libqos/rtas.h
>> new file mode 100644
>> index 0000000..a1b60a8
>> --- /dev/null
>> +++ b/tests/libqos/rtas.h
>> @@ -0,0 +1,11 @@
>> +/*
>> + * This work is licensed under the terms of the GNU GPL, version 2 or later.
>> + * See the COPYING file in the top-level directory.
>> + */
>> +
>> +#ifndef LIBQOS_RTAS_H
>> +#define LIBQOS_RTAS_H
>> +#include "libqos/malloc.h"
>> +
>> +int qrtas_get_time_of_day(QGuestAllocator *alloc, struct tm *tm, uint32_t *ns);
>> +#endif /* LIBQOS_RTAS_H */
>> diff --git a/tests/libqtest.c b/tests/libqtest.c
>> index eb00f13..c9dd57b 100644
>> --- a/tests/libqtest.c
>> +++ b/tests/libqtest.c
>> @@ -751,6 +751,16 @@ void qtest_memread(QTestState *s, uint64_t addr, void *data, size_t size)
>>      g_strfreev(args);
>>  }
>>  
>> +uint64_t qtest_rtas_call(QTestState *s, const char *name,
>> +                         uint32_t nargs, uint64_t args,
>> +                         uint32_t nret, uint64_t ret)
>> +{
>> +    qtest_sendf(s, "rtas %s %u 0x%"PRIx64" %u 0x%"PRIx64"\n",
>> +                name, nargs, args, nret, ret);
>> +    qtest_rsp(s, 0);
>> +    return 0;
>> +}
>> +
>>  void qtest_add_func(const char *str, void (*fn)(void))
>>  {
>>      gchar *path = g_strdup_printf("/%s/%s", qtest_get_arch(), str);
>> diff --git a/tests/libqtest.h b/tests/libqtest.h
>> index 37f37ad..1badb76 100644
>> --- a/tests/libqtest.h
>> +++ b/tests/libqtest.h
>> @@ -318,6 +318,21 @@ uint64_t qtest_readq(QTestState *s, uint64_t addr);
>>  void qtest_memread(QTestState *s, uint64_t addr, void *data, size_t size);
>>  
>>  /**
>> + * qtest_rtas_call:
>> + * @s: #QTestState instance to operate on.
>> + * @name: name of the command to call.
>> + * @nargs: Number of args.
>> + * @args: Guest address to read args from.
>> + * @nret: Number of return value.
>> + * @ret: Guest address to write return values to.
>> + *
>> + * Call an RTAS function
>> + */
>> +uint64_t qtest_rtas_call(QTestState *s, const char *name,
>> +                         uint32_t nargs, uint64_t args,
>> +                         uint32_t nret, uint64_t ret);
>> +
>> +/**
>>   * qtest_bufread:
>>   * @s: #QTestState instance to operate on.
>>   * @addr: Guest address to read from.
>> diff --git a/tests/rtas-test.c b/tests/rtas-test.c
>> new file mode 100644
>> index 0000000..3bca36b
>> --- /dev/null
>> +++ b/tests/rtas-test.c
>> @@ -0,0 +1,40 @@
>> +#include "qemu/osdep.h"
>> +#include "qemu/cutils.h"
>> +#include "libqtest.h"
>> +
>> +#include "libqos/libqos-spapr.h"
>> +#include "libqos/rtas.h"
>> +
>> +static void test_rtas_get_time_of_day(void)
>> +{
>> +    QOSState *qs;
>> +    struct tm tm;
>> +    uint32_t ns;
>> +    uint64_t ret;
>> +    time_t t1, t2;
>> +
>> +    qs = qtest_spapr_boot("");
>> +
>> +    t1 = time(NULL);
>> +    ret = qrtas_get_time_of_day(qs->alloc, &tm, &ns);
>> +    g_assert_cmpint(ret, ==, 0);
>> +    t2 = mktimegm(&tm);
>> +    g_assert(t2 - t1 < 5); /* 5 sec max to run the test */
>> +
>> +    qtest_spapr_shutdown(qs);
>> +}
>> +
>> +int main(int argc, char *argv[])
>> +{
>> +    const char *arch = qtest_get_arch();
>> +
>> +    g_test_init(&argc, &argv, NULL);
>> +
>> +    if (strcmp(arch, "ppc64") == 0) {
>> +        qtest_add_func("rtas/get-time-of-day", test_rtas_get_time_of_day);
>> +    } else {
>> +        g_assert_not_reached();
>> +    }
>> +
>> +    return g_test_run();
>> +}
> 

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

* Re: [Qemu-devel] [PATCH v6 3/3] tests: add RTAS command in the protocol
  2016-09-12 17:09     ` Laurent Vivier
@ 2016-09-13  5:36       ` David Gibson
  0 siblings, 0 replies; 10+ messages in thread
From: David Gibson @ 2016-09-13  5:36 UTC (permalink / raw)
  To: Laurent Vivier; +Cc: thuth, qemu-ppc, qemu-devel, groug

[-- Attachment #1: Type: text/plain, Size: 14715 bytes --]

On Mon, Sep 12, 2016 at 07:09:37PM +0200, Laurent Vivier wrote:
> 
> 
> On 12/09/2016 06:17, David Gibson wrote:
> > On Thu, Sep 08, 2016 at 09:00:07PM +0200, Laurent Vivier wrote:
> >> Add a first test to validate the protocol:
> >>
> >> - rtas/get-time-of-day compares the time
> >>   from the guest with the time from the host.
> >>
> >> Signed-off-by: Laurent Vivier <lvivier@redhat.com>
> >> ---
> >> v6:
> >> - rebase
> >>
> >> v5:
> >> - use qtest_spapr_boot() instead of machine_alloc_init()
> >>
> >> v4:
> >> - use qemu_strtoXXX() instead strtoXX()
> >>
> >> v3:
> >> - use mktimegm() instead of timegm()
> >>
> >> v2:
> >> - add a missing space in qrtas_call() prototype
> >>
> >>  hw/ppc/spapr_rtas.c         | 19 ++++++++++++
> >>  include/hw/ppc/spapr_rtas.h | 10 +++++++
> >>  qtest.c                     | 17 +++++++++++
> >>  tests/Makefile.include      |  3 ++
> >>  tests/libqos/rtas.c         | 71 +++++++++++++++++++++++++++++++++++++++++++++
> >>  tests/libqos/rtas.h         | 11 +++++++
> >>  tests/libqtest.c            | 10 +++++++
> >>  tests/libqtest.h            | 15 ++++++++++
> >>  tests/rtas-test.c           | 40 +++++++++++++++++++++++++
> >>  9 files changed, 196 insertions(+)
> >>  create mode 100644 include/hw/ppc/spapr_rtas.h
> >>  create mode 100644 tests/libqos/rtas.c
> >>  create mode 100644 tests/libqos/rtas.h
> >>  create mode 100644 tests/rtas-test.c
> >>
> >> diff --git a/hw/ppc/spapr_rtas.c b/hw/ppc/spapr_rtas.c
> >> index 27b5ad4..b80c1db 100644
> >> --- a/hw/ppc/spapr_rtas.c
> >> +++ b/hw/ppc/spapr_rtas.c
> >> @@ -37,6 +37,7 @@
> >>  
> >>  #include "hw/ppc/spapr.h"
> >>  #include "hw/ppc/spapr_vio.h"
> >> +#include "hw/ppc/spapr_rtas.h"
> >>  #include "hw/ppc/ppc.h"
> >>  #include "qapi-event.h"
> >>  #include "hw/boards.h"
> >> @@ -692,6 +693,24 @@ target_ulong spapr_rtas_call(PowerPCCPU *cpu, sPAPRMachineState *spapr,
> >>      return H_PARAMETER;
> >>  }
> >>  
> >> +uint64_t qtest_rtas_call(char *cmd, uint32_t nargs, uint64_t args,
> >> +                         uint32_t nret, uint64_t rets)
> >> +{
> >> +    int token;
> >> +
> >> +    for (token = 0; token < RTAS_TOKEN_MAX - RTAS_TOKEN_BASE; token++) {
> >> +        if (strcmp(cmd, rtas_table[token].name) == 0) {
> >> +            sPAPRMachineState *spapr = SPAPR_MACHINE(qdev_get_machine());
> >> +            PowerPCCPU *cpu = POWERPC_CPU(first_cpu);
> >> +
> >> +            rtas_table[token].fn(cpu, spapr, token + RTAS_TOKEN_BASE,
> >> +                                 nargs, args, nret, rets);
> >> +            return H_SUCCESS;
> >> +        }
> >> +    }
> >> +    return H_PARAMETER;
> >> +}
> > 
> > I may be misunderstanding how qtest works here.  But wouldn't it test
> 
> >From the point of view of the machine, qtest is an accelerator: so the
> CPU is stopped, and the qtest accelerator open a socket allowing another
> process to read/write/in/out/... the memory of the machine.
> This allows to test the machine hardware or the hypervisor, not the CPU
> or the firmware. kvm-unit-tests is better for this kind of test.

Ah!  Yes, I was misunderstanding.  So the qtest script is basically
replacing the guest's cpu.

> The qtest protocol is human readable: the second process sends strings
> like "read 0x1000" and the qtest accelerator answers something like "OK
> 0" or "ERROR". This is why, from my point of view, using the name of the
> service rather than the token number seems better.

I see your point.

> > a bit more of the common code paths if rather than doing your own
> > token lookup here, you actually generated a full guest style rtas
> > parameter buffer (token + args + rets in one structure), then dispatch
> 
> We can't do the token lookup at the level of the second process as the
> token is extracted from the OF device tree and for the moment we don't
> have the functions in this process to scan the OF device tree. It is
> possible as we can read the guest memory, but the functions are not
> here. I plan to add this kind of feature, for instance to read the
> memory size, but for the moment nothing is done.

Right. Possible, but fiddly.  Leaving it until later seems fair
enough.

> > through h_rtas, or spapr_rtas_call?
> > 
> >> +
> >>  void spapr_rtas_register(int token, const char *name, spapr_rtas_fn fn)
> >>  {
> >>      assert((token >= RTAS_TOKEN_BASE) && (token < RTAS_TOKEN_MAX));
> >> diff --git a/include/hw/ppc/spapr_rtas.h b/include/hw/ppc/spapr_rtas.h
> >> new file mode 100644
> >> index 0000000..383611f
> >> --- /dev/null
> >> +++ b/include/hw/ppc/spapr_rtas.h
> >> @@ -0,0 +1,10 @@
> >> +#ifndef HW_SPAPR_RTAS_H
> >> +#define HW_SPAPR_RTAS_H
> >> +/*
> >> + * This work is licensed under the terms of the GNU GPL, version 2 or later.
> >> + * See the COPYING file in the top-level directory.
> >> + */
> >> +
> >> +uint64_t qtest_rtas_call(char *cmd, uint32_t nargs, uint64_t args,
> >> +                         uint32_t nret, uint64_t rets);
> >> +#endif /* HW_SPAPR_RTAS_H */
> >> diff --git a/qtest.c b/qtest.c
> >> index 4c94708..beb62b4 100644
> >> --- a/qtest.c
> >> +++ b/qtest.c
> >> @@ -28,6 +28,9 @@
> >>  #include "qemu/option.h"
> >>  #include "qemu/error-report.h"
> >>  #include "qemu/cutils.h"
> >> +#ifdef TARGET_PPC64
> >> +#include "hw/ppc/spapr_rtas.h"
> >> +#endif
> >>  
> >>  #define MAX_IRQ 256
> >>  
> >> @@ -531,6 +534,20 @@ static void qtest_process_command(CharDriverState *chr, gchar **words)
> >>  
> >>          qtest_send_prefix(chr);
> >>          qtest_send(chr, "OK\n");
> >> +#ifdef TARGET_PPC64
> >> +    } else if (strcmp(words[0], "rtas") == 0) {
> >> +        uint64_t res, args, ret;
> >> +        unsigned long nargs, nret;
> >> +
> >> +        g_assert(qemu_strtoul(words[2], NULL, 0, &nargs) == 0);
> >> +        g_assert(qemu_strtoull(words[3], NULL, 0, &args) == 0);
> >> +        g_assert(qemu_strtoul(words[4], NULL, 0, &nret) == 0);
> >> +        g_assert(qemu_strtoull(words[5], NULL, 0, &ret) == 0);
> >> +        res = qtest_rtas_call(words[1], nargs, args, nret, ret);
> >> +
> >> +        qtest_send_prefix(chr);
> >> +        qtest_sendf(chr, "OK %"PRIu64"\n", res);
> >> +#endif
> >>      } else if (qtest_enabled() && strcmp(words[0], "clock_step") == 0) {
> >>          int64_t ns;
> >>  
> >> diff --git a/tests/Makefile.include b/tests/Makefile.include
> >> index 91df9f2..fd61f97 100644
> >> --- a/tests/Makefile.include
> >> +++ b/tests/Makefile.include
> >> @@ -265,6 +265,7 @@ check-qtest-ppc64-y += tests/prom-env-test$(EXESUF)
> >>  check-qtest-ppc64-y += tests/drive_del-test$(EXESUF)
> >>  check-qtest-ppc64-y += tests/postcopy-test$(EXESUF)
> >>  check-qtest-ppc64-y += tests/boot-serial-test$(EXESUF)
> >> +check-qtest-ppc64-y += tests/rtas-test$(EXESUF)
> >>  
> >>  check-qtest-sh4-y = tests/endianness-test$(EXESUF)
> >>  
> >> @@ -578,6 +579,7 @@ libqos-obj-y = tests/libqos/pci.o tests/libqos/fw_cfg.o tests/libqos/malloc.o
> >>  libqos-obj-y += tests/libqos/i2c.o tests/libqos/libqos.o
> >>  libqos-spapr-obj-y = $(libqos-obj-y) tests/libqos/malloc-spapr.o
> >>  libqos-spapr-obj-y += tests/libqos/libqos-spapr.o
> >> +libqos-spapr-obj-y += tests/libqos/rtas.o
> >>  libqos-pc-obj-y = $(libqos-obj-y) tests/libqos/pci-pc.o
> >>  libqos-pc-obj-y += tests/libqos/malloc-pc.o tests/libqos/libqos-pc.o
> >>  libqos-pc-obj-y += tests/libqos/ahci.o
> >> @@ -592,6 +594,7 @@ tests/m48t59-test$(EXESUF): tests/m48t59-test.o
> >>  tests/endianness-test$(EXESUF): tests/endianness-test.o
> >>  tests/spapr-phb-test$(EXESUF): tests/spapr-phb-test.o $(libqos-obj-y)
> >>  tests/prom-env-test$(EXESUF): tests/prom-env-test.o $(libqos-obj-y)
> >> +tests/rtas-test$(EXESUF): tests/rtas-test.o $(libqos-spapr-obj-y)
> >>  tests/fdc-test$(EXESUF): tests/fdc-test.o
> >>  tests/ide-test$(EXESUF): tests/ide-test.o $(libqos-pc-obj-y)
> >>  tests/ahci-test$(EXESUF): tests/ahci-test.o $(libqos-pc-obj-y)
> >> diff --git a/tests/libqos/rtas.c b/tests/libqos/rtas.c
> >> new file mode 100644
> >> index 0000000..d5f4ced
> >> --- /dev/null
> >> +++ b/tests/libqos/rtas.c
> >> @@ -0,0 +1,71 @@
> >> +/*
> >> + * 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 "qemu/osdep.h"
> >> +#include "libqtest.h"
> >> +#include "libqos/rtas.h"
> >> +
> >> +static void qrtas_copy_args(uint64_t target_args, uint32_t nargs,
> >> +                            uint32_t *args)
> >> +{
> >> +    int i;
> >> +
> >> +    for (i = 0; i < nargs; i++) {
> >> +        writel(target_args + i * sizeof(uint32_t), args[i]);
> >> +    }
> >> +}
> >> +
> >> +static void qrtas_copy_ret(uint64_t target_ret, uint32_t nret, uint32_t *ret)
> >> +{
> >> +    int i;
> >> +
> >> +    for (i = 0; i < nret; i++) {
> >> +        ret[i] = readl(target_ret + i * sizeof(uint32_t));
> >> +    }
> >> +}
> >> +
> >> +static uint64_t qrtas_call(QGuestAllocator *alloc, const char *name,
> >> +                           uint32_t nargs, uint32_t *args,
> >> +                           uint32_t nret, uint32_t *ret)
> >> +{
> >> +    uint64_t res;
> >> +    uint64_t target_args, target_ret;
> >> +
> >> +    target_args = guest_alloc(alloc, (nargs + nret) * sizeof(uint32_t));
> >> +    target_ret = guest_alloc(alloc, nret * sizeof(uint32_t));
> > 
> > Again, possibly I'm misunderstanding something, but it looks like
> > you're over-allocating here - target_args seems to get enough space
> > for both args and rets, then target_ret gets additional space for the
> > rets as well.
> 
> You're right.
> 
> >> +    qrtas_copy_args(target_args, nargs, args);
> >> +    res = qtest_rtas_call(global_qtest, name,
> >> +                          nargs, target_args, nret, target_ret);
> >> +    qrtas_copy_ret(target_ret, nret, ret);
> >> +
> >> +    guest_free(alloc, target_ret);
> >> +    guest_free(alloc, target_args);
> >> +
> >> +    return res;
> >> +}
> >> +
> >> +int qrtas_get_time_of_day(QGuestAllocator *alloc, struct tm *tm, uint32_t *ns)
> >> +{
> >> +    int res;
> >> +    uint32_t ret[8];
> >> +
> >> +    res = qrtas_call(alloc, "get-time-of-day", 0, NULL, 8, ret);
> >> +    if (res != 0) {
> >> +        return res;
> >> +    }
> >> +
> >> +    res = ret[0];
> >> +    memset(tm, 0, sizeof(*tm));
> >> +    tm->tm_year = ret[1] - 1900;
> >> +    tm->tm_mon = ret[2] - 1;
> >> +    tm->tm_mday = ret[3];
> >> +    tm->tm_hour = ret[4];
> >> +    tm->tm_min = ret[5];
> >> +    tm->tm_sec = ret[6];
> >> +    *ns = ret[7];
> >> +
> >> +    return res;
> >> +}
> >> diff --git a/tests/libqos/rtas.h b/tests/libqos/rtas.h
> >> new file mode 100644
> >> index 0000000..a1b60a8
> >> --- /dev/null
> >> +++ b/tests/libqos/rtas.h
> >> @@ -0,0 +1,11 @@
> >> +/*
> >> + * This work is licensed under the terms of the GNU GPL, version 2 or later.
> >> + * See the COPYING file in the top-level directory.
> >> + */
> >> +
> >> +#ifndef LIBQOS_RTAS_H
> >> +#define LIBQOS_RTAS_H
> >> +#include "libqos/malloc.h"
> >> +
> >> +int qrtas_get_time_of_day(QGuestAllocator *alloc, struct tm *tm, uint32_t *ns);
> >> +#endif /* LIBQOS_RTAS_H */
> >> diff --git a/tests/libqtest.c b/tests/libqtest.c
> >> index eb00f13..c9dd57b 100644
> >> --- a/tests/libqtest.c
> >> +++ b/tests/libqtest.c
> >> @@ -751,6 +751,16 @@ void qtest_memread(QTestState *s, uint64_t addr, void *data, size_t size)
> >>      g_strfreev(args);
> >>  }
> >>  
> >> +uint64_t qtest_rtas_call(QTestState *s, const char *name,
> >> +                         uint32_t nargs, uint64_t args,
> >> +                         uint32_t nret, uint64_t ret)
> >> +{
> >> +    qtest_sendf(s, "rtas %s %u 0x%"PRIx64" %u 0x%"PRIx64"\n",
> >> +                name, nargs, args, nret, ret);
> >> +    qtest_rsp(s, 0);
> >> +    return 0;
> >> +}
> >> +
> >>  void qtest_add_func(const char *str, void (*fn)(void))
> >>  {
> >>      gchar *path = g_strdup_printf("/%s/%s", qtest_get_arch(), str);
> >> diff --git a/tests/libqtest.h b/tests/libqtest.h
> >> index 37f37ad..1badb76 100644
> >> --- a/tests/libqtest.h
> >> +++ b/tests/libqtest.h
> >> @@ -318,6 +318,21 @@ uint64_t qtest_readq(QTestState *s, uint64_t addr);
> >>  void qtest_memread(QTestState *s, uint64_t addr, void *data, size_t size);
> >>  
> >>  /**
> >> + * qtest_rtas_call:
> >> + * @s: #QTestState instance to operate on.
> >> + * @name: name of the command to call.
> >> + * @nargs: Number of args.
> >> + * @args: Guest address to read args from.
> >> + * @nret: Number of return value.
> >> + * @ret: Guest address to write return values to.
> >> + *
> >> + * Call an RTAS function
> >> + */
> >> +uint64_t qtest_rtas_call(QTestState *s, const char *name,
> >> +                         uint32_t nargs, uint64_t args,
> >> +                         uint32_t nret, uint64_t ret);
> >> +
> >> +/**
> >>   * qtest_bufread:
> >>   * @s: #QTestState instance to operate on.
> >>   * @addr: Guest address to read from.
> >> diff --git a/tests/rtas-test.c b/tests/rtas-test.c
> >> new file mode 100644
> >> index 0000000..3bca36b
> >> --- /dev/null
> >> +++ b/tests/rtas-test.c
> >> @@ -0,0 +1,40 @@
> >> +#include "qemu/osdep.h"
> >> +#include "qemu/cutils.h"
> >> +#include "libqtest.h"
> >> +
> >> +#include "libqos/libqos-spapr.h"
> >> +#include "libqos/rtas.h"
> >> +
> >> +static void test_rtas_get_time_of_day(void)
> >> +{
> >> +    QOSState *qs;
> >> +    struct tm tm;
> >> +    uint32_t ns;
> >> +    uint64_t ret;
> >> +    time_t t1, t2;
> >> +
> >> +    qs = qtest_spapr_boot("");
> >> +
> >> +    t1 = time(NULL);
> >> +    ret = qrtas_get_time_of_day(qs->alloc, &tm, &ns);
> >> +    g_assert_cmpint(ret, ==, 0);
> >> +    t2 = mktimegm(&tm);
> >> +    g_assert(t2 - t1 < 5); /* 5 sec max to run the test */
> >> +
> >> +    qtest_spapr_shutdown(qs);
> >> +}
> >> +
> >> +int main(int argc, char *argv[])
> >> +{
> >> +    const char *arch = qtest_get_arch();
> >> +
> >> +    g_test_init(&argc, &argv, NULL);
> >> +
> >> +    if (strcmp(arch, "ppc64") == 0) {
> >> +        qtest_add_func("rtas/get-time-of-day", test_rtas_get_time_of_day);
> >> +    } else {
> >> +        g_assert_not_reached();
> >> +    }
> >> +
> >> +    return g_test_run();
> >> +}
> > 
> 

-- 
David Gibson			| I'll have my music baroque, and my code
david AT gibson.dropbear.id.au	| minimalist, thank you.  NOT _the_ _other_
				| _way_ _around_!
http://www.ozlabs.org/~dgibson

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 801 bytes --]

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

end of thread, other threads:[~2016-09-13  5:37 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-09-08 19:00 [Qemu-devel] [PATCH v6 0/3] tests: add RTAS protocol Laurent Vivier
2016-09-08 19:00 ` [Qemu-devel] [PATCH v6 1/3] qtest: replace strtoXX() by qemu_strtoXX() Laurent Vivier
2016-09-08 19:00 ` [Qemu-devel] [PATCH v6 2/3] libqos: define SPAPR libqos functions Laurent Vivier
2016-09-12  4:08   ` David Gibson
2016-09-08 19:00 ` [Qemu-devel] [PATCH v6 3/3] tests: add RTAS command in the protocol Laurent Vivier
2016-09-09 16:49   ` Greg Kurz
2016-09-12 15:41     ` Laurent Vivier
2016-09-12  4:17   ` David Gibson
2016-09-12 17:09     ` Laurent Vivier
2016-09-13  5:36       ` David Gibson

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