Merge "test(realm): add test for enabling pmu with multiple rec"
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"