fix(notifications): flag that Must Be Zero

According to FF-A v1.1 EAC0 specification the bits [31:4] of the 'flags'
argument to the FFA_NOTIFICATION_GET ABI Must Be Zero.

Change-Id: I6381d9572eb8d7f7af700833c26ced59493a36b0
Signed-off-by: J-Alves <joao.alves@arm.com>
diff --git a/inc/hf/arch/plat/ffa.h b/inc/hf/arch/plat/ffa.h
index 2c5a4b2..524cd1e 100644
--- a/inc/hf/arch/plat/ffa.h
+++ b/inc/hf/arch/plat/ffa.h
@@ -93,7 +93,8 @@
 				       struct ffa_value *ret);
 
 bool plat_ffa_is_notification_get_valid(struct vcpu *current,
-					ffa_vm_id_t receiver_id);
+					ffa_vm_id_t receiver_id,
+					uint32_t flags);
 
 bool plat_ffa_notifications_get_from_sp(struct vm_locked receiver_locked,
 					ffa_vcpu_index_t vcpu_id,
diff --git a/src/api.c b/src/api.c
index 55e7b81..e560f8b 100644
--- a/src/api.c
+++ b/src/api.c
@@ -3082,13 +3082,27 @@
 	ffa_notifications_bitmap_t vm_notifications = 0;
 	struct vm_locked receiver_locked;
 	struct ffa_value ret;
+	const uint32_t flags_mbz = ~(FFA_NOTIFICATION_FLAG_BITMAP_HYP |
+				     FFA_NOTIFICATION_FLAG_BITMAP_SPM |
+				     FFA_NOTIFICATION_FLAG_BITMAP_SP |
+				     FFA_NOTIFICATION_FLAG_BITMAP_VM);
+
+	/* The FF-A v1.1 EAC0 specification states bits [31:4] Must Be Zero. */
+	if ((flags & flags_mbz) != 0U) {
+		dlog_verbose(
+			"Invalid flags bit(s) set in notifications get. [31:4] "
+			"MBZ(%x)\n",
+			flags);
+		return ffa_error(FFA_INVALID_PARAMETERS);
+	}
 
 	/*
-	 * Following check should capture wrong uses of the interface, depending
-	 * on whether Hafnium is SPMC or hypervisor.
-	 * On the rest of the function it is assumed this condition is met.
+	 * Following check should capture wrong uses of the interface,
+	 * depending on whether Hafnium is SPMC or hypervisor. On the
+	 * rest of the function it is assumed this condition is met.
 	 */
-	if (!plat_ffa_is_notification_get_valid(current, receiver_vm_id)) {
+	if (!plat_ffa_is_notification_get_valid(current, receiver_vm_id,
+						flags)) {
 		dlog_verbose("Invalid use of notifications get interface.\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 8c0c27b..b7ce7df 100644
--- a/src/arch/aarch64/plat/ffa/absent.c
+++ b/src/arch/aarch64/plat/ffa/absent.c
@@ -170,8 +170,9 @@
 }
 
 bool plat_ffa_is_notification_get_valid(struct vcpu *current,
-					ffa_vm_id_t receiver_id)
+					ffa_vm_id_t receiver_id, uint32_t flags)
 {
+	(void)flags;
 	(void)current;
 	(void)receiver_id;
 	return false;
diff --git a/src/arch/aarch64/plat/ffa/hypervisor.c b/src/arch/aarch64/plat/ffa/hypervisor.c
index 6799535..7a7ec5e 100644
--- a/src/arch/aarch64/plat/ffa/hypervisor.c
+++ b/src/arch/aarch64/plat/ffa/hypervisor.c
@@ -365,10 +365,12 @@
 }
 
 bool plat_ffa_is_notification_get_valid(struct vcpu *current,
-					ffa_vm_id_t receiver_id)
+					ffa_vm_id_t receiver_id, uint32_t flags)
 {
 	ffa_vm_id_t current_vm_id = current->vm->id;
 
+	(void)flags;
+
 	/* If Hafnium is hypervisor, receiver needs to be current vm. */
 	return (current_vm_id == receiver_id);
 }
diff --git a/src/arch/aarch64/plat/ffa/spmc.c b/src/arch/aarch64/plat/ffa/spmc.c
index a40f2d7..942cc0a 100644
--- a/src/arch/aarch64/plat/ffa/spmc.c
+++ b/src/arch/aarch64/plat/ffa/spmc.c
@@ -363,18 +363,29 @@
 }
 
 bool plat_ffa_is_notification_get_valid(struct vcpu *current,
-					ffa_vm_id_t receiver_id)
+					ffa_vm_id_t receiver_id, uint32_t flags)
 {
 	ffa_vm_id_t current_vm_id = current->vm->id;
-
 	/*
 	 * SPMC:
 	 * - An SP can ask for its notifications, or the hypervisor can get
 	 *  notifications target to a VM.
 	 */
-	return (current_vm_id == receiver_id) ||
-	       (current_vm_id == HF_HYPERVISOR_VM_ID &&
-		!vm_id_is_current_world(receiver_id));
+	bool caller_and_receiver_valid =
+		(current_vm_id == receiver_id) ||
+		(current_vm_id == HF_HYPERVISOR_VM_ID &&
+		 !vm_id_is_current_world(receiver_id));
+
+	/*
+	 * Flags field is not valid if NWd endpoint requests notifications from
+	 * VMs or Hypervisor. Those are managed by the hypervisor if present.
+	 */
+	bool flags_valid =
+		!(plat_ffa_is_vm_id(receiver_id) &&
+		  ((flags & FFA_NOTIFICATION_FLAG_BITMAP_VM) != 0U ||
+		   (flags & FFA_NOTIFICATION_FLAG_BITMAP_HYP) != 0U));
+
+	return caller_and_receiver_valid && flags_valid;
 }
 
 void plat_ffa_notification_info_get_forward(  // NOLINTNEXTLINE
diff --git a/src/arch/fake/hypervisor/ffa.c b/src/arch/fake/hypervisor/ffa.c
index efd270b..f4bbd36 100644
--- a/src/arch/fake/hypervisor/ffa.c
+++ b/src/arch/fake/hypervisor/ffa.c
@@ -171,8 +171,9 @@
 }
 
 bool plat_ffa_is_notification_get_valid(struct vcpu *current,
-					ffa_vm_id_t receiver_id)
+					ffa_vm_id_t receiver_id, uint32_t flags)
 {
+	(void)flags;
 	(void)current;
 	(void)receiver_id;
 	return false;
diff --git a/test/vmapi/ffa_secure_partitions/notifications.c b/test/vmapi/ffa_secure_partitions/notifications.c
index e78e82b..bd72dde 100644
--- a/test/vmapi/ffa_secure_partitions/notifications.c
+++ b/test/vmapi/ffa_secure_partitions/notifications.c
@@ -227,3 +227,25 @@
 {
 	base_per_cpu_notifications_test(cpu_entry_sp_to_vm_signaling);
 }
+
+TEST(ffa_notifications, fail_if_mbz_set_in_notification_get)
+{
+	struct ffa_value res;
+	const ffa_vm_id_t sender = SP_ID(1);
+	ffa_vm_id_t own_id = hf_vm_get_id();
+
+	/* Arbitrarily bind notification. */
+	res = ffa_notification_bind(sender, own_id, 0,
+				    FFA_NOTIFICATION_MASK(1));
+	EXPECT_EQ(res.func, FFA_SUCCESS_32);
+
+	/* Requesting sender to set notification. */
+	res = sp_notif_set_cmd_send(own_id, sender, own_id, 0,
+				    FFA_NOTIFICATION_MASK(1));
+	EXPECT_EQ(res.func, FFA_MSG_SEND_DIRECT_RESP_32);
+	EXPECT_EQ(sp_resp(res), SP_SUCCESS);
+
+	/* Check return is FFA_INVALID_PARAMETERS if any bit that MBZ is set. */
+	res = ffa_notification_get(own_id, 0, 0xFF00U);
+	EXPECT_FFA_ERROR(res, FFA_INVALID_PARAMETERS);
+}