blob: c3d8a4a77e2f9e1793b007a01e3e9e933353b937 [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" {
Daniel Boulby84350712021-11-26 11:13:20 +000012#include "hf/check.h"
Andrew Scull3c257452019-11-26 13:32:50 +000013#include "hf/mpool.h"
14#include "hf/vm.h"
15}
16
J-Alvesb37fd082020-10-22 12:29:21 +010017#include <list>
Andrew Scull3c257452019-11-26 13:32:50 +000018#include <memory>
19#include <span>
20#include <vector>
21
22#include "mm_test.hh"
23
24namespace
25{
26using namespace ::std::placeholders;
27
28using ::testing::AllOf;
29using ::testing::Each;
30using ::testing::SizeIs;
31
32using struct_vm = struct vm;
J-Alves96f6e292021-06-08 17:32:40 +010033using struct_vm_locked = struct vm_locked;
Andrew Scull3c257452019-11-26 13:32:50 +000034
Olivier Deprezd5a54892023-02-02 16:45:59 +010035constexpr size_t TEST_HEAP_SIZE = PAGE_SIZE * 64;
Andrew Scull3c257452019-11-26 13:32:50 +000036const int TOP_LEVEL = arch_mm_stage2_max_level();
37
38class vm : public ::testing::Test
39{
Olivier Deprezd5a54892023-02-02 16:45:59 +010040 protected:
41 static std::unique_ptr<uint8_t[]> test_heap;
42
43 struct mpool ppool;
44
Andrew Scull3c257452019-11-26 13:32:50 +000045 void SetUp() override
46 {
Olivier Deprezd5a54892023-02-02 16:45:59 +010047 if (!test_heap) {
48 /*
49 * TODO: replace with direct use of stdlib allocator so
50 * sanitizers are more effective.
51 */
52 test_heap = std::make_unique<uint8_t[]>(TEST_HEAP_SIZE);
53 mpool_init(&ppool, sizeof(struct mm_page_table));
54 mpool_add_chunk(&ppool, test_heap.get(),
55 TEST_HEAP_SIZE);
56 }
Andrew Scull3c257452019-11-26 13:32:50 +000057 }
58
J-Alvesb37fd082020-10-22 12:29:21 +010059 public:
J-Alvesbeeb6dc2021-12-08 18:21:32 +000060 static bool BootOrderSmallerThan(struct_vm *vm1, struct_vm *vm2)
J-Alvesb37fd082020-10-22 12:29:21 +010061 {
J-Alvesbeeb6dc2021-12-08 18:21:32 +000062 return vm1->boot_order < vm2->boot_order;
J-Alvesb37fd082020-10-22 12:29:21 +010063 }
Andrew Scull3c257452019-11-26 13:32:50 +000064};
65
Olivier Deprezd5a54892023-02-02 16:45:59 +010066std::unique_ptr<uint8_t[]> vm::test_heap;
67
Andrew Scull3c257452019-11-26 13:32:50 +000068/**
69 * If nothing is mapped, unmapping the hypervisor has no effect.
70 */
71TEST_F(vm, vm_unmap_hypervisor_not_mapped)
72{
73 struct_vm *vm;
74 struct vm_locked vm_locked;
75
Raghu Krishnamurthycd1eceb2021-01-04 12:20:48 -080076 EXPECT_TRUE(vm_init_next(1, &ppool, &vm, false));
Andrew Scull3c257452019-11-26 13:32:50 +000077 vm_locked = vm_lock(vm);
Raghu Krishnamurthy0132b512021-02-03 14:13:26 -080078 ASSERT_TRUE(mm_vm_init(&vm->ptable, vm->id, &ppool));
Andrew Scull3c257452019-11-26 13:32:50 +000079 EXPECT_TRUE(vm_unmap_hypervisor(vm_locked, &ppool));
80 EXPECT_THAT(
81 mm_test::get_ptable(vm->ptable),
82 AllOf(SizeIs(4), Each(Each(arch_mm_absent_pte(TOP_LEVEL)))));
83 mm_vm_fini(&vm->ptable, &ppool);
84 vm_unlock(&vm_locked);
85}
86
J-Alvesb37fd082020-10-22 12:29:21 +010087/**
88 * Validate the "boot_list" is created properly, according to vm's "boot_order"
89 * field.
90 */
91TEST_F(vm, vm_boot_order)
92{
93 struct_vm *vm_cur;
94 std::list<struct_vm *> expected_final_order;
95
Olivier Deprezd5a54892023-02-02 16:45:59 +010096 EXPECT_TRUE(vm_get_first_boot() == NULL);
J-Alvesb37fd082020-10-22 12:29:21 +010097
98 /*
99 * Insertion when no call to "vm_update_boot" has been made yet.
100 * The "boot_list" is expected to be empty.
101 */
Raghu Krishnamurthycd1eceb2021-01-04 12:20:48 -0800102 EXPECT_TRUE(vm_init_next(1, &ppool, &vm_cur, false));
J-Alvesbeeb6dc2021-12-08 18:21:32 +0000103 vm_cur->boot_order = 3;
J-Alvesb37fd082020-10-22 12:29:21 +0100104 vm_update_boot(vm_cur);
105 expected_final_order.push_back(vm_cur);
106
107 EXPECT_EQ(vm_get_first_boot()->id, vm_cur->id);
108
109 /* Insertion at the head of the boot list */
Raghu Krishnamurthycd1eceb2021-01-04 12:20:48 -0800110 EXPECT_TRUE(vm_init_next(1, &ppool, &vm_cur, false));
J-Alvesbeeb6dc2021-12-08 18:21:32 +0000111 vm_cur->boot_order = 1;
J-Alvesb37fd082020-10-22 12:29:21 +0100112 vm_update_boot(vm_cur);
113 expected_final_order.push_back(vm_cur);
114
115 EXPECT_EQ(vm_get_first_boot()->id, vm_cur->id);
116
117 /* Insertion of two in the middle of the boot list */
118 for (int i = 0; i < 2; i++) {
Raghu Krishnamurthycd1eceb2021-01-04 12:20:48 -0800119 EXPECT_TRUE(vm_init_next(1, &ppool, &vm_cur, false));
J-Alvesb37fd082020-10-22 12:29:21 +0100120 vm_cur->boot_order = 2;
121 vm_update_boot(vm_cur);
122 expected_final_order.push_back(vm_cur);
123 }
124
125 /*
126 * Insertion in the end of the list.
127 * This tests shares the data with "vm_unmap_hypervisor_not_mapped".
128 * As such, a VM is expected to have been initialized before this
129 * test, with ID 1 and boot_order 0.
130 */
131 vm_cur = vm_find(1);
132 EXPECT_FALSE(vm_cur == NULL);
133 vm_update_boot(vm_cur);
134 expected_final_order.push_back(vm_cur);
135
136 /*
137 * Number of VMs initialized should be the same as in the
138 * "expected_final_order", before the final verification.
139 */
140 EXPECT_EQ(expected_final_order.size(), vm_get_count())
141 << "Something went wrong with the test itself...\n";
142
J-Alvesbeeb6dc2021-12-08 18:21:32 +0000143 /* Sort VMs from lower to higher "boot_order" field.*/
144 expected_final_order.sort(vm::BootOrderSmallerThan);
J-Alvesb37fd082020-10-22 12:29:21 +0100145
146 std::list<struct_vm *>::iterator it;
147 for (it = expected_final_order.begin(), vm_cur = vm_get_first_boot();
148 it != expected_final_order.end() && vm_cur != NULL;
149 it++, vm_cur = vm_cur->next_boot) {
150 EXPECT_EQ((*it)->id, vm_cur->id);
151 }
152}
J-Alves60eaff92021-05-27 14:54:41 +0100153
154/**
155 * Validates updates and check functions for binding notifications to endpoints.
156 */
157TEST_F(vm, vm_notifications_bind_diff_senders)
158{
J-Alvesd3e81622021-10-05 14:55:57 +0100159 struct_vm *current_vm = nullptr;
160 struct vm_locked current_vm_locked;
J-Alves60eaff92021-05-27 14:54:41 +0100161 std::vector<struct_vm *> dummy_senders;
162 ffa_notifications_bitmap_t bitmaps[] = {
163 0x00000000FFFFFFFFU, 0xFFFFFFFF00000000U, 0x0000FFFFFFFF0000U};
164 bool is_from_vm = true;
165
166 /* For the subsequent tests three VMs are used. */
167 CHECK(vm_get_count() >= 3);
168
J-Alvesd3e81622021-10-05 14:55:57 +0100169 current_vm = vm_find_index(0);
J-Alves60eaff92021-05-27 14:54:41 +0100170
171 dummy_senders.push_back(vm_find_index(1));
172 dummy_senders.push_back(vm_find_index(2));
173
J-Alvesd3e81622021-10-05 14:55:57 +0100174 current_vm_locked = vm_lock(current_vm);
J-Alves60eaff92021-05-27 14:54:41 +0100175
176 for (unsigned int i = 0; i < 2; i++) {
177 /* Validate bindings condition after initialization. */
178 EXPECT_TRUE(vm_notifications_validate_binding(
J-Alvesd3e81622021-10-05 14:55:57 +0100179 current_vm_locked, is_from_vm, HF_INVALID_VM_ID,
180 bitmaps[i], false));
J-Alves60eaff92021-05-27 14:54:41 +0100181
182 /*
183 * Validate bind related operations. For this test considering
184 * only global notifications.
185 */
J-Alvesd3e81622021-10-05 14:55:57 +0100186 vm_notifications_update_bindings(current_vm_locked, is_from_vm,
J-Alves60eaff92021-05-27 14:54:41 +0100187 dummy_senders[i]->id,
188 bitmaps[i], false);
189
190 EXPECT_TRUE(vm_notifications_validate_binding(
J-Alvesd3e81622021-10-05 14:55:57 +0100191 current_vm_locked, is_from_vm, dummy_senders[i]->id,
J-Alves60eaff92021-05-27 14:54:41 +0100192 bitmaps[i], false));
193
194 EXPECT_FALSE(vm_notifications_validate_binding(
J-Alvesd3e81622021-10-05 14:55:57 +0100195 current_vm_locked, is_from_vm, dummy_senders[1 - i]->id,
J-Alves60eaff92021-05-27 14:54:41 +0100196 bitmaps[i], false));
197
198 EXPECT_FALSE(vm_notifications_validate_binding(
J-Alvesd3e81622021-10-05 14:55:57 +0100199 current_vm_locked, is_from_vm, dummy_senders[i]->id,
J-Alves60eaff92021-05-27 14:54:41 +0100200 bitmaps[1 - i], false));
201
202 EXPECT_FALSE(vm_notifications_validate_binding(
J-Alvesd3e81622021-10-05 14:55:57 +0100203 current_vm_locked, is_from_vm, dummy_senders[i]->id,
J-Alves60eaff92021-05-27 14:54:41 +0100204 bitmaps[2], false));
205 }
206
207 /** Clean up bind for other tests. */
J-Alvesd3e81622021-10-05 14:55:57 +0100208 vm_notifications_update_bindings(current_vm_locked, is_from_vm, 0,
J-Alves60eaff92021-05-27 14:54:41 +0100209 bitmaps[0], false);
J-Alvesd3e81622021-10-05 14:55:57 +0100210 vm_notifications_update_bindings(current_vm_locked, is_from_vm, 0,
J-Alves60eaff92021-05-27 14:54:41 +0100211 bitmaps[1], false);
212
J-Alvesd3e81622021-10-05 14:55:57 +0100213 vm_unlock(&current_vm_locked);
J-Alves60eaff92021-05-27 14:54:41 +0100214}
215
216/**
217 * Validates updates and check functions for binding notifications, namely the
J-Alves96f6e292021-06-08 17:32:40 +0100218 * configuration of bindings of global and per-vCPU notifications.
J-Alves60eaff92021-05-27 14:54:41 +0100219 */
220TEST_F(vm, vm_notification_bind_per_vcpu_vs_global)
221{
J-Alvesd3e81622021-10-05 14:55:57 +0100222 struct_vm *current_vm;
223 struct vm_locked current_vm_locked;
J-Alves60eaff92021-05-27 14:54:41 +0100224 struct_vm *dummy_sender;
225 ffa_notifications_bitmap_t global = 0x00000000FFFFFFFFU;
226 ffa_notifications_bitmap_t per_vcpu = ~global;
227 bool is_from_vm = true;
228
229 CHECK(vm_get_count() >= 2);
230
J-Alvesd3e81622021-10-05 14:55:57 +0100231 current_vm = vm_find_index(0);
J-Alves60eaff92021-05-27 14:54:41 +0100232
233 dummy_sender = vm_find_index(1);
234
J-Alvesd3e81622021-10-05 14:55:57 +0100235 current_vm_locked = vm_lock(current_vm);
J-Alves60eaff92021-05-27 14:54:41 +0100236
J-Alvesd3e81622021-10-05 14:55:57 +0100237 vm_notifications_update_bindings(current_vm_locked, is_from_vm,
J-Alves60eaff92021-05-27 14:54:41 +0100238 dummy_sender->id, global, false);
J-Alvesd3e81622021-10-05 14:55:57 +0100239 vm_notifications_update_bindings(current_vm_locked, is_from_vm,
J-Alves60eaff92021-05-27 14:54:41 +0100240 dummy_sender->id, per_vcpu, true);
241
242 /* Check validation of global notifications bindings. */
243 EXPECT_TRUE(vm_notifications_validate_binding(
J-Alvesd3e81622021-10-05 14:55:57 +0100244 current_vm_locked, is_from_vm, dummy_sender->id, global,
245 false));
J-Alves60eaff92021-05-27 14:54:41 +0100246
J-Alves96f6e292021-06-08 17:32:40 +0100247 /* Check validation of per-vCPU notifications bindings. */
J-Alves60eaff92021-05-27 14:54:41 +0100248 EXPECT_TRUE(vm_notifications_validate_binding(
J-Alvesd3e81622021-10-05 14:55:57 +0100249 current_vm_locked, is_from_vm, dummy_sender->id, per_vcpu,
250 true));
J-Alves60eaff92021-05-27 14:54:41 +0100251
252 /**
J-Alves96f6e292021-06-08 17:32:40 +0100253 * Check that global notifications are not validated as per-vCPU, and
J-Alves60eaff92021-05-27 14:54:41 +0100254 * vice-versa.
255 */
256 EXPECT_FALSE(vm_notifications_validate_binding(
J-Alvesd3e81622021-10-05 14:55:57 +0100257 current_vm_locked, is_from_vm, dummy_sender->id, global, true));
J-Alves60eaff92021-05-27 14:54:41 +0100258 EXPECT_FALSE(vm_notifications_validate_binding(
J-Alvesd3e81622021-10-05 14:55:57 +0100259 current_vm_locked, is_from_vm, dummy_sender->id, per_vcpu,
J-Alves60eaff92021-05-27 14:54:41 +0100260 false));
J-Alvesd3e81622021-10-05 14:55:57 +0100261 EXPECT_FALSE(vm_notifications_validate_binding(
262 current_vm_locked, is_from_vm, dummy_sender->id,
263 global | per_vcpu, true));
264 EXPECT_FALSE(vm_notifications_validate_binding(
265 current_vm_locked, is_from_vm, dummy_sender->id,
266 global | per_vcpu, false));
J-Alves60eaff92021-05-27 14:54:41 +0100267
268 /** Undo the bindings */
J-Alvesd3e81622021-10-05 14:55:57 +0100269 vm_notifications_update_bindings(current_vm_locked, is_from_vm, 0,
270 global, false);
271 EXPECT_TRUE(vm_notifications_validate_binding(
272 current_vm_locked, is_from_vm, 0, global, false));
J-Alves60eaff92021-05-27 14:54:41 +0100273
J-Alvesd3e81622021-10-05 14:55:57 +0100274 vm_notifications_update_bindings(current_vm_locked, is_from_vm, 0,
275 per_vcpu, false);
276 EXPECT_TRUE(vm_notifications_validate_binding(
277 current_vm_locked, is_from_vm, 0, per_vcpu, false));
J-Alves60eaff92021-05-27 14:54:41 +0100278
J-Alvesd3e81622021-10-05 14:55:57 +0100279 vm_unlock(&current_vm_locked);
J-Alves60eaff92021-05-27 14:54:41 +0100280}
281
J-Alvesce2f8d32021-06-10 18:30:21 +0100282/**
283 * Validates accesses to notifications bitmaps.
284 */
285TEST_F(vm, vm_notifications_set_and_get)
286{
J-Alvesd3e81622021-10-05 14:55:57 +0100287 struct_vm *current_vm;
288 struct vm_locked current_vm_locked;
J-Alvesce2f8d32021-06-10 18:30:21 +0100289 struct_vm *dummy_sender;
290 ffa_notifications_bitmap_t global = 0x00000000FFFFFFFFU;
291 ffa_notifications_bitmap_t per_vcpu = ~global;
292 ffa_notifications_bitmap_t ret;
Raghu Krishnamurthy30aabd62022-09-17 21:41:00 -0700293 const unsigned int vcpu_idx = 0;
J-Alvesce2f8d32021-06-10 18:30:21 +0100294 struct notifications *notifications;
295 const bool is_from_vm = true;
296
297 CHECK(vm_get_count() >= 2);
298
J-Alvesd3e81622021-10-05 14:55:57 +0100299 current_vm = vm_find_index(0);
J-Alvesce2f8d32021-06-10 18:30:21 +0100300 dummy_sender = vm_find_index(1);
301
J-Alvesd3e81622021-10-05 14:55:57 +0100302 notifications = &current_vm->notifications.from_vm;
303 current_vm_locked = vm_lock(current_vm);
J-Alvesce2f8d32021-06-10 18:30:21 +0100304
J-Alvesd3e81622021-10-05 14:55:57 +0100305 vm_notifications_update_bindings(current_vm_locked, is_from_vm,
J-Alvesce2f8d32021-06-10 18:30:21 +0100306 dummy_sender->id, global, false);
J-Alvesd3e81622021-10-05 14:55:57 +0100307 vm_notifications_update_bindings(current_vm_locked, is_from_vm,
J-Alvesce2f8d32021-06-10 18:30:21 +0100308 dummy_sender->id, per_vcpu, true);
309
310 /*
J-Alvesd3e81622021-10-05 14:55:57 +0100311 * Validate get notifications bitmap for global notifications.
J-Alvesce2f8d32021-06-10 18:30:21 +0100312 */
J-Alves5a16c962022-03-25 12:32:51 +0000313 vm_notifications_partition_set_pending(current_vm_locked, is_from_vm,
314 global, 0ull, false);
J-Alvesce2f8d32021-06-10 18:30:21 +0100315
J-Alves5136dda2022-03-25 12:26:38 +0000316 ret = vm_notifications_partition_get_pending(current_vm_locked,
J-Alvesd3e81622021-10-05 14:55:57 +0100317 is_from_vm, 0ull);
J-Alvesce2f8d32021-06-10 18:30:21 +0100318 EXPECT_EQ(ret, global);
J-Alvesd3e81622021-10-05 14:55:57 +0100319 EXPECT_EQ(notifications->global.pending, 0ull);
J-Alvesce2f8d32021-06-10 18:30:21 +0100320
321 /*
J-Alvesd3e81622021-10-05 14:55:57 +0100322 * Validate get notifications bitmap for per-vCPU notifications.
J-Alvesce2f8d32021-06-10 18:30:21 +0100323 */
J-Alves5a16c962022-03-25 12:32:51 +0000324 vm_notifications_partition_set_pending(current_vm_locked, is_from_vm,
325 per_vcpu, vcpu_idx, true);
J-Alvesce2f8d32021-06-10 18:30:21 +0100326
J-Alves5136dda2022-03-25 12:26:38 +0000327 ret = vm_notifications_partition_get_pending(current_vm_locked,
J-Alvesd3e81622021-10-05 14:55:57 +0100328 is_from_vm, vcpu_idx);
J-Alvesce2f8d32021-06-10 18:30:21 +0100329 EXPECT_EQ(ret, per_vcpu);
J-Alvesd3e81622021-10-05 14:55:57 +0100330 EXPECT_EQ(notifications->per_vcpu[vcpu_idx].pending, 0ull);
J-Alvesce2f8d32021-06-10 18:30:21 +0100331
332 /*
J-Alvesd3e81622021-10-05 14:55:57 +0100333 * Validate that getting notifications for a specific vCPU also returns
334 * global notifications.
J-Alvesce2f8d32021-06-10 18:30:21 +0100335 */
J-Alves5a16c962022-03-25 12:32:51 +0000336 vm_notifications_partition_set_pending(current_vm_locked, is_from_vm,
337 per_vcpu, vcpu_idx, true);
338 vm_notifications_partition_set_pending(current_vm_locked, is_from_vm,
339 global, 0ull, false);
J-Alvesce2f8d32021-06-10 18:30:21 +0100340
J-Alves5136dda2022-03-25 12:26:38 +0000341 ret = vm_notifications_partition_get_pending(current_vm_locked,
J-Alvesd3e81622021-10-05 14:55:57 +0100342 is_from_vm, vcpu_idx);
J-Alvesce2f8d32021-06-10 18:30:21 +0100343 EXPECT_EQ(ret, per_vcpu | global);
J-Alvesd3e81622021-10-05 14:55:57 +0100344 EXPECT_EQ(notifications->per_vcpu[vcpu_idx].pending, 0ull);
345 EXPECT_EQ(notifications->global.pending, 0ull);
J-Alvesce2f8d32021-06-10 18:30:21 +0100346
347 /** Undo the binding */
J-Alvesd3e81622021-10-05 14:55:57 +0100348 vm_notifications_update_bindings(current_vm_locked, is_from_vm, 0ull,
349 global, false);
350 vm_notifications_update_bindings(current_vm_locked, is_from_vm, 0ull,
351 per_vcpu, true);
352 vm_unlock(&current_vm_locked);
J-Alvesce2f8d32021-06-10 18:30:21 +0100353}
354
J-Alves96f6e292021-06-08 17:32:40 +0100355/**
356 * Validates simple getting of notifications info for global notifications.
357 */
358TEST_F(vm, vm_notifications_info_get_global)
359{
360 ffa_notifications_bitmap_t to_set = 0xFU;
361 ffa_notifications_bitmap_t got;
362
363 /**
364 * Following set of variables that are also expected to be used when
365 * handling FFA_NOTIFICATION_INFO_GET.
366 */
367 uint16_t ids[FFA_NOTIFICATIONS_INFO_GET_MAX_IDS] = {0};
368 uint32_t lists_sizes[FFA_NOTIFICATIONS_INFO_GET_MAX_IDS] = {0};
369 uint32_t ids_count = 0;
370 uint32_t lists_count = 0;
371 enum notifications_info_get_state current_state = INIT;
372
373 CHECK(vm_get_count() >= 2);
374
375 for (unsigned int i = 0; i < 2; i++) {
376 struct_vm *current_vm = vm_find_index(0);
377 struct vm_locked current_vm_locked = vm_lock(current_vm);
378 struct notifications *notifications =
379 &current_vm->notifications.from_sp;
380 const bool is_from_vm = false;
381
J-Alves5a16c962022-03-25 12:32:51 +0000382 vm_notifications_partition_set_pending(
383 current_vm_locked, is_from_vm, to_set, 0, false);
J-Alves96f6e292021-06-08 17:32:40 +0100384
385 vm_notifications_info_get_pending(
386 current_vm_locked, is_from_vm, ids, &ids_count,
387 lists_sizes, &lists_count,
388 FFA_NOTIFICATIONS_INFO_GET_MAX_IDS, &current_state);
389
390 /*
391 * Here the number of IDs and list count should be the same.
392 * As we are testing with Global notifications, this is
393 * expected.
394 */
395 EXPECT_EQ(ids_count, i + 1);
396 EXPECT_EQ(lists_count, i + 1);
397 EXPECT_EQ(lists_sizes[i], 0);
398 EXPECT_EQ(to_set, notifications->global.info_get_retrieved);
399
400 /* Action must be reset to initial state for each VM. */
401 current_state = INIT;
402
403 /*
404 * Check that getting pending notifications gives the expected
405 * return and cleans the 'pending' and 'info_get_retrieved'
406 * bitmaps.
407 */
J-Alves5136dda2022-03-25 12:26:38 +0000408 got = vm_notifications_partition_get_pending(current_vm_locked,
J-Alves96f6e292021-06-08 17:32:40 +0100409 is_from_vm, 0);
410 EXPECT_EQ(got, to_set);
411
412 EXPECT_EQ(notifications->global.info_get_retrieved, 0U);
413 EXPECT_EQ(notifications->global.pending, 0U);
414
415 vm_unlock(&current_vm_locked);
416 }
417}
418
419/**
420 * Validates simple getting of notifications info for per-vCPU notifications.
421 */
422TEST_F(vm, vm_notifications_info_get_per_vcpu)
423{
424 const ffa_notifications_bitmap_t per_vcpu = 0xFU;
425 ffa_notifications_bitmap_t got;
426
427 /*
428 * Following set of variables that are also expected to be used when
429 * handling ffa_notification_info_get.
430 */
431 uint16_t ids[FFA_NOTIFICATIONS_INFO_GET_MAX_IDS] = {0};
432 uint32_t ids_count = 0;
433 uint32_t lists_sizes[FFA_NOTIFICATIONS_INFO_GET_MAX_IDS] = {0};
434 uint32_t lists_count = 0;
435 enum notifications_info_get_state current_state = INIT;
436
437 CHECK(vm_get_count() >= 2);
438
439 for (unsigned int i = 0; i < 2; i++) {
440 struct_vm *current_vm = vm_find_index(0);
441 struct vm_locked current_vm_locked = vm_lock(current_vm);
442 struct notifications *notifications =
443 &current_vm->notifications.from_sp;
444 const bool is_from_vm = false;
445
J-Alves5a16c962022-03-25 12:32:51 +0000446 vm_notifications_partition_set_pending(
447 current_vm_locked, is_from_vm, per_vcpu, 0, true);
J-Alves96f6e292021-06-08 17:32:40 +0100448
449 vm_notifications_info_get_pending(
450 current_vm_locked, is_from_vm, ids, &ids_count,
451 lists_sizes, &lists_count,
452 FFA_NOTIFICATIONS_INFO_GET_MAX_IDS, &current_state);
453
454 /*
455 * Here the number of IDs and list count should be the same.
456 * As we are testing with Global notifications, this is
457 * expected.
458 */
459 EXPECT_EQ(ids_count, (i + 1) * 2);
460 EXPECT_EQ(lists_count, i + 1);
461 EXPECT_EQ(lists_sizes[i], 1);
462 EXPECT_EQ(per_vcpu,
463 notifications->per_vcpu[0].info_get_retrieved);
464
465 /* Action must be reset to initial state for each VM. */
466 current_state = INIT;
467
468 /*
469 * Check that getting pending notifications gives the expected
470 * return and cleans the 'pending' and 'info_get_retrieved'
471 * bitmaps.
472 */
J-Alves5136dda2022-03-25 12:26:38 +0000473 got = vm_notifications_partition_get_pending(current_vm_locked,
J-Alves96f6e292021-06-08 17:32:40 +0100474 is_from_vm, 0);
475 EXPECT_EQ(got, per_vcpu);
476
477 EXPECT_EQ(notifications->per_vcpu[0].info_get_retrieved, 0U);
478 EXPECT_EQ(notifications->per_vcpu[0].pending, 0U);
479
480 vm_unlock(&current_vm_locked);
481 }
482}
483
484/**
485 * Validate getting of notifications information if all VCPUs have notifications
486 * pending.
487 */
488TEST_F(vm, vm_notifications_info_get_per_vcpu_all_vcpus)
489{
490 struct_vm *current_vm = nullptr;
491 struct vm_locked current_vm_locked;
492 const ffa_vcpu_count_t vcpu_count = MAX_CPUS;
493 ffa_notifications_bitmap_t got;
494 const ffa_notifications_bitmap_t global = 0xF0000;
495
496 /*
497 * Following set of variables that are also expected to be used when
498 * handling ffa_notification_info_get.
499 */
500 struct notifications *notifications;
501 const bool is_from_sp = false;
502 uint16_t ids[FFA_NOTIFICATIONS_INFO_GET_MAX_IDS] = {0};
503 uint32_t ids_count = 0;
504 uint32_t lists_sizes[FFA_NOTIFICATIONS_INFO_GET_MAX_IDS] = {0};
505 uint32_t lists_count = 0;
506 enum notifications_info_get_state current_state = INIT;
507
508 EXPECT_TRUE(vm_init_next(vcpu_count, &ppool, &current_vm, false));
509 current_vm_locked = vm_lock(current_vm);
510 notifications = &current_vm->notifications.from_sp;
511
512 for (unsigned int i = 0; i < vcpu_count; i++) {
J-Alves5a16c962022-03-25 12:32:51 +0000513 vm_notifications_partition_set_pending(
514 current_vm_locked, is_from_sp, FFA_NOTIFICATION_MASK(i),
515 i, true);
J-Alves96f6e292021-06-08 17:32:40 +0100516 }
517
518 /*
519 * Adding a global notification should not change the list of IDs,
520 * because global notifications only require the VM ID to be included in
521 * the list, at least once.
522 */
J-Alves5a16c962022-03-25 12:32:51 +0000523 vm_notifications_partition_set_pending(current_vm_locked, is_from_sp,
524 global, 0, false);
J-Alves96f6e292021-06-08 17:32:40 +0100525
526 vm_notifications_info_get_pending(current_vm_locked, is_from_sp, ids,
527 &ids_count, lists_sizes, &lists_count,
528 FFA_NOTIFICATIONS_INFO_GET_MAX_IDS,
529 &current_state);
530
531 /*
532 * This test has been conceived for the expected MAX_CPUS 4.
533 * All VCPUs have notifications of the same VM, to be broken down in 2
534 * lists with 3 VCPU IDs, and 1 VCPU ID respectively.
535 * The list of IDs should look like: {<vm_id>, 0, 1, 2, <vm_id>, 3}.
536 */
537 CHECK(MAX_CPUS == 4);
538 EXPECT_EQ(ids_count, 6U);
539 EXPECT_EQ(lists_count, 2U);
540 EXPECT_EQ(lists_sizes[0], 3);
541 EXPECT_EQ(lists_sizes[1], 1);
542
543 for (unsigned int i = 0; i < vcpu_count; i++) {
J-Alves5136dda2022-03-25 12:26:38 +0000544 got = vm_notifications_partition_get_pending(current_vm_locked,
J-Alves96f6e292021-06-08 17:32:40 +0100545 is_from_sp, i);
546
547 /*
J-Alves5136dda2022-03-25 12:26:38 +0000548 * The first call to
549 * vm_notifications_partition_get_pending should also
550 * include the global notifications on the return.
J-Alves96f6e292021-06-08 17:32:40 +0100551 */
552 ffa_notifications_bitmap_t to_check =
553 (i != 0) ? FFA_NOTIFICATION_MASK(i)
554 : FFA_NOTIFICATION_MASK(i) | global;
555
556 EXPECT_EQ(got, to_check);
557
558 EXPECT_EQ(notifications->per_vcpu[i].pending, 0);
559 EXPECT_EQ(notifications->per_vcpu[i].info_get_retrieved, 0);
560 }
561
562 vm_unlock(&current_vm_locked);
563}
564
565/**
566 * Validate change of state from 'vm_notifications_info_get_pending', when the
567 * list of IDs is full.
568 */
569TEST_F(vm, vm_notifications_info_get_full_per_vcpu)
570{
571 struct_vm *current_vm = vm_find_index(0);
572 struct vm_locked current_vm_locked = vm_lock(current_vm);
573 struct notifications *notifications =
574 &current_vm->notifications.from_sp;
575 const bool is_from_vm = false;
576 ffa_notifications_bitmap_t got = 0;
577
578 /*
579 * Following set of variables that are also expected to be used when
580 * handling ffa_notification_info_get.
581 * For this 'ids_count' has been initialized such that it indicates
582 * there is no space in the list for a per-vCPU notification (VM ID and
583 * VCPU ID).
584 */
585 uint16_t ids[FFA_NOTIFICATIONS_INFO_GET_MAX_IDS] = {0};
586 uint32_t ids_count = FFA_NOTIFICATIONS_INFO_GET_MAX_IDS - 1;
587 uint32_t lists_sizes[FFA_NOTIFICATIONS_INFO_GET_MAX_IDS] = {0};
588 uint32_t lists_count = 10;
589 enum notifications_info_get_state current_state = INIT;
590 CHECK(vm_get_count() >= 2);
591
J-Alves5a16c962022-03-25 12:32:51 +0000592 vm_notifications_partition_set_pending(current_vm_locked, is_from_vm,
593 FFA_NOTIFICATION_MASK(1), 0,
594 true);
J-Alves96f6e292021-06-08 17:32:40 +0100595
596 /* Call function to get notifications info, with only per-vCPU set. */
597 vm_notifications_info_get_pending(current_vm_locked, is_from_vm, ids,
598 &ids_count, lists_sizes, &lists_count,
599 FFA_NOTIFICATIONS_INFO_GET_MAX_IDS,
600 &current_state);
601
602 /*
603 * Verify that as soon as there isn't space to do the required
J-Alves5136dda2022-03-25 12:26:38 +0000604 * insertion in the list, the
605 * 'vm_notifications_partition_get_pending' returns and changes
606 * list state to FULL. In this case returning, because it would need to
607 * add two IDs (VM ID and VCPU ID).
J-Alves96f6e292021-06-08 17:32:40 +0100608 */
609 EXPECT_EQ(current_state, FULL);
610 EXPECT_EQ(ids_count, FFA_NOTIFICATIONS_INFO_GET_MAX_IDS - 1);
611 EXPECT_EQ(notifications->per_vcpu[0].info_get_retrieved, 0U);
612
613 /*
614 * At this point there is still room for the information of a global
615 * notification (only VM ID to be added). Reset 'current_state'
616 * for the insertion to happen at the last position of the array.
617 */
618 current_state = INIT;
619
620 /* Setting global notification */
J-Alves5a16c962022-03-25 12:32:51 +0000621 vm_notifications_partition_set_pending(current_vm_locked, is_from_vm,
622 FFA_NOTIFICATION_MASK(2), 0,
623 false);
J-Alves96f6e292021-06-08 17:32:40 +0100624
625 vm_notifications_info_get_pending(current_vm_locked, is_from_vm, ids,
626 &ids_count, lists_sizes, &lists_count,
627 FFA_NOTIFICATIONS_INFO_GET_MAX_IDS,
628 &current_state);
629
630 /*
631 * Now List must be full, the set global notification must be part of
632 * 'info_get_retrieved', and the 'current_state' should be set to FULL
633 * due to the pending per-vCPU notification in VCPU 0.
634 */
635 EXPECT_EQ(ids_count, FFA_NOTIFICATIONS_INFO_GET_MAX_IDS);
636 EXPECT_EQ(current_state, FULL);
637 EXPECT_EQ(notifications->global.info_get_retrieved,
638 FFA_NOTIFICATION_MASK(2));
639
J-Alves5136dda2022-03-25 12:26:38 +0000640 got = vm_notifications_partition_get_pending(current_vm_locked,
J-Alves96f6e292021-06-08 17:32:40 +0100641 is_from_vm, 0);
642 EXPECT_EQ(got, FFA_NOTIFICATION_MASK(1) | FFA_NOTIFICATION_MASK(2));
643
644 vm_unlock(&current_vm_locked);
645}
646
647TEST_F(vm, vm_notifications_info_get_full_global)
648{
649 struct_vm *current_vm = vm_find_index(0);
650 struct vm_locked current_vm_locked = vm_lock(current_vm);
651 ffa_notifications_bitmap_t got;
652 struct notifications *notifications;
653 const bool is_from_vm = false;
654 /*
655 * Following set of variables that are also expected to be used when
656 * handling ffa_notification_info_get.
657 * For this 'ids_count' has been initialized such that it indicates
658 * there is no space in the list for a global notification (VM ID only).
659 */
660 uint16_t ids[FFA_NOTIFICATIONS_INFO_GET_MAX_IDS] = {0};
661 uint32_t ids_count = FFA_NOTIFICATIONS_INFO_GET_MAX_IDS;
662 uint32_t lists_sizes[FFA_NOTIFICATIONS_INFO_GET_MAX_IDS] = {0};
663 uint32_t lists_count = 10;
664 enum notifications_info_get_state current_state = INIT;
665
666 CHECK(vm_get_count() >= 1);
667
668 current_vm = vm_find_index(0);
669
670 notifications = &current_vm->notifications.from_sp;
671
672 /* Set global notification. */
J-Alves5a16c962022-03-25 12:32:51 +0000673 vm_notifications_partition_set_pending(current_vm_locked, is_from_vm,
674 FFA_NOTIFICATION_MASK(10), 0,
675 false);
J-Alves96f6e292021-06-08 17:32:40 +0100676
677 /* Get notifications info for the given notifications. */
678 vm_notifications_info_get_pending(current_vm_locked, is_from_vm, ids,
679 &ids_count, lists_sizes, &lists_count,
680 FFA_NOTIFICATIONS_INFO_GET_MAX_IDS,
681 &current_state);
682
683 /* Expect 'info_get_retrieved' bitmap to be 0. */
684 EXPECT_EQ(notifications->global.info_get_retrieved, 0U);
685 EXPECT_EQ(notifications->global.pending, FFA_NOTIFICATION_MASK(10));
686 EXPECT_EQ(ids_count, FFA_NOTIFICATIONS_INFO_GET_MAX_IDS);
687 EXPECT_EQ(current_state, FULL);
688
J-Alves5136dda2022-03-25 12:26:38 +0000689 got = vm_notifications_partition_get_pending(current_vm_locked,
J-Alves96f6e292021-06-08 17:32:40 +0100690 is_from_vm, 0);
J-Alves9f74b932021-10-11 14:20:05 +0100691 EXPECT_EQ(got, FFA_NOTIFICATION_MASK(10));
692
J-Alves96f6e292021-06-08 17:32:40 +0100693 vm_unlock(&current_vm_locked);
694}
695
J-Alvesf31940e2022-03-25 17:24:00 +0000696TEST_F(vm, vm_notifications_info_get_from_framework)
697{
698 struct vm_locked vm_locked = vm_lock(vm_find_index(0));
699 uint16_t ids[FFA_NOTIFICATIONS_INFO_GET_MAX_IDS] = {0};
700 uint32_t ids_count = 0;
701 uint32_t lists_sizes[FFA_NOTIFICATIONS_INFO_GET_MAX_IDS] = {0};
702 uint32_t lists_count = 0;
703
704 vm_notifications_framework_set_pending(vm_locked, 0x1U);
705
706 /* Get notifications info for the given notifications. */
707 vm_notifications_info_get(vm_locked, ids, &ids_count, lists_sizes,
708 &lists_count,
709 FFA_NOTIFICATIONS_INFO_GET_MAX_IDS);
710
711 EXPECT_EQ(ids[0], vm_locked.vm->id);
712 EXPECT_EQ(ids_count, 1);
713 EXPECT_EQ(lists_sizes[0], 0);
714 EXPECT_EQ(lists_count, 1);
715
716 EXPECT_EQ(vm_notifications_framework_get_pending(vm_locked), 0x1U);
717
718 vm_unlock(&vm_locked);
719}
720
Andrew Scull3c257452019-11-26 13:32:50 +0000721} /* namespace */