test(notifications): per-vCPU notifications from VM to SP

Change-Id: I86290fe89d718e5740b96d6142db11a5a77bb9f2
Signed-off-by: J-Alves <joao.alves@arm.com>
diff --git a/inc/vmapi/hf/ffa.h b/inc/vmapi/hf/ffa.h
index 6af065a..cfa44f7 100644
--- a/inc/vmapi/hf/ffa.h
+++ b/inc/vmapi/hf/ffa.h
@@ -506,8 +506,12 @@
 #define FFA_NOTIFICATION_FLAG_BITMAP_SPM UINT32_C(0x1 << 2)
 #define FFA_NOTIFICATION_FLAG_BITMAP_HYP UINT32_C(0x1 << 3)
 
+/* Flag to configure notification as being per vCPU. */
+#define FFA_NOTIFICATIONS_FLAG_PER_VCPU UINT32_C(0x1 << 0)
+
 /** Flag for FFA_NOTIFICATION_SET to delay Schedule Receiver Interrupt */
 #define FFA_NOTIFICATIONS_FLAG_DELAY_SRI UINT32_C(0x1 << 1)
+#define FFA_NOTIFICATIONS_FLAGS_VCPU_ID(id) UINT32_C((id & 0xFFFF) << 16)
 
 static inline ffa_vcpu_index_t ffa_notifications_get_vcpu(struct ffa_value args)
 {
diff --git a/test/vmapi/ffa_secure_partitions/notifications.c b/test/vmapi/ffa_secure_partitions/notifications.c
index a593fb7..f117f69 100644
--- a/test/vmapi/ffa_secure_partitions/notifications.c
+++ b/test/vmapi/ffa_secure_partitions/notifications.c
@@ -6,8 +6,11 @@
  * https://opensource.org/licenses/BSD-3-Clause.
  */
 
+#include "hf/arch/vm/power_mgmt.h"
+
 #include "hf/dlog.h"
 #include "hf/ffa.h"
+#include "hf/spinlock.h"
 
 #include "vmapi/hf/call.h"
 
@@ -15,6 +18,44 @@
 #include "test/hftest.h"
 #include "test/vmapi/ffa.h"
 
+struct notif_cpu_entry_args {
+	struct spinlock *lock;
+	ffa_vcpu_index_t vcpu_id;
+};
+
+static void notif_signal_vm_to_sp(ffa_vm_id_t sender, ffa_vm_id_t receiver,
+				  ffa_notifications_bitmap_t bitmap,
+				  uint32_t flags)
+{
+	struct ffa_value res;
+	ffa_vcpu_index_t vcpu_id = (flags >> 16U) & 0xFFFFU;
+
+	/* Request receiver to bind notifications. */
+	res = sp_notif_bind_cmd_send(sender, receiver, sender,
+				     flags & FFA_NOTIFICATION_FLAG_PER_VCPU,
+				     bitmap);
+	EXPECT_EQ(res.func, FFA_MSG_SEND_DIRECT_RESP_32);
+	EXPECT_EQ(sp_resp(res), SP_SUCCESS);
+
+	res = ffa_notification_set(sender, receiver, flags, bitmap);
+	EXPECT_EQ(res.func, FFA_SUCCESS_32);
+
+	res = ffa_notification_info_get();
+	EXPECT_EQ(res.func, FFA_SUCCESS_64);
+
+	/* Request to get notifications pending */
+	res = sp_notif_get_cmd_send(sender, receiver, vcpu_id,
+				    FFA_NOTIFICATION_FLAG_BITMAP_VM);
+	EXPECT_EQ(sp_resp(res), SP_SUCCESS);
+	EXPECT_EQ(sp_notif_get_from_sp(res), 0);
+	EXPECT_EQ(sp_notif_get_from_vm(res), bitmap);
+
+	/* Request to unbind notifications */
+	res = sp_notif_unbind_cmd_send(sender, receiver, sender, bitmap);
+	EXPECT_EQ(res.func, FFA_MSG_SEND_DIRECT_RESP_32);
+	EXPECT_EQ(sp_resp(res), SP_SUCCESS);
+}
+
 /**
  * Test to validate notifications signaling from an SP to a VM.
  */
@@ -32,7 +73,6 @@
 	/* Requesting sender to set notification. */
 	res = sp_notif_set_cmd_send(own_id, notification_sender, own_id,
 				    FFA_NOTIFICATIONS_FLAG_DELAY_SRI, bitmap);
-
 	EXPECT_EQ(res.func, FFA_MSG_SEND_DIRECT_RESP_32);
 	EXPECT_EQ(sp_resp(res), SP_SUCCESS);
 
@@ -59,35 +99,56 @@
  */
 TEST(ffa_notifications, signaling_from_vm_to_sp)
 {
-	struct ffa_value res;
-	ffa_vm_id_t own_id = hf_vm_get_id();
-	const ffa_vm_id_t notification_receiver = SP_ID(1);
-	const ffa_notifications_bitmap_t bitmap = FFA_NOTIFICATION_MASK(35);
+	notif_signal_vm_to_sp(hf_vm_get_id(), SP_ID(1),
+			      FFA_NOTIFICATION_MASK(35),
+			      FFA_NOTIFICATIONS_FLAG_DELAY_SRI);
+}
 
-	/* Request receiver to bind notifications. */
-	res = sp_notif_bind_cmd_send(own_id, notification_receiver, own_id, 0,
-				     bitmap);
-	EXPECT_EQ(res.func, FFA_MSG_SEND_DIRECT_RESP_32);
-	EXPECT_EQ(sp_resp(res), SP_SUCCESS);
+static void cpu_entry_vm_to_sp_signaling(uintptr_t arg)
+{
+	struct notif_cpu_entry_args *test_args =
+		// NOLINTNEXTLINE(performance-no-int-to-ptr)
+		(struct notif_cpu_entry_args *)arg;
 
-	res = ffa_notification_set(own_id, notification_receiver,
-				   FFA_NOTIFICATIONS_FLAG_DELAY_SRI, bitmap);
-	EXPECT_EQ(res.func, FFA_SUCCESS_32);
+	notif_signal_vm_to_sp(
+		hf_vm_get_id(), SP_ID(1),
+		FFA_NOTIFICATION_MASK(test_args->vcpu_id),
+		FFA_NOTIFICATIONS_FLAG_DELAY_SRI |
+			FFA_NOTIFICATIONS_FLAG_PER_VCPU |
+			FFA_NOTIFICATIONS_FLAGS_VCPU_ID(test_args->vcpu_id));
 
-	res = ffa_notification_info_get();
-	EXPECT_EQ(res.func, FFA_SUCCESS_64);
+	sl_unlock(test_args->lock);
 
-	/* Request to get notifications pending */
-	res = sp_notif_get_cmd_send(own_id, notification_receiver, 0,
-				    FFA_NOTIFICATION_FLAG_BITMAP_VM);
+	arch_cpu_stop();
+}
 
-	EXPECT_EQ(sp_resp(res), SP_SUCCESS);
-	EXPECT_EQ(sp_notif_get_from_sp(res), 0);
-	EXPECT_EQ(sp_notif_get_from_vm(res), bitmap);
+TEST(ffa_notifications, per_vcpu_vm_to_sp)
+{
+	struct spinlock lock = SPINLOCK_INIT;
+	alignas(4096) static uint8_t other_stack[MAX_CPUS - 1][4096];
+	struct notif_cpu_entry_args args = {.lock = &lock};
 
-	/* Request to unbind notifications */
-	res = sp_notif_unbind_cmd_send(own_id, notification_receiver, own_id,
-				       bitmap);
-	EXPECT_EQ(res.func, FFA_MSG_SEND_DIRECT_RESP_32);
-	EXPECT_EQ(sp_resp(res), SP_SUCCESS);
+	/* Start secondary while holding lock. */
+	sl_lock(&lock);
+
+	for (size_t i = 1; i < MAX_CPUS - 1; i++) {
+		size_t hftest_cpu_index = MAX_CPUS - i;
+		HFTEST_LOG(
+			"Notifications signaling VM to SP. Booting CPU %u. \n",
+			i);
+
+		args.vcpu_id = i;
+
+		EXPECT_EQ(hftest_cpu_start(hftest_get_cpu_id(hftest_cpu_index),
+					   other_stack[i - 1],
+					   sizeof(other_stack[0]),
+					   cpu_entry_vm_to_sp_signaling,
+					   (uintptr_t)&args),
+			  true);
+
+		/* Wait for CPU to release the lock. */
+		sl_lock(&lock);
+
+		HFTEST_LOG("Done with CPU %u\n", i);
+	}
 }
diff --git a/test/vmapi/ffa_secure_partitions/services/inc/partition_services.h b/test/vmapi/ffa_secure_partitions/services/inc/partition_services.h
index 3a08de5..638ef6c 100644
--- a/test/vmapi/ffa_secure_partitions/services/inc/partition_services.h
+++ b/test/vmapi/ffa_secure_partitions/services/inc/partition_services.h
@@ -130,6 +130,11 @@
 				       vcpu_id, flags, 0, 0);
 }
 
+static inline uint16_t sp_notif_vcpu(struct ffa_value cmd)
+{
+	return (uint16_t)cmd.arg4;
+}
+
 struct ffa_value sp_notif_get_cmd(ffa_vm_id_t test_source, uint16_t vcpu_id,
 				  uint32_t flags);
 
diff --git a/test/vmapi/ffa_secure_partitions/services/message_loop.c b/test/vmapi/ffa_secure_partitions/services/message_loop.c
index 3144a95..5b7723d 100644
--- a/test/vmapi/ffa_secure_partitions/services/message_loop.c
+++ b/test/vmapi/ffa_secure_partitions/services/message_loop.c
@@ -46,7 +46,8 @@
 				sp_notif_flags(res), sp_notif_bitmap(res));
 			break;
 		case SP_NOTIF_GET_CMD:
-			res = sp_notif_get_cmd(ffa_sender(res), 0,
+			res = sp_notif_get_cmd(ffa_sender(res),
+					       sp_notif_vcpu(res),
 					       sp_notif_flags(res));
 			break;
 		case SP_NOTIF_BIND_CMD: