Wire it in.
[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         DEBUG("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         DEBUG("TYPE %d\n", TYPE(c->qid));
107         switch (TYPE(c->qid)) {
108         case Qtopdir:
109                 DEBUG("Qtopdir s %d nvm %d\n", s, nvm);
110                 /* Generate elements for the top level dir.  We support a clone and
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--;    /* 1 -> 0th element, 2 -> 1st element, etc */
118                 spin_lock(&vmlock);
119                 if (s >= nvm){
120                         DEBUG("DONE qtopdir\n");
121                         spin_unlock(&vmlock);
122                         return -1;
123                 }
124                 vm_i = &vms[s];
125                 snprintf(get_cur_genbuf(), GENBUF_SZ, "vm%d", vm_i->id);
126                 spin_unlock(&vmlock);
127                 mkqid(&q, QID(vm_i, Qvmdir), 0, QTDIR);
128                 devdir(c, q, get_cur_genbuf(), 0, eve, 0555, dp);
129                 return 1;
130         case Qvmdir:
131                 /* Gen the contents of the vm dirs */
132                 s += Qctl;      /* first time through, start on Qctl */
133                 switch (s) {
134                 case Qctl:
135                         mkqid(&q, QID(QID2VM(c->qid), Qctl), 0, QTFILE);
136                         devdir(c, q, "ctl", 0, eve, 0666, dp);
137                         return 1;
138                 case Qimage:
139                         mkqid(&q, QID(QID2VM(c->qid), Qimage), 0, QTFILE);
140                         devdir(c, q, "image", 0, eve, 0666, dp);
141                         return 1;
142                 }
143                 return -1;
144                 /* Need to also provide a direct hit for Qclone and all other files (at
145                  * all levels of the hierarchy).  Every file is both
146                  * generated (via the s increments in their respective directories) and
147                  * directly gen-able.  devstat() will call gen with a specific path in
148                  * the qid.  In these cases, we make a dir for whatever they are asking
149                  * for.  Note the qid stays the same.  I think this is what the old
150                  * plan9 comments above devgen were talking about for (ii).
151                  *
152                  * We don't need to do this for the directories - devstat will look for
153                  * the a directory by path and fail.  Then it will manually build the
154                  * stat output (check the -1 case in devstat). */
155         case Qclone:
156                 devdir(c, c->qid, "clone", 0, eve, 0666, dp);
157                 return 1;
158         case Qctl:
159                 devdir(c, c->qid, "ctl", 0, eve, 0666, dp);
160                 return 1;
161         case Qimage:
162                 devdir(c, c->qid, "image", 0, eve, 0666, dp);
163                 return 1;
164         }
165         return -1;
166 }
167
168 static void vminit(void)
169 {
170         spinlock_init(&vmlock);
171         spinlock_init(vmidlock);
172 }
173
174 static struct chan *vmattach(char *spec)
175 {
176         struct chan *c = devattach('V', spec);
177         mkqid(&c->qid, Qtopdir, 0, QTDIR);
178         return c;
179 }
180
181 static struct walkqid *vmwalk(struct chan *c, struct chan *nc, char **name,
182                               int nname)
183 {
184         return devwalk(c, nc, name, nname, 0, 0, vmgen);
185 }
186
187 static int vmstat(struct chan *c, uint8_t *db, int n)
188 {
189         return devstat(c, db, n, 0, 0, vmgen);
190 }
191
192 /* It shouldn't matter if p = current is DYING.  We'll eventually fail to insert
193  * the open chan into p's fd table, then decref the chan. */
194 static struct chan *vmopen(struct chan *c, int omode)
195 {
196         struct vm *v = c->aux;
197         switch (TYPE(c->qid)) {
198         case Qtopdir:
199         case Qvmdir:
200                 if (omode & ORCLOSE)
201                         error(Eperm);
202                 if (omode != OREAD)
203                         error(Eisdir);
204                 break;
205         case Qclone:
206                 spin_lock(&vmlock);
207                 vms = krealloc(vms, sizeof(vms[0])*(nvm+1),0);
208                 v = &vms[nvm];
209                 nvm++;
210                 spin_unlock(&vmlock);
211                 kref_init(&v->kref, vm_release, 1);
212                 v->id = newvmid();
213                 mkqid(&c->qid, QID(v, Qctl), 0, QTFILE);
214                 c->aux = v;
215                 break;
216         case Qctl:
217         case Qimage:
218                 /* the purpose of opening is to hold a kref on the proc_vm */
219                 v = c->aux;
220                 /* this isn't a valid pointer yet, since our chan doesn't have a
221                  * ref.  since the time that walk gave our chan the qid, the chan
222                  * could have been closed, and the vm decref'd and freed.  the
223                  * qid is essentially an uncounted reference, and we need to go to
224                  * the source to attempt to get a real ref.  Unfortunately, this is
225                  * another scan of the list, same as devsrv.  We could speed it up
226                  * by storing an "on_list" bool in the vm_is. */
227                 //if (!vm_i)
228                 //      error("Unable to open vm, concurrent closing");
229                 break;
230         }
231         c->mode = openmode(omode);
232         /* Assumes c is unique (can't be closed concurrently */
233         c->flag |= COPEN;
234         c->offset = 0;
235         return c;
236 }
237
238 static void vmcreate(struct chan *c, char *name, int omode, uint32_t perm)
239 {
240         error(Eperm);
241 }
242
243 static void vmremove(struct chan *c)
244 {
245         error(Eperm);
246 }
247
248 static int vmwstat(struct chan *c, uint8_t *dp, int n)
249 {
250         error("No vmwstat");
251         return 0;
252 }
253
254 static void vmclose(struct chan *c)
255 {
256         struct vm *v = c->aux;
257         if (!v)
258                 return;
259         /* There are more closes than opens.  For instance, sysstat doesn't open,
260          * but it will close the chan it got from namec.  We only want to clean
261          * up/decref chans that were actually open. */
262         if (!(c->flag & COPEN))
263                 return;
264         switch (TYPE(c->qid)) {
265         case Qctl:
266         case Qimage:
267                 kref_put(&v->kref);
268                 break;
269         }
270 }
271
272 static long vmread(struct chan *c, void *ubuf, long n, int64_t offset)
273 {
274         struct vm *v = c->aux;
275         switch (TYPE(c->qid)) {
276         case Qtopdir:
277         case Qvmdir:
278                 return devdirread(c, ubuf, n, 0, 0, vmgen);
279         case Qctl:
280                 return readnum(offset, ubuf, n, v->id, NUMSIZE32);
281         case Qimage:
282                 return readmem(offset, ubuf, n,
283                                v->image, v->imagesize);
284         default:
285                 panic("Bad QID %p in devvm", c->qid.path);
286         }
287         return 0;
288 }
289
290 static long vmwrite(struct chan *c, void *ubuf, long n, int64_t unused)
291 {
292         ERRSTACK(1);
293         char buf[32];
294         struct cmdbuf *cb;
295         struct vm *vm;
296         uint64_t hexval;
297
298         switch (TYPE(c->qid)) {
299         case Qtopdir:
300         case Qvmdir:
301                 error(Eperm);
302         case Qctl:
303                 vm = c->aux;
304                 cb = parsecmd(ubuf, n);
305                 if (waserror()) {
306                         kfree(cb);
307                         nexterror();
308                 }
309                 if (!strcmp(cb->f[0], "start")) {
310                         error("can't run a vm yet");
311                 } else if (!strcmp(cb->f[0], "stop")) {
312                         error("can't stop a vm yet");
313                 } else {
314                         error("%s: not implemented", cb->f[0]);
315                 }
316                 kfree(cb);
317                 poperror();
318                 break;
319         case Qimage:
320                 error("can't write an image yet");
321                 break;
322         default:
323                 panic("Bad QID %p in devvm", c->qid.path);
324         }
325         return n;
326 }
327
328 struct dev vmdevtab = {
329         'V',
330         "vm",
331
332         devreset,
333         vminit,
334         devshutdown,
335         vmattach,
336         vmwalk,
337         vmstat,
338         vmopen,
339         vmcreate,
340         vmclose,
341         vmread,
342         devbread,
343         vmwrite,
344         devbwrite,
345         vmremove,
346         vmwstat,
347         devpower,
348 //      devconfig,
349 //      devchaninfo,
350 };