
a portable SG_NOEXEC segment attribute was added to allow non-executable (physical) segments. which will set the PTENOEXEC bits for putmmu(). in the future, this can be used to make non-executable stack / bss segments. the SG_DEVICE attribute was added to distinguish between mmio regions and uncached memory. only matterns on arm64. on arm, theres the issue that PTEUNCACHED would have no bits set when using the hardware bit definitions. this is the reason bcm, kw, teg2 and omap kernels use arteficial PTE constants. on zynq, the XN bit was used as a hack to give PTEUNCACHED a non-zero value and when the bit is clear then cache attributes where added to the pte. to fix this, PTECACHED constant was added. the portable mmu code in fault.c will now explicitely set PTECACHED bits for cached memory and PTEUNCACHED for uncached memory. that way the hardware bit definitions can be used everywhere.
258 lines
4.4 KiB
C
258 lines
4.4 KiB
C
/*
|
|
* 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 Ramdisk Ramdisk;
|
|
struct Ramdisk {
|
|
Segment *seg;
|
|
Segio sio;
|
|
|
|
ulong nb;
|
|
ulong ss;
|
|
ulong off;
|
|
|
|
char buf[16];
|
|
|
|
Physseg;
|
|
};
|
|
|
|
static Ramdisk rds[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(Ramdisk *rd, 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", rd->name);
|
|
return;
|
|
}
|
|
|
|
base = ramdiskalloc(base, size/BY2PG);
|
|
if(base == 0){
|
|
print("%s: allocation failed\n", rd->name);
|
|
return;
|
|
}
|
|
rd->nb = nb;
|
|
rd->ss = ss;
|
|
rd->off = off;
|
|
|
|
rd->pa = base;
|
|
rd->size = size;
|
|
rd->attr = SG_PHYSICAL | SG_CACHED | SG_NOEXEC;
|
|
}
|
|
|
|
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)
|
|
{
|
|
Ramdisk *rd;
|
|
uvlong a[3];
|
|
char *p;
|
|
int subno, n;
|
|
|
|
for(subno=0; subno<nelem(rds); subno++){
|
|
rd = &rds[subno];
|
|
if(rd->nb != 0)
|
|
continue;
|
|
|
|
snprint(rd->name = rd->buf, sizeof(rd->buf), "ramdisk%d", subno);
|
|
if((p = getconf(rd->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(rd, 0, a[0], 0);
|
|
break;
|
|
case 2: /* ramdiskX=size ss */
|
|
ramdiskinit0(rd, 0, a[0], (ulong)a[1]);
|
|
break;
|
|
case 3: /* ramdiskX=base size ss */
|
|
ramdiskinit0(rd, a[0], a[1], (ulong)a[2]);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
static SDev*
|
|
rampnp(void)
|
|
{
|
|
SDev *sdev;
|
|
|
|
sdev = xalloc(sizeof(SDev));
|
|
if(sdev == nil)
|
|
return nil;
|
|
|
|
sdev->idno = 'Z';
|
|
sdev->ifc = &sdramifc;
|
|
sdev->nunit = nelem(rds);
|
|
|
|
return sdev;
|
|
}
|
|
|
|
static int
|
|
ramverify(SDunit *unit)
|
|
{
|
|
Ramdisk *rd = &rds[unit->subno];
|
|
|
|
if(rd->nb == 0)
|
|
return 0;
|
|
|
|
unit->inquiry[0] = 0;
|
|
unit->inquiry[1] = 0;
|
|
unit->inquiry[4] = sizeof unit->inquiry - 4;
|
|
strcpy((char*)unit->inquiry+8, rd->name);
|
|
|
|
return 1;
|
|
}
|
|
|
|
static int
|
|
ramonline(SDunit *unit)
|
|
{
|
|
Ramdisk *rd = &rds[unit->subno];
|
|
|
|
if(unit->sectors != 0)
|
|
return 1;
|
|
|
|
rd->seg = newseg(rd->attr, UTZERO, rd->size/BY2PG);
|
|
if(rd->seg == nil)
|
|
return 0;
|
|
rd->seg->pseg = rd;
|
|
unit->sectors = rd->nb;
|
|
unit->secsize = rd->ss;
|
|
|
|
return 2;
|
|
}
|
|
|
|
static int
|
|
ramrctl(SDunit *unit, char *p, int l)
|
|
{
|
|
Ramdisk *rd = &rds[unit->subno];
|
|
|
|
return snprint(p, l, "geometry %llud %ld\nalignment %lud %lud\n",
|
|
unit->sectors, unit->secsize,
|
|
(ulong)BY2PG, rd->off / unit->secsize);
|
|
}
|
|
|
|
static long
|
|
rambio(SDunit *unit, int, int write, void *data, long nb, uvlong bno)
|
|
{
|
|
Ramdisk *rd = &rds[unit->subno];
|
|
long secsize = unit->secsize;
|
|
|
|
return segio(&rd->sio, rd->seg, data, nb*secsize, bno*secsize + rd->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,
|
|
.verify = ramverify,
|
|
.online = ramonline,
|
|
.rctl = ramrctl,
|
|
.bio = rambio,
|
|
.rio = ramrio,
|
|
};
|