test(realm): add test for enabling pmu with multiple rec
Test creates realm with less number of pmu counters than available
Test verifies that only programmed num of pmu counters are available in realm
Change-Id: I479dd8949950357b9814576b1b6cef142d21c75f
Signed-off-by: Shruti Gupta <shruti.gupta@arm.com>
diff --git a/include/runtime_services/host_realm_managment/host_realm_helper.h b/include/runtime_services/host_realm_managment/host_realm_helper.h
index d7c70a9..9f6d934 100644
--- a/include/runtime_services/host_realm_managment/host_realm_helper.h
+++ b/include/runtime_services/host_realm_managment/host_realm_helper.h
@@ -10,6 +10,21 @@
#include <host_realm_rmi.h>
#include <tftf_lib.h>
+/*
+ * Creates realm, initializes heap and creates RTTs
+ */
+bool host_prepare_realm_payload(struct realm *realm_ptr,
+ u_register_t realm_payload_adr,
+ u_register_t plat_mem_pool_adr,
+ u_register_t realm_pages_size,
+ u_register_t feature_flag,
+ const u_register_t *rec_flag,
+ unsigned int rec_count);
+
+/*
+ * Creates realm, initializes heap, creates RTTs and also
+ * Creates recs
+ */
bool host_create_realm_payload(struct realm *realm_ptr,
u_register_t realm_payload_adr,
u_register_t plat_mem_pool_adr,
@@ -17,6 +32,11 @@
u_register_t feature_flag,
const u_register_t *rec_flag,
unsigned int rec_count);
+
+/*
+ * Creates realm, initializes heap, creates RTTs,
+ * creates recs and activate realm
+ */
bool host_create_activate_realm_payload(struct realm *realm_ptr,
u_register_t realm_payload_adr,
u_register_t plat_mem_pool_adr,
diff --git a/include/runtime_services/host_realm_managment/host_realm_pmu.h b/include/runtime_services/host_realm_managment/host_realm_pmu.h
index 48089f3..844bb29 100644
--- a/include/runtime_services/host_realm_managment/host_realm_pmu.h
+++ b/include/runtime_services/host_realm_managment/host_realm_pmu.h
@@ -20,7 +20,7 @@
#define PMU_CLEAR_ALL 0x1FFFFFFFF
/* Number of event counters implemented */
-#define GET_CNT_NUM \
+#define GET_PMU_CNT \
((read_pmcr_el0() >> PMCR_EL0_N_SHIFT) & PMCR_EL0_N_MASK)
void host_set_pmu_state(void);
diff --git a/include/runtime_services/host_realm_managment/host_shared_data.h b/include/runtime_services/host_realm_managment/host_shared_data.h
index 632fdaa..7cfffe6 100644
--- a/include/runtime_services/host_realm_managment/host_shared_data.h
+++ b/include/runtime_services/host_realm_managment/host_shared_data.h
@@ -50,6 +50,7 @@
REALM_INSTR_FETCH_CMD,
REALM_DATA_ACCESS_CMD,
REALM_PMU_CYCLE,
+ REALM_PMU_COUNTER,
REALM_PMU_EVENT,
REALM_PMU_PRESERVE,
REALM_PMU_INTERRUPT,
diff --git a/realm/include/realm_tests.h b/realm/include/realm_tests.h
index 3016a4d..b58949b 100644
--- a/realm/include/realm_tests.h
+++ b/realm/include/realm_tests.h
@@ -9,6 +9,7 @@
#define REALM_TESTS_H
bool test_pmuv3_cycle_works_realm(void);
+bool test_pmuv3_counter(void);
bool test_pmuv3_event_works_realm(void);
bool test_pmuv3_rmm_preserves(void);
bool test_pmuv3_overflow_interrupt(void);
diff --git a/realm/realm_payload_main.c b/realm/realm_payload_main.c
index ce25f43..5eec5b8 100644
--- a/realm/realm_payload_main.c
+++ b/realm/realm_payload_main.c
@@ -252,6 +252,9 @@
case REALM_PMU_CYCLE:
test_succeed = test_pmuv3_cycle_works_realm();
break;
+ case REALM_PMU_COUNTER:
+ test_succeed = test_pmuv3_counter();
+ break;
case REALM_PMU_EVENT:
test_succeed = test_pmuv3_event_works_realm();
break;
diff --git a/realm/realm_pmuv3.c b/realm/realm_pmuv3.c
index 3ae597d..0d4782a 100644
--- a/realm/realm_pmuv3.c
+++ b/realm/realm_pmuv3.c
@@ -162,6 +162,21 @@
return false;
}
+/* Test if max counter available is same as that programmed by host */
+bool test_pmuv3_counter(void)
+{
+ uint64_t num_cnts, num_cnts_host;
+
+ num_cnts_host = realm_shared_data_get_my_host_val(HOST_ARG1_INDEX);
+ num_cnts = GET_PMU_CNT;
+ realm_printf("CPU=%u num_cnts=%lu num_cnts_host=%lu\n", read_mpidr_el1() & MPID_MASK,
+ num_cnts, num_cnts_host);
+ if (num_cnts == num_cnts_host) {
+ return true;
+ }
+ return false;
+}
+
/*
* Try an event counter with some NOPs to see if it works.
*/
@@ -170,7 +185,7 @@
u_register_t evcounter_start;
u_register_t evcounter_end;
- if (GET_CNT_NUM == 0) {
+ if (GET_PMU_CNT == 0) {
realm_printf("no event counters implemented\n");
return false;
}
@@ -208,7 +223,7 @@
u_register_t ctr_end[MAX_COUNTERS] = {0};
u_register_t ctr_cfg_end[MAX_COUNTERS] = {0};
u_register_t pmu_cfg_end[3];
- unsigned int impl_ev_ctrs = GET_CNT_NUM;
+ unsigned int impl_ev_ctrs = GET_PMU_CNT;
realm_printf("testing %u event counters\n", impl_ev_ctrs);
diff --git a/tftf/tests/runtime_services/host_realm_managment/host_pmuv3.c b/tftf/tests/runtime_services/host_realm_managment/host_pmuv3.c
index 042132e..ceca36d 100644
--- a/tftf/tests/runtime_services/host_realm_managment/host_pmuv3.c
+++ b/tftf/tests/runtime_services/host_realm_managment/host_pmuv3.c
@@ -106,7 +106,7 @@
{
unsigned int core_pos = platform_get_core_pos(read_mpidr_el1());
struct pmu_registers *pmu_ptr = &pmu_state[core_pos];
- unsigned int num_cnts = GET_CNT_NUM;
+ unsigned int num_cnts = GET_PMU_CNT;
unsigned long val;
val = read_pmcr_el0() | PMCR_EL0_DP_BIT;
@@ -185,7 +185,7 @@
{
unsigned int core_pos = platform_get_core_pos(read_mpidr_el1());
struct pmu_registers *pmu_ptr = &pmu_state[core_pos];
- unsigned int num_cnts = GET_CNT_NUM;
+ unsigned int num_cnts = GET_PMU_CNT;
unsigned long val, read_val;
CHECK_PMREG(pmcr_el0);
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 59a0012..2c58919 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
@@ -105,13 +105,13 @@
return true;
}
-bool host_create_realm_payload(struct realm *realm_ptr,
- u_register_t realm_payload_adr,
- u_register_t plat_mem_pool_adr,
- u_register_t realm_pages_size,
- u_register_t feature_flag,
- const u_register_t *rec_flag,
- unsigned int rec_count)
+bool host_prepare_realm_payload(struct realm *realm_ptr,
+ u_register_t realm_payload_adr,
+ u_register_t plat_mem_pool_adr,
+ u_register_t realm_pages_size,
+ u_register_t feature_flag,
+ const u_register_t *rec_flag,
+ unsigned int rec_count)
{
int8_t value;
@@ -250,12 +250,6 @@
return false;
}
- if (host_realm_init_ipa_state(realm_ptr, 0U, 0U, 1ULL << 32)
- != RMI_SUCCESS) {
- ERROR("%s() failed\n", "host_realm_init_ipa_state");
- goto destroy_realm;
- }
-
/* RTT map Realm image */
if (host_realm_map_payload_image(realm_ptr, realm_payload_adr) !=
REALM_SUCCESS) {
@@ -263,12 +257,6 @@
goto destroy_realm;
}
- /* Create REC */
- if (host_realm_rec_create(realm_ptr) != REALM_SUCCESS) {
- ERROR("%s() failed\n", "host_realm_rec_create");
- goto destroy_realm;
- }
-
realm_ptr->payload_created = true;
return true;
@@ -283,6 +271,48 @@
return false;
}
+bool host_create_realm_payload(struct realm *realm_ptr,
+ u_register_t realm_payload_adr,
+ u_register_t plat_mem_pool_adr,
+ u_register_t realm_pages_size,
+ u_register_t feature_flag,
+ const u_register_t *rec_flag,
+ unsigned int rec_count)
+{
+ bool ret;
+
+ ret = host_prepare_realm_payload(realm_ptr,
+ realm_payload_adr,
+ plat_mem_pool_adr,
+ realm_pages_size,
+ feature_flag,
+ rec_flag,
+ rec_count);
+ if (!ret) {
+ goto destroy_realm;
+ } else {
+ /* Create REC */
+ if (host_realm_rec_create(realm_ptr) != REALM_SUCCESS) {
+ ERROR("%s() failed\n", "host_realm_rec_create");
+ goto destroy_realm;
+ }
+
+ if (host_realm_init_ipa_state(realm_ptr, 0U, 0U, 1ULL << 32)
+ != RMI_SUCCESS) {
+ ERROR("%s() failed\n", "host_realm_init_ipa_state");
+ goto destroy_realm;
+ }
+ }
+ return true;
+
+destroy_realm:
+ if (host_realm_destroy(realm_ptr) != REALM_SUCCESS) {
+ ERROR("%s() failed\n", "host_realm_destroy");
+ }
+ realm_ptr->payload_created = false;
+ return false;
+}
+
bool host_create_activate_realm_payload(struct realm *realm_ptr,
u_register_t realm_payload_adr,
u_register_t plat_mem_pool_adr,
diff --git a/tftf/tests/runtime_services/realm_payload/host_realm_payload_multiple_rec_tests.c b/tftf/tests/runtime_services/realm_payload/host_realm_payload_multiple_rec_tests.c
index d308784..4774dfc 100644
--- a/tftf/tests/runtime_services/realm_payload/host_realm_payload_multiple_rec_tests.c
+++ b/tftf/tests/runtime_services/realm_payload/host_realm_payload_multiple_rec_tests.c
@@ -21,6 +21,7 @@
static uint64_t is_secondary_cpu_on;
static struct realm realm;
+static struct realm realm1;
/*
* Test tries to create max Rec
@@ -544,3 +545,248 @@
}
return ret3;
}
+
+/*
+ * Test PMU counters available to each REC matches that programmed by host
+ * Test PMU counters are preserved for each rec
+ */
+static test_result_t cpu_on_handler_pmu(void)
+{
+ bool ret1;
+ unsigned int i;
+
+ spin_lock(&secondary_cpu_lock);
+ i = is_secondary_cpu_on++;
+ spin_unlock(&secondary_cpu_lock);
+ ret1 = host_enter_realm_execute(&realm, REALM_PMU_COUNTER, RMI_EXIT_HOST_CALL, i);
+ if (!ret1) {
+ return TEST_RESULT_FAIL;
+ }
+ ret1 = host_enter_realm_execute(&realm1, REALM_PMU_COUNTER, RMI_EXIT_HOST_CALL, i);
+ if (!ret1) {
+ return TEST_RESULT_FAIL;
+ }
+ ret1 = host_enter_realm_execute(&realm, REALM_PMU_PRESERVE, RMI_EXIT_HOST_CALL, i);
+ if (!ret1) {
+ return TEST_RESULT_FAIL;
+ }
+ ret1 = host_enter_realm_execute(&realm1, REALM_PMU_PRESERVE, RMI_EXIT_HOST_CALL, i);
+ if (ret1) {
+ return TEST_RESULT_SUCCESS;
+ }
+ return TEST_RESULT_FAIL;
+}
+
+/*
+ * Test realm creation with more PMU counter than available, expect failure
+ * Test realm creation with 0 PMU counter
+ * expect failure if FEAT_HPMN0 is not supported
+ * expect success if FEAT_HPMN0 is supported
+ * Create 2 Realms first one with MAX PMU counters
+ * second realm with lesser PMU counter than available
+ * Schedule multiple rec on multiple CPU
+ * Test PMU counters available to each REC matches that programmed by host
+ * Test PMU counters are preserved for each rec
+ */
+test_result_t host_realm_pmuv3_mul_rec(void)
+{
+ u_register_t feature_flag;
+ u_register_t rmm_feat_reg0;
+ u_register_t rec_flag[8U] = {RMI_RUNNABLE, RMI_RUNNABLE, RMI_RUNNABLE, RMI_RUNNABLE,
+ RMI_RUNNABLE, RMI_RUNNABLE, RMI_RUNNABLE, RMI_RUNNABLE};
+ bool ret1 = 0U, ret2;
+ unsigned int num_cnts, i = 0U;
+ u_register_t other_mpidr, my_mpidr, ret;
+ int cpu_node;
+
+ SKIP_TEST_IF_RME_NOT_SUPPORTED_OR_RMM_IS_TRP();
+
+ /* Get Max PMU counter implemented through RMI_FEATURES */
+ if (host_rmi_features(0UL, &rmm_feat_reg0) != REALM_SUCCESS) {
+ ERROR("%s() failed\n", "host_rmi_features");
+ return TEST_RESULT_FAIL;
+ }
+
+ num_cnts = EXTRACT(RMI_FEATURE_REGISTER_0_PMU_NUM_CTRS, rmm_feat_reg0);
+ host_set_pmu_state();
+ is_secondary_cpu_on = 0;
+ my_mpidr = read_mpidr_el1() & MPID_MASK;
+
+ if (num_cnts == 0U) {
+ ERROR("No PMU counters implemented\n");
+ return TEST_RESULT_SKIPPED;
+ }
+
+ feature_flag = RMI_FEATURE_REGISTER_0_PMU_EN |
+ INPLACE(FEATURE_PMU_NUM_CTRS, num_cnts + 1U);
+
+
+ /* Request more PMU counter than total, expect failure */
+ 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,
+ feature_flag, rec_flag, 1U)) {
+ ERROR("Realm create should have failed\n");
+ host_destroy_realm(&realm);
+ return TEST_RESULT_FAIL;
+ }
+
+ /* Request 0 PMU counter */
+ feature_flag = RMI_FEATURE_REGISTER_0_PMU_EN |
+ INPLACE(FEATURE_PMU_NUM_CTRS, 0U);
+
+ ret1 = 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,
+ feature_flag, rec_flag, 1U);
+
+ if (!get_feat_hpmn0_supported()) {
+ if (ret1) {
+ ERROR("Realm create with 0 PMU Counter should have failed\n");
+ host_destroy_realm(&realm);
+ return TEST_RESULT_FAIL;
+ }
+ } else {
+ if (!ret1) {
+ ERROR("Realm create with 0 PMU Counter should not have failed\n");
+ return TEST_RESULT_FAIL;
+ }
+ host_destroy_realm(&realm);
+ }
+
+ /* Test 2 create first realm with max PMU counters */
+ feature_flag = RMI_FEATURE_REGISTER_0_PMU_EN |
+ INPLACE(FEATURE_PMU_NUM_CTRS, num_cnts);
+
+ /* Prepare realm0, create recs for realm0 later */
+ if (!host_prepare_realm_payload(&realm, (u_register_t)REALM_IMAGE_BASE,
+ (u_register_t)PAGE_POOL_BASE,
+ (u_register_t)PAGE_POOL_MAX_SIZE,
+ feature_flag, rec_flag, MAX_REC_COUNT)) {
+ goto test_exit;
+ return TEST_RESULT_FAIL;
+ }
+ if (!host_create_shared_mem(&realm, NS_REALM_SHARED_MEM_BASE,
+ NS_REALM_SHARED_MEM_SIZE)) {
+ goto test_exit;
+ }
+
+ /* Second realm with less num of PMU counters */
+ feature_flag = RMI_FEATURE_REGISTER_0_PMU_EN |
+ INPLACE(FEATURE_PMU_NUM_CTRS, num_cnts - 1U);
+
+ if (!host_create_activate_realm_payload(&realm1, (u_register_t)REALM_IMAGE_BASE,
+ (u_register_t)PAGE_POOL_BASE + PAGE_POOL_MAX_SIZE,
+ (u_register_t)PAGE_POOL_MAX_SIZE,
+ feature_flag, rec_flag, MAX_REC_COUNT)) {
+ goto test_exit2;
+ }
+ if (!host_create_shared_mem(&realm1, NS_REALM_SHARED_MEM_BASE + NS_REALM_SHARED_MEM_SIZE,
+ NS_REALM_SHARED_MEM_SIZE)) {
+ goto test_exit2;
+ }
+
+ /* create realm0 recs, activate realm0 */
+ if (host_realm_rec_create(&realm) != REALM_SUCCESS) {
+ ERROR("%s() failed\n", "host_realm_rec_create");
+ goto test_exit2;
+ }
+
+ if (host_realm_init_ipa_state(&realm, 0U, 0U, 1ULL << 32)
+ != RMI_SUCCESS) {
+ ERROR("%s() failed\n", "host_realm_init_ipa_state");
+ goto test_exit2;
+ }
+
+ if (host_realm_activate(&realm) != REALM_SUCCESS) {
+ ERROR("%s() failed\n", "host_realm_activate");
+ goto test_exit2;
+ }
+ INFO("MAX PMU Counter=%u\n", num_cnts);
+
+ /* Pass num of PMU counters programmed to realm */
+ for (unsigned int j = 0U; j < MAX_REC_COUNT; j++) {
+ host_shared_data_set_host_val(&realm, j, HOST_ARG1_INDEX, num_cnts);
+ host_shared_data_set_host_val(&realm1, j, HOST_ARG1_INDEX, num_cnts - 1U);
+ }
+
+ /*
+ * Enter realm0 rec0 test PMU counters available is same as that programmed by host
+ * Validation is done by the Realm and will return error if the count does not match
+ */
+ ret1 = host_enter_realm_execute(&realm, REALM_PMU_COUNTER, RMI_EXIT_HOST_CALL, 0U);
+ if (!ret1) {
+ goto test_exit2;
+ }
+
+ /* Enter realm1 rec0 test PMU counters available is same as that programmed by host */
+ ret1 = host_enter_realm_execute(&realm1, REALM_PMU_COUNTER, RMI_EXIT_HOST_CALL, 0U);
+ if (!ret1) {
+ goto test_exit2;
+ }
+
+ /* Test if Realm0 rec0 entering/exiting preserves PMU state */
+ ret1 = host_enter_realm_execute(&realm, REALM_PMU_PRESERVE, RMI_EXIT_HOST_CALL, 0U);
+ if (!ret1) {
+ goto test_exit2;
+ }
+
+ /* Test if Realm1 rec0 entering/exiting preserves PMU state */
+ ret1 = host_enter_realm_execute(&realm1, REALM_PMU_PRESERVE, RMI_EXIT_HOST_CALL, 0U);
+ if (!ret1) {
+ goto test_exit2;
+ }
+
+ /* Turn on all CPUs */
+ for_each_cpu(cpu_node) {
+ if (i == (MAX_REC_COUNT - 1U)) {
+ break;
+ }
+ other_mpidr = tftf_get_mpidr_from_node(cpu_node);
+ if (other_mpidr == my_mpidr) {
+ continue;
+ }
+
+ /* Power on the other CPU */
+ ret = tftf_try_cpu_on(other_mpidr, (uintptr_t)cpu_on_handler_pmu, 0);
+ if (ret != PSCI_E_SUCCESS) {
+ ERROR("TFTF CPU ON failed\n");
+ goto test_exit2;
+ }
+ i++;
+ }
+
+ /* Wait for all CPU to power up */
+ while (is_secondary_cpu_on != MAX_REC_COUNT - 1U) {
+ waitms(100);
+ }
+
+ /* Wait for all CPU to power down */
+ for_each_cpu(cpu_node) {
+ other_mpidr = tftf_get_mpidr_from_node(cpu_node) & MPID_MASK;
+ if (other_mpidr == my_mpidr) {
+ continue;
+ }
+ while (tftf_psci_affinity_info(other_mpidr, MPIDR_AFFLVL0) != PSCI_STATE_OFF) {
+ continue;
+ }
+ }
+
+test_exit2:
+ ret2 = host_destroy_realm(&realm1);
+ if (!ret1 || !ret2) {
+ ERROR("%s() enter=%u destroy=%u\n", __func__, ret1, ret2);
+ }
+test_exit:
+ ret2 = host_destroy_realm(&realm);
+ if (!ret1 || !ret2) {
+ ERROR("%s() enter=%u destroy=%u\n", __func__, ret1, ret2);
+ return TEST_RESULT_FAIL;
+ }
+
+ if (!host_check_pmu_state()) {
+ return TEST_RESULT_FAIL;
+ }
+
+ return TEST_RESULT_SUCCESS;
+}
diff --git a/tftf/tests/tests-realm-payload.xml b/tftf/tests/tests-realm-payload.xml
index 9948ff1..51cb09f 100644
--- a/tftf/tests/tests-realm-payload.xml
+++ b/tftf/tests/tests-realm-payload.xml
@@ -58,6 +58,8 @@
function="host_realm_pmuv3_rmm_preserves" />
<testcase name="PMUv3 overflow interrupt"
function="host_realm_pmuv3_overflow_interrupt" />
+ <testcase name="PMUv3 multiple rec validations"
+ function="host_realm_pmuv3_mul_rec" />
<testcase name="Test Secure interrupt can preempt Realm EL1"
function="host_realm_sec_interrupt_can_preempt_rl" />
<testcase name="Check that FPU state registers context is preserved in RL/SE/NS"