fix(hftest): MP tests and S-EL0 partition

Introducing an S-EL0 partition into the 'ffa_secure_partitions' test has
broken the tests that run a MP setup.
Added function to fetch the information of the FF-A partitions in the
system. Using the UUID to determine the target of a test command, thus
helping to make an S-EL1 partition and an S-EL0 partition
interchangeable. Another S-EL1 partition was made the first to boot,
given it is an MP partition.
Power management tests validate that all SPs are running as expected.

Change-Id: If36378d93be4593bbfd1bedb7473c713e6426473
Signed-off-by: J-Alves <joao.alves@arm.com>
diff --git a/test/inc/test/vmapi/ffa.h b/test/inc/test/vmapi/ffa.h
index c2c1f71..8fc1223 100644
--- a/test/inc/test/vmapi/ffa.h
+++ b/test/inc/test/vmapi/ffa.h
@@ -70,3 +70,7 @@
 						     void *send_buf,
 						     struct ffa_value msg_ret,
 						     int32_t expected_error);
+
+ffa_vm_count_t get_ffa_partition_info(struct ffa_uuid *uuid,
+				      struct ffa_partition_info *info,
+				      size_t info_size);
diff --git a/test/vmapi/common/ffa.c b/test/vmapi/common/ffa.c
index 62f5d51..8d48bad 100644
--- a/test/vmapi/common/ffa.c
+++ b/test/vmapi/common/ffa.c
@@ -8,6 +8,7 @@
 
 #include "hf/ffa.h"
 
+#include "hf/check.h"
 #include "hf/mm.h"
 #include "hf/static_assert.h"
 
@@ -326,3 +327,34 @@
 
 	return sender;
 }
+
+ffa_vm_count_t get_ffa_partition_info(struct ffa_uuid *uuid,
+				      struct ffa_partition_info *info,
+				      size_t info_size)
+{
+	struct ffa_value ret;
+	struct ffa_partition_info *ret_info = set_up_mailbox().recv;
+
+	CHECK(uuid != NULL);
+	CHECK(info != NULL);
+
+	ffa_version(MAKE_FFA_VERSION(1, 1));
+
+	ret = ffa_partition_info_get(uuid, 0);
+
+	if (ffa_func_id(ret) != FFA_SUCCESS_32) {
+		return 0;
+	}
+
+	if (ret.arg2 != 0) {
+		size_t src_size = ret.arg2 * sizeof(struct ffa_partition_info);
+		size_t dest_size =
+			info_size * sizeof(struct ffa_partition_info);
+
+		memcpy_s(info, dest_size, ret_info, src_size);
+	}
+
+	ffa_rx_release();
+
+	return ret.arg2;
+}
diff --git a/test/vmapi/ffa_secure_partitions/BUILD.gn b/test/vmapi/ffa_secure_partitions/BUILD.gn
index 7a66035..6351f82 100644
--- a/test/vmapi/ffa_secure_partitions/BUILD.gn
+++ b/test/vmapi/ffa_secure_partitions/BUILD.gn
@@ -19,9 +19,7 @@
   sources = [
     "dir_msg.c",
     "notifications.c",
-
-    #TODO: Make changes to this patch, work with power_mgt.c
-    #"power_mgt.c",
+    "power_mgt.c",
     "setup_and_discovery.c",
   ]
 
diff --git a/test/vmapi/ffa_secure_partitions/partition_manifest_services_secondary_sp.dts b/test/vmapi/ffa_secure_partitions/partition_manifest_services_secondary_sp.dts
index a85e01f..f3b52b4 100644
--- a/test/vmapi/ffa_secure_partitions/partition_manifest_services_secondary_sp.dts
+++ b/test/vmapi/ffa_secure_partitions/partition_manifest_services_secondary_sp.dts
@@ -22,6 +22,6 @@
 	entrypoint-offset = <0x1000>;
 	xlat-granule = <0>; /* 4KiB */
 	messaging-method = <0x3>; /* Supports sending/receiving direct requests. */
-	boot-order = <3>;
+	boot-order = <1>;
 	notification-support; /* Receipt of notifications. */
 };
diff --git a/test/vmapi/ffa_secure_partitions/partition_manifest_services_sp.dts b/test/vmapi/ffa_secure_partitions/partition_manifest_services_sp.dts
index 9160604..2d56311 100644
--- a/test/vmapi/ffa_secure_partitions/partition_manifest_services_sp.dts
+++ b/test/vmapi/ffa_secure_partitions/partition_manifest_services_sp.dts
@@ -22,6 +22,6 @@
 	entrypoint-offset = <0x1000>;
 	xlat-granule = <0>; /* 4KiB */
 	messaging-method = <0x3>; /* Supports sending/receiving direct requests. */
-	boot-order = <1>; /* This should be the highest priority partition */
+	boot-order = <4>;
 	notification-support; /* Receipt of notifications. */
 };
diff --git a/test/vmapi/ffa_secure_partitions/partition_manifest_services_tertiary_sel0_sp.dts b/test/vmapi/ffa_secure_partitions/partition_manifest_services_tertiary_sel0_sp.dts
index a2f346e..e3fe862 100644
--- a/test/vmapi/ffa_secure_partitions/partition_manifest_services_tertiary_sel0_sp.dts
+++ b/test/vmapi/ffa_secure_partitions/partition_manifest_services_tertiary_sel0_sp.dts
@@ -22,6 +22,6 @@
   entrypoint-offset = <0x1000>;
   xlat-granule = <0>; /* 4KiB */
   messaging-method = <0x3>; /* Direct messaging only */
-  boot-order = <1>;
+  boot-order = <4>;
   notification-support; /* Receipt of notifications. */
 };
diff --git a/test/vmapi/ffa_secure_partitions/power_mgt.c b/test/vmapi/ffa_secure_partitions/power_mgt.c
index 35d5e4f..7800538 100644
--- a/test/vmapi/ffa_secure_partitions/power_mgt.c
+++ b/test/vmapi/ffa_secure_partitions/power_mgt.c
@@ -14,57 +14,113 @@
 
 #include "vmapi/hf/call.h"
 
+#include "ffa_endpoints.h"
 #include "partition_services.h"
 #include "test/hftest.h"
 #include "test/vmapi/ffa.h"
 
 alignas(4096) static uint8_t secondary_ec_stack[MAX_CPUS - 1][4096];
 
+struct pwr_mgt_cpu_entry_args {
+	ffa_vm_id_t receiver_id;
+	ffa_vcpu_index_t vcpu_id;
+	struct spinlock lock;
+};
+
 /**
  * Releases the lock passed in.
  */
 static void cpu_entry_echo(uintptr_t arg)
 {
 	ffa_vm_id_t own_id = hf_vm_get_id();
-	// NOLINTNEXTLINE(performance-no-int-to-ptr)
-	struct spinlock *lock = (struct spinlock *)arg;
 	const uint32_t msg[] = {SP_ECHO_CMD, 0x1, 0x2, 0x3, 0x4};
-	const ffa_vm_id_t receiver_id = HF_OTHER_WORLD_ID + 1;
+	struct pwr_mgt_cpu_entry_args *args =
+		// NOLINTNEXTLINE(performance-no-int-to-ptr)
+		(struct pwr_mgt_cpu_entry_args *)arg;
 	struct ffa_value res;
 
-	res = sp_echo_cmd_send(own_id, receiver_id, msg[0], msg[1], msg[2],
-			       msg[3]);
+	res = sp_echo_cmd_send(own_id, args->receiver_id, msg[0], msg[1],
+			       msg[2], msg[3]);
 
-	EXPECT_EQ(res.func, FFA_MSG_SEND_DIRECT_RESP_32);
+	EXPECT_EQ(ffa_func_id(res), FFA_MSG_SEND_DIRECT_RESP_32);
 	EXPECT_EQ(res.arg4, msg[0]);
 	EXPECT_EQ(res.arg5, msg[1]);
 	EXPECT_EQ(res.arg6, msg[2]);
 	EXPECT_EQ(res.arg7, msg[3]);
 
-	sl_unlock(lock);
+	sl_unlock(&args->lock);
 
 	arch_cpu_stop();
 }
 
-TEST(ffa_power_mgt, cpu_start)
+static void cpu_entry_echo_second_sp(uintptr_t arg)
 {
-	struct spinlock lock = SPINLOCK_INIT;
+	struct pwr_mgt_cpu_entry_args *args =
+		// NOLINTNEXTLINE(performance-no-int-to-ptr)
+		(struct pwr_mgt_cpu_entry_args *)arg;
+	struct ffa_value res;
+
+	/*
+	 * Second SP needs FFA_RUN before communicating with it.
+	 * TODO: the FFA_RUN ABI only needs to be called for the MP UP endpoints
+	 * to bootstrap the EC in the current core. Though there is an issue
+	 * with the current FFA_RUN implementation: it returns back to the
+	 * caller with FFA_MSG_WAIT interface, without resuming the target
+	 * SP. When fixing the FFA_RUN issue, this bit of code needs addressing.
+	 */
+	res = ffa_run(args->receiver_id, args->vcpu_id);
+	EXPECT_EQ(ffa_func_id(res), FFA_MSG_WAIT_32);
+
+	cpu_entry_echo(arg);
+}
+
+static void base_cpu_start_test(struct ffa_uuid *recv_uuid,
+				void (*entry)(uintptr_t arg))
+{
+	struct pwr_mgt_cpu_entry_args args = {.lock = SPINLOCK_INIT};
+	struct ffa_partition_info receiver;
+
+	EXPECT_EQ(get_ffa_partition_info(recv_uuid, &receiver, 1), 1);
+
+	args.receiver_id = receiver.vm_id;
 
 	/* Start secondary EC while holding lock. */
-	sl_lock(&lock);
+	sl_lock(&args.lock);
 
-	for (uint32_t i = 0; i < MAX_CPUS - 1; i++) {
-		dlog_verbose("Booting CPU %u\n", i + 1);
+	for (size_t i = 1; i < MAX_CPUS - 1; i++) {
+		size_t hftest_cpu_index = MAX_CPUS - i;
+		HFTEST_LOG("Booting CPU %u", i);
 
-		EXPECT_EQ(hftest_cpu_start(hftest_get_cpu_id(i + 1),
-					   secondary_ec_stack[i],
-					   sizeof(secondary_ec_stack[0]),
-					   cpu_entry_echo, (uintptr_t)&lock),
+		/*
+		 * If receiver is an S-EL0 partition it is expected to have one
+		 * execution context. If it is S-EL1 partition can have MAX_CPUS
+		 * or 1.
+		 */
+		args.vcpu_id =
+			(receiver.vcpu_count == 1) ? 0 : (ffa_vcpu_index_t)i;
+
+		EXPECT_EQ(hftest_cpu_start(hftest_get_cpu_id(hftest_cpu_index),
+					   secondary_ec_stack[i - 1],
+					   sizeof(secondary_ec_stack[0]), entry,
+					   (uintptr_t)&args),
 			  true);
 
 		/* Wait for CPU to release the lock. */
-		sl_lock(&lock);
+		sl_lock(&args.lock);
 
-		dlog_verbose("Done with CPU %u\n", i + 1);
+		HFTEST_LOG("Done with CPU %u", i);
 	}
 }
+
+TEST(ffa_power_mgt, cpu_start_second_sp)
+{
+	/* Second SP can be either S-EL0 or S-EL1 SP. */
+	base_cpu_start_test(&(struct ffa_uuid){SP_SERVICE_SECOND_UUID},
+			    cpu_entry_echo_second_sp);
+}
+
+TEST(ffa_power_mgt, cpu_start_first_sp)
+{
+	base_cpu_start_test(&(struct ffa_uuid){SP_SERVICE_FIRST_UUID},
+			    cpu_entry_echo);
+}
diff --git a/test/vmapi/ffa_secure_partitions/services/inc/ffa_endpoints.h b/test/vmapi/ffa_secure_partitions/services/inc/ffa_endpoints.h
new file mode 100644
index 0000000..9fbd562
--- /dev/null
+++ b/test/vmapi/ffa_secure_partitions/services/inc/ffa_endpoints.h
@@ -0,0 +1,26 @@
+/*
+ * Copyright 2022 The Hafnium Authors.
+ *
+ * Use of this source code is governed by a BSD-style
+ * license that can be found in the LICENSE file or at
+ * https://opensource.org/licenses/BSD-3-Clause.
+ */
+
+#pragma once
+
+/*
+ * FF-A UUID of the SP First. Named as it is the first SP to boot.
+ */
+#define SP_SERVICE_FIRST_UUID                                  \
+	{                                                      \
+		0x9458bb2d, 0x353b4ee2, 0xaa25710c, 0x99b73ddc \
+	}
+
+/*
+ * FF-A UUID of the SP Service Second. Named as it is the second service to
+ * boot. UUID To be shared between S-EL1 and S-EL0 partition.
+ */
+#define SP_SERVICE_SECOND_UUID                     \
+	{                                          \
+		0xa609f132, 0x6b4f, 0x4c14, 0x9489 \
+	}