plan 9 kernel history: overview | file list | diff list

1991/0705/port/fault.c (diff list | history)

1991/0619/sys/src/9/port/fault.c:6,2321991/0705/sys/src/9/port/fault.c:6,216 (short | long | prev | next)
1990/0227    
#include	"ureg.h" 
#include	"errno.h" 
 
1991/0705    
#define DPRINT 
 
1990/1212    
int 
fault(ulong addr, int read) 
1990/0227    
{ 
1991/0608    
	ulong mmuvirt, mmuphys, n; 
1990/0227    
	Seg *s; 
	PTE *opte, *pte, *npte; 
	Orig *o; 
	char *l; 
	Page *pg; 
	int zeroed = 0, head = 1; 
1991/0425    
	int i, touched = 0; 
1990/1212    
	KMap *k, *k1; 
1991/0705    
	ulong mmuphys=0, soff; 
	Segment *s; 
	Pte **p; 
	Page **pg, *lkp, *new = 0; 
	int type; 
1990/0227    
 
1991/0427    
	m->pfault++; 
1990/0227    
	s = seg(u->p, addr); 
	if(s == 0){ 
1991/0110    
		if(addr > USTKTOP) 
1990/1212    
			return -1; 
1990/0227    
		s = &u->p->seg[SSEG]; 
1991/0605    
		if(s->o==0 || addr<s->maxva-USTKSIZE || addr>=s->maxva) 
1990/1212    
			return -1; 
1990/0227    
		/* grow stack */ 
		o = s->o; 
		n = o->npte; 
1990/0802    
		if(waserror()){ 
			pprint("can't allocate stack page\n"); 
1990/1212    
			return -1; 
1990/0802    
		} 
1990/0227    
		growpte(o, (s->maxva-addr)>>PGSHIFT); 
1990/0802    
		poperror(); 
1990/0227    
		/* stacks grown down, sigh */ 
1990/0814    
		lock(o); 
1991/0318    
		memmove(o->pte+(o->npte-n), o->pte, n*sizeof(PTE)); 
1990/0227    
		memset(o->pte, 0, (o->npte-n)*sizeof(PTE)); 
		unlock(o); 
		s->minva = addr; 
		o->va = addr; 
	}else 
		o = s->o; 
1990/1212    
	if(!read && (o->flag&OWRPERM)==0) 
1991/0705    
again: 
	s = seg(u->p, addr, 1); 
	if(s == 0) 
1990/1212    
		return -1; 
1990/0227    
	lock(o); 
	opte = &o->pte[(addr-o->va)>>PGSHIFT]; 
	pte = opte; 
	if(s->mod){ 
		while(pte = pte->nextmod)	/* assign = */ 
			if(pte->proc == u->p){ 
				if(pte->page==0 || pte->page->va!=addr) 
					panic("bad page %lux", pte->page); 
				head = 0; 
				break; 
			} 
		if(pte == 0) 
			pte = opte; 
1991/0705    
 
	if(!read && (s->type&SG_RONLY)) { 
		qunlock(&s->lk); 
		return -1; 
1990/0227    
	} 
	if(pte->page == 0){ 
1991/0425    
		touched = 1; 
1990/0227    
		if(o->chan==0 || addr>(o->va+(o->maxca-o->minca))){ 
1991/0606    
			/* Make a new bss or lock segment page */ 
			if(s - u->p->seg == LSEG) { 
				pte->page = lkpage(o, addr); 
1991/0607    
				if(pte->page == 0) { 
					unlock(o); 
					return -1; 
				} 
1991/0606    
			} 
			else 
				pte->page = newpage(0, o, addr); 
1990/0227    
			zeroed = 1; 
1991/0606    
			o->npage++; 
1990/0227    
		}else{ 
			/* 
			 * Demand load.  Release o because it could take a while. 
			 */ 
			unlock(o); 
			n = (o->va+(o->maxca-o->minca)) - addr; 
			if(n > BY2PG) 
				n = BY2PG; 
			pg = newpage(1, o, addr); 
1990/1212    
			k = kmap(pg); 
1991/0411    
			qlock(&o->chan->rdl); 
1990/0227    
			if(waserror()){ 
1990/1212    
				kunmap(k); 
1991/0411    
				qunlock(&o->chan->rdl); 
1990/0227    
				pg->o = 0; 
				pg->ref--; 
1991/0501    
				pexit("demand load i/o error", 0); 
1990/0227    
			} 
1990/1212    
			l = (char*)VA(k); 
1991/0411    
			if((*devtab[o->chan->type].read)(o->chan, l, n, (addr-o->va) + o->minca) != n) 
1990/11211    
				error(Eioload); 
1991/0312    
			flushpage(pg->pa); 
1991/0411    
			qunlock(&o->chan->rdl); 
1990/0227    
			if(n<BY2PG) 
				memset(l+n, 0, BY2PG-n); 
			lock(o); 
1990/1212    
			kunmap(k); 
			poperror(); 
1990/0227    
			opte = &o->pte[(addr-s->minva)>>PGSHIFT];	/* could move */ 
			pte = opte; 
			if(pte->page == 0){ 
				pte->page = pg; 
				o->npage++; 
			}else{		/* someone beat us to it */ 
				pg->o = 0; 
				pg->ref--; 
			} 
1991/0705    
 
	addr &= ~(BY2PG-1); 
	soff = addr-s->base; 
	p = &s->map[soff/PTEMAPMEM]; 
	if(*p == 0)  
		*p = ptealloc(); 
 
	pg = &(*p)->pages[(soff&(PTEMAPMEM-1))/BY2PG]; 
	type = s->type&SG_TYPE; 
 
	switch(type) { 
	case SG_TEXT: 
		if(pagedout(*pg)) 		/* No data - must demand load */ 
			pio(s, addr, soff, pg); 
		 
		mmuphys = PPN((*pg)->pa) | PTERONLY|PTEVALID; 
		(*pg)->modref = PG_REF; 
		break; 
	case SG_SHARED: 
	case SG_BSS: 
	case SG_STACK:	 
			/* Zero fill on demand */ 
		if(*pg == 0) {			 
			if(new == 0 && (new = newpage(1, &s, addr)) && s == 0) 
				goto again; 
			*pg = new; 
			new = 0; 
1990/0227    
		} 
	} 
1991/0705    
						/* NO break */ 
	case SG_DATA: 
		if(pagedout(*pg)) 
			pio(s, addr, soff, pg); 
1991/0608    
 
	if(o->flag&OSHARED) { 
		/* BUG: Does not cover enough flag options to shared data */ 
		mmuphys = PTERONLY; 
		if(o->flag & OWRPERM) 
			mmuphys = PTEWRITE; 
	} 
	else if((o->flag&OWRPERM) && (conf.copymode || !read) 
1990/0227    
	&& ((head && ((o->flag&OPURE) || o->nproc>1)) 
	    || (!head && pte->page->ref>1))){ 
1991/0608    
		/* 
		 * Copy on reference (conf.copymode==1) or write (conf.copymode==0) 
		 */ 
1991/0705    
		if(type == SG_SHARED) 
			goto done; 
1991/0607    
 
		if(!(o->flag&OISMEM)) 
			panic("copy on ref/wr to non memory"); 
1991/0425    
		touched = 1; 
1990/0227    
		/* 
		 * Look for the easy way out: are we the last non-modified? 
		 */ 
		if(head && !(o->flag&OPURE)){ 
			npte = opte; 
			for(i=0; npte; i++) 
				npte = npte->nextmod; 
			if(i == o->nproc) 
				goto easy; 
1991/0705    
		if(read && conf.copymode == 0) { 
			mmuphys = PPN((*pg)->pa) | PTERONLY|PTEVALID; 
			(*pg)->modref |= PG_REF; 
			break; 
1990/0227    
		} 
		if(head){ 
			/* 
			 * Add to mod list 
			 */ 
1990/1013    
			pte = newmod(o); 
1990/0227    
			pte->proc = u->p; 
			pte->page = opte->page; 
			pte->page->ref++; 
			o->npage++; 
			/* 
			 * Link into opte mod list (same va) 
			 */ 
			pte->nextmod = opte->nextmod; 
			opte->nextmod = pte; 
			/* 
			 * Link into proc mod list (increasing va) 
			 */ 
			npte = s->mod; 
			if(npte == 0){ 
				s->mod = pte; 
				pte->nextva = 0; 
			}else{ 
				while(npte->nextva && npte->nextva->page->va<addr) 
					npte = npte->nextva; 
				pte->nextva = npte->nextva; 
				npte->nextva = pte; 
			} 
			head = 0; 
1991/0705    
 
		lkp = *pg; 
		lockpage(lkp); 
		if(lkp->ref > 1) { 
			unlockpage(lkp); 
			if(new == 0 && (new = newpage(0, &s, addr)) && s == 0) 
				goto again; 
			*pg = new; 
			new = 0; 
			copypage(lkp, *pg); 
			putpage(lkp); 
1990/0227    
		} 
		pg = pte->page; 
1991/0606    
		/* when creating pages in the bss which are zfod we create a double 
		 * increment on the mod list which must be removed 
		 */ 
		if(zeroed){ 
1991/0607    
			pg->ref--; 
1990/0227    
			o->npage--; 
			opte->page = 0; 
		}else{		/* copy page */ 
			pte->page = newpage(1, o, addr); 
1990/1212    
			k = kmap(pte->page); 
			k1 = kmap(pg); 
1991/0318    
			memmove((void*)VA(k), (void*)VA(k1), BY2PG); 
1990/1212    
			kunmap(k); 
			kunmap(k1); 
1990/0227    
			if(pg->ref <= 1) 
				panic("pg->ref <= 1"); 
1991/0607    
			pg->ref--; 
1991/0705    
		else { 
			/* put a duplicate of a text page back onto the free list */ 
			if(lkp->image)      
				duppage(lkp);	 
		 
			unlockpage(lkp); 
1990/0227    
		} 
1991/0705    
	done: 
		mmuphys = PPN((*pg)->pa) | PTEWRITE|PTEVALID; 
		(*pg)->modref = PG_MOD|PG_REF; 
		break; 
	case SG_PHYSICAL: 
		if(*pg == 0) 
			*pg = (*s->pgalloc)(addr); 
1991/0606    
 
1990/0227    
    easy: 
1991/0607    
		mmuphys = PTEWRITE; 
1990/0227    
	}else{ 
1991/0607    
		mmuphys = PTERONLY; 
1990/0227    
		if(o->flag & OWRPERM) 
			if(o->flag & OPURE){ 
				if(!head && pte->page->ref==1) 
1991/0607    
					mmuphys = PTEWRITE; 
1990/0227    
			}else 
				if((head && o->nproc==1) 
	  			  || (!head && pte->page->ref==1)) 
1991/0607    
					mmuphys = PTEWRITE; 
1991/0705    
		mmuphys = PPN((*pg)->pa) | PTEWRITE|PTEUNCACHED|PTEVALID; 
		(*pg)->modref = PG_MOD|PG_REF; 
		break; 
	default: 
		panic("fault"); 
1990/0227    
	} 
	mmuvirt = addr; 
1991/0608    
 
	/* Non memory is always uncached */ 
	if(o->flag&OISMEM) { 
		mmuphys |= PPN(pte->page->pa) | PTEVALID; 
1991/0607    
		usepage(pte->page, 1); 
1991/0608    
	}else 
		mmuphys |= PPN(pte->page->pa) | PTEVALID | PTEUNCACHED; 
1991/0705    
	qunlock(&s->lk); 
	if(new) 
		putpage(new); 
1991/0607    
 
1990/0227    
	if(pte->page->va != addr) 
		panic("wrong addr in tail %lux %lux", pte->page->va, addr); 
	if(pte->proc && pte->proc != u->p){ 
		print("wrong proc in tail %d %s\n", head, u->p->text); 
		print("u->p %lux pte->proc %lux\n", u->p, pte->proc); 
		panic("addr %lux seg %d wrong proc in tail", addr, s-u->p->seg); 
1991/0705    
	putmmu(addr, mmuphys, *pg); 
	return 0; 
} 
 
void 
pio(Segment *s, ulong addr, ulong soff, Page **p) 
{ 
	Page *new; 
	KMap *k; 
	Chan *c; 
	int n, ask; 
	char *kaddr; 
	ulong daddr; 
	Page *loadrec; 
 
	loadrec = *p; 
	if(loadrec == 0) { 
		daddr = s->fstart+soff;			/* Compute disc address */ 
		new = lookpage(s->image, daddr); 
1990/0227    
	} 
1991/0705    
	else { 
		daddr = swapaddr(loadrec); 
		new = lookpage(&swapimage, daddr); 
		if(new) 
			putswap(loadrec); 
	} 
1991/0607    
 
1990/0227    
	unlock(o); 
1991/0425    
	if(touched == 0) 
		m->tlbfault++; 
1991/0705    
	if(new) {			/* Page found from cache */ 
		*p = new; 
		return; 
	} 
1991/0607    
 
1990/0227    
	putmmu(mmuvirt, mmuphys); 
1990/1212    
	return 0; 
1991/0705    
	qunlock(&s->lk); 
 
	new = newpage(0, 0, addr); 
	k = kmap(new); 
	kaddr = (char*)VA(k); 
	 
	if(loadrec == 0) {			/* This is demand load */ 
		c = s->image->c; 
		qlock(&c->rdl); 
		if(waserror()) { 
			qunlock(&c->rdl); 
			kunmap(k); 
			putpage(new); 
			qlock(&s->lk); 
			qunlock(&s->lk); 
			pexit("demand load I/O error", 0); 
		} 
 
		ask = s->flen-soff; 
		if(ask > BY2PG) 
			ask = BY2PG; 
		n = (*devtab[c->type].read)(c, kaddr, ask, daddr); 
		if(n != ask) 
			error(Eioload); 
		if(ask < BY2PG) 
			memset(kaddr+ask, 0, BY2PG-ask); 
 
		if((s->type&SG_TYPE) == SG_TEXT) 
			memset(new->cachectl, PG_TXTFLUSH, sizeof(new->cachectl)); 
 
		poperror(); 
		kunmap(k); 
		qunlock(&c->rdl); 
		qlock(&s->lk); 
		if(*p == 0) { 			/* Someone may have got there first */ 
			new->daddr = daddr; 
			cachepage(new, s->image); 
			*p = new; 
		} 
		else  
			putpage(new); 
	} 
	else {					/* This is paged out */ 
		c = swapimage.c; 
		qlock(&c->rdl); 
 
		if(waserror()) { 
			qunlock(&c->rdl); 
			kunmap(k); 
			putpage(new); 
			qlock(&s->lk); 
			qunlock(&s->lk); 
			pexit("page in I/O error", 0); 
		} 
 
		n = (*devtab[c->type].read)(c, kaddr, BY2PG, daddr); 
		if(n != BY2PG) 
			error(Eioload); 
 
		poperror(); 
		kunmap(k); 
		qunlock(&c->rdl); 
		qlock(&s->lk); 
 
		if(pagedout(*p)) { 
			new->daddr = daddr; 
			cachepage(new, &swapimage); 
			putswap(*p); 
			*p = new; 
		} 
		else 
			putpage(new); 
	} 
1990/0227    
} 
 
/* 
1991/0619/sys/src/9/port/fault.c:235,2701991/0705/sys/src/9/port/fault.c:219,253
1990/0227    
void 
validaddr(ulong addr, ulong len, int write) 
{ 
1990/0617    
	Seg *s, *ns; 
1991/0705    
	Segment *s; 
1990/0227    
 
1990/0617    
	if((long)len < 0){ 
1990/0312    
    Err: 
1991/0606    
		pprint("invalid address %lux in sys call pc %lux sp %lux\n",  
			addr, ((Ureg*)UREGADDR)->pc, ((Ureg*)UREGADDR)->sp); 
1990/1110    
		postnote(u->p, 1, "sys: bad address", NDebug); 
1990/11211    
		error(Ebadarg); 
1991/0705    
	if((long)len >= 0) { 
		for(;;) { 
			s = seg(u->p, addr, 0); 
			if(s == 0 || (write && (s->type&SG_RONLY))) 
				break; 
 
			if(addr+len > s->top) { 
				len -= s->top - addr; 
				addr = s->top; 
				continue; 
			} 
			return; 
		} 
1990/0617    
	} 
    Again: 
	s = seg(u->p, addr); 
1990/0821    
	if(s==0){ 
		s = &u->p->seg[SSEG]; 
1991/0605    
		if(s->o==0 || addr<s->maxva-USTKSIZE || addr>=s->maxva) 
1990/0821    
			goto Err; 
	} 
1990/0617    
	if(write && (s->o->flag&OWRPERM)==0) 
		goto Err; 
	if(addr+len > s->maxva){ 
		len -= s->maxva - addr; 
		addr = s->maxva; 
		goto Again; 
1990/0227    
	} 
} 
 
1991/0705    
	pprint("invalid address %lux in sys call pc %lux sp %lux\n",  
			addr, ((Ureg*)UREGADDR)->pc, ((Ureg*)UREGADDR)->sp); 
 
	postnote(u->p, 1, "sys: bad address", NDebug); 
	error(Ebadarg); 
} 
   
1990/0227    
/* 
 * &s[0] is known to be a valid address. 
 */ 
void* 
1991/0619    
vmemchr(void *s, int c, ulong n) 
1991/0705    
vmemchr(void *s, int c, int n) 
1990/0227    
{ 
	int m; 
	char *t; 
1991/0619/sys/src/9/port/fault.c:272,3031991/0705/sys/src/9/port/fault.c:255,291
1990/0227    
 
	a = (ulong)s; 
	m = BY2PG - (a & (BY2PG-1)); 
1991/0619    
	while(n){ 
		if(n < m) 
			m = n; 
		t = memchr(s, c, m); 
1991/0705    
	if(m < n){ 
		t = vmemchr(s, c, m); 
1990/0227    
		if(t) 
			return t; 
1991/0619    
		if(n == m) 
			return 0; 
1990/0227    
		if(!(a & KZERO)) 
			validaddr(a+m, 1, 0); 
1991/0619    
		n -= m; 
		a += m; 
		m = BY2PG; 
1991/0705    
		return vmemchr((void*)(a+m), c, n-m); 
1990/0227    
	} 
1991/0619    
	return 0; 
1991/0705    
	/* 
	 * All in one page 
	 */ 
	return memchr(s, c, n); 
1990/0227    
} 
 
Seg* 
seg(Proc *p, ulong addr) 
1991/0705    
Segment* 
seg(Proc *p, ulong addr, int dolock) 
1990/0227    
{ 
1991/0606    
	Seg *s, *et; 
1991/0705    
	Segment **s, **et, *n; 
1990/0227    
 
1991/0606    
	et = &p->seg[NSEG]; 
	for(s=p->seg; s < et; s++) 
1990/0227    
		if(s->o && s->minva<=addr && addr<s->maxva) 
			return s; 
1991/0705    
	for(s = p->seg; s < et; s++) 
		if(n = *s) 
		if(addr >= n->base && addr < n->top) { 
			if(dolock == 0) 
				return n; 
 
			qlock(&n->lk); 
			if(addr >= n->base && addr < n->top) 
				return n; 
			qunlock(&n->lk); 
		} 
1991/0611    
 
1990/0227    
	return 0; 
} 


source code copyright © 1990-2005 Lucent Technologies; see license
Plan 9 distribution
comments to russ cox (rsc@swtch.com)