Get oprofile working more correctly.
[akaros.git] / kern / drivers / dev / vm.c
index 9587fe7..3067594 100644 (file)
@@ -37,25 +37,18 @@ enum {
        Qimage,
 };
 
-/* This paddr/kaddr is a bit dangerous.  it'll work so long as we don't need all
- * 64 bits for a physical address (48 is the current norm on x86_64).
- * We're probably going to move to a model where we put the VM index or something
- * into the qid, but this works for now.
+/* The QID is the TYPE and the index into the vms array.
+ * We reserve the right to make it an id later.
  */
-#define ADDR_SHIFT 5
-#define QID2VM(q) ((struct vm*)KADDR(((q).path >> ADDR_SHIFT)))
-#define TYPE(q) ((q).path & ((1 << ADDR_SHIFT) - 1))
-#define QID(ptr, type) ((PADDR(ptr) << ADDR_SHIFT) | type)
-
+#define ID_SHIFT 5
 /* vm's have an image.
  * Note that the image can be read even as it is running. */
 struct vm {
-       struct vm *next;
        struct kref kref;
        /* should this be an array of pages? Hmm. */
        void *image;
        unsigned long imagesize;
-       int id;
+       int id; // not used yet. 
        struct litevm *archvm;
 };
 
@@ -63,14 +56,41 @@ static spinlock_t vmlock;
 /* array, not linked list. We expect few, might as well be cache friendly. */
 static struct vm *vms = NULL;
 static int nvm = 0;
+static int vmok = 0;
 
 static spinlock_t vmidlock[1];
 static struct kref vmid[1] = { {(void *)1, fake_release} };
 
+/* not clear what .h to put these in. Put them here. */
+
+struct litevm *vmx_open(void);
+int vmx_create_vcpu(struct litevm *litevm, int n);
+int vmx_init(void);
+int vm_set_memory_region(struct litevm *litevm,
+                                                struct litevm_memory_region *mem);
+int vm_run(struct litevm *litevm, struct litevm_run *litevm_run);
+
+static inline struct vm *
+QID2VM(struct qid q)
+{
+       return &vms[((q).path >> ID_SHIFT)];
+}
+
+static inline int 
+TYPE(struct qid q)
+{
+       return ((q).path & ((1 << ID_SHIFT) - 1));
+}
+
+static inline int QID(int index, int type)
+{
+       return ((index << ID_SHIFT) | type);
+}
+
 /* we'll need this somewhere more generic. */
 static void readn(struct chan *c, void *vp, long n)
 {
-       print_func_entry();
+       //print_func_entry();
        char *p;
        long nn;
        int total = 0, want = n;
@@ -80,18 +100,19 @@ static void readn(struct chan *c, void *vp, long n)
                nn = devtab[c->type].read(c, p, n, c->offset);
                printk("readn: Got %d@%lld\n", nn, c->offset);
                if (nn == 0)
-                       error("%s: wanted %d, got %d", Eshort, total, want);
+                       error("%s: wanted %d, got %d", Eshort, want, total);
                c->offset += nn;
                p += nn;
                n -= nn;
                total += nn;
        }
-       print_func_exit();
+       //print_func_exit();
 }
 
+/* not called yet.  -- we have to unlink the vm */
 static void vm_release(struct kref *kref)
 {
-       print_func_entry();
+       //print_func_entry();
        struct vm *v = container_of(kref, struct vm, kref);
        spin_lock_irqsave(&vmlock);
        /* cute trick. Save the last element of the array in place of the
@@ -109,7 +130,7 @@ static void vm_release(struct kref *kref)
        }
        nvm--;
        spin_unlock(&vmlock);
-       print_func_exit();
+       //print_func_exit();
 }
 
 /* VM ids run in the range 1..infinity. But vmx.c wants them
@@ -117,13 +138,13 @@ static void vm_release(struct kref *kref)
  */
 static int newvmid(void)
 {
-       print_func_entry();
+       //print_func_entry();
        int id;
        spin_lock_irqsave(vmidlock);
        id = kref_refcnt(vmid);
        kref_get(vmid, 1);
        spin_unlock(vmidlock);
-       print_func_exit();
+       //print_func_exit();
        return id - 1;
 }
 
@@ -131,7 +152,7 @@ static int vmgen(struct chan *c, char *entry_name,
                                 struct dirtab *unused, int unused_nr_dirtab,
                                 int s, struct dir *dp)
 {
-       print_func_entry();
+       //print_func_entry();
        struct qid q;
        struct vm *vm_i;
        printd("GEN s %d\n", s);
@@ -139,7 +160,7 @@ static int vmgen(struct chan *c, char *entry_name,
        if (s == DEVDOTDOT) {
                mkqid(&q, Qtopdir, 0, QTDIR);
                devdir(c, c->qid, "#V", 0, eve, 0555, dp);
-               print_func_exit();
+               //print_func_exit();
                return 1;
        }
        printd("TYPE %d\n", TYPE(c->qid));
@@ -151,14 +172,14 @@ static int vmgen(struct chan *c, char *entry_name,
                        if (s == 0) {
                                mkqid(&q, Qclone, 0, QTFILE);
                                devdir(c, q, "clone", 0, eve, 0666, dp);
-                               print_func_exit();
+                               //print_func_exit();
                                return 1;
                        }
                        s--;
                        if (s == 0) {
                                mkqid(&q, Qstat, 0, QTFILE);
                                devdir(c, q, "stat", 0, eve, 0666, dp);
-                               print_func_exit();
+                               //print_func_exit();
                                return 1;
                        }
                        s--;    /* 1 -> 0th element, 2 -> 1st element, etc */
@@ -166,32 +187,32 @@ static int vmgen(struct chan *c, char *entry_name,
                        if (s >= nvm) {
                                printd("DONE qtopdir\n");
                                spin_unlock(&vmlock);
-                               print_func_exit();
+                               //print_func_exit();
                                return -1;
                        }
                        vm_i = &vms[s];
                        snprintf(get_cur_genbuf(), GENBUF_SZ, "vm%d", vm_i->id);
                        spin_unlock(&vmlock);
-                       mkqid(&q, QID(vm_i, Qvmdir), 0, QTDIR);
+                       mkqid(&q, QID(s, Qvmdir), 0, QTDIR);
                        devdir(c, q, get_cur_genbuf(), 0, eve, 0555, dp);
-                       print_func_exit();
+                       //print_func_exit();
                        return 1;
                case Qvmdir:
                        /* Gen the contents of the vm dirs */
                        s += Qctl;      /* first time through, start on Qctl */
                        switch (s) {
                                case Qctl:
-                                       mkqid(&q, QID(QID2VM(c->qid), Qctl), 0, QTFILE);
+                                       mkqid(&q, QID(s-Qctl, Qctl), 0, QTFILE);
                                        devdir(c, q, "ctl", 0, eve, 0666, dp);
-                                       print_func_exit();
+                                       //print_func_exit();
                                        return 1;
                                case Qimage:
-                                       mkqid(&q, QID(QID2VM(c->qid), Qimage), 0, QTFILE);
+                                       mkqid(&q, QID(s-Qctl, Qimage), 0, QTFILE);
                                        devdir(c, q, "image", 0, eve, 0666, dp);
-                                       print_func_exit();
+                                       //print_func_exit();
                                        return 1;
                        }
-                       print_func_exit();
+                       //print_func_exit();
                        return -1;
                        /* Need to also provide a direct hit for Qclone and all other files (at
                         * all levels of the hierarchy).  Every file is both
@@ -206,59 +227,62 @@ static int vmgen(struct chan *c, char *entry_name,
                         * stat output (check the -1 case in devstat). */
                case Qclone:
                        devdir(c, c->qid, "clone", 0, eve, 0666, dp);
-                       print_func_exit();
+                       //print_func_exit();
                        return 1;
                case Qstat:
                        devdir(c, c->qid, "stat", 0, eve, 0444, dp);
-                       print_func_exit();
+                       //print_func_exit();
                        return 1;
                case Qctl:
                        devdir(c, c->qid, "ctl", 0, eve, 0666, dp);
-                       print_func_exit();
+                       //print_func_exit();
                        return 1;
                case Qimage:
                        devdir(c, c->qid, "image", 0, eve, 0666, dp);
-                       print_func_exit();
+                       //print_func_exit();
                        return 1;
        }
-       print_func_exit();
+       //print_func_exit();
        return -1;
 }
 
 static void vminit(void)
 {
-       return;
-       print_func_entry();
+       //print_func_entry();
        int i;
        spinlock_init_irqsave(&vmlock);
        spinlock_init_irqsave(vmidlock);
        i = vmx_init();
+       if (i == 0)
+               vmok = 1;
        printk("vminit: litevm_init returns %d\n", i);
 
-       print_func_exit();
+       //print_func_exit();
 }
 
 static struct chan *vmattach(char *spec)
 {
-       print_func_entry();
+       //print_func_entry();
+       if (!vmok)
+               error("No VMs available");
        struct chan *c = devattach('V', spec);
        mkqid(&c->qid, Qtopdir, 0, QTDIR);
-       print_func_exit();
+       //print_func_exit();
        return c;
 }
 
 static struct walkqid *vmwalk(struct chan *c, struct chan *nc, char **name,
                                                          int nname)
 {
-       print_func_entry();
-       print_func_exit();
+       //print_func_entry();
+       //print_func_exit();
        return devwalk(c, nc, name, nname, 0, 0, vmgen);
 }
 
 static int vmstat(struct chan *c, uint8_t * db, int n)
 {
-       print_func_entry();
-       print_func_exit();
+       //print_func_entry();
+       //print_func_exit();
        return devstat(c, db, n, 0, 0, vmgen);
 }
 
@@ -266,7 +290,7 @@ static int vmstat(struct chan *c, uint8_t * db, int n)
  * the open chan into p's fd table, then decref the chan. */
 static struct chan *vmopen(struct chan *c, int omode)
 {
-       print_func_entry();
+       //print_func_entry();
        ERRSTACK(1);
        struct vm *v = QID2VM(c->qid);
        printk("vmopen: v is %p\n", v);
@@ -289,7 +313,7 @@ static struct chan *vmopen(struct chan *c, int omode)
                        spin_unlock(&vmlock);
                        kref_init(&v->kref, vm_release, 1);
                        v->id = newvmid();
-                       mkqid(&c->qid, QID(v, Qctl), 0, QTFILE);
+                       mkqid(&c->qid, QID(nvm, Qctl), 0, QTFILE);
                        c->aux = v;
                        printd("New VM id %d\n", v->id);
                        v->archvm = vmx_open();
@@ -301,13 +325,16 @@ static struct chan *vmopen(struct chan *c, int omode)
                                printk("vm_create failed");
                                error("vm_create failed");
                        }
+                       printk("Qclone open: id %d, v is %p, v->archvm is %p\n", 
+                                       nvm-1,
+                                       v, v->archvm);
                        break;
                case Qstat:
                        break;
                case Qctl:
                case Qimage:
                        c->aux = QID2VM(c->qid);
-                       printk("open qctl: aux is %p\n", c->aux);
+                       printk("open qctl: aux (vm) is %p\n", c->aux);
                        break;
        }
        c->mode = openmode(omode);
@@ -315,45 +342,45 @@ static struct chan *vmopen(struct chan *c, int omode)
        c->flag |= COPEN;
        c->offset = 0;
        poperror();
-       print_func_exit();
+       //print_func_exit();
        return c;
 }
 
 static void vmcreate(struct chan *c, char *name, int omode, uint32_t perm)
 {
-       print_func_entry();
+       //print_func_entry();
        error(Eperm);
-       print_func_exit();
+       //print_func_exit();
 }
 
 static void vmremove(struct chan *c)
 {
-       print_func_entry();
+       //print_func_entry();
        error(Eperm);
-       print_func_exit();
+       //print_func_exit();
 }
 
 static int vmwstat(struct chan *c, uint8_t * dp, int n)
 {
-       print_func_entry();
+       //print_func_entry();
        error("No vmwstat");
-       print_func_exit();
+       //print_func_exit();
        return 0;
 }
 
 static void vmclose(struct chan *c)
 {
-       print_func_entry();
+       //print_func_entry();
        struct vm *v = c->aux;
        if (!v) {
-               print_func_exit();
+               //print_func_exit();
                return;
        }
        /* There are more closes than opens.  For instance, sysstat doesn't open,
         * but it will close the chan it got from namec.  We only want to clean
         * up/decref chans that were actually open. */
        if (!(c->flag & COPEN)) {
-               print_func_exit();
+               //print_func_exit();
                return;
        }
        switch (TYPE(c->qid)) {
@@ -364,40 +391,40 @@ static void vmclose(struct chan *c)
                        kref_put(&v->kref);
                        break;
        }
-       print_func_exit();
+       //print_func_exit();
 }
 
 static long vmread(struct chan *c, void *ubuf, long n, int64_t offset)
 {
-       print_func_entry();
+       //print_func_entry();
        struct vm *v = c->aux;
        printd("VMREAD\n");
        switch (TYPE(c->qid)) {
                case Qtopdir:
                case Qvmdir:
-                       print_func_exit();
+                       //print_func_exit();
                        return devdirread(c, ubuf, n, 0, 0, vmgen);
                case Qstat:
-                       print_func_exit();
+                       //print_func_exit();
                        return readnum(offset, ubuf, n, nvm, NUMSIZE32);
                case Qctl:
                        assert(v);
-                       print_func_exit();
+                       //print_func_exit();
                        return readnum(offset, ubuf, n, v->id, NUMSIZE32);
                case Qimage:
                        assert(v);
-                       print_func_exit();
+                       //print_func_exit();
                        return readmem(offset, ubuf, n, v->image, v->imagesize);
                default:
                        panic("Bad QID %p in devvm", c->qid.path);
        }
-       print_func_exit();
+       //print_func_exit();
        return 0;
 }
 
 static long vmwrite(struct chan *c, void *ubuf, long n, int64_t unused)
 {
-       print_func_entry();
+       //print_func_entry();
        ERRSTACK(3);
        char buf[32];
        struct cmdbuf *cb;
@@ -412,6 +439,8 @@ static long vmwrite(struct chan *c, void *ubuf, long n, int64_t unused)
                        error(Eperm);
                case Qctl:
                        vm = c->aux;
+                       litevm = vm->archvm;
+                       printk("qctl: vm is %p, litevm is %p\n", vm, litevm);
                        cb = parsecmd(ubuf, n);
                        if (waserror()) {
                                kfree(cb);
@@ -421,22 +450,22 @@ static long vmwrite(struct chan *c, void *ubuf, long n, int64_t unused)
                                int ret;
                                if (cb->nf != 4)
                                        error("usage: run vcpu emulated mmio_completed");
-                               litevm = vm->archvm;
                                struct litevm_run vmr;
                                vmr.vcpu = strtoul(cb->f[1], NULL, 0);
                                vmr.emulated = strtoul(cb->f[2], NULL, 0);
                                vmr.mmio_completed = strtoul(cb->f[3], NULL, 0);
+                               disable_irq();
                                ret = vm_run(litevm, &vmr);
+                               enable_irq();
                                printk("vm_run returns %d\n", ret);
-                               print_func_exit();
+                               //print_func_exit();
                                return ret;
                        } else if (!strcmp(cb->f[0], "stop")) {
                                error("can't stop a vm yet");
-                       } else if (!strcmp(cb->f[0], "fillmem")) {
+                       } else if (!strcmp(cb->f[0], "mapmem")) {
                                struct chan *file;
                                void *v;
                                vm = c->aux;
-                               litevm = vm->archvm;
                                uint64_t filesize;
                                struct litevm_memory_region vmr;
                                int got;
@@ -452,6 +481,7 @@ static long vmwrite(struct chan *c, void *ubuf, long n, int64_t unused)
                                file = namec(cb->f[1], Aopen, OREAD, 0);
                                printk("after namec file is %p\n", file);
                                if (waserror()) {
+                                       printk("File open, alloc bad\n");
                                        cclose(file);
                                        nexterror();
                                }
@@ -461,6 +491,8 @@ static long vmwrite(struct chan *c, void *ubuf, long n, int64_t unused)
                                 */
                                v = kmalloc(vmr.memory_size, KMALLOC_WAIT);
                                if (waserror()) {
+                                       printk("memory allocated, read bad %s\n", 
+                                               current_errstr());
                                        kfree(v);
                                        nexterror();
                                }
@@ -470,6 +502,8 @@ static long vmwrite(struct chan *c, void *ubuf, long n, int64_t unused)
 
                                if (vm_set_memory_region(litevm, &vmr))
                                        error("vm_set_memory_region failed");
+                               void monitor(void *);
+                               monitor(NULL);
                                poperror();
                                poperror();
                                kfree(v);
@@ -478,13 +512,13 @@ static long vmwrite(struct chan *c, void *ubuf, long n, int64_t unused)
                        } else if (!strcmp(cb->f[0], "region")) {
                                void *v;
                                struct litevm_memory_region vmr;
-                               litevm = vm->archvm;
                                if (cb->nf != 5)
                                        error("usage: mapmem slot flags addr size");
-                               vmr.slot = strtoul(cb->f[2], NULL, 0);
-                               vmr.flags = strtoul(cb->f[3], NULL, 0);
-                               vmr.guest_phys_addr = strtoul(cb->f[4], NULL, 0);
-                               vmr.memory_size = strtoul(cb->f[5], NULL, 0);
+                               vmr.slot = strtoul(cb->f[1], NULL, 0);
+                               vmr.flags = strtoul(cb->f[2], NULL, 0);
+                               vmr.guest_phys_addr = strtoul(cb->f[3], NULL, 0);
+                               vmr.memory_size = strtoul(cb->f[4], NULL, 0);
+                               vmr.init_data = NULL;
                                if (vm_set_memory_region(litevm, &vmr))
                                        error("vm_set_memory_region failed");
                        } else {
@@ -499,7 +533,7 @@ static long vmwrite(struct chan *c, void *ubuf, long n, int64_t unused)
                default:
                        panic("Bad QID %p in devvm", c->qid.path);
        }
-       print_func_exit();
+       //print_func_exit();
        return n;
 }