NIX mode.
[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  */
10
11 #include <kmalloc.h>
12 #include <string.h>
13 #include <stdio.h>
14 #include <assert.h>
15 #include <error.h>
16 #include <pmap.h>
17 #include <sys/queue.h>
18 #include <smp.h>
19 #include <kref.h>
20 #include <atomic.h>
21 #include <alarm.h>
22 #include <event.h>
23 #include <umem.h>
24 #include <devalarm.h>
25 #include <arch/types.h>
26 #include <arch/nix.h>
27 #include <arch/emulate.h>
28 #include <arch/vmdebug.h>
29 #include <kdebug.h>
30
31 /* qid path types */
32 enum {
33         Qtopdir = 1,
34         Qclone,
35         Qstat,
36         Qnixdir,
37         Qctl,
38         Qimage,
39 };
40
41 /* The QID is the TYPE and the index into the nix array.
42  * We reserve the right to make it an id later.
43  */
44 #define ID_SHIFT 5
45 /* nix's have an image.
46  * Note that the image can be read even as it is running. */
47 struct nix {
48         struct kref kref;
49         /* should this be an array of pages? Hmm. */
50         void *image;
51         unsigned long imagesize;
52         int id; // not used yet.
53 };
54
55 // NIX style application cores for now.
56 // we set result to zero. We spin on assignment.
57 // assigner sets work pointer and then assignment IP.
58 // once assigned, we run until done, then set result non-zero.
59 struct mycore {
60         void (*assignment)(void);
61         void *work;
62         void *result;
63         void *done;
64         int usable;
65         int state;
66 };
67
68 static struct mycore allcores[32];
69 static spinlock_t nixlock;
70 /* array, not linked list. We expect few, might as well be cache friendly. */
71 static struct nix *nixs = NULL;
72 static int nnix = 0;
73 static int nixok = 0;
74 static int npages;
75 // only 4 gig for now.
76 static page_t *nixpages[1048576];
77
78 static spinlock_t nixidlock[1];
79 static struct kref nixid[1] = { {(void *)1, fake_release} };
80
81 //int nix_run(struct nix *nix, struct nix_run *nix_run);
82
83 static inline struct nix *
84 QID2NIX(struct qid q)
85 {
86         return &nixs[((q).vers)];
87 }
88
89 static inline int
90 TYPE(struct qid q)
91 {
92         return ((q).path & ((1 << ID_SHIFT) - 1));
93 }
94
95 static inline int QID(int index, int type)
96 {
97         return ((index << ID_SHIFT) | type);
98 }
99
100 /* we'll need this somewhere more generic. */
101 static void readn(struct chan *c, void *vp, long n)
102 {
103         print_func_entry();
104         char *p;
105         long nn;
106         int total = 0, want = n;
107
108         p = vp;
109         while (n > 0) {
110                 nn = devtab[c->type].read(c, p, n, c->offset);
111                 printk("readn: Got %d@%lld\n", nn, c->offset);
112                 if (nn == 0)
113                         error("%s: wanted %d, got %d", Eshort, want, total);
114                 c->offset += nn;
115                 p += nn;
116                 n -= nn;
117                 total += nn;
118         }
119         print_func_exit();
120 }
121
122 /* not called yet.  -- we have to unlink the nix */
123 static void nix_release(struct kref *kref)
124 {
125         print_func_entry();
126         struct nix *v = container_of(kref, struct nix, kref);
127         spin_lock_irqsave(&nixlock);
128         /* cute trick. Save the last element of the array in place of the
129          * one we're deleting. Reduce nnix. Don't realloc; that way, next
130          * time we add a nix the allocator will just return.
131          * Well, this is stupid, because when we do this, we break
132          * the QIDs, which have pointers embedded in them.
133          * darn it, may have to use a linked list. Nope, will probably
134          * just walk the array until we find a matching id. Still ... yuck.
135          */
136         if (v != &nixs[nnix - 1]) {
137                 /* free the image ... oops */
138                 /* get rid of the kref. */
139                 *v = nixs[nnix - 1];
140         }
141         nnix--;
142         spin_unlock(&nixlock);
143         print_func_exit();
144 }
145
146 /* NIX ids run in the range 1..infinity.
147  */
148 static int newnixid(void)
149 {
150         print_func_entry();
151         int id;
152         spin_lock_irqsave(nixidlock);
153         id = kref_refcnt(nixid);
154         kref_get(nixid, 1);
155         spin_unlock(nixidlock);
156         print_func_exit();
157         return id - 1;
158 }
159
160 static int nixgen(struct chan *c, char *entry_name,
161                    struct dirtab *unused, int unused_nr_dirtab,
162                    int s, struct dir *dp)
163 {
164         print_func_entry();
165         struct qid q;
166         struct nix *nix_i;
167         printd("GEN s %d\n", s);
168         /* Whether we're in one dir or at the top, .. still takes us to the top. */
169         if (s == DEVDOTDOT) {
170                 mkqid(&q, Qtopdir, 0, QTDIR);
171                 devdir(c, c->qid, "#V", 0, eve, 0555, dp);
172                 print_func_exit();
173                 return 1;
174         }
175         printd("TYPE %d\n", TYPE(c->qid));
176         switch (TYPE(c->qid)) {
177         case Qtopdir:
178                 printd("Qtopdir s %d nnix %d\n", s, nnix);
179                 /* Generate elements for the top level dir.  We support clone, stat,
180                  * nix dirs at the top level */
181                 if (s == 0) {
182                         mkqid(&q, Qclone, 0, QTFILE);
183                         devdir(c, q, "clone", 0, eve, 0666, dp);
184                         print_func_exit();
185                         return 1;
186                 }
187                 s--;
188                 if (s == 0) {
189                         mkqid(&q, Qstat, 0, QTFILE);
190                         devdir(c, q, "stat", 0, eve, 0666, dp);
191                         print_func_exit();
192                         return 1;
193                 }
194                 s--;    /* 1 -> 0th element, 2 -> 1st element, etc */
195                 spin_lock_irqsave(&nixlock);
196                 if (s >= nnix) {
197                         printd("DONE qtopdir\n");
198                         spin_unlock(&nixlock);
199                         print_func_exit();
200                         return -1;
201                 }
202                 nix_i = &nixs[s];
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                 print_func_exit();
208                 return 1;
209         case Qnixdir:
210                 /* Gen the contents of the nix dirs */
211                 s += Qctl;      /* first time through, start on Qctl */
212                 switch (s) {
213                 case Qctl:
214                         mkqid(&q, QID(s-Qctl, Qctl), 0, QTFILE);
215                         devdir(c, q, "ctl", 0, eve, 0666, dp);
216                         print_func_exit();
217                         return 1;
218                 case Qimage:
219                         mkqid(&q, QID(s-Qctl, Qimage), 0, QTFILE);
220                         devdir(c, q, "image", 0, eve, 0666, dp);
221                         print_func_exit();
222                         return 1;
223                 }
224                 print_func_exit();
225                 return -1;
226                 /* Need to also provide a direct hit for Qclone and all other files (at
227                  * all levels of the hierarchy).  Every file is both
228                  * generated (via the s increments in their respective directories) and
229                  * directly gen-able.  devstat() will call gen with a specific path in
230                  * the qid.  In these cases, we make a dir for whatever they are asking
231                  * for.  Note the qid stays the same.  I think this is what the old
232                  * plan9 comments above devgen were talking about for (ii).
233                  *
234                  * We don't need to do this for the directories - devstat will look for
235                  * the a directory by path and fail.  Then it will manually build the
236                  * stat output (check the -1 case in devstat). */
237         case Qclone:
238                 devdir(c, c->qid, "clone", 0, eve, 0666, dp);
239                 print_func_exit();
240                 return 1;
241         case Qstat:
242                 devdir(c, c->qid, "stat", 0, eve, 0444, dp);
243                 print_func_exit();
244                 return 1;
245         case Qctl:
246                 devdir(c, c->qid, "ctl", 0, eve, 0666, dp);
247                 print_func_exit();
248                 return 1;
249         case Qimage:
250                 devdir(c, c->qid, "image", 0, eve, 0666, dp);
251                 print_func_exit();
252                 return 1;
253         }
254         print_func_exit();
255         return -1;
256 }
257
258 void nixtest(void)
259 {
260         int core = hw_core_id();
261         allcores[core].state = 2;
262         wmb();
263         printk("nixtest\n");
264         allcores[core].assignment = 0;
265         wmb();
266 }
267
268 void nixhost(uint32_t srcid, long a0, long a1, long a2)
269 {
270         int core = a0;
271         printk("nixhost server starting: %d %d %d %d\n", srcid, core, a1, a2);
272         allcores[core].assignment = 0;
273         allcores[core].usable = 1;
274         allcores[core].state = 0;
275         while (1) {
276                 while (allcores[core].assignment == (void *)0) {
277                         allcores[core].state = 0;
278                         wmb();
279                         //printk("mwait for assignment\n");
280                         mwait(&allcores[core].assignment);
281                 }
282                 allcores[core].state = 1;
283                 wmb();
284                 printk("Core %d assigned %p\n", allcores[core].assignment);
285                 (allcores[core].assignment)();
286                 allcores[core].assignment = 0;
287                 allcores[core].state = 2;
288                 wmb();
289         }
290 }
291
292 // allocate pages, starting at 1G, and running until we run out.
293 static void nixinit(void)
294 {
295         //error_t kpage_alloc_specific(page_t** page, size_t ppn)
296         print_func_entry();
297         uint64_t ppn = GiB/4096;
298         spinlock_init_irqsave(&nixlock);
299         spinlock_init_irqsave(nixidlock);
300         while (1) {
301                 if (!page_is_free(ppn)) {
302                         printk("%s: got a non-free page@ppn %p\n", __func__, ppn);
303                         break;
304                 }
305                 kpage_alloc_specific(&nixpages[ppn], ppn);
306                 npages++;
307                 ppn++;
308         }
309         printk("nixinit: nix_init returns %d\n", npages);
310
311         if (npages > 0) {
312                 nixok = 1;
313         }
314
315         // are your cpu etc. etc.
316         // there has to be a better way but for now make it work.
317         int seen_0 = 0;
318         struct sched_pcore *p;
319         extern struct sched_pcore_tailq idlecores;
320         extern struct sched_pcore *all_pcores;
321         TAILQ_FOREACH(p, &idlecores, alloc_next) {
322                 int coreid = p - all_pcores;
323                 if (! coreid) {
324                         if (seen_0++ > 1)
325                                 break;
326                 }
327                 if (coreid > 3){
328                         TAILQ_REMOVE(&idlecores, p, alloc_next);
329                         send_kernel_message(coreid, nixhost, coreid, 0, 0,
330                                             KMSG_ROUTINE);
331                         warn("Using core %d for the ARSCs - there are probably issues with this.", coreid);
332                         break;
333
334                 }
335         }
336         print_func_exit();
337 }
338
339 static struct chan *nixattach(char *spec)
340 {
341         print_func_entry();
342         if (!nixok)
343                 error("No NIXs available");
344         struct chan *c = devattach('t', spec);
345         mkqid(&c->qid, Qtopdir, 0, QTDIR);
346         print_func_exit();
347         return c;
348 }
349
350 static struct walkqid *nixwalk(struct chan *c, struct chan *nc, char **name,
351                                 int nname)
352 {
353         print_func_entry();
354         print_func_exit();
355         return devwalk(c, nc, name, nname, 0, 0, nixgen);
356 }
357
358 static int nixstat(struct chan *c, uint8_t * db, int n)
359 {
360         print_func_entry();
361         print_func_exit();
362         return devstat(c, db, n, 0, 0, nixgen);
363 }
364
365 /* It shouldn't matter if p = current is DYING.  We'll eventually fail to insert
366  * the open chan into p's fd table, then decref the chan. */
367 static struct chan *nixopen(struct chan *c, int omode)
368 {
369         print_func_entry();
370         ERRSTACK(1);
371         struct nix *v = QID2NIX(c->qid);
372         printk("nixopen: v is %p\n", v);
373         if (waserror()) {
374                 nexterror();
375         }
376         switch (TYPE(c->qid)) {
377         case Qtopdir:
378         case Qnixdir:
379                 if (omode & ORCLOSE)
380                         error(Eperm);
381                 if (!IS_RDONLY(omode))
382                         error(Eisdir);
383                 break;
384         case Qclone:
385                 spin_lock_irqsave(&nixlock);
386                 nixs = krealloc(nixs, sizeof(nixs[0]) * (nnix + 1), 0);
387                 v = &nixs[nnix];
388                 mkqid(&c->qid, QID(nnix, Qctl), 0, QTFILE);
389                 nnix++;
390                 spin_unlock(&nixlock);
391                 kref_init(&v->kref, nix_release, 1);
392                 v->id = newnixid();
393                 v->image = KADDR(GiB);
394                 v->imagesize = npages * 4096;
395                 c->aux = v;
396                 printd("New NIX id %d @ %p\n", v->id, v);
397                 printk("image is %p with %d bytes\n", v->image, v->imagesize);
398                 printk("Qclone open: id %d, v is %p\n", nnix-1, v);
399                 break;
400         case Qstat:
401                 break;
402         case Qctl:
403         case Qimage:
404                 //kref_get(&v->kref, 1);
405                 c->aux = QID2NIX(c->qid);
406                 printk("open qctl/image: aux (nix) is %p\n", c->aux);
407                 break;
408         }
409         c->mode = openmode(omode);
410         /* Assumes c is unique (can't be closed concurrently */
411         c->flag |= COPEN;
412         c->offset = 0;
413         poperror();
414         print_func_exit();
415         return c;
416 }
417
418 static void nixcreate(struct chan *c, char *name, int omode, uint32_t perm)
419 {
420         print_func_entry();
421         error(Eperm);
422         print_func_exit();
423 }
424
425 static void nixremove(struct chan *c)
426 {
427         print_func_entry();
428         error(Eperm);
429         print_func_exit();
430 }
431
432 static int nixwstat(struct chan *c, uint8_t * dp, int n)
433 {
434         print_func_entry();
435         error("No nixwstat");
436         print_func_exit();
437         return 0;
438 }
439
440 static void nixclose(struct chan *c)
441 {
442         print_func_entry();
443         struct nix *v = c->aux;
444         if (!v) {
445                 print_func_exit();
446                 return;
447         }
448         /* There are more closes than opens.  For instance, sysstat doesn't open,
449          * but it will close the chan it got from namec.  We only want to clean
450          * up/decref chans that were actually open. */
451         if (!(c->flag & COPEN)) {
452                 print_func_exit();
453                 return;
454         }
455         switch (TYPE(c->qid)) {
456                 /* for now, leave the NIX active even when we close ctl */
457         case Qctl:
458                 break;
459         case Qimage:
460                 //kref_put(&v->kref);
461                 break;
462         }
463         print_func_exit();
464 }
465
466 static long nixread(struct chan *c, void *ubuf, long n, int64_t offset)
467 {
468         print_func_entry();
469         struct nix *v = c->aux;
470         printd("NIXREAD\n");
471         switch (TYPE(c->qid)) {
472         case Qtopdir:
473         case Qnixdir:
474                 print_func_exit();
475                 return devdirread(c, ubuf, n, 0, 0, nixgen);
476         case Qstat:
477                 print_func_exit();
478                 return readnum(offset, ubuf, n, nnix, NUMSIZE32);
479         case Qctl:
480                 assert(v);
481                 print_func_exit();
482                 return readnum(offset, ubuf, n, v->id, NUMSIZE32);
483         case Qimage:
484                 assert(v);
485                 print_func_exit();
486                 return readmem(offset, ubuf, n, v->image, v->imagesize);
487         default:
488                 panic("Bad QID %p in devnix", c->qid.path);
489         }
490         print_func_exit();
491         return 0;
492 }
493
494 static long nixwrite(struct chan *c, void *ubuf, long n, int64_t off)
495 {
496         struct nix *v = c->aux;
497         print_func_entry();
498         ERRSTACK(3);
499         char buf[32];
500         struct cmdbuf *cb;
501         struct nix *nix;
502         uint64_t hexval;
503         printd("nixwrite(%p, %p, %d)\n", c, ubuf, n);
504         switch (TYPE(c->qid)) {
505         case Qtopdir:
506         case Qnixdir:
507         case Qstat:
508                 error(Eperm);
509         case Qctl:
510                 nix = c->aux;
511                 printk("qctl: nix is %p, nix is %p\n", nix, nix);
512                 cb = parsecmd(ubuf, n);
513                 if (waserror()) {
514                         kfree(cb);
515                         nexterror();
516                 }
517                 if (!strcmp(cb->f[0], "run")) {
518                         int core;
519                         uintptr_t ip;
520                         if (cb->nf != 3)
521                                 error("usage: run core entry");
522                         core = strtoul(cb->f[1], 0, 0);
523                         ip = strtoul(cb->f[2], 0, 0);
524                         if (!allcores[core].usable)
525                                 error("Bad core %d", core);
526                         allcores[core].assignment = (void *)ip;
527                         wmb();
528                         printk("nix_run returns \n");
529                         print_func_exit();
530                 } else if (!strcmp(cb->f[0], "test")) {
531                         int core;
532                         if (cb->nf != 2)
533                                 error("usage: test core");
534                         core = strtoul(cb->f[1], 0, 0);
535                         if (!allcores[core].usable)
536                                 error("Bad core %d", core);
537                         allcores[core].assignment = nixtest;
538                         wmb();
539                         printk("nix_run returns \n");
540                         print_func_exit();
541                 } else if (!strcmp(cb->f[0], "check")) {
542                         int i;
543                         for(i = 0; i < ARRAY_SIZE(allcores); i++) {
544                                 if (! allcores[i].usable)
545                                         continue;
546                                 printk("%p %p %p %p %d %d\n",
547                                        allcores[i].assignment,
548                                        allcores[i].work,
549                                        allcores[i].result,
550                                        allcores[i].done,
551                                        allcores[i].usable,
552                                        allcores[i].state);
553                         }
554                 } else if (!strcmp(cb->f[0], "stop")) {
555                         error("can't stop a nix yet");
556                 } else {
557                         error("%s: not implemented", cb->f[0]);
558                 }
559                 kfree(cb);
560                 poperror();
561                 break;
562         case Qimage:
563                 if (off < 0)
564                         error("offset < 0!");
565
566                 if (off + n > v->imagesize) {
567                         n = v->imagesize - off;
568                 }
569                 printd("copy to %p ubuf %p size %d\n", v->image + off, ubuf, n);
570
571                 if (memcpy_from_user_errno(current, v->image + off, ubuf, n) < 0)
572                         error("%s: bad user addr %p", __FUNCTION__, ubuf);
573                 break;
574
575         default:
576                 panic("Bad QID %p in devnix", c->qid.path);
577         }
578         print_func_exit();
579         return n;
580 }
581
582 struct dev nixdevtab __devtab = {
583         't',
584         "nix",
585
586         devreset,
587         nixinit,
588         devshutdown,
589         nixattach,
590         nixwalk,
591         nixstat,
592         nixopen,
593         nixcreate,
594         nixclose,
595         nixread,
596         devbread,
597         nixwrite,
598         devbwrite,
599         nixremove,
600         nixwstat,
601         devpower,
602 //  devconfig,
603         devchaninfo,
604 };