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