File:  [Power 6/32 Unix Tahoe 4.2BSD] / cci / sys / tahoe / vm_machdep.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs
Sun Jul 28 12:24:19 2019 UTC (7 years ago) by root
Branches: bsd, MAIN
CVS tags: v12b, v121, HEAD
Power 6/32 Unix version 1.2b

/*	vm_machdep.c	6.1	83/07/29	*/

#include "../machine/pte.h"

#include "../h/param.h"
#include "../h/systm.h"
#include "../h/dir.h"
#include "../h/user.h"
#include "../h/proc.h"
#include "../h/cmap.h"
#include "../h/mount.h"
#include "../h/vm.h"
#include "../h/text.h"

#include "../machine/mtpr.h"

/*
 * Set a red zone in the kernel stack after the u. area.
 */
setredzone(pte, vaddr)
	register struct pte *pte;
	caddr_t vaddr;
{

	pte += (sizeof (struct user) + NBPG - 1) / NBPG;
	*(int *)pte &= ~PG_PROT;
	*(int *)pte |= PG_URKR;
	if (vaddr)
		mtpr(vaddr + sizeof (struct user) + NBPG - 1, TBIS);
}

#ifndef mapin
mapin(pte, v, pfnum, count, prot)
	struct pte *pte;
	u_int v, pfnum;
	int count, prot;
{

	while (count > 0) {
		*(int *)pte++ = pfnum | prot;
		mtpr(ptob(v), TBIS);
		v++;
		pfnum++;
		count--;
	}
}
#endif

#ifdef notdef
/*ARGSUSED*/
mapout(pte, size)
	register struct pte *pte;
	int size;
{

	panic("mapout");
}
#endif

/*
 * Check for valid program size
 */
chksize(ts, ds, ss)
	register unsigned ts, ds, ss;
{
	static int maxdmap = 0;

	if (ts > MAXTSIZ || ds > MAXDSIZ || ss > MAXSSIZ) {
		u.u_error = ENOMEM;
		return (1);
	}
	/* check for swap map overflow */
	if (maxdmap == 0) {
		register int i, blk;

		blk = dmmin;
		for (i = 0; i < NDMAP; i++) {
			maxdmap += blk;
			if (blk < dmmax)
				blk *= 2;
		}
	}
	if (ctod(ts) > NXDAD * dmtext ||
	    ctod(ds) > maxdmap || ctod(ss) > maxdmap) {
		u.u_error = ENOMEM;
		return (1);
	}
	/*
	 * Make sure the process isn't bigger than our
	 * virtual memory limit.
	 *
	 * THERE SHOULD BE A CONSTANT FOR THIS.
	 */
	if (ts + ds + ss + LOWPAGES + HIGHPAGES > btoc(USRSTACK)) {
		u.u_error = ENOMEM;
		return (1);
	}
	return (0);
}

/*ARGSUSED*/
newptes(pte, v, size)
	register struct pte *pte;
	u_int v;
	register int size;
{
	register caddr_t a = ptob(v);

#ifdef lint
	pte = pte;
#endif
	if (size >= 8) {
		mtpr(0, TBIA);
		return;
	}
	while (size > 0) {
		mtpr(a, TBIS);
		a += NBPG;
		size--;
	}
}

/*
 * Change protection codes of text segment.
 * Have to flush translation buffer since this
 * affect virtual memory mapping of current process.
 */
chgprot(addr, tprot)
	caddr_t addr;
	long tprot;
{
	unsigned v;
	int tp;
	register struct pte *pte;
	register struct cmap *c;

	v = clbase(btop(addr));
	if (!isatsv(u.u_procp, v)) {
		u.u_error = EFAULT;
		return (0);
	}
	tp = vtotp(u.u_procp, v);
	pte = tptopte(u.u_procp, tp);
	if (pte->pg_fod == 0 && pte->pg_pfnum) {
		c = &cmap[pgtocm(pte->pg_pfnum)];
		if (c->c_blkno && c->c_mdev != MSWAPX)
			munhash(mount[c->c_mdev].m_dev,
			    (daddr_t)(u_long)c->c_blkno);
	}
	*(int *)pte &= ~PG_PROT;
	*(int *)pte |= tprot;
	distcl(pte);
	tbiscl(v);
	return (1);
}

settprot(tprot)
	long tprot;
{
	register int *ptaddr, i;

	ptaddr = (int *)mfpr(P0BR);
	for (i = 0; i < u.u_tsize; i++) {
		ptaddr[i] &= ~PG_PROT;
		ptaddr[i] |= tprot;
	}
	mtpr(0, TBIA);
}

/*
 * Rest are machine-dependent
 */

getmemc(addr)
	caddr_t addr;
{
	register int c;
	struct pte savemap;

	savemap = mmap[0];
	*(int *)mmap = PG_V | PG_KR | btop(addr);
	mtpr(vmmap, TBIS);
	uncache (&vmmap[(int)addr & PGOFSET]);
	c = *(char *)&vmmap[(int)addr & PGOFSET];
	mmap[0] = savemap;
	mtpr(vmmap, TBIS);
	return (c & 0377);
}

putmemc(addr, val)
	caddr_t addr;
{
	struct pte savemap;

	savemap = mmap[0];
	*(int *)mmap = PG_V | PG_KW | btop(addr);
	mtpr(vmmap, TBIS);
	*(char *)&vmmap[(int)addr & PGOFSET] = val;

	mtpr (0, PADC);
	mtpr (0, PACC);

	mmap[0] = savemap;
	mtpr(vmmap, TBIS);
}

/*
 * Move pages from one kernel virtual address to another.
 * Both addresses are assumed to reside in the Sysmap,
 * and size must be a multiple of CLSIZE.
 */
pagemove(from, to, size)
	register caddr_t from, to;
	int size;
{
	register struct pte *fpte, *tpte;

	if (size % CLBYTES)
		panic("pagemove");
	fpte = &Sysmap[btop(from - 0xC0000000)];
	tpte = &Sysmap[btop(to - 0xC0000000)];
	while (size > 0) {
		*tpte++ = *fpte;
		*(int *)fpte++ = 0;
		mtpr(from, TBIS);
		mtpr(to, TBIS);
		mtpr(to, P1DC);		/* purge !! */
		from += NBPG;
		to += NBPG;
		size -= NBPG;
	}
}

/*
 * Some code and data key management routines.
 * The arrays ckey_cnt and ckey_cache are allways kept in such a way
 * 	that the following invariant holds:
 *	(ckey_cnt > 0) ==> (ckey_cache == 1)
 * meaning as long as a code key is used by at least one process, it's
 * marked as being 'in the cache'. Of course, the following invariant
 * also holds:
 *	(ckey_cache==0) ==> (ckey_cnt==0)
 * which is just the reciprocal of the 1'st invariant.
 * Equivalent invariants hold for the data key arrays.
 */


int	dbg_gck,
	dbg_gck1,
	dbg_gck2,
	dbg_gck3,
	dbg_gck4,
	dbg_gdk,
	dbg_gdk1,
	dbg_gdk2,
	dbg_gdk3;

/* 
 * ckeyrelease -- release a code key.
 */
ckeyrelease (key)
int	key;
{
	register int ipl;

	ipl = spl8();
	if (--ckey_cnt[key] < 0) {
		printf ("ckeyrelease: key = %d\n", key);
		ckey_cnt[key] = 0;
	}
	splx (ipl);
}


/* 
 * dkeyrelease -- release a data key.
 */
dkeyrelease (key)
int	key;
{
	register int ipl;

	ipl = spl8();
	if (--dkey_cnt[key] != 0) {
		printf ("dkeyrelease: key = %d\n", key);
		dkey_cnt[key] = 0;
	}
	splx (ipl);	
}


/* 
 * getcodekey -- get a code key.
 */
getcodekey()
{
	register int i,
		ipl,
		allocated,	/* number of non-zero ckey_cnt's */
		shared_key,
		return_key;
	register struct proc *p;

	dbg_gck++;

	ipl = spl8();
	allocated = 0;

	for (i = 1; i <= MAXCKEY; i++) {
		if ((int) ckey_cache[i] == 0) {		/* Bingo */
			ckey_cache[i] = 1;
			ckey_cnt[i] = 1;
			splx (ipl);
			dbg_gck1++;
			return (i);
		}

		if (ckey_cnt[i] != 0)
			allocated++;
		if (ckey_cnt[i] > 1 && i != MAXCKEY)
			shared_key = i;
	}

	/*
	 * If we are here, all code keys were marked as being in cache.
	 * Moreover, we are assured that 'shared_key' has a meaningful value,
	 * since we know that the 'init' process and the 'shell' are around
	 * and they have shared text!
	 *
	 * Two cases: some of them are free for re-allocation, or all of
	 * them are currently allocated. In this (second) case, a more
	 * drastic procedure will follow - i.e. we strip some processes of
	 * their keys and let them get new ones whenever they need it.
	 */
	if (allocated < MAXCKEY) {
		/*
		 * This is the easy case.
		 */
		for (i = 1; i <= MAXCKEY; i++) {
			if (ckey_cnt[i] == 0) {
				ckey_cache[i] = 0;
				return_key = i;
			}
		}

		ckey_cnt[return_key] = 1;
		ckey_cache[return_key] = 1;
		mtpr (0, PACC);
		splx (ipl);
		dbg_gck2++;
		return (return_key);
	}

	/*
	 * Now we have to get nasty.
	 * Strip some of them of the code key. First time,
	 * 1) Try hard not to do that to kernel processes !!
	 * 2) Try hard NOT to strip shared text processes of
	 *    their (shared) key, because then they'll run
	 *    with different keys from now on, i.e. less efficient
	 *    cache utilization.
	 */
	for (p = proc; p < procNPROC; p++) {
		/*
		 * Look for a meaningful key but not
		 * used and not shared text.
		 */
		if (p->p_ckey && p->p_ckey!=MAXCKEY && ckey_cnt[p->p_ckey]<2) {
			i = p->p_ckey;
			p->p_ckey = 0;
			ckey_cnt[i] = 1;
			ckey_cache[i] = 1;
			mtpr (0, PACC);
			splx (ipl);
			dbg_gck3++;
			return (i);
		}
	}

	/*
	 * Second time around!
	 * Highly unlikely situation. It means that all keys are
	 * allocated AND shared (i.e. we have at least 510 active
	 * processes).
	 * Strip some of them. We pick some key (known to be shared
	 * by several processes) and strip the poor process group.
	 * At least 2 processes will loose but we gain one key to be reused.
	 * The way 'shared_key' was produced (above) virtually assures
	 * us that this key isn't the 'init' group key (1) nor the
	 * 'shell' group key (2 or 3). It's probably something like 254.
	 * Could be more straightforward to strip all processes, but it's
	 * better to invest in one more loop here and keep the cache
	 * utilization to a maximum.
	 */
	for (p = proc; p < procNPROC; p++) {
		if (p->p_ckey == shared_key) {
			p->p_ckey = 0;
			ckey_cnt[shared_key]--;
		}
	}

	if (ckey_cnt[shared_key] != 0)
		printf("getcodekey: key = %d cnt = %d\n",
			shared_key, ckey_cnt[shared_key]);

	ckey_cnt[shared_key] = 1;
	ckey_cache[shared_key] = 1;
	mtpr (0, PACC);
	splx (ipl);
	dbg_gck4++;
	return (shared_key);
}


/* 
 * getdatakey -- get a data key.
 *
 * General strategy:
 * 1) Try to find a data key that isn't in the cache. Allocate it.
 * 2) If all data keys are in the cache, find one which isn't
 *    allocated. Clear all status and allocate this one.
 * 3) If all of them are allocated, pick some process, strip him
 *    of the data key and allocate it. We (cold-bloodedly) pick
 *    one process to be the poor looser because that's the
 *    easiest way to do it and because this extreme situation
 *    ( >255 active processes ) is expected to be temporary,
 *    after which 1) or 2) above should be the usual case.
 * The poor looser is the first process which has a data key.
 * However, we try to spare known kernel processes and daemons
 * (fired at bootstrap time), by searching from proc[LOOSER] and on.
 */
getdatakey()
{
	register int i,
		ipl,
		allocated,	/* number of non-zero dkey_cnt's */
		return_key;
	register struct proc *p;

#define LOOSER 20

	dbg_gdk++;
	
	ipl = spl8();
	allocated = 0;
	for (i = 1; i <= MAXDKEY; i++) {
		if ((int) dkey_cache[i] == 0) {
			/*
			 * Case 1. The best case.
			 */
			dkey_cache[i] = 1;
			dkey_cnt[i] = 1;
			splx (ipl);
			dbg_gdk1++;
			return (i);
		}
		if (dkey_cnt[i] > 0)
			allocated++;
	}

	if (allocated < MAXDKEY) {
		/*
		 * Case 2. This is the easy case.
		 */
		for (i = 1; i <= MAXDKEY; i++) {
			if (dkey_cnt[i] == 0) {
				dkey_cache[i] = 0;
				return_key = i;
			}
		}

		dkey_cnt[return_key] = 1;
		dkey_cache[return_key] = 1;
		mtpr (0, PADC);
		splx (ipl);
		dbg_gdk2++;
		return (return_key);
	}

	/*
	 * Now, we have to take a code from someone.
	 */
	for (p = &proc[LOOSER]; p < procNPROC; p++) {
		if (p->p_dkey != 0) {
			i = p->p_dkey;
			p->p_dkey = 0;
			dkey_cnt[i] = 1;
			dkey_cache[i] = 1;
			mtpr (0, PADC);
			splx (ipl);
			dbg_gdk3++;
			return (i);
		}
	}

	panic ("getdatakey");
}


/* General (includes system) virtual address to physical */
vtoph(p, v)
register struct proc *p;
register unsigned v;
{
	register struct pte *thispte;

	thispte = vtopte (p, btop(v));
	return ( (thispte->pg_pfnum << PGSHIFT) + (v & PGOFSET));
}
		

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.