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