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
