0aa911cc4fda9480a44aa828dffc5f58058c7000
[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  * FOR THE MOMENT, this is only intended to run one NIX at a time.
10  * Too many sharp edges for any other mode.
11  */
12
13 #include <kmalloc.h>
14 #include <string.h>
15 #include <stdio.h>
16 #include <assert.h>
17 #include <error.h>
18 #include <pmap.h>
19 #include <sys/queue.h>
20 #include <smp.h>
21 #include <kref.h>
22 #include <atomic.h>
23 #include <alarm.h>
24 #include <event.h>
25 #include <umem.h>
26 #include <devalarm.h>
27 #include <arch/types.h>
28 #include <arch/emulate.h>
29 #include <arch/vmdebug.h>
30 #include <kdebug.h>
31 #include <bitmap.h>
32
33 /* qid path types */
34 enum {
35         Qtopdir = 1,
36         Qclone,
37         Qstat,
38         Qnixdir,
39         Qctl,
40         Qimage,
41 };
42
43 /* The QID is the TYPE and the index into the nix array.
44  * We reserve the right to make it an id later. */
45 #define INDEX_SHIFT 5
46 /* nix's have an image.
47  * Note that the image can be read even as it is running. */
48 struct nix {
49         struct kref kref;
50         /* should this be an array of pages? Hmm. */
51         void *image;
52         unsigned long imagesize;
53         int id;
54         /* we could dynamically alloc one of these with num_cpus */
55         DECLARE_BITMAP(cpus, MAX_NUM_CPUS);
56 };
57
58 static spinlock_t nixlock = SPINLOCK_INITIALIZER_IRQSAVE;
59 /* array, not linked list. We expect few, might as well be cache friendly. */
60 static struct nix *nixs = NULL;
61 static int nnix = 0;
62 static int nixok = 0;
63 static int npages;
64 // only 4 gig for now.
65 // XXX is this for all nixs?
66 static page_t *nixpages[1048576];
67
68 static atomic_t nixid = 0;
69
70 /* The index is not the id, for now.  The index is the spot in nixs[].  The id
71  * is an increasing integer, regardless of struct nix* reuse. */
72 static inline struct nix *QID2NIX(struct qid q)
73 {
74         return &nixs[q.path >> INDEX_SHIFT];
75 }
76
77 static inline int TYPE(struct qid q)
78 {
79         return ((q).path & ((1 << INDEX_SHIFT) - 1));
80 }
81
82 static inline int QID(int index, int type)
83 {
84         return ((index << INDEX_SHIFT) | type);
85 }
86
87 /* we'll need this somewhere more generic. */
88 static void readn(struct chan *c, void *vp, long n)
89 {
90         char *p;
91         long nn;
92         int total = 0, want = n;
93
94         p = vp;
95         while (n > 0) {
96                 nn = devtab[c->type].read(c, p, n, c->offset);
97                 printk("readn: Got %d@%lld\n", nn, c->offset);
98                 if (nn == 0)
99                         error("%s: wanted %d, got %d", Eshort, want, total);
100                 c->offset += nn;
101                 p += nn;
102                 n -= nn;
103                 total += nn;
104         }
105 }
106
107 /* not called yet.  -- we have to unlink the nix */
108 static void nix_release(struct kref *kref)
109 {
110         struct nix *v = container_of(kref, struct nix, kref);
111         spin_lock_irqsave(&nixlock);
112         /* cute trick. Save the last element of the array in place of the
113          * one we're deleting. Reduce nnix. Don't realloc; that way, next
114          * time we add a nix the allocator will just return.
115          * Well, this is stupid, because when we do this, we break
116          * the QIDs, which have pointers embedded in them.
117          * darn it, may have to use a linked list. Nope, will probably
118          * just walk the array until we find a matching id. Still ... yuck.
119          */
120         if (v != &nixs[nnix - 1]) {
121                 /* free the image ... oops */
122                 /* get rid of the kref. */
123                 *v = nixs[nnix - 1];
124         }
125         nnix--;
126         spin_unlock(&nixlock);
127 }
128
129 /* NIX ids run in the range 0..infinity.  */
130 static int newnixid(void)
131 {
132         return atomic_fetch_and_add(&nixid, 1);
133 }
134
135 static int nixgen(struct chan *c, char *entry_name,
136                    struct dirtab *unused, int unused_nr_dirtab,
137                    int s, struct dir *dp)
138 {
139         struct qid q;
140         struct nix *nix_i;
141         /* Whether we're in one dir or at the top, .. still takes us to the top. */
142         if (s == DEVDOTDOT) {
143                 mkqid(&q, Qtopdir, 0, QTDIR);
144                 devdir(c, c->qid, "#V", 0, eve, 0555, dp);
145                 return 1;
146         }
147         switch (TYPE(c->qid)) {
148         case Qtopdir:
149                 /* Generate elements for the top level dir.  We support clone, stat,
150                  * nix dirs at the top level */
151                 if (s == 0) {
152                         mkqid(&q, Qclone, 0, QTFILE);
153                         devdir(c, q, "clone", 0, eve, 0666, dp);
154                         return 1;
155                 }
156                 s--;
157                 if (s == 0) {
158                         mkqid(&q, Qstat, 0, QTFILE);
159                         devdir(c, q, "stat", 0, eve, 0666, dp);
160                         return 1;
161                 }
162                 s--;    /* 1 -> 0th element, 2 -> 1st element, etc */
163                 spin_lock_irqsave(&nixlock);
164                 if (s >= nnix) {
165                         spin_unlock(&nixlock);
166                         return -1;
167                 }
168                 nix_i = &nixs[s];
169                 snprintf(get_cur_genbuf(), GENBUF_SZ, "nix%d", nix_i->id);
170                 spin_unlock(&nixlock);
171                 mkqid(&q, QID(s, Qnixdir), 0, QTDIR);
172                 devdir(c, q, get_cur_genbuf(), 0, eve, 0555, dp);
173                 return 1;
174         case Qnixdir:
175                 /* Gen the contents of the nix dirs */
176                 s += Qctl;      /* first time through, start on Qctl */
177                 switch (s) {
178                 case Qctl:
179                         mkqid(&q, QID(s-Qctl, Qctl), 0, QTFILE);
180                         devdir(c, q, "ctl", 0, eve, 0666, dp);
181                         return 1;
182                 case Qimage:
183                         mkqid(&q, QID(s-Qctl, Qimage), 0, QTFILE);
184                         devdir(c, q, "image", 0, eve, 0666, dp);
185                         return 1;
186                 }
187                 return -1;
188                 /* Need to also provide a direct hit for Qclone and all other files (at
189                  * all levels of the hierarchy).  Every file is both
190                  * generated (via the s increments in their respective directories) and
191                  * directly gen-able.  devstat() will call gen with a specific path in
192                  * the qid.  In these cases, we make a dir for whatever they are asking
193                  * for.  Note the qid stays the same.  I think this is what the old
194                  * plan9 comments above devgen were talking about for (ii).
195                  *
196                  * We don't need to do this for the directories - devstat will look for
197                  * the a directory by path and fail.  Then it will manually build the
198                  * stat output (check the -1 case in devstat). */
199         case Qclone:
200                 devdir(c, c->qid, "clone", 0, eve, 0666, dp);
201                 return 1;
202         case Qstat:
203                 devdir(c, c->qid, "stat", 0, eve, 0444, dp);
204                 return 1;
205         case Qctl:
206                 devdir(c, c->qid, "ctl", 0, eve, 0666, dp);
207                 return 1;
208         case Qimage:
209                 devdir(c, c->qid, "image", 0, eve, 0666, dp);
210                 return 1;
211         }
212         return -1;
213 }
214
215 void nixtest(void)
216 {
217         printk("nixtest ran on core %d\n", core_id());
218 }
219
220 // allocate pages, starting at 1G, and running until we run out.
221 static void nixinit(void)
222 {
223         //error_t kpage_alloc_specific(page_t** page, size_t ppn)
224         uint64_t ppn = GiB/4096;
225         while (1) {
226                 if (!page_is_free(ppn)) {
227                         printk("%s: got a non-free page@ppn %p\n", __func__, ppn);
228                         break;
229                 }
230                 kpage_alloc_specific(&nixpages[ppn], ppn);
231                 npages++;
232                 ppn++;
233         }
234         printk("nixinit: nix_init returns %d\n", npages);
235
236         if (npages > 0) {
237                 nixok = 1;
238         }
239 }
240
241 static struct chan *nixattach(char *spec)
242 {
243         if (!nixok)
244                 error("No NIXs available");
245         struct chan *c = devattach('t', spec);
246         mkqid(&c->qid, Qtopdir, 0, QTDIR);
247         return c;
248 }
249
250 static struct walkqid *nixwalk(struct chan *c, struct chan *nc, char **name,
251                                 int nname)
252 {
253         return devwalk(c, nc, name, nname, 0, 0, nixgen);
254 }
255
256 static int nixstat(struct chan *c, uint8_t * db, int n)
257 {
258         return devstat(c, db, n, 0, 0, nixgen);
259 }
260
261 /* It shouldn't matter if p = current is DYING.  We'll eventually fail to insert
262  * the open chan into p's fd table, then decref the chan. */
263 static struct chan *nixopen(struct chan *c, int omode)
264 {
265         ERRSTACK(1);
266         struct nix *v = QID2NIX(c->qid);
267         if (waserror()) {
268                 nexterror();
269         }
270         switch (TYPE(c->qid)) {
271         case Qtopdir:
272         case Qnixdir:
273                 if (omode & ORCLOSE)
274                         error(Eperm);
275                 if (!IS_RDONLY(omode))
276                         error(Eisdir);
277                 break;
278         case Qclone:
279                 spin_lock_irqsave(&nixlock);
280                 nixs = krealloc(nixs, sizeof(nixs[0]) * (nnix + 1), 0);
281                 v = &nixs[nnix];
282                 mkqid(&c->qid, QID(nnix, Qctl), 0, QTFILE);
283                 nnix++;
284                 spin_unlock(&nixlock);
285                 kref_init(&v->kref, nix_release, 1);
286                 v->id = newnixid();
287                 v->image = KADDR(GiB);
288                 v->imagesize = npages * 4096;
289                 printk("nix image is %p with %d bytes\n", v->image, v->imagesize);
290                 c->aux = v;
291                 bitmap_zero(v->cpus, MAX_NUM_CPUS);
292                 break;
293         case Qstat:
294                 break;
295         case Qctl:
296         case Qimage:
297                 //kref_get(&v->kref, 1);
298                 c->aux = QID2NIX(c->qid);
299                 break;
300         }
301         c->mode = openmode(omode);
302         /* Assumes c is unique (can't be closed concurrently */
303         c->flag |= COPEN;
304         c->offset = 0;
305         poperror();
306         return c;
307 }
308
309 static void nixcreate(struct chan *c, char *name, int omode, uint32_t perm)
310 {
311         error(Eperm);
312 }
313
314 static void nixremove(struct chan *c)
315 {
316         error(Eperm);
317 }
318
319 static int nixwstat(struct chan *c, uint8_t * dp, int n)
320 {
321         error("No nixwstat");
322         return 0;
323 }
324
325 static void nixclose(struct chan *c)
326 {
327         struct nix *v = c->aux;
328         if (!v)
329                 return;
330         /* There are more closes than opens.  For instance, sysstat doesn't open,
331          * but it will close the chan it got from namec.  We only want to clean
332          * up/decref chans that were actually open. */
333         if (!(c->flag & COPEN))
334                 return;
335         switch (TYPE(c->qid)) {
336                 /* the idea of 'stopping' a nix is tricky. 
337                  * for now, leave the NIX active even when we close ctl */
338         case Qctl:
339                 break;
340         case Qimage:
341                 //kref_put(&v->kref);
342                 break;
343         }
344 }
345
346 static long nixread(struct chan *c, void *ubuf, long n, int64_t offset)
347 {
348         struct nix *v = c->aux;
349         switch (TYPE(c->qid)) {
350         case Qtopdir:
351         case Qnixdir:
352                 return devdirread(c, ubuf, n, 0, 0, nixgen);
353         case Qstat:
354                 return readnum(offset, ubuf, n, nnix, NUMSIZE32);
355         case Qctl:
356                 assert(v);
357                 return readnum(offset, ubuf, n, v->id, NUMSIZE32);
358         case Qimage:
359                 assert(v);
360                 return readmem(offset, ubuf, n, v->image, v->imagesize);
361         default:
362                 panic("Bad QID %p in devnix", c->qid.path);
363         }
364         return 0;
365 }
366
367 static void nixwrapper(uint32_t srcid, long a0, long a1, long a2)
368 {
369         void (*f)(void) = (void (*)(void))a0;
370         f();
371 }
372
373 static long nixwrite(struct chan *c, void *ubuf, long n, int64_t off)
374 {
375         struct nix *v = c->aux;
376         ERRSTACK(1);
377         char buf[32];
378         struct cmdbuf *cb;
379         struct nix *nix;
380         uint64_t hexval;
381         switch (TYPE(c->qid)) {
382         case Qtopdir:
383         case Qnixdir:
384         case Qstat:
385                 error(Eperm);
386         case Qctl:
387                 nix = c->aux;
388                 cb = parsecmd(ubuf, n);
389                 /* TODO: lock the nix here, unlock in waserror and before popping */
390                 if (waserror()) {
391                         kfree(cb);
392                         nexterror();
393                 }
394                 if (!strcmp(cb->f[0], "run")) {
395                         int core;
396                         uintptr_t ip;
397                         if (cb->nf != 3)
398                                 error("usage: run core entry");
399                         core = strtoul(cb->f[1], 0, 0);
400                         ip = strtoul(cb->f[2], 0, 0);
401                         if (!test_bit(core, nix->cpus))
402                                 error("Bad core %d", core);
403                         send_kernel_message(core, nixwrapper, (long)ip, 0, 0, KMSG_ROUTINE);
404                 } else if (!strcmp(cb->f[0], "test")) {
405                         int core;
406                         if (cb->nf != 2)
407                                 error("usage: test core");
408                         core = strtoul(cb->f[1], 0, 0);
409                         if (!test_bit(core, nix->cpus))
410                                 error("Bad core %d", core);
411                         send_kernel_message(core, nixwrapper, (long)nixtest, 0, 0,
412                                             KMSG_ROUTINE);
413                 } else if (!strcmp(cb->f[0], "reserve")) {
414                         int core;
415                         if (cb->nf != 2)
416                                 error("Usage: reserve core (-1 for any)");
417                         core = strtol(cb->f[1], 0, 0);
418                         if (core == -1) {
419                                 core = get_any_idle_core();
420                                 if (core < 0)
421                                         error("No free idle cores!");
422                         } else {
423                                 if (get_this_idle_core(core) < 0)
424                                         error("Failed to reserve core %d\n", core);
425                         }
426                         set_bit(core, nix->cpus);
427                 } else if (!strcmp(cb->f[0], "check")) {
428                         int i;
429                         for(i = 0; i < MAX_NUM_CPUS; i++) {
430                                 if (!test_bit(i, nix->cpus))
431                                         continue;
432                                 printk("Core %d is available to nix%d\n", i, nix->id);
433                         }
434                 } else if (!strcmp(cb->f[0], "stop")) {
435                         error("can't stop a nix yet");
436                 } else {
437                         error("%s: not implemented", cb->f[0]);
438                 }
439                 kfree(cb);
440                 poperror();
441                 break;
442         case Qimage:
443                 if (off < 0)
444                         error("offset < 0!");
445
446                 if (off + n > v->imagesize) {
447                         n = v->imagesize - off;
448                 }
449
450                 if (memcpy_from_user_errno(current, v->image + off, ubuf, n) < 0)
451                         error("%s: bad user addr %p", __FUNCTION__, ubuf);
452                 break;
453
454         default:
455                 panic("Bad QID %p in devnix", c->qid.path);
456         }
457         return n;
458 }
459
460 struct dev nixdevtab __devtab = {
461         't',
462         "nix",
463
464         devreset,
465         nixinit,
466         devshutdown,
467         nixattach,
468         nixwalk,
469         nixstat,
470         nixopen,
471         nixcreate,
472         nixclose,
473         nixread,
474         devbread,
475         nixwrite,
476         devbwrite,
477         nixremove,
478         nixwstat,
479         devpower,
480 //  devconfig,
481         devchaninfo,
482 };