[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] Re: [PATCH v5 2/6] xen/arm: ffa: Rework partinfo_get implementation
Hi Bertrand, On Wed, Apr 16, 2025 at 9:40 AM Bertrand Marquis <bertrand.marquis@xxxxxxx> wrote: > > This patch is in preparation for VM to VM support in order to do the > changes on the SP handling part of partinfo_get before adding support > for the VM part. > > This patches is doing the following changes: > - split partinfo_get into 3 functions to have the locking handling and > proper exit on error handled more clearly > - add some potential overflow checks to validate the offset and sizes > passed by the VM on partinfo call. > - Introduce a maximum number of SPs (for now set to 64) to prevent > holding the CPU for too long in case there would be a lot of > partitions in the secure world. The limit currently set is thought to > be realistic for most use cases as 64 secure partitions is a very high > number compared to current seen usage (more 3 or 4). > - fix include ordering in ffa_private.h to be in alphabetic order > > Signed-off-by: Bertrand Marquis <bertrand.marquis@xxxxxxx> > --- > Changes in v5: > - patch added > --- > xen/arch/arm/tee/ffa_partinfo.c | 201 +++++++++++++++++++------------- > xen/arch/arm/tee/ffa_private.h | 18 ++- > 2 files changed, 131 insertions(+), 88 deletions(-) > > diff --git a/xen/arch/arm/tee/ffa_partinfo.c b/xen/arch/arm/tee/ffa_partinfo.c > index c0510ceb8338..e524445c6fb8 100644 > --- a/xen/arch/arm/tee/ffa_partinfo.c > +++ b/xen/arch/arm/tee/ffa_partinfo.c > @@ -63,9 +63,95 @@ static int32_t ffa_partition_info_get(uint32_t *uuid, > uint32_t flags, > return ret; > } > > -void ffa_handle_partition_info_get(struct cpu_user_regs *regs) > +static int32_t ffa_get_sp_count(uint32_t *uuid, uint32_t *sp_count) > +{ > + uint32_t src_size; > + > + return ffa_partition_info_get(uuid, FFA_PARTITION_INFO_GET_COUNT_FLAG, > + sp_count, &src_size); > +} > + > +static int32_t ffa_get_sp_partinfo(uint32_t *uuid, uint32_t *sp_count, > + void *dst_buf, void *end_buf, > + uint32_t dst_size) > { > int32_t ret; > + uint32_t src_size, real_sp_count; > + void *src_buf = ffa_rx; > + uint32_t count = 0; > + > + /* Do we have a RX buffer with the SPMC */ > + if ( !ffa_rx ) > + return FFA_RET_DENIED; > + > + /* We need to use the RX buffer to receive the list */ > + spin_lock(&ffa_rx_buffer_lock); > + > + ret = ffa_partition_info_get(uuid, 0, &real_sp_count, &src_size); > + if ( ret ) > + goto out; > + > + /* We now own the RX buffer */ > + > + /* Validate the src_size we got */ > + if ( src_size < sizeof(struct ffa_partition_info_1_0) || > + src_size >= FFA_PAGE_SIZE ) > + { > + ret = FFA_RET_NOT_SUPPORTED; > + goto out_release; > + } > + > + /* > + * Limit the maximum time we hold the CPU by limiting the number of SPs. > + * We just ignore the extra ones as this is tested during init in > + * ffa_partinfo_init so the only possible reason is SP have been added > + * since boot. > + */ > + if ( real_sp_count > FFA_MAX_NUM_SP ) > + real_sp_count = FFA_MAX_NUM_SP; > + > + /* Make sure the data fits in our buffer */ > + if ( real_sp_count > (FFA_RXTX_PAGE_COUNT * FFA_PAGE_SIZE) / src_size ) > + { > + ret = FFA_RET_NOT_SUPPORTED; > + goto out_release; > + } > + > + for ( uint32_t sp_num = 0; sp_num < real_sp_count; sp_num++ ) > + { > + 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) ) > + { > + if ( dst_buf > (end_buf - dst_size) ) > + { > + ret = FFA_RET_NO_MEMORY; > + goto out_release; > + } > + > + memcpy(dst_buf, src_buf, MIN(src_size, dst_size)); > + if ( dst_size > src_size ) > + memset(dst_buf + src_size, 0, dst_size - src_size); > + > + dst_buf += dst_size; > + count++; > + } > + > + src_buf += src_size; > + } > + > + *sp_count = count; > + > +out_release: > + ffa_hyp_rx_release(); > +out: > + spin_unlock(&ffa_rx_buffer_lock); > + return ret; > +} Please add an empty line before the next function. With that fixed: Reviewed-by: Jens Wiklander <jens.wiklander@xxxxxxxxxx> Cheers, Jens > +void ffa_handle_partition_info_get(struct cpu_user_regs *regs) > +{ > + int32_t ret = FFA_RET_OK; > struct domain *d = current->domain; > struct ffa_ctx *ctx = d->arch.tee; > uint32_t flags = get_user_reg(regs, 5); > @@ -75,8 +161,8 @@ void ffa_handle_partition_info_get(struct cpu_user_regs > *regs) > get_user_reg(regs, 3), > get_user_reg(regs, 4), > }; > - uint32_t src_size, dst_size; > - void *dst_buf; > + uint32_t dst_size = 0; > + void *dst_buf, *end_buf; > uint32_t ffa_sp_count = 0; > > /* > @@ -89,31 +175,26 @@ void ffa_handle_partition_info_get(struct cpu_user_regs > *regs) > else > dst_size = sizeof(struct ffa_partition_info_1_1); > > - /* > - * FF-A v1.0 has w5 MBZ while v1.1 allows > - * FFA_PARTITION_INFO_GET_COUNT_FLAG to be non-zero. > - * > - * FFA_PARTITION_INFO_GET_COUNT is only using registers and not the > - * rxtx buffer so do the partition_info_get directly. > - */ > - if ( flags == FFA_PARTITION_INFO_GET_COUNT_FLAG && > - ctx->guest_vers == FFA_VERSION_1_1 ) > + /* Only count requested */ > + if ( flags ) > { > + /* > + * FF-A v1.0 has w5 MBZ while v1.1 allows > + * FFA_PARTITION_INFO_GET_COUNT_FLAG to be non-zero. > + */ > + if ( ctx->guest_vers == FFA_VERSION_1_0 || > + flags != FFA_PARTITION_INFO_GET_COUNT_FLAG ) > + { > + ret = FFA_RET_INVALID_PARAMETERS; > + goto out; > + } > + > if ( ffa_fw_supports_fid(FFA_PARTITION_INFO_GET) ) > - ret = ffa_partition_info_get(uuid, flags, &ffa_sp_count, > - &src_size); > - else > - ret = FFA_RET_OK; > + ret = ffa_get_sp_count(uuid, &ffa_sp_count); > > goto out; > } > > - if ( flags ) > - { > - ret = FFA_RET_INVALID_PARAMETERS; > - goto out; > - } > - > if ( !ffa_fw_supports_fid(FFA_PARTITION_INFO_GET) ) > { > /* Just give an empty partition list to the caller */ > @@ -121,80 +202,33 @@ void ffa_handle_partition_info_get(struct cpu_user_regs > *regs) > goto out; > } > > + /* Get the RX buffer to write the list of partitions */ > ret = ffa_rx_acquire(d); > if ( ret != FFA_RET_OK ) > goto out; > > dst_buf = ctx->rx; > + end_buf = ctx->rx + ctx->page_count * FFA_PAGE_SIZE; > > - if ( !ffa_rx ) > - { > - 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_hyp_unlock; > + /* An entry should be smaller than a page */ > + BUILD_BUG_ON(sizeof(struct ffa_partition_info_1_1) > FFA_PAGE_SIZE); > > /* > - * ffa_partition_info_get() succeeded so we now own the RX buffer we > - * share with the SPMC. We must give it back using ffa_hyp_rx_release() > - * once we've copied the content. > + * Check for overflow and that we can at least store one entry. > + * page_count cannot be 0 so we have at least one page. > */ > - > - /* we cannot have a size smaller than 1.0 structure */ > - if ( src_size < sizeof(struct ffa_partition_info_1_0) ) > - { > - ret = FFA_RET_NOT_SUPPORTED; > - goto out_rx_hyp_release; > - } > - > - if ( ctx->page_count * FFA_PAGE_SIZE < ffa_sp_count * dst_size ) > + if ( dst_buf >= end_buf || dst_buf > (end_buf - dst_size) ) > { > - ret = FFA_RET_NO_MEMORY; > - goto out_rx_hyp_release; > + ret = FFA_RET_INVALID_PARAMETERS; > + goto out_rx_release; > } > > - if ( ffa_sp_count > 0 ) > - { > - uint32_t n, n_limit = ffa_sp_count; > - void *src_buf = ffa_rx; > - > - /* copy the secure partitions info */ > - for ( n = 0; n < n_limit; n++ ) > - { > - 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--; > + ret = ffa_get_sp_partinfo(uuid, &ffa_sp_count, dst_buf, end_buf, > + dst_size); > > - src_buf += src_size; > - } > - } > > -out_rx_hyp_release: > - ffa_hyp_rx_release(); > -out_rx_hyp_unlock: > - spin_unlock(&ffa_rx_buffer_lock); > out_rx_release: > - /* > - * The calling VM RX buffer only contains data to be used by the VM if > the > - * call was successful, 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 ) > + if ( ret ) > ffa_rx_release(d); > out: > if ( ret ) > @@ -353,9 +387,10 @@ bool ffa_partinfo_init(void) > goto out; > } > > - if ( count >= UINT16_MAX ) > + if ( count >= FFA_MAX_NUM_SP ) > { > - printk(XENLOG_ERR "ffa: Impossible number of SPs: %u\n", count); > + printk(XENLOG_ERR "ffa: More SPs than the maximum supported: %u - > %u\n", > + count, FFA_MAX_NUM_SP); > goto out; > } > > diff --git a/xen/arch/arm/tee/ffa_private.h b/xen/arch/arm/tee/ffa_private.h > index c4cd65538908..0a9c1082db28 100644 > --- a/xen/arch/arm/tee/ffa_private.h > +++ b/xen/arch/arm/tee/ffa_private.h > @@ -6,15 +6,15 @@ > #ifndef __FFA_PRIVATE_H__ > #define __FFA_PRIVATE_H__ > > +#include <xen/bitmap.h> > #include <xen/const.h> > -#include <xen/sizes.h> > -#include <xen/types.h> > -#include <xen/mm.h> > #include <xen/list.h> > -#include <xen/spinlock.h> > +#include <xen/mm.h> > #include <xen/sched.h> > +#include <xen/sizes.h> > +#include <xen/spinlock.h> > #include <xen/time.h> > -#include <xen/bitmap.h> > +#include <xen/types.h> > > /* Error codes */ > #define FFA_RET_OK 0 > @@ -108,6 +108,14 @@ > */ > #define FFA_CTX_TEARDOWN_DELAY SECONDS(1) > > +/* > + * The maximum number of Secure partitions we support for partinfo_get. > + * This prevents holding the CPU during potentially to long time during > + * a partinfo_get call. Value choosen seems realistic for any configuration > + * but can be incremented here if needed. > + */ > +#define FFA_MAX_NUM_SP 64 > + > /* > * We rely on the convention suggested but not mandated by the FF-A > * specification that secure world endpoint identifiers have the bit 15 > -- > 2.47.1 >
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |