Add special dummy VM for TrustZone.

Bug: 132429380
Change-Id: If6d7ecf674d2c3c1e8c26fd8c68fa89f362f3a10
diff --git a/inc/hf/vm.h b/inc/hf/vm.h
index e421a3d..0d7735e 100644
--- a/inc/hf/vm.h
+++ b/inc/hf/vm.h
@@ -142,8 +142,10 @@
 	struct vm_locked vm2;
 };
 
-bool vm_init(spci_vcpu_count_t vcpu_count, struct mpool *ppool,
-	     struct vm **new_vm);
+struct vm *vm_init(spci_vm_id_t id, spci_vcpu_count_t vcpu_count,
+		   struct mpool *ppool);
+bool vm_init_next(spci_vcpu_count_t vcpu_count, struct mpool *ppool,
+		  struct vm **new_vm);
 spci_vm_count_t vm_get_count(void);
 struct vm *vm_find(spci_vm_id_t id);
 struct vm_locked vm_lock(struct vm *vm);
diff --git a/inc/vmapi/hf/types.h b/inc/vmapi/hf/types.h
index 1f0d5d4..dc9f7a1 100644
--- a/inc/vmapi/hf/types.h
+++ b/inc/vmapi/hf/types.h
@@ -50,6 +50,12 @@
 #define HF_PRIMARY_VM_INDEX 0
 #define HF_PRIMARY_VM_ID (HF_VM_ID_OFFSET + HF_PRIMARY_VM_INDEX)
 
+/**
+ * The special VM ID reserved for the OS running in the trusted execution
+ * environment, e.g. secure EL1 on AArch64.
+ */
+#define HF_TEE_VM_ID 0x8000
+
 /** Sleep value for an indefinite period of time. */
 #define HF_SLEEP_INDEFINITE 0xffffffffffffffff
 
diff --git a/src/load.c b/src/load.c
index a8bb759..e2a272e 100644
--- a/src/load.c
+++ b/src/load.c
@@ -34,6 +34,9 @@
 
 #include "vmapi/hf/call.h"
 
+alignas(PAGE_SIZE) static uint8_t tee_send_buffer[HF_MAILBOX_SIZE];
+alignas(PAGE_SIZE) static uint8_t tee_recv_buffer[HF_MAILBOX_SIZE];
+
 /**
  * Copies data to an unmapped location by mapping it for write, copying the
  * data, then unmapping it.
@@ -134,7 +137,7 @@
 		return false;
 	}
 
-	if (!vm_init(MAX_CPUS, ppool, &vm)) {
+	if (!vm_init_next(MAX_CPUS, ppool, &vm)) {
 		dlog("Unable to initialise primary vm\n");
 		return false;
 	}
@@ -214,7 +217,7 @@
 		return false;
 	}
 
-	if (!vm_init(manifest_vm->secondary.vcpu_count, ppool, &vm)) {
+	if (!vm_init_next(manifest_vm->secondary.vcpu_count, ppool, &vm)) {
 		dlog("Unable to initialise VM.\n");
 		return false;
 	}
@@ -333,6 +336,7 @@
 	      struct boot_params_update *update, struct mpool *ppool)
 {
 	struct vm *primary;
+	struct vm *tee;
 	struct mem_range mem_ranges_available[MAX_MEM_RANGES];
 	struct vm_locked primary_vm_locked;
 	size_t i;
@@ -344,6 +348,15 @@
 		return false;
 	}
 
+	/*
+	 * Initialise the dummy VM which represents TrustZone, and set up its
+	 * RX/TX buffers.
+	 */
+	tee = vm_init(HF_TEE_VM_ID, 0, ppool);
+	CHECK(tee != NULL);
+	tee->mailbox.send = &tee_send_buffer;
+	tee->mailbox.recv = &tee_recv_buffer;
+
 	static_assert(
 		sizeof(mem_ranges_available) == sizeof(params->mem_ranges),
 		"mem_range arrays must be the same size for memcpy.");
diff --git a/src/manifest.c b/src/manifest.c
index c3b5566..d574e55 100644
--- a/src/manifest.c
+++ b/src/manifest.c
@@ -33,6 +33,8 @@
 
 #define VM_NAME_BUF_SIZE (2 + 5 + 1) /* "vm" + number + null terminator */
 static_assert(MAX_VMS <= 99999, "Insufficient VM_NAME_BUF_SIZE");
+static_assert(HF_TEE_VM_ID > MAX_VMS,
+	      "TrustZone VM ID clashes with normal VM range.");
 
 /**
  * Generates a string with the two letters "vm" followed by an integer.
diff --git a/src/vm.c b/src/vm.c
index 0f36e21..7237dfb 100644
--- a/src/vm.c
+++ b/src/vm.c
@@ -27,19 +27,24 @@
 #include "vmapi/hf/call.h"
 
 static struct vm vms[MAX_VMS];
+static struct vm tee_vm;
 static spci_vm_count_t vm_count;
 
-bool vm_init(spci_vcpu_count_t vcpu_count, struct mpool *ppool,
-	     struct vm **new_vm)
+struct vm *vm_init(spci_vm_id_t id, spci_vcpu_count_t vcpu_count,
+		   struct mpool *ppool)
 {
 	uint32_t i;
 	struct vm *vm;
 
-	if (vm_count >= MAX_VMS) {
-		return false;
-	}
+	if (id == HF_TEE_VM_ID) {
+		vm = &tee_vm;
+	} else {
+		uint16_t vm_index = id - HF_VM_ID_OFFSET;
 
-	vm = &vms[vm_count];
+		CHECK(id >= HF_VM_ID_OFFSET);
+		CHECK(vm_index < ARRAY_SIZE(vms));
+		vm = &vms[vm_index];
+	}
 
 	memset_s(vm, sizeof(*vm), 0, sizeof(*vm));
 
@@ -47,14 +52,13 @@
 	list_init(&vm->mailbox.ready_list);
 	sl_init(&vm->lock);
 
-	/* Generate IDs based on an offset, as low IDs e.g., 0, are reserved */
-	vm->id = vm_count + HF_VM_ID_OFFSET;
+	vm->id = id;
 	vm->vcpu_count = vcpu_count;
 	vm->mailbox.state = MAILBOX_STATE_EMPTY;
 	atomic_init(&vm->aborting, false);
 
 	if (!mm_vm_init(&vm->ptable, ppool)) {
-		return false;
+		return NULL;
 	}
 
 	/* Initialise waiter entries. */
@@ -69,8 +73,22 @@
 		vcpu_init(vm_get_vcpu(vm, i), vm);
 	}
 
+	return vm;
+}
+
+bool vm_init_next(spci_vcpu_count_t vcpu_count, struct mpool *ppool,
+		  struct vm **new_vm)
+{
+	if (vm_count >= MAX_VMS) {
+		return false;
+	}
+
+	/* Generate IDs based on an offset, as low IDs e.g., 0, are reserved */
+	*new_vm = vm_init(vm_count + HF_VM_ID_OFFSET, vcpu_count, ppool);
+	if (*new_vm == NULL) {
+		return false;
+	}
 	++vm_count;
-	*new_vm = vm;
 
 	return true;
 }
@@ -89,6 +107,13 @@
 		return NULL;
 	}
 
+	if (id == HF_TEE_VM_ID) {
+		if (tee_vm.id == HF_TEE_VM_ID) {
+			return &tee_vm;
+		}
+		return NULL;
+	}
+
 	index = id - HF_VM_ID_OFFSET;
 
 	/* Ensure the VM is initialized. */
diff --git a/src/vm_test.cc b/src/vm_test.cc
index fb33ec4..7bec31a 100644
--- a/src/vm_test.cc
+++ b/src/vm_test.cc
@@ -67,7 +67,7 @@
 	struct_vm *vm;
 	struct vm_locked vm_locked;
 
-	vm_init(1, &ppool, &vm);
+	EXPECT_TRUE(vm_init_next(1, &ppool, &vm));
 	vm_locked = vm_lock(vm);
 	ASSERT_TRUE(mm_vm_init(&vm->ptable, &ppool));
 	EXPECT_TRUE(vm_unmap_hypervisor(vm_locked, &ppool));