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