Patchwork [RFC,1/3] qtest: Prepare hypercall support

login
register
mail settings
Submitter Andreas Färber
Date Jan. 23, 2013, 10:01 a.m.
Message ID <1358935314-18768-2-git-send-email-afaerber@suse.de>
Download mbox | patch
Permalink /patch/214872/
State New
Headers show

Comments

Andreas Färber - Jan. 23, 2013, 10:01 a.m.
Signed-off-by: Andreas Färber <afaerber@suse.de>
---
 include/sysemu/qtest.h |    2 ++
 qtest.c                |   26 ++++++++++++++++++++++++++
 stubs/Makefile.objs    |    1 +
 stubs/qtest.c          |   12 ++++++++++++
 tests/libqtest.c       |   21 +++++++++++++++++++++
 tests/libqtest.h       |   17 +++++++++++++++++
 6 Dateien geändert, 79 Zeilen hinzugefügt(+)
 create mode 100644 stubs/qtest.c
Anthony Liguori - Jan. 23, 2013, 12:55 p.m.
Andreas Färber <afaerber@suse.de> writes:

> Signed-off-by: Andreas Färber <afaerber@suse.de>
> ---
>  include/sysemu/qtest.h |    2 ++
>  qtest.c                |   26 ++++++++++++++++++++++++++
>  stubs/Makefile.objs    |    1 +
>  stubs/qtest.c          |   12 ++++++++++++
>  tests/libqtest.c       |   21 +++++++++++++++++++++
>  tests/libqtest.h       |   17 +++++++++++++++++
>  6 Dateien geändert, 79 Zeilen hinzugefügt(+)
>  create mode 100644 stubs/qtest.c
>
> diff --git a/include/sysemu/qtest.h b/include/sysemu/qtest.h
> index 723a4f9..75ab29d 100644
> --- a/include/sysemu/qtest.h
> +++ b/include/sysemu/qtest.h
> @@ -32,6 +32,8 @@ static inline int qtest_available(void)
>  }
>  
>  int qtest_init(void);
> +bool qtest_hypercall_supported(void);
> +int qtest_hypercall(uint64_t code, uint64_t *args);
>  #else
>  static inline bool qtest_enabled(void)
>  {
> diff --git a/qtest.c b/qtest.c
> index c9b58ce..a5b54e3 100644
> --- a/qtest.c
> +++ b/qtest.c
> @@ -117,6 +117,11 @@ static bool qtest_opened;
>   * where NUM is an IRQ number.  For the PC, interrupts can be intercepted
>   * simply with "irq_intercept_in ioapic" (note that IRQ0 comes out with
>   * NUM=0 even though it is remapped to GSI 2).
> + *
> + * Hypercalls:
> + *
> + * > hypercall CODE
> + * < OK
>   */
>  
>  static int hex2nib(char ch)
> @@ -344,6 +349,27 @@ static void qtest_process_command(CharDriverState *chr, gchar **words)
>          qtest_clock_warp(ns);
>          qtest_send_prefix(chr);
>          qtest_send(chr, "OK %"PRIi64"\n", (int64_t)qemu_get_clock_ns(vm_clock));
> +    } else if (strcmp(words[0], "hypercall") == 0 &&
> +               qtest_hypercall_supported()) {
> +        uint64_t code;
> +        uint64_t args[13];
> +        int ret, i;
> +
> +        g_assert(words[1] != NULL);
> +        code = strtoull(words[1], NULL, 0);
> +
> +        memset(args, 0, sizeof(args));
> +        for (i = 0; i < 13 && words[2 + i] != NULL; i++) {
> +            args[i] = strtoull(words[2 + i], NULL, 0);
> +        }
> +
> +        ret = qtest_hypercall(code, args);
> +        qtest_send_prefix(chr);
> +        if (ret < 0) {
> +            qtest_send(chr, "ERR 0x%x\n", ret);
> +            return;
> +        }
> +        qtest_send(chr, "OK 0x%x\n", ret);

Certainly on x86 hypercalls have a well defined set of arguments.  I
seem to recall having this discussion with David and Paul though and
with PAPR, not all hypercalls follow the same conventions in terms of
what registers are used.

David, can you elaborate?  Am I remembering incorrectly?

Regards,

Anthony Liguori

>      } else {
>          qtest_send_prefix(chr);
>          qtest_send(chr, "FAIL Unknown command `%s'\n", words[0]);
> diff --git a/stubs/Makefile.objs b/stubs/Makefile.objs
> index a260394..50fb2a7 100644
> --- a/stubs/Makefile.objs
> +++ b/stubs/Makefile.objs
> @@ -15,6 +15,7 @@ stub-obj-y += mon-printf.o
>  stub-obj-y += mon-print-filename.o
>  stub-obj-y += mon-protocol-event.o
>  stub-obj-y += mon-set-error.o
> +stub-obj-y += qtest.o
>  stub-obj-y += reset.o
>  stub-obj-y += set-fd-handler.o
>  stub-obj-y += slirp.o
> diff --git a/stubs/qtest.c b/stubs/qtest.c
> new file mode 100644
> index 0000000..8860e4f
> --- /dev/null
> +++ b/stubs/qtest.c
> @@ -0,0 +1,12 @@
> +#include "qemu-common.h"
> +#include "sysemu/qtest.h"
> +
> +bool qtest_hypercall_supported(void)
> +{
> +    return false;
> +}
> +
> +int qtest_hypercall(uint64_t code, uint64_t *args)
> +{
> +    return -EINVAL;
> +}
> diff --git a/tests/libqtest.c b/tests/libqtest.c
> index 913fa05..5eb9521 100644
> --- a/tests/libqtest.c
> +++ b/tests/libqtest.c
> @@ -476,3 +476,24 @@ void qtest_memwrite(QTestState *s, uint64_t addr, const void *data, size_t size)
>      qtest_sendf(s, "\n");
>      qtest_rsp(s, 0);
>  }
> +
> +uint64_t qtest_hypercall(QTestState *s, uint64_t code, int argc, ...)
> +{
> +    va_list va;
> +    gchar **args;
> +    uint64_t resp, arg;
> +    int i;
> +
> +    qtest_sendf(s, "hypercall 0x%" PRIx64, code);
> +    va_start(va, argc);
> +    for (i = 0; i < argc; i++) {
> +        arg = va_arg(va, uint64_t);
> +        qtest_sendf(s, " 0x%" PRIx64, arg);
> +    }
> +    va_end(va);
> +    qtest_sendf(s, "\n");
> +    args = qtest_rsp(s, 2);
> +    resp = g_ascii_strtoull(args[1], NULL, 0);
> +    g_strfreev(args);
> +    return resp;
> +}
> diff --git a/tests/libqtest.h b/tests/libqtest.h
> index c8ade85..3a5a8f9 100644
> --- a/tests/libqtest.h
> +++ b/tests/libqtest.h
> @@ -187,6 +187,15 @@ int64_t qtest_clock_step(QTestState *s, int64_t step);
>  int64_t qtest_clock_set(QTestState *s, int64_t val);
>  
>  /**
> + * qtest_hypercall:
> + * @s: QTestState instance to operate on.
> + * @code: Hypercall code to call.
> + *
> + * Peform a hypercall @code on the guest.
> + */
> +uint64_t qtest_hypercall(QTestState *s, uint64_t code, int argc, ...);
> +
> +/**
>   * qtest_get_arch:
>   *
>   * Returns the architecture for the QEMU executable under test.
> @@ -349,4 +358,12 @@ void qtest_add_func(const char *str, void (*fn));
>   */
>  #define clock_set(val) qtest_clock_set(global_qtest, val)
>  
> +/**
> + * hypercall:
> + * @code: Hypercall code.
> + *
> + * Invokes a hypercall in the guest.
> + */
> +#define hypercall(code, argc, ...) qtest_hypercall(global_qtest, code, argc, ## __VA_ARGS__)
> +
>  #endif
> -- 
> 1.7.10.4
Alexander Graf - Jan. 25, 2013, 11:27 a.m.
On 23.01.2013, at 11:01, Andreas Färber wrote:

> Signed-off-by: Andreas Färber <afaerber@suse.de>
> ---
> include/sysemu/qtest.h |    2 ++
> qtest.c                |   26 ++++++++++++++++++++++++++
> stubs/Makefile.objs    |    1 +
> stubs/qtest.c          |   12 ++++++++++++
> tests/libqtest.c       |   21 +++++++++++++++++++++
> tests/libqtest.h       |   17 +++++++++++++++++
> 6 Dateien geändert, 79 Zeilen hinzugefügt(+)
> create mode 100644 stubs/qtest.c
> 
> diff --git a/include/sysemu/qtest.h b/include/sysemu/qtest.h
> index 723a4f9..75ab29d 100644
> --- a/include/sysemu/qtest.h
> +++ b/include/sysemu/qtest.h
> @@ -32,6 +32,8 @@ static inline int qtest_available(void)
> }
> 
> int qtest_init(void);
> +bool qtest_hypercall_supported(void);
> +int qtest_hypercall(uint64_t code, uint64_t *args);
> #else
> static inline bool qtest_enabled(void)
> {
> diff --git a/qtest.c b/qtest.c
> index c9b58ce..a5b54e3 100644
> --- a/qtest.c
> +++ b/qtest.c
> @@ -117,6 +117,11 @@ static bool qtest_opened;
>  * where NUM is an IRQ number.  For the PC, interrupts can be intercepted
>  * simply with "irq_intercept_in ioapic" (note that IRQ0 comes out with
>  * NUM=0 even though it is remapped to GSI 2).
> + *
> + * Hypercalls:
> + *
> + * > hypercall CODE
> + * < OK
>  */
> 
> static int hex2nib(char ch)
> @@ -344,6 +349,27 @@ static void qtest_process_command(CharDriverState *chr, gchar **words)
>         qtest_clock_warp(ns);
>         qtest_send_prefix(chr);
>         qtest_send(chr, "OK %"PRIi64"\n", (int64_t)qemu_get_clock_ns(vm_clock));
> +    } else if (strcmp(words[0], "hypercall") == 0 &&

I don't think we will be able to find a common dominator for hypercall ABIs across the board. So this one should be called s390_kvm_hypercall, as that's what you are really modeling :).


Alex

> +               qtest_hypercall_supported()) {
> +        uint64_t code;
> +        uint64_t args[13];
> +        int ret, i;
> +
> +        g_assert(words[1] != NULL);
> +        code = strtoull(words[1], NULL, 0);
> +
> +        memset(args, 0, sizeof(args));
> +        for (i = 0; i < 13 && words[2 + i] != NULL; i++) {
> +            args[i] = strtoull(words[2 + i], NULL, 0);
> +        }
> +
> +        ret = qtest_hypercall(code, args);
> +        qtest_send_prefix(chr);
> +        if (ret < 0) {
> +            qtest_send(chr, "ERR 0x%x\n", ret);
> +            return;
> +        }
> +        qtest_send(chr, "OK 0x%x\n", ret);
>     } else {
>         qtest_send_prefix(chr);
>         qtest_send(chr, "FAIL Unknown command `%s'\n", words[0]);
> diff --git a/stubs/Makefile.objs b/stubs/Makefile.objs
> index a260394..50fb2a7 100644
> --- a/stubs/Makefile.objs
> +++ b/stubs/Makefile.objs
> @@ -15,6 +15,7 @@ stub-obj-y += mon-printf.o
> stub-obj-y += mon-print-filename.o
> stub-obj-y += mon-protocol-event.o
> stub-obj-y += mon-set-error.o
> +stub-obj-y += qtest.o
> stub-obj-y += reset.o
> stub-obj-y += set-fd-handler.o
> stub-obj-y += slirp.o
> diff --git a/stubs/qtest.c b/stubs/qtest.c
> new file mode 100644
> index 0000000..8860e4f
> --- /dev/null
> +++ b/stubs/qtest.c
> @@ -0,0 +1,12 @@
> +#include "qemu-common.h"
> +#include "sysemu/qtest.h"
> +
> +bool qtest_hypercall_supported(void)
> +{
> +    return false;
> +}
> +
> +int qtest_hypercall(uint64_t code, uint64_t *args)
> +{
> +    return -EINVAL;
> +}
> diff --git a/tests/libqtest.c b/tests/libqtest.c
> index 913fa05..5eb9521 100644
> --- a/tests/libqtest.c
> +++ b/tests/libqtest.c
> @@ -476,3 +476,24 @@ void qtest_memwrite(QTestState *s, uint64_t addr, const void *data, size_t size)
>     qtest_sendf(s, "\n");
>     qtest_rsp(s, 0);
> }
> +
> +uint64_t qtest_hypercall(QTestState *s, uint64_t code, int argc, ...)
> +{
> +    va_list va;
> +    gchar **args;
> +    uint64_t resp, arg;
> +    int i;
> +
> +    qtest_sendf(s, "hypercall 0x%" PRIx64, code);
> +    va_start(va, argc);
> +    for (i = 0; i < argc; i++) {
> +        arg = va_arg(va, uint64_t);
> +        qtest_sendf(s, " 0x%" PRIx64, arg);
> +    }
> +    va_end(va);
> +    qtest_sendf(s, "\n");
> +    args = qtest_rsp(s, 2);
> +    resp = g_ascii_strtoull(args[1], NULL, 0);
> +    g_strfreev(args);
> +    return resp;
> +}
> diff --git a/tests/libqtest.h b/tests/libqtest.h
> index c8ade85..3a5a8f9 100644
> --- a/tests/libqtest.h
> +++ b/tests/libqtest.h
> @@ -187,6 +187,15 @@ int64_t qtest_clock_step(QTestState *s, int64_t step);
> int64_t qtest_clock_set(QTestState *s, int64_t val);
> 
> /**
> + * qtest_hypercall:
> + * @s: QTestState instance to operate on.
> + * @code: Hypercall code to call.
> + *
> + * Peform a hypercall @code on the guest.
> + */
> +uint64_t qtest_hypercall(QTestState *s, uint64_t code, int argc, ...);
> +
> +/**
>  * qtest_get_arch:
>  *
>  * Returns the architecture for the QEMU executable under test.
> @@ -349,4 +358,12 @@ void qtest_add_func(const char *str, void (*fn));
>  */
> #define clock_set(val) qtest_clock_set(global_qtest, val)
> 
> +/**
> + * hypercall:
> + * @code: Hypercall code.
> + *
> + * Invokes a hypercall in the guest.
> + */
> +#define hypercall(code, argc, ...) qtest_hypercall(global_qtest, code, argc, ## __VA_ARGS__)
> +
> #endif
> -- 
> 1.7.10.4
>
Andreas Färber - Jan. 25, 2013, 2:49 p.m.
Am 25.01.2013 12:27, schrieb Alexander Graf:
> 
> On 23.01.2013, at 11:01, Andreas Färber wrote:
> 
>> diff --git a/include/sysemu/qtest.h b/include/sysemu/qtest.h
>> index 723a4f9..75ab29d 100644
>> --- a/include/sysemu/qtest.h
>> +++ b/include/sysemu/qtest.h
>> @@ -32,6 +32,8 @@ static inline int qtest_available(void)
>> }
>>
>> int qtest_init(void);
>> +bool qtest_hypercall_supported(void);
>> +int qtest_hypercall(uint64_t code, uint64_t *args);
>> #else
>> static inline bool qtest_enabled(void)
>> {
>> diff --git a/qtest.c b/qtest.c
>> index c9b58ce..a5b54e3 100644
>> --- a/qtest.c
>> +++ b/qtest.c
>> @@ -117,6 +117,11 @@ static bool qtest_opened;
>>  * where NUM is an IRQ number.  For the PC, interrupts can be intercepted
>>  * simply with "irq_intercept_in ioapic" (note that IRQ0 comes out with
>>  * NUM=0 even though it is remapped to GSI 2).
>> + *
>> + * Hypercalls:
>> + *
>> + * > hypercall CODE
>> + * < OK
>>  */
>>
>> static int hex2nib(char ch)
>> @@ -344,6 +349,27 @@ static void qtest_process_command(CharDriverState *chr, gchar **words)
>>         qtest_clock_warp(ns);
>>         qtest_send_prefix(chr);
>>         qtest_send(chr, "OK %"PRIi64"\n", (int64_t)qemu_get_clock_ns(vm_clock));
>> +    } else if (strcmp(words[0], "hypercall") == 0 &&
> 
> I don't think we will be able to find a common d[en]ominator for hypercall ABIs across the board. So this one should be called s390_kvm_hypercall, as that's what you are really modeling :).

If that is so, the stated issue remains that this qtest.c is generic
code. So if we add a qtest_s390x_hypercall() and qtest_ppc_hypercall()
we need to add matching stubs for each and some mechanism to suppress
them or error out in all other environments. Where exactly do you see
differences? The number of arguments is kept variable here. The same
could be done for return values. Wider than uint64_t arguments are
pretty unlikely, no?

Andreas

Patch

diff --git a/include/sysemu/qtest.h b/include/sysemu/qtest.h
index 723a4f9..75ab29d 100644
--- a/include/sysemu/qtest.h
+++ b/include/sysemu/qtest.h
@@ -32,6 +32,8 @@  static inline int qtest_available(void)
 }
 
 int qtest_init(void);
+bool qtest_hypercall_supported(void);
+int qtest_hypercall(uint64_t code, uint64_t *args);
 #else
 static inline bool qtest_enabled(void)
 {
diff --git a/qtest.c b/qtest.c
index c9b58ce..a5b54e3 100644
--- a/qtest.c
+++ b/qtest.c
@@ -117,6 +117,11 @@  static bool qtest_opened;
  * where NUM is an IRQ number.  For the PC, interrupts can be intercepted
  * simply with "irq_intercept_in ioapic" (note that IRQ0 comes out with
  * NUM=0 even though it is remapped to GSI 2).
+ *
+ * Hypercalls:
+ *
+ * > hypercall CODE
+ * < OK
  */
 
 static int hex2nib(char ch)
@@ -344,6 +349,27 @@  static void qtest_process_command(CharDriverState *chr, gchar **words)
         qtest_clock_warp(ns);
         qtest_send_prefix(chr);
         qtest_send(chr, "OK %"PRIi64"\n", (int64_t)qemu_get_clock_ns(vm_clock));
+    } else if (strcmp(words[0], "hypercall") == 0 &&
+               qtest_hypercall_supported()) {
+        uint64_t code;
+        uint64_t args[13];
+        int ret, i;
+
+        g_assert(words[1] != NULL);
+        code = strtoull(words[1], NULL, 0);
+
+        memset(args, 0, sizeof(args));
+        for (i = 0; i < 13 && words[2 + i] != NULL; i++) {
+            args[i] = strtoull(words[2 + i], NULL, 0);
+        }
+
+        ret = qtest_hypercall(code, args);
+        qtest_send_prefix(chr);
+        if (ret < 0) {
+            qtest_send(chr, "ERR 0x%x\n", ret);
+            return;
+        }
+        qtest_send(chr, "OK 0x%x\n", ret);
     } else {
         qtest_send_prefix(chr);
         qtest_send(chr, "FAIL Unknown command `%s'\n", words[0]);
diff --git a/stubs/Makefile.objs b/stubs/Makefile.objs
index a260394..50fb2a7 100644
--- a/stubs/Makefile.objs
+++ b/stubs/Makefile.objs
@@ -15,6 +15,7 @@  stub-obj-y += mon-printf.o
 stub-obj-y += mon-print-filename.o
 stub-obj-y += mon-protocol-event.o
 stub-obj-y += mon-set-error.o
+stub-obj-y += qtest.o
 stub-obj-y += reset.o
 stub-obj-y += set-fd-handler.o
 stub-obj-y += slirp.o
diff --git a/stubs/qtest.c b/stubs/qtest.c
new file mode 100644
index 0000000..8860e4f
--- /dev/null
+++ b/stubs/qtest.c
@@ -0,0 +1,12 @@ 
+#include "qemu-common.h"
+#include "sysemu/qtest.h"
+
+bool qtest_hypercall_supported(void)
+{
+    return false;
+}
+
+int qtest_hypercall(uint64_t code, uint64_t *args)
+{
+    return -EINVAL;
+}
diff --git a/tests/libqtest.c b/tests/libqtest.c
index 913fa05..5eb9521 100644
--- a/tests/libqtest.c
+++ b/tests/libqtest.c
@@ -476,3 +476,24 @@  void qtest_memwrite(QTestState *s, uint64_t addr, const void *data, size_t size)
     qtest_sendf(s, "\n");
     qtest_rsp(s, 0);
 }
+
+uint64_t qtest_hypercall(QTestState *s, uint64_t code, int argc, ...)
+{
+    va_list va;
+    gchar **args;
+    uint64_t resp, arg;
+    int i;
+
+    qtest_sendf(s, "hypercall 0x%" PRIx64, code);
+    va_start(va, argc);
+    for (i = 0; i < argc; i++) {
+        arg = va_arg(va, uint64_t);
+        qtest_sendf(s, " 0x%" PRIx64, arg);
+    }
+    va_end(va);
+    qtest_sendf(s, "\n");
+    args = qtest_rsp(s, 2);
+    resp = g_ascii_strtoull(args[1], NULL, 0);
+    g_strfreev(args);
+    return resp;
+}
diff --git a/tests/libqtest.h b/tests/libqtest.h
index c8ade85..3a5a8f9 100644
--- a/tests/libqtest.h
+++ b/tests/libqtest.h
@@ -187,6 +187,15 @@  int64_t qtest_clock_step(QTestState *s, int64_t step);
 int64_t qtest_clock_set(QTestState *s, int64_t val);
 
 /**
+ * qtest_hypercall:
+ * @s: QTestState instance to operate on.
+ * @code: Hypercall code to call.
+ *
+ * Peform a hypercall @code on the guest.
+ */
+uint64_t qtest_hypercall(QTestState *s, uint64_t code, int argc, ...);
+
+/**
  * qtest_get_arch:
  *
  * Returns the architecture for the QEMU executable under test.
@@ -349,4 +358,12 @@  void qtest_add_func(const char *str, void (*fn));
  */
 #define clock_set(val) qtest_clock_set(global_qtest, val)
 
+/**
+ * hypercall:
+ * @code: Hypercall code.
+ *
+ * Invokes a hypercall in the guest.
+ */
+#define hypercall(code, argc, ...) qtest_hypercall(global_qtest, code, argc, ## __VA_ARGS__)
+
 #endif