feat(notifications): get notifications from SPs

Handling the call FFA_NOTIFICATION_GET to retrieve pending notifications
from SPs:
- SPMC retrieves the pending notifications from the partition's bitmap
field;
- Hypervisor forwards the call to SPMC, analyzes the returned value
and populates its return to the VM.
Hypervisor case useful to test notifications full signaling flow from
NWd.

Change-Id: Icda45d0bca025a023c75ec2ceecf15d06c2456a0
Signed-off-by: J-Alves <joao.alves@arm.com>
diff --git a/src/api.c b/src/api.c
index 37a6ca9..27189e9 100644
--- a/src/api.c
+++ b/src/api.c
@@ -2809,12 +2809,12 @@
 	}
 
 	if ((flags & FFA_NOTIFICATION_FLAG_BITMAP_SP) != 0U) {
-		/*
-		 * TODO: For hypervisor, forward call to SPMC to get VM's
-		 * notifications from SPs.
-		 */
-		sp_notifications = vm_notifications_get_pending_and_clear(
-			receiver_locked, false, vcpu_id);
+		if (!plat_ffa_notifications_get_from_sp(
+			    receiver_locked, vcpu_id, &sp_notifications,
+			    &ret)) {
+			dlog_verbose("Failed to get notifications from sps.");
+			goto out;
+		}
 	}
 
 	if ((flags & FFA_NOTIFICATION_FLAG_BITMAP_VM) != 0U) {
diff --git a/src/arch/aarch64/plat/ffa/absent.c b/src/arch/aarch64/plat/ffa/absent.c
index 6a27d69..950a409 100644
--- a/src/arch/aarch64/plat/ffa/absent.c
+++ b/src/arch/aarch64/plat/ffa/absent.c
@@ -144,6 +144,18 @@
 	return false;
 }
 
+bool plat_ffa_notifications_get_from_sp(
+	struct vm_locked receiver_locked, ffa_vcpu_index_t vcpu_id,
+	const ffa_notifications_bitmap_t *from_sp, struct ffa_value *ret)
+{
+	(void)receiver_locked;
+	(void)vcpu_id;
+	(void)from_sp;
+	(void)ret;
+
+	return false;
+}
+
 struct ffa_value plat_ffa_notifications_bitmap_create(
 	ffa_vm_id_t vm_id, ffa_vcpu_count_t vcpu_count)
 {
diff --git a/src/arch/aarch64/plat/ffa/hypervisor.c b/src/arch/aarch64/plat/ffa/hypervisor.c
index 350763b..90f9a3f 100644
--- a/src/arch/aarch64/plat/ffa/hypervisor.c
+++ b/src/arch/aarch64/plat/ffa/hypervisor.c
@@ -324,6 +324,30 @@
 	return vm_id_is_current_world(vm_id);
 }
 
+bool plat_ffa_notifications_get_from_sp(struct vm_locked receiver_locked,
+					ffa_vcpu_index_t vcpu_id,
+					ffa_notifications_bitmap_t *from_sp,
+					struct ffa_value *ret)
+{
+	CHECK(from_sp != NULL && ret != NULL);
+
+	ffa_vm_id_t receiver_id = receiver_locked.vm->id;
+
+	*ret = arch_other_world_call((struct ffa_value){
+		.func = FFA_NOTIFICATION_GET_32,
+		.arg1 = (receiver_id << 16) | (vcpu_id),
+		.arg2 = FFA_NOTIFICATION_FLAG_BITMAP_SP,
+	});
+
+	if (ret->func == FFA_ERROR_32) {
+		return false;
+	}
+
+	*from_sp = ffa_notification_get_from_sp(*ret);
+
+	return true;
+}
+
 bool plat_ffa_vm_notifications_info_get(const uint16_t *ids,
 					const uint32_t *ids_count,
 					const uint32_t *lists_sizes,
diff --git a/src/arch/aarch64/plat/ffa/spmc.c b/src/arch/aarch64/plat/ffa/spmc.c
index 817600c..31b04cc 100644
--- a/src/arch/aarch64/plat/ffa/spmc.c
+++ b/src/arch/aarch64/plat/ffa/spmc.c
@@ -471,6 +471,19 @@
 	return !vm_id_is_current_world(vm_id);
 }
 
+bool plat_ffa_notifications_get_from_sp(struct vm_locked receiver_locked,
+					ffa_vcpu_index_t vcpu_id,
+					ffa_notifications_bitmap_t *from_sp,
+					struct ffa_value *ret)
+{
+	(void)ret;
+
+	*from_sp = vm_notifications_get_pending_and_clear(receiver_locked,
+							  false, vcpu_id);
+
+	return true;
+}
+
 bool plat_ffa_vm_notifications_info_get(uint16_t *ids, uint32_t *ids_count,
 					uint32_t *lists_sizes,
 					uint32_t *lists_count,
diff --git a/src/arch/fake/hypervisor/ffa.c b/src/arch/fake/hypervisor/ffa.c
index 4dd3fcd..78c384b 100644
--- a/src/arch/fake/hypervisor/ffa.c
+++ b/src/arch/fake/hypervisor/ffa.c
@@ -147,6 +147,18 @@
 	return false;
 }
 
+bool plat_ffa_notifications_get_from_sp(
+	struct vm_locked receiver_locked, ffa_vcpu_index_t vcpu_id,
+	const ffa_notifications_bitmap_t *from_sp, struct ffa_value *ret)
+{
+	(void)receiver_locked;
+	(void)vcpu_id;
+	(void)from_sp;
+	(void)ret;
+
+	return false;
+}
+
 struct ffa_value plat_ffa_notifications_bitmap_create(
 	ffa_vm_id_t vm_id, ffa_vcpu_count_t vcpu_count)
 {