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
