Add the memory-tracking preflight and the single-granule delegate
helpers. Realm-owned pages have to come from fine, conventional
tracking regions.

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

diff --git a/xen/arch/arm/cca/Makefile b/xen/arch/arm/cca/Makefile
index aaa04e3b914b..7f20d43323c3 100644
--- a/xen/arch/arm/cca/Makefile
+++ b/xen/arch/arm/cca/Makefile
@@ -1,2 +1,3 @@
+obj-y += granule.o
 obj-y += rmi.o
 obj-y += state.o
diff --git a/xen/arch/arm/cca/granule.c b/xen/arch/arm/cca/granule.c
new file mode 100644
index 000000000000..d2be4d240f19
--- /dev/null
+++ b/xen/arch/arm/cca/granule.c
@@ -0,0 +1,150 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#include <xen/bootinfo.h>
+#include <xen/errno.h>
+#include <xen/init.h>
+#include <xen/lib.h>
+
+#include <asm/cca.h>
+
+#include "rmi.h"
+
+static paddr_t __init arm_cca_l0gpt_size(unsigned long features1)
+{
+    unsigned long l0gptsz = arm_cca_rmi_field_get(
+        features1, ARM_CCA_RMI_FEATURE_REGISTER_1_L0GPTSZ_SHIFT,
+        ARM_CCA_RMI_FEATURE_REGISTER_1_L0GPTSZ_WIDTH);
+
+    return 1ULL << (30 + l0gptsz);
+}
+
+static int __init arm_cca_verify_memory_tracking(paddr_t start, paddr_t end)
+{
+    while ( start < end )
+    {
+        unsigned long category, state;
+        paddr_t next;
+        int rc;
+
+        rc = arm_cca_rmi_granule_tracking_get(start, end, &category, &state,
+                                              &next);
+        if ( rc != 0 )
+            return rc;
+
+        if ( category != ARM_CCA_RMI_MEM_CATEGORY_CONVENTIONAL ||
+             state != ARM_CCA_RMI_TRACKING_FINE ||
+             next <= start || next > end )
+        {
+            printk(XENLOG_ERR
+                   "ARM CCA: memory [%#" PRIpaddr ", %#" PRIpaddr
+                   ") is not fine-tracked conventional memory\n",
+                   start, end);
+            return -EOPNOTSUPP;
+        }
+
+        start = next;
+    }
+
+    return 0;
+}
+
+static int __init arm_cca_create_gpts(paddr_t start, paddr_t end,
+                                      paddr_t l0gpt_size)
+{
+    paddr_t base = ROUNDDOWN(start, l0gpt_size);
+    paddr_t stop = ROUNDUP(end, l0gpt_size);
+
+    while ( base < stop )
+    {
+        int rc = arm_cca_rmi_gpt_l1_create(base);
+
+        if ( rc != 0 )
+        {
+            printk(XENLOG_ERR
+                   "ARM CCA: failed to create GPT L1 for %#" PRIpaddr "\n",
+                   base);
+            return rc;
+        }
+
+        base += l0gpt_size;
+    }
+
+    return 0;
+}
+
+int __init arm_cca_prepare_host_memory(unsigned long features1)
+{
+    const struct membanks *mem = bootinfo_get_mem();
+    paddr_t l0gpt_size = arm_cca_l0gpt_size(features1);
+    unsigned int i;
+    int rc;
+
+    for ( i = 0; i < mem->nr_banks; i++ )
+    {
+        paddr_t start = mem->bank[i].start;
+        paddr_t end = start + mem->bank[i].size;
+
+        rc = arm_cca_verify_memory_tracking(start, end);
+        if ( rc != 0 )
+            return rc;
+
+        rc = arm_cca_create_gpts(start, end, l0gpt_size);
+        if ( rc != 0 )
+            return rc;
+    }
+
+    return 0;
+}
+
+static int arm_cca_process_granule_range(paddr_t start, paddr_t end,
+                                         bool delegate)
+{
+    paddr_t cur = start;
+    int rc;
+
+    /*
+     * arm_cca_prepare_host_memory() checks that host DRAM is fine-tracked and
+     * has GPT L1 metadata before any Realm-owned granule can be delegated.
+     */
+    if ( start >= end || !IS_ALIGNED(start, PAGE_SIZE) ||
+         !IS_ALIGNED(end, PAGE_SIZE) )
+        return -EINVAL;
+
+    while ( cur < end )
+    {
+        paddr_t out_top = INVALID_PADDR;
+
+        if ( delegate )
+            rc = arm_cca_rmi_granule_range_delegate(cur, end, &out_top);
+        else
+            rc = arm_cca_rmi_granule_range_undelegate(cur, end, &out_top);
+
+        if ( rc != 0 )
+            return rc;
+
+        if ( out_top <= cur || out_top > end )
+            return -EIO;
+
+        cur = out_top;
+    }
+
+    return 0;
+}
+
+/* DEN0137 2.0-bet1 - D1.1.1 Granule delegation flow. */
+int arm_cca_delegate_granule(paddr_t granule)
+{
+    if ( !IS_ALIGNED(granule, PAGE_SIZE) )
+        return -EINVAL;
+
+    return arm_cca_process_granule_range(granule, granule + PAGE_SIZE, true);
+}
+
+/* DEN0137 2.0-bet1 - D1.1.2 Granule undelegation flow. */
+int arm_cca_undelegate_granule(paddr_t granule)
+{
+    if ( !IS_ALIGNED(granule, PAGE_SIZE) )
+        return -EINVAL;
+
+    return arm_cca_process_granule_range(granule, granule + PAGE_SIZE, false);
+}
diff --git a/xen/arch/arm/include/asm/cca.h b/xen/arch/arm/include/asm/cca.h
index 6bf644fbcee5..c35d51f750a3 100644
--- a/xen/arch/arm/include/asm/cca.h
+++ b/xen/arch/arm/include/asm/cca.h
@@ -2,6 +2,7 @@
 #ifndef ARM_CCA_H
 #define ARM_CCA_H
 
+#include <xen/init.h>
 #include <xen/types.h>
 
 /*
@@ -79,4 +80,8 @@ void arm_cca_vcpu_destroy(struct vcpu *v);
 void *arm_cca_alloc_rec_run(void);
 void arm_cca_free_rec_run(void *run);
 
+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;
+
 #endif /* ARM_CCA_H */
-- 
2.51.0


Reply via email to