xref: /plan9-contrib/sys/src/9k/port/segment.c (revision 094d68186d4cdde21fdab9786d6c843a03693e4e)
19ef1f84bSDavid du Colombier #include	"u.h"
29ef1f84bSDavid du Colombier #include	"../port/lib.h"
39ef1f84bSDavid du Colombier #include	"mem.h"
49ef1f84bSDavid du Colombier #include	"dat.h"
59ef1f84bSDavid du Colombier #include	"fns.h"
69ef1f84bSDavid du Colombier #include	"../port/error.h"
79ef1f84bSDavid du Colombier 
89ef1f84bSDavid du Colombier Segment *
newseg(int type,uintptr base,uintptr top)99ef1f84bSDavid du Colombier newseg(int type, uintptr base, uintptr top)
109ef1f84bSDavid du Colombier {
119ef1f84bSDavid du Colombier 	Segment *s;
129ef1f84bSDavid du Colombier 	int mapsize;
139ef1f84bSDavid du Colombier 	usize size;
149ef1f84bSDavid du Colombier 
159ef1f84bSDavid du Colombier 	if((base|top) & (PGSZ-1))
169ef1f84bSDavid du Colombier 		panic("newseg");
179ef1f84bSDavid du Colombier 
189ef1f84bSDavid du Colombier 	size = (top-base)/PGSZ;
199ef1f84bSDavid du Colombier 	if(size > (SEGMAPSIZE*PTEPERTAB))
209ef1f84bSDavid du Colombier 		error(Enovmem);
219ef1f84bSDavid du Colombier 
229ef1f84bSDavid du Colombier 	s = smalloc(sizeof(Segment));
239ef1f84bSDavid du Colombier 	s->ref = 1;
249ef1f84bSDavid du Colombier 	s->type = type;
259ef1f84bSDavid du Colombier 	s->base = base;
269ef1f84bSDavid du Colombier 	s->top = top;
279ef1f84bSDavid du Colombier 	s->size = size;
289ef1f84bSDavid du Colombier 	s->lg2pgsize = PGSHFT;
299ef1f84bSDavid du Colombier 	s->ptemapmem = PTEPERTAB<<s->lg2pgsize;
309ef1f84bSDavid du Colombier 	s->sema.prev = &s->sema;
319ef1f84bSDavid du Colombier 	s->sema.next = &s->sema;
329ef1f84bSDavid du Colombier 
339ef1f84bSDavid du Colombier 	mapsize = HOWMANY(size, PTEPERTAB);
349ef1f84bSDavid du Colombier 	if(mapsize > nelem(s->ssegmap)){
359ef1f84bSDavid du Colombier 		mapsize *= 2;
369ef1f84bSDavid du Colombier 		if(mapsize > SEGMAPSIZE)
379ef1f84bSDavid du Colombier 			mapsize = SEGMAPSIZE;
389ef1f84bSDavid du Colombier 		s->map = smalloc(mapsize*sizeof(Pte*));
399ef1f84bSDavid du Colombier 		s->mapsize = mapsize;
409ef1f84bSDavid du Colombier 	}
419ef1f84bSDavid du Colombier 	else{
429ef1f84bSDavid du Colombier 		s->map = s->ssegmap;
439ef1f84bSDavid du Colombier 		s->mapsize = nelem(s->ssegmap);
449ef1f84bSDavid du Colombier 	}
459ef1f84bSDavid du Colombier 
469ef1f84bSDavid du Colombier 	return s;
479ef1f84bSDavid du Colombier }
489ef1f84bSDavid du Colombier 
499ef1f84bSDavid du Colombier void
putseg(Segment * s)509ef1f84bSDavid du Colombier putseg(Segment *s)
519ef1f84bSDavid du Colombier {
529ef1f84bSDavid du Colombier 	Pte **pp, **emap;
539ef1f84bSDavid du Colombier 	Image *i;
549ef1f84bSDavid du Colombier 
554498a243SDavid du Colombier 	if(s == nil)
569ef1f84bSDavid du Colombier 		return;
579ef1f84bSDavid du Colombier 
589ef1f84bSDavid du Colombier 	i = s->image;
594498a243SDavid du Colombier 	if(i != nil) {
609ef1f84bSDavid du Colombier 		lock(i);
619ef1f84bSDavid du Colombier 		lock(s);
629ef1f84bSDavid du Colombier 		if(i->s == s && s->ref == 1)
639ef1f84bSDavid du Colombier 			i->s = 0;
649ef1f84bSDavid du Colombier 		unlock(i);
659ef1f84bSDavid du Colombier 	}
669ef1f84bSDavid du Colombier 	else
679ef1f84bSDavid du Colombier 		lock(s);
689ef1f84bSDavid du Colombier 
699ef1f84bSDavid du Colombier 	s->ref--;
709ef1f84bSDavid du Colombier 	if(s->ref != 0) {
719ef1f84bSDavid du Colombier 		unlock(s);
729ef1f84bSDavid du Colombier 		return;
739ef1f84bSDavid du Colombier 	}
749ef1f84bSDavid du Colombier 	unlock(s);
759ef1f84bSDavid du Colombier 
769ef1f84bSDavid du Colombier 	qlock(&s->lk);
779ef1f84bSDavid du Colombier 	if(i)
789ef1f84bSDavid du Colombier 		putimage(i);
799ef1f84bSDavid du Colombier 
809ef1f84bSDavid du Colombier 	emap = &s->map[s->mapsize];
819ef1f84bSDavid du Colombier 	for(pp = s->map; pp < emap; pp++)
824498a243SDavid du Colombier 		if(*pp != nil)
839ef1f84bSDavid du Colombier 			freepte(s, *pp);
849ef1f84bSDavid du Colombier 
859ef1f84bSDavid du Colombier 	qunlock(&s->lk);
869ef1f84bSDavid du Colombier 	if(s->map != s->ssegmap)
879ef1f84bSDavid du Colombier 		free(s->map);
884498a243SDavid du Colombier 	if(s->profile != nil)
899ef1f84bSDavid du Colombier 		free(s->profile);
909ef1f84bSDavid du Colombier 	free(s);
919ef1f84bSDavid du Colombier }
929ef1f84bSDavid du Colombier 
939ef1f84bSDavid du Colombier void
relocateseg(Segment * s,uintptr offset)949ef1f84bSDavid du Colombier relocateseg(Segment *s, uintptr offset)
959ef1f84bSDavid du Colombier {
969ef1f84bSDavid du Colombier 	Page **pg, *x;
979ef1f84bSDavid du Colombier 	Pte *pte, **p, **endpte;
989ef1f84bSDavid du Colombier 
999ef1f84bSDavid du Colombier 	endpte = &s->map[s->mapsize];
1009ef1f84bSDavid du Colombier 	for(p = s->map; p < endpte; p++) {
1019ef1f84bSDavid du Colombier 		if(*p == 0)
1029ef1f84bSDavid du Colombier 			continue;
1039ef1f84bSDavid du Colombier 		pte = *p;
1049ef1f84bSDavid du Colombier 		for(pg = pte->first; pg <= pte->last; pg++) {
1059ef1f84bSDavid du Colombier 			if(x = *pg)
1069ef1f84bSDavid du Colombier 				x->va += offset;
1079ef1f84bSDavid du Colombier 		}
1089ef1f84bSDavid du Colombier 	}
1099ef1f84bSDavid du Colombier }
1109ef1f84bSDavid du Colombier 
1119ef1f84bSDavid du Colombier Segment*
dupseg(Segment ** seg,int segno,int share)1129ef1f84bSDavid du Colombier dupseg(Segment **seg, int segno, int share)
1139ef1f84bSDavid du Colombier {
1149ef1f84bSDavid du Colombier 	int i, size;
1159ef1f84bSDavid du Colombier 	Pte *pte;
1169ef1f84bSDavid du Colombier 	Segment *n, *s;
1179ef1f84bSDavid du Colombier 
1189ef1f84bSDavid du Colombier 	SET(n);
1199ef1f84bSDavid du Colombier 	s = seg[segno];
1209ef1f84bSDavid du Colombier 
1219ef1f84bSDavid du Colombier 	qlock(&s->lk);
1229ef1f84bSDavid du Colombier 	if(waserror()){
1239ef1f84bSDavid du Colombier 		qunlock(&s->lk);
1249ef1f84bSDavid du Colombier 		nexterror();
1259ef1f84bSDavid du Colombier 	}
1269ef1f84bSDavid du Colombier 	switch(s->type&SG_TYPE) {
1279ef1f84bSDavid du Colombier 	case SG_TEXT:		/* New segment shares pte set */
1289ef1f84bSDavid du Colombier 	case SG_SHARED:
1299ef1f84bSDavid du Colombier 	case SG_PHYSICAL:
1309ef1f84bSDavid du Colombier 		goto sameseg;
1319ef1f84bSDavid du Colombier 
1329ef1f84bSDavid du Colombier 	case SG_STACK:
1339ef1f84bSDavid du Colombier 		n = newseg(s->type, s->base, s->top);
1349ef1f84bSDavid du Colombier 		break;
1359ef1f84bSDavid du Colombier 
1369ef1f84bSDavid du Colombier 	case SG_BSS:		/* Just copy on write */
1379ef1f84bSDavid du Colombier 		if(share)
1389ef1f84bSDavid du Colombier 			goto sameseg;
1399ef1f84bSDavid du Colombier 		n = newseg(s->type, s->base, s->top);
1409ef1f84bSDavid du Colombier 		break;
1419ef1f84bSDavid du Colombier 
1429ef1f84bSDavid du Colombier 	case SG_DATA:		/* Copy on write plus demand load info */
1439ef1f84bSDavid du Colombier 		if(segno == TSEG){
1449ef1f84bSDavid du Colombier 			poperror();
1459ef1f84bSDavid du Colombier 			qunlock(&s->lk);
1469ef1f84bSDavid du Colombier 			return data2txt(s);
1479ef1f84bSDavid du Colombier 		}
1489ef1f84bSDavid du Colombier 
1499ef1f84bSDavid du Colombier 		if(share)
1509ef1f84bSDavid du Colombier 			goto sameseg;
1519ef1f84bSDavid du Colombier 		n = newseg(s->type, s->base, s->top);
1529ef1f84bSDavid du Colombier 
1539ef1f84bSDavid du Colombier 		incref(s->image);
1549ef1f84bSDavid du Colombier 		n->image = s->image;
1559ef1f84bSDavid du Colombier 		n->fstart = s->fstart;
1569ef1f84bSDavid du Colombier 		n->flen = s->flen;
157a8c2c03cSDavid du Colombier 		n->lg2pgsize = s->lg2pgsize;
158*094d6818SDavid du Colombier 		n->color = s->color;
1599ef1f84bSDavid du Colombier 		break;
1609ef1f84bSDavid du Colombier 	}
1619ef1f84bSDavid du Colombier 	size = s->mapsize;
1629ef1f84bSDavid du Colombier 	for(i = 0; i < size; i++)
1634498a243SDavid du Colombier 		if((pte = s->map[i]) != nil)
1649ef1f84bSDavid du Colombier 			n->map[i] = ptecpy(pte);
1659ef1f84bSDavid du Colombier 
1669ef1f84bSDavid du Colombier 	n->flushme = s->flushme;
1679ef1f84bSDavid du Colombier 	if(s->ref > 1)
1689ef1f84bSDavid du Colombier 		procflushseg(s);
1699ef1f84bSDavid du Colombier 	poperror();
1709ef1f84bSDavid du Colombier 	qunlock(&s->lk);
1719ef1f84bSDavid du Colombier 	return n;
1729ef1f84bSDavid du Colombier 
1739ef1f84bSDavid du Colombier sameseg:
1749ef1f84bSDavid du Colombier 	incref(s);
1759ef1f84bSDavid du Colombier 	poperror();
1769ef1f84bSDavid du Colombier 	qunlock(&s->lk);
1779ef1f84bSDavid du Colombier 	return s;
1789ef1f84bSDavid du Colombier }
1799ef1f84bSDavid du Colombier 
1809ef1f84bSDavid du Colombier void
segpage(Segment * s,Page * p)1819ef1f84bSDavid du Colombier segpage(Segment *s, Page *p)
1829ef1f84bSDavid du Colombier {
1839ef1f84bSDavid du Colombier 	Pte **pte;
1849ef1f84bSDavid du Colombier 	uintptr soff;
1859ef1f84bSDavid du Colombier 	Page **pg;
1869ef1f84bSDavid du Colombier 
187*094d6818SDavid du Colombier 	if(s->color == NOCOLOR)
188*094d6818SDavid du Colombier 		s->color = p->color;
189*094d6818SDavid du Colombier 
1909ef1f84bSDavid du Colombier 	if(p->va < s->base || p->va >= s->top)
1919ef1f84bSDavid du Colombier 		panic("segpage");
1929ef1f84bSDavid du Colombier 
1939ef1f84bSDavid du Colombier 	soff = p->va - s->base;
1949ef1f84bSDavid du Colombier 	pte = &s->map[soff/s->ptemapmem];
1959ef1f84bSDavid du Colombier 	if(*pte == 0)
1969ef1f84bSDavid du Colombier 		*pte = ptealloc();
1979ef1f84bSDavid du Colombier 
1989ef1f84bSDavid du Colombier 	pg = &(*pte)->pages[(soff&(s->ptemapmem-1))>>s->lg2pgsize];
1999ef1f84bSDavid du Colombier 	*pg = p;
2009ef1f84bSDavid du Colombier 	if(pg < (*pte)->first)
2019ef1f84bSDavid du Colombier 		(*pte)->first = pg;
2029ef1f84bSDavid du Colombier 	if(pg > (*pte)->last)
2039ef1f84bSDavid du Colombier 		(*pte)->last = pg;
2049ef1f84bSDavid du Colombier }
2059ef1f84bSDavid du Colombier 
2069ef1f84bSDavid du Colombier /*
2079ef1f84bSDavid du Colombier  *  called with s->lk locked
2089ef1f84bSDavid du Colombier  */
2099ef1f84bSDavid du Colombier void
mfreeseg(Segment * s,uintptr start,uintptr top)2109ef1f84bSDavid du Colombier mfreeseg(Segment *s, uintptr start, uintptr top)
2119ef1f84bSDavid du Colombier {
2129ef1f84bSDavid du Colombier 	int i, j, size;
2139ef1f84bSDavid du Colombier 	usize pages;
2149ef1f84bSDavid du Colombier 	uintptr soff;
2159ef1f84bSDavid du Colombier 	Page *pg;
2169ef1f84bSDavid du Colombier 	Page *list;
2179ef1f84bSDavid du Colombier 
2189ef1f84bSDavid du Colombier 	pages = (top-start)>>s->lg2pgsize;
2199ef1f84bSDavid du Colombier 	soff = start-s->base;
2209ef1f84bSDavid du Colombier 	j = (soff&(s->ptemapmem-1))>>s->lg2pgsize;
2219ef1f84bSDavid du Colombier 
2229ef1f84bSDavid du Colombier 	size = s->mapsize;
2239ef1f84bSDavid du Colombier 	list = nil;
2249ef1f84bSDavid du Colombier 	for(i = soff/s->ptemapmem; i < size; i++) {
2259ef1f84bSDavid du Colombier 		if(pages <= 0)
2269ef1f84bSDavid du Colombier 			break;
2279ef1f84bSDavid du Colombier 		if(s->map[i] == 0) {
2289ef1f84bSDavid du Colombier 			pages -= PTEPERTAB-j;
2299ef1f84bSDavid du Colombier 			j = 0;
2309ef1f84bSDavid du Colombier 			continue;
2319ef1f84bSDavid du Colombier 		}
2329ef1f84bSDavid du Colombier 		while(j < PTEPERTAB) {
2339ef1f84bSDavid du Colombier 			pg = s->map[i]->pages[j];
2349ef1f84bSDavid du Colombier 			/*
2359ef1f84bSDavid du Colombier 			 * We want to zero s->map[i]->page[j] and putpage(pg),
2369ef1f84bSDavid du Colombier 			 * but we have to make sure other processors flush the
2379ef1f84bSDavid du Colombier 			 * entry from their TLBs before the page is freed.
2389ef1f84bSDavid du Colombier 			 * We construct a list of the pages to be freed, zero
2399ef1f84bSDavid du Colombier 			 * the entries, then (below) call procflushseg, and call
2409ef1f84bSDavid du Colombier 			 * putpage on the whole list. If swapping were implemented,
2419ef1f84bSDavid du Colombier 			 * paged-out pages can't be in a TLB and could be disposed of here.
2429ef1f84bSDavid du Colombier 			 */
2439ef1f84bSDavid du Colombier 			if(pg != nil){
2449ef1f84bSDavid du Colombier 				pg->next = list;
2459ef1f84bSDavid du Colombier 				list = pg;
2469ef1f84bSDavid du Colombier 				s->map[i]->pages[j] = nil;
2479ef1f84bSDavid du Colombier 			}
2489ef1f84bSDavid du Colombier 			if(--pages == 0)
2499ef1f84bSDavid du Colombier 				goto out;
2509ef1f84bSDavid du Colombier 			j++;
2519ef1f84bSDavid du Colombier 		}
2529ef1f84bSDavid du Colombier 		j = 0;
2539ef1f84bSDavid du Colombier 	}
2549ef1f84bSDavid du Colombier out:
2559ef1f84bSDavid du Colombier 	/* flush this seg in all other processes */
2569ef1f84bSDavid du Colombier 	if(s->ref > 1)
2579ef1f84bSDavid du Colombier 		procflushseg(s);
2589ef1f84bSDavid du Colombier 
2599ef1f84bSDavid du Colombier 	/* free the pages */
2609ef1f84bSDavid du Colombier 	for(pg = list; pg != nil; pg = list){
2619ef1f84bSDavid du Colombier 		list = list->next;
2629ef1f84bSDavid du Colombier 		putpage(pg);
2639ef1f84bSDavid du Colombier 	}
2649ef1f84bSDavid du Colombier }
2659ef1f84bSDavid du Colombier 
2669ef1f84bSDavid du Colombier Segment*
isoverlap(Proc * p,uintptr va,usize len)2679ef1f84bSDavid du Colombier isoverlap(Proc* p, uintptr va, usize len)
2689ef1f84bSDavid du Colombier {
2699ef1f84bSDavid du Colombier 	int i;
2709ef1f84bSDavid du Colombier 	Segment *ns;
2719ef1f84bSDavid du Colombier 	uintptr newtop;
2729ef1f84bSDavid du Colombier 
2739ef1f84bSDavid du Colombier 	newtop = va+len;
2749ef1f84bSDavid du Colombier 	for(i = 0; i < NSEG; i++) {
2759ef1f84bSDavid du Colombier 		ns = p->seg[i];
2764498a243SDavid du Colombier 		if(ns == nil)
2779ef1f84bSDavid du Colombier 			continue;
2781105a4a2SDavid du Colombier 		if(newtop > ns->base && va < ns->top)
2799ef1f84bSDavid du Colombier 			return ns;
2809ef1f84bSDavid du Colombier 	}
2819ef1f84bSDavid du Colombier 	return nil;
2829ef1f84bSDavid du Colombier }
2839ef1f84bSDavid du Colombier 
2849ef1f84bSDavid du Colombier void
segclock(uintptr pc)2859ef1f84bSDavid du Colombier segclock(uintptr pc)
2869ef1f84bSDavid du Colombier {
2879ef1f84bSDavid du Colombier 	Segment *s;
2889ef1f84bSDavid du Colombier 
2899ef1f84bSDavid du Colombier 	s = up->seg[TSEG];
2904498a243SDavid du Colombier 	if(s == nil || s->profile == nil)
2919ef1f84bSDavid du Colombier 		return;
2929ef1f84bSDavid du Colombier 
2939ef1f84bSDavid du Colombier 	s->profile[0] += TK2MS(1);
2949ef1f84bSDavid du Colombier 	if(pc >= s->base && pc < s->top) {
2959ef1f84bSDavid du Colombier 		pc -= s->base;
2969ef1f84bSDavid du Colombier 		s->profile[pc>>LRESPROF] += TK2MS(1);
2979ef1f84bSDavid du Colombier 	}
2989ef1f84bSDavid du Colombier }
299