| plan 9 kernel history: overview | file list | diff list |
1994/0515/port/segment.c (diff list | history)
| 1994/0515/sys/src/9/port/segment.c:1,545 – 1994/0602/sys/src/9/port/segment.c:1,545 (short | long | prev | next) | ||
| 1991/0705 | #include "u.h" | |
| 1992/0321 | #include "../port/lib.h" | |
| 1991/0705 | #include "mem.h" #include "dat.h" #include "fns.h" | |
| 1992/0111 | #include "../port/error.h" | |
| 1991/0705 | ||
| 1993/1012 | Page* lkpage(Segment*, ulong); void lkpgfree(Page*); void imagereclaim(void); | |
| 1991/0705 | /* System specific segattach devices */ | |
| 1993/0210 | #include "io.h" | |
| 1991/0705 | #include "segment.h" #define IHASHSIZE 64 #define ihash(s) imagealloc.hash[s%IHASHSIZE] | |
| 1992/0625 | struct | |
| 1991/0705 | { Lock; Image *free; Image *hash[IHASHSIZE]; | |
| 1992/0625 | QLock ireclaim; | |
| 1991/0705 | }imagealloc; void initseg(void) { Image *i, *ie; | |
| 1992/0619 | imagealloc.free = xalloc(conf.nimage*sizeof(Image)); | |
| 1991/0705 | ie = &imagealloc.free[conf.nimage-1]; for(i = imagealloc.free; i < ie; i++) i->next = i+1; i->next = 0; } Segment * newseg(int type, ulong base, ulong size) { Segment *s; if(size > (SEGMAPSIZE*PTEPERTAB)) | |
| 1992/0114 | error(Enovmem); | |
| 1991/0705 | ||
| 1992/0619 | s = smalloc(sizeof(Segment)); s->ref = 1; s->type = type; s->base = base; s->top = base+(size*BY2PG); s->size = size; return s; | |
| 1991/0705 | } void putseg(Segment *s) { Pte **pp, **emap; Image *i; | |
| 1991/0726 | if(s == 0) return; i = s->image; | |
| 1993/0725 | if(i != 0) { | |
| 1991/0726 | lock(i); | |
| 1993/0725 | lock(s); if(i->s == s && s->ref == 1) | |
| 1991/0726 | i->s = 0; unlock(i); } | |
| 1993/0725 | else lock(s); | |
| 1991/0726 | ||
| 1993/0725 | s->ref--; if(s->ref != 0) { unlock(s); return; } | |
| 1991/0726 | ||
| 1993/0725 | qlock(&s->lk); if(i) putimage(i); | |
| 1991/1109 | ||
| 1993/0725 | emap = &s->map[SEGMAPSIZE]; for(pp = s->map; pp < emap; pp++) if(*pp) freepte(s, *pp); | |
| 1991/0705 | ||
| 1993/0725 | qunlock(&s->lk); free(s); | |
| 1991/0705 | } void relocateseg(Segment *s, ulong offset) { | |
| 1993/0810 | Page **pg, *x; Pte *pte, **p, **endpte; | |
| 1991/0705 | endpte = &s->map[SEGMAPSIZE]; | |
| 1992/0824 | for(p = s->map; p < endpte; p++) { | |
| 1993/0810 | if(*p == 0) continue; pte = *p; for(pg = pte->first; pg <= pte->last; pg++) { if(x = *pg) x->va += offset; | |
| 1991/0705 | } | |
| 1992/0824 | } | |
| 1991/0705 | } Segment* | |
| 1992/1104 | dupseg(Segment **seg, int segno, int share) | |
| 1991/0705 | { | |
| 1992/0824 | int i; | |
| 1991/0705 | Pte *pte; | |
| 1992/1104 | Segment *n, *s; | |
| 1991/0705 | ||
| 1992/0824 | SET(n); | |
| 1992/1104 | s = seg[segno]; | |
| 1991/0705 | switch(s->type&SG_TYPE) { | |
| 1994/0515 | case SG_TEXT: /* New segment shares pte set */ | |
| 1991/0705 | case SG_SHARED: case SG_PHYSICAL: | |
| 1992/0307 | case SG_SHDATA: | |
| 1991/0705 | incref(s); return s; | |
| 1991/0706 | case SG_STACK: qlock(&s->lk); | |
| 1991/0705 | n = newseg(s->type, s->base, s->size); | |
| 1992/0824 | break; | |
| 1991/0705 | ||
| 1994/0515 | case SG_BSS: /* Just copy on write */ | |
| 1992/0430 | qlock(&s->lk); if(share && s->ref == 1) { s->type = (s->type&~SG_TYPE)|SG_SHARED; incref(s); qunlock(&s->lk); return s; } n = newseg(s->type, s->base, s->size); | |
| 1992/0824 | break; | |
| 1992/0430 | ||
| 1994/0515 | case SG_DATA: /* Copy on write plus demand load info */ | |
| 1992/1104 | if(segno == TSEG) return data2txt(s); | |
| 1991/0706 | qlock(&s->lk); | |
| 1992/0430 | if(share && s->ref == 1) { s->type = (s->type&~SG_TYPE)|SG_SHDATA; incref(s); qunlock(&s->lk); return s; } | |
| 1991/0706 | n = newseg(s->type, s->base, s->size); | |
| 1991/0705 | incref(s->image); n->image = s->image; n->fstart = s->fstart; n->flen = s->flen; | |
| 1992/0824 | break; | |
| 1991/0705 | } | |
| 1992/0824 | for(i = 0; i < SEGMAPSIZE; i++) if(pte = s->map[i]) n->map[i] = ptecpy(pte); | |
| 1991/0705 | ||
| 1992/0824 | n->flushme = s->flushme; qunlock(&s->lk); return n; | |
| 1991/0705 | } void segpage(Segment *s, Page *p) { Pte **pte; ulong off; | |
| 1991/1122 | Page **pg; | |
| 1991/0705 | if(p->va < s->base || p->va >= s->top) panic("segpage"); off = p->va - s->base; pte = &s->map[off/PTEMAPMEM]; if(*pte == 0) *pte = ptealloc(); | |
| 1991/1122 | pg = &(*pte)->pages[(off&(PTEMAPMEM-1))/BY2PG]; *pg = p; if(pg < (*pte)->first) (*pte)->first = pg; if(pg > (*pte)->last) (*pte)->last = pg; | |
| 1991/0705 | } Image* attachimage(int type, Chan *c, ulong base, ulong len) { Image *i, **l; lock(&imagealloc); | |
| 1991/0724 | /* * Search the image cache for remains of the text from a previous * or currently running incarnation */ | |
| 1991/0705 | for(i = ihash(c->qid.path); i; i = i->hash) { if(c->qid.path == i->qid.path) { lock(i); | |
| 1992/0619 | if(eqqid(c->qid, i->qid) && eqqid(c->mqid, i->mqid) && c->mchan == i->mchan && c->type == i->type) { | |
| 1991/0705 | i->ref++; goto found; } unlock(i); } } | |
| 1991/0724 | /* * imagereclaim dumps pages from the free list which are cached by image * structures. This should free some image structures. */ | |
| 1991/0705 | while(!(i = imagealloc.free)) { unlock(&imagealloc); | |
| 1991/0706 | imagereclaim(); | |
| 1991/0710 | resrcwait(0); | |
| 1991/0705 | lock(&imagealloc); } imagealloc.free = i->next; lock(i); incref(c); i->c = c; i->type = c->type; i->qid = c->qid; i->mqid = c->mqid; i->mchan = c->mchan; i->ref = 1; l = &ihash(c->qid.path); i->hash = *l; *l = i; found: unlock(&imagealloc); if(i->s == 0) { | |
| 1993/0725 | /* Disaster after commit in exec */ if(waserror()) { unlock(i); pexit(Enovmem, 1); } | |
| 1991/0705 | i->s = newseg(type, base, len); i->s->image = i; | |
| 1993/0725 | poperror(); | |
| 1991/0705 | } else incref(i->s); return i; } void | |
| 1991/0706 | imagereclaim(void) { Page *p; | |
| 1992/0625 | /* Somebody is already cleaning the page cache */ if(!canqlock(&imagealloc.ireclaim)) | |
| 1991/0706 | return; | |
| 1992/0404 | lock(&palloc); for(p = palloc.head; p; p = p->next) { | |
| 1992/0822 |
| |
| 1992/0225 |
| |
| 1994/0602 | if(p->ref == 0 && p->image && canlock(p)) { if(p->ref == 0 && p->image != &swapimage) | |
| 1992/0404 | uncachepage(p); | |
| 1992/0625 | unlock(p); | |
| 1992/0314 | } | |
| 1991/0706 | } | |
| 1992/0404 | unlock(&palloc); | |
| 1992/0625 | qunlock(&imagealloc.ireclaim); | |
| 1991/0706 | } void | |
| 1991/0705 | putimage(Image *i) { Chan *c; | |
| 1992/0625 | Image *f, **l; | |
| 1991/0705 | if(i == &swapimage) return; lock(i); if(--i->ref == 0) { l = &ihash(i->qid.path); i->qid = (Qid){~0, ~0}; unlock(i); c = i->c; lock(&imagealloc); for(f = *l; f; f = f->hash) { if(f == i) { *l = i->hash; break; } l = &f->hash; } i->next = imagealloc.free; imagealloc.free = i; unlock(&imagealloc); | |
| 1992/0625 | close(c); | |
| 1991/0705 | return; } unlock(i); } long | |
| 1991/0706 | ibrk(ulong addr, int seg) | |
| 1991/0705 | { Segment *s, *ns; ulong newtop, newsize; int i; | |
| 1993/0501 | s = up->seg[seg]; | |
| 1991/0705 | if(s == 0) | |
| 1992/0114 | error(Ebadarg); | |
| 1991/0705 | if(addr == 0) return s->base; | |
| 1991/1125 | qlock(&s->lk); | |
| 1992/0824 | /* We may start with the bss overlapping the data */ | |
| 1991/0705 | if(addr < s->base) { | |
| 1993/0501 | if(seg != BSEG || up->seg[DSEG] == 0 || addr < up->seg[DSEG]->base) { | |
| 1991/0705 | qunlock(&s->lk); | |
| 1992/0114 | error(Enovmem); | |
| 1991/1125 | } | |
| 1991/0705 | addr = s->base; } newtop = PGROUND(addr); newsize = (newtop-s->base)/BY2PG; if(newtop < s->top) { mfreeseg(s, newtop, (s->top-newtop)/BY2PG); qunlock(&s->lk); | |
| 1992/1206 | flushmmu(); | |
| 1991/0705 | return 0; } for(i = 0; i < NSEG; i++) { | |
| 1993/0501 | ns = up->seg[i]; | |
| 1991/0705 | if(ns == 0 || ns == s) continue; | |
| 1992/0824 | if(newtop >= ns->base && newtop < ns->top) { | |
| 1991/0705 | qunlock(&s->lk); | |
| 1992/0824 | error(Esoverlap); | |
| 1991/0705 | } } | |
| 1992/0824 | if(newsize > (PTEMAPMEM*SEGMAPSIZE)/BY2PG) { qunlock(&s->lk); | |
| 1992/0912 | error(Enovmem); | |
| 1992/0824 | } | |
| 1991/0705 | s->top = newtop; s->size = newsize; qunlock(&s->lk); return 0; } void mfreeseg(Segment *s, ulong start, int pages) { int i, j; ulong soff; Page *pg; soff = start-s->base; j = (soff&(PTEMAPMEM-1))/BY2PG; for(i = soff/PTEMAPMEM; i < SEGMAPSIZE; i++) { if(pages <= 0) | |
| 1992/1206 | break; if(s->map[i] == 0) { pages -= PTEPERTAB-j; j = 0; continue; } while(j < PTEPERTAB) { pg = s->map[i]->pages[j]; if(pg) { putpage(pg); s->map[i]->pages[j] = 0; | |
| 1991/0705 | } | |
| 1992/1206 | if(--pages == 0) return; j++; | |
| 1991/0705 | } | |
| 1991/0726 | j = 0; | |
| 1991/0705 | } } | |
| 1994/0514 | int isoverlap(Proc *p, ulong va, int len) { int i; Segment *ns; ulong newtop; newtop = va+len; for(i = 0; i < NSEG; i++) { ns = p->seg[i]; if(ns == 0) continue; if((newtop > ns->base && newtop <= ns->top) || (va >= ns->base && va < ns->top)) return 1; } return 0; } | |
| 1991/0705 | ulong segattach(Proc *p, ulong attr, char *name, ulong va, ulong len) { int i, sno; | |
| 1994/0514 | Segment *s; Physseg *ps; | |
| 1991/0705 | ||
| 1991/1115 | USED(p); | |
| 1994/0514 | if(va != 0 && (va&KZERO) == KZERO) /* BUG: Only ok for now */ | |
| 1992/0114 | error(Ebadarg); | |
| 1991/0705 | validaddr((ulong)name, 1, 0); vmemchr(name, 0, ~0); for(sno = 0; sno < NSEG; sno++) | |
| 1994/0514 | if(p->seg[sno] == 0 && sno != ESEG) | |
| 1991/0705 | break; if(sno == NSEG) | |
| 1992/0114 | error(Enovmem); | |
| 1991/0705 | len = PGROUND(len); | |
| 1994/0514 | /* Find a hole in the address space */ if(va == 0) { va = p->seg[SSEG]->base - len; for(i = 0; i < 20; i++) { if(isoverlap(p, va, len) == 0) break; va -= len; } | |
| 1991/0705 | } | |
| 1994/0514 | va = va&~(BY2PG-1); if(isoverlap(p, va, len)) error(Esoverlap); | |
| 1991/0731 | for(ps = physseg; ps->name; ps++) | |
| 1991/0705 | if(strcmp(name, ps->name) == 0) goto found; | |
| 1992/0114 | error(Ebadarg); | |
| 1991/0705 | found: if(len > ps->size) | |
| 1992/0114 | error(Enovmem); | |
| 1991/0705 | ||
| 1993/0725 | attr &= ~SG_TYPE; /* Turn off what we are not allowed */ attr |= ps->attr; /* Copy in defaults */ | |
| 1991/0705 | s = newseg(attr, va, len/BY2PG); | |
| 1993/0210 | s->pseg = ps; | |
| 1994/0514 | p->seg[sno] = s; | |
| 1991/0705 | ||
| 1994/0514 | return va; | |
| 1991/0705 | } | |
| 1993/0919 | void pteflush(Pte *pte, int s, int e) { int i; Page *p; for(i = s; i < e; i++) { p = pte->pages[i]; | |
| 1993/1001 | if(pagedout(p) == 0) | |
| 1993/0919 | memset(p->cachectl, PG_TXTFLUSH, sizeof(p->cachectl)); } } | |
| 1991/0705 | long syssegflush(ulong *arg) { Segment *s; | |
| 1993/1001 | ulong addr, l; Pte *pte; | |
| 1993/0919 | int chunk, ps, pe, len; | |
| 1991/0705 | ||
| 1993/0919 | addr = arg[0]; len = arg[1]; | |
| 1991/0706 | ||
| 1993/0919 | while(len > 0) { | |
| 1993/0930 | s = seg(up, addr, 1); | |
| 1993/0919 | if(s == 0) error(Ebadarg); | |
| 1991/0705 | ||
| 1993/0919 | s->flushme = 1; | |
| 1993/1001 | more: | |
| 1993/0919 | l = len; if(addr+l > s->top) l = s->top - addr; | |
| 1993/0725 | ||
| 1993/1001 | ps = addr-s->base; pte = s->map[ps/PTEMAPMEM]; ps &= PTEMAPMEM-1; pe = PTEMAPMEM; if(pe-ps > l){ pe = ps + l; pe = (pe+BY2PG-1)&~(BY2PG-1); } if(pe == ps) { qunlock(&s->lk); error(Ebadarg); } if(pte) pteflush(pte, ps/BY2PG, pe/BY2PG); | |
| 1993/0919 | chunk = pe-ps; len -= chunk; addr += chunk; | |
| 1993/1001 | if(len > 0 && addr < s->top) goto more; | |
| 1993/0919 | qunlock(&s->lk); } | |
| 1991/0705 | flushmmu(); | |
| 1992/0520 | return 0; | |
| 1991/0705 | } | |