Adding vmexits to proc.
[akaros.git] / kern / drivers / dev / proc.c
1 /* 
2  * This file is part of the UCB release of Plan 9. It is subject to the license
3  * terms in the LICENSE file found in the top-level directory of this
4  * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
5  * part of the UCB release of Plan 9, including this file, may be copied,
6  * modified, propagated, or distributed except according to the terms contained
7  * in the LICENSE file.
8  */
9
10 //#define DEBUG
11 /* proc on plan 9 has lots of capabilities, some of which we might
12  * want for akaros:
13  * debug control
14  * event tracing
15  * process control (no need for signal system call, etc.)
16  * textual status
17  * rather than excise code that won't work, I'm bracketing it with
18  * #if 0 until we know we don't want it
19  */
20 #include <vfs.h>
21 #include <kfs.h>
22 #include <slab.h>
23 #include <kmalloc.h>
24 #include <kref.h>
25 #include <string.h>
26 #include <stdio.h>
27 #include <assert.h>
28 #include <error.h>
29 #include <cpio.h>
30 #include <pmap.h>
31 #include <smp.h>
32 #include <arch/vmm/vmm.h>
33 #include <ros/vmx.h>
34
35 struct dev procdevtab;
36
37 static char *devname(void)
38 {
39         return procdevtab.name;
40 }
41
42 enum {
43         Qdir,
44         Qtrace,
45         Qtracepids,
46         Qns,
47         Qargs,
48         Qctl,
49         Qfd,
50         Qfpregs,
51         Qkregs,
52         Qmem,
53         Qnote,
54         Qnoteid,
55         Qnotepg,
56         Qproc,
57         Qregs,
58         Qsegment,
59         Qstatus,
60         Qvmstatus,
61         Qtext,
62         Qwait,
63         Qprofile,
64         Qsyscall,
65         Qcore,
66 };
67
68 enum {
69         CMclose,
70         CMclosefiles,
71         CMfixedpri,
72         CMhang,
73         CMkill,
74         CMnohang,
75         CMnoswap,
76         CMpri,
77         CMprivate,
78         CMprofile,
79         CMstart,
80         CMstartstop,
81         CMstartsyscall,
82         CMstop,
83         CMwaitstop,
84         CMwired,
85         CMtrace,
86         CMcore,
87         CMvminit,
88         CMvmstart,
89         CMvmkill,
90 };
91
92 enum {
93         Nevents = 0x4000,
94         Emask = Nevents - 1,
95         Ntracedpids = 1024,
96         STATSIZE = 8 + 1 + 10 + 1 + 6 + 2,
97 };
98
99 /*
100  * Status, fd, and ns are left fully readable (0444) because of their use in debugging,
101  * particularly on shared servers.
102  * Arguably, ns and fd shouldn't be readable; if you'd prefer, change them to 0000
103  */
104 struct dirtab procdir[] = {
105         {"args", {Qargs}, 0, 0660},
106         {"ctl", {Qctl}, 0, 0660},
107         {"fd", {Qfd}, 0, 0444},
108         {"fpregs", {Qfpregs}, 0, 0000},
109         //  {"kregs",   {Qkregs},   sizeof(Ureg),       0600},
110         {"mem", {Qmem}, 0, 0000},
111         {"note", {Qnote}, 0, 0000},
112         {"noteid", {Qnoteid}, 0, 0664},
113         {"notepg", {Qnotepg}, 0, 0000},
114         {"ns", {Qns}, 0, 0444},
115         {"proc", {Qproc}, 0, 0400},
116         //  {"regs",        {Qregs},    sizeof(Ureg),       0000},
117         {"segment", {Qsegment}, 0, 0444},
118         {"status", {Qstatus}, STATSIZE, 0444},
119         {"vmstatus", {Qvmstatus}, 0, 0444},
120         {"text", {Qtext}, 0, 0000},
121         {"wait", {Qwait}, 0, 0400},
122         {"profile", {Qprofile}, 0, 0400},
123         {"syscall", {Qsyscall}, 0, 0400},
124         {"core", {Qcore}, 0, 0444},
125 };
126
127 static
128 struct cmdtab proccmd[] = {
129         {CMclose, "close", 2},
130         {CMclosefiles, "closefiles", 1},
131         {CMfixedpri, "fixedpri", 2},
132         {CMhang, "hang", 1},
133         {CMnohang, "nohang", 1},
134         {CMnoswap, "noswap", 1},
135         {CMkill, "kill", 1},
136         {CMpri, "pri", 2},
137         {CMprivate, "private", 1},
138         {CMprofile, "profile", 1},
139         {CMstart, "start", 1},
140         {CMstartstop, "startstop", 1},
141         {CMstartsyscall, "startsyscall", 1},
142         {CMstop, "stop", 1},
143         {CMwaitstop, "waitstop", 1},
144         {CMwired, "wired", 2},
145         {CMtrace, "trace", 0},
146         {CMcore, "core", 2},
147         {CMcore, "core", 2},
148         {CMcore, "core", 2},
149         {CMvminit, "vminit", 0},
150         {CMvmstart, "vmstart", 0},
151         {CMvmkill, "vmkill", 0},
152 };
153
154 /*
155  * struct qids are, in path:
156  *       5 bits of file type (qids above) (old comment said 4 here)
157  *      23 bits of process slot number + 1 (pid + 1 is stored)
158  *           in vers,
159  *      32 bits of pid, for consistency checking
160  * If notepg, c->pgrpid.path is pgrp slot, .vers is noteid.
161  */
162 #define QSHIFT  5       /* location in qid of proc slot # */
163 #define SLOTBITS 23     /* number of bits in the slot */
164 #define QIDMASK ((1<<QSHIFT)-1)
165 #define SLOTMASK        (((1<<SLOTBITS)-1) << QSHIFT)
166
167 #define QID(q)          ((((uint32_t)(q).path)&QIDMASK)>>0)
168 #define SLOT(q)         (((((uint32_t)(q).path)&SLOTMASK)>>QSHIFT)-1)
169 #define PID(q)          ((q).vers)
170 #define NOTEID(q)       ((q).vers)
171
172 static void procctlreq(struct proc *, char *, int);
173 static int procctlmemio(struct proc *, uintptr_t, int, void *, int);
174 //static struct chan*   proctext(struct chan*, struct proc*);
175 //static Segment* txt2data(struct proc*, Segment*);
176 //static int    procstopped(void*);
177 static void mntscan(struct mntwalk *, struct proc *);
178
179 //static Traceevent *tevents;
180 static char *tpids, *tpidsc, *tpidse;
181 static spinlock_t tlock;
182 static int topens;
183 static int tproduced, tconsumed;
184 //static void notrace(struct proc*, int, int64_t);
185
186 //void (*proctrace)(struct proc*, int, int64_t) = notrace;
187
188 #if 0
189 static void profclock(Ureg * ur, Timer *)
190 {
191         Tos *tos;
192
193         if (up == NULL || current->state != Running)
194                 return;
195
196         /* user profiling clock */
197         if (userureg(ur)) {
198                 tos = (Tos *) (USTKTOP - sizeof(Tos));
199                 tos->clock += TK2MS(1);
200                 segclock(userpc(ur));
201         }
202 }
203 #endif
204 static int
205 procgen(struct chan *c, char *name, struct dirtab *tab, int unused, int s,
206                 struct dir *dp)
207 {
208         struct qid qid;
209         struct proc *p;
210         char *ename;
211
212         int pid;
213         uint32_t path, perm, len;
214         if (s == DEVDOTDOT) {
215                 mkqid(&qid, Qdir, 0, QTDIR);
216                 devdir(c, qid, devname(), 0, eve, 0555, dp);
217                 return 1;
218         }
219
220         if (c->qid.path == Qdir) {
221                 if (s == 0) {
222                         strlcpy(get_cur_genbuf(), "trace", GENBUF_SZ);
223                         mkqid(&qid, Qtrace, -1, QTFILE);
224                         devdir(c, qid, get_cur_genbuf(), 0, eve, 0444, dp);
225                         return 1;
226                 }
227                 if (s == 1) {
228                         strlcpy(get_cur_genbuf(), "tracepids", GENBUF_SZ);
229                         mkqid(&qid, Qtracepids, -1, QTFILE);
230                         devdir(c, qid, get_cur_genbuf(), 0, eve, 0444, dp);
231                         return 1;
232                 }
233                 s -= 2;
234                 if (name != NULL) {
235                         /* ignore s and use name to find pid */
236                         pid = strtol(name, &ename, 10);
237                         if (pid <= 0 || ename[0] != '\0')
238                                 return -1;
239                         p = pid2proc(pid);
240                         if (!p)
241                                 return -1;
242                         /* Need to update s, so that it's the correct 'index' for our proc
243                          * (aka, the pid).  We use s later when making the qid. */
244                         s = pid;
245                 } else {
246                         /* This is a shitty iterator, and the list isn't guaranteed to give
247                          * you the same ordering twice in a row. (procs come and go). */
248                         p = pid_nth(s);
249                         if (!p)
250                                 return -1;
251                         pid = p->pid;
252                 }
253
254                 snprintf(get_cur_genbuf(), GENBUF_SZ, "%u", pid);
255                 /*
256                  * String comparison is done in devwalk so
257                  * name must match its formatted pid.
258                  */
259                 if (name != NULL && strcmp(name, get_cur_genbuf()) != 0) {
260                         printk("pid-name mismatch, name: %s, pid %d\n", name, pid);
261                         kref_put(&p->p_kref);
262                         return -1;
263                 }
264                 mkqid(&qid, (s + 1) << QSHIFT, pid, QTDIR);
265                 devdir(c, qid, get_cur_genbuf(), 0, p->user, DMDIR | 0555, dp);
266                 kref_put(&p->p_kref);
267                 return 1;
268         }
269         if (c->qid.path == Qtrace) {
270                 strlcpy(get_cur_genbuf(), "trace", GENBUF_SZ);
271                 mkqid(&qid, Qtrace, -1, QTFILE);
272                 devdir(c, qid, get_cur_genbuf(), 0, eve, 0444, dp);
273                 return 1;
274         }
275         if (c->qid.path == Qtracepids) {
276                 strlcpy(get_cur_genbuf(), "tracepids", GENBUF_SZ);
277                 mkqid(&qid, Qtracepids, -1, QTFILE);
278                 devdir(c, qid, get_cur_genbuf(), 0, eve, 0444, dp);
279                 return 1;
280         }
281         if (s >= ARRAY_SIZE(procdir))
282                 return -1;
283         if (tab)
284                 panic("procgen");
285
286         tab = &procdir[s];
287         /* path is everything other than the QID part.  Not sure from the orig code
288          * if they wanted just the pid part (SLOTMASK) or everything above QID */
289         path = c->qid.path & ~QIDMASK;  /* slot component */
290         if ((p = pid2proc(SLOT(c->qid))) == NULL)
291                 return -1;
292         perm = 0444 | tab->perm;
293 #if 0
294         if (perm == 0)
295                 perm = p->procmode;
296         else    /* just copy read bits */
297                 perm |= p->procmode & 0444;
298 #endif
299
300         len = tab->length;
301 #if 0
302         switch (QID(c->qid)) {
303                 case Qwait:
304                         len = p->nwait; /* incorrect size, but >0 means there's something to read */
305                         break;
306                 case Qprofile:
307                         q = p->seg[TSEG];
308                         if (q && q->profile) {
309                                 len = (q->top - q->base) >> LRESPROF;
310                                 len *= sizeof(*q->profile);
311                         }
312                         break;
313         }
314 #endif
315
316         mkqid(&qid, path | tab->qid.path, c->qid.vers, QTFILE);
317         devdir(c, qid, tab->name, len, p->user, perm, dp);
318         kref_put(&p->p_kref);
319         return 1;
320 }
321
322 #if 0
323 static void notrace(struct proc *, Tevent, int64_t)
324 {
325 }
326
327 static spinlock_t tlck = SPINLOCK_INITIALIZER_IRQSAVE;
328
329 static void _proctrace(struct proc *p, Tevent etype, int64_t ts)
330 {
331         Traceevent *te;
332         int tp;
333
334         ilock(&tlck);
335         if (p->trace == 0 || topens == 0 || tproduced - tconsumed >= Nevents) {
336                 iunlock(&tlck);
337                 return;
338         }
339         tp = tproduced++;
340         iunlock(&tlck);
341
342         te = &tevents[tp & Emask];
343         te->pid = p->pid;
344         te->etype = etype;
345         if (ts == 0)
346                 te->time = todget(NULL);
347         else
348                 te->time = ts;
349         te->core = m->machno;
350 }
351
352 void proctracepid(struct proc *p)
353 {
354         if (p->trace == 1 && proctrace != notrace) {
355                 p->trace = 2;
356                 ilock(&tlck);
357                 tpidsc = seprint(tpidsc, tpidse, "%d %s\n", p->pid, p->text);
358                 iunlock(&tlck);
359         }
360 }
361
362 #endif
363 static void procinit(void)
364 {
365 #if 0
366         if (conf.nproc >= (SLOTMASK >> QSHIFT) - 1)
367                 printd("warning: too many procs for devproc\n");
368         addclock0link((void (*)(void))profclock, 113);  /* Relative prime to HZ */
369 #endif
370 }
371
372 static struct chan *procattach(char *spec)
373 {
374         return devattach(devname(), spec);
375 }
376
377 static struct walkqid *procwalk(struct chan *c, struct chan *nc, char **name,
378                                                                 int nname)
379 {
380         return devwalk(c, nc, name, nname, 0, 0, procgen);
381 }
382
383 static int procstat(struct chan *c, uint8_t * db, int n)
384 {
385         return devstat(c, db, n, 0, 0, procgen);
386 }
387
388 /*
389  *  none can't read or write state on other
390  *  processes.  This is to contain access of
391  *  servers running as none should they be
392  *  subverted by, for example, a stack attack.
393  */
394 static void nonone(struct proc *p)
395 {
396         return;
397 #if 0
398         if (p == up)
399                 return;
400         if (strcmp(current->user, "none") != 0)
401                 return;
402         if (iseve())
403                 return;
404         error(EPERM, NULL);
405 #endif
406 }
407
408 static struct chan *procopen(struct chan *c, int omode)
409 {
410         ERRSTACK(2);
411         struct proc *p;
412         struct pgrp *pg;
413         struct chan *tc;
414         int pid;
415
416         if (c->qid.type & QTDIR)
417                 return devopen(c, omode, 0, 0, procgen);
418
419         if (QID(c->qid) == Qtrace) {
420                 error(ENOSYS, NULL);
421 #if 0
422                 if (omode != OREAD)
423                         error(EPERM, NULL);
424                 lock(&tlock);
425                 if (waserror()) {
426                         unlock(&tlock);
427                         nexterror();
428                 }
429                 if (topens > 0)
430                         error(EFAIL, "already open");
431                 topens++;
432                 if (tevents == NULL) {
433                         tevents = (Traceevent *) kzmalloc(sizeof(Traceevent) * Nevents,
434                                                                                           KMALLOC_WAIT);
435                         if (tevents == NULL)
436                                 error(ENOMEM, NULL);
437                         tpids = kzmalloc(Ntracedpids * 20, KMALLOC_WAIT);
438                         if (tpids == NULL) {
439                                 kfree(tpids);
440                                 tpids = NULL;
441                                 error(ENOMEM, NULL);
442                         }
443                         tpidsc = tpids;
444                         tpidse = tpids + Ntracedpids * 20;
445                         *tpidsc = 0;
446                         tproduced = tconsumed = 0;
447                 }
448                 proctrace = _proctrace;
449                 poperror();
450                 unlock(&tlock);
451
452                 c->mode = openmode(omode);
453                 c->flag |= COPEN;
454                 c->offset = 0;
455                 return c;
456 #endif
457         }
458         if (QID(c->qid) == Qtracepids) {
459                 error(ENOSYS, NULL);
460 #if 0
461                 if (omode != OREAD)
462                         error(EPERM, NULL);
463                 c->mode = openmode(omode);
464                 c->flag |= COPEN;
465                 c->offset = 0;
466                 return c;
467 #endif
468         }
469         if ((p = pid2proc(SLOT(c->qid))) == NULL)
470                 error(ESRCH, NULL);
471         //qlock(&p->debug);
472         if (waserror()) {
473                 //qunlock(&p->debug);
474                 kref_put(&p->p_kref);
475                 nexterror();
476         }
477         pid = PID(c->qid);
478         if (p->pid != pid)
479                 error(ESRCH, NULL);
480
481         omode = openmode(omode);
482
483         switch (QID(c->qid)) {
484                 case Qtext:
485                         error(ENOSYS, NULL);
486 /*
487                         if (omode != OREAD)
488                                 error(EPERM, NULL);
489                         tc = proctext(c, p);
490                         tc->offset = 0;
491                         poperror();
492                         qunlock(&p->debug);
493                         kref_put(&p->p_kref);
494                         cclose(c);
495                         return tc;
496 */
497                 case Qproc:
498                 case Qsegment:
499                 case Qprofile:
500                 case Qfd:
501                         if (omode != O_READ)
502                                 error(EPERM, NULL);
503                         break;
504
505                 case Qnote:
506 //          if (p->privatemem)
507                         error(EPERM, NULL);
508                         break;
509
510                 case Qmem:
511 //          if (p->privatemem)
512                         error(EPERM, NULL);
513                         //nonone(p);
514                         break;
515
516                 case Qargs:
517                 case Qnoteid:
518                 case Qwait:
519                 case Qregs:
520                 case Qfpregs:
521                 case Qkregs:
522                 case Qsyscall:
523                 case Qcore:
524                         nonone(p);
525                         break;
526
527                 case Qns:
528                         if (omode != O_READ)
529                                 error(EPERM, NULL);
530                         c->aux = kzmalloc(sizeof(struct mntwalk), KMALLOC_WAIT);
531                         break;
532                 case Qstatus:
533                 case Qvmstatus:
534                 case Qctl:
535                         break;
536                 case Qnotepg:
537                         error(ENOSYS, NULL);
538 #if 0
539                         nonone(p);
540                         pg = p->pgrp;
541                         if (pg == NULL)
542                                 error(ESRCH, NULL);
543                         if (omode != OWRITE || pg->pgrpid == 1)
544                                 error(EPERM, NULL);
545                         c->pgrpid.path = pg->pgrpid + 1;
546                         c->pgrpid.vers = p->noteid;
547 #endif
548                         break;
549
550                 default:
551                         poperror();
552                         //qunlock(&p->debug);
553                         kref_put(&p->p_kref);
554                         printk("procopen %#llux\n", c->qid.path);
555                         error(EINVAL, NULL);
556         }
557
558         /* Affix pid to qid */
559 //  if (p->state != Dead)
560         c->qid.vers = p->pid;
561         /* make sure the process slot didn't get reallocated while we were playing */
562         //coherence();
563         /* TODO: think about what we really want here.  In akaros, we wouldn't have
564          * our pid changed like that. */
565         if (p->pid != pid)
566                 error(ESRCH, NULL);
567
568         tc = devopen(c, omode, 0, 0, procgen);
569         poperror();
570         //qunlock(&p->debug);
571         kref_put(&p->p_kref);
572         return tc;
573 }
574
575 static int procwstat(struct chan *c, uint8_t * db, int n)
576 {
577         ERRSTACK(2);
578         error(ENOSYS, NULL);
579 #if 0
580         struct proc *p;
581         struct dir *d;
582
583         if (c->qid.type & QTDIR)
584                 error(EPERM, NULL);
585
586         if (QID(c->qid) == Qtrace)
587                 return devwstat(c, db, n);
588
589         if ((p = pid2proc(SLOT(c->qid))) == NULL)
590                 error(ESRCH, NULL);
591         nonone(p);
592         d = NULL;
593         qlock(&p->debug);
594         if (waserror()) {
595                 qunlock(&p->debug);
596                 kref_put(&p->p_kref);
597                 kfree(d);
598                 nexterror();
599         }
600
601         if (p->pid != PID(c->qid))
602                 error(ESRCH, NULL);
603
604         if (strcmp(current->user, p->user) != 0 && strcmp(current->user, eve) != 0)
605                 error(EPERM, NULL);
606
607         d = kzmalloc(sizeof(struct dir) + n, KMALLOC_WAIT);
608         n = convM2D(db, n, &d[0], (char *)&d[1]);
609         if (n == 0)
610                 error(ENOENT, NULL);
611         if (!emptystr(d->uid) && strcmp(d->uid, p->user) != 0) {
612                 if (strcmp(current->user, eve) != 0)
613                         error(EPERM, NULL);
614                 else
615                         kstrdup(&p->user, d->uid);
616         }
617         if (d->mode != ~0UL)
618                 p->procmode = d->mode & 0777;
619
620         poperror();
621         qunlock(&p->debug);
622         kref_put(&p->p_kref);
623         kfree(d);
624
625         return n;
626 #endif
627 }
628
629 #if 0
630 static long procoffset(long offset, char *va, int *np)
631 {
632         if (offset > 0) {
633                 offset -= *np;
634                 if (offset < 0) {
635                         memmove(va, va + *np + offset, -offset);
636                         *np = -offset;
637                 } else
638                         *np = 0;
639         }
640         return offset;
641 }
642
643 static int procqidwidth(struct chan *c)
644 {
645         char buf[32];
646
647         return sprint(buf, "%lu", c->qid.vers);
648 }
649
650 int procfdprint(struct chan *c, int fd, int w, char *s, int ns)
651 {
652         int n;
653
654         if (w == 0)
655                 w = procqidwidth(c);
656         n = snprint(s, ns,
657                                 "%3d %.2s %C %4ud (%.16llux %*lud %.2ux) %5ld %8lld %s\n", fd,
658                                 &"r w rw"[(c->mode & 3) << 1], c->dev->dc, c->devno,
659                                 c->qid.path, w, c->qid.vers, c->qid.type, c->iounit, c->offset,
660                                 c->name->s);
661         return n;
662 }
663
664 static int procfds(struct proc *p, char *va, int count, long offset)
665 {
666         ERRSTACK(2);
667         struct fgrp *f;
668         struct chan *c;
669         char buf[256];
670         int n, i, w, ww;
671         char *a;
672
673         /* print to buf to avoid holding fgrp lock while writing to user space */
674         if (count > sizeof buf)
675                 count = sizeof buf;
676         a = buf;
677
678         qlock(&p->debug);
679         f = p->fgrp;
680         if (f == NULL) {
681                 qunlock(&p->debug);
682                 return 0;
683         }
684         lock(f);
685         if (waserror()) {
686                 unlock(f);
687                 qunlock(&p->debug);
688                 nexterror();
689         }
690
691         n = readstr(0, a, count, p->dot->name->s);
692         n += snprint(a + n, count - n, "\n");
693         offset = procoffset(offset, a, &n);
694         /* compute width of qid.path */
695         w = 0;
696         for (i = 0; i <= f->maxfd; i++) {
697                 c = f->fd[i];
698                 if (c == NULL)
699                         continue;
700                 ww = procqidwidth(c);
701                 if (ww > w)
702                         w = ww;
703         }
704         for (i = 0; i <= f->maxfd; i++) {
705                 c = f->fd[i];
706                 if (c == NULL)
707                         continue;
708                 n += procfdprint(c, i, w, a + n, count - n);
709                 offset = procoffset(offset, a, &n);
710         }
711         poperror();
712         unlock(f);
713         qunlock(&p->debug);
714
715         /* copy result to user space, now that locks are released */
716         memmove(va, buf, n);
717
718         return n;
719 }
720 #endif
721 static void procclose(struct chan *c)
722 {
723         if (QID(c->qid) == Qtrace) {
724                 spin_lock(&tlock);
725                 if (topens > 0)
726                         topens--;
727                 /* ??
728                    if(topens == 0)
729                    proctrace = notrace;
730                  */
731                 spin_unlock(&tlock);
732         }
733         if (QID(c->qid) == Qns && c->aux != 0)
734                 kfree(c->aux);
735 }
736
737 void int2flag(int flag, char *s)
738 {
739         if (flag == 0) {
740                 *s = '\0';
741                 return;
742         }
743         *s++ = '-';
744         if (flag & MAFTER)
745                 *s++ = 'a';
746         if (flag & MBEFORE)
747                 *s++ = 'b';
748         if (flag & MCREATE)
749                 *s++ = 'c';
750         if (flag & MCACHE)
751                 *s++ = 'C';
752         *s = '\0';
753 }
754
755 #if 0
756 static char *argcpy(char *s, char *p)
757 {
758         char *t, *tp, *te;
759         int n;
760
761         n = p - s;
762         if (n > 128)
763                 n = 128;
764         if (n <= 0) {
765                 t = kzmalloc(1, KMALLOC_WAIT);
766                 *t = 0;
767                 return t;
768         }
769         t = kzmalloc(n, KMALLOC_WAIT);
770         tp = t;
771         te = t + n;
772
773         while (tp + 1 < te) {
774                 for (p--; p > s && p[-1] != 0; p--) ;
775                 tp = seprint(tp, te, "%q ", p);
776                 if (p == s)
777                         break;
778         }
779         if (*tp == ' ')
780                 *tp = 0;
781         return t;
782 }
783
784 static int procargs(struct proc *p, char *buf, int nbuf)
785 {
786         char *s;
787
788         if (p->setargs == 0) {
789                 s = argcpy(p->args, p->args + p->nargs);
790                 kfree(p->args);
791                 p->nargs = strlen(s);
792                 p->args = s;
793                 p->setargs = 1;
794         }
795         return snprint(buf, nbuf, "%s", p->args);
796 }
797
798 static int eventsavailable(void *)
799 {
800         return tproduced > tconsumed;
801 }
802 #endif
803 static long procread(struct chan *c, void *va, long n, int64_t off)
804 {
805         ERRSTACK(5);
806         struct proc *p;
807         long l, r;
808         int i, j, navail, pid, rsize;
809         char flag[10], *sps, *srv, statbuf[512];
810         uintptr_t offset, u;
811         int tesz;
812         uint8_t *rptr;
813         struct mntwalk *mw;
814
815         if (c->qid.type & QTDIR) {
816                 int nn;
817                 printd("procread: dir\n");
818                 nn = devdirread(c, va, n, 0, 0, procgen);
819                 printd("procread: %d\n", nn);
820                 return nn;
821         }
822
823         offset = off;
824 #if 0
825         if (QID(c->qid) == Qtrace) {
826                 if (!eventsavailable(NULL))
827                         return 0;
828
829                 rptr = va;
830                 tesz = BIT32SZ + BIT32SZ + BIT64SZ + BIT32SZ;
831                 navail = tproduced - tconsumed;
832                 if (navail > n / tesz)
833                         navail = n / tesz;
834                 while (navail > 0) {
835                         PBIT32(rptr, tevents[tconsumed & Emask].pid);
836                         rptr += BIT32SZ;
837                         PBIT32(rptr, tevents[tconsumed & Emask].etype);
838                         rptr += BIT32SZ;
839                         PBIT64(rptr, tevents[tconsumed & Emask].time);
840                         rptr += BIT64SZ;
841                         PBIT32(rptr, tevents[tconsumed & Emask].core);
842                         rptr += BIT32SZ;
843                         tconsumed++;
844                         navail--;
845                 }
846                 return rptr - (uint8_t *) va;
847         }
848
849         if (QID(c->qid) == Qtracepids)
850                 if (tpids == NULL)
851                         return 0;
852                 else
853                         return readstr(off, va, n, tpids);
854 #endif
855         if ((p = pid2proc(SLOT(c->qid))) == NULL)
856                 error(ESRCH, NULL);
857         if (p->pid != PID(c->qid)) {
858                 kref_put(&p->p_kref);
859                 error(ESRCH, NULL);
860         }
861         switch (QID(c->qid)) {
862                 default:
863                         kref_put(&p->p_kref);
864                         break;
865 #if 0
866 #warning check refcnting in here
867                 case Qargs:
868                         qlock(&p->debug);
869                         j = procargs(p, current->genbuf, sizeof current->genbuf);
870                         qunlock(&p->debug);
871                         kref_put(&p->p_kref);
872                         if (offset >= j)
873                                 return 0;
874                         if (offset + n > j)
875                                 n = j - offset;
876                         memmove(va, &current->genbuf[offset], n);
877                         return n;
878
879                 case Qsyscall:
880                         if (p->syscalltrace == NULL)
881                                 return 0;
882                         return readstr(offset, va, n, p->syscalltrace);
883
884                 case Qcore:
885                         i = 0;
886                         ac = p->ac;
887                         wired = p->wired;
888                         if (ac != NULL)
889                                 i = ac->machno;
890                         else if (wired != NULL)
891                                 i = wired->machno;
892                         snprint(statbuf, sizeof statbuf, "%d\n", i);
893                         return readstr(offset, va, n, statbuf);
894
895                 case Qmem:
896                         if (offset < KZERO
897                                 || (offset >= USTKTOP - USTKSIZE && offset < USTKTOP)) {
898                                 r = procctlmemio(p, offset, n, va, 1);
899                                 kref_put(&p->p_kref);
900                                 return r;
901                         }
902
903                         if (!iseve()) {
904                                 kref_put(&p->p_kref);
905                                 error(EPERM, NULL);
906                         }
907
908                         /* validate kernel addresses */
909                         if (offset < PTR2UINT(end)) {
910                                 if (offset + n > PTR2UINT(end))
911                                         n = PTR2UINT(end) - offset;
912                                 memmove(va, UINT2PTR(offset), n);
913                                 kref_put(&p->p_kref);
914                                 return n;
915                         }
916                         for (i = 0; i < nelem(conf.mem); i++) {
917                                 cm = &conf.mem[i];
918                                 /* klimit-1 because klimit might be zero! */
919                                 if (cm->kbase <= offset && offset <= cm->klimit - 1) {
920                                         if (offset + n >= cm->klimit - 1)
921                                                 n = cm->klimit - offset;
922                                         memmove(va, UINT2PTR(offset), n);
923                                         kref_put(&p->p_kref);
924                                         return n;
925                                 }
926                         }
927                         kref_put(&p->p_kref);
928                         error(EINVAL, NULL);
929
930                 case Qprofile:
931                         s = p->seg[TSEG];
932                         if (s == 0 || s->profile == 0)
933                                 error(EFAIL, "profile is off");
934                         i = (s->top - s->base) >> LRESPROF;
935                         i *= sizeof(*s->profile);
936                         if (offset >= i) {
937                                 kref_put(&p->p_kref);
938                                 return 0;
939                         }
940                         if (offset + n > i)
941                                 n = i - offset;
942                         memmove(va, ((char *)s->profile) + offset, n);
943                         kref_put(&p->p_kref);
944                         return n;
945
946                 case Qnote:
947                         qlock(&p->debug);
948                         if (waserror()) {
949                                 qunlock(&p->debug);
950                                 kref_put(&p->p_kref);
951                                 nexterror();
952                         }
953                         if (p->pid != PID(c->qid))
954                                 error(ESRCH, NULL);
955                         if (n < 1)      /* must accept at least the '\0' */
956                                 error(ENAMETOOLONG, NULL);
957                         if (p->nnote == 0)
958                                 n = 0;
959                         else {
960                                 i = strlen(p->note[0].msg) + 1;
961                                 if (i > n)
962                                         i = n;
963                                 rptr = va;
964                                 memmove(rptr, p->note[0].msg, i);
965                                 rptr[i - 1] = '\0';
966                                 p->nnote--;
967                                 memmove(p->note, p->note + 1, p->nnote * sizeof(Note));
968                                 n = i;
969                         }
970                         if (p->nnote == 0)
971                                 p->notepending = 0;
972                         poperror();
973                         qunlock(&p->debug);
974                         kref_put(&p->p_kref);
975                         return n;
976
977                 case Qproc:
978                         if (offset >= sizeof(struct proc)) {
979                                 kref_put(&p->p_kref);
980                                 return 0;
981                         }
982                         if (offset + n > sizeof(struct proc))
983                                 n = sizeof(struct proc) - offset;
984                         memmove(va, ((char *)p) + offset, n);
985                         kref_put(&p->p_kref);
986                         return n;
987
988                 case Qregs:
989                         rptr = (uint8_t *) p->dbgreg;
990                         rsize = sizeof(Ureg);
991 regread:
992                         if (rptr == 0) {
993                                 kref_put(&p->p_kref);
994                                 error(ENODATA, NULL);
995                         }
996                         if (offset >= rsize) {
997                                 kref_put(&p->p_kref);
998                                 return 0;
999                         }
1000                         if (offset + n > rsize)
1001                                 n = rsize - offset;
1002                         memmove(va, rptr + offset, n);
1003                         kref_put(&p->p_kref);
1004                         return n;
1005
1006                 case Qkregs:
1007                         memset(&kur, 0, sizeof(Ureg));
1008                         setkernur(&kur, p);
1009                         rptr = (uint8_t *) & kur;
1010                         rsize = sizeof(Ureg);
1011                         goto regread;
1012
1013                 case Qfpregs:
1014                         r = fpudevprocio(p, va, n, offset, 0);
1015                         kref_put(&p->p_kref);
1016                         return r;
1017
1018                 case Qstatus:
1019                         if (offset >= STATSIZE) {
1020                                 kref_put(&p->p_kref);
1021                                 return 0;
1022                         }
1023                         if (offset + n > STATSIZE)
1024                                 n = STATSIZE - offset;
1025
1026                         sps = p->psstate;
1027                         if (sps == 0)
1028                                 sps = statename[p->state];
1029                         memset(statbuf, ' ', sizeof statbuf);
1030                         j = 2 * KNAMELEN + 12;
1031                         snprint(statbuf, j + 1, "%-*.*s%-*.*s%-12.11s",
1032                                         KNAMELEN, KNAMELEN - 1, p->text,
1033                                         KNAMELEN, KNAMELEN - 1, p->user, sps);
1034
1035                         for (i = 0; i < 6; i++) {
1036                                 l = p->time[i];
1037                                 if (i == TReal)
1038                                         l = sys->ticks - l;
1039                                 l = TK2MS(l);
1040                                 readnum(0, statbuf + j + NUMSIZE * i, NUMSIZE, l, NUMSIZE);
1041                         }
1042                         /* ignore stack, which is mostly non-existent */
1043                         u = 0;
1044                         for (i = 1; i < NSEG; i++) {
1045                                 s = p->seg[i];
1046                                 if (s)
1047                                         u += s->top - s->base;
1048                         }
1049                         readnum(0, statbuf + j + NUMSIZE * 6, NUMSIZE, u >> 10u, NUMSIZE);      /* wrong size */
1050                         readnum(0, statbuf + j + NUMSIZE * 7, NUMSIZE, p->basepri, NUMSIZE);
1051                         readnum(0, statbuf + j + NUMSIZE * 8, NUMSIZE, p->priority,
1052                                         NUMSIZE);
1053
1054                         /*
1055                          * NIX: added # of traps, syscalls, and iccs
1056                          */
1057                         readnum(0, statbuf + j + NUMSIZE * 9, NUMSIZE, p->ntrap, NUMSIZE);
1058                         readnum(0, statbuf + j + NUMSIZE * 10, NUMSIZE, p->nintr, NUMSIZE);
1059                         readnum(0, statbuf + j + NUMSIZE * 11, NUMSIZE, p->nsyscall,
1060                                         NUMSIZE);
1061                         readnum(0, statbuf + j + NUMSIZE * 12, NUMSIZE, p->nicc, NUMSIZE);
1062                         readnum(0, statbuf + j + NUMSIZE * 13, NUMSIZE, p->nactrap,
1063                                         NUMSIZE);
1064                         readnum(0, statbuf + j + NUMSIZE * 14, NUMSIZE, p->nacsyscall,
1065                                         NUMSIZE);
1066                         memmove(va, statbuf + offset, n);
1067                         kref_put(&p->p_kref);
1068                         return n;
1069
1070                 case Qsegment:
1071                         j = 0;
1072                         for (i = 0; i < NSEG; i++) {
1073                                 sg = p->seg[i];
1074                                 if (sg == 0)
1075                                         continue;
1076                                 j += sprint(statbuf + j, "%-6s %c%c %p %p %4d\n",
1077                                                         sname[sg->type & SG_TYPE],
1078                                                         sg->type & SG_RONLY ? 'R' : ' ',
1079                                                         sg->profile ? 'P' : ' ',
1080                                                         sg->base, sg->top, sg->ref);
1081                         }
1082                         kref_put(&p->p_kref);
1083                         if (offset >= j)
1084                                 return 0;
1085                         if (offset + n > j)
1086                                 n = j - offset;
1087                         if (n == 0 && offset == 0)
1088                                 exhausted("segments");
1089                         memmove(va, &statbuf[offset], n);
1090                         return n;
1091
1092                 case Qwait:
1093                         if (!canqlock(&p->qwaitr)) {
1094                                 kref_put(&p->p_kref);
1095                                 error(EBUSY, NULL);
1096                         }
1097
1098                         if (waserror()) {
1099                                 qunlock(&p->qwaitr);
1100                                 kref_put(&p->p_kref);
1101                                 nexterror();
1102                         }
1103
1104                         lock(&p->exl);
1105                         if (up == p && p->nchild == 0 && p->waitq == 0) {
1106                                 unlock(&p->exl);
1107                                 error(ECHILD, NULL);
1108                         }
1109                         pid = p->pid;
1110                         while (p->waitq == 0) {
1111                                 unlock(&p->exl);
1112                                 rendez_sleep(&p->waitr, haswaitq, p);
1113                                 if (p->pid != pid)
1114                                         error(ESRCH, NULL);
1115                                 lock(&p->exl);
1116                         }
1117                         wq = p->waitq;
1118                         p->waitq = wq->next;
1119                         p->nwait--;
1120                         unlock(&p->exl);
1121
1122                         poperror();
1123                         qunlock(&p->qwaitr);
1124                         kref_put(&p->p_kref);
1125                         n = snprint(va, n, "%d %lu %lud %lud %q",
1126                                                 wq->w.pid,
1127                                                 wq->w.time[TUser], wq->w.time[TSys], wq->w.time[TReal],
1128                                                 wq->w.msg);
1129                         kfree(wq);
1130                         return n;
1131 #endif
1132                 case Qstatus:{
1133                                 /* the extra 2 is paranoia */
1134                                 char buf[8 + 1 + PROC_PROGNAME_SZ + 1 + 10 + 1 + 6 + 2];
1135                                 snprintf(buf, sizeof(buf),
1136                                          "%8d %-*s %-10s %6d", p->pid, PROC_PROGNAME_SZ,
1137                                          p->progname, procstate2str(p->state),
1138                                          p->ppid);
1139                                 kref_put(&p->p_kref);
1140                                 return readstr(off, va, n, buf);
1141                         }
1142
1143                 case Qvmstatus:
1144                         {
1145                                 char buf[50*65 + 2];
1146                                 int i, offset;
1147                                 offset=0;
1148                                 offset += snprintf(buf+offset, sizeof(buf)-offset, "{\n");
1149                                 for (i = 0; i < 65; i++) {
1150                                         if (p->vmm.vmexits[i] != 0) {
1151                                                 offset += snprintf(buf+offset, sizeof(buf)-offset,
1152                                                                    "\"%s\":\"%lld\",\n",
1153                                                                    VMX_EXIT_REASON_NAMES[i],
1154                                                                    p->vmm.vmexits[i]);
1155                                         }
1156                                 }
1157                                 offset += snprintf(buf+offset, sizeof(buf)-offset, "}\n");
1158                                 kref_put(&p->p_kref);
1159                                 return readstr(off, va, n, buf);
1160                         }
1161                 case Qns:
1162                         //qlock(&p->debug);
1163                         if (waserror()) {
1164                                 //qunlock(&p->debug);
1165                                 kref_put(&p->p_kref);
1166                                 nexterror();
1167                         }
1168                         if (p->pgrp == NULL || p->pid != PID(c->qid))
1169                                 error(ESRCH, NULL);
1170                         mw = c->aux;
1171                         if (mw->cddone) {
1172                                 poperror();
1173                                 //qunlock(&p->debug);
1174                                 kref_put(&p->p_kref);
1175                                 return 0;
1176                         }
1177                         mntscan(mw, p);
1178                         if (mw->mh == 0) {
1179                                 mw->cddone = 1;
1180                                 i = snprintf(va, n, "cd %s\n", p->dot->name->s);
1181                                 poperror();
1182                                 //qunlock(&p->debug);
1183                                 kref_put(&p->p_kref);
1184                                 return i;
1185                         }
1186                         int2flag(mw->cm->mflag, flag);
1187                         if (strcmp(mw->cm->to->name->s, "#M") == 0) {
1188                                 srv = srvname(mw->cm->to->mchan);
1189                                 i = snprintf(va, n, "mount %s %s %s %s\n", flag,
1190                                                          srv == NULL ? mw->cm->to->mchan->name->s : srv,
1191                                                          mw->mh->from->name->s,
1192                                                          mw->cm->spec ? mw->cm->spec : "");
1193                                 kfree(srv);
1194                         } else
1195                                 i = snprintf(va, n, "bind %s %s %s\n", flag,
1196                                                          mw->cm->to->name->s, mw->mh->from->name->s);
1197                         poperror();
1198                         //qunlock(&p->debug);
1199                         kref_put(&p->p_kref);
1200                         return i;
1201 #if 0
1202                 case Qnoteid:
1203                         r = readnum(offset, va, n, p->noteid, NUMSIZE);
1204                         kref_put(&p->p_kref);
1205                         return r;
1206                 case Qfd:
1207                         r = procfds(p, va, n, offset);
1208                         kref_put(&p->p_kref);
1209                         return r;
1210 #endif
1211         }
1212
1213         error(EINVAL, NULL);
1214         return 0;       /* not reached */
1215 }
1216
1217 static void mntscan(struct mntwalk *mw, struct proc *p)
1218 {
1219         struct pgrp *pg;
1220         struct mount *t;
1221         struct mhead *f;
1222         int best, i, last, nxt;
1223
1224         pg = p->pgrp;
1225         rlock(&pg->ns);
1226
1227         nxt = 0;
1228         best = (int)(~0U >> 1); /* largest 2's complement int */
1229
1230         last = 0;
1231         if (mw->mh)
1232                 last = mw->cm->mountid;
1233
1234         for (i = 0; i < MNTHASH; i++) {
1235                 for (f = pg->mnthash[i]; f; f = f->hash) {
1236                         for (t = f->mount; t; t = t->next) {
1237                                 if (mw->mh == 0 || (t->mountid > last && t->mountid < best)) {
1238                                         mw->cm = t;
1239                                         mw->mh = f;
1240                                         best = mw->cm->mountid;
1241                                         nxt = 1;
1242                                 }
1243                         }
1244                 }
1245         }
1246         if (nxt == 0)
1247                 mw->mh = 0;
1248
1249         runlock(&pg->ns);
1250 }
1251
1252 static long procwrite(struct chan *c, void *va, long n, int64_t off)
1253 {
1254         ERRSTACK(2);
1255
1256         struct proc *p, *t;
1257         int i, id, l;
1258         char *args;
1259         uintptr_t offset;
1260
1261         if (c->qid.type & QTDIR)
1262                 error(EISDIR, NULL);
1263
1264         if ((p = pid2proc(SLOT(c->qid))) == NULL)
1265                 error(ESRCH, NULL);
1266
1267         if (waserror()) {
1268                 kref_put(&p->p_kref);
1269                 nexterror();
1270         }
1271         if (p->pid != PID(c->qid))
1272                 error(ESRCH, NULL);
1273
1274         offset = off;
1275
1276         switch (QID(c->qid)) {
1277 #if 0
1278                 case Qargs:
1279                         if (n == 0)
1280                                 error(EINVAL, NULL);
1281                         if (n >= sizeof buf - strlen(p->text) - 1)
1282                                 error(E2BIG, NULL);
1283                         l = snprintf(buf, sizeof buf, "%s [%s]", p->text, (char *)va);
1284                         args = kzmalloc(l + 1, KMALLOC_WAIT);
1285                         if (args == NULL)
1286                                 error(ENOMEM, NULL);
1287                         memmove(args, buf, l);
1288                         args[l] = 0;
1289                         kfree(p->args);
1290                         p->nargs = l;
1291                         p->args = args;
1292                         p->setargs = 1;
1293                         break;
1294
1295                 case Qmem:
1296                         if (p->state != Stopped)
1297                                 error(EINVAL, NULL);
1298
1299                         n = procctlmemio(p, offset, n, va, 0);
1300                         break;
1301
1302                 case Qregs:
1303                         if (offset >= sizeof(Ureg))
1304                                 n = 0;
1305                         else if (offset + n > sizeof(Ureg))
1306                                 n = sizeof(Ureg) - offset;
1307                         if (p->dbgreg == 0)
1308                                 error(ENODATA, NULL);
1309                         setregisters(p->dbgreg, (char *)(p->dbgreg) + offset, va, n);
1310                         break;
1311
1312                 case Qfpregs:
1313                         n = fpudevprocio(p, va, n, offset, 1);
1314                         break;
1315 #endif
1316                 case Qctl:
1317                         procctlreq(p, va, n);
1318                         break;
1319
1320                 default:
1321                         poperror();
1322                         kref_put(&p->p_kref);
1323                         error(EFAIL, "unknown qid %#llux in procwrite\n", c->qid.path);
1324         }
1325         poperror();
1326         kref_put(&p->p_kref);
1327         return n;
1328
1329 }
1330
1331 struct dev procdevtab __devtab = {
1332         "proc",
1333
1334         devreset,
1335         procinit,
1336         devshutdown,
1337         procattach,
1338         procwalk,
1339         procstat,
1340         procopen,
1341         devcreate,
1342         procclose,
1343         procread,
1344         devbread,
1345         procwrite,
1346         devbwrite,
1347         devremove,
1348         procwstat,
1349         devpower,
1350         devchaninfo,
1351 };
1352
1353 #if 0
1354 static struct chan *proctext(struct chan *c, struct proc *p)
1355 {
1356         ERRSTACK(2);
1357         struct chan *tc;
1358         Image *i;
1359         Segment *s;
1360
1361         s = p->seg[TSEG];
1362         if (s == 0)
1363                 error(ENOENT, NULL);
1364         if (p->state == Dead)
1365                 error(ESRCH, NULL);
1366
1367         lock(s);
1368         i = s->image;
1369         if (i == 0) {
1370                 unlock(s);
1371                 error(ESRCH, NULL);
1372         }
1373         unlock(s);
1374
1375         lock(i);
1376         if (waserror()) {
1377                 unlock(i);
1378                 nexterror();
1379         }
1380
1381         tc = i->c;
1382         if (tc == 0)
1383                 error(ESRCH, NULL);
1384
1385         /* TODO: what do you want here?  you can't get a kref and have the new val
1386          * be 1.  Here is the old code: if (kref_get(&tc->ref, 1) == 1 || ... ) */
1387         if (kref_refcnt(&tc->ref, 1) == 1 || (tc->flag & COPEN) == 0
1388                 || tc->mode != OREAD) {
1389                 cclose(tc);
1390                 error(ESRCH, NULL);
1391         }
1392
1393         if (p->pid != PID(c->qid)) {
1394                 cclose(tc);
1395                 error(ESRCH, NULL);
1396         }
1397
1398         poperror();
1399         unlock(i);
1400
1401         return tc;
1402 }
1403
1404 /* TODO: this will fail at compile time, since we don't have a proc-wide rendez,
1405  * among other things, and we'll need to rewrite this for akaros */
1406 void procstopwait(struct proc *p, int ctl)
1407 {
1408         ERRSTACK(2);
1409         int pid;
1410
1411         if (p->pdbg)
1412                 error(EBUSY, NULL);
1413         if (procstopped(p) || p->state == Broken)
1414                 return;
1415
1416         if (ctl != 0)
1417                 p->procctl = ctl;
1418         p->pdbg = up;
1419         pid = p->pid;
1420         qunlock(&p->debug);
1421         current->psstate = "Stopwait";
1422         if (waserror()) {
1423                 p->pdbg = 0;
1424                 qlock(&p->debug);
1425                 nexterror();
1426         }
1427         rendez_sleep(&current->sleep, procstopped, p);
1428         poperror();
1429         qlock(&p->debug);
1430         if (p->pid != pid)
1431                 error(ESRCH, NULL);
1432 }
1433
1434 #endif
1435 static void procctlcloseone(struct proc *p, int fd)
1436 {
1437 // TODO: resolve this and sys_close
1438         struct file *file = get_file_from_fd(&p->open_files, fd);
1439         int retval = 0;
1440         printd("%s %d\n", __func__, fd);
1441         /* VFS */
1442         if (file) {
1443                 put_file_from_fd(&p->open_files, fd);
1444                 kref_put(&file->f_kref);        /* Drop the ref from get_file */
1445                 return;
1446         }
1447         /* 9ns, should also handle errors (bad FD, etc) */
1448         retval = sysclose(fd);
1449         return;
1450
1451         //sys_close(p, fd);
1452 }
1453
1454 void procctlclosefiles(struct proc *p, int all, int fd)
1455 {
1456         int i;
1457
1458         if (all)
1459                 for (i = 0; i < NR_FILE_DESC_MAX; i++)
1460                         procctlcloseone(p, i);
1461         else
1462                 procctlcloseone(p, fd);
1463 }
1464
1465 static void procctlreq(struct proc *p, char *va, int n)
1466 {
1467         ERRSTACK(1);
1468         int8_t irq_state = 0;
1469         int npc, pri, core;
1470         struct cmdbuf *cb;
1471         struct cmdtab *ct;
1472         int64_t time;
1473         char *e;
1474
1475         cb = parsecmd(va, n);
1476         if (waserror()) {
1477                 kfree(cb);
1478                 nexterror();
1479         }
1480
1481         ct = lookupcmd(cb, proccmd, ARRAY_SIZE(proccmd));
1482
1483         switch (ct->index) {
1484                 case CMvmstart:
1485                 case CMvmkill:
1486                 default:
1487                         error(EFAIL, "nope\n");
1488                         break;
1489                 case CMtrace:
1490                         systrace_trace_pid(p);
1491                         break;
1492                 case CMclose:
1493                         procctlclosefiles(p, 0, atoi(cb->f[1]));
1494                         break;
1495                 case CMclosefiles:
1496                         procctlclosefiles(p, 1, 0);
1497                         break;
1498 #if 0
1499                         we may want this.Let us pause a proc.case CMhang:p->hang = 1;
1500                         break;
1501 #endif
1502                 case CMkill:
1503                         p = pid2proc(strtol(cb->f[1], 0, 0));
1504                         if (!p)
1505                                 error(EFAIL, "No such proc\n");
1506
1507                         enable_irqsave(&irq_state);
1508                         proc_destroy(p);
1509                         disable_irqsave(&irq_state);
1510                         proc_decref(p);
1511                         /* this is a little ghetto. it's not fully free yet, but we are also
1512                          * slowing it down by messing with it, esp with the busy waiting on a
1513                          * hyperthreaded core. */
1514                         spin_on(p->env_cr3);
1515                         break;
1516                 case CMvminit:
1517                         break;
1518         }
1519         poperror();
1520         kfree(cb);
1521 }
1522
1523 #if 0
1524 static int procstopped(void *a)
1525 {
1526         struct proc *p = a;
1527         return p->state == Stopped;
1528 }
1529
1530 static int
1531 procctlmemio(struct proc *p, uintptr_t offset, int n, void *va, int read)
1532 {
1533         KMap *k;
1534         Pte *pte;
1535         Page *pg;
1536         Segment *s;
1537         uintptr_t soff, l;                      /* hmmmm */
1538         uint8_t *b;
1539         uintmem pgsz;
1540
1541         for (;;) {
1542                 s = seg(p, offset, 1);
1543                 if (s == 0)
1544                         error(EINVAL, NULL);
1545
1546                 if (offset + n >= s->top)
1547                         n = s->top - offset;
1548
1549                 if (!read && (s->type & SG_TYPE) == SG_TEXT)
1550                         s = txt2data(p, s);
1551
1552                 s->steal++;
1553                 soff = offset - s->base;
1554                 if (waserror()) {
1555                         s->steal--;
1556                         nexterror();
1557                 }
1558                 if (fixfault(s, offset, read, 0, s->color) == 0)
1559                         break;
1560                 poperror();
1561                 s->steal--;
1562         }
1563         poperror();
1564         pte = s->map[soff / PTEMAPMEM];
1565         if (pte == 0)
1566                 panic("procctlmemio");
1567         pgsz = m->pgsz[s->pgszi];
1568         pg = pte->pages[(soff & (PTEMAPMEM - 1)) / pgsz];
1569         if (pagedout(pg))
1570                 panic("procctlmemio1");
1571
1572         l = pgsz - (offset & (pgsz - 1));
1573         if (n > l)
1574                 n = l;
1575
1576         k = kmap(pg);
1577         if (waserror()) {
1578                 s->steal--;
1579                 kunmap(k);
1580                 nexterror();
1581         }
1582         b = (uint8_t *) VA(k);
1583         b += offset & (pgsz - 1);
1584         if (read == 1)
1585                 memmove(va, b, n);      /* This can fault */
1586         else
1587                 memmove(b, va, n);
1588         poperror();
1589         kunmap(k);
1590
1591         /* Ensure the process sees text page changes */
1592         if (s->flushme)
1593                 memset(pg->cachectl, PG_TXTFLUSH, sizeof(pg->cachectl));
1594
1595         s->steal--;
1596
1597         if (read == 0)
1598                 p->newtlb = 1;
1599
1600         return n;
1601 }
1602
1603 static Segment *txt2data(struct proc *p, Segment * s)
1604 {
1605         int i;
1606         Segment *ps;
1607
1608         ps = newseg(SG_DATA, s->base, s->size);
1609         ps->image = s->image;
1610         kref_get(&ps->image->ref, 1);
1611         ps->fstart = s->fstart;
1612         ps->flen = s->flen;
1613         ps->flushme = 1;
1614
1615         qlock(&p->seglock);
1616         for (i = 0; i < NSEG; i++)
1617                 if (p->seg[i] == s)
1618                         break;
1619         if (i == NSEG)
1620                 panic("segment gone");
1621
1622         qunlock(&s->lk);
1623         putseg(s);
1624         qlock(&ps->lk);
1625         p->seg[i] = ps;
1626         qunlock(&p->seglock);
1627
1628         return ps;
1629 }
1630
1631 Segment *data2txt(Segment * s)
1632 {
1633         Segment *ps;
1634
1635         ps = newseg(SG_TEXT, s->base, s->size);
1636         ps->image = s->image;
1637         kref_get(&ps->image->ref, 1);
1638         ps->fstart = s->fstart;
1639         ps->flen = s->flen;
1640         ps->flushme = 1;
1641
1642         return ps;
1643 }
1644 #endif