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.
