blob: 4dd8dc5b93ff7578fd5b292cfb74971eafb331be [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}
Andrew Scull3c257452019-11-26 13:32:50 +0000146} /* namespace */