Lindent pass
[akaros.git] / kern / drivers / dev / proc.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 #include <arch/types.h>
26 #include <arch/vm.h>
27 #include <arch/emulate.h>
28 #include <arch/vmdebug.h>
29
30 #define ADDR_SHIFT 32
31 #define QID2PID(q) ((struct vm*)KADDR(((q).path >> ADDR_SHIFT)))
32 #define TYPE(q) ((q).path & ((1 << ADDR_SHIFT) - 1))
33 #define QID(pid, type) ((PADDR(pid) << ADDR_SHIFT) | type)
34
35 /* the QID definition allows 2^32 procs and
36  * 2^32 types.
37  */
38 enum {
39         Qtopdir = 1,
40         Qprocdir,
41         Qctl,
42         Qns,
43 };
44
45 static int procgen(struct chan *c, char *entry_name,
46                                    struct dirtab *unused, int unused_nr_dirtab,
47                                    int s, struct dir *dp)
48 {
49         print_func_entry();
50         struct qid q;
51
52         printd("GEN s %d\n", s);
53         /* Whether we're in one dir or at the top, .. still takes us to the top. */
54         if (s == DEVDOTDOT) {
55                 mkqid(&q, Qtopdir, 0, QTDIR);
56                 devdir(c, c->qid, "#p", 0, eve, 0555, dp);
57                 print_func_exit();
58                 return 1;
59         }
60         printd("TYPE %d\n", TYPE(c->qid));
61         switch (TYPE(c->qid)) {
62                 case Qtopdir:
63                         printd("Qtopdir s %d nvm %d\n", s, nvm);
64                         return 1;
65                 case Qprocdir:
66                         /* Gen the contents of the proc dirs */
67                         s += Qctl;      /* first time through, start on Qctl */
68                         switch (s) {
69                                 case Qctl:
70                                         mkqid(&q, QID(QID2PID(c->qid), Qctl), 0, QTFILE);
71                                         devdir(c, q, "ctl", 0, eve, 0666, dp);
72                                         print_func_exit();
73                                         return 1;
74                                 case Qns:
75                                         mkqid(&q, QID(QID2PID(c->qid), Qns), 0, QTFILE);
76                                         devdir(c, q, "image", 0, eve, 0666, dp);
77                                         print_func_exit();
78                                         return 1;
79                         }
80                         print_func_exit();
81                         return -1;
82                         /* Need to also provide a direct hit for Qclone and all other files (at
83                          * all levels of the hierarchy).  Every file is both
84                          * generated (via the s increments in their respective directories) and
85                          * directly gen-able.  devstat() will call gen with a specific path in
86                          * the qid.  In these cases, we make a dir for whatever they are asking
87                          * for.  Note the qid stays the same.  I think this is what the old
88                          * plan9 comments above devgen were talking about for (ii).
89                          *
90                          * We don't need to do this for the directories - devstat will look for
91                          * the a directory by path and fail.  Then it will manually build the
92                          * stat output (check the -1 case in devstat). */
93                 case Qclone:
94                         devdir(c, c->qid, "clone", 0, eve, 0666, dp);
95                         print_func_exit();
96                         return 1;
97                 case Qstat:
98                         devdir(c, c->qid, "stat", 0, eve, 0444, dp);
99                         print_func_exit();
100                         return 1;
101                 case Qctl:
102                         devdir(c, c->qid, "ctl", 0, eve, 0666, dp);
103                         print_func_exit();
104                         return 1;
105                 case Qns:
106                         devdir(c, c->qid, "image", 0, eve, 0666, dp);
107                         print_func_exit();
108                         return 1;
109         }
110         print_func_exit();
111         return -1;
112 }
113
114 static void vminit(void)
115 {
116         return;
117         print_func_entry();
118         int i;
119         spinlock_init_irqsave(&vmlock);
120         spinlock_init_irqsave(vmidlock);
121         i = vmx_init();
122         printk("vminit: litevm_init returns %d\n", i);
123
124         print_func_exit();
125 }
126
127 static struct chan *vmattach(char *spec)
128 {
129         print_func_entry();
130         struct chan *c = devattach('V', spec);
131         mkqid(&c->qid, Qtopdir, 0, QTDIR);
132         print_func_exit();
133         return c;
134 }
135
136 static struct walkqid *vmwalk(struct chan *c, struct chan *nc, char **name,
137                                                           int nname)
138 {
139         print_func_entry();
140         print_func_exit();
141         return devwalk(c, nc, name, nname, 0, 0, vmgen);
142 }
143
144 static int vmstat(struct chan *c, uint8_t * db, int n)
145 {
146         print_func_entry();
147         print_func_exit();
148         return devstat(c, db, n, 0, 0, vmgen);
149 }
150
151 /* It shouldn't matter if p = current is DYING.  We'll eventually fail to insert
152  * the open chan into p's fd table, then decref the chan. */
153 static struct chan *vmopen(struct chan *c, int omode)
154 {
155         print_func_entry();
156         ERRSTACK(1);
157         struct vm *v = QID2PID(c->qid);
158         printk("vmopen: v is %p\n", v);
159         if (waserror()) {
160                 nexterror();
161         }
162         switch (TYPE(c->qid)) {
163                 case Qtopdir:
164                 case Qvmdir:
165                         if (omode & ORCLOSE)
166                                 error(Eperm);
167                         if (!IS_RDONLY(omode))
168                                 error(Eisdir);
169                         break;
170                 case Qclone:
171                         spin_lock_irqsave(&vmlock);
172                         vms = krealloc(vms, sizeof(vms[0]) * (nvm + 1), 0);
173                         v = &vms[nvm];
174                         nvm++;
175                         spin_unlock(&vmlock);
176                         kref_init(&v->kref, vm_release, 1);
177                         v->id = newvmid();
178                         mkqid(&c->qid, QID(v, Qctl), 0, QTFILE);
179                         c->aux = v;
180                         printd("New VM id %d\n", v->id);
181                         v->archvm = vmx_open();
182                         if (!v->archvm) {
183                                 printk("vm_open failed\n");
184                                 error("vm_open failed");
185                         }
186                         if (vmx_create_vcpu(v->archvm, v->id) < 0) {
187                                 printk("vm_create failed");
188                                 error("vm_create failed");
189                         }
190                         break;
191                 case Qstat:
192                         break;
193                 case Qctl:
194                 case Qns:
195                         c->aux = QID2PID(c->qid);
196                         printk("open qctl: aux is %p\n", c->aux);
197                         break;
198         }
199         c->mode = openmode(omode);
200         /* Assumes c is unique (can't be closed concurrently */
201         c->flag |= COPEN;
202         c->offset = 0;
203         poperror();
204         print_func_exit();
205         return c;
206 }
207
208 static void vmcreate(struct chan *c, char *name, int omode, uint32_t perm)
209 {
210         print_func_entry();
211         error(Eperm);
212         print_func_exit();
213 }
214
215 static void vmremove(struct chan *c)
216 {
217         print_func_entry();
218         error(Eperm);
219         print_func_exit();
220 }
221
222 static int vmwstat(struct chan *c, uint8_t * dp, int n)
223 {
224         print_func_entry();
225         error("No vmwstat");
226         print_func_exit();
227         return 0;
228 }
229
230 static void vmclose(struct chan *c)
231 {
232         print_func_entry();
233         struct vm *v = c->aux;
234         if (!v) {
235                 print_func_exit();
236                 return;
237         }
238         /* There are more closes than opens.  For instance, sysstat doesn't open,
239          * but it will close the chan it got from namec.  We only want to clean
240          * up/decref chans that were actually open. */
241         if (!(c->flag & COPEN)) {
242                 print_func_exit();
243                 return;
244         }
245         switch (TYPE(c->qid)) {
246                         /* for now, leave the VM active even when we close ctl */
247                 case Qctl:
248                         break;
249                 case Qns:
250                         kref_put(&v->kref);
251                         break;
252         }
253         print_func_exit();
254 }
255
256 static long vmread(struct chan *c, void *ubuf, long n, int64_t offset)
257 {
258         print_func_entry();
259         struct vm *v = c->aux;
260         printd("VMREAD\n");
261         switch (TYPE(c->qid)) {
262                 case Qtopdir:
263                 case Qvmdir:
264                         print_func_exit();
265                         return devdirread(c, ubuf, n, 0, 0, vmgen);
266                 case Qstat:
267                         print_func_exit();
268                         return readnum(offset, ubuf, n, nvm, NUMSIZE32);
269                 case Qctl:
270                         assert(v);
271                         print_func_exit();
272                         return readnum(offset, ubuf, n, v->id, NUMSIZE32);
273                 case Qns:
274                         assert(v);
275                         print_func_exit();
276                         return readmem(offset, ubuf, n, v->image, v->imagesize);
277                 default:
278                         panic("Bad QID %p in devvm", c->qid.path);
279         }
280         print_func_exit();
281         return 0;
282 }
283
284 static long vmwrite(struct chan *c, void *ubuf, long n, int64_t unused)
285 {
286         print_func_entry();
287         ERRSTACK(3);
288         char buf[32];
289         struct cmdbuf *cb;
290         struct vm *vm;
291         struct litevm *litevm;
292         uint64_t hexval;
293         printd("vmwrite(%p, %p, %d)\n", c, ubuf, n);
294         switch (TYPE(c->qid)) {
295                 case Qtopdir:
296                 case Qvmdir:
297                 case Qstat:
298                         error(Eperm);
299                 case Qctl:
300                         vm = c->aux;
301                         cb = parsecmd(ubuf, n);
302                         if (waserror()) {
303                                 kfree(cb);
304                                 nexterror();
305                         }
306                         if (!strcmp(cb->f[0], "run")) {
307                                 int ret;
308                                 if (cb->nf != 4)
309                                         error("usage: run vcpu emulated mmio_completed");
310                                 litevm = vm->archvm;
311                                 struct litevm_run vmr;
312                                 vmr.vcpu = strtoul(cb->f[1], NULL, 0);
313                                 vmr.emulated = strtoul(cb->f[2], NULL, 0);
314                                 vmr.mmio_completed = strtoul(cb->f[3], NULL, 0);
315                                 ret = vm_run(litevm, &vmr);
316                                 printk("vm_run returns %d\n", ret);
317                                 print_func_exit();
318                                 return ret;
319                         } else if (!strcmp(cb->f[0], "stop")) {
320                                 error("can't stop a vm yet");
321                         } else if (!strcmp(cb->f[0], "fillmem")) {
322                                 struct chan *file;
323                                 void *v;
324                                 vm = c->aux;
325                                 litevm = vm->archvm;
326                                 uint64_t filesize;
327                                 struct litevm_memory_region vmr;
328                                 int got;
329
330                                 if (cb->nf != 6)
331                                         error("usage: mapmem file slot flags addr size");
332                                 vmr.slot = strtoul(cb->f[2], NULL, 0);
333                                 vmr.flags = strtoul(cb->f[3], NULL, 0);
334                                 vmr.guest_phys_addr = strtoul(cb->f[4], NULL, 0);
335                                 filesize = strtoul(cb->f[5], NULL, 0);
336                                 vmr.memory_size = (filesize + 4095) & ~4095ULL;
337
338                                 file = namec(cb->f[1], Aopen, OREAD, 0);
339                                 printk("after namec file is %p\n", file);
340                                 if (waserror()) {
341                                         cclose(file);
342                                         nexterror();
343                                 }
344                                 /* at some point we want to mmap from the kernel
345                                  * but we don't have that yet. This all needs
346                                  * rethinking but the abstractions of kvm do too.
347                                  */
348                                 v = kmalloc(vmr.memory_size, KMALLOC_WAIT);
349                                 if (waserror()) {
350                                         kfree(v);
351                                         nexterror();
352                                 }
353
354                                 readn(file, v, filesize);
355                                 vmr.init_data = v;
356
357                                 if (vm_set_memory_region(litevm, &vmr))
358                                         error("vm_set_memory_region failed");
359                                 poperror();
360                                 poperror();
361                                 kfree(v);
362                                 cclose(file);
363
364                         } else if (!strcmp(cb->f[0], "region")) {
365                                 void *v;
366                                 struct litevm_memory_region vmr;
367                                 litevm = vm->archvm;
368                                 if (cb->nf != 5)
369                                         error("usage: mapmem slot flags addr size");
370                                 vmr.slot = strtoul(cb->f[2], NULL, 0);
371                                 vmr.flags = strtoul(cb->f[3], NULL, 0);
372                                 vmr.guest_phys_addr = strtoul(cb->f[4], NULL, 0);
373                                 vmr.memory_size = strtoul(cb->f[5], NULL, 0);
374                                 if (vm_set_memory_region(litevm, &vmr))
375                                         error("vm_set_memory_region failed");
376                         } else {
377                                 error("%s: not implemented", cb->f[0]);
378                         }
379                         kfree(cb);
380                         poperror();
381                         break;
382                 case Qns:
383                         error("Can't write namespace this way");
384                         break;
385                 default:
386                         panic("Bad QID %p in devvm", c->qid.path);
387         }
388         print_func_exit();
389         return n;
390 }
391
392 struct dev procdevtab __devtab = {
393         'p',
394         "proc",
395
396         devreset,
397         procinit,
398         devshutdown,
399         procattach,
400         procwalk,
401         procstat,
402         procopen,
403         proccreate,
404         procclose,
405         procread,
406         devbread,
407         procwrite,
408         devbwrite,
409         procremove,
410         procwstat,
411         devpower,
412 //  devconfig,
413         devchaninfo,
414 };