sooner or later I'll get this right. Probably later.

On Tue, Sep 6, 2016 at 9:59 AM Ronald G. Minnich <[email protected]> wrote:

> 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.

Reply via email to