ref: 461c2b68a16ab3314202ec7796fe7eb8a7731f2d
parent: aadbcf0a32c92b1ba4584ad9487854ede43932ca
author: cinap_lenrek <cinap_lenrek@felloff.net>
date: Sun Apr 12 18:30:30 EDT 2015
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.
--- a/sys/src/9/port/devproc.c
+++ b/sys/src/9/port/devproc.c
@@ -134,7 +134,7 @@
};
/* 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:
--- a/sys/src/9/port/devsegment.c
+++ b/sys/src/9/port/devsegment.c
@@ -56,6 +56,7 @@
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 @@
{
Qid q;
Globalseg *g;
- ulong size;
+ uintptr size;
switch(TYPE(c)) {
case Qtopdir:
@@ -328,7 +329,11 @@
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 @@
{
Cmdbuf *cb;
Globalseg *g;
- ulong va, len, top;
+ uintptr va, top, len;
if(c->qid.type == QTDIR)
error(Eperm);
@@ -376,14 +381,19 @@
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;
@@ -559,6 +569,73 @@
}
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 = {
--- a/sys/src/9/port/fault.c
+++ b/sys/src/9/port/fault.c
@@ -267,6 +267,7 @@
copypage(old, *pg);
putpage(old);
}
+ case SG_FIXED: /* Never paged out */
mmuphys = PPN((*pg)->pa) | PTEWRITE | PTEVALID;
(*pg)->modref = PG_MOD|PG_REF;
break;
--- a/sys/src/9/port/portdat.h
+++ b/sys/src/9/port/portdat.h
@@ -341,6 +341,7 @@
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 */
--- a/sys/src/9/port/segment.c
+++ b/sys/src/9/port/segment.c
@@ -156,6 +156,7 @@
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 @@
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
--- a/sys/src/9/port/sysproc.c
+++ b/sys/src/9/port/sysproc.c
@@ -751,6 +751,7 @@
case SG_DATA:
case SG_STACK:
case SG_PHYSICAL:
+ case SG_FIXED:
error(Ebadarg);
default:
return (uintptr)ibrk(va_arg(list, uintptr), i);