From 461c2b68a16ab3314202ec7796fe7eb8a7731f2d Mon Sep 17 00:00:00 2001 From: cinap_lenrek Date: Sun, 12 Apr 2015 22:30:30 +0200 Subject: [PATCH] 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. --- sys/src/9/port/devproc.c | 2 +- sys/src/9/port/devsegment.c | 93 +++++++++++++++++++++++++++++++++---- sys/src/9/port/fault.c | 1 + sys/src/9/port/portdat.h | 1 + sys/src/9/port/segment.c | 6 ++- sys/src/9/port/sysproc.c | 1 + 6 files changed, 94 insertions(+), 10 deletions(-) diff --git a/sys/src/9/port/devproc.c b/sys/src/9/port/devproc.c index 566d81740..97a2dba5f 100644 --- a/sys/src/9/port/devproc.c +++ b/sys/src/9/port/devproc.c @@ -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: diff --git a/sys/src/9/port/devsegment.c b/sys/src/9/port/devsegment.c index bbf591320..7e5a18e72 100644 --- a/sys/src/9/port/devsegment.c +++ b/sys/src/9/port/devsegment.c @@ -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", diff --git a/sys/src/9/port/fault.c b/sys/src/9/port/fault.c index 5aff0a731..f1ce5c223 100644 --- a/sys/src/9/port/fault.c +++ b/sys/src/9/port/fault.c @@ -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; diff --git a/sys/src/9/port/portdat.h b/sys/src/9/port/portdat.h index a85dc831b..495baac93 100644 --- a/sys/src/9/port/portdat.h +++ b/sys/src/9/port/portdat.h @@ -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 */ diff --git a/sys/src/9/port/segment.c b/sys/src/9/port/segment.c index f9143f314..7adc005ea 100644 --- a/sys/src/9/port/segment.c +++ b/sys/src/9/port/segment.c @@ -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 diff --git a/sys/src/9/port/sysproc.c b/sys/src/9/port/sysproc.c index b2e017c12..2dd5fe9e6 100644 --- a/sys/src/9/port/sysproc.c +++ b/sys/src/9/port/sysproc.c @@ -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);