Initial commit.
diff --git a/inc/alloc.h b/inc/alloc.h
new file mode 100644
index 0000000..b3fc110
--- /dev/null
+++ b/inc/alloc.h
@@ -0,0 +1,11 @@
+#ifndef _ALLOC_H
+#define _ALLOC_H
+
+#include <stddef.h>
+
+void halloc_init(size_t base, size_t size);
+void *halloc(size_t size);
+void hfree(void *ptr);
+void *halloc_aligned(size_t size, size_t align);
+
+#endif  /* _ALLOC_H */
diff --git a/inc/arch.h b/inc/arch.h
new file mode 100644
index 0000000..e12a8cf
--- /dev/null
+++ b/inc/arch.h
@@ -0,0 +1,12 @@
+#ifndef _ARCH_H
+#define _ARCH_H
+
+#include "cpu.h"
+#include "irq.h"
+
+void arch_init(struct cpu *cpu);
+void arch_irq_init_percpu(void);
+void arch_irq_config(uint32_t num, enum irq_trigger t, enum irq_polarity p);
+void arch_putchar(char c);
+
+#endif  /* _ARCH_H */
diff --git a/inc/cpio.h b/inc/cpio.h
new file mode 100644
index 0000000..cc244ce
--- /dev/null
+++ b/inc/cpio.h
@@ -0,0 +1,22 @@
+#ifndef _CPIO_H
+#define _CPIO_H
+
+#include <stdbool.h>
+#include <stddef.h>
+
+struct cpio {
+	const struct cpio_header *first;
+	size_t total_size;
+};
+
+struct cpio_iter {
+	const struct cpio_header *cur;
+	size_t size_left;
+};
+
+void cpio_init(struct cpio *c, const void *buf, size_t size);
+void cpio_init_iter(struct cpio *c, struct cpio_iter *iter);
+bool cpio_next(struct cpio_iter *iter, const char **name,
+	       const void **contents, size_t *size);
+
+#endif  /* _CPIO_H */
diff --git a/inc/cpu.h b/inc/cpu.h
new file mode 100644
index 0000000..6eb90ab
--- /dev/null
+++ b/inc/cpu.h
@@ -0,0 +1,61 @@
+#ifndef _CPU_H
+#define _CPU_H
+
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdint.h>
+
+#include "arch_cpu.h"
+#include "list.h"
+#include "spinlock.h"
+
+struct vcpu {
+	struct list_entry links;
+	bool is_runnable;
+	bool interrupt;
+	struct arch_regs regs;
+	struct cpu *cpu;
+	struct vm *vm;
+};
+
+/* TODO: Update alignment such that cpus are in different cache lines. */
+struct cpu {
+	struct spinlock lock;
+
+	struct vcpu *current;
+
+	struct list_entry ready_queue;
+
+	/*
+	 * Enabling/disabling irqs are counted per-cpu. They are enabled when
+	 * the count is zero, and disabled when it's non-zero.
+	 */
+	uint32_t irq_disable_count;
+
+	/*
+	 * The number of VMs that have turned this CPU on. CPUs are off when
+	 * this count is zero, and on when this count is ono-zero.
+	 */
+	uint32_t cpu_on_count;
+
+	bool (*timer_cb)(void *context);
+	void *timer_context;
+
+	/* CPU identifier. Doesn't have to be contiguous. */
+	size_t id;
+
+	/* Pointer to bottom of the stack. */
+	void *stack_bottom;
+};
+
+void cpu_init(struct cpu *c);
+void cpu_irq_enable(struct cpu *c);
+void cpu_irq_disable(struct cpu *c);
+void cpu_on(struct cpu *c);
+void cpu_off(struct cpu *c);
+
+void vcpu_init(struct vcpu *vcpu, struct cpu *cpu, struct vm *vm);
+void vcpu_ready(struct vcpu *v);
+void vcpu_unready(struct vcpu *v);
+
+#endif  /* _CPU_H */
diff --git a/inc/decl_offsets.h b/inc/decl_offsets.h
new file mode 100644
index 0000000..01f182f
--- /dev/null
+++ b/inc/decl_offsets.h
@@ -0,0 +1,10 @@
+#ifndef _DECL_OFFSETS_H
+#define _DECL_OFFSETS_H
+
+#define DECL(name, type, field) \
+	__asm("DEFINE_OFFSET " #name " %0" : : "n" (offsetof(type, field)))
+
+#define DECL_SIZE(name, type) \
+	__asm("DEFINE_OFFSET " #name " %0" : : "n" (sizeof(type)))
+
+#endif  /* _DECL_OFFSETS_H */
diff --git a/inc/dlog.h b/inc/dlog.h
new file mode 100644
index 0000000..d4c08c0
--- /dev/null
+++ b/inc/dlog.h
@@ -0,0 +1,12 @@
+#ifndef _DLOG_H
+#define _DLOG_H
+
+#if DEBUG
+void dlog(const char *fmt, ...);
+#else
+#define dlog(...)
+#endif
+
+void dlog_init(void (*pchar)(char));
+
+#endif  /* _DLOG_H */
diff --git a/inc/fdt.h b/inc/fdt.h
new file mode 100644
index 0000000..fb23c8e
--- /dev/null
+++ b/inc/fdt.h
@@ -0,0 +1,23 @@
+#ifndef _FDT_H
+#define _FDT_H
+
+#include <stdbool.h>
+#include <stdint.h>
+
+struct fdt_node {
+	/* TODO: What do we need here? */
+	const struct fdt_header *hdr;
+	const char *begin;
+	const char *end;
+	const char *strs;
+};
+
+void fdt_dump(struct fdt_header *hdr);
+void fdt_root_node(struct fdt_node *node, const struct fdt_header *hdr);
+bool fdt_find_child(struct fdt_node *node, const char *child);
+bool fdt_read_property(const struct fdt_node *node, const char *name,
+		       const char **buf, uint32_t *size);
+
+void fdt_add_mem_reservation(struct fdt_header *hdr, uint64_t addr, uint64_t len);
+
+#endif  /* _FDT_H */
diff --git a/inc/irq.h b/inc/irq.h
new file mode 100644
index 0000000..af5faba
--- /dev/null
+++ b/inc/irq.h
@@ -0,0 +1,32 @@
+#ifndef _IRQ_H
+#define _IRQ_H
+
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdint.h>
+
+struct irq_handle;
+
+enum irq_trigger {
+	irq_trigger_level,
+	irq_trigger_edge,
+};
+
+enum irq_polarity {
+	irq_polarity_active_high,
+	irq_polarity_active_low,
+};
+
+/* TODO: Add target CPUs here. */
+void irq_config(uint32_t num, enum irq_trigger t, enum irq_polarity p,
+		bool (*cb)(void *, struct irq_handle *), void *context);
+void irq_enable(uint32_t num);
+
+void irq_dismiss(struct irq_handle *h);
+
+/* TODO: These don't really belong here, do they?. */
+bool irq_handle(uint32_t num, struct irq_handle *h);
+void irq_init(void);
+void irq_init_percpu(void);
+
+#endif
diff --git a/inc/list.h b/inc/list.h
new file mode 100644
index 0000000..3001394
--- /dev/null
+++ b/inc/list.h
@@ -0,0 +1,50 @@
+#ifndef _LIST_H
+#define _LIST_H
+
+#include <stdbool.h>
+
+struct list_entry {
+	struct list_entry *next;
+	struct list_entry *prev;
+};
+
+#define LIST_INIT(l) {.next = &l, .prev = &l}
+#define LIST_ELEM(ptr, type, field) \
+	((type*)(char*)ptr - offsetof(type, field))
+
+static inline void list_init(struct list_entry *e)
+{
+	e->next = e;
+	e->prev = e;
+}
+
+static inline void list_append(struct list_entry *l, struct list_entry *e)
+{
+	e->next = l;
+	e->prev = l->prev;
+
+	e->next->prev = e;
+	e->prev->next = e;
+}
+
+static inline void list_prepend(struct list_entry *l, struct list_entry *e)
+{
+	e->next = l->next;
+	e->prev = l;
+
+	e->next->prev = e;
+	e->prev->next = e;
+}
+
+static inline bool list_empty(struct list_entry *l)
+{
+	return l->next == l;
+}
+
+static inline void list_remove(struct list_entry *e)
+{
+	e->prev->next = e->next;
+	e->next->prev = e->prev;
+}
+
+#endif  /* _LIST_H */
diff --git a/inc/spinlock.h b/inc/spinlock.h
new file mode 100644
index 0000000..7761980
--- /dev/null
+++ b/inc/spinlock.h
@@ -0,0 +1,27 @@
+#ifndef _SPINLOCK_H
+#define _SPINLOCK_H
+
+#include <stdatomic.h>
+
+struct spinlock {
+	atomic_flag v;
+};
+
+#define SPINLOCK_INIT {.v = ATOMIC_FLAG_INIT}
+
+static inline void sl_init(struct spinlock *l)
+{
+	*l = (struct spinlock)SPINLOCK_INIT;
+}
+
+static inline void sl_lock(struct spinlock *l)
+{
+	while (atomic_flag_test_and_set_explicit(&l->v, memory_order_acquire));
+}
+
+static inline void sl_unlock(struct spinlock *l)
+{
+	atomic_flag_clear_explicit(&l->v, memory_order_release);
+}
+
+#endif  /* _SPINLOCK_H */
diff --git a/inc/std.h b/inc/std.h
new file mode 100644
index 0000000..d2438a2
--- /dev/null
+++ b/inc/std.h
@@ -0,0 +1,52 @@
+#ifndef _STD_H
+#define _STD_H
+
+#include <stddef.h>
+#include <stdint.h>
+
+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);
+int memcmp(const void *a, const void *b, size_t n);
+
+size_t strlen(const char *str);
+int strcmp(const char *a, const char *b);
+
+static inline uint16_t ntohs(uint16_t v)
+{
+	return v << 8 | v >> 8;
+}
+
+static inline uint32_t ntohl(uint32_t v)
+{
+	/* TODO: no conversion needed if native is big endian. */
+	return (v << 24) |
+	       (v >> 24) |
+	       ((v & 0xff00) << 8) |
+	       ((v & 0xff0000) >> 8);
+}
+
+static inline uint64_t ntohll(uint64_t v)
+{
+	/* TODO: no conversion needed if native is big endian. */
+	return (v << 56) |
+	       (v >> 56) |
+	       ((v & 0xff00) << 40) |
+	       ((v & 0xff000000000000) >> 40) |
+	       ((v & 0xff0000) << 24) |
+	       ((v & 0xff0000000000) >> 24) |
+	       ((v & 0xff000000) << 8) |
+	       ((v & 0xff00000000) >> 8);
+}
+
+static inline uint32_t htonl(uint32_t v)
+{
+	return ntohl(v);
+}
+
+static inline uint64_t htonll(uint64_t v)
+{
+	return ntohll(v);
+}
+
+#endif  /* STD_H */
diff --git a/inc/timer.h b/inc/timer.h
new file mode 100644
index 0000000..aac58c4
--- /dev/null
+++ b/inc/timer.h
@@ -0,0 +1,10 @@
+#ifndef _TIMER_H
+#define _TIMER_H
+
+#include <stdbool.h>
+
+void timer_init(void);
+void timer_init_percpu(void);
+void timer_set(uint64_t time, bool (*cb)(void *), void *context);
+
+#endif  /* _TIMER_H */
diff --git a/inc/vm.h b/inc/vm.h
new file mode 100644
index 0000000..aa9133c
--- /dev/null
+++ b/inc/vm.h
@@ -0,0 +1,14 @@
+#ifndef _VM_H
+#define _VM_H
+
+#include "cpu.h"
+
+struct vm {
+	struct vcpu vcpus[MAX_CPUS];
+	struct arch_page_table page_table;
+};
+
+void vm_init(struct vm *vm, struct cpu *cpus);
+void vm_start_vcpu(struct vm *vm, size_t index, size_t entry, size_t arg);
+
+#endif  /* _VM_H */