static char rcsid[] = "$Header: map.c,v 820.1 86/12/04 19:53:37 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.				*
*									*
************************************************************************/

/*
 * History:
 * ========
 * 860317 jht -- Add code to define and subsequently use register for V_CONTEXT.
 * 860321 jht -- Board-up/document holes regarding getpagemap() returning -1;
 * 860405 jht -- Augment mmu subsystem with MMU_BINGO debugging facility..
 * 860425 elp -- Rewrote sureg to conform to new LRU scheme
 * 860519 jht -- Augment mmu subsystem with CMD_BINGO debugging facility..
 */

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

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

#include "../machine/context.h"

extern	short	nContexts;	/* C.f., ../s32/context.c */

#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

/*
 * Write a set of kernel page table entries
 * into the hardware map.  This replaces the
 * Vax   mtpr TBIA,0  insruction and can be
 * used to just invalidate a select group
 * of page maps.
 */
/*
 * NOTE: setsysmap() only affects the page map
 * for the CURRENT context.
 * Therefore no additional CONTEXT or STATUS register
 * processing is necessary.
 */
u_short
setsysmap(page, pte, count)
	int			page;
/*A5*/	register struct pte   *	pte;
/*D7*/	register int		count;
{
/*A4*/	A_V_CONTEXT;				/* Allocate register-var */
/*D6*/	register u_short	entry    = pte->pg_pfnum;
/*A3*/	register u_char	      *	byteaddr = (u_char *)ptob(page);
/*D5*/	register u_char		oldctxt;
/*D4*/	register u_char		newctxt;
/*  */	int			lowleft;
/*  */	int			s;
/*  */	u_short			previous;	/* Prior page table entry */
	extern			_end;
#ifdef KERN_RESTART
	extern	int		kernrestarting;
#endif KERN_RESTART
	struct	pte		upage_pte[UPAGES];
#ifdef	DEBUG
	u_long			saspage;
	u_long			sasp0br;
#endif	DEBUG
	

#ifdef	DEBUG
	/*
	 * If suregp0br is set and we are mapping user space,
	 * enter the debugger if we are using the current process's
	 * pte pages as fodder.
	 * sas 860315  --  debug code
	 * jht 860909  --  Ammended to constrain to pg_v pte's.
	 */
	if (pte->pg_v && suregp0br && page < usrtop(u.u_procp) && page> usrbase)
	{
		saspage = (*(int *)pte & V_PAGEMASK) << PGSHIFT;
		sasp0br = *(int *)((u_long)Usrptmap + 
				(((u_long)suregp0br - (u_long)usrpt)>>10));

		sasp0br = (sasp0br&V_PAGEMASK) << PGSHIFT;
		if (saspage == sasp0br)
			cdebugger("setsysmap: sasp0br");
	}
#endif	DEBUG

#ifdef KERN_RESTART
	if (!kernrestarting)
#endif KERN_RESTART
	if ( page == 0			/* Don't remap the 'rupt vectors! */
	  || page+count-1 > maxpage	/* Out of range... */
#if 0
	 /*
	  * NOTE:  We now set the pagemaps of BOTH
	  * kernel and non-kernel TEXT+DATA+BSS areas.
	  * C.f., initCache() for the former.
	  */
	 || !(K_A <= (long)byteaddr && (long)byteaddr < (long)&_end)
#endif 0
	   )
	{
		printf("setsysmap: page=0x%x entry=0x%x maxpage=0x%x\n",
				   page,     entry,	maxpage);
		panic("setsysmap");
	}

	if (count == UPAGES
	 && ((u_long)pte & pagemask) == ((NPTEPG-UPAGES) * sizeof *pte))
	{
		struct pte upage_pte[UPAGES];

		bcopy (pte, upage_pte, UPAGES * sizeof *pte);
		pte = upage_pte;
	}

	lowleft = btop(V_PAGEMAP) - page;

#ifdef	MMU_BINGO
	if (mmu_BINGO && (page == (mmu_BINGO_addr >> pageshift))) cdebugger("mmu_BINGO: setsysmap");
#endif	MMU_BINGO
	s = spl7();

	oldctxt = R_V_CONTEXT;
#ifdef	M68020_REV_B
	newctxt = (oldctxt  & ~V_MAP_CONTROL) | V_ACCPM |
		(((u_long)byteaddr & V_PAGEMAP) ? V_ACCHIGH : V_ACCLOW);
#else	M68020_REV_B
	if (lowleft > 0)
		newctxt = (oldctxt & ~V_MAP_CONTROL) | V_ACCPM | V_ACCLOW;
	else
		newctxt = (oldctxt & ~V_MAP_CONTROL) | V_ACCPM | V_ACCHIGH;
#endif	M68020_REV_B
#ifdef WHITE
	if (usrbase <= page && page < usrtop || maxpage-HIGHPAGES < page)
		newctxt |= V_ACCUSER;
#endif WHITE

	/*
	 * Once for each page requested.
	 */
	while (count--)
	{
		R_V_CONTEXT = (oldctxt & ~V_MAP_CONTROL) | V_ACCSM |
			(((u_long)byteaddr&V_PAGEMAP) ? V_ACCHIGH : V_ACCLOW);	
		/*
		 * If the is no read, write or execute access to the segment
		 * which contains the page then the segment is not really there
		 * and we really shouldn't screw up some other processes h/w
		 * map, or we think that the 68020 double bus faults in this
		 * event.
		 *
		 * ELP & JHT et. al. 4/11/86
		 */
		if (((*(u_short *)((u_long)byteaddr | V_PAGEMAP)) & V_SKERNEL) == 0) {
			R_V_CONTEXT = oldctxt;
			continue;
		}
		if (((*(u_short *)((u_long)byteaddr|V_PAGEMAP))&SEG_PAGE) == DUMMYSMAP)
			cdebugger ("Someone flipped my bits");
		DODEBUG (D_PMEM, ("[SSM:P0x%x:S0x%x:", btop(byteaddr),
			*((u_short *)((u_long)byteaddr|V_PAGEMAP))));
		R_V_CONTEXT = oldctxt;
			
#ifdef	M68020_REV_B
		newctxt = (oldctxt  & ~V_MAP_CONTROL) | V_ACCPM |
			(((u_long)byteaddr & V_PAGEMAP) ? V_ACCHIGH : V_ACCLOW);
#else	M68020_REV_B
		if (lowleft-- == 0)
			newctxt = (oldctxt & ~V_MAP_CONTROL) | V_ACCPM | V_ACCHIGH;
#endif	M68020_REV_B
		/*
		 * The ORDER of the "walking" (bit checking)
		 * of the pte-s fine-structure HEIRARCHY
		 * is VERY important:
		 *
		 *	1) pg_v is common to ALL pte-s	-- check FIRST;
		 *	2) pg_fod is fill-on-demand "variant record selector";
		 *	3) pg_m is the NOT-fod variation	-- check LAST;
		 */
		if (pte->pg_v)
			entry = pte->pg_pfnum;

		/*
		 * See if we have the FOD branch of the tree...
		 */
		else if (pte->pg_fod && ((struct fpte *)pte)->pg_fileno == PG_FPHYS) {
			entry = ((struct fpte *)pte)->pg_blkno;
#if	!defined(WHITE) && defined(M68020)
			if (chipType==CHIPTYPE_68020)
				/*
				 * BUG: There's a potential for inconsistency
				 * here if we have been silly enough to also
				 * have specified V_MBIO in the pg_blkno field.
				 */
				if (((struct fpte *)pte)->pg_noncached)
					entry |= V_NONCACHED;
#endif	!defined(WHITE) && defined(M68020)
		/*
		 * ...neither explicitly valid or FOD -- show as invalid.
		 */
		} else
			entry = V_PAGE_INVALID;
#ifdef CTXT_MODIFY
		/*
		 * (The pg_m bit-slot also ocurrs
		 * in the FOD branch as pg_noncached.
		 * This is not a problem.)
		 */
		if (pte->pg_m)
			entry |= V_DIRTY;
#endif CTXT_MODIFY
		R_V_CONTEXT = newctxt;
		previous = *(u_short *)((u_long)byteaddr|V_PAGEMAP);
		*(u_short *)((u_long)byteaddr|V_PAGEMAP) = entry;
		DODEBUG (D_PMEM, ("F0x%x:T0x%x]", previous, entry));
#ifdef WHITE
		if (newctxt & V_ACCUSER)
		{
			R_V_CONTEXT &= ~V_ACCUSER;
			*(u_short *)((u_long)byteaddr|V_PAGEMAP) = entry;
		}
#endif WHITE
		R_V_CONTEXT = oldctxt;
		++pte;
		byteaddr = (u_char *) ((u_long)byteaddr + (u_long)ptob(1));
	}

	splx(s);

	return previous;	/* For debugging... */
}

/*
 * Write a page table entry directly into
 * the map.  The entry looks like the hardware
 * unlike setsysmap above.
 *
 * setpagemap() only affects the page map
 * for the CURRENT context.
 * Therefore no processing is necessary.
 */
u_short
setpagemap(page, entry)
   int page;
   u_short entry;
{
	register u_long byteaddr = (u_long)ptob(page);
	register u_short *pageaddr = (u_short *)(byteaddr | V_PAGEMAP);
/*A4*/	A_V_CONTEXT;				/* Allocate register-var */
	register u_short previous;
	register u_char oldctxt;
	register int s;
	extern _end;
#ifdef KERN_RESTART
	extern int kernrestarting;
#endif KERN_RESTART

#ifdef KERN_RESTART
	if (!kernrestarting)
#endif KERN_RESTART
	if (page == 0				/* 'rupt vectors */
	 || page > maxpage			/* Out of bounds */
#if 0
	 /*
	  * NOTE:  We now set the pagemaps of BOTH
	  * kernel and non-kernel TEXT+DATA+BSS areas.
	  * C.f., initCache() for the former.
	  */
	 || !(K_A <= (long)byteaddr && (long)byteaddr < (long)&_end)
#endif 0
	   )
	{
		printf("setpagemap/E-1: page=0x%x entry=0x%x maxpage=0x%X\n",
			page, entry, maxpage);
		panic("setpagemap");
	}

	s = spl7();

#ifdef	MMU_BINGO
	if (mmu_BINGO && (page == (mmu_BINGO_addr >> pageshift))) cdebugger("mmu_BINGO: setpagemap");
#endif	MMU_BINGO
	oldctxt = R_V_CONTEXT;
#ifdef	M68020_REV_B
	R_V_CONTEXT = (oldctxt  & ~V_MAP_CONTROL) | V_ACCSM |
		((byteaddr & V_PAGEMAP) ? V_ACCHIGH : V_ACCLOW);
	if ((*pageaddr & V_SKERNEL) == 0)	/* No access to segment */
		panic ("setpagemap: Invalid segment");
	DODEBUG (D_PMEM, ("[SPM:P0x%x:S0x%x:", btop(byteaddr), *pageaddr));
	R_V_CONTEXT = (oldctxt  & ~V_MAP_CONTROL) | V_ACCPM |
		((byteaddr & V_PAGEMAP) ? V_ACCHIGH : V_ACCLOW);
	DODEBUG (D_PMEM, ("F0x%x:t0x%x]",*pageaddr,entry));
#else	M68020_REV_B
	oldctxt = V_CONTEXT;
	if (page < btop(V_PAGEMAP))
		R_V_CONTEXT = (oldctxt & ~V_MAP_CONTROL) | V_ACCPM | V_ACCLOW;
	else
		R_V_CONTEXT = (oldctxt & ~V_MAP_CONTROL) | V_ACCPM | V_ACCHIGH;
#endif	M68020_REV_B
	previous = *pageaddr;
	*pageaddr = entry;
#ifdef WHITE
	if (usrbase <= page && page < usrtop || maxpage-HIGHPAGES < page)
	{
		R_V_CONTEXT |= V_ACCUSER;
		*pageaddr = entry;
	}
#endif WHITE
	R_V_CONTEXT = oldctxt;

	splx(s);

	return previous;
}

/*
 * getpagemap() only queries (and returns)
 * from the current context.
 * Therefore no changes are required.
 */
 u_short
getpagemap( pageno )
	u_short	pageno;
{
/*A5*/	A_V_CONTEXT;				/* Allocate register-var */
	register u_short entry;
	register u_char  oldctxt;
	register	 s;
	register u_long byteaddr = (u_long)ptob(pageno);


	if( pageno > maxpage ) {
		printf("getpagemap/E-0: page=%x > maxpage=0x%x\n",
			pageno, maxpage);
#if 1
		/*
		 * Prevent runaway...
		 */
		cdebugger("getpagemap/E-0: bad page\n");
#endif 1
		return (pageno);
	}

	s = spl7();

	oldctxt = R_V_CONTEXT;		/* save old context */
#ifdef	M68020_REV_B
	R_V_CONTEXT = (oldctxt  & ~V_MAP_CONTROL) | V_ACCSM |
		((pageno & btop(V_PAGEMAP)) ? V_ACCHIGH : V_ACCLOW);
	 /* No access to segment */
	 if ((*((u_short *)((pageno<<pageshift)|V_PAGEMAP)) & V_SKERNEL) == 0) {
		register struct pte *pte;
		
		R_V_CONTEXT = oldctxt;		/* restore old context */
		if (isatsv(u.u_procp, pageno) || isadsv(u.u_procp, pageno))
			pte = (struct pte *)&suregp0br[pageno-LOWPAGES];
		else if ((byteaddr & ~segmask) == ((nSegs - 1) << segshift))
			pte = (struct pte *)
			    &suregp0br[(u.u_procp->p_szpt*NPTEPG)-PPS];
		else	/* Stack */
			pte = (struct pte *)&suregp1br[pageno];
		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;
		splx( s );
		return entry;
	}
		
	R_V_CONTEXT = (oldctxt  & ~V_MAP_CONTROL) | V_ACCPM |
		((pageno & btop(V_PAGEMAP)) ? V_ACCHIGH : V_ACCLOW);
#else	M68020_REV_B
	if (pageno < btop(V_PAGEMAP))
		R_V_CONTEXT = (oldctxt & ~V_MAP_CONTROL) | V_ACCPM | V_ACCLOW;
	else
		R_V_CONTEXT = (oldctxt & ~V_MAP_CONTROL) | V_ACCPM | V_ACCHIGH;
#endif	M68020_REV_B
#ifdef WHITE
	if (usrbase <= pageno && pageno < usrtop || maxpage-HIGHPAGES < pageno)
		R_V_CONTEXT |= V_ACCUSER;
#endif WHITE

	entry = *(u_short *)((pageno << pageshift) | V_PAGEMAP);

	R_V_CONTEXT = oldctxt;		/* restore old context */

	splx( s );
	return entry;
}

/*
 * getsegmap() only queries (and returns)
 * from the current context.
 * Therefore no V_CONTEXT-changes are required.
 */
 u_short
getsegmap(ctxt, va)
	register int	ctxt;	/* Context #	   */
	register u_long	va;	/* Virtual address */
{
/*A5*/	A_V_CONTEXT;				/* Allocate register-var */
	register u_short entry;
	register u_short oldctxt;
	register int	 s;

	if (va >> segshift >= nsegs(u.u_procp))
	{
		printf("getsegmap: virtual address 0x%x\n", va);
		panic("getsegmap");
	}

	s = spl7();

	/*
	 * BUG: Note that if ctxt==ALLCTXT,
	 * then the value from (only) context 15
	 * is returned, which is misleading!
	 */
	oldctxt = R_V_CONTEXT;
	if (ctxt == MYCTXT)
		ctxt = oldctxt & ~V_MAP_CONTROL;
#ifdef	M68020_REV_B
	R_V_CONTEXT = ctxt | V_ACCSM | ((va & V_SEGMAP) ? V_ACCHIGH : V_ACCLOW);
#else	M68020_REV_B
	if (va < (u_long)V_SEGMAP)
		R_V_CONTEXT = ctxt | V_ACCSM | V_ACCLOW;
	else
		R_V_CONTEXT = ctxt | V_ACCSM | V_ACCHIGH;
#endif	M68020_REV_B
#ifdef WHITE
	if ((u_long)USRTEXT <= va && va < (u_long)usrstack ||
	    (u_long)ptob(maxpage+1-HIGHPAGES) <= va)
		R_V_CONTEXT |= V_ACCUSER;
#endif WHITE
	entry = *(u_short *)((va & ~1) | V_SEGMAP);
	R_V_CONTEXT = oldctxt;

	splx( s );

#ifdef SEGDEBUG
	if (debug & D_VMEM)
		printf("getsegmap: se %x\n",
			entry);
#endif

	return( entry & (SEG_PAGE | SEG_ACCMODE));	/* flush context */
}

/* this procedure sets a particular (or ALL)
   context's segment map entry for "va" (a virtual address)
   to "entry".
*/

 u_short
setsegmap(ctxt, va, entry)
/*D6*/	register int	 ctxt;		/* Context #		*/
/*D5*/	register u_long	 va;		/* Virtual address	*/
/*D4*/	register u_short entry;		/* Segment map entry	*/
{
/*A5*/	A_V_CONTEXT;				/* Allocate register-var */
/*A4*/	register u_short * saddr = (u_short *)((va & ~1) | V_SEGMAP);
/*D3*/	register u_short   oldctxt;
/*  */		 u_short   previous;
/*  */	register int	   s;


	if ((va >> segshift) >= nsegs(u.u_procp))
	{
		printf("setsegmap: address 0x%x, entry 0x%x\n", va, entry);
		panic("setsegmap");
	}

	if ((entry & SEG_PAGE) == DUMMYSMAP && (entry & V_SKERNEL))
		cdebugger ("About to commit a stupidity");
	if ((va >> segshift) == (nsegs(u.u_procp) - 2))
		cdebugger ("Am I doing something wrong?");
#ifdef	MMU_BINGO
	if (mmu_BINGO && ((va>>segshift) == (mmu_BINGO_addr>>segshift))) cdebugger("mmu_BINGO: setsegmap");
#endif	MMU_BINGO
	s = spl7();

	/*
	 * Preserve the current context state.
	 * Note that we don't SWITCH contexts,
	 * except for the ALLCTXT clause several
	 * lines below here.
	 */
	getContextReg(u.u_procp,oldctxt);
	if (ctxt == ALLCTXT)
	{
		register u_short newctxt;

#ifdef	M68020_REV_B
		newctxt = V_ACCSM | ((va & V_SEGMAP) ? V_ACCHIGH : V_ACCLOW);
#else	M68020_REV_B
		if (va < (u_long)V_SEGMAP)
			newctxt = V_ACCSM | V_ACCLOW;
		else
			newctxt = V_ACCSM | V_ACCHIGH;
#endif	M68020_REV_B
		/*
		 * BUG: This may break for entries
		 * in a context larger than the nominal 16Mb.
		 * The notion of "top" is different
		 * for the various address space sizes.
		 * BUG: A context may be in the "shadow"
		 * of a larger, subsuming context.
		 */
		for (ctxt=0; ctxt < NCONTEXTS; ++ctxt)
		{
			R_V_CONTEXT = ctxt | newctxt;
			*saddr = entry;
		}
#ifdef WHITE
		if ((u_long)USRTEXT <= va && va < (u_long)usrstack ||
		    (u_long)ptob(maxpage+1-HIGHPAGES) <= va)
		{
			newctxt |= V_ACCUSER;
			for (ctxt=0; ctxt < NCONTEXTS; ++ctxt)
			{
				R_V_CONTEXT = ctxt | newctxt;
				*saddr = entry;
			}
		}
#endif WHITE
		previous = 0;	/* For want of something better */
	}
	else
	{
		if (ctxt == MYCTXT)
			ctxt = oldctxt & ~V_MAP_CONTROL;
#ifdef	M68020_REV_B
		R_V_CONTEXT = ctxt | V_ACCSM | ((va&V_SEGMAP)?V_ACCHIGH:V_ACCLOW);
#else	M68020_REV_B
		if (va < (u_long)V_SEGMAP)
			R_V_CONTEXT = ctxt | V_ACCSM | V_ACCLOW;
		else
			R_V_CONTEXT = ctxt | V_ACCSM | V_ACCHIGH;
#endif	M68020_REV_B
#ifdef WHITE
		if ((u_long)USRTEXT <= va && va < (u_long)usrstack ||
		    (u_long)ptob(maxpage+1-HIGHPAGES) <= va)
			R_V_CONTEXT |= V_ACCUSER;
#endif WHITE
		previous = *saddr;
		*saddr = entry;
#ifdef WHITE
		if (R_V_CONTEXT & V_ACCUSER)
		{
			R_V_CONTEXT &= ~V_ACCUSER;
			*saddr = entry;
		}
#endif WHITE
	}
	/*
	 * Restore and preserve the prior context
	 */
	setContextReg(u.u_procp,oldctxt);
	splx( s );
	return (previous & (SEG_PAGE | SEG_ACCMODE));	/* flush context */
}
/*
 * getSegMap() only queries (and returns)
 * from the current context.
 *
 * NOTE: No u-page or proc references are made herein.
 * Therefore no changes are required vis-a-vis
 * the CONTEXT or STATUS registers,
 * both of which are involved in the "larger" mmu.
 *
 * BUG: However, getSegMap() will break
 * for inhomogeneous process virtual address space sizes,
 * since 'nSegs' ==> 'normalMmuIndx'
 */
u_short
getSegMap(ctxt, vaddr, nSegs)
	register int	ctxt;
	register u_long	vaddr;
	register	nSegs;		/* Size of the segment map */
{
/*A5*/	A_V_CONTEXT;				/* Allocate register-var */
	register u_short entry;
	register u_short oldctxt;
	register int	 s;

	if (vaddr >> segshift >= nSegs)
	{
		printf("getSegMap: virtual address 0x%x\n", vaddr);
		panic("getSegMap");
	}
	s = spl7();
	/*
	 * BUG: Note that if ctxt==ALLCTXT,
	 * then the value from (only) context 15
	 * is returned, which is misleading!
	 */
	oldctxt = R_V_CONTEXT;
	if (ctxt == MYCTXT)
		ctxt = oldctxt & ~V_MAP_CONTROL;
#ifdef	M68020_REV_B
	R_V_CONTEXT = ctxt | V_ACCSM | ((vaddr & V_SEGMAP) ? V_ACCHIGH:V_ACCLOW);
#else	M68020_REV_B
	if (vaddr < (u_long)V_SEGMAP)
		R_V_CONTEXT = ctxt | V_ACCSM | V_ACCLOW;
	else
		R_V_CONTEXT = ctxt | V_ACCSM | V_ACCHIGH;
#endif	M68020_REV_B
#ifdef WHITE
	if ((u_long)USRTEXT <= vaddr && vaddr < (u_long)usrstack ||
	    (u_long)ptob(maxpage+1-HIGHPAGES) <= vaddr)
		R_V_CONTEXT |= V_ACCUSER;
#endif WHITE
	entry = *(u_short *)((vaddr & ~1) | V_SEGMAP);
	R_V_CONTEXT = oldctxt;
	splx( s );

	return( entry & (SEG_PAGE | SEG_ACCMODE));	/* flush context */
}

/*
 * setSegMap() sets a particular (or ALL)
 * context's segment map entry
 * for "vaddr" (a virtual address) to "entry".
 */
u_short
setSegMap(ctxt, vaddr, entry, nSegs)
/*D6*/	register int	 ctxt;
/*D5*/	register u_long	 vaddr;
/*D4*/	register u_short entry;
/*D3*/	register	 nSegs;		/* Size of the segment map	*/
{
/*A5*/	A_V_CONTEXT;				/* Allocate register-var */
/*A4*/	register u_short *saddr = (u_short *)((vaddr & ~1) | V_SEGMAP);
/*  */		 u_short oldctxt;
/*  */		 u_short previous;
/*  */		 int	 s;

	if ((vaddr >> segshift) >= nSegs)
	{
		printf("setSegMap: address 0x%x, entry 0x%x\n", vaddr, entry);
		panic("setSegMap");	/* BUG: specious panic()??? */
	}
#ifdef	MMU_BINGO
	if (mmu_BINGO && ((vaddr>>segshift) == (mmu_BINGO_addr>>segshift))) cdebugger("mmu_BINGO: setSegMap");
#endif	MMU_BINGO
	s = spl7();
	oldctxt = R_V_CONTEXT;
	if (ctxt == ALLCTXT)
	{
		register u_short newctxt;

#ifdef	M68020_REV_B
		newctxt = V_ACCSM | ((vaddr & V_SEGMAP) ? V_ACCHIGH : V_ACCLOW);
#else	M68020_REV_B
		if (vaddr < (u_long)V_SEGMAP)
			newctxt = V_ACCSM | V_ACCLOW;
		else
			newctxt = V_ACCSM | V_ACCHIGH;
#endif	M68020_REV_B
		/*
		 * BUG: This may break for entries
		 * in a context larger than the nominal 16Mb.
		 * The notion of "top" is different
		 * for the various address space sizes.
		 * BUG: A context may be in the "shadow"
		 * of a larger, subsuming context.
		 */
		for (ctxt=0; ctxt < NCONTEXTS; ++ctxt)
		{
			R_V_CONTEXT = ctxt | newctxt;
			*saddr = entry;
		}
#ifdef WHITE
		if ((u_long)USRTEXT <= vaddr && vaddr < (u_long)usrstack ||
		    (u_long)ptob(maxpage+1-HIGHPAGES) <= vaddr)
		{
			newctxt |= V_ACCUSER;
			for (ctxt=0; ctxt < NCONTEXTS; ++ctxt)
			{
				R_V_CONTEXT = ctxt | newctxt;
				*saddr = entry;
			}
		}
#endif WHITE
		previous = 0;	/* For want of something better */
	}
	else
	{
		if (ctxt == MYCTXT)
			ctxt = oldctxt & ~V_MAP_CONTROL;
#ifdef	M68020_REV_B
		R_V_CONTEXT = ctxt |V_ACCSM|((vaddr&V_SEGMAP)?V_ACCHIGH:V_ACCLOW);
#else	M68020_REV_B
		if (vaddr < (u_long)V_SEGMAP)
			R_V_CONTEXT = ctxt | V_ACCSM | V_ACCLOW;
		else
			R_V_CONTEXT = ctxt | V_ACCSM | V_ACCHIGH;
#endif	M68020_REV_B
#ifdef WHITE
		if ((u_long)USRTEXT <= vaddr && vaddr < (u_long)usrstack ||
		    (u_long)ptob(maxpage+1-HIGHPAGES) <= vaddr)
			R_V_CONTEXT |= V_ACCUSER;
#endif WHITE
		previous = *saddr;
		*saddr = entry;
#ifdef WHITE
		if (R_V_CONTEXT & V_ACCUSER)
		{
			R_V_CONTEXT &= ~V_ACCUSER;
			*saddr = entry;
		}
#endif WHITE
	}
	R_V_CONTEXT = oldctxt;
	splx( s );
	return (previous & (SEG_PAGE | SEG_ACCMODE));	/* flush context */
}

#ifndef	USE_CTXT	/* OLD_SUREG */

int	gapstart = HALFSEGS;	/* First segment of gap from last context */
int	gapend = HALFSEGS;	/* First non-gap segment from last context */
int	gap;
#ifdef DEBUG
char	checkgap = 0;		/* Check that the REMEMBER_GAP code worked */
int	segsdone = 0;		/* Number of segments mapped by sureg */
int	gapsaved = 0;		/* Number of re-maps which were saved */
#endif 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_head;		/* Head of segment map list */
smap_t	smap;			/* Index into smaps[]		 */
int	nSmaps	= NSMAPS;	/* # segment maps for (16Mb) proc[0] */
int	maxPsmapsAvail;
int	segsMappedSoFar;
int	pagesMappedSoFar;
int	unMappedPages;

/*
 * This bitmap is used by sureg to create a list of segments to map
 *
 * This may be too slow, using a character array instead - ELP 10/06/86
 */
#ifdef	SMAP_BITMAP
u_char	smap_bitmap [btos (V_MAXVA) / NBBY];
#else	SMAP_BITMAP
u_char	smap_charmap[btos (V_MAXVA)];
#endif	SMAP_BITMAP

/*
 *	smap_init() -- Segment initialization
 *
 * Initialize the segment map resources.
 * Called from startup().
 *
 * NOTE:  1) None of the process slots
 *	     or upages are initialized yet.
 *	  2) Neither is process #0 extant.
 *
 */
smap_init()
{
	register smap_t smap;
	register struct proc *p;

	/* 
	 * 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.
	 */
	maxPsmapsAvail = 1;	/* Include last smap in count */
	smap_free = smap_head	= 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;
	maxPsmapsAvail ++;
	/*
	 * 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) {
		maxPsmapsAvail ++;
		smaps[smap] = smap + 1;
	}
	while (--smap)
		smaps[smap] = NOSMAP;

}

/*
 * mapSegs  --	Only map up to the theoretical limit
 *		of the # of segments that the PHYSICAL memory will support.
 *
 * CONVENTIONS:
 * ===========
 *	1) '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.
 *
 *	2) 'count' is the # of segment to be so mapped;
 *
 *	3) 'new?ctxt' is the baseline context value:  ctxt# + V_ACC?M;
 */
mapSegs (oldSaddr, pte, prot, count)
/*A4*/	register struct pte	*pte;
/*D7*/	register u_long 	oldSaddr;
/*D6*/	register smap_t		prot;
/*D5*/	register int		count;
{
/*A3*/	register u_short	*saddr;
#ifdef	SMAP_BITMAP
/*A2*/	register u_char		*bitmap = &smap_bitmap[btos(oldSaddr)/NBBY];
#else	SMAP_BITMAP
/*A2*/	register u_char		*charmap = &smap_charmap[btos(oldSaddr)];
#endif	SMAP_BITMAP
/*D4*/	register u_char		newsctxt,
/*D3*/				newpctxt;
/*D2*/	register int		pagesToMap;
/*  */		 u_char		oldctxt;
/*  */		 u_long		olda23;
#ifdef	SMAP_BITMAP
/*  */		 u_short	smap_mask = 1 << (btos(oldSaddr)%NBBY);
#endif	SMAP_BITMAP
/*  */		 u_short	entry;
/*  */           int		ps = pagesize / sizeof(u_short);
/*  */	         int		ss = segsize / sizeof(u_short);

   DODEBUG (D_CTXT,(" (cnt=%d) oldSaddr=0x%x", count, oldSaddr));
   olda23  = 0; 
   oldctxt = V_CONTEXT & ~V_MAP_CONTROL;
   newsctxt = oldctxt | V_ACCSM | V_ACCLOW; 
   newpctxt = oldctxt | 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 = oldctxt | 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)
	 */
#ifdef	SMAP_BITMAP
	if (*bitmap & smap_mask) {
#else	SMAP_BITMAP
	if (*charmap) {
#endif	SMAP_BITMAP
#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  */
		if (!smap)
			panic ("sureg: out of smaps");
		DODEBUG (D_CTXT,(" %x", smap));
		*saddr = smap | (prot);
#ifdef	WHITE
		V_CONTEXT ^= V_ACCUSER;
		*saddr = smap | (prot);
#endif	WHITE
		smap_free = smaps[smap];
		smap = smap_free;
		V_CONTEXT = oldctxt;	/* 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 = oldctxt;
			saddr += ps;
			oldSaddr += pagesize;
		}
	} else {
		V_CONTEXT = newsctxt;/* Access h/w segment map  */
		*saddr = DUMMYSMAP;	/* GAP IT!!! */
		V_CONTEXT = oldctxt;	/* Revert: paranoid  */
		saddr += ss;		/* Advance to next segment */
		oldSaddr += segsize;
		pte += PPS;		/* Increment the pte ptr */
	}
#ifdef	SMAP_BITMAP
	smap_mask <<= 1;
	if (smap_mask == (1 << NBBY)) {
		smap_mask = 1;
		bitmap ++;
	}
#else	SMAP_BITMAP
	charmap++;
#endif	SMAP_BITMAP
   }
   DODEBUG (D_CTXT,(" oldSaddr=0x%x;", oldSaddr));
}

/*
 * Set the hardware segment and page maps
 * to reflect the mapping for the current
 * process.  Use the pseudo-Vax registers
 * to find the locations of the page tables
 * to be used.
 */
sureg()
{
/*A5*/	register struct	proc  *	myproc		= u.u_procp; /* CURRENT proc */
/*A4*/	A_V_CONTEXT;				/* Allocate register-var*/
/*D7*/	register u_long		nSegsToMap = 0;
/*D6*/	register int	unMappedSegs	= COUNTSMAPS (myproc);
	int	 s = spl7();	/* MUST spl7() for suregp[01][bl]r integrity */

	if (smap_head == NOSMAP)
		smap_init ();	/* Initialize the smaps */
	else
		smap_free = smap_head;
	/*
	 * Build bitmap for process
	 *
	 * Now using a character map - ELP 10/06/86
	 */
	{
/*D5*/		register smap_t	 smapIndx;

		while (u.u_vSmapsInUse > maxPsmapsAvail) {
			delAtHead ();
		}
#ifdef	SMAP_BITMAP
		/*
		 * 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);
#else	SMAP_BITMAP
		/*
		 * Clear the charmap BEFORE using it, this prevents the
		 * code below from trying to set too many segment maps.
		 */
		bclear (smap_charmap, sizeof smap_charmap);
		for (smapIndx = HEAD; smapIndx != NOSMAP;
		     smapIndx = (U_sMaps[smapIndx].s_fwdIndx & M_),
		     nSegsToMap ++)
			smap_charmap [smapIndx] = 1;
#endif	SMAP_BITMAP
		if (nSegsToMap != u.u_vSmapsInUse)
			panic ("sureg: LRU list corrupted");
		if (nSegsToMap > maxPsmapsAvail) /* Can NEVER happen HA! HA ! */
			panic ("sureg: LRU list > avail smaps");
	}
			/************************/
			/*			*/
			/*	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;
/*  */	            int	ps = pagesize / sizeof(u_short);
/*  */	            int	ss = segsize / sizeof(u_short);
#ifndef	M68020_REV_B
	   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		= smap_free;
	   /*
	    * 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.
	    */

	   /*
	    * 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		*/
		 );
	   /*
	    * 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);
	   if (unMappedSegs < count)
		count = unMappedSegs;
	   unMappedSegs -= count;

	   setContextReg (myproc, (R_V_CONTEXT & ~V_MAP_CONTROL));


			/************************/
			/*	TEXT SEGS	*/
			/************************/

	   DODEBUG(D_CTXT,(" T:"));

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

	   if (count)
		mapSegs (oldSaddr, suregp0br, prot, count);

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

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

	   DODEBUG(D_CTXT,(" D:"));

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

	   if (count)
		mapSegs (ptob(LOWPAGES + myproc->p_tsize),
		&suregp0br [myproc->p_tsize], SEG_AURW, count);

			/************************/
			/*	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


	   /*
	    * 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:  '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		= gapstart - segnum;
		gapstart	= segnum;		/* New lwrbnd */

		DODEBUG(D_CTXT,(" gap S%x", gapstart));
		if (count > gap)
			count = gap;
		DODEBUG(D_CTXT,(" 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.
		 */
		if (count)
			mapSegs (stob(gapstart),
				&suregp0br [stoc(gapstart)-LOWPAGES], 0, count);

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

		DODEBUG(D_CTXT,(" gap E%x", gapend));
		if (count > 0)
		{
			if (count > gap)
				count = gap;
			segnum = gapend - count;
		} else {
			segnum = 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;

		DODEBUG(D_CTXT,(" M%x", count));

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

		if (count)
			mapSegs (oldSaddr, &suregp0br [btop(oldSaddr)-LOWPAGES],
				0, count);
	   }
			/************************/
			/*	STACK SEGS	*/
			/************************/

	   /*
	    * Put the stack segment maps into the
	    * hardware.
	    */
	   count = ptos(p1pages(myproc) - suregp1lr - HIGHPAGES);
	   if (unMappedSegs < count)
		count = unMappedSegs;
	   unMappedSegs -= count;
	   DODEBUG(D_CTXT,(" S:"));

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

	   oldSaddr  = (u_long) ptob(LOWPAGES + suregp0lr + (PPS - 
		((suregp0lr & SPMASK) ? (suregp0lr & SPMASK) : PPS)))
		+ (stoc(gap) * ps * sizeof(u_short));
	   if (count)
		mapSegs(oldSaddr, &suregp1br[btop(oldSaddr)], SEG_AURW, count);

			/************************/
			/*	TOPMOST SEG	*/
			/************************/
	   /*
	    * Map the top 64K of memory into this
	    * process' space.
	    */

		saddr = (u_short *)(((nsegs(myproc)-1)<<SEGSHIFT) | V_SEGMAP);
		oldSaddr = ( nsegs(myproc) - 1) << SEGSHIFT;
		count = 1;

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

		DODEBUG(D_CTXT,(" top:"));

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

		   if (count)
			mapSegs(oldSaddr, &suregp1br[btop(oldSaddr)-LOWPAGES],
				SEG_AURW, count);

	} 
asm(" .globl suregEnd");
asm("suregEnd: ");
	splx(s);
}

#endif	!USE_CTXT	/* OLD_SUREG */
