xref: /plan9-contrib/sys/src/9k/port/sysseg.c (revision 0d74731bc0e92f599316bb993220a7ecf480c626)
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* (*_globalsegattach)(Proc*, char*);
99ef1f84bSDavid du Colombier 
109ef1f84bSDavid du Colombier static Lock physseglock;
119ef1f84bSDavid du Colombier 
129ef1f84bSDavid du Colombier int
addphysseg(Physseg * new)139ef1f84bSDavid du Colombier addphysseg(Physseg* new)
149ef1f84bSDavid du Colombier {
159ef1f84bSDavid du Colombier 	Physseg *ps;
169ef1f84bSDavid du Colombier 
179ef1f84bSDavid du Colombier 	/*
189ef1f84bSDavid du Colombier 	 * Check not already entered and there is room
199ef1f84bSDavid du Colombier 	 * for a new entry and the terminating null entry.
209ef1f84bSDavid du Colombier 	 */
219ef1f84bSDavid du Colombier 	lock(&physseglock);
229ef1f84bSDavid du Colombier 	for(ps = physseg; ps->name; ps++){
239ef1f84bSDavid du Colombier 		if(strcmp(ps->name, new->name) == 0){
249ef1f84bSDavid du Colombier 			unlock(&physseglock);
259ef1f84bSDavid du Colombier 			return -1;
269ef1f84bSDavid du Colombier 		}
279ef1f84bSDavid du Colombier 	}
289ef1f84bSDavid du Colombier 	if(ps-physseg >= nphysseg-2){
299ef1f84bSDavid du Colombier 		unlock(&physseglock);
309ef1f84bSDavid du Colombier 		return -1;
319ef1f84bSDavid du Colombier 	}
329ef1f84bSDavid du Colombier 
339ef1f84bSDavid du Colombier 	*ps = *new;
349ef1f84bSDavid du Colombier 	unlock(&physseglock);
359ef1f84bSDavid du Colombier 
369ef1f84bSDavid du Colombier 	return 0;
379ef1f84bSDavid du Colombier }
389ef1f84bSDavid du Colombier 
399ef1f84bSDavid du Colombier int
isphysseg(char * name)409ef1f84bSDavid du Colombier isphysseg(char *name)
419ef1f84bSDavid du Colombier {
429ef1f84bSDavid du Colombier 	int rv;
439ef1f84bSDavid du Colombier 	Physseg *ps;
449ef1f84bSDavid du Colombier 
459ef1f84bSDavid du Colombier 	lock(&physseglock);
469ef1f84bSDavid du Colombier 	rv = 0;
479ef1f84bSDavid du Colombier 	for(ps = physseg; ps->name; ps++){
489ef1f84bSDavid du Colombier 		if(strcmp(ps->name, name) == 0){
499ef1f84bSDavid du Colombier 			rv = 1;
509ef1f84bSDavid du Colombier 			break;
519ef1f84bSDavid du Colombier 		}
529ef1f84bSDavid du Colombier 	}
539ef1f84bSDavid du Colombier 	unlock(&physseglock);
549ef1f84bSDavid du Colombier 	return rv;
559ef1f84bSDavid du Colombier }
569ef1f84bSDavid du Colombier 
579ef1f84bSDavid du Colombier /* Needs to be non-static for BGP support */
589ef1f84bSDavid du Colombier uintptr
ibrk(uintptr addr,int seg)599ef1f84bSDavid du Colombier ibrk(uintptr addr, int seg)
609ef1f84bSDavid du Colombier {
619ef1f84bSDavid du Colombier 	Segment *s, *ns;
629ef1f84bSDavid du Colombier 	uintptr newtop, pgsize;
639ef1f84bSDavid du Colombier 	usize newsize;
649ef1f84bSDavid du Colombier 	int i, mapsize;
659ef1f84bSDavid du Colombier 	Pte **map;
669ef1f84bSDavid du Colombier 
679ef1f84bSDavid du Colombier 	s = up->seg[seg];
684498a243SDavid du Colombier 	if(s == nil)
699ef1f84bSDavid du Colombier 		error(Ebadarg);
709ef1f84bSDavid du Colombier 
719ef1f84bSDavid du Colombier 	if(addr == 0)
729ef1f84bSDavid du Colombier 		return s->top;
739ef1f84bSDavid du Colombier 
749ef1f84bSDavid du Colombier 	qlock(&s->lk);
7535a7d776SDavid du Colombier 	if(waserror()){
7635a7d776SDavid du Colombier 		qunlock(&s->lk);
7735a7d776SDavid du Colombier 		nexterror();
7835a7d776SDavid du Colombier 	}
799ef1f84bSDavid du Colombier 
809ef1f84bSDavid du Colombier 	/* We may start with the bss overlapping the data */
819ef1f84bSDavid du Colombier 	if(addr < s->base) {
824498a243SDavid du Colombier 		if(seg != BSEG || up->seg[DSEG] == nil || addr < up->seg[DSEG]->base)
839ef1f84bSDavid du Colombier 			error(Enovmem);
849ef1f84bSDavid du Colombier 		addr = s->base;
859ef1f84bSDavid du Colombier 	}
869ef1f84bSDavid du Colombier 
8757fe3081SDavid du Colombier 	pgsize = segpgsize(s);
889ef1f84bSDavid du Colombier 	newtop = ROUNDUP(addr, pgsize);
899ef1f84bSDavid du Colombier 	newsize = (newtop-s->base)/pgsize;
909ef1f84bSDavid du Colombier 	if(newtop < s->top) {
919ef1f84bSDavid du Colombier 		/*
929ef1f84bSDavid du Colombier 		 * do not shrink a segment shared with other procs, as the
939ef1f84bSDavid du Colombier 		 * to-be-freed address space may have been passed to the kernel
949ef1f84bSDavid du Colombier 		 * already by another proc and is past the validaddr stage.
959ef1f84bSDavid du Colombier 		 */
9635a7d776SDavid du Colombier 		if(s->ref > 1)
979ef1f84bSDavid du Colombier 			error(Einuse);
989ef1f84bSDavid du Colombier 		mfreeseg(s, newtop, s->top);
999ef1f84bSDavid du Colombier 		s->top = newtop;
10035a7d776SDavid du Colombier 		poperror();
1019ef1f84bSDavid du Colombier 		s->size = newsize;
1029ef1f84bSDavid du Colombier 		qunlock(&s->lk);
1039ef1f84bSDavid du Colombier 		mmuflush();
1049ef1f84bSDavid du Colombier 		return newtop;
1059ef1f84bSDavid du Colombier 	}
1069ef1f84bSDavid du Colombier 
1079ef1f84bSDavid du Colombier 	for(i = 0; i < NSEG; i++) {
1089ef1f84bSDavid du Colombier 		ns = up->seg[i];
1094498a243SDavid du Colombier 		if(ns == nil || ns == s)
1109ef1f84bSDavid du Colombier 			continue;
1111105a4a2SDavid du Colombier 		if(newtop > ns->base && s->base < ns->top)
1129ef1f84bSDavid du Colombier 			error(Esoverlap);
1139ef1f84bSDavid du Colombier 	}
1149ef1f84bSDavid du Colombier 
1159ef1f84bSDavid du Colombier 	mapsize = HOWMANY(newsize, PTEPERTAB);
11635a7d776SDavid du Colombier 	if(mapsize > SEGMAPSIZE)
1179ef1f84bSDavid du Colombier 		error(Enovmem);
1189ef1f84bSDavid du Colombier 	if(mapsize > s->mapsize){
1199ef1f84bSDavid du Colombier 		map = smalloc(mapsize*sizeof(Pte*));
1209ef1f84bSDavid du Colombier 		memmove(map, s->map, s->mapsize*sizeof(Pte*));
1219ef1f84bSDavid du Colombier 		if(s->map != s->ssegmap)
1229ef1f84bSDavid du Colombier 			free(s->map);
1239ef1f84bSDavid du Colombier 		s->map = map;
1249ef1f84bSDavid du Colombier 		s->mapsize = mapsize;
1259ef1f84bSDavid du Colombier 	}
1269ef1f84bSDavid du Colombier 
1279ef1f84bSDavid du Colombier 	s->top = newtop;
1289ef1f84bSDavid du Colombier 	s->size = newsize;
12935a7d776SDavid du Colombier 
13035a7d776SDavid du Colombier 	poperror();
1319ef1f84bSDavid du Colombier 	qunlock(&s->lk);
1329ef1f84bSDavid du Colombier 
1339ef1f84bSDavid du Colombier 	return newtop;
1349ef1f84bSDavid du Colombier }
1359ef1f84bSDavid du Colombier 
1369ef1f84bSDavid du Colombier void
syssegbrk(Ar0 * ar0,va_list list)1379ef1f84bSDavid du Colombier syssegbrk(Ar0* ar0, va_list list)
1389ef1f84bSDavid du Colombier {
1399ef1f84bSDavid du Colombier 	int i;
1409ef1f84bSDavid du Colombier 	uintptr addr;
1419ef1f84bSDavid du Colombier 	Segment *s;
1429ef1f84bSDavid du Colombier 
1439ef1f84bSDavid du Colombier 	/*
1449ef1f84bSDavid du Colombier 	 * int segbrk(void*, void*);
1459ef1f84bSDavid du Colombier 	 * should be
1469ef1f84bSDavid du Colombier 	 * void* segbrk(void* saddr, void* addr);
1479ef1f84bSDavid du Colombier 	 */
1489ef1f84bSDavid du Colombier 	addr = PTR2UINT(va_arg(list, void*));
1499ef1f84bSDavid du Colombier 	for(i = 0; i < NSEG; i++) {
1509ef1f84bSDavid du Colombier 		s = up->seg[i];
1519ef1f84bSDavid du Colombier 		if(s == nil || addr < s->base || addr >= s->top)
1529ef1f84bSDavid du Colombier 			continue;
1539ef1f84bSDavid du Colombier 		switch(s->type&SG_TYPE) {
1549ef1f84bSDavid du Colombier 		case SG_TEXT:
1559ef1f84bSDavid du Colombier 		case SG_DATA:
1569ef1f84bSDavid du Colombier 		case SG_STACK:
1579ef1f84bSDavid du Colombier 			error(Ebadarg);
1589ef1f84bSDavid du Colombier 		default:
1599ef1f84bSDavid du Colombier 			addr = PTR2UINT(va_arg(list, void*));
1609ef1f84bSDavid du Colombier 			ar0->v = UINT2PTR(ibrk(addr, i));
1619ef1f84bSDavid du Colombier 			return;
1629ef1f84bSDavid du Colombier 		}
1639ef1f84bSDavid du Colombier 	}
1649ef1f84bSDavid du Colombier 	error(Ebadarg);
1659ef1f84bSDavid du Colombier }
1669ef1f84bSDavid du Colombier 
1679ef1f84bSDavid du Colombier void
sysbrk_(Ar0 * ar0,va_list list)1689ef1f84bSDavid du Colombier sysbrk_(Ar0* ar0, va_list list)
1699ef1f84bSDavid du Colombier {
1709ef1f84bSDavid du Colombier 	uintptr addr;
1719ef1f84bSDavid du Colombier 
1729ef1f84bSDavid du Colombier 	/*
1739ef1f84bSDavid du Colombier 	 * int brk(void*);
1749ef1f84bSDavid du Colombier 	 *
1759ef1f84bSDavid du Colombier 	 * Deprecated; should be for backwards compatibility only.
1769ef1f84bSDavid du Colombier 	 */
1779ef1f84bSDavid du Colombier 	addr = PTR2UINT(va_arg(list, void*));
1789ef1f84bSDavid du Colombier 
1799ef1f84bSDavid du Colombier 	ibrk(addr, BSEG);
1809ef1f84bSDavid du Colombier 
1819ef1f84bSDavid du Colombier 	ar0->i = 0;
1829ef1f84bSDavid du Colombier }
1839ef1f84bSDavid du Colombier 
1849ef1f84bSDavid du Colombier static uintptr
segattach(Proc * p,int attr,char * name,uintptr va,usize len)1859ef1f84bSDavid du Colombier segattach(Proc* p, int attr, char* name, uintptr va, usize len)
1869ef1f84bSDavid du Colombier {
1879ef1f84bSDavid du Colombier 	int sno;
1889ef1f84bSDavid du Colombier 	Segment *s, *os;
1899ef1f84bSDavid du Colombier 	Physseg *ps;
190c4f97bc1SDavid du Colombier 	uintptr pgsize;
1919ef1f84bSDavid du Colombier 
1929ef1f84bSDavid du Colombier 	/* BUG: Only ok for now */
193fe56f827SDavid du Colombier 	if((va != 0 && va < UTZERO) || iskaddr(va))
1949ef1f84bSDavid du Colombier 		error("virtual address in kernel");
1959ef1f84bSDavid du Colombier 
1969ef1f84bSDavid du Colombier 	vmemchr(name, 0, ~0);
1979ef1f84bSDavid du Colombier 
1989ef1f84bSDavid du Colombier 	for(sno = 0; sno < NSEG; sno++)
1999ef1f84bSDavid du Colombier 		if(p->seg[sno] == nil && sno != ESEG)
2009ef1f84bSDavid du Colombier 			break;
2019ef1f84bSDavid du Colombier 
2029ef1f84bSDavid du Colombier 	if(sno == NSEG)
2039ef1f84bSDavid du Colombier 		error("too many segments in process");
2049ef1f84bSDavid du Colombier 
2059ef1f84bSDavid du Colombier 	/*
2069ef1f84bSDavid du Colombier 	 *  first look for a global segment with the
2079ef1f84bSDavid du Colombier 	 *  same name
2089ef1f84bSDavid du Colombier 	 */
2099ef1f84bSDavid du Colombier 	if(_globalsegattach != nil){
2109ef1f84bSDavid du Colombier 		s = (*_globalsegattach)(p, name);
2119ef1f84bSDavid du Colombier 		if(s != nil){
2129ef1f84bSDavid du Colombier 			p->seg[sno] = s;
2139ef1f84bSDavid du Colombier 			return s->base;
2149ef1f84bSDavid du Colombier 		}
2159ef1f84bSDavid du Colombier 	}
2169ef1f84bSDavid du Colombier 
217c4f97bc1SDavid du Colombier 	for(ps = physseg; ps->name; ps++)
218c4f97bc1SDavid du Colombier 		if(strcmp(name, ps->name) == 0)
219c4f97bc1SDavid du Colombier 			goto found;
220c4f97bc1SDavid du Colombier 
221c4f97bc1SDavid du Colombier 	error("segment not found");
222c4f97bc1SDavid du Colombier found:
223c4f97bc1SDavid du Colombier 	pgsize = physsegpgsize(ps);
224c4f97bc1SDavid du Colombier 	len = ROUNDUP(len, pgsize);
2259ef1f84bSDavid du Colombier 	if(len == 0)
2269ef1f84bSDavid du Colombier 		error("length overflow");
2279ef1f84bSDavid du Colombier 
2289ef1f84bSDavid du Colombier 	/*
2299ef1f84bSDavid du Colombier 	 * Find a hole in the address space.
2309ef1f84bSDavid du Colombier 	 * Starting at the lowest possible stack address - len,
2319ef1f84bSDavid du Colombier 	 * check for an overlapping segment, and repeat at the
2329ef1f84bSDavid du Colombier 	 * base of that segment - len until either a hole is found
2339ef1f84bSDavid du Colombier 	 * or the address space is exhausted.
2349ef1f84bSDavid du Colombier 	 */
2359ef1f84bSDavid du Colombier //need check here to prevent mapping page 0?
2369ef1f84bSDavid du Colombier 	if(va == 0) {
2379ef1f84bSDavid du Colombier 		va = p->seg[SSEG]->base - len;
2389ef1f84bSDavid du Colombier 		for(;;) {
2399ef1f84bSDavid du Colombier 			os = isoverlap(p, va, len);
2409ef1f84bSDavid du Colombier 			if(os == nil)
2419ef1f84bSDavid du Colombier 				break;
2429ef1f84bSDavid du Colombier 			va = os->base;
2439ef1f84bSDavid du Colombier 			if(len > va)
2449ef1f84bSDavid du Colombier 				error("cannot fit segment at virtual address");
2459ef1f84bSDavid du Colombier 			va -= len;
2469ef1f84bSDavid du Colombier 		}
2479ef1f84bSDavid du Colombier 	}
2489ef1f84bSDavid du Colombier 
249c4f97bc1SDavid du Colombier 	va = va&~(pgsize-1);
2509ef1f84bSDavid du Colombier 	if(isoverlap(p, va, len) != nil)
2519ef1f84bSDavid du Colombier 		error(Esoverlap);
2529ef1f84bSDavid du Colombier 
253c4f97bc1SDavid du Colombier 	if((len/pgsize) > ps->size)
2549ef1f84bSDavid du Colombier 		error("len > segment size");
2559ef1f84bSDavid du Colombier 
2569ef1f84bSDavid du Colombier 	attr &= ~SG_TYPE;		/* Turn off what is not allowed */
2579ef1f84bSDavid du Colombier 	attr |= ps->attr;		/* Copy in defaults */
2589ef1f84bSDavid du Colombier 
2599ef1f84bSDavid du Colombier 	s = newseg(attr, va, va+len);
2609ef1f84bSDavid du Colombier 	s->pseg = ps;
2619ef1f84bSDavid du Colombier 	p->seg[sno] = s;
2629ef1f84bSDavid du Colombier 
2639ef1f84bSDavid du Colombier 	return va;
2649ef1f84bSDavid du Colombier }
2659ef1f84bSDavid du Colombier 
2669ef1f84bSDavid du Colombier void
syssegattach(Ar0 * ar0,va_list list)2679ef1f84bSDavid du Colombier syssegattach(Ar0* ar0, va_list list)
2689ef1f84bSDavid du Colombier {
2699ef1f84bSDavid du Colombier 	int attr;
2709ef1f84bSDavid du Colombier 	char *name;
2719ef1f84bSDavid du Colombier 	uintptr va;
2729ef1f84bSDavid du Colombier 	usize len;
2739ef1f84bSDavid du Colombier 
2749ef1f84bSDavid du Colombier 	/*
2759ef1f84bSDavid du Colombier 	 * long segattach(int, char*, void*, ulong);
2769ef1f84bSDavid du Colombier 	 * should be
2779ef1f84bSDavid du Colombier 	 * void* segattach(int, char*, void*, usize);
2789ef1f84bSDavid du Colombier 	 */
2799ef1f84bSDavid du Colombier 	attr = va_arg(list, int);
2809ef1f84bSDavid du Colombier 	name = va_arg(list, char*);
2819ef1f84bSDavid du Colombier 	va = PTR2UINT(va_arg(list, void*));
2829ef1f84bSDavid du Colombier 	len = va_arg(list, usize);
2839ef1f84bSDavid du Colombier 
2849ef1f84bSDavid du Colombier 	ar0->v = UINT2PTR(segattach(up, attr, validaddr(name, 1, 0), va, len));
2859ef1f84bSDavid du Colombier }
2869ef1f84bSDavid du Colombier 
2879ef1f84bSDavid du Colombier void
syssegdetach(Ar0 * ar0,va_list list)2889ef1f84bSDavid du Colombier syssegdetach(Ar0* ar0, va_list list)
2899ef1f84bSDavid du Colombier {
2909ef1f84bSDavid du Colombier 	int i;
2919ef1f84bSDavid du Colombier 	uintptr addr;
2929ef1f84bSDavid du Colombier 	Segment *s;
2939ef1f84bSDavid du Colombier 
2949ef1f84bSDavid du Colombier 	/*
2959ef1f84bSDavid du Colombier 	 * int segdetach(void*);
2969ef1f84bSDavid du Colombier 	 */
2979ef1f84bSDavid du Colombier 	addr = PTR2UINT(va_arg(list, void*));
2989ef1f84bSDavid du Colombier 
2999ef1f84bSDavid du Colombier 	qlock(&up->seglock);
3009ef1f84bSDavid du Colombier 	if(waserror()){
3019ef1f84bSDavid du Colombier 		qunlock(&up->seglock);
3029ef1f84bSDavid du Colombier 		nexterror();
3039ef1f84bSDavid du Colombier 	}
3049ef1f84bSDavid du Colombier 
3059ef1f84bSDavid du Colombier 	s = 0;
3069ef1f84bSDavid du Colombier 	for(i = 0; i < NSEG; i++)
3079ef1f84bSDavid du Colombier 		if(s = up->seg[i]) {
3089ef1f84bSDavid du Colombier 			qlock(&s->lk);
3099ef1f84bSDavid du Colombier 			if((addr >= s->base && addr < s->top) ||
3109ef1f84bSDavid du Colombier 			   (s->top == s->base && addr == s->base))
3119ef1f84bSDavid du Colombier 				goto found;
3129ef1f84bSDavid du Colombier 			qunlock(&s->lk);
3139ef1f84bSDavid du Colombier 		}
3149ef1f84bSDavid du Colombier 
3159ef1f84bSDavid du Colombier 	error(Ebadarg);
3169ef1f84bSDavid du Colombier 
3179ef1f84bSDavid du Colombier found:
3189ef1f84bSDavid du Colombier 	/*
3199ef1f84bSDavid du Colombier 	 * Can't detach the initial stack segment
3209ef1f84bSDavid du Colombier 	 * because the clock writes profiling info
3219ef1f84bSDavid du Colombier 	 * there.
3229ef1f84bSDavid du Colombier 	 */
3239ef1f84bSDavid du Colombier 	if(s == up->seg[SSEG]){
3249ef1f84bSDavid du Colombier 		qunlock(&s->lk);
3259ef1f84bSDavid du Colombier 		error(Ebadarg);
3269ef1f84bSDavid du Colombier 	}
3279ef1f84bSDavid du Colombier 	up->seg[i] = 0;
3289ef1f84bSDavid du Colombier 	qunlock(&s->lk);
3299ef1f84bSDavid du Colombier 	putseg(s);
3309ef1f84bSDavid du Colombier 	qunlock(&up->seglock);
3319ef1f84bSDavid du Colombier 	poperror();
3329ef1f84bSDavid du Colombier 
3339ef1f84bSDavid du Colombier 	/* Ensure we flush any entries from the lost segment */
3349ef1f84bSDavid du Colombier 	mmuflush();
3359ef1f84bSDavid du Colombier 
3369ef1f84bSDavid du Colombier 	ar0->i = 0;
3379ef1f84bSDavid du Colombier }
3389ef1f84bSDavid du Colombier 
3399ef1f84bSDavid du Colombier void
syssegfree(Ar0 * ar0,va_list list)3409ef1f84bSDavid du Colombier syssegfree(Ar0* ar0, va_list list)
3419ef1f84bSDavid du Colombier {
3429ef1f84bSDavid du Colombier 	Segment *s;
343c4f97bc1SDavid du Colombier 	uintptr from, to, pgsize;
3449ef1f84bSDavid du Colombier 	usize len;
3459ef1f84bSDavid du Colombier 
3469ef1f84bSDavid du Colombier 	/*
3479ef1f84bSDavid du Colombier 	 * int segfree(void*, ulong);
3489ef1f84bSDavid du Colombier 	 * should be
3499ef1f84bSDavid du Colombier 	 * int segfree(void*, usize);
3509ef1f84bSDavid du Colombier 	 */
3519ef1f84bSDavid du Colombier 	from = PTR2UINT(va_arg(list, void*));
3529ef1f84bSDavid du Colombier 	s = seg(up, from, 1);
3539ef1f84bSDavid du Colombier 	if(s == nil)
3549ef1f84bSDavid du Colombier 		error(Ebadarg);
3559ef1f84bSDavid du Colombier 	len = va_arg(list, usize);
356c4f97bc1SDavid du Colombier 	pgsize = segpgsize(s);
357c4f97bc1SDavid du Colombier 	to = (from + len) & ~(pgsize-1);
3589ef1f84bSDavid du Colombier 	if(to < from || to > s->top){
3599ef1f84bSDavid du Colombier 		qunlock(&s->lk);
3609ef1f84bSDavid du Colombier 		error(Ebadarg);
3619ef1f84bSDavid du Colombier 	}
362c4f97bc1SDavid du Colombier 	from = ROUNDUP(from, pgsize);
3639ef1f84bSDavid du Colombier 
3649ef1f84bSDavid du Colombier 	mfreeseg(s, from, to);
3659ef1f84bSDavid du Colombier 	qunlock(&s->lk);
3669ef1f84bSDavid du Colombier 	mmuflush();
3679ef1f84bSDavid du Colombier 
3689ef1f84bSDavid du Colombier 	ar0->i = 0;
3699ef1f84bSDavid du Colombier }
3709ef1f84bSDavid du Colombier 
3719ef1f84bSDavid du Colombier static void
pteflush(Pte * pte,int s,int e)3729ef1f84bSDavid du Colombier pteflush(Pte *pte, int s, int e)
3739ef1f84bSDavid du Colombier {
3749ef1f84bSDavid du Colombier 	int i;
3759ef1f84bSDavid du Colombier 
376*0d74731bSDavid du Colombier 	for(i = s; i < e; i++)
377*0d74731bSDavid du Colombier 		mmucachectl(pte->pages[i], PG_TXTFLUSH);
3789ef1f84bSDavid du Colombier }
3799ef1f84bSDavid du Colombier 
3809ef1f84bSDavid du Colombier void
syssegflush(Ar0 * ar0,va_list list)3819ef1f84bSDavid du Colombier syssegflush(Ar0* ar0, va_list list)
3829ef1f84bSDavid du Colombier {
3839ef1f84bSDavid du Colombier 	Segment *s;
3849ef1f84bSDavid du Colombier 	uintptr addr, pgsize;
3859ef1f84bSDavid du Colombier 	Pte *pte;
3869ef1f84bSDavid du Colombier 	usize chunk, l, len, pe, ps;
3879ef1f84bSDavid du Colombier 
3889ef1f84bSDavid du Colombier 	/*
3899ef1f84bSDavid du Colombier 	 * int segflush(void*, ulong);
3909ef1f84bSDavid du Colombier 	 * should be
3919ef1f84bSDavid du Colombier 	 * int segflush(void*, usize);
3929ef1f84bSDavid du Colombier 	 */
3939ef1f84bSDavid du Colombier 	addr = PTR2UINT(va_arg(list, void*));
3949ef1f84bSDavid du Colombier 	len = va_arg(list, usize);
3959ef1f84bSDavid du Colombier 
3969ef1f84bSDavid du Colombier 	while(len > 0) {
3979ef1f84bSDavid du Colombier 		s = seg(up, addr, 1);
3989ef1f84bSDavid du Colombier 		if(s == nil)
3999ef1f84bSDavid du Colombier 			error(Ebadarg);
4009ef1f84bSDavid du Colombier 
4019ef1f84bSDavid du Colombier 		s->flushme = 1;
40257fe3081SDavid du Colombier 		pgsize = segpgsize(s);
4039ef1f84bSDavid du Colombier 	more:
4049ef1f84bSDavid du Colombier 		l = len;
4059ef1f84bSDavid du Colombier 		if(addr+l > s->top)
4069ef1f84bSDavid du Colombier 			l = s->top - addr;
4079ef1f84bSDavid du Colombier 
4089ef1f84bSDavid du Colombier 		ps = addr-s->base;
4099ef1f84bSDavid du Colombier 		pte = s->map[ps/s->ptemapmem];
4109ef1f84bSDavid du Colombier 		ps &= s->ptemapmem-1;
4119ef1f84bSDavid du Colombier 		pe = s->ptemapmem;
4129ef1f84bSDavid du Colombier 		if(pe-ps > l){
4139ef1f84bSDavid du Colombier 			pe = ps + l;
4149ef1f84bSDavid du Colombier 			pe = (pe+pgsize-1)&~(pgsize-1);
4159ef1f84bSDavid du Colombier 		}
4169ef1f84bSDavid du Colombier 		if(pe == ps) {
4179ef1f84bSDavid du Colombier 			qunlock(&s->lk);
4189ef1f84bSDavid du Colombier 			error(Ebadarg);
4199ef1f84bSDavid du Colombier 		}
4209ef1f84bSDavid du Colombier 
4219ef1f84bSDavid du Colombier 		if(pte)
4229ef1f84bSDavid du Colombier 			pteflush(pte, ps/pgsize, pe/pgsize);
4239ef1f84bSDavid du Colombier 
4249ef1f84bSDavid du Colombier 		chunk = pe-ps;
4259ef1f84bSDavid du Colombier 		len -= chunk;
4269ef1f84bSDavid du Colombier 		addr += chunk;
4279ef1f84bSDavid du Colombier 
4289ef1f84bSDavid du Colombier 		if(len > 0 && addr < s->top)
4299ef1f84bSDavid du Colombier 			goto more;
4309ef1f84bSDavid du Colombier 
4319ef1f84bSDavid du Colombier 		qunlock(&s->lk);
4329ef1f84bSDavid du Colombier 	}
4339ef1f84bSDavid du Colombier 	mmuflush();
4349ef1f84bSDavid du Colombier 
4359ef1f84bSDavid du Colombier 	ar0->i = 0;
4369ef1f84bSDavid du Colombier }
437