7ed43861fec78ad8181e3d4b694378741b81d3da
[akaros.git] / kern / drivers / dev / nix.c
1 //#define DEBUG
2 /* Copyright 2014 Google Inc.
3  * Copyright (c) 2013 The Regents of the University of California
4  * Barret Rhoden <brho@cs.berkeley.edu>
5  * See LICENSE for details.
6  *
7  * devnix/#t: a device for NIX mode
8  *
9  * A struct nix is a "visitor" chunk of code.  It has a memory image, and can be
10  * told to run an arbitrary address (in that image or otherwise) in kernel mode
11  * on various pcores, to which it has exclusive access.
12  *
13  * TODO:
14  *
15  * - FOR THE MOMENT, this is only intended to run one NIX at a time.  Too many
16  * sharp edges for any other mode.
17  *
18  * - memory images: we have one now for all nixs.  that'll be a mess.
19  *
20  * - what do we want to do for refcnting?  decref on chan close?  or remove?
21  * how do we manage the struct nix memory? (MGMT)
22  *              - right now, we aren't decreffing at all.  it's easier to work with from
23  *              the shell, but it's definitely a debugging thing.  the proper way to do
24  *              these devices is to release on close (i think).  the use case for the
25  *              NIX is a "turn it on once and reboot if you don't like it", so this is
26  *              fine for now.
27  *              - we're using c->aux, which needs to be an uncounted ref, in my opinion.
28  *              i messed around with this for a long time with devsrv, and all the
29  *              different ways 9ns interacts with a device make it very tricky.
30  *              - once we start freeing, we'll need to manage the memory better.  if we
31  *              have holes in the nixs[], we'll need to handle that in nixgen
32  *
33  * - how are we going to stop a nix?
34  *              - graceful vs immediate?  with some sort of immediate power-cord style
35  *              halting, the entire nix is garbage once we pull the plug.  a more
36  *              graceful style would require the nix to poll or something - probably
37  *              overkill.
38  *              - could send an immediate kmsg (IPI), but we'd need to do some
39  *              bookkeeping to know we're interrupting a NIX and whatnot
40  *              - if we were sure it's a nix core, we might be able to send an immediate
41  *              message telling the core to just smp_idle.  doing that from hard IRQ
42  *              would break a little, so we'd need to be careful (adjust various
43  *              flags, etc).
44  *              - another option would be to hack the halted context and have it call
45  *              a cleanup function (which ultimately smp_idles)
46  *              - if we had a process running the core, and "running the NIX" was a
47  *              syscall or something, we'd want to abort the syscall.  but since the
48  *              syscall isn't trying to rendez or sleep, we couldn't use the existing
49  *              facilities.  so it's the same problem: know it is a nix, somehow
50  *              kill/cleanup.  then just smp_idle.
51  *              - we'll also need to unreserve a core first, so we don't have any
52  *              concurrent startups.  careful of various races with cores coming and
53  *              going.  we can lock the nix before sending the message, but stale RKMs
54  *              could exist for a while.
55  *              - maybe we use a ktask, named nixID or something, to help detect if a
56  *              nix is running.  might also need to track the number of messages sent
57  *              and completed (track completed via the wrapper)
58  */
59
60 #include <kmalloc.h>
61 #include <string.h>
62 #include <stdio.h>
63 #include <assert.h>
64 #include <error.h>
65 #include <pmap.h>
66 #include <sys/queue.h>
67 #include <smp.h>
68 #include <kref.h>
69 #include <atomic.h>
70 #include <alarm.h>
71 #include <event.h>
72 #include <umem.h>
73 #include <devalarm.h>
74 #include <arch/types.h>
75 #include <arch/emulate.h>
76 #include <arch/vmdebug.h>
77 #include <kdebug.h>
78 #include <bitmap.h>
79
80 /* qid path types */
81 enum {
82         Qtopdir = 1,
83         Qclone,
84         Qstat,
85         Qnixdir,
86         Qctl,
87         Qimage,
88 };
89
90 /* The QID is the TYPE and the index into the nix array.
91  * We reserve the right to make it an id later. */
92 #define INDEX_SHIFT 5
93 /* nix's have an image.
94  * Note that the image can be read even as it is running. */
95 struct nix {
96         struct kref kref;
97         /* should this be an array of pages? Hmm. */
98         void *image;
99         unsigned long imagesize;
100         int id;
101         /* we could dynamically alloc one of these with num_cpus */
102         DECLARE_BITMAP(cpus, MAX_NUM_CPUS);
103 };
104
105 static spinlock_t nixlock = SPINLOCK_INITIALIZER_IRQSAVE;
106 /* array, not linked list. We expect few, might as well be cache friendly. */
107 static struct nix *nixs = NULL;
108 static int nnix = 0;
109 static int nixok = 0;
110 /* TODO: make this per-nix, somehow. */
111 static physaddr_t img_paddr = CONFIG_NIX_IMG_PADDR;
112 static size_t img_size = CONFIG_NIX_IMG_SIZE;
113
114 static atomic_t nixid = 0;
115
116 /* The index is not the id, for now.  The index is the spot in nixs[].  The id
117  * is an increasing integer, regardless of struct nix* reuse. */
118 static inline struct nix *QID2NIX(struct qid q)
119 {
120         return &nixs[q.path >> INDEX_SHIFT];
121 }
122
123 static inline int TYPE(struct qid q)
124 {
125         return ((q).path & ((1 << INDEX_SHIFT) - 1));
126 }
127
128 static inline int QID(int index, int type)
129 {
130         return ((index << INDEX_SHIFT) | type);
131 }
132
133 static inline int QID2ID(struct qid q)
134 {
135         return q.path >> INDEX_SHIFT;
136 }
137
138 /* TODO: (MGMT) not called yet.  -- we have to unlink the nix */
139 static void nix_release(struct kref *kref)
140 {
141         struct nix *v = container_of(kref, struct nix, kref);
142         spin_lock_irqsave(&nixlock);
143         /* cute trick. Save the last element of the array in place of the
144          * one we're deleting. Reduce nnix. Don't realloc; that way, next
145          * time we add a nix the allocator will just return.
146          * Well, this is stupid, because when we do this, we break
147          * the QIDs, which have pointers embedded in them.
148          * darn it, may have to use a linked list. Nope, will probably
149          * just walk the array until we find a matching id. Still ... yuck.
150          *
151          * If we have lots, we can track the lowest free, similar to FDs and low_fd.
152          * honestly, we need an integer allocator (vmem and magazine paper) */
153         if (v != &nixs[nnix - 1]) {
154                 /* free the image ... oops */
155                 /* get rid of the kref. */
156                 *v = nixs[nnix - 1];
157         }
158         nnix--;
159         spin_unlock(&nixlock);
160 }
161
162 /* NIX ids run in the range 0..infinity.  */
163 static int newnixid(void)
164 {
165         return atomic_fetch_and_add(&nixid, 1);
166 }
167
168 static int nixgen(struct chan *c, char *entry_name,
169                    struct dirtab *unused, int unused_nr_dirtab,
170                    int s, struct dir *dp)
171 {
172         struct qid q;
173         struct nix *nix_i;
174         /* Whether we're in one dir or at the top, .. still takes us to the top. */
175         if (s == DEVDOTDOT) {
176                 mkqid(&q, Qtopdir, 0, QTDIR);
177                 devdir(c, c->qid, "#V", 0, eve, 0555, dp);
178                 return 1;
179         }
180         switch (TYPE(c->qid)) {
181         case Qtopdir:
182                 /* Generate elements for the top level dir.  We support clone, stat,
183                  * nix dirs at the top level */
184                 if (s == 0) {
185                         mkqid(&q, Qclone, 0, QTFILE);
186                         devdir(c, q, "clone", 0, eve, 0666, dp);
187                         return 1;
188                 }
189                 s--;
190                 if (s == 0) {
191                         mkqid(&q, Qstat, 0, QTFILE);
192                         devdir(c, q, "stat", 0, eve, 0666, dp);
193                         return 1;
194                 }
195                 s--;    /* 1 -> 0th element, 2 -> 1st element, etc */
196                 spin_lock_irqsave(&nixlock);
197                 if (s >= nnix) {
198                         spin_unlock(&nixlock);
199                         return -1;
200                 }
201                 nix_i = &nixs[s];
202                 /* TODO (MGMT): if no nix_i, advance (in case of holes) */
203                 snprintf(get_cur_genbuf(), GENBUF_SZ, "nix%d", nix_i->id);
204                 spin_unlock(&nixlock);
205                 mkqid(&q, QID(s, Qnixdir), 0, QTDIR);
206                 devdir(c, q, get_cur_genbuf(), 0, eve, 0555, dp);
207                 return 1;
208         case Qnixdir:
209                 /* Gen the contents of the nix dirs */
210                 s += Qctl;      /* first time through, start on Qctl */
211                 switch (s) {
212                 case Qctl:
213                         mkqid(&q, QID(QID2ID(c->qid), Qctl), 0, QTFILE);
214                         devdir(c, q, "ctl", 0, eve, 0666, dp);
215                         return 1;
216                 case Qimage:
217                         mkqid(&q, QID(QID2ID(c->qid), Qimage), 0, QTFILE);
218                         devdir(c, q, "image", 0, eve, 0666, dp);
219                         return 1;
220                 }
221                 return -1;
222                 /* Need to also provide a direct hit for Qclone and all other files (at
223                  * all levels of the hierarchy).  Every file is both
224                  * generated (via the s increments in their respective directories) and
225                  * directly gen-able.  devstat() will call gen with a specific path in
226                  * the qid.  In these cases, we make a dir for whatever they are asking
227                  * for.  Note the qid stays the same.  I think this is what the old
228                  * plan9 comments above devgen were talking about for (ii).
229                  *
230                  * We don't need to do this for the directories - devstat will look for
231                  * the a directory by path and fail.  Then it will manually build the
232                  * stat output (check the -1 case in devstat). */
233         case Qclone:
234                 devdir(c, c->qid, "clone", 0, eve, 0666, dp);
235                 return 1;
236         case Qstat:
237                 devdir(c, c->qid, "stat", 0, eve, 0444, dp);
238                 return 1;
239         case Qctl:
240                 devdir(c, c->qid, "ctl", 0, eve, 0666, dp);
241                 return 1;
242         case Qimage:
243                 devdir(c, c->qid, "image", 0, eve, 0666, dp);
244                 return 1;
245         }
246         return -1;
247 }
248
249 void nixtest(void)
250 {
251         printk("nixtest ran on core %d\n", core_id());
252 }
253
254 static void nixinit(void)
255 {
256         size_t img_order = LOG2_UP(nr_pages(img_size));
257         void *img_kaddr;
258
259         if (img_size != 1ULL << img_order << PGSHIFT) {
260                 printk("nixinit rounding up image size to a power of 2 pgs (was %p)\n",
261                        img_size);
262                 img_size = 1ULL << img_order << PGSHIFT;
263         }
264         img_kaddr = get_cont_phys_pages_at(img_order, img_paddr, 0);
265         if (!img_kaddr) {
266                 printk("nixinit failed to get an image!\n");
267                 return;
268         }
269         nixok = 1;
270         printk("nixinit image at KVA %p of size %p\n", img_kaddr, img_size);
271 }
272
273 static struct chan *nixattach(char *spec)
274 {
275         if (!nixok)
276                 error("No NIXs available");
277         struct chan *c = devattach('t', spec);
278         mkqid(&c->qid, Qtopdir, 0, QTDIR);
279         return c;
280 }
281
282 static struct walkqid *nixwalk(struct chan *c, struct chan *nc, char **name,
283                                 int nname)
284 {
285         return devwalk(c, nc, name, nname, 0, 0, nixgen);
286 }
287
288 static int nixstat(struct chan *c, uint8_t * db, int n)
289 {
290         return devstat(c, db, n, 0, 0, nixgen);
291 }
292
293 /* It shouldn't matter if p = current is DYING.  We'll eventually fail to insert
294  * the open chan into p's fd table, then decref the chan. */
295 static struct chan *nixopen(struct chan *c, int omode)
296 {
297         ERRSTACK(1);
298         struct nix *v = QID2NIX(c->qid);
299         if (waserror()) {
300                 nexterror();
301         }
302         switch (TYPE(c->qid)) {
303         case Qtopdir:
304         case Qnixdir:
305                 if (omode & ORCLOSE)
306                         error(Eperm);
307                 if (!IS_RDONLY(omode))
308                         error(Eisdir);
309                 break;
310         case Qclone:
311                 spin_lock_irqsave(&nixlock);
312                 if (nnix >= 1) {
313                         spin_unlock_irqsave(&nixlock);
314                         set_errno(EBUSY);
315                         error("Already have 1 nix, we don't support more");
316                 }
317                 nixs = krealloc(nixs, sizeof(nixs[0]) * (nnix + 1), 0);
318                 v = &nixs[nnix];
319                 mkqid(&c->qid, QID(nnix, Qctl), 0, QTFILE);
320                 nnix++;
321                 spin_unlock(&nixlock);
322                 kref_init(&v->kref, nix_release, 1);
323                 v->id = newnixid();
324                 v->image = KADDR(img_paddr);
325                 v->imagesize = img_size;
326                 printk("nix image is %p with %d bytes\n", v->image, v->imagesize);
327                 c->aux = v;
328                 bitmap_zero(v->cpus, MAX_NUM_CPUS);
329                 break;
330         case Qstat:
331                 break;
332         case Qctl:
333         case Qimage:
334                 /* TODO: (MGMT) refcnting */
335                 //kref_get(&v->kref, 1);
336                 c->aux = QID2NIX(c->qid);
337                 break;
338         }
339         c->mode = openmode(omode);
340         /* Assumes c is unique (can't be closed concurrently */
341         c->flag |= COPEN;
342         c->offset = 0;
343         poperror();
344         return c;
345 }
346
347 static void nixcreate(struct chan *c, char *name, int omode, uint32_t perm)
348 {
349         error(Eperm);
350 }
351
352 static void nixremove(struct chan *c)
353 {
354         error(Eperm);
355 }
356
357 static int nixwstat(struct chan *c, uint8_t * dp, int n)
358 {
359         error("No nixwstat");
360         return 0;
361 }
362
363 static void nixclose(struct chan *c)
364 {
365         struct nix *v = c->aux;
366         if (!v)
367                 return;
368         /* There are more closes than opens.  For instance, sysstat doesn't open,
369          * but it will close the chan it got from namec.  We only want to clean
370          * up/decref chans that were actually open. */
371         if (!(c->flag & COPEN))
372                 return;
373         switch (TYPE(c->qid)) {
374                 /* TODO: (MGMT) the idea of 'stopping' a nix is tricky.
375                  * for now, leave the NIX active even when we close ctl */
376         case Qctl:
377                 break;
378         case Qimage:
379                 //kref_put(&v->kref);
380                 break;
381         }
382 }
383
384 static long nixread(struct chan *c, void *ubuf, long n, int64_t offset)
385 {
386         struct nix *v = c->aux;
387         switch (TYPE(c->qid)) {
388         case Qtopdir:
389         case Qnixdir:
390                 return devdirread(c, ubuf, n, 0, 0, nixgen);
391         case Qstat:
392                 return readnum(offset, ubuf, n, nnix, NUMSIZE32);
393         case Qctl:
394                 assert(v);
395                 return readnum(offset, ubuf, n, v->id, NUMSIZE32);
396         case Qimage:
397                 assert(v);
398                 return readmem(offset, ubuf, n, v->image, v->imagesize);
399         default:
400                 panic("Bad QID %p in devnix", c->qid.path);
401         }
402         return 0;
403 }
404
405 static void nixwrapper(uint32_t srcid, long a0, long a1, long a2)
406 {
407         void (*f)(void) = (void (*)(void))a0;
408         f();
409         /* TODO: could do some tracking to say this message has been completed */
410 }
411
412 static long nixwrite(struct chan *c, void *ubuf, long n, int64_t off)
413 {
414         struct nix *v = c->aux;
415         ERRSTACK(1);
416         char buf[32];
417         struct cmdbuf *cb;
418         struct nix *nix;
419         uint64_t hexval;
420         switch (TYPE(c->qid)) {
421         case Qtopdir:
422         case Qnixdir:
423         case Qstat:
424                 error(Eperm);
425         case Qctl:
426                 nix = c->aux;
427                 cb = parsecmd(ubuf, n);
428                 /* TODO: lock the nix here, unlock in waserror and before popping */
429                 if (waserror()) {
430                         kfree(cb);
431                         nexterror();
432                 }
433                 if (!strcmp(cb->f[0], "run")) {
434                         int core;
435                         uintptr_t ip;
436                         if (cb->nf != 3)
437                                 error("usage: run core entry");
438                         core = strtoul(cb->f[1], 0, 0);
439                         ip = strtoul(cb->f[2], 0, 0);
440                         if (!test_bit(core, nix->cpus))
441                                 error("Bad core %d", core);
442                         send_kernel_message(core, nixwrapper, (long)ip, 0, 0, KMSG_ROUTINE);
443                 } else if (!strcmp(cb->f[0], "test")) {
444                         int core;
445                         if (cb->nf != 2)
446                                 error("usage: test core");
447                         core = strtoul(cb->f[1], 0, 0);
448                         if (!test_bit(core, nix->cpus))
449                                 error("Bad core %d", core);
450                         send_kernel_message(core, nixwrapper, (long)nixtest, 0, 0,
451                                             KMSG_ROUTINE);
452                 } else if (!strcmp(cb->f[0], "reserve")) {
453                         int core;
454                         if (cb->nf != 2)
455                                 error("Usage: reserve core (-1 for any)");
456                         core = strtol(cb->f[1], 0, 0);
457                         if (core == -1) {
458                                 core = get_any_idle_core();
459                                 if (core < 0)
460                                         error("No free idle cores!");
461                         } else {
462                                 if (get_this_idle_core(core) < 0)
463                                         error("Failed to reserve core %d\n", core);
464                         }
465                         set_bit(core, nix->cpus);
466                 } else if (!strcmp(cb->f[0], "check")) {
467                         int i;
468                         for(i = 0; i < MAX_NUM_CPUS; i++) {
469                                 if (!test_bit(i, nix->cpus))
470                                         continue;
471                                 printk("Core %d is available to nix%d\n", i, nix->id);
472                         }
473                 } else if (!strcmp(cb->f[0], "stop")) {
474                         error("can't stop a nix yet");
475                 } else {
476                         error("%s: not implemented", cb->f[0]);
477                 }
478                 kfree(cb);
479                 poperror();
480                 break;
481         case Qimage:
482                 if (off < 0)
483                         error("offset < 0!");
484
485                 if (off + n > v->imagesize) {
486                         n = v->imagesize - off;
487                 }
488
489                 if (memcpy_from_user_errno(current, v->image + off, ubuf, n) < 0)
490                         error("%s: bad user addr %p", __FUNCTION__, ubuf);
491                 break;
492
493         default:
494                 panic("Bad QID %p in devnix", c->qid.path);
495         }
496         return n;
497 }
498
499 struct dev nixdevtab __devtab = {
500         't',
501         "nix",
502
503         devreset,
504         nixinit,
505         devshutdown,
506         nixattach,
507         nixwalk,
508         nixstat,
509         nixopen,
510         nixcreate,
511         nixclose,
512         nixread,
513         devbread,
514         nixwrite,
515         devbwrite,
516         nixremove,
517         nixwstat,
518         devpower,
519 //  devconfig,
520         devchaninfo,
521 };