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

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

port/fault.c on 1990/0227
1990/0227    
#include	"u.h" 
#include	"lib.h" 
#include	"mem.h" 
#include	"dat.h" 
#include	"fns.h" 
#include	"ureg.h" 
#include	"errno.h" 
 
1991/0705    
#define DPRINT 
 
1990/1212    
int 
fault(ulong addr, int read) 
1990/0227    
{ 
1991/0705    
	ulong mmuphys=0, soff; 
	Segment *s; 
	Pte **p; 
	Page **pg, *lkp, *new = 0; 
	int type; 
1991/0926    
	char *sps; 
1990/0227    
 
1991/0926    
	sps = u->p->psstate; 
	u->p->psstate = "Fault"; 
 
1991/0427    
	m->pfault++; 
1991/0705    
again: 
	s = seg(u->p, addr, 1); 
1991/0926    
	if(s == 0) { 
		u->p->psstate = sps; 
1990/1212    
		return -1; 
1991/0926    
	} 
1991/0705    
 
	if(!read && (s->type&SG_RONLY)) { 
		qunlock(&s->lk); 
1991/0926    
		u->p->psstate = sps; 
1991/0705    
		return -1; 
1990/0227    
	} 
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    
 
1991/0705    
		if(type == SG_SHARED) 
			goto done; 
1991/0607    
 
1991/0705    
		if(read && conf.copymode == 0) { 
			mmuphys = PPN((*pg)->pa) | PTERONLY|PTEVALID; 
			(*pg)->modref |= PG_REF; 
			break; 
1990/0227    
		} 
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    
		} 
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    
 
1991/0705    
		mmuphys = PPN((*pg)->pa) | PTEWRITE|PTEUNCACHED|PTEVALID; 
		(*pg)->modref = PG_MOD|PG_REF; 
		break; 
	default: 
		panic("fault"); 
1990/0227    
	} 
1991/0608    
 
1991/0705    
	qunlock(&s->lk); 
1991/0719    
 
	/* 
	 * A race may provide a page we never used when	 
	 * a fault is fixed while process slept in newpage 
	 */ 
	if(new) 
		putpage(new); 
1991/0607    
 
1991/0705    
	putmmu(addr, mmuphys, *pg); 
1991/0926    
	u->p->psstate = sps; 
1991/0705    
	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) { 
1991/0709    
		daddr = s->fstart+soff;		/* Compute disc address */ 
1991/0705    
		new = lookpage(s->image, daddr); 
1990/0227    
	} 
1991/0705    
	else { 
		daddr = swapaddr(loadrec); 
		new = lookpage(&swapimage, daddr); 
		if(new) 
			putswap(loadrec); 
	} 
1991/0607    
 
1991/0709    
	if(new) {				/* Page found from cache */ 
1991/0705    
		*p = new; 
		return; 
	} 
1991/0607    
 
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); 
1991/0906    
		/* We are unable to correctly error up throught the kernel 
		 * during faults. Therefore note delivery is postponed until 
		 * we leave the system. Read errors cause the process to die. 
		 */ 
		while(waserror()) { 
			if(strcmp(u->error, errstrtab[Eintr]) == 0) 
				continue; 
1991/0705    
			qunlock(&c->rdl); 
			kunmap(k); 
			putpage(new); 
			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); 
 
		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; 
1991/0706    
			if(s->flushme) 
				memset(new->cachectl, PG_TXTFLUSH, sizeof(new->cachectl)); 
1991/0705    
		} 
		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; 
1991/0706    
			if(s->flushme) 
				memset(new->cachectl, PG_TXTFLUSH, sizeof(new->cachectl)); 
1991/0705    
		} 
		else 
			putpage(new); 
	} 
1990/0227    
} 
 
/* 
 * Called only in a system call 
 */ 
void 
validaddr(ulong addr, ulong len, int write) 
{ 
1991/0705    
	Segment *s; 
1990/0227    
 
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    
	} 
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/0705    
vmemchr(void *s, int c, int n) 
1990/0227    
{ 
	int m; 
	char *t; 
	ulong a; 
 
	a = (ulong)s; 
	m = BY2PG - (a & (BY2PG-1)); 
1991/0705    
	if(m < n){ 
		t = vmemchr(s, c, m); 
1990/0227    
		if(t) 
			return t; 
		if(!(a & KZERO)) 
			validaddr(a+m, 1, 0); 
1991/0705    
		return vmemchr((void*)(a+m), c, n-m); 
1990/0227    
	} 
1991/0705    
	/* 
	 * All in one page 
	 */ 
	return memchr(s, c, n); 
1990/0227    
} 
 
1991/0705    
Segment* 
seg(Proc *p, ulong addr, int dolock) 
1990/0227    
{ 
1991/0705    
	Segment **s, **et, *n; 
1990/0227    
 
1991/0606    
	et = &p->seg[NSEG]; 
1991/0705    
	for(s = p->seg; s < et; s++) 
1991/0927    
		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/0705    
		} 
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)