blob: 3aa680079033cb49dbbe5f9eda43f97f4a5c98d1 [file] [log] [blame]
Andrew Scull18834872018-10-12 11:48:09 +01001/*
2 * Copyright 2018 Google LLC
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * https://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
Andrew Scullc9ccb3f2018-08-13 15:27:12 +010017#include <assert.h>
18#include <stdalign.h>
Andrew Scullf35a5c92018-08-07 18:09:46 +010019#include <stdint.h>
20
Andrew Scull18c78fc2018-08-20 12:57:41 +010021#include "hf/mm.h"
Andrew Scull4b6c2fc2018-10-05 18:14:02 +010022#include "hf/std.h"
Andrew Scull18c78fc2018-08-20 12:57:41 +010023
Andrew Scullf35a5c92018-08-07 18:09:46 +010024#include "vmapi/hf/call.h"
25
Andrew Scull4b6c2fc2018-10-05 18:14:02 +010026#include "hftest.h"
Andrew Scull18c78fc2018-08-20 12:57:41 +010027
Andrew Scullbc7189d2018-08-14 09:35:13 +010028static alignas(PAGE_SIZE) uint8_t send_page[PAGE_SIZE];
29static alignas(PAGE_SIZE) uint8_t recv_page[PAGE_SIZE];
Andrew Scullc9ccb3f2018-08-13 15:27:12 +010030static_assert(sizeof(send_page) == PAGE_SIZE, "Send page is not a page.");
31static_assert(sizeof(recv_page) == PAGE_SIZE, "Recv page is not a page.");
Andrew Scullf35a5c92018-08-07 18:09:46 +010032
Andrew Scullbc7189d2018-08-14 09:35:13 +010033static hf_ipaddr_t send_page_addr = (hf_ipaddr_t)send_page;
34static hf_ipaddr_t recv_page_addr = (hf_ipaddr_t)recv_page;
35
Andrew Scull3a942572018-10-05 21:36:09 +010036/* Keep macro alignment */
37/* clang-format off */
38
39#define RELAY_A_VM_ID 1
40#define RELAY_B_VM_ID 2
41#define ECHO_VM_ID 3
42
43/* clang-format on */
Andrew Scull4b6c2fc2018-10-05 18:14:02 +010044
Andrew Scullbc7189d2018-08-14 09:35:13 +010045/**
Wedson Almeida Filhoba641ef2018-12-03 04:19:44 +000046 * Reverses the order of the elements in the given array.
47 */
48void reverse(char *s, size_t len)
49{
50 size_t i;
51
52 for (i = 0; i < len / 2; i++) {
53 char t = s[i];
54 s[i] = s[len - 1 - i];
55 s[len - 1 - i] = t;
56 }
57}
58
59/**
60 * Finds the next lexicographic permutation of the given array, if there is one.
61 */
62void next_permutation(char *s, size_t len)
63{
64 size_t i, j;
65
66 for (i = len - 2; i < len; i--) {
67 const char t = s[i];
68 if (t >= s[i + 1]) {
69 continue;
70 }
71
72 for (j = len - 1; t >= s[j]; j--) {
73 }
74
75 s[i] = s[j];
76 s[j] = t;
77 reverse(s + i + 1, len - i - 1);
78 return;
79 }
80}
81
82/**
Andrew Scull6d2db332018-10-10 15:28:17 +010083 * Confirm there are 3 secondary VMs as well as this primary VM.
Andrew Scullbc7189d2018-08-14 09:35:13 +010084 */
Andrew Scull3a942572018-10-05 21:36:09 +010085TEST(hf_vm_get_count, three_secondary_vms)
Andrew Scullf35a5c92018-08-07 18:09:46 +010086{
Andrew Scull3a942572018-10-05 21:36:09 +010087 EXPECT_EQ(hf_vm_get_count(), 4);
Andrew Scullf35a5c92018-08-07 18:09:46 +010088}
89
Andrew Scullbc7189d2018-08-14 09:35:13 +010090/**
91 * Confirm there that secondary VM has 1 VCPU.
92 */
93TEST(hf_vcpu_get_count, secondary_has_one_vcpu)
Andrew Scullf35a5c92018-08-07 18:09:46 +010094{
Andrew Scull19503262018-09-20 14:48:39 +010095 EXPECT_EQ(hf_vcpu_get_count(1), 1);
Andrew Scullf35a5c92018-08-07 18:09:46 +010096}
97
Andrew Scullbc7189d2018-08-14 09:35:13 +010098/**
99 * Confirm it is an error to query how many VCPUs are assigned to a nonexistent
100 * secondary VM.
101 */
102TEST(hf_vcpu_get_count, large_invalid_vm_index)
Andrew Scullf35a5c92018-08-07 18:09:46 +0100103{
104 EXPECT_EQ(hf_vcpu_get_count(0xffffffff), -1);
105}
106
Andrew Scullbc7189d2018-08-14 09:35:13 +0100107/**
Andrew Scull6d2db332018-10-10 15:28:17 +0100108 * The primary can't be run by the hypervisor.
109 */
110TEST(hf_vcpu_run, cannot_run_primary)
111{
112 struct hf_vcpu_run_return res = hf_vcpu_run(HF_PRIMARY_VM_ID, 0);
113 EXPECT_EQ(res.code, HF_VCPU_RUN_WAIT_FOR_INTERRUPT);
114}
115
116/**
117 * Can only run a VM that exists.
118 */
119TEST(hf_vcpu_run, cannot_run_absent_secondary)
120{
121 struct hf_vcpu_run_return res = hf_vcpu_run(1234, 0);
122 EXPECT_EQ(res.code, HF_VCPU_RUN_WAIT_FOR_INTERRUPT);
123}
124
125/**
126 * Can only run a vcpu that exists.
127 */
128TEST(hf_vcpu_run, cannot_run_absent_vcpu)
129{
130 struct hf_vcpu_run_return res = hf_vcpu_run(ECHO_VM_ID, 1234);
131 EXPECT_EQ(res.code, HF_VCPU_RUN_WAIT_FOR_INTERRUPT);
132}
133
134/**
Andrew Scullbc7189d2018-08-14 09:35:13 +0100135 * The configured send/receive addresses can't be unaligned.
136 */
137TEST(hf_vm_configure, fails_with_unaligned_pointer)
Andrew Scullc9ccb3f2018-08-13 15:27:12 +0100138{
139 uint8_t maybe_aligned[2];
140 hf_ipaddr_t unaligned_addr = (hf_ipaddr_t)&maybe_aligned[1];
Andrew Scullbc7189d2018-08-14 09:35:13 +0100141 hf_ipaddr_t aligned_addr = (hf_ipaddr_t)send_page;
Andrew Scullc9ccb3f2018-08-13 15:27:12 +0100142
143 /* Check the the address is unaligned. */
144 ASSERT_EQ(unaligned_addr & 1, 1);
145
146 EXPECT_EQ(hf_vm_configure(aligned_addr, unaligned_addr), -1);
147 EXPECT_EQ(hf_vm_configure(unaligned_addr, aligned_addr), -1);
148 EXPECT_EQ(hf_vm_configure(unaligned_addr, unaligned_addr), -1);
149}
150
Andrew Scullbc7189d2018-08-14 09:35:13 +0100151/**
152 * The configured send/receive addresses can't be the same page.
153 */
154TEST(hf_vm_configure, fails_with_same_page)
Andrew Scullc9ccb3f2018-08-13 15:27:12 +0100155{
Andrew Scullbc7189d2018-08-14 09:35:13 +0100156 EXPECT_EQ(hf_vm_configure(send_page_addr, send_page_addr), -1);
157 EXPECT_EQ(hf_vm_configure(recv_page_addr, recv_page_addr), -1);
Andrew Scullc9ccb3f2018-08-13 15:27:12 +0100158}
159
Andrew Scullbc7189d2018-08-14 09:35:13 +0100160/**
161 * The configuration of the send/receive addresses can only happen once.
162 */
163TEST(hf_vm_configure, fails_if_already_succeeded)
Andrew Scullc9ccb3f2018-08-13 15:27:12 +0100164{
Andrew Scullbc7189d2018-08-14 09:35:13 +0100165 EXPECT_EQ(hf_vm_configure(send_page_addr, recv_page_addr), 0);
166 EXPECT_EQ(hf_vm_configure(send_page_addr, recv_page_addr), -1);
Andrew Scullc9ccb3f2018-08-13 15:27:12 +0100167}
168
Andrew Scullbc7189d2018-08-14 09:35:13 +0100169/**
170 * The configuration of the send/receive address is successful with valid
171 * arguments.
172 */
173TEST(hf_vm_configure, succeeds)
Andrew Scullc9ccb3f2018-08-13 15:27:12 +0100174{
Andrew Scullbc7189d2018-08-14 09:35:13 +0100175 EXPECT_EQ(hf_vm_configure(send_page_addr, recv_page_addr), 0);
Andrew Scullf35a5c92018-08-07 18:09:46 +0100176}
Andrew Scull4b6c2fc2018-10-05 18:14:02 +0100177
178/**
Andrew Scull6d2db332018-10-10 15:28:17 +0100179 * The primary receives messages from hf_vcpu_run().
180 */
181TEST(hf_mailbox_receive, cannot_receive_from_primary_blocking)
182{
183 struct hf_mailbox_receive_return res = hf_mailbox_receive(true);
184 EXPECT_EQ(res.vm_id, HF_INVALID_VM_ID);
185 EXPECT_EQ(res.size, 0);
186}
187
188/**
189 * The primary receives messages from hf_vcpu_run().
190 */
191TEST(hf_mailbox_receive, cannot_receive_from_primary_non_blocking)
192{
193 struct hf_mailbox_receive_return res = hf_mailbox_receive(false);
194 EXPECT_EQ(res.vm_id, HF_INVALID_VM_ID);
195 EXPECT_EQ(res.size, 0);
196}
197
198/**
Andrew Scull4b6c2fc2018-10-05 18:14:02 +0100199 * Send and receive the same message from the echo VM.
200 */
201TEST(mailbox, echo)
202{
203 const char message[] = "Echo this back to me!";
Andrew Scull6d2db332018-10-10 15:28:17 +0100204 struct hf_vcpu_run_return run_res;
Andrew Scull4b6c2fc2018-10-05 18:14:02 +0100205
206 /* Configure mailbox pages. */
207 EXPECT_EQ(hf_vm_configure(send_page_addr, recv_page_addr), 0);
Andrew Scull6d2db332018-10-10 15:28:17 +0100208 run_res = hf_vcpu_run(ECHO_VM_ID, 0);
209 EXPECT_EQ(run_res.code, HF_VCPU_RUN_WAIT_FOR_INTERRUPT);
Andrew Scull4b6c2fc2018-10-05 18:14:02 +0100210
211 /* Set the message, echo it and check it didn't change. */
212 memcpy(send_page, message, sizeof(message));
213 EXPECT_EQ(hf_mailbox_send(ECHO_VM_ID, sizeof(message)), 0);
Andrew Scull6d2db332018-10-10 15:28:17 +0100214 run_res = hf_vcpu_run(ECHO_VM_ID, 0);
215 EXPECT_EQ(run_res.code, HF_VCPU_RUN_MESSAGE);
216 EXPECT_EQ(run_res.message.size, sizeof(message));
Andrew Scull4b6c2fc2018-10-05 18:14:02 +0100217 EXPECT_EQ(memcmp(recv_page, message, sizeof(message)), 0);
218 EXPECT_EQ(hf_mailbox_clear(), 0);
219}
Andrew Scull3a942572018-10-05 21:36:09 +0100220
221/**
Wedson Almeida Filhoba641ef2018-12-03 04:19:44 +0000222 * Repeatedly send a message and receive it back from the echo VM.
223 */
224TEST(mailbox, repeated_echo)
225{
226 char message[] = "Echo this back to me!";
227 struct hf_vcpu_run_return run_res;
228 uint8_t i;
229
230 /* Configure mailbox pages. */
231 EXPECT_EQ(hf_vm_configure(send_page_addr, recv_page_addr), 0);
232
233 for (i = 0; i < 100; i++) {
234 /* Run secondary until it reaches the wait for messages. */
235 run_res = hf_vcpu_run(ECHO_VM_ID, 0);
236 EXPECT_EQ(run_res.code, HF_VCPU_RUN_WAIT_FOR_INTERRUPT);
237
238 /* Set the message, echo it and check it didn't change. */
239 next_permutation(message, sizeof(message) - 1);
240 memcpy(send_page, message, sizeof(message));
241 EXPECT_EQ(hf_mailbox_send(ECHO_VM_ID, sizeof(message)), 0);
242 run_res = hf_vcpu_run(ECHO_VM_ID, 0);
243 EXPECT_EQ(run_res.code, HF_VCPU_RUN_MESSAGE);
244 EXPECT_EQ(run_res.message.size, sizeof(message));
245 EXPECT_EQ(memcmp(recv_page, message, sizeof(message)), 0);
246 EXPECT_EQ(hf_mailbox_clear(), 0);
247 }
248}
249
250/**
Andrew Scull3a942572018-10-05 21:36:09 +0100251 * Send a message to relay_a which will forward it to relay_b where it will be
252 * sent back here.
253 */
254TEST(mailbox, relay)
255{
256 const char message[] = "Send this round the relay!";
Andrew Scull6d2db332018-10-10 15:28:17 +0100257 struct hf_vcpu_run_return run_res;
Andrew Scull3a942572018-10-05 21:36:09 +0100258
259 /* Configure mailbox pages. */
260 EXPECT_EQ(hf_vm_configure(send_page_addr, recv_page_addr), 0);
Andrew Scull6d2db332018-10-10 15:28:17 +0100261 run_res = hf_vcpu_run(RELAY_A_VM_ID, 0);
262 EXPECT_EQ(run_res.code, HF_VCPU_RUN_WAIT_FOR_INTERRUPT);
263 run_res = hf_vcpu_run(RELAY_B_VM_ID, 0);
264 EXPECT_EQ(run_res.code, HF_VCPU_RUN_WAIT_FOR_INTERRUPT);
Andrew Scull3a942572018-10-05 21:36:09 +0100265
266 /*
267 * Send the message to relay_a which is then sent to relay_b before
268 * checking that relay_b send the message back here.
269 */
270 memcpy(send_page, message, sizeof(message));
271 EXPECT_EQ(hf_mailbox_send(RELAY_A_VM_ID, sizeof(message)), 0);
Andrew Scull6d2db332018-10-10 15:28:17 +0100272 run_res = hf_vcpu_run(RELAY_A_VM_ID, 0);
273 EXPECT_EQ(run_res.code, HF_VCPU_RUN_WAKE_UP);
274 EXPECT_EQ(run_res.wake_up.vm_id, RELAY_B_VM_ID);
275 EXPECT_EQ(run_res.wake_up.vcpu, 0);
276 run_res = hf_vcpu_run(RELAY_B_VM_ID, 0);
277 EXPECT_EQ(run_res.code, HF_VCPU_RUN_MESSAGE);
278 EXPECT_EQ(run_res.message.size, sizeof(message));
Andrew Scull3a942572018-10-05 21:36:09 +0100279 EXPECT_EQ(memcmp(recv_page, message, sizeof(message)), 0);
280 EXPECT_EQ(hf_mailbox_clear(), 0);
281}