Activate the RMM during Xen init and keep the small Realm/REC parameter
initializers with the rest of the CCA code.

Signed-off-by: Koichiro Den <[email protected]>
---
 xen/arch/arm/cca/Makefile      |   1 +
 xen/arch/arm/cca/realm.c       | 191 +++++++++++++++++++++++++++++++++
 xen/arch/arm/include/asm/cca.h |  10 ++
 3 files changed, 202 insertions(+)
 create mode 100644 xen/arch/arm/cca/realm.c

diff --git a/xen/arch/arm/cca/Makefile b/xen/arch/arm/cca/Makefile
index 7f20d43323c3..57c3986d5de8 100644
--- a/xen/arch/arm/cca/Makefile
+++ b/xen/arch/arm/cca/Makefile
@@ -1,3 +1,4 @@
 obj-y += granule.o
+obj-y += realm.o
 obj-y += rmi.o
 obj-y += state.o
diff --git a/xen/arch/arm/cca/realm.c b/xen/arch/arm/cca/realm.c
new file mode 100644
index 000000000000..14aa7bba595f
--- /dev/null
+++ b/xen/arch/arm/cca/realm.c
@@ -0,0 +1,191 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#include <xen/errno.h>
+#include <xen/init.h>
+#include <xen/lib.h>
+#include <xen/mm.h>
+#include <xen/sched.h>
+
+#include <asm/cca.h>
+
+#include "rmi.h"
+#include "sro.h"
+
+/*
+ * Pages donated while activating the RMM are owned by the activated RMM until
+ * system reset.  Keep the host references here to make that lifetime explicit.
+ */
+static struct page_info *arm_cca_rmm_sro_pages[ARM_CCA_MAX_SRO_DONATION_PAGES];
+static unsigned int arm_cca_nr_rmm_sro_pages;
+static struct page_list_head arm_cca_rmm_abandoned_pages =
+    PAGE_LIST_HEAD_INIT(arm_cca_rmm_abandoned_pages);
+static bool arm_cca_rmm_available;
+static unsigned long arm_cca_rmm_features0;
+static unsigned long arm_cca_rmm_features1;
+
+static int arm_cca_set_rmm_config(struct arm_cca_rmi_rmm_config *cfg)
+{
+    memset(cfg, 0, ARM_CCA_RMI_RMM_CONFIG_SIZE);
+    cfg->rmi_granule_size = ARM_CCA_RMI_GRANULE_SIZE_4KB;
+    cfg->tracking_region_size = ARM_CCA_RMI_TRACKING_4KB_REGION_1GB;
+
+    return arm_cca_rmi_rmm_config_set(virt_to_maddr(cfg));
+}
+
+static int arm_cca_activate_rmm(void)
+{
+    struct arm_cca_rmi_rmm_config *cfg;
+    struct arm_cca_sro_mem_xfer xfer = {
+        .pages = arm_cca_rmm_sro_pages,
+        .nr_pages = &arm_cca_nr_rmm_sro_pages,
+        .max_pages = ARRAY_SIZE(arm_cca_rmm_sro_pages),
+        .abandoned_pages = &arm_cca_rmm_abandoned_pages,
+    };
+    struct arm_smccc_res res;
+    int rc = 0;
+
+    cfg = alloc_xenheap_page();
+    if ( cfg == NULL )
+        return -ENOMEM;
+
+    rc = arm_cca_set_rmm_config(cfg);
+    if ( rc == 0 )
+    {
+        rc = arm_cca_rmi_rmm_activate(&res);
+        rc = arm_cca_sro_complete_mem_transfer(rc, &res, &xfer);
+    }
+
+    if ( rc != 0 && (arm_cca_nr_rmm_sro_pages != 0 ||
+                     !page_list_empty(&arm_cca_rmm_abandoned_pages)) )
+        rc = -EIO;
+
+    free_xenheap_page(cfg);
+
+    return rc;
+}
+
+static int arm_cca_validate_rmm_config(void)
+{
+    struct arm_cca_rmi_rmm_config *cfg;
+    struct arm_smccc_res res;
+    int rc;
+
+    cfg = alloc_xenheap_page();
+    if ( cfg == NULL )
+        return -ENOMEM;
+
+    memset(cfg, 0, ARM_CCA_RMI_RMM_CONFIG_SIZE);
+
+    rc = arm_cca_rmi_rmm_config_get(virt_to_maddr(cfg), &res);
+    if ( rc != 0 )
+    {
+        printk(XENLOG_ERR
+               "ARM CCA: RMI_RMM_CONFIG_GET failed status=%#x data=%#lx\n",
+               arm_cca_rmi_status_code(arm_cca_rmi_result(&res)),
+               (unsigned long)arm_cca_rmi_result_data(
+                   arm_cca_rmi_result(&res)));
+        rc = -EOPNOTSUPP;
+        goto out;
+    }
+
+    /*
+     * Xen's current Realm build and teardown paths assume 4KB RMI granules
+     * and the matching 1GB tracking region.  Other active RMM configurations
+     * are valid RMI, but need explicit Xen support before they can be
+     * accepted here.
+     */
+    if ( cfg->rmi_granule_size != ARM_CCA_RMI_GRANULE_SIZE_4KB )
+    {
+        printk(XENLOG_ERR
+               "ARM CCA: requires 4KB RMI granules, but current RMM "
+               "granule size encoding is %u\n", cfg->rmi_granule_size);
+        rc = -EOPNOTSUPP;
+        goto out;
+    }
+
+    if ( cfg->tracking_region_size != ARM_CCA_RMI_TRACKING_4KB_REGION_1GB )
+    {
+        printk(XENLOG_ERR
+               "ARM CCA: requires 1GB tracking regions for 4KB RMI "
+               "granules, but current RMM tracking-region encoding is %u\n",
+               cfg->tracking_region_size);
+        rc = -EOPNOTSUPP;
+        goto out;
+    }
+
+    rc = 0;
+
+out:
+    free_xenheap_page(cfg);
+
+    return rc;
+}
+
+static int __init arm_cca_init_rmi(void)
+{
+    unsigned long revision_lower;
+    int rc;
+
+    rc = arm_cca_rmi_version(ARM_CCA_RMI_ABI_VERSION, &revision_lower, NULL);
+    if ( rc != 0 || revision_lower != ARM_CCA_RMI_ABI_VERSION )
+        return 0;
+
+    arm_cca_rmm_features0 = arm_cca_rmi_features(0);
+    arm_cca_rmm_features1 = arm_cca_rmi_features(1);
+
+    rc = arm_cca_activate_rmm();
+    if ( rc != 0 )
+    {
+        printk(XENLOG_ERR "ARM CCA: RMM activate failed: %d\n", rc);
+        return 0;
+    }
+
+    rc = arm_cca_validate_rmm_config();
+    if ( rc != 0 )
+        return 0;
+
+    rc = arm_cca_prepare_host_memory(arm_cca_rmm_features1);
+    if ( rc != 0 )
+    {
+        printk(XENLOG_ERR "ARM CCA: host memory metadata check failed: %d\n",
+               rc);
+        return 0;
+    }
+
+    arm_cca_rmm_available = true;
+    printk(XENLOG_INFO "ARM CCA: RMI configured\n");
+
+    return 0;
+}
+__initcall(arm_cca_init_rmi);
+
+int arm_cca_probe(struct domain *d)
+{
+    if ( !arm_cca_rmm_available )
+        return -EOPNOTSUPP;
+
+    d->arch.cca.rmi_features0 = arm_cca_rmm_features0;
+    d->arch.cca.rmi_features1 = arm_cca_rmm_features1;
+
+    return 0;
+}
+
+void arm_cca_realm_params_init(struct arm_cca_rmi_realm_params *params)
+{
+    memset(params, 0, sizeof(*params));
+}
+
+void arm_cca_rec_params_init(struct arm_cca_rmi_rec_params *params,
+                             register_t mpidr, register_t pc, bool runnable)
+{
+    memset(params, 0, sizeof(*params));
+
+    params->flags = runnable ? ARM_CCA_RMI_REC_CREATE_RUNNABLE : 0;
+    params->mpidr = mpidr;
+    params->pc = pc;
+}
+
+void arm_cca_rec_run_init(struct arm_cca_rmi_rec_run *run)
+{
+    memset(run, 0, sizeof(*run));
+}
diff --git a/xen/arch/arm/include/asm/cca.h b/xen/arch/arm/include/asm/cca.h
index c35d51f750a3..80c161078d6c 100644
--- a/xen/arch/arm/include/asm/cca.h
+++ b/xen/arch/arm/include/asm/cca.h
@@ -24,6 +24,9 @@
 
 struct domain;
 struct vcpu;
+struct arm_cca_rmi_realm_params;
+struct arm_cca_rmi_rec_params;
+struct arm_cca_rmi_rec_run;
 struct page_info;
 
 struct arm_cca_rtt_record {
@@ -84,4 +87,11 @@ int arm_cca_delegate_granule(paddr_t granule);
 int arm_cca_undelegate_granule(paddr_t granule);
 int arm_cca_prepare_host_memory(unsigned long features1) __init;
 
+int arm_cca_probe(struct domain *d);
+
+void arm_cca_realm_params_init(struct arm_cca_rmi_realm_params *params);
+void arm_cca_rec_params_init(struct arm_cca_rmi_rec_params *params,
+                             register_t mpidr, register_t pc, bool runnable);
+void arm_cca_rec_run_init(struct arm_cca_rmi_rec_run *run);
+
 #endif /* ARM_CCA_H */
-- 
2.51.0


Reply via email to