Build the initial RTT tree in restartable chunks, recording each table
so Realm destruction can walk the reverse path later.

Signed-off-by: Koichiro Den <[email protected]>
---
 xen/arch/arm/cca/build.c | 139 +++++++++++++++++++++++++++++++++++++++
 1 file changed, 139 insertions(+)

diff --git a/xen/arch/arm/cca/build.c b/xen/arch/arm/cca/build.c
index 66d9c88da161..10f61b5038ef 100644
--- a/xen/arch/arm/cca/build.c
+++ b/xen/arch/arm/cca/build.c
@@ -525,3 +525,142 @@ out:
 
     return rc;
 }
+
+static int arm_cca_create_rtt_table(struct domain *d, paddr_t ipa,
+                                    unsigned int level,
+                                    uint64_t *rmi_result)
+{
+    struct page_info *pg;
+    struct arm_smccc_res res;
+    int rc;
+    unsigned int idx = d->arch.cca.nr_rtts;
+
+    pg = arm_cca_alloc_host_page();
+    if ( !pg )
+        return -ENOMEM;
+
+    rc = arm_cca_delegate_granule(page_to_maddr(pg));
+    if ( rc != 0 )
+        goto err_free_page;
+
+    rc = arm_cca_rmi_rtt_create(d->arch.cca.rd, page_to_maddr(pg), ipa,
+                                level, &res);
+    rc = arm_cca_build_record_rmi_failure(rmi_result, rc, &res);
+    if ( rc != 0 )
+        goto err_undelegate;
+
+    d->arch.cca.rtts[idx].ipa = ipa;
+    d->arch.cca.rtts[idx].pa = page_to_maddr(pg);
+    d->arch.cca.rtts[idx].level = level;
+    d->arch.cca.nr_rtts++;
+
+    return 0;
+
+err_undelegate:
+    arm_cca_free_or_abandon_build_page(d, pg, true);
+    return rc;
+err_free_page:
+    free_domheap_page(pg);
+    return rc;
+}
+
+static paddr_t arm_cca_rtt_span(unsigned int level)
+{
+    switch ( level )
+    {
+    case 1:
+        return ARM_CCA_L0_TABLE_SPAN;
+    case 2:
+        return ARM_CCA_L1_TABLE_SPAN;
+    case 3:
+        return ARM_CCA_L2_TABLE_SPAN;
+    default:
+        return 0;
+    }
+}
+
+static paddr_t arm_cca_rtt_start(paddr_t base, unsigned int level)
+{
+    return ROUNDDOWN(base, arm_cca_rtt_span(level));
+}
+
+static unsigned int arm_cca_count_rtt_tables(paddr_t base, paddr_t end)
+{
+    unsigned int level, nr_tables = 0;
+
+    for ( level = 1; level <= 3; level++ )
+    {
+        paddr_t span = arm_cca_rtt_span(level);
+
+        nr_tables += (unsigned int)((ROUNDUP(end, span) -
+                                     ROUNDDOWN(base, span)) / span);
+    }
+
+    return nr_tables;
+}
+
+static bool arm_cca_build_should_preempt(unsigned long work,
+                                         unsigned long soft_limit,
+                                         unsigned long hard_limit)
+{
+    if ( work < soft_limit )
+        return false;
+
+    return hypercall_preempt_check() || work >= hard_limit;
+}
+
+/*
+ * DEN0137 2.0-bet1 - D1.2.2 Realm Translation Table creation flow.
+ */
+static int arm_cca_build_rtts(struct domain *d, paddr_t base,
+                              unsigned long nr_pages,
+                              uint64_t *rmi_result)
+{
+    paddr_t end = base + nr_pages * PAGE_SIZE;
+    unsigned long work = 0;
+    int rc;
+
+    if ( !d->arch.cca.rtts )
+    {
+        unsigned int nr_tables = arm_cca_count_rtt_tables(base, end);
+
+        d->arch.cca.rtts = xzalloc_array(struct arm_cca_rtt_record, nr_tables);
+        if ( !d->arch.cca.rtts )
+            return -ENOMEM;
+
+        d->arch.cca.build_rtt_level = 1;
+        d->arch.cca.build_next_ipa = arm_cca_rtt_start(base, 1);
+    }
+
+    while ( d->arch.cca.build_rtt_level <= 3 )
+    {
+        unsigned int level = d->arch.cca.build_rtt_level;
+        paddr_t span = arm_cca_rtt_span(level);
+        paddr_t ipa = d->arch.cca.build_next_ipa;
+
+        if ( ipa >= end )
+        {
+            level++;
+            d->arch.cca.build_rtt_level = level;
+            if ( level <= 3 )
+                d->arch.cca.build_next_ipa = arm_cca_rtt_start(base, level);
+            continue;
+        }
+
+        rc = arm_cca_create_rtt_table(d, ipa, level, rmi_result);
+        if ( rc != 0 )
+            return rc;
+
+        d->arch.cca.build_next_ipa = ipa + span;
+
+        if ( arm_cca_build_should_preempt(++work,
+                                          ARM_CCA_BUILD_PREEMPT_TABLES,
+                                          ARM_CCA_BUILD_FORCE_PREEMPT_TABLES) )
+            return -ERESTART;
+    }
+
+    d->arch.cca.build_next_ipa = INVALID_PADDR;
+    d->arch.cca.build_rtt_level = 0;
+
+    return 0;
+}
-- 
2.51.0


Reply via email to