Ports uses of get_any_idle_core()
[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         int nix_coreid = get_any_idle_core();
316         /* TODO: gracefully fail */
317         assert(nix_coreid >= 0);
318         send_kernel_message(nix_coreid, nixhost, nix_coreid, 0, 0, KMSG_ROUTINE);
319         printk("Using core %d for a NIX host\n", nix_coreid);
320
321         print_func_exit();
322 }
323
324 static struct chan *nixattach(char *spec)
325 {
326         print_func_entry();
327         if (!nixok)
328                 error("No NIXs available");
329         struct chan *c = devattach('t', spec);
330         mkqid(&c->qid, Qtopdir, 0, QTDIR);
331         print_func_exit();
332         return c;
333 }
334
335 static struct walkqid *nixwalk(struct chan *c, struct chan *nc, char **name,
336                                 int nname)
337 {
338         print_func_entry();
339         print_func_exit();
340         return devwalk(c, nc, name, nname, 0, 0, nixgen);
341 }
342
343 static int nixstat(struct chan *c, uint8_t * db, int n)
344 {
345         print_func_entry();
346         print_func_exit();
347         return devstat(c, db, n, 0, 0, nixgen);
348 }
349
350 /* It shouldn't matter if p = current is DYING.  We'll eventually fail to insert
351  * the open chan into p's fd table, then decref the chan. */
352 static struct chan *nixopen(struct chan *c, int omode)
353 {
354         print_func_entry();
355         ERRSTACK(1);
356         struct nix *v = QID2NIX(c->qid);
357         printk("nixopen: v is %p\n", v);
358         if (waserror()) {
359                 nexterror();
360         }
361         switch (TYPE(c->qid)) {
362         case Qtopdir:
363         case Qnixdir:
364                 if (omode & ORCLOSE)
365                         error(Eperm);
366                 if (!IS_RDONLY(omode))
367                         error(Eisdir);
368                 break;
369         case Qclone:
370                 spin_lock_irqsave(&nixlock);
371                 nixs = krealloc(nixs, sizeof(nixs[0]) * (nnix + 1), 0);
372                 v = &nixs[nnix];
373                 mkqid(&c->qid, QID(nnix, Qctl), 0, QTFILE);
374                 nnix++;
375                 spin_unlock(&nixlock);
376                 kref_init(&v->kref, nix_release, 1);
377                 v->id = newnixid();
378                 v->image = KADDR(GiB);
379                 v->imagesize = npages * 4096;
380                 c->aux = v;
381                 printd("New NIX id %d @ %p\n", v->id, v);
382                 printk("image is %p with %d bytes\n", v->image, v->imagesize);
383                 printk("Qclone open: id %d, v is %p\n", nnix-1, v);
384                 break;
385         case Qstat:
386                 break;
387         case Qctl:
388         case Qimage:
389                 //kref_get(&v->kref, 1);
390                 c->aux = QID2NIX(c->qid);
391                 printk("open qctl/image: aux (nix) is %p\n", c->aux);
392                 break;
393         }
394         c->mode = openmode(omode);
395         /* Assumes c is unique (can't be closed concurrently */
396         c->flag |= COPEN;
397         c->offset = 0;
398         poperror();
399         print_func_exit();
400         return c;
401 }
402
403 static void nixcreate(struct chan *c, char *name, int omode, uint32_t perm)
404 {
405         print_func_entry();
406         error(Eperm);
407         print_func_exit();
408 }
409
410 static void nixremove(struct chan *c)
411 {
412         print_func_entry();
413         error(Eperm);
414         print_func_exit();
415 }
416
417 static int nixwstat(struct chan *c, uint8_t * dp, int n)
418 {
419         print_func_entry();
420         error("No nixwstat");
421         print_func_exit();
422         return 0;
423 }
424
425 static void nixclose(struct chan *c)
426 {
427         print_func_entry();
428         struct nix *v = c->aux;
429         if (!v) {
430                 print_func_exit();
431                 return;
432         }
433         /* There are more closes than opens.  For instance, sysstat doesn't open,
434          * but it will close the chan it got from namec.  We only want to clean
435          * up/decref chans that were actually open. */
436         if (!(c->flag & COPEN)) {
437                 print_func_exit();
438                 return;
439         }
440         switch (TYPE(c->qid)) {
441                 /* for now, leave the NIX active even when we close ctl */
442         case Qctl:
443                 break;
444         case Qimage:
445                 //kref_put(&v->kref);
446                 break;
447         }
448         print_func_exit();
449 }
450
451 static long nixread(struct chan *c, void *ubuf, long n, int64_t offset)
452 {
453         print_func_entry();
454         struct nix *v = c->aux;
455         printd("NIXREAD\n");
456         switch (TYPE(c->qid)) {
457         case Qtopdir:
458         case Qnixdir:
459                 print_func_exit();
460                 return devdirread(c, ubuf, n, 0, 0, nixgen);
461         case Qstat:
462                 print_func_exit();
463                 return readnum(offset, ubuf, n, nnix, NUMSIZE32);
464         case Qctl:
465                 assert(v);
466                 print_func_exit();
467                 return readnum(offset, ubuf, n, v->id, NUMSIZE32);
468         case Qimage:
469                 assert(v);
470                 print_func_exit();
471                 return readmem(offset, ubuf, n, v->image, v->imagesize);
472         default:
473                 panic("Bad QID %p in devnix", c->qid.path);
474         }
475         print_func_exit();
476         return 0;
477 }
478
479 static long nixwrite(struct chan *c, void *ubuf, long n, int64_t off)
480 {
481         struct nix *v = c->aux;
482         print_func_entry();
483         ERRSTACK(3);
484         char buf[32];
485         struct cmdbuf *cb;
486         struct nix *nix;
487         uint64_t hexval;
488         printd("nixwrite(%p, %p, %d)\n", c, ubuf, n);
489         switch (TYPE(c->qid)) {
490         case Qtopdir:
491         case Qnixdir:
492         case Qstat:
493                 error(Eperm);
494         case Qctl:
495                 nix = c->aux;
496                 printk("qctl: nix is %p, nix is %p\n", nix, nix);
497                 cb = parsecmd(ubuf, n);
498                 if (waserror()) {
499                         kfree(cb);
500                         nexterror();
501                 }
502                 if (!strcmp(cb->f[0], "run")) {
503                         int core;
504                         uintptr_t ip;
505                         if (cb->nf != 3)
506                                 error("usage: run core entry");
507                         core = strtoul(cb->f[1], 0, 0);
508                         ip = strtoul(cb->f[2], 0, 0);
509                         if (!allcores[core].usable)
510                                 error("Bad core %d", core);
511                         allcores[core].assignment = (void *)ip;
512                         wmb();
513                         printk("nix_run returns \n");
514                         print_func_exit();
515                 } else if (!strcmp(cb->f[0], "test")) {
516                         int core;
517                         if (cb->nf != 2)
518                                 error("usage: test core");
519                         core = strtoul(cb->f[1], 0, 0);
520                         if (!allcores[core].usable)
521                                 error("Bad core %d", core);
522                         allcores[core].assignment = nixtest;
523                         wmb();
524                         printk("nix_run returns \n");
525                         print_func_exit();
526                 } else if (!strcmp(cb->f[0], "check")) {
527                         int i;
528                         for(i = 0; i < ARRAY_SIZE(allcores); i++) {
529                                 if (! allcores[i].usable)
530                                         continue;
531                                 printk("%p %p %p %p %d %d\n",
532                                        allcores[i].assignment,
533                                        allcores[i].work,
534                                        allcores[i].result,
535                                        allcores[i].done,
536                                        allcores[i].usable,
537                                        allcores[i].state);
538                         }
539                 } else if (!strcmp(cb->f[0], "stop")) {
540                         error("can't stop a nix yet");
541                 } else {
542                         error("%s: not implemented", cb->f[0]);
543                 }
544                 kfree(cb);
545                 poperror();
546                 break;
547         case Qimage:
548                 if (off < 0)
549                         error("offset < 0!");
550
551                 if (off + n > v->imagesize) {
552                         n = v->imagesize - off;
553                 }
554                 printd("copy to %p ubuf %p size %d\n", v->image + off, ubuf, n);
555
556                 if (memcpy_from_user_errno(current, v->image + off, ubuf, n) < 0)
557                         error("%s: bad user addr %p", __FUNCTION__, ubuf);
558                 break;
559
560         default:
561                 panic("Bad QID %p in devnix", c->qid.path);
562         }
563         print_func_exit();
564         return n;
565 }
566
567 struct dev nixdevtab __devtab = {
568         't',
569         "nix",
570
571         devreset,
572         nixinit,
573         devshutdown,
574         nixattach,
575         nixwalk,
576         nixstat,
577         nixopen,
578         nixcreate,
579         nixclose,
580         nixread,
581         devbread,
582         nixwrite,
583         devbwrite,
584         nixremove,
585         nixwstat,
586         devpower,
587 //  devconfig,
588         devchaninfo,
589 };