vmm: refactor userspace's emsr_fakewrite()
[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 <assert.h>
21 #include <cpio.h>
22 #include <error.h>
23 #include <kmalloc.h>
24 #include <kref.h>
25 #include <pmap.h>
26 #include <ros/vmm.h>
27 #include <slab.h>
28 #include <smp.h>
29 #include <stdio.h>
30 #include <string.h>
31 #include <umem.h>
32
33 #include <arch/vmm/vmm.h>
34
35 struct dev procdevtab;
36
37 static char *devname(void)
38 {
39         return procdevtab.name;
40 }
41
42 enum { Qdir,
43        Qtrace,
44        Qtracepids,
45        Qself,
46        Qns,
47        Qargs,
48        Qctl,
49        Qfd,
50        Qfpregs,
51        Qkregs,
52        Qmaps,
53        Qmem,
54        Qnote,
55        Qnoteid,
56        Qnotepg,
57        Qproc,
58        Qregs,
59        Quser,
60        Qsegment,
61        Qstatus,
62        Qstrace,
63        Qstrace_traceset,
64        Qvmstatus,
65        Qtext,
66        Qwait,
67        Qprofile,
68        Qsyscall,
69        Qcore,
70 };
71
72 enum { CMclose,
73        CMclosefiles,
74        CMhang,
75        CMstraceme,
76        CMstraceall,
77        CMstrace_drop,
78 };
79
80 enum { 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
88  * debugging, particularly on shared servers. Arguably, ns and fd shouldn't be
89  * 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     {"maps", {Qmaps}, 0, 0000},
98     {"mem", {Qmem}, 0, 0000},
99     {"note", {Qnote}, 0, 0000},
100     {"noteid", {Qnoteid}, 0, 0664},
101     {"notepg", {Qnotepg}, 0, 0000},
102     {"ns", {Qns}, 0, 0444},
103     {"proc", {Qproc}, 0, 0400},
104     //  {"regs",        {Qregs},    sizeof(Ureg),       0000},
105     {"user", {Quser}, 0, 0444},
106     {"segment", {Qsegment}, 0, 0444},
107     {"status", {Qstatus}, STATSIZE, 0444},
108     {"strace", {Qstrace}, 0, 0444},
109     {"strace_traceset", {Qstrace_traceset}, 0, 0666},
110     {"vmstatus", {Qvmstatus}, 0, 0444},
111     {"text", {Qtext}, 0, 0000},
112     {"wait", {Qwait}, 0, 0400},
113     {"profile", {Qprofile}, 0, 0400},
114     {"syscall", {Qsyscall}, 0, 0400},
115     {"core", {Qcore}, 0, 0444},
116 };
117
118 static struct cmdtab proccmd[] = {
119     {CMclose, "close", 2},         {CMclosefiles, "closefiles", 0},
120     {CMhang, "hang", 0},           {CMstraceme, "straceme", 0},
121     {CMstraceall, "straceall", 0}, {CMstrace_drop, "strace_drop", 2},
122 };
123
124 /*
125  * struct qids are, in path:
126  *       5 bits of file type (qids above) (old comment said 4 here)
127  *      23 bits of process slot number + 1 (pid + 1 is stored)
128  *           in vers,
129  *      32 bits of pid, for consistency checking
130  * If notepg, c->pgrpid.path is pgrp slot, .vers is noteid.
131  */
132 #define QSHIFT 5    /* location in qid of proc slot # */
133 #define SLOTBITS 23 /* number of bits in the slot */
134 #define QIDMASK ((1 << QSHIFT) - 1)
135 #define SLOTMASK (((1 << SLOTBITS) - 1) << QSHIFT)
136
137 #define QID(q) ((((uint32_t)(q).path) & QIDMASK) >> 0)
138 #define SLOT(q) (((((uint32_t)(q).path) & SLOTMASK) >> QSHIFT) - 1)
139 #define PID(q) ((q).vers)
140 #define NOTEID(q) ((q).vers)
141
142 static void procctlreq(struct proc *, char *, size_t);
143 static int procctlmemio(struct proc *, uintptr_t, int, void *, int);
144 // static struct chan*   proctext(struct chan*, struct proc*);
145 // static Segment* txt2data(struct proc*, Segment*);
146 // static int    procstopped(void*);
147 static void mntscan(struct mntwalk *, struct proc *);
148
149 // static Traceevent *tevents;
150 static char *tpids, *tpidsc, *tpidse;
151 static spinlock_t tlock;
152 static int topens;
153 static int tproduced, tconsumed;
154 // static void notrace(struct proc*, int, int64_t);
155
156 // void (*proctrace)(struct proc*, int, int64_t) = notrace;
157
158 #if 0
159 static void profclock(Ureg * ur, Timer *)
160 {
161         Tos *tos;
162
163         if (up == NULL || current->state != Running)
164                 return;
165
166         /* user profiling clock */
167         if (userureg(ur)) {
168                 tos = (Tos *) (USTKTOP - sizeof(Tos));
169                 tos->clock += TK2MS(1);
170                 segclock(userpc(ur));
171         }
172 }
173 #endif
174 static int procgen(struct chan *c, char *name, struct dirtab *tab, int unused,
175                    int s, struct dir *dp)
176 {
177         struct qid qid;
178         struct proc *p;
179         char *ename;
180
181         int pid;
182         uint32_t path, perm, len;
183         if (s == DEVDOTDOT) {
184                 mkqid(&qid, Qdir, 0, QTDIR);
185                 devdir(c, qid, devname(), 0, eve.name, 0555, dp);
186                 return 1;
187         }
188
189         if (c->qid.path == Qdir) {
190                 if (s == 0) {
191                         strlcpy(get_cur_genbuf(), "trace", GENBUF_SZ);
192                         mkqid(&qid, Qtrace, -1, QTFILE);
193                         devdir(c, qid, get_cur_genbuf(), 0, eve.name, 0444, dp);
194                         return 1;
195                 }
196                 if (s == 1) {
197                         strlcpy(get_cur_genbuf(), "tracepids", GENBUF_SZ);
198                         mkqid(&qid, Qtracepids, -1, QTFILE);
199                         devdir(c, qid, get_cur_genbuf(), 0, eve.name, 0444, dp);
200                         return 1;
201                 }
202                 if (s == 2) {
203                         p = current;
204                         strlcpy(get_cur_genbuf(), "self", GENBUF_SZ);
205                         mkqid(&qid, (p->pid + 1) << QSHIFT, p->pid, QTDIR);
206                         devdir(c, qid, get_cur_genbuf(), 0, p->user.name,
207                                DMDIR | 0555, dp);
208                         return 1;
209                 }
210                 s -= 3;
211                 if (name != NULL) {
212                         /* ignore s and use name to find pid */
213                         pid = strtol(name, &ename, 10);
214                         if (pid <= 0 || ename[0] != '\0')
215                                 return -1;
216                         p = pid2proc(pid);
217                         if (!p)
218                                 return -1;
219                         /* Need to update s, so that it's the correct 'index'
220                          * for our proc (aka, the pid).  We use s later when
221                          * making the qid. */
222                         s = pid;
223                 } else {
224                         /* This is a shitty iterator, and the list isn't
225                          * guaranteed to give you the same ordering twice in a
226                          * row. (procs come and go). */
227                         p = pid_nth(s);
228                         if (!p)
229                                 return -1;
230                         pid = p->pid;
231                 }
232
233                 snprintf(get_cur_genbuf(), GENBUF_SZ, "%u", pid);
234                 /*
235                  * String comparison is done in devwalk so
236                  * name must match its formatted pid.
237                  */
238                 if (name != NULL && strcmp(name, get_cur_genbuf()) != 0) {
239                         printk("pid-name mismatch, name: %s, pid %d\n", name,
240                                pid);
241                         proc_decref(p);
242                         return -1;
243                 }
244                 mkqid(&qid, (s + 1) << QSHIFT, pid, QTDIR);
245                 devdir(c, qid, get_cur_genbuf(), 0, p->user.name, DMDIR | 0555,
246                        dp);
247                 proc_decref(p);
248                 return 1;
249         }
250         if (c->qid.path == Qtrace) {
251                 strlcpy(get_cur_genbuf(), "trace", GENBUF_SZ);
252                 mkqid(&qid, Qtrace, -1, QTFILE);
253                 devdir(c, qid, get_cur_genbuf(), 0, eve.name, 0444, dp);
254                 return 1;
255         }
256         if (c->qid.path == Qtracepids) {
257                 strlcpy(get_cur_genbuf(), "tracepids", GENBUF_SZ);
258                 mkqid(&qid, Qtracepids, -1, QTFILE);
259                 devdir(c, qid, get_cur_genbuf(), 0, eve.name, 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
269          * code
270          * if they wanted just the pid part (SLOTMASK) or everything above QID
271          */
272         path = c->qid.path & ~QIDMASK; /* slot component */
273         if ((p = pid2proc(SLOT(c->qid))) == NULL)
274                 return -1;
275         perm = 0444 | tab->perm;
276 #if 0
277         if (perm == 0)
278                 perm = p->procmode;
279         else    /* just copy read bits */
280                 perm |= p->procmode & 0444;
281 #endif
282
283         len = tab->length;
284 #if 0
285         switch (QID(c->qid)) {
286                 case Qwait:
287                         len = p->nwait; /* incorrect size, but >0 means there's something to read */
288                         break;
289                 case Qprofile:
290                         q = p->seg[TSEG];
291                         if (q && q->profile) {
292                                 len = (q->top - q->base) >> LRESPROF;
293                                 len *= sizeof(*q->profile);
294                         }
295                         break;
296         }
297 #endif
298
299         mkqid(&qid, path | tab->qid.path, c->qid.vers, QTFILE);
300         devdir(c, qid, tab->name, len, p->user.name, perm, dp);
301         proc_decref(p);
302         return 1;
303 }
304
305 #if 0
306 static void notrace(struct proc *, Tevent, int64_t)
307 {
308 }
309
310 static spinlock_t tlck = SPINLOCK_INITIALIZER_IRQSAVE;
311
312 static void _proctrace(struct proc *p, Tevent etype, int64_t ts)
313 {
314         Traceevent *te;
315         int tp;
316
317         ilock(&tlck);
318         if (p->trace == 0 || topens == 0 || tproduced - tconsumed >= Nevents) {
319                 iunlock(&tlck);
320                 return;
321         }
322         tp = tproduced++;
323         iunlock(&tlck);
324
325         te = &tevents[tp & Emask];
326         te->pid = p->pid;
327         te->etype = etype;
328         if (ts == 0)
329                 te->time = todget(NULL);
330         else
331                 te->time = ts;
332         te->core = m->machno;
333 }
334
335 void proctracepid(struct proc *p)
336 {
337         if (p->trace == 1 && proctrace != notrace) {
338                 p->trace = 2;
339                 ilock(&tlck);
340                 tpidsc = seprint(tpidsc, tpidse, "%d %s\n", p->pid, p->text);
341                 iunlock(&tlck);
342         }
343 }
344
345 #endif
346 static void procinit(void)
347 {
348 #if 0
349         if (conf.nproc >= (SLOTMASK >> QSHIFT) - 1)
350                 printd("warning: too many procs for devproc\n");
351         addclock0link((void (*)(void))profclock, 113);  /* Relative prime to HZ */
352 #endif
353 }
354
355 static struct chan *procattach(char *spec)
356 {
357         return devattach(devname(), spec);
358 }
359
360 static struct walkqid *procwalk(struct chan *c, struct chan *nc, char **name,
361                                 unsigned int nname)
362 {
363         return devwalk(c, nc, name, nname, 0, 0, procgen);
364 }
365
366 static size_t procstat(struct chan *c, uint8_t *db, size_t n)
367 {
368         return devstat(c, db, n, 0, 0, procgen);
369 }
370
371 /*
372  *  none can't read or write state on other
373  *  processes.  This is to contain access of
374  *  servers running as none should they be
375  *  subverted by, for example, a stack attack.
376  */
377 static void nonone(struct proc *p)
378 {
379         return;
380 #if 0
381         if (p == up)
382                 return;
383         if (strcmp(current->user.name, "none") != 0)
384                 return;
385         if (iseve())
386                 return;
387         error(EPERM, ERROR_FIXME);
388 #endif
389 }
390
391 struct bm_helper {
392         struct sized_alloc *sza;
393         size_t buflen;
394 };
395
396 static void get_needed_sz_cb(struct vm_region *vmr, void *arg)
397 {
398         struct bm_helper *bmh = (struct bm_helper *)arg;
399
400         /* ballpark estimate of a line */
401         bmh->buflen += 150;
402 }
403
404 static void build_maps_cb(struct vm_region *vmr, void *arg)
405 {
406         struct bm_helper *bmh = (struct bm_helper *)arg;
407         struct sized_alloc *sza = bmh->sza;
408         size_t old_sofar;
409         char path_buf[MAX_FILENAME_SZ];
410         char *path;
411         unsigned long inode_nr;
412
413         if (vmr_has_file(vmr)) {
414                 path = foc_abs_path(vmr->__vm_foc);
415                 inode_nr = 0; /* TODO: do we care about this? */
416         } else {
417                 strlcpy(path_buf, "[heap]", sizeof(path_buf));
418                 path = path_buf;
419                 inode_nr = 0;
420         }
421
422         old_sofar = sza->sofar;
423         sza_printf(sza, "%08lx-%08lx %c%c%c%c %08x %02d:%02d %d ", vmr->vm_base,
424                    vmr->vm_end, vmr->vm_prot & PROT_READ ? 'r' : '-',
425                    vmr->vm_prot & PROT_WRITE ? 'w' : '-',
426                    vmr->vm_prot & PROT_EXEC ? 'x' : '-',
427                    vmr->vm_flags & MAP_PRIVATE ? 'p' : 's',
428                    vmr_has_file(vmr) ? vmr->vm_foff : 0,
429                    vmr_has_file(vmr) ? 1 : 0, /* VFS == 1 for major */
430                    0, inode_nr);
431         /* Align the filename to the 74th char, like Linux (73 chars so far) */
432         sza_printf(sza, "%*s", 73 - (sza->sofar - old_sofar), "");
433         sza_printf(sza, "%s\n", path);
434 }
435
436 static struct sized_alloc *build_maps(struct proc *p)
437 {
438         struct bm_helper bmh[1];
439
440         /* Try to figure out the size needed: start with extra space, then add a
441          * bit for each VMR */
442         bmh->buflen = 150;
443         enumerate_vmrs(p, get_needed_sz_cb, bmh);
444         bmh->sza = sized_kzmalloc(bmh->buflen, MEM_WAIT);
445         enumerate_vmrs(p, build_maps_cb, bmh);
446         return bmh->sza;
447 }
448
449 static struct chan *procopen(struct chan *c, int omode)
450 {
451         ERRSTACK(2);
452         struct proc *p;
453         struct pgrp *pg;
454         struct chan *tc;
455         int pid;
456
457         if (c->qid.type & QTDIR)
458                 return devopen(c, omode, 0, 0, procgen);
459
460         if (QID(c->qid) == Qtrace) {
461                 error(ENOSYS, ERROR_FIXME);
462 #if 0
463                 if (omode != OREAD)
464                         error(EPERM, ERROR_FIXME);
465                 lock(&tlock);
466                 if (waserror()) {
467                         unlock(&tlock);
468                         nexterror();
469                 }
470                 if (topens > 0)
471                         error(EFAIL, "already open");
472                 topens++;
473                 if (tevents == NULL) {
474                         tevents = (Traceevent *) kzmalloc(sizeof(Traceevent) * Nevents,
475                                                                                           MEM_WAIT);
476                         if (tevents == NULL)
477                                 error(ENOMEM, ERROR_FIXME);
478                         tpids = kzmalloc(Ntracedpids * 20, MEM_WAIT);
479                         if (tpids == NULL) {
480                                 kfree(tpids);
481                                 tpids = NULL;
482                                 error(ENOMEM, ERROR_FIXME);
483                         }
484                         tpidsc = tpids;
485                         tpidse = tpids + Ntracedpids * 20;
486                         *tpidsc = 0;
487                         tproduced = tconsumed = 0;
488                 }
489                 proctrace = _proctrace;
490                 poperror();
491                 unlock(&tlock);
492
493                 c->mode = openmode(omode);
494                 c->flag |= COPEN;
495                 c->offset = 0;
496                 return c;
497 #endif
498         }
499         if (QID(c->qid) == Qtracepids) {
500                 error(ENOSYS, ERROR_FIXME);
501 #if 0
502                 if (omode != OREAD)
503                         error(EPERM, ERROR_FIXME);
504                 c->mode = openmode(omode);
505                 c->flag |= COPEN;
506                 c->offset = 0;
507                 return c;
508 #endif
509         }
510         if ((p = pid2proc(SLOT(c->qid))) == NULL)
511                 error(ESRCH, ERROR_FIXME);
512         // qlock(&p->debug);
513         if (waserror()) {
514                 // qunlock(&p->debug);
515                 proc_decref(p);
516                 nexterror();
517         }
518         pid = PID(c->qid);
519         if (p->pid != pid)
520                 error(ESRCH, ERROR_FIXME);
521
522         omode = openmode(omode);
523
524         switch (QID(c->qid)) {
525         case Qtext:
526                 error(ENOSYS, ERROR_FIXME);
527                 /*
528                                         if (omode != OREAD)
529                                                 error(EPERM, ERROR_FIXME);
530                                         tc = proctext(c, p);
531                                         tc->offset = 0;
532                                         poperror();
533                                         qunlock(&p->debug);
534                                         proc_decref(p);
535                                         cclose(c);
536                                         return tc;
537                 */
538         case Qproc:
539         case Qsegment:
540         case Qprofile:
541         case Qfd:
542                 if (omode != O_READ)
543                         error(EPERM, ERROR_FIXME);
544                 break;
545
546         case Qnote:
547                 //          if (p->privatemem)
548                 error(EPERM, ERROR_FIXME);
549                 break;
550
551         case Qmem:
552                 //          if (p->privatemem)
553                 error(EPERM, ERROR_FIXME);
554                 // nonone(p);
555                 break;
556
557         case Qargs:
558         case Qnoteid:
559         case Qwait:
560         case Qregs:
561         case Qfpregs:
562         case Qkregs:
563         case Qsyscall:
564         case Qcore:
565                 nonone(p);
566                 break;
567
568         case Qns:
569                 if (omode != O_READ)
570                         error(EPERM, ERROR_FIXME);
571                 c->aux = kzmalloc(sizeof(struct mntwalk), MEM_WAIT);
572                 break;
573         case Quser:
574         case Qstatus:
575         case Qvmstatus:
576         case Qctl:
577                 break;
578
579         case Qstrace:
580                 if (!p->strace)
581                         error(ENOENT, "Process does not have tracing enabled");
582                 spin_lock(&p->strace->lock);
583                 if (p->strace->tracing) {
584                         spin_unlock(&p->strace->lock);
585                         error(EBUSY, "Process is already being traced");
586                 }
587                 /* It's not critical that we reopen before setting tracing, but
588                  * it's a little cleaner (concurrent syscalls could be trying to
589                  * use the queue before it was reopened, and they'd throw). */
590                 qreopen(p->strace->q);
591                 p->strace->tracing = TRUE;
592                 spin_unlock(&p->strace->lock);
593                 /* the ref we are upping is the one we put in __proc_free, which
594                  * is the one we got from CMstrace{on,me}.  We have a ref on p,
595                  * so we know we won't free until we decref the proc. */
596                 kref_get(&p->strace->users, 1);
597                 c->aux = p->strace;
598                 break;
599         case Qstrace_traceset:
600                 if (!p->strace)
601                         error(ENOENT, "Process does not have tracing enabled");
602                 kref_get(&p->strace->users, 1);
603                 c->aux = p->strace;
604                 break;
605         case Qmaps:
606                 c->aux = build_maps(p);
607                 break;
608         case Qnotepg:
609                 error(ENOSYS, ERROR_FIXME);
610 #if 0
611                         nonone(p);
612                         pg = p->pgrp;
613                         if (pg == NULL)
614                                 error(ESRCH, ERROR_FIXME);
615                         if (omode != OWRITE || pg->pgrpid == 1)
616                                 error(EPERM, ERROR_FIXME);
617                         c->pgrpid.path = pg->pgrpid + 1;
618                         c->pgrpid.vers = p->noteid;
619 #endif
620                 break;
621
622         default:
623                 printk("procopen %#llux\n", c->qid.path);
624                 error(EINVAL, ERROR_FIXME);
625         }
626
627         /* Affix pid to qid */
628         //  if (p->state != Dead)
629         c->qid.vers = p->pid;
630         /* make sure the process slot didn't get reallocated while we were
631          * playing */
632         // coherence();
633         /* TODO: think about what we really want here.  In akaros, we wouldn't
634          * have our pid changed like that. */
635         if (p->pid != pid)
636                 error(ESRCH, ERROR_FIXME);
637
638         tc = devopen(c, omode, 0, 0, procgen);
639         poperror();
640         // qunlock(&p->debug);
641         proc_decref(p);
642         return tc;
643 }
644
645 static size_t procwstat(struct chan *c, uint8_t *db, size_t n)
646 {
647         ERRSTACK(2);
648         error(ENOSYS, ERROR_FIXME);
649 #if 0
650         struct proc *p;
651         struct dir *d;
652
653         if (c->qid.type & QTDIR)
654                 error(EPERM, ERROR_FIXME);
655
656         if (QID(c->qid) == Qtrace)
657                 return devwstat(c, db, n);
658
659         if ((p = pid2proc(SLOT(c->qid))) == NULL)
660                 error(ESRCH, ERROR_FIXME);
661         nonone(p);
662         d = NULL;
663         qlock(&p->debug);
664         if (waserror()) {
665                 qunlock(&p->debug);
666                 proc_decref(p);
667                 kfree(d);
668                 nexterror();
669         }
670
671         if (p->pid != PID(c->qid))
672                 error(ESRCH, ERROR_FIXME);
673
674         if (strcmp(current->user.name, p->user.name) != 0 && !iseve())
675                 error(EPERM, ERROR_FIXME);
676
677         d = kzmalloc(sizeof(struct dir) + n, MEM_WAIT);
678         n = convM2D(db, n, &d[0], (char *)&d[1]);
679         if (n == 0)
680                 error(ENOENT, ERROR_FIXME);
681         if (!emptystr(d->uid) && strcmp(d->uid, p->user.name) != 0) {
682                 if (!iseve())
683                         error(EPERM, ERROR_FIXME);
684                 else
685                         proc_set_username(p, d->uid);
686         }
687         if (d->mode != -1)
688                 p->procmode = d->mode & 0777;
689
690         poperror();
691         qunlock(&p->debug);
692         proc_decref(p);
693         kfree(d);
694
695         return n;
696 #endif
697 }
698
699 #if 0
700 static long procoffset(long offset, char *va, int *np)
701 {
702         if (offset > 0) {
703                 offset -= *np;
704                 if (offset < 0) {
705                         memmove(va, va + *np + offset, -offset);
706                         *np = -offset;
707                 } else
708                         *np = 0;
709         }
710         return offset;
711 }
712
713 static int procqidwidth(struct chan *c)
714 {
715         char buf[32];
716
717         return sprint(buf, "%lu", c->qid.vers);
718 }
719
720 int procfdprint(struct chan *c, int fd, int w, char *s, int ns)
721 {
722         int n;
723
724         if (w == 0)
725                 w = procqidwidth(c);
726         n = snprint(s, ns,
727                                 "%3d %.2s %C %4ud (%.16llux %*lud %.2ux) %5ld %8lld %s\n", fd,
728                                 &"r w rw"[(c->mode & 3) << 1], c->dev->dc, c->devno,
729                                 c->qid.path, w, c->qid.vers, c->qid.type, c->iounit, c->offset,
730                                 c->name->s);
731         return n;
732 }
733
734 static int procfds(struct proc *p, char *va, int count, long offset)
735 {
736         ERRSTACK(2);
737         struct fgrp *f;
738         struct chan *c;
739         char buf[256];
740         int n, i, w, ww;
741         char *a;
742
743         /* print to buf to avoid holding fgrp lock while writing to user space */
744         if (count > sizeof buf)
745                 count = sizeof buf;
746         a = buf;
747
748         qlock(&p->debug);
749         f = p->fgrp;
750         if (f == NULL) {
751                 qunlock(&p->debug);
752                 return 0;
753         }
754         lock(f);
755         if (waserror()) {
756                 unlock(f);
757                 qunlock(&p->debug);
758                 nexterror();
759         }
760
761         n = readstr(0, a, count, p->dot->name->s);
762         n += snprint(a + n, count - n, "\n");
763         offset = procoffset(offset, a, &n);
764         /* compute width of qid.path */
765         w = 0;
766         for (i = 0; i <= f->maxfd; i++) {
767                 c = f->fd[i];
768                 if (c == NULL)
769                         continue;
770                 ww = procqidwidth(c);
771                 if (ww > w)
772                         w = ww;
773         }
774         for (i = 0; i <= f->maxfd; i++) {
775                 c = f->fd[i];
776                 if (c == NULL)
777                         continue;
778                 n += procfdprint(c, i, w, a + n, count - n);
779                 offset = procoffset(offset, a, &n);
780         }
781         poperror();
782         unlock(f);
783         qunlock(&p->debug);
784
785         /* copy result to user space, now that locks are released */
786         memmove(va, buf, n);
787
788         return n;
789 }
790 #endif
791 static void procclose(struct chan *c)
792 {
793         if (QID(c->qid) == Qtrace) {
794                 spin_lock(&tlock);
795                 if (topens > 0)
796                         topens--;
797                 /* ??
798                    if(topens == 0)
799                    proctrace = notrace;
800                  */
801                 spin_unlock(&tlock);
802         }
803         if (QID(c->qid) == Qsyscall) {
804                 if (c->aux)
805                         qclose(c->aux);
806                 c->aux = NULL;
807         }
808         if (QID(c->qid) == Qns && c->aux != 0)
809                 kfree(c->aux);
810         if (QID(c->qid) == Qmaps && c->aux != 0)
811                 kfree(c->aux);
812         if (QID(c->qid) == Qstrace && c->aux != 0) {
813                 struct strace *s = c->aux;
814
815                 assert(c->flag & COPEN); /* only way aux should have been set */
816                 s->tracing = FALSE;
817                 qhangup(s->q, NULL);
818                 kref_put(&s->users);
819                 c->aux = NULL;
820         }
821         if (QID(c->qid) == Qstrace_traceset && c->aux != 0) {
822                 struct strace *s = c->aux;
823
824                 assert(c->flag & COPEN);
825                 kref_put(&s->users);
826                 c->aux = NULL;
827         }
828 }
829
830 void int2flag(int flag, char *s)
831 {
832         if (flag == 0) {
833                 *s = '\0';
834                 return;
835         }
836         *s++ = '-';
837         if (flag & MAFTER)
838                 *s++ = 'a';
839         if (flag & MBEFORE)
840                 *s++ = 'b';
841         if (flag & MCREATE)
842                 *s++ = 'c';
843         if (flag & MCACHE)
844                 *s++ = 'C';
845         *s = '\0';
846 }
847
848 #if 0
849 static char *argcpy(char *s, char *p)
850 {
851         char *t, *tp, *te;
852         int n;
853
854         n = p - s;
855         if (n > 128)
856                 n = 128;
857         if (n <= 0) {
858                 t = kzmalloc(1, MEM_WAIT);
859                 *t = 0;
860                 return t;
861         }
862         t = kzmalloc(n, MEM_WAIT);
863         tp = t;
864         te = t + n;
865
866         while (tp + 1 < te) {
867                 for (p--; p > s && p[-1] != 0; p--) ;
868                 tp = seprint(tp, te, "%q ", p);
869                 if (p == s)
870                         break;
871         }
872         if (*tp == ' ')
873                 *tp = 0;
874         return t;
875 }
876
877 static int procargs(struct proc *p, char *buf, int nbuf)
878 {
879         char *s;
880
881         if (p->setargs == 0) {
882                 s = argcpy(p->args, p->args + p->nargs);
883                 kfree(p->args);
884                 p->nargs = strlen(s);
885                 p->args = s;
886                 p->setargs = 1;
887         }
888         return snprint(buf, nbuf, "%s", p->args);
889 }
890
891 static int eventsavailable(void *)
892 {
893         return tproduced > tconsumed;
894 }
895 #endif
896
897 static size_t procread(struct chan *c, void *va, size_t n, off64_t off)
898 {
899         ERRSTACK(1);
900         struct proc *p;
901         long l, r;
902         int i, j, navail, pid, rsize;
903         char flag[10], *sps, *srv;
904         uintptr_t offset, u;
905         int tesz;
906         uint8_t *rptr;
907         struct mntwalk *mw;
908         struct strace *s;
909         struct sized_alloc *sza;
910
911         if (c->qid.type & QTDIR) {
912                 int nn;
913                 printd("procread: dir\n");
914                 nn = devdirread(c, va, n, 0, 0, procgen);
915                 printd("procread: %d\n", nn);
916                 return nn;
917         }
918
919         offset = off;
920         /* Some shit in proc doesn't need to grab the reference.  For strace, we
921          * already have the chan open, and all we want to do is read the queue,
922          * which exists because of our kref on it. */
923         switch (QID(c->qid)) {
924         case Qstrace:
925                 s = c->aux;
926                 n = qread(s->q, va, n);
927                 return n;
928         case Qstrace_traceset:
929                 s = c->aux;
930                 return readmem(offset, va, n, s->trace_set,
931                                bitmap_size(MAX_SYSCALL_NR));
932         }
933
934         if ((p = pid2proc(SLOT(c->qid))) == NULL)
935                 error(ESRCH, "%d: no such process", SLOT(c->qid));
936         if (p->pid != PID(c->qid)) {
937                 proc_decref(p);
938                 error(ESRCH, "weird: p->pid is %d, PID(c->qid) is %d: mismatch",
939                       p->pid, PID(c->qid));
940         }
941         switch (QID(c->qid)) {
942         default:
943                 proc_decref(p);
944                 break;
945         case Quser: {
946                 int i;
947
948                 i = readstr(off, va, n, p->user.name);
949                 proc_decref(p);
950                 return i;
951         }
952         case Qstatus: {
953                 /* the old code grew the stack and was hideous.
954                  * status is not a high frequency operation; just malloc. */
955                 char *buf = kmalloc(4096, MEM_WAIT);
956                 char *s = buf, *e = buf + 4096;
957                 int i;
958
959                 s = seprintf(s, e, "%8d %-*s %-10s %6d", p->pid,
960                              PROC_PROGNAME_SZ, p->progname,
961                              procstate2str(p->state), p->ppid);
962                 if (p->strace)
963                         s = seprintf(s, e, " %d trace users %d traced procs",
964                                      kref_refcnt(&p->strace->users),
965                                      kref_refcnt(&p->strace->procs));
966                 proc_decref(p);
967                 i = readstr(off, va, n, buf);
968                 kfree(buf);
969                 return i;
970         }
971
972         case Qvmstatus: {
973                 size_t buflen = 50 * 65 + 2;
974                 char *buf = kmalloc(buflen, MEM_WAIT);
975                 int i, offset;
976                 offset = 0;
977                 offset += snprintf(buf + offset, buflen - offset, "{\n");
978                 for (i = 0; i < 65; i++) {
979                         if (p->vmm.vmexits[i] != 0) {
980                                 offset +=
981                                     snprintf(buf + offset, buflen - offset,
982                                              "\"%s\":\"%lld\",\n",
983                                              VMX_EXIT_REASON_NAMES[i],
984                                              p->vmm.vmexits[i]);
985                         }
986                 }
987                 offset += snprintf(buf + offset, buflen - offset, "}\n");
988                 proc_decref(p);
989                 n = readstr(off, va, n, buf);
990                 kfree(buf);
991                 return n;
992         }
993         case Qns:
994                 // qlock(&p->debug);
995                 if (waserror()) {
996                         // qunlock(&p->debug);
997                         proc_decref(p);
998                         nexterror();
999                 }
1000                 if (p->pgrp == NULL || p->pid != PID(c->qid))
1001                         error(ESRCH, ERROR_FIXME);
1002                 mw = c->aux;
1003                 if (mw->cddone) {
1004                         poperror();
1005                         // qunlock(&p->debug);
1006                         proc_decref(p);
1007                         return 0;
1008                 }
1009                 mntscan(mw, p);
1010                 if (mw->mh == 0) {
1011                         mw->cddone = 1;
1012                         i = snprintf(va, n, "cd %s\n", p->dot->name->s);
1013                         poperror();
1014                         // qunlock(&p->debug);
1015                         proc_decref(p);
1016                         return i;
1017                 }
1018                 int2flag(mw->cm->mflag, flag);
1019                 if (strcmp(mw->cm->to->name->s, "#mnt") == 0) {
1020                         srv = srvname(mw->cm->to->mchan);
1021                         i = snprintf(va, n, "mount %s %s %s %s\n", flag,
1022                                      srv == NULL ? mw->cm->to->mchan->name->s
1023                                                  : srv,
1024                                      mw->mh->from->name->s,
1025                                      mw->cm->spec ? mw->cm->spec : "");
1026                         kfree(srv);
1027                 } else
1028                         i = snprintf(va, n, "bind %s %s %s\n", flag,
1029                                      mw->cm->to->name->s,
1030                                      mw->mh->from->name->s);
1031                 poperror();
1032                 // qunlock(&p->debug);
1033                 proc_decref(p);
1034                 return i;
1035         case Qmaps:
1036                 sza = c->aux;
1037                 i = readstr(off, va, n, sza->buf);
1038                 proc_decref(p);
1039                 return i;
1040         }
1041         error(EINVAL, "QID %d did not match any QIDs for #proc", QID(c->qid));
1042         return 0; /* not reached */
1043 }
1044
1045 static void mntscan(struct mntwalk *mw, struct proc *p)
1046 {
1047         struct pgrp *pg;
1048         struct mount *t;
1049         struct mhead *f;
1050         int best, i, last, nxt;
1051
1052         pg = p->pgrp;
1053         rlock(&pg->ns);
1054
1055         nxt = 0;
1056         best = (int)(~0U >> 1); /* largest 2's complement int */
1057
1058         last = 0;
1059         if (mw->mh)
1060                 last = mw->cm->mountid;
1061
1062         for (i = 0; i < MNTHASH; i++) {
1063                 for (f = pg->mnthash[i]; f; f = f->hash) {
1064                         for (t = f->mount; t; t = t->next) {
1065                                 if (mw->mh == 0 ||
1066                                     (t->mountid > last && t->mountid < best)) {
1067                                         mw->cm = t;
1068                                         mw->mh = f;
1069                                         best = mw->cm->mountid;
1070                                         nxt = 1;
1071                                 }
1072                         }
1073                 }
1074         }
1075         if (nxt == 0)
1076                 mw->mh = 0;
1077
1078         runlock(&pg->ns);
1079 }
1080
1081 static size_t procwrite(struct chan *c, void *va, size_t n, off64_t off)
1082 {
1083         ERRSTACK(2);
1084
1085         struct proc *p, *t;
1086         int i, id, l;
1087         char *args;
1088         uintptr_t offset = off;
1089         struct strace *s;
1090
1091         if (c->qid.type & QTDIR)
1092                 error(EISDIR, ERROR_FIXME);
1093
1094         if ((p = pid2proc(SLOT(c->qid))) == NULL)
1095                 error(ESRCH, ERROR_FIXME);
1096
1097         if (waserror()) {
1098                 proc_decref(p);
1099                 nexterror();
1100         }
1101         if (p->pid != PID(c->qid))
1102                 error(ESRCH, ERROR_FIXME);
1103
1104         offset = off;
1105
1106         switch (QID(c->qid)) {
1107 #if 0
1108                 case Qargs:
1109                         if (n == 0)
1110                                 error(EINVAL, ERROR_FIXME);
1111                         if (n >= sizeof buf - strlen(p->text) - 1)
1112                                 error(E2BIG, ERROR_FIXME);
1113                         l = snprintf(buf, sizeof buf, "%s [%s]", p->text, (char *)va);
1114                         args = kzmalloc(l + 1, MEM_WAIT);
1115                         if (args == NULL)
1116                                 error(ENOMEM, ERROR_FIXME);
1117                         memmove(args, buf, l);
1118                         args[l] = 0;
1119                         kfree(p->args);
1120                         p->nargs = l;
1121                         p->args = args;
1122                         p->setargs = 1;
1123                         break;
1124
1125                 case Qmem:
1126                         if (p->state != Stopped)
1127                                 error(EINVAL, ERROR_FIXME);
1128
1129                         n = procctlmemio(p, offset, n, va, 0);
1130                         break;
1131
1132                 case Qregs:
1133                         if (offset >= sizeof(Ureg))
1134                                 n = 0;
1135                         else if (offset + n > sizeof(Ureg))
1136                                 n = sizeof(Ureg) - offset;
1137                         if (p->dbgreg == 0)
1138                                 error(ENODATA, ERROR_FIXME);
1139                         setregisters(p->dbgreg, (char *)(p->dbgreg) + offset, va, n);
1140                         break;
1141
1142                 case Qfpregs:
1143                         n = fpudevprocio(p, va, n, offset, 1);
1144                         break;
1145 #endif
1146         case Qctl:
1147                 procctlreq(p, va, n);
1148                 break;
1149         case Qstrace_traceset:
1150                 s = c->aux;
1151                 if (n + offset > bitmap_size(MAX_SYSCALL_NR))
1152                         error(EINVAL,
1153                               "strace_traceset: Short write (%llu at off %llu)",
1154                               n, offset);
1155                 if (memcpy_from_user(current, (void *)s->trace_set + offset, va,
1156                                      n))
1157                         error(EFAULT, "strace_traceset: Bad addr (%p + %llu)",
1158                               va, n);
1159                 break;
1160         default:
1161                 error(EFAIL, "unknown qid %#llux in procwrite\n", c->qid.path);
1162         }
1163         poperror();
1164         proc_decref(p);
1165         return n;
1166 }
1167
1168 struct dev procdevtab __devtab = {
1169     .name = "proc",
1170
1171     .reset = devreset,
1172     .init = procinit,
1173     .shutdown = devshutdown,
1174     .attach = procattach,
1175     .walk = procwalk,
1176     .stat = procstat,
1177     .open = procopen,
1178     .create = devcreate,
1179     .close = procclose,
1180     .read = procread,
1181     .bread = devbread,
1182     .write = procwrite,
1183     .bwrite = devbwrite,
1184     .remove = devremove,
1185     .wstat = procwstat,
1186     .power = devpower,
1187     .chaninfo = devchaninfo,
1188 };
1189
1190 #if 0
1191 static struct chan *proctext(struct chan *c, struct proc *p)
1192 {
1193         ERRSTACK(2);
1194         struct chan *tc;
1195         Image *i;
1196         Segment *s;
1197
1198         s = p->seg[TSEG];
1199         if (s == 0)
1200                 error(ENOENT, ERROR_FIXME);
1201         if (p->state == Dead)
1202                 error(ESRCH, ERROR_FIXME);
1203
1204         lock(s);
1205         i = s->image;
1206         if (i == 0) {
1207                 unlock(s);
1208                 error(ESRCH, ERROR_FIXME);
1209         }
1210         unlock(s);
1211
1212         lock(i);
1213         if (waserror()) {
1214                 unlock(i);
1215                 nexterror();
1216         }
1217
1218         tc = i->c;
1219         if (tc == 0)
1220                 error(ESRCH, ERROR_FIXME);
1221
1222         /* TODO: what do you want here?  you can't get a kref and have the new val
1223          * be 1.  Here is the old code: if (kref_get(&tc->ref, 1) == 1 || ... ) */
1224         if (kref_refcnt(&tc->ref, 1) == 1 || (tc->flag & COPEN) == 0
1225                 || tc->mode != OREAD) {
1226                 cclose(tc);
1227                 error(ESRCH, ERROR_FIXME);
1228         }
1229
1230         if (p->pid != PID(c->qid)) {
1231                 cclose(tc);
1232                 error(ESRCH, ERROR_FIXME);
1233         }
1234
1235         poperror();
1236         unlock(i);
1237
1238         return tc;
1239 }
1240
1241 /* TODO: this will fail at compile time, since we don't have a proc-wide rendez,
1242  * among other things, and we'll need to rewrite this for akaros */
1243 void procstopwait(struct proc *p, int ctl)
1244 {
1245         ERRSTACK(2);
1246         int pid;
1247
1248         if (p->pdbg)
1249                 error(EBUSY, ERROR_FIXME);
1250         if (procstopped(p) || p->state == Broken)
1251                 return;
1252
1253         if (ctl != 0)
1254                 p->procctl = ctl;
1255         p->pdbg = up;
1256         pid = p->pid;
1257         qunlock(&p->debug);
1258         current->psstate = "Stopwait";
1259         if (waserror()) {
1260                 p->pdbg = 0;
1261                 qlock(&p->debug);
1262                 nexterror();
1263         }
1264         rendez_sleep(&current->sleep, procstopped, p);
1265         poperror();
1266         qlock(&p->debug);
1267         if (p->pid != pid)
1268                 error(ESRCH, ERROR_FIXME);
1269 }
1270
1271 #endif
1272 static void procctlcloseone(struct proc *p, int fd)
1273 {
1274         // TODO: resolve this and sys_close
1275         sysclose(fd);
1276         return;
1277 }
1278
1279 void procctlclosefiles(struct proc *p, int all, int fd)
1280 {
1281         int i;
1282
1283         if (all)
1284                 for (i = 0; i < NR_FILE_DESC_MAX; i++)
1285                         procctlcloseone(p, i);
1286         else
1287                 procctlcloseone(p, fd);
1288 }
1289
1290 static void strace_shutdown(struct kref *a)
1291 {
1292         struct strace *strace = container_of(a, struct strace, procs);
1293         static const char base_msg[] = "# Traced ~%lu syscs, Dropped %lu";
1294         size_t msg_len = NUMSIZE64 * 2 + sizeof(base_msg);
1295         char *msg = kmalloc(msg_len, 0);
1296
1297         if (msg)
1298                 snprintf(msg, msg_len, base_msg, strace->appx_nr_sysc,
1299                          atomic_read(&strace->nr_drops));
1300         qhangup(strace->q, msg);
1301         kfree(msg);
1302 }
1303
1304 static void strace_release(struct kref *a)
1305 {
1306         struct strace *strace = container_of(a, struct strace, users);
1307
1308         qfree(strace->q);
1309         kfree(strace);
1310 }
1311
1312 static void procctlreq(struct proc *p, char *va, size_t n)
1313 {
1314         ERRSTACK(1);
1315         int8_t irq_state = 0;
1316         int npc, pri, core;
1317         struct cmdbuf *cb;
1318         struct cmdtab *ct;
1319         int64_t time;
1320         char *e;
1321         struct strace *strace;
1322
1323         cb = parsecmd(va, n);
1324         if (waserror()) {
1325                 kfree(cb);
1326                 nexterror();
1327         }
1328
1329         ct = lookupcmd(cb, proccmd, ARRAY_SIZE(proccmd));
1330
1331         switch (ct->index) {
1332         case CMstraceall:
1333         case CMstraceme:
1334         case CMstrace_drop:
1335                 /* common allocation.  if we inherited, we might have one
1336                  * already */
1337                 if (!p->strace) {
1338                         strace = kzmalloc(sizeof(*p->strace), MEM_WAIT);
1339                         spinlock_init(&strace->lock);
1340                         bitmap_set(strace->trace_set, 0, MAX_SYSCALL_NR);
1341                         strace->q = qopen(65536, Qmsg, NULL, NULL);
1342                         /* The queue is reopened and hungup whenever we open the
1343                          * Qstrace file.  This hangup might not be necessary,
1344                          * but is safer. */
1345                         qhangup(strace->q, NULL);
1346                         /* both of these refs are put when the proc is freed.
1347                          * procs is for every process that has this p->strace.
1348                          * users is procs + every user (e.g. from open()).
1349                          *
1350                          * it is possible to kref_put the procs kref in
1351                          * proc_destroy, which would make strace's job easier
1352                          * (no need to do an async wait on the child), and we
1353                          * wouldn't need to decref p in procread(Qstrace).  But
1354                          * the downside is that proc_destroy races
1355                          * with us here with the kref initialization. */
1356                         kref_init(&strace->procs, strace_shutdown, 1);
1357                         kref_init(&strace->users, strace_release, 1);
1358                         if (!atomic_cas_ptr((void **)&p->strace, 0, strace)) {
1359                                 /* someone else won the race and installed
1360                                  * strace. */
1361                                 qfree(strace->q);
1362                                 kfree(strace);
1363                                 error(EAGAIN,
1364                                       "Concurrent strace init, try again");
1365                         }
1366                 }
1367                 break;
1368         }
1369
1370         /* actually do the command. */
1371         switch (ct->index) {
1372         default:
1373                 error(EFAIL, "Command not implemented");
1374                 break;
1375         case CMclose:
1376                 procctlclosefiles(p, 0, atoi(cb->f[1]));
1377                 break;
1378         case CMclosefiles:
1379                 procctlclosefiles(p, 1, 0);
1380                 break;
1381 #if 0
1382                 we may want this.Let us pause a proc.case CMhang:p->hang = 1;
1383                 break;
1384 #endif
1385         case CMstraceme:
1386                 p->strace->inherit = FALSE;
1387                 break;
1388         case CMstraceall:
1389                 p->strace->inherit = TRUE;
1390                 break;
1391         case CMstrace_drop:
1392                 if (!strcmp(cb->f[1], "on"))
1393                         p->strace->drop_overflow = TRUE;
1394                 else if (!strcmp(cb->f[1], "off"))
1395                         p->strace->drop_overflow = FALSE;
1396                 else
1397                         error(EINVAL, "strace_drop takes on|off %s", cb->f[1]);
1398                 break;
1399         }
1400         poperror();
1401         kfree(cb);
1402 }
1403
1404 #if 0
1405 static int procstopped(void *a)
1406 {
1407         struct proc *p = a;
1408         return p->state == Stopped;
1409 }
1410
1411 static int
1412 procctlmemio(struct proc *p, uintptr_t offset, int n, void *va, int read)
1413 {
1414         KMap *k;
1415         Pte *pte;
1416         Page *pg;
1417         Segment *s;
1418         uintptr_t soff, l;                      /* hmmmm */
1419         uint8_t *b;
1420         uintmem pgsz;
1421
1422         for (;;) {
1423                 s = seg(p, offset, 1);
1424                 if (s == 0)
1425                         error(EINVAL, ERROR_FIXME);
1426
1427                 if (offset + n >= s->top)
1428                         n = s->top - offset;
1429
1430                 if (!read && (s->type & SG_TYPE) == SG_TEXT)
1431                         s = txt2data(p, s);
1432
1433                 s->steal++;
1434                 soff = offset - s->base;
1435                 if (waserror()) {
1436                         s->steal--;
1437                         nexterror();
1438                 }
1439                 if (fixfault(s, offset, read, 0, s->color) == 0)
1440                         break;
1441                 poperror();
1442                 s->steal--;
1443         }
1444         poperror();
1445         pte = s->map[soff / PTEMAPMEM];
1446         if (pte == 0)
1447                 panic("procctlmemio");
1448         pgsz = m->pgsz[s->pgszi];
1449         pg = pte->pages[(soff & (PTEMAPMEM - 1)) / pgsz];
1450         if (pagedout(pg))
1451                 panic("procctlmemio1");
1452
1453         l = pgsz - (offset & (pgsz - 1));
1454         if (n > l)
1455                 n = l;
1456
1457         k = kmap(pg);
1458         if (waserror()) {
1459                 s->steal--;
1460                 kunmap(k);
1461                 nexterror();
1462         }
1463         b = (uint8_t *) VA(k);
1464         b += offset & (pgsz - 1);
1465         if (read == 1)
1466                 memmove(va, b, n);      /* This can fault */
1467         else
1468                 memmove(b, va, n);
1469         poperror();
1470         kunmap(k);
1471
1472         /* Ensure the process sees text page changes */
1473         if (s->flushme)
1474                 memset(pg->cachectl, PG_TXTFLUSH, sizeof(pg->cachectl));
1475
1476         s->steal--;
1477
1478         if (read == 0)
1479                 p->newtlb = 1;
1480
1481         return n;
1482 }
1483
1484 static Segment *txt2data(struct proc *p, Segment * s)
1485 {
1486         int i;
1487         Segment *ps;
1488
1489         ps = newseg(SG_DATA, s->base, s->size);
1490         ps->image = s->image;
1491         kref_get(&ps->image->ref, 1);
1492         ps->fstart = s->fstart;
1493         ps->flen = s->flen;
1494         ps->flushme = 1;
1495
1496         qlock(&p->seglock);
1497         for (i = 0; i < NSEG; i++)
1498                 if (p->seg[i] == s)
1499                         break;
1500         if (i == NSEG)
1501                 panic("segment gone");
1502
1503         qunlock(&s->lk);
1504         putseg(s);
1505         qlock(&ps->lk);
1506         p->seg[i] = ps;
1507         qunlock(&p->seglock);
1508
1509         return ps;
1510 }
1511
1512 Segment *data2txt(Segment * s)
1513 {
1514         Segment *ps;
1515
1516         ps = newseg(SG_TEXT, s->base, s->size);
1517         ps->image = s->image;
1518         kref_get(&ps->image->ref, 1);
1519         ps->fstart = s->fstart;
1520         ps->flen = s->flen;
1521         ps->flushme = 1;
1522
1523         return ps;
1524 }
1525 #endif