xref: /plan9/sys/src/9/port/fault.c (revision 0400b64795cb7922fbea5587531527b381e1e588)
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 
83e12c5d1SDavid du Colombier int
fault(ulong addr,int read)93e12c5d1SDavid du Colombier fault(ulong addr, int read)
103e12c5d1SDavid du Colombier {
113e12c5d1SDavid du Colombier 	Segment *s;
123e12c5d1SDavid du Colombier 	char *sps;
133e12c5d1SDavid du Colombier 
14b8a11165SDavid du Colombier 	if(up == nil)
15b8a11165SDavid du Colombier 		panic("fault: nil up");
16b8a11165SDavid du Colombier 	if(up->nlocks.ref)
1723173ec1SDavid du Colombier 		print("fault: addr %#p: nlocks %ld\n", addr, up->nlocks.ref);
18e288d156SDavid du Colombier 
197dd7cddfSDavid du Colombier 	sps = up->psstate;
207dd7cddfSDavid du Colombier 	up->psstate = "Fault";
213e12c5d1SDavid du Colombier 	spllo();
223e12c5d1SDavid du Colombier 
233e12c5d1SDavid du Colombier 	m->pfault++;
24*0400b647SDavid du Colombier 	for(;;) {
257dd7cddfSDavid du Colombier 		s = seg(up, addr, 1);		/* leaves s->lk qlocked if seg != nil */
263e12c5d1SDavid du Colombier 		if(s == 0) {
277dd7cddfSDavid du Colombier 			up->psstate = sps;
283e12c5d1SDavid du Colombier 			return -1;
293e12c5d1SDavid du Colombier 		}
303e12c5d1SDavid du Colombier 
313e12c5d1SDavid du Colombier 		if(!read && (s->type&SG_RONLY)) {
323e12c5d1SDavid du Colombier 			qunlock(&s->lk);
337dd7cddfSDavid du Colombier 			up->psstate = sps;
343e12c5d1SDavid du Colombier 			return -1;
353e12c5d1SDavid du Colombier 		}
363e12c5d1SDavid du Colombier 
37afa28516SDavid du Colombier 		if(fixfault(s, addr, read, 1) == 0)	/* qunlocks s->lk */
383e12c5d1SDavid du Colombier 			break;
393e12c5d1SDavid du Colombier 	}
403e12c5d1SDavid du Colombier 
417dd7cddfSDavid du Colombier 	up->psstate = sps;
423e12c5d1SDavid du Colombier 	return 0;
433e12c5d1SDavid du Colombier }
443e12c5d1SDavid du Colombier 
457dd7cddfSDavid du Colombier static void
faulterror(char * s,Chan * c,int freemem)469a747e4fSDavid du Colombier faulterror(char *s, Chan *c, int freemem)
477dd7cddfSDavid du Colombier {
489a747e4fSDavid du Colombier 	char buf[ERRMAX];
499a747e4fSDavid du Colombier 
504afe124fSDavid du Colombier 	if(c && c->path){
514afe124fSDavid du Colombier 		snprint(buf, sizeof buf, "%s accessing %s: %s", s, c->path->s, up->errstr);
529a747e4fSDavid du Colombier 		s = buf;
539a747e4fSDavid du Colombier 	}
547dd7cddfSDavid du Colombier 	if(up->nerrlab) {
557dd7cddfSDavid du Colombier 		postnote(up, 1, s, NDebug);
567dd7cddfSDavid du Colombier 		error(s);
577dd7cddfSDavid du Colombier 	}
587dd7cddfSDavid du Colombier 	pexit(s, freemem);
597dd7cddfSDavid du Colombier }
607dd7cddfSDavid du Colombier 
61ea58ad6fSDavid du Colombier void	(*checkaddr)(ulong, Segment *, Page *);
62ea58ad6fSDavid du Colombier ulong	addr2check;
63ea58ad6fSDavid du Colombier 
643e12c5d1SDavid du Colombier int
fixfault(Segment * s,ulong addr,int read,int doputmmu)653e12c5d1SDavid du Colombier fixfault(Segment *s, ulong addr, int read, int doputmmu)
663e12c5d1SDavid du Colombier {
67219b2ee8SDavid du Colombier 	int type;
687dd7cddfSDavid du Colombier 	int ref;
69219b2ee8SDavid du Colombier 	Pte **p, *etp;
709a747e4fSDavid du Colombier 	ulong mmuphys=0, soff;
713e12c5d1SDavid du Colombier 	Page **pg, *lkp, *new;
72219b2ee8SDavid du Colombier 	Page *(*fn)(Segment*, ulong);
733e12c5d1SDavid du Colombier 
743e12c5d1SDavid du Colombier 	addr &= ~(BY2PG-1);
753e12c5d1SDavid du Colombier 	soff = addr-s->base;
763e12c5d1SDavid du Colombier 	p = &s->map[soff/PTEMAPMEM];
773e12c5d1SDavid du Colombier 	if(*p == 0)
783e12c5d1SDavid du Colombier 		*p = ptealloc();
793e12c5d1SDavid du Colombier 
803e12c5d1SDavid du Colombier 	etp = *p;
813e12c5d1SDavid du Colombier 	pg = &etp->pages[(soff&(PTEMAPMEM-1))/BY2PG];
823e12c5d1SDavid du Colombier 	type = s->type&SG_TYPE;
833e12c5d1SDavid du Colombier 
843e12c5d1SDavid du Colombier 	if(pg < etp->first)
853e12c5d1SDavid du Colombier 		etp->first = pg;
863e12c5d1SDavid du Colombier 	if(pg > etp->last)
873e12c5d1SDavid du Colombier 		etp->last = pg;
883e12c5d1SDavid du Colombier 
893e12c5d1SDavid du Colombier 	switch(type) {
903e12c5d1SDavid du Colombier 	default:
913e12c5d1SDavid du Colombier 		panic("fault");
923e12c5d1SDavid du Colombier 		break;
933e12c5d1SDavid du Colombier 
947dd7cddfSDavid du Colombier 	case SG_TEXT: 			/* Demand load */
957dd7cddfSDavid du Colombier 		if(pagedout(*pg))
963e12c5d1SDavid du Colombier 			pio(s, addr, soff, pg);
973e12c5d1SDavid du Colombier 
983e12c5d1SDavid du Colombier 		mmuphys = PPN((*pg)->pa) | PTERONLY|PTEVALID;
993e12c5d1SDavid du Colombier 		(*pg)->modref = PG_REF;
1003e12c5d1SDavid du Colombier 		break;
1013e12c5d1SDavid du Colombier 
1023e12c5d1SDavid du Colombier 	case SG_BSS:
1033e12c5d1SDavid du Colombier 	case SG_SHARED:			/* Zero fill on demand */
1043e12c5d1SDavid du Colombier 	case SG_STACK:
1053e12c5d1SDavid du Colombier 		if(*pg == 0) {
1063e12c5d1SDavid du Colombier 			new = newpage(1, &s, addr);
1073e12c5d1SDavid du Colombier 			if(s == 0)
1083e12c5d1SDavid du Colombier 				return -1;
1093e12c5d1SDavid du Colombier 
1103e12c5d1SDavid du Colombier 			*pg = new;
1113e12c5d1SDavid du Colombier 		}
1127dd7cddfSDavid du Colombier 		goto common;
1133e12c5d1SDavid du Colombier 
1147dd7cddfSDavid du Colombier 	case SG_DATA:
1157dd7cddfSDavid du Colombier 	common:			/* Demand load/pagein/copy on write */
1163e12c5d1SDavid du Colombier 		if(pagedout(*pg))
1173e12c5d1SDavid du Colombier 			pio(s, addr, soff, pg);
1183e12c5d1SDavid du Colombier 
11980ee5cbfSDavid du Colombier 		/*
12080ee5cbfSDavid du Colombier 		 *  It's only possible to copy on write if
12180ee5cbfSDavid du Colombier 		 *  we're the only user of the segment.
12280ee5cbfSDavid du Colombier 		 */
12380ee5cbfSDavid du Colombier 		if(read && conf.copymode == 0 && s->ref == 1) {
1243e12c5d1SDavid du Colombier 			mmuphys = PPN((*pg)->pa)|PTERONLY|PTEVALID;
1253e12c5d1SDavid du Colombier 			(*pg)->modref |= PG_REF;
1263e12c5d1SDavid du Colombier 			break;
1273e12c5d1SDavid du Colombier 		}
1283e12c5d1SDavid du Colombier 
1293e12c5d1SDavid du Colombier 		lkp = *pg;
1303e12c5d1SDavid du Colombier 		lock(lkp);
1317dd7cddfSDavid du Colombier 
1327dd7cddfSDavid du Colombier 		if(lkp->image == &swapimage)
1337dd7cddfSDavid du Colombier 			ref = lkp->ref + swapcount(lkp->daddr);
1347dd7cddfSDavid du Colombier 		else
1357dd7cddfSDavid du Colombier 			ref = lkp->ref;
136afa28516SDavid du Colombier 		if(ref == 1 && lkp->image){
137afa28516SDavid du Colombier 			/* save a copy of the original for the image cache */
138afa28516SDavid du Colombier 			duppage(lkp);
139afa28516SDavid du Colombier 			ref = lkp->ref;
140afa28516SDavid du Colombier 		}
1413e12c5d1SDavid du Colombier 		unlock(lkp);
142afa28516SDavid du Colombier 		if(ref > 1){
1433e12c5d1SDavid du Colombier 			new = newpage(0, &s, addr);
1443e12c5d1SDavid du Colombier 			if(s == 0)
1453e12c5d1SDavid du Colombier 				return -1;
1463e12c5d1SDavid du Colombier 			*pg = new;
1473e12c5d1SDavid du Colombier 			copypage(lkp, *pg);
1483e12c5d1SDavid du Colombier 			putpage(lkp);
1493e12c5d1SDavid du Colombier 		}
1503e12c5d1SDavid du Colombier 		mmuphys = PPN((*pg)->pa) | PTEWRITE | PTEVALID;
1513e12c5d1SDavid du Colombier 		(*pg)->modref = PG_MOD|PG_REF;
1523e12c5d1SDavid du Colombier 		break;
1533e12c5d1SDavid du Colombier 
1543e12c5d1SDavid du Colombier 	case SG_PHYSICAL:
155219b2ee8SDavid du Colombier 		if(*pg == 0) {
156219b2ee8SDavid du Colombier 			fn = s->pseg->pgalloc;
157219b2ee8SDavid du Colombier 			if(fn)
158219b2ee8SDavid du Colombier 				*pg = (*fn)(s, addr);
159219b2ee8SDavid du Colombier 			else {
160219b2ee8SDavid du Colombier 				new = smalloc(sizeof(Page));
161219b2ee8SDavid du Colombier 				new->va = addr;
162219b2ee8SDavid du Colombier 				new->pa = s->pseg->pa+(addr-s->base);
163219b2ee8SDavid du Colombier 				new->ref = 1;
164219b2ee8SDavid du Colombier 				*pg = new;
165219b2ee8SDavid du Colombier 			}
166219b2ee8SDavid du Colombier 		}
1673e12c5d1SDavid du Colombier 
168ea58ad6fSDavid du Colombier 		if (checkaddr && addr == addr2check)
169ea58ad6fSDavid du Colombier 			(*checkaddr)(addr, s, *pg);
1703e12c5d1SDavid du Colombier 		mmuphys = PPN((*pg)->pa) |PTEWRITE|PTEUNCACHED|PTEVALID;
1713e12c5d1SDavid du Colombier 		(*pg)->modref = PG_MOD|PG_REF;
1723e12c5d1SDavid du Colombier 		break;
1733e12c5d1SDavid du Colombier 	}
1743e12c5d1SDavid du Colombier 	qunlock(&s->lk);
1753e12c5d1SDavid du Colombier 
1763e12c5d1SDavid du Colombier 	if(doputmmu)
1773e12c5d1SDavid du Colombier 		putmmu(addr, mmuphys, *pg);
1783e12c5d1SDavid du Colombier 
1793e12c5d1SDavid du Colombier 	return 0;
1803e12c5d1SDavid du Colombier }
1813e12c5d1SDavid du Colombier 
1823e12c5d1SDavid du Colombier void
pio(Segment * s,ulong addr,ulong soff,Page ** p)1833e12c5d1SDavid du Colombier pio(Segment *s, ulong addr, ulong soff, Page **p)
1843e12c5d1SDavid du Colombier {
1853e12c5d1SDavid du Colombier 	Page *new;
1863e12c5d1SDavid du Colombier 	KMap *k;
1873e12c5d1SDavid du Colombier 	Chan *c;
1883e12c5d1SDavid du Colombier 	int n, ask;
1893e12c5d1SDavid du Colombier 	char *kaddr;
1903e12c5d1SDavid du Colombier 	ulong daddr;
1913e12c5d1SDavid du Colombier 	Page *loadrec;
1923e12c5d1SDavid du Colombier 
1937dd7cddfSDavid du Colombier retry:
1943e12c5d1SDavid du Colombier 	loadrec = *p;
1957dd7cddfSDavid du Colombier 	if(loadrec == 0) {	/* from a text/data image */
1967dd7cddfSDavid du Colombier 		daddr = s->fstart+soff;
1973e12c5d1SDavid du Colombier 		new = lookpage(s->image, daddr);
1987dd7cddfSDavid du Colombier 		if(new != nil) {
1993e12c5d1SDavid du Colombier 			*p = new;
2003e12c5d1SDavid du Colombier 			return;
2013e12c5d1SDavid du Colombier 		}
202d1be6b08SDavid du Colombier 
203d1be6b08SDavid du Colombier 		c = s->image->c;
204d1be6b08SDavid du Colombier 		ask = s->flen-soff;
205d1be6b08SDavid du Colombier 		if(ask > BY2PG)
206d1be6b08SDavid du Colombier 			ask = BY2PG;
2077dd7cddfSDavid du Colombier 	}
2087dd7cddfSDavid du Colombier 	else {			/* from a swap image */
2097dd7cddfSDavid du Colombier 		daddr = swapaddr(loadrec);
2107dd7cddfSDavid du Colombier 		new = lookpage(&swapimage, daddr);
2117dd7cddfSDavid du Colombier 		if(new != nil) {
2127dd7cddfSDavid du Colombier 			putswap(loadrec);
2137dd7cddfSDavid du Colombier 			*p = new;
2147dd7cddfSDavid du Colombier 			return;
2157dd7cddfSDavid du Colombier 		}
216d1be6b08SDavid du Colombier 
217d1be6b08SDavid du Colombier 		c = swapimage.c;
218d1be6b08SDavid du Colombier 		ask = BY2PG;
2197dd7cddfSDavid du Colombier 	}
2203e12c5d1SDavid du Colombier 	qunlock(&s->lk);
2213e12c5d1SDavid du Colombier 
2223e12c5d1SDavid du Colombier 	new = newpage(0, 0, addr);
2233e12c5d1SDavid du Colombier 	k = kmap(new);
2243e12c5d1SDavid du Colombier 	kaddr = (char*)VA(k);
2253e12c5d1SDavid du Colombier 
2263e12c5d1SDavid du Colombier 	while(waserror()) {
2279a747e4fSDavid du Colombier 		if(strcmp(up->errstr, Eintr) == 0)
2283e12c5d1SDavid du Colombier 			continue;
2293e12c5d1SDavid du Colombier 		kunmap(k);
2303e12c5d1SDavid du Colombier 		putpage(new);
231d1be6b08SDavid du Colombier 		faulterror(Eioload, c, 0);
2323e12c5d1SDavid du Colombier 	}
2333e12c5d1SDavid du Colombier 
2347dd7cddfSDavid du Colombier 	n = devtab[c->type]->read(c, kaddr, ask, daddr);
2357dd7cddfSDavid du Colombier 	if(n != ask)
2369a747e4fSDavid du Colombier 		faulterror(Eioload, c, 0);
2373e12c5d1SDavid du Colombier 	if(ask < BY2PG)
2383e12c5d1SDavid du Colombier 		memset(kaddr+ask, 0, BY2PG-ask);
2393e12c5d1SDavid du Colombier 
2403e12c5d1SDavid du Colombier 	poperror();
2413e12c5d1SDavid du Colombier 	kunmap(k);
2423e12c5d1SDavid du Colombier 	qlock(&s->lk);
243d1be6b08SDavid du Colombier 	if(loadrec == 0) {	/* This is demand load */
2447dd7cddfSDavid du Colombier 		/*
2457dd7cddfSDavid du Colombier 		 *  race, another proc may have gotten here first while
2467dd7cddfSDavid du Colombier 		 *  s->lk was unlocked
2477dd7cddfSDavid du Colombier 		 */
2487dd7cddfSDavid du Colombier 		if(*p == 0) {
2493e12c5d1SDavid du Colombier 			new->daddr = daddr;
2503e12c5d1SDavid du Colombier 			cachepage(new, s->image);
2513e12c5d1SDavid du Colombier 			*p = new;
2523e12c5d1SDavid du Colombier 		}
2533e12c5d1SDavid du Colombier 		else
2543e12c5d1SDavid du Colombier 			putpage(new);
2553e12c5d1SDavid du Colombier 	}
2563e12c5d1SDavid du Colombier 	else {			/* This is paged out */
2577dd7cddfSDavid du Colombier 		/*
2587dd7cddfSDavid du Colombier 		 *  race, another proc may have gotten here first
2597dd7cddfSDavid du Colombier 		 *  (and the pager may have run on that page) while
2607dd7cddfSDavid du Colombier 		 *  s->lk was unlocked
2617dd7cddfSDavid du Colombier 		 */
2627dd7cddfSDavid du Colombier 		if(*p != loadrec){
2637dd7cddfSDavid du Colombier 			if(!pagedout(*p)){
2647dd7cddfSDavid du Colombier 				/* another process did it for me */
2653e12c5d1SDavid du Colombier 				putpage(new);
2667dd7cddfSDavid du Colombier 				goto done;
2677dd7cddfSDavid du Colombier 			} else {
2687dd7cddfSDavid du Colombier 				/* another process and the pager got in */
2697dd7cddfSDavid du Colombier 				putpage(new);
2707dd7cddfSDavid du Colombier 				goto retry;
2713e12c5d1SDavid du Colombier 			}
2723e12c5d1SDavid du Colombier 		}
2733e12c5d1SDavid du Colombier 
2747dd7cddfSDavid du Colombier 		new->daddr = daddr;
2757dd7cddfSDavid du Colombier 		cachepage(new, &swapimage);
2767dd7cddfSDavid du Colombier 		*p = new;
2777dd7cddfSDavid du Colombier 		putswap(loadrec);
2783e12c5d1SDavid du Colombier 	}
2797dd7cddfSDavid du Colombier 
2807dd7cddfSDavid du Colombier done:
2817dd7cddfSDavid du Colombier 	if(s->flushme)
2827dd7cddfSDavid du Colombier 		memset((*p)->cachectl, PG_TXTFLUSH, sizeof((*p)->cachectl));
2833e12c5d1SDavid du Colombier }
2843e12c5d1SDavid du Colombier 
2853e12c5d1SDavid du Colombier /*
2863e12c5d1SDavid du Colombier  * Called only in a system call
2873e12c5d1SDavid du Colombier  */
2883e12c5d1SDavid du Colombier int
okaddr(ulong addr,ulong len,int write)2893e12c5d1SDavid du Colombier okaddr(ulong addr, ulong len, int write)
2903e12c5d1SDavid du Colombier {
2913e12c5d1SDavid du Colombier 	Segment *s;
2923e12c5d1SDavid du Colombier 
2933e12c5d1SDavid du Colombier 	if((long)len >= 0) {
2943e12c5d1SDavid du Colombier 		for(;;) {
2957dd7cddfSDavid du Colombier 			s = seg(up, addr, 0);
2963e12c5d1SDavid du Colombier 			if(s == 0 || (write && (s->type&SG_RONLY)))
2973e12c5d1SDavid du Colombier 				break;
2983e12c5d1SDavid du Colombier 
2993e12c5d1SDavid du Colombier 			if(addr+len > s->top) {
3003e12c5d1SDavid du Colombier 				len -= s->top - addr;
3013e12c5d1SDavid du Colombier 				addr = s->top;
3023e12c5d1SDavid du Colombier 				continue;
3033e12c5d1SDavid du Colombier 			}
3043e12c5d1SDavid du Colombier 			return 1;
3053e12c5d1SDavid du Colombier 		}
3063e12c5d1SDavid du Colombier 	}
307567483c8SDavid du Colombier 	pprint("suicide: invalid address %#lux/%lud in sys call pc=%#lux\n", addr, len, userpc());
3083e12c5d1SDavid du Colombier 	return 0;
3093e12c5d1SDavid du Colombier }
3103e12c5d1SDavid du Colombier 
3113e12c5d1SDavid du Colombier void
validaddr(ulong addr,ulong len,int write)3123e12c5d1SDavid du Colombier validaddr(ulong addr, ulong len, int write)
3133e12c5d1SDavid du Colombier {
314d1be6b08SDavid du Colombier 	if(!okaddr(addr, len, write)){
315d1be6b08SDavid du Colombier 		postnote(up, 1, "sys: bad address in syscall", NDebug);
316d1be6b08SDavid du Colombier 		error(Ebadarg);
317d1be6b08SDavid du Colombier 	}
3183e12c5d1SDavid du Colombier }
3193e12c5d1SDavid du Colombier 
3203e12c5d1SDavid du Colombier /*
3213e12c5d1SDavid du Colombier  * &s[0] is known to be a valid address.
3223e12c5d1SDavid du Colombier  */
3233e12c5d1SDavid du Colombier void*
vmemchr(void * s,int c,int n)3243e12c5d1SDavid du Colombier vmemchr(void *s, int c, int n)
3253e12c5d1SDavid du Colombier {
3263e12c5d1SDavid du Colombier 	int m;
3273e12c5d1SDavid du Colombier 	ulong a;
3283ff48bf5SDavid du Colombier 	void *t;
3293e12c5d1SDavid du Colombier 
3303e12c5d1SDavid du Colombier 	a = (ulong)s;
3313ff48bf5SDavid du Colombier 	while(PGROUND(a) != PGROUND(a+n-1)){
3323ff48bf5SDavid du Colombier 		/* spans pages; handle this page */
3333e12c5d1SDavid du Colombier 		m = BY2PG - (a & (BY2PG-1));
3343ff48bf5SDavid du Colombier 		t = memchr((void*)a, c, m);
3353e12c5d1SDavid du Colombier 		if(t)
3363e12c5d1SDavid du Colombier 			return t;
3373ff48bf5SDavid du Colombier 		a += m;
3389a747e4fSDavid du Colombier 		n -= m;
3394de34a7eSDavid du Colombier 		if(a < KZERO)
3403ff48bf5SDavid du Colombier 			validaddr(a, 1, 0);
3413e12c5d1SDavid du Colombier 	}
3423ff48bf5SDavid du Colombier 
3433ff48bf5SDavid du Colombier 	/* fits in one page */
3443ff48bf5SDavid du Colombier 	return memchr((void*)a, c, n);
3453e12c5d1SDavid du Colombier }
3463e12c5d1SDavid du Colombier 
3473e12c5d1SDavid du Colombier Segment*
seg(Proc * p,ulong addr,int dolock)3483e12c5d1SDavid du Colombier seg(Proc *p, ulong addr, int dolock)
3493e12c5d1SDavid du Colombier {
3503e12c5d1SDavid du Colombier 	Segment **s, **et, *n;
3513e12c5d1SDavid du Colombier 
3523e12c5d1SDavid du Colombier 	et = &p->seg[NSEG];
3537dd7cddfSDavid du Colombier 	for(s = p->seg; s < et; s++) {
3547dd7cddfSDavid du Colombier 		n = *s;
3557dd7cddfSDavid du Colombier 		if(n == 0)
3567dd7cddfSDavid du Colombier 			continue;
3573e12c5d1SDavid du Colombier 		if(addr >= n->base && addr < n->top) {
3583e12c5d1SDavid du Colombier 			if(dolock == 0)
3593e12c5d1SDavid du Colombier 				return n;
3603e12c5d1SDavid du Colombier 
3613e12c5d1SDavid du Colombier 			qlock(&n->lk);
3623e12c5d1SDavid du Colombier 			if(addr >= n->base && addr < n->top)
3633e12c5d1SDavid du Colombier 				return n;
3643e12c5d1SDavid du Colombier 			qunlock(&n->lk);
3653e12c5d1SDavid du Colombier 		}
3663e12c5d1SDavid du Colombier 	}
3673e12c5d1SDavid du Colombier 
3683e12c5d1SDavid du Colombier 	return 0;
3693e12c5d1SDavid du Colombier }
370d717568cSDavid du Colombier 
371d717568cSDavid du Colombier extern void checkmmu(ulong, ulong);
372d717568cSDavid du Colombier void
checkpages(void)373d717568cSDavid du Colombier checkpages(void)
374d717568cSDavid du Colombier {
375d717568cSDavid du Colombier 	int checked;
376d717568cSDavid du Colombier 	ulong addr, off;
377d717568cSDavid du Colombier 	Pte *p;
378d717568cSDavid du Colombier 	Page *pg;
379d717568cSDavid du Colombier 	Segment **sp, **ep, *s;
380d717568cSDavid du Colombier 
381d717568cSDavid du Colombier 	if(up == nil)
382d717568cSDavid du Colombier 		return;
383d717568cSDavid du Colombier 
384d717568cSDavid du Colombier 	checked = 0;
385d717568cSDavid du Colombier 	for(sp=up->seg, ep=&up->seg[NSEG]; sp<ep; sp++){
386d717568cSDavid du Colombier 		s = *sp;
387d717568cSDavid du Colombier 		if(s == nil)
388d717568cSDavid du Colombier 			continue;
389d717568cSDavid du Colombier 		qlock(&s->lk);
390d717568cSDavid du Colombier 		for(addr=s->base; addr<s->top; addr+=BY2PG){
391d717568cSDavid du Colombier 			off = addr - s->base;
392d717568cSDavid du Colombier 			p = s->map[off/PTEMAPMEM];
393d717568cSDavid du Colombier 			if(p == 0)
394d717568cSDavid du Colombier 				continue;
395d717568cSDavid du Colombier 			pg = p->pages[(off&(PTEMAPMEM-1))/BY2PG];
396d717568cSDavid du Colombier 			if(pg == 0 || pagedout(pg))
397d717568cSDavid du Colombier 				continue;
398d717568cSDavid du Colombier 			checkmmu(addr, pg->pa);
399d717568cSDavid du Colombier 			checked++;
400d717568cSDavid du Colombier 		}
401d717568cSDavid du Colombier 		qunlock(&s->lk);
402d717568cSDavid du Colombier 	}
403d717568cSDavid du Colombier 	print("%ld %s: checked %d page table entries\n", up->pid, up->text, checked);
404d717568cSDavid du Colombier }
405