Improve arch-specific separation in API code.
diff --git a/inc/api.h b/inc/api.h
new file mode 100644
index 0000000..edc9797
--- /dev/null
+++ b/inc/api.h
@@ -0,0 +1,17 @@
+#ifndef _API_H
+#define _API_H
+
+#include "cpu.h"
+#include "vm.h"
+
+/* TODO: Can we hide these? */
+extern struct vm secondary_vm[MAX_VMS];
+extern uint32_t secondary_vm_count;
+extern struct vm primary_vm;
+
+int32_t api_vm_get_count(void);
+int32_t api_vcpu_get_count(uint32_t vm_idx);
+int32_t api_vcpu_run(uint32_t vm_idx, uint32_t vcpu_idx, struct vcpu **next);
+struct vcpu *api_wait_for_interrupt(void);
+
+#endif /* _API_H */
diff --git a/inc/cpu.h b/inc/cpu.h
index 2eae33b..43bd356 100644
--- a/inc/cpu.h
+++ b/inc/cpu.h
@@ -37,7 +37,10 @@
void *stack_bottom;
};
+void cpu_module_init(void);
+
void cpu_init(struct cpu *c);
+size_t cpu_index(struct cpu *c);
void cpu_irq_enable(struct cpu *c);
void cpu_irq_disable(struct cpu *c);
bool cpu_on(struct cpu *c);
diff --git a/src/api.c b/src/api.c
new file mode 100644
index 0000000..a105f6d
--- /dev/null
+++ b/src/api.c
@@ -0,0 +1,72 @@
+#include "api.h"
+
+#include "arch_api.h"
+#include "vm.h"
+
+struct vm secondary_vm[MAX_VMS];
+uint32_t secondary_vm_count;
+struct vm primary_vm;
+
+/**
+ * Returns the number of VMs configured to run.
+ */
+int32_t api_vm_get_count(void)
+{
+ return secondary_vm_count;
+}
+
+/**
+ * Returns the number of vcpus configured in the given VM.
+ */
+int32_t api_vcpu_get_count(uint32_t vm_idx)
+{
+ if (vm_idx >= secondary_vm_count)
+ return -1;
+
+ return secondary_vm[vm_idx].vcpu_count;
+}
+
+/**
+ * Runs the given vcpu of the given vm.
+ */
+int32_t api_vcpu_run(uint32_t vm_idx, uint32_t vcpu_idx, struct vcpu **next)
+{
+ struct vm *vm = secondary_vm + vm_idx;
+ struct vcpu *vcpu;
+
+ /* Only the primary VM can switch vcpus. */
+ if (cpu()->current->vm != &primary_vm)
+ return HF_VCPU_WAIT_FOR_INTERRUPT;
+
+ if (vm_idx >= secondary_vm_count)
+ return HF_VCPU_WAIT_FOR_INTERRUPT;
+
+ vcpu = vm->vcpus + vcpu_idx;
+ if (vcpu_idx >= vm->vcpu_count || !vcpu->is_on)
+ return HF_VCPU_WAIT_FOR_INTERRUPT;
+
+ arch_set_vm_mm(&vm->page_table);
+ *next = vcpu;
+
+ return HF_VCPU_YIELD;
+}
+
+/**
+ * Puts current vcpu in wait for interrupt mode, and returns to the primary
+ * vm.
+ */
+struct vcpu *api_wait_for_interrupt(void)
+{
+ struct vcpu *vcpu = &primary_vm.vcpus[cpu_index(cpu())];
+
+ /* Switch back to primary VM. */
+ arch_set_vm_mm(&primary_vm.page_table);
+
+ /*
+ * Inidicate to primary VM that this vcpu blocked waiting for an
+ * interrupt.
+ */
+ arch_regs_set_retval(&vcpu->regs, HF_VCPU_WAIT_FOR_INTERRUPT);
+
+ return vcpu;
+}
diff --git a/src/arch/aarch64/handler.c b/src/arch/aarch64/handler.c
index 1844e37..48de85d 100644
--- a/src/arch/aarch64/handler.c
+++ b/src/arch/aarch64/handler.c
@@ -1,3 +1,5 @@
+#include "api.h"
+#include "arch_api.h"
#include "cpu.h"
#include "dlog.h"
#include "vm.h"
@@ -21,17 +23,6 @@
for (;;);
}
-/* TODO: Define constants below according to spec. */
-#define HF_VCPU_RUN 0xff00
-#define HF_VM_GET_COUNT 0xff01
-#define HF_VCPU_GET_COUNT 0xff02
-
-/* TODO: Move these decl elsewhere. */
-extern struct vm secondary_vm[MAX_VMS];
-extern uint32_t secondary_vm_count;
-extern struct vm primary_vm;
-extern struct cpu cpus[];
-
struct hvc_handler_return hvc_handler(size_t arg0, size_t arg1, size_t arg2,
size_t arg3)
{
@@ -49,28 +40,15 @@
break;
case HF_VM_GET_COUNT:
- ret.user_ret = secondary_vm_count;
+ ret.user_ret = api_vm_get_count();
break;
case HF_VCPU_GET_COUNT:
- if (arg1 >= secondary_vm_count)
- ret.user_ret = -1;
- else
- ret.user_ret = secondary_vm[arg1].vcpu_count;
+ ret.user_ret = api_vcpu_get_count(arg1);
break;
case HF_VCPU_RUN:
- /* TODO: Make sure we don't allow secondary VMs to make this
- * hvc call. */
- ret.user_ret = 1; /* WFI */
- if (arg1 < secondary_vm_count &&
- arg2 < secondary_vm[arg1].vcpu_count &&
- secondary_vm[arg1].vcpus[arg2].is_on) {
- arch_set_vm_mm(&secondary_vm[arg1].page_table);
- /* TODO: Update the virtual memory. */
- ret.new = secondary_vm[arg1].vcpus + arg2;
- ret.user_ret = 0;
- }
+ ret.user_ret = api_vcpu_run(arg1, arg2, &ret.new);
break;
default:
@@ -87,7 +65,7 @@
/* Switch back to primary VM, interrupts will be handled there. */
arch_set_vm_mm(&primary_vm.page_table);
- return &primary_vm.vcpus[cpus - cpu()];
+ return &primary_vm.vcpus[cpu_index(cpu())];
}
struct vcpu *sync_lower_exception(uint64_t esr)
@@ -100,18 +78,7 @@
/* Check TI bit of ISS, 0 = WFI, 1 = WFE. */
if (esr & 1)
return NULL;
-
- /* Switch back to primary VM. */
- arch_set_vm_mm(&primary_vm.page_table);
- vcpu = &primary_vm.vcpus[cpus - cpu()];
-
- dlog("Returning due to WFI\n");
-
- /* TODO: Use constant. */
- /* Set return value to 1, indicating to primary VM that this
- * vcpu blocked on a WFI. */
- arch_regs_set_retval(&vcpu->regs, 1);
- return vcpu;
+ return api_wait_for_interrupt();
case 0x24: /* EC = 100100, Data abort. */
dlog("Data abort: pc=0x%x, esr=0x%x, ec=0x%x", vcpu->regs.pc, esr, esr >> 26);
diff --git a/src/arch/aarch64/inc/arch_api.h b/src/arch/aarch64/inc/arch_api.h
new file mode 100644
index 0000000..733d818
--- /dev/null
+++ b/src/arch/aarch64/inc/arch_api.h
@@ -0,0 +1,14 @@
+#ifndef _ARCH_API_H
+#define _ARCH_API_H
+
+/* Return values for vcpu_run() hypervisor call. */
+#define HF_VCPU_YIELD 0x00
+#define HF_VCPU_WAIT_FOR_INTERRUPT 0x01
+#define HF_VCPU_WAKE_UP 0x02
+
+/* TODO: Define constants below according to spec. */
+#define HF_VCPU_RUN 0xff00
+#define HF_VM_GET_COUNT 0xff01
+#define HF_VCPU_GET_COUNT 0xff02
+
+#endif /* _ARCH_API_H */
diff --git a/src/cpu.c b/src/cpu.c
index 73a2d1c..bb84bbb 100644
--- a/src/cpu.c
+++ b/src/cpu.c
@@ -5,6 +5,35 @@
#include "std.h"
#include "vm.h"
+/* The stack to be used by the CPUs. */
+alignas(2 * sizeof(size_t)) static char callstacks[STACK_SIZE * MAX_CPUS];
+
+/* State of all supported CPUs. The stack of the first one is initialized. */
+struct cpu cpus[MAX_CPUS] = {
+ {
+ .is_on = 1,
+ .stack_bottom = callstacks + STACK_SIZE,
+ },
+};
+
+void cpu_module_init(void)
+{
+ size_t i;
+
+ /* Initialize all CPUs. */
+ for (i = 0; i < MAX_CPUS; i++) {
+ struct cpu *c = cpus + i;
+ cpu_init(c);
+ c->id = i; /* TODO: Initialize ID. */
+ c->stack_bottom = callstacks + STACK_SIZE * (i + 1);
+ }
+}
+
+size_t cpu_index(struct cpu *c)
+{
+ return cpus - c;
+}
+
void cpu_init(struct cpu *c)
{
/* TODO: Assumes that c is zeroed out already. */
diff --git a/src/main.c b/src/main.c
index 885f577..946dceb 100644
--- a/src/main.c
+++ b/src/main.c
@@ -11,17 +11,6 @@
void *fdt;
-/* The stack to be used by the CPUs. */
-alignas(2 * sizeof(size_t)) char callstacks[STACK_SIZE * MAX_CPUS];
-
-/* State of all supported CPUs. The stack of the first one is initialized. */
-struct cpu cpus[MAX_CPUS] = {
- {
- .is_on = 1,
- .stack_bottom = callstacks + STACK_SIZE,
- },
-};
-
bool fdt_find_node(struct fdt_node *node, const char *path)
{
while (*path) {
@@ -411,17 +400,9 @@
static void one_time_init(void)
{
- size_t i;
-
dlog("Initializing hafnium\n");
- /* Initialize all CPUs. */
- for (i = 0; i < MAX_CPUS; i++) {
- struct cpu *c = cpus + i;
- cpu_init(c);
- c->id = i; /* TODO: Initialize ID. */
- c->stack_bottom = callstacks + STACK_SIZE * (i + 1);
- }
+ cpu_module_init();
/* TODO: Code below this point should be removed from this function. */
/* TODO: Remove this. */
@@ -470,7 +451,7 @@
if (!atomic_flag_test_and_set_explicit(&inited, memory_order_acq_rel))
one_time_init();
- dlog("Starting up cpu %d\n", c - cpus);
+ dlog("Starting up cpu %d\n", cpu_index(c));
- return primary_vm.vcpus + (c - cpus);
+ return primary_vm.vcpus + cpu_index(c);
}
diff --git a/src/rules.mk b/src/rules.mk
index e8022f2..313748d 100644
--- a/src/rules.mk
+++ b/src/rules.mk
@@ -1,4 +1,5 @@
SRCS += alloc.c
+SRCS += api.c
SRCS += cpio.c
SRCS += cpu.c
SRCS += fdt.c