Add support for notifying VMs when mailboxes become writable.

This allows VMs to know when they can retry sending messages to another
VM after an attempt fails because the recipient's mailbox is not
available.

Change-Id: Ib20159f7ecf81544e40149edcd663876c58851c7
diff --git a/src/vm.c b/src/vm.c
index 40aa294..9bc616f 100644
--- a/src/vm.c
+++ b/src/vm.c
@@ -38,6 +38,10 @@
 
 	memset(vm, 0, sizeof(*vm));
 
+	list_init(&vm->mailbox.waiter_list);
+	list_init(&vm->mailbox.ready_list);
+	sl_init(&vm->lock);
+
 	vm->id = vm_count;
 	vm->vcpu_count = vcpu_count;
 	vm->mailbox.state = mailbox_state_empty;
@@ -46,6 +50,13 @@
 		return false;
 	}
 
+	/* Initialise waiter entries. */
+	for (i = 0; i < MAX_VMS; i++) {
+		vm->wentry[i].waiting_vm = vm;
+		list_init(&vm->wentry[i].wait_links);
+		list_init(&vm->wentry[i].ready_links);
+	}
+
 	/* Do basic initialization of vcpus. */
 	for (i = 0; i < vcpu_count; i++) {
 		vcpu_init(&vm->vcpus[i], vm);
@@ -72,6 +83,25 @@
 	return &vms[id];
 }
 
+/**
+ * Locks the given VM and updates `locked` to hold the newly locked vm.
+ */
+void vm_lock(struct vm *vm, struct vm_locked *locked)
+{
+	sl_lock(&vm->lock);
+	locked->vm = vm;
+}
+
+/**
+ * Unlocks a VM previously locked with vm_lock, and updates `locked` to reflect
+ * the fact that the VM is no longer locked.
+ */
+void vm_unlock(struct vm_locked *locked)
+{
+	sl_unlock(&locked->vm->lock);
+	locked->vm = NULL;
+}
+
 /* TODO: Shall we use index or id here? */
 void vm_start_vcpu(struct vm *vm, size_t index, ipaddr_t entry, uintreg_t arg)
 {