feat(hftest): drive test execution via FF-A v1.1 indirect message
FF-A v1.1 indirect messaging is implemented for both SPs and VMs.
This allows the hftest framework to drive tests to NWd VMs as well
as SPs.
Change mostly impacts 'SELECT_SERVICE' macro and 'hftest_service_main'
function:
- The macro SELECT_SERVICE is used to drive the tests from the Primary
VM, by sending indirect messages to Secondary VMs/SPs.
- The function hftest_service_main handles the indirect message requests
in the target partition.
Change-Id: If8874f434ad598444222403c6d8450ad283f1b95
Signed-off-by: J-Alves <joao.alves@arm.com>
diff --git a/test/hftest/BUILD.gn b/test/hftest/BUILD.gn
index 57db19f..5394561 100644
--- a/test/hftest/BUILD.gn
+++ b/test/hftest/BUILD.gn
@@ -274,6 +274,7 @@
"//src:memiter",
"//src:panic",
"//src:std",
+ "//test/vmapi/common:common",
]
}
diff --git a/test/hftest/service_common.c b/test/hftest/service_common.c
index 25df466..43455f1 100644
--- a/test/hftest/service_common.c
+++ b/test/hftest/service_common.c
@@ -19,18 +19,13 @@
#include "test/hftest.h"
#include "test/hftest_impl.h"
+#include "test/vmapi/ffa.h"
HFTEST_ENABLE();
extern struct hftest_test hftest_begin[];
extern struct hftest_test hftest_end[];
-static alignas(HF_MAILBOX_SIZE) uint8_t send[HF_MAILBOX_SIZE];
-static alignas(HF_MAILBOX_SIZE) uint8_t recv[HF_MAILBOX_SIZE];
-
-static hf_ipaddr_t send_addr = (hf_ipaddr_t)send;
-static hf_ipaddr_t recv_addr = (hf_ipaddr_t)recv;
-
static struct hftest_context global_context;
struct hftest_context *hftest_get_context(void)
@@ -76,16 +71,29 @@
struct hftest_context *ctx;
struct ffa_value ret;
struct fdt fdt;
-
- /* Prepare the context. */
-
- /* Set up the mailbox. */
- ffa_rxtx_map(send_addr, recv_addr);
+ ffa_vm_id_t own_id = hf_vm_get_id();
+ struct mailbox_buffers mb = set_up_mailbox();
+ ffa_notifications_bitmap_t bitmap;
+ struct ffa_partition_msg *message = (struct ffa_partition_msg *)mb.recv;
/* Receive the name of the service to run. */
- ret = ffa_msg_wait();
- ASSERT_EQ(ret.func, FFA_MSG_SEND_32);
- memiter_init(&args, recv, ffa_msg_send_size(ret));
+ ffa_msg_wait();
+
+ /*
+ * Expect to wake up with indirect message related to the next service
+ * to be executed.
+ */
+ ret = ffa_notification_get(own_id, 0,
+ FFA_NOTIFICATION_FLAG_BITMAP_SPM |
+ FFA_NOTIFICATION_FLAG_BITMAP_HYP);
+ ASSERT_EQ(ret.func, FFA_SUCCESS_32);
+ bitmap = ffa_notification_get_from_framework(ret);
+ ASSERT_TRUE(is_ffa_spm_buffer_full_notification(bitmap) ||
+ is_ffa_hyp_buffer_full_notification(bitmap));
+ ASSERT_EQ(own_id, ffa_rxtx_header_receiver(&message->header));
+ memiter_init(&args, message->payload, message->header.size);
+
+ /* Find service handler. */
service = find_service(&args);
EXPECT_EQ(ffa_rx_release().func, FFA_SUCCESS_32);
@@ -106,9 +114,16 @@
ctx = hftest_get_context();
memset_s(ctx, sizeof(*ctx), 0, sizeof(*ctx));
ctx->abort = abort;
- ctx->send = send;
- ctx->recv = recv;
- if (!fdt_get_memory_size(&fdt, &ctx->memory_size)) {
+ ctx->send = mb.send;
+ ctx->recv = mb.recv;
+
+ /*
+ * The memory size argument is to be used only by VMs. It is part of
+ * the dt provided by the Hypervisor. SPs expect to receive their
+ * FF-A manifest which doesn't have a memory size field.
+ */
+ if (!IS_SP_ID(own_id) &&
+ !fdt_get_memory_size(&fdt, &ctx->memory_size)) {
HFTEST_LOG_FAILURE();
HFTEST_LOG(HFTEST_LOG_INDENT
"No entry in the FDT on memory size details");
diff --git a/test/inc/test/hftest_impl.h b/test/inc/test/hftest_impl.h
index ff388e9..8b83488 100644
--- a/test/inc/test/hftest_impl.h
+++ b/test/inc/test/hftest_impl.h
@@ -274,29 +274,35 @@
/**
* Select the service to run in a service VM.
*/
-#define HFTEST_SERVICE_SELECT(vm_id, service, send_buffer) \
- do { \
- struct ffa_value run_res; \
- uint32_t msg_length = \
- strnlen_s(service, SERVICE_NAME_MAX_LENGTH); \
- \
- /* \
- * Let the service configure its mailbox and wait for a \
- * message. \
- */ \
- run_res = ffa_run(vm_id, 0); \
- ASSERT_EQ(run_res.func, FFA_MSG_WAIT_32); \
- ASSERT_EQ(run_res.arg2, FFA_SLEEP_INDEFINITE); \
- \
- /* Send the selected service to run and let it be handled. */ \
- memcpy_s(send_buffer, FFA_MSG_PAYLOAD_MAX, service, \
- msg_length); \
- \
- ASSERT_EQ(ffa_msg_send(hf_vm_get_id(), vm_id, msg_length, 0) \
- .func, \
- FFA_SUCCESS_32); \
- run_res = ffa_run(vm_id, 0); \
- ASSERT_EQ(run_res.func, FFA_YIELD_32); \
+#define HFTEST_SERVICE_SELECT(vm_id, service, send_buffer) \
+ do { \
+ struct ffa_value res; \
+ uint32_t msg_length = \
+ strnlen_s(service, SERVICE_NAME_MAX_LENGTH); \
+ struct ffa_partition_msg *message = \
+ (struct ffa_partition_msg *)send_buffer; \
+ \
+ /* \
+ * If service is a Secondary VM, let the service configure \
+ * its mailbox and wait for a message. \
+ */ \
+ res = ffa_run(vm_id, 0); \
+ ASSERT_EQ(res.func, FFA_MSG_WAIT_32); \
+ ASSERT_EQ(res.arg2, FFA_SLEEP_INDEFINITE); \
+ \
+ /* \
+ * Send the selected service to run and let it be \
+ * handled. \
+ */ \
+ ffa_rxtx_header_init(hf_vm_get_id(), vm_id, msg_length, \
+ &message->header); \
+ memcpy_s(message->payload, FFA_PARTITION_MSG_PAYLOAD_MAX, \
+ service, msg_length); \
+ res = ffa_msg_send2(0); \
+ \
+ ASSERT_EQ(res.func, FFA_SUCCESS_32); \
+ res = ffa_run(vm_id, 0); \
+ ASSERT_EQ(res.func, FFA_YIELD_32); \
} while (0)
#define HFTEST_SERVICE_SEND_BUFFER() hftest_get_context()->send