blob: 81110051bb161a23f8ec2ac9dcfe69af5dcfb310 [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;
Olivier Deprez181074b2023-02-02 14:53:23 +010033using struct_vcpu = struct vcpu;
J-Alves96f6e292021-06-08 17:32:40 +010034using struct_vm_locked = struct vm_locked;
Andrew Scull3c257452019-11-26 13:32:50 +000035
Olivier Deprezd5a54892023-02-02 16:45:59 +010036constexpr size_t TEST_HEAP_SIZE = PAGE_SIZE * 64;
Andrew Scull3c257452019-11-26 13:32:50 +000037const int TOP_LEVEL = arch_mm_stage2_max_level();
38
39class vm : public ::testing::Test
40{
Olivier Deprezd5a54892023-02-02 16:45:59 +010041 protected:
42 static std::unique_ptr<uint8_t[]> test_heap;
43
44 struct mpool ppool;
45
Andrew Scull3c257452019-11-26 13:32:50 +000046 void SetUp() override
47 {
Olivier Deprezd5a54892023-02-02 16:45:59 +010048 if (!test_heap) {
49 /*
50 * TODO: replace with direct use of stdlib allocator so
51 * sanitizers are more effective.
52 */
53 test_heap = std::make_unique<uint8_t[]>(TEST_HEAP_SIZE);
54 mpool_init(&ppool, sizeof(struct mm_page_table));
55 mpool_add_chunk(&ppool, test_heap.get(),
56 TEST_HEAP_SIZE);
57 }
Andrew Scull3c257452019-11-26 13:32:50 +000058 }
59
J-Alvesb37fd082020-10-22 12:29:21 +010060 public:
J-Alvesbeeb6dc2021-12-08 18:21:32 +000061 static bool BootOrderSmallerThan(struct_vm *vm1, struct_vm *vm2)
J-Alvesb37fd082020-10-22 12:29:21 +010062 {
J-Alvesbeeb6dc2021-12-08 18:21:32 +000063 return vm1->boot_order < vm2->boot_order;
J-Alvesb37fd082020-10-22 12:29:21 +010064 }
Andrew Scull3c257452019-11-26 13:32:50 +000065};
66
Olivier Deprezd5a54892023-02-02 16:45:59 +010067std::unique_ptr<uint8_t[]> vm::test_heap;
68
Andrew Scull3c257452019-11-26 13:32:50 +000069/**
70 * If nothing is mapped, unmapping the hypervisor has no effect.
71 */
72TEST_F(vm, vm_unmap_hypervisor_not_mapped)
73{
74 struct_vm *vm;
75 struct vm_locked vm_locked;
76
Raghu Krishnamurthycd1eceb2021-01-04 12:20:48 -080077 EXPECT_TRUE(vm_init_next(1, &ppool, &vm, false));
Andrew Scull3c257452019-11-26 13:32:50 +000078 vm_locked = vm_lock(vm);
Raghu Krishnamurthy0132b512021-02-03 14:13:26 -080079 ASSERT_TRUE(mm_vm_init(&vm->ptable, vm->id, &ppool));
Andrew Scull3c257452019-11-26 13:32:50 +000080 EXPECT_TRUE(vm_unmap_hypervisor(vm_locked, &ppool));
81 EXPECT_THAT(
82 mm_test::get_ptable(vm->ptable),
83 AllOf(SizeIs(4), Each(Each(arch_mm_absent_pte(TOP_LEVEL)))));
84 mm_vm_fini(&vm->ptable, &ppool);
85 vm_unlock(&vm_locked);
86}
87
J-Alvesb37fd082020-10-22 12:29:21 +010088/**
89 * Validate the "boot_list" is created properly, according to vm's "boot_order"
90 * field.
91 */
92TEST_F(vm, vm_boot_order)
93{
94 struct_vm *vm_cur;
Olivier Deprez181074b2023-02-02 14:53:23 +010095 struct_vcpu *vcpu;
J-Alvesb37fd082020-10-22 12:29:21 +010096 std::list<struct_vm *> expected_final_order;
97
Olivier Deprez181074b2023-02-02 14:53:23 +010098 EXPECT_TRUE(vcpu_get_boot_vcpu() == NULL);
J-Alvesb37fd082020-10-22 12:29:21 +010099
100 /*
Olivier Deprez181074b2023-02-02 14:53:23 +0100101 * Insertion when no call to "vcpu_update_boot" has been made yet.
J-Alvesb37fd082020-10-22 12:29:21 +0100102 * The "boot_list" is expected to be empty.
103 */
Raghu Krishnamurthycd1eceb2021-01-04 12:20:48 -0800104 EXPECT_TRUE(vm_init_next(1, &ppool, &vm_cur, false));
J-Alvesbeeb6dc2021-12-08 18:21:32 +0000105 vm_cur->boot_order = 3;
Olivier Deprez181074b2023-02-02 14:53:23 +0100106 vcpu = vm_get_vcpu(vm_cur, 0);
107 vcpu_update_boot(vcpu);
J-Alvesb37fd082020-10-22 12:29:21 +0100108 expected_final_order.push_back(vm_cur);
109
Olivier Deprez181074b2023-02-02 14:53:23 +0100110 EXPECT_EQ(vcpu_get_boot_vcpu()->vm->id, vm_cur->id);
J-Alvesb37fd082020-10-22 12:29:21 +0100111
112 /* Insertion at the head of the boot list */
Raghu Krishnamurthycd1eceb2021-01-04 12:20:48 -0800113 EXPECT_TRUE(vm_init_next(1, &ppool, &vm_cur, false));
J-Alvesbeeb6dc2021-12-08 18:21:32 +0000114 vm_cur->boot_order = 1;
Olivier Deprez181074b2023-02-02 14:53:23 +0100115 vcpu = vm_get_vcpu(vm_cur, 0);
116 vcpu_update_boot(vcpu);
J-Alvesb37fd082020-10-22 12:29:21 +0100117 expected_final_order.push_back(vm_cur);
118
Olivier Deprez181074b2023-02-02 14:53:23 +0100119 EXPECT_EQ(vcpu_get_boot_vcpu()->vm->id, vm_cur->id);
J-Alvesb37fd082020-10-22 12:29:21 +0100120
121 /* Insertion of two in the middle of the boot list */
Olivier Deprez181074b2023-02-02 14:53:23 +0100122 for (uint32_t i = 0; i < 2; i++) {
Raghu Krishnamurthycd1eceb2021-01-04 12:20:48 -0800123 EXPECT_TRUE(vm_init_next(1, &ppool, &vm_cur, false));
J-Alvesb37fd082020-10-22 12:29:21 +0100124 vm_cur->boot_order = 2;
Olivier Deprez181074b2023-02-02 14:53:23 +0100125 vcpu = vm_get_vcpu(vm_cur, 0);
126 vcpu_update_boot(vcpu);
J-Alvesb37fd082020-10-22 12:29:21 +0100127 expected_final_order.push_back(vm_cur);
128 }
129
130 /*
131 * Insertion in the end of the list.
132 * This tests shares the data with "vm_unmap_hypervisor_not_mapped".
133 * As such, a VM is expected to have been initialized before this
134 * test, with ID 1 and boot_order 0.
135 */
136 vm_cur = vm_find(1);
137 EXPECT_FALSE(vm_cur == NULL);
Olivier Deprez181074b2023-02-02 14:53:23 +0100138 vcpu = vm_get_vcpu(vm_cur, 0);
139 vcpu_update_boot(vcpu);
J-Alvesb37fd082020-10-22 12:29:21 +0100140 expected_final_order.push_back(vm_cur);
141
142 /*
143 * Number of VMs initialized should be the same as in the
144 * "expected_final_order", before the final verification.
145 */
146 EXPECT_EQ(expected_final_order.size(), vm_get_count())
147 << "Something went wrong with the test itself...\n";
148
J-Alvesbeeb6dc2021-12-08 18:21:32 +0000149 /* Sort VMs from lower to higher "boot_order" field.*/
150 expected_final_order.sort(vm::BootOrderSmallerThan);
J-Alvesb37fd082020-10-22 12:29:21 +0100151
152 std::list<struct_vm *>::iterator it;
Olivier Deprez181074b2023-02-02 14:53:23 +0100153 vcpu = vcpu_get_boot_vcpu();
154 for (it = expected_final_order.begin();
155 it != expected_final_order.end(); it++) {
156 EXPECT_TRUE(vcpu != NULL);
157 EXPECT_EQ((*it)->id, vcpu->vm->id);
158 vcpu = vcpu->next_boot;
J-Alvesb37fd082020-10-22 12:29:21 +0100159 }
160}
J-Alves60eaff92021-05-27 14:54:41 +0100161
162/**
163 * Validates updates and check functions for binding notifications to endpoints.
164 */
165TEST_F(vm, vm_notifications_bind_diff_senders)
166{
J-Alvesd3e81622021-10-05 14:55:57 +0100167 struct_vm *current_vm = nullptr;
168 struct vm_locked current_vm_locked;
J-Alves60eaff92021-05-27 14:54:41 +0100169 std::vector<struct_vm *> dummy_senders;
170 ffa_notifications_bitmap_t bitmaps[] = {
171 0x00000000FFFFFFFFU, 0xFFFFFFFF00000000U, 0x0000FFFFFFFF0000U};
172 bool is_from_vm = true;
173
174 /* For the subsequent tests three VMs are used. */
175 CHECK(vm_get_count() >= 3);
176
J-Alvesd3e81622021-10-05 14:55:57 +0100177 current_vm = vm_find_index(0);
J-Alves60eaff92021-05-27 14:54:41 +0100178
179 dummy_senders.push_back(vm_find_index(1));
180 dummy_senders.push_back(vm_find_index(2));
181
J-Alvesd3e81622021-10-05 14:55:57 +0100182 current_vm_locked = vm_lock(current_vm);
J-Alves60eaff92021-05-27 14:54:41 +0100183
184 for (unsigned int i = 0; i < 2; i++) {
185 /* Validate bindings condition after initialization. */
186 EXPECT_TRUE(vm_notifications_validate_binding(
J-Alvesd3e81622021-10-05 14:55:57 +0100187 current_vm_locked, is_from_vm, HF_INVALID_VM_ID,
188 bitmaps[i], false));
J-Alves60eaff92021-05-27 14:54:41 +0100189
190 /*
191 * Validate bind related operations. For this test considering
192 * only global notifications.
193 */
J-Alvesd3e81622021-10-05 14:55:57 +0100194 vm_notifications_update_bindings(current_vm_locked, is_from_vm,
J-Alves60eaff92021-05-27 14:54:41 +0100195 dummy_senders[i]->id,
196 bitmaps[i], false);
197
198 EXPECT_TRUE(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[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[1 - i]->id,
J-Alves60eaff92021-05-27 14:54:41 +0100204 bitmaps[i], false));
205
206 EXPECT_FALSE(vm_notifications_validate_binding(
J-Alvesd3e81622021-10-05 14:55:57 +0100207 current_vm_locked, is_from_vm, dummy_senders[i]->id,
J-Alves60eaff92021-05-27 14:54:41 +0100208 bitmaps[1 - i], false));
209
210 EXPECT_FALSE(vm_notifications_validate_binding(
J-Alvesd3e81622021-10-05 14:55:57 +0100211 current_vm_locked, is_from_vm, dummy_senders[i]->id,
J-Alves60eaff92021-05-27 14:54:41 +0100212 bitmaps[2], false));
213 }
214
215 /** Clean up bind for other tests. */
J-Alvesd3e81622021-10-05 14:55:57 +0100216 vm_notifications_update_bindings(current_vm_locked, is_from_vm, 0,
J-Alves60eaff92021-05-27 14:54:41 +0100217 bitmaps[0], false);
J-Alvesd3e81622021-10-05 14:55:57 +0100218 vm_notifications_update_bindings(current_vm_locked, is_from_vm, 0,
J-Alves60eaff92021-05-27 14:54:41 +0100219 bitmaps[1], false);
220
J-Alvesd3e81622021-10-05 14:55:57 +0100221 vm_unlock(&current_vm_locked);
J-Alves60eaff92021-05-27 14:54:41 +0100222}
223
224/**
225 * Validates updates and check functions for binding notifications, namely the
J-Alves96f6e292021-06-08 17:32:40 +0100226 * configuration of bindings of global and per-vCPU notifications.
J-Alves60eaff92021-05-27 14:54:41 +0100227 */
228TEST_F(vm, vm_notification_bind_per_vcpu_vs_global)
229{
J-Alvesd3e81622021-10-05 14:55:57 +0100230 struct_vm *current_vm;
231 struct vm_locked current_vm_locked;
J-Alves60eaff92021-05-27 14:54:41 +0100232 struct_vm *dummy_sender;
233 ffa_notifications_bitmap_t global = 0x00000000FFFFFFFFU;
234 ffa_notifications_bitmap_t per_vcpu = ~global;
235 bool is_from_vm = true;
236
237 CHECK(vm_get_count() >= 2);
238
J-Alvesd3e81622021-10-05 14:55:57 +0100239 current_vm = vm_find_index(0);
J-Alves60eaff92021-05-27 14:54:41 +0100240
241 dummy_sender = vm_find_index(1);
242
J-Alvesd3e81622021-10-05 14:55:57 +0100243 current_vm_locked = vm_lock(current_vm);
J-Alves60eaff92021-05-27 14:54:41 +0100244
J-Alvesd3e81622021-10-05 14:55:57 +0100245 vm_notifications_update_bindings(current_vm_locked, is_from_vm,
J-Alves60eaff92021-05-27 14:54:41 +0100246 dummy_sender->id, global, false);
J-Alvesd3e81622021-10-05 14:55:57 +0100247 vm_notifications_update_bindings(current_vm_locked, is_from_vm,
J-Alves60eaff92021-05-27 14:54:41 +0100248 dummy_sender->id, per_vcpu, true);
249
250 /* Check validation of global notifications bindings. */
251 EXPECT_TRUE(vm_notifications_validate_binding(
J-Alvesd3e81622021-10-05 14:55:57 +0100252 current_vm_locked, is_from_vm, dummy_sender->id, global,
253 false));
J-Alves60eaff92021-05-27 14:54:41 +0100254
J-Alves96f6e292021-06-08 17:32:40 +0100255 /* Check validation of per-vCPU notifications bindings. */
J-Alves60eaff92021-05-27 14:54:41 +0100256 EXPECT_TRUE(vm_notifications_validate_binding(
J-Alvesd3e81622021-10-05 14:55:57 +0100257 current_vm_locked, is_from_vm, dummy_sender->id, per_vcpu,
258 true));
J-Alves60eaff92021-05-27 14:54:41 +0100259
260 /**
J-Alves96f6e292021-06-08 17:32:40 +0100261 * Check that global notifications are not validated as per-vCPU, and
J-Alves60eaff92021-05-27 14:54:41 +0100262 * vice-versa.
263 */
264 EXPECT_FALSE(vm_notifications_validate_binding(
J-Alvesd3e81622021-10-05 14:55:57 +0100265 current_vm_locked, is_from_vm, dummy_sender->id, global, true));
J-Alves60eaff92021-05-27 14:54:41 +0100266 EXPECT_FALSE(vm_notifications_validate_binding(
J-Alvesd3e81622021-10-05 14:55:57 +0100267 current_vm_locked, is_from_vm, dummy_sender->id, per_vcpu,
J-Alves60eaff92021-05-27 14:54:41 +0100268 false));
J-Alvesd3e81622021-10-05 14:55:57 +0100269 EXPECT_FALSE(vm_notifications_validate_binding(
270 current_vm_locked, is_from_vm, dummy_sender->id,
271 global | per_vcpu, true));
272 EXPECT_FALSE(vm_notifications_validate_binding(
273 current_vm_locked, is_from_vm, dummy_sender->id,
274 global | per_vcpu, false));
J-Alves60eaff92021-05-27 14:54:41 +0100275
276 /** Undo the bindings */
J-Alvesd3e81622021-10-05 14:55:57 +0100277 vm_notifications_update_bindings(current_vm_locked, is_from_vm, 0,
278 global, false);
279 EXPECT_TRUE(vm_notifications_validate_binding(
280 current_vm_locked, is_from_vm, 0, global, false));
J-Alves60eaff92021-05-27 14:54:41 +0100281
J-Alvesd3e81622021-10-05 14:55:57 +0100282 vm_notifications_update_bindings(current_vm_locked, is_from_vm, 0,
283 per_vcpu, false);
284 EXPECT_TRUE(vm_notifications_validate_binding(
285 current_vm_locked, is_from_vm, 0, per_vcpu, false));
J-Alves60eaff92021-05-27 14:54:41 +0100286
J-Alvesd3e81622021-10-05 14:55:57 +0100287 vm_unlock(&current_vm_locked);
J-Alves60eaff92021-05-27 14:54:41 +0100288}
289
J-Alvesce2f8d32021-06-10 18:30:21 +0100290/**
291 * Validates accesses to notifications bitmaps.
292 */
293TEST_F(vm, vm_notifications_set_and_get)
294{
J-Alvesd3e81622021-10-05 14:55:57 +0100295 struct_vm *current_vm;
296 struct vm_locked current_vm_locked;
J-Alvesce2f8d32021-06-10 18:30:21 +0100297 struct_vm *dummy_sender;
298 ffa_notifications_bitmap_t global = 0x00000000FFFFFFFFU;
299 ffa_notifications_bitmap_t per_vcpu = ~global;
300 ffa_notifications_bitmap_t ret;
Raghu Krishnamurthy30aabd62022-09-17 21:41:00 -0700301 const unsigned int vcpu_idx = 0;
J-Alvesce2f8d32021-06-10 18:30:21 +0100302 struct notifications *notifications;
303 const bool is_from_vm = true;
304
305 CHECK(vm_get_count() >= 2);
306
J-Alvesd3e81622021-10-05 14:55:57 +0100307 current_vm = vm_find_index(0);
J-Alvesce2f8d32021-06-10 18:30:21 +0100308 dummy_sender = vm_find_index(1);
309
J-Alvesd3e81622021-10-05 14:55:57 +0100310 notifications = &current_vm->notifications.from_vm;
311 current_vm_locked = vm_lock(current_vm);
J-Alvesce2f8d32021-06-10 18:30:21 +0100312
J-Alvesd3e81622021-10-05 14:55:57 +0100313 vm_notifications_update_bindings(current_vm_locked, is_from_vm,
J-Alvesce2f8d32021-06-10 18:30:21 +0100314 dummy_sender->id, global, false);
J-Alvesd3e81622021-10-05 14:55:57 +0100315 vm_notifications_update_bindings(current_vm_locked, is_from_vm,
J-Alvesce2f8d32021-06-10 18:30:21 +0100316 dummy_sender->id, per_vcpu, true);
317
318 /*
J-Alvesd3e81622021-10-05 14:55:57 +0100319 * Validate get notifications bitmap for global notifications.
J-Alvesce2f8d32021-06-10 18:30:21 +0100320 */
J-Alves5a16c962022-03-25 12:32:51 +0000321 vm_notifications_partition_set_pending(current_vm_locked, is_from_vm,
322 global, 0ull, false);
J-Alvesce2f8d32021-06-10 18:30:21 +0100323
J-Alves5136dda2022-03-25 12:26:38 +0000324 ret = vm_notifications_partition_get_pending(current_vm_locked,
J-Alvesd3e81622021-10-05 14:55:57 +0100325 is_from_vm, 0ull);
J-Alvesce2f8d32021-06-10 18:30:21 +0100326 EXPECT_EQ(ret, global);
J-Alvesd3e81622021-10-05 14:55:57 +0100327 EXPECT_EQ(notifications->global.pending, 0ull);
J-Alvesce2f8d32021-06-10 18:30:21 +0100328
329 /*
J-Alvesd3e81622021-10-05 14:55:57 +0100330 * Validate get notifications bitmap for per-vCPU notifications.
J-Alvesce2f8d32021-06-10 18:30:21 +0100331 */
J-Alves5a16c962022-03-25 12:32:51 +0000332 vm_notifications_partition_set_pending(current_vm_locked, is_from_vm,
333 per_vcpu, vcpu_idx, true);
J-Alvesce2f8d32021-06-10 18:30:21 +0100334
J-Alves5136dda2022-03-25 12:26:38 +0000335 ret = vm_notifications_partition_get_pending(current_vm_locked,
J-Alvesd3e81622021-10-05 14:55:57 +0100336 is_from_vm, vcpu_idx);
J-Alvesce2f8d32021-06-10 18:30:21 +0100337 EXPECT_EQ(ret, per_vcpu);
J-Alvesd3e81622021-10-05 14:55:57 +0100338 EXPECT_EQ(notifications->per_vcpu[vcpu_idx].pending, 0ull);
J-Alvesce2f8d32021-06-10 18:30:21 +0100339
340 /*
J-Alvesd3e81622021-10-05 14:55:57 +0100341 * Validate that getting notifications for a specific vCPU also returns
342 * global notifications.
J-Alvesce2f8d32021-06-10 18:30:21 +0100343 */
J-Alves5a16c962022-03-25 12:32:51 +0000344 vm_notifications_partition_set_pending(current_vm_locked, is_from_vm,
345 per_vcpu, vcpu_idx, true);
346 vm_notifications_partition_set_pending(current_vm_locked, is_from_vm,
347 global, 0ull, false);
J-Alvesce2f8d32021-06-10 18:30:21 +0100348
J-Alves5136dda2022-03-25 12:26:38 +0000349 ret = vm_notifications_partition_get_pending(current_vm_locked,
J-Alvesd3e81622021-10-05 14:55:57 +0100350 is_from_vm, vcpu_idx);
J-Alvesce2f8d32021-06-10 18:30:21 +0100351 EXPECT_EQ(ret, per_vcpu | global);
J-Alvesd3e81622021-10-05 14:55:57 +0100352 EXPECT_EQ(notifications->per_vcpu[vcpu_idx].pending, 0ull);
353 EXPECT_EQ(notifications->global.pending, 0ull);
J-Alvesce2f8d32021-06-10 18:30:21 +0100354
355 /** Undo the binding */
J-Alvesd3e81622021-10-05 14:55:57 +0100356 vm_notifications_update_bindings(current_vm_locked, is_from_vm, 0ull,
357 global, false);
358 vm_notifications_update_bindings(current_vm_locked, is_from_vm, 0ull,
359 per_vcpu, true);
360 vm_unlock(&current_vm_locked);
J-Alvesce2f8d32021-06-10 18:30:21 +0100361}
362
J-Alves96f6e292021-06-08 17:32:40 +0100363/**
364 * Validates simple getting of notifications info for global notifications.
365 */
366TEST_F(vm, vm_notifications_info_get_global)
367{
368 ffa_notifications_bitmap_t to_set = 0xFU;
369 ffa_notifications_bitmap_t got;
370
371 /**
372 * Following set of variables that are also expected to be used when
373 * handling FFA_NOTIFICATION_INFO_GET.
374 */
375 uint16_t ids[FFA_NOTIFICATIONS_INFO_GET_MAX_IDS] = {0};
376 uint32_t lists_sizes[FFA_NOTIFICATIONS_INFO_GET_MAX_IDS] = {0};
377 uint32_t ids_count = 0;
378 uint32_t lists_count = 0;
379 enum notifications_info_get_state current_state = INIT;
380
381 CHECK(vm_get_count() >= 2);
382
383 for (unsigned int i = 0; i < 2; i++) {
384 struct_vm *current_vm = vm_find_index(0);
385 struct vm_locked current_vm_locked = vm_lock(current_vm);
386 struct notifications *notifications =
387 &current_vm->notifications.from_sp;
388 const bool is_from_vm = false;
389
J-Alves5a16c962022-03-25 12:32:51 +0000390 vm_notifications_partition_set_pending(
391 current_vm_locked, is_from_vm, to_set, 0, false);
J-Alves96f6e292021-06-08 17:32:40 +0100392
393 vm_notifications_info_get_pending(
394 current_vm_locked, is_from_vm, ids, &ids_count,
395 lists_sizes, &lists_count,
396 FFA_NOTIFICATIONS_INFO_GET_MAX_IDS, &current_state);
397
398 /*
399 * Here the number of IDs and list count should be the same.
400 * As we are testing with Global notifications, this is
401 * expected.
402 */
403 EXPECT_EQ(ids_count, i + 1);
404 EXPECT_EQ(lists_count, i + 1);
405 EXPECT_EQ(lists_sizes[i], 0);
406 EXPECT_EQ(to_set, notifications->global.info_get_retrieved);
407
408 /* Action must be reset to initial state for each VM. */
409 current_state = INIT;
410
411 /*
412 * Check that getting pending notifications gives the expected
413 * return and cleans the 'pending' and 'info_get_retrieved'
414 * bitmaps.
415 */
J-Alves5136dda2022-03-25 12:26:38 +0000416 got = vm_notifications_partition_get_pending(current_vm_locked,
J-Alves96f6e292021-06-08 17:32:40 +0100417 is_from_vm, 0);
418 EXPECT_EQ(got, to_set);
419
420 EXPECT_EQ(notifications->global.info_get_retrieved, 0U);
421 EXPECT_EQ(notifications->global.pending, 0U);
422
423 vm_unlock(&current_vm_locked);
424 }
425}
426
427/**
428 * Validates simple getting of notifications info for per-vCPU notifications.
429 */
430TEST_F(vm, vm_notifications_info_get_per_vcpu)
431{
432 const ffa_notifications_bitmap_t per_vcpu = 0xFU;
433 ffa_notifications_bitmap_t got;
434
435 /*
436 * Following set of variables that are also expected to be used when
437 * handling ffa_notification_info_get.
438 */
439 uint16_t ids[FFA_NOTIFICATIONS_INFO_GET_MAX_IDS] = {0};
440 uint32_t ids_count = 0;
441 uint32_t lists_sizes[FFA_NOTIFICATIONS_INFO_GET_MAX_IDS] = {0};
442 uint32_t lists_count = 0;
443 enum notifications_info_get_state current_state = INIT;
444
445 CHECK(vm_get_count() >= 2);
446
447 for (unsigned int i = 0; i < 2; i++) {
448 struct_vm *current_vm = vm_find_index(0);
449 struct vm_locked current_vm_locked = vm_lock(current_vm);
450 struct notifications *notifications =
451 &current_vm->notifications.from_sp;
452 const bool is_from_vm = false;
453
J-Alves5a16c962022-03-25 12:32:51 +0000454 vm_notifications_partition_set_pending(
455 current_vm_locked, is_from_vm, per_vcpu, 0, true);
J-Alves96f6e292021-06-08 17:32:40 +0100456
457 vm_notifications_info_get_pending(
458 current_vm_locked, is_from_vm, ids, &ids_count,
459 lists_sizes, &lists_count,
460 FFA_NOTIFICATIONS_INFO_GET_MAX_IDS, &current_state);
461
462 /*
463 * Here the number of IDs and list count should be the same.
464 * As we are testing with Global notifications, this is
465 * expected.
466 */
467 EXPECT_EQ(ids_count, (i + 1) * 2);
468 EXPECT_EQ(lists_count, i + 1);
469 EXPECT_EQ(lists_sizes[i], 1);
470 EXPECT_EQ(per_vcpu,
471 notifications->per_vcpu[0].info_get_retrieved);
472
473 /* Action must be reset to initial state for each VM. */
474 current_state = INIT;
475
476 /*
477 * Check that getting pending notifications gives the expected
478 * return and cleans the 'pending' and 'info_get_retrieved'
479 * bitmaps.
480 */
J-Alves5136dda2022-03-25 12:26:38 +0000481 got = vm_notifications_partition_get_pending(current_vm_locked,
J-Alves96f6e292021-06-08 17:32:40 +0100482 is_from_vm, 0);
483 EXPECT_EQ(got, per_vcpu);
484
485 EXPECT_EQ(notifications->per_vcpu[0].info_get_retrieved, 0U);
486 EXPECT_EQ(notifications->per_vcpu[0].pending, 0U);
487
488 vm_unlock(&current_vm_locked);
489 }
490}
491
492/**
493 * Validate getting of notifications information if all VCPUs have notifications
494 * pending.
495 */
496TEST_F(vm, vm_notifications_info_get_per_vcpu_all_vcpus)
497{
498 struct_vm *current_vm = nullptr;
499 struct vm_locked current_vm_locked;
500 const ffa_vcpu_count_t vcpu_count = MAX_CPUS;
501 ffa_notifications_bitmap_t got;
502 const ffa_notifications_bitmap_t global = 0xF0000;
503
504 /*
505 * Following set of variables that are also expected to be used when
506 * handling ffa_notification_info_get.
507 */
508 struct notifications *notifications;
509 const bool is_from_sp = false;
510 uint16_t ids[FFA_NOTIFICATIONS_INFO_GET_MAX_IDS] = {0};
511 uint32_t ids_count = 0;
512 uint32_t lists_sizes[FFA_NOTIFICATIONS_INFO_GET_MAX_IDS] = {0};
513 uint32_t lists_count = 0;
514 enum notifications_info_get_state current_state = INIT;
515
516 EXPECT_TRUE(vm_init_next(vcpu_count, &ppool, &current_vm, false));
517 current_vm_locked = vm_lock(current_vm);
518 notifications = &current_vm->notifications.from_sp;
519
520 for (unsigned int i = 0; i < vcpu_count; i++) {
J-Alves5a16c962022-03-25 12:32:51 +0000521 vm_notifications_partition_set_pending(
522 current_vm_locked, is_from_sp, FFA_NOTIFICATION_MASK(i),
523 i, true);
J-Alves96f6e292021-06-08 17:32:40 +0100524 }
525
526 /*
527 * Adding a global notification should not change the list of IDs,
528 * because global notifications only require the VM ID to be included in
529 * the list, at least once.
530 */
J-Alves5a16c962022-03-25 12:32:51 +0000531 vm_notifications_partition_set_pending(current_vm_locked, is_from_sp,
532 global, 0, false);
J-Alves96f6e292021-06-08 17:32:40 +0100533
534 vm_notifications_info_get_pending(current_vm_locked, is_from_sp, ids,
535 &ids_count, lists_sizes, &lists_count,
536 FFA_NOTIFICATIONS_INFO_GET_MAX_IDS,
537 &current_state);
538
539 /*
540 * This test has been conceived for the expected MAX_CPUS 4.
541 * All VCPUs have notifications of the same VM, to be broken down in 2
542 * lists with 3 VCPU IDs, and 1 VCPU ID respectively.
543 * The list of IDs should look like: {<vm_id>, 0, 1, 2, <vm_id>, 3}.
544 */
545 CHECK(MAX_CPUS == 4);
546 EXPECT_EQ(ids_count, 6U);
547 EXPECT_EQ(lists_count, 2U);
548 EXPECT_EQ(lists_sizes[0], 3);
549 EXPECT_EQ(lists_sizes[1], 1);
550
551 for (unsigned int i = 0; i < vcpu_count; i++) {
J-Alves5136dda2022-03-25 12:26:38 +0000552 got = vm_notifications_partition_get_pending(current_vm_locked,
J-Alves96f6e292021-06-08 17:32:40 +0100553 is_from_sp, i);
554
555 /*
J-Alves5136dda2022-03-25 12:26:38 +0000556 * The first call to
557 * vm_notifications_partition_get_pending should also
558 * include the global notifications on the return.
J-Alves96f6e292021-06-08 17:32:40 +0100559 */
560 ffa_notifications_bitmap_t to_check =
561 (i != 0) ? FFA_NOTIFICATION_MASK(i)
562 : FFA_NOTIFICATION_MASK(i) | global;
563
564 EXPECT_EQ(got, to_check);
565
566 EXPECT_EQ(notifications->per_vcpu[i].pending, 0);
567 EXPECT_EQ(notifications->per_vcpu[i].info_get_retrieved, 0);
568 }
569
570 vm_unlock(&current_vm_locked);
571}
572
573/**
574 * Validate change of state from 'vm_notifications_info_get_pending', when the
575 * list of IDs is full.
576 */
577TEST_F(vm, vm_notifications_info_get_full_per_vcpu)
578{
579 struct_vm *current_vm = vm_find_index(0);
580 struct vm_locked current_vm_locked = vm_lock(current_vm);
581 struct notifications *notifications =
582 &current_vm->notifications.from_sp;
583 const bool is_from_vm = false;
584 ffa_notifications_bitmap_t got = 0;
585
586 /*
587 * Following set of variables that are also expected to be used when
588 * handling ffa_notification_info_get.
589 * For this 'ids_count' has been initialized such that it indicates
590 * there is no space in the list for a per-vCPU notification (VM ID and
591 * VCPU ID).
592 */
593 uint16_t ids[FFA_NOTIFICATIONS_INFO_GET_MAX_IDS] = {0};
594 uint32_t ids_count = FFA_NOTIFICATIONS_INFO_GET_MAX_IDS - 1;
595 uint32_t lists_sizes[FFA_NOTIFICATIONS_INFO_GET_MAX_IDS] = {0};
596 uint32_t lists_count = 10;
597 enum notifications_info_get_state current_state = INIT;
598 CHECK(vm_get_count() >= 2);
599
J-Alves5a16c962022-03-25 12:32:51 +0000600 vm_notifications_partition_set_pending(current_vm_locked, is_from_vm,
601 FFA_NOTIFICATION_MASK(1), 0,
602 true);
J-Alves96f6e292021-06-08 17:32:40 +0100603
604 /* Call function to get notifications info, with only per-vCPU set. */
605 vm_notifications_info_get_pending(current_vm_locked, is_from_vm, ids,
606 &ids_count, lists_sizes, &lists_count,
607 FFA_NOTIFICATIONS_INFO_GET_MAX_IDS,
608 &current_state);
609
610 /*
611 * Verify that as soon as there isn't space to do the required
J-Alves5136dda2022-03-25 12:26:38 +0000612 * insertion in the list, the
613 * 'vm_notifications_partition_get_pending' returns and changes
614 * list state to FULL. In this case returning, because it would need to
615 * add two IDs (VM ID and VCPU ID).
J-Alves96f6e292021-06-08 17:32:40 +0100616 */
617 EXPECT_EQ(current_state, FULL);
618 EXPECT_EQ(ids_count, FFA_NOTIFICATIONS_INFO_GET_MAX_IDS - 1);
619 EXPECT_EQ(notifications->per_vcpu[0].info_get_retrieved, 0U);
620
621 /*
622 * At this point there is still room for the information of a global
623 * notification (only VM ID to be added). Reset 'current_state'
624 * for the insertion to happen at the last position of the array.
625 */
626 current_state = INIT;
627
628 /* Setting global notification */
J-Alves5a16c962022-03-25 12:32:51 +0000629 vm_notifications_partition_set_pending(current_vm_locked, is_from_vm,
630 FFA_NOTIFICATION_MASK(2), 0,
631 false);
J-Alves96f6e292021-06-08 17:32:40 +0100632
633 vm_notifications_info_get_pending(current_vm_locked, is_from_vm, ids,
634 &ids_count, lists_sizes, &lists_count,
635 FFA_NOTIFICATIONS_INFO_GET_MAX_IDS,
636 &current_state);
637
638 /*
639 * Now List must be full, the set global notification must be part of
640 * 'info_get_retrieved', and the 'current_state' should be set to FULL
641 * due to the pending per-vCPU notification in VCPU 0.
642 */
643 EXPECT_EQ(ids_count, FFA_NOTIFICATIONS_INFO_GET_MAX_IDS);
644 EXPECT_EQ(current_state, FULL);
645 EXPECT_EQ(notifications->global.info_get_retrieved,
646 FFA_NOTIFICATION_MASK(2));
647
J-Alves5136dda2022-03-25 12:26:38 +0000648 got = vm_notifications_partition_get_pending(current_vm_locked,
J-Alves96f6e292021-06-08 17:32:40 +0100649 is_from_vm, 0);
650 EXPECT_EQ(got, FFA_NOTIFICATION_MASK(1) | FFA_NOTIFICATION_MASK(2));
651
652 vm_unlock(&current_vm_locked);
653}
654
655TEST_F(vm, vm_notifications_info_get_full_global)
656{
657 struct_vm *current_vm = vm_find_index(0);
658 struct vm_locked current_vm_locked = vm_lock(current_vm);
659 ffa_notifications_bitmap_t got;
660 struct notifications *notifications;
661 const bool is_from_vm = false;
662 /*
663 * Following set of variables that are also expected to be used when
664 * handling ffa_notification_info_get.
665 * For this 'ids_count' has been initialized such that it indicates
666 * there is no space in the list for a global notification (VM ID only).
667 */
668 uint16_t ids[FFA_NOTIFICATIONS_INFO_GET_MAX_IDS] = {0};
669 uint32_t ids_count = FFA_NOTIFICATIONS_INFO_GET_MAX_IDS;
670 uint32_t lists_sizes[FFA_NOTIFICATIONS_INFO_GET_MAX_IDS] = {0};
671 uint32_t lists_count = 10;
672 enum notifications_info_get_state current_state = INIT;
673
674 CHECK(vm_get_count() >= 1);
675
676 current_vm = vm_find_index(0);
677
678 notifications = &current_vm->notifications.from_sp;
679
680 /* Set global notification. */
J-Alves5a16c962022-03-25 12:32:51 +0000681 vm_notifications_partition_set_pending(current_vm_locked, is_from_vm,
682 FFA_NOTIFICATION_MASK(10), 0,
683 false);
J-Alves96f6e292021-06-08 17:32:40 +0100684
685 /* Get notifications info for the given notifications. */
686 vm_notifications_info_get_pending(current_vm_locked, is_from_vm, ids,
687 &ids_count, lists_sizes, &lists_count,
688 FFA_NOTIFICATIONS_INFO_GET_MAX_IDS,
689 &current_state);
690
691 /* Expect 'info_get_retrieved' bitmap to be 0. */
692 EXPECT_EQ(notifications->global.info_get_retrieved, 0U);
693 EXPECT_EQ(notifications->global.pending, FFA_NOTIFICATION_MASK(10));
694 EXPECT_EQ(ids_count, FFA_NOTIFICATIONS_INFO_GET_MAX_IDS);
695 EXPECT_EQ(current_state, FULL);
696
J-Alves5136dda2022-03-25 12:26:38 +0000697 got = vm_notifications_partition_get_pending(current_vm_locked,
J-Alves96f6e292021-06-08 17:32:40 +0100698 is_from_vm, 0);
J-Alves9f74b932021-10-11 14:20:05 +0100699 EXPECT_EQ(got, FFA_NOTIFICATION_MASK(10));
700
J-Alves96f6e292021-06-08 17:32:40 +0100701 vm_unlock(&current_vm_locked);
702}
703
J-Alvesf31940e2022-03-25 17:24:00 +0000704TEST_F(vm, vm_notifications_info_get_from_framework)
705{
706 struct vm_locked vm_locked = vm_lock(vm_find_index(0));
707 uint16_t ids[FFA_NOTIFICATIONS_INFO_GET_MAX_IDS] = {0};
708 uint32_t ids_count = 0;
709 uint32_t lists_sizes[FFA_NOTIFICATIONS_INFO_GET_MAX_IDS] = {0};
710 uint32_t lists_count = 0;
711
712 vm_notifications_framework_set_pending(vm_locked, 0x1U);
713
714 /* Get notifications info for the given notifications. */
715 vm_notifications_info_get(vm_locked, ids, &ids_count, lists_sizes,
716 &lists_count,
717 FFA_NOTIFICATIONS_INFO_GET_MAX_IDS);
718
719 EXPECT_EQ(ids[0], vm_locked.vm->id);
720 EXPECT_EQ(ids_count, 1);
721 EXPECT_EQ(lists_sizes[0], 0);
722 EXPECT_EQ(lists_count, 1);
723
724 EXPECT_EQ(vm_notifications_framework_get_pending(vm_locked), 0x1U);
725
726 vm_unlock(&vm_locked);
727}
728
Andrew Scull3c257452019-11-26 13:32:50 +0000729} /* namespace */