feat(ff-a): add uuid to partition info descriptors
The uuid field is required as specified in table 13.4 "Partition
information descriptor" from the FF-A 1.1 BETA0 EAC specification.
To maintain compatability with endpoint of a lower version we must
return the appropriate partition info descriptor according to the
endpoints version set by the endpoint calling FFA_VERSION earlier.
Signed-off-by: Daniel Boulby <daniel.boulby@arm.com>
Change-Id: Iac239c4115a7f80c3f38a5f590c722e82f82e773
diff --git a/src/api.c b/src/api.c
index 60dc65d..bb9c79e 100644
--- a/src/api.c
+++ b/src/api.c
@@ -31,9 +31,12 @@
#include "vmapi/hf/call.h"
#include "vmapi/hf/ffa.h"
-static_assert(sizeof(struct ffa_partition_info) == 8,
+static_assert(sizeof(struct ffa_partition_info_v1_0) == 8,
"Partition information descriptor size doesn't match the one in "
"the FF-A 1.0 EAC specification, Table 82.");
+static_assert(sizeof(struct ffa_partition_info) == 24,
+ "Partition information descriptor size doesn't match the one in "
+ "the FF-A 1.1 BETA0 EAC specification, Table 13.34.");
/*
* To eliminate the risk of deadlocks, we define a partial order for the
@@ -355,18 +358,88 @@
return api_switch_to_primary(current, ret, VCPU_STATE_ABORTED);
}
+/*
+ * Format the partition info descriptors according to the version supported
+ * by the endpoint and return the size of the array created.
+ */
+static struct ffa_value send_versioned_partition_info_descriptors(
+ struct vm *current_vm, struct ffa_partition_info *partitions,
+ uint32_t vm_count)
+{
+ struct vm_locked current_vm_locked;
+ uint32_t version = current_vm->ffa_version;
+ void *versioned_partition_info;
+ uint32_t size;
+ struct ffa_value ret;
+
+ if (version == MAKE_FFA_VERSION(1, 0)) {
+ struct ffa_partition_info_v1_0 v1_0_partitions[2 * MAX_VMS];
+
+ for (uint32_t i = 0; i < vm_count; i++) {
+ v1_0_partitions[i].vm_id = partitions[i].vm_id;
+ v1_0_partitions[i].vcpu_count =
+ partitions[i].vcpu_count;
+ v1_0_partitions[i].properties =
+ partitions[i].properties;
+ }
+ versioned_partition_info = v1_0_partitions;
+ size = sizeof(v1_0_partitions[0]) * vm_count;
+ } else {
+ versioned_partition_info = partitions;
+ size = sizeof(partitions[0]) * vm_count;
+ }
+
+ if (size > FFA_MSG_PAYLOAD_MAX) {
+ dlog_error(
+ "Partition information does not fit in the VM's RX "
+ "buffer.\n");
+ return ffa_error(FFA_NO_MEMORY);
+ }
+
+ /*
+ * Partition information is returned in the VM's RX buffer, which is why
+ * the lock is needed.
+ */
+ current_vm_locked = vm_lock(current_vm);
+
+ if (msg_receiver_busy(current_vm_locked, NULL, false)) {
+ /*
+ * Can't retrieve memory information if the mailbox is not
+ * available.
+ */
+ dlog_verbose("RX buffer not ready.\n");
+ ret = ffa_error(FFA_BUSY);
+ goto out_unlock;
+ }
+
+ /* Populate the VM's RX buffer with the partition information. */
+ memcpy_s(current_vm->mailbox.recv, FFA_MSG_PAYLOAD_MAX,
+ versioned_partition_info, size);
+ current_vm->mailbox.recv_size = size;
+
+ /* Sender is Hypervisor in the normal world (TEE in secure world). */
+ current_vm->mailbox.recv_sender = HF_VM_ID_BASE;
+ current_vm->mailbox.recv_func = FFA_PARTITION_INFO_GET_32;
+ current_vm->mailbox.state = MAILBOX_STATE_READ;
+
+ /* Return the count of partition information descriptors in w2. */
+ ret = (struct ffa_value){.func = FFA_SUCCESS_32, .arg2 = vm_count};
+
+out_unlock:
+ vm_unlock(¤t_vm_locked);
+
+ return ret;
+}
+
struct ffa_value api_ffa_partition_info_get(struct vcpu *current,
const struct ffa_uuid *uuid,
const uint32_t flags)
{
struct vm *current_vm = current->vm;
- struct vm_locked current_vm_locked;
ffa_vm_count_t vm_count = 0;
bool count_flag = (flags && FFA_PARTITION_COUNT_FLAG_MASK) ==
FFA_PARTITION_COUNT_FLAG;
bool uuid_is_null = ffa_uuid_is_null(uuid);
- struct ffa_value ret;
- uint32_t size;
struct ffa_partition_info partitions[2 * MAX_VMS];
/* Bits 31:1 Must Be Zero */
@@ -406,6 +479,7 @@
vm_are_notifications_enabled(vm)
? FFA_PARTITION_NOTIFICATION
: 0;
+ partitions[array_index].uuid = vm->uuid;
}
}
}
@@ -442,47 +516,8 @@
.arg2 = vm_count};
}
- size = vm_count * sizeof(partitions[0]);
- if (size > FFA_MSG_PAYLOAD_MAX) {
- dlog_error(
- "Partition information does not fit in the VM's RX "
- "buffer.\n");
- return ffa_error(FFA_NO_MEMORY);
- }
-
- /*
- * Partition information is returned in the VM's RX buffer, which is why
- * the lock is needed.
- */
- current_vm_locked = vm_lock(current_vm);
-
- if (msg_receiver_busy(current_vm_locked, NULL, false)) {
- /*
- * Can't retrieve memory information if the mailbox is not
- * available.
- */
- dlog_verbose("RX buffer not ready.\n");
- ret = ffa_error(FFA_BUSY);
- goto out_unlock;
- }
-
- /* Populate the VM's RX buffer with the partition information. */
- memcpy_s(current_vm->mailbox.recv, FFA_MSG_PAYLOAD_MAX, partitions,
- size);
- current_vm->mailbox.recv_size = size;
-
- /* Sender is Hypervisor in the normal world (TEE in secure world). */
- current_vm->mailbox.recv_sender = HF_VM_ID_BASE;
- current_vm->mailbox.recv_func = FFA_PARTITION_INFO_GET_32;
- current_vm->mailbox.state = MAILBOX_STATE_READ;
-
- /* Return the count of partition information descriptors in w2. */
- ret = (struct ffa_value){.func = FFA_SUCCESS_32, .arg2 = vm_count};
-
-out_unlock:
- vm_unlock(¤t_vm_locked);
-
- return ret;
+ return send_versioned_partition_info_descriptors(current_vm, partitions,
+ vm_count);
}
/**