Adds chaninfo()
[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,
277                                v->image, v->imagesize);
278         default:
279                 panic("Bad QID %p in devvm", c->qid.path);
280         }
281         print_func_exit();
282         return 0;
283 }
284
285 static long vmwrite(struct chan *c, void *ubuf, long n, int64_t unused)
286 {
287         print_func_entry();
288         ERRSTACK(3);
289         char buf[32];
290         struct cmdbuf *cb;
291         struct vm *vm;
292         struct litevm *litevm;
293         uint64_t hexval;
294         printd("vmwrite(%p, %p, %d)\n", c, ubuf, n);
295         switch (TYPE(c->qid)) {
296         case Qtopdir:
297         case Qvmdir:
298         case Qstat:
299                 error(Eperm);
300         case Qctl:
301                 vm = c->aux;
302                 cb = parsecmd(ubuf, n);
303                 if (waserror()) {
304                         kfree(cb);
305                         nexterror();
306                 }
307                 if (!strcmp(cb->f[0], "run")) {
308                         int ret;
309                         if (cb->nf != 4)
310                                 error("usage: run vcpu emulated mmio_completed");
311                         litevm = vm->archvm;
312                         struct litevm_run vmr;
313                         vmr.vcpu = strtoul(cb->f[1], NULL, 0);
314                         vmr.emulated = strtoul(cb->f[2], NULL, 0);
315                         vmr.mmio_completed = strtoul(cb->f[3], NULL, 0);
316                         ret = vm_run(litevm, &vmr);
317                         printk("vm_run returns %d\n", ret);
318                         print_func_exit();
319                         return ret;
320                 } else if (!strcmp(cb->f[0], "stop")) {
321                         error("can't stop a vm yet");
322                 } else if (!strcmp(cb->f[0], "fillmem")) {
323                         struct chan *file;
324                         void *v;
325                         vm = c->aux;
326                         litevm = vm->archvm;
327                         uint64_t filesize;
328                         struct litevm_memory_region vmr;
329                         int got;
330
331                         if (cb->nf != 6)
332                                 error("usage: mapmem file slot flags addr size");
333                         vmr.slot = strtoul(cb->f[2], NULL, 0);
334                         vmr.flags = strtoul(cb->f[3], NULL, 0);
335                         vmr.guest_phys_addr = strtoul(cb->f[4], NULL, 0);
336                         filesize = strtoul(cb->f[5], NULL, 0);
337                         vmr.memory_size = (filesize + 4095) & ~4095ULL;
338
339                         file = namec(cb->f[1], Aopen, OREAD, 0);
340                         printk("after namec file is %p\n", file);
341                         if (waserror()){
342                                 cclose(file);
343                                 nexterror();
344                         }
345                         /* at some point we want to mmap from the kernel
346                          * but we don't have that yet. This all needs
347                          * rethinking but the abstractions of kvm do too.
348                          */
349                         v = kmalloc(vmr.memory_size, KMALLOC_WAIT);
350                         if (waserror()){
351                                 kfree(v);
352                                 nexterror();
353                         }
354
355                         readn(file, v, filesize);
356                         vmr.init_data = v;
357
358                         if (vm_set_memory_region(litevm, &vmr))
359                                 error("vm_set_memory_region failed");
360                         poperror();
361                         poperror();
362                         kfree(v);
363                         cclose(file);
364
365                 } else if (!strcmp(cb->f[0], "region")) {
366                         void *v;
367                         struct litevm_memory_region vmr;
368                         litevm = vm->archvm;
369                         if (cb->nf != 5)
370                                 error("usage: mapmem slot flags addr size");
371                         vmr.slot = strtoul(cb->f[2], NULL, 0);
372                         vmr.flags = strtoul(cb->f[3], NULL, 0);
373                         vmr.guest_phys_addr = strtoul(cb->f[4], NULL, 0);
374                         vmr.memory_size = strtoul(cb->f[5], NULL, 0);
375                         if (vm_set_memory_region(litevm, &vmr))
376                                 error("vm_set_memory_region failed");
377                 } else {
378                         error("%s: not implemented", cb->f[0]);
379                 }
380                 kfree(cb);
381                 poperror();
382                 break;
383         case Qns:
384                 error("Can't write namespace this way");
385                 break;
386         default:
387                 panic("Bad QID %p in devvm", c->qid.path);
388         }
389         print_func_exit();
390         return n;
391 }
392
393 struct dev procdevtab __devtab = {
394         'p',
395         "proc",
396
397         devreset,
398         procinit,
399         devshutdown,
400         procattach,
401         procwalk,
402         procstat,
403         procopen,
404         proccreate,
405         procclose,
406         procread,
407         devbread,
408         procwrite,
409         devbwrite,
410         procremove,
411         procwstat,
412         devpower,
413 //      devconfig,
414         devchaninfo,
415 };