1 /*
2 * Copyright 2018 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 <stdalign.h>
10 #include <stdint.h>
11
12 #include "hf/mm.h"
13 #include "hf/static_assert.h"
14 #include "hf/std.h"
15
16 #include "vmapi/hf/call.h"
17
18 #include "primary_with_secondary.h"
19 #include "test/hftest.h"
20 #include "test/vmapi/ffa.h"
21
22 static alignas(PAGE_SIZE) uint8_t send_page[PAGE_SIZE];
23 static alignas(PAGE_SIZE) uint8_t recv_page[PAGE_SIZE];
24 static_assert(sizeof(send_page) == PAGE_SIZE, "Send page is not a page.");
25 static_assert(sizeof(recv_page) == PAGE_SIZE, "Recv page is not a page.");
26
27 static hf_ipaddr_t send_page_addr = (hf_ipaddr_t)send_page;
28 static hf_ipaddr_t recv_page_addr = (hf_ipaddr_t)recv_page;
29
30 /**
31 * Confirms the primary VM has the primary ID.
32 */
TEST(hf_vm_get_id,primary_has_primary_id)33 TEST(hf_vm_get_id, primary_has_primary_id)
34 {
35 EXPECT_EQ(hf_vm_get_id(), HF_PRIMARY_VM_ID);
36 }
37
TEAR_DOWN(ffa_partition_info_get)38 TEAR_DOWN(ffa_partition_info_get)
39 {
40 EXPECT_FFA_ERROR(ffa_rx_release(), FFA_DENIED);
41 }
42
43 /**
44 * Confirm there are 3 secondary VMs as well as this primary VM, and that they
45 * have the expected number of vCPUs.
46 */
TEST(ffa_partition_info_get,three_secondary_vms)47 TEST(ffa_partition_info_get, three_secondary_vms)
48 {
49 struct mailbox_buffers mb;
50 struct ffa_value ret;
51 const struct ffa_partition_info *partitions;
52 struct ffa_uuid uuid;
53
54 /* A Null UUID requests information for all partitions. */
55 ffa_uuid_init(0, 0, 0, 0, &uuid);
56
57 /* Try to get partition information before the RX buffer is setup. */
58 ret = ffa_partition_info_get(&uuid, 0);
59 EXPECT_FFA_ERROR(ret, FFA_BUSY);
60
61 /* Only getting the partition count should succeed however. */
62 ret = ffa_partition_info_get(&uuid, FFA_PARTITION_COUNT_FLAG);
63 EXPECT_EQ(ret.func, FFA_SUCCESS_32);
64 EXPECT_EQ(ret.arg2, 4);
65
66 /* Setup the mailbox (which holds the RX buffer). */
67 mb = set_up_mailbox();
68 partitions = mb.recv;
69
70 /* Check that the expected partition information is returned. */
71 ret = ffa_partition_info_get(&uuid, 0);
72 EXPECT_EQ(ret.func, FFA_SUCCESS_32);
73 /* Confirm there are 3 secondary VMs as well as this primary VM. */
74 EXPECT_EQ(ret.arg2, 4);
75 EXPECT_EQ(partitions[0].vm_id, hf_vm_get_id());
76
77 /* The first two secondary VMs should have 1 vCPU, the other one 2. */
78 EXPECT_EQ(partitions[1].vcpu_count, 8);
79 EXPECT_EQ(partitions[2].vcpu_count, 8);
80 EXPECT_EQ(partitions[3].vcpu_count, 8);
81
82 EXPECT_EQ(ffa_rx_release().func, FFA_SUCCESS_32);
83 }
84
85 /**
86 * Confirm that it is an error to get partition info for a nonexistent VM.
87 */
TEST(ffa_partition_info_get,invalid_vm_uuid)88 TEST(ffa_partition_info_get, invalid_vm_uuid)
89 {
90 struct ffa_value ret;
91 struct ffa_uuid uuid;
92
93 /* Try to get partition information for an unrecognized UUID. */
94 ffa_uuid_init(0, 0, 0, 1, &uuid);
95
96 ret = ffa_partition_info_get(&uuid, 0);
97 EXPECT_FFA_ERROR(ret, FFA_INVALID_PARAMETERS);
98 }
99
TEST(ffa_partition_info_get,get_v1_0_descriptor)100 TEST(ffa_partition_info_get, get_v1_0_descriptor)
101 {
102 struct mailbox_buffers mb;
103 struct ffa_value ret;
104 const struct ffa_partition_info_v1_0 *partitions;
105 struct ffa_uuid uuid;
106
107 /* Set ffa_version to v1.0. */
108 ffa_version(MAKE_FFA_VERSION(1, 0));
109
110 /* A Null UUID requests information for all partitions. */
111 ffa_uuid_init(0, 0, 0, 0, &uuid);
112
113 /* Try to get partition information before the RX buffer is setup. */
114 ret = ffa_partition_info_get(&uuid, 0);
115 EXPECT_FFA_ERROR(ret, FFA_BUSY);
116
117 /* Only getting the partition count should succeed however. */
118 ret = ffa_partition_info_get(&uuid, FFA_PARTITION_COUNT_FLAG);
119 EXPECT_EQ(ret.func, FFA_SUCCESS_32);
120
121 /* Setup the mailbox (which holds the RX buffer). */
122 mb = set_up_mailbox();
123 partitions = mb.recv;
124
125 /* Check that the expected partition information is returned. */
126 ret = ffa_partition_info_get(&uuid, 0);
127 EXPECT_EQ(ret.func, FFA_SUCCESS_32);
128 /* Confirm there are 3 secondary VMs as well as this primary VM. */
129 EXPECT_EQ(ret.arg2, 4);
130 EXPECT_EQ(partitions[0].vm_id, hf_vm_get_id());
131
132 /* The first two secondary VMs should have 1 vCPU, the other one 2. */
133 EXPECT_EQ(partitions[1].vcpu_count, 8);
134 EXPECT_EQ(partitions[2].vcpu_count, 8);
135 EXPECT_EQ(partitions[3].vcpu_count, 8);
136
137 EXPECT_EQ(ffa_rx_release().func, FFA_SUCCESS_32);
138 }
139
140 /**
141 * The primary can't be run by the hypervisor.
142 */
TEST(ffa_run,cannot_run_primary)143 TEST(ffa_run, cannot_run_primary)
144 {
145 struct ffa_value res = ffa_run(HF_PRIMARY_VM_ID, 0);
146 EXPECT_FFA_ERROR(res, FFA_INVALID_PARAMETERS);
147 }
148
149 /**
150 * Can only run a VM that exists.
151 */
TEST(ffa_run,cannot_run_absent_secondary)152 TEST(ffa_run, cannot_run_absent_secondary)
153 {
154 struct ffa_value res = ffa_run(1234, 0);
155 EXPECT_FFA_ERROR(res, FFA_INVALID_PARAMETERS);
156 }
157
158 /**
159 * Can only run a vCPU that exists.
160 */
TEST(ffa_run,cannot_run_absent_vcpu)161 TEST(ffa_run, cannot_run_absent_vcpu)
162 {
163 struct ffa_value res = ffa_run(SERVICE_VM1, 1234);
164 EXPECT_FFA_ERROR(res, FFA_INVALID_PARAMETERS);
165 }
166
TEAR_DOWN(ffa_rxtx_map)167 TEAR_DOWN(ffa_rxtx_map)
168 {
169 EXPECT_FFA_ERROR(ffa_rx_release(), FFA_DENIED);
170 }
171
172 /**
173 * The configured send/receive addresses can't be device memory.
174 */
TEST(ffa_rxtx_map,fails_with_device_memory)175 TEST(ffa_rxtx_map, fails_with_device_memory)
176 {
177 EXPECT_FFA_ERROR(ffa_rxtx_map(PAGE_SIZE, PAGE_SIZE * 2),
178 FFA_INVALID_PARAMETERS);
179 }
180
181 /**
182 * The configured send/receive addresses can't be unaligned.
183 */
TEST(ffa_rxtx_map,fails_with_unaligned_pointer)184 TEST(ffa_rxtx_map, fails_with_unaligned_pointer)
185 {
186 uint8_t maybe_aligned[2];
187 hf_ipaddr_t unaligned_addr = (hf_ipaddr_t)&maybe_aligned[1];
188 hf_ipaddr_t aligned_addr = (hf_ipaddr_t)send_page;
189
190 /* Check that the address is unaligned. */
191 ASSERT_EQ(unaligned_addr & 1, 1);
192
193 EXPECT_FFA_ERROR(ffa_rxtx_map(aligned_addr, unaligned_addr),
194 FFA_INVALID_PARAMETERS);
195 EXPECT_FFA_ERROR(ffa_rxtx_map(unaligned_addr, aligned_addr),
196 FFA_INVALID_PARAMETERS);
197 EXPECT_FFA_ERROR(ffa_rxtx_map(unaligned_addr, unaligned_addr),
198 FFA_INVALID_PARAMETERS);
199 }
200
201 /**
202 * The configured send/receive addresses can't be the same page.
203 */
TEST(ffa_rxtx_map,fails_with_same_page)204 TEST(ffa_rxtx_map, fails_with_same_page)
205 {
206 EXPECT_FFA_ERROR(ffa_rxtx_map(send_page_addr, send_page_addr),
207 FFA_INVALID_PARAMETERS);
208 EXPECT_FFA_ERROR(ffa_rxtx_map(recv_page_addr, recv_page_addr),
209 FFA_INVALID_PARAMETERS);
210 }
211
212 /**
213 * The configuration of the send/receive addresses can only happen once.
214 */
TEST(ffa_rxtx_map,fails_if_already_succeeded)215 TEST(ffa_rxtx_map, fails_if_already_succeeded)
216 {
217 EXPECT_EQ(ffa_rxtx_map(send_page_addr, recv_page_addr).func,
218 FFA_SUCCESS_32);
219 EXPECT_FFA_ERROR(ffa_rxtx_map(send_page_addr, recv_page_addr),
220 FFA_DENIED);
221 }
222
223 /**
224 * The configuration of the send/receive address is successful with valid
225 * arguments.
226 */
TEST(ffa_rxtx_map,succeeds)227 TEST(ffa_rxtx_map, succeeds)
228 {
229 EXPECT_EQ(ffa_rxtx_map(send_page_addr, recv_page_addr).func,
230 FFA_SUCCESS_32);
231 }
232
233 /**
234 * The primary receives messages from ffa_run().
235 */
TEST(hf_mailbox_receive,cannot_receive_from_primary_blocking)236 TEST(hf_mailbox_receive, cannot_receive_from_primary_blocking)
237 {
238 struct ffa_value res = ffa_msg_wait();
239 EXPECT_NE(res.func, FFA_SUCCESS_32);
240 }
241
242 /**
243 * The primary receives messages from ffa_run().
244 */
TEST(hf_mailbox_receive,cannot_receive_from_primary_non_blocking)245 TEST(hf_mailbox_receive, cannot_receive_from_primary_non_blocking)
246 {
247 struct ffa_value res = ffa_msg_poll();
248 EXPECT_NE(res.func, FFA_SUCCESS_32);
249 }
250
251 /**
252 * The buffer pair can be successfully unmapped from a VM that has
253 * just created the mapping.
254 */
TEST(ffa_rxtx_unmap,succeeds)255 TEST(ffa_rxtx_unmap, succeeds)
256 {
257 EXPECT_EQ(ffa_rxtx_map(send_page_addr, recv_page_addr).func,
258 FFA_SUCCESS_32);
259 EXPECT_EQ(ffa_rxtx_unmap().func, FFA_SUCCESS_32);
260 }
261
262 /**
263 * Unmap will fail if no mapping exists for the VM.
264 */
TEST(ffa_rxtx_unmap,fails_if_no_mapping)265 TEST(ffa_rxtx_unmap, fails_if_no_mapping)
266 {
267 EXPECT_FFA_ERROR(ffa_rxtx_unmap(), FFA_INVALID_PARAMETERS);
268 }
269
270 /**
271 * A buffer pair cannot be unmapped multiple times.
272 */
TEST(ffa_rxtx_unmap,fails_if_already_unmapped)273 TEST(ffa_rxtx_unmap, fails_if_already_unmapped)
274 {
275 EXPECT_EQ(ffa_rxtx_map(send_page_addr, recv_page_addr).func,
276 FFA_SUCCESS_32);
277 EXPECT_EQ(ffa_rxtx_unmap().func, FFA_SUCCESS_32);
278 EXPECT_FFA_ERROR(ffa_rxtx_unmap(), FFA_INVALID_PARAMETERS);
279 }
280
281 /**
282 * Test we can remap a region after it has been unmapped.
283 */
TEST(ffa_rxtx_unmap,succeeds_in_remapping_region)284 TEST(ffa_rxtx_unmap, succeeds_in_remapping_region)
285 {
286 EXPECT_EQ(ffa_rxtx_map(send_page_addr, recv_page_addr).func,
287 FFA_SUCCESS_32);
288 EXPECT_EQ(ffa_rxtx_unmap().func, FFA_SUCCESS_32);
289 EXPECT_EQ(ffa_rxtx_map(send_page_addr, recv_page_addr).func,
290 FFA_SUCCESS_32);
291 }
292
293 /**
294 * The `allocator_id` must be 0 at virtual instances.
295 */
TEST(ffa_rxtx_unmap,validate_allocator_id)296 TEST(ffa_rxtx_unmap, validate_allocator_id)
297 {
298 struct ffa_value ret;
299
300 EXPECT_EQ(ffa_rxtx_map(send_page_addr, recv_page_addr).func,
301 FFA_SUCCESS_32);
302
303 /* Set the `allocator_id`, which MBZ at virtual instances. */
304 ret = ffa_call(
305 (struct ffa_value){.func = FFA_RXTX_UNMAP_32, .arg1 = 1});
306 EXPECT_FFA_ERROR(ret, FFA_INVALID_PARAMETERS);
307
308 EXPECT_EQ(ffa_rxtx_unmap().func, FFA_SUCCESS_32);
309 }
310