:p
atchew
Login
This serie contains various patches to rework how firmware discovery and feature detection is done and allow to have a more fine granular filtering of the calls we do or not to the firmware. There is also a patch introducing the use of the "bit 15" convention from the FF-A specification to distinguish between secure and non-secure identifiers as Xen VM IDs cannot have bit 15 set. Finally we introduce support for indirect messages and for that we transmit the RXTX buffers to the SPMC and we put the message related functions into their own source file. Bertrand Marquis (10): xen/arm: ffa: Rework firmware discovery xen/arm: ffa: Rework feature discovery xen/arm: ffa: fix version negociation xen/arm: ffa: Fine granular call support xen/arm: ffa: Rework partition info get xen/arm: ffa: Use bit 15 convention for SPs xen/arm: ffa: Transmit RXTX buffers to the SPMC xen/arm: ffa: move message function into ffa_msg.c xen/arm: ffa: Remove per VM notif_enabled xen/arm: ffa: Add indirect message support xen/arch/arm/tee/Makefile | 1 + xen/arch/arm/tee/ffa.c | 242 ++++++++++++++------------------ xen/arch/arm/tee/ffa_msg.c | 129 +++++++++++++++++ xen/arch/arm/tee/ffa_notif.c | 17 ++- xen/arch/arm/tee/ffa_partinfo.c | 230 +++++++++++++++++++++--------- xen/arch/arm/tee/ffa_private.h | 66 +++++++-- xen/arch/arm/tee/ffa_rxtx.c | 139 +++++++++++++++--- xen/arch/arm/tee/ffa_shm.c | 39 ++--- 8 files changed, 605 insertions(+), 258 deletions(-) create mode 100644 xen/arch/arm/tee/ffa_msg.c -- 2.39.5 (Apple Git-154)
Rework firmware discovery during probe: - move prints into the probe - rename ffa_version to ffa_fw_version as the variable identifies the version of the firmware and not the one we support - add error prints when allocation fail during probe No functional changes. Signed-off-by: Bertrand Marquis <bertrand.marquis@arm.com> --- xen/arch/arm/tee/ffa.c | 52 +++++++++++++++++++++++++----------------- 1 file changed, 31 insertions(+), 21 deletions(-) diff --git a/xen/arch/arm/tee/ffa.c b/xen/arch/arm/tee/ffa.c index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/arm/tee/ffa.c +++ b/xen/arch/arm/tee/ffa.c @@ -XXX,XX +XXX,XX @@ #include "ffa_private.h" -/* Negotiated FF-A version to use with the SPMC */ -static uint32_t __ro_after_init ffa_version; +/* Negotiated FF-A version to use with the SPMC, 0 if not there or supported */ +static uint32_t __ro_after_init ffa_fw_version; /* @@ -XXX,XX +XXX,XX @@ static bool ffa_get_version(uint32_t *vers) arm_smccc_1_2_smc(&arg, &resp); if ( resp.a0 == FFA_RET_NOT_SUPPORTED ) - { - gprintk(XENLOG_ERR, "ffa: FFA_VERSION returned not supported\n"); return false; - } *vers = resp.a0; @@ -XXX,XX +XXX,XX @@ static int ffa_domain_init(struct domain *d) struct ffa_ctx *ctx; int ret; - if ( !ffa_version ) + if ( !ffa_fw_version ) return -ENODEV; /* * We can't use that last possible domain ID or ffa_get_vm_id() would @@ -XXX,XX +XXX,XX @@ static bool ffa_probe(void) */ BUILD_BUG_ON(PAGE_SIZE != FFA_PAGE_SIZE); + printk(XENLOG_INFO "ARM FF-A Mediator version %u.%u\n", + FFA_MY_VERSION_MAJOR, FFA_MY_VERSION_MINOR); + /* * psci_init_smccc() updates this value with what's reported by EL-3 * or secure world. @@ -XXX,XX +XXX,XX @@ static bool ffa_probe(void) printk(XENLOG_ERR "ffa: unsupported SMCCC version %#x (need at least %#x)\n", smccc_ver, ARM_SMCCC_VERSION_1_2); - return false; + goto err_no_fw; } if ( !ffa_get_version(&vers) ) - return false; + { + gprintk(XENLOG_ERR, "ffa: FFA_VERSION returned not supported\n"); + goto err_no_fw; + } if ( vers < FFA_MIN_SPMC_VERSION || vers > FFA_MY_VERSION ) { printk(XENLOG_ERR "ffa: Incompatible version %#x found\n", vers); - return false; + goto err_no_fw; } - major_vers = (vers >> FFA_VERSION_MAJOR_SHIFT) & FFA_VERSION_MAJOR_MASK; - minor_vers = vers & FFA_VERSION_MINOR_MASK; - printk(XENLOG_INFO "ARM FF-A Mediator version %u.%u\n", - FFA_MY_VERSION_MAJOR, FFA_MY_VERSION_MINOR); - printk(XENLOG_INFO "ARM FF-A Firmware version %u.%u\n", - major_vers, minor_vers); - /* * At the moment domains must support the same features used by Xen. * TODO: Rework the code to allow domain to use a subset of the @@ -XXX,XX +XXX,XX @@ static bool ffa_probe(void) !check_mandatory_feature(FFA_MEM_SHARE_32) || !check_mandatory_feature(FFA_MEM_RECLAIM) || !check_mandatory_feature(FFA_MSG_SEND_DIRECT_REQ_32) ) - return false; + { + printk(XENLOG_ERR "ffa: Mandatory feature not supported by fw\n"); + goto err_no_fw; + } - if ( !ffa_rxtx_init() ) - return false; + major_vers = (vers >> FFA_VERSION_MAJOR_SHIFT) + & FFA_VERSION_MAJOR_MASK; + minor_vers = vers & FFA_VERSION_MINOR_MASK; + printk(XENLOG_INFO "ARM FF-A Firmware version %u.%u\n", + major_vers, minor_vers); + + ffa_fw_version = vers; - ffa_version = vers; + if ( !ffa_rxtx_init() ) + { + printk(XENLOG_ERR "ffa: Error during RXTX buffer init\n"); + goto err_no_fw; + } if ( !ffa_partinfo_init() ) goto err_rxtx_destroy; @@ -XXX,XX +XXX,XX @@ static bool ffa_probe(void) err_rxtx_destroy: ffa_rxtx_destroy(); - ffa_version = 0; +err_no_fw: + ffa_fw_version = 0; + printk(XENLOG_INFO "ARM FF-A No firmware support\n"); return false; } -- 2.39.5 (Apple Git-154)
Store the list of ABI we need in a list and go through the list instead of having a list of conditions inside the code. No functional change. Signed-off-by: Bertrand Marquis <bertrand.marquis@arm.com> --- xen/arch/arm/tee/ffa.c | 61 +++++++++++++++++++++--------------------- 1 file changed, 30 insertions(+), 31 deletions(-) diff --git a/xen/arch/arm/tee/ffa.c b/xen/arch/arm/tee/ffa.c index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/arm/tee/ffa.c +++ b/xen/arch/arm/tee/ffa.c @@ -XXX,XX +XXX,XX @@ /* Negotiated FF-A version to use with the SPMC, 0 if not there or supported */ static uint32_t __ro_after_init ffa_fw_version; +/* List of ABI we use from the firmware */ +static const uint32_t ffa_fw_feat_needed[] = { + FFA_VERSION, + FFA_FEATURES, + FFA_NOTIFICATION_BITMAP_CREATE, + FFA_NOTIFICATION_BITMAP_DESTROY, + FFA_PARTITION_INFO_GET, + FFA_NOTIFICATION_INFO_GET_64, + FFA_NOTIFICATION_GET, + FFA_RX_RELEASE, + FFA_RXTX_MAP_64, + FFA_RXTX_UNMAP, + FFA_MEM_SHARE_32, + FFA_MEM_SHARE_64, + FFA_MEM_RECLAIM, + FFA_MSG_SEND_DIRECT_REQ_32, + FFA_MSG_SEND_DIRECT_REQ_64, +}; /* * Our rx/tx buffers shared with the SPMC. FFA_RXTX_PAGE_COUNT is the @@ -XXX,XX +XXX,XX @@ static bool ffa_get_version(uint32_t *vers) return true; } -static int32_t ffa_features(uint32_t id) +static bool ffa_feature_supported(uint32_t id) { - return ffa_simple_call(FFA_FEATURES, id, 0, 0, 0); -} - -static bool check_mandatory_feature(uint32_t id) -{ - int32_t ret = ffa_features(id); - - if ( ret ) - printk(XENLOG_ERR "ffa: mandatory feature id %#x missing: error %d\n", - id, ret); - - return !ret; + return !ffa_simple_call(FFA_FEATURES, id, 0, 0, 0); } static void handle_version(struct cpu_user_regs *regs) @@ -XXX,XX +XXX,XX @@ static bool ffa_probe(void) goto err_no_fw; } - /* - * At the moment domains must support the same features used by Xen. - * TODO: Rework the code to allow domain to use a subset of the - * features supported. - */ - if ( !check_mandatory_feature(FFA_PARTITION_INFO_GET) || - !check_mandatory_feature(FFA_RX_RELEASE) || - !check_mandatory_feature(FFA_RXTX_MAP_64) || - !check_mandatory_feature(FFA_MEM_SHARE_64) || - !check_mandatory_feature(FFA_RXTX_UNMAP) || - !check_mandatory_feature(FFA_MEM_SHARE_32) || - !check_mandatory_feature(FFA_MEM_RECLAIM) || - !check_mandatory_feature(FFA_MSG_SEND_DIRECT_REQ_32) ) - { - printk(XENLOG_ERR "ffa: Mandatory feature not supported by fw\n"); - goto err_no_fw; - } - major_vers = (vers >> FFA_VERSION_MAJOR_SHIFT) & FFA_VERSION_MAJOR_MASK; minor_vers = vers & FFA_VERSION_MINOR_MASK; @@ -XXX,XX +XXX,XX @@ static bool ffa_probe(void) ffa_fw_version = vers; + for ( int i = 0; i < ARRAY_SIZE(ffa_fw_feat_needed); i++ ) + { + if ( !ffa_feature_supported(ffa_fw_feat_needed[i]) ) + { + printk(XENLOG_INFO "ARM FF-A Firmware does not support 0x%08x\n", + ffa_fw_feat_needed[i]); + goto err_no_fw; + } + } + if ( !ffa_rxtx_init() ) { printk(XENLOG_ERR "ffa: Error during RXTX buffer init\n"); -- 2.39.5 (Apple Git-154)
Fix FFA version negotiation with the firmware to follow the specification guidance more closely. When the firmware returns OK we can have several cases: - the version requested is accepted but the firmware supports a greater one in the same major. - the firmware supports a greater major version. It could still return OK even if the version requested is not accepted. Reject it. - the firmware supports a lower version. It will return OK and give that version. Check if we support it and use it or reject it if we do not. Adapt the code to: - reject any version lower than the one we support or not with the same major version - use the version returned if in our supported range (currently 1.1 only) - use 1.1 if the version returned is greater. Also adapt the handling of version requests from VM: - return an error for a different major - return 1.1 for a version >= 1.1 - return 1.0 if 1.0 was requested Signed-off-by: Bertrand Marquis <bertrand.marquis@arm.com> --- xen/arch/arm/tee/ffa.c | 38 ++++++++++++++++++++++++++++++-------- 1 file changed, 30 insertions(+), 8 deletions(-) diff --git a/xen/arch/arm/tee/ffa.c b/xen/arch/arm/tee/ffa.c index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/arm/tee/ffa.c +++ b/xen/arch/arm/tee/ffa.c @@ -XXX,XX +XXX,XX @@ static void handle_version(struct cpu_user_regs *regs) struct ffa_ctx *ctx = d->arch.tee; uint32_t vers = get_user_reg(regs, 1); - if ( vers < FFA_VERSION_1_1 ) - vers = FFA_VERSION_1_0; - else - vers = FFA_VERSION_1_1; + /** + * As of now we only support 1.0 or 1.1. + * For any 1.x >= 1.1 return OK with 1.1 + * For 1.0 return OK with 1.0 + * For anything else return an error. + */ + if ( (vers >> FFA_VERSION_MAJOR_SHIFT) == FFA_MY_VERSION_MAJOR ) + { + if ( vers < FFA_VERSION_1_1 ) + vers = FFA_VERSION_1_0; + else + vers = FFA_VERSION_1_1; - ctx->guest_vers = vers; - ffa_set_regs(regs, vers, 0, 0, 0, 0, 0, 0, 0); + ctx->guest_vers = vers; + ffa_set_regs(regs, vers, 0, 0, 0, 0, 0, 0, 0); + } + else + ffa_set_regs_error(regs, FFA_RET_NOT_SUPPORTED); } static void handle_msg_send_direct_req(struct cpu_user_regs *regs, uint32_t fid) @@ -XXX,XX +XXX,XX @@ static bool ffa_probe(void) goto err_no_fw; } - if ( vers < FFA_MIN_SPMC_VERSION || vers > FFA_MY_VERSION ) + if ( vers < FFA_MIN_SPMC_VERSION || + (vers >> FFA_VERSION_MAJOR_SHIFT) != FFA_MY_VERSION_MAJOR ) { printk(XENLOG_ERR "ffa: Incompatible version %#x found\n", vers); goto err_no_fw; @@ -XXX,XX +XXX,XX @@ static bool ffa_probe(void) printk(XENLOG_INFO "ARM FF-A Firmware version %u.%u\n", major_vers, minor_vers); - ffa_fw_version = vers; + /** + * If the call succeed and the version returned is higher or equal to + * the one Xen requested, the version requested by Xen will be the one + * used. If the version returned is lower but compatible with Xen, Xen + * will use that version instead. + * A version with a different major is rejected before. + */ + if ( vers > FFA_MY_VERSION ) + ffa_fw_version = FFA_MY_VERSION; + else + ffa_fw_version = vers; for ( int i = 0; i < ARRAY_SIZE(ffa_fw_feat_needed); i++ ) { -- 2.39.5 (Apple Git-154)
Create a bitmap to store which feature is supported or not by the firmware and use it to filter which calls done to the firmware. With this enabled. allow FF-A support to be activated for guest even if the firmware does not support it. As a consequence, if the firmware is not there or not supported, we return an empty list of partitions to VMs requesting it through PARTINFO_GET ABI. Signed-off-by: Bertrand Marquis <bertrand.marquis@arm.com> --- xen/arch/arm/tee/ffa.c | 31 ++++++++++++++++++++----------- xen/arch/arm/tee/ffa_notif.c | 7 +++++++ xen/arch/arm/tee/ffa_partinfo.c | 31 +++++++++++++++++++++++++++++-- xen/arch/arm/tee/ffa_private.h | 28 ++++++++++++++++++++++++++++ xen/arch/arm/tee/ffa_rxtx.c | 13 ++++++------- xen/arch/arm/tee/ffa_shm.c | 12 ++++++++++++ 6 files changed, 102 insertions(+), 20 deletions(-) diff --git a/xen/arch/arm/tee/ffa.c b/xen/arch/arm/tee/ffa.c index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/arm/tee/ffa.c +++ b/xen/arch/arm/tee/ffa.c @@ -XXX,XX +XXX,XX @@ #include "ffa_private.h" /* Negotiated FF-A version to use with the SPMC, 0 if not there or supported */ -static uint32_t __ro_after_init ffa_fw_version; +uint32_t __ro_after_init ffa_fw_version; + +/* Features supported by the SPMC or secure world when present */ +DECLARE_BITMAP(ffa_fw_feat_supported, FEAT_FUNC_BITMAP_SIZE); /* List of ABI we use from the firmware */ static const uint32_t ffa_fw_feat_needed[] = { @@ -XXX,XX +XXX,XX @@ static void handle_msg_send_direct_req(struct cpu_user_regs *regs, uint32_t fid) else mask = GENMASK_ULL(31, 0); + if ( !ffa_fw_supports_fid(fid) ) + { + resp.a0 = FFA_ERROR; + resp.a2 = FFA_RET_NOT_SUPPORTED; + goto out; + } + src_dst = get_user_reg(regs, 1); if ( (src_dst >> 16) != ffa_get_vm_id(d) ) { @@ -XXX,XX +XXX,XX @@ static int ffa_domain_init(struct domain *d) struct ffa_ctx *ctx; int ret; - if ( !ffa_fw_version ) - return -ENODEV; /* * We can't use that last possible domain ID or ffa_get_vm_id() would * cause an overflow. @@ -XXX,XX +XXX,XX @@ static bool ffa_probe(void) printk(XENLOG_INFO "ARM FF-A Mediator version %u.%u\n", FFA_MY_VERSION_MAJOR, FFA_MY_VERSION_MINOR); + INIT_LIST_HEAD(&ffa_teardown_head); + init_timer(&ffa_teardown_timer, ffa_teardown_timer_callback, NULL, 0); + /* * psci_init_smccc() updates this value with what's reported by EL-3 * or secure world. @@ -XXX,XX +XXX,XX @@ static bool ffa_probe(void) for ( int i = 0; i < ARRAY_SIZE(ffa_fw_feat_needed); i++ ) { - if ( !ffa_feature_supported(ffa_fw_feat_needed[i]) ) - { + if ( ffa_feature_supported(ffa_fw_feat_needed[i]) ) + set_bit(FEAT_FUNC_BITNUM(ffa_fw_feat_needed[i]), + ffa_fw_feat_supported); + else printk(XENLOG_INFO "ARM FF-A Firmware does not support 0x%08x\n", - ffa_fw_feat_needed[i]); - goto err_no_fw; - } + ffa_fw_feat_needed[i]); } if ( !ffa_rxtx_init() ) @@ -XXX,XX +XXX,XX @@ static bool ffa_probe(void) goto err_rxtx_destroy; ffa_notif_init(); - INIT_LIST_HEAD(&ffa_teardown_head); - init_timer(&ffa_teardown_timer, ffa_teardown_timer_callback, NULL, 0); return true; @@ -XXX,XX +XXX,XX @@ err_no_fw: ffa_fw_version = 0; printk(XENLOG_INFO "ARM FF-A No firmware support\n"); - return false; + return true; } static const struct tee_mediator_ops ffa_ops = diff --git a/xen/arch/arm/tee/ffa_notif.c b/xen/arch/arm/tee/ffa_notif.c index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/arm/tee/ffa_notif.c +++ b/xen/arch/arm/tee/ffa_notif.c @@ -XXX,XX +XXX,XX @@ void ffa_notif_init(void) unsigned int irq; int ret; + /* Only enable fw notification if all ABIs we need are supported */ + if ( !(ffa_fw_supports_fid(FFA_NOTIFICATION_BITMAP_CREATE) && + ffa_fw_supports_fid(FFA_NOTIFICATION_BITMAP_DESTROY) && + ffa_fw_supports_fid(FFA_NOTIFICATION_GET) && + ffa_fw_supports_fid(FFA_NOTIFICATION_INFO_GET_64)) ) + return; + arm_smccc_1_2_smc(&arg, &resp); if ( resp.a0 != FFA_SUCCESS_32 ) return; diff --git a/xen/arch/arm/tee/ffa_partinfo.c b/xen/arch/arm/tee/ffa_partinfo.c index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/arm/tee/ffa_partinfo.c +++ b/xen/arch/arm/tee/ffa_partinfo.c @@ -XXX,XX +XXX,XX @@ int32_t ffa_handle_partition_info_get(uint32_t w1, uint32_t w2, uint32_t w3, */ if ( w5 == FFA_PARTITION_INFO_GET_COUNT_FLAG && ctx->guest_vers == FFA_VERSION_1_1 ) - return ffa_partition_info_get(w1, w2, w3, w4, w5, count, fpi_size); + { + if ( ffa_fw_supports_fid(FFA_PARTITION_INFO_GET) ) + return ffa_partition_info_get(w1, w2, w3, w4, w5, count, fpi_size); + else + { + *count = 0; + return FFA_RET_OK; + } + } if ( w5 ) return FFA_RET_INVALID_PARAMETERS; @@ -XXX,XX +XXX,XX @@ int32_t ffa_handle_partition_info_get(uint32_t w1, uint32_t w2, uint32_t w3, if ( !spin_trylock(&ctx->rx_lock) ) return FFA_RET_BUSY; + if ( !ffa_fw_supports_fid(FFA_PARTITION_INFO_GET) ) + { + if ( ctx->guest_vers == FFA_VERSION_1_0 ) + *fpi_size = sizeof(struct ffa_partition_info_1_0); + else + *fpi_size = sizeof(struct ffa_partition_info_1_1); + + *count = 0; + ret = FFA_RET_OK; + goto out; + } + if ( !ctx->page_count || !ctx->rx_is_free ) goto out; spin_lock(&ffa_rx_buffer_lock); @@ -XXX,XX +XXX,XX @@ bool ffa_partinfo_init(void) uint32_t count; int e; + if ( !ffa_fw_supports_fid(FFA_PARTITION_INFO_GET) || + !ffa_fw_supports_fid(FFA_MSG_SEND_DIRECT_REQ_32) || + !ffa_rx || !ffa_tx ) + return false; + e = ffa_partition_info_get(0, 0, 0, 0, 0, &count, &fpi_size); if ( e ) { @@ -XXX,XX +XXX,XX @@ bool ffa_partinfo_init(void) out: ffa_rx_release(); - return ret; } @@ -XXX,XX +XXX,XX @@ int ffa_partinfo_domain_init(struct domain *d) unsigned int n; int32_t res; + if ( !ffa_fw_supports_fid(FFA_MSG_SEND_DIRECT_REQ_32) ) + return 0; + ctx->vm_destroy_bitmap = xzalloc_array(unsigned long, count); if ( !ctx->vm_destroy_bitmap ) return -ENOMEM; diff --git a/xen/arch/arm/tee/ffa_private.h b/xen/arch/arm/tee/ffa_private.h index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/arm/tee/ffa_private.h +++ b/xen/arch/arm/tee/ffa_private.h @@ -XXX,XX +XXX,XX @@ #include <xen/spinlock.h> #include <xen/sched.h> #include <xen/time.h> +#include <xen/bitmap.h> /* Error codes */ #define FFA_RET_OK 0 @@ -XXX,XX +XXX,XX @@ #define FFA_NOTIFICATION_INFO_GET_32 0x84000083U #define FFA_NOTIFICATION_INFO_GET_64 0xC4000083U +/** + * Encoding of features supported or not by the fw in a bitmap: + * - Function IDs are going from 0x60 to 0xFF + * - A function can be supported in 32 and/or 64bit + * The bitmap has one bit for each function in 32 and 64 bit. + */ +#define FFA_FUNC_MIN FFA_ERROR +#define FFA_FUNC_MAX FFA_NOTIFICATION_INFO_GET_64 +#define FFA_FUNC_ID(id) ((id) & ARM_SMCCC_FUNC_MASK) +#define FFA_FUNC_CONV(id) (((id) >> ARM_SMCCC_CONV_SHIFT) & BIT(0,U)) + +#define FEAT_FUNC_BITMAP_SIZE (2 * (FFA_FUNC_ID(FFA_FUNC_MAX) - \ + FFA_FUNC_ID(FFA_FUNC_MIN) + 1)) +#define FEAT_FUNC_BITNUM(id) ((FFA_FUNC_ID(id) - \ + FFA_FUNC_ID(FFA_FUNC_MIN)) << 1 | \ + FFA_FUNC_CONV(id)) + struct ffa_ctx_notif { bool enabled; @@ -XXX,XX +XXX,XX @@ extern void *ffa_rx; extern void *ffa_tx; extern spinlock_t ffa_rx_buffer_lock; extern spinlock_t ffa_tx_buffer_lock; +extern uint32_t __ro_after_init ffa_fw_version; +extern DECLARE_BITMAP(ffa_fw_feat_supported, FEAT_FUNC_BITMAP_SIZE); bool ffa_shm_domain_destroy(struct domain *d); void ffa_handle_mem_share(struct cpu_user_regs *regs); @@ -XXX,XX +XXX,XX @@ static inline int32_t ffa_rx_release(void) return ffa_simple_call(FFA_RX_RELEASE, 0, 0, 0, 0); } +static inline bool ffa_fw_supports_fid(uint32_t fid) +{ + if ( ffa_fw_version == 0 ) + return false; + else + return test_bit(FEAT_FUNC_BITNUM(fid), ffa_fw_feat_supported); +} + #endif /*__FFA_PRIVATE_H__*/ diff --git a/xen/arch/arm/tee/ffa_rxtx.c b/xen/arch/arm/tee/ffa_rxtx.c index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/arm/tee/ffa_rxtx.c +++ b/xen/arch/arm/tee/ffa_rxtx.c @@ -XXX,XX +XXX,XX @@ bool ffa_rxtx_init(void) { int e; + /* Firmware not there or not supporting */ + if ( !ffa_fw_supports_fid(FFA_RXTX_MAP_64) ) + return false; + ffa_rx = alloc_xenheap_pages(get_order_from_pages(FFA_RXTX_PAGE_COUNT), 0); if ( !ffa_rx ) return false; ffa_tx = alloc_xenheap_pages(get_order_from_pages(FFA_RXTX_PAGE_COUNT), 0); if ( !ffa_tx ) - goto err; + return false; e = ffa_rxtx_map(__pa(ffa_tx), __pa(ffa_rx), FFA_RXTX_PAGE_COUNT); if ( e ) { printk(XENLOG_ERR "ffa: Failed to map rxtx: error %d\n", e); - goto err; + return false; } return true; - -err: - ffa_rxtx_destroy(); - - return false; } diff --git a/xen/arch/arm/tee/ffa_shm.c b/xen/arch/arm/tee/ffa_shm.c index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/arm/tee/ffa_shm.c +++ b/xen/arch/arm/tee/ffa_shm.c @@ -XXX,XX +XXX,XX @@ static int32_t ffa_mem_share(uint32_t tot_len, uint32_t frag_len, static int32_t ffa_mem_reclaim(uint32_t handle_lo, uint32_t handle_hi, uint32_t flags) { + if ( !ffa_fw_supports_fid(FFA_MEM_RECLAIM) ) + return FFA_RET_NOT_SUPPORTED; + return ffa_simple_call(FFA_MEM_RECLAIM, handle_lo, handle_hi, flags, 0); } @@ -XXX,XX +XXX,XX @@ void ffa_handle_mem_share(struct cpu_user_regs *regs) uint32_t range_count; uint32_t region_offs; + if ( !ffa_fw_supports_fid(FFA_MEM_SHARE_64) ) + { + ret = FFA_RET_NOT_SUPPORTED; + goto out_set_ret; + } + /* * We're only accepting memory transaction descriptors via the rx/tx * buffer. @@ -XXX,XX +XXX,XX @@ int ffa_handle_mem_reclaim(uint64_t handle, uint32_t flags) register_t handle_lo; int ret; + if ( !ffa_fw_supports_fid(FFA_MEM_RECLAIM) ) + return FFA_RET_NOT_SUPPORTED; + spin_lock(&ctx->lock); shm = find_shm_mem(ctx, handle); if ( shm ) -- 2.39.5 (Apple Git-154)
Rework the partition info get implementation to use the correct size of structure depending on the version of the protocol and simplifies the structure copy to use only memcpy and prevent recreating the structure each time. The goal here is to have an implementation that will be easier to maintain in the long term as the specification is only adding fields to structure with versions to simplify support of several protocol versions and as such an SPMC implementation in the future could use this and return a size higher than the one we expect. The patch is fixing the part_info_get function for this and the subscriber discovery on probe. No functional changes expected. Signed-off-by: Bertrand Marquis <bertrand.marquis@arm.com> --- xen/arch/arm/tee/ffa.c | 13 +-- xen/arch/arm/tee/ffa_partinfo.c | 185 ++++++++++++++++++++------------ xen/arch/arm/tee/ffa_private.h | 4 +- 3 files changed, 118 insertions(+), 84 deletions(-) diff --git a/xen/arch/arm/tee/ffa.c b/xen/arch/arm/tee/ffa.c index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/arm/tee/ffa.c +++ b/xen/arch/arm/tee/ffa.c @@ -XXX,XX +XXX,XX @@ static bool ffa_handle_call(struct cpu_user_regs *regs) uint32_t fid = get_user_reg(regs, 0); struct domain *d = current->domain; struct ffa_ctx *ctx = d->arch.tee; - uint32_t fpi_size; - uint32_t count; int e; if ( !ctx ) @@ -XXX,XX +XXX,XX @@ static bool ffa_handle_call(struct cpu_user_regs *regs) e = ffa_handle_rxtx_unmap(); break; case FFA_PARTITION_INFO_GET: - e = ffa_handle_partition_info_get(get_user_reg(regs, 1), - get_user_reg(regs, 2), - get_user_reg(regs, 3), - get_user_reg(regs, 4), - get_user_reg(regs, 5), &count, - &fpi_size); - if ( e ) - ffa_set_regs_error(regs, e); - else - ffa_set_regs_success(regs, count, fpi_size); + ffa_handle_partition_info_get(regs); return true; case FFA_RX_RELEASE: e = ffa_handle_rx_release(); diff --git a/xen/arch/arm/tee/ffa_partinfo.c b/xen/arch/arm/tee/ffa_partinfo.c index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/arm/tee/ffa_partinfo.c +++ b/xen/arch/arm/tee/ffa_partinfo.c @@ -XXX,XX +XXX,XX @@ static uint16_t subscr_vm_created_count __read_mostly; static uint16_t *subscr_vm_destroyed __read_mostly; static uint16_t subscr_vm_destroyed_count __read_mostly; -static int32_t ffa_partition_info_get(uint32_t w1, uint32_t w2, uint32_t w3, - uint32_t w4, uint32_t w5, uint32_t *count, - uint32_t *fpi_size) +static int32_t ffa_partition_info_get(uint32_t *uuid, uint32_t flags, + uint32_t *count, uint32_t *fpi_size) { - const struct arm_smccc_1_2_regs arg = { + struct arm_smccc_1_2_regs arg = { .a0 = FFA_PARTITION_INFO_GET, - .a1 = w1, - .a2 = w2, - .a3 = w3, - .a4 = w4, - .a5 = w5, + .a5 = flags, }; struct arm_smccc_1_2_regs resp; uint32_t ret; + if ( uuid ) + { + arg.a1 = uuid[0]; + arg.a2 = uuid[1]; + arg.a3 = uuid[2]; + arg.a4 = uuid[3]; + } + arm_smccc_1_2_smc(&arg, &resp); ret = ffa_get_ret_code(&resp); @@ -XXX,XX +XXX,XX @@ static int32_t ffa_partition_info_get(uint32_t w1, uint32_t w2, uint32_t w3, return ret; } -int32_t ffa_handle_partition_info_get(uint32_t w1, uint32_t w2, uint32_t w3, - uint32_t w4, uint32_t w5, uint32_t *count, - uint32_t *fpi_size) +void ffa_handle_partition_info_get(struct cpu_user_regs *regs) { - int32_t ret = FFA_RET_DENIED; + int32_t ret; struct domain *d = current->domain; struct ffa_ctx *ctx = d->arch.tee; + uint32_t flags = get_user_reg(regs, 5); + uint32_t uuid[4] = { + get_user_reg(regs, 1), + get_user_reg(regs, 2), + get_user_reg(regs, 3), + get_user_reg(regs, 4), + }; + uint32_t src_size, dst_size; + void *dst_buf; + uint32_t ffa_sp_count = 0; + + /* + * If the guest is v1.0, he does not get back the entry size so we must + * use the v1.0 structure size in the destination buffer. + * Otherwise use the size of the highest version we support, here 1.1. + */ + if ( ctx->guest_vers == FFA_VERSION_1_0 ) + dst_size = sizeof(struct ffa_partition_info_1_0); + else + dst_size = sizeof(struct ffa_partition_info_1_1); /* * FF-A v1.0 has w5 MBZ while v1.1 allows @@ -XXX,XX +XXX,XX @@ int32_t ffa_handle_partition_info_get(uint32_t w1, uint32_t w2, uint32_t w3, * FFA_PARTITION_INFO_GET_COUNT is only using registers and not the * rxtx buffer so do the partition_info_get directly. */ - if ( w5 == FFA_PARTITION_INFO_GET_COUNT_FLAG && + if ( flags == FFA_PARTITION_INFO_GET_COUNT_FLAG && ctx->guest_vers == FFA_VERSION_1_1 ) { if ( ffa_fw_supports_fid(FFA_PARTITION_INFO_GET) ) - return ffa_partition_info_get(w1, w2, w3, w4, w5, count, fpi_size); + ret = ffa_partition_info_get(uuid, flags, &ffa_sp_count, + &src_size); else - { - *count = 0; - return FFA_RET_OK; - } - } - if ( w5 ) - return FFA_RET_INVALID_PARAMETERS; + ret = FFA_RET_OK; - if ( !ffa_rx ) - return FFA_RET_DENIED; + goto out; + } - if ( !spin_trylock(&ctx->rx_lock) ) - return FFA_RET_BUSY; + if ( flags ) + { + ret = FFA_RET_INVALID_PARAMETERS; + goto out; + } if ( !ffa_fw_supports_fid(FFA_PARTITION_INFO_GET) ) { - if ( ctx->guest_vers == FFA_VERSION_1_0 ) - *fpi_size = sizeof(struct ffa_partition_info_1_0); - else - *fpi_size = sizeof(struct ffa_partition_info_1_1); - - *count = 0; + /* Just give an empty partition list to the caller */ ret = FFA_RET_OK; goto out; } - if ( !ctx->page_count || !ctx->rx_is_free ) + if ( !spin_trylock(&ctx->rx_lock) ) + { + ret = FFA_RET_BUSY; goto out; + } + + dst_buf = ctx->rx; + + if ( !ffa_rx ) + { + ret = FFA_RET_DENIED; + goto out_rx_release; + } + + if ( !ctx->page_count || !ctx->rx_is_free ) + { + ret = FFA_RET_DENIED; + goto out_rx_release; + } + spin_lock(&ffa_rx_buffer_lock); - ret = ffa_partition_info_get(w1, w2, w3, w4, w5, count, fpi_size); + + ret = ffa_partition_info_get(uuid, 0, &ffa_sp_count, &src_size); + if ( ret ) goto out_rx_buf_unlock; + /* * ffa_partition_info_get() succeeded so we now own the RX buffer we * share with the SPMC. We must give it back using ffa_rx_release() * once we've copied the content. */ - if ( ctx->guest_vers == FFA_VERSION_1_0 ) + /* we cannot have a size smaller than 1.0 structure */ + if ( src_size < sizeof(struct ffa_partition_info_1_0) ) { - size_t n; - struct ffa_partition_info_1_1 *src = ffa_rx; - struct ffa_partition_info_1_0 *dst = ctx->rx; - - if ( ctx->page_count * FFA_PAGE_SIZE < *count * sizeof(*dst) ) - { - ret = FFA_RET_NO_MEMORY; - goto out_rx_release; - } + ret = FFA_RET_NOT_SUPPORTED; + goto out_rx_hyp_release; + } - for ( n = 0; n < *count; n++ ) - { - dst[n].id = src[n].id; - dst[n].execution_context = src[n].execution_context; - dst[n].partition_properties = src[n].partition_properties; - } + if ( ctx->page_count * FFA_PAGE_SIZE < ffa_sp_count * dst_size ) + { + ret = FFA_RET_NO_MEMORY; + goto out_rx_hyp_release; } - else + + if ( ffa_sp_count > 0 ) { - size_t sz = *count * *fpi_size; + uint32_t n; + void *src_buf = ffa_rx; - if ( ctx->page_count * FFA_PAGE_SIZE < sz ) + /* copy the secure partitions info */ + for ( n = 0; n < ffa_sp_count; n++ ) { - ret = FFA_RET_NO_MEMORY; - goto out_rx_release; + memcpy(dst_buf, src_buf, dst_size); + dst_buf += dst_size; + src_buf += src_size; } - - memcpy(ctx->rx, ffa_rx, sz); } + ctx->rx_is_free = false; -out_rx_release: + +out_rx_hyp_release: ffa_rx_release(); out_rx_buf_unlock: spin_unlock(&ffa_rx_buffer_lock); -out: +out_rx_release: spin_unlock(&ctx->rx_lock); - return ret; +out: + if ( ret ) + ffa_set_regs_error(regs, ret); + else + ffa_set_regs_success(regs, ffa_sp_count, dst_size); } static int32_t ffa_direct_req_send_vm(uint16_t sp_id, uint16_t vm_id, @@ -XXX,XX +XXX,XX @@ static void uninit_subscribers(void) XFREE(subscr_vm_destroyed); } -static bool init_subscribers(struct ffa_partition_info_1_1 *fpi, uint16_t count) +static bool init_subscribers(uint16_t count, uint32_t fpi_size) { uint16_t n; uint16_t c_pos; uint16_t d_pos; + struct ffa_partition_info_1_1 *fpi; + + if ( fpi_size < sizeof(struct ffa_partition_info_1_1) ) + { + printk(XENLOG_ERR "ffa: partition info size invalid: %u\n", fpi_size); + return false; + } subscr_vm_created_count = 0; subscr_vm_destroyed_count = 0; for ( n = 0; n < count; n++ ) { - if ( fpi[n].partition_properties & FFA_PART_PROP_NOTIF_CREATED ) + fpi = ffa_rx + n * fpi_size; + + if ( fpi->partition_properties & FFA_PART_PROP_NOTIF_CREATED ) subscr_vm_created_count++; - if ( fpi[n].partition_properties & FFA_PART_PROP_NOTIF_DESTROYED ) + if ( fpi->partition_properties & FFA_PART_PROP_NOTIF_DESTROYED ) subscr_vm_destroyed_count++; } @@ -XXX,XX +XXX,XX @@ static bool init_subscribers(struct ffa_partition_info_1_1 *fpi, uint16_t count) for ( c_pos = 0, d_pos = 0, n = 0; n < count; n++ ) { - if ( fpi[n].partition_properties & FFA_PART_PROP_NOTIF_CREATED ) - subscr_vm_created[c_pos++] = fpi[n].id; - if ( fpi[n].partition_properties & FFA_PART_PROP_NOTIF_DESTROYED ) - subscr_vm_destroyed[d_pos++] = fpi[n].id; + fpi = ffa_rx + n * fpi_size; + + if ( fpi->partition_properties & FFA_PART_PROP_NOTIF_CREATED ) + subscr_vm_created[c_pos++] = fpi->id; + if ( fpi->partition_properties & FFA_PART_PROP_NOTIF_DESTROYED ) + subscr_vm_destroyed[d_pos++] = fpi->id; } return true; @@ -XXX,XX +XXX,XX @@ bool ffa_partinfo_init(void) !ffa_rx || !ffa_tx ) return false; - e = ffa_partition_info_get(0, 0, 0, 0, 0, &count, &fpi_size); + e = ffa_partition_info_get(NULL, 0, &count, &fpi_size); if ( e ) { printk(XENLOG_ERR "ffa: Failed to get list of SPs: %d\n", e); @@ -XXX,XX +XXX,XX @@ bool ffa_partinfo_init(void) goto out; } - ret = init_subscribers(ffa_rx, count); + ret = init_subscribers(count, fpi_size); out: ffa_rx_release(); diff --git a/xen/arch/arm/tee/ffa_private.h b/xen/arch/arm/tee/ffa_private.h index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/arm/tee/ffa_private.h +++ b/xen/arch/arm/tee/ffa_private.h @@ -XXX,XX +XXX,XX @@ int ffa_handle_mem_reclaim(uint64_t handle, uint32_t flags); bool ffa_partinfo_init(void); int ffa_partinfo_domain_init(struct domain *d); bool ffa_partinfo_domain_destroy(struct domain *d); -int32_t ffa_handle_partition_info_get(uint32_t w1, uint32_t w2, uint32_t w3, - uint32_t w4, uint32_t w5, uint32_t *count, - uint32_t *fpi_size); +void ffa_handle_partition_info_get(struct cpu_user_regs *regs); bool ffa_rxtx_init(void); void ffa_rxtx_destroy(void); -- 2.39.5 (Apple Git-154)
Make use and required to have bit 15 convention respected by secure world (having bit 15 of IDs set for secure endpoints and non-set for non-secure ones). If any secure partition has an ID with bit 15 not set, it will not be possible to contact or detect them. Print an error log during probe for each secure endpoint detected with bit 15 not set. We are switching to this convention because Xen is currently not using VMIDs with bit 15 set so we are sure that no VM will have it set (this is ensured by BUILD_BUG_ON in case this becomes false in the future). It is allowing to easily distinguish between secure and non-secure endpoints, preventing the need to store a list of secure endpoint IDs in Xen. Signed-off-by: Bertrand Marquis <bertrand.marquis@arm.com> --- xen/arch/arm/tee/ffa.c | 22 +++++++++++--- xen/arch/arm/tee/ffa_partinfo.c | 54 +++++++++++++++++++++++++-------- xen/arch/arm/tee/ffa_private.h | 7 +++++ xen/arch/arm/tee/ffa_shm.c | 12 +++++++- 4 files changed, 77 insertions(+), 18 deletions(-) diff --git a/xen/arch/arm/tee/ffa.c b/xen/arch/arm/tee/ffa.c index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/arm/tee/ffa.c +++ b/xen/arch/arm/tee/ffa.c @@ -XXX,XX +XXX,XX @@ static void handle_msg_send_direct_req(struct cpu_user_regs *regs, uint32_t fid) goto out; } + /* we do not support direct messages to VMs */ + if ( !FFA_ID_IS_SECURE(src_dst & GENMASK(15,0)) ) + { + resp.a0 = FFA_ERROR; + resp.a2 = FFA_RET_NOT_SUPPORTED; + goto out; + } + arg.a1 = src_dst; arg.a2 = get_user_reg(regs, 2) & mask; arg.a3 = get_user_reg(regs, 3) & mask; @@ -XXX,XX +XXX,XX @@ static int ffa_domain_init(struct domain *d) struct ffa_ctx *ctx; int ret; - /* - * We can't use that last possible domain ID or ffa_get_vm_id() would - * cause an overflow. - */ - if ( d->domain_id >= UINT16_MAX) + /* + * We are using the domain_id + 1 as the FF-A ID for VMs as FF-A ID 0 is + * reserved for the hypervisor and we only support secure endpoints using + * FF-A IDs with BIT 15 set to 1 so make sure those are not used by Xen. + */ + BUILD_BUG_ON(DOMID_FIRST_RESERVED >= UINT16_MAX); + BUILD_BUG_ON((DOMID_MASK & BIT(15, U)) != 0); + + if ( d->domain_id >= DOMID_FIRST_RESERVED ) return -ERANGE; ctx = xzalloc(struct ffa_ctx); diff --git a/xen/arch/arm/tee/ffa_partinfo.c b/xen/arch/arm/tee/ffa_partinfo.c index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/arm/tee/ffa_partinfo.c +++ b/xen/arch/arm/tee/ffa_partinfo.c @@ -XXX,XX +XXX,XX @@ void ffa_handle_partition_info_get(struct cpu_user_regs *regs) if ( ffa_sp_count > 0 ) { - uint32_t n; + uint32_t n, real_num = ffa_sp_count; void *src_buf = ffa_rx; /* copy the secure partitions info */ - for ( n = 0; n < ffa_sp_count; n++ ) + for ( n = 0; n < real_num; n++ ) { - memcpy(dst_buf, src_buf, dst_size); - dst_buf += dst_size; + struct ffa_partition_info_1_1 *fpi = src_buf; + + /* filter out SP not following bit 15 convention if any */ + if ( FFA_ID_IS_SECURE(fpi->id) ) + { + memcpy(dst_buf, src_buf, dst_size); + dst_buf += dst_size; + } + else + { + printk(XENLOG_INFO "ffa: sp id 0x%04x skipped, bit 15 is 0\n", + fpi->id); + ffa_sp_count--; + } src_buf += src_size; } } @@ -XXX,XX +XXX,XX @@ static bool init_subscribers(uint16_t count, uint32_t fpi_size) { fpi = ffa_rx + n * fpi_size; - if ( fpi->partition_properties & FFA_PART_PROP_NOTIF_CREATED ) - subscr_vm_created_count++; - if ( fpi->partition_properties & FFA_PART_PROP_NOTIF_DESTROYED ) - subscr_vm_destroyed_count++; + /* + * We need to have secure partitions using bit 15 set convention for + * secure partition IDs. + * Inform the user with a log and discard giving created or destroy + * event to those IDs. + */ + if ( !FFA_ID_IS_SECURE(fpi->id) ) + { + printk(XENLOG_ERR "ffa: Firmware is not using bit 15 convention for IDs !!\n" + "ffa: Secure partition with id 0x%04x cannot be used\n", + fpi->id); + } + else + { + if ( fpi->partition_properties & FFA_PART_PROP_NOTIF_CREATED ) + subscr_vm_created_count++; + if ( fpi->partition_properties & FFA_PART_PROP_NOTIF_DESTROYED ) + subscr_vm_destroyed_count++; + } } if ( subscr_vm_created_count ) @@ -XXX,XX +XXX,XX @@ static bool init_subscribers(uint16_t count, uint32_t fpi_size) { fpi = ffa_rx + n * fpi_size; - if ( fpi->partition_properties & FFA_PART_PROP_NOTIF_CREATED ) - subscr_vm_created[c_pos++] = fpi->id; - if ( fpi->partition_properties & FFA_PART_PROP_NOTIF_DESTROYED ) - subscr_vm_destroyed[d_pos++] = fpi->id; + if ( FFA_ID_IS_SECURE(fpi->id) ) + { + if ( fpi->partition_properties & FFA_PART_PROP_NOTIF_CREATED ) + subscr_vm_created[c_pos++] = fpi->id; + if ( fpi->partition_properties & FFA_PART_PROP_NOTIF_DESTROYED ) + subscr_vm_destroyed[d_pos++] = fpi->id; + } } return true; diff --git a/xen/arch/arm/tee/ffa_private.h b/xen/arch/arm/tee/ffa_private.h index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/arm/tee/ffa_private.h +++ b/xen/arch/arm/tee/ffa_private.h @@ -XXX,XX +XXX,XX @@ */ #define FFA_CTX_TEARDOWN_DELAY SECONDS(1) +/* + * We rely on the convention suggested but not mandated by the FF-A + * specification that secure world endpoint identifiers have the bit 15 + * set and normal world have it set to 0. + */ +#define FFA_ID_IS_SECURE(id) ((id) & BIT(15, U)) + /* FF-A-1.1-REL0 section 10.9.2 Memory region handle, page 167 */ #define FFA_HANDLE_HYP_FLAG BIT(63, ULL) #define FFA_HANDLE_INVALID 0xffffffffffffffffULL diff --git a/xen/arch/arm/tee/ffa_shm.c b/xen/arch/arm/tee/ffa_shm.c index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/arm/tee/ffa_shm.c +++ b/xen/arch/arm/tee/ffa_shm.c @@ -XXX,XX +XXX,XX @@ void ffa_handle_mem_share(struct cpu_user_regs *regs) int ret = FFA_RET_DENIED; uint32_t range_count; uint32_t region_offs; + uint16_t dst_id; if ( !ffa_fw_supports_fid(FFA_MEM_SHARE_64) ) { @@ -XXX,XX +XXX,XX @@ void ffa_handle_mem_share(struct cpu_user_regs *regs) goto out_unlock; mem_access = ctx->tx + trans.mem_access_offs; + + dst_id = ACCESS_ONCE(mem_access->access_perm.endpoint_id); + if ( !FFA_ID_IS_SECURE(dst_id) ) + { + /* we do not support sharing with VMs */ + ret = FFA_RET_NOT_SUPPORTED; + goto out_unlock; + } + if ( ACCESS_ONCE(mem_access->access_perm.perm) != FFA_MEM_ACC_RW ) { ret = FFA_RET_NOT_SUPPORTED; @@ -XXX,XX +XXX,XX @@ void ffa_handle_mem_share(struct cpu_user_regs *regs) goto out_unlock; } shm->sender_id = trans.sender_id; - shm->ep_id = ACCESS_ONCE(mem_access->access_perm.endpoint_id); + shm->ep_id = dst_id; /* * Check that the Composite memory region descriptor fits. -- 2.39.5 (Apple Git-154)
When an RXTX buffer is mapped by a VM transmit it to the SPMC when it supports RX_ACQUIRE. As a consequence of that, we must acquire the RX buffer of a VM from the SPMC when we want to use it: - create a generic acquire and release function to get the rx buffer of a VM which gets it from the SPMC when supported - rename the rx_acquire to hyp_rx_acquire to remove confusion - rework the rx_lock to only lock access to rx_is_free and only allow usage of the rx buffer to one who managed to acquire it, thus removing the trylock and returning busy if rx_is_free is false As part of this change move some structure definition to ffa_private from ffa_shm as those are need for the MAP call with the SPMC. Signed-off-by: Bertrand Marquis <bertrand.marquis@arm.com> --- xen/arch/arm/tee/ffa.c | 2 +- xen/arch/arm/tee/ffa_partinfo.c | 28 +++---- xen/arch/arm/tee/ffa_private.h | 22 +++++- xen/arch/arm/tee/ffa_rxtx.c | 126 ++++++++++++++++++++++++++++---- xen/arch/arm/tee/ffa_shm.c | 15 ---- 5 files changed, 142 insertions(+), 51 deletions(-) diff --git a/xen/arch/arm/tee/ffa.c b/xen/arch/arm/tee/ffa.c index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/arm/tee/ffa.c +++ b/xen/arch/arm/tee/ffa.c @@ -XXX,XX +XXX,XX @@ static bool ffa_handle_call(struct cpu_user_regs *regs) ffa_handle_partition_info_get(regs); return true; case FFA_RX_RELEASE: - e = ffa_handle_rx_release(); + e = ffa_rx_release(d); break; case FFA_MSG_SEND_DIRECT_REQ_32: case FFA_MSG_SEND_DIRECT_REQ_64: diff --git a/xen/arch/arm/tee/ffa_partinfo.c b/xen/arch/arm/tee/ffa_partinfo.c index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/arm/tee/ffa_partinfo.c +++ b/xen/arch/arm/tee/ffa_partinfo.c @@ -XXX,XX +XXX,XX @@ void ffa_handle_partition_info_get(struct cpu_user_regs *regs) goto out; } - if ( !spin_trylock(&ctx->rx_lock) ) - { - ret = FFA_RET_BUSY; + ret = ffa_rx_acquire(d); + if ( ret != FFA_RET_OK ) goto out; - } dst_buf = ctx->rx; @@ -XXX,XX +XXX,XX @@ void ffa_handle_partition_info_get(struct cpu_user_regs *regs) goto out_rx_release; } - if ( !ctx->page_count || !ctx->rx_is_free ) - { - ret = FFA_RET_DENIED; - goto out_rx_release; - } - spin_lock(&ffa_rx_buffer_lock); ret = ffa_partition_info_get(uuid, 0, &ffa_sp_count, &src_size); if ( ret ) - goto out_rx_buf_unlock; + goto out_rx_hyp_unlock; /* * ffa_partition_info_get() succeeded so we now own the RX buffer we - * share with the SPMC. We must give it back using ffa_rx_release() + * share with the SPMC. We must give it back using ffa_hyp_rx_release() * once we've copied the content. */ @@ -XXX,XX +XXX,XX @@ void ffa_handle_partition_info_get(struct cpu_user_regs *regs) } } - ctx->rx_is_free = false; - out_rx_hyp_release: - ffa_rx_release(); -out_rx_buf_unlock: + ffa_hyp_rx_release(); +out_rx_hyp_unlock: spin_unlock(&ffa_rx_buffer_lock); out_rx_release: - spin_unlock(&ctx->rx_lock); - + if ( ret != FFA_RET_OK ) + ffa_rx_release(d); out: if ( ret ) ffa_set_regs_error(regs, ret); @@ -XXX,XX +XXX,XX @@ bool ffa_partinfo_init(void) ret = init_subscribers(count, fpi_size); out: - ffa_rx_release(); + ffa_hyp_rx_release(); return ret; } diff --git a/xen/arch/arm/tee/ffa_private.h b/xen/arch/arm/tee/ffa_private.h index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/arm/tee/ffa_private.h +++ b/xen/arch/arm/tee/ffa_private.h @@ -XXX,XX +XXX,XX @@ FFA_FUNC_ID(FFA_FUNC_MIN)) << 1 | \ FFA_FUNC_CONV(id)) +/* Constituent memory region descriptor */ +struct ffa_address_range { + uint64_t address; + uint32_t page_count; + uint32_t reserved; +}; + +/* Composite memory region descriptor */ +struct ffa_mem_region { + uint32_t total_page_count; + uint32_t address_range_count; + uint64_t reserved; + struct ffa_address_range address_range_array[]; +}; + struct ffa_ctx_notif { bool enabled; @@ -XXX,XX +XXX,XX @@ struct ffa_ctx { struct ffa_ctx_notif notif; /* * tx_lock is used to serialize access to tx - * rx_lock is used to serialize access to rx + * rx_lock is used to serialize access to rx_is_free * lock is used for the rest in this struct */ spinlock_t tx_lock; @@ -XXX,XX +XXX,XX @@ void ffa_rxtx_domain_destroy(struct domain *d); uint32_t ffa_handle_rxtx_map(uint32_t fid, register_t tx_addr, register_t rx_addr, uint32_t page_count); uint32_t ffa_handle_rxtx_unmap(void); -int32_t ffa_handle_rx_release(void); +int32_t ffa_rx_acquire(struct domain *d); +int32_t ffa_rx_release(struct domain *d); void ffa_notif_init(void); void ffa_notif_init_interrupt(void); @@ -XXX,XX +XXX,XX @@ static inline int32_t ffa_simple_call(uint32_t fid, register_t a1, return ffa_get_ret_code(&resp); } -static inline int32_t ffa_rx_release(void) +static inline int32_t ffa_hyp_rx_release(void) { return ffa_simple_call(FFA_RX_RELEASE, 0, 0, 0, 0); } diff --git a/xen/arch/arm/tee/ffa_rxtx.c b/xen/arch/arm/tee/ffa_rxtx.c index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/arm/tee/ffa_rxtx.c +++ b/xen/arch/arm/tee/ffa_rxtx.c @@ -XXX,XX +XXX,XX @@ struct ffa_endpoint_rxtx_descriptor_1_1 { uint32_t tx_region_offs; }; +static int32_t ffa_rxtx_map(paddr_t tx_addr, paddr_t rx_addr, + uint32_t page_count) +{ + return ffa_simple_call(FFA_RXTX_MAP_64, tx_addr, rx_addr, page_count, 0); +} + +static int32_t ffa_rxtx_unmap(void) +{ + return ffa_simple_call(FFA_RXTX_UNMAP, 0, 0, 0, 0); +} + uint32_t ffa_handle_rxtx_map(uint32_t fid, register_t tx_addr, register_t rx_addr, uint32_t page_count) { @@ -XXX,XX +XXX,XX @@ uint32_t ffa_handle_rxtx_map(uint32_t fid, register_t tx_addr, void *rx; void *tx; + /* The code is considering that we only get one page for now */ + BUILD_BUG_ON(FFA_MAX_RXTX_PAGE_COUNT != 1); + if ( !smccc_is_conv_64(fid) ) { /* @@ -XXX,XX +XXX,XX @@ uint32_t ffa_handle_rxtx_map(uint32_t fid, register_t tx_addr, if ( !rx ) goto err_unmap_tx; + /* + * Transmit the RX/TX buffer information to the SPM if acquire is supported + * as the spec says that if not there is not need to acquire/release/map + * rxtx buffers from the SPMC + */ + if ( ffa_fw_supports_fid(FFA_RX_ACQUIRE) ) + { + struct ffa_endpoint_rxtx_descriptor_1_1 *rxtx_desc; + struct ffa_mem_region *mem_reg; + + /* All must fit in our TX buffer */ + BUILD_BUG_ON((sizeof(*rxtx_desc) + sizeof(*mem_reg)*2 + + sizeof(struct ffa_address_range)*2) > FFA_PAGE_SIZE); + + spin_lock(&ffa_tx_buffer_lock); + rxtx_desc = ffa_tx; + + /* + * We have only one page for each so we pack everything: + * - rx region descriptor + * - rx region range + * - tx region descriptor + * - tx region range + */ + rxtx_desc->sender_id = ffa_get_vm_id(d); + rxtx_desc->reserved = 0; + rxtx_desc->rx_region_offs = sizeof(*rxtx_desc); + rxtx_desc->tx_region_offs = sizeof(*rxtx_desc) + + offsetof(struct ffa_mem_region, + address_range_array[1]); + + /* rx buffer */ + mem_reg = ffa_tx + sizeof(*rxtx_desc); + mem_reg->total_page_count = 1; + mem_reg->address_range_count = 1; + mem_reg->reserved = 0; + + mem_reg->address_range_array[0].address = page_to_maddr(rx_pg); + mem_reg->address_range_array[0].page_count = 1; + mem_reg->address_range_array[0].reserved = 0; + + /* tx buffer */ + mem_reg = ffa_tx + rxtx_desc->tx_region_offs; + mem_reg->total_page_count = 1; + mem_reg->address_range_count = 1; + mem_reg->reserved = 0; + + mem_reg->address_range_array[0].address = page_to_maddr(tx_pg); + mem_reg->address_range_array[0].page_count = 1; + mem_reg->address_range_array[0].reserved = 0; + + ret = ffa_rxtx_map(0, 0, 1); + + spin_unlock(&ffa_tx_buffer_lock); + + if ( ret != FFA_RET_OK ) + goto err_unmap_tx; + } + ctx->rx = rx; ctx->tx = tx; ctx->rx_pg = rx_pg; @@ -XXX,XX +XXX,XX @@ uint32_t ffa_handle_rxtx_unmap(void) return FFA_RET_OK; } -int32_t ffa_handle_rx_release(void) +int32_t ffa_rx_acquire(struct domain *d) { int32_t ret = FFA_RET_DENIED; - struct domain *d = current->domain; struct ffa_ctx *ctx = d->arch.tee; - if ( !spin_trylock(&ctx->rx_lock) ) - return FFA_RET_BUSY; + spin_lock(&ctx->rx_lock); - if ( !ctx->page_count || ctx->rx_is_free ) + if ( !ctx->page_count ) + { + ret = FFA_RET_DENIED; + goto out; + } + + if ( !ctx->rx_is_free ) + { + ret = FFA_RET_BUSY; goto out; + } + + if ( ffa_fw_supports_fid(FFA_RX_ACQUIRE) ) + { + ret = ffa_simple_call(FFA_RX_ACQUIRE, ffa_get_vm_id(d), 0, 0, 0); + if ( ret != FFA_RET_OK ) + goto out; + } ret = FFA_RET_OK; - ctx->rx_is_free = true; + ctx->rx_is_free = false; out: spin_unlock(&ctx->rx_lock); return ret; } -static int32_t ffa_rxtx_map(paddr_t tx_addr, paddr_t rx_addr, - uint32_t page_count) +int32_t ffa_rx_release(struct domain *d) { - return ffa_simple_call(FFA_RXTX_MAP_64, tx_addr, rx_addr, page_count, 0); -} + int32_t ret = FFA_RET_DENIED; + struct ffa_ctx *ctx = d->arch.tee; -static int32_t ffa_rxtx_unmap(void) -{ - return ffa_simple_call(FFA_RXTX_UNMAP, 0, 0, 0, 0); + spin_lock(&ctx->rx_lock); + + if ( !ctx->page_count || ctx->rx_is_free ) + goto out; + + if ( ffa_fw_supports_fid(FFA_RX_ACQUIRE) ) + { + ret = ffa_simple_call(FFA_RX_RELEASE, ffa_get_vm_id(d), 0, 0, 0); + if ( ret != FFA_RET_OK ) + goto out; + } + ret = FFA_RET_OK; + ctx->rx_is_free = true; +out: + spin_unlock(&ctx->rx_lock); + + return ret; } void ffa_rxtx_domain_destroy(struct domain *d) diff --git a/xen/arch/arm/tee/ffa_shm.c b/xen/arch/arm/tee/ffa_shm.c index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/arm/tee/ffa_shm.c +++ b/xen/arch/arm/tee/ffa_shm.c @@ -XXX,XX +XXX,XX @@ #include "ffa_private.h" -/* Constituent memory region descriptor */ -struct ffa_address_range { - uint64_t address; - uint32_t page_count; - uint32_t reserved; -}; - -/* Composite memory region descriptor */ -struct ffa_mem_region { - uint32_t total_page_count; - uint32_t address_range_count; - uint64_t reserved; - struct ffa_address_range address_range_array[]; -}; - /* Memory access permissions descriptor */ struct ffa_mem_access_perm { uint16_t endpoint_id; -- 2.39.5 (Apple Git-154)
Move the direct message handling function in its own source file and rename it to have a ffa_ prefix. This is a preparation to add support for indirect messages which will go into this newly created source file. Signed-off-by: Bertrand Marquis <bertrand.marquis@arm.com> --- xen/arch/arm/tee/Makefile | 1 + xen/arch/arm/tee/ffa.c | 69 +---------------------------- xen/arch/arm/tee/ffa_msg.c | 80 ++++++++++++++++++++++++++++++++++ xen/arch/arm/tee/ffa_private.h | 2 + 4 files changed, 84 insertions(+), 68 deletions(-) create mode 100644 xen/arch/arm/tee/ffa_msg.c diff --git a/xen/arch/arm/tee/Makefile b/xen/arch/arm/tee/Makefile index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/arm/tee/Makefile +++ b/xen/arch/arm/tee/Makefile @@ -XXX,XX +XXX,XX @@ obj-$(CONFIG_FFA) += ffa_shm.o obj-$(CONFIG_FFA) += ffa_partinfo.o obj-$(CONFIG_FFA) += ffa_rxtx.o obj-$(CONFIG_FFA) += ffa_notif.o +obj-$(CONFIG_FFA) += ffa_msg.o obj-y += tee.o obj-$(CONFIG_OPTEE) += optee.o diff --git a/xen/arch/arm/tee/ffa.c b/xen/arch/arm/tee/ffa.c index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/arm/tee/ffa.c +++ b/xen/arch/arm/tee/ffa.c @@ -XXX,XX +XXX,XX @@ static void handle_version(struct cpu_user_regs *regs) ffa_set_regs_error(regs, FFA_RET_NOT_SUPPORTED); } -static void handle_msg_send_direct_req(struct cpu_user_regs *regs, uint32_t fid) -{ - struct arm_smccc_1_2_regs arg = { .a0 = fid, }; - struct arm_smccc_1_2_regs resp = { }; - struct domain *d = current->domain; - uint32_t src_dst; - uint64_t mask; - - if ( smccc_is_conv_64(fid) ) - mask = GENMASK_ULL(63, 0); - else - mask = GENMASK_ULL(31, 0); - - if ( !ffa_fw_supports_fid(fid) ) - { - resp.a0 = FFA_ERROR; - resp.a2 = FFA_RET_NOT_SUPPORTED; - goto out; - } - - src_dst = get_user_reg(regs, 1); - if ( (src_dst >> 16) != ffa_get_vm_id(d) ) - { - resp.a0 = FFA_ERROR; - resp.a2 = FFA_RET_INVALID_PARAMETERS; - goto out; - } - - /* we do not support direct messages to VMs */ - if ( !FFA_ID_IS_SECURE(src_dst & GENMASK(15,0)) ) - { - resp.a0 = FFA_ERROR; - resp.a2 = FFA_RET_NOT_SUPPORTED; - goto out; - } - - arg.a1 = src_dst; - arg.a2 = get_user_reg(regs, 2) & mask; - arg.a3 = get_user_reg(regs, 3) & mask; - arg.a4 = get_user_reg(regs, 4) & mask; - arg.a5 = get_user_reg(regs, 5) & mask; - arg.a6 = get_user_reg(regs, 6) & mask; - arg.a7 = get_user_reg(regs, 7) & mask; - - arm_smccc_1_2_smc(&arg, &resp); - switch ( resp.a0 ) - { - case FFA_ERROR: - case FFA_SUCCESS_32: - case FFA_SUCCESS_64: - case FFA_MSG_SEND_DIRECT_RESP_32: - case FFA_MSG_SEND_DIRECT_RESP_64: - break; - default: - /* Bad fid, report back to the caller. */ - memset(&resp, 0, sizeof(resp)); - resp.a0 = FFA_ERROR; - resp.a1 = src_dst; - resp.a2 = FFA_RET_ABORTED; - } - -out: - ffa_set_regs(regs, resp.a0, resp.a1 & mask, resp.a2 & mask, resp.a3 & mask, - resp.a4 & mask, resp.a5 & mask, resp.a6 & mask, - resp.a7 & mask); -} - static void handle_features(struct cpu_user_regs *regs) { struct domain *d = current->domain; @@ -XXX,XX +XXX,XX @@ static bool ffa_handle_call(struct cpu_user_regs *regs) break; case FFA_MSG_SEND_DIRECT_REQ_32: case FFA_MSG_SEND_DIRECT_REQ_64: - handle_msg_send_direct_req(regs, fid); + ffa_handle_msg_send_direct_req(regs, fid); return true; case FFA_MEM_SHARE_32: case FFA_MEM_SHARE_64: diff --git a/xen/arch/arm/tee/ffa_msg.c b/xen/arch/arm/tee/ffa_msg.c new file mode 100644 index XXXXXXX..XXXXXXX --- /dev/null +++ b/xen/arch/arm/tee/ffa_msg.c @@ -XXX,XX +XXX,XX @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (C) 2024 Linaro Limited + */ + +#include <xen/const.h> +#include <xen/sizes.h> +#include <xen/types.h> + +#include <asm/smccc.h> +#include <asm/regs.h> + +#include "ffa_private.h" + +void ffa_handle_msg_send_direct_req(struct cpu_user_regs *regs, uint32_t fid) +{ + struct arm_smccc_1_2_regs arg = { .a0 = fid, }; + struct arm_smccc_1_2_regs resp = { }; + struct domain *d = current->domain; + uint32_t src_dst; + uint64_t mask; + + if ( smccc_is_conv_64(fid) ) + mask = GENMASK_ULL(63, 0); + else + mask = GENMASK_ULL(31, 0); + + if ( !ffa_fw_supports_fid(fid) ) + { + resp.a0 = FFA_ERROR; + resp.a2 = FFA_RET_NOT_SUPPORTED; + goto out; + } + + src_dst = get_user_reg(regs, 1); + if ( (src_dst >> 16) != ffa_get_vm_id(d) ) + { + resp.a0 = FFA_ERROR; + resp.a2 = FFA_RET_INVALID_PARAMETERS; + goto out; + } + + /* we do not support direct messages to VMs */ + if ( !FFA_ID_IS_SECURE(src_dst & GENMASK(15,0)) ) + { + resp.a0 = FFA_ERROR; + resp.a2 = FFA_RET_NOT_SUPPORTED; + goto out; + } + + arg.a1 = src_dst; + arg.a2 = get_user_reg(regs, 2) & mask; + arg.a3 = get_user_reg(regs, 3) & mask; + arg.a4 = get_user_reg(regs, 4) & mask; + arg.a5 = get_user_reg(regs, 5) & mask; + arg.a6 = get_user_reg(regs, 6) & mask; + arg.a7 = get_user_reg(regs, 7) & mask; + + arm_smccc_1_2_smc(&arg, &resp); + switch ( resp.a0 ) + { + case FFA_ERROR: + case FFA_SUCCESS_32: + case FFA_SUCCESS_64: + case FFA_MSG_SEND_DIRECT_RESP_32: + case FFA_MSG_SEND_DIRECT_RESP_64: + break; + default: + /* Bad fid, report back to the caller. */ + memset(&resp, 0, sizeof(resp)); + resp.a0 = FFA_ERROR; + resp.a1 = src_dst; + resp.a2 = FFA_RET_ABORTED; + } + +out: + ffa_set_regs(regs, resp.a0, resp.a1 & mask, resp.a2 & mask, resp.a3 & mask, + resp.a4 & mask, resp.a5 & mask, resp.a6 & mask, + resp.a7 & mask); +} diff --git a/xen/arch/arm/tee/ffa_private.h b/xen/arch/arm/tee/ffa_private.h index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/arm/tee/ffa_private.h +++ b/xen/arch/arm/tee/ffa_private.h @@ -XXX,XX +XXX,XX @@ void ffa_handle_notification_info_get(struct cpu_user_regs *regs); void ffa_handle_notification_get(struct cpu_user_regs *regs); int ffa_handle_notification_set(struct cpu_user_regs *regs); +void ffa_handle_msg_send_direct_req(struct cpu_user_regs *regs, uint32_t fid); + static inline uint16_t ffa_get_vm_id(const struct domain *d) { /* +1 since 0 is reserved for the hypervisor in FF-A */ -- 2.39.5 (Apple Git-154)
Remove the per VM flag to store if notifications are enabled or not as the only case where they are not, if notifications are enabled globally, will make the VM creation fail. Also use the opportunity to always give the notifications interrupts IDs to VM. If the firmware does not support notifications, there won't be any generated and setting one will give back a NOT_SUPPORTED. Signed-off-by: Bertrand Marquis <bertrand.marquis@arm.com> --- xen/arch/arm/tee/ffa.c | 17 +++-------------- xen/arch/arm/tee/ffa_notif.c | 10 +--------- xen/arch/arm/tee/ffa_private.h | 2 -- 3 files changed, 4 insertions(+), 25 deletions(-) diff --git a/xen/arch/arm/tee/ffa.c b/xen/arch/arm/tee/ffa.c index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/arm/tee/ffa.c +++ b/xen/arch/arm/tee/ffa.c @@ -XXX,XX +XXX,XX @@ static void handle_version(struct cpu_user_regs *regs) static void handle_features(struct cpu_user_regs *regs) { - struct domain *d = current->domain; - struct ffa_ctx *ctx = d->arch.tee; uint32_t a1 = get_user_reg(regs, 1); unsigned int n; @@ -XXX,XX +XXX,XX @@ static void handle_features(struct cpu_user_regs *regs) ffa_set_regs_success(regs, 0, 0); break; case FFA_FEATURE_NOTIF_PEND_INTR: - if ( ctx->notif.enabled ) - ffa_set_regs_success(regs, GUEST_FFA_NOTIF_PEND_INTR_ID, 0); - else - ffa_set_regs_error(regs, FFA_RET_NOT_SUPPORTED); + ffa_set_regs_success(regs, GUEST_FFA_NOTIF_PEND_INTR_ID, 0); break; case FFA_FEATURE_SCHEDULE_RECV_INTR: - if ( ctx->notif.enabled ) - ffa_set_regs_success(regs, GUEST_FFA_SCHEDULE_RECV_INTR_ID, 0); - else - ffa_set_regs_error(regs, FFA_RET_NOT_SUPPORTED); + ffa_set_regs_success(regs, GUEST_FFA_SCHEDULE_RECV_INTR_ID, 0); break; case FFA_NOTIFICATION_BIND: @@ -XXX,XX +XXX,XX @@ static void handle_features(struct cpu_user_regs *regs) case FFA_NOTIFICATION_SET: case FFA_NOTIFICATION_INFO_GET_32: case FFA_NOTIFICATION_INFO_GET_64: - if ( ctx->notif.enabled ) - ffa_set_regs_success(regs, 0, 0); - else - ffa_set_regs_error(regs, FFA_RET_NOT_SUPPORTED); + ffa_set_regs_success(regs, 0, 0); break; default: ffa_set_regs_error(regs, FFA_RET_NOT_SUPPORTED); diff --git a/xen/arch/arm/tee/ffa_notif.c b/xen/arch/arm/tee/ffa_notif.c index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/arm/tee/ffa_notif.c +++ b/xen/arch/arm/tee/ffa_notif.c @@ -XXX,XX +XXX,XX @@ void ffa_notif_init(void) int ffa_notif_domain_init(struct domain *d) { - struct ffa_ctx *ctx = d->arch.tee; int32_t res; if ( !notif_enabled ) @@ -XXX,XX +XXX,XX @@ int ffa_notif_domain_init(struct domain *d) if ( res ) return -ENOMEM; - ctx->notif.enabled = true; - return 0; } void ffa_notif_domain_destroy(struct domain *d) { - struct ffa_ctx *ctx = d->arch.tee; - - if ( ctx->notif.enabled ) - { + if ( notif_enabled ) ffa_notification_bitmap_destroy(ffa_get_vm_id(d)); - ctx->notif.enabled = false; - } } diff --git a/xen/arch/arm/tee/ffa_private.h b/xen/arch/arm/tee/ffa_private.h index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/arm/tee/ffa_private.h +++ b/xen/arch/arm/tee/ffa_private.h @@ -XXX,XX +XXX,XX @@ struct ffa_mem_region { }; struct ffa_ctx_notif { - bool enabled; - /* * True if domain is reported by FFA_NOTIFICATION_INFO_GET to have * pending global notifications. -- 2.39.5 (Apple Git-154)
Add support for FFA_MSG_SEND2 to send indirect messages from a VM to a secure partition. Signed-off-by: Bertrand Marquis <bertrand.marquis@arm.com> --- xen/arch/arm/tee/ffa.c | 5 ++++ xen/arch/arm/tee/ffa_msg.c | 49 ++++++++++++++++++++++++++++++++++ xen/arch/arm/tee/ffa_private.h | 1 + 3 files changed, 55 insertions(+) diff --git a/xen/arch/arm/tee/ffa.c b/xen/arch/arm/tee/ffa.c index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/arm/tee/ffa.c +++ b/xen/arch/arm/tee/ffa.c @@ -XXX,XX +XXX,XX @@ static const uint32_t ffa_fw_feat_needed[] = { FFA_MEM_RECLAIM, FFA_MSG_SEND_DIRECT_REQ_32, FFA_MSG_SEND_DIRECT_REQ_64, + FFA_MSG_SEND2, }; /* @@ -XXX,XX +XXX,XX @@ static void handle_features(struct cpu_user_regs *regs) case FFA_PARTITION_INFO_GET: case FFA_MSG_SEND_DIRECT_REQ_32: case FFA_MSG_SEND_DIRECT_REQ_64: + case FFA_MSG_SEND2: ffa_set_regs_success(regs, 0, 0); break; case FFA_MEM_SHARE_64: @@ -XXX,XX +XXX,XX @@ static bool ffa_handle_call(struct cpu_user_regs *regs) case FFA_MSG_SEND_DIRECT_REQ_64: ffa_handle_msg_send_direct_req(regs, fid); return true; + case FFA_MSG_SEND2: + e = ffa_handle_msg_send2(regs); + break; case FFA_MEM_SHARE_32: case FFA_MEM_SHARE_64: ffa_handle_mem_share(regs); diff --git a/xen/arch/arm/tee/ffa_msg.c b/xen/arch/arm/tee/ffa_msg.c index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/arm/tee/ffa_msg.c +++ b/xen/arch/arm/tee/ffa_msg.c @@ -XXX,XX +XXX,XX @@ #include "ffa_private.h" +/* Encoding of partition message in RX/TX buffer */ +struct ffa_part_msg_rxtx { + uint32_t flags; + uint32_t reserved; + uint32_t msg_offset; + uint32_t send_recv_id; + uint32_t msg_size; +}; + void ffa_handle_msg_send_direct_req(struct cpu_user_regs *regs, uint32_t fid) { struct arm_smccc_1_2_regs arg = { .a0 = fid, }; @@ -XXX,XX +XXX,XX @@ out: resp.a4 & mask, resp.a5 & mask, resp.a6 & mask, resp.a7 & mask); } + +int32_t ffa_handle_msg_send2(struct cpu_user_regs *regs) +{ + struct domain *src_d = current->domain; + struct ffa_ctx *src_ctx = src_d->arch.tee; + const struct ffa_part_msg_rxtx *src_msg; + uint16_t dst_id, src_id; + int32_t ret; + + if ( !ffa_fw_supports_fid(FFA_MSG_SEND2) ) + return FFA_RET_NOT_SUPPORTED; + + if ( !spin_trylock(&src_ctx->tx_lock) ) + return FFA_RET_BUSY; + + src_msg = src_ctx->tx; + src_id = src_msg->send_recv_id >> 16; + dst_id = src_msg->send_recv_id & GENMASK(15,0); + + if ( src_id != ffa_get_vm_id(src_d) || !FFA_ID_IS_SECURE(dst_id) ) + { + ret = FFA_RET_INVALID_PARAMETERS; + goto out_unlock_tx; + } + + /* check source message fits in buffer */ + if ( src_ctx->page_count * FFA_PAGE_SIZE < + src_msg->msg_offset + src_msg->msg_size || + src_msg->msg_offset < sizeof(struct ffa_part_msg_rxtx) ) + { + ret = FFA_RET_INVALID_PARAMETERS; + goto out_unlock_tx; + } + + ret = ffa_simple_call(FFA_MSG_SEND2, ((uint32_t)src_id) << 16, 0, 0, 0); + +out_unlock_tx: + spin_unlock(&src_ctx->tx_lock); + return ret; +} diff --git a/xen/arch/arm/tee/ffa_private.h b/xen/arch/arm/tee/ffa_private.h index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/arm/tee/ffa_private.h +++ b/xen/arch/arm/tee/ffa_private.h @@ -XXX,XX +XXX,XX @@ void ffa_handle_notification_get(struct cpu_user_regs *regs); int ffa_handle_notification_set(struct cpu_user_regs *regs); void ffa_handle_msg_send_direct_req(struct cpu_user_regs *regs, uint32_t fid); +int32_t ffa_handle_msg_send2(struct cpu_user_regs *regs); static inline uint16_t ffa_get_vm_id(const struct domain *d) { -- 2.39.5 (Apple Git-154)
This serie contains various patches to rework how firmware discovery and feature detection is done and allow to have a more fine granular filtering of the calls we do or not to the firmware. There is also a patch introducing the use of the "bit 15" convention from the FF-A specification to distinguish between secure and non-secure identifiers as Xen VM IDs cannot have bit 15 set. Finally we introduce support for indirect messages and for that we transmit the RXTX buffers to the SPMC and we put the message related functions into their own source file. Changes in v3: - add some comments in code - add some R-b from Jens - handle comments from Jens (details in each patch) - rebase on top of latest staging Changes in v2: - do not activate FF-A if firmware does not support it - various clean up and small fixes explained in each patch - rebase on top of latest staging Bertrand Marquis (10): xen/arm: ffa: Rework firmware discovery xen/arm: ffa: Rework feature discovery xen/arm: ffa: Fix version negotiation xen/arm: ffa: Fine granular call support xen/arm: ffa: Rework partition info get xen/arm: ffa: Use bit 15 convention for SPs xen/arm: ffa: Transmit RXTX buffers to the SPMC xen/arm: ffa: move message function into ffa_msg.c xen/arm: ffa: Remove per VM notif_enabled xen/arm: ffa: Add indirect message support xen/arch/arm/tee/Makefile | 1 + xen/arch/arm/tee/ffa.c | 251 +++++++++++++++----------------- xen/arch/arm/tee/ffa_msg.c | 130 +++++++++++++++++ xen/arch/arm/tee/ffa_notif.c | 21 +-- xen/arch/arm/tee/ffa_partinfo.c | 234 ++++++++++++++++++++--------- xen/arch/arm/tee/ffa_private.h | 79 ++++++++-- xen/arch/arm/tee/ffa_rxtx.c | 169 +++++++++++++++++---- xen/arch/arm/tee/ffa_shm.c | 39 +++-- 8 files changed, 654 insertions(+), 270 deletions(-) create mode 100644 xen/arch/arm/tee/ffa_msg.c -- 2.47.0
Rework firmware discovery during probe: - move prints into the probe - rename ffa_version to ffa_fw_version as the variable identifies the version of the firmware and not the one we support - add error prints when allocation fail during probe No functional changes. Signed-off-by: Bertrand Marquis <bertrand.marquis@arm.com> --- Changes in v3: - Revert spurious change assigning major_vers - Remove error print in ffa_rxtx_init as we have already a print in the main init function Changes in v2: - Fix error message when we fail to retrieve ffa_version - Move back printing the firmware version before checking supported features - Use Warning instead of Info to inform user that FF-A is not supported in firmware. --- xen/arch/arm/tee/ffa.c | 41 ++++++++++++++++++++++--------------- xen/arch/arm/tee/ffa_rxtx.c | 4 +--- 2 files changed, 26 insertions(+), 19 deletions(-) diff --git a/xen/arch/arm/tee/ffa.c b/xen/arch/arm/tee/ffa.c index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/arm/tee/ffa.c +++ b/xen/arch/arm/tee/ffa.c @@ -XXX,XX +XXX,XX @@ #include "ffa_private.h" -/* Negotiated FF-A version to use with the SPMC */ -static uint32_t __ro_after_init ffa_version; +/* Negotiated FF-A version to use with the SPMC, 0 if not there or supported */ +static uint32_t __ro_after_init ffa_fw_version; /* @@ -XXX,XX +XXX,XX @@ static bool ffa_get_version(uint32_t *vers) arm_smccc_1_2_smc(&arg, &resp); if ( resp.a0 == FFA_RET_NOT_SUPPORTED ) - { - gprintk(XENLOG_ERR, "ffa: FFA_VERSION returned not supported\n"); return false; - } *vers = resp.a0; @@ -XXX,XX +XXX,XX @@ static int ffa_domain_init(struct domain *d) struct ffa_ctx *ctx; int ret; - if ( !ffa_version ) + if ( !ffa_fw_version ) return -ENODEV; /* * We can't use that last possible domain ID or ffa_get_vm_id() would @@ -XXX,XX +XXX,XX @@ static bool ffa_probe(void) */ BUILD_BUG_ON(PAGE_SIZE != FFA_PAGE_SIZE); + printk(XENLOG_INFO "ARM FF-A Mediator version %u.%u\n", + FFA_MY_VERSION_MAJOR, FFA_MY_VERSION_MINOR); + /* * psci_init_smccc() updates this value with what's reported by EL-3 * or secure world. @@ -XXX,XX +XXX,XX @@ static bool ffa_probe(void) printk(XENLOG_ERR "ffa: unsupported SMCCC version %#x (need at least %#x)\n", smccc_ver, ARM_SMCCC_VERSION_1_2); - return false; + goto err_no_fw; } if ( !ffa_get_version(&vers) ) - return false; + { + gprintk(XENLOG_ERR, "Cannot retrieve the FFA version\n"); + goto err_no_fw; + } if ( vers < FFA_MIN_SPMC_VERSION || vers > FFA_MY_VERSION ) { printk(XENLOG_ERR "ffa: Incompatible version %#x found\n", vers); - return false; + goto err_no_fw; } major_vers = (vers >> FFA_VERSION_MAJOR_SHIFT) & FFA_VERSION_MAJOR_MASK; minor_vers = vers & FFA_VERSION_MINOR_MASK; - printk(XENLOG_INFO "ARM FF-A Mediator version %u.%u\n", - FFA_MY_VERSION_MAJOR, FFA_MY_VERSION_MINOR); printk(XENLOG_INFO "ARM FF-A Firmware version %u.%u\n", major_vers, minor_vers); @@ -XXX,XX +XXX,XX @@ static bool ffa_probe(void) !check_mandatory_feature(FFA_MEM_SHARE_32) || !check_mandatory_feature(FFA_MEM_RECLAIM) || !check_mandatory_feature(FFA_MSG_SEND_DIRECT_REQ_32) ) - return false; + { + printk(XENLOG_ERR "ffa: Mandatory feature not supported by fw\n"); + goto err_no_fw; + } - if ( !ffa_rxtx_init() ) - return false; + ffa_fw_version = vers; - ffa_version = vers; + if ( !ffa_rxtx_init() ) + { + printk(XENLOG_ERR "ffa: Error during RXTX buffer init\n"); + goto err_no_fw; + } if ( !ffa_partinfo_init() ) goto err_rxtx_destroy; @@ -XXX,XX +XXX,XX @@ static bool ffa_probe(void) err_rxtx_destroy: ffa_rxtx_destroy(); - ffa_version = 0; +err_no_fw: + ffa_fw_version = 0; + printk(XENLOG_WARNING "ARM FF-A No firmware support\n"); return false; } diff --git a/xen/arch/arm/tee/ffa_rxtx.c b/xen/arch/arm/tee/ffa_rxtx.c index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/arm/tee/ffa_rxtx.c +++ b/xen/arch/arm/tee/ffa_rxtx.c @@ -XXX,XX +XXX,XX @@ bool ffa_rxtx_init(void) e = ffa_rxtx_map(__pa(ffa_tx), __pa(ffa_rx), FFA_RXTX_PAGE_COUNT); if ( e ) - { - printk(XENLOG_ERR "ffa: Failed to map rxtx: error %d\n", e); goto err; - } + return true; err: -- 2.47.0
Store the list of ABI we need in a list and go through the list instead of having a list of conditions inside the code. No functional change. Signed-off-by: Bertrand Marquis <bertrand.marquis@arm.com> --- Changes in v3: - remove const attribute for id in ffa_fw_abi struct Changes in v2: - Store a string version of ABI needed from firmware and print the name of the ABI not supported instead of the id - Restore comment with TODO which should not have been removed at this stage - fix to unsigned int the index in the loop on the array - use abi instead of feature in the names of the functions and variables as we are not checking features but abis --- xen/arch/arm/tee/ffa.c | 57 +++++++++++++++++++++++++----------------- 1 file changed, 34 insertions(+), 23 deletions(-) diff --git a/xen/arch/arm/tee/ffa.c b/xen/arch/arm/tee/ffa.c index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/arm/tee/ffa.c +++ b/xen/arch/arm/tee/ffa.c @@ -XXX,XX +XXX,XX @@ /* Negotiated FF-A version to use with the SPMC, 0 if not there or supported */ static uint32_t __ro_after_init ffa_fw_version; +struct ffa_fw_abi { + uint32_t id; + const char *name; +}; + +#define FW_ABI(abi) {abi,#abi} + +/* List of ABI we use from the firmware */ +static const struct ffa_fw_abi ffa_fw_abi_needed[] = { + FW_ABI(FFA_VERSION), + FW_ABI(FFA_FEATURES), + FW_ABI(FFA_NOTIFICATION_BITMAP_CREATE), + FW_ABI(FFA_NOTIFICATION_BITMAP_DESTROY), + FW_ABI(FFA_PARTITION_INFO_GET), + FW_ABI(FFA_NOTIFICATION_INFO_GET_64), + FW_ABI(FFA_NOTIFICATION_GET), + FW_ABI(FFA_RX_RELEASE), + FW_ABI(FFA_RXTX_MAP_64), + FW_ABI(FFA_RXTX_UNMAP), + FW_ABI(FFA_MEM_SHARE_32), + FW_ABI(FFA_MEM_SHARE_64), + FW_ABI(FFA_MEM_RECLAIM), + FW_ABI(FFA_MSG_SEND_DIRECT_REQ_32), + FW_ABI(FFA_MSG_SEND_DIRECT_REQ_64), +}; /* * Our rx/tx buffers shared with the SPMC. FFA_RXTX_PAGE_COUNT is the @@ -XXX,XX +XXX,XX @@ static bool ffa_get_version(uint32_t *vers) return true; } -static int32_t ffa_features(uint32_t id) -{ - return ffa_simple_call(FFA_FEATURES, id, 0, 0, 0); -} - -static bool check_mandatory_feature(uint32_t id) +static bool ffa_abi_supported(uint32_t id) { - int32_t ret = ffa_features(id); - - if ( ret ) - printk(XENLOG_ERR "ffa: mandatory feature id %#x missing: error %d\n", - id, ret); - - return !ret; + return !ffa_simple_call(FFA_FEATURES, id, 0, 0, 0); } static void handle_version(struct cpu_user_regs *regs) @@ -XXX,XX +XXX,XX @@ static bool ffa_probe(void) * TODO: Rework the code to allow domain to use a subset of the * features supported. */ - if ( !check_mandatory_feature(FFA_PARTITION_INFO_GET) || - !check_mandatory_feature(FFA_RX_RELEASE) || - !check_mandatory_feature(FFA_RXTX_MAP_64) || - !check_mandatory_feature(FFA_MEM_SHARE_64) || - !check_mandatory_feature(FFA_RXTX_UNMAP) || - !check_mandatory_feature(FFA_MEM_SHARE_32) || - !check_mandatory_feature(FFA_MEM_RECLAIM) || - !check_mandatory_feature(FFA_MSG_SEND_DIRECT_REQ_32) ) + for ( unsigned int i = 0; i < ARRAY_SIZE(ffa_fw_abi_needed); i++ ) { - printk(XENLOG_ERR "ffa: Mandatory feature not supported by fw\n"); - goto err_no_fw; + if ( !ffa_abi_supported(ffa_fw_abi_needed[i].id) ) + { + printk(XENLOG_INFO "ARM FF-A Firmware does not support %s\n", + ffa_fw_abi_needed[i].name); + goto err_no_fw; + } } ffa_fw_version = vers; -- 2.47.0
Fix FFA version negotiation with the firmware to follow the specification guidance more closely (see FF-A Specification Version 1.1 in chapter 13.2.1). When the firmware returns OK we can have several cases: - the version requested is accepted but the firmware supports a greater one in the same major. - the firmware supports a greater major version. It could still return OK even if the version requested is not accepted. Reject it. - the firmware supports a lower version. It will return OK and give that version. Check if we support it and use it or reject it if we do not. Adapt the code to: - reject any version lower than the one we support or not with the same major version - use the version returned if in our supported range (currently 1.1 only) - use 1.1 if the version returned is greater. Also adapt the handling of version requests from VM: - use our version if same major but greater minor is requested - use requested version if same major but lower minor is requested - do not use if incompatible major is requested - always return our version without error to the requester [1] https://developer.arm.com/documentation/den0077/e/ Signed-off-by: Bertrand Marquis <bertrand.marquis@arm.com> Reviewed-by: Jens Wiklander <jens.wiklander@linaro.org> --- Changes in v3: - add Jens R-b Changes in v2: - add link in commit message and code to the version and chapter of the spec. - fix comment coding style - introduce macros to get the major and minor of a version - add BUILD_BUG_ON to validate that the SPMC version we want is compatible with our own version - rework version testing and selecting to be clearer by discarding different major or version lower than what we want and then selecting based on the minor version. - fix get_version handling to be more generic --- xen/arch/arm/tee/ffa.c | 53 +++++++++++++++++++++++++--------- xen/arch/arm/tee/ffa_private.h | 3 ++ 2 files changed, 43 insertions(+), 13 deletions(-) diff --git a/xen/arch/arm/tee/ffa.c b/xen/arch/arm/tee/ffa.c index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/arm/tee/ffa.c +++ b/xen/arch/arm/tee/ffa.c @@ -XXX,XX +XXX,XX @@ static void handle_version(struct cpu_user_regs *regs) struct ffa_ctx *ctx = d->arch.tee; uint32_t vers = get_user_reg(regs, 1); - if ( vers < FFA_VERSION_1_1 ) - vers = FFA_VERSION_1_0; - else - vers = FFA_VERSION_1_1; - - ctx->guest_vers = vers; - ffa_set_regs(regs, vers, 0, 0, 0, 0, 0, 0, 0); + /* + * Guest will use the version it requested if it is our major and minor + * lower or equals to ours. If the minor is greater, our version will be + * used. + * In any case return our version to the caller. + */ + if ( FFA_VERSION_MAJOR(vers) == FFA_MY_VERSION_MAJOR ) + { + if ( FFA_VERSION_MINOR(vers) > FFA_MY_VERSION_MINOR ) + ctx->guest_vers = FFA_MY_VERSION; + else + ctx->guest_vers = vers; + } + ffa_set_regs(regs, FFA_MY_VERSION, 0, 0, 0, 0, 0, 0, 0); } static void handle_msg_send_direct_req(struct cpu_user_regs *regs, uint32_t fid) @@ -XXX,XX +XXX,XX @@ static bool ffa_probe(void) goto err_no_fw; } - if ( vers < FFA_MIN_SPMC_VERSION || vers > FFA_MY_VERSION ) + /* Some sanity check in case we update the version we support */ + BUILD_BUG_ON(FFA_MIN_SPMC_VERSION > FFA_MY_VERSION); + BUILD_BUG_ON(FFA_VERSION_MAJOR(FFA_MIN_SPMC_VERSION) != + FFA_MY_VERSION_MAJOR); + + major_vers = FFA_VERSION_MAJOR(vers); + minor_vers = FFA_VERSION_MINOR(vers); + + if ( major_vers != FFA_MY_VERSION_MAJOR || + minor_vers < FFA_VERSION_MINOR(FFA_MIN_SPMC_VERSION) ) { - printk(XENLOG_ERR "ffa: Incompatible version %#x found\n", vers); + printk(XENLOG_ERR "ffa: Incompatible firmware version %u.%u\n", + major_vers, minor_vers); goto err_no_fw; } - major_vers = (vers >> FFA_VERSION_MAJOR_SHIFT) & FFA_VERSION_MAJOR_MASK; - minor_vers = vers & FFA_VERSION_MINOR_MASK; printk(XENLOG_INFO "ARM FF-A Firmware version %u.%u\n", major_vers, minor_vers); + /* + * If the call succeed and the version returned is higher or equal to + * the one Xen requested, the version requested by Xen will be the one + * used. If the version returned is lower but compatible with Xen, Xen + * will use that version instead. + * A version with a different major or lower than the minimum version + * we support is rejected before. + * See https://developer.arm.com/documentation/den0077/e/ chapter 13.2.1 + */ + if ( minor_vers > FFA_MY_VERSION_MINOR ) + ffa_fw_version = FFA_MY_VERSION; + else + ffa_fw_version = vers; + /* * At the moment domains must support the same features used by Xen. * TODO: Rework the code to allow domain to use a subset of the @@ -XXX,XX +XXX,XX @@ static bool ffa_probe(void) } } - ffa_fw_version = vers; - if ( !ffa_rxtx_init() ) { printk(XENLOG_ERR "ffa: Error during RXTX buffer init\n"); diff --git a/xen/arch/arm/tee/ffa_private.h b/xen/arch/arm/tee/ffa_private.h index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/arm/tee/ffa_private.h +++ b/xen/arch/arm/tee/ffa_private.h @@ -XXX,XX +XXX,XX @@ #define MAKE_FFA_VERSION(major, minor) \ ((((major) & FFA_VERSION_MAJOR_MASK) << FFA_VERSION_MAJOR_SHIFT) | \ ((minor) & FFA_VERSION_MINOR_MASK)) +#define FFA_VERSION_MAJOR(vers) (((vers) >> FFA_VERSION_MAJOR_SHIFT) & \ + FFA_VERSION_MAJOR_MASK) +#define FFA_VERSION_MINOR(vers) ((vers) & FFA_VERSION_MINOR_MASK) #define FFA_VERSION_1_0 MAKE_FFA_VERSION(1, 0) #define FFA_VERSION_1_1 MAKE_FFA_VERSION(1, 1) -- 2.47.0
Create a bitmap to store which feature is supported or not by the firmware and use it to filter which calls are done to the firmware. While there reoder ABI definition by numbers to easily find the min and max ones. Signed-off-by: Bertrand Marquis <bertrand.marquis@arm.com> Reviewed-by: Jens Wiklander <jens.wiklander@linaro.org> --- Changes in v3: - add Jens R-b Changes in v2: - rename fw_feat to abi and macros to FFA_ABI to be coherent with the abi needed change done before - rework the macros to be simpler by directly defining MIN and MAX using only Function ids - check that requested function ids do not go over the bitmap size in ffa_fw_supports_fid - add an ASSERT to make sure that we do not try to set bits outside of the bitmap - turn off FF-A if there is not firmware support and adapt the commit message to reflect this - add a compile time check that FFA_ABI_MIN < FFA_ABI_MAX - remove spurious line removal - restore proper cleanup of rxtx init in case of error - reorder ABI by numbers --- xen/arch/arm/tee/ffa.c | 28 +++++++++++++++--------- xen/arch/arm/tee/ffa_notif.c | 7 ++++++ xen/arch/arm/tee/ffa_partinfo.c | 30 +++++++++++++++++++++++++- xen/arch/arm/tee/ffa_private.h | 38 ++++++++++++++++++++++++++++----- xen/arch/arm/tee/ffa_rxtx.c | 4 ++++ xen/arch/arm/tee/ffa_shm.c | 12 +++++++++++ 6 files changed, 103 insertions(+), 16 deletions(-) diff --git a/xen/arch/arm/tee/ffa.c b/xen/arch/arm/tee/ffa.c index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/arm/tee/ffa.c +++ b/xen/arch/arm/tee/ffa.c @@ -XXX,XX +XXX,XX @@ #include "ffa_private.h" /* Negotiated FF-A version to use with the SPMC, 0 if not there or supported */ -static uint32_t __ro_after_init ffa_fw_version; +uint32_t __ro_after_init ffa_fw_version; + +/* Features supported by the SPMC or secure world when present */ +DECLARE_BITMAP(ffa_fw_abi_supported, FFA_ABI_BITMAP_SIZE); struct ffa_fw_abi { uint32_t id; @@ -XXX,XX +XXX,XX @@ static void handle_msg_send_direct_req(struct cpu_user_regs *regs, uint32_t fid) else mask = GENMASK_ULL(31, 0); + if ( !ffa_fw_supports_fid(fid) ) + { + resp.a0 = FFA_ERROR; + resp.a2 = FFA_RET_NOT_SUPPORTED; + goto out; + } + src_dst = get_user_reg(regs, 1); if ( (src_dst >> 16) != ffa_get_vm_id(d) ) { @@ -XXX,XX +XXX,XX @@ static bool ffa_probe(void) else ffa_fw_version = vers; - /* - * At the moment domains must support the same features used by Xen. - * TODO: Rework the code to allow domain to use a subset of the - * features supported. - */ for ( unsigned int i = 0; i < ARRAY_SIZE(ffa_fw_abi_needed); i++ ) { - if ( !ffa_abi_supported(ffa_fw_abi_needed[i].id) ) - { + ASSERT(FFA_ABI_BITNUM(ffa_fw_abi_needed[i].id) < FFA_ABI_BITMAP_SIZE); + + if ( ffa_abi_supported(ffa_fw_abi_needed[i].id) ) + set_bit(FFA_ABI_BITNUM(ffa_fw_abi_needed[i].id), + ffa_fw_abi_supported); + else printk(XENLOG_INFO "ARM FF-A Firmware does not support %s\n", ffa_fw_abi_needed[i].name); - goto err_no_fw; - } } if ( !ffa_rxtx_init() ) @@ -XXX,XX +XXX,XX @@ err_rxtx_destroy: ffa_rxtx_destroy(); err_no_fw: ffa_fw_version = 0; + bitmap_zero(ffa_fw_abi_supported, FFA_ABI_BITMAP_SIZE); printk(XENLOG_WARNING "ARM FF-A No firmware support\n"); return false; diff --git a/xen/arch/arm/tee/ffa_notif.c b/xen/arch/arm/tee/ffa_notif.c index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/arm/tee/ffa_notif.c +++ b/xen/arch/arm/tee/ffa_notif.c @@ -XXX,XX +XXX,XX @@ void ffa_notif_init(void) unsigned int irq; int ret; + /* Only enable fw notification if all ABIs we need are supported */ + if ( !(ffa_fw_supports_fid(FFA_NOTIFICATION_BITMAP_CREATE) && + ffa_fw_supports_fid(FFA_NOTIFICATION_BITMAP_DESTROY) && + ffa_fw_supports_fid(FFA_NOTIFICATION_GET) && + ffa_fw_supports_fid(FFA_NOTIFICATION_INFO_GET_64)) ) + return; + arm_smccc_1_2_smc(&arg, &resp); if ( resp.a0 != FFA_SUCCESS_32 ) return; diff --git a/xen/arch/arm/tee/ffa_partinfo.c b/xen/arch/arm/tee/ffa_partinfo.c index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/arm/tee/ffa_partinfo.c +++ b/xen/arch/arm/tee/ffa_partinfo.c @@ -XXX,XX +XXX,XX @@ int32_t ffa_handle_partition_info_get(uint32_t w1, uint32_t w2, uint32_t w3, */ if ( w5 == FFA_PARTITION_INFO_GET_COUNT_FLAG && ctx->guest_vers == FFA_VERSION_1_1 ) - return ffa_partition_info_get(w1, w2, w3, w4, w5, count, fpi_size); + { + if ( ffa_fw_supports_fid(FFA_PARTITION_INFO_GET) ) + return ffa_partition_info_get(w1, w2, w3, w4, w5, count, fpi_size); + else + { + *count = 0; + return FFA_RET_OK; + } + } if ( w5 ) return FFA_RET_INVALID_PARAMETERS; @@ -XXX,XX +XXX,XX @@ int32_t ffa_handle_partition_info_get(uint32_t w1, uint32_t w2, uint32_t w3, if ( !spin_trylock(&ctx->rx_lock) ) return FFA_RET_BUSY; + if ( !ffa_fw_supports_fid(FFA_PARTITION_INFO_GET) ) + { + if ( ctx->guest_vers == FFA_VERSION_1_0 ) + *fpi_size = sizeof(struct ffa_partition_info_1_0); + else + *fpi_size = sizeof(struct ffa_partition_info_1_1); + + *count = 0; + ret = FFA_RET_OK; + goto out; + } + if ( !ctx->page_count || !ctx->rx_is_free ) goto out; spin_lock(&ffa_rx_buffer_lock); @@ -XXX,XX +XXX,XX @@ bool ffa_partinfo_init(void) uint32_t count; int e; + if ( !ffa_fw_supports_fid(FFA_PARTITION_INFO_GET) || + !ffa_fw_supports_fid(FFA_MSG_SEND_DIRECT_REQ_32) || + !ffa_rx || !ffa_tx ) + return false; + e = ffa_partition_info_get(0, 0, 0, 0, 0, &count, &fpi_size); if ( e ) { @@ -XXX,XX +XXX,XX @@ int ffa_partinfo_domain_init(struct domain *d) unsigned int n; int32_t res; + if ( !ffa_fw_supports_fid(FFA_MSG_SEND_DIRECT_REQ_32) ) + return 0; + ctx->vm_destroy_bitmap = xzalloc_array(unsigned long, count); if ( !ctx->vm_destroy_bitmap ) return -ENOMEM; diff --git a/xen/arch/arm/tee/ffa_private.h b/xen/arch/arm/tee/ffa_private.h index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/arm/tee/ffa_private.h +++ b/xen/arch/arm/tee/ffa_private.h @@ -XXX,XX +XXX,XX @@ #include <xen/spinlock.h> #include <xen/sched.h> #include <xen/time.h> +#include <xen/bitmap.h> /* Error codes */ #define FFA_RET_OK 0 @@ -XXX,XX +XXX,XX @@ #define FFA_INTERRUPT 0x84000062U #define FFA_VERSION 0x84000063U #define FFA_FEATURES 0x84000064U -#define FFA_RX_ACQUIRE 0x84000084U #define FFA_RX_RELEASE 0x84000065U #define FFA_RXTX_MAP_32 0x84000066U #define FFA_RXTX_MAP_64 0xC4000066U #define FFA_RXTX_UNMAP 0x84000067U #define FFA_PARTITION_INFO_GET 0x84000068U #define FFA_ID_GET 0x84000069U -#define FFA_SPM_ID_GET 0x84000085U +#define FFA_MSG_POLL 0x8400006AU #define FFA_MSG_WAIT 0x8400006BU #define FFA_MSG_YIELD 0x8400006CU #define FFA_RUN 0x8400006DU -#define FFA_MSG_SEND2 0x84000086U +#define FFA_MSG_SEND 0x8400006EU #define FFA_MSG_SEND_DIRECT_REQ_32 0x8400006FU #define FFA_MSG_SEND_DIRECT_REQ_64 0xC400006FU #define FFA_MSG_SEND_DIRECT_RESP_32 0x84000070U @@ -XXX,XX +XXX,XX @@ #define FFA_MEM_RECLAIM 0x84000077U #define FFA_MEM_FRAG_RX 0x8400007AU #define FFA_MEM_FRAG_TX 0x8400007BU -#define FFA_MSG_SEND 0x8400006EU -#define FFA_MSG_POLL 0x8400006AU #define FFA_NOTIFICATION_BITMAP_CREATE 0x8400007DU #define FFA_NOTIFICATION_BITMAP_DESTROY 0x8400007EU #define FFA_NOTIFICATION_BIND 0x8400007FU @@ -XXX,XX +XXX,XX @@ #define FFA_NOTIFICATION_GET 0x84000082U #define FFA_NOTIFICATION_INFO_GET_32 0x84000083U #define FFA_NOTIFICATION_INFO_GET_64 0xC4000083U +#define FFA_RX_ACQUIRE 0x84000084U +#define FFA_SPM_ID_GET 0x84000085U +#define FFA_MSG_SEND2 0x84000086U + +/** + * Encoding of features supported or not by the fw in a bitmap: + * - Function IDs are going from 0x60 to 0xFF + * - A function can be supported in 32 and/or 64bit + * The bitmap has one bit for each function in 32 and 64 bit. + */ +#define FFA_ABI_ID(id) ((id) & ARM_SMCCC_FUNC_MASK) +#define FFA_ABI_CONV(id) (((id) >> ARM_SMCCC_CONV_SHIFT) & BIT(0,U)) + +#define FFA_ABI_MIN FFA_ABI_ID(FFA_ERROR) +#define FFA_ABI_MAX FFA_ABI_ID(FFA_MSG_SEND2) + +#define FFA_ABI_BITMAP_SIZE (2 * (FFA_ABI_MAX - FFA_ABI_MIN + 1)) +#define FFA_ABI_BITNUM(id) ((FFA_ABI_ID(id) - FFA_ABI_MIN) << 1 | \ + FFA_ABI_CONV(id)) struct ffa_ctx_notif { bool enabled; @@ -XXX,XX +XXX,XX @@ extern void *ffa_rx; extern void *ffa_tx; extern spinlock_t ffa_rx_buffer_lock; extern spinlock_t ffa_tx_buffer_lock; +extern uint32_t __ro_after_init ffa_fw_version; +extern DECLARE_BITMAP(ffa_fw_abi_supported, FFA_ABI_BITMAP_SIZE); bool ffa_shm_domain_destroy(struct domain *d); void ffa_handle_mem_share(struct cpu_user_regs *regs); @@ -XXX,XX +XXX,XX @@ static inline int32_t ffa_rx_release(void) return ffa_simple_call(FFA_RX_RELEASE, 0, 0, 0, 0); } +static inline bool ffa_fw_supports_fid(uint32_t fid) +{ + BUILD_BUG_ON(FFA_ABI_MIN > FFA_ABI_MAX); + + if ( FFA_ABI_BITNUM(fid) > FFA_ABI_BITMAP_SIZE) + return false; + return test_bit(FFA_ABI_BITNUM(fid), ffa_fw_abi_supported); +} + #endif /*__FFA_PRIVATE_H__*/ diff --git a/xen/arch/arm/tee/ffa_rxtx.c b/xen/arch/arm/tee/ffa_rxtx.c index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/arm/tee/ffa_rxtx.c +++ b/xen/arch/arm/tee/ffa_rxtx.c @@ -XXX,XX +XXX,XX @@ bool ffa_rxtx_init(void) { int e; + /* Firmware not there or not supporting */ + if ( !ffa_fw_supports_fid(FFA_RXTX_MAP_64) ) + return false; + ffa_rx = alloc_xenheap_pages(get_order_from_pages(FFA_RXTX_PAGE_COUNT), 0); if ( !ffa_rx ) return false; diff --git a/xen/arch/arm/tee/ffa_shm.c b/xen/arch/arm/tee/ffa_shm.c index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/arm/tee/ffa_shm.c +++ b/xen/arch/arm/tee/ffa_shm.c @@ -XXX,XX +XXX,XX @@ static int32_t ffa_mem_share(uint32_t tot_len, uint32_t frag_len, static int32_t ffa_mem_reclaim(uint32_t handle_lo, uint32_t handle_hi, uint32_t flags) { + if ( !ffa_fw_supports_fid(FFA_MEM_RECLAIM) ) + return FFA_RET_NOT_SUPPORTED; + return ffa_simple_call(FFA_MEM_RECLAIM, handle_lo, handle_hi, flags, 0); } @@ -XXX,XX +XXX,XX @@ void ffa_handle_mem_share(struct cpu_user_regs *regs) uint32_t range_count; uint32_t region_offs; + if ( !ffa_fw_supports_fid(FFA_MEM_SHARE_64) ) + { + ret = FFA_RET_NOT_SUPPORTED; + goto out_set_ret; + } + /* * We're only accepting memory transaction descriptors via the rx/tx * buffer. @@ -XXX,XX +XXX,XX @@ int ffa_handle_mem_reclaim(uint64_t handle, uint32_t flags) register_t handle_lo; int ret; + if ( !ffa_fw_supports_fid(FFA_MEM_RECLAIM) ) + return FFA_RET_NOT_SUPPORTED; + spin_lock(&ctx->lock); shm = find_shm_mem(ctx, handle); if ( shm ) -- 2.47.0
Rework the partition info get implementation to use the correct size of structure depending on the version of the protocol and simplifies the structure copy to use only memcpy and prevent recreating the structure each time. The goal here is to have an implementation that will be easier to maintain in the long term as the specification is only adding fields to structure with versions to simplify support of several protocol versions and as such an SPMC implementation in the future could use this and return a size higher than the one we expect. The patch is fixing the part_info_get function for this and the subscriber discovery on probe. No functional changes expected. Signed-off-by: Bertrand Marquis <bertrand.marquis@arm.com> Reviewed-by: Jens Wiklander <jens.wiklander@linaro.org> --- Changes in v3: - add Jens R-b Changes in v2: - rebase --- xen/arch/arm/tee/ffa.c | 13 +-- xen/arch/arm/tee/ffa_partinfo.c | 185 ++++++++++++++++++++------------ xen/arch/arm/tee/ffa_private.h | 4 +- 3 files changed, 118 insertions(+), 84 deletions(-) diff --git a/xen/arch/arm/tee/ffa.c b/xen/arch/arm/tee/ffa.c index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/arm/tee/ffa.c +++ b/xen/arch/arm/tee/ffa.c @@ -XXX,XX +XXX,XX @@ static bool ffa_handle_call(struct cpu_user_regs *regs) uint32_t fid = get_user_reg(regs, 0); struct domain *d = current->domain; struct ffa_ctx *ctx = d->arch.tee; - uint32_t fpi_size; - uint32_t count; int e; if ( !ctx ) @@ -XXX,XX +XXX,XX @@ static bool ffa_handle_call(struct cpu_user_regs *regs) e = ffa_handle_rxtx_unmap(); break; case FFA_PARTITION_INFO_GET: - e = ffa_handle_partition_info_get(get_user_reg(regs, 1), - get_user_reg(regs, 2), - get_user_reg(regs, 3), - get_user_reg(regs, 4), - get_user_reg(regs, 5), &count, - &fpi_size); - if ( e ) - ffa_set_regs_error(regs, e); - else - ffa_set_regs_success(regs, count, fpi_size); + ffa_handle_partition_info_get(regs); return true; case FFA_RX_RELEASE: e = ffa_handle_rx_release(); diff --git a/xen/arch/arm/tee/ffa_partinfo.c b/xen/arch/arm/tee/ffa_partinfo.c index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/arm/tee/ffa_partinfo.c +++ b/xen/arch/arm/tee/ffa_partinfo.c @@ -XXX,XX +XXX,XX @@ static uint16_t subscr_vm_created_count __read_mostly; static uint16_t *subscr_vm_destroyed __read_mostly; static uint16_t subscr_vm_destroyed_count __read_mostly; -static int32_t ffa_partition_info_get(uint32_t w1, uint32_t w2, uint32_t w3, - uint32_t w4, uint32_t w5, uint32_t *count, - uint32_t *fpi_size) +static int32_t ffa_partition_info_get(uint32_t *uuid, uint32_t flags, + uint32_t *count, uint32_t *fpi_size) { - const struct arm_smccc_1_2_regs arg = { + struct arm_smccc_1_2_regs arg = { .a0 = FFA_PARTITION_INFO_GET, - .a1 = w1, - .a2 = w2, - .a3 = w3, - .a4 = w4, - .a5 = w5, + .a5 = flags, }; struct arm_smccc_1_2_regs resp; uint32_t ret; + if ( uuid ) + { + arg.a1 = uuid[0]; + arg.a2 = uuid[1]; + arg.a3 = uuid[2]; + arg.a4 = uuid[3]; + } + arm_smccc_1_2_smc(&arg, &resp); ret = ffa_get_ret_code(&resp); @@ -XXX,XX +XXX,XX @@ static int32_t ffa_partition_info_get(uint32_t w1, uint32_t w2, uint32_t w3, return ret; } -int32_t ffa_handle_partition_info_get(uint32_t w1, uint32_t w2, uint32_t w3, - uint32_t w4, uint32_t w5, uint32_t *count, - uint32_t *fpi_size) +void ffa_handle_partition_info_get(struct cpu_user_regs *regs) { - int32_t ret = FFA_RET_DENIED; + int32_t ret; struct domain *d = current->domain; struct ffa_ctx *ctx = d->arch.tee; + uint32_t flags = get_user_reg(regs, 5); + uint32_t uuid[4] = { + get_user_reg(regs, 1), + get_user_reg(regs, 2), + get_user_reg(regs, 3), + get_user_reg(regs, 4), + }; + uint32_t src_size, dst_size; + void *dst_buf; + uint32_t ffa_sp_count = 0; + + /* + * If the guest is v1.0, he does not get back the entry size so we must + * use the v1.0 structure size in the destination buffer. + * Otherwise use the size of the highest version we support, here 1.1. + */ + if ( ctx->guest_vers == FFA_VERSION_1_0 ) + dst_size = sizeof(struct ffa_partition_info_1_0); + else + dst_size = sizeof(struct ffa_partition_info_1_1); /* * FF-A v1.0 has w5 MBZ while v1.1 allows @@ -XXX,XX +XXX,XX @@ int32_t ffa_handle_partition_info_get(uint32_t w1, uint32_t w2, uint32_t w3, * FFA_PARTITION_INFO_GET_COUNT is only using registers and not the * rxtx buffer so do the partition_info_get directly. */ - if ( w5 == FFA_PARTITION_INFO_GET_COUNT_FLAG && + if ( flags == FFA_PARTITION_INFO_GET_COUNT_FLAG && ctx->guest_vers == FFA_VERSION_1_1 ) { if ( ffa_fw_supports_fid(FFA_PARTITION_INFO_GET) ) - return ffa_partition_info_get(w1, w2, w3, w4, w5, count, fpi_size); + ret = ffa_partition_info_get(uuid, flags, &ffa_sp_count, + &src_size); else - { - *count = 0; - return FFA_RET_OK; - } - } - if ( w5 ) - return FFA_RET_INVALID_PARAMETERS; + ret = FFA_RET_OK; - if ( !ffa_rx ) - return FFA_RET_DENIED; + goto out; + } - if ( !spin_trylock(&ctx->rx_lock) ) - return FFA_RET_BUSY; + if ( flags ) + { + ret = FFA_RET_INVALID_PARAMETERS; + goto out; + } if ( !ffa_fw_supports_fid(FFA_PARTITION_INFO_GET) ) { - if ( ctx->guest_vers == FFA_VERSION_1_0 ) - *fpi_size = sizeof(struct ffa_partition_info_1_0); - else - *fpi_size = sizeof(struct ffa_partition_info_1_1); - - *count = 0; + /* Just give an empty partition list to the caller */ ret = FFA_RET_OK; goto out; } - if ( !ctx->page_count || !ctx->rx_is_free ) + if ( !spin_trylock(&ctx->rx_lock) ) + { + ret = FFA_RET_BUSY; goto out; + } + + dst_buf = ctx->rx; + + if ( !ffa_rx ) + { + ret = FFA_RET_DENIED; + goto out_rx_release; + } + + if ( !ctx->page_count || !ctx->rx_is_free ) + { + ret = FFA_RET_DENIED; + goto out_rx_release; + } + spin_lock(&ffa_rx_buffer_lock); - ret = ffa_partition_info_get(w1, w2, w3, w4, w5, count, fpi_size); + + ret = ffa_partition_info_get(uuid, 0, &ffa_sp_count, &src_size); + if ( ret ) goto out_rx_buf_unlock; + /* * ffa_partition_info_get() succeeded so we now own the RX buffer we * share with the SPMC. We must give it back using ffa_rx_release() * once we've copied the content. */ - if ( ctx->guest_vers == FFA_VERSION_1_0 ) + /* we cannot have a size smaller than 1.0 structure */ + if ( src_size < sizeof(struct ffa_partition_info_1_0) ) { - size_t n; - struct ffa_partition_info_1_1 *src = ffa_rx; - struct ffa_partition_info_1_0 *dst = ctx->rx; - - if ( ctx->page_count * FFA_PAGE_SIZE < *count * sizeof(*dst) ) - { - ret = FFA_RET_NO_MEMORY; - goto out_rx_release; - } + ret = FFA_RET_NOT_SUPPORTED; + goto out_rx_hyp_release; + } - for ( n = 0; n < *count; n++ ) - { - dst[n].id = src[n].id; - dst[n].execution_context = src[n].execution_context; - dst[n].partition_properties = src[n].partition_properties; - } + if ( ctx->page_count * FFA_PAGE_SIZE < ffa_sp_count * dst_size ) + { + ret = FFA_RET_NO_MEMORY; + goto out_rx_hyp_release; } - else + + if ( ffa_sp_count > 0 ) { - size_t sz = *count * *fpi_size; + uint32_t n; + void *src_buf = ffa_rx; - if ( ctx->page_count * FFA_PAGE_SIZE < sz ) + /* copy the secure partitions info */ + for ( n = 0; n < ffa_sp_count; n++ ) { - ret = FFA_RET_NO_MEMORY; - goto out_rx_release; + memcpy(dst_buf, src_buf, dst_size); + dst_buf += dst_size; + src_buf += src_size; } - - memcpy(ctx->rx, ffa_rx, sz); } + ctx->rx_is_free = false; -out_rx_release: + +out_rx_hyp_release: ffa_rx_release(); out_rx_buf_unlock: spin_unlock(&ffa_rx_buffer_lock); -out: +out_rx_release: spin_unlock(&ctx->rx_lock); - return ret; +out: + if ( ret ) + ffa_set_regs_error(regs, ret); + else + ffa_set_regs_success(regs, ffa_sp_count, dst_size); } static int32_t ffa_direct_req_send_vm(uint16_t sp_id, uint16_t vm_id, @@ -XXX,XX +XXX,XX @@ static void uninit_subscribers(void) XFREE(subscr_vm_destroyed); } -static bool init_subscribers(struct ffa_partition_info_1_1 *fpi, uint16_t count) +static bool init_subscribers(uint16_t count, uint32_t fpi_size) { uint16_t n; uint16_t c_pos; uint16_t d_pos; + struct ffa_partition_info_1_1 *fpi; + + if ( fpi_size < sizeof(struct ffa_partition_info_1_1) ) + { + printk(XENLOG_ERR "ffa: partition info size invalid: %u\n", fpi_size); + return false; + } subscr_vm_created_count = 0; subscr_vm_destroyed_count = 0; for ( n = 0; n < count; n++ ) { - if ( fpi[n].partition_properties & FFA_PART_PROP_NOTIF_CREATED ) + fpi = ffa_rx + n * fpi_size; + + if ( fpi->partition_properties & FFA_PART_PROP_NOTIF_CREATED ) subscr_vm_created_count++; - if ( fpi[n].partition_properties & FFA_PART_PROP_NOTIF_DESTROYED ) + if ( fpi->partition_properties & FFA_PART_PROP_NOTIF_DESTROYED ) subscr_vm_destroyed_count++; } @@ -XXX,XX +XXX,XX @@ static bool init_subscribers(struct ffa_partition_info_1_1 *fpi, uint16_t count) for ( c_pos = 0, d_pos = 0, n = 0; n < count; n++ ) { - if ( fpi[n].partition_properties & FFA_PART_PROP_NOTIF_CREATED ) - subscr_vm_created[c_pos++] = fpi[n].id; - if ( fpi[n].partition_properties & FFA_PART_PROP_NOTIF_DESTROYED ) - subscr_vm_destroyed[d_pos++] = fpi[n].id; + fpi = ffa_rx + n * fpi_size; + + if ( fpi->partition_properties & FFA_PART_PROP_NOTIF_CREATED ) + subscr_vm_created[c_pos++] = fpi->id; + if ( fpi->partition_properties & FFA_PART_PROP_NOTIF_DESTROYED ) + subscr_vm_destroyed[d_pos++] = fpi->id; } return true; @@ -XXX,XX +XXX,XX @@ bool ffa_partinfo_init(void) !ffa_rx || !ffa_tx ) return false; - e = ffa_partition_info_get(0, 0, 0, 0, 0, &count, &fpi_size); + e = ffa_partition_info_get(NULL, 0, &count, &fpi_size); if ( e ) { printk(XENLOG_ERR "ffa: Failed to get list of SPs: %d\n", e); @@ -XXX,XX +XXX,XX @@ bool ffa_partinfo_init(void) goto out; } - ret = init_subscribers(ffa_rx, count); + ret = init_subscribers(count, fpi_size); out: ffa_rx_release(); diff --git a/xen/arch/arm/tee/ffa_private.h b/xen/arch/arm/tee/ffa_private.h index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/arm/tee/ffa_private.h +++ b/xen/arch/arm/tee/ffa_private.h @@ -XXX,XX +XXX,XX @@ int ffa_handle_mem_reclaim(uint64_t handle, uint32_t flags); bool ffa_partinfo_init(void); int ffa_partinfo_domain_init(struct domain *d); bool ffa_partinfo_domain_destroy(struct domain *d); -int32_t ffa_handle_partition_info_get(uint32_t w1, uint32_t w2, uint32_t w3, - uint32_t w4, uint32_t w5, uint32_t *count, - uint32_t *fpi_size); +void ffa_handle_partition_info_get(struct cpu_user_regs *regs); bool ffa_rxtx_init(void); void ffa_rxtx_destroy(void); -- 2.47.0
Make use and required to have bit 15 convention respected by secure world (having bit 15 of IDs set for secure endpoints and non-set for non-secure ones). If any secure partition has an ID with bit 15 not set, it will not be possible to contact or detect them. Print an error log during probe for each secure endpoint detected with bit 15 not set. We are switching to this convention because Xen is currently not using VMIDs with bit 15 set so we are sure that no VM will have it set (this is ensured by BUILD_BUG_ON in case this becomes false in the future). It is allowing to easily distinguish between secure and non-secure endpoints, preventing the need to store a list of secure endpoint IDs in Xen. Signed-off-by: Bertrand Marquis <bertrand.marquis@arm.com> --- Changes in v3: - rename real_num to n_limit - remove log of skipped SP due to invalid ID as it is already printed Changes in v2: - rebase --- xen/arch/arm/tee/ffa.c | 22 ++++++++++---- xen/arch/arm/tee/ffa_partinfo.c | 51 +++++++++++++++++++++++++-------- xen/arch/arm/tee/ffa_private.h | 7 +++++ xen/arch/arm/tee/ffa_shm.c | 12 +++++++- 4 files changed, 74 insertions(+), 18 deletions(-) diff --git a/xen/arch/arm/tee/ffa.c b/xen/arch/arm/tee/ffa.c index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/arm/tee/ffa.c +++ b/xen/arch/arm/tee/ffa.c @@ -XXX,XX +XXX,XX @@ static void handle_msg_send_direct_req(struct cpu_user_regs *regs, uint32_t fid) goto out; } + /* we do not support direct messages to VMs */ + if ( !FFA_ID_IS_SECURE(src_dst & GENMASK(15,0)) ) + { + resp.a0 = FFA_ERROR; + resp.a2 = FFA_RET_NOT_SUPPORTED; + goto out; + } + arg.a1 = src_dst; arg.a2 = get_user_reg(regs, 2) & mask; arg.a3 = get_user_reg(regs, 3) & mask; @@ -XXX,XX +XXX,XX @@ static int ffa_domain_init(struct domain *d) if ( !ffa_fw_version ) return -ENODEV; - /* - * We can't use that last possible domain ID or ffa_get_vm_id() would - * cause an overflow. - */ - if ( d->domain_id >= UINT16_MAX) + /* + * We are using the domain_id + 1 as the FF-A ID for VMs as FF-A ID 0 is + * reserved for the hypervisor and we only support secure endpoints using + * FF-A IDs with BIT 15 set to 1 so make sure those are not used by Xen. + */ + BUILD_BUG_ON(DOMID_FIRST_RESERVED >= UINT16_MAX); + BUILD_BUG_ON((DOMID_MASK & BIT(15, U)) != 0); + + if ( d->domain_id >= DOMID_FIRST_RESERVED ) return -ERANGE; ctx = xzalloc(struct ffa_ctx); diff --git a/xen/arch/arm/tee/ffa_partinfo.c b/xen/arch/arm/tee/ffa_partinfo.c index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/arm/tee/ffa_partinfo.c +++ b/xen/arch/arm/tee/ffa_partinfo.c @@ -XXX,XX +XXX,XX @@ void ffa_handle_partition_info_get(struct cpu_user_regs *regs) if ( ffa_sp_count > 0 ) { - uint32_t n; + uint32_t n, n_limit = ffa_sp_count; void *src_buf = ffa_rx; /* copy the secure partitions info */ - for ( n = 0; n < ffa_sp_count; n++ ) + for ( n = 0; n < n_limit; n++ ) { - memcpy(dst_buf, src_buf, dst_size); - dst_buf += dst_size; + struct ffa_partition_info_1_1 *fpi = src_buf; + + /* filter out SP not following bit 15 convention if any */ + if ( FFA_ID_IS_SECURE(fpi->id) ) + { + memcpy(dst_buf, src_buf, dst_size); + dst_buf += dst_size; + } + else + ffa_sp_count--; + src_buf += src_size; } } @@ -XXX,XX +XXX,XX @@ static bool init_subscribers(uint16_t count, uint32_t fpi_size) { fpi = ffa_rx + n * fpi_size; - if ( fpi->partition_properties & FFA_PART_PROP_NOTIF_CREATED ) - subscr_vm_created_count++; - if ( fpi->partition_properties & FFA_PART_PROP_NOTIF_DESTROYED ) - subscr_vm_destroyed_count++; + /* + * We need to have secure partitions using bit 15 set convention for + * secure partition IDs. + * Inform the user with a log and discard giving created or destroy + * event to those IDs. + */ + if ( !FFA_ID_IS_SECURE(fpi->id) ) + { + printk(XENLOG_ERR "ffa: Firmware is not using bit 15 convention for IDs !!\n" + "ffa: Secure partition with id 0x%04x cannot be used\n", + fpi->id); + } + else + { + if ( fpi->partition_properties & FFA_PART_PROP_NOTIF_CREATED ) + subscr_vm_created_count++; + if ( fpi->partition_properties & FFA_PART_PROP_NOTIF_DESTROYED ) + subscr_vm_destroyed_count++; + } } if ( subscr_vm_created_count ) @@ -XXX,XX +XXX,XX @@ static bool init_subscribers(uint16_t count, uint32_t fpi_size) { fpi = ffa_rx + n * fpi_size; - if ( fpi->partition_properties & FFA_PART_PROP_NOTIF_CREATED ) - subscr_vm_created[c_pos++] = fpi->id; - if ( fpi->partition_properties & FFA_PART_PROP_NOTIF_DESTROYED ) - subscr_vm_destroyed[d_pos++] = fpi->id; + if ( FFA_ID_IS_SECURE(fpi->id) ) + { + if ( fpi->partition_properties & FFA_PART_PROP_NOTIF_CREATED ) + subscr_vm_created[c_pos++] = fpi->id; + if ( fpi->partition_properties & FFA_PART_PROP_NOTIF_DESTROYED ) + subscr_vm_destroyed[d_pos++] = fpi->id; + } } return true; diff --git a/xen/arch/arm/tee/ffa_private.h b/xen/arch/arm/tee/ffa_private.h index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/arm/tee/ffa_private.h +++ b/xen/arch/arm/tee/ffa_private.h @@ -XXX,XX +XXX,XX @@ */ #define FFA_CTX_TEARDOWN_DELAY SECONDS(1) +/* + * We rely on the convention suggested but not mandated by the FF-A + * specification that secure world endpoint identifiers have the bit 15 + * set and normal world have it set to 0. + */ +#define FFA_ID_IS_SECURE(id) ((id) & BIT(15, U)) + /* FF-A-1.1-REL0 section 10.9.2 Memory region handle, page 167 */ #define FFA_HANDLE_HYP_FLAG BIT(63, ULL) #define FFA_HANDLE_INVALID 0xffffffffffffffffULL diff --git a/xen/arch/arm/tee/ffa_shm.c b/xen/arch/arm/tee/ffa_shm.c index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/arm/tee/ffa_shm.c +++ b/xen/arch/arm/tee/ffa_shm.c @@ -XXX,XX +XXX,XX @@ void ffa_handle_mem_share(struct cpu_user_regs *regs) int ret = FFA_RET_DENIED; uint32_t range_count; uint32_t region_offs; + uint16_t dst_id; if ( !ffa_fw_supports_fid(FFA_MEM_SHARE_64) ) { @@ -XXX,XX +XXX,XX @@ void ffa_handle_mem_share(struct cpu_user_regs *regs) goto out_unlock; mem_access = ctx->tx + trans.mem_access_offs; + + dst_id = ACCESS_ONCE(mem_access->access_perm.endpoint_id); + if ( !FFA_ID_IS_SECURE(dst_id) ) + { + /* we do not support sharing with VMs */ + ret = FFA_RET_NOT_SUPPORTED; + goto out_unlock; + } + if ( ACCESS_ONCE(mem_access->access_perm.perm) != FFA_MEM_ACC_RW ) { ret = FFA_RET_NOT_SUPPORTED; @@ -XXX,XX +XXX,XX @@ void ffa_handle_mem_share(struct cpu_user_regs *regs) goto out_unlock; } shm->sender_id = trans.sender_id; - shm->ep_id = ACCESS_ONCE(mem_access->access_perm.endpoint_id); + shm->ep_id = dst_id; /* * Check that the Composite memory region descriptor fits. -- 2.47.0
When an RXTX buffer is mapped by a VM transmit it to the SPMC when it supports RX_ACQUIRE. As a consequence of that, we must acquire the RX buffer of a VM from the SPMC when we want to use it: - create a generic acquire and release function to get the rx buffer of a VM which gets it from the SPMC when supported - rename the rx_acquire to hyp_rx_acquire to remove confusion - rework the rx_lock to only lock access to rx_is_free and only allow usage of the rx buffer to one who managed to acquire it, thus removing the trylock and returning busy if rx_is_free is false As part of this change move some structure definition to ffa_private from ffa_shm as those are need for the MAP call with the SPMC. While there also fix ffa_handle_rxtx_map which was testing the wrong variable after getting the page for the rx buffer, testing tx_pg instead of rx_pg. Fixes: be75f686eb03 ("xen/arm: ffa: separate rxtx buffer routines") Signed-off-by: Bertrand Marquis <bertrand.marquis@arm.com> --- Changes in v3: - add a comment to explain why we only release the RX buffer if an error occurs during partition_info_get - fix the BUILD_BUG_ON check for TX buffer size in rxtx_map (coding style and use PAGE_SIZE * NUM_PAGE) - remove invalid 3 argument to ffa_rxtx_map when forwarding the call to the SPMC - fix bug in ffa_handle_rxtx_map testing wrong variable Changes in v2: - unmap VM rxtx buffer in SPMC on unmap call or on VM destroy - rework the unmap call to the SPMC to properly pass the VM ID --- xen/arch/arm/tee/ffa.c | 2 +- xen/arch/arm/tee/ffa_partinfo.c | 36 ++++--- xen/arch/arm/tee/ffa_private.h | 22 ++++- xen/arch/arm/tee/ffa_rxtx.c | 161 ++++++++++++++++++++++++++------ xen/arch/arm/tee/ffa_shm.c | 15 --- 5 files changed, 170 insertions(+), 66 deletions(-) diff --git a/xen/arch/arm/tee/ffa.c b/xen/arch/arm/tee/ffa.c index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/arm/tee/ffa.c +++ b/xen/arch/arm/tee/ffa.c @@ -XXX,XX +XXX,XX @@ static bool ffa_handle_call(struct cpu_user_regs *regs) ffa_handle_partition_info_get(regs); return true; case FFA_RX_RELEASE: - e = ffa_handle_rx_release(); + e = ffa_rx_release(d); break; case FFA_MSG_SEND_DIRECT_REQ_32: case FFA_MSG_SEND_DIRECT_REQ_64: diff --git a/xen/arch/arm/tee/ffa_partinfo.c b/xen/arch/arm/tee/ffa_partinfo.c index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/arm/tee/ffa_partinfo.c +++ b/xen/arch/arm/tee/ffa_partinfo.c @@ -XXX,XX +XXX,XX @@ void ffa_handle_partition_info_get(struct cpu_user_regs *regs) goto out; } - if ( !spin_trylock(&ctx->rx_lock) ) - { - ret = FFA_RET_BUSY; + ret = ffa_rx_acquire(d); + if ( ret != FFA_RET_OK ) goto out; - } dst_buf = ctx->rx; @@ -XXX,XX +XXX,XX @@ void ffa_handle_partition_info_get(struct cpu_user_regs *regs) goto out_rx_release; } - if ( !ctx->page_count || !ctx->rx_is_free ) - { - ret = FFA_RET_DENIED; - goto out_rx_release; - } - spin_lock(&ffa_rx_buffer_lock); ret = ffa_partition_info_get(uuid, 0, &ffa_sp_count, &src_size); if ( ret ) - goto out_rx_buf_unlock; + goto out_rx_hyp_unlock; /* * ffa_partition_info_get() succeeded so we now own the RX buffer we - * share with the SPMC. We must give it back using ffa_rx_release() + * share with the SPMC. We must give it back using ffa_hyp_rx_release() * once we've copied the content. */ @@ -XXX,XX +XXX,XX @@ void ffa_handle_partition_info_get(struct cpu_user_regs *regs) } } - ctx->rx_is_free = false; - out_rx_hyp_release: - ffa_rx_release(); -out_rx_buf_unlock: + ffa_hyp_rx_release(); +out_rx_hyp_unlock: spin_unlock(&ffa_rx_buffer_lock); out_rx_release: - spin_unlock(&ctx->rx_lock); - + /* + * The calling VM RX buffer only contains data to be used by the VM if the + * call was successfull, in which case the VM has to release the buffer + * once it has used the data. + * If something went wrong during the call, we have to release the RX + * buffer back to the SPMC as the VM will not do it. + */ + if ( ret != FFA_RET_OK ) + ffa_rx_release(d); out: if ( ret ) ffa_set_regs_error(regs, ret); @@ -XXX,XX +XXX,XX @@ bool ffa_partinfo_init(void) ret = init_subscribers(count, fpi_size); out: - ffa_rx_release(); - + ffa_hyp_rx_release(); return ret; } diff --git a/xen/arch/arm/tee/ffa_private.h b/xen/arch/arm/tee/ffa_private.h index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/arm/tee/ffa_private.h +++ b/xen/arch/arm/tee/ffa_private.h @@ -XXX,XX +XXX,XX @@ #define FFA_ABI_BITNUM(id) ((FFA_ABI_ID(id) - FFA_ABI_MIN) << 1 | \ FFA_ABI_CONV(id)) +/* Constituent memory region descriptor */ +struct ffa_address_range { + uint64_t address; + uint32_t page_count; + uint32_t reserved; +}; + +/* Composite memory region descriptor */ +struct ffa_mem_region { + uint32_t total_page_count; + uint32_t address_range_count; + uint64_t reserved; + struct ffa_address_range address_range_array[]; +}; + struct ffa_ctx_notif { bool enabled; @@ -XXX,XX +XXX,XX @@ struct ffa_ctx { struct ffa_ctx_notif notif; /* * tx_lock is used to serialize access to tx - * rx_lock is used to serialize access to rx + * rx_lock is used to serialize access to rx_is_free * lock is used for the rest in this struct */ spinlock_t tx_lock; @@ -XXX,XX +XXX,XX @@ void ffa_rxtx_domain_destroy(struct domain *d); uint32_t ffa_handle_rxtx_map(uint32_t fid, register_t tx_addr, register_t rx_addr, uint32_t page_count); uint32_t ffa_handle_rxtx_unmap(void); -int32_t ffa_handle_rx_release(void); +int32_t ffa_rx_acquire(struct domain *d); +int32_t ffa_rx_release(struct domain *d); void ffa_notif_init(void); void ffa_notif_init_interrupt(void); @@ -XXX,XX +XXX,XX @@ static inline int32_t ffa_simple_call(uint32_t fid, register_t a1, return ffa_get_ret_code(&resp); } -static inline int32_t ffa_rx_release(void) +static inline int32_t ffa_hyp_rx_release(void) { return ffa_simple_call(FFA_RX_RELEASE, 0, 0, 0, 0); } diff --git a/xen/arch/arm/tee/ffa_rxtx.c b/xen/arch/arm/tee/ffa_rxtx.c index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/arm/tee/ffa_rxtx.c +++ b/xen/arch/arm/tee/ffa_rxtx.c @@ -XXX,XX +XXX,XX @@ struct ffa_endpoint_rxtx_descriptor_1_1 { uint32_t tx_region_offs; }; +static int32_t ffa_rxtx_map(paddr_t tx_addr, paddr_t rx_addr, + uint32_t page_count) +{ + return ffa_simple_call(FFA_RXTX_MAP_64, tx_addr, rx_addr, page_count, 0); +} + +static int32_t ffa_rxtx_unmap(uint16_t id) +{ + return ffa_simple_call(FFA_RXTX_UNMAP, ((uint64_t)id)<<16, 0, 0, 0); +} + uint32_t ffa_handle_rxtx_map(uint32_t fid, register_t tx_addr, register_t rx_addr, uint32_t page_count) { @@ -XXX,XX +XXX,XX @@ uint32_t ffa_handle_rxtx_map(uint32_t fid, register_t tx_addr, void *rx; void *tx; + /* The code is considering that we only get one page for now */ + BUILD_BUG_ON(FFA_MAX_RXTX_PAGE_COUNT != 1); + if ( !smccc_is_conv_64(fid) ) { /* @@ -XXX,XX +XXX,XX @@ uint32_t ffa_handle_rxtx_map(uint32_t fid, register_t tx_addr, goto err_put_tx_pg; rx_pg = get_page_from_gfn(d, gfn_x(gaddr_to_gfn(rx_addr)), &t, P2M_ALLOC); - if ( !tx_pg ) + if ( !rx_pg ) goto err_put_tx_pg; /* Only normal RW RAM for now */ @@ -XXX,XX +XXX,XX @@ uint32_t ffa_handle_rxtx_map(uint32_t fid, register_t tx_addr, if ( !rx ) goto err_unmap_tx; + /* + * Transmit the RX/TX buffer information to the SPM if acquire is supported + * as the spec says that if not there is not need to acquire/release/map + * rxtx buffers from the SPMC + */ + if ( ffa_fw_supports_fid(FFA_RX_ACQUIRE) ) + { + struct ffa_endpoint_rxtx_descriptor_1_1 *rxtx_desc; + struct ffa_mem_region *mem_reg; + + /* All must fit in our TX buffer */ + BUILD_BUG_ON(sizeof(*rxtx_desc) + sizeof(*mem_reg) * 2 + + sizeof(struct ffa_address_range) * 2 > + FFA_MAX_RXTX_PAGE_COUNT * FFA_PAGE_SIZE); + + spin_lock(&ffa_tx_buffer_lock); + rxtx_desc = ffa_tx; + + /* + * We have only one page for each so we pack everything: + * - rx region descriptor + * - rx region range + * - tx region descriptor + * - tx region range + */ + rxtx_desc->sender_id = ffa_get_vm_id(d); + rxtx_desc->reserved = 0; + rxtx_desc->rx_region_offs = sizeof(*rxtx_desc); + rxtx_desc->tx_region_offs = sizeof(*rxtx_desc) + + offsetof(struct ffa_mem_region, + address_range_array[1]); + + /* rx buffer */ + mem_reg = ffa_tx + sizeof(*rxtx_desc); + mem_reg->total_page_count = 1; + mem_reg->address_range_count = 1; + mem_reg->reserved = 0; + + mem_reg->address_range_array[0].address = page_to_maddr(rx_pg); + mem_reg->address_range_array[0].page_count = 1; + mem_reg->address_range_array[0].reserved = 0; + + /* tx buffer */ + mem_reg = ffa_tx + rxtx_desc->tx_region_offs; + mem_reg->total_page_count = 1; + mem_reg->address_range_count = 1; + mem_reg->reserved = 0; + + mem_reg->address_range_array[0].address = page_to_maddr(tx_pg); + mem_reg->address_range_array[0].page_count = 1; + mem_reg->address_range_array[0].reserved = 0; + + ret = ffa_rxtx_map(0, 0, 0); + + spin_unlock(&ffa_tx_buffer_lock); + + if ( ret != FFA_RET_OK ) + goto err_unmap_rx; + } + ctx->rx = rx; ctx->tx = tx; ctx->rx_pg = rx_pg; @@ -XXX,XX +XXX,XX @@ uint32_t ffa_handle_rxtx_map(uint32_t fid, register_t tx_addr, ctx->rx_is_free = true; return FFA_RET_OK; +err_unmap_rx: + unmap_domain_page_global(rx); err_unmap_tx: unmap_domain_page_global(tx); err_put_rx_pg: @@ -XXX,XX +XXX,XX @@ err_put_tx_pg: return ret; } -static void rxtx_unmap(struct ffa_ctx *ctx) +static uint32_t rxtx_unmap(struct domain *d) { + struct ffa_ctx *ctx = d->arch.tee; + + if ( !ctx->page_count ) + return FFA_RET_INVALID_PARAMETERS; + + if ( ffa_fw_supports_fid(FFA_RX_ACQUIRE) ) + { + uint32_t ret; + + ret = ffa_rxtx_unmap(ffa_get_vm_id(d)); + if ( ret != FFA_RET_OK ) + return ret; + } + unmap_domain_page_global(ctx->rx); unmap_domain_page_global(ctx->tx); put_page(ctx->rx_pg); @@ -XXX,XX +XXX,XX @@ static void rxtx_unmap(struct ffa_ctx *ctx) ctx->tx_pg = NULL; ctx->page_count = 0; ctx->rx_is_free = false; + + return FFA_RET_OK; } uint32_t ffa_handle_rxtx_unmap(void) { - struct domain *d = current->domain; + return rxtx_unmap(current->domain); +} + +int32_t ffa_rx_acquire(struct domain *d) +{ + int32_t ret = FFA_RET_OK; struct ffa_ctx *ctx = d->arch.tee; - if ( !ctx->rx ) - return FFA_RET_INVALID_PARAMETERS; + spin_lock(&ctx->rx_lock); - rxtx_unmap(ctx); + if ( !ctx->page_count ) + { + ret = FFA_RET_DENIED; + goto out; + } - return FFA_RET_OK; + if ( !ctx->rx_is_free ) + { + ret = FFA_RET_BUSY; + goto out; + } + + if ( ffa_fw_supports_fid(FFA_RX_ACQUIRE) ) + { + ret = ffa_simple_call(FFA_RX_ACQUIRE, ffa_get_vm_id(d), 0, 0, 0); + if ( ret != FFA_RET_OK ) + goto out; + } + ctx->rx_is_free = false; +out: + spin_unlock(&ctx->rx_lock); + + return ret; } -int32_t ffa_handle_rx_release(void) +int32_t ffa_rx_release(struct domain *d) { int32_t ret = FFA_RET_DENIED; - struct domain *d = current->domain; struct ffa_ctx *ctx = d->arch.tee; - if ( !spin_trylock(&ctx->rx_lock) ) - return FFA_RET_BUSY; + spin_lock(&ctx->rx_lock); if ( !ctx->page_count || ctx->rx_is_free ) goto out; + + if ( ffa_fw_supports_fid(FFA_RX_ACQUIRE) ) + { + ret = ffa_simple_call(FFA_RX_RELEASE, ffa_get_vm_id(d), 0, 0, 0); + if ( ret != FFA_RET_OK ) + goto out; + } ret = FFA_RET_OK; ctx->rx_is_free = true; out: @@ -XXX,XX +XXX,XX @@ out: return ret; } -static int32_t ffa_rxtx_map(paddr_t tx_addr, paddr_t rx_addr, - uint32_t page_count) -{ - return ffa_simple_call(FFA_RXTX_MAP_64, tx_addr, rx_addr, page_count, 0); -} - -static int32_t ffa_rxtx_unmap(void) -{ - return ffa_simple_call(FFA_RXTX_UNMAP, 0, 0, 0, 0); -} - void ffa_rxtx_domain_destroy(struct domain *d) { - struct ffa_ctx *ctx = d->arch.tee; - - if ( ctx->rx ) - rxtx_unmap(ctx); + rxtx_unmap(d); } void ffa_rxtx_destroy(void) @@ -XXX,XX +XXX,XX @@ void ffa_rxtx_destroy(void) } if ( need_unmap ) - ffa_rxtx_unmap(); + ffa_rxtx_unmap(0); } bool ffa_rxtx_init(void) diff --git a/xen/arch/arm/tee/ffa_shm.c b/xen/arch/arm/tee/ffa_shm.c index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/arm/tee/ffa_shm.c +++ b/xen/arch/arm/tee/ffa_shm.c @@ -XXX,XX +XXX,XX @@ #include "ffa_private.h" -/* Constituent memory region descriptor */ -struct ffa_address_range { - uint64_t address; - uint32_t page_count; - uint32_t reserved; -}; - -/* Composite memory region descriptor */ -struct ffa_mem_region { - uint32_t total_page_count; - uint32_t address_range_count; - uint64_t reserved; - struct ffa_address_range address_range_array[]; -}; - /* Memory access permissions descriptor */ struct ffa_mem_access_perm { uint16_t endpoint_id; -- 2.47.0
Move the direct message handling function in its own source file and rename it to have a ffa_ prefix. This is a preparation to add support for indirect messages which will go into this newly created source file. Signed-off-by: Bertrand Marquis <bertrand.marquis@arm.com> Reviewed-by: Jens Wiklander <jens.wiklander@linaro.org> --- Changes in v3: - add Jens R-b Changes in v2: - rebase --- xen/arch/arm/tee/Makefile | 1 + xen/arch/arm/tee/ffa.c | 69 +---------------------------- xen/arch/arm/tee/ffa_msg.c | 80 ++++++++++++++++++++++++++++++++++ xen/arch/arm/tee/ffa_private.h | 2 + 4 files changed, 84 insertions(+), 68 deletions(-) create mode 100644 xen/arch/arm/tee/ffa_msg.c diff --git a/xen/arch/arm/tee/Makefile b/xen/arch/arm/tee/Makefile index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/arm/tee/Makefile +++ b/xen/arch/arm/tee/Makefile @@ -XXX,XX +XXX,XX @@ obj-$(CONFIG_FFA) += ffa_shm.o obj-$(CONFIG_FFA) += ffa_partinfo.o obj-$(CONFIG_FFA) += ffa_rxtx.o obj-$(CONFIG_FFA) += ffa_notif.o +obj-$(CONFIG_FFA) += ffa_msg.o obj-y += tee.o obj-$(CONFIG_OPTEE) += optee.o diff --git a/xen/arch/arm/tee/ffa.c b/xen/arch/arm/tee/ffa.c index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/arm/tee/ffa.c +++ b/xen/arch/arm/tee/ffa.c @@ -XXX,XX +XXX,XX @@ static void handle_version(struct cpu_user_regs *regs) ffa_set_regs(regs, FFA_MY_VERSION, 0, 0, 0, 0, 0, 0, 0); } -static void handle_msg_send_direct_req(struct cpu_user_regs *regs, uint32_t fid) -{ - struct arm_smccc_1_2_regs arg = { .a0 = fid, }; - struct arm_smccc_1_2_regs resp = { }; - struct domain *d = current->domain; - uint32_t src_dst; - uint64_t mask; - - if ( smccc_is_conv_64(fid) ) - mask = GENMASK_ULL(63, 0); - else - mask = GENMASK_ULL(31, 0); - - if ( !ffa_fw_supports_fid(fid) ) - { - resp.a0 = FFA_ERROR; - resp.a2 = FFA_RET_NOT_SUPPORTED; - goto out; - } - - src_dst = get_user_reg(regs, 1); - if ( (src_dst >> 16) != ffa_get_vm_id(d) ) - { - resp.a0 = FFA_ERROR; - resp.a2 = FFA_RET_INVALID_PARAMETERS; - goto out; - } - - /* we do not support direct messages to VMs */ - if ( !FFA_ID_IS_SECURE(src_dst & GENMASK(15,0)) ) - { - resp.a0 = FFA_ERROR; - resp.a2 = FFA_RET_NOT_SUPPORTED; - goto out; - } - - arg.a1 = src_dst; - arg.a2 = get_user_reg(regs, 2) & mask; - arg.a3 = get_user_reg(regs, 3) & mask; - arg.a4 = get_user_reg(regs, 4) & mask; - arg.a5 = get_user_reg(regs, 5) & mask; - arg.a6 = get_user_reg(regs, 6) & mask; - arg.a7 = get_user_reg(regs, 7) & mask; - - arm_smccc_1_2_smc(&arg, &resp); - switch ( resp.a0 ) - { - case FFA_ERROR: - case FFA_SUCCESS_32: - case FFA_SUCCESS_64: - case FFA_MSG_SEND_DIRECT_RESP_32: - case FFA_MSG_SEND_DIRECT_RESP_64: - break; - default: - /* Bad fid, report back to the caller. */ - memset(&resp, 0, sizeof(resp)); - resp.a0 = FFA_ERROR; - resp.a1 = src_dst; - resp.a2 = FFA_RET_ABORTED; - } - -out: - ffa_set_regs(regs, resp.a0, resp.a1 & mask, resp.a2 & mask, resp.a3 & mask, - resp.a4 & mask, resp.a5 & mask, resp.a6 & mask, - resp.a7 & mask); -} - static void handle_features(struct cpu_user_regs *regs) { struct domain *d = current->domain; @@ -XXX,XX +XXX,XX @@ static bool ffa_handle_call(struct cpu_user_regs *regs) break; case FFA_MSG_SEND_DIRECT_REQ_32: case FFA_MSG_SEND_DIRECT_REQ_64: - handle_msg_send_direct_req(regs, fid); + ffa_handle_msg_send_direct_req(regs, fid); return true; case FFA_MEM_SHARE_32: case FFA_MEM_SHARE_64: diff --git a/xen/arch/arm/tee/ffa_msg.c b/xen/arch/arm/tee/ffa_msg.c new file mode 100644 index XXXXXXX..XXXXXXX --- /dev/null +++ b/xen/arch/arm/tee/ffa_msg.c @@ -XXX,XX +XXX,XX @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (C) 2024 Linaro Limited + */ + +#include <xen/const.h> +#include <xen/sizes.h> +#include <xen/types.h> + +#include <asm/smccc.h> +#include <asm/regs.h> + +#include "ffa_private.h" + +void ffa_handle_msg_send_direct_req(struct cpu_user_regs *regs, uint32_t fid) +{ + struct arm_smccc_1_2_regs arg = { .a0 = fid, }; + struct arm_smccc_1_2_regs resp = { }; + struct domain *d = current->domain; + uint32_t src_dst; + uint64_t mask; + + if ( smccc_is_conv_64(fid) ) + mask = GENMASK_ULL(63, 0); + else + mask = GENMASK_ULL(31, 0); + + if ( !ffa_fw_supports_fid(fid) ) + { + resp.a0 = FFA_ERROR; + resp.a2 = FFA_RET_NOT_SUPPORTED; + goto out; + } + + src_dst = get_user_reg(regs, 1); + if ( (src_dst >> 16) != ffa_get_vm_id(d) ) + { + resp.a0 = FFA_ERROR; + resp.a2 = FFA_RET_INVALID_PARAMETERS; + goto out; + } + + /* we do not support direct messages to VMs */ + if ( !FFA_ID_IS_SECURE(src_dst & GENMASK(15,0)) ) + { + resp.a0 = FFA_ERROR; + resp.a2 = FFA_RET_NOT_SUPPORTED; + goto out; + } + + arg.a1 = src_dst; + arg.a2 = get_user_reg(regs, 2) & mask; + arg.a3 = get_user_reg(regs, 3) & mask; + arg.a4 = get_user_reg(regs, 4) & mask; + arg.a5 = get_user_reg(regs, 5) & mask; + arg.a6 = get_user_reg(regs, 6) & mask; + arg.a7 = get_user_reg(regs, 7) & mask; + + arm_smccc_1_2_smc(&arg, &resp); + switch ( resp.a0 ) + { + case FFA_ERROR: + case FFA_SUCCESS_32: + case FFA_SUCCESS_64: + case FFA_MSG_SEND_DIRECT_RESP_32: + case FFA_MSG_SEND_DIRECT_RESP_64: + break; + default: + /* Bad fid, report back to the caller. */ + memset(&resp, 0, sizeof(resp)); + resp.a0 = FFA_ERROR; + resp.a1 = src_dst; + resp.a2 = FFA_RET_ABORTED; + } + +out: + ffa_set_regs(regs, resp.a0, resp.a1 & mask, resp.a2 & mask, resp.a3 & mask, + resp.a4 & mask, resp.a5 & mask, resp.a6 & mask, + resp.a7 & mask); +} diff --git a/xen/arch/arm/tee/ffa_private.h b/xen/arch/arm/tee/ffa_private.h index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/arm/tee/ffa_private.h +++ b/xen/arch/arm/tee/ffa_private.h @@ -XXX,XX +XXX,XX @@ void ffa_handle_notification_info_get(struct cpu_user_regs *regs); void ffa_handle_notification_get(struct cpu_user_regs *regs); int ffa_handle_notification_set(struct cpu_user_regs *regs); +void ffa_handle_msg_send_direct_req(struct cpu_user_regs *regs, uint32_t fid); + static inline uint16_t ffa_get_vm_id(const struct domain *d) { /* +1 since 0 is reserved for the hypervisor in FF-A */ -- 2.47.0
Remove the per VM flag to store if notifications are enabled or not as the only case where they are not, if notifications are enabled globally, will make the VM creation fail. Also use the opportunity to always give the notifications interrupts IDs to VM. If the firmware does not support notifications, there won't be any generated and setting one will give back a NOT_SUPPORTED. Signed-off-by: Bertrand Marquis <bertrand.marquis@arm.com> --- Changes in v3: - Add a comment explaining why it is ok to call bitmap destroy even if bitmap create failed. Changes in v2: - rebase --- xen/arch/arm/tee/ffa.c | 17 +++-------------- xen/arch/arm/tee/ffa_notif.c | 14 +++++--------- xen/arch/arm/tee/ffa_private.h | 2 -- 3 files changed, 8 insertions(+), 25 deletions(-) diff --git a/xen/arch/arm/tee/ffa.c b/xen/arch/arm/tee/ffa.c index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/arm/tee/ffa.c +++ b/xen/arch/arm/tee/ffa.c @@ -XXX,XX +XXX,XX @@ static void handle_version(struct cpu_user_regs *regs) static void handle_features(struct cpu_user_regs *regs) { - struct domain *d = current->domain; - struct ffa_ctx *ctx = d->arch.tee; uint32_t a1 = get_user_reg(regs, 1); unsigned int n; @@ -XXX,XX +XXX,XX @@ static void handle_features(struct cpu_user_regs *regs) ffa_set_regs_success(regs, 0, 0); break; case FFA_FEATURE_NOTIF_PEND_INTR: - if ( ctx->notif.enabled ) - ffa_set_regs_success(regs, GUEST_FFA_NOTIF_PEND_INTR_ID, 0); - else - ffa_set_regs_error(regs, FFA_RET_NOT_SUPPORTED); + ffa_set_regs_success(regs, GUEST_FFA_NOTIF_PEND_INTR_ID, 0); break; case FFA_FEATURE_SCHEDULE_RECV_INTR: - if ( ctx->notif.enabled ) - ffa_set_regs_success(regs, GUEST_FFA_SCHEDULE_RECV_INTR_ID, 0); - else - ffa_set_regs_error(regs, FFA_RET_NOT_SUPPORTED); + ffa_set_regs_success(regs, GUEST_FFA_SCHEDULE_RECV_INTR_ID, 0); break; case FFA_NOTIFICATION_BIND: @@ -XXX,XX +XXX,XX @@ static void handle_features(struct cpu_user_regs *regs) case FFA_NOTIFICATION_SET: case FFA_NOTIFICATION_INFO_GET_32: case FFA_NOTIFICATION_INFO_GET_64: - if ( ctx->notif.enabled ) - ffa_set_regs_success(regs, 0, 0); - else - ffa_set_regs_error(regs, FFA_RET_NOT_SUPPORTED); + ffa_set_regs_success(regs, 0, 0); break; default: ffa_set_regs_error(regs, FFA_RET_NOT_SUPPORTED); diff --git a/xen/arch/arm/tee/ffa_notif.c b/xen/arch/arm/tee/ffa_notif.c index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/arm/tee/ffa_notif.c +++ b/xen/arch/arm/tee/ffa_notif.c @@ -XXX,XX +XXX,XX @@ void ffa_notif_init(void) int ffa_notif_domain_init(struct domain *d) { - struct ffa_ctx *ctx = d->arch.tee; int32_t res; if ( !notif_enabled ) @@ -XXX,XX +XXX,XX @@ int ffa_notif_domain_init(struct domain *d) if ( res ) return -ENOMEM; - ctx->notif.enabled = true; - return 0; } void ffa_notif_domain_destroy(struct domain *d) { - struct ffa_ctx *ctx = d->arch.tee; - - if ( ctx->notif.enabled ) - { + /* + * Call bitmap_destroy even if bitmap create failed as the SPMC will + * return a DENIED error that we will ignore. + */ + if ( notif_enabled ) ffa_notification_bitmap_destroy(ffa_get_vm_id(d)); - ctx->notif.enabled = false; - } } diff --git a/xen/arch/arm/tee/ffa_private.h b/xen/arch/arm/tee/ffa_private.h index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/arm/tee/ffa_private.h +++ b/xen/arch/arm/tee/ffa_private.h @@ -XXX,XX +XXX,XX @@ struct ffa_mem_region { }; struct ffa_ctx_notif { - bool enabled; - /* * True if domain is reported by FFA_NOTIFICATION_INFO_GET to have * pending global notifications. -- 2.47.0
Add support for FFA_MSG_SEND2 to send indirect messages from a VM to a secure partition. Signed-off-by: Bertrand Marquis <bertrand.marquis@arm.com> --- Changes in v3: - in ffa_handle_msg_send2 use ffa_get_vm_id instead of a local variable to make sure that we use the right VM ID as source without having a potential solution for the VM to give a wrong identity. Changes in v2: - rebase --- xen/arch/arm/tee/ffa.c | 5 ++++ xen/arch/arm/tee/ffa_msg.c | 50 ++++++++++++++++++++++++++++++++++ xen/arch/arm/tee/ffa_private.h | 1 + 3 files changed, 56 insertions(+) diff --git a/xen/arch/arm/tee/ffa.c b/xen/arch/arm/tee/ffa.c index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/arm/tee/ffa.c +++ b/xen/arch/arm/tee/ffa.c @@ -XXX,XX +XXX,XX @@ static const struct ffa_fw_abi ffa_fw_abi_needed[] = { FW_ABI(FFA_MEM_RECLAIM), FW_ABI(FFA_MSG_SEND_DIRECT_REQ_32), FW_ABI(FFA_MSG_SEND_DIRECT_REQ_64), + FW_ABI(FFA_MSG_SEND2), }; /* @@ -XXX,XX +XXX,XX @@ static void handle_features(struct cpu_user_regs *regs) case FFA_PARTITION_INFO_GET: case FFA_MSG_SEND_DIRECT_REQ_32: case FFA_MSG_SEND_DIRECT_REQ_64: + case FFA_MSG_SEND2: ffa_set_regs_success(regs, 0, 0); break; case FFA_MEM_SHARE_64: @@ -XXX,XX +XXX,XX @@ static bool ffa_handle_call(struct cpu_user_regs *regs) case FFA_MSG_SEND_DIRECT_REQ_64: ffa_handle_msg_send_direct_req(regs, fid); return true; + case FFA_MSG_SEND2: + e = ffa_handle_msg_send2(regs); + break; case FFA_MEM_SHARE_32: case FFA_MEM_SHARE_64: ffa_handle_mem_share(regs); diff --git a/xen/arch/arm/tee/ffa_msg.c b/xen/arch/arm/tee/ffa_msg.c index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/arm/tee/ffa_msg.c +++ b/xen/arch/arm/tee/ffa_msg.c @@ -XXX,XX +XXX,XX @@ #include "ffa_private.h" +/* Encoding of partition message in RX/TX buffer */ +struct ffa_part_msg_rxtx { + uint32_t flags; + uint32_t reserved; + uint32_t msg_offset; + uint32_t send_recv_id; + uint32_t msg_size; +}; + void ffa_handle_msg_send_direct_req(struct cpu_user_regs *regs, uint32_t fid) { struct arm_smccc_1_2_regs arg = { .a0 = fid, }; @@ -XXX,XX +XXX,XX @@ out: resp.a4 & mask, resp.a5 & mask, resp.a6 & mask, resp.a7 & mask); } + +int32_t ffa_handle_msg_send2(struct cpu_user_regs *regs) +{ + struct domain *src_d = current->domain; + struct ffa_ctx *src_ctx = src_d->arch.tee; + const struct ffa_part_msg_rxtx *src_msg; + uint16_t dst_id, src_id; + int32_t ret; + + if ( !ffa_fw_supports_fid(FFA_MSG_SEND2) ) + return FFA_RET_NOT_SUPPORTED; + + if ( !spin_trylock(&src_ctx->tx_lock) ) + return FFA_RET_BUSY; + + src_msg = src_ctx->tx; + src_id = src_msg->send_recv_id >> 16; + dst_id = src_msg->send_recv_id & GENMASK(15,0); + + if ( src_id != ffa_get_vm_id(src_d) || !FFA_ID_IS_SECURE(dst_id) ) + { + ret = FFA_RET_INVALID_PARAMETERS; + goto out_unlock_tx; + } + + /* check source message fits in buffer */ + if ( src_ctx->page_count * FFA_PAGE_SIZE < + src_msg->msg_offset + src_msg->msg_size || + src_msg->msg_offset < sizeof(struct ffa_part_msg_rxtx) ) + { + ret = FFA_RET_INVALID_PARAMETERS; + goto out_unlock_tx; + } + + ret = ffa_simple_call(FFA_MSG_SEND2, + ((uint32_t)ffa_get_vm_id(src_d)) << 16, 0, 0, 0); + +out_unlock_tx: + spin_unlock(&src_ctx->tx_lock); + return ret; +} diff --git a/xen/arch/arm/tee/ffa_private.h b/xen/arch/arm/tee/ffa_private.h index XXXXXXX..XXXXXXX 100644 --- a/xen/arch/arm/tee/ffa_private.h +++ b/xen/arch/arm/tee/ffa_private.h @@ -XXX,XX +XXX,XX @@ void ffa_handle_notification_get(struct cpu_user_regs *regs); int ffa_handle_notification_set(struct cpu_user_regs *regs); void ffa_handle_msg_send_direct_req(struct cpu_user_regs *regs, uint32_t fid); +int32_t ffa_handle_msg_send2(struct cpu_user_regs *regs); static inline uint16_t ffa_get_vm_id(const struct domain *d) { -- 2.47.0