From 5da4f0fc0f55b43815adbdbc8f2e0e26eaac84e6 Mon Sep 17 00:00:00 2001 From: cinap_lenrek Date: Sun, 27 May 2018 22:59:19 +0200 Subject: [PATCH] sdram: experimental ramdisk driver this driver makes regions of physical memory accessible as a disk. to use it, ramdiskinit() has to be called before confinit(), so that conf.mem[] banks can be reserved. currently, only pc and pc64 kernel use it, but otherwise the implementation is portable. ramdisks are not zeroed when allocated, so that the contents are preserved across warm reboots. to not waste memory, physical segments do not allocate Page structures or populate the segment pte's anymore. theres also a new SG_CHACHED attribute. --- sys/man/8/plan9.ini | 9 ++ sys/src/9/pc/dat.h | 2 - sys/src/9/pc/main.c | 1 + sys/src/9/pc/pc | 1 + sys/src/9/pc64/main.c | 1 + sys/src/9/pc64/pc64 | 1 + sys/src/9/port/fault.c | 159 +++++++++++++----------- sys/src/9/port/mkdevc | 8 +- sys/src/9/port/portdat.h | 1 + sys/src/9/port/portfns.h | 2 +- sys/src/9/port/sdram.c | 256 +++++++++++++++++++++++++++++++++++++++ sys/src/9/port/segment.c | 20 +-- 12 files changed, 376 insertions(+), 85 deletions(-) create mode 100644 sys/src/9/port/sdram.c diff --git a/sys/man/8/plan9.ini b/sys/man/8/plan9.ini index 981e43fc5..29bdb7acf 100644 --- a/sys/man/8/plan9.ini +++ b/sys/man/8/plan9.ini @@ -500,6 +500,15 @@ on AoE and .I slot to use as a root device for bootstrapping. +.SS \fLramdisk\fIX\fL=\fIsize\fP +.SS \fLramdisk\fIX\fL=\fIsize sectorsize\fP +.SS \fLramdisk\fIX\fL=\fIaddress size sectorsize\fP +This reserves physical memory as a ramdisk that will appear as an +.IR sd(3) +device. When the +.I address +argument is omited or zero, then the ramdisk will be allocated +from the top of physical memory. .SS AUDIO .SS \fLaudio\fIX\fL=\fIvalue\fP This defines a sound interface. PCI based audio devices such as diff --git a/sys/src/9/pc/dat.h b/sys/src/9/pc/dat.h index 34a1841bc..7bb2e8c6f 100644 --- a/sys/src/9/pc/dat.h +++ b/sys/src/9/pc/dat.h @@ -126,8 +126,6 @@ struct Conf ulong nimage; /* number of page cache image headers */ ulong nswap; /* number of swap pages */ int nswppo; /* max # of pageouts per segment pass */ - ulong base0; /* base of bank 0 */ - ulong base1; /* base of bank 1 */ ulong copymode; /* 0 is copy on write, 1 is copy on reference */ ulong ialloc; /* max interrupt time allocation in bytes */ ulong pipeqsize; /* size in bytes of pipe queues */ diff --git a/sys/src/9/pc/main.c b/sys/src/9/pc/main.c index 3ef3d773e..e47abdc3a 100644 --- a/sys/src/9/pc/main.c +++ b/sys/src/9/pc/main.c @@ -36,6 +36,7 @@ main(void) i8253init(); cpuidentify(); meminit(); + ramdiskinit(); confinit(); xinit(); archinit(); diff --git a/sys/src/9/pc/pc b/sys/src/9/pc/pc index 923621f91..ffdb41a4a 100644 --- a/sys/src/9/pc/pc +++ b/sys/src/9/pc/pc @@ -106,6 +106,7 @@ misc sdmmc pci pmmc sdnvme pci sdloop + sdram uarti8250 uartisa diff --git a/sys/src/9/pc64/main.c b/sys/src/9/pc64/main.c index 7e1b8449a..997322e43 100644 --- a/sys/src/9/pc64/main.c +++ b/sys/src/9/pc64/main.c @@ -305,6 +305,7 @@ main() i8253init(); cpuidentify(); meminit(); + ramdiskinit(); confinit(); xinit(); archinit(); diff --git a/sys/src/9/pc64/pc64 b/sys/src/9/pc64/pc64 index a9a672225..ca464f96b 100644 --- a/sys/src/9/pc64/pc64 +++ b/sys/src/9/pc64/pc64 @@ -104,6 +104,7 @@ misc sdmmc pci pmmc sdnvme pci sdloop + sdram uarti8250 uartisa diff --git a/sys/src/9/port/fault.c b/sys/src/9/port/fault.c index 8180747e4..eaa1d5bd1 100644 --- a/sys/src/9/port/fault.c +++ b/sys/src/9/port/fault.c @@ -5,63 +5,6 @@ #include "fns.h" #include "../port/error.h" -int -fault(uintptr addr, int read) -{ - Segment *s; - char *sps; - int pnd, attr; - - if(up == nil) - panic("fault: nil up"); - if(up->nlocks){ - Lock *l = up->lastlock; - print("fault: nlocks %d, proc %lud %s, addr %#p, lock %#p, lpc %#p\n", - up->nlocks, up->pid, up->text, addr, l, l ? l->pc : 0); - } - - pnd = up->notepending; - sps = up->psstate; - up->psstate = "Fault"; - - m->pfault++; - for(;;) { - spllo(); - - s = seg(up, addr, 1); /* leaves s locked if seg != nil */ - if(s == nil) { - up->psstate = sps; - return -1; - } - - attr = s->type; - if((attr & SG_TYPE) == SG_PHYSICAL) - attr |= s->pseg->attr; - if((attr & SG_FAULT) != 0 || !read && (attr & SG_RONLY) != 0) { - qunlock(s); - up->psstate = sps; - if(up->kp && up->nerrlab) /* for segio */ - error(Eio); - return -1; - } - - if(fixfault(s, addr, read) == 0) - break; - - splhi(); - switch(up->procctl){ - case Proc_exitme: - case Proc_exitbig: - procctl(); - } - } - - up->psstate = sps; - up->notepending |= pnd; - - return 0; -} - static void faulterror(char *s, Chan *c) { @@ -196,10 +139,7 @@ done: (*p)->txtflush = ~0; } -void (*checkaddr)(uintptr, Segment *, Page *); -uintptr addr2check; - -int +static int fixfault(Segment *s, uintptr addr, int read) { int type; @@ -276,19 +216,8 @@ fixfault(Segment *s, uintptr addr, int read) (*pg)->modref = PG_MOD|PG_REF; break; - case SG_PHYSICAL: - if(*pg == nil){ - new = smalloc(sizeof(Page)); - new->va = addr; - new->pa = s->pseg->pa+(addr-s->base); - new->ref = 1; - *pg = new; - } - /* wet floor */ case SG_FIXED: /* Never paged out */ - if (checkaddr && addr == addr2check) - (*checkaddr)(addr, s, *pg); - mmuphys = PPN((*pg)->pa) |PTEWRITE|PTEUNCACHED|PTEVALID; + mmuphys = PPN((*pg)->pa) | PTEWRITE | PTEUNCACHED | PTEVALID; (*pg)->modref = PG_MOD|PG_REF; break; } @@ -299,6 +228,90 @@ fixfault(Segment *s, uintptr addr, int read) return 0; } +static void +mapphys(Segment *s, uintptr addr, int attr) +{ + uintptr mmuphys; + Page pg = {0}; + + addr &= ~(BY2PG-1); + pg.ref = 1; + pg.va = addr; + pg.pa = s->pseg->pa+(addr-s->base); + + mmuphys = PPN(pg.pa) | PTEVALID; + if((attr & SG_RONLY) == 0) + mmuphys |= PTEWRITE; + if((attr & SG_CACHED) == 0) + mmuphys |= PTEUNCACHED; + qunlock(s); + + putmmu(addr, mmuphys, &pg); +} + +int +fault(uintptr addr, int read) +{ + Segment *s; + char *sps; + int pnd, attr; + + if(up == nil) + panic("fault: nil up"); + if(up->nlocks){ + Lock *l = up->lastlock; + print("fault: nlocks %d, proc %lud %s, addr %#p, lock %#p, lpc %#p\n", + up->nlocks, up->pid, up->text, addr, l, l ? l->pc : 0); + } + + pnd = up->notepending; + sps = up->psstate; + up->psstate = "Fault"; + + m->pfault++; + for(;;) { + spllo(); + + s = seg(up, addr, 1); /* leaves s locked if seg != nil */ + if(s == nil) { + up->psstate = sps; + return -1; + } + + attr = s->type; + if((attr & SG_TYPE) == SG_PHYSICAL) + attr |= s->pseg->attr; + + if((attr & SG_FAULT) != 0 || !read && (attr & SG_RONLY) != 0) { + qunlock(s); + up->psstate = sps; + if(up->kp && up->nerrlab) /* for segio */ + error(Eio); + return -1; + } + + if((attr & SG_TYPE) == SG_PHYSICAL){ + mapphys(s, addr, attr); + break; + } + + if(fixfault(s, addr, read) == 0) + break; + + splhi(); + switch(up->procctl){ + case Proc_exitme: + case Proc_exitbig: + procctl(); + } + } + + up->psstate = sps; + up->notepending |= pnd; + + return 0; +} + /* * Called only in a system call */ diff --git a/sys/src/9/port/mkdevc b/sys/src/9/port/mkdevc index 004bc4f41..283c69a27 100755 --- a/sys/src/9/port/mkdevc +++ b/sys/src/9/port/mkdevc @@ -43,9 +43,11 @@ collect && section == "misc"{ arch[narch++] = $1; else if($1 ~ "^ad.*") adifc[nadifc++] = $1; - else if($1 ~ "^sd.*") + else if($1 ~ "^sd.*"){ sdifc[nsdifc++] = $1; - else if($1 ~ "^uart.*") + if($1 == "sdram") + ramdisk = 1; + }else if($1 ~ "^uart.*") physuart[nphysuart++] = substr($1, 5, length($1)-4) "physuart"; else if($1 ~ "^vga.*"){ if(NF == 1) @@ -136,6 +138,8 @@ END{ printf "\t&%sifc,\n", sdifc[i]; printf "\tnil,\n};\n\n"; } + if(!ramdisk) + printf "void ramdiskinit(void)\n{\n}\n\n"; if(devuart){ for(i = 0; i < nphysuart; i++) diff --git a/sys/src/9/port/portdat.h b/sys/src/9/port/portdat.h index 059af4e60..3f4ec4e75 100644 --- a/sys/src/9/port/portdat.h +++ b/sys/src/9/port/portdat.h @@ -373,6 +373,7 @@ enum SG_RONLY = 0040, /* Segment is read only */ SG_CEXEC = 0100, /* Detach at exec */ SG_FAULT = 0200, /* Fault on access */ + SG_CACHED = 0400, }; #define PG_ONSWAP 1 diff --git a/sys/src/9/port/portfns.h b/sys/src/9/port/portfns.h index 5f60c1b9e..004017145 100644 --- a/sys/src/9/port/portfns.h +++ b/sys/src/9/port/portfns.h @@ -109,7 +109,6 @@ int fault(uintptr, int); void fdclose(int, int); Chan* fdtochan(int, int, int, int); int findmount(Chan**, Mhead**, int, int, Qid); -int fixfault(Segment*, uintptr, int); void flushmmu(void); void forceclosefgrp(void); void forkchild(Proc*, Ureg*); @@ -284,6 +283,7 @@ int qwrite(Queue*, void*, int); void qnoblock(Queue*, int); void randominit(void); ulong randomread(void*, ulong); +void ramdiskinit(void); void rdb(void); long readblist(Block*, uchar*, long, ulong); int readnum(ulong, char*, ulong, ulong, int); diff --git a/sys/src/9/port/sdram.c b/sys/src/9/port/sdram.c new file mode 100644 index 000000000..2853c1afd --- /dev/null +++ b/sys/src/9/port/sdram.c @@ -0,0 +1,256 @@ +/* + * ramdisk driver + */ + +#include "u.h" +#include "../port/lib.h" +#include "../port/error.h" +#include "mem.h" +#include "dat.h" +#include "fns.h" +#include "io.h" + +#include "../port/sd.h" + +typedef struct Ctlr Ctlr; +struct Ctlr { + SDev *dev; + Segment *seg; + Segio sio; + + ulong nb; + ulong ss; + ulong off; + + char buf[16]; + + Physseg; +}; + +static Ctlr ctlrs[4]; + +extern SDifc sdramifc; + +static uvlong +ramdiskalloc(uvlong base, ulong pages) +{ + uvlong limit, mbase, mlimit; + int i, j; + + if(pages == 0) + return 0; + + if(base == 0){ + /* allocate pages from the end of memoy banks */ + for(i=nelem(conf.mem)-1; i>=0; i--) + if(conf.mem[i].npage >= pages){ + conf.mem[i].npage -= pages; + return (uvlong)conf.mem[i].base + (uvlong)conf.mem[i].npage*BY2PG; + } + return 0; + } + + /* exclude pages from memory banks */ + limit = base + (uvlong)pages*BY2PG; + for(i=0; i= mlimit || limit <= mbase) + continue; + if(base >= mbase) + conf.mem[i].npage = (base - mbase) / BY2PG; + if(limit < mlimit){ + for(j=0; jname); + return; + } + + base = ramdiskalloc(base, size/BY2PG); + if(base == 0){ + print("%s: allocation failed\n", ctlr->name); + return; + } + ctlr->nb = nb; + ctlr->ss = ss; + ctlr->off = off; + ctlr->pa = base; + ctlr->size = size; + print("%s: %llux+%lud %llud %lud (%lud sectors)\n", + ctlr->name, (uvlong)ctlr->pa, ctlr->off, (uvlong)ctlr->size, ctlr->ss, ctlr->nb); +} + +static vlong +getsizenum(char **p) +{ + vlong v = strtoll(*p, p, 0); + switch(**p){ + case 'T': case 't': v <<= 10; + case 'G': case 'g': v <<= 10; + case 'M': case 'm': v <<= 10; + case 'K': case 'k': v <<= 10; + (*p)++; + } + return v; +} + +void +ramdiskinit(void) +{ + Ctlr *ctlr; + uvlong a[3]; + char *p; + int ctlrno, n; + + for(ctlrno=0; ctlrnonb != 0) + continue; + + snprint(ctlr->name = ctlr->buf, sizeof(ctlr->buf), "ramdisk%d", ctlrno); + if((p = getconf(ctlr->name)) == nil) + continue; + + for(n = 0; n < nelem(a); n++){ + while(*p == ' ' || *p == '\t') + p++; + if(*p == 0) + break; + a[n] = getsizenum(&p); + switch(*p){ + case '-': case '+': + a[n] += getsizenum(&p); + break; + } + } + switch(n){ + case 1: /* ramdiskX=size */ + ramdiskinit0(ctlr, 0, a[0], 0); + break; + case 2: /* ramdiskX=size ss */ + ramdiskinit0(ctlr, 0, a[0], (ulong)a[1]); + break; + case 3: /* ramdiskX=base size ss */ + ramdiskinit0(ctlr, a[0], a[1], (ulong)a[2]); + break; + } + } +} + +static SDev* +rampnp(void) +{ + SDev *sdev; + Ctlr *ctlr; + + for(ctlr = ctlrs; ctlr < &ctlrs[nelem(ctlrs)]; ctlr++){ + if(ctlr->nb == 0 || ctlr->dev != nil) + continue; + sdev = malloc(sizeof(SDev)); + if(sdev == nil) + break; + sdev->idno = 'Z'; + sdev->ifc = &sdramifc; + sdev->nunit = 1; + sdev->ctlr = ctlr; + ctlr->dev = sdev; + return sdev; + } + return nil; +} + +static int +ramenable(SDev* dev) +{ + Ctlr *ctlr = dev->ctlr; + + ctlr->attr = SG_CACHED; + ctlr->seg = newseg(SG_PHYSICAL, UTZERO, ctlr->size/BY2PG); + if(ctlr->seg == nil) + return 0; + ctlr->seg->pseg = ctlr; + return 1; +} + +static int +ramverify(SDunit*) +{ + return 1; +} + +static int +ramonline(SDunit *unit) +{ + Ctlr *ctlr = unit->dev->ctlr; + unit->sectors = ctlr->nb; + unit->secsize = ctlr->ss; + return 1; +} + +static int +ramrctl(SDunit *unit, char *p, int l) +{ + return snprint(p, l, "geometry %llud %ld\n", + unit->sectors, unit->secsize); +} + +static long +rambio(SDunit *unit, int, int write, void *data, long nb, uvlong bno) +{ + Ctlr *ctlr = unit->dev->ctlr; + long secsize = unit->secsize; + return segio(&ctlr->sio, ctlr->seg, data, nb*secsize, bno*secsize + ctlr->off, !write); +} + +static int +ramrio(SDreq *r) +{ + int i, rw, count; + uvlong lba; + + if((i = sdfakescsi(r)) != SDnostatus) + return r->status = i; + if((i = sdfakescsirw(r, &lba, &count, &rw)) != SDnostatus) + return i; + r->rlen = rambio(r->unit, r->lun, rw == SDwrite, r->data, count, lba); + return r->status = SDok; +} + +SDifc sdramifc = { + .name = "ram", + .pnp = rampnp, + .enable = ramenable, + .verify = ramverify, + .online = ramonline, + .rctl = ramrctl, + .bio = rambio, + .rio = ramrio, +}; diff --git a/sys/src/9/port/segment.c b/sys/src/9/port/segment.c index ca67c4b56..eedbb7b14 100644 --- a/sys/src/9/port/segment.c +++ b/sys/src/9/port/segment.c @@ -64,6 +64,9 @@ newseg(int type, uintptr base, ulong size) s->sema.prev = &s->sema; s->sema.next = &s->sema; + if((type & SG_TYPE) == SG_PHYSICAL) + return s; + mapsize = ROUND(size, PTEPERTAB)/PTEPERTAB; if(mapsize > nelem(s->ssegmap)){ s->map = malloc(mapsize*sizeof(Pte*)); @@ -104,13 +107,16 @@ putseg(Segment *s) } else if(decref(s) != 0) return; - emap = &s->map[s->mapsize]; - for(pte = s->map; pte < emap; pte++) - if(*pte != nil) - freepte(s, *pte); + if(s->mapsize > 0){ + emap = &s->map[s->mapsize]; + for(pte = s->map; pte < emap; pte++) + if(*pte != nil) + freepte(s, *pte); + + if(s->map != s->ssegmap) + free(s->map); + } - if(s->map != s->ssegmap) - free(s->map); if(s->profile != nil) free(s->profile); @@ -212,7 +218,7 @@ segpage(Segment *s, Page *p) uintptr soff; Page **pg; - if(p->va < s->base || p->va >= s->top) + if(p->va < s->base || p->va >= s->top || s->mapsize == 0) panic("segpage"); soff = p->va - s->base;