Basic layout of the driver is sorta done.
[akaros.git] / kern / drivers / dev / vm.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  * devvm/#V: a device for VMs
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
26 /* qid path types */
27 enum {
28         Qtopdir = 1,
29         Qclone,
30         Qstat,
31         Qvmdir,
32         Qctl,
33         Qimage,
34 };
35
36 /* This paddr/kaddr is a bit dangerous.  it'll work so long as we don't need all
37  * 64 bits for a physical address (48 is the current norm on x86_64).
38  * We're probably going to move to a model where we put the VM index or something
39  * into the qid, but this works for now.
40  */
41 #define ADDR_SHIFT 5
42 #define QID2VM(q) ((struct proc_alarm*)KADDR(((q).path >> ADDR_SHIFT)))
43 #define TYPE(q) ((q).path & ((1 << ADDR_SHIFT) - 1))
44 #define QID(ptr, type) ((PADDR(ptr) << ADDR_SHIFT) | type)
45
46 /* vm's have an image.
47  * Note that the image can be read even as it is running. */
48 struct vm {
49         struct vm *next;
50         struct kref                                     kref;
51         /* should this be an array of pages? Hmm. */
52         void                                           *image;
53         unsigned long                                   imagesize;
54         int                                             id;
55 };
56
57 static spinlock_t vmlock;
58 /* array, not linked list. We expect few, might as well be cache friendly. */
59 static struct vm *vms = NULL;
60 static int nvm = 0;
61
62 static spinlock_t vmidlock[1];
63 static struct kref vmid[1] = { {(void *)1, fake_release} };
64
65 static void vm_release(struct kref *kref)
66 {
67         struct vm *v = container_of(kref, struct vm, kref);
68         spin_lock(&vmlock);
69         /* cute trick. Save the last element of the array in place of the
70          * one we're deleting. Reduce nvm. Don't realloc; that way, next
71
72          * do and just return.
73          */
74         if (v != &vms[nvm-1]){
75                 /* free the image ... oops */
76                 /* get rid of the kref. */
77                 *v = vms[nvm-1];
78         }
79         nvm--;
80         spin_unlock(&vmlock);
81 }
82
83 static int newvmid(void)
84 {
85         int id;
86         spin_lock(vmidlock);
87         id = kref_refcnt(vmid);
88         kref_get(vmid, 1);
89         spin_unlock(vmidlock);
90         return id;
91 }
92
93 static int vmgen(struct chan *c, char *entry_name,
94                  struct dirtab *unused, int unused_nr_dirtab,
95                  int s, struct dir *dp)
96 {
97         struct qid q;
98         struct vm *vm_i;
99         printd("GEN s %d\n", s);
100         /* Whether we're in one dir or at the top, .. still takes us to the top. */
101         if (s == DEVDOTDOT) {
102                 mkqid(&q, Qtopdir, 0, QTDIR);
103                 devdir(c, c->qid, "#V", 0, eve, 0555, dp);
104                 return 1;
105         }
106         printd("TYPE %d\n", TYPE(c->qid));
107         switch (TYPE(c->qid)) {
108         case Qtopdir:
109                 printd("Qtopdir s %d nvm %d\n", s, nvm);
110                 /* Generate elements for the top level dir.  We support clone, stat,
111                  * vm dirs at the top level */
112                 if (s == 0) {
113                         mkqid(&q, Qclone, 0, QTFILE);
114                         devdir(c, q, "clone", 0, eve, 0666, dp);
115                         return 1;
116                 }
117                 s--;
118                 if (s == 0) {
119                         mkqid(&q, Qstat, 0, QTFILE);
120                         devdir(c, q, "stat", 0, eve, 0666, dp);
121                         return 1;
122                 }
123                 s--;    /* 1 -> 0th element, 2 -> 1st element, etc */
124                 spin_lock(&vmlock);
125                 if (s >= nvm){
126                         printd("DONE qtopdir\n");
127                         spin_unlock(&vmlock);
128                         return -1;
129                 }
130                 vm_i = &vms[s];
131                 snprintf(get_cur_genbuf(), GENBUF_SZ, "vm%d", vm_i->id);
132                 spin_unlock(&vmlock);
133                 mkqid(&q, QID(vm_i, Qvmdir), 0, QTDIR);
134                 devdir(c, q, get_cur_genbuf(), 0, eve, 0555, dp);
135                 return 1;
136         case Qvmdir:
137                 /* Gen the contents of the vm dirs */
138                 s += Qctl;      /* first time through, start on Qctl */
139                 switch (s) {
140                 case Qctl:
141                         mkqid(&q, QID(QID2VM(c->qid), Qctl), 0, QTFILE);
142                         devdir(c, q, "ctl", 0, eve, 0666, dp);
143                         return 1;
144                 case Qimage:
145                         mkqid(&q, QID(QID2VM(c->qid), Qimage), 0, QTFILE);
146                         devdir(c, q, "image", 0, eve, 0666, dp);
147                         return 1;
148                 }
149                 return -1;
150                 /* Need to also provide a direct hit for Qclone and all other files (at
151                  * all levels of the hierarchy).  Every file is both
152                  * generated (via the s increments in their respective directories) and
153                  * directly gen-able.  devstat() will call gen with a specific path in
154                  * the qid.  In these cases, we make a dir for whatever they are asking
155                  * for.  Note the qid stays the same.  I think this is what the old
156                  * plan9 comments above devgen were talking about for (ii).
157                  *
158                  * We don't need to do this for the directories - devstat will look for
159                  * the a directory by path and fail.  Then it will manually build the
160                  * stat output (check the -1 case in devstat). */
161         case Qclone:
162                 devdir(c, c->qid, "clone", 0, eve, 0666, dp);
163                 return 1;
164         case Qstat:
165                 devdir(c, c->qid, "stat", 0, eve, 0444, dp);
166                 return 1;
167         case Qctl:
168                 devdir(c, c->qid, "ctl", 0, eve, 0666, dp);
169                 return 1;
170         case Qimage:
171                 devdir(c, c->qid, "image", 0, eve, 0666, dp);
172                 return 1;
173         }
174         return -1;
175 }
176
177 static void vminit(void)
178 {
179         spinlock_init(&vmlock);
180         spinlock_init(vmidlock);
181 }
182
183 static struct chan *vmattach(char *spec)
184 {
185         struct chan *c = devattach('V', spec);
186         mkqid(&c->qid, Qtopdir, 0, QTDIR);
187         return c;
188 }
189
190 static struct walkqid *vmwalk(struct chan *c, struct chan *nc, char **name,
191                               int nname)
192 {
193         return devwalk(c, nc, name, nname, 0, 0, vmgen);
194 }
195
196 static int vmstat(struct chan *c, uint8_t *db, int n)
197 {
198         return devstat(c, db, n, 0, 0, vmgen);
199 }
200
201 /* It shouldn't matter if p = current is DYING.  We'll eventually fail to insert
202  * the open chan into p's fd table, then decref the chan. */
203 static struct chan *vmopen(struct chan *c, int omode)
204 {
205         struct vm *v = c->aux;
206         switch (TYPE(c->qid)) {
207         case Qtopdir:
208         case Qvmdir:
209                 if (omode & ORCLOSE)
210                         error(Eperm);
211                 if (omode != OREAD)
212                         error(Eisdir);
213                 break;
214         case Qclone:
215                 spin_lock(&vmlock);
216                 vms = krealloc(vms, sizeof(vms[0])*(nvm+1),0);
217                 v = &vms[nvm];
218                 nvm++;
219                 spin_unlock(&vmlock);
220                 kref_init(&v->kref, vm_release, 1);
221                 v->id = newvmid();
222                 mkqid(&c->qid, QID(v, Qctl), 0, QTFILE);
223                 c->aux = v;
224                 printd("New VM id %d\n", v->id);
225                 break;
226         case Qstat:
227                 break;
228         case Qctl:
229         case Qimage:
230                 /* the purpose of opening is to hold a kref on the proc_vm */
231                 v = c->aux;
232                 /* this isn't a valid pointer yet, since our chan doesn't have a
233                  * ref.  since the time that walk gave our chan the qid, the chan
234                  * could have been closed, and the vm decref'd and freed.  the
235                  * qid is essentially an uncounted reference, and we need to go to
236                  * the source to attempt to get a real ref.  Unfortunately, this is
237                  * another scan of the list, same as devsrv.  We could speed it up
238                  * by storing an "on_list" bool in the vm_is. */
239                 //if (!vm_i)
240                 //      error("Unable to open vm, concurrent closing");
241                 break;
242         }
243         c->mode = openmode(omode);
244         /* Assumes c is unique (can't be closed concurrently */
245         c->flag |= COPEN;
246         c->offset = 0;
247         return c;
248 }
249
250 static void vmcreate(struct chan *c, char *name, int omode, uint32_t perm)
251 {
252         error(Eperm);
253 }
254
255 static void vmremove(struct chan *c)
256 {
257         error(Eperm);
258 }
259
260 static int vmwstat(struct chan *c, uint8_t *dp, int n)
261 {
262         error("No vmwstat");
263         return 0;
264 }
265
266 static void vmclose(struct chan *c)
267 {
268         struct vm *v = c->aux;
269         if (!v)
270                 return;
271         /* There are more closes than opens.  For instance, sysstat doesn't open,
272          * but it will close the chan it got from namec.  We only want to clean
273          * up/decref chans that were actually open. */
274         if (!(c->flag & COPEN))
275                 return;
276         switch (TYPE(c->qid)) {
277                 /* for now, leave the VM active even when we close ctl */
278         case Qctl:
279                 break;
280         case Qimage:
281                 kref_put(&v->kref);
282                 break;
283         }
284 }
285
286 static long vmread(struct chan *c, void *ubuf, long n, int64_t offset)
287 {
288         struct vm *v = c->aux;
289         printd("VMREAD\n");
290         switch (TYPE(c->qid)) {
291         case Qtopdir:
292         case Qvmdir:
293                 return devdirread(c, ubuf, n, 0, 0, vmgen);
294         case Qstat:
295                 return readnum(offset, ubuf, n, nvm, NUMSIZE32);
296         case Qctl:
297                 assert(v);
298                 return readnum(offset, ubuf, n, v->id, NUMSIZE32);
299         case Qimage:
300                 assert(v);
301                 return readmem(offset, ubuf, n,
302                                v->image, v->imagesize);
303         default:
304                 panic("Bad QID %p in devvm", c->qid.path);
305         }
306         return 0;
307 }
308
309 static long vmwrite(struct chan *c, void *ubuf, long n, int64_t unused)
310 {
311         ERRSTACK(1);
312         char buf[32];
313         struct cmdbuf *cb;
314         struct vm *vm;
315         uint64_t hexval;
316
317         switch (TYPE(c->qid)) {
318         case Qtopdir:
319         case Qvmdir:
320         case Qstat:
321                 error(Eperm);
322         case Qctl:
323                 vm = c->aux;
324                 cb = parsecmd(ubuf, n);
325                 if (waserror()) {
326                         kfree(cb);
327                         nexterror();
328                 }
329                 if (!strcmp(cb->f[0], "start")) {
330                         error("can't run a vm yet");
331                 } else if (!strcmp(cb->f[0], "stop")) {
332                         error("can't stop a vm yet");
333                 } else {
334                         error("%s: not implemented", cb->f[0]);
335                 }
336                 kfree(cb);
337                 poperror();
338                 break;
339         case Qimage:
340                 error("can't write an image yet");
341                 break;
342         default:
343                 panic("Bad QID %p in devvm", c->qid.path);
344         }
345         return n;
346 }
347
348 struct dev vmdevtab = {
349         'V',
350         "vm",
351
352         devreset,
353         vminit,
354         devshutdown,
355         vmattach,
356         vmwalk,
357         vmstat,
358         vmopen,
359         vmcreate,
360         vmclose,
361         vmread,
362         devbread,
363         vmwrite,
364         devbwrite,
365         vmremove,
366         vmwstat,
367         devpower,
368 //      devconfig,
369 //      devchaninfo,
370 };