blob: c45252aa549084b3ce7c159e508494a3fd650d63 [file] [log] [blame]
Andrew Scull3c257452019-11-26 13:32:50 +00001/*
2 * Copyright 2019 The Hafnium Authors.
3 *
Andrew Walbrane959ec12020-06-17 15:01:09 +01004 * 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.
Andrew Scull3c257452019-11-26 13:32:50 +00007 */
8
9#include <gmock/gmock.h>
10
11extern "C" {
12#include "hf/mpool.h"
13#include "hf/vm.h"
14}
15
J-Alvesb37fd082020-10-22 12:29:21 +010016#include <list>
Andrew Scull3c257452019-11-26 13:32:50 +000017#include <memory>
18#include <span>
19#include <vector>
20
21#include "mm_test.hh"
22
23namespace
24{
25using namespace ::std::placeholders;
26
27using ::testing::AllOf;
28using ::testing::Each;
29using ::testing::SizeIs;
30
31using struct_vm = struct vm;
32
J-Alvesb37fd082020-10-22 12:29:21 +010033constexpr size_t TEST_HEAP_SIZE = PAGE_SIZE * 32;
Andrew Scull3c257452019-11-26 13:32:50 +000034const int TOP_LEVEL = arch_mm_stage2_max_level();
35
36class vm : public ::testing::Test
37{
38 void SetUp() override
39 {
40 /*
41 * TODO: replace with direct use of stdlib allocator so
42 * sanitizers are more effective.
43 */
44 test_heap = std::make_unique<uint8_t[]>(TEST_HEAP_SIZE);
45 mpool_init(&ppool, sizeof(struct mm_page_table));
46 mpool_add_chunk(&ppool, test_heap.get(), TEST_HEAP_SIZE);
47 }
48
49 std::unique_ptr<uint8_t[]> test_heap;
50
51 protected:
52 struct mpool ppool;
J-Alvesb37fd082020-10-22 12:29:21 +010053
54 public:
55 static bool BootOrderBiggerThan(struct_vm *vm1, struct_vm *vm2)
56 {
57 return vm1->boot_order > vm2->boot_order;
58 }
Andrew Scull3c257452019-11-26 13:32:50 +000059};
60
61/**
62 * If nothing is mapped, unmapping the hypervisor has no effect.
63 */
64TEST_F(vm, vm_unmap_hypervisor_not_mapped)
65{
66 struct_vm *vm;
67 struct vm_locked vm_locked;
68
Raghu Krishnamurthycd1eceb2021-01-04 12:20:48 -080069 EXPECT_TRUE(vm_init_next(1, &ppool, &vm, false));
Andrew Scull3c257452019-11-26 13:32:50 +000070 vm_locked = vm_lock(vm);
Raghu Krishnamurthy0132b512021-02-03 14:13:26 -080071 ASSERT_TRUE(mm_vm_init(&vm->ptable, vm->id, &ppool));
Andrew Scull3c257452019-11-26 13:32:50 +000072 EXPECT_TRUE(vm_unmap_hypervisor(vm_locked, &ppool));
73 EXPECT_THAT(
74 mm_test::get_ptable(vm->ptable),
75 AllOf(SizeIs(4), Each(Each(arch_mm_absent_pte(TOP_LEVEL)))));
76 mm_vm_fini(&vm->ptable, &ppool);
77 vm_unlock(&vm_locked);
78}
79
J-Alvesb37fd082020-10-22 12:29:21 +010080/**
81 * Validate the "boot_list" is created properly, according to vm's "boot_order"
82 * field.
83 */
84TEST_F(vm, vm_boot_order)
85{
86 struct_vm *vm_cur;
87 std::list<struct_vm *> expected_final_order;
88
89 EXPECT_FALSE(vm_get_first_boot());
90
91 /*
92 * Insertion when no call to "vm_update_boot" has been made yet.
93 * The "boot_list" is expected to be empty.
94 */
Raghu Krishnamurthycd1eceb2021-01-04 12:20:48 -080095 EXPECT_TRUE(vm_init_next(1, &ppool, &vm_cur, false));
J-Alvesb37fd082020-10-22 12:29:21 +010096 vm_cur->boot_order = 1;
97 vm_update_boot(vm_cur);
98 expected_final_order.push_back(vm_cur);
99
100 EXPECT_EQ(vm_get_first_boot()->id, vm_cur->id);
101
102 /* Insertion at the head of the boot list */
Raghu Krishnamurthycd1eceb2021-01-04 12:20:48 -0800103 EXPECT_TRUE(vm_init_next(1, &ppool, &vm_cur, false));
J-Alvesb37fd082020-10-22 12:29:21 +0100104 vm_cur->boot_order = 3;
105 vm_update_boot(vm_cur);
106 expected_final_order.push_back(vm_cur);
107
108 EXPECT_EQ(vm_get_first_boot()->id, vm_cur->id);
109
110 /* Insertion of two in the middle of the boot list */
111 for (int i = 0; i < 2; i++) {
Raghu Krishnamurthycd1eceb2021-01-04 12:20:48 -0800112 EXPECT_TRUE(vm_init_next(1, &ppool, &vm_cur, false));
J-Alvesb37fd082020-10-22 12:29:21 +0100113 vm_cur->boot_order = 2;
114 vm_update_boot(vm_cur);
115 expected_final_order.push_back(vm_cur);
116 }
117
118 /*
119 * Insertion in the end of the list.
120 * This tests shares the data with "vm_unmap_hypervisor_not_mapped".
121 * As such, a VM is expected to have been initialized before this
122 * test, with ID 1 and boot_order 0.
123 */
124 vm_cur = vm_find(1);
125 EXPECT_FALSE(vm_cur == NULL);
126 vm_update_boot(vm_cur);
127 expected_final_order.push_back(vm_cur);
128
129 /*
130 * Number of VMs initialized should be the same as in the
131 * "expected_final_order", before the final verification.
132 */
133 EXPECT_EQ(expected_final_order.size(), vm_get_count())
134 << "Something went wrong with the test itself...\n";
135
136 /* Sort "expected_final_order" by "boot_order" field */
137 expected_final_order.sort(vm::BootOrderBiggerThan);
138
139 std::list<struct_vm *>::iterator it;
140 for (it = expected_final_order.begin(), vm_cur = vm_get_first_boot();
141 it != expected_final_order.end() && vm_cur != NULL;
142 it++, vm_cur = vm_cur->next_boot) {
143 EXPECT_EQ((*it)->id, vm_cur->id);
144 }
145}
J-Alves60eaff92021-05-27 14:54:41 +0100146
147/**
148 * Validates updates and check functions for binding notifications to endpoints.
149 */
150TEST_F(vm, vm_notifications_bind_diff_senders)
151{
J-Alvesd3e81622021-10-05 14:55:57 +0100152 struct_vm *current_vm = nullptr;
153 struct vm_locked current_vm_locked;
J-Alves60eaff92021-05-27 14:54:41 +0100154 std::vector<struct_vm *> dummy_senders;
155 ffa_notifications_bitmap_t bitmaps[] = {
156 0x00000000FFFFFFFFU, 0xFFFFFFFF00000000U, 0x0000FFFFFFFF0000U};
157 bool is_from_vm = true;
158
159 /* For the subsequent tests three VMs are used. */
160 CHECK(vm_get_count() >= 3);
161
J-Alvesd3e81622021-10-05 14:55:57 +0100162 current_vm = vm_find_index(0);
J-Alves60eaff92021-05-27 14:54:41 +0100163
164 dummy_senders.push_back(vm_find_index(1));
165 dummy_senders.push_back(vm_find_index(2));
166
J-Alvesd3e81622021-10-05 14:55:57 +0100167 current_vm_locked = vm_lock(current_vm);
J-Alves60eaff92021-05-27 14:54:41 +0100168
169 for (unsigned int i = 0; i < 2; i++) {
170 /* Validate bindings condition after initialization. */
171 EXPECT_TRUE(vm_notifications_validate_binding(
J-Alvesd3e81622021-10-05 14:55:57 +0100172 current_vm_locked, is_from_vm, HF_INVALID_VM_ID,
173 bitmaps[i], false));
J-Alves60eaff92021-05-27 14:54:41 +0100174
175 /*
176 * Validate bind related operations. For this test considering
177 * only global notifications.
178 */
J-Alvesd3e81622021-10-05 14:55:57 +0100179 vm_notifications_update_bindings(current_vm_locked, is_from_vm,
J-Alves60eaff92021-05-27 14:54:41 +0100180 dummy_senders[i]->id,
181 bitmaps[i], false);
182
183 EXPECT_TRUE(vm_notifications_validate_binding(
J-Alvesd3e81622021-10-05 14:55:57 +0100184 current_vm_locked, is_from_vm, dummy_senders[i]->id,
J-Alves60eaff92021-05-27 14:54:41 +0100185 bitmaps[i], false));
186
187 EXPECT_FALSE(vm_notifications_validate_binding(
J-Alvesd3e81622021-10-05 14:55:57 +0100188 current_vm_locked, is_from_vm, dummy_senders[1 - i]->id,
J-Alves60eaff92021-05-27 14:54:41 +0100189 bitmaps[i], false));
190
191 EXPECT_FALSE(vm_notifications_validate_binding(
J-Alvesd3e81622021-10-05 14:55:57 +0100192 current_vm_locked, is_from_vm, dummy_senders[i]->id,
J-Alves60eaff92021-05-27 14:54:41 +0100193 bitmaps[1 - i], false));
194
195 EXPECT_FALSE(vm_notifications_validate_binding(
J-Alvesd3e81622021-10-05 14:55:57 +0100196 current_vm_locked, is_from_vm, dummy_senders[i]->id,
J-Alves60eaff92021-05-27 14:54:41 +0100197 bitmaps[2], false));
198 }
199
200 /** Clean up bind for other tests. */
J-Alvesd3e81622021-10-05 14:55:57 +0100201 vm_notifications_update_bindings(current_vm_locked, is_from_vm, 0,
J-Alves60eaff92021-05-27 14:54:41 +0100202 bitmaps[0], false);
J-Alvesd3e81622021-10-05 14:55:57 +0100203 vm_notifications_update_bindings(current_vm_locked, is_from_vm, 0,
J-Alves60eaff92021-05-27 14:54:41 +0100204 bitmaps[1], false);
205
J-Alvesd3e81622021-10-05 14:55:57 +0100206 vm_unlock(&current_vm_locked);
J-Alves60eaff92021-05-27 14:54:41 +0100207}
208
209/**
210 * Validates updates and check functions for binding notifications, namely the
211 * configuration of bindings of global and per VCPU notifications.
212 */
213TEST_F(vm, vm_notification_bind_per_vcpu_vs_global)
214{
J-Alvesd3e81622021-10-05 14:55:57 +0100215 struct_vm *current_vm;
216 struct vm_locked current_vm_locked;
J-Alves60eaff92021-05-27 14:54:41 +0100217 struct_vm *dummy_sender;
218 ffa_notifications_bitmap_t global = 0x00000000FFFFFFFFU;
219 ffa_notifications_bitmap_t per_vcpu = ~global;
220 bool is_from_vm = true;
221
222 CHECK(vm_get_count() >= 2);
223
J-Alvesd3e81622021-10-05 14:55:57 +0100224 current_vm = vm_find_index(0);
J-Alves60eaff92021-05-27 14:54:41 +0100225
226 dummy_sender = vm_find_index(1);
227
J-Alvesd3e81622021-10-05 14:55:57 +0100228 current_vm_locked = vm_lock(current_vm);
J-Alves60eaff92021-05-27 14:54:41 +0100229
J-Alvesd3e81622021-10-05 14:55:57 +0100230 vm_notifications_update_bindings(current_vm_locked, is_from_vm,
J-Alves60eaff92021-05-27 14:54:41 +0100231 dummy_sender->id, global, false);
J-Alvesd3e81622021-10-05 14:55:57 +0100232 vm_notifications_update_bindings(current_vm_locked, is_from_vm,
J-Alves60eaff92021-05-27 14:54:41 +0100233 dummy_sender->id, per_vcpu, true);
234
235 /* Check validation of global notifications bindings. */
236 EXPECT_TRUE(vm_notifications_validate_binding(
J-Alvesd3e81622021-10-05 14:55:57 +0100237 current_vm_locked, is_from_vm, dummy_sender->id, global,
238 false));
J-Alves60eaff92021-05-27 14:54:41 +0100239
240 /* Check validation of per vcpu notifications bindings. */
241 EXPECT_TRUE(vm_notifications_validate_binding(
J-Alvesd3e81622021-10-05 14:55:57 +0100242 current_vm_locked, is_from_vm, dummy_sender->id, per_vcpu,
243 true));
J-Alves60eaff92021-05-27 14:54:41 +0100244
245 /**
246 * Check that global notifications are not validated as per VCPU, and
247 * vice-versa.
248 */
249 EXPECT_FALSE(vm_notifications_validate_binding(
J-Alvesd3e81622021-10-05 14:55:57 +0100250 current_vm_locked, is_from_vm, dummy_sender->id, global, true));
J-Alves60eaff92021-05-27 14:54:41 +0100251 EXPECT_FALSE(vm_notifications_validate_binding(
J-Alvesd3e81622021-10-05 14:55:57 +0100252 current_vm_locked, is_from_vm, dummy_sender->id, per_vcpu,
J-Alves60eaff92021-05-27 14:54:41 +0100253 false));
J-Alvesd3e81622021-10-05 14:55:57 +0100254 EXPECT_FALSE(vm_notifications_validate_binding(
255 current_vm_locked, is_from_vm, dummy_sender->id,
256 global | per_vcpu, true));
257 EXPECT_FALSE(vm_notifications_validate_binding(
258 current_vm_locked, is_from_vm, dummy_sender->id,
259 global | per_vcpu, false));
J-Alves60eaff92021-05-27 14:54:41 +0100260
261 /** Undo the bindings */
J-Alvesd3e81622021-10-05 14:55:57 +0100262 vm_notifications_update_bindings(current_vm_locked, is_from_vm, 0,
263 global, false);
264 EXPECT_TRUE(vm_notifications_validate_binding(
265 current_vm_locked, is_from_vm, 0, global, false));
J-Alves60eaff92021-05-27 14:54:41 +0100266
J-Alvesd3e81622021-10-05 14:55:57 +0100267 vm_notifications_update_bindings(current_vm_locked, is_from_vm, 0,
268 per_vcpu, false);
269 EXPECT_TRUE(vm_notifications_validate_binding(
270 current_vm_locked, is_from_vm, 0, per_vcpu, false));
J-Alves60eaff92021-05-27 14:54:41 +0100271
J-Alvesd3e81622021-10-05 14:55:57 +0100272 vm_unlock(&current_vm_locked);
J-Alves60eaff92021-05-27 14:54:41 +0100273}
274
J-Alvesce2f8d32021-06-10 18:30:21 +0100275/**
276 * Validates accesses to notifications bitmaps.
277 */
278TEST_F(vm, vm_notifications_set_and_get)
279{
J-Alvesd3e81622021-10-05 14:55:57 +0100280 struct_vm *current_vm;
281 struct vm_locked current_vm_locked;
J-Alvesce2f8d32021-06-10 18:30:21 +0100282 struct_vm *dummy_sender;
283 ffa_notifications_bitmap_t global = 0x00000000FFFFFFFFU;
284 ffa_notifications_bitmap_t per_vcpu = ~global;
285 ffa_notifications_bitmap_t ret;
286 const unsigned int vcpu_idx = 1;
287 struct notifications *notifications;
288 const bool is_from_vm = true;
289
290 CHECK(vm_get_count() >= 2);
291
J-Alvesd3e81622021-10-05 14:55:57 +0100292 current_vm = vm_find_index(0);
J-Alvesce2f8d32021-06-10 18:30:21 +0100293 dummy_sender = vm_find_index(1);
294
J-Alvesd3e81622021-10-05 14:55:57 +0100295 notifications = &current_vm->notifications.from_vm;
296 current_vm_locked = vm_lock(current_vm);
J-Alvesce2f8d32021-06-10 18:30:21 +0100297
J-Alvesd3e81622021-10-05 14:55:57 +0100298 vm_notifications_update_bindings(current_vm_locked, is_from_vm,
J-Alvesce2f8d32021-06-10 18:30:21 +0100299 dummy_sender->id, global, false);
J-Alvesd3e81622021-10-05 14:55:57 +0100300 vm_notifications_update_bindings(current_vm_locked, is_from_vm,
J-Alvesce2f8d32021-06-10 18:30:21 +0100301 dummy_sender->id, per_vcpu, true);
302
303 /*
J-Alvesd3e81622021-10-05 14:55:57 +0100304 * Validate get notifications bitmap for global notifications.
J-Alvesce2f8d32021-06-10 18:30:21 +0100305 */
J-Alvesd3e81622021-10-05 14:55:57 +0100306 vm_notifications_set(current_vm_locked, is_from_vm, global, 0ull,
307 false);
J-Alvesce2f8d32021-06-10 18:30:21 +0100308
J-Alvesd3e81622021-10-05 14:55:57 +0100309 ret = vm_notifications_get_pending_and_clear(current_vm_locked,
310 is_from_vm, 0ull);
J-Alvesce2f8d32021-06-10 18:30:21 +0100311 EXPECT_EQ(ret, global);
J-Alvesd3e81622021-10-05 14:55:57 +0100312 EXPECT_EQ(notifications->global.pending, 0ull);
J-Alvesce2f8d32021-06-10 18:30:21 +0100313
314 /*
J-Alvesd3e81622021-10-05 14:55:57 +0100315 * Validate get notifications bitmap for per-vCPU notifications.
J-Alvesce2f8d32021-06-10 18:30:21 +0100316 */
J-Alvesd3e81622021-10-05 14:55:57 +0100317 vm_notifications_set(current_vm_locked, is_from_vm, per_vcpu, vcpu_idx,
J-Alvesce2f8d32021-06-10 18:30:21 +0100318 true);
319
J-Alvesd3e81622021-10-05 14:55:57 +0100320 ret = vm_notifications_get_pending_and_clear(current_vm_locked,
321 is_from_vm, vcpu_idx);
J-Alvesce2f8d32021-06-10 18:30:21 +0100322 EXPECT_EQ(ret, per_vcpu);
J-Alvesd3e81622021-10-05 14:55:57 +0100323 EXPECT_EQ(notifications->per_vcpu[vcpu_idx].pending, 0ull);
J-Alvesce2f8d32021-06-10 18:30:21 +0100324
325 /*
J-Alvesd3e81622021-10-05 14:55:57 +0100326 * Validate that getting notifications for a specific vCPU also returns
327 * global notifications.
J-Alvesce2f8d32021-06-10 18:30:21 +0100328 */
J-Alvesd3e81622021-10-05 14:55:57 +0100329 vm_notifications_set(current_vm_locked, is_from_vm, per_vcpu, vcpu_idx,
J-Alvesce2f8d32021-06-10 18:30:21 +0100330 true);
J-Alvesd3e81622021-10-05 14:55:57 +0100331 vm_notifications_set(current_vm_locked, is_from_vm, global, 0ull,
332 false);
J-Alvesce2f8d32021-06-10 18:30:21 +0100333
J-Alvesd3e81622021-10-05 14:55:57 +0100334 ret = vm_notifications_get_pending_and_clear(current_vm_locked,
335 is_from_vm, vcpu_idx);
J-Alvesce2f8d32021-06-10 18:30:21 +0100336 EXPECT_EQ(ret, per_vcpu | global);
J-Alvesd3e81622021-10-05 14:55:57 +0100337 EXPECT_EQ(notifications->per_vcpu[vcpu_idx].pending, 0ull);
338 EXPECT_EQ(notifications->global.pending, 0ull);
J-Alvesce2f8d32021-06-10 18:30:21 +0100339
340 /** Undo the binding */
J-Alvesd3e81622021-10-05 14:55:57 +0100341 vm_notifications_update_bindings(current_vm_locked, is_from_vm, 0ull,
342 global, false);
343 vm_notifications_update_bindings(current_vm_locked, is_from_vm, 0ull,
344 per_vcpu, true);
345 vm_unlock(&current_vm_locked);
J-Alvesce2f8d32021-06-10 18:30:21 +0100346}
347
Andrew Scull3c257452019-11-26 13:32:50 +0000348} /* namespace */