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