shithub: riscv

Download patch

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;