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