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

1991/1003/port/page.c (diff list | history)

port/page.c on 1990/0227
1990/0227    
#include	"u.h" 
#include	"lib.h" 
#include	"mem.h" 
#include	"dat.h" 
#include	"fns.h" 
#include	"ureg.h" 
1990/0802    
#include	"errno.h" 
1990/0227    
 
1991/0705    
#define PGHFUN(x, y)	(((ulong)x^(ulong)y)%PGHSIZE) 
#define	pghash(s)	palloc.hash[PGHFUN(s->image, p->daddr)] 
1990/0227    
 
1991/0705    
struct Palloc palloc; 
 
struct Ptealloc 
1990/0227    
{ 
	Lock; 
1991/0705    
	Pte	*free; 
	int	pages; 
}ptealloclk; 
1990/0227    
 
1991/0705    
extern long end; 
static Lock pglock; 
1990/0227    
 
1991/0705    
/* Multiplex a hardware lock for per page manipulations */ 
void 
lockpage(Page *p) 
{	 
	int s; 
1990/0227    
 
1991/0705    
	for(;;) { 
		if(p->lock == 0) { 
			s = splhi(); 
			lock(&pglock); 
			if(p->lock == 0) { 
				p->lock = 1; 
				unlock(&pglock); 
				splx(s); 
				return; 
			} 
			unlock(&pglock); 
			splx(s); 
		} 
		sched(); 
	} 
} 
1990/0227    
 
1991/0705    
void 
unlockpage(Page *p) 
{ 
	p->lock = 0; 
} 
1991/0425    
 
1990/0227    
/* 
1991/0802    
 *  Called to allocate permanent data structures, before calling pageinit(). 
 *  We assume all of text+data+bss is in the first memory bank. 
1990/0227    
 */ 
void* 
ialloc(ulong n, int align) 
{ 
	ulong p; 
1991/0802    
	ulong *ap; 
1990/0227    
 
1990/1212    
	if(palloc.active && n!=0) 
1990/0227    
		print("ialloc bad\n"); 
1991/0606    
 
1991/0802    
	if(palloc.addr0 == 0){ 
1991/0807    
		/* addr0 and addr1 are physical addresses */ 
		palloc.addr0 = (((ulong)&end)&~KZERO) + conf.base0; 
1991/0802    
		palloc.addr1 = conf.base1; 
	} 
1991/0801    
 
1991/0802    
	/* 
	 *  try first bank 
	 */ 
	p = align ? PGROUND(palloc.addr0) : palloc.addr0; 
	if(p+n > conf.base0 + (conf.npage0<<PGSHIFT)){ 
		/* 
		 *  no room in first bank, try second bank 
		 */ 
		if(conf.npage1 <= 0) 
			panic("keep bill joy away 1"); 
		p = align ? PGROUND(palloc.addr1) : palloc.addr1; 
		ap = &palloc.addr1; 
	} else 
		ap = &palloc.addr0; 
1991/0606    
 
1991/0802    
	if(p >= conf.maxialloc) 
		panic("keep bill joy away 2"); 
1991/0705    
 
1991/0802    
	/* 
	 *  zero it 
	 */ 
	memset((void*)(p|KZERO), 0, n); 
 
	/* 
	 *  don't put anything else into a page aligned ialloc 
	 */ 
	*ap = align ? PGROUND(p+n) : (p+n); 
 
1990/0227    
	return (void*)(p|KZERO); 
} 
 
void 
pageinit(void) 
{ 
1991/0802    
	ulong np, addr, lim; 
1991/0705    
	ulong i, vmem, pmem; 
1990/0227    
	Page *p; 
 
1991/0802    
	/* 
	 *  calculate an upper bound to the number of pages structures 
	 *  we'll need (np). 
	 */ 
	np = (conf.npage0<<PGSHIFT) - (palloc.addr0 - conf.base0); 
	np += (conf.npage1<<PGSHIFT) - (palloc.addr1 - conf.base1); 
	np = np>>PGSHIFT; 
1990/0227    
 
	/* 
1991/0802    
	 *  allocate Page structs (no more ialloc's allowed after this). 
	 *  np is useless after this ialloc since we've just eaten up 
	 *  some pages for the Page structures. 
1990/0227    
	 */ 
1991/0802    
	palloc.head = ialloc(np*sizeof(Page), 0); 
	palloc.active = 1; 
1990/0227    
 
1991/0802    
	/* 
 	 *  for each page in each bank, point a page structure to 
	 *  the page and chain it into the free list 
	 */ 
	p = palloc.head; 
	addr = palloc.addr0 = PGROUND(palloc.addr0); 
	lim = conf.base0 + (conf.npage0<<PGSHIFT); 
	for(; addr < lim; addr += BY2PG){ 
1990/0227    
		p->next = p+1; 
		p->prev = p-1; 
1991/0802    
		p->pa = addr; 
		p++; 
1990/0227    
	} 
1991/0802    
	addr = palloc.addr1 = PGROUND(palloc.addr1); 
	lim = conf.base1 + (conf.npage1<<PGSHIFT); 
	for(; addr < lim; addr += BY2PG){ 
		p->next = p+1; 
		p->prev = p-1; 
		p->pa = addr; 
		p++; 
	} 
	palloc.tail = p - 1; 
1990/0227    
	palloc.head->prev = 0; 
	palloc.tail->next = 0; 
1991/0802    
 
	palloc.user = palloc.freecount = p - palloc.head; 
	pmem = palloc.user*BY2PG/1024; 
	vmem = pmem + ((conf.nswap)*BY2PG)/1024; 
	print("%lud free pages, %dK bytes, swap %dK bytes\n", palloc.user, pmem, vmem); 
1990/0227    
} 
 
Page* 
1991/0705    
newpage(int clear, Segment **s, ulong va) 
1990/0227    
{ 
	Page *p; 
1990/0617    
	KMap *k; 
1991/0705    
	int i; 
1990/0227    
 
	if(palloc.active == 0) 
		print("newpage inactive\n"); 
1991/0705    
 
1990/0227    
	lock(&palloc); 
1991/0705    
 
	/* The kp test is a poor guard against the pager deadlocking */ 
	while((palloc.freecount < HIGHWATER && u->p->kp == 0) || palloc.freecount == 0) { 
		palloc.wanted++; 
1991/0806    
		unlock(&palloc); 
1991/0705    
		if(s && *s) { 
			qunlock(&((*s)->lk)); 
			*s = 0; 
1990/0227    
		} 
1991/0705    
		qlock(&palloc.pwait);			/* Hold memory requesters here */ 
 
1991/0906    
		while(waserror())			/* Ignore interrupts */ 
			; 
1991/0806    
 
1991/0705    
		kickpager(); 
		tsleep(&palloc.r, ispages, 0, 1000); 
1991/0806    
 
		poperror(); 
1991/0705    
 
		qunlock(&palloc.pwait); 
		lock(&palloc); 
		palloc.wanted--; 
1990/0227    
	} 
1991/0705    
 
	p = palloc.head; 
	if(palloc.head = p->next)		/* = Assign */ 
		palloc.head->prev = 0; 
	else 
		palloc.tail = 0; 
 
	palloc.freecount--; 
1990/0227    
	unlock(&palloc); 
1991/0705    
 
	lockpage(p); 
 
	if(p->ref != 0) 
1990/0227    
		panic("newpage"); 
1991/0705    
 
	uncachepage(p); 
	p->ref++; 
	p->va = va; 
	p->modref = 0; 
	for(i = 0; i < MAXMACH; i++) 
		p->cachectl[i] = PG_NOFLUSH; 
	unlockpage(p); 
 
	if(clear){ 
1990/0617    
		k = kmap(p); 
		memset((void*)VA(k), 0, BY2PG); 
		kunmap(k); 
	} 
1990/0227    
 
	return p; 
} 
 
1991/0705    
int 
ispages(void *p) 
1990/0227    
{ 
1991/0705    
	return palloc.freecount >= HIGHWATER; 
1990/0227    
} 
 
1990/0801    
void 
1991/0705    
putpage(Page *p) 
1990/0801    
{ 
1991/0705    
	int count; 
1990/0801    
 
1991/0705    
	if(onswap(p)) { 
		putswap(p); 
		return; 
	} 
1990/0227    
 
1991/0705    
	lockpage(p); 
	if(--p->ref == 0) { 
		lock(&palloc); 
		if(p->image) { 
			if(palloc.tail) { 
				p->prev = palloc.tail; 
				palloc.tail->next = p; 
				p->next = 0; 
				palloc.tail = p; 
1990/0227    
			} 
1991/0705    
			else { 
				palloc.head = palloc.tail = p; 
				p->prev = p->next = 0; 
			} 
1990/0227    
		} 
1991/0705    
		else { 
			if(palloc.head) { 
				p->next = palloc.head; 
				palloc.head->prev = p; 
				p->prev = 0; 
				palloc.head = p; 
			} 
			else { 
				palloc.head = palloc.tail = p; 
				p->prev = p->next = 0; 
			} 
		} 
 
		palloc.freecount++;		/* Release people waiting for memory */ 
		unlock(&palloc); 
	} 
	unlockpage(p); 
 
	if(palloc.wanted) 
		wakeup(&palloc.r); 
1990/0227    
} 
 
1991/0705    
void 
1991/1003    
simpleputpage(Page *pg)			/* Always call with palloc locked */ 
{ 
	pg->ref = 0; 
	palloc.freecount++; 
	if(palloc.head) { 
		pg->next = palloc.head; 
		palloc.head->prev = pg; 
		pg->prev = 0; 
		palloc.head = pg; 
	} 
	else { 
		palloc.head = palloc.tail = pg; 
		pg->prev = pg->next = 0; 
	} 
} 
 
void 
1991/0705    
duppage(Page *p)				/* Always call with p locked */ 
1990/0227    
{ 
1991/0705    
	Page *np; 
1990/0227    
 
1991/0705    
	lock(&palloc); 
 
	if(palloc.freecount < HIGHWATER || /* No freelist cache when memory is very low */ 
	   p->image == &swapimage) {	   /* No dup for swap pages */ 
		unlock(&palloc); 
		uncachepage(p);	 
		return; 
1990/0227    
	} 
1991/0705    
 
	np = palloc.head;			/* Allocate a new page from freelist */ 
	if(palloc.head = np->next)		/* = Assign */ 
		palloc.head->prev = 0; 
	else 
		palloc.tail = 0; 
 
	if(palloc.tail) {			/* Link back onto tail to give us lru */ 
		np->prev = palloc.tail; 
		palloc.tail->next = np; 
		np->next = 0; 
		palloc.tail = np; 
1990/0227    
	} 
1991/0705    
	else { 
		palloc.head = palloc.tail = np; 
		np->prev = np->next = 0; 
	} 
1990/0227    
 
1991/0705    
	unlock(&palloc); 
1990/0227    
 
1991/0705    
	lockpage(np);				/* Cache the new version */ 
	if(np->ref != 0) {			/* Stolen by new page */ 
		uncachepage(p); 
		unlockpage(np); 
		return; 
1990/0227    
	} 
1991/0705    
	 
	uncachepage(np); 
	np->va = p->va; 
	np->daddr = p->daddr; 
	copypage(p, np); 
	cachepage(np, p->image); 
	unlockpage(np); 
	uncachepage(p); 
1990/0227    
} 
 
void 
1991/0705    
copypage(Page *f, Page *t) 
1990/0227    
{ 
1991/0705    
	KMap *ks, *kd; 
1990/0227    
 
1991/0705    
	ks = kmap(f); 
	kd = kmap(t); 
	memmove((void*)VA(kd), (void*)VA(ks), BY2PG); 
	kunmap(ks); 
	kunmap(kd); 
1990/0227    
} 
 
void 
1991/0718    
uncachepage(Page *p)				/* Always called with a locked page */ 
1990/0227    
{ 
1991/0705    
	Page **l, *f; 
1990/0227    
 
1991/0705    
	if(p->image) { 
		lock(&palloc.hashlock); 
		l = &pghash(p); 
		for(f = *l; f; f = f->hash) { 
			if(f == p) { 
				*l = p->hash; 
				break; 
1990/0227    
			} 
1991/0705    
			l = &f->hash; 
1990/0227    
		} 
1991/0705    
		unlock(&palloc.hashlock); 
		putimage(p->image); 
		p->image = 0; 
1990/0227    
	} 
} 
 
1991/0705    
void 
cachepage(Page *p, Image *i) 
1990/0227    
{ 
1991/0705    
	Page **l; 
1990/0227    
 
1991/0705    
	incref(i); 
	lock(&palloc.hashlock); 
	p->image = i; 
	l = &pghash(p); 
	p->hash = *l; 
	*l = p; 
	unlock(&palloc.hashlock); 
1990/0227    
} 
 
1991/0705    
Page * 
lookpage(Image *i, ulong daddr) 
1990/0227    
{ 
1991/0705    
	Page *f; 
1990/0227    
 
1991/0705    
	lock(&palloc.hashlock); 
	for(f = palloc.hash[PGHFUN(i, daddr)]; f; f = f->hash) { 
		if(f->image == i && f->daddr == daddr) { 
			unlock(&palloc.hashlock); 
 
			lockpage(f); 
			if(f->image != i || f->daddr != daddr) { 
				unlockpage(f); 
				return 0; 
1990/0227    
			} 
1991/0705    
 
			lock(&palloc); 
			if(++f->ref == 1) { 
				if(f->prev)  
					f->prev->next = f->next; 
				else 
					palloc.head = f->next; 
 
				if(f->next) 
					f->next->prev = f->prev; 
				else 
					palloc.tail = f->prev; 
				palloc.freecount--; 
			} 
			unlock(&palloc); 
 
			unlockpage(f); 
			return f;	 
1990/0227    
		} 
1991/0607    
	} 
1991/0705    
	unlock(&palloc.hashlock); 
	return 0; 
1990/0227    
} 
 
1991/0705    
Pte* 
ptecpy(Pte *old) 
1990/0227    
{ 
1991/0705    
	Page **src, **dst, **end; 
	Pte *new; 
1990/0227    
 
1991/0705    
	new = ptealloc(); 
1990/0227    
 
1991/0705    
	end = &old->pages[PTEPERTAB]; 
	for(src = old->pages, dst = new->pages; src < end; src++, dst++) 
		if(*src) { 
			if(onswap(*src)) 
				dupswap(*src); 
			else { 
				lockpage(*src); 
				(*src)->ref++; 
				unlockpage(*src); 
			} 
			*dst = *src; 
1990/0227    
		} 
1990/0802    
 
1991/0705    
	return new;		 
1990/0227    
} 
 
1991/0705    
Pte* 
ptealloc(void) 
1990/0227    
{ 
1991/0705    
	Pte *new; 
	int i, n; 
	KMap *k; 
1990/0227    
 
1991/0705    
	lock(&ptealloclk); 
	while(ptealloclk.free == 0) { 
		unlock(&ptealloclk); 
 
		k = kmap(newpage(1, 0, 0)); 
		new = (Pte*)VA(k); 
		n = (BY2PG/sizeof(Pte))-1; 
		for(i = 0; i < n; i++) 
			new[i].next = &new[i+1]; 
 
		lock(&ptealloclk); 
		ptealloclk.pages++; 
		new[i].next = ptealloclk.free; 
		ptealloclk.free = new; 
1990/0227    
	} 
1991/0705    
 
	new = ptealloclk.free; 
	ptealloclk.free = new->next; 
	unlock(&ptealloclk); 
	memset(new->pages, 0, sizeof(new->pages)); 
	return new; 
1991/0606    
} 
 
1991/0705    
void 
freepte(Segment *s, Pte *p) 
1991/0606    
{ 
1991/0705    
	Page **pg, **ptop; 
1991/0606    
 
1991/0705    
	ptop = &p->pages[PTEPERTAB]; 
1991/0606    
 
1991/0705    
	switch(s->type&SG_TYPE) { 
	case SG_PHYSICAL: 
		for(pg = p->pages; pg < ptop; pg++) 
			if(*pg) 
				(*s->pgfree)(*pg); 
		break; 
	default: 
		for(pg = p->pages; pg < ptop; pg++) 
			if(*pg) 
				putpage(*pg); 
1991/0606    
	} 
 
1991/0705    
	lock(&ptealloclk); 
	p->next = ptealloclk.free; 
	ptealloclk.free = p; 
	unlock(&ptealloclk); 
1990/0227    
} 


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