Activate the RMM during Xen init and keep the small Realm/REC parameter initializers with the rest of the CCA code.
Signed-off-by: Koichiro Den <[email protected]> --- xen/arch/arm/cca/Makefile | 1 + xen/arch/arm/cca/realm.c | 191 +++++++++++++++++++++++++++++++++ xen/arch/arm/include/asm/cca.h | 10 ++ 3 files changed, 202 insertions(+) create mode 100644 xen/arch/arm/cca/realm.c diff --git a/xen/arch/arm/cca/Makefile b/xen/arch/arm/cca/Makefile index 7f20d43323c3..57c3986d5de8 100644 --- a/xen/arch/arm/cca/Makefile +++ b/xen/arch/arm/cca/Makefile @@ -1,3 +1,4 @@ obj-y += granule.o +obj-y += realm.o obj-y += rmi.o obj-y += state.o diff --git a/xen/arch/arm/cca/realm.c b/xen/arch/arm/cca/realm.c new file mode 100644 index 000000000000..14aa7bba595f --- /dev/null +++ b/xen/arch/arm/cca/realm.c @@ -0,0 +1,191 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#include <xen/errno.h> +#include <xen/init.h> +#include <xen/lib.h> +#include <xen/mm.h> +#include <xen/sched.h> + +#include <asm/cca.h> + +#include "rmi.h" +#include "sro.h" + +/* + * Pages donated while activating the RMM are owned by the activated RMM until + * system reset. Keep the host references here to make that lifetime explicit. + */ +static struct page_info *arm_cca_rmm_sro_pages[ARM_CCA_MAX_SRO_DONATION_PAGES]; +static unsigned int arm_cca_nr_rmm_sro_pages; +static struct page_list_head arm_cca_rmm_abandoned_pages = + PAGE_LIST_HEAD_INIT(arm_cca_rmm_abandoned_pages); +static bool arm_cca_rmm_available; +static unsigned long arm_cca_rmm_features0; +static unsigned long arm_cca_rmm_features1; + +static int arm_cca_set_rmm_config(struct arm_cca_rmi_rmm_config *cfg) +{ + memset(cfg, 0, ARM_CCA_RMI_RMM_CONFIG_SIZE); + cfg->rmi_granule_size = ARM_CCA_RMI_GRANULE_SIZE_4KB; + cfg->tracking_region_size = ARM_CCA_RMI_TRACKING_4KB_REGION_1GB; + + return arm_cca_rmi_rmm_config_set(virt_to_maddr(cfg)); +} + +static int arm_cca_activate_rmm(void) +{ + struct arm_cca_rmi_rmm_config *cfg; + struct arm_cca_sro_mem_xfer xfer = { + .pages = arm_cca_rmm_sro_pages, + .nr_pages = &arm_cca_nr_rmm_sro_pages, + .max_pages = ARRAY_SIZE(arm_cca_rmm_sro_pages), + .abandoned_pages = &arm_cca_rmm_abandoned_pages, + }; + struct arm_smccc_res res; + int rc = 0; + + cfg = alloc_xenheap_page(); + if ( cfg == NULL ) + return -ENOMEM; + + rc = arm_cca_set_rmm_config(cfg); + if ( rc == 0 ) + { + rc = arm_cca_rmi_rmm_activate(&res); + rc = arm_cca_sro_complete_mem_transfer(rc, &res, &xfer); + } + + if ( rc != 0 && (arm_cca_nr_rmm_sro_pages != 0 || + !page_list_empty(&arm_cca_rmm_abandoned_pages)) ) + rc = -EIO; + + free_xenheap_page(cfg); + + return rc; +} + +static int arm_cca_validate_rmm_config(void) +{ + struct arm_cca_rmi_rmm_config *cfg; + struct arm_smccc_res res; + int rc; + + cfg = alloc_xenheap_page(); + if ( cfg == NULL ) + return -ENOMEM; + + memset(cfg, 0, ARM_CCA_RMI_RMM_CONFIG_SIZE); + + rc = arm_cca_rmi_rmm_config_get(virt_to_maddr(cfg), &res); + if ( rc != 0 ) + { + printk(XENLOG_ERR + "ARM CCA: RMI_RMM_CONFIG_GET failed status=%#x data=%#lx\n", + arm_cca_rmi_status_code(arm_cca_rmi_result(&res)), + (unsigned long)arm_cca_rmi_result_data( + arm_cca_rmi_result(&res))); + rc = -EOPNOTSUPP; + goto out; + } + + /* + * Xen's current Realm build and teardown paths assume 4KB RMI granules + * and the matching 1GB tracking region. Other active RMM configurations + * are valid RMI, but need explicit Xen support before they can be + * accepted here. + */ + if ( cfg->rmi_granule_size != ARM_CCA_RMI_GRANULE_SIZE_4KB ) + { + printk(XENLOG_ERR + "ARM CCA: requires 4KB RMI granules, but current RMM " + "granule size encoding is %u\n", cfg->rmi_granule_size); + rc = -EOPNOTSUPP; + goto out; + } + + if ( cfg->tracking_region_size != ARM_CCA_RMI_TRACKING_4KB_REGION_1GB ) + { + printk(XENLOG_ERR + "ARM CCA: requires 1GB tracking regions for 4KB RMI " + "granules, but current RMM tracking-region encoding is %u\n", + cfg->tracking_region_size); + rc = -EOPNOTSUPP; + goto out; + } + + rc = 0; + +out: + free_xenheap_page(cfg); + + return rc; +} + +static int __init arm_cca_init_rmi(void) +{ + unsigned long revision_lower; + int rc; + + rc = arm_cca_rmi_version(ARM_CCA_RMI_ABI_VERSION, &revision_lower, NULL); + if ( rc != 0 || revision_lower != ARM_CCA_RMI_ABI_VERSION ) + return 0; + + arm_cca_rmm_features0 = arm_cca_rmi_features(0); + arm_cca_rmm_features1 = arm_cca_rmi_features(1); + + rc = arm_cca_activate_rmm(); + if ( rc != 0 ) + { + printk(XENLOG_ERR "ARM CCA: RMM activate failed: %d\n", rc); + return 0; + } + + rc = arm_cca_validate_rmm_config(); + if ( rc != 0 ) + return 0; + + rc = arm_cca_prepare_host_memory(arm_cca_rmm_features1); + if ( rc != 0 ) + { + printk(XENLOG_ERR "ARM CCA: host memory metadata check failed: %d\n", + rc); + return 0; + } + + arm_cca_rmm_available = true; + printk(XENLOG_INFO "ARM CCA: RMI configured\n"); + + return 0; +} +__initcall(arm_cca_init_rmi); + +int arm_cca_probe(struct domain *d) +{ + if ( !arm_cca_rmm_available ) + return -EOPNOTSUPP; + + d->arch.cca.rmi_features0 = arm_cca_rmm_features0; + d->arch.cca.rmi_features1 = arm_cca_rmm_features1; + + return 0; +} + +void arm_cca_realm_params_init(struct arm_cca_rmi_realm_params *params) +{ + memset(params, 0, sizeof(*params)); +} + +void arm_cca_rec_params_init(struct arm_cca_rmi_rec_params *params, + register_t mpidr, register_t pc, bool runnable) +{ + memset(params, 0, sizeof(*params)); + + params->flags = runnable ? ARM_CCA_RMI_REC_CREATE_RUNNABLE : 0; + params->mpidr = mpidr; + params->pc = pc; +} + +void arm_cca_rec_run_init(struct arm_cca_rmi_rec_run *run) +{ + memset(run, 0, sizeof(*run)); +} diff --git a/xen/arch/arm/include/asm/cca.h b/xen/arch/arm/include/asm/cca.h index c35d51f750a3..80c161078d6c 100644 --- a/xen/arch/arm/include/asm/cca.h +++ b/xen/arch/arm/include/asm/cca.h @@ -24,6 +24,9 @@ struct domain; struct vcpu; +struct arm_cca_rmi_realm_params; +struct arm_cca_rmi_rec_params; +struct arm_cca_rmi_rec_run; struct page_info; struct arm_cca_rtt_record { @@ -84,4 +87,11 @@ 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; +int arm_cca_probe(struct domain *d); + +void arm_cca_realm_params_init(struct arm_cca_rmi_realm_params *params); +void arm_cca_rec_params_init(struct arm_cca_rmi_rec_params *params, + register_t mpidr, register_t pc, bool runnable); +void arm_cca_rec_run_init(struct arm_cca_rmi_rec_run *run); + #endif /* ARM_CCA_H */ -- 2.51.0
