feat(notifications): information get interface

Handled FFA_NOTIFICATION_INFO_GET interface, to be used by a VM
(receiver's scheduler), Hypervisor or OS kernel.
Returns a list of IDs including Endpoints and vCPUs IDs that have
pending notifications. Provides support for multiple calls to the
FFA_NOTIFICATION_INFO_GET, in case there still are notifications whose
information needs to be retrieved after a call.

Change-Id: I4e73f18ee3301da4829313ffae247b6d0d262622
Signed-off-by: J-Alves <joao.alves@arm.com>
diff --git a/src/arch/aarch64/hypervisor/handler.c b/src/arch/aarch64/hypervisor/handler.c
index 9104028..147c711 100644
--- a/src/arch/aarch64/hypervisor/handler.c
+++ b/src/arch/aarch64/hypervisor/handler.c
@@ -626,6 +626,9 @@
 			ffa_notifications_get_receiver(*args),
 			ffa_notifications_get_vcpu(*args), args->arg2, current);
 		return true;
+	case FFA_NOTIFICATION_INFO_GET_64:
+		*args = api_ffa_notification_info_get(current);
+		return true;
 	}
 
 	return false;
diff --git a/src/arch/aarch64/plat/ffa/absent.c b/src/arch/aarch64/plat/ffa/absent.c
index 0902bca..bb41c7b 100644
--- a/src/arch/aarch64/plat/ffa/absent.c
+++ b/src/arch/aarch64/plat/ffa/absent.c
@@ -166,3 +166,18 @@
 
 	return false;
 }
+
+bool plat_ffa_vm_notifications_info_get(const uint16_t *ids,
+					const uint32_t *ids_count,
+					const uint32_t *lists_sizes,
+					const uint32_t *lists_count,
+					const uint32_t ids_count_max)
+{
+	(void)ids;
+	(void)ids_count;
+	(void)lists_sizes;
+	(void)lists_count;
+	(void)ids_count_max;
+
+	return false;
+}
diff --git a/src/arch/aarch64/plat/ffa/hypervisor.c b/src/arch/aarch64/plat/ffa/hypervisor.c
index 4f35c9f..158cd37 100644
--- a/src/arch/aarch64/plat/ffa/hypervisor.c
+++ b/src/arch/aarch64/plat/ffa/hypervisor.c
@@ -290,3 +290,18 @@
 {
 	return vm_id_is_current_world(vm_id);
 }
+
+bool plat_ffa_vm_notifications_info_get(const uint16_t *ids,
+					const uint32_t *ids_count,
+					const uint32_t *lists_sizes,
+					const uint32_t *lists_count,
+					const uint32_t ids_count_max)
+{
+	(void)ids;
+	(void)ids_count;
+	(void)lists_sizes;
+	(void)lists_count;
+	(void)ids_count_max;
+
+	return false;
+}
diff --git a/src/arch/aarch64/plat/ffa/spmc.c b/src/arch/aarch64/plat/ffa/spmc.c
index 5645f39..dded83c 100644
--- a/src/arch/aarch64/plat/ffa/spmc.c
+++ b/src/arch/aarch64/plat/ffa/spmc.c
@@ -446,3 +446,47 @@
 {
 	return !vm_id_is_current_world(vm_id);
 }
+
+bool plat_ffa_vm_notifications_info_get(uint16_t *ids, uint32_t *ids_count,
+					uint32_t *lists_sizes,
+					uint32_t *lists_count,
+					const uint32_t ids_count_max)
+{
+	enum notifications_info_get_state info_get_state = INIT;
+	struct nwd_vms_locked nwd_vms_locked = nwd_vms_lock();
+	struct vm_locked other_world_locked = vm_find_locked(HF_OTHER_WORLD_ID);
+
+	CHECK(other_world_locked.vm != NULL);
+
+	vm_notifications_info_get_pending(other_world_locked, false, ids,
+					  ids_count, lists_sizes, lists_count,
+					  ids_count_max, &info_get_state);
+
+	if (info_get_state == FULL) {
+		goto out;
+	}
+
+	vm_unlock(&other_world_locked);
+
+	for (unsigned int i = 0; i < nwd_vms_size; i++) {
+		info_get_state = INIT;
+
+		if (nwd_vms[i].id != HF_INVALID_VM_ID) {
+			struct vm_locked vm_locked = vm_lock(&nwd_vms[i]);
+
+			vm_notifications_info_get_pending(
+				vm_locked, false, ids, ids_count, lists_sizes,
+				lists_count, ids_count_max, &info_get_state);
+
+			if (info_get_state == FULL) {
+				goto out;
+			}
+
+			vm_unlock(&vm_locked);
+		}
+	}
+out:
+	nwd_vms_unlock(&nwd_vms_locked);
+
+	return info_get_state == FULL;
+}
diff --git a/src/arch/fake/hypervisor/ffa.c b/src/arch/fake/hypervisor/ffa.c
index 00a0005..6ea1dda 100644
--- a/src/arch/fake/hypervisor/ffa.c
+++ b/src/arch/fake/hypervisor/ffa.c
@@ -159,3 +159,18 @@
 	(void)vm_id;
 	return false;
 }
+
+bool plat_ffa_vm_notifications_info_get(const uint16_t *ids,
+					const uint32_t *ids_count,
+					const uint32_t *lists_sizes,
+					const uint32_t *lists_count,
+					const uint32_t ids_count_max)
+{
+	(void)ids;
+	(void)ids_count;
+	(void)lists_sizes;
+	(void)lists_count;
+	(void)ids_count_max;
+
+	return false;
+}