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