Basic memory sharing.

The introduces the basic functionality for memory sharing. The API used
to invoke memory sharing is a placeholder while we decide on what the
proper interface should look like.

Change-Id: Ia5c2c224119d896b3fc2294b0828626ec325e1e7
diff --git a/inc/hf/api.h b/inc/hf/api.h
index 8357a89..e9ffe88 100644
--- a/inc/hf/api.h
+++ b/inc/hf/api.h
@@ -39,6 +39,8 @@
 int64_t api_mailbox_clear(struct vcpu *current, struct vcpu **next);
 int64_t api_mailbox_writable_get(const struct vcpu *current);
 int64_t api_mailbox_waiter_get(uint32_t vm_id, const struct vcpu *current);
+int64_t api_share_memory(uint32_t vm_id, ipaddr_t addr, size_t size,
+			 enum hf_share share, struct vcpu *current);
 
 struct vcpu *api_preempt(struct vcpu *current);
 struct vcpu *api_yield(struct vcpu *current);
diff --git a/inc/hf/spinlock.h b/inc/hf/spinlock.h
index 7a307f6..57ce3a8 100644
--- a/inc/hf/spinlock.h
+++ b/inc/hf/spinlock.h
@@ -39,6 +39,21 @@
 	}
 }
 
+/**
+ * Locks both locks, enforcing the lowest address first ordering for locks of
+ * the same kind.
+ */
+static inline void sl_lock_both(struct spinlock *a, struct spinlock *b)
+{
+	if (a < b) {
+		sl_lock(a);
+		sl_lock(b);
+	} else {
+		sl_lock(b);
+		sl_lock(a);
+	}
+}
+
 static inline void sl_unlock(struct spinlock *l)
 {
 	atomic_flag_clear_explicit(&l->v, memory_order_release);
diff --git a/inc/hf/std.h b/inc/hf/std.h
index c872fd4..6e5e82a 100644
--- a/inc/hf/std.h
+++ b/inc/hf/std.h
@@ -19,6 +19,8 @@
 #include <stddef.h>
 #include <stdint.h>
 
+#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
+
 void *memset(void *s, int c, size_t n);
 void *memcpy(void *dst, const void *src, size_t n);
 void *memmove(void *dst, const void *src, size_t n);