feat(notifications): hypervisor forward bind/unbind

Hypervisor forwards call to SPMC of bind/unbind interfaces, when
the specified sender is an SP.
This will be useful for testing notifications with both hypervisor and
SPMC.

Change-Id: I62c44211f251a84d6bdc459bbe6b8d4fb2571933
Signed-off-by: J-Alves <joao.alves@arm.com>
diff --git a/src/api.c b/src/api.c
index 7b615ce..37a6ca9 100644
--- a/src/api.c
+++ b/src/api.c
@@ -2599,6 +2599,13 @@
 		return ffa_error(FFA_INVALID_PARAMETERS);
 	}
 
+	if (plat_ffa_notifications_update_bindings_forward(
+		    receiver_vm_id, sender_vm_id, flags, notifications, is_bind,
+		    &ret)) {
+		dlog_verbose("Forwarding call to other world.\n");
+		return ret;
+	}
+
 	if (notifications == 0U) {
 		dlog_verbose("No notifications have been specified.\n");
 		return ffa_error(FFA_INVALID_PARAMETERS);
diff --git a/src/arch/aarch64/plat/ffa/absent.c b/src/arch/aarch64/plat/ffa/absent.c
index e9a10e6..6a27d69 100644
--- a/src/arch/aarch64/plat/ffa/absent.c
+++ b/src/arch/aarch64/plat/ffa/absent.c
@@ -111,6 +111,21 @@
 	return false;
 }
 
+bool plat_ffa_notifications_update_bindings_forward(
+	ffa_vm_id_t receiver_id, ffa_vm_id_t sender_id, uint32_t flags,
+	ffa_notifications_bitmap_t bitmap, bool is_bind, struct ffa_value *ret)
+{
+	(void)ret;
+	(void)receiver_id;
+	(void)sender_id;
+	(void)flags;
+	(void)bitmap;
+	(void)is_bind;
+	(void)ret;
+
+	return false;
+}
+
 bool plat_ffa_is_notification_set_valid(struct vcpu *current,
 					ffa_vm_id_t sender_id,
 					ffa_vm_id_t receiver_id)
diff --git a/src/arch/aarch64/plat/ffa/hypervisor.c b/src/arch/aarch64/plat/ffa/hypervisor.c
index ba9ae23..350763b 100644
--- a/src/arch/aarch64/plat/ffa/hypervisor.c
+++ b/src/arch/aarch64/plat/ffa/hypervisor.c
@@ -240,6 +240,27 @@
 	return sender_id != receiver_id && current_vm_id == receiver_id;
 }
 
+bool plat_ffa_notifications_update_bindings_forward(
+	ffa_vm_id_t receiver_id, ffa_vm_id_t sender_id, uint32_t flags,
+	ffa_notifications_bitmap_t bitmap, bool is_bind, struct ffa_value *ret)
+{
+	CHECK(ret != NULL);
+
+	if (vm_id_is_current_world(receiver_id) &&
+	    !vm_id_is_current_world(sender_id)) {
+		*ret = arch_other_world_call((struct ffa_value){
+			.func = is_bind ? FFA_NOTIFICATION_BIND_32
+					: FFA_NOTIFICATION_UNBIND_32,
+			.arg1 = (sender_id << 16) | (receiver_id),
+			.arg2 = is_bind ? flags : 0U,
+			.arg3 = (uint32_t)(bitmap),
+			.arg4 = (uint32_t)(bitmap >> 32),
+		});
+		return true;
+	}
+	return false;
+}
+
 bool plat_ffa_is_notification_set_valid(struct vcpu *current,
 					ffa_vm_id_t sender_id,
 					ffa_vm_id_t receiver_id)
diff --git a/src/arch/aarch64/plat/ffa/spmc.c b/src/arch/aarch64/plat/ffa/spmc.c
index d2eb754..817600c 100644
--- a/src/arch/aarch64/plat/ffa/spmc.c
+++ b/src/arch/aarch64/plat/ffa/spmc.c
@@ -197,6 +197,21 @@
 		 vm_id_is_current_world(sender_id)));
 }
 
+bool plat_ffa_notifications_update_bindings_forward(
+	ffa_vm_id_t receiver_id, ffa_vm_id_t sender_id, uint32_t flags,
+	ffa_notifications_bitmap_t bitmap, bool is_bind, struct ffa_value *ret)
+{
+	(void)ret;
+	(void)receiver_id;
+	(void)sender_id;
+	(void)flags;
+	(void)bitmap;
+	(void)is_bind;
+	(void)ret;
+
+	return false;
+}
+
 bool plat_ffa_is_notification_set_valid(struct vcpu *current,
 					ffa_vm_id_t sender_id,
 					ffa_vm_id_t receiver_id)
diff --git a/src/arch/fake/hypervisor/ffa.c b/src/arch/fake/hypervisor/ffa.c
index 6ea1dda..4dd3fcd 100644
--- a/src/arch/fake/hypervisor/ffa.c
+++ b/src/arch/fake/hypervisor/ffa.c
@@ -91,6 +91,21 @@
 	return false;
 }
 
+bool plat_ffa_notifications_update_bindings_forward(
+	ffa_vm_id_t receiver_id, ffa_vm_id_t sender_id, uint32_t flags,
+	ffa_notifications_bitmap_t bitmap, bool is_bind, struct ffa_value *ret)
+{
+	(void)ret;
+	(void)receiver_id;
+	(void)sender_id;
+	(void)flags;
+	(void)bitmap;
+	(void)is_bind;
+	(void)ret;
+
+	return false;
+}
+
 ffa_partition_properties_t plat_ffa_partition_properties(
 	ffa_vm_id_t current_id, const struct vm *target)
 {