Add message relay test.

This test sends messages between two secondary VMs. The message is send
from the primary, to relay_a, to relay_b and finally back to the
primary.

Bug: 116705004
Change-Id: Iff5b1726b870e9f502dedd9a4075da2529f50a09
diff --git a/test/vm/BUILD.gn b/test/vm/BUILD.gn
index 4d7155f..743326d 100644
--- a/test/vm/BUILD.gn
+++ b/test/vm/BUILD.gn
@@ -65,10 +65,24 @@
 initrd("primary_with_secondaries_test") {
   testonly = true
   primary_vm = ":primary_with_secondaries_test_vm"
-  secondary_vms = [ [
-        "1048576",
-        "1",
-        "echo",
-        "//test/vm/secondaries:echo",
-      ] ]
+  secondary_vms = [
+    [
+      "1048576",
+      "1",
+      "relay_a",
+      "//test/vm/secondaries:relay_a",
+    ],
+    [
+      "1048576",
+      "1",
+      "relay_b",
+      "//test/vm/secondaries:relay_b",
+    ],
+    [
+      "1048576",
+      "1",
+      "echo",
+      "//test/vm/secondaries:echo",
+    ],
+  ]
 }
diff --git a/test/vm/primary_with_secondaries.c b/test/vm/primary_with_secondaries.c
index 52417f8..9e9fce0 100644
--- a/test/vm/primary_with_secondaries.c
+++ b/test/vm/primary_with_secondaries.c
@@ -17,14 +17,21 @@
 static hf_ipaddr_t send_page_addr = (hf_ipaddr_t)send_page;
 static hf_ipaddr_t recv_page_addr = (hf_ipaddr_t)recv_page;
 
-#define ECHO_VM_ID 1
+/* Keep macro alignment */
+/* clang-format off */
+
+#define RELAY_A_VM_ID 1
+#define RELAY_B_VM_ID 2
+#define ECHO_VM_ID    3
+
+/* clang-format on */
 
 /**
- * Confirm there is 1 secondary VM.
+ * Confirm there are 3 secondary VMs.
  */
-TEST(hf_vm_get_count, one_secondary_vm)
+TEST(hf_vm_get_count, three_secondary_vms)
 {
-	EXPECT_EQ(hf_vm_get_count(), 2);
+	EXPECT_EQ(hf_vm_get_count(), 4);
 }
 
 /**
@@ -109,3 +116,33 @@
 	EXPECT_EQ(memcmp(recv_page, message, sizeof(message)), 0);
 	EXPECT_EQ(hf_mailbox_clear(), 0);
 }
+
+/**
+ * Send a message to relay_a which will forward it to relay_b where it will be
+ * sent back here.
+ */
+TEST(mailbox, relay)
+{
+	const char message[] = "Send this round the relay!";
+
+	/* Configure mailbox pages. */
+	EXPECT_EQ(hf_vm_configure(send_page_addr, recv_page_addr), 0);
+	EXPECT_EQ(hf_vcpu_run(RELAY_A_VM_ID, 0),
+		  HF_VCPU_RUN_RESPONSE(HF_VCPU_RUN_WAIT_FOR_INTERRUPT, 0, 0));
+	EXPECT_EQ(hf_vcpu_run(RELAY_B_VM_ID, 0),
+		  HF_VCPU_RUN_RESPONSE(HF_VCPU_RUN_WAIT_FOR_INTERRUPT, 0, 0));
+
+	/*
+	 * Send the message to relay_a which is then sent to relay_b before
+	 * checking that relay_b send the message back here.
+	 */
+	memcpy(send_page, message, sizeof(message));
+	EXPECT_EQ(hf_mailbox_send(RELAY_A_VM_ID, sizeof(message)), 0);
+	EXPECT_EQ(hf_vcpu_run(RELAY_A_VM_ID, 0),
+		  HF_VCPU_RUN_RESPONSE(HF_VCPU_RUN_WAKE_UP, RELAY_B_VM_ID, 0));
+	EXPECT_EQ(
+		hf_vcpu_run(RELAY_B_VM_ID, 0),
+		HF_VCPU_RUN_RESPONSE(HF_VCPU_RUN_MESSAGE, 0, sizeof(message)));
+	EXPECT_EQ(memcmp(recv_page, message, sizeof(message)), 0);
+	EXPECT_EQ(hf_mailbox_clear(), 0);
+}
diff --git a/test/vm/secondaries/BUILD.gn b/test/vm/secondaries/BUILD.gn
index 3f17fc6..85700da 100644
--- a/test/vm/secondaries/BUILD.gn
+++ b/test/vm/secondaries/BUILD.gn
@@ -11,3 +11,27 @@
     "//test/vm:secondary_vm",
   ]
 }
+
+vm_kernel("relay_a") {
+  testonly = true
+
+  sources = [
+    "relay_a.c",
+  ]
+
+  deps = [
+    "//test/vm:secondary_vm",
+  ]
+}
+
+vm_kernel("relay_b") {
+  testonly = true
+
+  sources = [
+    "relay_b.c",
+  ]
+
+  deps = [
+    "//test/vm:secondary_vm",
+  ]
+}
diff --git a/test/vm/secondaries/relay_a.c b/test/vm/secondaries/relay_a.c
new file mode 100644
index 0000000..e44267d
--- /dev/null
+++ b/test/vm/secondaries/relay_a.c
@@ -0,0 +1,32 @@
+#include <stdalign.h>
+#include <stdint.h>
+
+#include "hf/mm.h"
+#include "hf/std.h"
+
+#include "vmapi/hf/call.h"
+
+#define FORWARD_VM_ID 2
+
+alignas(4096) uint8_t kstack[4096];
+
+static alignas(PAGE_SIZE) uint8_t send_page[PAGE_SIZE];
+static alignas(PAGE_SIZE) uint8_t recv_page[PAGE_SIZE];
+
+static hf_ipaddr_t send_page_addr = (hf_ipaddr_t)send_page;
+static hf_ipaddr_t recv_page_addr = (hf_ipaddr_t)recv_page;
+
+void kmain(void)
+{
+	hf_vm_configure(send_page_addr, recv_page_addr);
+	hf_vm_configure(send_page_addr, recv_page_addr);
+
+	/* Loop, forward messages to the next VM. */
+	for (;;) {
+		uint64_t ret = hf_mailbox_receive(true);
+		uint32_t size = HF_MAILBOX_RECEIVE_SIZE(ret);
+		memcpy(send_page, recv_page, size);
+		hf_mailbox_clear();
+		hf_mailbox_send(FORWARD_VM_ID, size);
+	}
+}
diff --git a/test/vm/secondaries/relay_b.c b/test/vm/secondaries/relay_b.c
new file mode 100644
index 0000000..ce83ce2
--- /dev/null
+++ b/test/vm/secondaries/relay_b.c
@@ -0,0 +1,30 @@
+#include <stdalign.h>
+#include <stdint.h>
+
+#include "hf/mm.h"
+#include "hf/std.h"
+
+#include "vmapi/hf/call.h"
+
+alignas(4096) uint8_t kstack[4096];
+
+static alignas(PAGE_SIZE) uint8_t send_page[PAGE_SIZE];
+static alignas(PAGE_SIZE) uint8_t recv_page[PAGE_SIZE];
+
+static hf_ipaddr_t send_page_addr = (hf_ipaddr_t)send_page;
+static hf_ipaddr_t recv_page_addr = (hf_ipaddr_t)recv_page;
+
+void kmain(void)
+{
+	hf_vm_configure(send_page_addr, recv_page_addr);
+	hf_vm_configure(send_page_addr, recv_page_addr);
+
+	/* Loop, forward messages to the primary. */
+	for (;;) {
+		uint64_t ret = hf_mailbox_receive(true);
+		uint32_t size = HF_MAILBOX_RECEIVE_SIZE(ret);
+		memcpy(send_page, recv_page, size);
+		hf_mailbox_clear();
+		hf_mailbox_send(HF_PRIMARY_VM_ID, size);
+	}
+}