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.
This commit is contained in:
cinap_lenrek 2018-05-27 22:59:19 +02:00
parent ad7390dda8
commit 5da4f0fc0f
12 changed files with 376 additions and 85 deletions

View file

@ -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

View file

@ -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 */

View file

@ -36,6 +36,7 @@ main(void)
i8253init();
cpuidentify();
meminit();
ramdiskinit();
confinit();
xinit();
archinit();

View file

@ -106,6 +106,7 @@ misc
sdmmc pci pmmc
sdnvme pci
sdloop
sdram
uarti8250
uartisa

View file

@ -305,6 +305,7 @@ main()
i8253init();
cpuidentify();
meminit();
ramdiskinit();
confinit();
xinit();
archinit();

View file

@ -104,6 +104,7 @@ misc
sdmmc pci pmmc
sdnvme pci
sdloop
sdram
uarti8250
uartisa

View file

@ -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
*/

View file

@ -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++)

View file

@ -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

View file

@ -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);

256
sys/src/9/port/sdram.c Normal file
View file

@ -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<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,
};

View file

@ -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;