Run Realm termination and destruction from the relinquish path. Keep the
metadata until RMM ownership has really ended.

Signed-off-by: Koichiro Den <[email protected]>
---
 xen/arch/arm/cca/state.c       | 119 ++++++++++++++++++++++++++++++++-
 xen/arch/arm/include/asm/cca.h |   3 +
 2 files changed, 121 insertions(+), 1 deletion(-)

diff --git a/xen/arch/arm/cca/state.c b/xen/arch/arm/cca/state.c
index 3646948eb11c..e58e261265f3 100644
--- a/xen/arch/arm/cca/state.c
+++ b/xen/arch/arm/cca/state.c
@@ -3,10 +3,12 @@
 #include <xen/lib.h>
 #include <xen/mm.h>
 #include <xen/sched.h>
+#include <xen/xmalloc.h>
 
 #include <asm/cca.h>
 
 #include "rmi.h"
+#include "sro.h"
 
 static void arm_cca_reset_domain_state(struct domain *d)
 {
@@ -24,6 +26,7 @@ static void arm_cca_reset_domain_state(struct domain *d)
     d->arch.cca.nr_rtts = 0;
     d->arch.cca.data_pages = NULL;
     d->arch.cca.nr_data_pages = 0;
+    d->arch.cca.realm_terminate_done = false;
 
     for ( i = 0; i < ARRAY_SIZE(d->arch.cca.realm_sro_pages); ++i )
         d->arch.cca.realm_sro_pages[i] = NULL;
@@ -48,8 +51,20 @@ void arm_cca_domain_init(struct domain *d)
     arm_cca_reset_domain_state(d);
 }
 
+static void arm_cca_domain_free_metadata(struct domain *d)
+{
+    xfree(d->arch.cca.data_pages);
+    xfree(d->arch.cca.rtts);
+}
+
+/*
+ * RMI teardown is returnable and runs from
+ * arm_cca_domain_relinquish_resources().  The final domain hook only releases
+ * metadata if an earlier setup path left it behind.
+ */
 void arm_cca_domain_destroy(struct domain *d)
 {
+    arm_cca_domain_free_metadata(d);
     arm_cca_reset_domain_state(d);
 }
 
@@ -71,9 +86,111 @@ static int arm_cca_relinquish_abandoned_pages(struct domain 
*d)
     return 0;
 }
 
+static int arm_cca_rmi_realm_destroy_complete(struct domain *d)
+{
+    struct arm_cca_sro_mem_xfer xfer = {
+        .pages = d->arch.cca.realm_sro_pages,
+        .nr_pages = &d->arch.cca.nr_realm_sro_pages,
+        .abandoned_pages = &d->arch.cca.abandoned_pages,
+    };
+    struct arm_smccc_res res;
+    int rc;
+
+    rc = arm_cca_rmi_realm_destroy(d->arch.cca.rd, &res);
+    rc = arm_cca_sro_complete_mem_transfer(rc, &res, &xfer);
+    if ( rc == 0 && d->arch.cca.nr_realm_sro_pages != 0 )
+        rc = -EIO;
+
+    return rc;
+}
+
+static int arm_cca_terminate_realm(struct domain *d)
+{
+    struct arm_smccc_res res;
+    int rc;
+
+    if ( d->arch.cca.rd == INVALID_PADDR || d->arch.cca.realm_terminate_done )
+        return 0;
+
+    /*
+     * DEN0137 2.0-bet1 - D1.2.5 starts Realm destruction by terminating the
+     * Realm.  Remember success because later host-side undelegation may fail
+     * and force a retry.
+     */
+    rc = arm_cca_rmi_realm_terminate(d->arch.cca.rd, &res);
+    if ( rc != 0 )
+        return rc;
+
+    d->arch.cca.realm_terminate_done = true;
+
+    return 0;
+}
+
+static int arm_cca_destroy_realm(struct domain *d)
+{
+    int rc;
+
+    if ( d->arch.cca.rd != INVALID_PADDR )
+    {
+        rc = arm_cca_rmi_realm_destroy_complete(d);
+        if ( rc != 0 )
+            return rc;
+
+        d->arch.cca.rd = INVALID_PADDR;
+        d->arch.cca.realm_active = false;
+    }
+
+    if ( d->arch.cca.rtt_root_page )
+    {
+        rc = arm_cca_undelegate_granule(
+            page_to_maddr(d->arch.cca.rtt_root_page));
+        if ( rc != 0 )
+            return rc;
+
+        free_domheap_page(d->arch.cca.rtt_root_page);
+        d->arch.cca.rtt_root_page = NULL;
+    }
+
+    if ( d->arch.cca.rd_page )
+    {
+        rc = arm_cca_undelegate_granule(page_to_maddr(d->arch.cca.rd_page));
+        if ( rc != 0 )
+            return rc;
+
+        free_domheap_page(d->arch.cca.rd_page);
+        d->arch.cca.rd_page = NULL;
+    }
+
+    return 0;
+}
+
+/*
+ * DEN0137 2.0-bet1 - D1.2.5 Realm destruction flow.
+ *
+ * RMI teardown runs in the returnable relinquish path so Xen can retry
+ * incomplete destruction and avoid resource leaks.  Realm-associated objects
+ * can be destroyed in any order.
+ */
 int arm_cca_domain_relinquish_resources(struct domain *d)
 {
-    return arm_cca_relinquish_abandoned_pages(d);
+    int rc;
+
+    rc = arm_cca_terminate_realm(d);
+    if ( rc != 0 )
+        return rc;
+
+    rc = arm_cca_destroy_realm(d);
+    if ( rc != 0 )
+        return rc;
+
+    rc = arm_cca_relinquish_abandoned_pages(d);
+    if ( rc != 0 )
+        return rc;
+
+    arm_cca_domain_free_metadata(d);
+    arm_cca_reset_domain_state(d);
+
+    return 0;
 }
 
 void arm_cca_vcpu_init(struct vcpu *v)
diff --git a/xen/arch/arm/include/asm/cca.h b/xen/arch/arm/include/asm/cca.h
index 9b53c80b5bba..b135dd176751 100644
--- a/xen/arch/arm/include/asm/cca.h
+++ b/xen/arch/arm/include/asm/cca.h
@@ -66,6 +66,9 @@ struct arm_cca_domain_state {
 
     struct arm_cca_data_page_record *data_pages;
     unsigned long nr_data_pages;
+
+    /* Realm destruction state for domain_relinquish_resources(). */
+    bool realm_terminate_done;
 };
 
 struct arm_cca_vcpu_state {
-- 
2.51.0


Reply via email to