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