Begin to abstract the ABI.

Different architectures or standards will require different ABIs but
this should be hidden from the Hafnium API. Further changes are required
to support returning multiple registers but that will be hidden from the
API.

Change-Id: I35bc674c35bd4bb4c8c30e02f1075024a3bc44db
diff --git a/inc/vmapi/hf/abi.h b/inc/vmapi/hf/abi.h
new file mode 100644
index 0000000..9866059
--- /dev/null
+++ b/inc/vmapi/hf/abi.h
@@ -0,0 +1,120 @@
+/*
+ * Copyright 2018 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include "hf/types.h"
+
+enum hf_vcpu_run_code {
+	HF_VCPU_RUN_YIELD,
+	HF_VCPU_RUN_WAIT_FOR_INTERRUPT,
+	HF_VCPU_RUN_WAKE_UP,
+	HF_VCPU_RUN_MESSAGE,
+	HF_VCPU_RUN_SLEEP,
+};
+
+struct hf_vcpu_run_return {
+	enum hf_vcpu_run_code code;
+	union {
+		struct {
+			uint32_t vm_id;
+			uint16_t vcpu;
+		} wake_up;
+		struct {
+			uint32_t size;
+		} message;
+		struct {
+			uint64_t ns;
+		} sleep;
+	};
+};
+
+struct hf_mailbox_receive_return {
+	uint32_t vm_id;
+	uint32_t size;
+};
+
+/**
+ * Encode an hf_vcpu_run_return struct in the 64-bit packing ABI.
+ */
+static inline uint64_t hf_vcpu_run_return_encode(struct hf_vcpu_run_return res)
+{
+	uint64_t ret = res.code & 0xff;
+	switch (res.code) {
+	case HF_VCPU_RUN_WAKE_UP:
+		ret |= (uint64_t)res.wake_up.vm_id << 32;
+		ret |= (uint64_t)res.wake_up.vcpu << 16;
+		break;
+	case HF_VCPU_RUN_MESSAGE:
+		ret |= (uint64_t)res.message.size << 32;
+		break;
+	case HF_VCPU_RUN_SLEEP:
+		ret |= res.sleep.ns << 8;
+		break;
+	default:
+		break;
+	}
+	return ret;
+}
+
+/**
+ * Decode an hf_vcpu_run_return struct from the 64-bit packing ABI.
+ */
+static inline struct hf_vcpu_run_return hf_vcpu_run_return_decode(uint64_t res)
+{
+	struct hf_vcpu_run_return ret;
+
+	ret.code = (enum hf_vcpu_run_code)(res & 0xff);
+
+	/* Some codes include more data. */
+	switch (ret.code) {
+	case HF_VCPU_RUN_WAKE_UP:
+		ret.wake_up.vm_id = res >> 32;
+		ret.wake_up.vcpu = (res >> 16) & 0xffff;
+		break;
+	case HF_VCPU_RUN_MESSAGE:
+		ret.message.size = res >> 32;
+		break;
+	case HF_VCPU_RUN_SLEEP:
+		ret.sleep.ns = res >> 8;
+		break;
+	default:
+		break;
+	}
+
+	return ret;
+}
+
+/**
+ * Encode an hf_mailbox_receive_return struct in the 64-bit packing ABI.
+ */
+static inline uint64_t hf_mailbox_receive_return_encode(
+	struct hf_mailbox_receive_return res)
+{
+	return res.vm_id | ((uint64_t)res.size << 32);
+}
+
+/**
+ * Decode an hf_mailbox_receive_return struct from the 64-bit packing ABI.
+ */
+static inline struct hf_mailbox_receive_return hf_mailbox_receive_return_decode(
+	uint64_t res)
+{
+	return (struct hf_mailbox_receive_return){
+		.vm_id = (uint32_t)(res & 0xffffffff),
+		.size = (uint32_t)(res >> 32),
+	};
+}
diff --git a/inc/vmapi/hf/call.h b/inc/vmapi/hf/call.h
index 4e70395..771997a 100644
--- a/inc/vmapi/hf/call.h
+++ b/inc/vmapi/hf/call.h
@@ -16,21 +16,8 @@
 
 #pragma once
 
-#if defined(__linux__) && defined(__KERNEL__)
-
-#include <linux/types.h>
-
-typedef phys_addr_t hf_ipaddr_t;
-
-#else
-
-#include <stdbool.h>
-#include <stddef.h>
-#include <stdint.h>
-
-typedef uintptr_t hf_ipaddr_t;
-
-#endif
+#include "hf/abi.h"
+#include "hf/types.h"
 
 /* Keep macro alignment */
 /* clang-format off */
@@ -44,34 +31,9 @@
 #define HF_MAILBOX_RECEIVE  0xff05
 #define HF_MAILBOX_CLEAR    0xff06
 
-/* The ID of the primary VM which is responsile for scheduling. */
-#define HF_PRIMARY_VM_ID 0
-
-/* Return codes for hf_vcpu_run(). */
-#define HF_VCPU_RUN_YIELD              0x00
-#define HF_VCPU_RUN_WAIT_FOR_INTERRUPT 0x01
-#define HF_VCPU_RUN_WAKE_UP            0x02
-#define HF_VCPU_RUN_MESSAGE            0x03
-
-/* Construct and destruct the hf_vcpu_run() response. */
-#define HF_VCPU_RUN_RESPONSE(code, vm_id, data)               \
-	((code & 0xff) | ((uint64_t)(vm_id & 0xffff) << 16) | \
-	 ((uint64_t)data << 32))
-#define HF_VCPU_RUN_CODE(ret) (ret & 0xff)
-#define HF_VCPU_RUN_VM_ID(ret) ((ret >> 16) & 0xffff)
-#define HF_VCPU_RUN_DATA(ret) (ret >> 32)
-
-/* Construct and destruct the hf_mailbox_receive() response. */
-#define HF_MAILBOX_RECEIVE_RESPONSE(vm_id, size) \
-	((vm_id & 0xffff) | ((uint64_t)size << 32))
-#define HF_MAILBOX_RECEIVE_VM_ID(ret) (ret & 0xffff)
-#define HF_MAILBOX_RECEIVE_SIZE(ret) (ret >> 32)
-
+/* The amount of data that can be sent to a mailbox. */
 #define HF_MAILBOX_SIZE 4096
 
-#define HF_INVALID_VM_ID 0xffff
-#define HF_INVALID_VCPU  0xffff
-
 /* clang-format on */
 
 /**
@@ -83,9 +45,11 @@
 /**
  * Runs the given vcpu of the given vm.
  */
-static inline int64_t hf_vcpu_run(uint32_t vm_id, uint32_t vcpu_idx)
+static inline struct hf_vcpu_run_return hf_vcpu_run(uint32_t vm_id,
+						    uint32_t vcpu_idx)
 {
-	return hf_call(HF_VCPU_RUN, vm_id, vcpu_idx, 0);
+	return hf_vcpu_run_return_decode(
+		hf_call(HF_VCPU_RUN, vm_id, vcpu_idx, 0));
 }
 
 /**
@@ -125,11 +89,14 @@
  * Called by secondary VMs to receive a message. The call can optionally block
  * until a message is received.
  *
+ * If no message was received, the VM ID will be HF_INVALID_VM_ID.
+ *
  * The mailbox must be cleared before a new message can be received.
  */
-static inline int64_t hf_mailbox_receive(bool block)
+static inline struct hf_mailbox_receive_return hf_mailbox_receive(bool block)
 {
-	return hf_call(HF_MAILBOX_RECEIVE, block, 0, 0);
+	return hf_mailbox_receive_return_decode(
+		hf_call(HF_MAILBOX_RECEIVE, block, 0, 0));
 }
 
 /**
diff --git a/inc/vmapi/hf/types.h b/inc/vmapi/hf/types.h
index 1e4c7f8..55de5f1 100644
--- a/inc/vmapi/hf/types.h
+++ b/inc/vmapi/hf/types.h
@@ -16,14 +16,13 @@
 
 #pragma once
 
+/* Define the standard types for the platform. */
 #if defined(__linux__) && defined(__KERNEL__)
 
 #include <linux/types.h>
 
 typedef phys_addr_t hf_ipaddr_t;
 
-#define PRIu16 "hu"
-
 #else
 
 #include <stdbool.h>
@@ -34,10 +33,9 @@
 
 #endif
 
-typedef uint16_t hf_vm_id_t;
-
-#define HF_VM_ID_MAX UINT16_MAX
-#define HF_PRI_VM_ID PRIu16
-
 /* The ID of the primary VM which is responsile for scheduling. */
 #define HF_PRIMARY_VM_ID 0
+
+/* Invalid values for fields to indicate absence or errors. */
+#define HF_INVALID_VM_ID 0xffffffff
+#define HF_INVALID_VCPU 0xffff