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