libsp: Add high level SP discovery function.

The patch adds functions for accessing the caller's and other
partitions' 16 bit FF-A ID and for discovering other partitions of the
system.

Signed-off-by: Imre Kis <imre.kis@arm.com>
Change-Id: I761e7771653bec22afc2d121afbf3798041688d2
diff --git a/components/messaging/ffa/libsp/component.cmake b/components/messaging/ffa/libsp/component.cmake
index 0f372be..e9c3cba 100644
--- a/components/messaging/ffa/libsp/component.cmake
+++ b/components/messaging/ffa/libsp/component.cmake
@@ -13,6 +13,7 @@
 	"${CMAKE_CURRENT_LIST_DIR}/ffa.c"
 	"${CMAKE_CURRENT_LIST_DIR}/ffa_interrupt_handler.c"
 	"${CMAKE_CURRENT_LIST_DIR}/ffa_memory_descriptors.c"
+	"${CMAKE_CURRENT_LIST_DIR}/sp_discovery.c"
 	"${CMAKE_CURRENT_LIST_DIR}/sp_memory_management.c"
 	"${CMAKE_CURRENT_LIST_DIR}/sp_rxtx.c"
 	)
@@ -20,6 +21,7 @@
 set_property(TARGET ${TGT} PROPERTY PUBLIC_HEADER
 	${CMAKE_CURRENT_LIST_DIR}/include/ffa_api_defines.h
 	${CMAKE_CURRENT_LIST_DIR}/include/ffa_api_types.h
+	${CMAKE_CURRENT_LIST_DIR}/include/sp_discovery.h
 	${CMAKE_CURRENT_LIST_DIR}/include/ffa_api.h
 	${CMAKE_CURRENT_LIST_DIR}/include/ffa_internal_api.h
 	${CMAKE_CURRENT_LIST_DIR}/include/ffa_memory_descriptors.h
diff --git a/components/messaging/ffa/libsp/include/sp_api_defines.h b/components/messaging/ffa/libsp/include/sp_api_defines.h
index 9a80559..601d3ee 100644
--- a/components/messaging/ffa/libsp/include/sp_api_defines.h
+++ b/components/messaging/ffa/libsp/include/sp_api_defines.h
@@ -24,5 +24,6 @@
 #define SP_RESULT_INTERNAL_ERROR	SP_RESULT_CREATE(-1)
 #define SP_RESULT_INVALID_PARAMETERS	SP_RESULT_CREATE(-2)
 #define SP_RESULT_INVALID_STATE		SP_RESULT_CREATE(-3)
+#define SP_RESULT_NOT_FOUND		SP_RESULT_CREATE(-4)
 
 #endif /* LIBSP_INCLUDE_SP_API_DEFINES_H_ */
diff --git a/components/messaging/ffa/libsp/include/sp_discovery.h b/components/messaging/ffa/libsp/include/sp_discovery.h
new file mode 100644
index 0000000..a85e946
--- /dev/null
+++ b/components/messaging/ffa/libsp/include/sp_discovery.h
@@ -0,0 +1,89 @@
+/* SPDX-License-Identifier: BSD-3-Clause */
+/*
+ * Copyright (c) 2020, Arm Limited and Contributors. All rights reserved.
+ */
+
+#ifndef LIBSP_INCLUDE_SP_DISCOVERY_H_
+#define LIBSP_INCLUDE_SP_DISCOVERY_H_
+
+#include "sp_api_defines.h"
+#include "sp_api_types.h"
+#include <stdbool.h>
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct sp_uuid {
+	uint8_t uuid[16];
+};
+
+struct sp_partition_info {
+	uint16_t partition_id;
+	uint16_t execution_context_count;
+	bool supports_direct_requests;
+	bool can_send_direct_requests;
+	bool supports_indirect_requests;
+};
+
+/**
+ * @brief       Queries the FF-A version of the FF-A instance.
+ *
+ * @param[out]  major  The major FF-A version
+ * @param[out]  minor  The minor FF-A version
+ *
+ * @return      The SP API result
+ */
+sp_result sp_discovery_ffa_version_get(uint16_t *major, uint16_t *minor);
+
+/**
+ * @brief       Queries the 16 bit FF-A ID of the calling partition.
+ *
+ * @param[out]  id    The 16 bit FF-A ID of the calling partition
+ *
+ * @return      The SP API result
+ */
+sp_result sp_discovery_own_id_get(uint16_t *id);
+
+/**
+ * @brief       Queries the 16 bit FF-A ID of a partition by its UUID.
+ *
+ * @param[in]   uuid  The UUID of the partition
+ * @param[out]  id    The 16 bit FF-A ID of the partition
+ *
+ * @return      The SP API result
+ */
+sp_result sp_discovery_partition_id_get(const struct sp_uuid *uuid,
+					uint16_t *id);
+
+/**
+ * @brief       Queries the information about a partition by its UUID.
+ *
+ * @param[in]   uuid  The UUID of the partition
+ * @param[out]  info  The partition information
+ *
+ * @return      The SP API result
+ */
+sp_result sp_discovery_partition_info_get(const struct sp_uuid *uuid,
+					  struct sp_partition_info *info);
+
+/**
+ * @brief          Queries partition information of all partitions.
+ *
+ * @param[out]     info   The partition information buffer
+ * @param[in,out]  count  As an input value it specifies the count of partition
+ *                        info structures that would fit into the output buffer.
+ *                        As an output it indicates the count of the valid
+ *                        entries in the buffer.
+ *
+ * @return         The SP API result
+ */
+sp_result sp_discovery_partition_info_get_all(struct sp_partition_info info[],
+					      uint32_t *count);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* LIBSP_INCLUDE_SP_DISCOVERY_H_ */
diff --git a/components/messaging/ffa/libsp/sp_discovery.c b/components/messaging/ffa/libsp/sp_discovery.c
new file mode 100644
index 0000000..a801167
--- /dev/null
+++ b/components/messaging/ffa/libsp/sp_discovery.c
@@ -0,0 +1,188 @@
+// SPDX-License-Identifier: BSD-3-Clause
+/*
+ * Copyright (c) 2020, Arm Limited and Contributors. All rights reserved.
+ */
+
+#include "sp_discovery.h"
+#include "ffa_api.h"
+#include "sp_rxtx.h"
+#include "util.h"
+#include <string.h>
+
+static const struct sp_uuid uuid_nil = {0};
+
+sp_result sp_discovery_ffa_version_get(uint16_t *major, uint16_t *minor)
+{
+	uint32_t version = 0;
+	ffa_result ffa_res = FFA_OK;
+
+	ffa_res = ffa_version(&version);
+	if (ffa_res != FFA_OK) {
+		*major = UINT16_C(0);
+		*minor = UINT16_C(0);
+
+		return SP_RESULT_FFA(ffa_res);
+	}
+
+	*major = (version >> FFA_VERSION_MAJOR_SHIFT) & FFA_VERSION_MAJOR_MASK;
+	*minor = (version >> FFA_VERSION_MINOR_SHIFT) & FFA_VERSION_MINOR_MASK;
+
+	return SP_RESULT_OK;
+}
+
+sp_result sp_discovery_own_id_get(uint16_t *id)
+{
+	ffa_result ffa_res = FFA_OK;
+
+	ffa_res = ffa_id_get(id);
+	return SP_RESULT_FFA(ffa_res);
+}
+
+static sp_result
+partition_info_get(const struct sp_uuid *uuid,
+		   const struct ffa_partition_information **info,
+		   uint32_t *count)
+{
+	const void *buffer = NULL;
+	size_t buffer_size = 0;
+	struct ffa_uuid ffa_uuid = {0};
+	sp_result sp_res = SP_RESULT_OK;
+	ffa_result ffa_res = FFA_OK;
+
+	sp_res = sp_rxtx_buffer_rx_get(&buffer, &buffer_size);
+	if (sp_res != SP_RESULT_OK) {
+		*count = UINT32_C(0);
+		return sp_res;
+	}
+
+	/* Safely convert to FF-A UUID format */
+	memcpy(&ffa_uuid.uuid, uuid->uuid, sizeof(ffa_uuid.uuid));
+
+	ffa_res = ffa_partition_info_get(&ffa_uuid, count);
+	if (ffa_res != FFA_OK) {
+		*count = UINT32_C(0);
+		return SP_RESULT_FFA(ffa_res);
+	}
+
+	if (*count * sizeof(struct ffa_partition_information) < buffer_size) {
+		/*
+		 * The indicated amount of info structures doesn't fit into the
+		 * RX buffer.
+		 */
+		*count = UINT32_C(0);
+		return SP_RESULT_INTERNAL_ERROR;
+	}
+
+	*info = (const struct ffa_partition_information *)buffer;
+
+	return SP_RESULT_OK;
+}
+
+static void unpack_ffa_info(const struct ffa_partition_information ffa_info[],
+			    struct sp_partition_info *sp_info)
+{
+	uint32_t props = ffa_info->partition_properties;
+
+	sp_info->partition_id = ffa_info->partition_id;
+	sp_info->execution_context_count = ffa_info->execution_context_count;
+	sp_info->supports_direct_requests =
+			props & FFA_PARTITION_SUPPORTS_DIRECT_REQUESTS;
+	sp_info->can_send_direct_requests =
+			props & FFA_PARTITION_CAN_SEND_DIRECT_REQUESTS;
+	sp_info->supports_indirect_requests =
+			props & FFA_PARTITION_SUPPORTS_INDIRECT_REQUESTS;
+}
+
+sp_result sp_discovery_partition_id_get(const struct sp_uuid *uuid,
+					uint16_t *id)
+{
+	const struct ffa_partition_information *ffa_info = NULL;
+	uint32_t count = 0;
+	sp_result sp_res = SP_RESULT_OK;
+
+	if (uuid == NULL || id == NULL)
+		return SP_RESULT_INVALID_PARAMETERS;
+
+	/*
+	 * Nil UUID means querying all partitions which is handled by a separate
+	 * function.
+	 */
+	if (memcmp(&uuid_nil, uuid, sizeof(struct sp_uuid)) == 0) {
+		*id = FFA_ID_GET_ID_MASK;
+		return SP_RESULT_INVALID_PARAMETERS;
+	}
+
+	sp_res = partition_info_get(uuid, &ffa_info, &count);
+	if (sp_res != SP_RESULT_OK) {
+		*id = FFA_ID_GET_ID_MASK;
+		return sp_res;
+	}
+
+	if (count == 0) {
+		*id = FFA_ID_GET_ID_MASK;
+		return SP_RESULT_NOT_FOUND;
+	}
+
+	*id = ffa_info->partition_id;
+
+	return SP_RESULT_OK;
+}
+
+sp_result sp_discovery_partition_info_get(const struct sp_uuid *uuid,
+					  struct sp_partition_info *info)
+{
+	const struct ffa_partition_information *ffa_info = NULL;
+	uint32_t count = 0;
+	sp_result sp_res = SP_RESULT_OK;
+
+	if (uuid == NULL || info == NULL)
+		return SP_RESULT_INVALID_PARAMETERS;
+
+	/*
+	 * Nil UUID means querying all partitions which is handled by a separate
+	 * function.
+	 */
+	if (memcmp(&uuid_nil, uuid, sizeof(struct sp_uuid)) == 0) {
+		*info = (struct sp_partition_info){0};
+		return SP_RESULT_INVALID_PARAMETERS;
+	}
+
+	sp_res = partition_info_get(uuid, &ffa_info, &count);
+	if (sp_res != SP_RESULT_OK) {
+		*info = (struct sp_partition_info){0};
+		return sp_res;
+	}
+
+	if (count == 0) {
+		*info = (struct sp_partition_info){0};
+		return SP_RESULT_NOT_FOUND;
+	}
+
+	unpack_ffa_info(ffa_info, info);
+
+	return SP_RESULT_OK;
+}
+
+sp_result sp_discovery_partition_info_get_all(struct sp_partition_info info[],
+					      uint32_t *count)
+{
+	const struct ffa_partition_information *ffa_info = NULL;
+	uint32_t ffa_count = 0;
+	uint32_t i = 0;
+	sp_result sp_res = SP_RESULT_OK;
+
+	if (info == NULL || count == NULL)
+		return SP_RESULT_INVALID_PARAMETERS;
+
+	sp_res = partition_info_get(&uuid_nil, &ffa_info, &ffa_count);
+	if (sp_res != SP_RESULT_OK) {
+		*count = UINT32_C(0);
+		return sp_res;
+	}
+
+	*count = MIN(*count, ffa_count);
+	for (i = 0; i < *count; i++)
+		unpack_ffa_info(&ffa_info[i], &info[i]);
+
+	return SP_RESULT_OK;
+}