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