Export policy for selecting message recipient.
Previously this was a first come first served policy but the scheduler
may be in the position to make a better choice. This also conforms to
our intent of exporting policy outside of the hypervisor.
Change-Id: I8cee6ce9b976e5ed990616c896cd53ecd0f083c8
diff --git a/test/hftest/inc/hftest_impl.h b/test/hftest/inc/hftest_impl.h
index 093ecf0..5778b20 100644
--- a/test/hftest/inc/hftest_impl.h
+++ b/test/hftest/inc/hftest_impl.h
@@ -277,7 +277,8 @@
* message. \
*/ \
run_res = hf_vcpu_run(vm_id, 0); \
- ASSERT_EQ(run_res.code, HF_VCPU_RUN_WAIT_FOR_INTERRUPT); \
+ ASSERT_EQ(run_res.code, HF_VCPU_RUN_WAIT_FOR_MESSAGE); \
+ 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)); \
diff --git a/test/vmapi/gicv3/busy_secondary.c b/test/vmapi/gicv3/busy_secondary.c
index 3d6d176..9ea691f 100644
--- a/test/vmapi/gicv3/busy_secondary.c
+++ b/test/vmapi/gicv3/busy_secondary.c
@@ -36,15 +36,8 @@
SET_UP(busy_secondary)
{
- struct hf_vcpu_run_return run_res;
-
system_setup();
-
- /* Configure mailbox pages. */
EXPECT_EQ(hf_vm_configure(send_page_addr, recv_page_addr), 0);
- run_res = hf_vcpu_run(SERVICE_VM0, 0);
- EXPECT_EQ(run_res.code, HF_VCPU_RUN_WAIT_FOR_INTERRUPT);
-
SERVICE_SELECT(SERVICE_VM0, "busy", send_page);
}
@@ -69,7 +62,8 @@
/* Let the secondary get started and wait for our message. */
run_res = hf_vcpu_run(SERVICE_VM0, 0);
- EXPECT_EQ(run_res.code, HF_VCPU_RUN_WAIT_FOR_INTERRUPT);
+ EXPECT_EQ(run_res.code, HF_VCPU_RUN_WAIT_FOR_MESSAGE);
+ EXPECT_EQ(run_res.sleep.ns, HF_SLEEP_INDEFINITE);
/* Check that no interrupts are active or pending to start with. */
EXPECT_EQ(GICD_ISPENDR(0), 0);
@@ -123,7 +117,8 @@
/* Let the secondary get started and wait for our message. */
run_res = hf_vcpu_run(SERVICE_VM0, 0);
- EXPECT_EQ(run_res.code, HF_VCPU_RUN_WAIT_FOR_INTERRUPT);
+ EXPECT_EQ(run_res.code, HF_VCPU_RUN_WAIT_FOR_MESSAGE);
+ EXPECT_EQ(run_res.sleep.ns, HF_SLEEP_INDEFINITE);
/* Check that no interrupts are active or pending to start with. */
EXPECT_EQ(GICD_ISPENDR(0), 0);
diff --git a/test/vmapi/gicv3/services/timer.c b/test/vmapi/gicv3/services/timer.c
index 16ccccb..029c729 100644
--- a/test/vmapi/gicv3/services/timer.c
+++ b/test/vmapi/gicv3/services/timer.c
@@ -59,72 +59,74 @@
arch_irq_enable();
for (;;) {
- const char timer_wfi_message[] = "WFI xxxxxxx";
- const char timer_wfe_message[] = "WFE xxxxxxx";
- const char timer_receive_message[] = "RECV xxxxxxx";
+ const char timer_wfi_message[] = "**** xxxxxxx";
+ char *message = SERVICE_RECV_BUFFER();
+ bool wfi, wfe, receive;
+ bool disable_interrupts;
+ uint32_t ticks;
struct hf_mailbox_receive_return received_message =
mailbox_receive_retry();
- if (received_message.vm_id == HF_PRIMARY_VM_ID &&
- received_message.size == sizeof(timer_wfi_message)) {
- /*
- * Start a timer to send the message back: enable it and
- * set it for the requested number of ticks.
- */
- char *message = SERVICE_RECV_BUFFER();
- bool wfi = memcmp(message, timer_wfi_message, 5) == 0;
- bool wfe = memcmp(message, timer_wfe_message, 5) == 0;
- bool receive =
- memcmp(message, timer_receive_message, 5) == 0;
- int32_t ticks = (message[5] - '0') * 1000000 +
- (message[6] - '0') * 100000 +
- (message[7] - '0') * 10000 +
- (message[8] - '0') * 1000 +
- (message[9] - '0') * 100 +
- (message[10] - '0') * 10 +
- (message[11] - '0');
- dlog("Starting timer for %d ticks.\n", ticks);
- if (wfi || receive) {
- arch_irq_disable();
- }
- timer_set(ticks);
- timer_start();
- dlog("Waiting for timer...\n");
- if (wfi) {
- /* WFI until the timer fires. */
- interrupt_wait();
- arch_irq_enable();
- } else if (wfe) {
- /* WFE until the timer fires. */
- while (!timer_fired) {
- event_wait();
- }
- } else if (receive) {
- /*
- * Block on hf_mailbox_receive until timer
- * fires.
- */
- struct hf_mailbox_receive_return received =
- hf_mailbox_receive(true);
- /*
- * Expect to be interrupted, not to actually
- * receive a message.
- */
- EXPECT_EQ(received.vm_id, HF_INVALID_VM_ID);
- EXPECT_EQ(received.size, 0);
- arch_irq_enable();
- } else {
- /* Busy wait until the timer fires. */
- while (!timer_fired) {
- }
- }
- EXPECT_TRUE(timer_fired);
- timer_fired = false;
- dlog("Done waiting.\n");
- } else {
- dlog("Got unexpected message from VM %d, size %d.\n",
+
+ if (received_message.vm_id != HF_PRIMARY_VM_ID ||
+ received_message.size != sizeof(timer_wfi_message)) {
+ FAIL("Got unexpected message from VM %d, size %d.\n",
received_message.vm_id, received_message.size);
- FAIL("Unexpected message");
}
+
+ /*
+ * Start a timer to send the message back: enable it and
+ * set it for the requested number of ticks.
+ */
+ wfi = memcmp(message, "WFI ", 4) == 0;
+ wfe = memcmp(message, "WFE ", 4) == 0;
+ receive = memcmp(message, "RECV", 4) == 0;
+ disable_interrupts = wfi || receive;
+ ticks = (message[5] - '0') * 1000000 +
+ (message[6] - '0') * 100000 +
+ (message[7] - '0') * 10000 + (message[8] - '0') * 1000 +
+ (message[9] - '0') * 100 + (message[10] - '0') * 10 +
+ (message[11] - '0');
+
hf_mailbox_clear();
+
+ dlog("Starting timer for %d ticks.\n", ticks);
+
+ if (disable_interrupts) {
+ arch_irq_disable();
+ }
+
+ timer_set(ticks);
+ timer_start();
+ dlog("Waiting for timer...\n");
+
+ /* Wait for the timer interrupt. */
+ if (wfi) {
+ interrupt_wait();
+ } else if (wfe) {
+ while (!timer_fired) {
+ event_wait();
+ }
+ } else if (receive) {
+ struct hf_mailbox_receive_return received =
+ hf_mailbox_receive(true);
+ /*
+ * Expect to be interrupted, not to actually
+ * receive a message.
+ */
+ EXPECT_EQ(received.vm_id, HF_INVALID_VM_ID);
+ EXPECT_EQ(received.size, 0);
+ } else {
+ /* Busy wait until the timer fires. */
+ while (!timer_fired) {
+ }
+ }
+
+ if (disable_interrupts) {
+ arch_irq_enable();
+ }
+
+ EXPECT_TRUE(timer_fired);
+ timer_fired = false;
+ dlog("Done waiting.\n");
}
}
diff --git a/test/vmapi/gicv3/timer_secondary.c b/test/vmapi/gicv3/timer_secondary.c
index 9baa24e..dcb2e87 100644
--- a/test/vmapi/gicv3/timer_secondary.c
+++ b/test/vmapi/gicv3/timer_secondary.c
@@ -27,13 +27,7 @@
{
system_setup();
- struct hf_vcpu_run_return run_res;
-
- /* Configure mailbox pages. */
EXPECT_EQ(hf_vm_configure(send_page_addr, recv_page_addr), 0);
- run_res = hf_vcpu_run(SERVICE_VM0, 0);
- EXPECT_EQ(run_res.code, HF_VCPU_RUN_WAIT_FOR_INTERRUPT);
-
SERVICE_SELECT(SERVICE_VM0, "timer", send_page);
interrupt_enable(VIRTUAL_TIMER_IRQ, true);
@@ -42,7 +36,7 @@
arch_irq_enable();
}
-void timer_busywait_secondary()
+static void timer_busywait_secondary()
{
const char message[] = "loop 0099999";
const char expected_response[] = "Got IRQ 03.";
@@ -50,7 +44,8 @@
/* Let the secondary get started and wait for our message. */
run_res = hf_vcpu_run(SERVICE_VM0, 0);
- EXPECT_EQ(run_res.code, HF_VCPU_RUN_WAIT_FOR_INTERRUPT);
+ EXPECT_EQ(run_res.code, HF_VCPU_RUN_WAIT_FOR_MESSAGE);
+ 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));
@@ -96,7 +91,8 @@
timer_busywait_secondary();
}
-void timer_wfi_secondary(const char message[], bool wfe)
+static void timer_secondary(const char message[],
+ enum hf_vcpu_run_code expected_code)
{
const char expected_response[] = "Got IRQ 03.";
size_t message_length = strlen(message) + 1;
@@ -104,7 +100,8 @@
/* Let the secondary get started and wait for our message. */
run_res = hf_vcpu_run(SERVICE_VM0, 0);
- EXPECT_EQ(run_res.code, HF_VCPU_RUN_WAIT_FOR_INTERRUPT);
+ EXPECT_EQ(run_res.code, HF_VCPU_RUN_WAIT_FOR_MESSAGE);
+ 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);
@@ -112,53 +109,44 @@
/*
* Let the secondary handle the message and set the timer. Then there's
- * a race for whether it manages to WFI before the hardware timer fires,
- * so we need to handle both cases.
+ * a race for whether it manages to block and switch to the primary
+ * before the hardware timer fires, so we need to handle both cases.
*/
last_interrupt_id = 0;
run_res = hf_vcpu_run(SERVICE_VM0, 0);
- if (run_res.code == HF_VCPU_RUN_SLEEP && !wfe) {
+ if (run_res.code == expected_code) {
/*
- * This case happens if the secondary manages to call WFI before
- * the timer fires. This is likely when the timer is set for a
- * long time.
+ * This case happens if the secondary manages to block and
+ * switch to the primary before the timer fires.
*/
dlog("secondary sleeping after receiving timer message\n");
/* Loop until the timer fires. */
- while (run_res.code == HF_VCPU_RUN_SLEEP) {
- dlog("Primary looping until timer fires; %d ns "
- "remaining\n",
- run_res.sleep.ns);
- run_res = hf_vcpu_run(SERVICE_VM0, 0);
- }
- dlog("Primary done looping\n");
- } else if (run_res.code == HF_VCPU_RUN_YIELD && wfe) {
- /*
- * This case happens if the secondary manages to call WFE before
- * the timer fires. This is likely when the timer is set for a
- * long time.
- */
- dlog("secondary yielding after receiving timer message\n");
- /* Loop until the timer fires. */
- while (run_res.code == HF_VCPU_RUN_YIELD) {
+ while (run_res.code == expected_code) {
dlog("Primary looping until timer fires\n");
+ if (expected_code == HF_VCPU_RUN_WAIT_FOR_INTERRUPT ||
+ expected_code == HF_VCPU_RUN_WAIT_FOR_MESSAGE) {
+ EXPECT_NE(run_res.sleep.ns,
+ HF_SLEEP_INDEFINITE);
+ dlog("%d ns remaining\n", run_res.sleep.ns);
+ }
run_res = hf_vcpu_run(SERVICE_VM0, 0);
}
dlog("Primary done looping\n");
} else if (run_res.code == HF_VCPU_RUN_PREEMPTED) {
/*
* This case happens if the (hardware) timer fires before the
- * secondary calls WFI. Then we get the interrupt to the
- * primary, ignore it, and see a HF_VCPU_RUN_PREEMPTED code from
- * the hf_vcpu_run call, so we should call it again for the
- * timer interrupt to be injected automatically by Hafnium.
+ * secondary blocks and switches to the primary. Then we get the
+ * interrupt to the primary, ignore it, and see a
+ * HF_VCPU_RUN_PREEMPTED code from the hf_vcpu_run call, so we
+ * should call it again for the timer interrupt to be injected
+ * automatically by Hafnium.
*/
EXPECT_EQ(last_interrupt_id, VIRTUAL_TIMER_IRQ);
- dlog("Primary yielded, running again\n");
+ dlog("Preempted by timer interrupt, running again\n");
run_res = hf_vcpu_run(SERVICE_VM0, 0);
} else {
/* No other return codes should occur here, so fail. */
- FAIL("Unexpected run result code.");
+ FAIL("Unexpected run result code (%d).", run_res.code);
}
/* Once we wake it up it should get the timer interrupt and respond. */
@@ -174,7 +162,8 @@
* Send a message to the interruptible VM, which will start a timer to interrupt
* itself to send a response back. This test is run with both long and short
* timer lengths, to try to cover both cases of the race for whether the timer
- * fires before or after the WFI in the secondary VM.
+ * fires before or after the secondary VM blocks and switches back to the
+ * primary.
*/
TEST(timer_secondary, wfi_short)
{
@@ -182,8 +171,8 @@
* Run the test twice in a row, to check that the state doesn't get
* messed up.
*/
- timer_wfi_secondary("WFI 0000001", false);
- timer_wfi_secondary("WFI 0000001", false);
+ timer_secondary("WFI 0000001", HF_VCPU_RUN_WAIT_FOR_INTERRUPT);
+ timer_secondary("WFI 0000001", HF_VCPU_RUN_WAIT_FOR_INTERRUPT);
}
TEST(timer_secondary, wfi_long)
@@ -192,8 +181,8 @@
* Run the test twice in a row, to check that the state doesn't get
* messed up.
*/
- timer_wfi_secondary("WFI 0099999", false);
- timer_wfi_secondary("WFI 0099999", false);
+ timer_secondary("WFI 0099999", HF_VCPU_RUN_WAIT_FOR_INTERRUPT);
+ timer_secondary("WFI 0099999", HF_VCPU_RUN_WAIT_FOR_INTERRUPT);
}
TEST(timer_secondary, wfe_short)
@@ -202,8 +191,8 @@
* Run the test twice in a row, to check that the state doesn't get
* messed up.
*/
- timer_wfi_secondary("WFE 0000001", true);
- timer_wfi_secondary("WFE 0000001", true);
+ timer_secondary("WFE 0000001", HF_VCPU_RUN_YIELD);
+ timer_secondary("WFE 0000001", HF_VCPU_RUN_YIELD);
}
TEST(timer_secondary, wfe_long)
@@ -212,8 +201,8 @@
* Run the test twice in a row, to check that the state doesn't get
* messed up.
*/
- timer_wfi_secondary("WFE 0099999", true);
- timer_wfi_secondary("WFE 0099999", true);
+ timer_secondary("WFE 0099999", HF_VCPU_RUN_YIELD);
+ timer_secondary("WFE 0099999", HF_VCPU_RUN_YIELD);
}
TEST(timer_secondary, receive_short)
@@ -222,8 +211,8 @@
* Run the test twice in a row, to check that the state doesn't get
* messed up.
*/
- timer_wfi_secondary("RECV 0000001", false);
- timer_wfi_secondary("RECV 0000001", false);
+ timer_secondary("RECV 0000001", HF_VCPU_RUN_WAIT_FOR_MESSAGE);
+ timer_secondary("RECV 0000001", HF_VCPU_RUN_WAIT_FOR_MESSAGE);
}
TEST(timer_secondary, receive_long)
@@ -232,8 +221,8 @@
* Run the test twice in a row, to check that the state doesn't get
* messed up.
*/
- timer_wfi_secondary("RECV 0099999", false);
- timer_wfi_secondary("RECV 0099999", false);
+ timer_secondary("RECV 0099999", HF_VCPU_RUN_WAIT_FOR_MESSAGE);
+ timer_secondary("RECV 0099999", HF_VCPU_RUN_WAIT_FOR_MESSAGE);
}
/**
@@ -247,7 +236,8 @@
/* Let the secondary get started and wait for our message. */
run_res = hf_vcpu_run(SERVICE_VM0, 0);
- EXPECT_EQ(run_res.code, HF_VCPU_RUN_WAIT_FOR_INTERRUPT);
+ EXPECT_EQ(run_res.code, HF_VCPU_RUN_WAIT_FOR_MESSAGE);
+ 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);
@@ -259,7 +249,7 @@
last_interrupt_id = 0;
for (int i = 0; i < 20; ++i) {
run_res = hf_vcpu_run(SERVICE_VM0, 0);
- EXPECT_EQ(run_res.code, HF_VCPU_RUN_SLEEP);
+ EXPECT_EQ(run_res.code, HF_VCPU_RUN_WAIT_FOR_INTERRUPT);
dlog("Primary looping until timer fires; %d ns "
"remaining\n",
run_res.sleep.ns);
diff --git a/test/vmapi/primary_only/primary_only.c b/test/vmapi/primary_only/primary_only.c
index b5e45a4..df19d32 100644
--- a/test/vmapi/primary_only/primary_only.c
+++ b/test/vmapi/primary_only/primary_only.c
@@ -74,6 +74,7 @@
{
struct hf_vcpu_run_return res = hf_vcpu_run(HF_PRIMARY_VM_ID, 0);
EXPECT_EQ(res.code, HF_VCPU_RUN_WAIT_FOR_INTERRUPT);
+ EXPECT_EQ(res.sleep.ns, HF_SLEEP_INDEFINITE);
}
/**
@@ -84,6 +85,7 @@
{
struct hf_vcpu_run_return res = hf_vcpu_run(1, 0);
EXPECT_EQ(res.code, HF_VCPU_RUN_WAIT_FOR_INTERRUPT);
+ EXPECT_EQ(res.sleep.ns, HF_SLEEP_INDEFINITE);
}
/**
diff --git a/test/vmapi/primary_with_secondaries/interrupts.c b/test/vmapi/primary_with_secondaries/interrupts.c
index 09f8719..7791c64 100644
--- a/test/vmapi/primary_with_secondaries/interrupts.c
+++ b/test/vmapi/primary_with_secondaries/interrupts.c
@@ -37,7 +37,8 @@
SERVICE_SELECT(SERVICE_VM0, "interruptible", mb.send);
run_res = hf_vcpu_run(SERVICE_VM0, 0);
- EXPECT_EQ(run_res.code, HF_VCPU_RUN_WAIT_FOR_INTERRUPT);
+ EXPECT_EQ(run_res.code, HF_VCPU_RUN_WAIT_FOR_MESSAGE);
+ 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));
@@ -64,7 +65,8 @@
SERVICE_SELECT(SERVICE_VM0, "interruptible", mb.send);
run_res = hf_vcpu_run(SERVICE_VM0, 0);
- EXPECT_EQ(run_res.code, HF_VCPU_RUN_WAIT_FOR_INTERRUPT);
+ EXPECT_EQ(run_res.code, HF_VCPU_RUN_WAIT_FOR_MESSAGE);
+ EXPECT_EQ(run_res.sleep.ns, HF_SLEEP_INDEFINITE);
/* Inject the interrupt and wait for a message. */
hf_interrupt_inject(SERVICE_VM0, 0, EXTERNAL_INTERRUPT_ID_A);
@@ -99,7 +101,8 @@
SERVICE_SELECT(SERVICE_VM0, "interruptible", mb.send);
run_res = hf_vcpu_run(SERVICE_VM0, 0);
- EXPECT_EQ(run_res.code, HF_VCPU_RUN_WAIT_FOR_INTERRUPT);
+ EXPECT_EQ(run_res.code, HF_VCPU_RUN_WAIT_FOR_MESSAGE);
+ EXPECT_EQ(run_res.sleep.ns, HF_SLEEP_INDEFINITE);
/* Inject the interrupt and wait for a message. */
hf_interrupt_inject(SERVICE_VM0, 0, EXTERNAL_INTERRUPT_ID_A);
@@ -137,7 +140,8 @@
SERVICE_SELECT(SERVICE_VM0, "interruptible", mb.send);
run_res = hf_vcpu_run(SERVICE_VM0, 0);
- EXPECT_EQ(run_res.code, HF_VCPU_RUN_WAIT_FOR_INTERRUPT);
+ EXPECT_EQ(run_res.code, HF_VCPU_RUN_WAIT_FOR_MESSAGE);
+ EXPECT_EQ(run_res.sleep.ns, HF_SLEEP_INDEFINITE);
/* Inject the interrupt and wait for a message. */
hf_interrupt_inject(SERVICE_VM0, 0, EXTERNAL_INTERRUPT_ID_A);
@@ -149,7 +153,8 @@
EXPECT_EQ(hf_mailbox_clear(), 0);
run_res = hf_vcpu_run(SERVICE_VM0, 0);
- EXPECT_EQ(run_res.code, HF_VCPU_RUN_WAIT_FOR_INTERRUPT);
+ EXPECT_EQ(run_res.code, HF_VCPU_RUN_WAIT_FOR_MESSAGE);
+ EXPECT_EQ(run_res.sleep.ns, HF_SLEEP_INDEFINITE);
/* Now send a message to the secondary. */
memcpy(mb.send, message, sizeof(message));
@@ -180,7 +185,8 @@
/* Inject the interrupt and expect not to get a message. */
hf_interrupt_inject(SERVICE_VM0, 0, EXTERNAL_INTERRUPT_ID_C);
run_res = hf_vcpu_run(SERVICE_VM0, 0);
- EXPECT_EQ(run_res.code, HF_VCPU_RUN_WAIT_FOR_INTERRUPT);
+ EXPECT_EQ(run_res.code, HF_VCPU_RUN_WAIT_FOR_MESSAGE);
+ EXPECT_EQ(run_res.sleep.ns, HF_SLEEP_INDEFINITE);
/*
* Now send a message to the secondary to enable the interrupt ID, and
@@ -249,3 +255,29 @@
0);
EXPECT_EQ(hf_mailbox_clear(), 0);
}
+
+/*
+ * Deliver an interrupt and a message to the same vCPU and check that both are
+ * delivered the next time the vCPU is run.
+ */
+TEST(interrupts, deliver_interrupt_and_message)
+{
+ const char message[] = "I\'ll see you again.";
+ struct hf_vcpu_run_return run_res;
+ struct mailbox_buffers mb = set_up_mailbox();
+
+ SERVICE_SELECT(SERVICE_VM0, "interruptible_echo", mb.send);
+
+ run_res = hf_vcpu_run(SERVICE_VM0, 0);
+ 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);
+ 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(hf_mailbox_clear(), 0);
+}
diff --git a/test/vmapi/primary_with_secondaries/mailbox.c b/test/vmapi/primary_with_secondaries/mailbox.c
index afb09eb..c3ee826 100644
--- a/test/vmapi/primary_with_secondaries/mailbox.c
+++ b/test/vmapi/primary_with_secondaries/mailbox.c
@@ -82,7 +82,8 @@
SERVICE_SELECT(SERVICE_VM0, "echo", mb.send);
run_res = hf_vcpu_run(SERVICE_VM0, 0);
- EXPECT_EQ(run_res.code, HF_VCPU_RUN_WAIT_FOR_INTERRUPT);
+ EXPECT_EQ(run_res.code, HF_VCPU_RUN_WAIT_FOR_MESSAGE);
+ 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));
@@ -109,7 +110,8 @@
for (i = 0; i < 100; i++) {
/* Run secondary until it reaches the wait for messages. */
run_res = hf_vcpu_run(SERVICE_VM0, 0);
- EXPECT_EQ(run_res.code, HF_VCPU_RUN_WAIT_FOR_INTERRUPT);
+ EXPECT_EQ(run_res.code, HF_VCPU_RUN_WAIT_FOR_MESSAGE);
+ EXPECT_EQ(run_res.sleep.ns, HF_SLEEP_INDEFINITE);
/* Set the message, echo it and check it didn't change. */
next_permutation(message, sizeof(message) - 1);
@@ -138,9 +140,11 @@
SERVICE_SELECT(SERVICE_VM1, "relay", mb.send);
run_res = hf_vcpu_run(SERVICE_VM0, 0);
- EXPECT_EQ(run_res.code, HF_VCPU_RUN_WAIT_FOR_INTERRUPT);
+ EXPECT_EQ(run_res.code, HF_VCPU_RUN_WAIT_FOR_MESSAGE);
+ EXPECT_EQ(run_res.sleep.ns, HF_SLEEP_INDEFINITE);
run_res = hf_vcpu_run(SERVICE_VM1, 0);
- EXPECT_EQ(run_res.code, HF_VCPU_RUN_WAIT_FOR_INTERRUPT);
+ EXPECT_EQ(run_res.code, HF_VCPU_RUN_WAIT_FOR_MESSAGE);
+ EXPECT_EQ(run_res.sleep.ns, HF_SLEEP_INDEFINITE);
/*
* Build the message chain so the message is sent from here to
@@ -160,15 +164,16 @@
/* Let SERVICE_VM0 forward the message. */
run_res = hf_vcpu_run(SERVICE_VM0, 0);
- EXPECT_EQ(run_res.code, HF_VCPU_RUN_WAKE_UP);
- EXPECT_EQ(run_res.wake_up.vm_id, SERVICE_VM1);
- EXPECT_EQ(run_res.wake_up.vcpu, 0);
+ EXPECT_EQ(run_res.code, HF_VCPU_RUN_MESSAGE);
+ EXPECT_EQ(run_res.message.vm_id, SERVICE_VM1);
+ EXPECT_EQ(run_res.message.size, 0);
/* Let SERVICE_VM1 forward the message. */
run_res = hf_vcpu_run(SERVICE_VM1, 0);
EXPECT_EQ(run_res.code, HF_VCPU_RUN_MESSAGE);
/* 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(hf_mailbox_clear(), 0);
@@ -187,7 +192,8 @@
EXPECT_EQ(hf_mailbox_send(SERVICE_VM0, 0, false), -1);
run_res = hf_vcpu_run(SERVICE_VM0, 0);
- EXPECT_EQ(run_res.code, HF_VCPU_RUN_WAIT_FOR_INTERRUPT);
+ 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);
}
@@ -215,8 +221,8 @@
EXPECT_EQ(hf_mailbox_waiter_get(SERVICE_VM0), HF_PRIMARY_VM_ID);
EXPECT_EQ(hf_mailbox_waiter_get(SERVICE_VM0), -1);
- /* Send should succeed now, though no vCPU is blocked waiting for it. */
- EXPECT_EQ(hf_mailbox_send(SERVICE_VM0, 0, false), HF_INVALID_VCPU);
+ /* Send should now succeed. */
+ EXPECT_EQ(hf_mailbox_send(SERVICE_VM0, 0, false), 0);
}
/**
@@ -233,7 +239,8 @@
SERVICE_SELECT(SERVICE_VM0, "echo_with_notification", mb.send);
run_res = hf_vcpu_run(SERVICE_VM0, 0);
- EXPECT_EQ(run_res.code, HF_VCPU_RUN_WAIT_FOR_INTERRUPT);
+ EXPECT_EQ(run_res.code, HF_VCPU_RUN_WAIT_FOR_MESSAGE);
+ 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));
@@ -245,7 +252,8 @@
/* Let secondary VM continue running so that it will wait again. */
run_res = hf_vcpu_run(SERVICE_VM0, 0);
- EXPECT_EQ(run_res.code, HF_VCPU_RUN_WAIT_FOR_INTERRUPT);
+ EXPECT_EQ(run_res.code, HF_VCPU_RUN_WAIT_FOR_MESSAGE);
+ EXPECT_EQ(run_res.sleep.ns, HF_SLEEP_INDEFINITE);
/* Without clearing our mailbox, send message again. */
reverse(message, strlen(message));
@@ -253,6 +261,7 @@
EXPECT_EQ(hf_mailbox_send(SERVICE_VM0, sizeof(message), false), 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);
/* Clear the mailbox. We expect to be told there are pending waiters. */
EXPECT_EQ(hf_mailbox_clear(), 1);
@@ -288,7 +297,8 @@
SERVICE_SELECT(SERVICE_VM0, "echo_with_notification", mb.send);
run_res = hf_vcpu_run(SERVICE_VM0, 0);
- EXPECT_EQ(run_res.code, HF_VCPU_RUN_WAIT_FOR_INTERRUPT);
+ EXPECT_EQ(run_res.code, HF_VCPU_RUN_WAIT_FOR_MESSAGE);
+ 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));
@@ -309,6 +319,6 @@
EXPECT_EQ(hf_mailbox_waiter_get(SERVICE_VM0), HF_PRIMARY_VM_ID);
EXPECT_EQ(hf_mailbox_waiter_get(SERVICE_VM0), -1);
- /* Send should succeed now, though no vCPU is blocked waiting for it. */
- EXPECT_EQ(hf_mailbox_send(SERVICE_VM0, 0, false), HF_INVALID_VCPU);
+ /* Send should now succeed. */
+ EXPECT_EQ(hf_mailbox_send(SERVICE_VM0, 0, false), 0);
}
diff --git a/test/vmapi/primary_with_secondaries/memory_sharing.c b/test/vmapi/primary_with_secondaries/memory_sharing.c
index 39106ee..d1adea5 100644
--- a/test/vmapi/primary_with_secondaries/memory_sharing.c
+++ b/test/vmapi/primary_with_secondaries/memory_sharing.c
@@ -104,8 +104,7 @@
* explicitly to test the mechanism.
*/
memcpy(mb.send, &ptr, sizeof(ptr));
- EXPECT_EQ(hf_mailbox_send(SERVICE_VM0, sizeof(ptr), false),
- HF_INVALID_VCPU);
+ EXPECT_EQ(hf_mailbox_send(SERVICE_VM0, sizeof(ptr), false), 0);
run_res = hf_vcpu_run(SERVICE_VM0, 0);
EXPECT_EQ(run_res.code, HF_VCPU_RUN_YIELD);
@@ -147,8 +146,7 @@
* explicitly to test the mechanism.
*/
memcpy(mb.send, &ptr, sizeof(ptr));
- EXPECT_EQ(hf_mailbox_send(SERVICE_VM0, sizeof(ptr), false),
- HF_INVALID_VCPU);
+ EXPECT_EQ(hf_mailbox_send(SERVICE_VM0, sizeof(ptr), false), 0);
/* Let the memory be returned. */
run_res = hf_vcpu_run(SERVICE_VM0, 0);
@@ -185,8 +183,7 @@
* explicitly to test the mechanism.
*/
memcpy(mb.send, &ptr, sizeof(ptr));
- EXPECT_EQ(hf_mailbox_send(SERVICE_VM0, sizeof(ptr), false),
- HF_INVALID_VCPU);
+ EXPECT_EQ(hf_mailbox_send(SERVICE_VM0, sizeof(ptr), false), 0);
/* Let the memory be returned. */
run_res = hf_vcpu_run(SERVICE_VM0, 0);
@@ -223,8 +220,7 @@
* explicitly to test the mechanism.
*/
memcpy(mb.send, &ptr, sizeof(ptr));
- EXPECT_EQ(hf_mailbox_send(SERVICE_VM0, sizeof(ptr), false),
- HF_INVALID_VCPU);
+ EXPECT_EQ(hf_mailbox_send(SERVICE_VM0, sizeof(ptr), false), 0);
/* Let the memory be returned. */
run_res = hf_vcpu_run(SERVICE_VM0, 0);
@@ -260,8 +256,7 @@
* explicitly to test the mechanism.
*/
memcpy(mb.send, &ptr, sizeof(ptr));
- EXPECT_EQ(hf_mailbox_send(SERVICE_VM0, sizeof(ptr), false),
- HF_INVALID_VCPU);
+ EXPECT_EQ(hf_mailbox_send(SERVICE_VM0, sizeof(ptr), false), 0);
/* Let the memory be returned. */
run_res = hf_vcpu_run(SERVICE_VM0, 0);
@@ -274,7 +269,8 @@
/* Observe the service doesn't fault when accessing the memory. */
run_res = hf_vcpu_run(SERVICE_VM0, 0);
- EXPECT_EQ(run_res.code, HF_VCPU_RUN_WAIT_FOR_INTERRUPT);
+ EXPECT_EQ(run_res.code, HF_VCPU_RUN_WAIT_FOR_MESSAGE);
+ EXPECT_EQ(run_res.sleep.ns, HF_SLEEP_INDEFINITE);
}
/**
@@ -299,8 +295,7 @@
* explicitly to test the mechanism.
*/
memcpy(mb.send, &ptr, sizeof(ptr));
- EXPECT_EQ(hf_mailbox_send(SERVICE_VM0, sizeof(ptr), false),
- HF_INVALID_VCPU);
+ EXPECT_EQ(hf_mailbox_send(SERVICE_VM0, sizeof(ptr), false), 0);
/* Let the memory be returned. */
run_res = hf_vcpu_run(SERVICE_VM0, 0);
diff --git a/test/vmapi/primary_with_secondaries/no_services.c b/test/vmapi/primary_with_secondaries/no_services.c
index a90da65..9d7f29b 100644
--- a/test/vmapi/primary_with_secondaries/no_services.c
+++ b/test/vmapi/primary_with_secondaries/no_services.c
@@ -75,6 +75,7 @@
{
struct hf_vcpu_run_return res = hf_vcpu_run(HF_PRIMARY_VM_ID, 0);
EXPECT_EQ(res.code, HF_VCPU_RUN_WAIT_FOR_INTERRUPT);
+ EXPECT_EQ(res.sleep.ns, HF_SLEEP_INDEFINITE);
}
/**
@@ -84,6 +85,7 @@
{
struct hf_vcpu_run_return res = hf_vcpu_run(1234, 0);
EXPECT_EQ(res.code, HF_VCPU_RUN_WAIT_FOR_INTERRUPT);
+ EXPECT_EQ(res.sleep.ns, HF_SLEEP_INDEFINITE);
}
/**
@@ -93,6 +95,7 @@
{
struct hf_vcpu_run_return res = hf_vcpu_run(SERVICE_VM0, 1234);
EXPECT_EQ(res.code, HF_VCPU_RUN_WAIT_FOR_INTERRUPT);
+ EXPECT_EQ(res.sleep.ns, HF_SLEEP_INDEFINITE);
}
/**
diff --git a/test/vmapi/primary_with_secondaries/run_race.c b/test/vmapi/primary_with_secondaries/run_race.c
index 4230ba5..51c25a3 100644
--- a/test/vmapi/primary_with_secondaries/run_race.c
+++ b/test/vmapi/primary_with_secondaries/run_race.c
@@ -41,7 +41,8 @@
/* Run until it manages to schedule vCPU on this CPU. */
do {
run_res = hf_vcpu_run(SERVICE_VM0, 0);
- } while (run_res.code == HF_VCPU_RUN_WAIT_FOR_INTERRUPT);
+ } while (run_res.code == HF_VCPU_RUN_WAIT_FOR_INTERRUPT &&
+ run_res.sleep.ns == HF_SLEEP_INDEFINITE);
/* Break out if we received a message with non-zero length. */
if (run_res.code == HF_VCPU_RUN_MESSAGE &&
diff --git a/test/vmapi/primary_with_secondaries/services/BUILD.gn b/test/vmapi/primary_with_secondaries/services/BUILD.gn
index 75a797e..b0ef794 100644
--- a/test/vmapi/primary_with_secondaries/services/BUILD.gn
+++ b/test/vmapi/primary_with_secondaries/services/BUILD.gn
@@ -82,6 +82,7 @@
sources = [
"interruptible.c",
+ "interruptible_echo.c",
]
deps = [
diff --git a/test/vmapi/primary_with_secondaries/services/interruptible_echo.c b/test/vmapi/primary_with_secondaries/services/interruptible_echo.c
new file mode 100644
index 0000000..e1eb643
--- /dev/null
+++ b/test/vmapi/primary_with_secondaries/services/interruptible_echo.c
@@ -0,0 +1,53 @@
+/*
+ * 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/cpu.h"
+#include "hf/arch/std.h"
+#include "hf/arch/vm/interrupts_gicv3.h"
+
+#include "hf/dlog.h"
+
+#include "vmapi/hf/call.h"
+
+#include "hftest.h"
+#include "primary_with_secondary.h"
+
+static void irq(void)
+{
+ /* Clear the interrupt. */
+ hf_interrupt_get();
+}
+
+TEST_SERVICE(interruptible_echo)
+{
+ exception_setup(irq);
+ hf_interrupt_enable(EXTERNAL_INTERRUPT_ID_A, true);
+ arch_irq_enable();
+
+ for (;;) {
+ struct hf_mailbox_receive_return res = hf_mailbox_receive(true);
+
+ /* Retry if interrupted but made visible with the yield. */
+ while (res.vm_id == HF_INVALID_VM_ID && res.size == 0) {
+ hf_vcpu_yield();
+ res = hf_mailbox_receive(true);
+ }
+
+ memcpy(SERVICE_SEND_BUFFER(), SERVICE_RECV_BUFFER(), res.size);
+ hf_mailbox_clear();
+ hf_mailbox_send(res.vm_id, res.size, false);
+ }
+}