devram.c - vx32 - Local 9vx git repository for patches.
 (HTM) git clone git://r-36.net/vx32
 (DIR) Log
 (DIR) Files
 (DIR) Refs
       ---
       devram.c (6712B)
       ---
            1 #include        "u.h"
            2 #include        "lib.h"
            3 #include        "mem.h"
            4 #include        "dat.h"
            5 #include        "fns.h"
            6 #include        "error.h"
            7 
            8 #include        "netif.h"
            9 
           10 typedef struct Ram        Ram;
           11 struct Ram
           12 {
           13         QLock lk;
           14         Ram        *next;
           15         int        ref;
           16         /* simple for now */
           17         uchar **pages;
           18         int pagecount;
           19         int size;
           20         int        qref[2];
           21         ulong        path;
           22 };
           23 
           24 struct
           25 {
           26         Lock lk;
           27         ulong        path;
           28 } ramalloc;
           29 
           30 enum
           31 {
           32         Qdir,
           33         Qdata0,
           34         Qctl,
           35 };
           36 
           37 Dirtab ramdir[] =
           38 {
           39         ".",                {Qdir,0,QTDIR},        0,                DMDIR|0500,
           40         "data",                {Qdata0},        0,                0600,
           41         "ctl",        {Qctl},        0,                0600,
           42 };
           43 #define NPIPEDIR 3
           44 
           45 static void
           46 raminit(void)
           47 {
           48 }
           49 
           50 /*
           51  *  create a ram, no streams are created until an open
           52  */
           53 static Chan*
           54 ramattach(char *spec)
           55 {
           56         Ram *p;
           57         Chan *c;
           58 
           59         c = devattach('R', spec);
           60         p = malloc(sizeof(Ram));
           61         if(p == 0)
           62                 exhausted("memory");
           63         p->ref = 1;
           64         p->size = 0;
           65         p->pagecount = 1;
           66         p->pages = mallocz(sizeof(char *), 1);
           67         p->pages[0] = mallocz(BY2PG, 1);
           68         lock(&ramalloc.lk);
           69         p->path = ++ramalloc.path;
           70         unlock(&ramalloc.lk);
           71 
           72         mkqid(&c->qid, NETQID(2*p->path, Qdir), 0, QTDIR);
           73         c->aux = p;
           74         c->dev = 0;
           75         return c;
           76 }
           77 
           78 static int
           79 ramgen(Chan *c, char *name, Dirtab *tab, int ntab, int i, Dir *dp)
           80 {
           81         Qid q;
           82         int len;
           83         Ram *p;
           84 
           85         if(i == DEVDOTDOT){
           86                 devdir(c, c->qid, "#R", 0, eve, DMDIR|0555, dp);
           87                 return 1;
           88         }
           89         i++;        /* skip . */
           90         if(tab==0 || i>=ntab)
           91                 return -1;
           92 
           93         tab += i;
           94         p = c->aux;
           95         switch((ulong)tab->qid.path){
           96         case Qdata0:
           97                 len = p->size;
           98                 break;
           99         case Qctl:
          100                 len = 0;
          101                 break;
          102         default:
          103                 len = tab->length;
          104                 break;
          105         }
          106         mkqid(&q, NETQID(NETID(c->qid.path), tab->qid.path), 0, QTFILE);
          107         devdir(c, q, tab->name, len, eve, tab->perm, dp);
          108         return 1;
          109 }
          110 
          111 
          112 static Walkqid*
          113 ramwalk(Chan *c, Chan *nc, char **name, int nname)
          114 {
          115         Walkqid *wq;
          116         Ram *p;
          117 
          118         wq = devwalk(c, nc, name, nname, ramdir, NPIPEDIR, ramgen);
          119         if(wq != nil && wq->clone != nil && wq->clone != c){
          120                 p = c->aux;
          121                 qlock(&p->lk);
          122                 p->ref++;
          123                 if(c->flag & COPEN){
          124                         print("channel open in ramwalk\n");
          125                         switch(NETTYPE(c->qid.path)){
          126                         case Qdata0:
          127                                 p->qref[0]++;
          128                                 break;
          129                         case Qctl:
          130                                 p->qref[1]++;
          131                                 break;
          132                         }
          133                 }
          134                 qunlock(&p->lk);
          135         }
          136         return wq;
          137 }
          138 
          139 static int
          140 ramstat(Chan *c, uchar *db, int n)
          141 {
          142         Ram *p;
          143         Dir dir;
          144 
          145         p = c->aux;
          146 
          147         switch(NETTYPE(c->qid.path)){
          148         case Qdir:
          149                 devdir(c, c->qid, ".", 0, eve, DMDIR|0555, &dir);
          150                 break;
          151         case Qdata0:
          152                 devdir(c, c->qid, "data", p->size, eve, 0600, &dir);
          153                 break;
          154         case Qctl:
          155                 devdir(c, c->qid, "ctl", 0, eve, 0600, &dir);
          156                 break;
          157         default:
          158                 panic("ramstat");
          159         }
          160         n = convD2M(&dir, db, n);
          161         if(n < BIT16SZ)
          162                 error(Eshortstat);
          163         return n;
          164 }
          165 
          166 /*
          167  *  if the stream doesn't exist, create it
          168  */
          169 static Chan*
          170 ramopen(Chan *c, int omode)
          171 {
          172         Ram *p;
          173 
          174         if(c->qid.type & QTDIR){
          175                 if(omode != OREAD)
          176                         error(Ebadarg);
          177                 c->mode = omode;
          178                 c->flag |= COPEN;
          179                 c->offset = 0;
          180                 return c;
          181         }
          182 
          183         p = c->aux;
          184         qlock(&p->lk);
          185         switch(NETTYPE(c->qid.path)){
          186         case Qdata0:
          187                 p->qref[0]++;
          188                 break;
          189         case Qctl:
          190                 p->qref[1]++;
          191                 break;
          192         }
          193         qunlock(&p->lk);
          194 
          195         c->mode = openmode(omode);
          196         c->flag |= COPEN;
          197         c->offset = 0;
          198         c->iounit = qiomaxatomic;
          199         return c;
          200 }
          201 
          202 static void
          203 ramclose(Chan *c)
          204 {
          205         Ram *p;
          206 
          207         p = c->aux;
          208         qlock(&p->lk);
          209 
          210         if(c->flag & COPEN){
          211                 switch(NETTYPE(c->qid.path)){
          212                 case Qdata0:
          213                         p->qref[0]--;
          214                         break;
          215                 case Qctl:
          216                         p->qref[1]--;
          217                         break;
          218                 }
          219         }
          220 
          221         /*
          222          *  free the structure on last close
          223          */
          224         p->ref--;
          225         if(p->ref == 0){
          226                 int i;
          227                 qunlock(&p->lk);
          228                 for(i = 0; i < p->pagecount; i++)
          229                         free(p->pages[i]);
          230                 free(p->pages);
          231                 free(p);
          232         } else
          233                 qunlock(&p->lk);
          234 }
          235 
          236 static long 
          237 rampageread(Ram *p, void *va, long n, vlong offset)
          238 {
          239         int i;
          240         long total, offinpage, leninpage;
          241 
          242         total = n;
          243 
          244         /* figure out what range we can actually read */
          245         if(offset > p->size)
          246                 return 0;
          247         if(offset + n > p->size) 
          248                 n = p->size - offset;
          249         /* granular copy */
          250         for(i = offset / BY2PG; n > 0; i++) {
          251                 /* i is the page */
          252                 offinpage = offset & (BY2PG - 1);
          253                 leninpage = BY2PG - offinpage;
          254                 /* unless there is too little left ... */
          255                 if(leninpage > n)
          256                         leninpage = n;
          257                 memcpy(va, p->pages[i] + offinpage, leninpage);
          258                 offset += offinpage;
          259                 n -= leninpage; 
          260                 va += leninpage;
          261         }
          262         return total;
          263 }
          264 
          265 static long
          266 ramread(Chan *c, void *va, long n, vlong offset)
          267 {
          268         Ram *p;
          269         char *buf, *s, *e;
          270 
          271         p = c->aux;
          272 
          273         switch(NETTYPE(c->qid.path)){
          274         case Qdir:
          275                 return devdirread(c, va, n, ramdir, NPIPEDIR, ramgen);
          276         case Qdata0:
          277                 return rampageread(p, va, n, offset);
          278         case Qctl:
          279                 buf = smalloc(8192);
          280                 s = buf;
          281                 e = buf + 8192;
          282                 s = seprint(s, e, "pages %p count %d ", p->pages, p->pagecount);
          283                 seprint(s, e, "size %d\n", p->size);
          284                 n = readstr(offset, va, n, buf);
          285                 free(buf);
          286                 return n;
          287         default:
          288                 panic("ramread");
          289         }
          290         return -1;        /* not reached */
          291 }
          292 
          293 /* for the range offset .. offset + n, make sure we have pages */
          294 static 
          295 void pages(Ram *p, long n, vlong offset)
          296 {
          297         int i;
          298         int newpagecount;
          299         uchar **newpages;
          300 
          301         newpagecount = (offset + n + BY2PG-1)/BY2PG;
          302         if(newpagecount > p->pagecount) {
          303                 newpages = mallocz(sizeof(char *) * newpagecount, 1);
          304                 if(!newpages)
          305                         error("No more pages in devram");
          306                 memcpy(newpages, p->pages, sizeof(char *) * p->pagecount);
          307                 free(p->pages);
          308                 p->pages = newpages;
          309                 p->pagecount = newpagecount;
          310                 /* now allocate them */
          311                 for(i = offset / BY2PG; i < newpagecount; i++) {
          312                         if(p->pages[i])
          313                                 continue;
          314                         p->pages[i] = mallocz(BY2PG, 1);
          315                 }
          316         }
          317 }
          318 
          319 static long 
          320 rampagewrite(Ram *p, void *va, long n, vlong offset)
          321 {
          322         int i;
          323         long total, offinpage, leninpage;
          324         long newsize;
          325 
          326         total = n;
          327         pages(p, n, offset);
          328         
          329         /* granular copy */
          330         newsize = offset + n;
          331         for(i = offset / BY2PG; n > 0; i++) {
          332                 /* i is the page */
          333                 offinpage = offset & (BY2PG - 1);
          334                 leninpage = BY2PG - offinpage;
          335                 /* unless there is too little left ... */
          336                 if(leninpage > n)
          337                         leninpage = n;
          338                 memcpy(p->pages[i] + offinpage, va, leninpage);
          339                 offset += leninpage;
          340                 n -= leninpage; 
          341                 va += leninpage;
          342         }
          343         p->size = newsize > p->size? newsize : p->size;
          344         return total;
          345 }
          346 static long
          347 ramwrite(Chan *c, void *va, long n, vlong offset)
          348 {
          349         Ram *p;
          350         int i;
          351         uchar **new;
          352         uchar *page;
          353 
          354         if(!islo())
          355                 print("ramwrite hi %lux\n", getcallerpc(&c));
          356         p = c->aux;
          357         switch(NETTYPE(c->qid.path)){
          358         case Qdata0:
          359                 n = rampagewrite(p, va, n, offset);
          360                 break;
          361 
          362         case Qctl:
          363                 if(strcmp(va, "free") == 0) {
          364                         new = mallocz(sizeof(char *), 1);
          365                         page = p->pages[0];
          366                         for(i = 1; i < p->pagecount; i++)
          367                                 free(p->pages[i]);
          368                         free(p->pages);
          369                         p->pages = new;
          370                         p->pages[0] = page;
          371                         p->size = 0;
          372                         p->pagecount = 1;
          373                 } else {
          374                         error("bad command");
          375                 }
          376                 break;
          377 
          378         default:
          379                 panic("ramwrite");
          380         }
          381 
          382         return n;
          383 }
          384 
          385 
          386 Dev ramdevtab = {
          387         'R',
          388         "ram",
          389 
          390         devreset,
          391         raminit,
          392         devshutdown,
          393         ramattach,
          394         ramwalk,
          395         ramstat,
          396         ramopen,
          397         devcreate,
          398         ramclose,
          399         ramread,
          400         devbread,
          401         ramwrite,
          402         devbwrite,
          403         devremove,
          404         devwstat,
          405 };