test(realm): add support for RSI Planes ABI
Add Planes RSI support.
Add helpers to setup initialize and enter planes.
Signed-off-by: Shruti Gupta <shruti.gupta@arm.com>
Change-Id: I62946a185c47fe77a04f42751d0b0a467d41ceee
diff --git a/realm/include/realm_helpers.h b/realm/include/realm_helpers.h
index 11c4423..a9b2f7c 100644
--- a/realm/include/realm_helpers.h
+++ b/realm/include/realm_helpers.h
@@ -10,6 +10,19 @@
/* Generate 64-bit random number */
unsigned long long realm_rand64(void);
+/*
+ * Function to enter Aux Plane from Primary Plane
+ * arg1 == plane index
+ * arg2 == permission index to be used by plane
+ * arg3 == base entrypoint
+ * arg4 == entry flags
+ * aarg5 == run object, needs to be PAGE aligned
+ */
+bool realm_plane_enter(u_register_t plane_index, u_register_t perm_index,
+ u_register_t base, u_register_t flags, rsi_plane_run *run);
+
+/* Function for initializing planes, called at Boot */
+void realm_plane_init(void);
#endif /* REALM_HELPERS_H */
diff --git a/realm/include/realm_rsi.h b/realm/include/realm_rsi.h
index 72ee80e..33e8fcf 100644
--- a/realm/include/realm_rsi.h
+++ b/realm/include/realm_rsi.h
@@ -8,6 +8,7 @@
#ifndef REALM_RSI_H
#define REALM_RSI_H
+#include <arch.h>
#include <stdint.h>
#include <host_shared_data.h>
#include <tftf_lib.h>
@@ -71,7 +72,9 @@
/* IPA width in bits */
SET_MEMBER(unsigned long ipa_width, 0, 8); /* Offset 0 */
/* Hash algorithm */
- SET_MEMBER(unsigned long algorithm, 8, 0x200); /* Offset 8 */
+ SET_MEMBER(unsigned long algorithm, 8, 0x10); /* Offset 8 */
+ /* Number of auxiliary Planes */
+ SET_MEMBER(unsigned long num_aux_planes, 0x10, 0x200); /* Offset 0x10 */
/* Realm Personalization Value */
SET_MEMBER(unsigned char rpv[RSI_RPV_SIZE], 0x200, 0x1000); /* Offset 0x200 */
};
@@ -157,7 +160,151 @@
#define RSI_NO_CHANGE_DESTROYED 0UL
#define RSI_CHANGE_DESTROYED 1UL
-/* Request RIPAS of a target IPA range to be changed to a specified value */
+/*
+ * arg1 == plane index
+ * arg2 == perm index
+ *
+ * ret0 == status
+ * ret1 == perm value
+ */
+#define RSI_MEM_GET_PERM_VALUE SMC_RSI_FID(0x10U)
+
+/*
+ * arg1 == base adr
+ * arg2 == top adr
+ * arg3 == perm index
+ * arg4 == cookie
+ *
+ * ret0 == status
+ * ret1 == new_base
+ * ret2 == response
+ * ret3 == new_cookie
+ */
+#define RSI_MEM_SET_PERM_INDEX SMC_RSI_FID(0x11U)
+
+/*
+ * arg1 == plane index
+ * arg2 == perm index
+ *
+ * ret0 == status
+ */
+#define RSI_MEM_SET_PERM_VALUE SMC_RSI_FID(0x12U)
+
+#define RSI_PLANE_NR_GPRS 31U
+#define RSI_PLANE_GIC_NUM_LRS 16U
+
+/*
+ * Flags provided by the Primary Plane to the secondary ones upon
+ * plane entry.
+ */
+#define RSI_PLANE_ENTRY_FLAG_TRAP_WFI U(1UL << 0)
+#define RSI_PLANE_ENTRY_FLAG_TRAP_WFE U(1UL << 1)
+#define RSI_PLANE_ENTRY_FLAG_TRAP_HC U(1UL << 2)
+
+/* Data structure used to pass values from P0 to the RMM on Plane entry */
+struct rsi_plane_entry {
+ /* Flags */
+ SET_MEMBER(u_register_t flags, 0, 0x8); /* Offset 0 */
+ /* PC */
+ SET_MEMBER(u_register_t pc, 0x8, 0x100); /* Offset 0x8 */
+ /* General-purpose registers */
+ SET_MEMBER(u_register_t gprs[RSI_PLANE_NR_GPRS], 0x100, 0x200); /* 0x100 */
+ /* EL1 system registers */
+ SET_MEMBER(struct {
+ /* GICv3 Hypervisor Control Register */
+ u_register_t gicv3_hcr; /* 0x200 */
+ /* GICv3 List Registers */
+ u_register_t gicv3_lrs[RSI_PLANE_GIC_NUM_LRS]; /* 0x208 */
+ }, 0x200, 0x800);
+};
+
+/* Data structure used to pass values from the RMM to P0 on Plane exit */
+struct rsi_plane_exit {
+ /* Exit reason */
+ SET_MEMBER(u_register_t exit_reason, 0, 0x100);/* Offset 0 */
+ SET_MEMBER(struct {
+ /* Exception Link Register */
+ u_register_t elr; /* 0x100 */
+ /* Exception Syndrome Register */
+ u_register_t esr; /* 0x108 */
+ /* Fault Address Register */
+ u_register_t far; /* 0x108 */
+ /* Hypervisor IPA Fault Address register */
+ u_register_t hpfar; /* 0x110 */
+ }, 0x100, 0x200);
+ /* General-purpose registers */
+ SET_MEMBER(u_register_t gprs[RSI_PLANE_NR_GPRS], 0x200, 0x300); /* 0x200 */
+ SET_MEMBER(struct {
+ /* GICv3 Hypervisor Control Register */
+ u_register_t gicv3_hcr; /* 0x300 */
+ /* GICv3 List Registers */
+ u_register_t gicv3_lrs[RSI_PLANE_GIC_NUM_LRS]; /* 0x308 */
+ /* GICv3 Maintenance Interrupt State Register */
+ u_register_t gicv3_misr; /* 0x388 */
+ /* GICv3 Virtual Machine Control Register */
+ u_register_t gicv3_vmcr; /* 0x390 */
+ }, 0x300, 0x600);
+};
+
+typedef struct {
+ /* Entry information */
+ SET_MEMBER(struct rsi_plane_entry enter, 0, 0x800); /* Offset 0 */
+ /* Exit information */
+ SET_MEMBER(struct rsi_plane_exit exit, 0x800, 0x1000);/* 0x800 */
+} rsi_plane_run;
+
+/*
+ * arg1 == plane index
+ * arg2 == run pointer
+ *
+ * ret0 == status
+ */
+#define RSI_PLANE_ENTER SMC_RSI_FID(0x13U)
+
+/*
+ * arg1 == plane index
+ * arg2 == register encoding
+ *
+ * ret0 == status
+ * ret1 = register value
+ */
+#define RSI_PLANE_REG_READ SMC_RSI_FID(0x1EU)
+
+/*
+ * arg1 == plane index
+ * arg2 == register encoding
+ * arg3 == register value
+ *
+ * ret0 == status
+ */
+#define RSI_PLANE_REG_WRITE SMC_RSI_FID(0x1FU)
+
+/*
+ * Function to set overlay permission value for a specified
+ * (plane index, overlay permission index) tuple
+ */
+u_register_t rsi_mem_set_perm_value(u_register_t plane_index,
+ u_register_t perm_index,
+ u_register_t perm);
+
+/*
+ * Function to Get overlay permission value for a specified
+ * (plane index, overlay permission index) tuple
+ */
+u_register_t rsi_mem_get_perm_value(u_register_t plane_index,
+ u_register_t perm_index,
+ u_register_t *perm);
+
+/* Function to Set overlay permission index for a specified IPA range See RSI_MEM_SET_PERM_INDEX */
+u_register_t rsi_mem_set_perm_index(u_register_t base,
+ u_register_t top,
+ u_register_t perm_index,
+ u_register_t cookie,
+ u_register_t *new_base,
+ u_register_t *response,
+ u_register_t *new_cookie);
+
+/* Request RIPAS of a target IPA range to be changed to a specified value. */
u_register_t rsi_ipa_state_set(u_register_t base,
u_register_t top,
rsi_ripas_type ripas,
@@ -197,4 +344,10 @@
/* This function call Host and request to exit Realm with proper exit code */
void rsi_exit_to_host(enum host_call_cmd exit_code);
+/* Function to get Realm configuration. See RSI_REALM_CONFIG */
+u_register_t rsi_realm_config(struct rsi_realm_config *s);
+
+/* Function to enter aux plane. See RSI_PLANE_ENTER */
+u_register_t rsi_plane_enter(u_register_t plane_index, u_register_t run);
+
#endif /* REALM_RSI_H */
diff --git a/realm/realm.mk b/realm/realm.mk
index 3e66adc..f59387c 100644
--- a/realm/realm.mk
+++ b/realm/realm.mk
@@ -34,6 +34,7 @@
realm_multiple_rec.c \
realm_pauth.c \
realm_payload_main.c \
+ realm_plane.c \
realm_pmuv3.c \
realm_psci.c \
realm_rsi.c \
diff --git a/realm/realm_plane.c b/realm/realm_plane.c
new file mode 100644
index 0000000..ef1e0ab
--- /dev/null
+++ b/realm/realm_plane.c
@@ -0,0 +1,108 @@
+/*
+ * Copyright (c) 2022-2023, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+#include <stdio.h>
+#include <arch.h>
+#include <arch_features.h>
+#include <assert.h>
+#include <debug.h>
+
+#include <host_realm_helper.h>
+#include <realm_rsi.h>
+#include <sync.h>
+
+bool is_plane0;
+
+void realm_plane_init(void)
+{
+ u_register_t ret;
+
+ ret = rsi_get_version(RSI_ABI_VERSION_VAL);
+ if (ret == RSI_ERROR_STATE) {
+ is_plane0 = false;
+ } else {
+ is_plane0 = true;
+ }
+}
+
+static void restore_plane_context(rsi_plane_run *run)
+{
+ for (unsigned int i = 0U; i < RSI_PLANE_NR_GPRS; i++) {
+ run->enter.gprs[i] = run->exit.gprs[i];
+ }
+
+ run->enter.pc = run->exit.elr;
+}
+
+/* return true to re-enter PlaneN, false to exit to P0 */
+static bool handle_plane_exit(u_register_t plane_index,
+ u_register_t perm_index,
+ rsi_plane_run *run)
+{
+ u_register_t ec = EC_BITS(run->exit.esr);
+
+ /* Disallow SMC from Plane N */
+ if (ec == EC_AARCH64_SMC) {
+ restore_plane_context(run);
+ run->enter.gprs[0] = RSI_ERROR_STATE;
+ return true;
+ }
+ return false;
+}
+
+static bool plane_common_init(u_register_t plane_index,
+ u_register_t perm_index,
+ u_register_t base,
+ rsi_plane_run *run)
+{
+ u_register_t ret;
+
+ memset(run, 0, sizeof(rsi_plane_run));
+ run->enter.pc = base;
+
+ /* Perm init */
+ ret = rsi_mem_set_perm_value(plane_index, perm_index, PERM_LABEL_RW_upX);
+ if (ret != RSI_SUCCESS) {
+ ERROR("rsi_mem_set_perm_value failed %u\n", plane_index);
+ return false;
+ }
+ return true;
+}
+
+bool realm_plane_enter(u_register_t plane_index,
+ u_register_t perm_index,
+ u_register_t base,
+ u_register_t flags,
+ rsi_plane_run *run)
+{
+ u_register_t ret;
+ bool ret1;
+
+ ret1 = plane_common_init(plane_index, perm_index, base, run);
+ if (!ret1) {
+ return ret1;
+ }
+
+ run->enter.flags = flags;
+
+ while (ret1) {
+ ret = rsi_plane_enter(plane_index, (u_register_t)run);
+ if (ret != RSI_SUCCESS) {
+ ERROR("Plane %u enter failed ret= 0x%lx\n", plane_index, ret);
+ return false;
+ }
+
+ VERBOSE("plane exit_reason=0x%lx esr=0x%lx hpfar=0x%lx far=0x%lx\n",
+ run->exit.exit_reason,
+ run->exit.esr,
+ run->exit.hpfar,
+ run->exit.far);
+
+ ret1 = handle_plane_exit(plane_index, perm_index, run);
+ }
+ return true;
+}
+
diff --git a/realm/realm_rsi.c b/realm/realm_rsi.c
index db2394c..1c6fc8e 100644
--- a/realm/realm_rsi.c
+++ b/realm/realm_rsi.c
@@ -22,6 +22,11 @@
if (res.ret0 == SMC_UNKNOWN) {
return SMC_UNKNOWN;
}
+
+ if (res.ret0 == RSI_ERROR_STATE) {
+ return RSI_ERROR_STATE;
+ }
+
/* Return lower version */
return res.ret1;
}
@@ -141,3 +146,67 @@
}
return res.ret0;
}
+
+u_register_t rsi_realm_config(struct rsi_realm_config *s)
+{
+ smc_ret_values res = {};
+
+ res = tftf_smc(&(smc_args)
+ {RSI_REALM_CONFIG, (u_register_t)s});
+ return res.ret0;
+}
+
+u_register_t rsi_mem_get_perm_value(u_register_t plane_index,
+ u_register_t perm_index,
+ u_register_t *perm)
+{
+ smc_ret_values res = {};
+
+ res = tftf_smc(&(smc_args)
+ {RSI_MEM_GET_PERM_VALUE, plane_index, perm_index});
+ if (res.ret0 == RSI_SUCCESS) {
+ *perm = res.ret1;
+ }
+ return res.ret0;
+}
+
+u_register_t rsi_mem_set_perm_value(u_register_t plane_index,
+ u_register_t perm_index,
+ u_register_t perm)
+{
+ smc_ret_values res = {};
+
+ res = tftf_smc(&(smc_args)
+ {RSI_MEM_SET_PERM_VALUE, plane_index, perm_index, perm});
+ return res.ret0;
+}
+
+u_register_t rsi_mem_set_perm_index(u_register_t base,
+ u_register_t top,
+ u_register_t perm_index,
+ u_register_t cookie,
+ u_register_t *new_base,
+ u_register_t *response,
+ u_register_t *new_cookie)
+{
+ smc_ret_values res = {};
+
+ res = tftf_smc(&(smc_args)
+ {RSI_MEM_SET_PERM_INDEX, base, top, perm_index, cookie});
+ if (res.ret0 == RSI_SUCCESS) {
+ *new_base = res.ret1;
+ *response = res.ret2;
+ *new_cookie = res.ret3;
+ }
+ return res.ret0;
+}
+
+u_register_t rsi_plane_enter(u_register_t plane_index,
+ u_register_t plane_run)
+{
+ smc_ret_values res = {};
+
+ res = tftf_smc(&(smc_args)
+ {RSI_PLANE_ENTER, plane_index, plane_run});
+ return res.ret0;
+}