Migrated position dependent initialization, to label based
[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/vmm.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         .name = "proc",
1333
1334         .reset = devreset,
1335         .init = procinit,
1336         .shutdown = devshutdown,
1337         .attach = procattach,
1338         .walk = procwalk,
1339         .stat = procstat,
1340         .open = procopen,
1341         .create = devcreate,
1342         .close = procclose,
1343         .read = procread,
1344         .bread = devbread,
1345         .write = procwrite,
1346         .bwrite = devbwrite,
1347         .remove = devremove,
1348         .wstat = procwstat,
1349         .power = devpower,
1350         .chaninfo = 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