xref: /plan9-contrib/sys/src/9/port/segment.c (revision 4aeffbf5869a066cad266dfda04e87c99bacbc21)
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 
87dd7cddfSDavid du Colombier static void	imagereclaim(void);
97dd7cddfSDavid du Colombier static void	imagechanreclaim(void);
103e12c5d1SDavid du Colombier 
11219b2ee8SDavid du Colombier #include "io.h"
129a747e4fSDavid du Colombier 
139a747e4fSDavid du Colombier /*
149a747e4fSDavid du Colombier  * Attachable segment types
159a747e4fSDavid du Colombier  */
169a747e4fSDavid du Colombier static Physseg physseg[10] = {
179a747e4fSDavid du Colombier 	{ SG_SHARED,	"shared",	0,	SEGMAXSIZE,	0, 	0 },
189a747e4fSDavid du Colombier 	{ SG_BSS,	"memory",	0,	SEGMAXSIZE,	0,	0 },
199a747e4fSDavid du Colombier 	{ 0,		0,		0,	0,		0,	0 },
209a747e4fSDavid du Colombier };
213e12c5d1SDavid du Colombier 
227dd7cddfSDavid du Colombier static Lock physseglock;
237dd7cddfSDavid du Colombier 
247dd7cddfSDavid du Colombier #define NFREECHAN	64
253e12c5d1SDavid du Colombier #define IHASHSIZE	64
263e12c5d1SDavid du Colombier #define ihash(s)	imagealloc.hash[s%IHASHSIZE]
2759cc4ca5SDavid du Colombier static struct Imagealloc
283e12c5d1SDavid du Colombier {
293e12c5d1SDavid du Colombier 	Lock;
303e12c5d1SDavid du Colombier 	Image	*free;
313e12c5d1SDavid du Colombier 	Image	*hash[IHASHSIZE];
327dd7cddfSDavid du Colombier 	QLock	ireclaim;	/* mutex on reclaiming free images */
337dd7cddfSDavid du Colombier 
347dd7cddfSDavid du Colombier 	Chan	**freechan;	/* free image channels */
357dd7cddfSDavid du Colombier 	int	nfreechan;	/* number of free channels */
367dd7cddfSDavid du Colombier 	int	szfreechan;	/* size of freechan array */
377dd7cddfSDavid du Colombier 	QLock	fcreclaim;	/* mutex on reclaiming free channels */
383e12c5d1SDavid du Colombier }imagealloc;
393e12c5d1SDavid du Colombier 
409a747e4fSDavid du Colombier Segment* (*_globalsegattach)(Proc*, char*);
419a747e4fSDavid du Colombier 
423e12c5d1SDavid du Colombier void
433e12c5d1SDavid du Colombier initseg(void)
443e12c5d1SDavid du Colombier {
453e12c5d1SDavid du Colombier 	Image *i, *ie;
463e12c5d1SDavid du Colombier 
473e12c5d1SDavid du Colombier 	imagealloc.free = xalloc(conf.nimage*sizeof(Image));
483e12c5d1SDavid du Colombier 	ie = &imagealloc.free[conf.nimage-1];
493e12c5d1SDavid du Colombier 	for(i = imagealloc.free; i < ie; i++)
503e12c5d1SDavid du Colombier 		i->next = i+1;
513e12c5d1SDavid du Colombier 	i->next = 0;
527dd7cddfSDavid du Colombier 	imagealloc.freechan = malloc(NFREECHAN * sizeof(Chan*));
537dd7cddfSDavid du Colombier 	imagealloc.szfreechan = NFREECHAN;
543e12c5d1SDavid du Colombier }
553e12c5d1SDavid du Colombier 
563e12c5d1SDavid du Colombier Segment *
573e12c5d1SDavid du Colombier newseg(int type, ulong base, ulong size)
583e12c5d1SDavid du Colombier {
593e12c5d1SDavid du Colombier 	Segment *s;
607dd7cddfSDavid du Colombier 	int mapsize;
613e12c5d1SDavid du Colombier 
623e12c5d1SDavid du Colombier 	if(size > (SEGMAPSIZE*PTEPERTAB))
633e12c5d1SDavid du Colombier 		error(Enovmem);
643e12c5d1SDavid du Colombier 
657dd7cddfSDavid du Colombier 	if(swapfull())
667dd7cddfSDavid du Colombier 		error(Enoswap);
673e12c5d1SDavid du Colombier 	s = smalloc(sizeof(Segment));
683e12c5d1SDavid du Colombier 	s->ref = 1;
693e12c5d1SDavid du Colombier 	s->type = type;
703e12c5d1SDavid du Colombier 	s->base = base;
713e12c5d1SDavid du Colombier 	s->top = base+(size*BY2PG);
723e12c5d1SDavid du Colombier 	s->size = size;
737dd7cddfSDavid du Colombier 
747dd7cddfSDavid du Colombier 	mapsize = ROUND(size, PTEPERTAB)/PTEPERTAB;
757dd7cddfSDavid du Colombier 	if(mapsize > nelem(s->ssegmap)){
767dd7cddfSDavid du Colombier 		mapsize *= 2;
777dd7cddfSDavid du Colombier 		if(mapsize > (SEGMAPSIZE*PTEPERTAB))
787dd7cddfSDavid du Colombier 			mapsize = (SEGMAPSIZE*PTEPERTAB);
797dd7cddfSDavid du Colombier 		s->map = smalloc(mapsize*sizeof(Pte*));
807dd7cddfSDavid du Colombier 		s->mapsize = mapsize;
817dd7cddfSDavid du Colombier 	}
827dd7cddfSDavid du Colombier 	else{
837dd7cddfSDavid du Colombier 		s->map = s->ssegmap;
847dd7cddfSDavid du Colombier 		s->mapsize = nelem(s->ssegmap);
857dd7cddfSDavid du Colombier 	}
867dd7cddfSDavid du Colombier 
873e12c5d1SDavid du Colombier 	return s;
883e12c5d1SDavid du Colombier }
893e12c5d1SDavid du Colombier 
903e12c5d1SDavid du Colombier void
913e12c5d1SDavid du Colombier putseg(Segment *s)
923e12c5d1SDavid du Colombier {
933e12c5d1SDavid du Colombier 	Pte **pp, **emap;
943e12c5d1SDavid du Colombier 	Image *i;
953e12c5d1SDavid du Colombier 
963e12c5d1SDavid du Colombier 	if(s == 0)
973e12c5d1SDavid du Colombier 		return;
983e12c5d1SDavid du Colombier 
993e12c5d1SDavid du Colombier 	i = s->image;
100219b2ee8SDavid du Colombier 	if(i != 0) {
1013e12c5d1SDavid du Colombier 		lock(i);
102219b2ee8SDavid du Colombier 		lock(s);
103219b2ee8SDavid du Colombier 		if(i->s == s && s->ref == 1)
1043e12c5d1SDavid du Colombier 			i->s = 0;
1053e12c5d1SDavid du Colombier 		unlock(i);
1063e12c5d1SDavid du Colombier 	}
107219b2ee8SDavid du Colombier 	else
108219b2ee8SDavid du Colombier 		lock(s);
1093e12c5d1SDavid du Colombier 
110219b2ee8SDavid du Colombier 	s->ref--;
111219b2ee8SDavid du Colombier 	if(s->ref != 0) {
112219b2ee8SDavid du Colombier 		unlock(s);
113219b2ee8SDavid du Colombier 		return;
114219b2ee8SDavid du Colombier 	}
1159a747e4fSDavid du Colombier 	unlock(s);
116219b2ee8SDavid du Colombier 
1173e12c5d1SDavid du Colombier 	qlock(&s->lk);
1183e12c5d1SDavid du Colombier 	if(i)
1193e12c5d1SDavid du Colombier 		putimage(i);
1203e12c5d1SDavid du Colombier 
1217dd7cddfSDavid du Colombier 	emap = &s->map[s->mapsize];
1223e12c5d1SDavid du Colombier 	for(pp = s->map; pp < emap; pp++)
1233e12c5d1SDavid du Colombier 		if(*pp)
1243e12c5d1SDavid du Colombier 			freepte(s, *pp);
1253e12c5d1SDavid du Colombier 
1263e12c5d1SDavid du Colombier 	qunlock(&s->lk);
1277dd7cddfSDavid du Colombier 	if(s->map != s->ssegmap)
1287dd7cddfSDavid du Colombier 		free(s->map);
1297dd7cddfSDavid du Colombier 	if(s->profile != 0)
1307dd7cddfSDavid du Colombier 		free(s->profile);
1313e12c5d1SDavid du Colombier 	free(s);
1323e12c5d1SDavid du Colombier }
1333e12c5d1SDavid du Colombier 
1343e12c5d1SDavid du Colombier void
1353e12c5d1SDavid du Colombier relocateseg(Segment *s, ulong offset)
1363e12c5d1SDavid du Colombier {
1377dd7cddfSDavid du Colombier 	Page **pg, *x;
1387dd7cddfSDavid du Colombier 	Pte *pte, **p, **endpte;
1393e12c5d1SDavid du Colombier 
1407dd7cddfSDavid du Colombier 	endpte = &s->map[s->mapsize];
1413e12c5d1SDavid du Colombier 	for(p = s->map; p < endpte; p++) {
1427dd7cddfSDavid du Colombier 		if(*p == 0)
1437dd7cddfSDavid du Colombier 			continue;
1447dd7cddfSDavid du Colombier 		pte = *p;
1457dd7cddfSDavid du Colombier 		for(pg = pte->first; pg <= pte->last; pg++) {
1467dd7cddfSDavid du Colombier 			if(x = *pg)
1477dd7cddfSDavid du Colombier 				x->va += offset;
1483e12c5d1SDavid du Colombier 		}
1493e12c5d1SDavid du Colombier 	}
1503e12c5d1SDavid du Colombier }
1513e12c5d1SDavid du Colombier 
1523e12c5d1SDavid du Colombier Segment*
153bd389b36SDavid du Colombier dupseg(Segment **seg, int segno, int share)
1543e12c5d1SDavid du Colombier {
1557dd7cddfSDavid du Colombier 	int i, size;
1563e12c5d1SDavid du Colombier 	Pte *pte;
157bd389b36SDavid du Colombier 	Segment *n, *s;
1583e12c5d1SDavid du Colombier 
1593e12c5d1SDavid du Colombier 	SET(n);
160bd389b36SDavid du Colombier 	s = seg[segno];
161bd389b36SDavid du Colombier 
16280ee5cbfSDavid du Colombier 	qlock(&s->lk);
16380ee5cbfSDavid du Colombier 	if(waserror()){
16480ee5cbfSDavid du Colombier 		qunlock(&s->lk);
16580ee5cbfSDavid du Colombier 		nexterror();
16680ee5cbfSDavid du Colombier 	}
1673e12c5d1SDavid du Colombier 	switch(s->type&SG_TYPE) {
1683e12c5d1SDavid du Colombier 	case SG_TEXT:		/* New segment shares pte set */
1693e12c5d1SDavid du Colombier 	case SG_SHARED:
1703e12c5d1SDavid du Colombier 	case SG_PHYSICAL:
17180ee5cbfSDavid du Colombier 		goto sameseg;
1723e12c5d1SDavid du Colombier 
1733e12c5d1SDavid du Colombier 	case SG_STACK:
1743e12c5d1SDavid du Colombier 		n = newseg(s->type, s->base, s->size);
1753e12c5d1SDavid du Colombier 		break;
1763e12c5d1SDavid du Colombier 
1773e12c5d1SDavid du Colombier 	case SG_BSS:		/* Just copy on write */
1789a747e4fSDavid du Colombier 		if(share)
17980ee5cbfSDavid du Colombier 			goto sameseg;
1803e12c5d1SDavid du Colombier 		n = newseg(s->type, s->base, s->size);
1813e12c5d1SDavid du Colombier 		break;
1823e12c5d1SDavid du Colombier 
1833e12c5d1SDavid du Colombier 	case SG_DATA:		/* Copy on write plus demand load info */
18480ee5cbfSDavid du Colombier 		if(segno == TSEG){
18580ee5cbfSDavid du Colombier 			poperror();
18680ee5cbfSDavid du Colombier 			qunlock(&s->lk);
187bd389b36SDavid du Colombier 			return data2txt(s);
1883e12c5d1SDavid du Colombier 		}
18980ee5cbfSDavid du Colombier 
1909a747e4fSDavid du Colombier 		if(share)
19180ee5cbfSDavid du Colombier 			goto sameseg;
1923e12c5d1SDavid du Colombier 		n = newseg(s->type, s->base, s->size);
1933e12c5d1SDavid du Colombier 
1943e12c5d1SDavid du Colombier 		incref(s->image);
1953e12c5d1SDavid du Colombier 		n->image = s->image;
1963e12c5d1SDavid du Colombier 		n->fstart = s->fstart;
1973e12c5d1SDavid du Colombier 		n->flen = s->flen;
1983e12c5d1SDavid du Colombier 		break;
1993e12c5d1SDavid du Colombier 	}
2007dd7cddfSDavid du Colombier 	size = s->mapsize;
2017dd7cddfSDavid du Colombier 	for(i = 0; i < size; i++)
2023e12c5d1SDavid du Colombier 		if(pte = s->map[i])
2033e12c5d1SDavid du Colombier 			n->map[i] = ptecpy(pte);
2043e12c5d1SDavid du Colombier 
2053e12c5d1SDavid du Colombier 	n->flushme = s->flushme;
2069a747e4fSDavid du Colombier 	if(s->ref > 1)
2079a747e4fSDavid du Colombier 		procflushseg(s);
20880ee5cbfSDavid du Colombier 	poperror();
2093e12c5d1SDavid du Colombier 	qunlock(&s->lk);
2103e12c5d1SDavid du Colombier 	return n;
21180ee5cbfSDavid du Colombier 
21280ee5cbfSDavid du Colombier sameseg:
21380ee5cbfSDavid du Colombier 	incref(s);
21480ee5cbfSDavid du Colombier 	poperror();
21580ee5cbfSDavid du Colombier 	qunlock(&s->lk);
21680ee5cbfSDavid du Colombier 	return s;
2173e12c5d1SDavid du Colombier }
2183e12c5d1SDavid du Colombier 
2193e12c5d1SDavid du Colombier void
2203e12c5d1SDavid du Colombier segpage(Segment *s, Page *p)
2213e12c5d1SDavid du Colombier {
2223e12c5d1SDavid du Colombier 	Pte **pte;
2233e12c5d1SDavid du Colombier 	ulong off;
2243e12c5d1SDavid du Colombier 	Page **pg;
2253e12c5d1SDavid du Colombier 
2263e12c5d1SDavid du Colombier 	if(p->va < s->base || p->va >= s->top)
2273e12c5d1SDavid du Colombier 		panic("segpage");
2283e12c5d1SDavid du Colombier 
2293e12c5d1SDavid du Colombier 	off = p->va - s->base;
2303e12c5d1SDavid du Colombier 	pte = &s->map[off/PTEMAPMEM];
2313e12c5d1SDavid du Colombier 	if(*pte == 0)
2323e12c5d1SDavid du Colombier 		*pte = ptealloc();
2333e12c5d1SDavid du Colombier 
2343e12c5d1SDavid du Colombier 	pg = &(*pte)->pages[(off&(PTEMAPMEM-1))/BY2PG];
2353e12c5d1SDavid du Colombier 	*pg = p;
2363e12c5d1SDavid du Colombier 	if(pg < (*pte)->first)
2373e12c5d1SDavid du Colombier 		(*pte)->first = pg;
2383e12c5d1SDavid du Colombier 	if(pg > (*pte)->last)
2393e12c5d1SDavid du Colombier 		(*pte)->last = pg;
2403e12c5d1SDavid du Colombier }
2413e12c5d1SDavid du Colombier 
2423e12c5d1SDavid du Colombier Image*
2433e12c5d1SDavid du Colombier attachimage(int type, Chan *c, ulong base, ulong len)
2443e12c5d1SDavid du Colombier {
2453e12c5d1SDavid du Colombier 	Image *i, **l;
2463e12c5d1SDavid du Colombier 
2477dd7cddfSDavid du Colombier 	/* reclaim any free channels from reclaimed segments */
2487dd7cddfSDavid du Colombier 	if(imagealloc.nfreechan)
2497dd7cddfSDavid du Colombier 		imagechanreclaim();
2507dd7cddfSDavid du Colombier 
2513e12c5d1SDavid du Colombier 	lock(&imagealloc);
2523e12c5d1SDavid du Colombier 
2533e12c5d1SDavid du Colombier 	/*
2543e12c5d1SDavid du Colombier 	 * Search the image cache for remains of the text from a previous
2553e12c5d1SDavid du Colombier 	 * or currently running incarnation
2563e12c5d1SDavid du Colombier 	 */
2573e12c5d1SDavid du Colombier 	for(i = ihash(c->qid.path); i; i = i->hash) {
2583e12c5d1SDavid du Colombier 		if(c->qid.path == i->qid.path) {
2593e12c5d1SDavid du Colombier 			lock(i);
2603e12c5d1SDavid du Colombier 			if(eqqid(c->qid, i->qid) &&
2613e12c5d1SDavid du Colombier 			   eqqid(c->mqid, i->mqid) &&
2623e12c5d1SDavid du Colombier 			   c->mchan == i->mchan &&
2633e12c5d1SDavid du Colombier 			   c->type == i->type) {
2643e12c5d1SDavid du Colombier 				goto found;
2653e12c5d1SDavid du Colombier 			}
2663e12c5d1SDavid du Colombier 			unlock(i);
2673e12c5d1SDavid du Colombier 		}
2683e12c5d1SDavid du Colombier 	}
2693e12c5d1SDavid du Colombier 
2703e12c5d1SDavid du Colombier 	/*
2713e12c5d1SDavid du Colombier 	 * imagereclaim dumps pages from the free list which are cached by image
2723e12c5d1SDavid du Colombier 	 * structures. This should free some image structures.
2733e12c5d1SDavid du Colombier 	 */
2743e12c5d1SDavid du Colombier 	while(!(i = imagealloc.free)) {
2753e12c5d1SDavid du Colombier 		unlock(&imagealloc);
2763e12c5d1SDavid du Colombier 		imagereclaim();
2777dd7cddfSDavid du Colombier 		sched();
2783e12c5d1SDavid du Colombier 		lock(&imagealloc);
2793e12c5d1SDavid du Colombier 	}
2803e12c5d1SDavid du Colombier 
2813e12c5d1SDavid du Colombier 	imagealloc.free = i->next;
2823e12c5d1SDavid du Colombier 
2833e12c5d1SDavid du Colombier 	lock(i);
2843e12c5d1SDavid du Colombier 	incref(c);
2853e12c5d1SDavid du Colombier 	i->c = c;
2863e12c5d1SDavid du Colombier 	i->type = c->type;
2873e12c5d1SDavid du Colombier 	i->qid = c->qid;
2883e12c5d1SDavid du Colombier 	i->mqid = c->mqid;
2893e12c5d1SDavid du Colombier 	i->mchan = c->mchan;
2903e12c5d1SDavid du Colombier 	l = &ihash(c->qid.path);
2913e12c5d1SDavid du Colombier 	i->hash = *l;
2923e12c5d1SDavid du Colombier 	*l = i;
2933e12c5d1SDavid du Colombier found:
2943e12c5d1SDavid du Colombier 	unlock(&imagealloc);
2953e12c5d1SDavid du Colombier 
2963e12c5d1SDavid du Colombier 	if(i->s == 0) {
297219b2ee8SDavid du Colombier 		/* Disaster after commit in exec */
298219b2ee8SDavid du Colombier 		if(waserror()) {
299219b2ee8SDavid du Colombier 			unlock(i);
300219b2ee8SDavid du Colombier 			pexit(Enovmem, 1);
301219b2ee8SDavid du Colombier 		}
3023e12c5d1SDavid du Colombier 		i->s = newseg(type, base, len);
3033e12c5d1SDavid du Colombier 		i->s->image = i;
3042839d78eSDavid du Colombier 		i->ref++;
305219b2ee8SDavid du Colombier 		poperror();
3063e12c5d1SDavid du Colombier 	}
3073e12c5d1SDavid du Colombier 	else
3083e12c5d1SDavid du Colombier 		incref(i->s);
3093e12c5d1SDavid du Colombier 
3103e12c5d1SDavid du Colombier 	return i;
3113e12c5d1SDavid du Colombier }
3123e12c5d1SDavid du Colombier 
3137dd7cddfSDavid du Colombier static struct {
3147dd7cddfSDavid du Colombier 	int	calls;			/* times imagereclaim was called */
3157dd7cddfSDavid du Colombier 	int	loops;			/* times the main loop was run */
3167dd7cddfSDavid du Colombier 	uvlong	ticks;			/* total time in the main loop */
3177dd7cddfSDavid du Colombier 	uvlong	maxt;			/* longest time in main loop */
3187dd7cddfSDavid du Colombier } irstats;
3197dd7cddfSDavid du Colombier 
3207dd7cddfSDavid du Colombier static void
3213e12c5d1SDavid du Colombier imagereclaim(void)
3223e12c5d1SDavid du Colombier {
3233e12c5d1SDavid du Colombier 	Page *p;
3247dd7cddfSDavid du Colombier 	uvlong ticks;
3253e12c5d1SDavid du Colombier 
3267dd7cddfSDavid du Colombier 	irstats.calls++;
3273e12c5d1SDavid du Colombier 	/* Somebody is already cleaning the page cache */
3283e12c5d1SDavid du Colombier 	if(!canqlock(&imagealloc.ireclaim))
3293e12c5d1SDavid du Colombier 		return;
3303e12c5d1SDavid du Colombier 
3313e12c5d1SDavid du Colombier 	lock(&palloc);
3327dd7cddfSDavid du Colombier 	ticks = fastticks(nil);
3333e12c5d1SDavid du Colombier 	for(p = palloc.head; p; p = p->next) {
3347dd7cddfSDavid du Colombier 		if(p->ref == 0 && p->image && canlock(p)) {
3353e12c5d1SDavid du Colombier 			if(p->ref == 0)
3363e12c5d1SDavid du Colombier 				uncachepage(p);
3373e12c5d1SDavid du Colombier 			unlock(p);
3383e12c5d1SDavid du Colombier 		}
3393e12c5d1SDavid du Colombier 	}
3407dd7cddfSDavid du Colombier 	ticks = fastticks(nil) - ticks;
3413e12c5d1SDavid du Colombier 	unlock(&palloc);
3427dd7cddfSDavid du Colombier 	irstats.loops++;
3437dd7cddfSDavid du Colombier 	irstats.ticks += ticks;
3447dd7cddfSDavid du Colombier 	if(ticks > irstats.maxt)
3457dd7cddfSDavid du Colombier 		irstats.maxt = ticks;
3467dd7cddfSDavid du Colombier 	//print("T%llud+", ticks);
3473e12c5d1SDavid du Colombier 	qunlock(&imagealloc.ireclaim);
3483e12c5d1SDavid du Colombier }
3493e12c5d1SDavid du Colombier 
3507dd7cddfSDavid du Colombier /*
3517dd7cddfSDavid du Colombier  *  since close can block, this has to be called outside of
3527dd7cddfSDavid du Colombier  *  spin locks.
3537dd7cddfSDavid du Colombier  */
3547dd7cddfSDavid du Colombier static void
3557dd7cddfSDavid du Colombier imagechanreclaim(void)
3567dd7cddfSDavid du Colombier {
3577dd7cddfSDavid du Colombier 	Chan *c;
3587dd7cddfSDavid du Colombier 
3597dd7cddfSDavid du Colombier 	/* Somebody is already cleaning the image chans */
3607dd7cddfSDavid du Colombier 	if(!canqlock(&imagealloc.fcreclaim))
3617dd7cddfSDavid du Colombier 		return;
3627dd7cddfSDavid du Colombier 
3637dd7cddfSDavid du Colombier 	/*
3647dd7cddfSDavid du Colombier 	 * We don't have to recheck that nfreechan > 0 after we
3657dd7cddfSDavid du Colombier 	 * acquire the lock, because we're the only ones who decrement
3667dd7cddfSDavid du Colombier 	 * it (the other lock contender increments it), and there's only
3677dd7cddfSDavid du Colombier 	 * one of us thanks to the qlock above.
3687dd7cddfSDavid du Colombier 	 */
3697dd7cddfSDavid du Colombier 	while(imagealloc.nfreechan > 0){
3707dd7cddfSDavid du Colombier 		lock(&imagealloc);
3717dd7cddfSDavid du Colombier 		imagealloc.nfreechan--;
3727dd7cddfSDavid du Colombier 		c = imagealloc.freechan[imagealloc.nfreechan];
3737dd7cddfSDavid du Colombier 		unlock(&imagealloc);
3747dd7cddfSDavid du Colombier 		cclose(c);
3757dd7cddfSDavid du Colombier 	}
3767dd7cddfSDavid du Colombier 
3777dd7cddfSDavid du Colombier 	qunlock(&imagealloc.fcreclaim);
3787dd7cddfSDavid du Colombier }
3797dd7cddfSDavid du Colombier 
3803e12c5d1SDavid du Colombier void
3813e12c5d1SDavid du Colombier putimage(Image *i)
3823e12c5d1SDavid du Colombier {
3837dd7cddfSDavid du Colombier 	Chan *c, **cp;
3843e12c5d1SDavid du Colombier 	Image *f, **l;
3853e12c5d1SDavid du Colombier 
3867dd7cddfSDavid du Colombier 	if(i->notext)
3873e12c5d1SDavid du Colombier 		return;
3883e12c5d1SDavid du Colombier 
3893e12c5d1SDavid du Colombier 	lock(i);
3903e12c5d1SDavid du Colombier 	if(--i->ref == 0) {
3913e12c5d1SDavid du Colombier 		l = &ihash(i->qid.path);
3929a747e4fSDavid du Colombier 		mkqid(&i->qid, ~0, ~0, QTFILE);
3933e12c5d1SDavid du Colombier 		unlock(i);
3943e12c5d1SDavid du Colombier 		c = i->c;
3953e12c5d1SDavid du Colombier 
3963e12c5d1SDavid du Colombier 		lock(&imagealloc);
3973e12c5d1SDavid du Colombier 		for(f = *l; f; f = f->hash) {
3983e12c5d1SDavid du Colombier 			if(f == i) {
3993e12c5d1SDavid du Colombier 				*l = i->hash;
4003e12c5d1SDavid du Colombier 				break;
4013e12c5d1SDavid du Colombier 			}
4023e12c5d1SDavid du Colombier 			l = &f->hash;
4033e12c5d1SDavid du Colombier 		}
4043e12c5d1SDavid du Colombier 
4053e12c5d1SDavid du Colombier 		i->next = imagealloc.free;
4063e12c5d1SDavid du Colombier 		imagealloc.free = i;
4077dd7cddfSDavid du Colombier 
4087dd7cddfSDavid du Colombier 		/* defer freeing channel till we're out of spin lock's */
4097dd7cddfSDavid du Colombier 		if(imagealloc.nfreechan == imagealloc.szfreechan){
4107dd7cddfSDavid du Colombier 			imagealloc.szfreechan += NFREECHAN;
4117dd7cddfSDavid du Colombier 			cp = malloc(imagealloc.szfreechan*sizeof(Chan*));
4127dd7cddfSDavid du Colombier 			if(cp == nil)
4137dd7cddfSDavid du Colombier 				panic("putimage");
4147dd7cddfSDavid du Colombier 			memmove(cp, imagealloc.freechan, imagealloc.nfreechan*sizeof(Chan*));
4157dd7cddfSDavid du Colombier 			free(imagealloc.freechan);
4167dd7cddfSDavid du Colombier 			imagealloc.freechan = cp;
4177dd7cddfSDavid du Colombier 		}
4187dd7cddfSDavid du Colombier 		imagealloc.freechan[imagealloc.nfreechan++] = c;
4193e12c5d1SDavid du Colombier 		unlock(&imagealloc);
4203e12c5d1SDavid du Colombier 
4213e12c5d1SDavid du Colombier 		return;
4223e12c5d1SDavid du Colombier 	}
4233e12c5d1SDavid du Colombier 	unlock(i);
4243e12c5d1SDavid du Colombier }
4253e12c5d1SDavid du Colombier 
4263e12c5d1SDavid du Colombier long
4273e12c5d1SDavid du Colombier ibrk(ulong addr, int seg)
4283e12c5d1SDavid du Colombier {
4293e12c5d1SDavid du Colombier 	Segment *s, *ns;
4303e12c5d1SDavid du Colombier 	ulong newtop, newsize;
4317dd7cddfSDavid du Colombier 	int i, mapsize;
4327dd7cddfSDavid du Colombier 	Pte **map;
4333e12c5d1SDavid du Colombier 
4347dd7cddfSDavid du Colombier 	s = up->seg[seg];
4353e12c5d1SDavid du Colombier 	if(s == 0)
4363e12c5d1SDavid du Colombier 		error(Ebadarg);
4373e12c5d1SDavid du Colombier 
4383e12c5d1SDavid du Colombier 	if(addr == 0)
4393e12c5d1SDavid du Colombier 		return s->base;
4403e12c5d1SDavid du Colombier 
4413e12c5d1SDavid du Colombier 	qlock(&s->lk);
4423e12c5d1SDavid du Colombier 
4433e12c5d1SDavid du Colombier 	/* We may start with the bss overlapping the data */
4443e12c5d1SDavid du Colombier 	if(addr < s->base) {
4457dd7cddfSDavid du Colombier 		if(seg != BSEG || up->seg[DSEG] == 0 || addr < up->seg[DSEG]->base) {
4463e12c5d1SDavid du Colombier 			qunlock(&s->lk);
4473e12c5d1SDavid du Colombier 			error(Enovmem);
4483e12c5d1SDavid du Colombier 		}
4493e12c5d1SDavid du Colombier 		addr = s->base;
4503e12c5d1SDavid du Colombier 	}
4513e12c5d1SDavid du Colombier 
4523e12c5d1SDavid du Colombier 	newtop = PGROUND(addr);
4533e12c5d1SDavid du Colombier 	newsize = (newtop-s->base)/BY2PG;
4543e12c5d1SDavid du Colombier 	if(newtop < s->top) {
4553e12c5d1SDavid du Colombier 		mfreeseg(s, newtop, (s->top-newtop)/BY2PG);
456*4aeffbf5SDavid du Colombier 		s->top = newtop;
457*4aeffbf5SDavid du Colombier 		s->size = newsize;
4583e12c5d1SDavid du Colombier 		qunlock(&s->lk);
459bd389b36SDavid du Colombier 		flushmmu();
4603e12c5d1SDavid du Colombier 		return 0;
4613e12c5d1SDavid du Colombier 	}
4623e12c5d1SDavid du Colombier 
4637dd7cddfSDavid du Colombier 	if(swapfull()){
4647dd7cddfSDavid du Colombier 		qunlock(&s->lk);
4657dd7cddfSDavid du Colombier 		error(Enoswap);
4667dd7cddfSDavid du Colombier 	}
4677dd7cddfSDavid du Colombier 
4683e12c5d1SDavid du Colombier 	for(i = 0; i < NSEG; i++) {
4697dd7cddfSDavid du Colombier 		ns = up->seg[i];
4703e12c5d1SDavid du Colombier 		if(ns == 0 || ns == s)
4713e12c5d1SDavid du Colombier 			continue;
4723e12c5d1SDavid du Colombier 		if(newtop >= ns->base && newtop < ns->top) {
4733e12c5d1SDavid du Colombier 			qunlock(&s->lk);
4743e12c5d1SDavid du Colombier 			error(Esoverlap);
4753e12c5d1SDavid du Colombier 		}
4763e12c5d1SDavid du Colombier 	}
4773e12c5d1SDavid du Colombier 
4787dd7cddfSDavid du Colombier 	if(newsize > (SEGMAPSIZE*PTEPERTAB)) {
4793e12c5d1SDavid du Colombier 		qunlock(&s->lk);
4803e12c5d1SDavid du Colombier 		error(Enovmem);
4813e12c5d1SDavid du Colombier 	}
4827dd7cddfSDavid du Colombier 	mapsize = ROUND(newsize, PTEPERTAB)/PTEPERTAB;
4837dd7cddfSDavid du Colombier 	if(mapsize > s->mapsize){
4847dd7cddfSDavid du Colombier 		map = smalloc(mapsize*sizeof(Pte*));
4857dd7cddfSDavid du Colombier 		memmove(map, s->map, s->mapsize*sizeof(Pte*));
4867dd7cddfSDavid du Colombier 		if(s->map != s->ssegmap)
4877dd7cddfSDavid du Colombier 			free(s->map);
4887dd7cddfSDavid du Colombier 		s->map = map;
4897dd7cddfSDavid du Colombier 		s->mapsize = mapsize;
4907dd7cddfSDavid du Colombier 	}
4913e12c5d1SDavid du Colombier 
4923e12c5d1SDavid du Colombier 	s->top = newtop;
4933e12c5d1SDavid du Colombier 	s->size = newsize;
4943e12c5d1SDavid du Colombier 	qunlock(&s->lk);
4953e12c5d1SDavid du Colombier 	return 0;
4963e12c5d1SDavid du Colombier }
4973e12c5d1SDavid du Colombier 
4987dd7cddfSDavid du Colombier /*
4997dd7cddfSDavid du Colombier  *  called with s->lk locked
5007dd7cddfSDavid du Colombier  */
5013e12c5d1SDavid du Colombier void
5023e12c5d1SDavid du Colombier mfreeseg(Segment *s, ulong start, int pages)
5033e12c5d1SDavid du Colombier {
5047dd7cddfSDavid du Colombier 	int i, j, size;
5053e12c5d1SDavid du Colombier 	ulong soff;
5063e12c5d1SDavid du Colombier 	Page *pg;
5077dd7cddfSDavid du Colombier 	Page *list;
5083e12c5d1SDavid du Colombier 
5093e12c5d1SDavid du Colombier 	soff = start-s->base;
5103e12c5d1SDavid du Colombier 	j = (soff&(PTEMAPMEM-1))/BY2PG;
5113e12c5d1SDavid du Colombier 
5127dd7cddfSDavid du Colombier 	size = s->mapsize;
5137dd7cddfSDavid du Colombier 	list = nil;
5147dd7cddfSDavid du Colombier 	for(i = soff/PTEMAPMEM; i < size; i++) {
5153e12c5d1SDavid du Colombier 		if(pages <= 0)
516bd389b36SDavid du Colombier 			break;
517bd389b36SDavid du Colombier 		if(s->map[i] == 0) {
518bd389b36SDavid du Colombier 			pages -= PTEPERTAB-j;
519bd389b36SDavid du Colombier 			j = 0;
520bd389b36SDavid du Colombier 			continue;
521bd389b36SDavid du Colombier 		}
5223e12c5d1SDavid du Colombier 		while(j < PTEPERTAB) {
523bd389b36SDavid du Colombier 			pg = s->map[i]->pages[j];
5243ff48bf5SDavid du Colombier 			/*
5253ff48bf5SDavid du Colombier 			 * We want to zero s->map[i]->page[j] and putpage(pg),
5264de34a7eSDavid du Colombier 			 * but we have to make sure other processors flush the
5273ff48bf5SDavid du Colombier 			 * entry from their TLBs before the page is freed.
5283ff48bf5SDavid du Colombier 			 * We construct a list of the pages to be freed, zero
5293ff48bf5SDavid du Colombier 			 * the entries, then (below) call procflushseg, and call
5303ff48bf5SDavid du Colombier 			 * putpage on the whole list.
5313ff48bf5SDavid du Colombier 			 *
5323ff48bf5SDavid du Colombier 			 * Swapped-out pages don't appear in TLBs, so it's okay
5333ff48bf5SDavid du Colombier 			 * to putswap those pages before procflushseg.
5343ff48bf5SDavid du Colombier 			 */
535bd389b36SDavid du Colombier 			if(pg){
5363ff48bf5SDavid du Colombier 				if(onswap(pg))
5373ff48bf5SDavid du Colombier 					putswap(pg);
5383ff48bf5SDavid du Colombier 				else{
5397dd7cddfSDavid du Colombier 					pg->next = list;
5407dd7cddfSDavid du Colombier 					list = pg;
5413e12c5d1SDavid du Colombier 				}
5423ff48bf5SDavid du Colombier 				s->map[i]->pages[j] = 0;
5433ff48bf5SDavid du Colombier 			}
5443e12c5d1SDavid du Colombier 			if(--pages == 0)
5457dd7cddfSDavid du Colombier 				goto out;
5463e12c5d1SDavid du Colombier 			j++;
5473e12c5d1SDavid du Colombier 		}
5483e12c5d1SDavid du Colombier 		j = 0;
5493e12c5d1SDavid du Colombier 	}
5507dd7cddfSDavid du Colombier out:
5517dd7cddfSDavid du Colombier 	/* flush this seg in all other processes */
5529a747e4fSDavid du Colombier 	if(s->ref > 1)
5537dd7cddfSDavid du Colombier 		procflushseg(s);
5543e12c5d1SDavid du Colombier 
5557dd7cddfSDavid du Colombier 	/* free the pages */
5567dd7cddfSDavid du Colombier 	for(pg = list; pg != nil; pg = list){
5577dd7cddfSDavid du Colombier 		list = list->next;
5587dd7cddfSDavid du Colombier 		putpage(pg);
5597dd7cddfSDavid du Colombier 	}
5607dd7cddfSDavid du Colombier }
5617dd7cddfSDavid du Colombier 
5627dd7cddfSDavid du Colombier Segment*
5637dd7cddfSDavid du Colombier isoverlap(Proc *p, ulong va, int len)
564219b2ee8SDavid du Colombier {
565219b2ee8SDavid du Colombier 	int i;
566219b2ee8SDavid du Colombier 	Segment *ns;
567219b2ee8SDavid du Colombier 	ulong newtop;
568219b2ee8SDavid du Colombier 
569219b2ee8SDavid du Colombier 	newtop = va+len;
570219b2ee8SDavid du Colombier 	for(i = 0; i < NSEG; i++) {
5717dd7cddfSDavid du Colombier 		ns = p->seg[i];
572219b2ee8SDavid du Colombier 		if(ns == 0)
573219b2ee8SDavid du Colombier 			continue;
574219b2ee8SDavid du Colombier 		if((newtop > ns->base && newtop <= ns->top) ||
575219b2ee8SDavid du Colombier 		   (va >= ns->base && va < ns->top))
5767dd7cddfSDavid du Colombier 			return ns;
577219b2ee8SDavid du Colombier 	}
5787dd7cddfSDavid du Colombier 	return nil;
5797dd7cddfSDavid du Colombier }
5807dd7cddfSDavid du Colombier 
5817dd7cddfSDavid du Colombier int
5827dd7cddfSDavid du Colombier addphysseg(Physseg* new)
5837dd7cddfSDavid du Colombier {
5847dd7cddfSDavid du Colombier 	Physseg *ps;
5857dd7cddfSDavid du Colombier 
5867dd7cddfSDavid du Colombier 	/*
5877dd7cddfSDavid du Colombier 	 * Check not already entered and there is room
5887dd7cddfSDavid du Colombier 	 * for a new entry and the terminating null entry.
5897dd7cddfSDavid du Colombier 	 */
5907dd7cddfSDavid du Colombier 	lock(&physseglock);
5917dd7cddfSDavid du Colombier 	for(ps = physseg; ps->name; ps++){
5927dd7cddfSDavid du Colombier 		if(strcmp(ps->name, new->name) == 0){
5937dd7cddfSDavid du Colombier 			unlock(&physseglock);
5947dd7cddfSDavid du Colombier 			return -1;
5957dd7cddfSDavid du Colombier 		}
5967dd7cddfSDavid du Colombier 	}
5977dd7cddfSDavid du Colombier 	if(ps-physseg >= nelem(physseg)-2){
5987dd7cddfSDavid du Colombier 		unlock(&physseglock);
5997dd7cddfSDavid du Colombier 		return -1;
6007dd7cddfSDavid du Colombier 	}
6017dd7cddfSDavid du Colombier 
6027dd7cddfSDavid du Colombier 	*ps = *new;
6037dd7cddfSDavid du Colombier 	unlock(&physseglock);
6047dd7cddfSDavid du Colombier 
605219b2ee8SDavid du Colombier 	return 0;
606219b2ee8SDavid du Colombier }
607219b2ee8SDavid du Colombier 
6089a747e4fSDavid du Colombier int
6099a747e4fSDavid du Colombier isphysseg(char *name)
6109a747e4fSDavid du Colombier {
6119a747e4fSDavid du Colombier 	Physseg *ps;
6129a747e4fSDavid du Colombier 	int rv = 0;
6139a747e4fSDavid du Colombier 
6149a747e4fSDavid du Colombier 	lock(&physseglock);
6159a747e4fSDavid du Colombier 	for(ps = physseg; ps->name; ps++){
6169a747e4fSDavid du Colombier 		if(strcmp(ps->name, name) == 0){
6179a747e4fSDavid du Colombier 			rv = 1;
6189a747e4fSDavid du Colombier 			break;
6199a747e4fSDavid du Colombier 		}
6209a747e4fSDavid du Colombier 	}
6219a747e4fSDavid du Colombier 	unlock(&physseglock);
6229a747e4fSDavid du Colombier 	return rv;
6239a747e4fSDavid du Colombier }
6249a747e4fSDavid du Colombier 
6253e12c5d1SDavid du Colombier ulong
6263e12c5d1SDavid du Colombier segattach(Proc *p, ulong attr, char *name, ulong va, ulong len)
6273e12c5d1SDavid du Colombier {
6287dd7cddfSDavid du Colombier 	int sno;
6297dd7cddfSDavid du Colombier 	Segment *s, *os;
630219b2ee8SDavid du Colombier 	Physseg *ps;
6313e12c5d1SDavid du Colombier 
6324de34a7eSDavid du Colombier 	if(va != 0 && va >= USTKTOP)
6333e12c5d1SDavid du Colombier 		error(Ebadarg);
6343e12c5d1SDavid du Colombier 
6353e12c5d1SDavid du Colombier 	validaddr((ulong)name, 1, 0);
6363e12c5d1SDavid du Colombier 	vmemchr(name, 0, ~0);
6373e12c5d1SDavid du Colombier 
6383e12c5d1SDavid du Colombier 	for(sno = 0; sno < NSEG; sno++)
6397dd7cddfSDavid du Colombier 		if(p->seg[sno] == nil && sno != ESEG)
6403e12c5d1SDavid du Colombier 			break;
6413e12c5d1SDavid du Colombier 
6423e12c5d1SDavid du Colombier 	if(sno == NSEG)
6433e12c5d1SDavid du Colombier 		error(Enovmem);
6443e12c5d1SDavid du Colombier 
6459a747e4fSDavid du Colombier 	/*
6469a747e4fSDavid du Colombier 	 *  first look for a global segment with the
6479a747e4fSDavid du Colombier 	 *  same name
6489a747e4fSDavid du Colombier 	 */
6499a747e4fSDavid du Colombier 	if(_globalsegattach != nil){
6509a747e4fSDavid du Colombier 		s = (*_globalsegattach)(p, name);
6519a747e4fSDavid du Colombier 		if(s != nil){
6529a747e4fSDavid du Colombier 			p->seg[sno] = s;
6539a747e4fSDavid du Colombier 			return s->base;
6549a747e4fSDavid du Colombier 		}
6559a747e4fSDavid du Colombier 	}
6569a747e4fSDavid du Colombier 
6573e12c5d1SDavid du Colombier 	len = PGROUND(len);
6587dd7cddfSDavid du Colombier 	if(len == 0)
6597dd7cddfSDavid du Colombier 		error(Ebadarg);
660219b2ee8SDavid du Colombier 
6617dd7cddfSDavid du Colombier 	/*
6627dd7cddfSDavid du Colombier 	 * Find a hole in the address space.
6637dd7cddfSDavid du Colombier 	 * Starting at the lowest possible stack address - len,
6647dd7cddfSDavid du Colombier 	 * check for an overlapping segment, and repeat at the
6657dd7cddfSDavid du Colombier 	 * base of that segment - len until either a hole is found
6667dd7cddfSDavid du Colombier 	 * or the address space is exhausted.
6677dd7cddfSDavid du Colombier 	 */
668219b2ee8SDavid du Colombier 	if(va == 0) {
669219b2ee8SDavid du Colombier 		va = p->seg[SSEG]->base - len;
6707dd7cddfSDavid du Colombier 		for(;;) {
6717dd7cddfSDavid du Colombier 			os = isoverlap(p, va, len);
6727dd7cddfSDavid du Colombier 			if(os == nil)
673219b2ee8SDavid du Colombier 				break;
6747dd7cddfSDavid du Colombier 			va = os->base;
6757dd7cddfSDavid du Colombier 			if(len > va)
6767dd7cddfSDavid du Colombier 				error(Enovmem);
677219b2ee8SDavid du Colombier 			va -= len;
6783e12c5d1SDavid du Colombier 		}
679219b2ee8SDavid du Colombier 	}
680219b2ee8SDavid du Colombier 
681219b2ee8SDavid du Colombier 	va = va&~(BY2PG-1);
6827dd7cddfSDavid du Colombier 	if(isoverlap(p, va, len) != nil)
683219b2ee8SDavid du Colombier 		error(Esoverlap);
6843e12c5d1SDavid du Colombier 
6853e12c5d1SDavid du Colombier 	for(ps = physseg; ps->name; ps++)
6863e12c5d1SDavid du Colombier 		if(strcmp(name, ps->name) == 0)
6873e12c5d1SDavid du Colombier 			goto found;
6883e12c5d1SDavid du Colombier 
6893e12c5d1SDavid du Colombier 	error(Ebadarg);
6903e12c5d1SDavid du Colombier found:
6913e12c5d1SDavid du Colombier 	if(len > ps->size)
6923e12c5d1SDavid du Colombier 		error(Enovmem);
6933e12c5d1SDavid du Colombier 
6947dd7cddfSDavid du Colombier 	attr &= ~SG_TYPE;		/* Turn off what is not allowed */
6953e12c5d1SDavid du Colombier 	attr |= ps->attr;		/* Copy in defaults */
6963e12c5d1SDavid du Colombier 
6973e12c5d1SDavid du Colombier 	s = newseg(attr, va, len/BY2PG);
698219b2ee8SDavid du Colombier 	s->pseg = ps;
6997dd7cddfSDavid du Colombier 	p->seg[sno] = s;
7003e12c5d1SDavid du Colombier 
701219b2ee8SDavid du Colombier 	return va;
7023e12c5d1SDavid du Colombier }
7033e12c5d1SDavid du Colombier 
704219b2ee8SDavid du Colombier void
705219b2ee8SDavid du Colombier pteflush(Pte *pte, int s, int e)
706219b2ee8SDavid du Colombier {
707219b2ee8SDavid du Colombier 	int i;
708219b2ee8SDavid du Colombier 	Page *p;
709219b2ee8SDavid du Colombier 
710219b2ee8SDavid du Colombier 	for(i = s; i < e; i++) {
711219b2ee8SDavid du Colombier 		p = pte->pages[i];
712219b2ee8SDavid du Colombier 		if(pagedout(p) == 0)
713219b2ee8SDavid du Colombier 			memset(p->cachectl, PG_TXTFLUSH, sizeof(p->cachectl));
714219b2ee8SDavid du Colombier 	}
715219b2ee8SDavid du Colombier }
716219b2ee8SDavid du Colombier 
7173e12c5d1SDavid du Colombier long
7183e12c5d1SDavid du Colombier syssegflush(ulong *arg)
7197dd7cddfSDavid du Colombier {
7207dd7cddfSDavid du Colombier 	Segment *s;
721219b2ee8SDavid du Colombier 	ulong addr, l;
722219b2ee8SDavid du Colombier 	Pte *pte;
723219b2ee8SDavid du Colombier 	int chunk, ps, pe, len;
7243e12c5d1SDavid du Colombier 
725219b2ee8SDavid du Colombier 	addr = arg[0];
726219b2ee8SDavid du Colombier 	len = arg[1];
727219b2ee8SDavid du Colombier 
728219b2ee8SDavid du Colombier 	while(len > 0) {
7297dd7cddfSDavid du Colombier 		s = seg(up, addr, 1);
7303e12c5d1SDavid du Colombier 		if(s == 0)
7313e12c5d1SDavid du Colombier 			error(Ebadarg);
7323e12c5d1SDavid du Colombier 
7333e12c5d1SDavid du Colombier 		s->flushme = 1;
734219b2ee8SDavid du Colombier 	more:
735219b2ee8SDavid du Colombier 		l = len;
736219b2ee8SDavid du Colombier 		if(addr+l > s->top)
737219b2ee8SDavid du Colombier 			l = s->top - addr;
7383e12c5d1SDavid du Colombier 
739219b2ee8SDavid du Colombier 		ps = addr-s->base;
740219b2ee8SDavid du Colombier 		pte = s->map[ps/PTEMAPMEM];
741219b2ee8SDavid du Colombier 		ps &= PTEMAPMEM-1;
742219b2ee8SDavid du Colombier 		pe = PTEMAPMEM;
743219b2ee8SDavid du Colombier 		if(pe-ps > l){
744219b2ee8SDavid du Colombier 			pe = ps + l;
745219b2ee8SDavid du Colombier 			pe = (pe+BY2PG-1)&~(BY2PG-1);
7463e12c5d1SDavid du Colombier 		}
747219b2ee8SDavid du Colombier 		if(pe == ps) {
7483e12c5d1SDavid du Colombier 			qunlock(&s->lk);
749219b2ee8SDavid du Colombier 			error(Ebadarg);
750219b2ee8SDavid du Colombier 		}
751219b2ee8SDavid du Colombier 
752219b2ee8SDavid du Colombier 		if(pte)
753219b2ee8SDavid du Colombier 			pteflush(pte, ps/BY2PG, pe/BY2PG);
754219b2ee8SDavid du Colombier 
755219b2ee8SDavid du Colombier 		chunk = pe-ps;
756219b2ee8SDavid du Colombier 		len -= chunk;
757219b2ee8SDavid du Colombier 		addr += chunk;
758219b2ee8SDavid du Colombier 
759219b2ee8SDavid du Colombier 		if(len > 0 && addr < s->top)
760219b2ee8SDavid du Colombier 			goto more;
761219b2ee8SDavid du Colombier 
762219b2ee8SDavid du Colombier 		qunlock(&s->lk);
763219b2ee8SDavid du Colombier 	}
7643e12c5d1SDavid du Colombier 	flushmmu();
7653e12c5d1SDavid du Colombier 	return 0;
7663e12c5d1SDavid du Colombier }
7677dd7cddfSDavid du Colombier 
7687dd7cddfSDavid du Colombier void
7697dd7cddfSDavid du Colombier segclock(ulong pc)
7707dd7cddfSDavid du Colombier {
7717dd7cddfSDavid du Colombier 	Segment *s;
7727dd7cddfSDavid du Colombier 
7737dd7cddfSDavid du Colombier 	s = up->seg[TSEG];
7747dd7cddfSDavid du Colombier 	if(s == 0 || s->profile == 0)
7757dd7cddfSDavid du Colombier 		return;
7767dd7cddfSDavid du Colombier 
7777dd7cddfSDavid du Colombier 	s->profile[0] += TK2MS(1);
7787dd7cddfSDavid du Colombier 	if(pc >= s->base && pc < s->top) {
7797dd7cddfSDavid du Colombier 		pc -= s->base;
7807dd7cddfSDavid du Colombier 		s->profile[pc>>LRESPROF] += TK2MS(1);
7817dd7cddfSDavid du Colombier 	}
7827dd7cddfSDavid du Colombier }
783