blob: 6a370904444c261f7e8c91c620330da62ae9c7f8 [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/**
Andrew Scull6d2db332018-10-10 15:28:17 +010046 * Confirm there are 3 secondary VMs as well as this primary VM.
Andrew Scullbc7189d2018-08-14 09:35:13 +010047 */
Andrew Scull3a942572018-10-05 21:36:09 +010048TEST(hf_vm_get_count, three_secondary_vms)
Andrew Scullf35a5c92018-08-07 18:09:46 +010049{
Andrew Scull3a942572018-10-05 21:36:09 +010050 EXPECT_EQ(hf_vm_get_count(), 4);
Andrew Scullf35a5c92018-08-07 18:09:46 +010051}
52
Andrew Scullbc7189d2018-08-14 09:35:13 +010053/**
54 * Confirm there that secondary VM has 1 VCPU.
55 */
56TEST(hf_vcpu_get_count, secondary_has_one_vcpu)
Andrew Scullf35a5c92018-08-07 18:09:46 +010057{
Andrew Scull19503262018-09-20 14:48:39 +010058 EXPECT_EQ(hf_vcpu_get_count(1), 1);
Andrew Scullf35a5c92018-08-07 18:09:46 +010059}
60
Andrew Scullbc7189d2018-08-14 09:35:13 +010061/**
62 * Confirm it is an error to query how many VCPUs are assigned to a nonexistent
63 * secondary VM.
64 */
65TEST(hf_vcpu_get_count, large_invalid_vm_index)
Andrew Scullf35a5c92018-08-07 18:09:46 +010066{
67 EXPECT_EQ(hf_vcpu_get_count(0xffffffff), -1);
68}
69
Andrew Scullbc7189d2018-08-14 09:35:13 +010070/**
Andrew Scull6d2db332018-10-10 15:28:17 +010071 * The primary can't be run by the hypervisor.
72 */
73TEST(hf_vcpu_run, cannot_run_primary)
74{
75 struct hf_vcpu_run_return res = hf_vcpu_run(HF_PRIMARY_VM_ID, 0);
76 EXPECT_EQ(res.code, HF_VCPU_RUN_WAIT_FOR_INTERRUPT);
77}
78
79/**
80 * Can only run a VM that exists.
81 */
82TEST(hf_vcpu_run, cannot_run_absent_secondary)
83{
84 struct hf_vcpu_run_return res = hf_vcpu_run(1234, 0);
85 EXPECT_EQ(res.code, HF_VCPU_RUN_WAIT_FOR_INTERRUPT);
86}
87
88/**
89 * Can only run a vcpu that exists.
90 */
91TEST(hf_vcpu_run, cannot_run_absent_vcpu)
92{
93 struct hf_vcpu_run_return res = hf_vcpu_run(ECHO_VM_ID, 1234);
94 EXPECT_EQ(res.code, HF_VCPU_RUN_WAIT_FOR_INTERRUPT);
95}
96
97/**
Andrew Scullbc7189d2018-08-14 09:35:13 +010098 * The configured send/receive addresses can't be unaligned.
99 */
100TEST(hf_vm_configure, fails_with_unaligned_pointer)
Andrew Scullc9ccb3f2018-08-13 15:27:12 +0100101{
102 uint8_t maybe_aligned[2];
103 hf_ipaddr_t unaligned_addr = (hf_ipaddr_t)&maybe_aligned[1];
Andrew Scullbc7189d2018-08-14 09:35:13 +0100104 hf_ipaddr_t aligned_addr = (hf_ipaddr_t)send_page;
Andrew Scullc9ccb3f2018-08-13 15:27:12 +0100105
106 /* Check the the address is unaligned. */
107 ASSERT_EQ(unaligned_addr & 1, 1);
108
109 EXPECT_EQ(hf_vm_configure(aligned_addr, unaligned_addr), -1);
110 EXPECT_EQ(hf_vm_configure(unaligned_addr, aligned_addr), -1);
111 EXPECT_EQ(hf_vm_configure(unaligned_addr, unaligned_addr), -1);
112}
113
Andrew Scullbc7189d2018-08-14 09:35:13 +0100114/**
115 * The configured send/receive addresses can't be the same page.
116 */
117TEST(hf_vm_configure, fails_with_same_page)
Andrew Scullc9ccb3f2018-08-13 15:27:12 +0100118{
Andrew Scullbc7189d2018-08-14 09:35:13 +0100119 EXPECT_EQ(hf_vm_configure(send_page_addr, send_page_addr), -1);
120 EXPECT_EQ(hf_vm_configure(recv_page_addr, recv_page_addr), -1);
Andrew Scullc9ccb3f2018-08-13 15:27:12 +0100121}
122
Andrew Scullbc7189d2018-08-14 09:35:13 +0100123/**
124 * The configuration of the send/receive addresses can only happen once.
125 */
126TEST(hf_vm_configure, fails_if_already_succeeded)
Andrew Scullc9ccb3f2018-08-13 15:27:12 +0100127{
Andrew Scullbc7189d2018-08-14 09:35:13 +0100128 EXPECT_EQ(hf_vm_configure(send_page_addr, recv_page_addr), 0);
129 EXPECT_EQ(hf_vm_configure(send_page_addr, recv_page_addr), -1);
Andrew Scullc9ccb3f2018-08-13 15:27:12 +0100130}
131
Andrew Scullbc7189d2018-08-14 09:35:13 +0100132/**
133 * The configuration of the send/receive address is successful with valid
134 * arguments.
135 */
136TEST(hf_vm_configure, succeeds)
Andrew Scullc9ccb3f2018-08-13 15:27:12 +0100137{
Andrew Scullbc7189d2018-08-14 09:35:13 +0100138 EXPECT_EQ(hf_vm_configure(send_page_addr, recv_page_addr), 0);
Andrew Scullf35a5c92018-08-07 18:09:46 +0100139}
Andrew Scull4b6c2fc2018-10-05 18:14:02 +0100140
141/**
Andrew Scull6d2db332018-10-10 15:28:17 +0100142 * The primary receives messages from hf_vcpu_run().
143 */
144TEST(hf_mailbox_receive, cannot_receive_from_primary_blocking)
145{
146 struct hf_mailbox_receive_return res = hf_mailbox_receive(true);
147 EXPECT_EQ(res.vm_id, HF_INVALID_VM_ID);
148 EXPECT_EQ(res.size, 0);
149}
150
151/**
152 * The primary receives messages from hf_vcpu_run().
153 */
154TEST(hf_mailbox_receive, cannot_receive_from_primary_non_blocking)
155{
156 struct hf_mailbox_receive_return res = hf_mailbox_receive(false);
157 EXPECT_EQ(res.vm_id, HF_INVALID_VM_ID);
158 EXPECT_EQ(res.size, 0);
159}
160
161/**
Andrew Scull4b6c2fc2018-10-05 18:14:02 +0100162 * Send and receive the same message from the echo VM.
163 */
164TEST(mailbox, echo)
165{
166 const char message[] = "Echo this back to me!";
Andrew Scull6d2db332018-10-10 15:28:17 +0100167 struct hf_vcpu_run_return run_res;
Andrew Scull4b6c2fc2018-10-05 18:14:02 +0100168
169 /* Configure mailbox pages. */
170 EXPECT_EQ(hf_vm_configure(send_page_addr, recv_page_addr), 0);
Andrew Scull6d2db332018-10-10 15:28:17 +0100171 run_res = hf_vcpu_run(ECHO_VM_ID, 0);
172 EXPECT_EQ(run_res.code, HF_VCPU_RUN_WAIT_FOR_INTERRUPT);
Andrew Scull4b6c2fc2018-10-05 18:14:02 +0100173
174 /* Set the message, echo it and check it didn't change. */
175 memcpy(send_page, message, sizeof(message));
176 EXPECT_EQ(hf_mailbox_send(ECHO_VM_ID, sizeof(message)), 0);
Andrew Scull6d2db332018-10-10 15:28:17 +0100177 run_res = hf_vcpu_run(ECHO_VM_ID, 0);
178 EXPECT_EQ(run_res.code, HF_VCPU_RUN_MESSAGE);
179 EXPECT_EQ(run_res.message.size, sizeof(message));
Andrew Scull4b6c2fc2018-10-05 18:14:02 +0100180 EXPECT_EQ(memcmp(recv_page, message, sizeof(message)), 0);
181 EXPECT_EQ(hf_mailbox_clear(), 0);
182}
Andrew Scull3a942572018-10-05 21:36:09 +0100183
184/**
185 * Send a message to relay_a which will forward it to relay_b where it will be
186 * sent back here.
187 */
188TEST(mailbox, relay)
189{
190 const char message[] = "Send this round the relay!";
Andrew Scull6d2db332018-10-10 15:28:17 +0100191 struct hf_vcpu_run_return run_res;
Andrew Scull3a942572018-10-05 21:36:09 +0100192
193 /* Configure mailbox pages. */
194 EXPECT_EQ(hf_vm_configure(send_page_addr, recv_page_addr), 0);
Andrew Scull6d2db332018-10-10 15:28:17 +0100195 run_res = hf_vcpu_run(RELAY_A_VM_ID, 0);
196 EXPECT_EQ(run_res.code, HF_VCPU_RUN_WAIT_FOR_INTERRUPT);
197 run_res = hf_vcpu_run(RELAY_B_VM_ID, 0);
198 EXPECT_EQ(run_res.code, HF_VCPU_RUN_WAIT_FOR_INTERRUPT);
Andrew Scull3a942572018-10-05 21:36:09 +0100199
200 /*
201 * Send the message to relay_a which is then sent to relay_b before
202 * checking that relay_b send the message back here.
203 */
204 memcpy(send_page, message, sizeof(message));
205 EXPECT_EQ(hf_mailbox_send(RELAY_A_VM_ID, sizeof(message)), 0);
Andrew Scull6d2db332018-10-10 15:28:17 +0100206 run_res = hf_vcpu_run(RELAY_A_VM_ID, 0);
207 EXPECT_EQ(run_res.code, HF_VCPU_RUN_WAKE_UP);
208 EXPECT_EQ(run_res.wake_up.vm_id, RELAY_B_VM_ID);
209 EXPECT_EQ(run_res.wake_up.vcpu, 0);
210 run_res = hf_vcpu_run(RELAY_B_VM_ID, 0);
211 EXPECT_EQ(run_res.code, HF_VCPU_RUN_MESSAGE);
212 EXPECT_EQ(run_res.message.size, sizeof(message));
Andrew Scull3a942572018-10-05 21:36:09 +0100213 EXPECT_EQ(memcmp(recv_page, message, sizeof(message)), 0);
214 EXPECT_EQ(hf_mailbox_clear(), 0);
215}