The intent of these functions it to give users a familiar
API (pthreads). I just had the experience of running the
naming by a non-Akaros person and the reaction was really
positive to the pthreads similarity.
Here's a usage example:
struct virtual_machine vm[1];
static volatile int count;
static void vmcall(void *a)
{
while (count < 1000000) {
__asm__ __volatile__("vmcall\n\t");
count++;
}
count++;
while (1);
}
unsigned long long s[512];
int main(int argc, char **argv)
{
vthread_attr_init(vm, 0);
vthread_create(vm, 0, (uint64_t) vmcall, NULL, &s[511]);
while(count < 2) {
}
return 0;
}
Change-Id: I3e72d8a0efd89482d2f9856daccb7945f7ae1c92
Signed-off-by: Ronald G. Minnich <[email protected]>
---
user/vmm/include/vmm/sched.h | 4 ++
user/vmm/include/vmm/vmm.h | 7 +++
user/vmm/vthread.c | 145 +++++++++++++++++++++++++++++++++++++++++++
3 files changed, 156 insertions(+)
create mode 100644 user/vmm/vthread.c
diff --git a/user/vmm/include/vmm/sched.h b/user/vmm/include/vmm/sched.h
index c9a7136..7fc8fad 100644
--- a/user/vmm/include/vmm/sched.h
+++ b/user/vmm/include/vmm/sched.h
@@ -80,4 +80,8 @@ void start_guest_thread(struct guest_thread *gth);
struct task_thread *vmm_run_task(struct virtual_machine *vm,
void (*func)(void *), void *arg);
+int vthread_attr_init(struct virtual_machine *vm, int vmmflags);
+int vthread_attr_kernel_init(struct virtual_machine *vm, int vmmflags);
+int vthread_create(struct virtual_machine *vm, int guest, void *rip, void
*arg, void *stack);
+
__END_DECLS
diff --git a/user/vmm/include/vmm/vmm.h b/user/vmm/include/vmm/vmm.h
index 5139b2a..6577651 100644
--- a/user/vmm/include/vmm/vmm.h
+++ b/user/vmm/include/vmm/vmm.h
@@ -27,12 +27,19 @@ struct virtual_machine {
struct guest_thread **gths;
unsigned int nr_gpcs;
struct vmm_gpcore_init *gpcis;
+ bool vminit;
/* TODO: put these in appropriate structures. e.g., virtio things in
* something related to virtio. low4k in something related to the
guest's
* memory. */
uint8_t *low4k;
struct virtio_mmio_dev
*virtio_mmio_devices[VIRTIO_MMIO_MAX_NUM_DEV];
+
+ /* Default root pointer to use if one is not set in a
+ * guest thread. We expect this to be the common case,
+ * where all guests share a page table. It's not required
+ * however. */
+ void *root;
};
char *regname(uint8_t reg);
diff --git a/user/vmm/vthread.c b/user/vmm/vthread.c
new file mode 100644
index 0000000..74de0bc
--- /dev/null
+++ b/user/vmm/vthread.c
@@ -0,0 +1,145 @@
+/* Copyright (c) 2016 Google Inc.
+ *
+ * See LICENSE for details.
+ *
+ * Helper functions for virtual machines */
+
+#include <errno.h>
+#include <parlib/bitmask.h>
+#include <parlib/uthread.h>
+#include <sys/mman.h>
+#include <sys/syscall.h>
+#include <vmm/vmm.h>
+
+static void *page(void *addr)
+{
+ void *v;
+ unsigned long flags = MAP_POPULATE | MAP_ANONYMOUS;
+
+ if (addr)
+ flags |= MAP_FIXED;
+ return mmap(addr, 4096, PROT_READ | PROT_WRITE, flags, -1, 0);
+}
+
+/* vmsetup is a basic helper function used by vthread_attr_init
+ * and vthread_attr_kernel_init. */
+static int vmsetup(struct virtual_machine *vm, int flags)
+{
+ unsigned long long *p512, *p1;
+ struct vm_trapframe *vm_tf;
+ int i, ret;
+
+ if (vm->vminit)
+ return -EBUSY;
+
+ if (vm->nr_gpcs == 0)
+ vm->nr_gpcs = 1;
+
+ vm->gpcis = calloc(vm->nr_gpcs, sizeof(*vm->gpcis));
+
+ /* Set up default page mappings. The common case,
+ * for user VM threads and kernel VM threads, is that
+ * they need some kind of initial page tables. The kernels
+ * will almost always throw them away; the user VM threads
+ * will almost always continue to use them. Using two
+ * pages and setting up an initial page table is
+ * cheap and makes users lives easier. This initial
+ * page table can grow to 512 GiB, which should be enough
+ * for now.
+ *
+ * At the same time, we allow users to select other
+ * arrangements if they wish. Here's a simple example: is it
+ * possible someone will want a different guest page table for
+ * every guest? Yes.
+ *
+ * We lock the page table to 0x1000000 for now. We can't just
+ * let it pick anything as it may pick something the guest
+ * can't address (i.e. outside EPT range). */
+
+ /* Allocate 2 pages for page table pages: a page of
+ * 512 GiB PTEs with only one entry filled to point to
+ * a page of 1 GiB PTEs; a page of 1 GiB PTEs with
+ * only one entry filled. */
+
+ p512 = page((void *)0x1000000);
+ p1 = page(p512 + 512);
+
+ /* Set up a 1:1 ("identity") page mapping from host
+ * virtual to guest physical for 1 GiB. This mapping
+ * is used unless the guest (e.g. Linux) sets up its
+ * own page tables. Be aware that the values stored in
+ * the table are physical addresses. This is subtle
+ * and mistakes are easily disguised due to the
+ * identity mapping, so take care when manipulating
+ * these mappings. Note: we don't yet have symbols for
+ * "start of virtual address common to host and guest"
+ * so we just use the first GiB for now. */
+ p512[PML4(0x400000)] = (uint64_t)p1 | PTE_KERN_RW;
+ p1[PML3(0x400000)] = PTE_PS | PTE_KERN_RW;
+
+ /* technically, we don't need these pages for the
+ * all guests. Currently, the kernel requires them. */
+ vm->gpcis->posted_irq_desc = page(NULL);
+ vm->gpcis->vapic_addr = page(NULL);
+ vm->gpcis->apic_addr = page((void *)0xfee00000);
+
+ ret = vmm_init(vm, flags);
+ if (ret)
+ return ret;
+
+ vm->vminit = 1;
+ vm->root = p512;
+ for (i = 0; i < vm->nr_gpcs; i++){
+ vm_tf = gth_to_vmtf(vm->gths[i]);
+ vm_tf->tf_cr3 = (uint64_t)p512;
+ }
+
+ return 0;
+}
+/* vthread_addr sets up a virtual_machine struct such that functions
+ * can start up VM guests. It is like pthread_attr in that it sets up
+ * default attributes and can be used in vthread_create calls. If
+ * vm->nrgpcs is not set then the vm will be set up for 1 guest. */
+int vthread_attr_init(struct virtual_machine *vm, int vmmflags)
+{
+ return vmsetup(vm, vmmflags);
+}
+
+/* vthread_attr_kernel_init sets up minimum basic attributes for
+ * running a kernel, as opposed to just user mode. This setup
+ * includes an APIC page at 0xfee00000, to be shared by all cores. */
+int vthread_attr_kernel_init(struct virtual_machine *vm, int vmmflags)
+{
+ int ret;
+ uint32_t *apic;
+
+ ret = vmsetup(vm, vmmflags);
+ if (ret)
+ return ret;
+
+ apic = vm->gpcis->apic_addr;
+ memset(apic, 0, 4096);
+ apic[0x30 / 4] = 0x01060015;
+ return 0;
+}
+
+/* vthread_create creates and starts a VM guest. The interface is intended
+ * to be as much like pthread_create as possible. */
+int vthread_create(struct virtual_machine *vm, int guest, void *rip, void
*arg, void *stack)
+{
+ struct vm_trapframe *vm_tf;
+
+ if (!vm->vminit) {
+ return -EAGAIN;
+ }
+
+ if (guest > vm->nr_gpcs)
+ return -ENOENT;
+
+ vm_tf = gth_to_vmtf(vm->gths[guest]);
+ vm_tf->tf_rip = (uint64_t)rip;
+ vm_tf->tf_rsp = (uint64_t)stack;
+ vm_tf->tf_rdi = (uint64_t)arg;
+ start_guest_thread(vm->gths[guest]);
+ return 0;
+}
--
2.8.0.rc3.226.g39d4020
--
You received this message because you are subscribed to the Google Groups
"Akaros" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
To post to this group, send email to [email protected].
For more options, visit https://groups.google.com/d/optout.