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(&current_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(&current_vm_locked);
-
-	return ret;
+	return send_versioned_partition_info_descriptors(current_vm, partitions,
+							 vm_count);
 }
 
 /**