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