diff mbox series

Example patch to send SGIs with a hypercall

Message ID alpine.DEB.2.21.2109201835220.17979@sstabellini-ThinkPad-T480s (mailing list archive)
State New, archived
Headers show
Series Example patch to send SGIs with a hypercall | expand

Commit Message

Stefano Stabellini Sept. 21, 2021, 1:47 a.m. UTC
Hi all,

Next week I'll be giving a talk about VM-to-VM communication mechanisms
at Embedded Linux Conf in Seattle.

One of the techniques I'll discuss, also the simplest, is shared memory
and interrupts. Although there is no binding to share memory between
dom0less VMs yet, it is already possible to do that with a workaround.
But it is not possible to send interrupts between dom0less VMs yet.

The attached patch introduces a trivial hypercall to inject SGI
interrupts into other Dom0less VMs. It is easy to use for baremetal
guests and other kernels without Xen support (no Xen drivers needed).
I'd like to share the patch publicly in advance of the talk, so that I
can reference it during the presentation. The patch is not meant for
upstreaming at this point.

Beware that it comes with no usage restrictions (no rate limiting
and/or no target limits).

Cheers,

Stefano
diff mbox series

Patch

From c169e2c287c16d6cdef6f073d12fa02cbd80086c Mon Sep 17 00:00:00 2001
From: Stefano Stabellini <stefano.stabellini@xilinx.com>
Date: Mon, 20 Sep 2021 18:33:45 -0700
Subject: [PATCH] xen/arm: introduce PHYSDEV_sgi_send

Introduce a simple hypercall to inject an SGI interrupt into a target
domain/vcpu. Please note that the implementation doesn't come with any
rate limiting.

Signed-off-by: Stefano Stabellini <stefano.stabellini@xilinx.com>
---
 xen/arch/arm/physdev.c          | 34 ++++++++++++++++++++++++++++++---
 xen/arch/arm/traps.c            |  2 +-
 xen/include/asm-arm/hypercall.h |  3 ++-
 xen/include/public/physdev.h    | 19 ++++++++++++++++++
 4 files changed, 53 insertions(+), 5 deletions(-)

diff --git a/xen/arch/arm/physdev.c b/xen/arch/arm/physdev.c
index e91355fe22..2ee29939d2 100644
--- a/xen/arch/arm/physdev.c
+++ b/xen/arch/arm/physdev.c
@@ -11,10 +11,38 @@ 
 #include <asm/hypercall.h>
 
 
-int do_physdev_op(int cmd, XEN_GUEST_HANDLE_PARAM(void) arg)
+int do_physdev_op(int cmd, uint8_t sgi, uint16_t domid, uint32_t vcpuid)
 {
-    gdprintk(XENLOG_DEBUG, "PHYSDEVOP cmd=%d: not implemented\n", cmd);
-    return -ENOSYS;
+    int rc = 0;
+    struct domain *d;
+
+    if ( cmd != PHYSDEV_sgi_send )
+    {
+        gdprintk(XENLOG_DEBUG, "PHYSDEVOP cmd=%d: not implemented\n", cmd);
+        return -ENOSYS;
+    }
+
+    if ( sgi >= 16 )
+    {
+        gdprintk(XENLOG_DEBUG, "PHYSDEVOP_sgi_send invalid sgi=%u\n", sgi);
+        return -EINVAL;
+    }
+
+
+    d = rcu_lock_domain_by_any_id(domid);
+    if ( d == NULL )
+        return -ESRCH;
+    if ( vcpuid >= d->max_vcpus )
+    {
+        rc = -EINVAL;
+        goto out;
+    }
+
+    vgic_inject_irq(d, d->vcpu[vcpuid], sgi, true);
+
+out:
+    rcu_unlock_domain(d);
+    return rc;
 }
 
 /*
diff --git a/xen/arch/arm/traps.c b/xen/arch/arm/traps.c
index 219ab3c3fb..374ed490a2 100644
--- a/xen/arch/arm/traps.c
+++ b/xen/arch/arm/traps.c
@@ -1377,7 +1377,7 @@  static arm_hypercall_t arm_hypercall_table[] = {
     HYPERCALL(xsm_op, 1),
     HYPERCALL(event_channel_op, 2),
     HYPERCALL_DEPRECATED(event_channel_op_compat, 1),
-    HYPERCALL(physdev_op, 2),
+    HYPERCALL(physdev_op, 4),
     HYPERCALL_DEPRECATED(physdev_op_compat, 1),
     HYPERCALL(sysctl, 2),
     HYPERCALL(hvm_op, 2),
diff --git a/xen/include/asm-arm/hypercall.h b/xen/include/asm-arm/hypercall.h
index a0c5a31a2f..4299548907 100644
--- a/xen/include/asm-arm/hypercall.h
+++ b/xen/include/asm-arm/hypercall.h
@@ -2,7 +2,8 @@ 
 #define __ASM_ARM_HYPERCALL_H__
 
 #include <public/domctl.h> /* for arch_do_domctl */
-int do_physdev_op(int cmd, XEN_GUEST_HANDLE_PARAM(void) arg);
+
+int do_physdev_op(int cmd, uint8_t sgi, uint16_t domid, uint32_t vcpuid);
 
 long do_arm_vcpu_op(int cmd, unsigned int vcpuid, XEN_GUEST_HANDLE_PARAM(void) arg);
 
diff --git a/xen/include/public/physdev.h b/xen/include/public/physdev.h
index d271766ad0..64458fe7a1 100644
--- a/xen/include/public/physdev.h
+++ b/xen/include/public/physdev.h
@@ -340,6 +340,25 @@  struct physdev_dbgp_op {
 typedef struct physdev_dbgp_op physdev_dbgp_op_t;
 DEFINE_XEN_GUEST_HANDLE(physdev_dbgp_op_t);
 
+/*
+ * ARM only hypercall to send an SGI to another VM
+ *
+ * int physdev_op(int cmd, uint8_t sgi, uint16_t domid, uint32_t vcpuid)
+ *
+ * sgi: SGI number of the interrupt to inject
+ * domid: target domid
+ * vcpuid: target vcpusid
+ *
+ * example:
+ *     mov x0, #30  // PHYSDEV_sgi_send command
+ *     mov x1, #5   // SGI number 5, can chose any in the range 0-15
+ *     mov x2, #1   // destination domain id (e.g. 0 for dom0, 1 for first domU)
+ *     mov x3, #0   // destination vcpu id (not physical cpu), typically 0
+ *     mov x16, #33 // hypercall physdev_op number 33
+ *     hvc 0xEA1    // hypercall command
+ */
+#define PHYSDEV_sgi_send 30
+
 /*
  * Notify that some PIRQ-bound event channels have been unmasked.
  * ** This command is obsolete since interface version 0x00030202 and is **
-- 
2.17.1