static char rcsid[] = "$Header: context.c,v 820.1 86/12/04 19:52:51 root Exp $";
static char sccsid[]="%W% %Y% %Q% %G%";

/************************************************************************
*									*
*				Copyright 1984				*
*			VALID LOGIC SYSTEMS INCORPORATED		*
*									*
*	This listing contains confidential proprietary information	*
*	which is not to be disclosed to unauthorized persons without	*
*	written consent of an officer of Valid Logic Systems 		*
*	Incorporated.							*
*									*
*	The copyright notice appearing above is included to provide	*
*	statutory protection in the event of unauthorized or 		*
*	unintentional public disclosure.				*
*									*
************************************************************************/

/*
 * Context manipulation functions.
 *
 * History:
 * ========
 * 850??? jam -- Origional version.
 * 860201 jht -- Add code for variable maximum process size: SETTABLE_MMU_SIZE
 * 860209 jht -- Add code to support 32Mb, 64Mb, 128Mb vaddr: M68020_REV_B
 * 860308 jht -- Add code for LRU allocation of virtual segments.
 * 860317 jht -- Add code to define and subsequently use register for V_CONTEXT.
 * 860321 jht -- Board-up/document holes regarding getpagemap() returning -1;
 * 860327 jht -- Rewrite the MAPPAGES macro to properly handle V_PAGEMAP;
 * 860331 jht -- Rewrite the MAPSEGS macro to not run long-enables on segmap;
 * 860331 jht -- Reallocate registers for sanity, performance and symmetry.
 * 860404 jht -- Add more asm() formatted labels for c-debugger use.
 * 860404 jht -- Ammend MAPSEGS() and GAPSEGS() to parameterize maxSmapsAvail. 
 * 860405 jht -- Augment mmu subsystem with MMU_BINGO debugging facility..
 * 860416 elp -- Rewrote sureg to handle virtual segment LRU scheme
 * 860407 jht -- Forcibly map the MRU-th segment and pagemap entries.
 * 860409 elp -- Save entirely, both maps upon exit from sureg() for post mortem
 * 860409 jht -- General cleanup, etc.
 * 86mmdd jht -- Rewrite the whole scheme of virtual memory data structures.
 *		 ...We have labored under the VAX-11/7x0 paradigm long enough!
 */


/*
 * Contexts (abstract entities) each have a corresponding
 * context desciptor (struct ctxt or ctxt_t) in the
 * kernel.  These descriptors contain the context number
 * and gap information about each context.  The gap
 * information defines the area of unmapped space
 * between the data space and stack space when the
 * context was last mapped into, so that the space
 * will not have to be unmapped again (this space is
 * usually rather large).
 *
 * Each context may be owned by a process as indicated
 * by ctxt.procp.  As long as a process owns a context
 * any segment maps, which are not stolen from it (see
 * below), will remain in hardware.
 *
 * If another process needs a context it takes the least
 * recently used one from the context list and invalidates
 * the p_ctxt for the previously owning process (if any).
 * Stealing the context, however, does NOT invalidate
 * any pages which are still mapped by the victim, only
 * the segment map for it is invalidated.
 * 
 * Each process may own up to as many segment maps as
 * it needs to map itself into memory.  When it first
 * gets them it fills them with the correct page maps
 * and, as long the process has a context, the segment
 * maps will reside in hardware as well.  NOTE that a
 * process may NOT own more segment maps than it needs.
 *
 * Other processes, however, may steal some or all of
 * the segment maps owned by a process; in this case
 * the segments stolen will be from the FRONT of the
 * p_smaps list (those representing lower process
 * memory) and later ones will be untouched.  p_needmap
 * will be incremented for each segment map stolen
 * from a process so that only those segment maps will
 * need to be allocated and mapped, segment and page
 * wise, in hardware as long as the process still
 * has a context.
 *
 * In order for processes to steal segment maps there
 * are two lists of processes: those with contexts
 * and those without.  If a process has no segment
 * maps then it does not reside on either list.
 */

#include "../h/types.h"

#include "../machine/reg.h"
#include "../machine/pte.h"
#include "../machine/psl.h"
#include "../machine/cpu.h"
#if	defined(M68020_REV_B) || defined(SETTABLE_MMU_SIZE)
#include "../machine/ecm.h"		/* MAXPHYSMEM_PAGES */
#include "../machine/context.h"
#endif	defined(M68020_REV_B) || defined(SETTABLE_MMU_SIZE)

#include "../h/param.h"
#include "../h/systm.h"
#include "../h/dir.h"
#include "../h/user.h"
#include "../h/kernel.h"
#include "../s32/vmparam.h"
#include "../h/map.h"
#include "../h/vm.h"
#include "../h/vmmac.h"
#include "../h/proc.h"
#include "../h/text.h"
#include "../s32/ecm.h"

#include "../s32/debug.h"


/*
 * These defines will be moved to s32/cpu.h
 */
#define	V_SEGMASK	(V_VSEGNO<<PGSHIFT)	/* Seg-addr from addr */
#define	V_VSEGNO_MASK	(V_VSEGNO>>PTOSSHIFT)	/* Seg-# from page #  */


extern	short	verbosity;	/* DEBUG: defined in s32/startup.c -- jht */


#ifdef	MMU_BINGO		/* C.f., s32/{context.c,map.c,startup.c}    */
short	mmu_BINGO;		/* 0==>Disable; 1==>Enable pattern matching */
u_long	mmu_BINGO_addr;		/* Address @ which a match ==> "BINGO!"	    */
#endif	MMU_BINGO


/*
 * These were formerly macros,
 * upon which the compiler would run amuck.
 * They have been transformed temporarily (permanently?)
 * into nominal 'c' functions.
 */
#ifndef	CTXT_MACROS
/*
 * dequeue  --	Delete an element from the MRU-end
 *		of a doubly linked list.
 */
dequeue(l)
dlist_t	*l;
{
	l->lru->mru = l->mru;
	l->mru->lru = l->lru;
}

/*
 * addmru   --	Add an element to the MRU-end
 *		of a doubly linked list.
 */
addmru(h,l)
dlist_t	*h, *l;
{
	l->lru = h;
	l->mru = h->mru;
	l->mru->lru = l;
	h->mru = l;
}

/*
 * addlru   --	Add an element to the LRU-end
 *		of a doubly linked list.
 */
addlru(h,l)
dlist_t	*h, *l;
{
	l->mru = h;
	l->lru = h->lru;
	l->lru->mru = l;
	h->lru = l;
}

/*
 * emptyList   --	Effectively delete any/all of the elements
 *			of a doubly linked list.
 */
emptyList(h)
dlist_t	*h;
{
	h->mru = h;
	h->lru = h;
}
#endif	CTXT_MACROS


/*
 * Data structures for context information
 */
#ifdef CTXT_STATS
struct	ctxt_stats ctxt_stats;	/* Context switching statistics */
#endif	CTXT_STATS


#ifdef CTXT_DEBUG
#undef CTXT_DEBUG
#define CTXT_DEBUG(stuff)	DODEBUG(D_CTXT,stuff)
#else CTXT_DEBUG
#define CTXT_DEBUG(stuff)
#endif CTXT_DEBUG



/*
 * Segment map management table.
 * -----------------------------
 *
 * The table represent the PHYSICAL segments of primary storage,
 * the table-index being the physical segment #.
 *
 * The table is created as a forward-chained linear list.
 * A freelist selector points into the table
 * at the beginning of the available segment maps.
 *
 * NOTE: As the smaps are allocated, deallocated or stolen
 * during normal context switching from process to process,
 * the initial monotonicity of the linear list will disappear.
 *
 *	Descr.		Entry #I through #J				Contents
 *	======		========================================	========
 *	Kernel		0		--> (ptos(usrbase)-1)		I+1
 *
 *	User		ptos(usrbase)	--> (ptos(usrtop)-1)		I+1
 *
 *	LastSeg		ptos(usrtop)	--> (nSmaps-1)			0=NOSMAP
 */

smap_t	smaps[NSMAPS];		/* Table of 'real' segment maps  */
smap_t	smap_free;		/* Head of free segment map list */
smap_t	smap;			/* Index into smaps[]		 */


u_short	ctxt_dequeue_debug = 0;	/* 0==> debug dequeued context requeueing    */
u_long	dequeue_fixup_count;	/* # Fixups attempted for dequeued processes */

/*
 * This bitmap is used by sureg to create a list of segments to map
 */
u_char	smap_bitmap [btos (V_MAXVA) / NBBY];
#ifdef USE_CTXT	/* !OLD_SUREG */

extern	short	nContexts;		/* Alterable @ startup() time	     */
int		nSmaps	= NSMAPS;	/* # segment maps for (16Mb) proc[0] */


#ifndef	SUREG_WORKING

#define   	V_MAXVA_CTXT	V_MAXVA_32MB	/* C.f., s32/context.h */

u_short		debug_smap[btos(V_MAXVA_CTXT)];
u_short		debug_pmap[MAXPHYSMEM_PAGES];
u_char		debug_page0[NBPG];

/*
 * Define places where we can store the segment and page maps for later
 * debugging.
 */
copyMaps (ctxt)
/*A5*/	register ctxt_t		*ctxt;
{
/*A4*/	A_V_CONTEXT;
/*A3*/	register u_short	*mapAddr;
/*A2*/	register u_short	*pArray;
/*D7*/	register u_long		a23;
/*D6*/	register int		count;
/*D5*/	register int		incr;
/*D4*/	register u_char		newctxt;
/*D3*/	register u_long		addr;
/*D2*/	register u_short	segnum;
		 u_short	oldseg;

	/*
	 * Copy the segment maps into a global buffer for later perusal
	 */
	incr = segsize / (sizeof *mapAddr);
	addr = 0;
	mapAddr = (u_short *)V_SEGMAP;
	a23 = 0;
	count = btos (V_MAXVA_CTXT);
	pArray = debug_smap;
	newctxt	= ctxt->number | V_ACCSM | V_ACCLOW;
	while (count --) {
		if (a23 != (addr & V_SEGMAP)) {
			a23 = addr & V_SEGMAP;
			mapAddr = (u_short *)(addr | V_SEGMAP);
			newctxt	= ctxt->number | V_ACCSM
				| (a23 ? V_ACCHIGH : V_ACCLOW);
		}
		R_V_CONTEXT = newctxt;
		*pArray++ = *mapAddr;
		R_V_CONTEXT = ctxt->number;
		mapAddr += incr;
		addr += segsize;
	}

	/*
	 * Copy the page maps into a global buffer for later perusal
	 */
#define	V_CTXT_SEG	0xFF0000	/* Segment addr to use for map read */
#define	V_CTXT_LOC	V_ACCHIGH

	incr = pagesize / (sizeof *mapAddr);
	addr = 0;
	mapAddr = (u_short *) V_CTXT_SEG;
	segnum = 0;
	count = MAXPHYSMEM_PAGES;
	pArray = debug_pmap;
	newctxt	= ctxt->number | V_ACCPM | V_CTXT_LOC;
	R_V_CONTEXT = ctxt->number | V_ACCSM | V_CTXT_LOC;
	oldseg = *mapAddr;
	*mapAddr = segnum | V_SKERNEL;
	R_V_CONTEXT = ctxt->number;
	while (count --) {
		if (addr == segsize) {
			addr = 0;
			mapAddr = (u_short *) V_CTXT_SEG;
			segnum++;
			R_V_CONTEXT = ctxt->number | V_ACCSM | V_CTXT_LOC;
			*mapAddr = segnum | V_SKERNEL;
			R_V_CONTEXT = ctxt->number;
		}
		R_V_CONTEXT = newctxt;
		*pArray++ = *mapAddr;
		R_V_CONTEXT = ctxt->number;
		mapAddr += incr;
		addr += pagesize;
	}
	mapAddr = (u_short *) V_CTXT_SEG;
	R_V_CONTEXT = ctxt->number | V_ACCSM | V_CTXT_LOC;
	*mapAddr = oldseg;
	R_V_CONTEXT = ctxt->number;
	CTXT_DEBUG (("debug_smap = 0x%x debug_pmap = 0x%x\n",
		      debug_smap,	debug_pmap));
	count = PPS;
	pArray = &debug_pmap [DUMMYSMAP << (SEGSHIFT-pageshift)];
	while (count --)
		if (*pArray++ != 0x3000) {
			cdebugger ("Seg 1 scrog");
			break;
		}
}
#endif	SUREG_WORKING

/*
 *	ctxt_init() -- Context initialization
 *
 * Initialize the context and segment map resources.
#ifdef	SETTABLE_MMU_SIZE
 * Called from startup().
 *
 * NOTE:  1) None of the process slots
 *	     or upages are initialized yet.
 *	  2) Neither is process #0 extant.
 *
#endif	SETTABLE_MMU_SIZE
 */
ctxt_init()
{
	register smap_t smap;
	register ctxt_t *ctxt;
	register struct proc *p;

#ifndef	SETTABLE_MMU_SIZE
	/* 
	 * Put all segment maps not used by the
	 * kernel into the free list.
	 */
	smap_free	= ptos(usrbase);
	smaps[NSMAPS-1] = NOSMAP;				/* End list */

	/*
	 * Point top of user area
	 * at the topmost segment,
	 * which is hers, also.
	 */
	smap		= (usrtop-1) >> PTOSSHIFT;
	smaps[smap]	= NSMAPS - 1;
#else	SETTABLE_MMU_SIZE

	/* 
	 * Put all segment maps not used by the
	 * kernel into the free list.
	 * We need only point at the start
	 * of the monotonically ascending linear list.
	 */
	smap_free	= ptos(usrbase);
	smaps[nSmaps-1]	= NOSMAP;

	/*
	 * Chain in the topmost segment,
	 * which is hers, also: Point top
	 * of user area at the topmost segment,
	 *
	 * NOTE:  The relativized/normalized 'usrtop'.
	 */
	smap  = (usrTop-1) >> PTOSSHIFT;		/* Relativize */
	smap &= nSmaps-1;				/* Normalize  */

	smaps[smap] = nSmaps - 1;
#endif	SETTABLE_MMU_SIZE
	/*
	 * Now fill in the rest of the user's
	 * portion of the monotonic linear list.
	 *
	 * NOTE: The lowest (0-->ptos(usrbase)) entries
	 * are each designated as end-of-list for safety.
	 */
	while (--smap >= smap_free)
		smaps[smap] = smap + 1;
	while (--smap)
		smaps[smap] = NOSMAP;


	/*
	 * Build the context list and mark all
	 * contexts as unused.
	 */
	emptyList(&ctxt_list);
	for (ctxt=ctxts; ctxt != &ctxts[nContexts]; ++ctxt)
	{
#ifdef	SETTABLE_MMU_SIZE
		ctxt->mmuIndxPrev =
		ctxt->mmuIndx	= normalMmuIndx;	/* Defalt MMU sizing */
#endif	SETTABLE_MMU_SIZE
		ctxt->number	= ctxt - ctxts;
		ctxt->procp	= NULL;
#ifndef	M68020_REV_B
		ctxt->gapstart	= HALFSEGS;
		ctxt->gapend	= HALFSEGS;
#else	M68020_REV_B
		ctxt->gapstart	=
		ctxt->gapend	= btos( (u_long)mmu_sizing[ ctxt->mmuIndx ].mmu_ctxtMaxVaddr >> 1);
#endif	M68020_REV_B
		addmru(&ctxt_list, ctxt);
	}

	/*
	 * Make the no-context and have-context lists
	 * empty and initialize the values in each
	 * proc structure to indicate that the process
	 * has no resources.
	 */
	emptyList(&ctxt_noctxt);
	emptyList(&ctxt_havectxt);
	for (p=proc; p != &proc[nproc]; ++p)
	{
		p->p_ctxt	= NOCTXT;
		p->p_smaps	= NOSMAP;
#ifdef	SETTABLE_MMU_SIZE
		p->p_mmuIndx	= normalMmuIndx; /* Defalt MMU sizing	  */

		/*
		 * BUG: Beware of possible conflict
		 * within main() in sys/init_main.c
		 */
		p->p_mmuStatRegBits = 0;  	 /* Status reg bits for ctxt */
#endif	SETTABLE_MMU_SIZE
		p->p_needmap	= 0;
#ifdef	M68020_REV_B
		p->p_procp	= p;
#endif	M68020_REV_B
		emptyList(&p->p_lru);
	}
}

#ifdef	CTXT_DEMUX
/*
 * ctxt_deMux()	  --	Disassemble the aggregated contexts for process 'p',
 *			such that its constitiuents may be reused
 *			as nominal 16Mb or 32Mb entities.
 *
 * NOTE:	1) No enqueue/dequeue-ing is performed.
 *		2) The process must designate its context (chain).
 *		3) This routine should be invoked @ spl7
 *		   because we alter global data structures.
 */
ctxt_deMux(p)
	register struct	proc	*p;
{
	register ctxt_t	*ctxt;
	register ctxt_t	*cTxt;
	register	i, j;
	register 	range	= MMU_idsInACtxt(myproc);
	register 	incr	= MMU_ctxtCntsBy(myproc);
	
	if ((ctxt = p->p_ctxt) != NOCTXT) {
		/*
		 * See if the context-# "handle"
		 * is a properly "aligned" number.
		 */
		CTXT_DEBUG(("\nctxt_deMux/I: ChkAligned: "));
		for (i=j=0; j++ < range; i++) {
			CTXT_DEBUG((" %d:p_ctxt(%d:candidate)",
				ctxt->number, i));
			if (ctxt->number == MMU_alignedIds(p)[i]) {
				/*
				 * Have an "aligned" id
				 */
				CTXT_DEBUG((": itsAligned\n"));
				goto itsAligned;
			}
		}
		cdebugger("p_ctxt->number NOT aligned");
		panic("p_ctxt->number NOT aligned");
	} else {
		cdebugger("ctxt_deMux/E: p_ctxt==NOCTXT");
		panic("ctxt_deMux/E: p_ctxt==NOCTXT");
	}


itsAligned:

	/*
	 * Now we need to disassemble the specific context(s)
	 * that are entirely within the "shadow"
	 * of the supplied/validated "aligned" context.
	 */
	i = ctxt->number;
	for (j=0; j++ < range; i+=incr) {
		cTxt = &ctxts[i];

		/*
		 * ctxt->number:	The aligned context
		 * cTxt->number:	In the SHADOW..
		 */
		CTXT_DEBUG((" deMux #%d:A(%d:S)",
			ctxt->number,	/* The aligned context	*/
			cTxt->number));	/* In the SHADOW..	*/

		/*
		 * Copy all of the segment maps for the kernel
		 * from the current context (p-p_ctxt)
		 * into each of the "normal" constitiuent contexts(s).
		 *
		 * BUG: Should I use MYCTXT or SYSCTXT??
		 */
		{
			register nsegs = mmu_sizing[normalMmuIndx].mmu_nsegs;

			kvinit(	MYCTXT,
				nsegs * j /*segBias*/,
				nsegs);
		}

		/*
		 * Audit trail for/of the alterations
		 */
		cTxt->mmuIndxPrev = cTxt->mmuIndx; /* History  */
		cTxt->mmuIndx	  = normalMmuIndx; /* Rational */
	}
}
#endif	CTXT_DEMUX

#ifndef OLD_SUREG	/* I.e., this is the NEW sureg() */

#ifdef	M68020_REV_B
/*
 * Low usage variables "global" to only:
 *
 *	sureg(),
 *
 * Our registers were over committed (and still are),
 * so little, if anything is lost by globalizing these vars.
 * There is also some additional clarity added to debugging.
 */
#if 1
#define	Static			/* To allow use with cdebugger()	*/
#else 0
#define	Static	static		/* Later, hide from external visibility	*/
#endif 0

/*
 * Segment map bean counters.
 * These physical and virtual counters
 * operate largely in tandem.
 */
Static	int	pSmapsMappedSoFar;	/* PHYSICAL segs  */
Static	int  oldPSmapsMappedSoFar;
Static	int	vSmapsMappedSoFar;	/* VIRTUAL  segs  */


Static	int	segsMappedSoFar,
		pagesMappedSoFar;
/*
 * Indicies into an LRU list
 * of VIRTUAL smaps for a process.
 */
Static	smap_t	cIndex;			/* Current  index */
Static	smap_t	pIndex;			/* Previous index */

Static	int	skipMRU;		/* 1==> map it, even if it is MRU_HEAD*/

Static	int	unMappedSegs;		/* Bean counters for the h/w maps */
Static	int	unMappedPages;

/*
 * mapSegs  --	Only map up to the theoretical limit
 *		of the # of segments that the PHYSICAL memory will support.
 *
 * CONVENTIONS:
 * ===========
 *	1) Parameter 'maxSmapsAvail' is the LIMIT upon # of smaps available;
 *
 *	2) Parameter 'segsMappedSoFar' is the TALLY of smaps mapped so far;
 *
 *	3) Parameter 'work' is a thunk that computes and installs the VALUE
 *	   of the new mmu entry upon each of 'count' iterations;
 *
 *	4) 'oldSaddr' is virtual address of 1st segment
 *	   in the group of segments to be given a new SMAP entry.
 *	   'saddr' is herein computed from 'oldSaddr'.
 *	   NOTE:  This is the REVERSE of the non-M68020_REV_B convention.
 *
 *	5) 'count' is the # of segment to be so mapped;
 *
 *	6) 'newctxt' is the baseline context value:  ctxt# + V_ACCPM;
 */
mapSegs (ctxt, oldSaddr, pte, prot, count)
/*A5*/	register struct ctxt	*ctxt;
/*A4*/	register struct pte	*pte;
/*D7*/	register u_long 	oldSaddr;
/*D6*/	register smap_t		prot;
/*D5*/	register int		count;
{
/*A3*/	register u_short	*saddr;
/*A2*/	register u_char		*bitmap = &smap_bitmap[btos(oldSaddr)/NBBY];
/*D4*/	register u_char		newsctxt,
/*D3*/				newpctxt;
/*D2*/	register int		pagesToMap;
/*  */		 u_long		olda23;
/*  */		 u_short	smap_mask = 1 << (btos(oldSaddr)%NBBY);
/*  */		 u_short	entry;
/*  */           int		ps = pagesize / sizeof(u_short);
/*  */	         int		ss = segsize / sizeof(u_short);

   CTXT_DEBUG((" (cnt=%d) oldSaddr=0x%x", count, oldSaddr));
   olda23  = 0; 
   newsctxt = ctxt->number | V_ACCSM | V_ACCLOW; 
   newpctxt = ctxt->number | V_ACCPM | V_ACCLOW;
   saddr   = (u_short *) (oldSaddr | V_SEGMAP);
   while (--count >= 0) 
   { 
	if (mmu_BINGO && ((oldSaddr & V_SEGMASK) == (mmu_BINGO_addr & V_SEGMASK))) cdebugger("BINGO! sureg: Seg"); 
	/*
	 * 'saddr' always has V_SEGMAP asserted;
	 * Toggle between V_ACCLOW and V_ACCHIGH every V_SEGMAP bytes;
	 * Advance 'saddr' and 'oldSaddr' for next segment;
	 */
	if (olda23 != (oldSaddr & V_SEGMAP))
	{
		saddr	= (u_short *)(oldSaddr|V_SEGMAP);
		olda23	= oldSaddr & V_SEGMAP;
		newsctxt = ctxt->number | V_ACCSM
			| (olda23 ? V_ACCHIGH : V_ACCLOW);
		newpctxt = (newsctxt & ~V_ACCSM) | V_ACCPM;
	}
	/*
	 * Maintain TIGHT control on acces to the segment map!
	 *
	 * Added the (&& prot) to protect from a gapping call having a 
	 * miscalculated pte page.  Possible if we shrink the stack to 0.
	 * (ELP 4/23/86)
	 */
	if (*bitmap & smap_mask) {
#ifdef	DEBUG_LATER
		if (!prot)
			panic ("Valid segment in gap");
#endif	DEBUG_LATER
		++segsMappedSoFar;
		V_CONTEXT = newsctxt;/* Access h/w segment map  */
		/* Pound in the h/w entry  */
		CTXT_DEBUG((" %x", smap));
		*saddr = smap | (prot);
#ifdef	WHITE
		V_CONTEXT ^= V_ACCUSER;
		*saddr = smap | (prot);
#endif	WHITE
		smap = smaps[smap];
		V_CONTEXT = ctxt->number;	/* Revert: paranoid */
		pagesToMap = PPS;
		while (pagesToMap --) {	
			++pagesMappedSoFar;
			--unMappedPages;
			if (prot == 0)
				entry = V_PAGE_INVALID;
			else {
				if (pte->pg_v)
					entry = pte->pg_pfnum; 
				else if (pte->pg_fod && ((struct fpte *)pte)
				    ->pg_fileno == PG_FPHYS) {
					entry = ((struct fpte *)pte)->pg_blkno;
#ifdef	M68020
					if (((struct fpte *)pte)->pg_noncached)
						entry |= V_NONCACHED;
#endif	M68020
				} else
					entry = V_PAGE_INVALID;
				if (pte->pg_m)
					entry |= V_DIRTY;
			}
			++pte;
			V_CONTEXT = newpctxt;
			*saddr = entry;
			V_CONTEXT = ctxt->number;
			saddr += ps;
			oldSaddr += pagesize;
		}
	} else {
		V_CONTEXT = newsctxt;/* Access h/w segment map  */
		*saddr = DUMMYSMAP;	/* GAP IT!!! */
		V_CONTEXT = ctxt->number;	/* Revert: paranoid  */
		saddr += ss;		/* Advance to next segment */
		oldSaddr += segsize;
		pte += PPS;		/* Increment the pte ptr */
	}
	smap_mask <<= 1;
	if (smap_mask == (1 << NBBY)) {
		smap_mask = 1;
		bitmap ++;
	}
   }
   CTXT_DEBUG((" oldSaddr=0x%x;", oldSaddr));
}
#endif	M68020_REV_B

#ifdef	SETTABLE_MMU_SIZE
/*
 * Context and process pointers
 * for location and allocation
 * of the former to the latter.
 */
Static	ctxt_t		* shadowCtxt;	/* Context in a "shadow"*/
Static	ctxt_t		* alignedCtxt;	/* Old context struct	*/
Static	struct	proc	* shadowProc; 	/* Proc-slot in "shadow"*/
Static	struct	proc	* saveProc; 	/* Old proc-slot	*/
#endif	SETTABLE_MMU_SIZE


/*	
 *	sureg() -- Load the context and both maps into the h/w.
 *
 * Map the current process into the hardware
 * and make it the current context.  The
 * basic algorithm is:
 *	Get more segment maps (if we do not have enough).
 *	Get a context (if we do not have one).
 *	Put us on the most used lists.
 *	Switch to the correct context.
 *	Put the new segment maps into the hardware.
 *	Put the new page table entries into the hardware.
#ifdef	SETTABLE_MMU_SIZE
 *
 * NOTE:  This routine, the NEW sureg(),
 * only operates with respect
 * to the CURRENT process (u.u_procp), with the exception
 * of processes on the lru/mru context lists.
 *
#endif	SETTABLE_MMU_SIZE
 */
sureg()			/* This is the NEW sureg() */
{
/*  */		 struct	proc  *	myproc		= u.u_procp; /* CURRENT proc */
/*A5*/	register ctxt_t	      *	ctxt;
/*A4*/	A_V_CONTEXT;				/* Allocate register-var*/
#ifdef	M68020_REV_B
	/*
	 * NOTE:  "wantSmaps!=0", is used herein ALSO as a flag
	 * indicating incipient incomplete smap coverage.
	 */
#endif	M68020_REV_B
/*D7*/	register u_long		nSegsToMap = 0;
/*D6*/	register u_long		wantSmaps;
/*  */		 u_long		segsAlreadyHave;

	int	 gap;
	int	 s = spl7();	/* MUST spl7() for suregp[01][bl]r integrity */


#ifdef	M68020_REV_B
	pSmapsMappedSoFar	= 0;		/* PHYSICAL segs  */
     oldPSmapsMappedSoFar	= 0;
	vSmapsMappedSoFar	= 0;		/* VIRTUAL  segs  */

	cIndex			= NOSMAP;	/* Current  index */
	pIndex			= NOSMAP;	/* Previous index */

	skipMRU			= 0;		/* Don't skip MRU_HEAD'th */

	unMappedSegs		= myproc->p_needmap;
	unMappedPages		= unMappedSegs << PTOSSHIFT;
#endif	M68020_REV_B

    {

	segsMappedSoFar = 0;
	/*
	 * Indicate entry conditions.
	 */
	CTXT_INCSTAT(sureg);
	CTXT_DEBUG(("SUREG: pid=%d p=0x%x: p_smaps=0x%x p_needmap=0x%x=%d",
		myproc->p_pid, myproc,
		myproc->p_smaps,
		myproc->p_needmap,
		myproc->p_needmap));

	/*
	 * Report on # of PHYSICAL segment maps available
	 * with the physical address space at hand -- 24bit Multibus.
	 * Set in startup().
	 */
	CTXT_DEBUG((" maxPSmapsAvail=0x%x=%d:",		/* Physical */
		      maxPSmapsAvail,
		      maxPSmapsAvail));

	/*
	 * Report on # of VIRTUAL segment maps available
	 * with the virtual address space at hand for current process.
	 * Set in startup() in s32/startup.c; but the value may be
	 * different for each process.
	 */
	maxVSmapsAvail = MMU_maxVSmaps(myproc);

	CTXT_DEBUG((" maxVSmapsAvail=0x%x=%d:",		/* Virtual */
		      maxVSmapsAvail,
		      maxVSmapsAvail));

	if ((int) myproc <= NULL) {
		cdebugger("sureg: bad proc addr: NULL");
	}

	/*
	 * Take our process off any lists so that
	 * we will not take smaps from ourselves
	 * in case we start stealing them from
	 * processes.
	 */
	dequeue(&myproc->p_lru);

	/*
	 * Build bitmap for process
	 */
	{
/*D5*/		register smap_t	 smapIndx;

		/*
		 * Clear the bitmap BEFORE using it, this prevents the
		 * code below from trying to set too many segment maps.
		 */
		bclear (smap_bitmap, sizeof smap_bitmap);
		for (smapIndx = HEAD; smapIndx != NOSMAP;
		     smapIndx = (U_sMaps[smapIndx].s_fwdIndx & M_),
		     nSegsToMap ++)
			smap_bitmap [smapIndx / NBBY] |= 1 << (smapIndx % NBBY);
		if (nSegsToMap > maxPSmapsAvail) /* Can NEVER happen HA! HA ! */
			panic ("sureg: LRU list > avail smaps");
	}

			/************************/
			/*			*/
			/*	  SMAPS 	*/
			/*	  ===== 	*/
			/*			*/
			/************************/

	/*
	 * If we do not have enough segment maps allocated
	 * to us then we must start taking them from
	 * somewhere.  Note that it should be IMPOSSIBLE
	 * to not find enough in the code below.
#ifdef	M68020_REV_B
	 *
	 * NOTE:  1) With the larger virtual address spaces (32MB, 64MB, 128MB)
	 *	  one can indeed NOT find enough PHYSICAL smaps for a process.
	 *
	 *	  2) The solution to the problem of insufficient 'real' smaps
	 *	  is to have yet another lru/mru list
	 *	  which describe 'virtual' smaps.  The list is modeled
	 *	  upon the context lru/mru paradigm.
	 *
	 *	  3) This 'virtual' smap lru/mru lists needs to be per-process
	 *	  and will be kept in the yet-again-expanded upage.
	 *
#endif	M68020_REV_B
	 */
	if (nSegsToMap)
	{
/*  */		int	taken;

		wantSmaps = nSegsToMap;
		CTXT_DEBUG(("\nwantSmaps=0x%x=%d:", wantSmaps, wantSmaps));
		CTXT_INCSTAT(needmap);
#define TAKESMAPS(list)	\
 if ((list) != NOSMAP) \
 { \
/*D5*/	register smap_t	next; \
/*D4*/	register smap_t	prevMap; \
/*D3*/	register smap_t	firstMap  = -1;		/* Overload: state-var	*/ \
	\
	smap	  = (list);		/* Front of list */ \
	next	  = smaps[smap]; \
	prevMap	  = smap; \
	taken = wantSmaps;		/* Predict we get all we want-ed */ \
	while (--wantSmaps && next != NOSMAP) \
	{ \
		if (firstMap == -1) {		/* Initial-State */ \
			firstMap = prevMap; \
			prevMap  = smap; \
		} else if (prevMap+1 == smap) {	/* Mid-run*/ \
			prevMap++; \
		} else {			/* End-of-run */ \
			/* \
			 * This used to print 'next' rather \
			 * that "current" or "range". \
			 */ \
			if ((prevMap > firstMap) /* Ascending sequence	*/ \
			 && (prevMap > smap)) {  /* ...but broken...	*/ \
				CTXT_DEBUG((" [%x-%x]",	\
					firstMap, prevMap)); \
			} else {		/* Singleton */ \
				CTXT_DEBUG((" %x", firstMap)); \
			} \
			firstMap = prevMap  = smap; /* Set start-of-run */ \
		} \
		smap = next; \
		next = smaps[smap]; \
	} \
	if (prevMap > firstMap) /* Ascending sequence	*/ \
	{			/* ...but never printed	*/ \
		CTXT_DEBUG((" [%x-%x]",	\
			firstMap, prevMap)); \
	} else {		/* Singleton */ \
		CTXT_DEBUG((" %x", firstMap)); \
	} \
	smaps[smap] = myproc->p_smaps;	/* Join the lists  */ \
	myproc->p_smaps = (list);	/* Front of joined list */ \
	(list)   = next;		/* Remainder of what we didn't take */ \
	taken -= wantSmaps;		/* Say we took only what we got */ \
 } else \
	taken  = 0;

			/************************/
			/*	Free list	*/
			/************************/

		CTXT_DEBUG((" free:"));
		TAKESMAPS(smap_free);
		CTXT_ADDSTAT(freetaken, taken);


			/********************************/
			/*	"No-Contexts"		*/
			/********************************/

		/*
		 * If there are any processes with segment
		 * maps, but no context, then start stealing
		 * segment maps from them.
		 */
		while (wantSmaps && ctxt_noctxt.lru != &ctxt_noctxt)
		{
/*A2*/			register struct proc *oldproc = P(ctxt_noctxt.lru);

			CTXT_INCSTAT(noctxt);
			CTXT_DEBUG((" no%d:", oldproc->p_pid));
			TAKESMAPS(oldproc->p_smaps);
#if 1
			oldproc->p_needmap =
			oldproc->p_needmap + taken;  /* REG-OP /lib/ccom prob */
#else 1
			oldproc->p_needmap += taken;
#endif
			CTXT_ADDSTAT(noctxttaken, taken);

			/*
			 * If the process has no segment maps
			 * left then take it off all lists.
			 */
			if (oldproc->p_smaps == NOSMAP)
			{
				CTXT_INCSTAT(noctxtempty);
				CTXT_DEBUG((" empty"));
				dequeue(&oldproc->p_lru);
				emptyList(&oldproc->p_lru);
			}
		}

			/********************************/
			/*	"Have-Contexts"		*/
			/********************************/

		/*
		 * Finally, we must steal segment maps
		 * from processes that have contexts.
		 */
ctxt_loopback:
		while (wantSmaps && ctxt_havectxt.lru != &ctxt_havectxt)
		{
/*A2*/			register struct proc *oldproc = P(ctxt_havectxt.lru);

			CTXT_INCSTAT(havectxt);
			CTXT_DEBUG((" have%d:", oldproc->p_pid));
			TAKESMAPS(oldproc->p_smaps);
#if 1
			oldproc->p_needmap =
			oldproc->p_needmap + taken;	/* REG OP ccom-prob */
#else 1
			oldproc->p_needmap += taken;
#endif 1
			CTXT_ADDSTAT(havectxttaken, taken);

			/*
			 * If the process has no segment maps
			 * left then take it off all lists and
			 * make it give up its context since
			 * it no longer contains any valid
			 * data.
			 */
			if (oldproc->p_smaps == NOSMAP)
			{
				CTXT_INCSTAT(havectxtempty);
				CTXT_DEBUG((" empty"));
				dequeue(&oldproc->p_lru);
				emptyList(&oldproc->p_lru);
				if (oldproc->p_ctxt == NOCTXT)
					panic("sureg: ctxt_havectxt list is bad");
				oldproc->p_ctxt->procp = NULL;
				dequeue(oldproc->p_ctxt);
				addlru(&ctxt_list, oldproc->p_ctxt);
				oldproc->p_ctxt = NOCTXT;
			}
		}

		/*
		 * BUG:  This is a BANDAID until
		 * we can find and fix the real problem!
		 *
		 * If we didn't find enough segment maps,
		 * perhaps due to "leakage" elsewhere,
		 * try to recover some smaps from a process
		 * on the ctxt_list.
		 */

		/*
		 * If we still need smaps we are really hurting now.  It
		 * seems that there are processes which have contexts (and
		 * smaps) which are possibly not on the "havectxt" list.
		 * No clue (yet) as to how they get there, but we can use 
		 * brute force to seek them out and put them back on the
		 * "havectxt" list then jump back and try to get more
		 * smaps.  This is ineffecient and kludgy; but when the
		 * alternative is panic-ing, you can get creative.
		 *
		 * ELP - 3/6/86
		 */

		if (wantSmaps && (dequeue_fixup_count < 10)) {
			ctxt = (ctxt_t *) ctxt_list.lru;
			while (ctxt != (ctxt_t *) &ctxt_list) {
				if (ctxt->procp && myproc != ctxt->procp &&
				    ctxt->procp->p_smaps != NOSMAP) {
					if (ctxt_dequeue_debug) {
						cdebugger ("About to reclaim dequeued context");
						debug |= D_CTXT;
					}
					dequeue_fixup_count ++;	
					CTXT_DEBUG((" dequeued context pid %d",
						ctxt->procp->p_pid));
					dequeue (&ctxt->procp->p_lru);
					addlru (&ctxt_havectxt, &ctxt->procp->p_lru);
					goto ctxt_loopback;
				}
				ctxt = ctxt->lru;
			}
		}

#ifndef	M68020_REV_B
		if (wantSmaps)
			panic("sureg: not enough segment maps");
#else	M68020_REV_B
		/*
		 * With the larger virtual address spaces (32MB, 64MB, 128MB)
		 * one can indeed NOT find enough smaps for a large process.
		 *
		 * Our task here is to map the list of smaps, headed by p_smaps,
		 * into the virtual segment map kept in the upage
		 * for the process.  All other virtual smaps will be marked
		 * as un-instantiated.
		 *
		 * NOTE:  1) The virtual segment map is rebuilt in the upage
		 *	     for the process by sureg(); and subsequently
		 *	     modified by setsegmap() invocations.
		 *
		 *	  2) 'wantSmaps' is used subsequently herein as a flag
		 *	     indicating incomplete smap coverage.
		 */
#endif	M68020_REV_B
	}

	if (ctxt_dequeue_debug)
		debug &= ~D_CTXT;

			/************************/
			/*			*/
			/*	CONTEXTS	*/
			/*	========	*/
			/*			*/
			/************************/

	/*
	 * If we do not already have a context
	 * descriptor then get the least recently
	 * used one.  Also indicate that all of
	 * the segments need mapping.
	 */
	if ((ctxt = myproc->p_ctxt) == NOCTXT)
	{
/*A2*/		register struct proc *oldproc;

		CTXT_INCSTAT(needctxt);
		myproc->p_ctxt = ctxt = (ctxt_t *)ctxt_list.lru;
#ifdef	SETTABLE_MMU_SIZE
		/*
		 * We must qualify the selection of a new context
		 * by the requirements of an address space potentially
		 * larger than the nominal 16Mb.  Note that 32Mb
		 * is mostly a special case in this selection,
		 * since 32Mb has the same number of contexts as 16Mb.
		 *
		 * Algorithm:
		 *	if 16Mb or 32Mb, then we already have it;
		 *	otherwise
		 *		Look further up the lru-chain of contexts
		 *		for a context that meets our alignment criteria,
		 *		according to the mmu_sizing[] table.
		 *	
		 *	When found, also RELEASE any contexts that
		 *	are subsumed by the domain of the selected
		 *	address space.
		 */
		CTXT_DEBUG((" NOCTXT: "));
		if (myproc->p_mmuIndx) {	/* Firewall */
/*D5*/		   register wantContext = -1;

		   while (ctxt			/* Firewall */
		       && ctxt != (ctxt_t *)&ctxt_list.lru   /* End of chain */
		       && wantContext) {
/*D4,D3*/		register i, j;
/*D2*/			register 	range	= MMU_nContexts(myproc);
			register 	incr	= MMU_ctxtCntsBy(myproc);
			register ctxt_t	*cTxt;
			
			/*
			 * See if the context-# is a properly "aligned" one.
			 */
			if (verbosity>12)
			CTXT_DEBUG((" GetAlignedLRU: "));
			for (i=j=0; j++ < range; i++) {
				register k = MMU_alignedIds(myproc)[i];

				if (verbosity>12)
				CTXT_DEBUG((" %d?%d", ctxt->number, k));
				if (ctxt->number == k) {
					/*
					 * Have an "aligned" id
					 */
					wantContext = 0;
					CTXT_DEBUG((": itsAligned"));
					goto itsAligned;
				}
			}
			/*
			 * Crawl up the lru list of contexts
			 */
			CTXT_DEBUG((";"));
			ctxt = (ctxt_t *)ctxt->lru;
		   }
		   cdebugger("sureg/E-4: Unable to get an LRU context");
		
		} else {
			printf("myproc=0x%X + p_mmuIndx=0x%x\n",
				myproc,
				(u_long) &myproc->p_mmuIndx - (u_long)myproc);
			cdebugger("sureg/E-5: myproc->p_mmuIndx==0");
		}
itsAligned:

#endif	SETTABLE_MMU_SIZE
		if (verbosity>12)
		CTXT_DEBUG(("\ngetting ctxt #%d", ctxt->number));
		/*segstomap = COUNTSMAPS(myproc);*/

		/*
		 * If the context was owned by another
		 * process then put the process on either
		 * the no context list or no list at all.
		 */
		if (oldproc = ctxt->procp)
		{
/*A2*/			register dlist_t *list = (dlist_t *)&oldproc->p_lru;

			CTXT_INCSTAT(procctxt);
			CTXT_DEBUG((", stolen from pid %d", oldproc->p_pid));
			oldproc->p_ctxt = NOCTXT;
			dequeue(list);
			if (oldproc->p_smaps != NOSMAP)
			{
				CTXT_DEBUG((" which has 0x%x smaps;",
					oldproc->p_smaps));
				addmru(&ctxt_noctxt, list);
			}
			else
				emptyList(list);
		}
		ctxt->procp = myproc;
	}
#ifdef	SETTABLE_MMU_SIZE
	alignedCtxt	= ctxt;
	saveProc	= ctxt->procp;

	/*
	 * We need to make a exhaustive search
	 * for ALL contexts within the "shadow"
	 * of our "aligned" context.
	 *
	 * Therefore we must start at the front
	 * of the lru context-list; we may have
	 * already passed one or more.
	 */
	shadowCtxt	= (ctxt_t *)ctxt_list.lru;	/* 1st candidate */

	/*
	 * Same treatment for any OTHER processes
	 * whose contexts are in the "shadow"
	 * of the "aligned" context.
	 */
	while (shadowCtxt			      /* Firewall */
	    && shadowCtxt != (ctxt_t *)&ctxt_list.lru)/* End of chain */
	{
/*D5*/	   register 	range	= MMU_idsInACtxt(myproc);
/*D4*/	   register 	incr	= MMU_ctxtCntsBy(myproc);

	   /*
	    * Nothing to do for aggregates of size==1
	    */
	   if (range <= 1)
		break;

	   if (shadowProc = shadowCtxt->procp) {
/*D3,D2*/	register i, j;

		/*
		 * alignedCtxt-number is the "aligned" context.
		 * It is the first in the sequence of contexts
		 * which comprise a aggregate/large "context"
		 * supporting an address space of 32MB or greater.
		 *
		 * We want to start looking at the NEXT context
		 * in the "shadow" of alignedCtxt->number,
		 * if there is one.
		 */
		i = alignedCtxt->number + incr;

		/*
		 * See if the context-# is in the "shadow".
		 */
		for (j=0; j++ < range; i += incr) {
		   if (shadowCtxt->number == i) {
			/*
			 * If "shadowed" context was owned by another
			 * process, then put the process on either
			 * the no-context-list or no list at all.
			 */ 
			if (shadowProc = shadowCtxt->procp) {
				register dlist_t *list = (dlist_t *)&shadowProc->p_lru;

				CTXT_INCSTAT(procctxt);
				CTXT_DEBUG(("; ctxt #%d stolen from SHADOWED %s pid %d",
					shadowCtxt->number,
					MMU_name(shadowProc),
					shadowProc->p_pid));
				shadowProc->p_ctxt = NOCTXT;
				dequeue(list);
				if (shadowProc->p_smaps)
				{
					CTXT_DEBUG((" which has 0x%x smaps;",
						shadowProc->p_smaps));
					addmru(&ctxt_noctxt, list);
				}
				else
					emptyList(list);
			}
			/*
			 * BUG: This extra linkage of "shadow"
			 * contexts to myproc may be an error...
			 */
			shadowCtxt->procp = myproc;
		   }
		}
	   }
	   /*
	    * Continue crawling up the lru list of contexts.
	    *
	    * ASSUMPTION: any (remaining) contexts within the "shadow"
	    * of the "aligned" context will be further along
	    * the lru list.  We will NOT have already passed them!
	    */
	   shadowCtxt = (ctxt_t *)shadowCtxt->lru;
	
	}
#endif	SETTABLE_MMU_SIZE

#ifndef	SETTABLE_MMU_SIZE
	/*
	 * Make this the most recently used context
	 * so that it will not be as likely to get
	 * taken by someone else.  Also, put this
	 * process on the have-context list as the
	 * most recently used.
	 */
	dequeue(ctxt);
	addmru(&ctxt_list, ctxt);
	addmru(&ctxt_havectxt, &myproc->p_lru);

#else	SETTABLE_MMU_SIZE
	/*
	 * Make these the Most Recently Used contexts
	 * so that they will not be as likely to get
	 * taken by someone else.  Also, put this
	 * process on the have-context list as the
	 * most recently used.
	 */
	{
/*D5,D4*/	register i, j = 0;
/*A2*/		register ctxt_t	*cTxt;
/*D3*/		register 	range	= MMU_idsInACtxt(myproc);
/*D2*/		register 	incr	= MMU_ctxtCntsBy(myproc);
		
		/*
		 * We do this at least once,
		 * even though 'range' may be a singleton.
		 */
		for (i = ctxt->number; j++ < range; i+=incr) {
			cTxt = &ctxts[i];

			/*
			 * ctxt->number:	The aligned context
			 * cTxt->number:	In the SHADOW..
			 */
			if (verbosity>12)
			CTXT_DEBUG((" dequeue/addmru ctxt #%d:A(%d:S)",
				ctxt->number,	/* The aligned context	*/
				cTxt->number));	/* In the SHADOW..	*/
			dequeue(cTxt);
			addmru(&ctxt_list, cTxt);	/* MRU the context */
		}
		addmru(&ctxt_havectxt, &myproc->p_lru);	/* MRU the process */
	}
#endif	SETTABLE_MMU_SIZE

			/************************/
			/*			*/
			/*	LOAD CONTEXT	*/
			/*	============	*/
			/*			*/
			/************************/

	/*
	 * Switch to the new context so that all of
	 * our mapping changes affect the right
	 * process (us).
	 */
#ifndef	SETTABLE_MMU_SIZE
	CTXT_DEBUG(("; Switching to context %d", ctxt->number));
#else	SETTABLE_MMU_SIZE
	CTXT_DEBUG(("; Switching to %s context #%d",
		mmu_sizing[ctxt->mmuIndx].mmu_name,
		ctxt->number));
#endif	SETTABLE_MMU_SIZE
#ifndef	SETTABLE_MMU_SIZE
	R_V_CONTEXT = ctxt->number;
#else	SETTABLE_MMU_SIZE

	/*
	 * Recall that myproc is really u.u_procp,
	 * and that this is exactly the time to bind
	 * the <context,statBits> tuple with the
	 * appropriate process.
	 */
	setContextReg(myproc,ctxt->number);
#endif	SETTABLE_MMU_SIZE

			/************************/
			/*			*/
			/*	LOAD SMAPS	*/
			/*	==========	*/
			/*			*/
			/************************/

	/*
	 * Place all new segment maps into the hardware
	 * for this context.  Only map as many segments
	 * as have changed for this process.
#ifdef	M68020_REV_B
	 *
	 * NOTE:  With the recent 8-to-1 leveraging of virtual addr space
	 * to real memory (viz., 128MB vs 16Mb of smaps),
	 * we break yet another paradigm in the o/s s/w architecture!
	 *
	 * To wit, we must now add an additional level of consideration
	 * for the allocation of (already scarce) physical smaps.
	 *
	 * The algorithm is to use the bitmap constructed above as a
	 * guide to map the vitrual segments into physical segments.
#endif	M68020_REV_B
	 */
	{
/*A3*/	   register u_short *saddr = (u_short *)
		((u_long)ptob(LOWPAGES)|V_SEGMAP);
/*A2*/	   register struct pte *pte = (struct pte *) suregp0br;
/*  */		    u_char *bitmap =  &smap_bitmap [ptos(LOWPAGES)];
/*  */	            int	ps = pagesize / sizeof(u_short);
/*  */	            int	ss = segsize / sizeof(u_short);
#ifndef	M68020_REV_B
	   register int	unMappedSegs	= nSegsToMap;
	   register int	nleft		= HALFSEGS - ptos(LOWPAGES);
#endif	M68020_REV_B
/*D5*/	   register int		count;
	   register u_char	newctxt;
/*  */	   u_short		prot;
#ifdef	M68020_REV_B
	   /*
	    * NOTE: 'oldSaddr' determines 'saddr'; not vice-versa.
	    */
/*  */	   u_long		oldSaddr = ((u_long)ptob(LOWPAGES));
/*  */	   u_long		olda23;
#endif	M68020_REV_B
	   int	s;


	   smap		= myproc->p_smaps;
	   CTXT_INCSTAT(mapsegs);
	   CTXT_ADDSTAT(segstomap, unMappedSegs);     /* Slightly overstated? */
	   CTXT_DEBUG(("\nmapping 0x%x=%d segs:",
			unMappedSegs,
			unMappedSegs));
	   /*
	    * Compute the number of segments between
	    * the data and stack regions.  This will
	    * also be used by the page mapping code
	    * below the segment mapping code.
	    */
#ifndef	SETTABLE_MMU_SIZE
	   gap = ptos(usrtop+HIGHPAGES)
	       - ptos(p1pages-suregp1lr)
	       - (ptos(LOWPAGES) + ptos(suregp0lr));
#else	SETTABLE_MMU_SIZE

	   /*
	    * NOTE:  'myproc->p_mmuIndx' has been set by now,
	    * thus properly preparing
	    * for the 'usrtop' and 'p1pages' references below.
	    */
	   gap =  ptos( usrtop(myproc) + HIGHPAGES)	/* Everything	*/

	       -  ptos(p1pages(myproc) -  suregp1lr)	/* Above stack	*/
	       - (ptos(LOWPAGES)			/* Below T+D	*/
		 +ptos(suregp0lr)			/* T+D		*/
		 );
#endif	SETTABLE_MMU_SIZE

	   /*
	    * Portray the fine-structure of the computation.
	    */
	   CTXT_DEBUG(("gap(=0x%x) = ptos(usrtop=0x%X + HIGHPAGES(=0x%x) - p1pages(=0x%x) + suregp1lr(=0x%x) - LOWPAGES(=0x%x) - suregp0lr(=0x%x))\n",
			gap,
			usrtop(myproc),  HIGHPAGES,
			p1pages(myproc), suregp1lr,
			LOWPAGES,	 suregp0lr));

	   /*
	    * NOTE:  'newctxt' is toggled from V_ACCLOW to V_ACCHIGH,
	    * based upon (olda23 & V_{SEGMENT,PAGE}MAP).
	    * This toggling-code is in the segment and page macros.
	    */
	   newctxt = ctxt->number | V_ACCSM | V_ACCLOW;

	   /*
	    * Select the appropriate protection bits
	    * for the smap hardware.
	    */
	   if ((*(u_long *)suregp0br & PG_PROT) == PG_URKR)
		prot = SEG_AUR;
	   else
		prot = SEG_AURW;

	   count = ptos(myproc->p_tsize);

#ifndef	M68020_REV_B
	   if (unMappedSegs < count)
		count = unMappedSegs;
	   unMappedSegs -= count;
#endif	M68020_REV_B
#ifndef	M68020_REV_B
/*
 * This following scheme is incorrect for address spaces larger
 * than 16Mb.  Recall that 'large' address spaces are really
 * the aggregation of 2**(N-1) nominal (16Mb) contexts,
 * where N is the # of extra high-order bits of addressibility
 * beyond 16Mb.
 *	E.g.,	 32Mb	==> N==1	==> 2**0	==> No extra contexts;
 *		 64Mb	==> N==2	==> 2**1	==> 2 contexts/space;
 *		128Mb	==> N==3	==> 2**2	==> 4 contexts/space;
 *
 *	I.e., one must toggle V_SEGMAP in 'saddr' @ EACH 8Mb increment
 *	within the address space:  0, 8, 16, 24, 32, 40, 48, 56, 64, etc...
 *	'nleft' only toggles once @ HALFSEGS, which is OK
 *	for a single 16Mb address space.
 */
#define SEGLOOP(work)	if (nleft < count) \
			{ \
				count -= nleft; \
				while (--nleft >= 0) \
				{ \
					work; \
					saddr += ss; \
				} \
				R_V_CONTEXT = ctxt->number | V_ACCSM|V_ACCHIGH;\
				saddr = (u_short *)V_SEGMAP; \
				nleft = HALFSEGS; \
			} \
			nleft -= count; \
			while (--count >= 0) \
			{ \
				work; \
				saddr += ss; \
			}
#endif	M68020_REV_B
#ifdef WHITE
#define MAPSEGS(prot)	SEGLOOP(CTXT_DEBUG((" %x", smap)); \
				*saddr = smap | (prot); \
				R_V_CONTEXT ^= V_ACCUSER; \
				*saddr = smap | (prot); \
				smap = smaps[smap] \
			)
#define GAPSEGS()	SEGLOOP(*saddr = 0;\
				R_V_CONTEXT ^= V_ACCUSER; \
				*saddr = 0 \
			)
#else WHITE

#ifndef	M68020_REV_B
#define MAPSEGS(prot)	SEGLOOP(CTXT_DEBUG((" %x", smap)); \
				*saddr = smap | (prot); \
				smap = smaps[smap] \
			)
#define GAPSEGS()	SEGLOOP(*saddr = 0)
#endif	M68020_REV_B
#endif WHITE

			/************************/
			/*	TEXT SEGS	*/
			/************************/

	   CTXT_DEBUG((" T:"));

asm(" .globl segT");
asm("segT: ");

#ifndef	M68020_REV_B
	   MAPSEGS(prot);
#else	M68020_REV_B
	   mapSegs (ctxt, oldSaddr, suregp0br, prot, count);
#endif	M68020_REV_B

			/************************/
			/*	DATA SEGS	*/
			/************************/

	   /*
	    * Put the data segment maps into the
	    * hardware.
	    */
	   count = ptos(suregp0lr - myproc->p_tsize);
	   if (unMappedSegs < count)
		count = unMappedSegs;
	   unMappedSegs -= count;

	   CTXT_DEBUG((" D:"));

asm(" .globl segD");
asm("segD: ");

#ifndef	M68020_REV_B
	   MAPSEGS(SEG_AURW);
#else	M68020_REV_B
	   mapSegs (ctxt, ptob(LOWPAGES + myproc->p_tsize),
		&suregp0br [myproc->p_tsize], SEG_AURW, count);
#endif	M68020_REV_B

			/************************/
			/*	GAP SEGS	*/
			/************************/

/*


0: Physical                                                       Physical: 16Mb
|                                                                              |
|                                                                              |
v                                                                              v
--------------------------------------------------------------------------------
|////|          |             *--- PHYSICAL --*                         |\\\\\\|
|////|          |                                                       |\\\\\\|
|////|          |                                                       |\\\\\\|
|////|          |                                                       |\\\\\\|
|////|<-kernel->|<-- text-><-data--><--------gap----------><---stack--->|\\\\\\|
|////|          |                                                       |\\\\\\|
|////|          |                                                       |\\\\\\|
|////|          |                                                       |\\\\\\|
|////|          |             *--- VIRTUAL ---*                         |\\\\\\|
--------------------------------------------------------------------------------

^    ^          ^                       ^                               ^      ^
|    |          |                       |                               |      |
|<====LOWPAGES=>|                       |                               |      |
|    |          |                       |                               |      |
|    |          |                       |                               |      |
|<================================================ p1pages ===================>|
|    |          |                       |                               |      |
|    |          |                       |                               |      |
0  0x20,000     0x100,000            (middle)                      usrtop  128Mb
		^                                                       |      |
		|                       or                              |      |
		|                                                       |      |
		|                    HALFSEGS                           |<====>|
		|							|   *
		|							|   |
		|						   kvarea   |
		usrbase=0x100           or                                  |
		^                    HALFPAGES                              |
		|                                                      HIGHPAGES
		usrtext=0x100,000



Glossary:
=========

Handle:		Definition:		Explanation:
--------------	----------------------	----------------------------------------

o BIGMAP_PAGES	0x8000			128Mb map (# of pages.)

o HIGHPAGES	(uPages + UWASTE)	Pages above stack in page tables.

o LOWPAGES	btoc(USRTEXT)		Pages missing from low end.

o SYM_PA	0x5000			Symbol table:  pages [5-E] ==> 10 pages.
					C.f., s32/locore.s near 'start:'

o SYSPTSIZE	216			Assumes that kernel-text + the pages
					unused below kernel + buffers that're
					allocated in startup() (via valloc())
					fit in 1024K-32K bytes (224 pages).

o TMPSTACK	0x1000			Temporary stack addr for context switch.

o UPAGENUM	0x0FD			btop(&u + sizeof(struct user))
					< U_SMAPNUM

o UPAGES	(2			      sizeof(struct user) + kernel stack
		 + (sizeof(vSMaps_dlist_t)    sizeof LRU-list for hyperMmu(),
		    * ptos(BIGMAP_PAGES)      ...manager of virt. segments,
		   )
		   / NBPG		      ...converted to # pages required.
		)

o USRPTSIZE 	128			This is an UPPER BOUND checked
					in machine/startup.c

o UWASTE	(stoc(1) - uPages)	Page table entries wasted below
					U page entry in user page tables.

*/
	   /*
	    * ASSUME that MOST of the time the gap is very large
	    * for both the old process and the new process.
	    *
	    * This gap is especially onerous to remap quickly
	    * with the larger address spaces -- viz, 128Mb gap:
	    *
	    *	0x0100 segments/16Mb ==> 0x0800 segments/128Mb
	    *	0x1000    pages/16Mb ==> 0x8000    pages/128Mb!!
	    *
	    * Just PATCH UP EACH END of the gap as needed
	    * and SAVE MORE THAN 99% OF THE SEGMENT MAPPING
	    * in most cases.  (This ASSUMEs that most processes have
	    * less than one segment of text+data and
	    * less than one segment of stack).
	    */
	   if (unMappedSegs)
	   {
		register int segnum = ptos(suregp0lr + LOWPAGES);

		/*
		 * Handle the lower extremity of the gap.
		 *
		 * NOTE:  'ctxt->gapstart' begins with a value
		 * of 1/2 of the address space size, i.e., "middle".
		 * For a process address space
		 * with (initially) no text, we 'gap'
		 * from LOWPAGES up to the "middle".
		 * Then the balance of the space is 'gapped'
		 * from the "middle" to usrtop(u.u_procp)
		 *
		 * "middle" can be any of HALFSEGS, HALFPAGES,
		 * or (mmu_sizing[ i ].mmu_maxVaddr >> 1),
		 * depending upon compile-time options.
		 *
		 * NOTE:  We retain the notion of "middle"
		 * for complicity with prior strictly 16Mb algorithms.
		 * Beyond that, the notion of a division/split
		 * in the gap between end-of-data/beginning-of-stack
		 * could be abandoned entirely.
		 */
		count		= ctxt->gapstart - segnum;
		ctxt->gapstart	= segnum;		/* New lwrbnd */

		CTXT_DEBUG((" gap S%x", ctxt->gapstart));
		if (count > gap)
			count = gap;
		CTXT_DEBUG((" M%x", count));

asm(" .globl segGL");
asm("segGL: ");

		/*
		 * NOTE:  We must not confuse
		 *	'maxPSmapsAvail' with 'maxVSmapsAvail'
		 * Only virtual smaps are required
		 * for mapping the gap between the data and stack.
		 */
#ifndef	M68020_REV_B
		GAPSEGS();
#else	M68020_REV_B
		mapSegs (ctxt, stob(ctxt->gapstart),
			&suregp0br [stoc(ctxt->gapstart)-LOWPAGES], 0, count);
#endif	M68020_REV_B


		/*
		 * Now twiddle with the UPPER extremity of the gap.
		 */
		count		= ctxt->gapstart + gap - ctxt->gapend;
		ctxt->gapend	= ctxt->gapstart + gap;	/* New uprbnd */

		CTXT_DEBUG((" gap E%x", ctxt->gapend));
		if (count > 0)
		{
			if (count > gap)
				count = gap;
			segnum = ctxt->gapend - count;
		} else {
			segnum = ctxt->gapend;

			/*
			 * NOTE:  If size of the entire gap is a single
			 * segment contained in the lower portion,
			 * then 'count' will be (observably) -1,
			 * so reset it for tidiness and sanity.
			 */
			count  = 0;
		}

		/*
		 * Guarantee the (non-monotonic!) segment address
		 * pointing at the UPPER extremity of the gap.
		 */
		oldSaddr = segnum << SEGSHIFT;

#ifndef	M68020_REV_B
		/*
		 * Everything should ALREADY be set up
		 * as a side effect of doing the last set
		 * of mappings.  Only need to recompute if
		 * we fall into a different V_SEGMAP-Mb chunk.
		 *
		 * BUG:  This may break if we go back to the old
		 * algorighms -- dunno for sure...
		 */
		if ((nleft = HALFSEGS - segnum) <= 0)
		{
			newctxt   = ctxt->number | V_ACCSM |V_ACCHIGH;
			saddr	  = (u_short *)(oldSaddr | V_SEGMAP);
			nleft	  = HALFSEGS;
		}
#endif	M68020_REV_B

		CTXT_DEBUG((" M%x", count));

asm(" .globl segGU");
asm("segGU: ");

#ifndef	M68020_REV_B
		GAPSEGS();
#else	M68020_REV_B
		mapSegs (ctxt, oldSaddr, &suregp0br [btop(oldSaddr)-LOWPAGES],
			0, count);
#endif	M68020_REV_B
	   }
			/************************/
			/*	STACK SEGS	*/
			/************************/

	   /*
	    * Put the stack segment maps into the
	    * hardware.
	    */
#ifndef	SETTABLE_MMU_SIZE
	   count = ptos(p1pages - suregp1lr - HIGHPAGES);
#else	SETTABLE_MMU_SIZE
	   count = ptos(p1pages(myproc) - suregp1lr - HIGHPAGES);
#endif	SETTABLE_MMU_SIZE
	   if (unMappedSegs < count)
		count = unMappedSegs;
	   unMappedSegs -= count;
	   CTXT_DEBUG((" S:"));

asm(" .globl segS");
asm("segS: ");

#ifndef	M68020_REV_B
	   MAPSEGS(SEG_AURW);
#else	M68020_REV_B
	   oldSaddr  = (u_long) ptob(LOWPAGES + suregp0lr + (PPS - 
		((suregp0lr & SPMASK) ? (suregp0lr & SPMASK) : PPS)))
		+ (stoc(gap) * ps * sizeof(u_short));
	   mapSegs(ctxt, oldSaddr, &suregp1br[btop(oldSaddr)],
		SEG_AURW, count);
#endif	M68020_REV_B

			/************************/
			/*	TOPMOST SEG	*/
			/************************/
	   /*
	    * Map the top 64K of memory into this
	    * process' space.
	    */
#ifndef	SETTABLE_MMU_SIZE
		saddr = (u_short *)(((nsegs-1)<<SEGSHIFT) | V_SEGMAP);
#ifdef	M68020_REV_B
		oldSaddr = (nsegs-1) << SEGSHIFT;
#endif	M68020_REV_B
#else	SETTABLE_MMU_SIZE

		saddr = (u_short *)(((nsegs(myproc)-1)<<SEGSHIFT) | V_SEGMAP);
#ifdef	M68020_REV_B
		oldSaddr = ( nsegs(myproc) - 1) << SEGSHIFT;
#endif	M68020_REV_B
#endif	SETTABLE_MMU_SIZE
		count = 1;
#ifdef	M68020_REV_B

		/*
		 * Keep the final bean-count accurate.
		 */
		if (unMappedSegs < count)
			count = unMappedSegs;
		unMappedSegs -= count;
#endif	M68020_REV_B

		CTXT_DEBUG((" top:"));

asm(" .globl segTop");
asm("segTop: ");

#ifndef	M68020_REV_B
		   MAPSEGS(SEG_AURW);
#else	M68020_REV_B
		   mapSegs(ctxt, oldSaddr, &suregp1br[btop(oldSaddr)-LOWPAGES],
			SEG_AURW, count);
#endif	M68020_REV_B

	   /*
	    * BUG: This revertion is probably NOT necessary;
		    * but I will sleep better at night...
		    */
		   R_V_CONTEXT = ctxt->number;

		   CTXT_DEBUG(("; wantSmaps=%d count=%d pSmapsMappedSoFar=0x%x=%d vSmapsMappedSoFar=0x%x=%d;",
					wantSmaps,  count,   pSmapsMappedSoFar, /*PHYS*/
							     pSmapsMappedSoFar,
							     vSmapsMappedSoFar, /*VIRT*/
							     vSmapsMappedSoFar));

	} /* if (segstomap) */

    }	/* End-of-1st-section (dealing with segments) */
#ifndef	M68020_REV_B

/*============================================================================*/
/*============================================================================*/
/*======								======*/
/*======  We now make another complete pass over the address space,	======*/
/*======   starting with LOWPAGES, to initialize the page map(s).	======*/
/*======								======*/
/*============================================================================*/
/*============================================================================*/

			/************************/
			/*			*/
			/*	LOAD PMAPS	*/
			/*	==========	*/
			/*			*/
			/************************/

	/*
	 * Copy the page table entries into each
	 * segment map that does not already contain
	 * the right value.
#ifdef	M68020_REV_B
	 *
	 * Since we have a 24-bit limitation on the physical memory available,
	 * (pg_pfnum is only 12-bits,) we have at best,
	 * only 4096 virtual pages that we can map to physical memory.
	 *
#endif	M68020_REV_B
	 */
	if (myproc->p_needmap)
	{
/*A2*/		register u_short *paddr = (u_short *)((u_long)ptob(LOWPAGES)|V_PAGEMAP);
/*  */	        	 int ps = pagesize / sizeof(u_short);
#ifndef	M68020_REV_B
		register int nleft = HALFSEGS - ptos(LOWPAGES);
#else	M68020_REV_B
		/*
		 * NOTE: 'oldPaddr' determines 'paddr'; not vice-versa.
		 */
/*D5*/		register u_long	oldPaddr	= ((u_long)ptob(LOWPAGES));
#endif	M68020_REV_B
/*  */		register struct	pte   *	pte;
/*D4*/		register int		count;
/*D3*/		register u_char		newctxt;
/*  */		u_short			entry;
#ifdef	M68020_REV_B
		u_long			olda23;		/* A<23> := 2^23 */
#endif	M68020_REV_B


#ifdef	M68020_REV_B
		olda23		= 0;
		unMappedPages	= (myproc->p_needmap << PTOSSHIFT);

		/*
		 * Maximum possible physical memory -- 24-bits -- limits the #
		 * of pages we might try to map to 2^12 == 4096 pages, minus
		 * at least the pages below USRTEXT ('usrbase' pages.)
		 */
		maxPagesAvail	 = min(4096-usrbase,pSmapsMappedSoFar<<PTOSSHIFT);
		pagesMappedSoFar = 0;

#endif	M68020_REV_B
		CTXT_INCSTAT(mappages);
		CTXT_DEBUG(("\nmaxPagesAvail=0x%x=%d",
			       maxPagesAvail,
			       maxPagesAvail));

		/*
		 * This was a partial lie:  There are at least UPAGES
		 * of pages that we do/might not remap each time
		 * which are located in the top segment
		 * of the virtual address space.
		 */
		CTXT_DEBUG((", unMappedPages=%d:",
			       unMappedPages));
		CTXT_ADDSTAT(pagestomap,	  
			       unMappedPages - UPAGES);

		newctxt = ctxt->number | V_ACCPM | V_ACCLOW;	/* Baseline */

				/*||||||||||||||||||||||*/
				/*			*/
				/*	  MRU Page	*/
				/*			*/
				/*||||||||||||||||||||||*/

		/*
		 * HACK2:  Map the pages for the segment at the head
		 * of the virtual MRU-list.
		 * We don't subsequently remap those pages; no harm is done.
		 *	
	 	 * The rationale for this is that while the LRU list contains
		 * more or less random values, sureg() sets both h/w maps
		 * in order * of scending virtual address.  Since we must
		 * guarantee that at least the faulted page is mapped,
		 * we map that (the MRU'th) segment first.  The only problem is
		 * that we end up performing the mapping litany more or less
		 * twice, which is a lexical unpleasantness.
		 *
		 * u.u_hndlrState==0 when we get here
		 * via sbreak() ==> ovadvise().  I.e., explicit requests
		 * for more memory; and without faulting on anything.
		 *
		 * Algorithm:
		 * ==========
		 *	SEGMENT map:		...Already done...
		 *	------------
		 *
		 *	if (wantSmaps)		==> Insufficient smaps
		 *	{
		 *		1) Determine flavor of the segment:
		 *			C.f. u_aAddr if addr is text, data, gap,
		 *			stack, or top;
		 *		2) Set segment access protections accordingly;
		 *		3) Punch entry into the h/w segment map;
		 *		4) Point mapping s/w at "next" physical smap;
		 *	}
		 *
		 *	PAGE map:		...Herewith...
		 *	---------
		 *	if (wantSmaps)		==> Insufficient smaps
		 *	{
		 *		1) For each page in the segment's worth of pte-s
		 *		   corresponding to u_aAddr:
		 *			 i) Set pte access bits appropriately;
		 *			    "Gap" page(s) as necessary.
		 *			    This is the particularly unpleasant
		 *			    portion.
		 *				BUG:  This fine granularity
		 *				differential mapping is NOT
		 *				done yet!
		 *			ii) Punch entry into the h/w page map
		 *			    for each page in the affected
		 *			    segment;
		 *		2) Reset u_hndlrState, which busaddr() set;
		 *		3) Remember NOT to subsequently remap
		 *		   the MRU'th entries
		 *	}
		 *
		 *
		 *	In general:
		 *	-----------
		 *	1) DON'T remap the corresponding segment and pages
		 *	   because we will lose track of a PHYSICAL smap.
		 *
		 *	2) Carefully map the pages in complete compliance
		 *      with their fine-structure.
		 */
		skipMRU  = 0;		/* Remap MRU_HEAD'th pagemap	*/

		if (wantSmaps)		/* Insufficient PHYSICAL smaps	*/
		{
/*  */			register struct	pte   *	pte;
			u_long		  	vpno;	/* Page #  */

asm(" .globl pageMRU");
asm("pageMRU: ");
			if (!u.u_smapLRU_HEAD) { /* And nothing to prempt */
				/*
				 * Firewall.
				 */
				cdebugger("sureg/E-6: pageMRU: LRU_HEAD==NULL");
			}

			/*
			 * PAGE map:
			 * ---------
			 *	1) Determine flavor of the segment:
			 *		C.f., u_smapMRU_HEAD if addr is text,
			 *		data, gap, stack, or top -- use code
			 *		lifted from vtopte().
			 */
			count	 = SEGSIZE/NBPG;	/* Full seg's worth */
			oldPaddr = (u.u_smapLRU_TAIL&V_VSEGNO_MASK) << SEGSHIFT;

	
			vpno = oldPaddr >> PGSHIFT;
			if (isatsv(myproc, vpno)) {

				/*
				 * Text segment:
				 */
				pte = tptopte(myproc, vtotp(myproc, vpno));

				/*
				 * Put the page maps
				 * into the hardware.
				 */
				count = mapTextOrDataPages(ctxt, pte, oldPaddr, count);

			} else if (isadsv(myproc, vpno)) {

				/*
				 * Data segment:
				 */
				pte	= dptopte(myproc, vtodp(myproc, vpno));
				count	= mapTextOrDataPages(ctxt, pte, oldPaddr, count);

asm(" .globl MRUpageDG");
asm("MRUpageDG: ");
				/*
				 * Deal with any "gaps" at end of data.
				 * The DATAGAP() macro properly computes
				 * the 'count' within the macro.
				 */
				oldPaddr = (u_long)ptob(LOWPAGES + suregp0lr);
				/*
				 * We only do a DATAGAP if the segment at the
				 * head of the list is at the end of the data 
				 * segment AND needs to be gapped.
				 */
				if (btos (oldPaddr) == PTOS (vpno))
					DATAGAP();	/* 'count' OK */

			} else if (isasSv(myproc, vpno)) {
				/*
				 * Stack segment:
				 */
				pte	= sptopte(myproc, vtosp(myproc, vpno));
				count	= mapStackPages(ctxt, pte, oldPaddr, count);

asm(" .globl MRUpageSG");
asm("MRUpageSG: ");
				/*
				 * Deal with any "gaps" at bottom of stack.
				 * 'oldPaddr' is properly computed again
				 * within the STACKGAP() macro.
				 */
				oldPaddr  = (u_long)
					ptob(LOWPAGES + suregp0lr + (PPS - 
						((suregp0lr & SPMASK) ? 
						(suregp0lr & SPMASK) : PPS)))
					+ (stoc(gap) * ps * sizeof(u_short));
				/*
				 * We only do a STACKGAP if the segment at the
				 * head of the list is at the beginning of the
				 * stack segment AND needs to be gapped.
				 */
				if (btos (oldPaddr) == PTOS (vpno))
					STACKGAP();

#ifdef	s32	/* MAPUPPER64K */
#ifndef	SETTABLE_MMU_SIZE
			} else if ((vpno >> PAGE_TO_SEG_SHIFT) == nsegs-1) {
#else	SETTABLE_MMU_SIZE
			} else if ((vpno >> PAGE_TO_SEG_SHIFT) == nsegs(myproc)-1) {
#endif	SETTABLE_MMU_SIZE
				/*
				 * Top segment:
				 */
				pte	= myproc->p_p0br
					+ myproc->p_szpt * NPTEPG
					- HIGHPAGES
					+ (vpno & V_VPAGENO);
				count	= mapTopPages(ctxt, pte, oldPaddr, count);

#endif	s32	/* MAPUPPER64K */
			} else {

				/*
				 * Nothing we know anything about!
				 */
				cdebugger("sureg/E-8: pageMRU: GAP?!");
			}
		}

		/*
		 * Reinstate the environment
		 * for normal mapping of segments.
		 */
		oldPaddr = (u_long)ptob(LOWPAGES);
		skipMRU  = 1;		/* Don't remap MRU_HEAD'th pagemep */

		/*
		 * Map all pages in the text AND data
		 * regions of the process.
		 */
		pte   = suregp0br;
		count = suregp0lr;
		if (unMappedPages < count)
			count = unMappedPages;
		unMappedPages -= count;

#ifdef	M68020
	/*
	 * Non-cached pages are strictly fill-on-demand, pg_fileno==FPHYS;
	 * and the may only reside as a "DATAENTRY"
	 * or as a "TOPENTRY" in the programs's address space.
	 */
#define	M68020_CACHE	if (((struct fpte *)pte)->pg_noncached) \
				entry |= V_NONCACHED;
#else	M68020
#define	M68020_CACHE	;
#endif	M68020

/*
 * Pte-s for iospace pages are constrained
 * to ONLY the fill-on-demand s/w pte format.
 * Any V_MBIO-ness is buried in the pg_blkno subfield
 * of the p_fod==1 fpte's.
 * Thereby we pass along all the information
 * from the s/w pte's to the h/w pte's.
 */

#define DATAENTRY	if (pte->pg_v) \
				entry = pte->pg_pfnum; \
			else if (pte->pg_fod && ((struct fpte *)pte)->pg_fileno == PG_FPHYS) { \
				entry = ((struct fpte *)pte)->pg_blkno; \
				M68020_CACHE; \
			} else \
				entry = V_PAGE_INVALID; \
			if (pte->pg_m) \
				entry |= V_DIRTY; \
			++pte;

#define STACKENTRY	if (pte->pg_v) \
				entry = pte->pg_pfnum; \
			else \
				entry = V_PAGE_INVALID; \
			if (pte->pg_m) \
				entry |= V_DIRTY; \
			++pte;

#define TOPENTRY	if (pte->pg_fod && ((struct fpte *)pte)->pg_fileno == PG_FPHYS) { \
				entry = ((struct fpte *)pte)->pg_blkno; \
				M68020_CACHE; \
			} else \
				entry = V_PAGE_INVALID; \
			if (pte->pg_m) \
				entry |= V_DIRTY; \
			++pte;

#ifdef WHITE
#define WHITEMAPPAGES	R_V_CONTEXT = newctxt | V_ACCUSER; \
			*paddr = entry;
#else WHITE
#define WHITEMAPPAGES
#endif WHITE

			/********************************/
			/*	Text & data pages	*/
			/********************************/

		CTXT_DEBUG((" TD:"));

asm(" .globl pageTD");
asm("pageTD: ");

		MAPPAGES(DATAENTRY);

			/********************************/
			/*	Data-margin gap pages	*/
			/********************************/

		if (unMappedPages)
		{
asm(" .globl pageDG");
asm("pageDG: ");
			/*
			 * Deal with any "gaps" at end of data.
			 * The DATAGAP() macro properly computes
			 * the 'count' within the macro.
			 */
			DATAGAP();

			/****************************************/
			/*	  Stack-margin gap pages	*/
			/****************************************/

asm(" .globl pageSG");
asm("pageSG: ");
			/*
			 * Deal with any "gaps" at bottom of stack.
			 * 'oldPaddr' is properly computed
			 * within the STACKGAP() macro.
			 */
			STACKGAP();
		}

			/************************/
			/*	Stack pages	*/
			/************************/

		/*
		 * Map all pages which are in the stack
		 * area.
		 */
		pte = &suregp1br[suregp1lr];

#ifndef	SETTABLE_MMU_SIZE
		count = p1pages - suregp1lr - HIGHPAGES;
#else	SETTABLE_MMU_SIZE
		count = p1pages(myproc) - suregp1lr - HIGHPAGES;
#endif	SETTABLE_MMU_SIZE

		if (unMappedPages < count)
			count = unMappedPages;
		unMappedPages -= count;

		CTXT_DEBUG((" S:"));

asm(" .globl pageS");
asm("pageS: ");

		MAPPAGES(STACKENTRY);

			/********************************/
			/*	Top-segment's pages	*/
			/********************************/

		/*
		 * Map the top 64K of memory if this process
		 * requests it.
		 */
#ifndef	M68020_REV_B
#ifndef	SETTABLE_MMU_SIZE
		paddr = (u_short *)(((nsegs-1)<<SEGSHIFT) | V_PAGEMAP);
#else	SETTABLE_MMU_SIZE
		paddr = (u_short *)(((nsegs(myproc)-1)<<SEGSHIFT) | V_PAGEMAP);
#endif	SETTABLE_MMU_SIZE
#else	M68020_REV_B

#ifndef	SETTABLE_MMU_SIZE
		oldPaddr = ( nsegs	   - 1) << SEGSHIFT;
#else	SETTABLE_MMU_SIZE
		oldPaddr = ( nsegs(myproc) - 1) << SEGSHIFT;
#endif	SETTABLE_MMU_SIZE
		paddr    = (u_short *) (oldPaddr | V_PAGEMAP);	/* 2ndary... */
#endif	M68020_REV_B

		count = HIGHPAGES - UPAGES;

		if (unMappedPages < count)
			count = unMappedPages;
		unMappedPages -= count;
		CTXT_DEBUG((" top:"));

asm(" .globl pageTop");
asm("pageTop: ");

		MAPPAGES(TOPENTRY);
	}
#endif	M68020_REV_B
#ifndef	M68020_REV_B
	/*
	 * We now have all of the segment maps we
	 * need and they are mapped correctly so
	 * we indicate this fact.
	 */
	myproc->p_needmap = 0;
#else	M68020_REV_B

canDoNoMorePages:

	/*
	 * We now have all of the PHYSICSL segment maps we need,
	 * or at least could get (up to the theoretical limit),
	 * and they are mapped correctly,
	 * so we indicate this fact,
	 * even though we may still need
	 * additional PHYSICAL segment maps.
	 * 
	 * We leave the latter situation
	 * in the hands of the segment-fault hardware
	 * for appropriate and timely feedback.
	 */
	myproc->p_needmap = (pSmapsMappedSoFar >= myproc->p_needmap)
				? 0
				: myproc->p_needmap - pSmapsMappedSoFar;
	if (myproc->p_needmap)
		CTXT_DEBUG((" Exit needing %x smaps\n", myproc->p_needmap));
#endif	M68020_REV_B
	CTXT_DEBUG(("; unMappedSegs=%d unMappedPages=%d\n",
		       unMappedSegs,   unMappedPages));

#ifndef	SUREG_WORKING
	copyMaps (ctxt);	/* Squirrel away the hardware maps */
#endif	SUREG_WORKING

asm(" .globl suregExit");
asm("suregExit: ");
	if (segsMappedSoFar > nSegsToMap)
		cdebugger ("Sureg Botch");

	splx(s);
}
#endif !OLD_SUREG	/* I.e., this is the NEW sureg() */

/*
 * Free the context and segment maps used
 * by a process and compute the number of
 * segment maps the process will need.
 * This is called when the process changes
 * size or exits.
 */
#if	!defined(SETTABLE_MMU_SIZE)
ctxt_invalidate(p)
#else	!defined(SETTABLE_MMU_SIZE)

/*
 * Invalidate ALL context(s) associated with process 'p',
 * including any context(s) within its "shadow".
 */
ctxt_invalidate(p)
   register struct proc *p;
{
/*A5*/	register ctxt_t		* shadowCtxt;	/* Context in a "shadow"*/
/*A4*/	register ctxt_t		* alignedCtxt;	/* Old context struct	*/
/*A3*/	register struct	proc	* shadowProc; 	/* Proc-slot in "shadow"*/
/*A2*/	register struct	proc	* saveProc; 	/* Old proc-slot	*/
#ifdef	SETTABLE_MMU_SIZE
/*  */	register struct proc	* curProc = u.u_procp;	/* CURRENT process */
#endif	SETTABLE_MMU_SIZE

	if ((int) p <= NULL)
		panic("ctxt_invalidate: bad proc addr");
	/*
	 * Have the process: need its context(s)
	 */
	saveProc	= p;
	alignedCtxt	= saveProc->p_ctxt;

	shadowCtxt	= alignedCtxt;		/* For starters */
	CTXT_DEBUG(("ctxt_invalidate #%d for proc=0x%x pid=%d:",
		((p->p_ctxt > 0)
			? p->p_ctxt->number
			: -1),
		p, p->p_pid));

#ifdef	CTXT_DEMUX
	/*
	 * First we take apart any aggregated contexts
	 * and reset their h/w maps to be 1:1 with a
	 * 'normalMmuIndx' version of MYCTXT.
	 */
	ctxt_deMux(p);
#endif	CTXT_DEMUX

	/*
	 * We ALWAYS invalidate the 1st one
	 * to insure that ALL dequeue-ing is performed.
	 */
	ctxt_oneInvalidate(p);

	/*
	 * Same treatment for any OTHER processes
	 * whose contexts are in the "shadow".
	 */
	do {
		register i, j;
		register 	range	= MMU_nContexts(curProc);
		register 	incr	= MMU_ctxtCntsBy(curProc);

		/*
		 * alignedCtxt->number is the "aligned" context.
		 * NOTE that the "aligned" context is,
		 * by definition, in its own shadow.
		 */
		i = alignedCtxt->number;

		/*
		 * Search for "shadow" candidates.
		 */
		for (j=0; j++ < range; i+=incr) {

		   /*
		    * Is it in the "shadow"?
		    */
		   if (shadowCtxt->number == i) {
			/*
			 * If "shadowed" context was owned by a DIFFERENT
			 * process then we are probably in trouble;
			 * or I don't understand an aspect
			 * of the connectivity...
			 *
			 * Otherwise, release the context.
			 */ 
			if (shadowProc = shadowCtxt->procp) {
				/*
				 * BUG: The extra linkage of "shadow"
				 * contexts to saveProc may produce
				 * an error during MULTIPLE dequeuing.
				 */
				ctxt_oneInvalidate(shadowProc);
			} else {
				printf("shadowProc=0x%X NOT associated with shadowCtxt=0x%x\n",
					shadowProc, shadowCtxt);
				cdebugger("sureg/E-6: We don't own this context!");
			}
		   }
		}

		/*
		 * Crawl up the lru list of contexts.
		 * We should still be in the context's lru-list.
		 *
		 * Remove the PROCESS from the p_lru list.
		 *
		 * BUG: ARE we still on the context lru-list,
		 * or did ctxt_invalidate() remove the linkage?
		 */
		shadowCtxt = (ctxt_t *)shadowCtxt->lru;

	} while (shadowCtxt			      /* Firewall */
	      && shadowCtxt != (ctxt_t *)&ctxt_list.lru)/* BUG: End of chain */
}

/*
 * ctxt_oneInvalidate -- Invalidate the context associated
 *			 with process 'p'.
 */
ctxt_oneInvalidate(p)
#endif	!defined(SETTABLE_MMU_SIZE)
   register struct proc *p;
{
	if ((int) p <= NULL)
		panic("ctxt_oneInvalidate: bad proc addr");

	CTXT_INCSTAT(inval);

#if	!defined(SETTABLE_MMU_SIZE)
	CTXT_DEBUG(("ctxt_invalidate #%d for proc 0x%x pid %d:",
		((p->p_ctxt > 0)
			? p->p_ctxt->number
			: -1),
		p, p->p_pid));
#else	!defined(SETTABLE_MMU_SIZE)

	CTXT_DEBUG(("ctxt_oneInvalidate #%d for proc=0x%x pid=%d:",
		((p->p_ctxt > 0)
			? p->p_ctxt->number
			: -1),
		p, p->p_pid));
#endif	!defined(SETTABLE_MMU_SIZE)

	/*
	 * Take the process off any lists that
	 * it is on since we are it will no
	 * longer own anything worth stealing.
	 */
	dequeue(&p->p_lru);

	/*
	 * If the process had a context then
	 * make the context least recently used.
	 */
	if (p->p_ctxt != NOCTXT)
	{
		CTXT_INCSTAT(invalctxt);
		CTXT_DEBUG((" ctxt #%d", p->p_ctxt->number));
		p->p_ctxt->procp = NULL;
		dequeue(p->p_ctxt);
		addlru(&ctxt_list, p->p_ctxt);
		p->p_ctxt = NOCTXT;
	}

	/*
	 * If the process had any segment maps
	 * then we put them on the free list.
	 */
	if (p->p_smaps != NOSMAP)
	{
		register smap_t next;

		smap = p->p_smaps;
		CTXT_INCSTAT(invalsmaps);
		CTXT_DEBUG((" smaps:"));
		CTXT_DEBUG((" %x", smap));
		while ((next = smaps[smap]) != NOSMAP)
		{
			CTXT_DEBUG((" %x", next));
			smap = next;
		}
		smaps[smap] = smap_free;
		smap_free = p->p_smaps;
		p->p_smaps = NOSMAP;
	}

	/*
	 * Compute how many segment maps this
	 * process will need so that sureg()
	 * can get them.
	 */
	p->p_needmap = COUNTSMAPS(p);
	CTXT_ADDSTAT(invalneed, p->p_needmap);
	CTXT_DEBUG((" p_needmap=0x%x=%d\n", p->p_needmap, p->p_needmap));
}

#ifdef OLDWAY
/*
 * ctxt_pageupdate -- Update a page for a process.
 *
 * Make sure that the given page is up to
 * date for the given process.  If the process
 * has no context then it will be updated next
 * time sureg() is called for it.  If it does
 * have a context then we must switch to it,
 * call setpagemap, and switch back.  If the
 * process has no context but has smaps then
 * it must be invalidated since we cannot get
 * to the smaps for it.
 */
ctxt_pageupdate(p, v, pte)
   register struct proc *p;
   register int v;
   register struct pte *pte;
{
/*A3*/	A_V_CONTEXT;				/* Allocate register-var*/
	register u_char oldctxt;
	register int s;

	if ((int) p <= NULL)
		panic("ctxt_pageupdate: bad proc addr");

	CTXT_INCSTAT(pageupdates);

	if (p->p_ctxt == NOCTXT)
	{
		if (p->p_smaps)
		{
			CTXT_INCSTAT(updateinvals);
			CTXT_DEBUG(("ctxt_pageupdate: "));
			ctxt_invalidate(p);
		}
		return;
	}
	CTXT_INCSTAT(realupdates);
	CTXT_DEBUG(("ctxt_pageupdate: pid %d, page 0x%x, pte 0x%x\n", p->p_pid, v, *(int *)pte));

	s = spl7();

#ifndef	SETTABLE_MMU_SIZE
	oldctxt = R_V_CONTEXT;
	R_V_CONTEXT = p->p_ctxt->number;
	setsysmap(v, pte, 1);
	R_V_CONTEXT = oldctxt;
#else	SETTABLE_MMU_SIZE

	/*
	 * BUG:  I presume that p != u.u_procp,
	 * or there could be a serious problem!
	 */
	getContextReg(u.u_procp,oldctxt);	/* BUG: ??? */
	setContextReg(p,p->p_ctxt->number);
	setsysmap(v, pte, 1);
	setContextReg(u.u_procp,oldctxt);	/* BUG: ??? */
#endif	SETTABLE_MMU_SIZE

	splx(s);
}

#else	OLDWAY		/* ...The NEW way... */

/*
 * ctxt_pageupdate -- Update a page for a process.
 *
 * Make sure that the given page is up to
 * date for the given process.  If the process
 * has no context then it will be updated next
 * time sureg() is called for it.  If it does
 * have a context then we must switch to it,
 * call setpagemap, and switch back.  If the
 * process has no context but has smaps then
 * it must be invalidated since we cannot get
 * to the smaps for it.
 */
ctxt_pageupdate(p, v, pte)		/* ...The NEW way... */
   register struct proc *p;
   register int v;
   register struct pte *pte;
{
/*A3*/	A_V_CONTEXT;				/* Allocate register-var*/
	register int sindex;
	register u_short *saddr;
	register u_short smap;
	register u_char oldctxt;
	u_short oldsme;
	int s;

	if ((int) p <= NULL)
		panic("ctxt_pageupdate: bad proc addr");

	CTXT_INCSTAT(pageupdates);

	/*
	 * Find the index of the smap corresponding
	 * to the given virtual address.
	 */
	if (isatsv(p, v))
		sindex = vtotp(p, v) >> PTOSSHIFT;
	else if (isadsv(p, v))
		sindex = ptos(p->p_tsize) + (vtodp(p, v) >> PTOSSHIFT);
	else if (isassv(p, v))
		sindex = ptos(p->p_tsize) + ptos(p->p_dsize) +
				ptos(p->p_ssize) - ptos(vtosp(p, v) + 1);
	else if (v >= maxpage-0xF)
		sindex = ptos(p->p_tsize) + ptos(p->p_dsize) + ptos(p->p_ssize);
	else
		panic("ctxt_pageupdate: bad v");

	/*
	 * If the smap is not in hardware then we
	 * are through.
	 */
	if (sindex < p->p_needmap)
		return;

	CTXT_DEBUG(("ctxt_pageupdate: pid %d, page 0x%x, pte 0x%x", p->p_pid, v, *(int *)pte));

	/*
	 * If the process has a context then we
	 * can switch to it and use setsysmap
	 * to modify the map.
	 */
	if (p->p_ctxt)
	{
		CTXT_INCSTAT(realupdates);
		CTXT_DEBUG(("; easy, ctxt %d\n", p->p_ctxt->number));

		s = spl7();

#ifndef	SETTABLE_MMU_SIZE
		oldctxt = R_V_CONTEXT;
		R_V_CONTEXT = p->p_ctxt->number;
		setsysmap(v, pte, 1);
		R_V_CONTEXT = oldctxt;
#else	SETTABLE_MMU_SIZE

		/*
		 * BUG:  I presume that p != u.u_procp,
		 * or there could be a serious problem!
		 */
		getContextReg(u.u_procp,oldctxt);
		setContextReg(p,p->p_ctxt->number);
		setsysmap(v, pte, 1);
		setContextReg(u.u_procp,oldctxt);
#endif	SETTABLE_MMU_SIZE

		splx(s);

		return;
	}

	/*
	 * Must do it the hard way: scan the list
	 * of segment maps for the process until
	 * we come to the one (indexed by sindex)
	 * corresponding to the virtual page we
	 * are looking at.  Note that there are
	 * p_needmap smaps missing from the FRONT
	 * of the list.
	 */
	CTXT_INCSTAT(hardupdates);
	CTXT_DEBUG(("; hard\n"));

	s = spl7();

	sindex -= p->p_needmap;
	smap = p->p_smaps;
	while (sindex--)
		smap = smaps[smap];

	/*
	 * Force the given segment map into a
	 * known location (saving the old one),
	 * set the page map, and restore the
	 * segment map.
	 */
	saddr = (u_short *)(USRTEXT | V_SEGMAP);
#ifndef	SETTABLE_MMU_SIZE
	oldctxt = R_V_CONTEXT;
	R_V_CONTEXT = V_ACCSM | V_ACCLOW | 0;
#else	SETTABLE_MMU_SIZE

	/*
	 * BUG:  I presume that p != u.u_procp,
	 * or there could be a serious problem!
	 */
	getContextReg(u.u_procp,oldctxt);
	setContextReg(p,V_ACCSM | V_ACCLOW | 0);
#endif	SETTABLE_MMU_SIZE

	oldsme = *saddr;
	*saddr = smap | SEG_ASYS;

#ifndef	SETTABLE_MMU_SIZE
	R_V_CONTEXT = 0;
	setsysmap(usrbase + (v & (PPS-1)), pte, 1);
	R_V_CONTEXT = V_ACCSM | V_ACCLOW | 0;
	*saddr = oldsme;
	R_V_CONTEXT = oldctxt;
#else	SETTABLE_MMU_SIZE

	/*
	 * BUG:  I presume that p != u.u_procp,
	 * or there could be a serious problem!
	 */
	setContextReg(p,0);
	setsysmap(usrbase + (v & (PPS-1)), pte, 1);
	setContextReg(p,V_ACCSM | V_ACCLOW | 0);
	*saddr = oldsme;
	setContextReg(u.u_procp,oldctxt);
#endif	SETTABLE_MMU_SIZE

	splx(s);
}
#endif 	OLDWAY		/* ...The NEW way... */
#endif USE_CTXT	/* !OLD_SUREG */

/*
 * getprocmap -- Return process map; or -1.
 *
 * Return the hardware page map for a process
 * and a virtual page number.  Return -1 if the
 * page is not in hardware.
 */
getprocmap(p, v)
   register struct proc *p;
   register unsigned v;
{
/*A4*/	A_V_CONTEXT;				/* Allocate register-var */
	register int sindex;
	register u_short *paddr;
	register u_short smap;
	register u_char oldctxt;
	u_short oldsme;
	u_short pme;
	int s;

	if ((int) p <= NULL)
		panic("getprocmap: bad proc addr");

	CTXT_INCSTAT(getprocmap);

	/*
	 * Find the index of the smap corresponding
	 * to the given virtual address.
	 */
	if (isatsv(p, v))
		sindex = vtotp(p, v) >> PTOSSHIFT;
	else if (isadsv(p, v))
		sindex = ptos(p->p_tsize) + (vtodp(p, v) >> PTOSSHIFT);
	else if (isassv(p, v))
		sindex = ptos(p->p_tsize) + ptos(p->p_dsize) +
				ptos(p->p_ssize) - ptos(vtosp(p, v) + 1);
	else if (v >= maxpage-0xF)
		sindex = ptos(p->p_tsize) + ptos(p->p_dsize) + ptos(p->p_ssize);
	else
		panic("getprocmap: bad v");

	/*
	 * If the smap is not in hardware then we
	 * return -1 here.
	 */
	if (sindex < p->p_needmap)
		return(-1);

	/*
	 * If the process has a context then we
	 * can switch to it and use getpagemap()
	 * to examine the map.
	 */
	if (p->p_ctxt)
	{
		s = spl7();

#ifndef	SETTABLE_MMU_SIZE
		oldctxt = R_V_CONTEXT;
		R_V_CONTEXT = p->p_ctxt->number;
		pme = getpagemap(v);			/* Can return (-1) */
		R_V_CONTEXT = oldctxt;
#else	SETTABLE_MMU_SIZE

		/*
		 * BUG:  I presume that p != u.u_procp,
		 * or there could be a serious problem!
		 */
		getContextReg(u.u_procp,oldctxt);
		setContextReg(p,p->p_ctxt->number);
		pme = getpagemap(v);			/* Can return (-1) */
		setContextReg(u.u_procp,oldctxt);
#endif	SETTABLE_MMU_SIZE

		splx(s);

		return(pme);				/* Can return (-1) */
	}

	/*
	 * Must do it the hard way: scan the list
	 * of segment maps for the process until
	 * we come to the one (indexed by sindex)
	 * corresponding to the virtual page we
	 * are looking at.  Note that there are
	 * p_needmap smaps missing from the FRONT
	 * of the list.
	 */

	s = spl7();

	sindex -= p->p_needmap;
	smap = p->p_smaps;
	while (sindex--)
		smap = smaps[smap];

	/*
	 * Force the given segment map into a
	 * known location (saving the old one),
	 * get the page map, and restore the
	 * segment map.
	 */
	paddr = (u_short *)((USRTEXT + ((v & (PPS-1)) << PGSHIFT))|V_SEGMAP);
#ifndef	SETTABLE_MMU_SIZE
	oldctxt = R_V_CONTEXT;
	R_V_CONTEXT = V_ACCSM | V_ACCLOW | 0;
	oldsme = *paddr;
	*paddr = smap | SEG_ASYS;

	R_V_CONTEXT = V_ACCPM | V_ACCLOW | 0;
	pme = *paddr;

	R_V_CONTEXT = V_ACCSM | V_ACCLOW | 0;
	*paddr = oldsme;
	R_V_CONTEXT = oldctxt;
#else	SETTABLE_MMU_SIZE

	/*
	 * Save the segment map entry for the CURRENT process,
	 * to allow retrieval of the smap for process 'p'.
	 */
	getContextReg(u.u_procp,oldctxt);

	/*
	 * Get the page map entry for process 'p',
	 * by forcing to a known location for pickup.
	 */
	setContextReg(p,V_ACCSM | V_ACCLOW | 0);
	oldsme = *paddr;
	*paddr = smap | SEG_ASYS;

	/*
	 * Get the page map entry for process 'p'.
	 */
	setContextReg(p,V_ACCPM | V_ACCLOW | 0);
	pme = *paddr;

	/*
	 * Restore old segment map for process 'p'.
	 */
	setContextReg(p,V_ACCSM | V_ACCLOW | 0);
	*paddr = oldsme;

	/*
	 * Restore old context for the current process.
	 */
	setContextReg(u.u_procp,oldctxt);
#endif	SETTABLE_MMU_SIZE

	splx(s);

	return(pme);
}

/*
 * addAtTail -- Add an entry at the tail of the chain;
 *
 * Algorithm:
 *	1) Point old TAIL-entry at the new-TAIL entry;
 *	2) Terminate the new-TAIL's forward-chain;
 *	3) Update the TAIL-ptr;
 *
 * Presumption:
 *	1) The (prior) element's LRU (bwdptr) selector == NOSMAP;
 */
#ifdef	BIDIRECTIONAL_LRU
addAtTail(new)	/* Add entry to tail of list */	
register smap_t	new;
{
	if (TAIL==DUMMYSMAP || HEAD==DUMMYSMAP)
		cdebugger("addAtTail: HEAD or TAIL is DUMMYSMAP");
	if (TAIL==NOSMAP || HEAD==NOSMAP) {
		TAIL = HEAD = (new);  /* List with one entry */
		U_sMaps[  new  ].s_bwdIndx = NOSMAP;
		U_sMaps[  new  ].s_fwdIndx =(NOSMAP | I_);
		u.u_vSmapsInUse = 1;
	} else {
		U_sMaps[  TAIL ].s_fwdIndx =((new)  | I_);
	      if ((new)== TAIL) {
		U_sMaps[  new  ].s_bwdIndx = NOSMAP;
	      } else {
		U_sMaps[  new  ].s_bwdIndx = TAIL;
	      }	
		U_sMaps[  new  ].s_fwdIndx =(NOSMAP | I_);
			  TAIL    	   = (new);
		if (++u.u_vSmapsInUse > maxVSmaps(u.u_procp))
		      u.u_vSmapsInUse = maxVSmaps(u.u_procp);
	}
}
#else	!BIDIRECTIONAL_LRU
/*
	if (TAIL==DUMMYSMAP || HEAD==DUMMYSMAP)			\
		cdebugger("addAtTail: HEAD or TAIL is DUMMYSMAP");\
*/
addAtTail(new)	/* Add entry to tail of list */	
register smap_t	new;
{
	if (TAIL==NOSMAP || HEAD==NOSMAP) {
		TAIL = HEAD = (new);  /* List with one entry */
		U_sMaps[  new  ].s_fwdIndx = (NOSMAP | I_);
		u.u_vSmapsInUse = 1;
	} else {
		U_sMaps[  TAIL ].s_fwdIndx =((new)  | I_);
		U_sMaps[  new  ].s_fwdIndx =(NOSMAP | I_);
			  TAIL    	   = (new);
		if (++u.u_vSmapsInUse > maxVSmaps(u.u_procp))
		      u.u_vSmapsInUse = maxVSmaps(u.u_procp);
	}
}
#endif	!BIDIRECTIONAL_LRU

/*
 * delAtHead -- Delete from the HEAD of the chain.
 *
 * Algorithm:
 *	1) De-chain the HEAD entry;
 *	2) Clear the HEAD-selected entry;
 *	3) Point HEAD at the new head-of-chain element;
 */
#ifdef	BIDIRECTIONAL_LRU
delAtHead()	/* Delete entry from HEAD of the list */
{
	if (TAIL==DUMMYSMAP || HEAD==DUMMYSMAP)
		cdebugger("delAtHead: HEAD or TAIL is DUMMYSMAP");
	if (HEAD != NOSMAP) {
		register smap_t tmp;
		if ((tmp = U_sMaps[ HEAD ].s_fwdIndx & M_) != NOSMAP) {
			   U_sMaps[ tmp  ].s_bwdIndx	= NOSMAP;
			   U_sMaps[ HEAD ].s_bwdFwd	= NOSMAP;/*BOTH*/
				    HEAD		= tmp;
		} else {
			   U_sMaps[ HEAD ].s_bwdFwd	= NOSMAP;/*BOTH*/
				    HEAD = TAIL		= NOSMAP;
		}
		if (--u.u_vSmapsInUse < 0)
		      u.u_vSmapsInUse = 0;
	} else {
	    if (TAIL != NOSMAP)
		cdebugger("delAtHead/E: HEAD==NOSMAP; but TAIL nonzero");
	} 
}
#else	BIDIRECTIONAL_LRU
/*
	if (TAIL==DUMMYSMAP || HEAD==DUMMYSMAP)			\
		cdebugger("delAtHead: HEAD or TAIL is DUMMYSMAP");\
*/

delAtHead()	/* Delete entry from HEAD of the list */
{
	if (HEAD != NOSMAP) {
		register smap_t tmp = U_sMaps[ HEAD ].s_fwdIndx & M_;

		U_sMaps[ HEAD ].s_fwdIndx	= NOSMAP;/*BOTH*/
		HEAD				= tmp;
		if (tmp == NOSMAP) {	
		    TAIL			= tmp;
		}
		if (--u.u_vSmapsInUse < 0)
		      u.u_vSmapsInUse = 0;
	} else {
	    if (TAIL != NOSMAP)
		cdebugger("delAtHead/E: HEAD==NOSMAP; but TAIL nonzero");
	} 
}
#endif	BIDIRECTIONAL_LRU
