Removes debugging code
[akaros.git] / kern / drivers / dev / nix.c
index 977cb9d..c1cb598 100644 (file)
@@ -6,8 +6,55 @@
  *
  * devnix/#t: a device for NIX mode
  *
- * FOR THE MOMENT, this is only intended to run one NIX at a time.
- * Too many sharp edges for any other 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>
@@ -41,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 {
@@ -51,7 +97,7 @@ 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);
 };
@@ -61,51 +107,30 @@ static spinlock_t nixlock = SPINLOCK_INITIALIZER_IRQSAVE;
 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];
+/* TODO: make this per-nix, somehow. */
+static physaddr_t img_paddr = CONFIG_NIX_IMG_PADDR;
+static size_t img_size = CONFIG_NIX_IMG_SIZE;
 
 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)
-{
-       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;
-       }
+       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)
 {
        struct nix *v = container_of(kref, struct nix, kref);
@@ -117,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. */
@@ -127,8 +154,7 @@ static void nix_release(struct kref *kref)
        spin_unlock(&nixlock);
 }
 
-/* NIX ids run in the range 1..infinity.
- */
+/* NIX ids run in the range 0..infinity.  */
 static int newnixid(void)
 {
        return atomic_fetch_and_add(&nixid, 1);
@@ -168,6 +194,7 @@ static int nixgen(struct chan *c, char *entry_name,
                        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);
@@ -219,25 +246,23 @@ void nixtest(void)
        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)
-       uint64_t ppn = GiB/4096;
-       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;
+       }
+       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)
@@ -279,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);
@@ -286,8 +316,8 @@ 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);
@@ -296,6 +326,7 @@ static struct chan *nixopen(struct chan *c, int omode)
                break;
        case Qctl:
        case Qimage:
+               /* TODO: (MGMT) refcnting */
                //kref_get(&v->kref, 1);
                c->aux = QID2NIX(c->qid);
                break;
@@ -335,7 +366,7 @@ static void nixclose(struct chan *c)
        if (!(c->flag & COPEN))
                return;
        switch (TYPE(c->qid)) {
-               /* the idea of 'stopping' a nix is tricky. 
+               /* TODO: (MGMT) the idea of 'stopping' a nix is tricky.
                 * for now, leave the NIX active even when we close ctl */
        case Qctl:
                break;
@@ -370,6 +401,7 @@ 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)