blob: d9597a63a386a2ef2d82f5da43be951f0ed2fbb5 [file] [log] [blame]
/*
* Copyright 2019 The Hafnium Authors.
*
* Use of this source code is governed by a BSD-style
* license that can be found in the LICENSE file or at
* https://opensource.org/licenses/BSD-3-Clause.
*/
#include <stdint.h>
#include "hf/ffa.h"
#include "hf/std.h"
#include "vmapi/hf/call.h"
#include "primary_with_secondary.h"
#include "test/hftest.h"
#include "test/vmapi/ffa.h"
/**
* Causes secondary VM to send two messages to primary VM. The second message
* will reach the mailbox while it's not writable. Checks that notifications are
* properly delivered when mailbox is cleared.
*/
TEST(mailbox, primary_to_secondary)
{
char message[] = "not ready echo";
struct ffa_value run_res;
struct mailbox_buffers mb = set_up_mailbox();
SERVICE_SELECT(SERVICE_VM1, "echo_with_notification", mb.send);
run_res = ffa_run(SERVICE_VM1, 0);
EXPECT_EQ(run_res.func, FFA_MSG_WAIT_32);
EXPECT_EQ(run_res.arg2, FFA_SLEEP_INDEFINITE);
/* Send a message to echo service, and get response back. */
memcpy_s(mb.send, FFA_MSG_PAYLOAD_MAX, message, sizeof(message));
EXPECT_EQ(
ffa_msg_send(HF_PRIMARY_VM_ID, SERVICE_VM1, sizeof(message), 0)
.func,
FFA_SUCCESS_32);
run_res = ffa_run(SERVICE_VM1, 0);
EXPECT_EQ(run_res.func, FFA_MSG_SEND_32);
EXPECT_EQ(ffa_msg_send_size(run_res), sizeof(message));
EXPECT_EQ(memcmp(mb.recv, message, sizeof(message)), 0);
/* Let secondary VM continue running so that it will wait again. */
run_res = ffa_run(SERVICE_VM1, 0);
EXPECT_EQ(run_res.func, FFA_MSG_WAIT_32);
EXPECT_EQ(run_res.arg2, FFA_SLEEP_INDEFINITE);
/* Without clearing our mailbox, send message again. */
reverse(message, strnlen_s(message, sizeof(message)));
memcpy_s(mb.send, FFA_MSG_PAYLOAD_MAX, message, sizeof(message));
/* Message should be dropped since the mailbox was not cleared. */
EXPECT_EQ(
ffa_msg_send(HF_PRIMARY_VM_ID, SERVICE_VM1, sizeof(message), 0)
.func,
FFA_SUCCESS_32);
run_res = ffa_run(SERVICE_VM1, 0);
EXPECT_EQ(run_res.func, HF_FFA_RUN_WAIT_FOR_INTERRUPT);
EXPECT_EQ(run_res.arg2, FFA_SLEEP_INDEFINITE);
/* Clear the mailbox. We expect to be told there are pending waiters. */
EXPECT_EQ(ffa_rx_release().func, FFA_RX_RELEASE_32);
/* Retrieve a single waiter. */
EXPECT_EQ(hf_mailbox_waiter_get(HF_PRIMARY_VM_ID), SERVICE_VM1);
EXPECT_EQ(hf_mailbox_waiter_get(HF_PRIMARY_VM_ID), -1);
/*
* Inject interrupt into VM and let it run again. We should receive
* the echoed message.
*/
EXPECT_EQ(
hf_interrupt_inject(SERVICE_VM1, 0, HF_MAILBOX_WRITABLE_INTID),
1);
run_res = ffa_run(SERVICE_VM1, 0);
EXPECT_EQ(run_res.func, FFA_MSG_SEND_32);
EXPECT_EQ(ffa_msg_send_size(run_res), sizeof(message));
EXPECT_EQ(memcmp(mb.recv, message, sizeof(message)), 0);
EXPECT_EQ(ffa_rx_release().func, FFA_SUCCESS_32);
}