1 /*
2  * Copyright 2021 The Hafnium Authors.
3  *
4  * Use of this source code is governed by a BSD-style
5  * license that can be found in the LICENSE file or at
6  * https://opensource.org/licenses/BSD-3-Clause.
7  */
8 
9 #include <stdint.h>
10 
11 #include "hf/ffa.h"
12 #include "hf/std.h"
13 
14 #include "vmapi/hf/call.h"
15 
16 #include "primary_with_secondary.h"
17 #include "test/hftest.h"
18 #include "test/vmapi/ffa.h"
19 
20 /**
21  * Reverses the order of the elements in the given array.
22  */
reverse(char * s,size_t len)23 static void reverse(char *s, size_t len)
24 {
25 	size_t i;
26 
27 	for (i = 0; i < len / 2; i++) {
28 		char t = s[i];
29 		s[i] = s[len - 1 - i];
30 		s[len - 1 - i] = t;
31 	}
32 }
33 
34 /**
35  * Finds the next lexicographic permutation of the given array, if there is one.
36  */
next_permutation(char * s,size_t len)37 static void next_permutation(char *s, size_t len)
38 {
39 	size_t i;
40 	size_t j;
41 
42 	for (i = len - 2; i < len; i--) {
43 		const char t = s[i];
44 		if (t >= s[i + 1]) {
45 			continue;
46 		}
47 
48 		for (j = len - 1; t >= s[j]; j--) {
49 		}
50 
51 		s[i] = s[j];
52 		s[j] = t;
53 		reverse(s + i + 1, len - i - 1);
54 		return;
55 	}
56 }
57 
TEAR_DOWN(mailbox)58 TEAR_DOWN(mailbox)
59 {
60 	EXPECT_FFA_ERROR(ffa_rx_release(), FFA_DENIED);
61 }
62 
63 /**
64  * Clearing an empty mailbox is an error.
65  */
TEST(mailbox,clear_empty)66 TEST(mailbox, clear_empty)
67 {
68 	EXPECT_FFA_ERROR(ffa_rx_release(), FFA_DENIED);
69 	EXPECT_FFA_ERROR(ffa_rx_release(), FFA_DENIED);
70 	EXPECT_FFA_ERROR(ffa_rx_release(), FFA_DENIED);
71 }
72 
73 /**
74  * Send and receive the same message from the echo VM.
75  */
TEST(mailbox,echo)76 TEST(mailbox, echo)
77 {
78 	const char message[] = "Echo this back to me!";
79 	struct ffa_value run_res;
80 	struct mailbox_buffers mb = set_up_mailbox();
81 
82 	SERVICE_SELECT(SERVICE_VM1, "echo", mb.send);
83 
84 	run_res = ffa_run(SERVICE_VM1, 0);
85 	EXPECT_EQ(run_res.func, FFA_MSG_WAIT_32);
86 	EXPECT_EQ(run_res.arg2, FFA_SLEEP_INDEFINITE);
87 
88 	/* Set the message, echo it and check it didn't change. */
89 	memcpy_s(mb.send, FFA_MSG_PAYLOAD_MAX, message, sizeof(message));
90 	EXPECT_EQ(
91 		ffa_msg_send(HF_PRIMARY_VM_ID, SERVICE_VM1, sizeof(message), 0)
92 			.func,
93 		FFA_SUCCESS_32);
94 	run_res = ffa_run(SERVICE_VM1, 0);
95 	EXPECT_EQ(run_res.func, FFA_MSG_SEND_32);
96 	EXPECT_EQ(ffa_msg_send_size(run_res), sizeof(message));
97 	EXPECT_EQ(memcmp(mb.recv, message, sizeof(message)), 0);
98 	EXPECT_EQ(ffa_rx_release().func, FFA_SUCCESS_32);
99 }
100 
101 /**
102  * Repeatedly send a message and receive it back from the echo VM.
103  */
TEST(mailbox,repeated_echo)104 TEST(mailbox, repeated_echo)
105 {
106 	char message[] = "Echo this back to me!";
107 	struct ffa_value run_res;
108 	uint8_t i;
109 	struct mailbox_buffers mb = set_up_mailbox();
110 
111 	SERVICE_SELECT(SERVICE_VM1, "echo", mb.send);
112 
113 	for (i = 0; i < 100; i++) {
114 		/* Run secondary until it reaches the wait for messages. */
115 		run_res = ffa_run(SERVICE_VM1, 0);
116 		EXPECT_EQ(run_res.func, FFA_MSG_WAIT_32);
117 		EXPECT_EQ(run_res.arg2, FFA_SLEEP_INDEFINITE);
118 
119 		/* Set the message, echo it and check it didn't change. */
120 		next_permutation(message, sizeof(message) - 1);
121 		memcpy_s(mb.send, FFA_MSG_PAYLOAD_MAX, message,
122 			 sizeof(message));
123 		EXPECT_EQ(ffa_msg_send(HF_PRIMARY_VM_ID, SERVICE_VM1,
124 				       sizeof(message), 0)
125 				  .func,
126 			  FFA_SUCCESS_32);
127 		run_res = ffa_run(SERVICE_VM1, 0);
128 		EXPECT_EQ(run_res.func, FFA_MSG_SEND_32);
129 		EXPECT_EQ(ffa_msg_send_size(run_res), sizeof(message));
130 		EXPECT_EQ(memcmp(mb.recv, message, sizeof(message)), 0);
131 		EXPECT_EQ(ffa_rx_release().func, FFA_SUCCESS_32);
132 	}
133 }
134 
135 /**
136  * Send a message to relay_a which will forward it to relay_b where it will be
137  * sent back here.
138  */
TEST(mailbox,relay)139 TEST(mailbox, relay)
140 {
141 	const char message[] = "Send this round the relay!";
142 	struct ffa_value run_res;
143 	struct mailbox_buffers mb = set_up_mailbox();
144 
145 	SERVICE_SELECT(SERVICE_VM1, "relay", mb.send);
146 	SERVICE_SELECT(SERVICE_VM2, "relay", mb.send);
147 
148 	run_res = ffa_run(SERVICE_VM1, 0);
149 	EXPECT_EQ(run_res.func, FFA_MSG_WAIT_32);
150 	EXPECT_EQ(run_res.arg2, FFA_SLEEP_INDEFINITE);
151 	run_res = ffa_run(SERVICE_VM2, 0);
152 	EXPECT_EQ(run_res.func, FFA_MSG_WAIT_32);
153 	EXPECT_EQ(run_res.arg2, FFA_SLEEP_INDEFINITE);
154 
155 	/*
156 	 * Build the message chain so the message is sent from here to
157 	 * SERVICE_VM1, then to SERVICE_VM2 and finally back to here.
158 	 */
159 	{
160 		ffa_vm_id_t *chain = (ffa_vm_id_t *)mb.send;
161 		*chain++ = htole32(SERVICE_VM2);
162 		*chain++ = htole32(HF_PRIMARY_VM_ID);
163 		memcpy_s(chain, FFA_MSG_PAYLOAD_MAX - (2 * sizeof(ffa_vm_id_t)),
164 			 message, sizeof(message));
165 
166 		EXPECT_EQ(
167 			ffa_msg_send(
168 				HF_PRIMARY_VM_ID, SERVICE_VM1,
169 				sizeof(message) + (2 * sizeof(ffa_vm_id_t)), 0)
170 				.func,
171 			FFA_SUCCESS_32);
172 	}
173 
174 	/* Let SERVICE_VM1 forward the message. */
175 	run_res = ffa_run(SERVICE_VM1, 0);
176 	EXPECT_EQ(run_res.func, FFA_MSG_SEND_32);
177 	EXPECT_EQ(ffa_receiver(run_res), SERVICE_VM2);
178 	EXPECT_EQ(ffa_msg_send_size(run_res), 0);
179 
180 	/* Let SERVICE_VM2 forward the message. */
181 	run_res = ffa_run(SERVICE_VM2, 0);
182 	EXPECT_EQ(run_res.func, FFA_MSG_SEND_32);
183 
184 	/* Ensure the message is intact. */
185 	EXPECT_EQ(ffa_receiver(run_res), HF_PRIMARY_VM_ID);
186 	EXPECT_EQ(ffa_msg_send_size(run_res), sizeof(message));
187 	EXPECT_EQ(memcmp(mb.recv, message, sizeof(message)), 0);
188 	EXPECT_EQ(ffa_rx_release().func, FFA_SUCCESS_32);
189 }
190 
191 /**
192  * Send a message before the secondary VM is configured, but do not register
193  * for notification. Ensure we're not notified.
194  */
TEST(mailbox,no_primary_to_secondary_notification_on_configure)195 TEST(mailbox, no_primary_to_secondary_notification_on_configure)
196 {
197 	struct ffa_value run_res;
198 
199 	set_up_mailbox();
200 
201 	EXPECT_FFA_ERROR(ffa_msg_send(HF_PRIMARY_VM_ID, SERVICE_VM1, 0, 0),
202 			 FFA_BUSY);
203 
204 	run_res = ffa_run(SERVICE_VM1, 0);
205 	EXPECT_EQ(run_res.func, FFA_MSG_WAIT_32);
206 	EXPECT_EQ(run_res.arg2, FFA_SLEEP_INDEFINITE);
207 
208 	EXPECT_EQ(ffa_msg_send(HF_PRIMARY_VM_ID, SERVICE_VM1, 0, 0).func,
209 		  FFA_SUCCESS_32);
210 }
211