SPCI: Introduce SPCI_MSG_SEND.
Morph the vmapi service HF_MAILBOX_SEND onto SPCI_MSG_SEND.
The current SPCI_MSG_SEND only allows for implementation defined
messages to be exchanged between VMs.
The new SPCI service returns SPCI_SUCCESS if message is delivered or one
of the following error codes:
SPCI_INVALID_PARAMETER: one of the parameters in the header does
not conform;
SPCI_BUSY: the mailbox was full or the target VM does not exist.
Adapted the tests to this new service.
Added tests specific to spci_message_init and spci_msg_send.
Change-Id: I55adfe68502ddc7bf864432f3e567b6cfe785f92
diff --git a/driver/linux b/driver/linux
index 71f5736..1cc6c75 160000
--- a/driver/linux
+++ b/driver/linux
@@ -1 +1 @@
-Subproject commit 71f57364e99605d8c881649a34bbf4890051ed71
+Subproject commit 1cc6c75d8a5ca147274c31b98f25f33c6a5466c9
diff --git a/inc/hf/api.h b/inc/hf/api.h
index 4604123..e588575 100644
--- a/inc/hf/api.h
+++ b/inc/hf/api.h
@@ -32,8 +32,6 @@
struct vcpu **next);
int64_t api_vm_configure(ipaddr_t send, ipaddr_t recv, struct vcpu *current,
struct vcpu **next);
-int64_t api_mailbox_send(uint32_t vm_id, size_t size, bool notify,
- struct vcpu *current, struct vcpu **next);
struct hf_mailbox_receive_return api_mailbox_receive(bool block,
struct vcpu *current,
struct vcpu **next);
@@ -53,3 +51,6 @@
int64_t api_interrupt_inject(uint32_t target_vm_id, uint32_t target_vcpu_idx,
uint32_t intid, struct vcpu *current,
struct vcpu **next);
+
+int32_t api_spci_msg_send(uint32_t attributes, struct vcpu *current,
+ struct vcpu **next);
diff --git a/inc/hf/vm.h b/inc/hf/vm.h
index b3b7492..069a265 100644
--- a/inc/hf/vm.h
+++ b/inc/hf/vm.h
@@ -22,6 +22,7 @@
#include "hf/list.h"
#include "hf/mm.h"
#include "hf/mpool.h"
+#include "hf/spci.h"
enum mailbox_state {
/** There is no message in the mailbox. */
@@ -55,8 +56,8 @@
enum mailbox_state state;
uint32_t recv_from_id;
int16_t recv_bytes;
- void *recv;
- const void *send;
+ struct spci_message *recv;
+ const struct spci_message *send;
/**
* List of wait_entry structs representing VMs that want to be notified
diff --git a/inc/vmapi/hf/call.h b/inc/vmapi/hf/call.h
index 5c8b1c6..8bc9627 100644
--- a/inc/vmapi/hf/call.h
+++ b/inc/vmapi/hf/call.h
@@ -17,6 +17,7 @@
#pragma once
#include "hf/abi.h"
+#include "hf/spci.h"
#include "hf/types.h"
/* Keep macro alignment */
@@ -29,7 +30,6 @@
#define HF_VCPU_RUN 0xff03
#define HF_VCPU_YIELD 0xff04
#define HF_VM_CONFIGURE 0xff05
-#define HF_MAILBOX_SEND 0xff06
#define HF_MAILBOX_RECEIVE 0xff07
#define HF_MAILBOX_CLEAR 0xff08
#define HF_MAILBOX_WRITABLE_GET 0xff09
@@ -115,11 +115,14 @@
* If the recipient's receive buffer is busy, it can optionally register the
* caller to be notified when the recipient's receive buffer becomes available.
*
- * Returns -1 on failure and 0 on success.
+ * Returns SPCI_SUCCESS if the message is sent, an error code otherwise:
+ * - INVALID_PARAMETER: one or more of the parameters do not conform.
+ * - BUSY: the message could not be delivered either because the mailbox
+ * was full or the target VM does not yet exist.
*/
-static inline int64_t hf_mailbox_send(uint32_t vm_id, size_t size, bool notify)
+static inline int64_t spci_msg_send(uint32_t attributes)
{
- return hf_call(HF_MAILBOX_SEND, vm_id, size, notify);
+ return hf_call(SPCI_MSG_SEND_32, attributes, 0, 0);
}
/**
diff --git a/src/BUILD.gn b/src/BUILD.gn
index 89c476c..d0cbc90 100644
--- a/src/BUILD.gn
+++ b/src/BUILD.gn
@@ -108,6 +108,7 @@
"fdt_test.cc",
"mm_test.cc",
"mpool_test.cc",
+ "spci_test.cc",
]
sources += [ "layout_fake.c" ]
cflags_cc = [
diff --git a/src/api.c b/src/api.c
index 938d978..1fdb54a 100644
--- a/src/api.c
+++ b/src/api.c
@@ -28,6 +28,7 @@
#include "hf/vm.h"
#include "vmapi/hf/call.h"
+#include "vmapi/hf/spci.h"
/*
* To eliminate the risk of deadlocks, we define a partial order for the
@@ -729,43 +730,63 @@
* If the recipient's receive buffer is busy, it can optionally register the
* caller to be notified when the recipient's receive buffer becomes available.
*/
-int64_t api_mailbox_send(uint32_t vm_id, size_t size, bool notify,
- struct vcpu *current, struct vcpu **next)
+int32_t api_spci_msg_send(uint32_t attributes, struct vcpu *current,
+ struct vcpu **next)
{
struct vm *from = current->vm;
struct vm *to;
- const void *from_buf;
- int64_t ret;
struct hf_vcpu_run_return primary_ret = {
.code = HF_VCPU_RUN_MESSAGE,
};
+ struct spci_message from_msg_replica;
+ struct spci_message *to_msg;
+ const struct spci_message *from_msg;
- /* Limit the size of transfer. */
- if (size > HF_MAILBOX_SIZE) {
- return -1;
- }
+ uint32_t size;
- /* Disallow reflexive requests as this suggests an error in the VM. */
- if (vm_id == from->id) {
- return -1;
- }
+ int64_t ret;
+ bool notify = (attributes & SPCI_MSG_SEND_NOTIFY_MASK) ==
+ SPCI_MSG_SEND_NOTIFY;
- /* Ensure the target VM exists. */
- to = vm_get(vm_id);
- if (to == NULL) {
- return -1;
+ /*
+ * Check that the sender has configured its send buffer. Copy the
+ * message header. If the tx mailbox at from_msg is configured (i.e.
+ * from_msg != NULL) then it can be safely accessed after releasing the
+ * lock since the tx mailbox address can only be configured once.
+ */
+ sl_lock(&from->lock);
+ from_msg = from->mailbox.send;
+ sl_unlock(&from->lock);
+
+ if (from_msg == NULL) {
+ return SPCI_INVALID_PARAMETERS;
}
/*
- * Check that the sender has configured its send buffer. It is safe to
- * use from_buf after releasing the lock because the buffer cannot be
- * modified once it's configured.
+ * Note that the payload is not copied when the message header is.
*/
- sl_lock(&from->lock);
- from_buf = from->mailbox.send;
- sl_unlock(&from->lock);
- if (from_buf == NULL) {
- return -1;
+ from_msg_replica = *from_msg;
+
+ /* Ensure source VM id corresponds to the current VM. */
+ if (from_msg_replica.source_vm_id != from->id) {
+ return SPCI_INVALID_PARAMETERS;
+ }
+
+ size = from_msg_replica.length;
+ /* Limit the size of transfer. */
+ if (size > HF_MAILBOX_SIZE - sizeof(struct spci_message)) {
+ return SPCI_INVALID_PARAMETERS;
+ }
+
+ /* Disallow reflexive requests as this suggests an error in the VM. */
+ if (from_msg_replica.target_vm_id == from->id) {
+ return SPCI_INVALID_PARAMETERS;
+ }
+
+ /* Ensure the target VM exists. */
+ to = vm_get(from_msg_replica.target_vm_id);
+ if (to == NULL) {
+ return SPCI_INVALID_PARAMETERS;
}
sl_lock(&to->lock);
@@ -778,7 +799,8 @@
*/
if (notify) {
struct wait_entry *entry =
- ¤t->vm->wait_entries[vm_id];
+ ¤t->vm->wait_entries
+ [from_msg_replica.target_vm_id];
/* Append waiter only if it's not there yet. */
if (list_empty(&entry->wait_links)) {
@@ -787,16 +809,18 @@
}
}
- ret = -1;
+ ret = SPCI_BUSY;
goto out;
}
/* Copy data. */
- memcpy(to->mailbox.recv, from_buf, size);
+ to_msg = to->mailbox.recv;
+ *to_msg = from_msg_replica;
+ memcpy(to_msg->payload, from->mailbox.send->payload, size);
to->mailbox.recv_bytes = size;
to->mailbox.recv_from_id = from->id;
primary_ret.message.vm_id = to->id;
- ret = 0;
+ ret = SPCI_SUCCESS;
/* Messages for the primary VM are delivered directly. */
if (to->id == HF_PRIMARY_VM_ID) {
diff --git a/src/arch/aarch64/handler.c b/src/arch/aarch64/handler.c
index eb8f8dc..e29ddf0 100644
--- a/src/arch/aarch64/handler.c
+++ b/src/arch/aarch64/handler.c
@@ -21,6 +21,7 @@
#include "hf/api.h"
#include "hf/cpu.h"
#include "hf/dlog.h"
+#include "hf/spci.h"
#include "hf/vm.h"
#include "vmapi/hf/call.h"
@@ -404,7 +405,7 @@
}
}
- switch ((uint32_t)arg0 & ~SMCCC_CONVENTION_MASK) {
+ switch ((uint32_t)arg0) {
case HF_VM_GET_ID:
ret.user_ret = api_vm_get_id(current());
break;
@@ -432,9 +433,8 @@
current(), &ret.new);
break;
- case HF_MAILBOX_SEND:
- ret.user_ret =
- api_mailbox_send(arg1, arg2, arg3, current(), &ret.new);
+ case SPCI_MSG_SEND_32:
+ ret.user_ret = api_spci_msg_send(arg1, current(), &ret.new);
break;
case HF_MAILBOX_RECEIVE:
diff --git a/src/spci_test.cc b/src/spci_test.cc
new file mode 100644
index 0000000..a3191cc
--- /dev/null
+++ b/src/spci_test.cc
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2019 The Hafnium Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+extern "C" {
+#include "vmapi/hf/spci.h"
+}
+
+#include <gmock/gmock.h>
+
+namespace
+{
+using ::testing::Eq;
+
+/**
+ * Ensure that spci_message_init is correctly setting the expected fields in the
+ * SPCI common message header.
+ */
+TEST(spci, spci_message_init)
+{
+ spci_message header;
+ spci_message compare_header = {
+ .flags = SPCI_MESSAGE_IMPDEF_MASK,
+ .length = 1,
+ .target_vm_id = 2,
+ .source_vm_id = 3,
+ };
+
+ memset(&header, 0xff, sizeof(header));
+ spci_message_init(&header, 1, 2, 3);
+
+ EXPECT_THAT(memcmp(&header, &compare_header, sizeof(header)), 0);
+}
+} /* namespace */
diff --git a/test/hftest/hftest_service.c b/test/hftest/hftest_service.c
index 9850a07..2a1b2a0 100644
--- a/test/hftest/hftest_service.c
+++ b/test/hftest/hftest_service.c
@@ -20,6 +20,7 @@
#include "hf/arch/std.h"
#include "hf/memiter.h"
+#include "hf/spci.h"
#include "vmapi/hf/call.h"
@@ -80,17 +81,18 @@
{
struct memiter args;
hftest_test_fn service;
- struct hf_mailbox_receive_return res;
struct hftest_context *ctx;
+ struct spci_message *recv_msg = (struct spci_message *)recv;
+
/* Prepare the context. */
/* Set up the mailbox. */
hf_vm_configure(send_addr, recv_addr);
/* Receive the name of the service to run. */
- res = hf_mailbox_receive(true);
- memiter_init(&args, recv, res.size);
+ hf_mailbox_receive(true);
+ memiter_init(&args, recv_msg->payload, recv_msg->length);
service = find_service(&args);
hf_mailbox_clear();
@@ -108,8 +110,8 @@
ctx = hftest_get_context();
memset(ctx, 0, sizeof(*ctx));
ctx->abort = abort;
- ctx->send = send;
- ctx->recv = recv;
+ ctx->send = (struct spci_message *)send;
+ ctx->recv = (struct spci_message *)recv;
/* Pause so the next time cycles are given the service will be run. */
hf_vcpu_yield();
diff --git a/test/hftest/inc/hftest_impl.h b/test/hftest/inc/hftest_impl.h
index 5778b20..328f664 100644
--- a/test/hftest/inc/hftest_impl.h
+++ b/test/hftest/inc/hftest_impl.h
@@ -20,6 +20,8 @@
#include "hf/arch/std.h"
+#include "hf/spci.h"
+
#define HFTEST_MAX_TESTS 50
/*
@@ -133,8 +135,8 @@
noreturn void (*abort)(void);
/* These are used in services. */
- void *send;
- void *recv;
+ struct spci_message *send;
+ struct spci_message *recv;
};
struct hftest_context *hftest_get_context(void);
@@ -271,6 +273,7 @@
#define HFTEST_SERVICE_SELECT(vm_id, service, send_buffer) \
do { \
struct hf_vcpu_run_return run_res; \
+ uint32_t msg_length = strlen(service); \
\
/* \
* Let the service configure its mailbox and wait for a \
@@ -281,8 +284,11 @@
ASSERT_EQ(run_res.sleep.ns, HF_SLEEP_INDEFINITE); \
\
/* Send the selected service to run and let it be handled. */ \
- memcpy(send_buffer, service, strlen(service)); \
- ASSERT_EQ(hf_mailbox_send(vm_id, strlen(service), false), 0); \
+ memcpy(send_buffer->payload, service, msg_length); \
+ spci_message_init(send_buffer, msg_length, vm_id, \
+ hf_vm_get_id()); \
+ \
+ ASSERT_EQ(spci_msg_send(0), 0); \
run_res = hf_vcpu_run(vm_id, 0); \
ASSERT_EQ(run_res.code, HF_VCPU_RUN_YIELD); \
} while (0)
diff --git a/test/vmapi/gicv3/busy_secondary.c b/test/vmapi/gicv3/busy_secondary.c
index 9ea691f..f694031 100644
--- a/test/vmapi/gicv3/busy_secondary.c
+++ b/test/vmapi/gicv3/busy_secondary.c
@@ -19,6 +19,7 @@
#include "hf/arch/vm/interrupts_gicv3.h"
#include "hf/dlog.h"
+#include "hf/spci.h"
#include "vmapi/hf/call.h"
@@ -38,7 +39,7 @@
{
system_setup();
EXPECT_EQ(hf_vm_configure(send_page_addr, recv_page_addr), 0);
- SERVICE_SELECT(SERVICE_VM0, "busy", send_page);
+ SERVICE_SELECT(SERVICE_VM0, "busy", send_buffer);
}
TEST(busy_secondary, virtual_timer)
@@ -78,8 +79,10 @@
/* Let secondary start looping. */
dlog("Telling secondary to loop.\n");
- memcpy(send_page, message, sizeof(message));
- EXPECT_EQ(hf_mailbox_send(SERVICE_VM0, sizeof(message), false), 0);
+ memcpy(send_buffer->payload, message, sizeof(message));
+ spci_message_init(send_buffer, 0, SERVICE_VM0,
+ recv_buffer->target_vm_id);
+ EXPECT_EQ(spci_msg_send(0), 0);
run_res = hf_vcpu_run(SERVICE_VM0, 0);
EXPECT_EQ(run_res.code, HF_VCPU_RUN_PREEMPTED);
@@ -133,8 +136,10 @@
/* Let secondary start looping. */
dlog("Telling secondary to loop.\n");
- memcpy(send_page, message, sizeof(message));
- EXPECT_EQ(hf_mailbox_send(SERVICE_VM0, sizeof(message), false), 0);
+ memcpy(send_buffer->payload, message, sizeof(message));
+ spci_message_init(send_buffer, 0, SERVICE_VM0,
+ recv_buffer->target_vm_id);
+ EXPECT_EQ(spci_msg_send(0), 0);
run_res = hf_vcpu_run(SERVICE_VM0, 0);
EXPECT_EQ(run_res.code, HF_VCPU_RUN_PREEMPTED);
diff --git a/test/vmapi/gicv3/gicv3.c b/test/vmapi/gicv3/gicv3.c
index bc1e24d..dc0a081 100644
--- a/test/vmapi/gicv3/gicv3.c
+++ b/test/vmapi/gicv3/gicv3.c
@@ -34,6 +34,9 @@
hf_ipaddr_t send_page_addr = (hf_ipaddr_t)send_page;
hf_ipaddr_t recv_page_addr = (hf_ipaddr_t)recv_page;
+struct spci_message *send_buffer = (struct spci_message *)send_page;
+struct spci_message *recv_buffer = (struct spci_message *)recv_page;
+
volatile uint32_t last_interrupt_id = 0;
static void irq(void)
diff --git a/test/vmapi/gicv3/inc/gicv3.h b/test/vmapi/gicv3/inc/gicv3.h
index e4748cb..264dc0c 100644
--- a/test/vmapi/gicv3/inc/gicv3.h
+++ b/test/vmapi/gicv3/inc/gicv3.h
@@ -33,6 +33,9 @@
extern hf_ipaddr_t send_page_addr;
extern hf_ipaddr_t recv_page_addr;
+extern struct spci_message *send_buffer;
+extern struct spci_message *recv_buffer;
+
extern volatile uint32_t last_interrupt_id;
void system_setup();
diff --git a/test/vmapi/gicv3/services/busy.c b/test/vmapi/gicv3/services/busy.c
index f311124..4a18d35 100644
--- a/test/vmapi/gicv3/services/busy.c
+++ b/test/vmapi/gicv3/services/busy.c
@@ -31,7 +31,7 @@
TEST_SERVICE(busy)
{
dlog("Secondary waiting for message...\n");
- (void)mailbox_receive_retry();
+ mailbox_receive_retry();
hf_mailbox_clear();
dlog("Secondary received message, looping forever.\n");
for (;;) {
diff --git a/test/vmapi/gicv3/services/timer.c b/test/vmapi/gicv3/services/timer.c
index 029c729..79a2b8a 100644
--- a/test/vmapi/gicv3/services/timer.c
+++ b/test/vmapi/gicv3/services/timer.c
@@ -46,8 +46,10 @@
}
buffer[8] = '0' + interrupt_id / 10;
buffer[9] = '0' + interrupt_id % 10;
- memcpy(SERVICE_SEND_BUFFER(), buffer, size);
- hf_mailbox_send(HF_PRIMARY_VM_ID, size, false);
+ memcpy(SERVICE_SEND_BUFFER()->payload, buffer, size);
+ spci_message_init(SERVICE_SEND_BUFFER(), size, HF_PRIMARY_VM_ID,
+ SERVICE_RECV_BUFFER()->target_vm_id);
+ spci_msg_send(0);
dlog("secondary IRQ %d ended\n", interrupt_id);
event_send_local();
}
@@ -60,19 +62,22 @@
for (;;) {
const char timer_wfi_message[] = "**** xxxxxxx";
- char *message = SERVICE_RECV_BUFFER();
+ struct spci_message *message_header = SERVICE_RECV_BUFFER();
+ uint8_t *message;
bool wfi, wfe, receive;
bool disable_interrupts;
uint32_t ticks;
- struct hf_mailbox_receive_return received_message =
- mailbox_receive_retry();
+ mailbox_receive_retry();
- if (received_message.vm_id != HF_PRIMARY_VM_ID ||
- received_message.size != sizeof(timer_wfi_message)) {
+ if (message_header->source_vm_id != HF_PRIMARY_VM_ID ||
+ message_header->length != sizeof(timer_wfi_message)) {
FAIL("Got unexpected message from VM %d, size %d.\n",
- received_message.vm_id, received_message.size);
+ message_header->source_vm_id,
+ message_header->length);
}
+ message = message_header->payload;
+
/*
* Start a timer to send the message back: enable it and
* set it for the requested number of ticks.
diff --git a/test/vmapi/gicv3/timer_secondary.c b/test/vmapi/gicv3/timer_secondary.c
index dcb2e87..e554551 100644
--- a/test/vmapi/gicv3/timer_secondary.c
+++ b/test/vmapi/gicv3/timer_secondary.c
@@ -19,6 +19,7 @@
#include "hf/abi.h"
#include "hf/call.h"
+#include "hf/spci.h"
#include "gicv3.h"
#include "hftest.h"
@@ -28,7 +29,7 @@
system_setup();
EXPECT_EQ(hf_vm_configure(send_page_addr, recv_page_addr), 0);
- SERVICE_SELECT(SERVICE_VM0, "timer", send_page);
+ SERVICE_SELECT(SERVICE_VM0, "timer", send_buffer);
interrupt_enable(VIRTUAL_TIMER_IRQ, true);
interrupt_set_edge_triggered(VIRTUAL_TIMER_IRQ, true);
@@ -48,8 +49,10 @@
EXPECT_EQ(run_res.sleep.ns, HF_SLEEP_INDEFINITE);
/* Send the message for the secondary to set a timer. */
- memcpy(send_page, message, sizeof(message));
- EXPECT_EQ(hf_mailbox_send(SERVICE_VM0, sizeof(message), false), 0);
+ memcpy(send_buffer->payload, message, sizeof(message));
+ spci_message_init(send_buffer, sizeof(message), SERVICE_VM0,
+ HF_PRIMARY_VM_ID);
+ EXPECT_EQ(spci_msg_send(0), 0);
/*
* Let the secondary handle the message and set the timer. It will loop
@@ -71,9 +74,9 @@
run_res = hf_vcpu_run(SERVICE_VM0, 0);
EXPECT_EQ(run_res.code, HF_VCPU_RUN_MESSAGE);
EXPECT_EQ(run_res.message.size, sizeof(expected_response));
- EXPECT_EQ(
- memcmp(recv_page, expected_response, sizeof(expected_response)),
- 0);
+ EXPECT_EQ(memcmp(recv_buffer->payload, expected_response,
+ sizeof(expected_response)),
+ 0);
EXPECT_EQ(hf_mailbox_clear(), 0);
}
@@ -104,8 +107,10 @@
EXPECT_EQ(run_res.sleep.ns, HF_SLEEP_INDEFINITE);
/* Send the message for the secondary to set a timer. */
- memcpy(send_page, message, message_length);
- EXPECT_EQ(hf_mailbox_send(SERVICE_VM0, message_length, false), 0);
+ memcpy(send_buffer->payload, message, message_length);
+ spci_message_init(send_buffer, message_length, SERVICE_VM0,
+ HF_PRIMARY_VM_ID);
+ EXPECT_EQ(spci_msg_send(0), 0);
/*
* Let the secondary handle the message and set the timer. Then there's
@@ -152,9 +157,9 @@
/* Once we wake it up it should get the timer interrupt and respond. */
EXPECT_EQ(run_res.code, HF_VCPU_RUN_MESSAGE);
EXPECT_EQ(run_res.message.size, sizeof(expected_response));
- EXPECT_EQ(
- memcmp(recv_page, expected_response, sizeof(expected_response)),
- 0);
+ EXPECT_EQ(memcmp(recv_buffer->payload, expected_response,
+ sizeof(expected_response)),
+ 0);
EXPECT_EQ(hf_mailbox_clear(), 0);
}
@@ -240,8 +245,10 @@
EXPECT_EQ(run_res.sleep.ns, HF_SLEEP_INDEFINITE);
/* Send the message for the secondary to set a timer. */
- memcpy(send_page, message, message_length);
- EXPECT_EQ(hf_mailbox_send(SERVICE_VM0, message_length, false), 0);
+ memcpy(send_buffer->payload, message, message_length);
+ spci_message_init(send_buffer, message_length, SERVICE_VM0,
+ HF_PRIMARY_VM_ID);
+ EXPECT_EQ(spci_msg_send(0), 0);
/*
* Let the secondary handle the message and set the timer.
diff --git a/test/vmapi/primary_with_secondaries/BUILD.gn b/test/vmapi/primary_with_secondaries/BUILD.gn
index b82fa30..34f8857 100644
--- a/test/vmapi/primary_with_secondaries/BUILD.gn
+++ b/test/vmapi/primary_with_secondaries/BUILD.gn
@@ -30,6 +30,7 @@
"memory_sharing.c",
"no_services.c",
"run_race.c",
+ "spci.c",
]
sources += [ "util.c" ]
diff --git a/test/vmapi/primary_with_secondaries/inc/util.h b/test/vmapi/primary_with_secondaries/inc/util.h
index b127fae..eca641f 100644
--- a/test/vmapi/primary_with_secondaries/inc/util.h
+++ b/test/vmapi/primary_with_secondaries/inc/util.h
@@ -16,9 +16,11 @@
#pragma once
+#include "vmapi/hf/spci.h"
+
struct mailbox_buffers {
- void *send;
- void *recv;
+ struct spci_message *send;
+ struct spci_message *recv;
};
struct mailbox_buffers set_up_mailbox(void);
diff --git a/test/vmapi/primary_with_secondaries/interrupts.c b/test/vmapi/primary_with_secondaries/interrupts.c
index 655ca54..9429acc 100644
--- a/test/vmapi/primary_with_secondaries/interrupts.c
+++ b/test/vmapi/primary_with_secondaries/interrupts.c
@@ -42,12 +42,15 @@
EXPECT_EQ(run_res.sleep.ns, HF_SLEEP_INDEFINITE);
/* Set the message, echo it and wait for a response. */
- memcpy(mb.send, message, sizeof(message));
- EXPECT_EQ(hf_mailbox_send(SERVICE_VM0, sizeof(message), false), 0);
+ memcpy(mb.send->payload, message, sizeof(message));
+ spci_message_init(mb.send, sizeof(message), SERVICE_VM0,
+ HF_PRIMARY_VM_ID);
+ EXPECT_EQ(spci_msg_send(0), 0);
run_res = hf_vcpu_run(SERVICE_VM0, 0);
EXPECT_EQ(run_res.code, HF_VCPU_RUN_MESSAGE);
EXPECT_EQ(run_res.message.size, sizeof(expected_response));
- EXPECT_EQ(memcmp(mb.recv, expected_response, sizeof(expected_response)),
+ EXPECT_EQ(memcmp(mb.recv->payload, expected_response,
+ sizeof(expected_response)),
0);
EXPECT_EQ(hf_mailbox_clear(), 0);
}
@@ -74,7 +77,8 @@
run_res = hf_vcpu_run(SERVICE_VM0, 0);
EXPECT_EQ(run_res.code, HF_VCPU_RUN_MESSAGE);
EXPECT_EQ(run_res.message.size, sizeof(expected_response));
- EXPECT_EQ(memcmp(mb.recv, expected_response, sizeof(expected_response)),
+ EXPECT_EQ(memcmp(mb.recv->payload, expected_response,
+ sizeof(expected_response)),
0);
EXPECT_EQ(hf_mailbox_clear(), 0);
@@ -83,7 +87,8 @@
run_res = hf_vcpu_run(SERVICE_VM0, 0);
EXPECT_EQ(run_res.code, HF_VCPU_RUN_MESSAGE);
EXPECT_EQ(run_res.message.size, sizeof(expected_response));
- EXPECT_EQ(memcmp(mb.recv, expected_response, sizeof(expected_response)),
+ EXPECT_EQ(memcmp(mb.recv->payload, expected_response,
+ sizeof(expected_response)),
0);
EXPECT_EQ(hf_mailbox_clear(), 0);
}
@@ -110,7 +115,8 @@
run_res = hf_vcpu_run(SERVICE_VM0, 0);
EXPECT_EQ(run_res.code, HF_VCPU_RUN_MESSAGE);
EXPECT_EQ(run_res.message.size, sizeof(expected_response));
- EXPECT_EQ(memcmp(mb.recv, expected_response, sizeof(expected_response)),
+ EXPECT_EQ(memcmp(mb.recv->payload, expected_response,
+ sizeof(expected_response)),
0);
EXPECT_EQ(hf_mailbox_clear(), 0);
@@ -119,7 +125,7 @@
run_res = hf_vcpu_run(SERVICE_VM0, 0);
EXPECT_EQ(run_res.code, HF_VCPU_RUN_MESSAGE);
EXPECT_EQ(run_res.message.size, sizeof(expected_response_2));
- EXPECT_EQ(memcmp(mb.recv, expected_response_2,
+ EXPECT_EQ(memcmp(mb.recv->payload, expected_response_2,
sizeof(expected_response_2)),
0);
EXPECT_EQ(hf_mailbox_clear(), 0);
@@ -149,7 +155,8 @@
run_res = hf_vcpu_run(SERVICE_VM0, 0);
EXPECT_EQ(run_res.code, HF_VCPU_RUN_MESSAGE);
EXPECT_EQ(run_res.message.size, sizeof(expected_response));
- EXPECT_EQ(memcmp(mb.recv, expected_response, sizeof(expected_response)),
+ EXPECT_EQ(memcmp(mb.recv->payload, expected_response,
+ sizeof(expected_response)),
0);
EXPECT_EQ(hf_mailbox_clear(), 0);
@@ -158,12 +165,14 @@
EXPECT_EQ(run_res.sleep.ns, HF_SLEEP_INDEFINITE);
/* Now send a message to the secondary. */
- memcpy(mb.send, message, sizeof(message));
- EXPECT_EQ(hf_mailbox_send(SERVICE_VM0, sizeof(message), false), 0);
+ memcpy(mb.send->payload, message, sizeof(message));
+ spci_message_init(mb.send, sizeof(message), SERVICE_VM0,
+ HF_PRIMARY_VM_ID);
+ EXPECT_EQ(spci_msg_send(0), 0);
run_res = hf_vcpu_run(SERVICE_VM0, 0);
EXPECT_EQ(run_res.code, HF_VCPU_RUN_MESSAGE);
EXPECT_EQ(run_res.message.size, sizeof(expected_response_2));
- EXPECT_EQ(memcmp(mb.recv, expected_response_2,
+ EXPECT_EQ(memcmp(mb.recv->payload, expected_response_2,
sizeof(expected_response_2)),
0);
EXPECT_EQ(hf_mailbox_clear(), 0);
@@ -193,12 +202,15 @@
* Now send a message to the secondary to enable the interrupt ID, and
* expect the response from the interrupt we sent before.
*/
- memcpy(mb.send, message, sizeof(message));
- EXPECT_EQ(hf_mailbox_send(SERVICE_VM0, sizeof(message), false), 0);
+ memcpy(mb.send->payload, message, sizeof(message));
+ spci_message_init(mb.send, sizeof(message), SERVICE_VM0,
+ HF_PRIMARY_VM_ID);
+ EXPECT_EQ(spci_msg_send(0), 0);
run_res = hf_vcpu_run(SERVICE_VM0, 0);
EXPECT_EQ(run_res.code, HF_VCPU_RUN_MESSAGE);
EXPECT_EQ(run_res.message.size, sizeof(expected_response));
- EXPECT_EQ(memcmp(mb.recv, expected_response, sizeof(expected_response)),
+ EXPECT_EQ(memcmp(mb.recv->payload, expected_response,
+ sizeof(expected_response)),
0);
EXPECT_EQ(hf_mailbox_clear(), 0);
}
@@ -225,7 +237,8 @@
run_res = hf_vcpu_run(SERVICE_VM0, 0);
EXPECT_EQ(run_res.code, HF_VCPU_RUN_MESSAGE);
EXPECT_EQ(run_res.message.size, sizeof(expected_response));
- EXPECT_EQ(memcmp(mb.recv, expected_response, sizeof(expected_response)),
+ EXPECT_EQ(memcmp(mb.recv->payload, expected_response,
+ sizeof(expected_response)),
0);
EXPECT_EQ(hf_mailbox_clear(), 0);
}
@@ -252,7 +265,8 @@
run_res = hf_vcpu_run(SERVICE_VM0, 0);
EXPECT_EQ(run_res.code, HF_VCPU_RUN_MESSAGE);
EXPECT_EQ(run_res.message.size, sizeof(expected_response));
- EXPECT_EQ(memcmp(mb.recv, expected_response, sizeof(expected_response)),
+ EXPECT_EQ(memcmp(mb.recv->payload, expected_response,
+ sizeof(expected_response)),
0);
EXPECT_EQ(hf_mailbox_clear(), 0);
}
@@ -273,12 +287,14 @@
EXPECT_EQ(run_res.code, HF_VCPU_RUN_WAIT_FOR_MESSAGE);
EXPECT_EQ(run_res.sleep.ns, HF_SLEEP_INDEFINITE);
- memcpy(mb.send, message, sizeof(message));
- EXPECT_EQ(hf_mailbox_send(SERVICE_VM0, sizeof(message), false), 0);
+ memcpy(mb.send->payload, message, sizeof(message));
+ spci_message_init(mb.send, sizeof(message), SERVICE_VM0,
+ HF_PRIMARY_VM_ID);
+ EXPECT_EQ(spci_msg_send(0), SPCI_SUCCESS);
hf_interrupt_inject(SERVICE_VM0, 0, EXTERNAL_INTERRUPT_ID_A);
run_res = hf_vcpu_run(SERVICE_VM0, 0);
EXPECT_EQ(run_res.code, HF_VCPU_RUN_MESSAGE);
EXPECT_EQ(run_res.message.size, sizeof(message));
- EXPECT_EQ(memcmp(mb.recv, message, sizeof(message)), 0);
+ EXPECT_EQ(memcmp(mb.recv->payload, message, sizeof(message)), 0);
EXPECT_EQ(hf_mailbox_clear(), 0);
}
diff --git a/test/vmapi/primary_with_secondaries/mailbox.c b/test/vmapi/primary_with_secondaries/mailbox.c
index 1e1a4d3..8615957 100644
--- a/test/vmapi/primary_with_secondaries/mailbox.c
+++ b/test/vmapi/primary_with_secondaries/mailbox.c
@@ -18,6 +18,8 @@
#include "hf/arch/std.h"
+#include "hf/spci.h"
+
#include "vmapi/hf/call.h"
#include "hftest.h"
@@ -87,12 +89,14 @@
EXPECT_EQ(run_res.sleep.ns, HF_SLEEP_INDEFINITE);
/* Set the message, echo it and check it didn't change. */
- memcpy(mb.send, message, sizeof(message));
- EXPECT_EQ(hf_mailbox_send(SERVICE_VM0, sizeof(message), false), 0);
+ memcpy(mb.send->payload, message, sizeof(message));
+ spci_message_init(mb.send, sizeof(message), SERVICE_VM0,
+ HF_PRIMARY_VM_ID);
+ EXPECT_EQ(spci_msg_send(0), 0);
run_res = hf_vcpu_run(SERVICE_VM0, 0);
EXPECT_EQ(run_res.code, HF_VCPU_RUN_MESSAGE);
EXPECT_EQ(run_res.message.size, sizeof(message));
- EXPECT_EQ(memcmp(mb.recv, message, sizeof(message)), 0);
+ EXPECT_EQ(memcmp(mb.send->payload, message, sizeof(message)), 0);
EXPECT_EQ(hf_mailbox_clear(), 0);
}
@@ -116,13 +120,15 @@
/* Set the message, echo it and check it didn't change. */
next_permutation(message, sizeof(message) - 1);
- memcpy(mb.send, message, sizeof(message));
- EXPECT_EQ(hf_mailbox_send(SERVICE_VM0, sizeof(message), false),
- 0);
+ memcpy(mb.send->payload, message, sizeof(message));
+ spci_message_init(mb.send, sizeof(message), SERVICE_VM0,
+ HF_PRIMARY_VM_ID);
+ EXPECT_EQ(spci_msg_send(0), 0);
run_res = hf_vcpu_run(SERVICE_VM0, 0);
EXPECT_EQ(run_res.code, HF_VCPU_RUN_MESSAGE);
EXPECT_EQ(run_res.message.size, sizeof(message));
- EXPECT_EQ(memcmp(mb.recv, message, sizeof(message)), 0);
+ EXPECT_EQ(memcmp(mb.recv->payload, message, sizeof(message)),
+ 0);
EXPECT_EQ(hf_mailbox_clear(), 0);
}
}
@@ -152,15 +158,15 @@
* SERVICE_VM0, then to SERVICE_VM1 and finally back to here.
*/
{
- uint32_t *chain = mb.send;
+ uint32_t *chain = (uint32_t *)mb.send->payload;
*chain++ = htole32(SERVICE_VM1);
*chain++ = htole32(HF_PRIMARY_VM_ID);
memcpy(chain, message, sizeof(message));
- EXPECT_EQ(hf_mailbox_send(
- SERVICE_VM0,
+
+ spci_message_init(mb.send,
sizeof(message) + (2 * sizeof(uint32_t)),
- false),
- 0);
+ SERVICE_VM0, HF_PRIMARY_VM_ID);
+ EXPECT_EQ(spci_msg_send(0), 0);
}
/* Let SERVICE_VM0 forward the message. */
@@ -176,7 +182,7 @@
/* Ensure the message is in tact. */
EXPECT_EQ(run_res.message.vm_id, HF_PRIMARY_VM_ID);
EXPECT_EQ(run_res.message.size, sizeof(message));
- EXPECT_EQ(memcmp(mb.recv, message, sizeof(message)), 0);
+ EXPECT_EQ(memcmp(mb.recv->payload, message, sizeof(message)), 0);
EXPECT_EQ(hf_mailbox_clear(), 0);
}
@@ -188,15 +194,16 @@
{
struct hf_vcpu_run_return run_res;
- set_up_mailbox();
-
- EXPECT_EQ(hf_mailbox_send(SERVICE_VM0, 0, false), -1);
+ struct mailbox_buffers mb = set_up_mailbox();
+ spci_message_init(mb.send, 0, SERVICE_VM0, HF_PRIMARY_VM_ID);
+ EXPECT_EQ(spci_msg_send(0), SPCI_BUSY);
run_res = hf_vcpu_run(SERVICE_VM0, 0);
+ spci_message_init(mb.send, 0, SERVICE_VM0, HF_PRIMARY_VM_ID);
EXPECT_EQ(run_res.code, HF_VCPU_RUN_WAIT_FOR_MESSAGE);
EXPECT_EQ(run_res.sleep.ns, HF_SLEEP_INDEFINITE);
- EXPECT_EQ(hf_mailbox_send(SERVICE_VM0, 0, false), 0);
+ EXPECT_EQ(spci_msg_send(0), SPCI_SUCCESS);
}
/**
@@ -207,9 +214,10 @@
{
struct hf_vcpu_run_return run_res;
- set_up_mailbox();
+ struct mailbox_buffers mb = set_up_mailbox();
- EXPECT_EQ(hf_mailbox_send(SERVICE_VM0, 0, true), -1);
+ spci_message_init(mb.send, 0, SERVICE_VM0, HF_PRIMARY_VM_ID);
+ EXPECT_EQ(spci_msg_send(SPCI_MSG_SEND_NOTIFY), SPCI_BUSY);
/*
* Run first VM for it to configure itself. It should result in
@@ -223,7 +231,7 @@
EXPECT_EQ(hf_mailbox_waiter_get(SERVICE_VM0), -1);
/* Send should now succeed. */
- EXPECT_EQ(hf_mailbox_send(SERVICE_VM0, 0, false), 0);
+ EXPECT_EQ(spci_msg_send(0), SPCI_SUCCESS);
}
/**
@@ -244,12 +252,14 @@
EXPECT_EQ(run_res.sleep.ns, HF_SLEEP_INDEFINITE);
/* Send a message to echo service, and get response back. */
- memcpy(mb.send, message, sizeof(message));
- EXPECT_EQ(hf_mailbox_send(SERVICE_VM0, sizeof(message), false), 0);
+ memcpy(mb.send->payload, message, sizeof(message));
+ spci_message_init(mb.send, sizeof(message), SERVICE_VM0,
+ HF_PRIMARY_VM_ID);
+ EXPECT_EQ(spci_msg_send(0), 0);
run_res = hf_vcpu_run(SERVICE_VM0, 0);
EXPECT_EQ(run_res.code, HF_VCPU_RUN_MESSAGE);
EXPECT_EQ(run_res.message.size, sizeof(message));
- EXPECT_EQ(memcmp(mb.recv, message, sizeof(message)), 0);
+ EXPECT_EQ(memcmp(mb.recv->payload, message, sizeof(message)), 0);
/* Let secondary VM continue running so that it will wait again. */
run_res = hf_vcpu_run(SERVICE_VM0, 0);
@@ -258,8 +268,12 @@
/* Without clearing our mailbox, send message again. */
reverse(message, strlen(message));
- memcpy(mb.send, message, sizeof(message));
- EXPECT_EQ(hf_mailbox_send(SERVICE_VM0, sizeof(message), false), 0);
+ memcpy(mb.send->payload, message, sizeof(message));
+ spci_message_init(mb.send, sizeof(message), SERVICE_VM0,
+ HF_PRIMARY_VM_ID);
+
+ /* Message should be dropped since the mailbox was not cleared. */
+ EXPECT_EQ(spci_msg_send(0), 0);
run_res = hf_vcpu_run(SERVICE_VM0, 0);
EXPECT_EQ(run_res.code, HF_VCPU_RUN_WAIT_FOR_INTERRUPT);
EXPECT_EQ(run_res.sleep.ns, HF_SLEEP_INDEFINITE);
@@ -281,7 +295,7 @@
run_res = hf_vcpu_run(SERVICE_VM0, 0);
EXPECT_EQ(run_res.code, HF_VCPU_RUN_MESSAGE);
EXPECT_EQ(run_res.message.size, sizeof(message));
- EXPECT_EQ(memcmp(mb.recv, message, sizeof(message)), 0);
+ EXPECT_EQ(memcmp(mb.recv->payload, message, sizeof(message)), 0);
}
/**
@@ -302,15 +316,17 @@
EXPECT_EQ(run_res.sleep.ns, HF_SLEEP_INDEFINITE);
/* Send a message to echo service twice. The second should fail. */
- memcpy(mb.send, message, sizeof(message));
- EXPECT_EQ(hf_mailbox_send(SERVICE_VM0, sizeof(message), false), 0);
- EXPECT_EQ(hf_mailbox_send(SERVICE_VM0, sizeof(message), true), -1);
+ memcpy(mb.send->payload, message, sizeof(message));
+ spci_message_init(mb.send, sizeof(message), SERVICE_VM0,
+ HF_PRIMARY_VM_ID);
+ EXPECT_EQ(spci_msg_send(0), SPCI_SUCCESS);
+ EXPECT_EQ(spci_msg_send(SPCI_MSG_SEND_NOTIFY), SPCI_BUSY);
/* Receive a reply for the first message. */
run_res = hf_vcpu_run(SERVICE_VM0, 0);
EXPECT_EQ(run_res.code, HF_VCPU_RUN_MESSAGE);
EXPECT_EQ(run_res.message.size, sizeof(message));
- EXPECT_EQ(memcmp(mb.recv, message, sizeof(message)), 0);
+ EXPECT_EQ(memcmp(mb.recv->payload, message, sizeof(message)), 0);
/* Run VM again so that it clears its mailbox. */
run_res = hf_vcpu_run(SERVICE_VM0, 0);
@@ -321,5 +337,5 @@
EXPECT_EQ(hf_mailbox_waiter_get(SERVICE_VM0), -1);
/* Send should now succeed. */
- EXPECT_EQ(hf_mailbox_send(SERVICE_VM0, 0, false), 0);
+ EXPECT_EQ(spci_msg_send(0), SPCI_SUCCESS);
}
diff --git a/test/vmapi/primary_with_secondaries/memory_sharing.c b/test/vmapi/primary_with_secondaries/memory_sharing.c
index e44dd93..8d8bb47 100644
--- a/test/vmapi/primary_with_secondaries/memory_sharing.c
+++ b/test/vmapi/primary_with_secondaries/memory_sharing.c
@@ -104,8 +104,9 @@
* API is still to be agreed on so the address is passed
* explicitly to test the mechanism.
*/
- memcpy(mb.send, &ptr, sizeof(ptr));
- EXPECT_EQ(hf_mailbox_send(SERVICE_VM0, sizeof(ptr), false), 0);
+ memcpy(mb.send->payload, &ptr, sizeof(ptr));
+ spci_message_init(mb.send, sizeof(ptr), SERVICE_VM0, HF_PRIMARY_VM_ID);
+ EXPECT_EQ(spci_msg_send(0), SPCI_SUCCESS);
run_res = hf_vcpu_run(SERVICE_VM0, 0);
EXPECT_EQ(run_res.code, HF_VCPU_RUN_YIELD);
@@ -146,8 +147,9 @@
* API is still to be agreed on so the address is passed
* explicitly to test the mechanism.
*/
- memcpy(mb.send, &ptr, sizeof(ptr));
- EXPECT_EQ(hf_mailbox_send(SERVICE_VM0, sizeof(ptr), false), 0);
+ memcpy(mb.send->payload, &ptr, sizeof(ptr));
+ spci_message_init(mb.send, sizeof(ptr), SERVICE_VM0, HF_PRIMARY_VM_ID);
+ EXPECT_EQ(spci_msg_send(0), SPCI_SUCCESS);
/* Let the memory be returned. */
run_res = hf_vcpu_run(SERVICE_VM0, 0);
@@ -183,8 +185,9 @@
* API is still to be agreed on so the address is passed
* explicitly to test the mechanism.
*/
- memcpy(mb.send, &ptr, sizeof(ptr));
- EXPECT_EQ(hf_mailbox_send(SERVICE_VM0, sizeof(ptr), false), 0);
+ memcpy(mb.send->payload, &ptr, sizeof(ptr));
+ spci_message_init(mb.send, sizeof(ptr), SERVICE_VM0, HF_PRIMARY_VM_ID);
+ EXPECT_EQ(spci_msg_send(0), SPCI_SUCCESS);
/* Let the memory be returned. */
run_res = hf_vcpu_run(SERVICE_VM0, 0);
@@ -220,8 +223,9 @@
* API is still to be agreed on so the address is passed
* explicitly to test the mechanism.
*/
- memcpy(mb.send, &ptr, sizeof(ptr));
- EXPECT_EQ(hf_mailbox_send(SERVICE_VM0, sizeof(ptr), false), 0);
+ memcpy(mb.send->payload, &ptr, sizeof(ptr));
+ spci_message_init(mb.send, sizeof(ptr), SERVICE_VM0, HF_PRIMARY_VM_ID);
+ EXPECT_EQ(spci_msg_send(0), SPCI_SUCCESS);
/* Let the memory be returned. */
run_res = hf_vcpu_run(SERVICE_VM0, 0);
@@ -256,8 +260,9 @@
* API is still to be agreed on so the address is passed
* explicitly to test the mechanism.
*/
- memcpy(mb.send, &ptr, sizeof(ptr));
- EXPECT_EQ(hf_mailbox_send(SERVICE_VM0, sizeof(ptr), false), 0);
+ memcpy(mb.send->payload, &ptr, sizeof(ptr));
+ spci_message_init(mb.send, sizeof(ptr), SERVICE_VM0, HF_PRIMARY_VM_ID);
+ EXPECT_EQ(spci_msg_send(0), SPCI_SUCCESS);
/* Let the memory be returned. */
run_res = hf_vcpu_run(SERVICE_VM0, 0);
@@ -295,8 +300,9 @@
* API is still to be agreed on so the address is passed
* explicitly to test the mechanism.
*/
- memcpy(mb.send, &ptr, sizeof(ptr));
- EXPECT_EQ(hf_mailbox_send(SERVICE_VM0, sizeof(ptr), false), 0);
+ memcpy(mb.send->payload, &ptr, sizeof(ptr));
+ spci_message_init(mb.send, sizeof(ptr), SERVICE_VM0, HF_PRIMARY_VM_ID);
+ EXPECT_EQ(spci_msg_send(0), SPCI_SUCCESS);
/* Let the memory be returned. */
run_res = hf_vcpu_run(SERVICE_VM0, 0);
@@ -328,7 +334,7 @@
EXPECT_EQ(run_res.code, HF_VCPU_RUN_MESSAGE);
/* Check the memory was cleared. */
- memcpy(&ptr, mb.recv, sizeof(ptr));
+ memcpy(&ptr, mb.recv->payload, sizeof(ptr));
for (int i = 0; i < PAGE_SIZE; ++i) {
ASSERT_EQ(ptr[i], 0);
}
@@ -354,7 +360,7 @@
EXPECT_EQ(run_res.code, HF_VCPU_RUN_MESSAGE);
/* Check the memory was cleared. */
- memcpy(&ptr, mb.recv, sizeof(ptr));
+ memcpy(&ptr, mb.recv->payload, sizeof(ptr));
for (int i = 0; i < PAGE_SIZE; ++i) {
ASSERT_EQ(ptr[i], 0);
}
diff --git a/test/vmapi/primary_with_secondaries/run_race.c b/test/vmapi/primary_with_secondaries/run_race.c
index f77a7b1..2a25c65 100644
--- a/test/vmapi/primary_with_secondaries/run_race.c
+++ b/test/vmapi/primary_with_secondaries/run_race.c
@@ -57,7 +57,7 @@
/* Copies the contents of the received boolean to the return value. */
if (run_res.message.size == sizeof(ok)) {
- memcpy(&ok, mb->recv, sizeof(ok));
+ memcpy(&ok, mb->recv->payload, sizeof(ok));
}
hf_mailbox_clear();
diff --git a/test/vmapi/primary_with_secondaries/services/BUILD.gn b/test/vmapi/primary_with_secondaries/services/BUILD.gn
index b0ef794..6b15dc7 100644
--- a/test/vmapi/primary_with_secondaries/services/BUILD.gn
+++ b/test/vmapi/primary_with_secondaries/services/BUILD.gn
@@ -125,6 +125,19 @@
]
}
+# Service to receive messages in a secondary VM and ensure that the header fields are correctly set.
+source_set("spci_check") {
+ testonly = true
+ public_configs = [
+ "..:config",
+ "//test/hftest:hftest_config",
+ ]
+
+ sources = [
+ "spci_check.c",
+ ]
+}
+
# Group services together into VMs.
vm_kernel("service_vm0") {
@@ -139,6 +152,7 @@
":memory",
":receive_block",
":relay",
+ ":spci_check",
":wfi",
"//test/hftest:hftest_secondary_vm",
]
diff --git a/test/vmapi/primary_with_secondaries/services/check_state.c b/test/vmapi/primary_with_secondaries/services/check_state.c
index 735b8a5..e467f52 100644
--- a/test/vmapi/primary_with_secondaries/services/check_state.c
+++ b/test/vmapi/primary_with_secondaries/services/check_state.c
@@ -21,13 +21,13 @@
#include "hftest.h"
-void send_with_retry(uint32_t vm_id, size_t size)
+void send_with_retry()
{
int64_t res;
do {
- res = hf_mailbox_send(vm_id, size, false);
- } while (res == -1);
+ res = spci_msg_send(0);
+ } while (res != SPCI_SUCCESS);
}
/**
@@ -48,6 +48,9 @@
static volatile uintptr_t expected;
static volatile uintptr_t actual;
+ spci_message_init(SERVICE_SEND_BUFFER(), 0, HF_PRIMARY_VM_ID,
+ hf_vm_get_id());
+
for (i = 0; i < 100000; i++) {
/*
* We store the expected/actual values in volatile static
@@ -56,13 +59,15 @@
*/
expected = i;
per_cpu_ptr_set(expected);
- send_with_retry(HF_PRIMARY_VM_ID, 0);
+ send_with_retry();
actual = per_cpu_ptr_get();
ok &= expected == actual;
}
/* Send two replies, one for each physical CPU. */
- memcpy(SERVICE_SEND_BUFFER(), &ok, sizeof(ok));
- send_with_retry(HF_PRIMARY_VM_ID, sizeof(ok));
- send_with_retry(HF_PRIMARY_VM_ID, sizeof(ok));
+ memcpy(SERVICE_SEND_BUFFER()->payload, &ok, sizeof(ok));
+ spci_message_init(SERVICE_SEND_BUFFER(), sizeof(ok), HF_PRIMARY_VM_ID,
+ hf_vm_get_id());
+ send_with_retry();
+ send_with_retry();
}
diff --git a/test/vmapi/primary_with_secondaries/services/echo.c b/test/vmapi/primary_with_secondaries/services/echo.c
index ffb89df..c58ccfb 100644
--- a/test/vmapi/primary_with_secondaries/services/echo.c
+++ b/test/vmapi/primary_with_secondaries/services/echo.c
@@ -16,6 +16,8 @@
#include "hf/arch/std.h"
+#include "hf/spci.h"
+
#include "vmapi/hf/call.h"
#include "hftest.h"
@@ -24,9 +26,16 @@
{
/* Loop, echo messages back to the sender. */
for (;;) {
- struct hf_mailbox_receive_return res = hf_mailbox_receive(true);
- memcpy(SERVICE_SEND_BUFFER(), SERVICE_RECV_BUFFER(), res.size);
+ hf_mailbox_receive(true);
+ struct spci_message *send_buf = SERVICE_SEND_BUFFER();
+ struct spci_message *recv_buf = SERVICE_RECV_BUFFER();
+
+ memcpy(send_buf->payload, recv_buf->payload, recv_buf->length);
+ spci_message_init(SERVICE_SEND_BUFFER(), recv_buf->length,
+ recv_buf->source_vm_id,
+ recv_buf->target_vm_id);
+
hf_mailbox_clear();
- hf_mailbox_send(res.vm_id, res.size, false);
+ spci_msg_send(0);
}
}
diff --git a/test/vmapi/primary_with_secondaries/services/echo_with_notification.c b/test/vmapi/primary_with_secondaries/services/echo_with_notification.c
index 2e733ae..e6c66c0 100644
--- a/test/vmapi/primary_with_secondaries/services/echo_with_notification.c
+++ b/test/vmapi/primary_with_secondaries/services/echo_with_notification.c
@@ -18,6 +18,8 @@
#include "hf/arch/std.h"
#include "hf/arch/vm/interrupts_gicv3.h"
+#include "hf/spci.h"
+
#include "vmapi/hf/call.h"
#include "../msr.h"
@@ -51,11 +53,18 @@
/* Loop, echo messages back to the sender. */
for (;;) {
- struct hf_mailbox_receive_return res = hf_mailbox_receive(true);
+ hf_mailbox_receive(true);
- memcpy(SERVICE_SEND_BUFFER(), SERVICE_RECV_BUFFER(), res.size);
- while (hf_mailbox_send(res.vm_id, res.size, true) < 0) {
- wait_for_vm(res.vm_id);
+ struct spci_message *send_buf = SERVICE_SEND_BUFFER();
+ struct spci_message *recv_buf = SERVICE_RECV_BUFFER();
+
+ memcpy(send_buf->payload, recv_buf->payload, recv_buf->length);
+ spci_message_init(send_buf, recv_buf->length,
+ recv_buf->source_vm_id,
+ recv_buf->target_vm_id);
+
+ while (spci_msg_send(SPCI_MSG_SEND_NOTIFY) != SPCI_SUCCESS) {
+ wait_for_vm(recv_buf->source_vm_id);
}
hf_mailbox_clear();
diff --git a/test/vmapi/primary_with_secondaries/services/interruptible.c b/test/vmapi/primary_with_secondaries/services/interruptible.c
index 9b36e8c..c5c67a5 100644
--- a/test/vmapi/primary_with_secondaries/services/interruptible.c
+++ b/test/vmapi/primary_with_secondaries/services/interruptible.c
@@ -38,8 +38,10 @@
dlog("secondary IRQ %d from current\n", interrupt_id);
buffer[8] = '0' + interrupt_id / 10;
buffer[9] = '0' + interrupt_id % 10;
- memcpy(SERVICE_SEND_BUFFER(), buffer, size);
- hf_mailbox_send(HF_PRIMARY_VM_ID, size, false);
+ memcpy(SERVICE_SEND_BUFFER()->payload, buffer, size);
+ spci_message_init(SERVICE_SEND_BUFFER(), size, HF_PRIMARY_VM_ID,
+ hf_vm_get_id());
+ spci_msg_send(0);
dlog("secondary IRQ %d ended\n", interrupt_id);
}
@@ -62,6 +64,7 @@
TEST_SERVICE(interruptible)
{
uint32_t this_vm_id = hf_vm_get_id();
+ struct spci_message *recv_buf = SERVICE_RECV_BUFFER();
exception_setup(irq);
hf_interrupt_enable(SELF_INTERRUPT_ID, true);
@@ -72,23 +75,23 @@
for (;;) {
const char ping_message[] = "Ping";
const char enable_message[] = "Enable interrupt C";
- struct hf_mailbox_receive_return received_message =
- mailbox_receive_retry();
- if (received_message.vm_id == HF_PRIMARY_VM_ID &&
- received_message.size == sizeof(ping_message) &&
- memcmp(SERVICE_RECV_BUFFER(), ping_message,
+
+ mailbox_receive_retry();
+ if (recv_buf->source_vm_id == HF_PRIMARY_VM_ID &&
+ recv_buf->length == sizeof(ping_message) &&
+ memcmp(recv_buf->payload, ping_message,
sizeof(ping_message)) == 0) {
/* Interrupt ourselves */
hf_interrupt_inject(this_vm_id, 0, SELF_INTERRUPT_ID);
- } else if (received_message.vm_id == HF_PRIMARY_VM_ID &&
- received_message.size == sizeof(enable_message) &&
- memcmp(SERVICE_RECV_BUFFER(), enable_message,
+ } else if (recv_buf->source_vm_id == HF_PRIMARY_VM_ID &&
+ recv_buf->length == sizeof(enable_message) &&
+ memcmp(recv_buf->payload, enable_message,
sizeof(enable_message)) == 0) {
/* Enable interrupt ID C. */
hf_interrupt_enable(EXTERNAL_INTERRUPT_ID_C, true);
} else {
dlog("Got unexpected message from VM %d, size %d.\n",
- received_message.vm_id, received_message.size);
+ recv_buf->source_vm_id, recv_buf->length);
FAIL("Unexpected message");
}
hf_mailbox_clear();
diff --git a/test/vmapi/primary_with_secondaries/services/interruptible_echo.c b/test/vmapi/primary_with_secondaries/services/interruptible_echo.c
index e1eb643..dff3b6d 100644
--- a/test/vmapi/primary_with_secondaries/services/interruptible_echo.c
+++ b/test/vmapi/primary_with_secondaries/services/interruptible_echo.c
@@ -39,6 +39,7 @@
for (;;) {
struct hf_mailbox_receive_return res = hf_mailbox_receive(true);
+ struct spci_message *message = SERVICE_SEND_BUFFER();
/* Retry if interrupted but made visible with the yield. */
while (res.vm_id == HF_INVALID_VM_ID && res.size == 0) {
@@ -46,8 +47,12 @@
res = hf_mailbox_receive(true);
}
- memcpy(SERVICE_SEND_BUFFER(), SERVICE_RECV_BUFFER(), res.size);
+ memcpy(message->payload, SERVICE_RECV_BUFFER()->payload,
+ res.size);
+ spci_message_init(message, res.size, HF_PRIMARY_VM_ID,
+ SERVICE_VM0);
+
hf_mailbox_clear();
- hf_mailbox_send(res.vm_id, res.size, false);
+ spci_msg_send(0);
}
}
diff --git a/test/vmapi/primary_with_secondaries/services/memory.c b/test/vmapi/primary_with_secondaries/services/memory.c
index b85b003..a826184 100644
--- a/test/vmapi/primary_with_secondaries/services/memory.c
+++ b/test/vmapi/primary_with_secondaries/services/memory.c
@@ -28,12 +28,16 @@
{
/* Loop, writing message to the shared memory. */
for (;;) {
- struct hf_mailbox_receive_return res = hf_mailbox_receive(true);
+ hf_mailbox_receive(true);
uint8_t *ptr;
size_t i;
/* Check the memory was cleared. */
- memcpy(&ptr, SERVICE_RECV_BUFFER(), sizeof(ptr));
+ struct spci_message *recv_buf = SERVICE_RECV_BUFFER();
+ memcpy(&ptr, recv_buf->payload, sizeof(ptr));
+ spci_message_init(SERVICE_SEND_BUFFER(), sizeof(ptr),
+ recv_buf->source_vm_id, hf_vm_get_id());
+
for (int i = 0; i < PAGE_SIZE; ++i) {
ASSERT_EQ(ptr[i], 0);
}
@@ -48,7 +52,7 @@
/* Signal completion and reset. */
hf_mailbox_clear();
- hf_mailbox_send(res.vm_id, 0, false);
+ spci_msg_send(0);
}
}
@@ -56,21 +60,26 @@
{
/* Loop, giving memory back to the sender. */
for (;;) {
- struct hf_mailbox_receive_return res = hf_mailbox_receive(true);
+ hf_mailbox_receive(true);
uint8_t *ptr;
/* Check the memory was cleared. */
- memcpy(&ptr, SERVICE_RECV_BUFFER(), sizeof(ptr));
+ struct spci_message *recv_buf = SERVICE_RECV_BUFFER();
+ memcpy(&ptr, recv_buf->payload, sizeof(ptr));
+ spci_message_init(SERVICE_SEND_BUFFER(), sizeof(ptr),
+ recv_buf->source_vm_id, hf_vm_get_id());
+
for (int i = 0; i < PAGE_SIZE; ++i) {
ASSERT_EQ(ptr[i], 0);
}
/* Give the memory back and notify the sender. */
- ASSERT_EQ(hf_share_memory(res.vm_id, (hf_ipaddr_t)ptr,
- PAGE_SIZE, HF_MEMORY_GIVE),
+ ASSERT_EQ(hf_share_memory(recv_buf->source_vm_id,
+ (hf_ipaddr_t)ptr, PAGE_SIZE,
+ HF_MEMORY_GIVE),
0);
hf_mailbox_clear();
- hf_mailbox_send(res.vm_id, 0, false);
+ spci_msg_send(0);
/*
* Try and access the memory which will cause a fault unless the
@@ -94,8 +103,10 @@
* API is still to be agreed on so the address is passed
* explicitly to test the mechanism.
*/
- memcpy(SERVICE_SEND_BUFFER(), &ptr, sizeof(ptr));
- EXPECT_EQ(hf_mailbox_send(HF_PRIMARY_VM_ID, sizeof(ptr), false), 0);
+ memcpy(SERVICE_SEND_BUFFER()->payload, &ptr, sizeof(ptr));
+ spci_message_init(SERVICE_SEND_BUFFER(), sizeof(ptr), HF_PRIMARY_VM_ID,
+ hf_vm_get_id());
+ EXPECT_EQ(spci_msg_send(0), 0);
/* Try using the memory that isn't valid unless it's been returned. */
page[16] = 123;
@@ -115,8 +126,10 @@
* API is still to be agreed on so the address is passed
* explicitly to test the mechanism.
*/
- memcpy(SERVICE_SEND_BUFFER(), &ptr, sizeof(ptr));
- EXPECT_EQ(hf_mailbox_send(HF_PRIMARY_VM_ID, sizeof(ptr), false), 0);
+ memcpy(SERVICE_SEND_BUFFER()->payload, &ptr, sizeof(ptr));
+ spci_message_init(SERVICE_SEND_BUFFER(), sizeof(ptr), HF_PRIMARY_VM_ID,
+ hf_vm_get_id());
+ EXPECT_EQ(spci_msg_send(0), 0);
/* Try using the memory that isn't valid unless it's been returned. */
page[633] = 180;
diff --git a/test/vmapi/primary_with_secondaries/services/receive_block.c b/test/vmapi/primary_with_secondaries/services/receive_block.c
index bdfbed6..59a10a5 100644
--- a/test/vmapi/primary_with_secondaries/services/receive_block.c
+++ b/test/vmapi/primary_with_secondaries/services/receive_block.c
@@ -18,6 +18,7 @@
#include "hf/arch/vm/interrupts_gicv3.h"
#include "hf/dlog.h"
+#include "hf/spci.h"
#include "vmapi/hf/call.h"
@@ -50,6 +51,9 @@
EXPECT_EQ(res.size, 0);
}
- memcpy(SERVICE_SEND_BUFFER(), message, sizeof(message));
- hf_mailbox_send(HF_PRIMARY_VM_ID, sizeof(message), false);
+ memcpy(SERVICE_SEND_BUFFER()->payload, message, sizeof(message));
+ spci_message_init(SERVICE_SEND_BUFFER(), sizeof(message),
+ HF_PRIMARY_VM_ID, hf_vm_get_id());
+
+ spci_msg_send(0);
}
diff --git a/test/vmapi/primary_with_secondaries/services/relay.c b/test/vmapi/primary_with_secondaries/services/relay.c
index f509835..627a461 100644
--- a/test/vmapi/primary_with_secondaries/services/relay.c
+++ b/test/vmapi/primary_with_secondaries/services/relay.c
@@ -36,18 +36,24 @@
uint32_t next_message_size;
/* Receive the message to relay. */
- struct hf_mailbox_receive_return res = hf_mailbox_receive(true);
- ASSERT_GE(res.size, sizeof(uint32_t));
+ hf_mailbox_receive(true);
/* Prepare to relay the message. */
- chain = SERVICE_RECV_BUFFER();
+ struct spci_message *recv_buf = SERVICE_RECV_BUFFER();
+ struct spci_message *send_buf = SERVICE_SEND_BUFFER();
+ ASSERT_GE(recv_buf->length, sizeof(uint32_t));
+
+ chain = (uint32_t *)recv_buf->payload;
next_vm_id = le32toh(*chain);
next_message = chain + 1;
- next_message_size = res.size - sizeof(uint32_t);
+ next_message_size = recv_buf->length - sizeof(uint32_t);
/* Send the message to the next stage. */
- memcpy(SERVICE_SEND_BUFFER(), next_message, next_message_size);
+ memcpy(send_buf->payload, next_message, next_message_size);
+ spci_message_init(send_buf, next_message_size, next_vm_id,
+ hf_vm_get_id());
+
hf_mailbox_clear();
- hf_mailbox_send(next_vm_id, next_message_size, false);
+ spci_msg_send(0);
}
}
diff --git a/test/vmapi/primary_with_secondaries/services/spci_check.c b/test/vmapi/primary_with_secondaries/services/spci_check.c
new file mode 100644
index 0000000..a81fc01
--- /dev/null
+++ b/test/vmapi/primary_with_secondaries/services/spci_check.c
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2019 The Hafnium Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "hf/arch/std.h"
+
+#include "hf/spci.h"
+
+#include "vmapi/hf/call.h"
+
+#include "hftest.h"
+#include "primary_with_secondary.h"
+
+TEST_SERVICE(spci_check)
+{
+ struct spci_message *recv_buf = SERVICE_RECV_BUFFER();
+ const char message[] = "spci_msg_send";
+ struct spci_message expected_message = {
+ .flags = SPCI_MESSAGE_IMPDEF_MASK,
+ .length = sizeof(message),
+ .target_vm_id = SERVICE_VM0,
+ .source_vm_id = HF_PRIMARY_VM_ID,
+
+ /*
+ * TODO: Padding fields may be set to MBZ in the next SPCI spec
+ * versions.
+ */
+ .reserved_1 = 0,
+ .reserved_2 = 0,
+ };
+
+ /* Wait for single message to be sent by the primary VM. */
+ hf_mailbox_receive(true);
+
+ /* Ensure message header has all fields correctly set. */
+ EXPECT_EQ(recv_buf->flags, expected_message.flags);
+ EXPECT_EQ(recv_buf->length, expected_message.length);
+ EXPECT_EQ(recv_buf->target_vm_id, expected_message.target_vm_id);
+ EXPECT_EQ(recv_buf->source_vm_id, expected_message.source_vm_id);
+
+ /* TODO: Padding fields may be set to MBZ in the next SPCI spec
+ * versions. */
+ EXPECT_EQ(recv_buf->reserved_1, expected_message.reserved_1);
+ EXPECT_EQ(recv_buf->reserved_2, expected_message.reserved_2);
+
+ /* Ensure message header has all fields correctly set. */
+ EXPECT_EQ(memcmp(recv_buf, &expected_message, sizeof(expected_message)),
+ 0);
+
+ /* Ensure that the payload was correctly transmitted. */
+ EXPECT_EQ(memcmp(recv_buf->payload, message, sizeof(message)), 0);
+
+ hf_vcpu_yield();
+}
diff --git a/test/vmapi/primary_with_secondaries/services/wfi.c b/test/vmapi/primary_with_secondaries/services/wfi.c
index 9c4f66e..6d3a05c 100644
--- a/test/vmapi/primary_with_secondaries/services/wfi.c
+++ b/test/vmapi/primary_with_secondaries/services/wfi.c
@@ -48,6 +48,9 @@
interrupt_wait();
}
- memcpy(SERVICE_SEND_BUFFER(), message, sizeof(message));
- hf_mailbox_send(HF_PRIMARY_VM_ID, sizeof(message), false);
+ memcpy(SERVICE_SEND_BUFFER()->payload, message, sizeof(message));
+ spci_message_init(SERVICE_SEND_BUFFER(), sizeof(message),
+ HF_PRIMARY_VM_ID, hf_vm_get_id());
+
+ spci_msg_send(0);
}
diff --git a/test/vmapi/primary_with_secondaries/spci.c b/test/vmapi/primary_with_secondaries/spci.c
new file mode 100644
index 0000000..e6d1049
--- /dev/null
+++ b/test/vmapi/primary_with_secondaries/spci.c
@@ -0,0 +1,65 @@
+/*
+ * Copyright 2019 The Hafnium Authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "hf/spci.h"
+
+#include <stdint.h>
+
+#include "hf/arch/std.h"
+
+#include "vmapi/hf/call.h"
+
+#include "hftest.h"
+#include "primary_with_secondary.h"
+#include "util.h"
+
+/**
+ * Send a message to a secondary VM which checks the validity of the received
+ * header.
+ */
+TEST(spci, msg_send)
+{
+ const char message[] = "spci_msg_send";
+ struct hf_vcpu_run_return run_res;
+ struct mailbox_buffers mb = set_up_mailbox();
+
+ SERVICE_SELECT(SERVICE_VM0, "spci_check", mb.send);
+
+ /* Set the payload, init the message header and send the message. */
+ memcpy(mb.send->payload, message, sizeof(message));
+ spci_message_init(mb.send, sizeof(message), SERVICE_VM0,
+ HF_PRIMARY_VM_ID);
+ EXPECT_EQ(spci_msg_send(0), 0);
+
+ run_res = hf_vcpu_run(SERVICE_VM0, 0);
+ EXPECT_EQ(run_res.code, HF_VCPU_RUN_YIELD);
+}
+
+/**
+ * Send a message to a secondary VM spoofing the source vm id.
+ */
+TEST(spci, msg_send_spoof)
+{
+ const char message[] = "spci_msg_send";
+ struct mailbox_buffers mb = set_up_mailbox();
+
+ SERVICE_SELECT(SERVICE_VM0, "spci_check", mb.send);
+
+ /* Set the payload, init the message header and send the message. */
+ memcpy(mb.send->payload, message, sizeof(message));
+ spci_message_init(mb.send, sizeof(message), SERVICE_VM0, SERVICE_VM1);
+ EXPECT_EQ(spci_msg_send(0), SPCI_INVALID_PARAMETERS);
+}
diff --git a/test/vmapi/primary_with_secondaries/util.c b/test/vmapi/primary_with_secondaries/util.c
index 86830c4..24b2b9e 100644
--- a/test/vmapi/primary_with_secondaries/util.c
+++ b/test/vmapi/primary_with_secondaries/util.c
@@ -17,6 +17,7 @@
#include "util.h"
#include "hf/mm.h"
+#include "hf/spci.h"
#include "vmapi/hf/call.h"
@@ -34,7 +35,7 @@
{
ASSERT_EQ(hf_vm_configure(send_page_addr, recv_page_addr), 0);
return (struct mailbox_buffers){
- .send = send_page,
- .recv = recv_page,
+ .send = ((struct spci_message *)send_page),
+ .recv = ((struct spci_message *)recv_page),
};
}