test(realm): add AUX RTT support for planes
- Add support for new RMI_RTT_AUX ABIs and helpers.
- Create and destroy aux mappings for realm creation
with multiple planes and multiple RTTs.
Signed-off-by: Shruti Gupta <shruti.gupta@arm.com>
Change-Id: Ida808b9d311e8a662587257e015b0f62c110ac3b
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 0534ca2..00435b0 100644
--- a/include/runtime_services/host_realm_managment/host_realm_rmi.h
+++ b/include/runtime_services/host_realm_managment/host_realm_rmi.h
@@ -146,6 +146,30 @@
/*
* arg0 == RD address
+ * arg1 == RTT address
+ * arg2 == map address
+ * arg3 == level
+ * arg4 == RTT tree index
+ *
+ * ret0 == status/index
+ */
+#define RMI_RTT_AUX_CREATE SMC64_RMI_FID(U(0x2D))
+
+/*
+ * arg0 == RD address
+ * arg1 == map address
+ * arg2 == level
+ * arg3 == RTT tree index
+ *
+ * ret1 == Address (PA) of the RTT, if ret0 == RMI_SUCCESS
+ * Otherwise, undefined.
+ * ret2 == Top of the non-live address region. Only valid
+ * if ret0 == RMI_SUCCESS or ret0 == (RMI_ERROR_RTT_WALK, x)
+ */
+#define RMI_RTT_AUX_DESTROY SMC64_RMI_FID(U(0x2E))
+
+/*
+ * arg0 == RD address
* arg1 == map address
* arg2 == level
*
@@ -167,6 +191,31 @@
/*
* arg0 == RD address
* arg1 == map address
+ * arg2 == RTT tree index
+ *
+ * ret0 == status/index
+ * ret1 == fail_index
+ * ret2 == primary level
+ * ret3 == state
+ * ret4 == ripas
+ */
+#define RMI_RTT_AUX_MAP_PROTECTED SMC64_RMI_FID(U(0x30))
+
+/*
+ * arg0 == RD address
+ * arg1 == map address
+ * arg2 == RTT tree index
+ *
+ * ret0 == status/index
+ * ret1 == fail_index
+ * ret2 == primary level
+ * ret3 == state
+ */
+#define RMI_RTT_AUX_MAP_UNPROTECTED SMC64_RMI_FID(U(0x31))
+
+/*
+ * arg0 == RD address
+ * arg1 == map address
* arg2 == level
*
* ret1 == level
@@ -185,6 +234,40 @@
#define RMI_RTT_UNMAP_UNPROTECTED SMC64_RMI_FID(U(0x12))
/*
+ * arg0 == RD address
+ * arg1 == map address
+ * arg2 == RTT tree index
+ *
+ * ret0 == status/index
+ * ret1 == top
+ * ret2 == level
+ */
+#define RMI_RTT_AUX_UNMAP_PROTECTED SMC64_RMI_FID(U(0x33))
+
+/*
+ * arg0 == RD address
+ * arg1 == map address
+ * arg2 == RTT tree index
+ *
+ * ret0 == status/index
+ * ret1 == top
+ * ret2 == level
+ */
+#define RMI_RTT_AUX_UNMAP_UNPROTECTED SMC64_RMI_FID(U(0x34))
+
+/*
+ * arg0 == RD address
+ * arg1 == target rec
+ * arg2 == base adr
+ * arg3 == top adr
+ *
+ * ret0 == return code
+ * ret1 == Top IPA of range whose S2AP was modified
+ * ret2 == Index of RTT tree in which base alignment check failed
+ */
+#define RMI_RTT_SET_S2AP SMC64_RMI_FID(U(0x3B))
+
+/*
* arg0 == calling rec address
* arg1 == target rec address
*/
@@ -206,6 +289,16 @@
/*
* arg0 == RD address
+ * arg1 == map address
+ * arg2 == level
+ * arg3 == RTT tree index
+ *
+ * ret1 == Address(PA) of the RTT folded, if ret0 == RMI_SUCCESS
+ */
+#define RMI_RTT_AUX_FOLD SMC64_RMI_FID(U(0x2F))
+
+/*
+ * arg0 == RD address
*/
#define RMI_REC_AUX_COUNT SMC64_RMI_FID(U(0x17))
@@ -430,7 +523,11 @@
#define RMI_EXIT_RIPAS_CHANGE 4U
#define RMI_EXIT_HOST_CALL 5U
#define RMI_EXIT_SERROR 6U
-#define RMI_EXIT_INVALID (RMI_EXIT_SERROR + 1U)
+#define RMI_EXIT_IO 7U
+#define RMI_EXIT_RTT_REQUEST 8U
+#define RMI_EXIT_S2AP_CHANGE 9U
+#define RMI_EXIT_VDEV_REQUEST 10U
+#define RMI_EXIT_INVALID (RMI_EXIT_VDEV_REQUEST + 1U)
/* RmiRecRunnable types */
#define RMI_NOT_RUNNABLE 0U
@@ -537,6 +634,18 @@
* index: RTT level at which the walk terminated
*/
RMI_ERROR_RTT = 4,
+ /*
+ * An attribute of a device does not match the expected value
+ */
+ RMI_ERROR_DEVICE = 5,
+ /*
+ * The command is not supported
+ */
+ RMI_ERROR_NOT_SUPPORTED = 6,
+ /*
+ * RTTE in an auxiliary RTT contained an unexpected value
+ */
+ RMI_ERROR_RTT_AUX = 7,
RMI_ERROR_COUNT
} status_t;
@@ -1051,6 +1160,12 @@
u_register_t start,
u_register_t end,
u_register_t *top);
+u_register_t host_rmi_rtt_set_s2ap(u_register_t rd,
+ u_register_t rec,
+ u_register_t start,
+ u_register_t end,
+ u_register_t *top,
+ u_register_t *rtt_tree);
u_register_t host_rmi_psci_complete(u_register_t calling_rec, u_register_t target_rec,
unsigned long status);
void host_rmi_init_cmp_result(void);
diff --git a/include/runtime_services/host_realm_managment/realm_def.h b/include/runtime_services/host_realm_managment/realm_def.h
index 3bd166a..5d3a196 100644
--- a/include/runtime_services/host_realm_managment/realm_def.h
+++ b/include/runtime_services/host_realm_managment/realm_def.h
@@ -21,6 +21,9 @@
#define MAX_REALM_COUNT U(2)
#define MAX_AUX_PLANE_COUNT U(3)
#define MAX_PLANE_COUNT MAX_AUX_PLANE_COUNT + U(1)
+#define PRIMARY_RTT_INDEX 0U
+#define PRIMARY_PLANE_ID 0U
+
/* Only support 4KB at the moment */
#if (PAGE_SIZE == PAGE_SIZE_4KB)
diff --git a/tftf/tests/runtime_services/host_realm_managment/host_realm_helper.c b/tftf/tests/runtime_services/host_realm_managment/host_realm_helper.c
index 6149512..3a4121b 100644
--- a/tftf/tests/runtime_services/host_realm_managment/host_realm_helper.c
+++ b/tftf/tests/runtime_services/host_realm_managment/host_realm_helper.c
@@ -34,7 +34,11 @@
RMI_EXIT(PSCI),
RMI_EXIT(RIPAS_CHANGE),
RMI_EXIT(HOST_CALL),
- RMI_EXIT(SERROR)
+ RMI_EXIT(SERROR),
+ RMI_EXIT(IO),
+ RMI_EXIT(RTT_REQUEST),
+ RMI_EXIT(S2AP_CHANGE),
+ RMI_EXIT(VDEV_REQUEST)
};
/*
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 1255fc6..821a99e 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
@@ -76,7 +76,7 @@
* must be preserved unless they contain result,
* as specified in the function definition.
*/
- if (regs[0] != RMI_RTT_READ_ENTRY) {
+ if ((regs[0] != RMI_RTT_READ_ENTRY) && (regs[0] != RMI_RTT_AUX_MAP_PROTECTED)) {
CHECK_RET(4);
}
@@ -184,6 +184,16 @@
rd, rtt, map_addr, (u_register_t)level}, 5U).ret0;
}
+static inline u_register_t host_rmi_rtt_aux_create(u_register_t rd,
+ u_register_t rtt,
+ u_register_t map_addr,
+ long level,
+ u_register_t tree_index)
+{
+ return host_rmi_handler(&(smc_args) {RMI_RTT_AUX_CREATE,
+ rd, rtt, map_addr, (u_register_t)level, tree_index}, 6U).ret0;
+}
+
u_register_t host_rmi_rtt_destroy(u_register_t rd,
u_register_t map_addr,
long level,
@@ -200,6 +210,24 @@
return rets.ret0;
}
+u_register_t host_rmi_rtt_aux_destroy(u_register_t rd,
+ u_register_t map_addr,
+ long level,
+ u_register_t tree_index,
+ u_register_t *rtt,
+ u_register_t *top)
+{
+ smc_ret_values rets;
+
+ rets = host_rmi_handler(&(smc_args) {RMI_RTT_AUX_DESTROY,
+ rd, map_addr, (u_register_t)level,
+ tree_index,
+ (u_register_t)&rets}, 6U);
+ *rtt = rets.ret1;
+ *top = rets.ret2;
+ return rets.ret0;
+}
+
u_register_t host_rmi_features(u_register_t index, u_register_t *features)
{
smc_ret_values rets;
@@ -243,6 +271,22 @@
return rets.ret0;
}
+static inline u_register_t host_rmi_rtt_aux_fold(u_register_t rd,
+ u_register_t map_addr,
+ long level,
+ u_register_t tree_index,
+ u_register_t *pa)
+{
+ smc_ret_values rets;
+
+ rets = host_rmi_handler(&(smc_args) {RMI_RTT_AUX_FOLD,
+ rd, map_addr, (u_register_t)level,
+ tree_index,
+ (u_register_t)&rets}, 6U);
+ *pa = rets.ret1;
+ return rets.ret0;
+}
+
static inline u_register_t host_rmi_rec_aux_count(u_register_t rd,
u_register_t *aux_count)
{
@@ -276,6 +320,42 @@
rd, map_addr, (u_register_t)level, ns_pa}, 5U).ret0;
}
+u_register_t host_rmi_rtt_aux_map_unprotected(u_register_t rd,
+ u_register_t map_addr,
+ u_register_t tree_index,
+ u_register_t *fail_index,
+ u_register_t *level_pri,
+ u_register_t *state)
+{
+ smc_ret_values rets;
+
+ rets = host_rmi_handler(&(smc_args) {RMI_RTT_AUX_MAP_UNPROTECTED,
+ rd, map_addr, tree_index}, 4U);
+ *fail_index = rets.ret1;
+ *level_pri = rets.ret2;
+ *state = rets.ret3;
+ return rets.ret0;
+}
+
+u_register_t host_rmi_rtt_aux_map_protected(u_register_t rd,
+ u_register_t map_addr,
+ u_register_t tree_index,
+ u_register_t *fail_index,
+ u_register_t *level_pri,
+ u_register_t *state,
+ u_register_t *ripas)
+{
+ smc_ret_values rets;
+
+ rets = host_rmi_handler(&(smc_args) {RMI_RTT_AUX_MAP_PROTECTED,
+ rd, map_addr, tree_index}, 4U);
+ *fail_index = rets.ret1;
+ *level_pri = rets.ret2;
+ *state = rets.ret3;
+ *ripas = rets.ret4;
+ return rets.ret0;
+}
+
u_register_t host_rmi_rtt_readentry(u_register_t rd,
u_register_t map_addr,
long level,
@@ -305,6 +385,36 @@
return rets.ret0;
}
+u_register_t host_rmi_rtt_aux_unmap_unprotected(u_register_t rd,
+ u_register_t map_addr,
+ u_register_t tree_index,
+ u_register_t *top,
+ u_register_t *level)
+{
+ smc_ret_values rets;
+
+ rets = host_rmi_handler(&(smc_args) {RMI_RTT_AUX_UNMAP_UNPROTECTED,
+ rd, map_addr, tree_index}, 4U);
+ *top = rets.ret1;
+ *level = rets.ret2;
+ return rets.ret0;
+}
+
+u_register_t host_rmi_rtt_aux_unmap_protected(u_register_t rd,
+ u_register_t map_addr,
+ u_register_t tree_index,
+ u_register_t *top,
+ u_register_t *level)
+{
+ smc_ret_values rets;
+
+ rets = host_rmi_handler(&(smc_args) {RMI_RTT_AUX_UNMAP_PROTECTED,
+ rd, map_addr, tree_index}, 4U);
+ *top = rets.ret1;
+ *level = rets.ret2;
+ return rets.ret0;
+}
+
bool host_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);
@@ -351,6 +461,42 @@
return REALM_SUCCESS;
}
+static u_register_t host_realm_create_rtt_aux_levels(struct realm *realm,
+ u_register_t map_addr,
+ long level, long max_level,
+ u_register_t tree_index)
+{
+ u_register_t rtt, ret, ipa_align;
+
+ assert(tree_index != PRIMARY_RTT_INDEX);
+ while (level++ < max_level) {
+ rtt = (u_register_t)page_alloc(PAGE_SIZE);
+ if (rtt == HEAP_NULL_PTR) {
+ ERROR("Failed to allocate memory for rtt\n");
+ return REALM_ERROR;
+ } else {
+ ret = host_rmi_granule_delegate(rtt);
+ if (ret != RMI_SUCCESS) {
+ ERROR("%s() failed, rtt=0x%lx ret=0x%lx\n",
+ "host_rmi_granule_delegate", rtt, ret);
+ return REALM_ERROR;
+ }
+ }
+ ipa_align = ALIGN_DOWN(map_addr, RTT_MAP_SIZE(level - 1));
+ ret = host_rmi_rtt_aux_create(realm->rd, rtt, ipa_align, (u_register_t)level,
+ tree_index);
+ if (ret != RMI_SUCCESS) {
+ ERROR("%s() failed, rtt=0x%lx ret=0x%lx\n",
+ "host_realm_rtt_aux_create", rtt, ret);
+ host_rmi_granule_undelegate(rtt);
+ page_free(rtt);
+ return REALM_ERROR;
+ }
+ }
+
+ return REALM_SUCCESS;
+}
+
u_register_t host_realm_fold_rtt(u_register_t rd, u_register_t addr,
long level)
{
@@ -379,6 +525,93 @@
}
+u_register_t host_realm_aux_map_protected_data(struct realm *realm,
+ u_register_t target_pa,
+ u_register_t map_size,
+ u_register_t tree_index,
+ u_register_t *fail_index,
+ u_register_t *level_pri,
+ u_register_t *state,
+ u_register_t *ripas)
+{
+ u_register_t ret, top;
+ long level;
+ int8_t ulevel;
+ u_register_t size = 0UL;
+ u_register_t map_addr = target_pa;
+
+ assert(tree_index != PRIMARY_RTT_INDEX);
+ for (size = 0UL; size < map_size; size += PAGE_SIZE) {
+ ret = host_rmi_rtt_aux_map_protected(realm->rd, map_addr, tree_index,
+ fail_index, level_pri, state, ripas);
+
+ if (RMI_RETURN_STATUS(ret) == RMI_ERROR_RTT_AUX) {
+ /* Create missing RTTs till L3 and retry */
+ ulevel = RMI_RETURN_INDEX(ret);
+ level = (long)ulevel;
+
+ ret = host_realm_create_rtt_aux_levels(realm, map_addr,
+ (u_register_t)level,
+ 3U, tree_index);
+ if (ret != RMI_SUCCESS) {
+ ERROR("%s() failed, ret=0x%lx line=%u\n",
+ "host_realm_create_rtt_aux_levels",
+ ret, __LINE__);
+ goto err;
+ }
+ ret = host_rmi_rtt_aux_map_protected(realm->rd, target_pa, tree_index,
+ fail_index, level_pri, state, ripas);
+ if (ret != RMI_SUCCESS) {
+ ERROR("%s() failed, ret=0x%lx\n",
+ "host_rmi_data_create", ret);
+ goto err;
+ }
+ } else if (ret != RMI_SUCCESS) {
+ ERROR("host_rmi_rtt_aux_map_protected failed ret = 0x%lx", ret);
+ goto err;
+ }
+ map_addr += PAGE_SIZE;
+ }
+ return REALM_SUCCESS;
+
+err:
+ while (size >= PAGE_SIZE) {
+ ret = host_rmi_rtt_aux_unmap_protected(realm->rd, target_pa, tree_index,
+ &top, (u_register_t *)&level);
+ if (ret != RMI_SUCCESS) {
+ ERROR("%s() failed, addr=0x%lx ret=0x%lx\n",
+ "host_rmi_rtt_aux_unmap_protected", map_addr, ret);
+ }
+ size -= PAGE_SIZE;
+ map_addr -= PAGE_SIZE;
+ }
+ return REALM_ERROR;
+}
+
+u_register_t host_realm_aux_unmap_protected_data(struct realm *realm,
+ u_register_t target_ipa,
+ u_register_t map_size,
+ u_register_t tree_index,
+ u_register_t *top,
+ u_register_t *level)
+{
+ u_register_t ret, size = 0UL, map_addr = target_ipa;
+
+ assert(tree_index != PRIMARY_RTT_INDEX);
+ for (size = 0UL; size < map_size; size += PAGE_SIZE) {
+ ret = host_rmi_rtt_aux_unmap_protected(realm->rd, map_addr, tree_index,
+ top, level);
+ if (ret != RMI_SUCCESS) {
+ WARN("%s() failed, ret=0x%lx line=%u\n",
+ "host_rmi_rtt_aux_unmap_protected",
+ ret, __LINE__);
+ return REALM_ERROR;
+ }
+ map_addr += PAGE_SIZE;
+ }
+ return REALM_SUCCESS;
+}
+
u_register_t host_realm_delegate_map_protected_data(bool unknown,
struct realm *realm,
u_register_t target_pa,
@@ -562,6 +795,50 @@
return REALM_SUCCESS;
}
+static u_register_t host_realm_destroy_free_aux_rtt(struct realm *realm,
+ u_register_t addr,
+ long level)
+{
+ u_register_t rtt2, top, ret;
+
+ /* Destroy and undelegate RTT entry for all trees */
+ for (unsigned int tree_index = 1U;
+ tree_index <= realm->num_aux_planes;
+ tree_index++) {
+
+ ret = host_rmi_rtt_aux_destroy(realm->rd, ALIGN_DOWN(addr,
+ RTT_MAP_SIZE(level)),
+ level + 1L,
+ tree_index, &rtt2, &top);
+
+ if (ret != RMI_SUCCESS) {
+ /*
+ * IPA might not be mapped on all AUX RTTs
+ * ignore error
+ */
+ VERBOSE("%s() failed, map_addr=0x%lx ret=0x%lx \
+ rtt2=0x%lx \
+ top=0x%lx level=0x%lx\n",
+ "host_rmi_rtt_aux_destroy",
+ map_addr, ret, rtt2,
+ top, level + 1L);
+ }
+
+ if (rtt2 != 0UL) {
+ ret = host_rmi_granule_undelegate(rtt2);
+ if (ret != RMI_SUCCESS) {
+ ERROR("%s() failed, rtt=0x%lx ret=0x%lx\n",
+ "host_rmi_granule_undelegate",
+ rtt2, ret);
+ return REALM_ERROR;
+ }
+
+ page_free(rtt2);
+ }
+ }
+ return REALM_SUCCESS;
+}
+
static u_register_t host_realm_destroy_undelegate_range(struct realm *realm,
u_register_t ipa,
u_register_t addr,
@@ -573,6 +850,29 @@
while (size >= PAGE_SIZE) {
ret = host_rmi_data_destroy(rd, ipa, &data, &top);
+
+ if (ret == RMI_ERROR_RTT_AUX) {
+ /* Unmap from all Aux RTTs */
+ for (unsigned int tree_index = 1U; tree_index <= realm->num_aux_planes;
+ tree_index++) {
+ u_register_t top1, level1;
+
+ /* IPA might not be mapped in all Aux RTTs ignore error */
+ ret = host_rmi_rtt_aux_unmap_protected(
+ rd,
+ ipa,
+ tree_index,
+ &top1, &level1);
+ if (ret != RMI_SUCCESS) {
+ VERBOSE("%s() failed, addr=0x%lx ret=0x%lx tree=0x%lx\n",
+ "host_rmi_rtt_aux_unmap_protected",
+ ipa, ret, tree_index);
+ }
+ }
+ /* Retry DATA_DESTROY */
+ continue;
+ }
+
if (ret != RMI_SUCCESS) {
ERROR("%s() failed, addr=0x%lx ret=0x%lx\n",
"host_rmi_data_destroy", ipa, ret);
@@ -622,6 +922,28 @@
case RMI_ASSIGNED:
if (host_ipa_is_ns(map_addr, realm->rmm_feat_reg0)) {
+ u_register_t level1;
+
+ /* Unmap from all Aux RTT */
+ if (!realm->rtt_tree_single) {
+ for (unsigned int tree_index = 1U;
+ tree_index <= realm->num_aux_planes;
+ tree_index++) {
+
+ ret = host_rmi_rtt_aux_unmap_unprotected(
+ rd,
+ map_addr,
+ tree_index,
+ &top, &level1);
+
+ if (ret != RMI_SUCCESS) {
+ ERROR("%s() failed, addr=0x%lx ret=0x%lx\n",
+ "host_rmi_rtt_unmap_unprotected",
+ map_addr, ret);
+ }
+ }
+ }
+
ret = host_rmi_rtt_unmap_unprotected(
rd,
map_addr,
@@ -669,6 +991,19 @@
map_addr, ret);
return REALM_ERROR;
}
+
+ /* RTT_AUX_DESTROY */
+ if (!realm->rtt_tree_single) {
+ ret = host_realm_destroy_free_aux_rtt(realm, map_addr,
+ level);
+
+ if (ret != RMI_SUCCESS) {
+ ERROR("%s() failed, map_addr=0x%lx ret=0x%lx\n",
+ "host_realm_destroy_free_aux_rtt",
+ map_addr, ret);
+ return REALM_ERROR;
+ }
+ }
break;
default:
return REALM_ERROR;
@@ -700,6 +1035,23 @@
return ret.ret1;
}
+u_register_t host_rmi_rtt_set_s2ap(u_register_t rd,
+ u_register_t rec,
+ u_register_t base,
+ u_register_t top,
+ u_register_t *out_top,
+ u_register_t *rtt_tree)
+{
+ smc_ret_values rets;
+
+ rets = host_rmi_handler(&(smc_args) {RMI_RTT_SET_S2AP,
+ rd, rec, base, top,
+ (u_register_t)&rets}, 6U);
+ *out_top = rets.ret1;
+ *rtt_tree = rets.ret2;
+ return rets.ret0;
+}
+
u_register_t host_realm_create(struct realm *realm)
{
struct rmi_realm_params *params;