FF-A: Booting SPs according to 'boot-order'

Secure Hafnium boots partitions according to boot-order in the manifest.
In this patch:
- Added manifest parsing of "boot-order", and populated VM structure
with it;
- Added the field "next_boot" to the VM structure, in order to create a
boot list that is sorted by the "boot-order";
- The root of the list points to the highest priority VM;
- Booting consists on traversing the list upon use of MSG_WAIT
interface from the highest priority VMs;
- After traversing the whole boot list, returns execution to SPMD;
- "manifest_Test.cc" updated to include "boot-order" field in
tests to the partition manifest;
- "vm_test.cc" updated to include unit test for the main logic of this
patch.

Change-Id: I43adf90447eed3bc24c8eb2ccb8eb979b471f3c3
Signed-off-by: J-Alves <Joao.Alves@arm.com>
diff --git a/src/vm_test.cc b/src/vm_test.cc
index 6fb2bce..4a0c119 100644
--- a/src/vm_test.cc
+++ b/src/vm_test.cc
@@ -13,6 +13,7 @@
 #include "hf/vm.h"
 }
 
+#include <list>
 #include <memory>
 #include <span>
 #include <vector>
@@ -29,7 +30,7 @@
 
 using struct_vm = struct vm;
 
-constexpr size_t TEST_HEAP_SIZE = PAGE_SIZE * 16;
+constexpr size_t TEST_HEAP_SIZE = PAGE_SIZE * 32;
 const int TOP_LEVEL = arch_mm_stage2_max_level();
 
 class vm : public ::testing::Test
@@ -49,6 +50,12 @@
 
        protected:
 	struct mpool ppool;
+
+       public:
+	static bool BootOrderBiggerThan(struct_vm *vm1, struct_vm *vm2)
+	{
+		return vm1->boot_order > vm2->boot_order;
+	}
 };
 
 /**
@@ -70,4 +77,70 @@
 	vm_unlock(&vm_locked);
 }
 
+/**
+ * Validate the "boot_list" is created properly, according to vm's "boot_order"
+ * field.
+ */
+TEST_F(vm, vm_boot_order)
+{
+	struct_vm *vm_cur;
+	std::list<struct_vm *> expected_final_order;
+
+	EXPECT_FALSE(vm_get_first_boot());
+
+	/*
+	 * Insertion when no call to "vm_update_boot" has been made yet.
+	 * The "boot_list" is expected to be empty.
+	 */
+	EXPECT_TRUE(vm_init_next(1, &ppool, &vm_cur));
+	vm_cur->boot_order = 1;
+	vm_update_boot(vm_cur);
+	expected_final_order.push_back(vm_cur);
+
+	EXPECT_EQ(vm_get_first_boot()->id, vm_cur->id);
+
+	/* Insertion at the head of the boot list */
+	EXPECT_TRUE(vm_init_next(1, &ppool, &vm_cur));
+	vm_cur->boot_order = 3;
+	vm_update_boot(vm_cur);
+	expected_final_order.push_back(vm_cur);
+
+	EXPECT_EQ(vm_get_first_boot()->id, vm_cur->id);
+
+	/* Insertion of two in the middle of the boot list */
+	for (int i = 0; i < 2; i++) {
+		EXPECT_TRUE(vm_init_next(1, &ppool, &vm_cur));
+		vm_cur->boot_order = 2;
+		vm_update_boot(vm_cur);
+		expected_final_order.push_back(vm_cur);
+	}
+
+	/*
+	 * Insertion in the end of the list.
+	 * This tests shares the data with "vm_unmap_hypervisor_not_mapped".
+	 * As such, a VM is expected to have been initialized before this
+	 * test, with ID 1 and boot_order 0.
+	 */
+	vm_cur = vm_find(1);
+	EXPECT_FALSE(vm_cur == NULL);
+	vm_update_boot(vm_cur);
+	expected_final_order.push_back(vm_cur);
+
+	/*
+	 * Number of VMs initialized should be the same as in the
+	 * "expected_final_order", before the final verification.
+	 */
+	EXPECT_EQ(expected_final_order.size(), vm_get_count())
+		<< "Something went wrong with the test itself...\n";
+
+	/* Sort "expected_final_order" by "boot_order" field */
+	expected_final_order.sort(vm::BootOrderBiggerThan);
+
+	std::list<struct_vm *>::iterator it;
+	for (it = expected_final_order.begin(), vm_cur = vm_get_first_boot();
+	     it != expected_final_order.end() && vm_cur != NULL;
+	     it++, vm_cur = vm_cur->next_boot) {
+		EXPECT_EQ((*it)->id, vm_cur->id);
+	}
+}
 } /* namespace */