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
