Add APIs to yield and get the ID of the VM.
Change-Id: I2e6340d200cfddc7ca9877e91d785c438620b6c6
diff --git a/inc/hf/api.h b/inc/hf/api.h
index 94e3327..b4bbbf7 100644
--- a/inc/hf/api.h
+++ b/inc/hf/api.h
@@ -23,6 +23,7 @@
#include "vmapi/hf/call.h"
void api_init(struct mpool *ppool);
+int64_t api_vm_get_id(const struct vcpu *current);
int64_t api_vm_get_count(void);
int64_t api_vcpu_get_count(uint32_t vm_id, const struct vcpu *current);
struct hf_vcpu_run_return api_vcpu_run(uint32_t vm_id, uint32_t vcpu_idx,
diff --git a/inc/vmapi/hf/call.h b/inc/vmapi/hf/call.h
index 37428f3..a7c58a2 100644
--- a/inc/vmapi/hf/call.h
+++ b/inc/vmapi/hf/call.h
@@ -23,16 +23,18 @@
/* clang-format off */
/* TODO: Define constants below according to spec. */
-#define HF_VCPU_RUN 0xff00
+#define HF_VM_GET_ID 0xff00
#define HF_VM_GET_COUNT 0xff01
#define HF_VCPU_GET_COUNT 0xff02
-#define HF_VM_CONFIGURE 0xff03
-#define HF_MAILBOX_SEND 0xff04
-#define HF_MAILBOX_RECEIVE 0xff05
-#define HF_MAILBOX_CLEAR 0xff06
-#define HF_ENABLE_INTERRUPT 0xff07
-#define HF_GET_AND_ACKNOWLEDGE_INTERRUPT 0xff08
-#define HF_INJECT_INTERRUPT 0xff09
+#define HF_VCPU_RUN 0xff03
+#define HF_VCPU_YIELD 0xff04
+#define HF_VM_CONFIGURE 0xff05
+#define HF_MAILBOX_SEND 0xff06
+#define HF_MAILBOX_RECEIVE 0xff07
+#define HF_MAILBOX_CLEAR 0xff08
+#define HF_ENABLE_INTERRUPT 0xff09
+#define HF_GET_AND_ACKNOWLEDGE_INTERRUPT 0xff0a
+#define HF_INJECT_INTERRUPT 0xff0b
/** The amount of data that can be sent to a mailbox. */
#define HF_MAILBOX_SIZE 4096
@@ -46,15 +48,11 @@
int64_t hf_call(size_t arg0, size_t arg1, size_t arg2, size_t arg3);
/**
- * Runs the given vcpu of the given vm.
- *
- * Returns an hf_vcpu_run_return struct telling the scheduler what to do next.
+ * Returns the VM's own ID.
*/
-static inline struct hf_vcpu_run_return hf_vcpu_run(uint32_t vm_id,
- uint32_t vcpu_idx)
+static inline uint32_t hf_vm_get_id()
{
- return hf_vcpu_run_return_decode(
- hf_call(HF_VCPU_RUN, vm_id, vcpu_idx, 0));
+ return hf_call(HF_VM_GET_ID, 0, 0, 0);
}
/**
@@ -74,6 +72,26 @@
}
/**
+ * Runs the given vcpu of the given vm.
+ *
+ * Returns an hf_vcpu_run_return struct telling the scheduler what to do next.
+ */
+static inline struct hf_vcpu_run_return hf_vcpu_run(uint32_t vm_id,
+ uint32_t vcpu_idx)
+{
+ return hf_vcpu_run_return_decode(
+ hf_call(HF_VCPU_RUN, vm_id, vcpu_idx, 0));
+}
+
+/**
+ * Hints that the vcpu is willing to yield its current use of the physical CPU.
+ */
+static inline void hf_vcpu_yield(void)
+{
+ hf_call(HF_VCPU_YIELD, 0, 0, 0);
+}
+
+/**
* Configures the pages to send/receive data through. The pages must not be
* shared.
*
@@ -88,11 +106,11 @@
* Copies data from the sender's send buffer to the recipient's receive buffer.
*
* Returns -1 on failure, and on success either:
- * - 0, if the caller is a secondary VM
- * - the ID of the vCPU to run to receive the message, if the caller is the
- * primary VM.
- * - HF_INVALID_VCPU if the caller is the primary VM and no vCPUs on the target
- * VM are currently waiting to receive a message.
+ * - 0, if the caller is a secondary VM
+ * - the ID of the vCPU to run to receive the message, if the caller is the
+ * primary VM.
+ * - HF_INVALID_VCPU if the caller is the primary VM and no vCPUs on the target
+ * VM are currently waiting to receive a message.
*/
static inline int64_t hf_mailbox_send(uint32_t vm_id, size_t size)
{
diff --git a/src/api.c b/src/api.c
index 6be8702..7e6e4e6 100644
--- a/src/api.c
+++ b/src/api.c
@@ -101,6 +101,14 @@
}
/**
+ * Returns the ID of the VM.
+ */
+int64_t api_vm_get_id(const struct vcpu *current)
+{
+ return current->vm->id;
+}
+
+/**
* Returns the number of VMs configured to run.
*/
int64_t api_vm_get_count(void)
diff --git a/src/arch/aarch64/handler.c b/src/arch/aarch64/handler.c
index c15b550..990b212 100644
--- a/src/arch/aarch64/handler.c
+++ b/src/arch/aarch64/handler.c
@@ -217,6 +217,10 @@
}
switch ((uint32_t)arg0 & ~PSCI_CONVENTION_MASK) {
+ case HF_VM_GET_ID:
+ ret.user_ret = api_vm_get_id(current());
+ break;
+
case HF_VM_GET_COUNT:
ret.user_ret = api_vm_get_count();
break;
@@ -230,6 +234,11 @@
api_vcpu_run(arg1, arg2, current(), &ret.new));
break;
+ case HF_VCPU_YIELD:
+ ret.user_ret = 0;
+ ret.new = api_yield(current());
+ break;
+
case HF_VM_CONFIGURE:
ret.user_ret = api_vm_configure(ipa_init(arg1), ipa_init(arg2),
current());
diff --git a/test/vmapi/primary_only.c b/test/vmapi/primary_only.c
index ba9e6d7..5b3d0f0 100644
--- a/test/vmapi/primary_only.c
+++ b/test/vmapi/primary_only.c
@@ -24,32 +24,62 @@
#include "hftest.h"
+/**
+ * Confirms the primary VM has the primary ID.
+ */
+TEST(hf_vm_get_id, primary_has_primary_id)
+{
+ EXPECT_EQ(hf_vm_get_id(), HF_PRIMARY_VM_ID);
+}
+
+/**
+ * Confirm there is only the primary VM.
+ */
TEST(hf_vm_get_count, no_secondary_vms)
{
EXPECT_EQ(hf_vm_get_count(), 1);
}
+/**
+ * Confirm the primary has at least one vcpu.
+ */
TEST(hf_vcpu_get_count, primary_has_at_least_one)
{
EXPECT_GE(hf_vcpu_get_count(0), 0);
}
+/**
+ * Confirm an error is returned when getting the vcpu count of a non-existant
+ * VM.
+ */
TEST(hf_vcpu_get_count, no_secondary_vms)
{
EXPECT_EQ(hf_vcpu_get_count(1), -1);
}
+/**
+ * Confirm an error is returned when getting the vcpu count of a VM with an ID
+ * that is likely to be far outside the resource limit.
+ */
TEST(hf_vcpu_get_count, large_invalid_vm_index)
{
EXPECT_EQ(hf_vcpu_get_count(0xffffffff), -1);
}
+/**
+ * Confirm it is a no-op with a valid return code when running a vcpu from the
+ * primary VM.
+ */
TEST(hf_vcpu_run, cannot_run_primary)
{
struct hf_vcpu_run_return res = hf_vcpu_run(HF_PRIMARY_VM_ID, 0);
EXPECT_EQ(res.code, HF_VCPU_RUN_WAIT_FOR_INTERRUPT);
}
+/**
+ * Confirm it is a no-op with a valid return code when running a vcpu from a
+ * non-existant secondary VM.
+ */
TEST(hf_vcpu_run, cannot_run_absent_secondary)
{
struct hf_vcpu_run_return res = hf_vcpu_run(1, 0);
@@ -57,6 +87,14 @@
}
/**
+ * Confirm that yielding from the primary will still allow the test to complete.
+ */
+TEST(hf_vcpu_yield, yield_is_noop_for_primary)
+{
+ hf_vcpu_yield();
+}
+
+/**
* Releases the lock passed in.
*/
static void vm_cpu_entry(uintptr_t arg)
@@ -67,6 +105,9 @@
sl_unlock(lock);
}
+/**
+ * Confirm a new cpu can be started to execute in parallel.
+ */
TEST(cpus, start)
{
struct spinlock lock = SPINLOCK_INIT;
diff --git a/test/vmapi/primary_with_secondaries.c b/test/vmapi/primary_with_secondaries.c
index b13ac6e..10b06d0 100644
--- a/test/vmapi/primary_with_secondaries.c
+++ b/test/vmapi/primary_with_secondaries.c
@@ -82,6 +82,14 @@
}
/**
+ * Confirms the primary VM has the primary ID.
+ */
+TEST(hf_vm_get_id, primary_has_primary_id)
+{
+ EXPECT_EQ(hf_vm_get_id(), HF_PRIMARY_VM_ID);
+}
+
+/**
* Confirm there are 4 secondary VMs as well as this primary VM.
*/
TEST(hf_vm_get_count, four_secondary_vms)