test(realm): test for rtt_fold assigned

Test for RTT_FOLD for assigned ram, assigned empty
and assigned ns rtt entries
Fix helper to allow creating L1 block entry for unprotected IPA

Change-Id: I77693f76722d60427edcb112ca58bf772c194b06
Signed-off-by: Shruti Gupta <shruti.gupta@arm.com>
diff --git a/include/runtime_services/host_realm_managment/host_realm_rmi.h b/include/runtime_services/host_realm_managment/host_realm_rmi.h
index 6a1d987..59abdb5 100644
--- a/include/runtime_services/host_realm_managment/host_realm_rmi.h
+++ b/include/runtime_services/host_realm_managment/host_realm_rmi.h
@@ -351,6 +351,7 @@
 #define RTT_LEVEL_SHIFT(l)		XLAT_ADDR_SHIFT(l)
 #define RTT_L2_BLOCK_SIZE		(1UL << RTT_LEVEL_SHIFT(2U))
 #define RTT_MAP_SIZE(level)		(1UL << RTT_LEVEL_SHIFT(level))
+#define RTT_L1_BLOCK_SIZE		(1UL << RTT_LEVEL_SHIFT(1U))
 
 #define REC_CREATE_NR_GPRS		8U
 #define REC_HVC_NR_GPRS			7U
diff --git a/tftf/tests/runtime_services/host_realm_managment/host_realm_rmi.c b/tftf/tests/runtime_services/host_realm_managment/host_realm_rmi.c
index 805153b..22717e5 100644
--- a/tftf/tests/runtime_services/host_realm_managment/host_realm_rmi.c
+++ b/tftf/tests/runtime_services/host_realm_managment/host_realm_rmi.c
@@ -260,10 +260,10 @@
 	return rets.ret0;
 }
 
-static inline u_register_t host_rmi_rtt_mapunprotected(u_register_t rd,
-							u_register_t map_addr,
-							u_register_t level,
-							u_register_t ns_pa)
+u_register_t host_rmi_rtt_mapunprotected(u_register_t rd,
+					 u_register_t map_addr,
+					 u_register_t level,
+					 u_register_t ns_pa)
 {
 	return host_rmi_handler(&(smc_args) {RMI_RTT_MAP_UNPROTECTED,
 				rd, map_addr, level, ns_pa}, 5U).ret0;
@@ -476,6 +476,9 @@
 	case RTT_L2_BLOCK_SIZE:
 		map_level = 2UL;
 		break;
+	case RTT_L1_BLOCK_SIZE:
+		map_level = 1UL;
+		break;
 	default:
 		ERROR("Unknown map_size=0x%lx\n", map_size);
 		return REALM_ERROR;
diff --git a/tftf/tests/runtime_services/realm_payload/host_realm_payload_tests.c b/tftf/tests/runtime_services/realm_payload/host_realm_payload_tests.c
index 6842f49..25c65de 100644
--- a/tftf/tests/runtime_services/realm_payload/host_realm_payload_tests.c
+++ b/tftf/tests/runtime_services/realm_payload/host_realm_payload_tests.c
@@ -2152,3 +2152,344 @@
 
 	return res;
 }
+
+/*
+ * Test aims to test RMI_RTT_FOLD for Unprotected IPA range
+ * Host creates L1 1 GB block entry for unprotected IPA
+ * Host creates L2 entry for the same, this causes unfold of all 512 entries
+ * Host verifies walk_level is 2
+ * Host folds RTT back to L1
+ * Host verifies walk_level is 1
+ */
+test_result_t host_test_rtt_fold_unfold_assigned_ns(void)
+{
+
+	bool ret1;
+	test_result_t res = TEST_RESULT_FAIL;
+	u_register_t ret, ns_ipa, base_pa, top;
+	struct realm realm;
+	struct rtt_entry rtt;
+	u_register_t rec_flag[] = {RMI_RUNNABLE};
+
+	SKIP_TEST_IF_RME_NOT_SUPPORTED_OR_RMM_IS_TRP();
+
+	if (!host_create_activate_realm_payload(&realm, (u_register_t)REALM_IMAGE_BASE,
+			(u_register_t)PAGE_POOL_BASE,
+			(u_register_t)PAGE_POOL_MAX_SIZE,
+			0UL, rec_flag, 1U)) {
+		ERROR("Realm creation failed\n");
+		goto destroy_realm;
+	}
+	if (!host_create_shared_mem(&realm, NS_REALM_SHARED_MEM_BASE,
+			NS_REALM_SHARED_MEM_SIZE)) {
+		goto destroy_realm;
+	}
+
+	/*
+	 * Pick an address which is to be mapped to unprotected IPA space.
+	 * We use TFTF Base as the PA to map in unprotected IPA space of RMM.
+	 * Note that as long as Realm does not explicitly touch this unprotected IPA space,
+	 * it will not hit a fault.
+	 * Hence it does not matter even if the same pages are delegated
+	 * or even if it is invalid memory.
+	 */
+	base_pa = ALIGN(TFTF_BASE, RTT_L1_BLOCK_SIZE);
+	ns_ipa = base_pa | (1UL << (EXTRACT(RMI_FEATURE_REGISTER_0_S2SZ,
+					realm.rmm_feat_reg0) - 1U));
+
+	INFO("base=0x%lx\n", ns_ipa);
+	ret = host_realm_map_unprotected(&realm, base_pa, RTT_L1_BLOCK_SIZE);
+	if (ret != RMI_SUCCESS) {
+		ERROR("host_realm_map_unprotected fail base=0x%lx ret=0x%lx\n", ns_ipa, ret);
+		goto destroy_realm;
+	}
+
+	ret = host_rmi_rtt_readentry(realm.rd, ns_ipa, 3U, &rtt);
+	if (ret != RMI_SUCCESS || rtt.walk_level != 1U || rtt.state != RMI_ASSIGNED) {
+		INFO("rtt.state=0x%lx rtt.walk_level=0x%llx rtt.out_addr=0x%llx\n",
+				rtt.state, rtt.walk_level, rtt.out_addr);
+		goto destroy_realm;
+	}
+	INFO("rtt.state=0x%lx rtt.walk_level=0x%llx rtt.out_addr=0x%llx\n",
+		rtt.state, rtt.walk_level, rtt.out_addr);
+
+	/* Unfold Create L2 RTT entries */
+	ret = host_rmi_create_rtt_levels(&realm, ns_ipa, 1U, 2U);
+	if (ret != RMI_SUCCESS) {
+		ERROR("host_rmi_create_rtt_levels failed ret=0x%lx\n", ret);
+	}
+
+	ret = host_rmi_rtt_readentry(realm.rd, ns_ipa, 3U, &rtt);
+	if (ret != RMI_SUCCESS || rtt.walk_level != 2U || rtt.state != RMI_ASSIGNED) {
+		ERROR("Initial realm table creation changed\n");
+		INFO("rtt.state=0x%lx rtt.walk_level=0x%llx rtt.out_addr=0x%llx\n",
+				rtt.state, rtt.walk_level, rtt.out_addr);
+		goto destroy_realm;
+	}
+	INFO("rtt.state=0x%lx rtt.walk_level=0x%llx rtt.out_addr=0x%llx\n",
+		rtt.state, rtt.walk_level, rtt.out_addr);
+
+	INFO("Fold L2\n");
+	/* RTT Fold */
+	ret = host_realm_fold_rtt(realm.rd, ns_ipa, 2U);
+	if (ret != RMI_SUCCESS) {
+		ERROR("host_rmi_rtt_fold failed ret=0x%lx\n", ret);
+		goto destroy_realm;
+	}
+
+	/* Walk should terminate at L1 */
+	ret = host_rmi_rtt_readentry(realm.rd, ns_ipa, 3U, &rtt);
+	if (ret != RMI_SUCCESS || rtt.walk_level != 1U || rtt.state != RMI_ASSIGNED) {
+		ERROR("host_rmi_fold_rtt failed ret=0x%lx rtt.state=0x%lx"
+				" rtt.walk_level=0x%llx rtt.out_addr=0x%llx\n",
+				ret, rtt.state, rtt.walk_level, rtt.out_addr);
+		goto destroy_realm;
+	}
+	INFO("rtt.state=0x%lx rtt.walk_level=0x%llx rtt.out_addr=0x%llx\n",
+			rtt.state, rtt.walk_level, rtt.out_addr);
+
+	res = TEST_RESULT_SUCCESS;
+	INFO("unmap\n\n");
+
+	/* unmap */
+	ret = host_rmi_rtt_unmap_unprotected(realm.rd, ns_ipa, 1U, &top);
+	if (ret != RMI_SUCCESS) {
+		ERROR("host_rmi_rtt_mapunprotected failed ret=0x%lx\n", ret);
+	}
+
+destroy_realm:
+	ret1 = host_destroy_realm(&realm);
+
+	if (!ret1) {
+		ERROR("%s(): destroy=%d\n",
+		__func__, ret1);
+		return TEST_RESULT_FAIL;
+	}
+
+	return res;
+}
+
+/*
+ * Test aims to test RMI_RTT_FOLD for assigned empty entries
+ * Host calls DATA_CREATE_UNKNOWN on 2 mb range
+ * Host verifies walk_level is 3
+ * Host folds RTT_FOLD Level 2
+ * Host verifies walk_level is 2
+ */
+test_result_t host_test_rtt_fold_unfold_assigned_empty(void)
+{
+	bool ret1;
+	test_result_t res = TEST_RESULT_FAIL;
+	u_register_t ret, base;
+	struct realm realm;
+	struct rtt_entry rtt;
+	u_register_t rec_flag[] = {RMI_RUNNABLE};
+
+	SKIP_TEST_IF_RME_NOT_SUPPORTED_OR_RMM_IS_TRP();
+
+	if (!host_create_activate_realm_payload(&realm, (u_register_t)REALM_IMAGE_BASE,
+			(u_register_t)PAGE_POOL_BASE,
+			(u_register_t)PAGE_POOL_MAX_SIZE,
+			0UL, rec_flag, 1U)) {
+		ERROR("Realm creation failed\n");
+		goto destroy_realm;
+	}
+	if (!host_create_shared_mem(&realm, NS_REALM_SHARED_MEM_BASE,
+			NS_REALM_SHARED_MEM_SIZE)) {
+		goto destroy_realm;
+	}
+
+	/*
+	 * Any 2 MB range not mapped in RTT and which can be delegated,
+	 * using heap for second realm here.
+	 */
+	base = ALIGN_DOWN(PAGE_POOL_BASE + PAGE_POOL_MAX_SIZE, RTT_L2_BLOCK_SIZE);
+
+	for (unsigned int i = 0U; i < 512; i++) {
+		ret = host_realm_delegate_map_protected_data(true, &realm, base + (PAGE_SIZE * i),
+				PAGE_SIZE, 0U);
+		if (ret != RMI_SUCCESS) {
+			ERROR("host_realm_delegate_map_protected_data failed\n");
+			goto undelegate_destroy;
+		}
+	}
+
+	INFO("base=0x%lx\n", base);
+	ret = host_rmi_rtt_readentry(realm.rd, base, 3U, &rtt);
+	if (ret != RMI_SUCCESS || rtt.state != RMI_ASSIGNED ||
+			(rtt.ripas != RMI_EMPTY) || rtt.walk_level != 3U) {
+		ERROR("wrong state after DATA_CRATE_UNKNOWN\n");
+		goto undelegate_destroy;
+	}
+
+	/* RTT Fold */
+	ret = host_realm_fold_rtt(realm.rd, base, 3U);
+	if (ret != RMI_SUCCESS) {
+		ERROR("host_rmi_rtt_fold failed ret=0x%lx\n", ret);
+		goto undelegate_destroy;
+	}
+
+	/* Walk should terminate at L2 */
+	ret = host_rmi_rtt_readentry(realm.rd, base, 3U, &rtt);
+	if (ret != RMI_SUCCESS || rtt.walk_level != 2U || rtt.state != RMI_ASSIGNED ||
+			rtt.ripas != RMI_EMPTY) {
+		ERROR("host_rmi_fold_rtt failed ret=0x%lx rtt.state=0x%lx"
+				" rtt.walk_level=0x%llx rtt.out_addr=0x%llx\n",
+				ret, rtt.state, rtt.walk_level, rtt.out_addr);
+		goto undelegate_destroy;
+	}
+	INFO("rtt.state=0x%lx rtt.walk_level=0x%llx rtt.out_addr=0x%llx ripas=0x%lx\n",
+			rtt.state, rtt.walk_level, rtt.out_addr, rtt.ripas);
+
+	/* Create L3 RTT entries */
+	ret = host_rmi_create_rtt_levels(&realm, base, 2U, 3U);
+	if (ret != RMI_SUCCESS) {
+		ERROR("host_rmi_create_rtt_levels failed ret=0x%lx\n", ret);
+		goto destroy_realm;
+	}
+
+	/* L3 entry should be created */
+	ret = host_rmi_rtt_readentry(realm.rd, base, 3U, &rtt);
+	if (ret != RMI_SUCCESS || rtt.walk_level != 3U || rtt.state != RMI_ASSIGNED ||
+			rtt.ripas != RMI_EMPTY) {
+		ERROR("host_rmi_create_rtt_levels failed ret=0x%lx\n", ret);
+		goto destroy_realm;
+	}
+	INFO("rtt.state=0x%lx rtt.walk_level=0x%llx rtt.out_addr=0x%llx ripas=0x%lx\n",
+			rtt.state, rtt.walk_level, rtt.out_addr, rtt.ripas);
+
+	res = TEST_RESULT_SUCCESS;
+
+undelegate_destroy:
+	if (res != TEST_RESULT_SUCCESS) {
+		for (unsigned int i = 0U; i < 512; i++) {
+			ret = host_rmi_granule_undelegate(base + (PAGE_SIZE * i));
+			if (ret != RMI_SUCCESS) {
+				ERROR("host_rmi_granule_undelegate failed base=0x%lx ret=0x%lx\n",
+					base, ret);
+			}
+		}
+	}
+destroy_realm:
+	ret1 = host_destroy_realm(&realm);
+	if (!ret1) {
+		ERROR("%s(): destroy=%d\n",
+		__func__, ret1);
+		return TEST_RESULT_FAIL;
+	}
+	return res;
+}
+
+/*
+ * Test aims to test RMI_RTT_FOLD for assigned ram entries
+ * Host calls DATA_CREATE on 2 mb range
+ * Host verifies walk_level is 3
+ * Host folds RTT_FOLD Level 2
+ * Host verifies walk_level is 2 and RIPAS is RAM
+ */
+test_result_t host_test_rtt_fold_unfold_assigned_ram(void)
+{
+	bool ret1;
+	test_result_t res = TEST_RESULT_FAIL;
+	u_register_t ret, base;
+	struct realm realm;
+	struct rtt_entry rtt;
+	u_register_t rec_flag[] = {RMI_RUNNABLE};
+
+	SKIP_TEST_IF_RME_NOT_SUPPORTED_OR_RMM_IS_TRP();
+
+	if (!host_create_realm_payload(&realm, (u_register_t)REALM_IMAGE_BASE,
+			(u_register_t)PAGE_POOL_BASE,
+			(u_register_t)PAGE_POOL_MAX_SIZE,
+			0UL, rec_flag, 1U)) {
+		ERROR("Realm creation failed\n");
+		goto destroy_realm;
+	}
+	if (!host_create_shared_mem(&realm, NS_REALM_SHARED_MEM_BASE,
+			NS_REALM_SHARED_MEM_SIZE)) {
+		goto destroy_realm;
+	}
+
+	/*
+	 * Any 2 MB range not mapped in RTT and which can be delegated,
+	 * using heap for second realm here.
+	 */
+	base = ALIGN_DOWN(PAGE_POOL_BASE + (PAGE_POOL_MAX_SIZE), RTT_L2_BLOCK_SIZE);
+
+	INFO("base=0x%lx\n", base);
+	for (unsigned int i = 0U; i < 512; i++) {
+		ret = host_realm_delegate_map_protected_data(false, &realm, base + (PAGE_SIZE * i),
+				PAGE_SIZE, REALM_IMAGE_BASE);
+		if (ret != RMI_SUCCESS) {
+			ERROR("host_realm_delegate_map_protected_data failed base=0x%lx\n",
+					base + (PAGE_SIZE * i));
+			goto undelegate_destroy;
+		}
+	}
+
+	/* INIT_RIPAS should move state to unassigned ram */
+	ret = host_rmi_rtt_readentry(realm.rd, base, 3U, &rtt);
+	if (ret != RMI_SUCCESS || rtt.state != RMI_ASSIGNED ||
+			(rtt.ripas != RMI_RAM)) {
+		ERROR("wrong state after INIT_RIPAS\n");
+		return TEST_RESULT_FAIL;
+	}
+	host_realm_activate(&realm);
+
+	/* RTT Fold */
+	ret = host_realm_fold_rtt(realm.rd, base, 3U);
+	if (ret != RMI_SUCCESS) {
+		ERROR("host_rmi_rtt_fold failed ret=0x%lx\n", ret);
+		goto undelegate_destroy;
+	}
+
+	/* Walk should terminate at L2 */
+	ret = host_rmi_rtt_readentry(realm.rd, base, 3U, &rtt);
+	if (ret != RMI_SUCCESS || rtt.walk_level != 2U || rtt.state != RMI_ASSIGNED ||
+			rtt.ripas != RMI_RAM) {
+		ERROR("host_rmi_fold_rtt failed ret=0x%lx rtt.state=0x%lx"
+			" rtt.walk_level=0x%llx rtt.out_addr=0x%llx ripas=0x%lx\n",
+				ret, rtt.state, rtt.walk_level, rtt.out_addr, rtt.ripas);
+		goto undelegate_destroy;
+	}
+	INFO("rtt.state=0x%lx rtt.walk_level=0x%llx rtt.out_addr=0x%llx rtt.ripas=0x%lx\n",
+			rtt.state, rtt.walk_level, rtt.out_addr, rtt.ripas);
+
+	/* Create L3 RTT entries */
+	ret = host_rmi_create_rtt_levels(&realm, base, 2U, 3U);
+	if (ret != RMI_SUCCESS) {
+		ERROR("host_rmi_create_rtt_levels failed ret=0x%lx\n", ret);
+		goto destroy_realm;
+	}
+
+	/* L3 entry should be created */
+	ret = host_rmi_rtt_readentry(realm.rd, base, 3U, &rtt);
+	if (ret != RMI_SUCCESS || rtt.walk_level != 3U || rtt.state != RMI_ASSIGNED ||
+			rtt.ripas != RMI_RAM) {
+		ERROR("host_rmi_create_rtt_levels failed ret=0x%lx\n", ret);
+		goto destroy_realm;
+	}
+	INFO("rtt.state=0x%lx rtt.walk_level=0x%llx rtt.out_addr=0x%llx ripas=0x%lx\n",
+			rtt.state, rtt.walk_level, rtt.out_addr, rtt.ripas);
+
+	res = TEST_RESULT_SUCCESS;
+
+undelegate_destroy:
+	if (res != TEST_RESULT_SUCCESS) {
+		for (unsigned int i = 0U; i < 512; i++) {
+			ret = host_rmi_granule_undelegate(base + (PAGE_SIZE * i));
+			if (ret != RMI_SUCCESS) {
+				ERROR("host_rmi_granule_undelegate failed base=0x%lx ret=0x%lx\n",
+					base + (PAGE_SIZE * i), ret);
+			}
+		}
+	}
+destroy_realm:
+	ret1 = host_destroy_realm(&realm);
+	if (!ret1) {
+		ERROR("%s(): destroy=%d\n",
+		__func__, ret1);
+		return TEST_RESULT_FAIL;
+	}
+	return res;
+}
diff --git a/tftf/tests/tests-realm-payload.xml b/tftf/tests/tests-realm-payload.xml
index 985db7e..7eba425 100644
--- a/tftf/tests/tests-realm-payload.xml
+++ b/tftf/tests/tests-realm-payload.xml
@@ -14,6 +14,12 @@
 	  function="host_test_rtt_fold_unfold_unassigned_empty" />
 	  <testcase name="Realm RTT fold unfold test Unassigned RAM"
 	  function="host_test_rtt_fold_unfold_unassigned_ram" />
+	  <testcase name="Realm RTT fold unfold test Assigned Empty"
+	  function="host_test_rtt_fold_unfold_assigned_empty" />
+	  <testcase name="Realm RTT fold unfold test Assigned RAM"
+	  function="host_test_rtt_fold_unfold_assigned_ram" />
+	  <testcase name="Realm RTT fold unfold test Assigned NS"
+	  function="host_test_rtt_fold_unfold_assigned_ns" />
 	  <testcase name="Multiple Realm EL1 creation and execution test"
 	  function="host_test_multiple_realm_create_enter" />
 	  <testcase name="Realm payload multi rec multiple cpu"