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