Wrap the Realm, REC, RTT, SRO and PSCI calls used by Xen. Keep the stateful completion rules close to the raw RMI call boundary and avoid code duplication.
Signed-off-by: Koichiro Den <[email protected]> --- xen/arch/arm/cca/rmi.c | 271 +++++++++++++++++++++++++++++++++++++++++ xen/arch/arm/cca/rmi.h | 88 +++++++++++++ 2 files changed, 359 insertions(+) diff --git a/xen/arch/arm/cca/rmi.c b/xen/arch/arm/cca/rmi.c index d37f1226f834..5661d35e30da 100644 --- a/xen/arch/arm/cca/rmi.c +++ b/xen/arch/arm/cca/rmi.c @@ -56,6 +56,46 @@ static int arm_cca_rmi_initiate_sro(unsigned long fid, cpu_relax(); } } + +static int arm_cca_rmi_complete_no_mem_transfer(struct arm_smccc_res *res) +{ + unsigned long handle; + uint64_t result = arm_cca_rmi_result(res); + + if ( !arm_cca_rmi_status_is(result, ARM_CCA_RMI_INCOMPLETE) ) + return arm_cca_rmi_result_to_errno(result); + + /* + * The initiating command returns the SRO handle in X1. Once + * the operation is continued, X1 is not a stable handle output: + * completion returns the initiating command's output registers. + * + * See DEN0137 2.0-bet1 - B4.3.2 and B4.3.2.1 + */ + handle = res->a1; + + while ( arm_cca_rmi_status_is(result, ARM_CCA_RMI_INCOMPLETE) || + arm_cca_rmi_status_is(result, ARM_CCA_RMI_BUSY) ) + { + if ( arm_cca_rmi_status_is(result, ARM_CCA_RMI_INCOMPLETE) ) + { + /* + * This helper is only for commands specified as stateful but not + * memory-transferring. Callers with donate/reclaim flows handle SROs + * themselves because they must own the backing-page lifetime. + */ + if ( arm_cca_rmi_sro_mem_req(result) != + ARM_CCA_RMI_OP_MEM_REQ_NONE ) + return -EOPNOTSUPP; + } + + arm_cca_rmi_op_continue(handle, ARM_CCA_RMI_CONTINUE_KEEP_GOING, res); + result = arm_cca_rmi_result(res); + } + + return arm_cca_rmi_result_to_errno(result); +} + int arm_cca_rmi_version(unsigned long requested_revision, unsigned long *revision_lower, unsigned long *revision_higher) @@ -168,3 +208,234 @@ int arm_cca_rmi_gpt_l1_create(paddr_t base) return arm_cca_rmi_res_to_errno(&res); } + +int arm_cca_rmi_granule_range_delegate(paddr_t base, paddr_t top, + paddr_t *out_top) +{ + struct arm_smccc_res res; + int rc; + + rc = arm_cca_rmi_initiate_sro(ARM_CCA_RMI_GRANULE_RANGE_DELEGATE_FID, + base, top, 0, 0, 0, &res); + if ( rc != 0 ) + return rc; + + rc = arm_cca_rmi_complete_no_mem_transfer(&res); + if ( rc == 0 && out_top != NULL ) + *out_top = res.a1; + + return rc; +} + +int arm_cca_rmi_granule_range_undelegate(paddr_t base, paddr_t top, + paddr_t *out_top) +{ + struct arm_smccc_res res; + int rc; + + rc = arm_cca_rmi_initiate_sro(ARM_CCA_RMI_GRANULE_RANGE_UNDELEGATE_FID, + base, top, 0, 0, 0, &res); + if ( rc != 0 ) + return rc; + + rc = arm_cca_rmi_complete_no_mem_transfer(&res); + if ( rc == 0 && out_top != NULL ) + *out_top = res.a1; + + return rc; +} + +int arm_cca_rmi_realm_create(paddr_t rd, paddr_t params_ptr, + struct arm_smccc_res *res) +{ + int rc; + + rc = arm_cca_rmi_initiate_sro(ARM_CCA_RMI_REALM_CREATE_FID, + rd, params_ptr, 0, 0, 0, res); + if ( rc != 0 ) + return rc; + + return arm_cca_rmi_res_to_errno(res); +} + +int arm_cca_rmi_realm_activate(paddr_t rd, struct arm_smccc_res *res) +{ + arm_cca_rmi_invoke(ARM_CCA_RMI_REALM_ACTIVATE_FID, rd, 0, 0, 0, 0, res); + + return arm_cca_rmi_res_to_errno(res); +} + +int arm_cca_rmi_realm_terminate(paddr_t rd, struct arm_smccc_res *res) +{ + int rc; + + rc = arm_cca_rmi_initiate_sro(ARM_CCA_RMI_REALM_TERMINATE_FID, + rd, 0, 0, 0, 0, res); + if ( rc != 0 ) + return rc; + + rc = arm_cca_rmi_res_to_errno(res); + + if ( !arm_cca_rmi_status_is(arm_cca_rmi_result(res), + ARM_CCA_RMI_INCOMPLETE) ) + return rc; + + return arm_cca_rmi_complete_no_mem_transfer(res); +} + +int arm_cca_rmi_realm_destroy(paddr_t rd, struct arm_smccc_res *res) +{ + int rc; + + rc = arm_cca_rmi_initiate_sro(ARM_CCA_RMI_REALM_DESTROY_FID, + rd, 0, 0, 0, 0, res); + if ( rc != 0 ) + return rc; + + return arm_cca_rmi_res_to_errno(res); +} + +int arm_cca_rmi_rec_create(paddr_t rd, paddr_t rec, paddr_t params_ptr, + struct arm_smccc_res *res) +{ + int rc; + + rc = arm_cca_rmi_initiate_sro(ARM_CCA_RMI_REC_CREATE_FID, + rd, rec, params_ptr, 0, 0, res); + if ( rc != 0 ) + return rc; + + return arm_cca_rmi_res_to_errno(res); +} + +int arm_cca_rmi_rec_destroy(paddr_t rec, struct arm_smccc_res *res) +{ + int rc; + + rc = arm_cca_rmi_initiate_sro(ARM_CCA_RMI_REC_DESTROY_FID, + rec, 0, 0, 0, 0, res); + if ( rc != 0 ) + return rc; + + return arm_cca_rmi_res_to_errno(res); +} + +int arm_cca_rmi_rec_enter(paddr_t rec, paddr_t run, struct arm_smccc_res *res) +{ + arm_cca_rmi_invoke(ARM_CCA_RMI_REC_ENTER_FID, rec, run, 0, 0, 0, res); + + return arm_cca_rmi_res_to_errno(res); +} + +int arm_cca_rmi_op_continue(unsigned long handle, unsigned long flags, + struct arm_smccc_res *res) +{ + arm_cca_rmi_invoke(ARM_CCA_RMI_OP_CONTINUE_FID, + handle, flags, 0, 0, 0, res); + + return arm_cca_rmi_res_to_errno(res); +} + +int arm_cca_rmi_op_cancel(unsigned long handle, struct arm_smccc_res *res) +{ + arm_cca_rmi_invoke(ARM_CCA_RMI_OP_CANCEL_FID, handle, 0, 0, 0, 0, res); + + return arm_cca_rmi_res_to_errno(res); +} + +int arm_cca_rmi_op_mem_donate(unsigned long handle, paddr_t list, + unsigned long list_count, + struct arm_smccc_res *res) +{ + arm_cca_rmi_invoke(ARM_CCA_RMI_OP_MEM_DONATE_FID, + handle, list, list_count, 0, 0, res); + + return arm_cca_rmi_res_to_errno(res); +} + +int arm_cca_rmi_op_mem_reclaim(unsigned long handle, paddr_t list, + unsigned long list_count, + struct arm_smccc_res *res) +{ + arm_cca_rmi_invoke(ARM_CCA_RMI_OP_MEM_RECLAIM_FID, + handle, list, list_count, 0, 0, res); + + return arm_cca_rmi_res_to_errno(res); +} + +int arm_cca_rmi_rtt_create(paddr_t rd, paddr_t rtt, paddr_t ipa, + unsigned long level, struct arm_smccc_res *res) +{ + int rc; + + rc = arm_cca_rmi_initiate_sro(ARM_CCA_RMI_RTT_CREATE_FID, + rd, rtt, ipa, level, 0, res); + if ( rc != 0 ) + return rc; + + return arm_cca_rmi_complete_no_mem_transfer(res); +} + +int arm_cca_rmi_rtt_destroy(paddr_t rd, paddr_t ipa, unsigned long level, + struct arm_smccc_res *res) +{ + int rc; + + rc = arm_cca_rmi_initiate_sro(ARM_CCA_RMI_RTT_DESTROY_FID, + rd, ipa, level, 0, 0, res); + if ( rc != 0 ) + return rc; + + return arm_cca_rmi_complete_no_mem_transfer(res); +} + +int arm_cca_rmi_rtt_set_ripas(paddr_t rd, paddr_t rec, paddr_t base, + paddr_t top, struct arm_smccc_res *res) +{ + int rc; + + rc = arm_cca_rmi_initiate_sro(ARM_CCA_RMI_RTT_SET_RIPAS_FID, + rd, rec, base, top, 0, res); + if ( rc != 0 ) + return rc; + + return arm_cca_rmi_complete_no_mem_transfer(res); +} + +int arm_cca_rmi_rtt_data_map_init(paddr_t rd, paddr_t data, paddr_t ipa, + paddr_t src, unsigned long flags, + struct arm_smccc_res *res) +{ + int rc; + + rc = arm_cca_rmi_initiate_sro(ARM_CCA_RMI_RTT_DATA_MAP_INIT_FID, + rd, data, ipa, src, flags, res); + if ( rc != 0 ) + return rc; + + return arm_cca_rmi_complete_no_mem_transfer(res); +} + +int arm_cca_rmi_rtt_data_unmap(paddr_t rd, paddr_t base, paddr_t top, + unsigned long flags, unsigned long oaddr, + struct arm_smccc_res *res) +{ + int rc; + + rc = arm_cca_rmi_initiate_sro(ARM_CCA_RMI_RTT_DATA_UNMAP_FID, + rd, base, top, flags, oaddr, res); + if ( rc != 0 ) + return rc; + + return arm_cca_rmi_complete_no_mem_transfer(res); +} + +int arm_cca_rmi_psci_complete(paddr_t calling_rec, paddr_t target_rec, + int64_t status, struct arm_smccc_res *res) +{ + arm_cca_rmi_invoke(ARM_CCA_RMI_PSCI_COMPLETE_FID, + calling_rec, target_rec, (unsigned long)status, + 0, 0, res); + + return arm_cca_rmi_res_to_errno(res); +} diff --git a/xen/arch/arm/cca/rmi.h b/xen/arch/arm/cca/rmi.h index 4cd0bc64ccf5..589c12b24e79 100644 --- a/xen/arch/arm/cca/rmi.h +++ b/xen/arch/arm/cca/rmi.h @@ -110,6 +110,51 @@ static inline int arm_cca_rmi_res_to_errno(const struct arm_smccc_res *res) { return arm_cca_rmi_result_to_errno(arm_cca_rmi_result(res)); } + +static inline unsigned long arm_cca_rmi_sro_mem_req(uint64_t result) +{ + uint64_t incomplete_data = arm_cca_rmi_result_data(result); + + return arm_cca_rmi_field_get( + incomplete_data, ARM_CCA_RMI_RESULT_INCOMPLETE_MEM_SHIFT, + ARM_CCA_RMI_RESULT_INCOMPLETE_MEM_WIDTH); +} + +static inline bool arm_cca_rmi_sro_can_cancel(uint64_t result) +{ + uint64_t incomplete_data = arm_cca_rmi_result_data(result); + + return arm_cca_rmi_field_get( + incomplete_data, ARM_CCA_RMI_RESULT_INCOMPLETE_CAN_CANCEL_SHIFT, + ARM_CCA_RMI_RESULT_INCOMPLETE_CAN_CANCEL_WIDTH) == + ARM_CCA_RMI_OP_CAN_CANCEL; +} + +static inline paddr_t arm_cca_rmi_addr_desc_4k_pa(uint64_t desc) +{ + return arm_cca_rmi_field_get(desc, ARM_CCA_RMI_ADDR_DESC_4K_ADDR_SHIFT, + ARM_CCA_RMI_ADDR_DESC_4K_ADDR_WIDTH) + << PAGE_SHIFT; +} + +static inline unsigned long arm_cca_rmi_addr_desc_4k_size(uint64_t desc) +{ + return arm_cca_rmi_field_get(desc, ARM_CCA_RMI_ADDR_DESC_4K_SZ_SHIFT, + ARM_CCA_RMI_ADDR_DESC_4K_SZ_WIDTH); +} + +static inline unsigned long arm_cca_rmi_addr_desc_4k_count(uint64_t desc) +{ + return arm_cca_rmi_field_get(desc, ARM_CCA_RMI_ADDR_DESC_4K_CNT_SHIFT, + ARM_CCA_RMI_ADDR_DESC_4K_CNT_WIDTH); +} + +static inline unsigned long arm_cca_rmi_addr_desc_4k_state(uint64_t desc) +{ + return arm_cca_rmi_field_get(desc, ARM_CCA_RMI_ADDR_DESC_4K_ST_SHIFT, + ARM_CCA_RMI_ADDR_DESC_4K_ST_WIDTH); +} + int arm_cca_rmi_version(unsigned long requested_revision, unsigned long *revision_lower, unsigned long *revision_higher); @@ -123,4 +168,47 @@ int arm_cca_rmi_granule_tracking_get(paddr_t base, paddr_t top, unsigned long *state, paddr_t *out_top); int arm_cca_rmi_gpt_l1_create(paddr_t base); +int arm_cca_rmi_granule_range_delegate(paddr_t base, paddr_t top, + paddr_t *out_top); +int arm_cca_rmi_granule_range_undelegate(paddr_t base, paddr_t top, + paddr_t *out_top); + +int arm_cca_rmi_realm_create(paddr_t rd, paddr_t params_ptr, + struct arm_smccc_res *res); +int arm_cca_rmi_realm_activate(paddr_t rd, struct arm_smccc_res *res); +int arm_cca_rmi_realm_terminate(paddr_t rd, struct arm_smccc_res *res); +int arm_cca_rmi_realm_destroy(paddr_t rd, struct arm_smccc_res *res); + +int arm_cca_rmi_rec_create(paddr_t rd, paddr_t rec, paddr_t params_ptr, + struct arm_smccc_res *res); +int arm_cca_rmi_rec_destroy(paddr_t rec, struct arm_smccc_res *res); +int arm_cca_rmi_rec_enter(paddr_t rec, paddr_t run, struct arm_smccc_res *res); + +int arm_cca_rmi_op_continue(unsigned long handle, unsigned long flags, + struct arm_smccc_res *res); +int arm_cca_rmi_op_cancel(unsigned long handle, struct arm_smccc_res *res); +int arm_cca_rmi_op_mem_donate(unsigned long handle, paddr_t list, + unsigned long list_count, + struct arm_smccc_res *res); +int arm_cca_rmi_op_mem_reclaim(unsigned long handle, paddr_t list, + unsigned long list_count, + struct arm_smccc_res *res); + +int arm_cca_rmi_rtt_create(paddr_t rd, paddr_t rtt, paddr_t ipa, + unsigned long level, struct arm_smccc_res *res); +int arm_cca_rmi_rtt_destroy(paddr_t rd, paddr_t ipa, unsigned long level, + struct arm_smccc_res *res); +int arm_cca_rmi_rtt_set_ripas(paddr_t rd, paddr_t rec, paddr_t base, + paddr_t top, struct arm_smccc_res *res); + +int arm_cca_rmi_rtt_data_map_init(paddr_t rd, paddr_t data, paddr_t ipa, + paddr_t src, unsigned long flags, + struct arm_smccc_res *res); +int arm_cca_rmi_rtt_data_unmap(paddr_t rd, paddr_t base, paddr_t top, + unsigned long flags, unsigned long oaddr, + struct arm_smccc_res *res); + +int arm_cca_rmi_psci_complete(paddr_t calling_rec, paddr_t target_rec, + int64_t status, struct arm_smccc_res *res); + #endif /* ARM_CCA_RMI_H */ -- 2.51.0
