Hi -

On 2016-09-06 at 14:10 Ronald G. Minnich wrote:
> +     if (! p512) {
> +             werrstr("page table allocation failed: %r\n");

Just curious - did this work without clobbering the original errstr?
If it did, then I guess printf internally was buffering the input
before clobbering errstr, which is nice.

> +             ret = posix_memalign((void **)&stack, 4096, DEFAULT_STACK_SIZE);
> +             if (ret)
> +                     return ret;
> +             /* touch the top word on the stack so we don't page fault
> +              * on that in the VM. */
> +             stack[DEFAULT_STACK_SIZE/sizeof(uint64_t) - 1] = 0;
> +             vm_tf->tf_rsp = (uint64_t)stack;

I think that sets rsp to the bottom of the stack, instead of the top.

Maybe something like this:

                vm_tf->tf_rsp = &stack[DEFAULT_STACK_SIZE/sizeof(uint64_t) - 1];
                /* touch the top word on the stack so we don't page fault
                 * on that in the VM. */
                *(uintptr_t*)vm_tf->tf_rsp = 0;

(barring compiler warnings, etc).

Also, checkpatch had a few hits.  I fixed those and attached the
edited patch.

Barret

-- 
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.
From: "Ronald G. Minnich" <[email protected]>
Author: "Ronald G. Minnich"
Email: [email protected]
Subject: VMM: add two vthread functions.
Date: Tue, 6 Sep 2016 14:10:12 -0700

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);
}

int main(int argc, char **argv)
{

	vthread_attr_init(vm, 0);
	vthread_create(vm, 0, (uint64_t) vmcall, NULL);

	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           | 175 +++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 186 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..403ca3f 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);
+
 __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..9b7a397
--- /dev/null
+++ b/user/vmm/vthread.c
@@ -0,0 +1,175 @@
+/* Copyright (c) 2016 Google Inc.
+ *
+ * See LICENSE for details.
+ *
+ * Helper functions for virtual machines */
+
+#include <errno.h>
+#include <stdlib.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, int count)
+{
+	void *v;
+	unsigned long flags = MAP_POPULATE | MAP_ANONYMOUS;
+
+	if (addr)
+		flags |= MAP_FIXED;
+	return mmap(addr, count * 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;
+	uint8_t *p;
+
+	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, 2);
+	if (!p512) {
+		werrstr("page table allocation failed: %r\n");
+		return -1;
+	}
+	p1 = &p512[512];
+	vm->root = p512;
+
+	/* 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. */
+	for (i = 0; i < vm->nr_gpcs; i++) {
+		p = page(NULL, 3);
+		if (!p) {
+			werrstr("Can't allocate 3 pages for guest %d: %r", i);
+			return -1;
+		}
+		vm->gpcis[i].posted_irq_desc = &p[0];
+		vm->gpcis[i].vapic_addr = &p[4096];
+		vm->gpcis[i].apic_addr = &p[8192];
+	}
+
+	ret = vmm_init(vm, flags);
+	if (ret)
+		return ret;
+
+	for (i = 0; i < vm->nr_gpcs; i++) {
+		vm_tf = gth_to_vmtf(vm->gths[i]);
+		vm_tf->tf_cr3 = (uint64_t)p512;
+	}
+	vm->vminit = 1;
+
+	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;
+	int i;
+	uint32_t *apic;
+
+	ret = vmsetup(vm, vmmflags);
+	if (ret)
+		return ret;
+
+	for (i = 0; i < vm->nr_gpcs; i++) {
+		apic = vm->gpcis[i].apic_addr;
+		apic[0x30 / 4] = 0x01060015;
+	}
+	return 0;
+}
+
+#define DEFAULT_STACK_SIZE 65536
+/* 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)
+{
+	struct vm_trapframe *vm_tf;
+	int ret;
+	uint64_t *stack;
+
+	if (!vm->vminit)
+		return -EAGAIN;
+
+	if (guest > vm->nr_gpcs)
+		return -ENOENT;
+
+	vm_tf = gth_to_vmtf(vm->gths[guest]);
+
+	/* For now we make the default VM stack pretty small.
+	 * We can grow it as needed. */
+	if (!vm_tf->tf_rsp) {
+		ret = posix_memalign((void **)&stack, 4096, DEFAULT_STACK_SIZE);
+		if (ret)
+			return ret;
+		/* touch the top word on the stack so we don't page fault
+		 * on that in the VM. */
+		stack[DEFAULT_STACK_SIZE/sizeof(uint64_t) - 1] = 0;
+		vm_tf->tf_rsp = (uint64_t)stack;
+	}
+	vm_tf->tf_rip = (uint64_t)rip;
+	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