Merge changes from topic "mb/lfa-rmm-test"

* changes:
  test(realm): perform LFA of RMM with Realm Payload
  feat(lfa): add multi-CPU test for LFA of RMM
  feat(lfa): add LFA SMCs tests using a single CPU
diff --git a/include/runtime_services/host_realm_managment/host_realm_lfa.h b/include/runtime_services/host_realm_managment/host_realm_lfa.h
new file mode 100644
index 0000000..868b004
--- /dev/null
+++ b/include/runtime_services/host_realm_managment/host_realm_lfa.h
@@ -0,0 +1,12 @@
+/*
+ * Copyright (c) 2025, Arm Limited. All rights reserved.
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef HOST_REALM_LFA_H
+#define HOST_REALM_LFA_H
+
+test_result_t test_lfa_activate_rmm(void);
+test_result_t test_lfa_version(void);
+
+#endif /* HOST_REALM_LFA_H */
diff --git a/include/runtime_services/lfa.h b/include/runtime_services/lfa.h
new file mode 100644
index 0000000..09d397d
--- /dev/null
+++ b/include/runtime_services/lfa.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2025, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef LFA_H
+#define LFA_H
+
+#include <stdint.h>
+
+#include <arch_helpers.h>
+#include <arm_arch_svc.h>
+#include <smccc.h>
+
+#define LFA_VERSION_MAJOR		U(1)
+#define LFA_VERSION_MINOR		U(0)
+#define LFA_VERSION_MAJOR_SHIFT		U(16)
+#define LFA_VERSION_MAJOR_MASK 		U(0x7FFF)
+#define LFA_VERSION_MINOR_SHIFT		U(0)
+#define LFA_VERSION_MINOR_MASK		U(0xFFFF)
+
+#define LFA_VERSION			U(0xC40002E0)
+#define LFA_FEATURES			U(0xC40002E1)
+#define LFA_GET_INFO			U(0xC40002E2)
+#define LFA_GET_INVENTORY		U(0xC40002E3)
+#define LFA_PRIME			U(0xC40002E4)
+#define LFA_ACTIVATE			U(0xC40002E5)
+#define LFA_CANCEL			U(0xC40002E6)
+#define LFA_INVALID			LFA_CANCEL + 1U
+
+#endif /* LFA_H */
diff --git a/tftf/tests/runtime_services/lfa/test_lfa_multi_cpu.c b/tftf/tests/runtime_services/lfa/test_lfa_multi_cpu.c
new file mode 100644
index 0000000..59fe81f
--- /dev/null
+++ b/tftf/tests/runtime_services/lfa/test_lfa_multi_cpu.c
@@ -0,0 +1,131 @@
+/*
+ * Copyright (c) 2025, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch_helpers.h>
+#include <events.h>
+#include <lfa.h>
+#include <plat_topology.h>
+#include <platform.h>
+#include <power_management.h>
+#include <psci.h>
+#include <spinlock.h>
+#include <test_helpers.h>
+#include <tftf_lib.h>
+
+#define RMM_X1	UL(0x564bf212a662076c)
+#define RMM_X2	UL(0xd90636638fbacb92)
+
+static uint64_t fw_id;
+
+/*
+ * Test entry point function for non-lead CPUs.
+ * Specified by the lead CPU when bringing up other CPUs.
+ */
+static test_result_t non_lead_cpu_fn(void)
+{
+	smc_args args = { .fid = LFA_ACTIVATE, .arg1 = fw_id };
+	smc_ret_values ret;
+
+	ret = tftf_smc(&args);
+	if (ret.ret0 != SMC_OK) {
+		tftf_testcase_printf("%s: LFA_ACTIVATE error: 0x%08lx\n",
+				     __func__, ret.ret0);
+		return TEST_RESULT_FAIL;
+	}
+	return TEST_RESULT_SUCCESS;
+}
+
+static test_result_t test_lfa_activate_flow(uint64_t uuid1, uint64_t uuid2)
+{
+	unsigned int lead_mpid;
+	unsigned int cpu_mpid, cpu_node;
+	int psci_ret;
+
+	lead_mpid = read_mpidr_el1() & MPID_MASK;
+
+	SKIP_TEST_IF_LESS_THAN_N_CPUS(2);
+
+	smc_args args = { .fid = LFA_GET_INFO, .arg1 = 0 };
+	smc_ret_values ret;
+	uint64_t i, j;
+	bool found = false;
+
+	ret = tftf_smc(&args);
+	if (ret.ret0 != SMC_OK) {
+		tftf_testcase_printf("%s: LFA_GET_INFO error: 0x%08lx\n",
+				     __func__, ret.ret0);
+		return TEST_RESULT_FAIL;
+	}
+	j = ret.ret1;
+
+	for (i = 0U; i < j; i++) {
+		args.fid = LFA_GET_INVENTORY;
+		args.arg1 = i;
+		ret = tftf_smc(&args);
+		if (ret.ret0 != 0) {
+			tftf_testcase_printf("%s: LFA_GET_INVENTORY error: 0x%08lx\n",
+					     __func__, ret.ret0);
+			return TEST_RESULT_FAIL;
+		}
+		tftf_testcase_printf("ID %lld: 0x%16lx 0x%16lx - capable: %s, pending: %s\n",
+			i, ret.ret1, ret.ret2,
+			(ret.ret4 & 0x1) ? "yes" : "no",
+			(ret.ret4 & 0x2) ? "yes" : "no");
+
+		if ((ret.ret1 == uuid1) && (ret.ret2 == uuid2)) {
+			found = true;
+			fw_id = i;
+		}
+	}
+
+	if (found == false) {
+		tftf_testcase_printf("%s: Firmware not found\n", __func__);
+		return TEST_RESULT_SKIPPED;
+	}
+
+	args.fid = LFA_PRIME;
+	args.arg1 = fw_id;
+	ret = tftf_smc(&args);
+	if (ret.ret0 != SMC_OK) {
+		tftf_testcase_printf("%s: LFA_PRIME error: 0x%08lx\n",
+				     __func__, ret.ret0);
+		return TEST_RESULT_FAIL;
+	}
+
+	/* Power on all CPUs */
+	for_each_cpu(cpu_node) {
+		cpu_mpid = tftf_get_mpidr_from_node(cpu_node);
+		/* Skip lead CPU as it is already powered on */
+		if (cpu_mpid == lead_mpid)
+			continue;
+
+		psci_ret = tftf_cpu_on(cpu_mpid, (uintptr_t) non_lead_cpu_fn, 0);
+		if (psci_ret != PSCI_E_SUCCESS) {
+			tftf_testcase_printf(
+				"Failed to power on CPU 0x%x (%d)\n",
+				cpu_mpid, psci_ret);
+			return TEST_RESULT_SKIPPED;
+		}
+	}
+
+	args.fid = LFA_ACTIVATE;
+	args.arg1 = fw_id;
+	ret = tftf_smc(&args);
+	if (ret.ret0 != SMC_OK) {
+		tftf_testcase_printf("%s: LFA_ACTIVATE error: 0x%08lx\n", __func__, ret.ret0);
+		return TEST_RESULT_FAIL;
+	}
+
+	return TEST_RESULT_SUCCESS;
+}
+
+/*
+ * @Test_Aim@ Test RMM Live activation.
+ */
+test_result_t test_lfa_activate_rmm(void)
+{
+	return test_lfa_activate_flow(RMM_X1, RMM_X2);
+}
diff --git a/tftf/tests/runtime_services/lfa/test_lfa_single_cpu.c b/tftf/tests/runtime_services/lfa/test_lfa_single_cpu.c
new file mode 100644
index 0000000..796f3e9
--- /dev/null
+++ b/tftf/tests/runtime_services/lfa/test_lfa_single_cpu.c
@@ -0,0 +1,199 @@
+/*
+ * Copyright (c) 2025, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <debug.h>
+#include <lfa.h>
+#include <test_helpers.h>
+#include <tftf_lib.h>
+
+#define LFA_GET_INVENTORY_RESP_X1	UL(0x4698fe4c6d08d447)
+#define LFA_GET_INVENTORY_RESP_X2	UL(0x005abdcb5029959b)
+
+static uint64_t num_components;
+static uint64_t fw_id;
+
+/*
+ * @Test_Aim@ Simple surface tests for Live Firmware Activation.
+ *
+ * This test checks the version number. It runs on the lead CPU.
+ */
+test_result_t test_lfa_version(void)
+{
+	smc_args args = { LFA_VERSION };
+	uint32_t major, minor;
+	smc_ret_values ret = tftf_smc(&args);
+
+	major = (uint32_t)((ret.ret0 >> LFA_VERSION_MAJOR_SHIFT) & LFA_VERSION_MAJOR_MASK);
+	minor = (uint32_t)((ret.ret0 >> LFA_VERSION_MINOR_SHIFT) & LFA_VERSION_MINOR_MASK);
+
+	VERBOSE("%s LFA API Version : %d.%d\n", __func__, major, minor);
+
+	if ((major != LFA_VERSION_MAJOR) || (minor != LFA_VERSION_MINOR)) {
+		return TEST_RESULT_FAIL;
+	}
+
+	return TEST_RESULT_SUCCESS;
+}
+
+/*
+ * @Test_Aim@ Test for LFA_FEATURES.
+ *
+ * This test checks LFA_FEATURES for the two extreme FID values and then does
+ * one negative test.
+ */
+test_result_t test_lfa_features(void)
+{
+	smc_args args = { .fid = LFA_FEATURES, .arg1 = LFA_VERSION };
+	smc_ret_values ret = tftf_smc(&args);
+
+	if (ret.ret0 != SMC_OK) {
+		tftf_testcase_printf("%s: Features for FID=0x%08lx returned %08lx\n",
+				     __func__, args.arg1, ret.ret0);
+		return TEST_RESULT_FAIL;
+	}
+
+	args.arg1 = LFA_CANCEL;
+	ret = tftf_smc(&args);
+	if (ret.ret0 != SMC_OK) {
+		tftf_testcase_printf("%s: Features for FID=0x%08lx returned %08lx\n",
+				     __func__, args.arg1, ret.ret0);
+		return TEST_RESULT_FAIL;
+	}
+
+	args.arg1 = LFA_INVALID;
+	ret = tftf_smc(&args);
+	if (ret.ret0 == SMC_OK) {
+		tftf_testcase_printf("%s: Features for FID=0x%08lx returned %08lx\n",
+				     __func__, args.arg1, ret.ret0);
+		return TEST_RESULT_FAIL;
+	}
+
+	return TEST_RESULT_SUCCESS;
+}
+
+/*
+ * @Test_Aim@ Test for LFA_GET_INFO.
+ *
+ * This test checks that LFA_GET_INFO returns successfully and the proper
+ * error if an invalid lfa_selector is provided.
+ */
+test_result_t test_lfa_get_info(void)
+{
+	smc_args args = { .fid = LFA_GET_INFO, .arg1 = 0U };
+	smc_ret_values ret = tftf_smc(&args);
+
+	if (ret.ret0 != SMC_OK) {
+		tftf_testcase_printf("%s: Unexpected error: 0x%08lx\n",
+				     __func__, ret.ret0);
+		return TEST_RESULT_FAIL;
+	}
+
+	num_components = ret.ret1;
+
+	/* Try giving invalid argument and expect Failure from SMC */
+	args.arg1 = 1U;
+	ret = tftf_smc(&args);
+	if (ret.ret0 == SMC_OK) {
+		tftf_testcase_printf("%s: Unexpected success\n", __func__);
+		return TEST_RESULT_FAIL;
+	}
+
+	return TEST_RESULT_SUCCESS;
+}
+
+/*
+ * @Test_Aim@ Test for LFA_GET_INVENTORY.
+ */
+test_result_t test_lfa_get_inventory(void)
+{
+	smc_args args = { .fid = LFA_GET_INVENTORY, .arg1 = 0U };
+	smc_ret_values ret;
+
+	for (uint64_t i = 0U; i < num_components; i++) {
+		args.arg1 = i;
+
+		ret = tftf_smc(&args);
+		if (ret.ret0 != SMC_OK) {
+			tftf_testcase_printf("%s: Unexpected error: 0x%08lx\n",
+					     __func__, ret.ret0);
+			return TEST_RESULT_FAIL;
+		}
+
+		if ((ret.ret1 == LFA_GET_INVENTORY_RESP_X1) &&
+		    (ret.ret2 == LFA_GET_INVENTORY_RESP_X2)) {
+			fw_id = i;
+		}
+	}
+
+	return TEST_RESULT_SUCCESS;
+}
+
+/*
+ * @Test_Aim@ Test for LFA_PRIME.
+ */
+test_result_t test_lfa_prime(void)
+{
+	smc_args args = { .fid = LFA_PRIME, .arg1 = fw_id };
+	smc_ret_values ret = tftf_smc(&args);
+
+	if (ret.ret0 == SMC_OK) {
+		/*
+		 * TODO: currently expected to be failed as BL31 prime
+		 * is not present. This is added to exercise negative
+		 * scenario.
+		 */
+		tftf_testcase_printf("%s: Unexpected error: 0x%08lx\n",
+				     __func__, ret.ret0);
+		return TEST_RESULT_FAIL;
+	}
+
+	return TEST_RESULT_SUCCESS;
+}
+
+/*
+ * @Test_Aim@ Test for LFA_ACTIVATE.
+ */
+test_result_t test_lfa_activate(void)
+{
+	smc_args args = { .fid = LFA_ACTIVATE, .arg1 = fw_id };
+	smc_ret_values ret = tftf_smc(&args);
+
+	if (ret.ret0 == SMC_OK) {
+		/*
+		 * TODO: currently expected to be failed as BL31 activate
+		 * is not present. This is added to exercise negative
+		 * scenario.
+		 */
+		tftf_testcase_printf("%s: Unexpected error: 0x%08lx\n",
+				     __func__, ret.ret0);
+		return TEST_RESULT_FAIL;
+	}
+
+	return TEST_RESULT_SUCCESS;
+}
+
+/*
+ * @Test_Aim@ Test for LFA_CANCEL.
+ */
+test_result_t test_lfa_cancel(void)
+{
+	smc_args args = { .fid = LFA_CANCEL, .arg1 = fw_id };
+	smc_ret_values ret;
+
+	ret = tftf_smc(&args);
+	/*
+	 * TODO: currently expected to be failed as BL31 cancel
+	 * is not present. This is added to exercise negative
+	 * scenario.
+	 */
+	if (ret.ret0 == SMC_OK) {
+		tftf_testcase_printf("%s: Unexpected error: 0x%08lx\n",
+				     __func__, ret.ret0);
+		return TEST_RESULT_FAIL;
+	}
+
+	return TEST_RESULT_SUCCESS;
+}
diff --git a/tftf/tests/runtime_services/realm_payload/host_realm_lfa.c b/tftf/tests/runtime_services/realm_payload/host_realm_lfa.c
new file mode 100644
index 0000000..0da1be9
--- /dev/null
+++ b/tftf/tests/runtime_services/realm_payload/host_realm_lfa.c
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2025, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <stdlib.h>
+
+#include <arch_features.h>
+#include <debug.h>
+#include <host_realm_helper.h>
+#include <host_realm_lfa.h>
+#include <host_realm_mem_layout.h>
+#include <host_shared_data.h>
+#include <test_helpers.h>
+
+test_result_t host_test_realm_rsi_version_with_lfa(void)
+{
+	test_result_t lfa_ret;
+	u_register_t rec_flag[] = {RMI_RUNNABLE};
+	struct realm realm;
+	u_register_t feature_flag0 = 0U;
+	long sl = RTT_MIN_LEVEL;
+	bool ret1, ret2;
+
+	SKIP_TEST_IF_RME_NOT_SUPPORTED_OR_RMM_IS_TRP();
+
+	lfa_ret = test_lfa_version();
+	if (lfa_ret != TEST_RESULT_SUCCESS) {
+		ERROR("%s(): LFA is not supported=%d\n", __func__, lfa_ret);
+		return TEST_RESULT_SKIPPED;
+	}
+
+	if (is_feat_52b_on_4k_2_supported()) {
+		feature_flag0 = RMI_FEATURE_REGISTER_0_LPA2;
+		sl = RTT_MIN_LEVEL_LPA2;
+	}
+
+	if (!host_create_activate_realm_payload(&realm, (u_register_t)REALM_IMAGE_BASE,
+				feature_flag0, 0U, sl, rec_flag, 1U, 0U, get_test_mecid())) {
+		return TEST_RESULT_FAIL;
+	}
+
+	ret1 = host_enter_realm_execute(&realm, REALM_GET_RSI_VERSION, RMI_EXIT_HOST_CALL, 0U);
+	if (!ret1) {
+		ERROR("%s(): Initial enter failed\n", __func__);
+		goto cleanup;
+	}
+
+	/* Activate new RMM and then request RSI version again */
+	lfa_ret = test_lfa_activate_rmm();
+	if (lfa_ret != TEST_RESULT_SUCCESS) {
+		ERROR("%s(): LFA of RMM failed=%d\n", __func__, lfa_ret);
+		goto cleanup;
+	}
+
+	ret1 = host_enter_realm_execute(&realm, REALM_GET_RSI_VERSION, RMI_EXIT_HOST_CALL, 0U);
+	if (!ret1) {
+		ERROR("%s(): Enter Realm with newly activated RMM failed\n", __func__);
+	}
+
+cleanup:
+	ret2 = host_destroy_realm(&realm);
+	if (!ret2) {
+		ERROR("%s(): Realm destroy failed\n", __func__);
+	}
+
+	return (ret1 && ret2) ? host_cmp_result() : TEST_RESULT_FAIL;
+}
diff --git a/tftf/tests/tests-lfa.mk b/tftf/tests/tests-lfa.mk
new file mode 100644
index 0000000..1b42bf5
--- /dev/null
+++ b/tftf/tests/tests-lfa.mk
@@ -0,0 +1,10 @@
+#
+# Copyright (c) 2025, Arm Limited. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+TESTS_SOURCES	+=	$(addprefix tftf/tests/runtime_services/lfa/,	\
+				test_lfa_single_cpu.c			\
+				test_lfa_multi_cpu.c			\
+)
diff --git a/tftf/tests/tests-lfa.xml b/tftf/tests/tests-lfa.xml
new file mode 100644
index 0000000..4b584c7
--- /dev/null
+++ b/tftf/tests/tests-lfa.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+  Copyright (c) 2025, Arm Limited. All rights reserved.
+
+  SPDX-License-Identifier: BSD-3-Clause
+-->
+
+<testsuites>
+  <testsuite name="lfa" description="Live Firmware Activation">
+     <testcase name="Query version" function="test_lfa_version" />
+     <testcase name="Check features" function="test_lfa_features" />
+     <testcase name="Get Info" function="test_lfa_get_info" />
+     <testcase name="Get Inventory" function="test_lfa_get_inventory" />
+     <testcase name="Prime" function="test_lfa_prime" />
+     <testcase name="Activate" function="test_lfa_activate" />
+     <testcase name="Cancel" function="test_lfa_cancel" />
+     <testcase name="RMM Live Activation" function="test_lfa_activate_rmm" />
+  </testsuite>
+</testsuites>
diff --git a/tftf/tests/tests-realm-payload.mk b/tftf/tests/tests-realm-payload.mk
index b5e245b..7e4ac6c 100644
--- a/tftf/tests/tests-realm-payload.mk
+++ b/tftf/tests/tests-realm-payload.mk
@@ -19,6 +19,7 @@
 		host_realm_mpam_tests.c					\
 		host_realm_brbe_tests.c					\
 		host_realm_mec_tests.c					\
+		host_realm_lfa.c					\
 	)
 
 TESTS_SOURCES	+=							\
@@ -66,7 +67,14 @@
 		pcie_dvsec_rmeda.c	\
 	)
 
+TESTS_SOURCES	+=		\
+	$(addprefix tftf/tests/runtime_services/lfa/,	\
+		test_lfa_single_cpu.c \
+		test_lfa_multi_cpu.c \
+	)
+
 ifeq (${ENABLE_REALM_PAYLOAD_TESTS},1)
 include lib/ext_mbedtls/mbedtls.mk
 endif
+
 endif
diff --git a/tftf/tests/tests-realm-payload.xml b/tftf/tests/tests-realm-payload.xml
index ee3f846..8ac98a1 100644
--- a/tftf/tests/tests-realm-payload.xml
+++ b/tftf/tests/tests-realm-payload.xml
@@ -184,5 +184,8 @@
 	  <!-- Invoke DA workflow on PCIe off-chip device -->
 	  <testcase name="DA workflow on all PCIe off-chip devices"
 	  function="host_da_workflow_on_all_offchip_devices" />
+	  <!-- Test case for LFA with Realm Payload -->
+	  <testcase name="Test Live Firmware Activation of RMM with Realm Payload"
+	  function="host_test_realm_rsi_version_with_lfa" />
   </testsuite>
 </testsuites>