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->gths[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 |  3 ++
 user/vmm/vthread.c           | 98 ++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 101 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..b3866e6 100644
--- a/user/vmm/include/vmm/sched.h
+++ b/user/vmm/include/vmm/sched.h
@@ -80,4 +80,7 @@ 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_create(struct guest_thread *g, void *rip, void *arg, void *stack);
+
 __END_DECLS
diff --git a/user/vmm/vthread.c b/user/vmm/vthread.c
new file mode 100644
index 0000000..f470785
--- /dev/null
+++ b/user/vmm/vthread.c
@@ -0,0 +1,98 @@
+/* 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);
+}
+
+/* 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)
+{
+       uint32_t *apic;
+       unsigned long long *p512, *p1, *p2m;
+       struct vm_trapframe *vm_tf;
+
+       if (vm->nr_gpcs == 0) {
+               /* TODO: should we set up for the max cores available? */
+               vm->nr_gpcs = 1;
+               vm->gpcis = calloc(vm->nr_gpcs, sizeof(*vm->gpcis));
+               vm->gpcis->posted_irq_desc = page(NULL);
+               vm->gpcis->vapic_addr = page(NULL);
+               apic = vm->gpcis->apic_addr = page((void *)0xfee00000);
+               memset(apic, 0, 4096);
+               apic[0x30 / 4] = 0x01060015;
+
+               /* For now, only set up page mappings if they did not
+                * ask for anything.  Anything else we can think of
+                * here will get too constraining.  Here's a simple
+                * example: is it possible someone will want a
+                * different guest page table for every guest? Yes. So
+                * we don't want to rule that out. We lock the page
+                * table to 0x1000000 for now. We can't just let it
+                * pick anything as it will pick something the guest
+                * can't address (i.e. outside EPT range). */
+               p512 = page((void *)0x1000000);
+               p1 = page(p512 + 512);
+               p2m = page(p1 + 512);
+
+               /* Allocate 3 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 to point to a page of 2 MiB
+                * PTEs; and a page of 2 MiB PTEs, only a subset of
+                * which will be filled. */
+
+               /* 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 4M to 16M for now.*/
+               p512[PML4(0x400000)] = (uint64_t)p1 | PTE_KERN_RW;
+               p1[PML3(0x400000)] = PTE_PS | PTE_KERN_RW;
+
+               vmm_init(vm, vmmflags);
+               vm_tf = gth_to_vmtf(vm->gths[0]);
+               vm_tf->tf_cr3 = (uint64_t)p512;
+       } else {
+               vmm_init(vm, vmmflags);
+       }
+       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 guest_thread *g, void *rip, void *arg, void *stack)
+{
+       struct vm_trapframe *vm_tf;
+
+       vm_tf = gth_to_vmtf(g);
+       vm_tf->tf_rip = (uint64_t)rip;
+       vm_tf->tf_rsp = (uint64_t)stack;
+       vm_tf->tf_rdi = (uint64_t)arg;
+       start_guest_thread(g);
+       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.

Reply via email to