]> git.lizzy.rs Git - plan9front.git/blob - sys/src/9/port/devproc.c
b5097b1abb46fb113ae08e943190dfa630606b38
[plan9front.git] / sys / src / 9 / port / devproc.c
1 #include        "u.h"
2 #include        <trace.h>
3 #include        "tos.h"
4 #include        "../port/lib.h"
5 #include        "mem.h"
6 #include        "dat.h"
7 #include        "fns.h"
8 #include        "../port/error.h"
9 #include        "ureg.h"
10 #include        "edf.h"
11
12 enum
13 {
14         Qdir,
15         Qtrace,
16         Qargs,
17         Qctl,
18         Qfd,
19         Qfpregs,
20         Qkregs,
21         Qmem,
22         Qnote,
23         Qnoteid,
24         Qnotepg,
25         Qns,
26         Qppid,
27         Qproc,
28         Qregs,
29         Qsegment,
30         Qstatus,
31         Qtext,
32         Qwait,
33         Qprofile,
34         Qsyscall,
35 };
36
37 enum
38 {
39         CMclose,
40         CMclosefiles,
41         CMfixedpri,
42         CMhang,
43         CMkill,
44         CMnohang,
45         CMnoswap,
46         CMpri,
47         CMprivate,
48         CMprofile,
49         CMstart,
50         CMstartstop,
51         CMstartsyscall,
52         CMstop,
53         CMwaitstop,
54         CMwired,
55         CMtrace,
56         CMinterrupt,
57         CMnointerrupt,
58         /* real time */
59         CMperiod,
60         CMdeadline,
61         CMcost,
62         CMsporadic,
63         CMdeadlinenotes,
64         CMadmit,
65         CMextra,
66         CMexpel,
67         CMevent,
68 };
69
70 enum{
71         Nevents = 0x4000,
72         Emask = Nevents - 1,
73 };
74
75 #define STATSIZE        (2*KNAMELEN+12+9*12)
76 /*
77  * Status, fd, and ns are left fully readable (0444) because of their use in debugging,
78  * particularly on shared servers.
79  * Arguably, ns and fd shouldn't be readable; if you'd prefer, change them to 0000
80  */
81 Dirtab procdir[] =
82 {
83         "args",         {Qargs},        0,                      0660,
84         "ctl",          {Qctl},         0,                      0000,
85         "fd",           {Qfd},          0,                      0444,
86         "fpregs",       {Qfpregs},      sizeof(FPsave),         0000,
87         "kregs",        {Qkregs},       sizeof(Ureg),           0400,
88         "mem",          {Qmem},         0,                      0000,
89         "note",         {Qnote},        0,                      0000,
90         "noteid",       {Qnoteid},      0,                      0664,
91         "notepg",       {Qnotepg},      0,                      0000,
92         "ns",           {Qns},          0,                      0444,
93         "ppid",         {Qppid},        0,                      0444,
94         "proc",         {Qproc},        0,                      0400,
95         "regs",         {Qregs},        sizeof(Ureg),           0000,
96         "segment",      {Qsegment},     0,                      0444,
97         "status",       {Qstatus},      STATSIZE,               0444,
98         "text",         {Qtext},        0,                      0000,
99         "wait",         {Qwait},        0,                      0400,
100         "profile",      {Qprofile},     0,                      0400,
101         "syscall",      {Qsyscall},     0,                      0400,   
102 };
103
104 static
105 Cmdtab proccmd[] = {
106         CMclose,                "close",                2,
107         CMclosefiles,           "closefiles",           1,
108         CMfixedpri,             "fixedpri",             2,
109         CMhang,                 "hang",                 1,
110         CMnohang,               "nohang",               1,
111         CMnoswap,               "noswap",               1,
112         CMkill,                 "kill",                 1,
113         CMpri,                  "pri",                  2,
114         CMprivate,              "private",              1,
115         CMprofile,              "profile",              1,
116         CMstart,                "start",                1,
117         CMstartstop,            "startstop",            1,
118         CMstartsyscall,         "startsyscall",         1,
119         CMstop,                 "stop",                 1,
120         CMwaitstop,             "waitstop",             1,
121         CMwired,                "wired",                2,
122         CMtrace,                "trace",                0,
123         CMinterrupt,            "interrupt",            1,
124         CMnointerrupt,          "nointerrupt",          1,
125         CMperiod,               "period",               2,
126         CMdeadline,             "deadline",             2,
127         CMcost,                 "cost",                 2,
128         CMsporadic,             "sporadic",             1,
129         CMdeadlinenotes,        "deadlinenotes",        1,
130         CMadmit,                "admit",                1,
131         CMextra,                "extra",                1,
132         CMexpel,                "expel",                1,
133         CMevent,                "event",                1,
134 };
135
136 /* Segment type from portdat.h */
137 static char *sname[]={ "Text", "Data", "Bss", "Stack", "Shared", "Phys", };
138
139 /*
140  * Qids are, in path:
141  *       4 bits of file type (qids above)
142  *      23 bits of process slot number + 1
143  *           in vers,
144  *      32 bits of pid, for consistency checking
145  * If notepg, c->pgrpid.path is pgrp slot, .vers is noteid.
146  */
147 #define QSHIFT  5       /* location in qid of proc slot # */
148
149 #define QID(q)          ((((ulong)(q).path)&0x0000001F)>>0)
150 #define SLOT(q)         (((((ulong)(q).path)&0x07FFFFFE0)>>QSHIFT)-1)
151 #define PID(q)          ((q).vers)
152 #define NOTEID(q)       ((q).vers)
153
154 void    procctlreq(Proc*, char*, int);
155 int     procctlmemio(Proc*, uintptr, int, void*, int);
156 Chan*   proctext(Chan*, Proc*);
157 int     procstopped(void*);
158 void    mntscan(Mntwalk*, Proc*);
159 ulong   procpagecount(Proc *);
160
161 static Traceevent *tevents;
162 static Lock tlock;
163 static int topens;
164 static int tproduced, tconsumed;
165 void (*proctrace)(Proc*, int, vlong);
166
167 extern int unfair;
168
169 static void
170 profclock(Ureg *ur, Timer *)
171 {
172         Tos *tos;
173
174         if(up == 0 || up->state != Running)
175                 return;
176
177         /* user profiling clock */
178         if(userureg(ur)){
179                 tos = (Tos*)(USTKTOP-sizeof(Tos));
180                 tos->clock += TK2MS(1);
181                 segclock(ur->pc);
182         }
183 }
184
185 static int
186 procgen(Chan *c, char *name, Dirtab *tab, int, int s, Dir *dp)
187 {
188         Qid qid;
189         Proc *p;
190         char *ename;
191         Segment *q;
192         ulong pid, path, perm, len;
193
194         if(s == DEVDOTDOT){
195                 mkqid(&qid, Qdir, 0, QTDIR);
196                 devdir(c, qid, "#p", 0, eve, 0555, dp);
197                 return 1;
198         }
199
200         if(c->qid.path == Qdir){
201                 if(s == 0){
202                         strcpy(up->genbuf, "trace");
203                         mkqid(&qid, Qtrace, -1, QTFILE);
204                         devdir(c, qid, up->genbuf, 0, eve, 0444, dp);
205                         return 1;
206                 }
207
208                 if(name != nil){
209                         /* ignore s and use name to find pid */
210                         pid = strtol(name, &ename, 10);
211                         if(pid==0 || ename[0]!='\0')
212                                 return -1;
213                         s = procindex(pid);
214                         if(s < 0)
215                                 return -1;
216                 }
217                 else if(--s >= conf.nproc)
218                         return -1;
219
220                 p = proctab(s);
221                 pid = p->pid;
222                 if(pid == 0)
223                         return 0;
224                 sprint(up->genbuf, "%lud", pid);
225                 /*
226                  * String comparison is done in devwalk so name must match its formatted pid
227                 */
228                 if(name != nil && strcmp(name, up->genbuf) != 0)
229                         return -1;
230                 mkqid(&qid, (s+1)<<QSHIFT, pid, QTDIR);
231                 devdir(c, qid, up->genbuf, 0, p->user, DMDIR|0555, dp);
232                 return 1;
233         }
234         if(c->qid.path == Qtrace){
235                 strcpy(up->genbuf, "trace");
236                 mkqid(&qid, Qtrace, -1, QTFILE);
237                 devdir(c, qid, up->genbuf, 0, eve, 0444, dp);
238                 return 1;
239         }
240         if(s >= nelem(procdir))
241                 return -1;
242         if(tab)
243                 panic("procgen");
244
245         tab = &procdir[s];
246         path = c->qid.path&~(((1<<QSHIFT)-1));  /* slot component */
247
248         /* p->procmode determines default mode for files in /proc */
249         p = proctab(SLOT(c->qid));
250         perm = tab->perm;
251         if(perm == 0)
252                 perm = p->procmode;
253         else    /* just copy read bits */
254                 perm |= p->procmode & 0444;
255
256         len = tab->length;
257         switch(QID(c->qid)) {
258         case Qwait:
259                 len = p->nwait; /* incorrect size, but >0 means there's something to read */
260                 break;
261         case Qprofile:
262                 q = p->seg[TSEG];
263                 if(q != nil && q->profile != nil) {
264                         len = (q->top-q->base)>>LRESPROF;
265                         len *= sizeof(*q->profile);
266                 }
267                 break;
268         }
269
270         mkqid(&qid, path|tab->qid.path, c->qid.vers, QTFILE);
271         devdir(c, qid, tab->name, len, p->user, perm, dp);
272         return 1;
273 }
274
275 static void
276 _proctrace(Proc* p, Tevent etype, vlong ts)
277 {
278         Traceevent *te;
279
280         if (p->trace == 0 || topens == 0 ||
281                 tproduced - tconsumed >= Nevents)
282                 return;
283
284         te = &tevents[tproduced&Emask];
285         te->pid = p->pid;
286         te->etype = etype;
287         if (ts == 0)
288                 te->time = todget(nil);
289         else
290                 te->time = ts;
291         tproduced++;
292 }
293
294 static void
295 procinit(void)
296 {
297         if(conf.nproc >= (1<<(16-QSHIFT))-1)
298                 print("warning: too many procs for devproc\n");
299         addclock0link((void (*)(void))profclock, 113);  /* Relative prime to HZ */
300 }
301
302 static Chan*
303 procattach(char *spec)
304 {
305         return devattach('p', spec);
306 }
307
308 static Walkqid*
309 procwalk(Chan *c, Chan *nc, char **name, int nname)
310 {
311         return devwalk(c, nc, name, nname, 0, 0, procgen);
312 }
313
314 static int
315 procstat(Chan *c, uchar *db, int n)
316 {
317         return devstat(c, db, n, 0, 0, procgen);
318 }
319
320 /*
321  *  none can't read or write state on other
322  *  processes.  This is to contain access of
323  *  servers running as none should they be
324  *  subverted by, for example, a stack attack.
325  */
326 static void
327 nonone(Proc *p)
328 {
329         if(p == up)
330                 return;
331         if(strcmp(up->user, "none") != 0)
332                 return;
333         if(iseve())
334                 return;
335         error(Eperm);
336 }
337
338 static Chan*
339 procopen(Chan *c, int omode)
340 {
341         Proc *p;
342         Pgrp *pg;
343         Chan *tc;
344         int pid;
345
346         if(c->qid.type & QTDIR)
347                 return devopen(c, omode, 0, 0, procgen);
348
349         if(QID(c->qid) == Qtrace){
350                 if (omode != OREAD) 
351                         error(Eperm);
352                 lock(&tlock);
353                 if (waserror()){
354                         topens--;
355                         unlock(&tlock);
356                         nexterror();
357                 }
358                 if (topens++ > 0)
359                         error("already open");
360                 if (tevents == nil){
361                         tevents = (Traceevent*)malloc(sizeof(Traceevent) * Nevents);
362                         if(tevents == nil)
363                                 error(Enomem);
364                         tproduced = tconsumed = 0;
365                 }
366                 proctrace = _proctrace;
367                 unlock(&tlock);
368                 poperror();
369
370                 c->mode = openmode(omode);
371                 c->flag |= COPEN;
372                 c->offset = 0;
373                 return c;
374         }
375                 
376         p = proctab(SLOT(c->qid));
377         eqlock(&p->debug);
378         if(waserror()){
379                 qunlock(&p->debug);
380                 nexterror();
381         }
382         pid = PID(c->qid);
383         if(p->pid != pid)
384                 error(Eprocdied);
385
386         omode = openmode(omode);
387
388         switch(QID(c->qid)){
389         case Qtext:
390                 if(omode != OREAD)
391                         error(Eperm);
392                 tc = proctext(c, p);
393                 tc->offset = 0;
394                 qunlock(&p->debug);
395                 poperror();
396                 cclose(c);
397                 return tc;
398
399         case Qproc:
400         case Qkregs:
401         case Qsegment:
402         case Qprofile:
403         case Qfd:
404                 if(omode != OREAD)
405                         error(Eperm);
406                 break;
407
408         case Qnote:
409                 if(p->privatemem)
410                         error(Eperm);
411                 break;
412
413         case Qmem:
414         case Qctl:
415                 if(p->privatemem)
416                         error(Eperm);
417                 nonone(p);
418                 break;
419
420         case Qargs:
421         case Qnoteid:
422         case Qstatus:
423         case Qwait:
424         case Qregs:
425         case Qfpregs:
426         case Qsyscall:  
427         case Qppid:
428                 nonone(p);
429                 break;
430
431         case Qns:
432                 if(omode != OREAD)
433                         error(Eperm);
434                 c->aux = smalloc(sizeof(Mntwalk));
435                 break;
436
437         case Qnotepg:
438                 nonone(p);
439                 pg = p->pgrp;
440                 if(pg == nil)
441                         error(Eprocdied);
442                 if(omode!=OWRITE)
443                         error(Eperm);
444                 c->pgrpid.path = pg->pgrpid+1;
445                 c->pgrpid.vers = p->noteid;
446                 break;
447
448         default:
449                 print("procopen %#lux\n", QID(c->qid));
450                 error(Egreg);
451         }
452
453         /* Affix pid to qid */
454         if(p->state != Dead)
455                 c->qid.vers = p->pid;
456
457         /* make sure the process slot didn't get reallocated while we were playing */
458         coherence();
459         if(p->pid != pid)
460                 error(Eprocdied);
461
462         tc = devopen(c, omode, 0, 0, procgen);
463         qunlock(&p->debug);
464         poperror();
465
466         return tc;
467 }
468
469 static int
470 procwstat(Chan *c, uchar *db, int n)
471 {
472         Proc *p;
473         Dir *d;
474
475         if(c->qid.type&QTDIR)
476                 error(Eperm);
477
478         if(QID(c->qid) == Qtrace)
479                 return devwstat(c, db, n);
480                 
481         p = proctab(SLOT(c->qid));
482         nonone(p);
483         d = nil;
484
485         eqlock(&p->debug);
486         if(waserror()){
487                 qunlock(&p->debug);
488                 free(d);
489                 nexterror();
490         }
491
492         if(p->pid != PID(c->qid))
493                 error(Eprocdied);
494
495         if(strcmp(up->user, p->user) != 0 && strcmp(up->user, eve) != 0)
496                 error(Eperm);
497
498         d = smalloc(sizeof(Dir)+n);
499         n = convM2D(db, n, &d[0], (char*)&d[1]);
500         if(n == 0)
501                 error(Eshortstat);
502         if(!emptystr(d->uid) && strcmp(d->uid, p->user) != 0){
503                 if(strcmp(up->user, eve) != 0)
504                         error(Eperm);
505                 else
506                         kstrdup(&p->user, d->uid);
507         }
508         /* p->procmode determines default mode for files in /proc */
509         if(d->mode != ~0UL)
510                 p->procmode = d->mode&0777;
511
512         qunlock(&p->debug);
513         poperror();
514         free(d);
515         return n;
516 }
517
518
519 static long
520 procoffset(long offset, char *va, int *np)
521 {
522         if(offset > 0) {
523                 offset -= *np;
524                 if(offset < 0) {
525                         memmove(va, va+*np+offset, -offset);
526                         *np = -offset;
527                 }
528                 else
529                         *np = 0;
530         }
531         return offset;
532 }
533
534 static int
535 procqidwidth(Chan *c)
536 {
537         char buf[32];
538
539         return sprint(buf, "%lud", c->qid.vers);
540 }
541
542 int
543 procfdprint(Chan *c, int fd, int w, char *s, int ns)
544 {
545         int n;
546
547         if(w == 0)
548                 w = procqidwidth(c);
549         n = snprint(s, ns, "%3d %.2s %C %4ld (%.16llux %*lud %.2ux) %5ld %8lld %s\n",
550                 fd,
551                 &"r w rw"[(c->mode&3)<<1],
552                 devtab[c->type]->dc, c->dev,
553                 c->qid.path, w, c->qid.vers, c->qid.type,
554                 c->iounit, c->offset, c->path->s);
555         return n;
556 }
557
558 static int
559 procfds(Proc *p, char *va, int count, long offset)
560 {
561         Fgrp *f;
562         Chan *c;
563         char buf[256];
564         int n, i, w, ww;
565         char *a;
566
567         /* print to buf to avoid holding fgrp lock while writing to user space */
568         if(count > sizeof buf)
569                 count = sizeof buf;
570         a = buf;
571
572         eqlock(&p->debug);
573         f = p->fgrp;
574         if(f == nil || p->dot == nil){
575                 qunlock(&p->debug);
576                 return 0;
577         }
578         lock(f);
579         if(waserror()){
580                 unlock(f);
581                 qunlock(&p->debug);
582                 nexterror();
583         }
584
585         n = readstr(0, a, count, p->dot->path->s);
586         n += snprint(a+n, count-n, "\n");
587         offset = procoffset(offset, a, &n);
588         /* compute width of qid.path */
589         w = 0;
590         for(i = 0; i <= f->maxfd; i++) {
591                 c = f->fd[i];
592                 if(c == nil)
593                         continue;
594                 ww = procqidwidth(c);
595                 if(ww > w)
596                         w = ww;
597         }
598         for(i = 0; i <= f->maxfd; i++) {
599                 c = f->fd[i];
600                 if(c == nil)
601                         continue;
602                 n += procfdprint(c, i, w, a+n, count-n);
603                 offset = procoffset(offset, a, &n);
604         }
605         unlock(f);
606         qunlock(&p->debug);
607         poperror();
608
609         /* copy result to user space, now that locks are released */
610         memmove(va, buf, n);
611
612         return n;
613 }
614
615 static void
616 procclose(Chan *c)
617 {
618         if(QID(c->qid) == Qtrace && (c->flag & COPEN) != 0){
619                 lock(&tlock);
620                 if(topens > 0)
621                         topens--;
622                 if(topens == 0)
623                         proctrace = nil;
624                 unlock(&tlock);
625         }
626         if(QID(c->qid) == Qns && c->aux != 0){
627                 free(c->aux);
628                 c->aux = 0;
629         }
630 }
631
632 static void
633 int2flag(int flag, char *s)
634 {
635         if(flag == 0){
636                 *s = '\0';
637                 return;
638         }
639         *s++ = '-';
640         if(flag & MAFTER)
641                 *s++ = 'a';
642         if(flag & MBEFORE)
643                 *s++ = 'b';
644         if(flag & MCREATE)
645                 *s++ = 'c';
646         if(flag & MCACHE)
647                 *s++ = 'C';
648         *s = '\0';
649 }
650
651 static int
652 procargs(Proc *p, char *buf, int nbuf)
653 {
654         int j, k, m;
655         char *a;
656         int n;
657
658         a = p->args;
659         if(p->setargs){
660                 snprint(buf, nbuf, "%s [%s]", p->text, p->args);
661                 return strlen(buf);
662         }
663         n = p->nargs;
664         for(j = 0; j < nbuf - 1; j += m){
665                 if(n <= 0)
666                         break;
667                 if(j != 0)
668                         buf[j++] = ' ';
669                 m = snprint(buf+j, nbuf-j, "%q",  a);
670                 k = strlen(a) + 1;
671                 a += k;
672                 n -= k;
673         }
674         return j;
675 }
676
677 static int
678 eventsavailable(void *)
679 {
680         return tproduced > tconsumed;
681 }
682
683 static int
684 prochaswaitq(void *x)
685 {
686         Chan *c;
687         Proc *p;
688
689         c = (Chan *)x;
690         p = proctab(SLOT(c->qid));
691         return p->pid != PID(c->qid) || p->waitq != 0;
692 }
693
694 /*
695  * userspace can't pass negative file offset for a
696  * 64 bit kernel address, so we use 63 bit and sign
697  * extend to 64 bit.
698  */
699 static uintptr
700 off2addr(vlong off)
701 {
702         off <<= 1;
703         off >>= 1;
704         return off;
705 }
706
707 static long
708 procread(Chan *c, void *va, long n, vlong off)
709 {
710         /* NSEG*32 was too small for worst cases */
711         char *a, flag[10], *sps, *srv, statbuf[NSEG*64];
712         int i, j, m, navail, ne, rsize;
713         long l;
714         uchar *rptr;
715         uintptr addr;
716         ulong offset;
717         Confmem *cm;
718         Mntwalk *mw;
719         Proc *p;
720         Segment *sg, *s;
721         Ureg kur;
722         Waitq *wq;
723         
724         a = va;
725         offset = off;
726         if(c->qid.type & QTDIR)
727                 return devdirread(c, a, n, 0, 0, procgen);
728
729         if(QID(c->qid) == Qtrace){
730                 if(!eventsavailable(nil))
731                         return 0;
732
733                 rptr = (uchar*)va;
734                 navail = tproduced - tconsumed;
735                 if(navail > n / sizeof(Traceevent))
736                         navail = n / sizeof(Traceevent);
737                 while(navail > 0) {
738                         ne = ((tconsumed & Emask) + navail > Nevents)? 
739                                         Nevents - (tconsumed & Emask): navail;
740                         memmove(rptr, &tevents[tconsumed & Emask], 
741                                         ne * sizeof(Traceevent));
742
743                         tconsumed += ne;
744                         rptr += ne * sizeof(Traceevent);
745                         navail -= ne;
746                 }
747                 return rptr - (uchar*)va;
748         }
749
750         p = proctab(SLOT(c->qid));
751         if(p->pid != PID(c->qid))
752                 error(Eprocdied);
753
754         switch(QID(c->qid)){
755         case Qargs:
756                 eqlock(&p->debug);
757                 j = procargs(p, up->genbuf, sizeof up->genbuf);
758                 qunlock(&p->debug);
759                 if(offset >= j)
760                         return 0;
761                 if(offset+n > j)
762                         n = j-offset;
763                 memmove(a, &up->genbuf[offset], n);
764                 return n;
765         case Qsyscall:
766                 eqlock(&p->debug);
767                 if(p->syscalltrace)
768                         n = readstr(offset, a, n, p->syscalltrace);
769                 else
770                         n = 0;
771                 qunlock(&p->debug);
772                 return n;
773
774         case Qmem:
775                 addr = off2addr(off);
776                 if(addr < KZERO)
777                         return procctlmemio(p, addr, n, va, 1);
778
779                 if(!iseve())
780                         error(Eperm);
781
782                 /* validate kernel addresses */
783                 if(addr < (uintptr)end) {
784                         if(addr+n > (uintptr)end)
785                                 n = (uintptr)end - addr;
786                         memmove(a, (char*)addr, n);
787                         return n;
788                 }
789                 for(i=0; i<nelem(conf.mem); i++){
790                         cm = &conf.mem[i];
791                         /* klimit-1 because klimit might be zero! */
792                         if(cm->kbase <= addr && addr <= cm->klimit-1){
793                                 if(addr+n >= cm->klimit-1)
794                                         n = cm->klimit - addr;
795                                 memmove(a, (char*)addr, n);
796                                 return n;
797                         }
798                 }
799                 error(Ebadarg);
800
801         case Qprofile:
802                 s = p->seg[TSEG];
803                 if(s == nil || s->profile == nil)
804                         error("profile is off");
805                 i = (s->top-s->base)>>LRESPROF;
806                 i *= sizeof(*s->profile);
807                 if(offset >= i)
808                         return 0;
809                 if(offset+n > i)
810                         n = i - offset;
811                 memmove(a, ((char*)s->profile)+offset, n);
812                 return n;
813
814         case Qnote:
815                 eqlock(&p->debug);
816                 if(waserror()){
817                         qunlock(&p->debug);
818                         nexterror();
819                 }
820                 if(p->pid != PID(c->qid))
821                         error(Eprocdied);
822                 if(n < 1)       /* must accept at least the '\0' */
823                         error(Etoosmall);
824                 if(p->nnote == 0)
825                         n = 0;
826                 else {
827                         m = strlen(p->note[0].msg) + 1;
828                         if(m > n)
829                                 m = n;
830                         memmove(va, p->note[0].msg, m-1);
831                         ((char*)va)[m-1] = '\0';
832                         p->nnote--;
833                         memmove(p->note, p->note+1, p->nnote*sizeof(Note));
834                         n = m;
835                 }
836                 if(p->nnote == 0)
837                         p->notepending = 0;
838                 poperror();
839                 qunlock(&p->debug);
840                 return n;
841
842         case Qproc:
843                 if(offset >= sizeof(Proc))
844                         return 0;
845                 if(offset+n > sizeof(Proc))
846                         n = sizeof(Proc) - offset;
847                 memmove(a, ((char*)p)+offset, n);
848                 return n;
849
850         case Qregs:
851                 rptr = (uchar*)p->dbgreg;
852                 rsize = sizeof(Ureg);
853                 goto regread;
854
855         case Qkregs:
856                 memset(&kur, 0, sizeof(Ureg));
857                 setkernur(&kur, p);
858                 rptr = (uchar*)&kur;
859                 rsize = sizeof(Ureg);
860                 goto regread;
861
862         case Qfpregs:
863                 rptr = (uchar*)&p->fpsave;
864                 rsize = sizeof(FPsave);
865         regread:
866                 if(rptr == 0)
867                         error(Enoreg);
868                 if(offset >= rsize)
869                         return 0;
870                 if(offset+n > rsize)
871                         n = rsize - offset;
872                 memmove(a, rptr+offset, n);
873                 return n;
874
875         case Qstatus:
876                 if(offset >= STATSIZE)
877                         return 0;
878                 if(offset+n > STATSIZE)
879                         n = STATSIZE - offset;
880
881                 sps = p->psstate;
882                 if(sps == 0)
883                         sps = statename[p->state];
884
885                 memset(statbuf, ' ', sizeof statbuf);
886                 readstr(0, statbuf+0*KNAMELEN, KNAMELEN-1, p->text);
887                 readstr(0, statbuf+1*KNAMELEN, KNAMELEN-1, p->user);
888                 readstr(0, statbuf+2*KNAMELEN, 11, sps);
889
890                 j = 2*KNAMELEN + 12;
891                 for(i = 0; i < 6; i++) {
892                         l = p->time[i];
893                         if(i == TReal)
894                                 l = MACHP(0)->ticks - l;
895                         l = TK2MS(l);
896                         readnum(0, statbuf+j+NUMSIZE*i, NUMSIZE, l, NUMSIZE);
897                 }
898
899                 readnum(0, statbuf+j+NUMSIZE*6, NUMSIZE, procpagecount(p)*BY2PG/1024, NUMSIZE);
900                 readnum(0, statbuf+j+NUMSIZE*7, NUMSIZE, p->basepri, NUMSIZE);
901                 readnum(0, statbuf+j+NUMSIZE*8, NUMSIZE, p->priority, NUMSIZE);
902                 memmove(a, statbuf+offset, n);
903                 return n;
904
905         case Qsegment:
906                 j = 0;
907                 for(i = 0; i < NSEG; i++) {
908                         sg = p->seg[i];
909                         if(sg == 0)
910                                 continue;
911                         j += sprint(statbuf+j, "%-6s %c%c %8p %8p %4ld\n",
912                                 sname[sg->type&SG_TYPE],
913                                 sg->type&SG_RONLY ? 'R' : ' ',
914                                 sg->profile ? 'P' : ' ',
915                                 sg->base, sg->top, sg->ref);
916                 }
917                 if(offset >= j)
918                         return 0;
919                 if(offset+n > j)
920                         n = j-offset;
921                 if(n == 0 && offset == 0)
922                         exhausted("segments");
923                 memmove(a, &statbuf[offset], n);
924                 return n;
925
926         case Qwait:
927                 if(!canqlock(&p->qwaitr))
928                         error(Einuse);
929
930                 if(waserror()) {
931                         qunlock(&p->qwaitr);
932                         nexterror();
933                 }
934
935                 lock(&p->exl);
936                 while(p->waitq == 0 && p->pid == PID(c->qid)) {
937                         if(up == p && p->nchild == 0) {
938                                 unlock(&p->exl);
939                                 error(Enochild);
940                         }
941                         unlock(&p->exl);
942                         sleep(&p->waitr, prochaswaitq, c);
943                         lock(&p->exl);
944                 }
945                 if(p->pid != PID(c->qid)){
946                         unlock(&p->exl);
947                         error(Eprocdied);
948                 }
949                 wq = p->waitq;
950                 p->waitq = wq->next;
951                 p->nwait--;
952                 unlock(&p->exl);
953
954                 qunlock(&p->qwaitr);
955                 poperror();
956                 n = snprint(a, n, "%d %lud %lud %lud %q",
957                         wq->w.pid,
958                         wq->w.time[TUser], wq->w.time[TSys], wq->w.time[TReal],
959                         wq->w.msg);
960                 free(wq);
961                 return n;
962
963         case Qns:
964                 eqlock(&p->debug);
965                 if(waserror()){
966                         qunlock(&p->debug);
967                         nexterror();
968                 }
969                 if(p->pgrp == nil || p->dot == nil || p->pid != PID(c->qid))
970                         error(Eprocdied);
971                 mw = c->aux;
972                 if(mw->cddone){
973                         qunlock(&p->debug);
974                         poperror();
975                         return 0;
976                 }
977                 mntscan(mw, p);
978                 if(mw->mh == 0){
979                         mw->cddone = 1;
980                         i = snprint(a, n, "cd %s\n", p->dot->path->s);
981                         qunlock(&p->debug);
982                         poperror();
983                         return i;
984                 }
985                 int2flag(mw->cm->mflag, flag);
986                 if(strcmp(mw->cm->to->path->s, "#M") == 0){
987                         srv = srvname(mw->cm->to->mchan);
988                         i = snprint(a, n, "mount %s %s %s %s\n", flag,
989                                 srv==nil? mw->cm->to->mchan->path->s : srv,
990                                 mw->mh->from->path->s, mw->cm->spec? mw->cm->spec : "");
991                         free(srv);
992                 }else
993                         i = snprint(a, n, "bind %s %s %s\n", flag,
994                                 mw->cm->to->path->s, mw->mh->from->path->s);
995                 qunlock(&p->debug);
996                 poperror();
997                 return i;
998
999         case Qnoteid:
1000                 return readnum(offset, va, n, p->noteid, NUMSIZE);
1001         case Qppid:
1002                 return readnum(offset, va, n, p->parentpid, NUMSIZE);
1003         case Qfd:
1004                 return procfds(p, va, n, offset);
1005         }
1006         error(Egreg);
1007         return 0;               /* not reached */
1008 }
1009
1010 void
1011 mntscan(Mntwalk *mw, Proc *p)
1012 {
1013         Pgrp *pg;
1014         Mount *t;
1015         Mhead *f;
1016         int nxt, i;
1017         ulong last, bestmid;
1018
1019         pg = p->pgrp;
1020         rlock(&pg->ns);
1021
1022         nxt = 0;
1023         bestmid = ~0;
1024
1025         last = 0;
1026         if(mw->mh)
1027                 last = mw->cm->mountid;
1028
1029         for(i = 0; i < MNTHASH; i++) {
1030                 for(f = pg->mnthash[i]; f; f = f->hash) {
1031                         for(t = f->mount; t; t = t->next) {
1032                                 if(mw->mh == 0 ||
1033                                   (t->mountid > last && t->mountid < bestmid)) {
1034                                         mw->cm = t;
1035                                         mw->mh = f;
1036                                         bestmid = mw->cm->mountid;
1037                                         nxt = 1;
1038                                 }
1039                         }
1040                 }
1041         }
1042         if(nxt == 0)
1043                 mw->mh = 0;
1044
1045         runlock(&pg->ns);
1046 }
1047
1048 static long
1049 procwrite(Chan *c, void *va, long n, vlong off)
1050 {
1051         int id, m;
1052         Proc *p, *t, *et;
1053         char *a, *arg, buf[ERRMAX];
1054         ulong offset;
1055
1056         a = va;
1057         offset = off;
1058         if(c->qid.type & QTDIR)
1059                 error(Eisdir);
1060
1061         p = proctab(SLOT(c->qid));
1062
1063         /* Use the remembered noteid in the channel rather
1064          * than the process pgrpid
1065          */
1066         if(QID(c->qid) == Qnotepg) {
1067                 pgrpnote(NOTEID(c->pgrpid), va, n, NUser);
1068                 return n;
1069         }
1070
1071         eqlock(&p->debug);
1072         if(waserror()){
1073                 qunlock(&p->debug);
1074                 nexterror();
1075         }
1076         if(p->pid != PID(c->qid))
1077                 error(Eprocdied);
1078
1079         switch(QID(c->qid)){
1080         case Qargs:
1081                 if(n == 0)
1082                         error(Eshort);
1083                 if(n >= ERRMAX)
1084                         error(Etoobig);
1085                 arg = malloc(n+1);
1086                 if(arg == nil)
1087                         error(Enomem);
1088                 memmove(arg, va, n);
1089                 m = n;
1090                 if(arg[m-1] != 0)
1091                         arg[m++] = 0;
1092                 free(p->args);
1093                 p->nargs = m;
1094                 p->args = arg;
1095                 p->setargs = 1;
1096                 break;
1097
1098         case Qmem:
1099                 if(p->state != Stopped)
1100                         error(Ebadctl);
1101                 n = procctlmemio(p, off2addr(off), n, va, 0);
1102                 break;
1103
1104         case Qregs:
1105                 if(offset >= sizeof(Ureg))
1106                         n = 0;
1107                 else if(offset+n > sizeof(Ureg))
1108                         n = sizeof(Ureg) - offset;
1109                 if(p->dbgreg == 0)
1110                         error(Enoreg);
1111                 setregisters(p->dbgreg, (char*)(p->dbgreg)+offset, va, n);
1112                 break;
1113
1114         case Qfpregs:
1115                 if(offset >= sizeof(FPsave))
1116                         n = 0;
1117                 else if(offset+n > sizeof(FPsave))
1118                         n = sizeof(FPsave) - offset;
1119                 memmove((uchar*)&p->fpsave+offset, va, n);
1120                 break;
1121
1122         case Qctl:
1123                 procctlreq(p, va, n);
1124                 break;
1125
1126         case Qnote:
1127                 if(p->kp)
1128                         error(Eperm);
1129                 if(n >= ERRMAX-1)
1130                         error(Etoobig);
1131                 memmove(buf, va, n);
1132                 buf[n] = 0;
1133                 if(!postnote(p, 0, buf, NUser))
1134                         error("note not posted");
1135                 break;
1136         case Qnoteid:
1137                 if(p->kp)
1138                         error(Eperm);
1139                 id = atoi(a);
1140                 if(id <= 0)
1141                         error(Ebadarg);
1142                 if(id == p->pid) {
1143                         p->noteid = id;
1144                         break;
1145                 }
1146                 t = proctab(0);
1147                 for(et = t+conf.nproc; t < et; t++) {
1148                         if(t->state == Dead || t->kp)
1149                                 continue;
1150                         if(id == t->noteid) {
1151                                 nonone(t);
1152                                 if(strcmp(p->user, t->user) != 0)
1153                                         error(Eperm);
1154                                 p->noteid = id;
1155                                 break;
1156                         }
1157                 }
1158                 if(p->noteid != id)
1159                         error(Ebadarg);
1160                 break;
1161         default:
1162                 print("unknown qid in procwrite\n");
1163                 error(Egreg);
1164         }
1165         poperror();
1166         qunlock(&p->debug);
1167         return n;
1168 }
1169
1170 Dev procdevtab = {
1171         'p',
1172         "proc",
1173
1174         devreset,
1175         procinit,
1176         devshutdown,
1177         procattach,
1178         procwalk,
1179         procstat,
1180         procopen,
1181         devcreate,
1182         procclose,
1183         procread,
1184         devbread,
1185         procwrite,
1186         devbwrite,
1187         devremove,
1188         procwstat,
1189 };
1190
1191 Chan*
1192 proctext(Chan *c, Proc *p)
1193 {
1194         Chan *tc;
1195         Image *i;
1196         Segment *s;
1197
1198         s = p->seg[TSEG];
1199         if(s == nil)
1200                 error(Enonexist);
1201         if(p->state==Dead)
1202                 error(Eprocdied);
1203
1204         i = s->image;
1205         if(i == nil)
1206                 error(Eprocdied);
1207
1208         lock(i);
1209         if(waserror()) {
1210                 unlock(i);
1211                 nexterror();
1212         }
1213
1214         if(i->s != s)
1215                 error(Eprocdied);
1216                 
1217         tc = i->c;
1218         if(tc == nil)
1219                 error(Eprocdied);
1220
1221         if(incref(tc) == 1 || (tc->flag&COPEN) == 0 || tc->mode!=OREAD) {
1222                 cclose(tc);
1223                 error(Eprocdied);
1224         }
1225
1226         if(p->pid != PID(c->qid)) {
1227                 cclose(tc);
1228                 error(Eprocdied);
1229         }
1230
1231         unlock(i);
1232         poperror();
1233
1234         return tc;
1235 }
1236
1237 void
1238 procstopwait(Proc *p, int ctl)
1239 {
1240         int pid;
1241
1242         if(p->pdbg)
1243                 error(Einuse);
1244         if(procstopped(p) || p->state == Broken)
1245                 return;
1246         pid = p->pid;
1247         if(pid == 0)
1248                 error(Eprocdied);
1249         if(ctl != 0)
1250                 p->procctl = ctl;
1251         p->pdbg = up;
1252         qunlock(&p->debug);
1253         up->psstate = "Stopwait";
1254         if(waserror()) {
1255                 p->pdbg = 0;
1256                 qlock(&p->debug);
1257                 nexterror();
1258         }
1259         sleep(&up->sleep, procstopped, p);
1260         poperror();
1261         qlock(&p->debug);
1262         if(p->pid != pid)
1263                 error(Eprocdied);
1264 }
1265
1266 void
1267 procctlclosefiles(Proc *p, int all, int fd)
1268 {
1269         Fgrp *f;
1270         Chan *c;
1271
1272         if(fd < 0)
1273                 error(Ebadfd);
1274         f = p->fgrp;
1275         if(f == nil)
1276                 error(Eprocdied);
1277
1278         incref(f);
1279         lock(f);
1280         while(fd <= f->maxfd){
1281                 c = f->fd[fd];
1282                 if(c != nil){
1283                         f->fd[fd] = nil;
1284                         unlock(f);
1285                         qunlock(&p->debug);
1286                         cclose(c);
1287                         qlock(&p->debug);
1288                         lock(f);
1289                 }
1290                 if(!all)
1291                         break;
1292                 fd++;
1293         }
1294         unlock(f);
1295         closefgrp(f);
1296 }
1297
1298 static char *
1299 parsetime(vlong *rt, char *s)
1300 {
1301         uvlong ticks;
1302         ulong l;
1303         char *e, *p;
1304         static int p10[] = {100000000, 10000000, 1000000, 100000, 10000, 1000, 100, 10, 1};
1305
1306         if (s == nil)
1307                 return("missing value");
1308         ticks=strtoul(s, &e, 10);
1309         if (*e == '.'){
1310                 p = e+1;
1311                 l = strtoul(p, &e, 10);
1312                 if(e-p > nelem(p10))
1313                         return "too many digits after decimal point";
1314                 if(e-p == 0)
1315                         return "ill-formed number";
1316                 l *= p10[e-p-1];
1317         }else
1318                 l = 0;
1319         if (*e == '\0' || strcmp(e, "s") == 0){
1320                 ticks = 1000000000 * ticks + l;
1321         }else if (strcmp(e, "ms") == 0){
1322                 ticks = 1000000 * ticks + l/1000;
1323         }else if (strcmp(e, "µs") == 0 || strcmp(e, "us") == 0){
1324                 ticks = 1000 * ticks + l/1000000;
1325         }else if (strcmp(e, "ns") != 0)
1326                 return "unrecognized unit";
1327         *rt = ticks;
1328         return nil;
1329 }
1330
1331 void
1332 procctlreq(Proc *p, char *va, int n)
1333 {
1334         Segment *s;
1335         int npc, pri;
1336         Cmdbuf *cb;
1337         Cmdtab *ct;
1338         vlong time;
1339         char *e;
1340         void (*pt)(Proc*, int, vlong);
1341
1342         if(p->kp)       /* no ctl requests to kprocs */
1343                 error(Eperm);
1344
1345         cb = parsecmd(va, n);
1346         if(waserror()){
1347                 free(cb);
1348                 nexterror();
1349         }
1350
1351         ct = lookupcmd(cb, proccmd, nelem(proccmd));
1352
1353         switch(ct->index){
1354         case CMclose:
1355                 procctlclosefiles(p, 0, atoi(cb->f[1]));
1356                 break;
1357         case CMclosefiles:
1358                 procctlclosefiles(p, 1, 0);
1359                 break;
1360         case CMhang:
1361                 p->hang = 1;
1362                 break;
1363         case CMkill:
1364                 switch(p->state) {
1365                 case Broken:
1366                         unbreak(p);
1367                         break;
1368                 case Stopped:
1369                         p->procctl = Proc_exitme;
1370                         postnote(p, 0, "sys: killed", NExit);
1371                         ready(p);
1372                         break;
1373                 default:
1374                         p->procctl = Proc_exitme;
1375                         postnote(p, 0, "sys: killed", NExit);
1376                 }
1377                 break;
1378         case CMnohang:
1379                 p->hang = 0;
1380                 break;
1381         case CMnoswap:
1382                 p->noswap = 1;
1383                 break;
1384         case CMpri:
1385                 pri = atoi(cb->f[1]);
1386                 if(pri > PriNormal && !iseve())
1387                         error(Eperm);
1388                 procpriority(p, pri, 0);
1389                 break;
1390         case CMfixedpri:
1391                 pri = atoi(cb->f[1]);
1392                 if(pri > PriNormal && !iseve())
1393                         error(Eperm);
1394                 procpriority(p, pri, 1);
1395                 break;
1396         case CMprivate:
1397                 p->privatemem = 1;
1398                 break;
1399         case CMprofile:
1400                 s = p->seg[TSEG];
1401                 if(s == 0 || (s->type&SG_TYPE) != SG_TEXT)
1402                         error(Ebadctl);
1403                 if(s->profile != nil)
1404                         free(s->profile);
1405                 npc = (s->top-s->base)>>LRESPROF;
1406                 s->profile = malloc(npc*sizeof(*s->profile));
1407                 if(s->profile == nil)
1408                         error(Enomem);
1409                 break;
1410         case CMstart:
1411                 if(p->state != Stopped)
1412                         error(Ebadctl);
1413                 ready(p);
1414                 break;
1415         case CMstartstop:
1416                 if(p->state != Stopped)
1417                         error(Ebadctl);
1418                 p->procctl = Proc_traceme;
1419                 ready(p);
1420                 procstopwait(p, Proc_traceme);
1421                 break;
1422         case CMstartsyscall:
1423                 if(p->state != Stopped)
1424                         error(Ebadctl);
1425                 p->procctl = Proc_tracesyscall;
1426                 ready(p);
1427                 procstopwait(p, Proc_tracesyscall);
1428                 break;
1429         case CMstop:
1430                 procstopwait(p, Proc_stopme);
1431                 break;
1432         case CMwaitstop:
1433                 procstopwait(p, 0);
1434                 break;
1435         case CMwired:
1436                 procwired(p, atoi(cb->f[1]));
1437                 break;
1438         case CMtrace:
1439                 switch(cb->nf){
1440                 case 1:
1441                         p->trace ^= 1;
1442                         break;
1443                 case 2:
1444                         p->trace = (atoi(cb->f[1]) != 0);
1445                         break;
1446                 default:
1447                         error("args");
1448                 }
1449                 break;
1450         case CMinterrupt:
1451                 postnote(p, 0, nil, NUser);
1452                 break;
1453         case CMnointerrupt:
1454                 if(p->nnote == 0)
1455                         p->notepending = 0;
1456                 else
1457                         error("notes pending");
1458                 break;
1459         /* real time */
1460         case CMperiod:
1461                 if(p->edf == nil)
1462                         edfinit(p);
1463                 if(e=parsetime(&time, cb->f[1]))        /* time in ns */
1464                         error(e);
1465                 edfstop(p);
1466                 p->edf->T = time/1000;  /* Edf times are in µs */
1467                 break;
1468         case CMdeadline:
1469                 if(p->edf == nil)
1470                         edfinit(p);
1471                 if(e=parsetime(&time, cb->f[1]))
1472                         error(e);
1473                 edfstop(p);
1474                 p->edf->D = time/1000;
1475                 break;
1476         case CMcost:
1477                 if(p->edf == nil)
1478                         edfinit(p);
1479                 if(e=parsetime(&time, cb->f[1]))
1480                         error(e);
1481                 edfstop(p);
1482                 p->edf->C = time/1000;
1483                 break;
1484         case CMsporadic:
1485                 if(p->edf == nil)
1486                         edfinit(p);
1487                 p->edf->flags |= Sporadic;
1488                 break;
1489         case CMdeadlinenotes:
1490                 if(p->edf == nil)
1491                         edfinit(p);
1492                 p->edf->flags |= Sendnotes;
1493                 break;
1494         case CMadmit:
1495                 if(p->edf == 0)
1496                         error("edf params");
1497                 if(e = edfadmit(p))
1498                         error(e);
1499                 break;
1500         case CMextra:
1501                 if(p->edf == nil)
1502                         edfinit(p);
1503                 p->edf->flags |= Extratime;
1504                 break;
1505         case CMexpel:
1506                 if(p->edf)
1507                         edfstop(p);
1508                 break;
1509         case CMevent:
1510                 pt = proctrace;
1511                 if(up->trace && pt)
1512                         pt(up, SUser, 0);
1513                 break;
1514         }
1515
1516         poperror();
1517         free(cb);
1518 }
1519
1520 int
1521 procstopped(void *a)
1522 {
1523         Proc *p = a;
1524         return p->state == Stopped;
1525 }
1526
1527 ulong
1528 procpagecount(Proc *p)
1529 {
1530         Segment *s;
1531         ulong pages;
1532         int i;
1533
1534         eqlock(&p->seglock);
1535         if(waserror()){
1536                 qunlock(&p->seglock);
1537                 nexterror();
1538         }
1539         pages = 0;
1540         for(i=0; i<NSEG; i++){
1541                 if((s = p->seg[i]) != nil){
1542                         eqlock(s);
1543                         pages += mcountseg(s);
1544                         qunlock(s);
1545                 }
1546         }
1547         qunlock(&p->seglock);
1548         poperror();
1549
1550         return pages;
1551 }
1552
1553 int
1554 procctlmemio(Proc *p, uintptr offset, int n, void *va, int read)
1555 {
1556         KMap *k;
1557         Pte *pte;
1558         Page *pg;
1559         Segment *s;
1560         uintptr soff;
1561         char *a, *b;
1562         int i, l;
1563
1564         /* Only one page at a time */
1565         l = BY2PG - (offset&(BY2PG-1));
1566         if(n > l)
1567                 n = l;
1568
1569         /*
1570          * Make temporary copy to avoid fault while we have
1571          * segment locked as we would deadlock when trying
1572          * to read the calling procs memory.
1573          */
1574         a = malloc(n);
1575         if(a == nil)
1576                 error(Enomem);
1577         if(waserror()) {
1578                 free(a);
1579                 nexterror();
1580         }
1581
1582         if(!read)
1583                 memmove(a, va, n);      /* can fault */
1584
1585         for(;;) {
1586                 s = seg(p, offset, 0);
1587                 if(s == nil)
1588                         error(Ebadarg);
1589
1590                 eqlock(&p->seglock);
1591                 if(waserror()) {
1592                         qunlock(&p->seglock);
1593                         nexterror();
1594                 }
1595
1596                 for(i = 0; i < NSEG; i++) {
1597                         if(p->seg[i] == s)
1598                                 break;
1599                 }
1600                 if(i == NSEG)
1601                         error(Egreg);   /* segment gone */
1602
1603                 eqlock(s);
1604                 if(waserror()){
1605                         qunlock(s);
1606                         nexterror();
1607                 }
1608                 if(!read && (s->type&SG_TYPE) == SG_TEXT) {
1609                         s = txt2data(s);
1610                         p->seg[i] = s;
1611                 }
1612                 incref(s);
1613                 qunlock(&p->seglock);
1614                 poperror();
1615                 poperror();
1616                 /* segment s still locked, fixfault() unlocks */
1617                 if(waserror()){
1618                         putseg(s);
1619                         nexterror();
1620                 }
1621                 if(fixfault(s, offset, read, 0) == 0)
1622                         break;
1623                 putseg(s);
1624                 poperror();
1625         }
1626
1627         /*
1628          * Only access the page while segment is locked
1629          * as the proc could segfree or relocate the pte
1630          * concurrently.
1631          */ 
1632         eqlock(s);
1633         if(waserror()){
1634                 qunlock(s);
1635                 nexterror();
1636         }
1637         if(offset+n >= s->top)
1638                 n = s->top-offset;
1639         soff = offset-s->base;
1640         pte = s->map[soff/PTEMAPMEM];
1641         if(pte == nil)
1642                 error(Egreg);   /* page gone, should retry? */
1643         pg = pte->pages[(soff&(PTEMAPMEM-1))/BY2PG];
1644         if(pagedout(pg))
1645                 error(Egreg);   /* page gone, should retry?  */
1646
1647         /* Map and copy the page */
1648         k = kmap(pg);
1649         b = (char*)VA(k);
1650         b += offset&(BY2PG-1);
1651         if(read)
1652                 memmove(a, b, n);
1653         else
1654                 memmove(b, a, n);
1655         kunmap(k);
1656
1657         /* Ensure the process sees text page changes */
1658         if(s->flushme)
1659                 memset(pg->cachectl, PG_TXTFLUSH, sizeof(pg->cachectl));
1660
1661         if(!read)
1662                 p->newtlb = 1;
1663
1664         qunlock(s);
1665         poperror();
1666         putseg(s);
1667         poperror();
1668
1669         if(read)
1670                 memmove(va, a, n);      /* can fault */
1671
1672         free(a);
1673         poperror();
1674
1675         return n;
1676 }