test(realm) : add tests for PAS transitions

add tests for HIPAS and RIPAS changes at a
Protected IPA which can occur when the
Realm state is New and Active

Change-Id: I0ad13d697e8b69e71e58197878d1d58a2f6ebff7
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 3159ad4..55233a1 100644
--- a/include/runtime_services/host_realm_managment/host_realm_rmi.h
+++ b/include/runtime_services/host_realm_managment/host_realm_rmi.h
@@ -350,6 +350,7 @@
 #define PAGE_SHIFT			FOUR_KB_SHIFT
 #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 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 057dd00..313009c 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
@@ -292,15 +292,6 @@
 	return rets.ret0;
 }
 
-u_register_t host_rtt_level_mapsize(u_register_t level)
-{
-	if (level > RTT_MAX_LEVEL) {
-		return PAGE_SIZE;
-	}
-
-	return (1UL << RTT_LEVEL_SHIFT(level));
-}
-
 static inline bool ipa_is_ns(u_register_t addr, u_register_t rmm_feat_reg0)
 {
 	return (addr >> (EXTRACT(RMI_FEATURE_REGISTER_0_S2SZ, rmm_feat_reg0) - 1UL) == 1UL);
@@ -311,7 +302,7 @@
 						 u_register_t level,
 						 u_register_t phys)
 {
-	addr = ALIGN_DOWN(addr, host_rtt_level_mapsize(level - 1U));
+	addr = ALIGN_DOWN(addr, RTT_MAP_SIZE(level - 1U));
 	return host_rmi_rtt_create(realm->rd, phys, addr, level);
 }
 
@@ -547,7 +538,7 @@
 					   u_register_t *rtt,
 					   u_register_t *top)
 {
-	addr = ALIGN_DOWN(addr, host_rtt_level_mapsize(level - 1U));
+	addr = ALIGN_DOWN(addr, RTT_MAP_SIZE(level - 1U));
 	return host_rmi_rtt_destroy(realm->rd, addr, level, rtt, top);
 }
 
@@ -615,7 +606,7 @@
 						   u_register_t end)
 {
 	u_register_t rd = realm->rd;
-	u_register_t map_size = host_rtt_level_mapsize(level);
+	u_register_t map_size = RTT_MAP_SIZE(level);
 	u_register_t map_addr, next_addr, rtt_out_addr, end_addr, top;
 	struct rtt_entry rtt;
 	u_register_t ret;
@@ -863,7 +854,7 @@
 						src_pa + i * PAGE_SIZE);
 		if (ret != RMI_SUCCESS) {
 			ERROR("%s() failed, par_base=0x%lx ret=0x%lx\n",
-				"host_realm_map_protected_data",
+				"host_realm_delegate_map_protected_data",
 				realm->par_base, ret);
 			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 ff69869..4e5f662 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
@@ -1048,7 +1048,7 @@
 	/* DATA_CREATE_UNKNOWN */
 	ret = host_realm_delegate_map_protected_data(true, &realm, base, PAGE_SIZE, 0U);
 	if (ret != RMI_SUCCESS) {
-		ERROR("host_realm_map_protected_data failed\n");
+		ERROR("host_realm_delegate_map_protected_data failed\n");
 		goto destroy_realm;
 	}
 	ret = host_rmi_rtt_readentry(realm.rd, base, 3U, &rtt);
@@ -1273,3 +1273,404 @@
 
 	return TEST_RESULT_SUCCESS;
 }
+
+/*
+ * Helper to test whether RTT_DESTROY will change state of
+ * Unassigned ram page to Unassigned Destroyed
+ * Realm is in new state, activate realm before RTT_DESTROY if requested
+ */
+static test_result_t test_rtt_destroy_ram(struct realm *realm, bool activate)
+{
+	u_register_t ret, top, out_rtt, base;
+	struct rtt_entry rtt;
+
+	/* Find an address not mapped in L3 */
+	base = ALIGN_DOWN(PAGE_POOL_BASE, RTT_MAP_SIZE(2U));
+	while (true) {
+		ret = host_rmi_rtt_readentry(realm->rd, base, 3U, &rtt);
+		if (ret != RMI_SUCCESS || rtt.walk_level != 2U || rtt.state != RMI_UNASSIGNED
+				|| (rtt.ripas != RMI_EMPTY)) {
+			base += RTT_MAP_SIZE(2U);
+			continue;
+		}
+		break;
+	}
+
+	INFO("base = 0x%lx\n", base);
+
+	/* Create L3 RTT entries */
+	ret = host_rmi_create_rtt_levels(realm, base, rtt.walk_level, 3U);
+	if (ret != RMI_SUCCESS) {
+		ERROR("host_rmi_create_rtt_levels failed ret=0x%lx\n", ret);
+		return TEST_RESULT_FAIL;
+	}
+
+	/* L3 entry should be created */
+	ret = host_rmi_rtt_readentry(realm->rd, base, 3U, &rtt);
+	if (rtt.walk_level != 3U) {
+		ERROR("host_rmi_create_rtt_levels failed ret=0x%lx\n", ret);
+		return TEST_RESULT_FAIL;
+	}
+
+	ret = host_rmi_rtt_init_ripas(realm->rd, base, base + PAGE_SIZE, &top);
+	if (ret != RMI_SUCCESS) {
+		ERROR("%s() failed, ret=0x%lx line=%u\n",
+			"host_rmi_rtt_init_ripas", ret, __LINE__);
+		return TEST_RESULT_FAIL;
+	}
+
+	/* 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_UNASSIGNED ||
+			(rtt.ripas != RMI_RAM)) {
+		ERROR("wrong state after INIT_RIPAS\n");
+		return TEST_RESULT_FAIL;
+	}
+
+	if (activate) {
+		/* Activate Realm */
+		if (host_realm_activate(realm) != REALM_SUCCESS) {
+			ERROR("%s() failed\n", "host_realm_activate");
+			return TEST_RESULT_FAIL;
+		}
+	}
+
+	/* Destroy newly created rtt, for protected IPA there should be no live L3 entry */
+	ret = host_rmi_rtt_destroy(realm->rd, base, 3U, &out_rtt, &top);
+	if (ret != RMI_SUCCESS) {
+		ERROR("host_rmi_rtt_destroy failed ret=0x%lx\n", ret);
+		return TEST_RESULT_FAIL;
+	}
+	ret = host_rmi_granule_undelegate(out_rtt);
+
+	/* Walk should terminate at L2 after RTT_DESTROY */
+	ret = host_rmi_rtt_readentry(realm->rd, base, 3U, &rtt);
+	if (ret != RMI_SUCCESS || rtt.state != RMI_UNASSIGNED ||
+			rtt.ripas != RMI_DESTROYED || rtt.walk_level != 2U) {
+		ERROR("Wrong state after host_rmi_rtt_destroy\n");
+		return TEST_RESULT_FAIL;
+	}
+	return TEST_RESULT_SUCCESS;
+}
+
+/*
+ * Helper to test whether RTT_DESTROY will change state of
+ * Unassigned empty page to Unassigned Destroyed
+ * Realm can be in new or active state
+ */
+static test_result_t test_rtt_destroy_empty(struct realm *realm)
+{
+	u_register_t base, ret, top, out_rtt;
+	struct rtt_entry rtt;
+
+	/* Find an address not mapped in L3 */
+	base = ALIGN_DOWN(PAGE_POOL_BASE, RTT_MAP_SIZE(2U));
+	while (true) {
+		ret = host_rmi_rtt_readentry(realm->rd, base, 3U, &rtt);
+		if (ret != RMI_SUCCESS || rtt.walk_level != 2U || rtt.state != RMI_UNASSIGNED
+				|| (rtt.ripas != RMI_EMPTY)) {
+			base += RTT_MAP_SIZE(2U);
+			continue;
+		}
+		break;
+	}
+
+	INFO("base = 0x%lx\n", base);
+
+	/* Create L3 RTT entries */
+	ret = host_rmi_create_rtt_levels(realm, base, rtt.walk_level, 3U);
+	if (ret != RMI_SUCCESS) {
+		ERROR("host_rmi_create_rtt_levels failed ret=0x%lx\n", ret);
+		return TEST_RESULT_FAIL;
+	}
+
+	/* L3 entry should be created */
+	ret = host_rmi_rtt_readentry(realm->rd, base, 3U, &rtt);
+	if (rtt.walk_level != 3U) {
+		ERROR("host_rmi_create_rtt_levels failed ret=0x%lx\n", ret);
+		return TEST_RESULT_FAIL;
+	}
+
+	/* Destroy newly created rtt, for protected IPA there should be no live L3 entry */
+	ret = host_rmi_rtt_destroy(realm->rd, base, 3U, &out_rtt, &top);
+	if (ret != RMI_SUCCESS) {
+		ERROR("host_rmi_rtt_destroy failed ret=0x%lx\n", ret);
+		return TEST_RESULT_FAIL;
+	}
+	ret = host_rmi_granule_undelegate(out_rtt);
+	if (ret != RMI_SUCCESS) {
+		ERROR("host_rmi_granule_undelegate RTT failed ret=0x%lx\n", ret);
+		return TEST_RESULT_FAIL;
+	}
+
+	/* Walk should terminate at L2 after RTT_DESTROY */
+	ret = host_rmi_rtt_readentry(realm->rd, base, 3U, &rtt);
+	if (ret != RMI_SUCCESS || rtt.state != RMI_UNASSIGNED ||
+			rtt.ripas != RMI_DESTROYED || rtt.walk_level != 2U) {
+		ERROR("Wrong state after host_rmi_rtt_destroy\n");
+		return TEST_RESULT_FAIL;
+	}
+	return TEST_RESULT_SUCCESS;
+}
+
+/*
+ * Test aims to test PAS transitions
+ * when realm is in new state
+ * 1. Test initial state of PAGE is Unassigned Empty
+ * 2. Test DATA_CREATE moves initial state to Assigned Ram
+ *    a. Test DATA_DESTROY moves state to Unassigned Destroyed
+ *    b. Test DATA_CREATE_UNKNOWN moves state to Assigned Destroyed
+ *    c. Test DATA_DESTROY moves state to Unassigned Destroyed
+ * 3. Test DATA_CREATE_UNKNOWN moves initial state (new page) to Assigned Empty
+ *    Test DATA_DESTROY moves state to Unassigned Empty
+ * 4. Test INIT_RIPAS moves initial state (new page) to Unassigned RAM
+ *    a. Test DATA_CREATE_UNKNOWN moves state to Assigned Ram
+ * 5. Test RTT_DESTROY moves initial state (new page) to Unassigned Destroyed
+ * 6. Test RTT_DESTROY moves state (new page) unassigned ram to Unassigned Destroyed
+ * Transition
+ *
+ *     +------------------+            +-------------------+            +-------------------+
+ *     |  Assigned Empty  |            |   Assigned Dest   |            | Assigned RAM      |
+ *     +------------------+            +--+---^------------+            +-------^---+-----^-+
+ *          ^          |                  |   ^                                 ^   |     ^
+ *          |          |                  |   |                                 |   |     |
+ *          |          |                  |   |                 2a              |   |     |
+ *          |          |                  |   |      +--------------------------+---+     |
+ *          |          |                  |   | 2b   |                          |         |4a
+ *          |          |3a                |   +---------+                       |         |
+ *        3 |          |                2c|          |  |                       |         |
+ *          |          |                  |          |  |                       |         |
+ *          |    +-----+--------2---------+----------+--+-----------------------+         |
+ *          |    |     |                  |          |  |                                 |
+ *          |    |     V                  V          V  |                                 |
+ *     +----+----+-----v---+           |--V----------V--+---|         |------------------+--|
+ * --->|  Unassigned Empty |---------->|Unassigned Dest     |<--------|  Unassigned RAM     |
+ * 1   +--------------+----+     5     +--------------------+    6    +---------^-----------+
+ *                    |			                                        ^
+ *                    |                                                         |
+ *                    +---------------------------------------------------------+
+ *                                                      4
+ */
+test_result_t host_realm_pas_validation_new(void)
+{
+	bool ret1;
+	test_result_t test_result = TEST_RESULT_FAIL;
+	u_register_t ret, data, top;
+	struct realm realm;
+	struct rtt_entry rtt;
+	u_register_t rec_flag[2U] = {RMI_RUNNABLE, RMI_RUNNABLE}, base;
+
+	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, 2U)) {
+		return TEST_RESULT_FAIL;
+	}
+	if (!host_create_shared_mem(&realm, NS_REALM_SHARED_MEM_BASE,
+			NS_REALM_SHARED_MEM_SIZE)) {
+		goto destroy_realm;
+	}
+
+	INFO("Test 1\n");
+	base = (u_register_t)page_alloc(PAGE_SIZE);
+
+	/* Create level 3 RTT */
+	ret = host_rmi_create_rtt_levels(&realm, base, 3U, 3U);
+	if (ret != RMI_SUCCESS) {
+		ERROR("host_rmi_create_rtt_levels failed\n");
+		goto destroy_realm;
+	}
+
+	ret = host_rmi_rtt_readentry(realm.rd, base, 3U, &rtt);
+	if (ret != RMI_SUCCESS || rtt.state != RMI_UNASSIGNED ||
+			(rtt.ripas != RMI_EMPTY) || rtt.walk_level != 3U) {
+		ERROR("wrong initial state\n");
+		goto destroy_realm;
+	}
+
+	/* 2. DATA_CREATE copy TFTF_BASE, chosen for convenience, can be any adr */
+	INFO("Test 2\n");
+	ret = host_realm_delegate_map_protected_data(false, &realm, base, PAGE_SIZE, TFTF_BASE);
+	if (ret != RMI_SUCCESS) {
+		ERROR("host_realm_delegate_map_protected_data failed\n");
+		goto destroy_realm;
+	}
+	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 DATA_CRATE_UNKNOWN\n");
+		goto undelegate_destroy;
+	}
+
+	/* 2a DATA_DESTROY */
+	ret = host_rmi_data_destroy(realm.rd, base, &data, &top);
+	if (ret != RMI_SUCCESS || data != base) {
+		ERROR("host_rmi_data_destroy failed\n");
+		goto undelegate_destroy;
+	}
+	ret = host_rmi_rtt_readentry(realm.rd, base, 3U, &rtt);
+	if (ret != RMI_SUCCESS || rtt.state != RMI_UNASSIGNED ||
+			rtt.ripas != RMI_DESTROYED) {
+		ERROR("Wrong state after host_rmi_data_destroy\n");
+		goto undelegate_destroy;
+	}
+
+	/* Undelegated to use helper function host_realm_delegate_map_protected_data */
+	host_rmi_granule_undelegate(base);
+
+	/*2b DATA_CREATE_UNKNOWN */
+	ret = host_realm_delegate_map_protected_data(true, &realm, base, PAGE_SIZE, 0U);
+	if (ret != RMI_SUCCESS) {
+		ERROR("host_realm_delegate_map_protected_data failed\n");
+		goto undelegate_destroy;
+	}
+	ret = host_rmi_rtt_readentry(realm.rd, base, 3U, &rtt);
+	if (ret != RMI_SUCCESS || rtt.state != RMI_ASSIGNED ||
+			(rtt.ripas != RMI_DESTROYED)) {
+		ERROR("wrong state after DATA_CRATE_UNKNOWN\n");
+		goto undelegate_destroy;
+	}
+
+	/* 2c DATA_DESTROY */
+	ret = host_rmi_data_destroy(realm.rd, base, &data, &top);
+	if (ret != RMI_SUCCESS || data != base) {
+		ERROR("host_rmi_data_destroy failed\n");
+		goto undelegate_destroy;
+	}
+	ret = host_rmi_rtt_readentry(realm.rd, base, 3U, &rtt);
+	if (ret != RMI_SUCCESS || rtt.state != RMI_UNASSIGNED ||
+			rtt.ripas != RMI_DESTROYED) {
+		ERROR("Wrong state after host_rmi_data_destroy\n");
+		goto undelegate_destroy;
+	}
+
+	host_rmi_granule_undelegate(base);
+
+	/* 3. start with new page */
+	INFO("Test 3\n");
+	base = (u_register_t)page_alloc(PAGE_SIZE);
+	ret = host_realm_delegate_map_protected_data(true, &realm, base, PAGE_SIZE, 0U);
+	if (ret != RMI_SUCCESS) {
+		ERROR("host_realm_delegate_map_protected_data failed\n");
+		goto destroy_realm;
+	}
+	ret = host_rmi_rtt_readentry(realm.rd, base, 3U, &rtt);
+	if (ret != RMI_SUCCESS || rtt.state != RMI_ASSIGNED ||
+			(rtt.ripas != RMI_EMPTY)) {
+		ERROR("wrong state after DATA_CRATE_UNKNOWN\n");
+		goto undelegate_destroy;
+	}
+	ret = host_rmi_data_destroy(realm.rd, base, &data, &top);
+	if (ret != RMI_SUCCESS || data != base) {
+		ERROR("host_rmi_data_destroy failed\n");
+		goto undelegate_destroy;
+	}
+	ret = host_rmi_rtt_readentry(realm.rd, base, 3U, &rtt);
+	if (ret != RMI_SUCCESS || rtt.state != RMI_UNASSIGNED ||
+			rtt.ripas != RMI_EMPTY) {
+		ERROR("Wrong state after host_rmi_data_destroy\n");
+		goto undelegate_destroy;
+	}
+	host_rmi_granule_undelegate(base);
+
+	/* 4. start with new page */
+	INFO("Test 4\n");
+	base = (u_register_t)page_alloc(PAGE_SIZE);
+	ret = host_rmi_rtt_init_ripas(realm.rd, base, base + PAGE_SIZE, &top);
+	if (ret != RMI_SUCCESS) {
+		ERROR("%s() failed, ret=0x%lx line=%u\n",
+			"host_rmi_rtt_init_ripas", ret, __LINE__);
+		goto destroy_realm;
+	}
+	ret = host_rmi_rtt_readentry(realm.rd, base, 3U, &rtt);
+	if (ret != RMI_SUCCESS || rtt.state != RMI_UNASSIGNED ||
+			(rtt.ripas != RMI_RAM)) {
+		ERROR("wrong state after INIT_RIPAS\n");
+		goto undelegate_destroy;
+	}
+	/* 4a. DATA_CREATE_UNKNOWN */
+	ret = host_realm_delegate_map_protected_data(true, &realm, base, PAGE_SIZE, 0U);
+	if (ret != RMI_SUCCESS) {
+		ERROR("host_realm_delegate_map_protected_data failed\n");
+		goto destroy_realm;
+	}
+	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 DATA_CRATE_UNKNOWN\n");
+		goto undelegate_destroy;
+	}
+	host_rmi_granule_undelegate(base);
+
+	/* 5. */
+	INFO("Test 5\n");
+	test_result = test_rtt_destroy_empty(&realm);
+	if (test_result != TEST_RESULT_SUCCESS) {
+		ERROR("Test 5 failed\n");
+		goto destroy_realm;
+	}
+
+	/* 6. */
+	INFO("Test 6\n");
+	test_result = test_rtt_destroy_ram(&realm, false);
+	goto destroy_realm;
+
+undelegate_destroy:
+	ret = host_rmi_granule_undelegate(base);
+	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 test_result;
+}
+
+/*
+ * Test aim is to test RTT_DESTROY for active realm
+ * Test initial state of page is unassigned empty
+ * After RTT_DESTROY verify state is unassigned destroyed
+ */
+test_result_t host_realm_pas_validation_active(void)
+{
+	bool ret;
+	test_result_t test_result = TEST_RESULT_FAIL;
+	u_register_t rec_flag[] = {RMI_RUNNABLE};
+	struct realm realm;
+
+	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)) {
+		goto destroy_realm;
+	}
+	if (!host_create_shared_mem(&realm, NS_REALM_SHARED_MEM_BASE,
+			NS_REALM_SHARED_MEM_SIZE)) {
+		goto destroy_realm;
+	}
+
+	test_result = test_rtt_destroy_ram(&realm, true);
+	if (test_result != TEST_RESULT_SUCCESS) {
+		ERROR("test_rtt_destroy_ram failed\n");
+		goto destroy_realm;
+	}
+
+	test_result = test_rtt_destroy_empty(&realm);
+
+destroy_realm:
+	ret = host_destroy_realm(&realm);
+
+	if (!ret) {
+		ERROR("%s(): destroy=%d\n", __func__, ret);
+		return TEST_RESULT_FAIL;
+	}
+	return test_result;
+}
diff --git a/tftf/tests/tests-realm-payload.xml b/tftf/tests/tests-realm-payload.xml
index 0ecefee..00048fc 100644
--- a/tftf/tests/tests-realm-payload.xml
+++ b/tftf/tests/tests-realm-payload.xml
@@ -16,6 +16,10 @@
 	  function="host_realm_multi_rec_multiple_cpu" />
 	  <testcase name="Realm payload multi rec validations"
 	  function="host_realm_multi_rec_multiple_cpu2" />
+	  <testcase name="New Realm PAS Validation"
+	  function="host_realm_pas_validation_new" />
+          <testcase name="Active Realm PAS validation"
+          function="host_realm_pas_validation_active" />
 	  <testcase name="Realm SEA Empty"
 	  function="host_realm_sea_empty" />
 	  <testcase name="Realm SEA Unprotected"