Add the domctl, libxc wrapper and XSM permission used by libxl to turn a
paused Arm guest into a Realm. RMI failures are reported back as-is.

Signed-off-by: Koichiro Den <[email protected]>
---
 tools/flask/policy/modules/xen.if   |  1 +
 tools/include/xenctrl.h             | 12 ++++++
 tools/libs/ctrl/xc_domain.c         | 37 ++++++++++++++++++
 xen/arch/arm/domctl.c               | 60 +++++++++++++++++++++++++++++
 xen/include/public/domctl.h         | 12 ++++++
 xen/xsm/flask/hooks.c               |  3 ++
 xen/xsm/flask/policy/access_vectors |  2 +
 7 files changed, 127 insertions(+)

diff --git a/tools/flask/policy/modules/xen.if 
b/tools/flask/policy/modules/xen.if
index ef7d8f438c65..5eb2d98341e9 100644
--- a/tools/flask/policy/modules/xen.if
+++ b/tools/flask/policy/modules/xen.if
@@ -98,6 +98,7 @@ define(`create_domain_common', `
                vuart_op
                set_llc_colors
                get_domain_state
+               arm_cca_op
        };
        allow $1 $2:security check_context;
        allow $1 $2:shadow enable;
diff --git a/tools/include/xenctrl.h b/tools/include/xenctrl.h
index d5dbf69c8968..149e15f7c531 100644
--- a/tools/include/xenctrl.h
+++ b/tools/include/xenctrl.h
@@ -808,6 +808,18 @@ int xc_dom_vuart_init(xc_interface *xch,
                       xen_pfn_t gfn,
                       evtchn_port_t *evtchn);
 
+/*
+ * Finalize a paused ARM domain as a Realm backed by RMM. The toolstack is
+ * expected to have already built a normal ARM guest image in the domain RAM.
+ *
+ * Returns 0 on success, or -1 with errno set. If Xen receives an RMI error
+ * result from RMM, libxc logs the raw RMI result and reports EPROTO.
+ */
+int xc_arm_cca_init_realm(xc_interface *xch,
+                          uint32_t domid,
+                          xen_pfn_t base_gfn,
+                          uint64_t nr_pages);
+
 /**
  * This function returns information about the XSAVE state of a particular
  * vcpu of a domain. If extstate->size and extstate->xfeature_mask are 0,
diff --git a/tools/libs/ctrl/xc_domain.c b/tools/libs/ctrl/xc_domain.c
index 01c0669c8863..3cb8da9cc07d 100644
--- a/tools/libs/ctrl/xc_domain.c
+++ b/tools/libs/ctrl/xc_domain.c
@@ -345,6 +345,43 @@ int xc_dom_vuart_init(xc_interface *xch,
     return rc;
 }
 
+int xc_arm_cca_init_realm(xc_interface *xch,
+                          uint32_t domid,
+                          xen_pfn_t base_gfn,
+                          uint64_t nr_pages)
+{
+    struct xen_domctl domctl = {};
+    int rc;
+
+    memset(&domctl, 0, sizeof(domctl));
+
+    domctl.cmd = XEN_DOMCTL_arm_cca_op;
+    domctl.domain = domid;
+    domctl.u.arm_cca_op.cmd = XEN_DOMCTL_ARM_CCA_OP_INIT_REALM;
+    domctl.u.arm_cca_op.flags = 0;
+    domctl.u.arm_cca_op.base_gfn = base_gfn;
+    domctl.u.arm_cca_op.nr_pages = nr_pages;
+
+    rc = do_domctl(xch, &domctl);
+    if ( rc < 0 )
+    {
+        if ( domctl.u.arm_cca_op.rmi_result )
+        {
+            xc_report_error(xch, XC_INTERNAL_ERROR,
+                            "xc_arm_cca_init_realm failed with raw RMI "
+                            "result 0x%llx",
+                            (unsigned long long)
+                            domctl.u.arm_cca_op.rmi_result);
+            errno = EPROTO;
+            return -1;
+        }
+
+        return rc;
+    }
+
+    return rc;
+}
+
 int xc_domain_getinfo_single(xc_interface *xch,
                              uint32_t domid,
                              xc_domaininfo_t *info)
diff --git a/xen/arch/arm/domctl.c b/xen/arch/arm/domctl.c
index ad914c915f81..36461eeda633 100644
--- a/xen/arch/arm/domctl.c
+++ b/xen/arch/arm/domctl.c
@@ -16,6 +16,7 @@
 #include <xen/types.h>
 #include <xsm/xsm.h>
 #include <public/domctl.h>
+#include <public/sched.h>
 
 void arch_get_domain_info(const struct domain *d,
                           struct xen_domctl_getdomaininfo *info)
@@ -49,6 +50,42 @@ static int handle_vuart_init(struct domain *d,
     return rc;
 }
 
+static int handle_arm_cca_init_realm(struct domain *d,
+                                     struct xen_domctl_arm_cca_op *cca_op)
+{
+#ifdef CONFIG_ARM_CCA
+    uint64_t rmi_result = 0;
+    int rc;
+#endif
+
+    if ( cca_op->flags )
+        return -EINVAL;
+
+    cca_op->rmi_result = 0;
+
+#ifdef CONFIG_ARM_CCA
+    rc = arm_cca_domain_finalize(d, _gfn(cca_op->base_gfn),
+                                 cca_op->nr_pages, &rmi_result);
+
+    /*
+     * Once Realm data conversion starts, the original guest RAM image can no
+     * longer be trusted after a failed finalization attempt.
+     */
+    if ( rc == -EIO )
+        domain_shutdown(d, SHUTDOWN_crash);
+
+    if ( rc == -EIO && rmi_result )
+    {
+        cca_op->rmi_result = rmi_result;
+        return rc;
+    }
+
+    return rc;
+#else
+    return -EOPNOTSUPP;
+#endif
+}
+
 long arch_do_domctl(struct xen_domctl *domctl, struct domain *d,
                     XEN_GUEST_HANDLE_PARAM(xen_domctl_t) u_domctl)
 {
@@ -177,6 +214,29 @@ long arch_do_domctl(struct xen_domctl *domctl, struct 
domain *d,
 
         return rc;
     }
+    case XEN_DOMCTL_arm_cca_op:
+    {
+        struct xen_domctl_arm_cca_op *cca_op = &domctl->u.arm_cca_op;
+
+        switch ( cca_op->cmd )
+        {
+        case XEN_DOMCTL_ARM_CCA_OP_INIT_REALM:
+        {
+            long rc = handle_arm_cca_init_realm(d, cca_op);
+
+            if ( rc == -ERESTART )
+                rc = hypercall_create_continuation(__HYPERVISOR_domctl,
+                                                   "h", u_domctl);
+            else if ( rc == -EIO && cca_op->rmi_result &&
+                      copy_to_guest(u_domctl, domctl, 1) )
+                rc = -EFAULT;
+
+            return rc;
+        }
+        default:
+            return -EINVAL;
+        }
+    }
     case XEN_DOMCTL_dt_overlay:
         return dt_overlay_domctl(d, &domctl->u.dt_overlay);
     default:
diff --git a/xen/include/public/domctl.h b/xen/include/public/domctl.h
index 8f6708c0a7cd..2562647d93d3 100644
--- a/xen/include/public/domctl.h
+++ b/xen/include/public/domctl.h
@@ -1201,6 +1201,16 @@ struct xen_domctl_vuart_op {
                                  */
 };
 
+/* XEN_DOMCTL_arm_cca_op */
+struct xen_domctl_arm_cca_op {
+#define XEN_DOMCTL_ARM_CCA_OP_INIT_REALM  0
+        uint32_t cmd;              /* IN - XEN_DOMCTL_ARM_CCA_OP_* */
+        uint32_t flags;            /* IN - reserved, must be zero */
+        uint64_aligned_t base_gfn;   /* IN - first guest RAM gfn to protect */
+        uint64_aligned_t nr_pages;   /* IN - number of 4K pages to protect */
+        uint64_aligned_t rmi_result; /* OUT - raw RMI result on -EIO */
+};
+
 /* XEN_DOMCTL_vmtrace_op: Perform VM tracing operations. */
 struct xen_domctl_vmtrace_op {
     uint32_t cmd;           /* IN */
@@ -1368,6 +1378,7 @@ struct xen_domctl {
 #define XEN_DOMCTL_gsi_permission                88
 #define XEN_DOMCTL_set_llc_colors                89
 #define XEN_DOMCTL_get_domain_state              90 /* stable interface */
+#define XEN_DOMCTL_arm_cca_op                    91
 #define XEN_DOMCTL_gdbsx_guestmemio            1000
 #define XEN_DOMCTL_gdbsx_pausevcpu             1001
 #define XEN_DOMCTL_gdbsx_unpausevcpu           1002
@@ -1429,6 +1440,7 @@ struct xen_domctl {
         struct xen_domctl_monitor_op        monitor_op;
         struct xen_domctl_psr_alloc         psr_alloc;
         struct xen_domctl_vuart_op          vuart_op;
+        struct xen_domctl_arm_cca_op        arm_cca_op;
         struct xen_domctl_vmtrace_op        vmtrace_op;
         struct xen_domctl_paging_mempool    paging_mempool;
 #if defined(__arm__) || defined(__aarch64__)
diff --git a/xen/xsm/flask/hooks.c b/xen/xsm/flask/hooks.c
index 28522dcbd271..f95552992a26 100644
--- a/xen/xsm/flask/hooks.c
+++ b/xen/xsm/flask/hooks.c
@@ -805,6 +805,9 @@ static int cf_check flask_domctl(struct domain *d, unsigned 
int cmd,
     case XEN_DOMCTL_vuart_op:
         return current_has_perm(d, SECCLASS_DOMAIN2, DOMAIN2__VUART_OP);
 
+    case XEN_DOMCTL_arm_cca_op:
+        return current_has_perm(d, SECCLASS_DOMAIN2, DOMAIN2__ARM_CCA_OP);
+
     case XEN_DOMCTL_get_cpu_policy:
         return current_has_perm(d, SECCLASS_DOMAIN2, DOMAIN2__GET_CPU_POLICY);
 
diff --git a/xen/xsm/flask/policy/access_vectors 
b/xen/xsm/flask/policy/access_vectors
index bbb9c117ec4a..dee895bef673 100644
--- a/xen/xsm/flask/policy/access_vectors
+++ b/xen/xsm/flask/policy/access_vectors
@@ -253,6 +253,8 @@ class domain2
     set_llc_colors
 # XEN_DOMCTL_get_domain_state
     get_domain_state
+# XEN_DOMCTL_arm_cca_op
+    arm_cca_op
 }
 
 # Similar to class domain, but primarily contains domctls related to HVM 
domains
-- 
2.51.0


Reply via email to