ref: 5da4f0fc0f55b43815adbdbc8f2e0e26eaac84e6
parent: ad7390dda820db424821b19c572a44b4cc0838e8
author: cinap_lenrek <cinap_lenrek@felloff.net>
date: Sun May 27 18:59:19 EDT 2018
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.
--- a/sys/man/8/plan9.ini
+++ b/sys/man/8/plan9.ini
@@ -500,6 +500,15 @@
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
--- a/sys/src/9/pc/dat.h
+++ b/sys/src/9/pc/dat.h
@@ -126,8 +126,6 @@
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 */
--- a/sys/src/9/pc/main.c
+++ b/sys/src/9/pc/main.c
@@ -36,6 +36,7 @@
i8253init();
cpuidentify();
meminit();
+ ramdiskinit();
confinit();
xinit();
archinit();
--- a/sys/src/9/pc/pc
+++ b/sys/src/9/pc/pc
@@ -106,6 +106,7 @@
sdmmc pci pmmc
sdnvme pci
sdloop
+ sdram
uarti8250
uartisa
--- a/sys/src/9/pc64/main.c
+++ b/sys/src/9/pc64/main.c
@@ -305,6 +305,7 @@
i8253init();
cpuidentify();
meminit();
+ ramdiskinit();
confinit();
xinit();
archinit();
--- a/sys/src/9/pc64/pc64
+++ b/sys/src/9/pc64/pc64
@@ -104,6 +104,7 @@
sdmmc pci pmmc
sdnvme pci
sdloop
+ sdram
uarti8250
uartisa
--- 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 @@
(*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 @@
(*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;
}
@@ -295,6 +224,90 @@
qunlock(s);
putmmu(addr, mmuphys, *pg);
+
+ 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;
}
--- a/sys/src/9/port/mkdevc
+++ b/sys/src/9/port/mkdevc
@@ -43,9 +43,11 @@
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 @@
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++)
--- a/sys/src/9/port/portdat.h
+++ b/sys/src/9/port/portdat.h
@@ -373,6 +373,7 @@
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
--- a/sys/src/9/port/portfns.h
+++ b/sys/src/9/port/portfns.h
@@ -109,7 +109,6 @@
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 @@
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);
--- /dev/null
+++ b/sys/src/9/port/sdram.c
@@ -1,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<nelem(conf.mem); i++){
+ mbase = conf.mem[i].base;
+ mlimit = mbase + (uvlong)conf.mem[i].npage*BY2PG;
+ if(base >= mlimit || limit <= mbase)
+ continue;
+ if(base >= mbase)
+ conf.mem[i].npage = (base - mbase) / BY2PG;
+ if(limit < mlimit){
+ for(j=0; j<nelem(conf.mem); j++){
+ if(conf.mem[j].npage == 0){
+ conf.mem[j].base = limit;
+ conf.mem[j].npage = (mlimit - limit) / BY2PG;
+ break;
+ }
+ }
+ }
+ }
+
+ return base;
+}
+
+static void
+ramdiskinit0(Ctlr *ctlr, uvlong base, uvlong size, ulong ss)
+{
+ ulong nb, off;
+
+ if(ss == 0)
+ ss = 512;
+
+ nb = size / ss;
+ off = base & (BY2PG-1);
+ size = (uvlong)nb*ss;
+ size += off;
+ size += BY2PG-1;
+ size &= ~(BY2PG-1);
+ base &= ~(BY2PG-1);
+
+ if(size == 0 || size != (uintptr)size){
+ print("%s: invalid parameters\n", ctlr->name);
+ 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; ctlrno<nelem(ctlrs); ctlrno++){
+ ctlr = &ctlrs[ctlrno];
+ if(ctlr->nb != 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,
+};
--- a/sys/src/9/port/segment.c
+++ b/sys/src/9/port/segment.c
@@ -64,6 +64,9 @@
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 @@
} 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 @@
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;