|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [PATCH 06/10] xen/arm: ffa: add UUID helpers for partition info
Introduce struct ffa_uuid together with nil/equality/set helpers, and
use it end-to-end in the partition-info plumbing.
The SP and VM enumeration paths now build UUIDs from the guest
registers, call a new ffa_copy_info() helper and ensure non-nil UUID
queries only return matching SP entries, relying on firmware UUID
filtering. VM entries are skipped because we do not track per-VM UUIDs.
Count requests and subscriber initialisation are updated accordingly so
firmware is always called with an explicit UUID. This keeps count and
listing requests aligned with the FF-A v1.1 rules while preserving the
Linux compatibility workaround for v1.2 requesters.
Signed-off-by: Bertrand Marquis <bertrand.marquis@xxxxxxx>
---
xen/arch/arm/tee/ffa_partinfo.c | 206 ++++++++++++++++++++------------
xen/arch/arm/tee/ffa_private.h | 21 ++++
2 files changed, 152 insertions(+), 75 deletions(-)
diff --git a/xen/arch/arm/tee/ffa_partinfo.c b/xen/arch/arm/tee/ffa_partinfo.c
index 3f4a779f4146..4adbe2736c94 100644
--- a/xen/arch/arm/tee/ffa_partinfo.c
+++ b/xen/arch/arm/tee/ffa_partinfo.c
@@ -33,7 +33,7 @@ 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 *uuid, uint32_t flags,
+static int32_t ffa_partition_info_get(struct ffa_uuid uuid, uint32_t flags,
uint32_t *count, uint32_t *fpi_size)
{
struct arm_smccc_1_2_regs arg = {
@@ -41,15 +41,12 @@ static int32_t ffa_partition_info_get(uint32_t *uuid,
uint32_t flags,
.a5 = flags,
};
struct arm_smccc_1_2_regs resp;
- uint32_t ret;
+ int32_t ret;
- if ( uuid )
- {
- arg.a1 = uuid[0];
- arg.a2 = uuid[1];
- arg.a3 = uuid[2];
- arg.a4 = uuid[3];
- }
+ arg.a1 = uuid.val[0] & 0xFFFFFFFFU;
+ arg.a2 = (uuid.val[0] >> 32) & 0xFFFFFFFFU;
+ arg.a3 = uuid.val[1] & 0xFFFFFFFFU;
+ arg.a4 = (uuid.val[1] >> 32) & 0xFFFFFFFFU;
arm_smccc_1_2_smc(&arg, &resp);
@@ -63,7 +60,26 @@ static int32_t ffa_partition_info_get(uint32_t *uuid,
uint32_t flags,
return ret;
}
-static int32_t ffa_get_sp_count(uint32_t *uuid, uint32_t *sp_count)
+static int32_t ffa_copy_info(void **dst, void *dst_end, const void *src,
+ uint32_t dst_size, uint32_t src_size)
+{
+ uint8_t *pos = *dst;
+ uint8_t *end = dst_end;
+
+ if ( pos > end - dst_size )
+ return FFA_RET_NO_MEMORY;
+
+ memcpy(pos, src, MIN(dst_size, src_size));
+
+ if ( dst_size > src_size )
+ memset(pos + src_size, 0, dst_size - src_size);
+
+ *dst = pos + dst_size;
+
+ return FFA_RET_OK;
+}
+
+static int32_t ffa_get_sp_count(struct ffa_uuid uuid, uint32_t *sp_count)
{
uint32_t src_size;
@@ -71,8 +87,8 @@ static int32_t ffa_get_sp_count(uint32_t *uuid, uint32_t
*sp_count)
sp_count, &src_size);
}
-static int32_t ffa_get_sp_partinfo(uint32_t *uuid, uint32_t *sp_count,
- void *dst_buf, void *end_buf,
+static int32_t ffa_get_sp_partinfo(struct ffa_uuid uuid, uint32_t *sp_count,
+ void **dst_buf, void *end_buf,
uint32_t dst_size)
{
int32_t ret;
@@ -120,17 +136,18 @@ static int32_t ffa_get_sp_partinfo(uint32_t *uuid,
uint32_t *sp_count,
/* 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;
- }
+ /*
+ * If VM is 1.0 but firmware is 1.1 we could have several entries
+ * with the same ID but different UUIDs. In this case the VM will
+ * get a list with several time the same ID.
+ * This is a non-compliance to the specification but 1.0 VMs should
+ * handle that on their own to simplify Xen implementation.
+ */
- 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);
+ ret = ffa_copy_info(dst_buf, end_buf, src_buf, dst_size, src_size);
+ if ( ret )
+ goto out;
- dst_buf += dst_size;
count++;
}
@@ -144,69 +161,89 @@ out:
return ret;
}
-static int32_t ffa_get_vm_partinfo(uint32_t *vm_count, void *dst_buf,
- void *end_buf, uint32_t dst_size)
+static int32_t ffa_get_vm_partinfo(struct ffa_uuid uuid, uint32_t *vm_count,
+ void **dst_buf, void *end_buf,
+ uint32_t dst_size)
{
struct ffa_ctx *curr_ctx = current->domain->arch.tee;
struct ffa_ctx *dest_ctx;
uint32_t count = 0;
int32_t ret = FFA_RET_OK;
+ /*
+ * We do not have UUID info for VMs so use the 1.0 structure so that we set
+ * UUIDs to zero using memset
+ */
+ struct ffa_partition_info_1_0 info;
/*
- * There could potentially be a lot of VMs in the system and we could
- * hold the CPU for long here.
- * Right now there is no solution in FF-A specification to split
- * the work in this case.
- * TODO: Check how we could delay the work or have preemption checks.
+ * We do not have protocol UUIDs for VMs so if a request has non Nil UUID
+ * we must return an empty list.
*/
- read_lock(&ffa_ctx_list_rwlock);
- list_for_each_entry(dest_ctx, &ffa_ctx_head, ctx_list)
+ if ( !ffa_uuid_is_nil(uuid) )
+ {
+ *vm_count = 0;
+ return FFA_RET_OK;
+ }
+
+ /*
+ * Workaround for Linux FF-A Driver not accepting to have its own
+ * entry in the list before FF-A v1.2 was supported.
+ * This workaround is generally acceptable for other implementations
+ * as the specification was not completely clear on wether or not
+ * the requester endpoint information should be included or not
+ */
+ if ( curr_ctx->guest_vers >= FFA_VERSION_1_2 )
+ {
+ /* Add caller VM information */
+ info.id = curr_ctx->ffa_id;
+ info.execution_context = curr_ctx->num_vcpus;
+ info.partition_properties = FFA_PART_VM_PROP;
+ if ( curr_ctx->is_64bit )
+ info.partition_properties |= FFA_PART_PROP_AARCH64_STATE;
+
+ ret = ffa_copy_info(dst_buf, end_buf, &info, dst_size, sizeof(info));
+ if ( ret )
+ return ret;
+
+ count++;
+ }
+
+ if ( IS_ENABLED(CONFIG_FFA_VM_TO_VM) )
{
/*
- * Do not include an entry for the caller VM as the spec is not
- * clearly mandating it and it is not supported by Linux.
+ * There could potentially be a lot of VMs in the system and we could
+ * hold the CPU for long here.
+ * Right now there is no solution in FF-A specification to split
+ * the work in this case.
+ * TODO: Check how we could delay the work or have preemption checks.
*/
- if ( dest_ctx != curr_ctx )
+ read_lock(&ffa_ctx_list_rwlock);
+ list_for_each_entry(dest_ctx, &ffa_ctx_head, ctx_list)
{
- /*
- * We do not have UUID info for VMs so use
- * the 1.0 structure so that we set UUIDs to
- * zero using memset
- */
- struct ffa_partition_info_1_0 info;
-
- if ( dst_buf > (end_buf - dst_size) )
- {
- ret = FFA_RET_NO_MEMORY;
- goto out;
- }
+ /* Ignore the caller entry as it was already added */
+ if ( dest_ctx == curr_ctx )
+ continue;
- /*
- * Context might has been removed since we go it or being removed
- * right now so we might return information for a VM not existing
- * anymore. This is acceptable as we return a view of the system
- * which could change at any time.
- */
info.id = dest_ctx->ffa_id;
info.execution_context = dest_ctx->num_vcpus;
info.partition_properties = FFA_PART_VM_PROP;
if ( dest_ctx->is_64bit )
info.partition_properties |= FFA_PART_PROP_AARCH64_STATE;
- memcpy(dst_buf, &info, MIN(sizeof(info), dst_size));
-
- if ( dst_size > sizeof(info) )
- memset(dst_buf + sizeof(info), 0,
- dst_size - sizeof(info));
+ ret = ffa_copy_info(dst_buf, end_buf, &info, dst_size,
+ sizeof(info));
+ if ( ret )
+ {
+ read_unlock(&ffa_ctx_list_rwlock);
+ return ret;
+ }
- dst_buf += dst_size;
count++;
}
+ read_unlock(&ffa_ctx_list_rwlock);
}
- *vm_count = count;
-out:
- read_unlock(&ffa_ctx_list_rwlock);
+ *vm_count = count;
return ret;
}
@@ -217,16 +254,17 @@ void ffa_handle_partition_info_get(struct cpu_user_regs
*regs)
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),
- };
+ struct ffa_uuid uuid;
uint32_t dst_size = 0;
void *dst_buf, *end_buf;
uint32_t ffa_vm_count = 0, ffa_sp_count = 0;
+ ffa_uuid_set(&uuid,
+ get_user_reg(regs, 1),
+ get_user_reg(regs, 2),
+ get_user_reg(regs, 3),
+ get_user_reg(regs, 4));
+
/*
* 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.
@@ -259,10 +297,23 @@ void ffa_handle_partition_info_get(struct cpu_user_regs
*regs)
}
/*
- * Do not count the caller VM as the spec is not clearly mandating it
- * and it is not supported by Linux.
+ * We do not have protocol UUIDs for VMs so if a request has non Nil
+ * UUID we must return a vm_count of 0
*/
- ffa_vm_count = get_ffa_vm_count() - 1;
+ if ( ffa_uuid_is_nil(uuid) )
+ {
+ ffa_vm_count = get_ffa_vm_count();
+
+ /*
+ * Workaround for Linux FF-A Driver not accepting to have its own
+ * entry in the list before FF-A v1.2 was supported.
+ * This workaround is generally acceptable for other
implementations
+ * as the specification was not completely clear on wether or not
+ * the requester endpoint information should be included or not
+ */
+ if ( ctx->guest_vers < FFA_VERSION_1_2 )
+ ffa_vm_count -= 1;
+ }
goto out;
}
@@ -290,17 +341,15 @@ void ffa_handle_partition_info_get(struct cpu_user_regs
*regs)
if ( ffa_fw_supports_fid(FFA_PARTITION_INFO_GET) )
{
- ret = ffa_get_sp_partinfo(uuid, &ffa_sp_count, dst_buf, end_buf,
+ ret = ffa_get_sp_partinfo(uuid, &ffa_sp_count, &dst_buf, end_buf,
dst_size);
if ( ret )
goto out_rx_release;
-
- dst_buf += ffa_sp_count * dst_size;
}
- if ( IS_ENABLED(CONFIG_FFA_VM_TO_VM) )
- ret = ffa_get_vm_partinfo(&ffa_vm_count, dst_buf, end_buf, dst_size);
+ ret = ffa_get_vm_partinfo(uuid, &ffa_vm_count, &dst_buf, end_buf,
+ dst_size);
out_rx_release:
if ( ret )
@@ -309,7 +358,13 @@ out:
if ( ret )
ffa_set_regs_error(regs, ret);
else
+ {
+ /* Size should be 0 on count request and was not supported in 1.0 */
+ if ( flags || ctx->guest_vers == FFA_VERSION_1_0 )
+ dst_size = 0;
+
ffa_set_regs_success(regs, ffa_sp_count + ffa_vm_count, dst_size);
+ }
}
static int32_t ffa_direct_req_send_vm(uint16_t sp_id, uint16_t vm_id,
@@ -450,6 +505,7 @@ bool ffa_partinfo_init(void)
uint32_t count;
int32_t e;
void *spmc_rx;
+ struct ffa_uuid nil_uuid = { .val = { 0ULL, 0ULL } };
if ( !ffa_fw_supports_fid(FFA_PARTITION_INFO_GET) ||
!ffa_fw_supports_fid(FFA_MSG_SEND_DIRECT_REQ_32))
@@ -459,7 +515,7 @@ bool ffa_partinfo_init(void)
if (!spmc_rx)
return false;
- e = ffa_partition_info_get(NULL, 0, &count, &fpi_size);
+ e = ffa_partition_info_get(nil_uuid, 0, &count, &fpi_size);
if ( e )
{
printk(XENLOG_ERR "ffa: Failed to get list of SPs: %d\n", e);
diff --git a/xen/arch/arm/tee/ffa_private.h b/xen/arch/arm/tee/ffa_private.h
index 9cae238f972c..c1dac09c75ca 100644
--- a/xen/arch/arm/tee/ffa_private.h
+++ b/xen/arch/arm/tee/ffa_private.h
@@ -306,6 +306,10 @@ struct ffa_mem_region {
struct ffa_address_range address_range_array[];
};
+struct ffa_uuid {
+ uint64_t val[2];
+};
+
struct ffa_ctx_notif {
/*
* True if domain is reported by FFA_NOTIFICATION_INFO_GET to have
@@ -567,4 +571,21 @@ static inline bool ffa_fw_supports_fid(uint32_t fid)
return test_bit(FFA_ABI_BITNUM(fid), ffa_fw_abi_supported);
}
+static inline bool ffa_uuid_is_nil(struct ffa_uuid id)
+{
+ return id.val[0] == 0 && id.val[1] == 0;
+}
+
+static inline bool ffa_uuid_equal(struct ffa_uuid id1, struct ffa_uuid id2)
+{
+ return id1.val[0] == id2.val[0] && id1.val[1] == id2.val[1];
+}
+
+static inline void ffa_uuid_set(struct ffa_uuid *id, uint32_t val0,
+ uint32_t val1, uint32_t val2, uint32_t val3)
+{
+ id->val[0] = ((uint64_t)val1 << 32U) | val0;
+ id->val[1] = ((uint64_t)val3 << 32U) | val2;
+}
+
#endif /*__FFA_PRIVATE_H__*/
--
2.51.2
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |