kernel: fixed segment support (for fpga experiments)

fixed segments are continuous in physical memory but
allocated in user pages. unlike shared segments, they
are not allocated on demand but the pages are allocated
on creation time (devsegment). fixed segments are
never swapped out, segfreed or resized and can only be
destroyed as a whole.

the physical base address can be discovered by userspace
reading the ctl file in devsegment.
This commit is contained in:
cinap_lenrek 2015-04-12 22:30:30 +02:00
parent aadbcf0a32
commit 461c2b68a1
6 changed files with 94 additions and 10 deletions

View file

@ -134,7 +134,7 @@ Cmdtab proccmd[] = {
};
/* Segment type from portdat.h */
static char *sname[]={ "Text", "Data", "Bss", "Stack", "Shared", "Phys", };
static char *sname[]={ "Text", "Data", "Bss", "Stack", "Shared", "Phys", "Fixed", };
/*
* Qids are, in path:

View file

@ -56,6 +56,7 @@ static Segment* globalsegattach(Proc *p, char *name);
static int cmddone(void*);
static void segmentkproc(void*);
static void docmd(Globalseg *g, int cmd);
static Segment* fixedseg(uintptr va, ulong len);
/*
* returns with globalseg incref'd
@ -98,7 +99,7 @@ segmentgen(Chan *c, char*, Dirtab*, int, int s, Dir *dp)
{
Qid q;
Globalseg *g;
ulong size;
uintptr size;
switch(TYPE(c)) {
case Qtopdir:
@ -328,7 +329,11 @@ segmentread(Chan *c, void *a, long n, vlong voff)
g = c->aux;
if(g->s == nil)
error("segment not yet allocated");
sprint(buf, "va %#lux %#lux\n", g->s->base, g->s->top-g->s->base);
if(g->s->type&SG_TYPE == SG_FIXED)
sprint(buf, "va %#p %#p fixed %#p\n", g->s->base, g->s->top-g->s->base,
g->s->map[0]->pages[0]->pa);
else
sprint(buf, "va %#p %#p\n", g->s->base, g->s->top-g->s->base);
return readstr(voff, a, n, buf);
case Qdata:
g = c->aux;
@ -362,7 +367,7 @@ segmentwrite(Chan *c, void *a, long n, vlong voff)
{
Cmdbuf *cb;
Globalseg *g;
ulong va, len, top;
uintptr va, top, len;
if(c->qid.type == QTDIR)
error(Eperm);
@ -376,14 +381,19 @@ segmentwrite(Chan *c, void *a, long n, vlong voff)
error("already has a virtual address");
if(cb->nf < 3)
error(Ebadarg);
va = strtoul(cb->f[1], 0, 0);
len = strtoul(cb->f[2], 0, 0);
va = strtoull(cb->f[1], 0, 0);
len = strtoull(cb->f[2], 0, 0);
top = PGROUND(va + len);
va = va&~(BY2PG-1);
len = (top - va) / BY2PG;
if(len == 0)
if(va == 0 || top > USTKTOP || top <= va)
error(Ebadarg);
g->s = newseg(SG_SHARED, va, len);
len = (top - va) / BY2PG;
if(cb->nf >= 4 && strcmp(cb->f[3], "fixed") == 0){
if(!iseve())
error(Eperm);
g->s = fixedseg(va, len);
} else
g->s = newseg(SG_SHARED, va, len);
} else
error(Ebadctl);
break;
@ -561,6 +571,73 @@ segmentkproc(void *arg)
pexit("done", 1);
}
/*
* allocate a fixed segment with sequential run of of adjacent
* user memory pages.
*/
static Segment*
fixedseg(uintptr va, ulong len)
{
KMap *k;
Segment *s;
Page **f, *p;
ulong n, i, j;
int color;
s = newseg(SG_FIXED, va, len);
if(waserror()){
putseg(s);
nexterror();
}
lock(&palloc);
i = 0;
p = palloc.pages;
color = getpgcolor(va);
for(n = palloc.user; n >= len; n--, p++){
if(p->ref != 0 || i != 0 && (p[-1].pa+BY2PG) != p->pa || i == 0 && p->color != color){
Retry:
i = 0;
continue;
}
if(++i < len)
continue;
for(j = 0; j < i; j++, p--){
for(f = &palloc.head; *f != nil; f = &((*f)->next)){
if(*f == p){
*f = p->next;
goto Freed;
}
}
while(j-- > 0)
pagechainhead(++p);
goto Retry;
Freed:
palloc.freecount--;
}
unlock(&palloc);
while(i-- > 0){
p++;
p->ref = 1;
p->va = va;
p->modref = 0;
p->txtflush = ~0;
k = kmap(p);
memset((void*)VA(k), 0, BY2PG);
kunmap(k);
segpage(s, p);
va += BY2PG;
}
poperror();
return s;
}
unlock(&palloc);
error(Enomem);
return nil;
}
Dev segmentdevtab = {
'g',
"segment",

View file

@ -267,6 +267,7 @@ fixfault(Segment *s, uintptr addr, int read, int doputmmu)
copypage(old, *pg);
putpage(old);
}
case SG_FIXED: /* Never paged out */
mmuphys = PPN((*pg)->pa) | PTEWRITE | PTEVALID;
(*pg)->modref = PG_MOD|PG_REF;
break;

View file

@ -341,6 +341,7 @@ enum
SG_STACK = 03,
SG_SHARED = 04,
SG_PHYSICAL = 05,
SG_FIXED = 06,
SG_RONLY = 0040, /* Segment is read only */
SG_CEXEC = 0100, /* Detach at exec */

View file

@ -156,6 +156,7 @@ dupseg(Segment **seg, int segno, int share)
case SG_TEXT: /* New segment shares pte set */
case SG_SHARED:
case SG_PHYSICAL:
case SG_FIXED:
goto sameseg;
case SG_STACK:
@ -489,8 +490,11 @@ mfreeseg(Segment *s, uintptr start, ulong pages)
if(pages == 0)
return;
if((s->type&SG_TYPE) == SG_PHYSICAL)
switch(s->type&SG_TYPE){
case SG_PHYSICAL:
case SG_FIXED:
return;
}
/*
* we have to make sure other processors flush the

View file

@ -751,6 +751,7 @@ syssegbrk(va_list list)
case SG_DATA:
case SG_STACK:
case SG_PHYSICAL:
case SG_FIXED:
error(Ebadarg);
default:
return (uintptr)ibrk(va_arg(list, uintptr), i);