xref: /plan9/sys/src/9/port/segment.c (revision 219b2ee8daee37f4aad58d63f21287faa8e4ffdc)
13e12c5d1SDavid du Colombier #include	"u.h"
23e12c5d1SDavid du Colombier #include	"../port/lib.h"
33e12c5d1SDavid du Colombier #include	"mem.h"
43e12c5d1SDavid du Colombier #include	"dat.h"
53e12c5d1SDavid du Colombier #include	"fns.h"
63e12c5d1SDavid du Colombier #include	"../port/error.h"
73e12c5d1SDavid du Colombier 
8*219b2ee8SDavid du Colombier Page *lkpage(Segment*, ulong);
93e12c5d1SDavid du Colombier void lkpgfree(Page*);
103e12c5d1SDavid du Colombier void imagereclaim(void);
113e12c5d1SDavid du Colombier 
123e12c5d1SDavid du Colombier /* System specific segattach devices */
13*219b2ee8SDavid du Colombier #include "io.h"
143e12c5d1SDavid du Colombier #include "segment.h"
153e12c5d1SDavid du Colombier 
163e12c5d1SDavid du Colombier #define IHASHSIZE	64
173e12c5d1SDavid du Colombier #define ihash(s)	imagealloc.hash[s%IHASHSIZE]
183e12c5d1SDavid du Colombier struct
193e12c5d1SDavid du Colombier {
203e12c5d1SDavid du Colombier 	Lock;
213e12c5d1SDavid du Colombier 	Image	*free;
223e12c5d1SDavid du Colombier 	Image	*hash[IHASHSIZE];
233e12c5d1SDavid du Colombier 	QLock	ireclaim;
243e12c5d1SDavid du Colombier }imagealloc;
253e12c5d1SDavid du Colombier 
263e12c5d1SDavid du Colombier void
273e12c5d1SDavid du Colombier initseg(void)
283e12c5d1SDavid du Colombier {
293e12c5d1SDavid du Colombier 	Image *i, *ie;
303e12c5d1SDavid du Colombier 
313e12c5d1SDavid du Colombier 	imagealloc.free = xalloc(conf.nimage*sizeof(Image));
323e12c5d1SDavid du Colombier 	ie = &imagealloc.free[conf.nimage-1];
333e12c5d1SDavid du Colombier 	for(i = imagealloc.free; i < ie; i++)
343e12c5d1SDavid du Colombier 		i->next = i+1;
353e12c5d1SDavid du Colombier 	i->next = 0;
363e12c5d1SDavid du Colombier }
373e12c5d1SDavid du Colombier 
383e12c5d1SDavid du Colombier Segment *
393e12c5d1SDavid du Colombier newseg(int type, ulong base, ulong size)
403e12c5d1SDavid du Colombier {
413e12c5d1SDavid du Colombier 	Segment *s;
423e12c5d1SDavid du Colombier 
433e12c5d1SDavid du Colombier 	if(size > (SEGMAPSIZE*PTEPERTAB))
443e12c5d1SDavid du Colombier 		error(Enovmem);
453e12c5d1SDavid du Colombier 
463e12c5d1SDavid du Colombier 	s = smalloc(sizeof(Segment));
473e12c5d1SDavid du Colombier 	s->ref = 1;
483e12c5d1SDavid du Colombier 	s->type = type;
493e12c5d1SDavid du Colombier 	s->base = base;
503e12c5d1SDavid du Colombier 	s->top = base+(size*BY2PG);
513e12c5d1SDavid du Colombier 	s->size = size;
523e12c5d1SDavid du Colombier 	return s;
533e12c5d1SDavid du Colombier }
543e12c5d1SDavid du Colombier 
553e12c5d1SDavid du Colombier void
563e12c5d1SDavid du Colombier putseg(Segment *s)
573e12c5d1SDavid du Colombier {
583e12c5d1SDavid du Colombier 	Pte **pp, **emap;
593e12c5d1SDavid du Colombier 	Image *i;
603e12c5d1SDavid du Colombier 
613e12c5d1SDavid du Colombier 	if(s == 0)
623e12c5d1SDavid du Colombier 		return;
633e12c5d1SDavid du Colombier 
643e12c5d1SDavid du Colombier 	i = s->image;
65*219b2ee8SDavid du Colombier 	if(i != 0) {
663e12c5d1SDavid du Colombier 		lock(i);
67*219b2ee8SDavid du Colombier 		lock(s);
68*219b2ee8SDavid du Colombier 		if(i->s == s && s->ref == 1)
693e12c5d1SDavid du Colombier 			i->s = 0;
703e12c5d1SDavid du Colombier 		unlock(i);
713e12c5d1SDavid du Colombier 	}
72*219b2ee8SDavid du Colombier 	else
73*219b2ee8SDavid du Colombier 		lock(s);
743e12c5d1SDavid du Colombier 
75*219b2ee8SDavid du Colombier 	s->ref--;
76*219b2ee8SDavid du Colombier 	if(s->ref != 0) {
77*219b2ee8SDavid du Colombier 		unlock(s);
78*219b2ee8SDavid du Colombier 		return;
79*219b2ee8SDavid du Colombier 	}
80*219b2ee8SDavid du Colombier 
813e12c5d1SDavid du Colombier 	qlock(&s->lk);
823e12c5d1SDavid du Colombier 	if(i)
833e12c5d1SDavid du Colombier 		putimage(i);
843e12c5d1SDavid du Colombier 
853e12c5d1SDavid du Colombier 	emap = &s->map[SEGMAPSIZE];
863e12c5d1SDavid du Colombier 	for(pp = s->map; pp < emap; pp++)
873e12c5d1SDavid du Colombier 		if(*pp)
883e12c5d1SDavid du Colombier 			freepte(s, *pp);
893e12c5d1SDavid du Colombier 
903e12c5d1SDavid du Colombier 	qunlock(&s->lk);
913e12c5d1SDavid du Colombier 	free(s);
923e12c5d1SDavid du Colombier }
933e12c5d1SDavid du Colombier 
943e12c5d1SDavid du Colombier void
953e12c5d1SDavid du Colombier relocateseg(Segment *s, ulong offset)
963e12c5d1SDavid du Colombier {
973e12c5d1SDavid du Colombier 	Pte **p, **endpte;
983e12c5d1SDavid du Colombier 	Page **pg, **endpages;
993e12c5d1SDavid du Colombier 
1003e12c5d1SDavid du Colombier 	endpte = &s->map[SEGMAPSIZE];
1013e12c5d1SDavid du Colombier 	for(p = s->map; p < endpte; p++) {
1023e12c5d1SDavid du Colombier 		if(*p) {
1033e12c5d1SDavid du Colombier 			endpages = &((*p)->pages[PTEPERTAB]);
1043e12c5d1SDavid du Colombier 			for(pg = (*p)->pages; pg < endpages; pg++)
1053e12c5d1SDavid du Colombier 				if(*pg)
1063e12c5d1SDavid du Colombier 					(*pg)->va += offset;
1073e12c5d1SDavid du Colombier 		}
1083e12c5d1SDavid du Colombier 	}
1093e12c5d1SDavid du Colombier }
1103e12c5d1SDavid du Colombier 
1113e12c5d1SDavid du Colombier Segment*
112bd389b36SDavid du Colombier dupseg(Segment **seg, int segno, int share)
1133e12c5d1SDavid du Colombier {
1143e12c5d1SDavid du Colombier 	int i;
1153e12c5d1SDavid du Colombier 	Pte *pte;
116bd389b36SDavid du Colombier 	Segment *n, *s;
1173e12c5d1SDavid du Colombier 
1183e12c5d1SDavid du Colombier 	SET(n);
119bd389b36SDavid du Colombier 	s = seg[segno];
120bd389b36SDavid du Colombier 
1213e12c5d1SDavid du Colombier 	switch(s->type&SG_TYPE) {
1223e12c5d1SDavid du Colombier 	case SG_TEXT:			/* New segment shares pte set */
1233e12c5d1SDavid du Colombier 	case SG_SHARED:
1243e12c5d1SDavid du Colombier 	case SG_PHYSICAL:
1253e12c5d1SDavid du Colombier 	case SG_SHDATA:
1263e12c5d1SDavid du Colombier 		incref(s);
1273e12c5d1SDavid du Colombier 		return s;
1283e12c5d1SDavid du Colombier 
1293e12c5d1SDavid du Colombier 	case SG_STACK:
1303e12c5d1SDavid du Colombier 		qlock(&s->lk);
1313e12c5d1SDavid du Colombier 		n = newseg(s->type, s->base, s->size);
1323e12c5d1SDavid du Colombier 		break;
1333e12c5d1SDavid du Colombier 
1343e12c5d1SDavid du Colombier 	case SG_BSS:			/* Just copy on write */
1353e12c5d1SDavid du Colombier 		qlock(&s->lk);
1363e12c5d1SDavid du Colombier 		if(share && s->ref == 1) {
1373e12c5d1SDavid du Colombier 			s->type = (s->type&~SG_TYPE)|SG_SHARED;
1383e12c5d1SDavid du Colombier 			incref(s);
1393e12c5d1SDavid du Colombier 			qunlock(&s->lk);
1403e12c5d1SDavid du Colombier 			return s;
1413e12c5d1SDavid du Colombier 		}
1423e12c5d1SDavid du Colombier 		n = newseg(s->type, s->base, s->size);
1433e12c5d1SDavid du Colombier 		break;
1443e12c5d1SDavid du Colombier 
1453e12c5d1SDavid du Colombier 	case SG_DATA:			/* Copy on write plus demand load info */
146bd389b36SDavid du Colombier 		if(segno == TSEG)
147bd389b36SDavid du Colombier 			return data2txt(s);
148bd389b36SDavid du Colombier 
1493e12c5d1SDavid du Colombier 		qlock(&s->lk);
1503e12c5d1SDavid du Colombier 		if(share && s->ref == 1) {
1513e12c5d1SDavid du Colombier 			s->type = (s->type&~SG_TYPE)|SG_SHDATA;
1523e12c5d1SDavid du Colombier 			incref(s);
1533e12c5d1SDavid du Colombier 			qunlock(&s->lk);
1543e12c5d1SDavid du Colombier 			return s;
1553e12c5d1SDavid du Colombier 		}
1563e12c5d1SDavid du Colombier 		n = newseg(s->type, s->base, s->size);
1573e12c5d1SDavid du Colombier 
1583e12c5d1SDavid du Colombier 		incref(s->image);
1593e12c5d1SDavid du Colombier 		n->image = s->image;
1603e12c5d1SDavid du Colombier 		n->fstart = s->fstart;
1613e12c5d1SDavid du Colombier 		n->flen = s->flen;
1623e12c5d1SDavid du Colombier 		break;
1633e12c5d1SDavid du Colombier 	}
1643e12c5d1SDavid du Colombier 	for(i = 0; i < SEGMAPSIZE; i++)
1653e12c5d1SDavid du Colombier 		if(pte = s->map[i])
1663e12c5d1SDavid du Colombier 			n->map[i] = ptecpy(pte);
1673e12c5d1SDavid du Colombier 
1683e12c5d1SDavid du Colombier 	n->flushme = s->flushme;
1693e12c5d1SDavid du Colombier 	qunlock(&s->lk);
1703e12c5d1SDavid du Colombier 	return n;
1713e12c5d1SDavid du Colombier }
1723e12c5d1SDavid du Colombier 
1733e12c5d1SDavid du Colombier void
1743e12c5d1SDavid du Colombier segpage(Segment *s, Page *p)
1753e12c5d1SDavid du Colombier {
1763e12c5d1SDavid du Colombier 	Pte **pte;
1773e12c5d1SDavid du Colombier 	ulong off;
1783e12c5d1SDavid du Colombier 	Page **pg;
1793e12c5d1SDavid du Colombier 
1803e12c5d1SDavid du Colombier 	if(p->va < s->base || p->va >= s->top)
1813e12c5d1SDavid du Colombier 		panic("segpage");
1823e12c5d1SDavid du Colombier 
1833e12c5d1SDavid du Colombier 	off = p->va - s->base;
1843e12c5d1SDavid du Colombier 	pte = &s->map[off/PTEMAPMEM];
1853e12c5d1SDavid du Colombier 	if(*pte == 0)
1863e12c5d1SDavid du Colombier 		*pte = ptealloc();
1873e12c5d1SDavid du Colombier 
1883e12c5d1SDavid du Colombier 	pg = &(*pte)->pages[(off&(PTEMAPMEM-1))/BY2PG];
1893e12c5d1SDavid du Colombier 	*pg = p;
1903e12c5d1SDavid du Colombier 	if(pg < (*pte)->first)
1913e12c5d1SDavid du Colombier 		(*pte)->first = pg;
1923e12c5d1SDavid du Colombier 	if(pg > (*pte)->last)
1933e12c5d1SDavid du Colombier 		(*pte)->last = pg;
1943e12c5d1SDavid du Colombier }
1953e12c5d1SDavid du Colombier 
1963e12c5d1SDavid du Colombier Image*
1973e12c5d1SDavid du Colombier attachimage(int type, Chan *c, ulong base, ulong len)
1983e12c5d1SDavid du Colombier {
1993e12c5d1SDavid du Colombier 	Image *i, **l;
2003e12c5d1SDavid du Colombier 
2013e12c5d1SDavid du Colombier 	lock(&imagealloc);
2023e12c5d1SDavid du Colombier 
2033e12c5d1SDavid du Colombier 	/*
2043e12c5d1SDavid du Colombier 	 * Search the image cache for remains of the text from a previous
2053e12c5d1SDavid du Colombier 	 * or currently running incarnation
2063e12c5d1SDavid du Colombier 	 */
2073e12c5d1SDavid du Colombier 	for(i = ihash(c->qid.path); i; i = i->hash) {
2083e12c5d1SDavid du Colombier 		if(c->qid.path == i->qid.path) {
2093e12c5d1SDavid du Colombier 			lock(i);
2103e12c5d1SDavid du Colombier 			if(eqqid(c->qid, i->qid) &&
2113e12c5d1SDavid du Colombier 			   eqqid(c->mqid, i->mqid) &&
2123e12c5d1SDavid du Colombier 			   c->mchan == i->mchan &&
2133e12c5d1SDavid du Colombier 			   c->type == i->type) {
2143e12c5d1SDavid du Colombier 				i->ref++;
2153e12c5d1SDavid du Colombier 				goto found;
2163e12c5d1SDavid du Colombier 			}
2173e12c5d1SDavid du Colombier 			unlock(i);
2183e12c5d1SDavid du Colombier 		}
2193e12c5d1SDavid du Colombier 	}
2203e12c5d1SDavid du Colombier 
2213e12c5d1SDavid du Colombier 	/*
2223e12c5d1SDavid du Colombier 	 * imagereclaim dumps pages from the free list which are cached by image
2233e12c5d1SDavid du Colombier 	 * structures. This should free some image structures.
2243e12c5d1SDavid du Colombier 	 */
2253e12c5d1SDavid du Colombier 	while(!(i = imagealloc.free)) {
2263e12c5d1SDavid du Colombier 		unlock(&imagealloc);
2273e12c5d1SDavid du Colombier 		imagereclaim();
2283e12c5d1SDavid du Colombier 		resrcwait(0);
2293e12c5d1SDavid du Colombier 		lock(&imagealloc);
2303e12c5d1SDavid du Colombier 	}
2313e12c5d1SDavid du Colombier 
2323e12c5d1SDavid du Colombier 	imagealloc.free = i->next;
2333e12c5d1SDavid du Colombier 
2343e12c5d1SDavid du Colombier 	lock(i);
2353e12c5d1SDavid du Colombier 	incref(c);
2363e12c5d1SDavid du Colombier 	i->c = c;
2373e12c5d1SDavid du Colombier 	i->type = c->type;
2383e12c5d1SDavid du Colombier 	i->qid = c->qid;
2393e12c5d1SDavid du Colombier 	i->mqid = c->mqid;
2403e12c5d1SDavid du Colombier 	i->mchan = c->mchan;
2413e12c5d1SDavid du Colombier 	i->ref = 1;
2423e12c5d1SDavid du Colombier 	l = &ihash(c->qid.path);
2433e12c5d1SDavid du Colombier 	i->hash = *l;
2443e12c5d1SDavid du Colombier 	*l = i;
2453e12c5d1SDavid du Colombier found:
2463e12c5d1SDavid du Colombier 	unlock(&imagealloc);
2473e12c5d1SDavid du Colombier 
2483e12c5d1SDavid du Colombier 	if(i->s == 0) {
249*219b2ee8SDavid du Colombier 		/* Disaster after commit in exec */
250*219b2ee8SDavid du Colombier 		if(waserror()) {
251*219b2ee8SDavid du Colombier 			unlock(i);
252*219b2ee8SDavid du Colombier 			pexit(Enovmem, 1);
253*219b2ee8SDavid du Colombier 		}
2543e12c5d1SDavid du Colombier 		i->s = newseg(type, base, len);
2553e12c5d1SDavid du Colombier 		i->s->image = i;
256*219b2ee8SDavid du Colombier 		poperror();
2573e12c5d1SDavid du Colombier 	}
2583e12c5d1SDavid du Colombier 	else
2593e12c5d1SDavid du Colombier 		incref(i->s);
2603e12c5d1SDavid du Colombier 
2613e12c5d1SDavid du Colombier 	return i;
2623e12c5d1SDavid du Colombier }
2633e12c5d1SDavid du Colombier 
2643e12c5d1SDavid du Colombier void
2653e12c5d1SDavid du Colombier imagereclaim(void)
2663e12c5d1SDavid du Colombier {
2673e12c5d1SDavid du Colombier 	Page *p;
2683e12c5d1SDavid du Colombier 
2693e12c5d1SDavid du Colombier 	/* Somebody is already cleaning the page cache */
2703e12c5d1SDavid du Colombier 	if(!canqlock(&imagealloc.ireclaim))
2713e12c5d1SDavid du Colombier 		return;
2723e12c5d1SDavid du Colombier 
2733e12c5d1SDavid du Colombier 	lock(&palloc);
2743e12c5d1SDavid du Colombier 	for(p = palloc.head; p; p = p->next) {
2753e12c5d1SDavid du Colombier 		if(p->image && p->ref == 0 && p->image != &swapimage && canlock(p)) {
2763e12c5d1SDavid du Colombier 			if(p->ref == 0)
2773e12c5d1SDavid du Colombier 				uncachepage(p);
2783e12c5d1SDavid du Colombier 			unlock(p);
2793e12c5d1SDavid du Colombier 		}
2803e12c5d1SDavid du Colombier 	}
2813e12c5d1SDavid du Colombier 	unlock(&palloc);
2823e12c5d1SDavid du Colombier 	qunlock(&imagealloc.ireclaim);
2833e12c5d1SDavid du Colombier }
2843e12c5d1SDavid du Colombier 
2853e12c5d1SDavid du Colombier void
2863e12c5d1SDavid du Colombier putimage(Image *i)
2873e12c5d1SDavid du Colombier {
2883e12c5d1SDavid du Colombier 	Chan *c;
2893e12c5d1SDavid du Colombier 	Image *f, **l;
2903e12c5d1SDavid du Colombier 
2913e12c5d1SDavid du Colombier 	if(i == &swapimage)
2923e12c5d1SDavid du Colombier 		return;
2933e12c5d1SDavid du Colombier 
2943e12c5d1SDavid du Colombier 	lock(i);
2953e12c5d1SDavid du Colombier 	if(--i->ref == 0) {
2963e12c5d1SDavid du Colombier 		l = &ihash(i->qid.path);
2973e12c5d1SDavid du Colombier 		i->qid = (Qid){~0, ~0};
2983e12c5d1SDavid du Colombier 		unlock(i);
2993e12c5d1SDavid du Colombier 		c = i->c;
3003e12c5d1SDavid du Colombier 
3013e12c5d1SDavid du Colombier 		lock(&imagealloc);
3023e12c5d1SDavid du Colombier 		for(f = *l; f; f = f->hash) {
3033e12c5d1SDavid du Colombier 			if(f == i) {
3043e12c5d1SDavid du Colombier 				*l = i->hash;
3053e12c5d1SDavid du Colombier 				break;
3063e12c5d1SDavid du Colombier 			}
3073e12c5d1SDavid du Colombier 			l = &f->hash;
3083e12c5d1SDavid du Colombier 		}
3093e12c5d1SDavid du Colombier 
3103e12c5d1SDavid du Colombier 		i->next = imagealloc.free;
3113e12c5d1SDavid du Colombier 		imagealloc.free = i;
3123e12c5d1SDavid du Colombier 		unlock(&imagealloc);
3133e12c5d1SDavid du Colombier 
3143e12c5d1SDavid du Colombier 		close(c);
3153e12c5d1SDavid du Colombier 		return;
3163e12c5d1SDavid du Colombier 	}
3173e12c5d1SDavid du Colombier 	unlock(i);
3183e12c5d1SDavid du Colombier }
3193e12c5d1SDavid du Colombier 
3203e12c5d1SDavid du Colombier long
3213e12c5d1SDavid du Colombier ibrk(ulong addr, int seg)
3223e12c5d1SDavid du Colombier {
3233e12c5d1SDavid du Colombier 	Segment *s, *ns;
3243e12c5d1SDavid du Colombier 	ulong newtop, newsize;
3253e12c5d1SDavid du Colombier 	int i;
3263e12c5d1SDavid du Colombier 
3273e12c5d1SDavid du Colombier 	s = u->p->seg[seg];
3283e12c5d1SDavid du Colombier 	if(s == 0)
3293e12c5d1SDavid du Colombier 		error(Ebadarg);
3303e12c5d1SDavid du Colombier 
3313e12c5d1SDavid du Colombier 	if(addr == 0)
3323e12c5d1SDavid du Colombier 		return s->base;
3333e12c5d1SDavid du Colombier 
3343e12c5d1SDavid du Colombier 	qlock(&s->lk);
3353e12c5d1SDavid du Colombier 
3363e12c5d1SDavid du Colombier 	/* We may start with the bss overlapping the data */
3373e12c5d1SDavid du Colombier 	if(addr < s->base) {
3383e12c5d1SDavid du Colombier 		if(seg != BSEG || u->p->seg[DSEG] == 0 || addr < u->p->seg[DSEG]->base) {
3393e12c5d1SDavid du Colombier 			qunlock(&s->lk);
3403e12c5d1SDavid du Colombier 			error(Enovmem);
3413e12c5d1SDavid du Colombier 		}
3423e12c5d1SDavid du Colombier 		addr = s->base;
3433e12c5d1SDavid du Colombier 	}
3443e12c5d1SDavid du Colombier 
3453e12c5d1SDavid du Colombier 	newtop = PGROUND(addr);
3463e12c5d1SDavid du Colombier 	newsize = (newtop-s->base)/BY2PG;
3473e12c5d1SDavid du Colombier 	if(newtop < s->top) {
3483e12c5d1SDavid du Colombier 		mfreeseg(s, newtop, (s->top-newtop)/BY2PG);
3493e12c5d1SDavid du Colombier 		qunlock(&s->lk);
350bd389b36SDavid du Colombier 		flushmmu();
3513e12c5d1SDavid du Colombier 		return 0;
3523e12c5d1SDavid du Colombier 	}
3533e12c5d1SDavid du Colombier 
3543e12c5d1SDavid du Colombier 	for(i = 0; i < NSEG; i++) {
3553e12c5d1SDavid du Colombier 		ns = u->p->seg[i];
3563e12c5d1SDavid du Colombier 		if(ns == 0 || ns == s)
3573e12c5d1SDavid du Colombier 			continue;
3583e12c5d1SDavid du Colombier 		if(newtop >= ns->base && newtop < ns->top) {
3593e12c5d1SDavid du Colombier 			qunlock(&s->lk);
3603e12c5d1SDavid du Colombier 			error(Esoverlap);
3613e12c5d1SDavid du Colombier 		}
3623e12c5d1SDavid du Colombier 	}
3633e12c5d1SDavid du Colombier 
3643e12c5d1SDavid du Colombier 	if(newsize > (PTEMAPMEM*SEGMAPSIZE)/BY2PG) {
3653e12c5d1SDavid du Colombier 		qunlock(&s->lk);
3663e12c5d1SDavid du Colombier 		error(Enovmem);
3673e12c5d1SDavid du Colombier 	}
3683e12c5d1SDavid du Colombier 
3693e12c5d1SDavid du Colombier 	s->top = newtop;
3703e12c5d1SDavid du Colombier 	s->size = newsize;
3713e12c5d1SDavid du Colombier 	qunlock(&s->lk);
3723e12c5d1SDavid du Colombier 	return 0;
3733e12c5d1SDavid du Colombier }
3743e12c5d1SDavid du Colombier 
3753e12c5d1SDavid du Colombier void
3763e12c5d1SDavid du Colombier mfreeseg(Segment *s, ulong start, int pages)
3773e12c5d1SDavid du Colombier {
3783e12c5d1SDavid du Colombier 	int i, j;
3793e12c5d1SDavid du Colombier 	ulong soff;
3803e12c5d1SDavid du Colombier 	Page *pg;
3813e12c5d1SDavid du Colombier 
3823e12c5d1SDavid du Colombier 	soff = start-s->base;
3833e12c5d1SDavid du Colombier 	j = (soff&(PTEMAPMEM-1))/BY2PG;
3843e12c5d1SDavid du Colombier 
3853e12c5d1SDavid du Colombier 	for(i = soff/PTEMAPMEM; i < SEGMAPSIZE; i++) {
3863e12c5d1SDavid du Colombier 		if(pages <= 0)
387bd389b36SDavid du Colombier 			break;
388bd389b36SDavid du Colombier 		if(s->map[i] == 0) {
389bd389b36SDavid du Colombier 			pages -= PTEPERTAB-j;
390bd389b36SDavid du Colombier 			j = 0;
391bd389b36SDavid du Colombier 			continue;
392bd389b36SDavid du Colombier 		}
3933e12c5d1SDavid du Colombier 		while(j < PTEPERTAB) {
394bd389b36SDavid du Colombier 			pg = s->map[i]->pages[j];
395bd389b36SDavid du Colombier 			if(pg) {
3963e12c5d1SDavid du Colombier 				putpage(pg);
3973e12c5d1SDavid du Colombier 				s->map[i]->pages[j] = 0;
3983e12c5d1SDavid du Colombier 			}
3993e12c5d1SDavid du Colombier 			if(--pages == 0)
400bd389b36SDavid du Colombier 				return;
4013e12c5d1SDavid du Colombier 			j++;
4023e12c5d1SDavid du Colombier 		}
4033e12c5d1SDavid du Colombier 		j = 0;
4043e12c5d1SDavid du Colombier 	}
4053e12c5d1SDavid du Colombier }
4063e12c5d1SDavid du Colombier 
407*219b2ee8SDavid du Colombier int
408*219b2ee8SDavid du Colombier isoverlap(ulong va, int len)
409*219b2ee8SDavid du Colombier {
410*219b2ee8SDavid du Colombier 	int i;
411*219b2ee8SDavid du Colombier 	Segment *ns;
412*219b2ee8SDavid du Colombier 	ulong newtop;
413*219b2ee8SDavid du Colombier 
414*219b2ee8SDavid du Colombier 	newtop = va+len;
415*219b2ee8SDavid du Colombier 	for(i = 0; i < NSEG; i++) {
416*219b2ee8SDavid du Colombier 		ns = u->p->seg[i];
417*219b2ee8SDavid du Colombier 		if(ns == 0)
418*219b2ee8SDavid du Colombier 			continue;
419*219b2ee8SDavid du Colombier 		if((newtop > ns->base && newtop <= ns->top) ||
420*219b2ee8SDavid du Colombier 		   (va >= ns->base && va < ns->top))
421*219b2ee8SDavid du Colombier 			return 1;
422*219b2ee8SDavid du Colombier 	}
423*219b2ee8SDavid du Colombier 	return 0;
424*219b2ee8SDavid du Colombier }
425*219b2ee8SDavid du Colombier 
4263e12c5d1SDavid du Colombier ulong
4273e12c5d1SDavid du Colombier segattach(Proc *p, ulong attr, char *name, ulong va, ulong len)
4283e12c5d1SDavid du Colombier {
4293e12c5d1SDavid du Colombier 	int i, sno;
430*219b2ee8SDavid du Colombier 	Segment *s;
431*219b2ee8SDavid du Colombier 	Physseg *ps;
4323e12c5d1SDavid du Colombier 
4333e12c5d1SDavid du Colombier 	USED(p);
434*219b2ee8SDavid du Colombier 	if(va != 0 && (va&KZERO) == KZERO)	/* BUG: Only ok for now */
4353e12c5d1SDavid du Colombier 		error(Ebadarg);
4363e12c5d1SDavid du Colombier 
4373e12c5d1SDavid du Colombier 	validaddr((ulong)name, 1, 0);
4383e12c5d1SDavid du Colombier 	vmemchr(name, 0, ~0);
4393e12c5d1SDavid du Colombier 
4403e12c5d1SDavid du Colombier 	for(sno = 0; sno < NSEG; sno++)
441bd389b36SDavid du Colombier 		if(u->p->seg[sno] == 0 && sno != ESEG)
4423e12c5d1SDavid du Colombier 			break;
4433e12c5d1SDavid du Colombier 
4443e12c5d1SDavid du Colombier 	if(sno == NSEG)
4453e12c5d1SDavid du Colombier 		error(Enovmem);
4463e12c5d1SDavid du Colombier 
4473e12c5d1SDavid du Colombier 	len = PGROUND(len);
448*219b2ee8SDavid du Colombier 
449*219b2ee8SDavid du Colombier 	/* Find a hole in the address space */
450*219b2ee8SDavid du Colombier 	if(va == 0) {
451*219b2ee8SDavid du Colombier 		va = p->seg[SSEG]->base - len;
452*219b2ee8SDavid du Colombier 		for(i = 0; i < 20; i++) {
453*219b2ee8SDavid du Colombier 			if(isoverlap(va, len) == 0)
454*219b2ee8SDavid du Colombier 				break;
455*219b2ee8SDavid du Colombier 			va -= len;
4563e12c5d1SDavid du Colombier 		}
457*219b2ee8SDavid du Colombier 	}
458*219b2ee8SDavid du Colombier 
459*219b2ee8SDavid du Colombier 	va = va&~(BY2PG-1);
460*219b2ee8SDavid du Colombier 	if(isoverlap(va, len))
461*219b2ee8SDavid du Colombier 		error(Esoverlap);
4623e12c5d1SDavid du Colombier 
4633e12c5d1SDavid du Colombier 	for(ps = physseg; ps->name; ps++)
4643e12c5d1SDavid du Colombier 		if(strcmp(name, ps->name) == 0)
4653e12c5d1SDavid du Colombier 			goto found;
4663e12c5d1SDavid du Colombier 
4673e12c5d1SDavid du Colombier 	error(Ebadarg);
4683e12c5d1SDavid du Colombier found:
4693e12c5d1SDavid du Colombier 	if(len > ps->size)
4703e12c5d1SDavid du Colombier 		error(Enovmem);
4713e12c5d1SDavid du Colombier 
4723e12c5d1SDavid du Colombier 	attr &= ~SG_TYPE;		/* Turn off what we are not allowed */
4733e12c5d1SDavid du Colombier 	attr |= ps->attr;		/* Copy in defaults */
4743e12c5d1SDavid du Colombier 
4753e12c5d1SDavid du Colombier 	s = newseg(attr, va, len/BY2PG);
476*219b2ee8SDavid du Colombier 	s->pseg = ps;
4773e12c5d1SDavid du Colombier 	u->p->seg[sno] = s;
4783e12c5d1SDavid du Colombier 
479*219b2ee8SDavid du Colombier 	return va;
4803e12c5d1SDavid du Colombier }
4813e12c5d1SDavid du Colombier 
482*219b2ee8SDavid du Colombier void
483*219b2ee8SDavid du Colombier pteflush(Pte *pte, int s, int e)
484*219b2ee8SDavid du Colombier {
485*219b2ee8SDavid du Colombier 	int i;
486*219b2ee8SDavid du Colombier 	Page *p;
487*219b2ee8SDavid du Colombier 
488*219b2ee8SDavid du Colombier 	for(i = s; i < e; i++) {
489*219b2ee8SDavid du Colombier 		p = pte->pages[i];
490*219b2ee8SDavid du Colombier 		if(pagedout(p) == 0)
491*219b2ee8SDavid du Colombier 			memset(p->cachectl, PG_TXTFLUSH, sizeof(p->cachectl));
492*219b2ee8SDavid du Colombier 	}
493*219b2ee8SDavid du Colombier }
494*219b2ee8SDavid du Colombier 
495*219b2ee8SDavid du Colombier 
4963e12c5d1SDavid du Colombier long
4973e12c5d1SDavid du Colombier syssegflush(ulong *arg)
498*219b2ee8SDavid du Colombier {	Segment *s;
499*219b2ee8SDavid du Colombier 	ulong addr, l;
500*219b2ee8SDavid du Colombier 	Pte *pte;
501*219b2ee8SDavid du Colombier 	int chunk, ps, pe, len;
5023e12c5d1SDavid du Colombier 
503*219b2ee8SDavid du Colombier 	addr = arg[0];
504*219b2ee8SDavid du Colombier 	len = arg[1];
505*219b2ee8SDavid du Colombier 
506*219b2ee8SDavid du Colombier 	while(len > 0) {
507*219b2ee8SDavid du Colombier 		s = seg(u->p, addr, 1);
5083e12c5d1SDavid du Colombier 		if(s == 0)
5093e12c5d1SDavid du Colombier 			error(Ebadarg);
5103e12c5d1SDavid du Colombier 
5113e12c5d1SDavid du Colombier 		s->flushme = 1;
512*219b2ee8SDavid du Colombier 	more:
513*219b2ee8SDavid du Colombier 		l = len;
514*219b2ee8SDavid du Colombier 		if(addr+l > s->top)
515*219b2ee8SDavid du Colombier 			l = s->top - addr;
5163e12c5d1SDavid du Colombier 
517*219b2ee8SDavid du Colombier 		ps = addr-s->base;
518*219b2ee8SDavid du Colombier 		pte = s->map[ps/PTEMAPMEM];
519*219b2ee8SDavid du Colombier 		ps &= PTEMAPMEM-1;
520*219b2ee8SDavid du Colombier 		pe = PTEMAPMEM;
521*219b2ee8SDavid du Colombier 		if(pe-ps > l){
522*219b2ee8SDavid du Colombier 			pe = ps + l;
523*219b2ee8SDavid du Colombier 			pe = (pe+BY2PG-1)&~(BY2PG-1);
5243e12c5d1SDavid du Colombier 		}
525*219b2ee8SDavid du Colombier 		if(pe == ps) {
5263e12c5d1SDavid du Colombier 			qunlock(&s->lk);
527*219b2ee8SDavid du Colombier 			error(Ebadarg);
528*219b2ee8SDavid du Colombier 		}
529*219b2ee8SDavid du Colombier 
530*219b2ee8SDavid du Colombier 		if(pte)
531*219b2ee8SDavid du Colombier 			pteflush(pte, ps/BY2PG, pe/BY2PG);
532*219b2ee8SDavid du Colombier 
533*219b2ee8SDavid du Colombier 		chunk = pe-ps;
534*219b2ee8SDavid du Colombier 		len -= chunk;
535*219b2ee8SDavid du Colombier 		addr += chunk;
536*219b2ee8SDavid du Colombier 
537*219b2ee8SDavid du Colombier 		if(len > 0 && addr < s->top)
538*219b2ee8SDavid du Colombier 			goto more;
539*219b2ee8SDavid du Colombier 
540*219b2ee8SDavid du Colombier 		qunlock(&s->lk);
541*219b2ee8SDavid du Colombier 	}
5423e12c5d1SDavid du Colombier 	flushmmu();
5433e12c5d1SDavid du Colombier 	return 0;
5443e12c5d1SDavid du Colombier }
545