feat: add `vm_lock_both_in_order`
Adds helper function for acquiring a second lock ordered with respect to
a first lock.
Change-Id: I8f4d9d2e20f202d893c12755cf44d9c03d5b0122
Signed-off-by: Karl Meakin <karl.meakin@arm.com>
diff --git a/src/vm.c b/src/vm.c
index 266c3bc..577aeea 100644
--- a/src/vm.c
+++ b/src/vm.c
@@ -8,6 +8,7 @@
#include "hf/vm.h"
+#include "hf/arch/spinlock.h"
#include "hf/arch/vm.h"
#include "hf/api.h"
@@ -210,6 +211,34 @@
}
/**
+ * Locks two VMs ensuring that the locking order is according to the locks'
+ * addresses, given `vm1` is already locked.
+ */
+struct two_vm_locked vm_lock_both_in_order(struct vm_locked vm1, struct vm *vm2)
+{
+ struct spinlock *sl1 = &vm1.vm->lock;
+ struct spinlock *sl2 = &vm2->lock;
+
+ /*
+ * Use `sl_lock`/`sl_unlock` directly rather than
+ * `vm_lock`/`vm_unlock` because `vm_unlock` sets the vm field
+ * to NULL.
+ */
+ if (sl1 < sl2) {
+ sl_lock(sl2);
+ } else {
+ sl_unlock(sl1);
+ sl_lock(sl2);
+ sl_lock(sl1);
+ }
+
+ return (struct two_vm_locked){
+ .vm1 = vm1,
+ .vm2 = (struct vm_locked){.vm = vm2},
+ };
+}
+
+/**
* Unlocks a VM previously locked with vm_lock, and updates `locked` to reflect
* the fact that the VM is no longer locked.
*/