e2651dfb7d2a76400dda756014596375e1e10425
[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 <kdebug.h>
77 #include <bitmap.h>
78
79 /* qid path types */
80 enum {
81         Qtopdir = 1,
82         Qclone,
83         Qstat,
84         Qnixdir,
85         Qctl,
86         Qimage,
87 };
88
89 /* The QID is the TYPE and the index into the nix array.
90  * We reserve the right to make it an id later. */
91 #define INDEX_SHIFT 5
92 /* nix's have an image.
93  * Note that the image can be read even as it is running. */
94 struct nix {
95         struct kref kref;
96         /* should this be an array of pages? Hmm. */
97         void *image;
98         unsigned long imagesize;
99         int id;
100         /* we could dynamically alloc one of these with num_cpus */
101         DECLARE_BITMAP(cpus, MAX_NUM_CPUS);
102 };
103
104 static spinlock_t nixlock = SPINLOCK_INITIALIZER_IRQSAVE;
105 /* array, not linked list. We expect few, might as well be cache friendly. */
106 static struct nix *nixs = NULL;
107 static int nnix = 0;
108 static int nixok = 0;
109 /* TODO: make this per-nix, somehow. */
110 static physaddr_t img_paddr = CONFIG_NIX_IMG_PADDR;
111 static size_t img_size = CONFIG_NIX_IMG_SIZE;
112
113 static atomic_t nixid = 0;
114
115 /* initial guest program. */
116 /*
117 .code64
118         pushq   %rax
119         pushq   %rdx
120         movb    $0x30, %al
121         movw    $0x3f8, %dx
122         outb    %al, %dx
123         popq    %rdx
124         popq    %rax
125         ret
126 */
127 unsigned char it[] = {
128   0x50, 0x52, 0xb0, 0x30, 0x66, 0xba, 0xf8, 0x03, 0xee, 0x5a, 0x58, 0xc3
129 };
130 unsigned int it_len = 12;
131
132
133 /* The index is not the id, for now.  The index is the spot in nixs[].  The id
134  * is an increasing integer, regardless of struct nix* reuse. */
135 static inline struct nix *QID2NIX(struct qid q)
136 {
137         return &nixs[q.path >> INDEX_SHIFT];
138 }
139
140 static inline int TYPE(struct qid q)
141 {
142         return ((q).path & ((1 << INDEX_SHIFT) - 1));
143 }
144
145 static inline int QID(int index, int type)
146 {
147         return ((index << INDEX_SHIFT) | type);
148 }
149
150 static inline int QID2ID(struct qid q)
151 {
152         return q.path >> INDEX_SHIFT;
153 }
154
155 /* TODO: (MGMT) not called yet.  -- we have to unlink the nix */
156 static void nix_release(struct kref *kref)
157 {
158         struct nix *v = container_of(kref, struct nix, kref);
159         spin_lock_irqsave(&nixlock);
160         /* cute trick. Save the last element of the array in place of the
161          * one we're deleting. Reduce nnix. Don't realloc; that way, next
162          * time we add a nix the allocator will just return.
163          * Well, this is stupid, because when we do this, we break
164          * the QIDs, which have pointers embedded in them.
165          * darn it, may have to use a linked list. Nope, will probably
166          * just walk the array until we find a matching id. Still ... yuck.
167          *
168          * If we have lots, we can track the lowest free, similar to FDs and low_fd.
169          * honestly, we need an integer allocator (vmem and magazine paper) */
170         if (v != &nixs[nnix - 1]) {
171                 /* free the image ... oops */
172                 /* get rid of the kref. */
173                 *v = nixs[nnix - 1];
174         }
175         nnix--;
176         spin_unlock(&nixlock);
177 }
178
179 /* NIX ids run in the range 0..infinity.  */
180 static int newnixid(void)
181 {
182         return atomic_fetch_and_add(&nixid, 1);
183 }
184
185 static int nixgen(struct chan *c, char *entry_name,
186                    struct dirtab *unused, int unused_nr_dirtab,
187                    int s, struct dir *dp)
188 {
189         struct qid q;
190         struct nix *nix_i;
191         /* Whether we're in one dir or at the top, .. still takes us to the top. */
192         if (s == DEVDOTDOT) {
193                 mkqid(&q, Qtopdir, 0, QTDIR);
194                 devdir(c, c->qid, "#V", 0, eve, 0555, dp);
195                 return 1;
196         }
197         switch (TYPE(c->qid)) {
198         case Qtopdir:
199                 /* Generate elements for the top level dir.  We support clone, stat,
200                  * nix dirs at the top level */
201                 if (s == 0) {
202                         mkqid(&q, Qclone, 0, QTFILE);
203                         devdir(c, q, "clone", 0, eve, 0666, dp);
204                         return 1;
205                 }
206                 s--;
207                 if (s == 0) {
208                         mkqid(&q, Qstat, 0, QTFILE);
209                         devdir(c, q, "stat", 0, eve, 0666, dp);
210                         return 1;
211                 }
212                 s--;    /* 1 -> 0th element, 2 -> 1st element, etc */
213                 spin_lock_irqsave(&nixlock);
214                 if (s >= nnix) {
215                         spin_unlock(&nixlock);
216                         return -1;
217                 }
218                 nix_i = &nixs[s];
219                 /* TODO (MGMT): if no nix_i, advance (in case of holes) */
220                 snprintf(get_cur_genbuf(), GENBUF_SZ, "nix%d", nix_i->id);
221                 spin_unlock(&nixlock);
222                 mkqid(&q, QID(s, Qnixdir), 0, QTDIR);
223                 devdir(c, q, get_cur_genbuf(), 0, eve, 0555, dp);
224                 return 1;
225         case Qnixdir:
226                 /* Gen the contents of the nix dirs */
227                 s += Qctl;      /* first time through, start on Qctl */
228                 switch (s) {
229                 case Qctl:
230                         mkqid(&q, QID(QID2ID(c->qid), Qctl), 0, QTFILE);
231                         devdir(c, q, "ctl", 0, eve, 0666, dp);
232                         return 1;
233                 case Qimage:
234                         mkqid(&q, QID(QID2ID(c->qid), Qimage), 0, QTFILE);
235                         devdir(c, q, "image", 0, eve, 0666, dp);
236                         return 1;
237                 }
238                 return -1;
239                 /* Need to also provide a direct hit for Qclone and all other files (at
240                  * all levels of the hierarchy).  Every file is both
241                  * generated (via the s increments in their respective directories) and
242                  * directly gen-able.  devstat() will call gen with a specific path in
243                  * the qid.  In these cases, we make a dir for whatever they are asking
244                  * for.  Note the qid stays the same.  I think this is what the old
245                  * plan9 comments above devgen were talking about for (ii).
246                  *
247                  * We don't need to do this for the directories - devstat will look for
248                  * the a directory by path and fail.  Then it will manually build the
249                  * stat output (check the -1 case in devstat). */
250         case Qclone:
251                 devdir(c, c->qid, "clone", 0, eve, 0666, dp);
252                 return 1;
253         case Qstat:
254                 devdir(c, c->qid, "stat", 0, eve, 0444, dp);
255                 return 1;
256         case Qctl:
257                 devdir(c, c->qid, "ctl", 0, eve, 0666, dp);
258                 return 1;
259         case Qimage:
260                 devdir(c, c->qid, "image", 0, eve, 0666, dp);
261                 return 1;
262         }
263         return -1;
264 }
265
266 void nixtest(void)
267 {
268         printk("nixtest ran on core %d\n", core_id());
269 }
270
271 static void nixinit(void)
272 {
273         size_t img_order = LOG2_UP(nr_pages(img_size));
274         void *img_kaddr;
275
276         if (img_size != 1ULL << img_order << PGSHIFT) {
277                 printk("nixinit rounding up image size to a power of 2 pgs (was %p)\n",
278                        img_size);
279                 img_size = 1ULL << img_order << PGSHIFT;
280         }
281         img_kaddr = get_cont_phys_pages_at(img_order, img_paddr, 0);
282         if (!img_kaddr) {
283                 printk("nixinit failed to get an image!\n");
284                 return;
285         }
286         nixok = 1;
287         printk("nixinit image at KVA %p of size %p\n", img_kaddr, img_size);
288 }
289
290 static struct chan *nixattach(char *spec)
291 {
292         if (!nixok)
293                 error("No NIXs available");
294         struct chan *c = devattach('t', spec);
295         mkqid(&c->qid, Qtopdir, 0, QTDIR);
296         return c;
297 }
298
299 static struct walkqid *nixwalk(struct chan *c, struct chan *nc, char **name,
300                                 int nname)
301 {
302         return devwalk(c, nc, name, nname, 0, 0, nixgen);
303 }
304
305 static int nixstat(struct chan *c, uint8_t * db, int n)
306 {
307         return devstat(c, db, n, 0, 0, nixgen);
308 }
309
310 /* It shouldn't matter if p = current is DYING.  We'll eventually fail to insert
311  * the open chan into p's fd table, then decref the chan. */
312 static struct chan *nixopen(struct chan *c, int omode)
313 {
314         ERRSTACK(1);
315         struct nix *v = QID2NIX(c->qid);
316         if (waserror()) {
317                 nexterror();
318         }
319         switch (TYPE(c->qid)) {
320         case Qtopdir:
321         case Qnixdir:
322                 if (omode & ORCLOSE)
323                         error(Eperm);
324                 if (!IS_RDONLY(omode))
325                         error(Eisdir);
326                 break;
327         case Qclone:
328                 spin_lock_irqsave(&nixlock);
329                 if (nnix >= 1) {
330                         spin_unlock_irqsave(&nixlock);
331                         set_errno(EBUSY);
332                         error("Already have 1 nix, we don't support more");
333                 }
334                 nixs = krealloc(nixs, sizeof(nixs[0]) * (nnix + 1), 0);
335                 v = &nixs[nnix];
336                 mkqid(&c->qid, QID(nnix, Qctl), 0, QTFILE);
337                 nnix++;
338                 spin_unlock(&nixlock);
339                 kref_init(&v->kref, nix_release, 1);
340                 v->id = newnixid();
341                 v->image = KADDR(img_paddr);
342                 v->imagesize = img_size;
343                 printk("nix image is %p with %d bytes\n", v->image, v->imagesize);
344                 c->aux = v;
345                 bitmap_zero(v->cpus, MAX_NUM_CPUS);
346                 memcpy(v->image, it, sizeof(it));
347                 break;
348         case Qstat:
349                 break;
350         case Qctl:
351         case Qimage:
352                 /* TODO: (MGMT) refcnting */
353                 //kref_get(&v->kref, 1);
354                 c->aux = QID2NIX(c->qid);
355                 break;
356         }
357         c->mode = openmode(omode);
358         /* Assumes c is unique (can't be closed concurrently */
359         c->flag |= COPEN;
360         c->offset = 0;
361         poperror();
362         return c;
363 }
364
365 static void nixcreate(struct chan *c, char *name, int omode, uint32_t perm)
366 {
367         error(Eperm);
368 }
369
370 static void nixremove(struct chan *c)
371 {
372         error(Eperm);
373 }
374
375 static int nixwstat(struct chan *c, uint8_t * dp, int n)
376 {
377         error("No nixwstat");
378         return 0;
379 }
380
381 static void nixclose(struct chan *c)
382 {
383         struct nix *v = c->aux;
384         if (!v)
385                 return;
386         /* There are more closes than opens.  For instance, sysstat doesn't open,
387          * but it will close the chan it got from namec.  We only want to clean
388          * up/decref chans that were actually open. */
389         if (!(c->flag & COPEN))
390                 return;
391         switch (TYPE(c->qid)) {
392                 /* TODO: (MGMT) the idea of 'stopping' a nix is tricky.
393                  * for now, leave the NIX active even when we close ctl */
394         case Qctl:
395                 break;
396         case Qimage:
397                 //kref_put(&v->kref);
398                 break;
399         }
400 }
401
402 static long nixread(struct chan *c, void *ubuf, long n, int64_t offset)
403 {
404         struct nix *v = c->aux;
405         switch (TYPE(c->qid)) {
406         case Qtopdir:
407         case Qnixdir:
408                 return devdirread(c, ubuf, n, 0, 0, nixgen);
409         case Qstat:
410                 return readnum(offset, ubuf, n, nnix, NUMSIZE32);
411         case Qctl:
412                 assert(v);
413                 return readnum(offset, ubuf, n, v->id, NUMSIZE32);
414         case Qimage:
415                 assert(v);
416                 return readmem(offset, ubuf, n, v->image, v->imagesize);
417         default:
418                 panic("Bad QID %p in devnix", c->qid.path);
419         }
420         return 0;
421 }
422
423 static void nixwrapper(uint32_t srcid, long a0, long a1, long a2)
424 {
425         void (*f)(void) = (void (*)(void))a0;
426         f();
427         /* TODO: could do some tracking to say this message has been completed */
428 }
429
430 static long nixwrite(struct chan *c, void *ubuf, long n, int64_t off)
431 {
432         struct nix *v = c->aux;
433         ERRSTACK(1);
434         char buf[32];
435         struct cmdbuf *cb;
436         struct nix *nix;
437         uint64_t hexval;
438
439         switch (TYPE(c->qid)) {
440         case Qtopdir:
441         case Qnixdir:
442         case Qstat:
443                 error(Eperm);
444         case Qctl:
445                 nix = c->aux;
446                 cb = parsecmd(ubuf, n);
447                 /* TODO: lock the nix here, unlock in waserror and before popping */
448                 if (waserror()) {
449                         kfree(cb);
450                         nexterror();
451                 }
452                 if (cb->nf < 1)
453                         error("short control request");
454                 if (!strcmp(cb->f[0], "run")) {
455                         int core;
456                         uintptr_t ip;
457                         if (cb->nf != 3)
458                                 error("usage: run core entry");
459                         core = strtoul(cb->f[1], 0, 0);
460                         ip = strtoul(cb->f[2], 0, 0);
461                         if (!test_bit(core, nix->cpus))
462                                 error("Bad core %d", core);
463                         send_kernel_message(core, nixwrapper, (long)ip, 0, 0, KMSG_ROUTINE);
464                 } else if (!strcmp(cb->f[0], "test")) {
465                         int core;
466                         if (cb->nf != 2)
467                                 error("usage: test core");
468                         core = strtoul(cb->f[1], 0, 0);
469                         if (!test_bit(core, nix->cpus))
470                                 error("Bad core %d", core);
471                         send_kernel_message(core, nixwrapper, (long)nixtest, 0, 0,
472                                             KMSG_ROUTINE);
473                 } else if (!strcmp(cb->f[0], "reserve")) {
474                         int core;
475                         if (cb->nf != 2)
476                                 error("Usage: reserve core (-1 for any)");
477                         core = strtol(cb->f[1], 0, 0);
478                         if (core == -1) {
479                                 core = get_any_idle_core();
480                                 if (core < 0)
481                                         error("No free idle cores!");
482                         } else {
483                                 if (get_this_idle_core(core) < 0)
484                                         error("Failed to reserve core %d\n", core);
485                         }
486                         set_bit(core, nix->cpus);
487                 } else if (!strcmp(cb->f[0], "check")) {
488                         int i;
489                         for(i = 0; i < MAX_NUM_CPUS; i++) {
490                                 if (!test_bit(i, nix->cpus))
491                                         continue;
492                                 printk("Core %d is available to nix%d\n", i, nix->id);
493                         }
494                 } else if (!strcmp(cb->f[0], "stop")) {
495                         error("can't stop a nix yet");
496                 } else {
497                         error("%s: not implemented", cb->f[0]);
498                 }
499                 kfree(cb);
500                 poperror();
501                 break;
502         case Qimage:
503                 if (off < 0)
504                         error("offset < 0!");
505
506                 if (off + n > v->imagesize) {
507                         n = v->imagesize - off;
508                 }
509
510                 if (memcpy_from_user_errno(current, v->image + off, ubuf, n) < 0)
511                         error("%s: bad user addr %p", __FUNCTION__, ubuf);
512                 break;
513
514         default:
515                 panic("Bad QID %p in devnix", c->qid.path);
516         }
517         return n;
518 }
519
520 struct dev nixdevtab __devtab = {
521         't',
522         "nix",
523
524         devreset,
525         nixinit,
526         devshutdown,
527         nixattach,
528         nixwalk,
529         nixstat,
530         nixopen,
531         nixcreate,
532         nixclose,
533         nixread,
534         devbread,
535         nixwrite,
536         devbwrite,
537         nixremove,
538         nixwstat,
539         devpower,
540 //  devconfig,
541         devchaninfo,
542 };