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