AHCI: Replace MMIO accesses with helper functions
[akaros.git] / kern / drivers / dev / proc.c
index cbf96b0..28c0522 100644 (file)
@@ -50,6 +50,7 @@ enum {
        Qfd,
        Qfpregs,
        Qkregs,
+       Qmaps,
        Qmem,
        Qnote,
        Qnoteid,
@@ -111,6 +112,7 @@ struct dirtab procdir[] = {
        {"fd", {Qfd}, 0, 0444},
        {"fpregs", {Qfpregs}, 0, 0000},
        //  {"kregs",   {Qkregs},   sizeof(Ureg),       0600},
+       {"maps", {Qmaps}, 0, 0000},
        {"mem", {Qmem}, 0, 0000},
        {"note", {Qnote}, 0, 0000},
        {"noteid", {Qnoteid}, 0, 0664},
@@ -272,12 +274,12 @@ procgen(struct chan *c, char *name, struct dirtab *tab, int unused, int s,
                 */
                if (name != NULL && strcmp(name, get_cur_genbuf()) != 0) {
                        printk("pid-name mismatch, name: %s, pid %d\n", name, pid);
-                       kref_put(&p->p_kref);
+                       proc_decref(p);
                        return -1;
                }
                mkqid(&qid, (s + 1) << QSHIFT, pid, QTDIR);
                devdir(c, qid, get_cur_genbuf(), 0, p->user, DMDIR | 0555, dp);
-               kref_put(&p->p_kref);
+               proc_decref(p);
                return 1;
        }
        if (c->qid.path == Qtrace) {
@@ -329,7 +331,7 @@ procgen(struct chan *c, char *name, struct dirtab *tab, int unused, int s,
 
        mkqid(&qid, path | tab->qid.path, c->qid.vers, QTFILE);
        devdir(c, qid, tab->name, len, p->user, perm, dp);
-       kref_put(&p->p_kref);
+       proc_decref(p);
        return 1;
 }
 
@@ -419,6 +421,72 @@ static void nonone(struct proc *p)
 #endif
 }
 
+struct bm_helper {
+       void                                            *buf;
+       size_t                                          buflen;
+       size_t                                          sofar;
+};
+
+static void get_needed_sz_cb(struct vm_region *vmr, void *arg)
+{
+       struct bm_helper *bmh = (struct bm_helper*)arg;
+
+       /* ballpark estimate of a line */
+       bmh->buflen += 150;
+}
+
+static void build_maps_cb(struct vm_region *vmr, void *arg)
+{
+       struct bm_helper *bmh = (struct bm_helper*)arg;
+       size_t old_sofar;
+       char path_buf[MAX_FILENAME_SZ];
+       char *path;
+       unsigned long inode_nr;
+
+       if (vmr->vm_file) {
+               path = file_abs_path(vmr->vm_file, path_buf, sizeof(path_buf));
+               inode_nr = vmr->vm_file->f_dentry->d_inode->i_ino;
+       } else {
+               strlcpy(path_buf, "[heap]", sizeof(path_buf));
+               path = path_buf;
+               inode_nr = 0;
+       }
+
+       old_sofar = bmh->sofar;
+       bmh->sofar += snprintf(bmh->buf + bmh->sofar, bmh->buflen - bmh->sofar,
+                              "%08lx-%08lx %c%c%c%c %08x %02d:%02d %d ",
+                              vmr->vm_base, vmr->vm_end,
+                              vmr->vm_prot & PROT_READ    ? 'r' : '-',
+                              vmr->vm_prot & PROT_WRITE   ? 'w' : '-',
+                              vmr->vm_prot & PROT_EXEC    ? 'x' : '-',
+                              vmr->vm_flags & MAP_PRIVATE ? 'p' : '-',
+                              vmr->vm_file ? vmr->vm_foff : 0,
+                              vmr->vm_file ? 1 : 0,    /* VFS == 1 for major */
+                              0,
+                              inode_nr);
+       /* Align the filename to the 74th char, like Linux (73 chars so far) */
+       bmh->sofar += snprintf(bmh->buf + bmh->sofar, bmh->buflen - bmh->sofar,
+                              "%*s", 73 - (bmh->sofar - old_sofar), "");
+       bmh->sofar += snprintf(bmh->buf + bmh->sofar, bmh->buflen - bmh->sofar,
+                              "%s\n", path);
+}
+
+static struct sized_alloc *build_maps(struct proc *p)
+{
+       struct bm_helper bmh[1];
+       struct sized_alloc *sza;
+
+       /* Try to figure out the size needed: start with extra space, then add a bit
+        * for each VMR */
+       bmh->buflen = 150;
+       enumerate_vmrs(p, get_needed_sz_cb, bmh);
+       sza = sized_kzmalloc(bmh->buflen, MEM_WAIT);
+       bmh->buf = sza->buf;
+       bmh->sofar = 0;
+       enumerate_vmrs(p, build_maps_cb, bmh);
+       return sza;
+}
+
 static struct chan *procopen(struct chan *c, int omode)
 {
        ERRSTACK(2);
@@ -485,7 +553,7 @@ static struct chan *procopen(struct chan *c, int omode)
        //qlock(&p->debug);
        if (waserror()) {
                //qunlock(&p->debug);
-               kref_put(&p->p_kref);
+               proc_decref(p);
                nexterror();
        }
        pid = PID(c->qid);
@@ -504,7 +572,7 @@ static struct chan *procopen(struct chan *c, int omode)
                        tc->offset = 0;
                        poperror();
                        qunlock(&p->debug);
-                       kref_put(&p->p_kref);
+                       proc_decref(p);
                        cclose(c);
                        return tc;
 */
@@ -557,6 +625,9 @@ static struct chan *procopen(struct chan *c, int omode)
                        kref_get(&p->strace->users, 1);
                        c->aux = p->strace;
                        break;
+               case Qmaps:
+                       c->aux = build_maps(p);
+                       break;
                case Qnotepg:
                        error(ENOSYS, ERROR_FIXME);
 #if 0
@@ -589,7 +660,7 @@ static struct chan *procopen(struct chan *c, int omode)
        tc = devopen(c, omode, 0, 0, procgen);
        poperror();
        //qunlock(&p->debug);
-       kref_put(&p->p_kref);
+       proc_decref(p);
        return tc;
 }
 
@@ -614,7 +685,7 @@ static int procwstat(struct chan *c, uint8_t * db, int n)
        qlock(&p->debug);
        if (waserror()) {
                qunlock(&p->debug);
-               kref_put(&p->p_kref);
+               proc_decref(p);
                kfree(d);
                nexterror();
        }
@@ -640,7 +711,7 @@ static int procwstat(struct chan *c, uint8_t * db, int n)
 
        poperror();
        qunlock(&p->debug);
-       kref_put(&p->p_kref);
+       proc_decref(p);
        kfree(d);
 
        return n;
@@ -758,6 +829,8 @@ static void procclose(struct chan *c)
        }
        if (QID(c->qid) == Qns && c->aux != 0)
                kfree(c->aux);
+       if (QID(c->qid) == Qmaps && c->aux != 0)
+               kfree(c->aux);
        if (QID(c->qid) == Qstrace && c->aux != 0) {
                struct strace *s = c->aux;
 
@@ -832,6 +905,7 @@ static int eventsavailable(void *)
        return tproduced > tconsumed;
 }
 #endif
+
 static long procread(struct chan *c, void *va, long n, int64_t off)
 {
        ERRSTACK(1);
@@ -844,6 +918,7 @@ static long procread(struct chan *c, void *va, long n, int64_t off)
        uint8_t *rptr;
        struct mntwalk *mw;
        struct strace *s;
+       struct sized_alloc *sza;
 
        if (c->qid.type & QTDIR) {
                int nn;
@@ -867,13 +942,13 @@ static long procread(struct chan *c, void *va, long n, int64_t off)
        if ((p = pid2proc(SLOT(c->qid))) == NULL)
                error(ESRCH, "%d: no such process", SLOT(c->qid));
        if (p->pid != PID(c->qid)) {
-               kref_put(&p->p_kref);
+               proc_decref(p);
                error(ESRCH, "weird: p->pid is %d, PID(c->qid) is %d: mismatch",
                      p->pid, PID(c->qid));
        }
        switch (QID(c->qid)) {
                default:
-                       kref_put(&p->p_kref);
+                       proc_decref(p);
                        break;
                case Qstatus:{
                                /* the old code grew the stack and was hideous.
@@ -890,7 +965,7 @@ static long procread(struct chan *c, void *va, long n, int64_t off)
                                        s = seprintf(s, e, " %d trace users %d traced procs",
                                                     kref_refcnt(&p->strace->users),
                                                     kref_refcnt(&p->strace->procs));
-                               kref_put(&p->p_kref);
+                               proc_decref(p);
                                i = readstr(off, va, n, buf);
                                kfree(buf);
                                return i;
@@ -912,7 +987,7 @@ static long procread(struct chan *c, void *va, long n, int64_t off)
                                        }
                                }
                                offset += snprintf(buf + offset, buflen - offset, "}\n");
-                               kref_put(&p->p_kref);
+                               proc_decref(p);
                                n = readstr(off, va, n, buf);
                                kfree(buf);
                                return n;
@@ -921,7 +996,7 @@ static long procread(struct chan *c, void *va, long n, int64_t off)
                        //qlock(&p->debug);
                        if (waserror()) {
                                //qunlock(&p->debug);
-                               kref_put(&p->p_kref);
+                               proc_decref(p);
                                nexterror();
                        }
                        if (p->pgrp == NULL || p->pid != PID(c->qid))
@@ -930,7 +1005,7 @@ static long procread(struct chan *c, void *va, long n, int64_t off)
                        if (mw->cddone) {
                                poperror();
                                //qunlock(&p->debug);
-                               kref_put(&p->p_kref);
+                               proc_decref(p);
                                return 0;
                        }
                        mntscan(mw, p);
@@ -939,7 +1014,7 @@ static long procread(struct chan *c, void *va, long n, int64_t off)
                                i = snprintf(va, n, "cd %s\n", p->dot->name->s);
                                poperror();
                                //qunlock(&p->debug);
-                               kref_put(&p->p_kref);
+                               proc_decref(p);
                                return i;
                        }
                        int2flag(mw->cm->mflag, flag);
@@ -955,7 +1030,12 @@ static long procread(struct chan *c, void *va, long n, int64_t off)
                                                         mw->cm->to->name->s, mw->mh->from->name->s);
                        poperror();
                        //qunlock(&p->debug);
-                       kref_put(&p->p_kref);
+                       proc_decref(p);
+                       return i;
+               case Qmaps:
+                       sza = c->aux;
+                       i = readmem(off, va, n, sza->buf, sza->size);
+                       proc_decref(p);
                        return i;
        }
        error(EINVAL, "QID %d did not match any QIDs for #proc", QID(c->qid));
@@ -1013,7 +1093,7 @@ static long procwrite(struct chan *c, void *va, long n, int64_t off)
                error(ESRCH, ERROR_FIXME);
 
        if (waserror()) {
-               kref_put(&p->p_kref);
+               proc_decref(p);
                nexterror();
        }
        if (p->pid != PID(c->qid))
@@ -1078,7 +1158,7 @@ static long procwrite(struct chan *c, void *va, long n, int64_t off)
                        error(EFAIL, "unknown qid %#llux in procwrite\n", c->qid.path);
        }
        poperror();
-       kref_put(&p->p_kref);
+       proc_decref(p);
        return n;
 }