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