Removes debugging code
[akaros.git] / kern / drivers / dev / nix.c
index a3269ba..c1cb598 100644 (file)
@@ -6,6 +6,55 @@
  *
  * devnix/#t: a device for NIX mode
  *
+ * A struct nix is a "visitor" chunk of code.  It has a memory image, and can be
+ * told to run an arbitrary address (in that image or otherwise) in kernel mode
+ * on various pcores, to which it has exclusive access.
+ *
+ * TODO:
+ *
+ * - FOR THE MOMENT, this is only intended to run one NIX at a time.  Too many
+ * sharp edges for any other mode.
+ *
+ * - memory images: we have one now for all nixs.  that'll be a mess.
+ *
+ * - what do we want to do for refcnting?  decref on chan close?  or remove?
+ * how do we manage the struct nix memory? (MGMT)
+ *             - right now, we aren't decreffing at all.  it's easier to work with from
+ *             the shell, but it's definitely a debugging thing.  the proper way to do
+ *             these devices is to release on close (i think).  the use case for the
+ *             NIX is a "turn it on once and reboot if you don't like it", so this is
+ *             fine for now.
+ *             - we're using c->aux, which needs to be an uncounted ref, in my opinion.
+ *             i messed around with this for a long time with devsrv, and all the
+ *             different ways 9ns interacts with a device make it very tricky.
+ *             - once we start freeing, we'll need to manage the memory better.  if we
+ *             have holes in the nixs[], we'll need to handle that in nixgen
+ *
+ * - how are we going to stop a nix?
+ *             - graceful vs immediate?  with some sort of immediate power-cord style
+ *             halting, the entire nix is garbage once we pull the plug.  a more
+ *             graceful style would require the nix to poll or something - probably
+ *             overkill.
+ *             - could send an immediate kmsg (IPI), but we'd need to do some
+ *             bookkeeping to know we're interrupting a NIX and whatnot
+ *             - if we were sure it's a nix core, we might be able to send an immediate
+ *             message telling the core to just smp_idle.  doing that from hard IRQ
+ *             would break a little, so we'd need to be careful (adjust various
+ *             flags, etc).
+ *             - another option would be to hack the halted context and have it call
+ *             a cleanup function (which ultimately smp_idles)
+ *             - if we had a process running the core, and "running the NIX" was a
+ *             syscall or something, we'd want to abort the syscall.  but since the
+ *             syscall isn't trying to rendez or sleep, we couldn't use the existing
+ *             facilities.  so it's the same problem: know it is a nix, somehow
+ *             kill/cleanup.  then just smp_idle.
+ *             - we'll also need to unreserve a core first, so we don't have any
+ *             concurrent startups.  careful of various races with cores coming and
+ *             going.  we can lock the nix before sending the message, but stale RKMs
+ *             could exist for a while.
+ *             - maybe we use a ktask, named nixID or something, to help detect if a
+ *             nix is running.  might also need to track the number of messages sent
+ *             and completed (track completed via the wrapper)
  */
 
 #include <kmalloc.h>
@@ -23,7 +72,6 @@
 #include <umem.h>
 #include <devalarm.h>
 #include <arch/types.h>
-#include <arch/nix.h>
 #include <arch/emulate.h>
 #include <arch/vmdebug.h>
 #include <kdebug.h>
@@ -40,9 +88,8 @@ enum {
 };
 
 /* The QID is the TYPE and the index into the nix array.
- * We reserve the right to make it an id later.
- */
-#define ID_SHIFT 5
+ * We reserve the right to make it an id later. */
+#define INDEX_SHIFT 5
 /* nix's have an image.
  * Note that the image can be read even as it is running. */
 struct nix {
@@ -50,68 +97,42 @@ struct nix {
        /* should this be an array of pages? Hmm. */
        void *image;
        unsigned long imagesize;
-       int id; // not used yet.
+       int id;
        /* we could dynamically alloc one of these with num_cpus */
        DECLARE_BITMAP(cpus, MAX_NUM_CPUS);
 };
 
-static spinlock_t nixlock;
+static spinlock_t nixlock = SPINLOCK_INITIALIZER_IRQSAVE;
 /* array, not linked list. We expect few, might as well be cache friendly. */
 static struct nix *nixs = NULL;
 static int nnix = 0;
 static int nixok = 0;
-static int npages;
-// only 4 gig for now.
-static page_t *nixpages[1048576];
-
-static spinlock_t nixidlock[1];
-static struct kref nixid[1] = { {(void *)1, fake_release} };
+/* TODO: make this per-nix, somehow. */
+static physaddr_t img_paddr = CONFIG_NIX_IMG_PADDR;
+static size_t img_size = CONFIG_NIX_IMG_SIZE;
 
-//int nix_run(struct nix *nix, struct nix_run *nix_run);
+static atomic_t nixid = 0;
 
-static inline struct nix *
-QID2NIX(struct qid q)
+/* The index is not the id, for now.  The index is the spot in nixs[].  The id
+ * is an increasing integer, regardless of struct nix* reuse. */
+static inline struct nix *QID2NIX(struct qid q)
 {
-       return &nixs[((q).vers)];
+       return &nixs[q.path >> INDEX_SHIFT];
 }
 
-static inline int
-TYPE(struct qid q)
+static inline int TYPE(struct qid q)
 {
-       return ((q).path & ((1 << ID_SHIFT) - 1));
+       return ((q).path & ((1 << INDEX_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();
-       char *p;
-       long nn;
-       int total = 0, want = n;
-
-       p = vp;
-       while (n > 0) {
-               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, want, total);
-               c->offset += nn;
-               p += nn;
-               n -= nn;
-               total += nn;
-       }
-       print_func_exit();
+       return ((index << INDEX_SHIFT) | type);
 }
 
-/* not called yet.  -- we have to unlink the nix */
+/* TODO: (MGMT) not called yet.  -- we have to unlink the nix */
 static void nix_release(struct kref *kref)
 {
-       print_func_entry();
        struct nix *v = container_of(kref, struct nix, kref);
        spin_lock_irqsave(&nixlock);
        /* cute trick. Save the last element of the array in place of the
@@ -121,7 +142,9 @@ static void nix_release(struct kref *kref)
         * the QIDs, which have pointers embedded in them.
         * darn it, may have to use a linked list. Nope, will probably
         * just walk the array until we find a matching id. Still ... yuck.
-        */
+        *
+        * If we have lots, we can track the lowest free, similar to FDs and low_fd.
+        * honestly, we need an integer allocator (vmem and magazine paper) */
        if (v != &nixs[nnix - 1]) {
                /* free the image ... oops */
                /* get rid of the kref. */
@@ -129,71 +152,53 @@ static void nix_release(struct kref *kref)
        }
        nnix--;
        spin_unlock(&nixlock);
-       print_func_exit();
 }
 
-/* NIX ids run in the range 1..infinity.
- */
+/* NIX ids run in the range 0..infinity.  */
 static int newnixid(void)
 {
-       print_func_entry();
-       int id;
-       spin_lock_irqsave(nixidlock);
-       id = kref_refcnt(nixid);
-       kref_get(nixid, 1);
-       spin_unlock(nixidlock);
-       print_func_exit();
-       return id - 1;
+       return atomic_fetch_and_add(&nixid, 1);
 }
 
 static int nixgen(struct chan *c, char *entry_name,
                   struct dirtab *unused, int unused_nr_dirtab,
                   int s, struct dir *dp)
 {
-       print_func_entry();
        struct qid q;
        struct nix *nix_i;
-       printd("GEN s %d\n", s);
        /* Whether we're in one dir or at the top, .. still takes us to the top. */
        if (s == DEVDOTDOT) {
                mkqid(&q, Qtopdir, 0, QTDIR);
                devdir(c, c->qid, "#V", 0, eve, 0555, dp);
-               print_func_exit();
                return 1;
        }
-       printd("TYPE %d\n", TYPE(c->qid));
        switch (TYPE(c->qid)) {
        case Qtopdir:
-               printd("Qtopdir s %d nnix %d\n", s, nnix);
                /* Generate elements for the top level dir.  We support clone, stat,
                 * nix dirs at the top level */
                if (s == 0) {
                        mkqid(&q, Qclone, 0, QTFILE);
                        devdir(c, q, "clone", 0, eve, 0666, dp);
-                       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();
                        return 1;
                }
                s--;    /* 1 -> 0th element, 2 -> 1st element, etc */
                spin_lock_irqsave(&nixlock);
                if (s >= nnix) {
-                       printd("DONE qtopdir\n");
                        spin_unlock(&nixlock);
-                       print_func_exit();
                        return -1;
                }
                nix_i = &nixs[s];
+               /* TODO (MGMT): if no nix_i, advance (in case of holes) */
                snprintf(get_cur_genbuf(), GENBUF_SZ, "nix%d", nix_i->id);
                spin_unlock(&nixlock);
                mkqid(&q, QID(s, Qnixdir), 0, QTDIR);
                devdir(c, q, get_cur_genbuf(), 0, eve, 0555, dp);
-               print_func_exit();
                return 1;
        case Qnixdir:
                /* Gen the contents of the nix dirs */
@@ -202,15 +207,12 @@ static int nixgen(struct chan *c, char *entry_name,
                case Qctl:
                        mkqid(&q, QID(s-Qctl, Qctl), 0, QTFILE);
                        devdir(c, q, "ctl", 0, eve, 0666, dp);
-                       print_func_exit();
                        return 1;
                case Qimage:
                        mkqid(&q, QID(s-Qctl, Qimage), 0, QTFILE);
                        devdir(c, q, "image", 0, eve, 0666, dp);
-                       print_func_exit();
                        return 1;
                }
-               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
@@ -225,79 +227,61 @@ static int nixgen(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();
                return 1;
        case Qstat:
                devdir(c, c->qid, "stat", 0, eve, 0444, dp);
-               print_func_exit();
                return 1;
        case Qctl:
                devdir(c, c->qid, "ctl", 0, eve, 0666, dp);
-               print_func_exit();
                return 1;
        case Qimage:
                devdir(c, c->qid, "image", 0, eve, 0666, dp);
-               print_func_exit();
                return 1;
        }
-       print_func_exit();
        return -1;
 }
 
 void nixtest(void)
 {
-       printk("nixtest\n");
+       printk("nixtest ran on core %d\n", core_id());
 }
 
-// allocate pages, starting at 1G, and running until we run out.
 static void nixinit(void)
 {
-       //error_t kpage_alloc_specific(page_t** page, size_t ppn)
-       print_func_entry();
-       uint64_t ppn = GiB/4096;
-       spinlock_init_irqsave(&nixlock);
-       spinlock_init_irqsave(nixidlock);
-       while (1) {
-               if (!page_is_free(ppn)) {
-                       printk("%s: got a non-free page@ppn %p\n", __func__, ppn);
-                       break;
-               }
-               kpage_alloc_specific(&nixpages[ppn], ppn);
-               npages++;
-               ppn++;
-       }
-       printk("nixinit: nix_init returns %d\n", npages);
+       size_t img_order = LOG2_UP(nr_pages(img_size));
+       void *img_kaddr;
 
-       if (npages > 0) {
-               nixok = 1;
+       if (img_size != 1ULL << img_order << PGSHIFT) {
+               printk("nixinit rounding up image size to a power of 2 pgs (was %p)\n",
+                      img_size);
+               img_size = 1ULL << img_order << PGSHIFT;
        }
-
-       print_func_exit();
+       img_kaddr = get_cont_phys_pages_at(img_order, img_paddr, 0);
+       if (!img_kaddr) {
+               printk("nixinit failed to get an image!\n");
+               return;
+       }
+       nixok = 1;
+       printk("nixinit image at KVA %p of size %p\n", img_kaddr, img_size);
 }
 
 static struct chan *nixattach(char *spec)
 {
-       print_func_entry();
        if (!nixok)
                error("No NIXs available");
        struct chan *c = devattach('t', spec);
        mkqid(&c->qid, Qtopdir, 0, QTDIR);
-       print_func_exit();
        return c;
 }
 
 static struct walkqid *nixwalk(struct chan *c, struct chan *nc, char **name,
                                int nname)
 {
-       print_func_entry();
-       print_func_exit();
        return devwalk(c, nc, name, nname, 0, 0, nixgen);
 }
 
 static int nixstat(struct chan *c, uint8_t * db, int n)
 {
-       print_func_entry();
-       print_func_exit();
        return devstat(c, db, n, 0, 0, nixgen);
 }
 
@@ -305,10 +289,8 @@ static int nixstat(struct chan *c, uint8_t * db, int n)
  * the open chan into p's fd table, then decref the chan. */
 static struct chan *nixopen(struct chan *c, int omode)
 {
-       print_func_entry();
        ERRSTACK(1);
        struct nix *v = QID2NIX(c->qid);
-       printk("nixopen: v is %p\n", v);
        if (waserror()) {
                nexterror();
        }
@@ -322,6 +304,11 @@ static struct chan *nixopen(struct chan *c, int omode)
                break;
        case Qclone:
                spin_lock_irqsave(&nixlock);
+               if (nnix >= 1) {
+                       spin_unlock_irqsave(&nixlock);
+                       set_errno(EBUSY);
+                       error("Already have 1 nix, we don't support more");
+               }
                nixs = krealloc(nixs, sizeof(nixs[0]) * (nnix + 1), 0);
                v = &nixs[nnix];
                mkqid(&c->qid, QID(nnix, Qctl), 0, QTFILE);
@@ -329,21 +316,19 @@ static struct chan *nixopen(struct chan *c, int omode)
                spin_unlock(&nixlock);
                kref_init(&v->kref, nix_release, 1);
                v->id = newnixid();
-               v->image = KADDR(GiB);
-               v->imagesize = npages * 4096;
+               v->image = KADDR(img_paddr);
+               v->imagesize = img_size;
+               printk("nix image is %p with %d bytes\n", v->image, v->imagesize);
                c->aux = v;
                bitmap_zero(v->cpus, MAX_NUM_CPUS);
-               printd("New NIX id %d @ %p\n", v->id, v);
-               printk("image is %p with %d bytes\n", v->image, v->imagesize);
-               printk("Qclone open: id %d, v is %p\n", nnix-1, v);
                break;
        case Qstat:
                break;
        case Qctl:
        case Qimage:
+               /* TODO: (MGMT) refcnting */
                //kref_get(&v->kref, 1);
                c->aux = QID2NIX(c->qid);
-               printk("open qctl/image: aux (nix) is %p\n", c->aux);
                break;
        }
        c->mode = openmode(omode);
@@ -351,83 +336,64 @@ static struct chan *nixopen(struct chan *c, int omode)
        c->flag |= COPEN;
        c->offset = 0;
        poperror();
-       print_func_exit();
        return c;
 }
 
 static void nixcreate(struct chan *c, char *name, int omode, uint32_t perm)
 {
-       print_func_entry();
        error(Eperm);
-       print_func_exit();
 }
 
 static void nixremove(struct chan *c)
 {
-       print_func_entry();
        error(Eperm);
-       print_func_exit();
 }
 
 static int nixwstat(struct chan *c, uint8_t * dp, int n)
 {
-       print_func_entry();
        error("No nixwstat");
-       print_func_exit();
        return 0;
 }
 
 static void nixclose(struct chan *c)
 {
-       print_func_entry();
        struct nix *v = c->aux;
-       if (!v) {
-               print_func_exit();
+       if (!v)
                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();
+       if (!(c->flag & COPEN))
                return;
-       }
        switch (TYPE(c->qid)) {
-               /* for now, leave the NIX active even when we close ctl */
+               /* TODO: (MGMT) the idea of 'stopping' a nix is tricky.
+                * for now, leave the NIX active even when we close ctl */
        case Qctl:
                break;
        case Qimage:
                //kref_put(&v->kref);
                break;
        }
-       print_func_exit();
 }
 
 static long nixread(struct chan *c, void *ubuf, long n, int64_t offset)
 {
-       print_func_entry();
        struct nix *v = c->aux;
-       printd("NIXREAD\n");
        switch (TYPE(c->qid)) {
        case Qtopdir:
        case Qnixdir:
-               print_func_exit();
                return devdirread(c, ubuf, n, 0, 0, nixgen);
        case Qstat:
-               print_func_exit();
                return readnum(offset, ubuf, n, nnix, NUMSIZE32);
        case Qctl:
                assert(v);
-               print_func_exit();
                return readnum(offset, ubuf, n, v->id, NUMSIZE32);
        case Qimage:
                assert(v);
-               print_func_exit();
                return readmem(offset, ubuf, n, v->image, v->imagesize);
        default:
                panic("Bad QID %p in devnix", c->qid.path);
        }
-       print_func_exit();
        return 0;
 }
 
@@ -435,18 +401,17 @@ static void nixwrapper(uint32_t srcid, long a0, long a1, long a2)
 {
        void (*f)(void) = (void (*)(void))a0;
        f();
+       /* TODO: could do some tracking to say this message has been completed */
 }
 
 static long nixwrite(struct chan *c, void *ubuf, long n, int64_t off)
 {
        struct nix *v = c->aux;
-       print_func_entry();
-       ERRSTACK(3);
+       ERRSTACK(1);
        char buf[32];
        struct cmdbuf *cb;
        struct nix *nix;
        uint64_t hexval;
-       printd("nixwrite(%p, %p, %d)\n", c, ubuf, n);
        switch (TYPE(c->qid)) {
        case Qtopdir:
        case Qnixdir:
@@ -454,7 +419,6 @@ static long nixwrite(struct chan *c, void *ubuf, long n, int64_t off)
                error(Eperm);
        case Qctl:
                nix = c->aux;
-               printk("qctl: nix is %p, nix is %p\n", nix, nix);
                cb = parsecmd(ubuf, n);
                /* TODO: lock the nix here, unlock in waserror and before popping */
                if (waserror()) {
@@ -471,8 +435,6 @@ static long nixwrite(struct chan *c, void *ubuf, long n, int64_t off)
                        if (!test_bit(core, nix->cpus))
                                error("Bad core %d", core);
                        send_kernel_message(core, nixwrapper, (long)ip, 0, 0, KMSG_ROUTINE);
-                       printk("nix_run returns \n");
-                       print_func_exit();
                } else if (!strcmp(cb->f[0], "test")) {
                        int core;
                        if (cb->nf != 2)
@@ -482,8 +444,6 @@ static long nixwrite(struct chan *c, void *ubuf, long n, int64_t off)
                                error("Bad core %d", core);
                        send_kernel_message(core, nixwrapper, (long)nixtest, 0, 0,
                                            KMSG_ROUTINE);
-                       printk("nix_run (test) returns \n");
-                       print_func_exit();
                } else if (!strcmp(cb->f[0], "reserve")) {
                        int core;
                        if (cb->nf != 2)
@@ -520,7 +480,6 @@ static long nixwrite(struct chan *c, void *ubuf, long n, int64_t off)
                if (off + n > v->imagesize) {
                        n = v->imagesize - off;
                }
-               printd("copy to %p ubuf %p size %d\n", v->image + off, ubuf, n);
 
                if (memcpy_from_user_errno(current, v->image + off, ubuf, n) < 0)
                        error("%s: bad user addr %p", __FUNCTION__, ubuf);
@@ -529,7 +488,6 @@ static long nixwrite(struct chan *c, void *ubuf, long n, int64_t off)
        default:
                panic("Bad QID %p in devnix", c->qid.path);
        }
-       print_func_exit();
        return n;
 }