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);