test(ff-a): test secondary core boot
Secure partitions register their secondary entrypoint at
initialization.
Added test to validate secondary core bring up:
- The primary VM in the ffa_secure_partitions test setup, starts the
secondary cores.
- Each secondary EC is resumed from the first partition, the respective
pinned core's stack is setup, the mmu and caches are enabled, and
execution gets to the message loop (function `test_main_sp`).
- In the primary VM's execution context, it issues a echo request at
every core, to validate they are up and running.
Change-Id: I3a7e9f5fd8eb54181ed0d1af2becaed4268fa0fb
Signed-off-by: Olivier Deprez <olivier.deprez@arm.com>
Signed-off-by: J-Alves <joao.alves@arm.com>
diff --git a/inc/vmapi/hf/call.h b/inc/vmapi/hf/call.h
index 44aaf39..5b6ac0d 100644
--- a/inc/vmapi/hf/call.h
+++ b/inc/vmapi/hf/call.h
@@ -63,6 +63,17 @@
}
/**
+ * DEN0077A FF-A v1.1 Beta0 section 18.3.2.1
+ * Registers vCPU secondary entry point for the caller VM.
+ * Called from secure virtual FF-A instance.
+ */
+static inline struct ffa_value ffa_secondary_ep_register(uintptr_t address)
+{
+ return ffa_call((struct ffa_value){.func = FFA_SECONDARY_EP_REGISTER_64,
+ .arg1 = address});
+}
+
+/**
* Returns the VM's own ID.
*/
static inline ffa_vm_id_t hf_vm_get_id(void)
diff --git a/src/arch/aarch64/hftest/BUILD.gn b/src/arch/aarch64/hftest/BUILD.gn
index cd25e17..f569e63 100644
--- a/src/arch/aarch64/hftest/BUILD.gn
+++ b/src/arch/aarch64/hftest/BUILD.gn
@@ -13,6 +13,12 @@
]
}
+source_set("sp_secondary_entry") {
+ sources = [
+ "sp_secondary_entry.S",
+ ]
+}
+
# Implements image_entry for a simple EL0 partition.
source_set("el0_entry") {
sources = [
diff --git a/src/arch/aarch64/hftest/sp_secondary_entry.S b/src/arch/aarch64/hftest/sp_secondary_entry.S
new file mode 100644
index 0000000..b54feae
--- /dev/null
+++ b/src/arch/aarch64/hftest/sp_secondary_entry.S
@@ -0,0 +1,28 @@
+/*
+ * Copyright 2021 The Hafnium Authors.
+ *
+ * Use of this source code is governed by a BSD-style
+ * license that can be found in the LICENSE file or at
+ * https://opensource.org/licenses/BSD-3-Clause.
+ */
+
+.section .init.image_entry, "ax"
+.global secondary_ep_entry
+secondary_ep_entry:
+ /*
+ * Prepare the stack for core.
+ * The mpdir_el1 register contains the linear ID.
+ */
+ mrs x29, mpidr_el1
+ ubfx x29, x29, #0, #30
+ mov x27, #4096
+ mul x27, x29, x27
+ adrp x30, kstack
+ add sp, x30, x27
+
+ /* Enable MMU and cache. */
+ bl hftest_mm_vcpu_init
+
+ /* Branch to message loop hinting a secondary vCPU. */
+ mov x0, xzr
+ b test_main_sp
diff --git a/test/hftest/BUILD.gn b/test/hftest/BUILD.gn
index 15c214a..d9a342c 100644
--- a/test/hftest/BUILD.gn
+++ b/test/hftest/BUILD.gn
@@ -75,6 +75,7 @@
"//src/arch/${plat_arch}:entry",
"//src/arch/${plat_arch}/hftest:entry",
"//src/arch/${plat_arch}/hftest:power_mgmt",
+ "//src/arch/${plat_arch}/hftest:sp_secondary_entry",
"//vmlib/${plat_arch}:call",
]
}
diff --git a/test/hftest/secure_service.c b/test/hftest/secure_service.c
index 3a7e246..cff2f00 100644
--- a/test/hftest/secure_service.c
+++ b/test/hftest/secure_service.c
@@ -18,12 +18,15 @@
#include "test/abort.h"
#include "test/hftest.h"
-alignas(4096) uint8_t kstack[4096];
+alignas(4096) uint8_t kstack[MAX_CPUS][4096];
-void test_main_sp(void);
+void test_main_sp(bool);
noreturn void kmain(void)
{
+ extern void secondary_ep_entry(void);
+ struct ffa_value res;
+
/*
* Initialize the stage-1 MMU and identity-map the entire address space.
*/
@@ -33,7 +36,11 @@
abort();
}
- test_main_sp();
+ /* Register entry point for secondary vCPUs. */
+ res = ffa_secondary_ep_register((uintptr_t)secondary_ep_entry);
+ EXPECT_EQ(res.func, FFA_SUCCESS_32);
+
+ test_main_sp(true);
/* Do not expect to get to this point, so abort. */
abort();
diff --git a/test/vmapi/ffa_secure_partitions/BUILD.gn b/test/vmapi/ffa_secure_partitions/BUILD.gn
index e040c17..d80a973 100644
--- a/test/vmapi/ffa_secure_partitions/BUILD.gn
+++ b/test/vmapi/ffa_secure_partitions/BUILD.gn
@@ -15,10 +15,12 @@
sources = [
"dir_msg.c",
"notifications.c",
+ "power_mgt.c",
"setup_and_discovery.c",
]
deps = [
+ "//src/arch/${plat_arch}/hftest:power_mgmt",
"//test/hftest:hftest_primary_vm",
"//test/vmapi/common:common",
]
diff --git a/test/vmapi/ffa_secure_partitions/power_mgt.c b/test/vmapi/ffa_secure_partitions/power_mgt.c
new file mode 100644
index 0000000..35d5e4f
--- /dev/null
+++ b/test/vmapi/ffa_secure_partitions/power_mgt.c
@@ -0,0 +1,70 @@
+/*
+ * Copyright 2021 The Hafnium Authors.
+ *
+ * Use of this source code is governed by a BSD-style
+ * license that can be found in the LICENSE file or at
+ * https://opensource.org/licenses/BSD-3-Clause.
+ */
+
+#include "hf/arch/vm/power_mgmt.h"
+
+#include "hf/dlog.h"
+#include "hf/ffa.h"
+#include "hf/spinlock.h"
+
+#include "vmapi/hf/call.h"
+
+#include "partition_services.h"
+#include "test/hftest.h"
+#include "test/vmapi/ffa.h"
+
+alignas(4096) static uint8_t secondary_ec_stack[MAX_CPUS - 1][4096];
+
+/**
+ * Releases the lock passed in.
+ */
+static void cpu_entry_echo(uintptr_t arg)
+{
+ ffa_vm_id_t own_id = hf_vm_get_id();
+ // NOLINTNEXTLINE(performance-no-int-to-ptr)
+ struct spinlock *lock = (struct spinlock *)arg;
+ const uint32_t msg[] = {SP_ECHO_CMD, 0x1, 0x2, 0x3, 0x4};
+ const ffa_vm_id_t receiver_id = HF_OTHER_WORLD_ID + 1;
+ struct ffa_value res;
+
+ res = sp_echo_cmd_send(own_id, receiver_id, msg[0], msg[1], msg[2],
+ msg[3]);
+
+ EXPECT_EQ(res.func, FFA_MSG_SEND_DIRECT_RESP_32);
+ EXPECT_EQ(res.arg4, msg[0]);
+ EXPECT_EQ(res.arg5, msg[1]);
+ EXPECT_EQ(res.arg6, msg[2]);
+ EXPECT_EQ(res.arg7, msg[3]);
+
+ sl_unlock(lock);
+
+ arch_cpu_stop();
+}
+
+TEST(ffa_power_mgt, cpu_start)
+{
+ struct spinlock lock = SPINLOCK_INIT;
+
+ /* Start secondary EC while holding lock. */
+ sl_lock(&lock);
+
+ for (uint32_t i = 0; i < MAX_CPUS - 1; i++) {
+ dlog_verbose("Booting CPU %u\n", i + 1);
+
+ EXPECT_EQ(hftest_cpu_start(hftest_get_cpu_id(i + 1),
+ secondary_ec_stack[i],
+ sizeof(secondary_ec_stack[0]),
+ cpu_entry_echo, (uintptr_t)&lock),
+ true);
+
+ /* Wait for CPU to release the lock. */
+ sl_lock(&lock);
+
+ dlog_verbose("Done with CPU %u\n", i + 1);
+ }
+}
diff --git a/test/vmapi/ffa_secure_partitions/services/message_loop.c b/test/vmapi/ffa_secure_partitions/services/message_loop.c
index 8c50432..d7136d5 100644
--- a/test/vmapi/ffa_secure_partitions/services/message_loop.c
+++ b/test/vmapi/ffa_secure_partitions/services/message_loop.c
@@ -16,13 +16,18 @@
* Message loop to add tests to be controlled by the control partition(depends
* on the test set-up).
*/
-noreturn void test_main_sp(void)
+noreturn void test_main_sp(bool is_boot_vcpu)
{
struct ffa_value res = ffa_msg_wait();
while (1) {
EXPECT_EQ(res.func, FFA_MSG_SEND_DIRECT_REQ_32);
+ if (is_boot_vcpu) {
+ /* TODO: can only print from boot vCPU. */
+ HFTEST_LOG("Received direct message request");
+ }
+
switch (res.arg3) {
case SP_ECHO_CMD:
res = sp_echo_cmd(ffa_sender(res), res.arg3, res.arg4,
@@ -50,7 +55,8 @@
default:
HFTEST_LOG_FAILURE();
HFTEST_LOG(HFTEST_LOG_INDENT
- "0x%x is not a valid command id\n");
+ "0x%x is not a valid command id\n",
+ res.arg3);
abort();
}
}