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

#define	STARTUP_DOT_C	/* Enable initialization of mmu_sizing */

/*
 * Startup and initializations.
 *
 * History
 * -------
 * 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.
 * 860405 jht -- Augment mmu subsystem with MMU_BINGO debugging facility..
 * 860519 jht -- Augment mmu subsystem with CMD_BINGO debugging facility..
 * 860602 jht -- Add 'quicken' facility: jsr lmul ==> 68020 machine code.
 * 860609 jht -- Install M68881 FPU coprocessor support.
 * 860627 jht -- Document major allocation quantities for sys administrator.
 */

#include "../machine/reg.h"
#include "../machine/pte.h"
#include "../machine/psl.h"
#include "../machine/cpu.h"
#include "../machine/mem.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/proc.h"
#include "../h/buf.h"
#include "../h/reboot.h"
#include "../h/conf.h"
#include "../h/inode.h"
#include "../h/file.h"
#include "../h/text.h"
#include "../h/clist.h"
#include "../h/callout.h"
#include "../h/cmap.h"
#include "../h/mbuf.h"
#include "../h/msgbuf.h"
#include "../h/quota.h"

#include "../s32/trap.h"
#include "../s32/debug.h"
#include "../s32/ecm.h"			/* PHYSMEMPAGES */
#ifdef	M68020
#include "../s32/clock.h"
#endif	M68020

#ifdef WHITE
#include "../white/config.h"
#include "../white/via.h"
#endif WHITE

#define	MAPONLY_PAGE	0x1000		/* Ostensively never write to it      */
short	mmuIndx;			/* Workvar: index into mmu_sizing     */
short	nContexts	= NCONTEXTS;	/* Alterable @ startup() time	      */
short	largeContexts;			/* 1 ==> Running w/Rev-B+ 68020       */
u_short	setsysmap();			/* Returns previous entry for debug   */

/*
 * Initialization of 'bingo' debugging constants.
 * BUG: 'normalMmuIndx' and 'vaGate' MUST be coordinated!
 */
#ifdef	CMD_BINGO		    /* C.f., s32/{context.c,map.c,startup.c}  */
short	cmd_BINGO	  = 0;	    /* 0==>Disable; 1==>Enable pattern match'g*/
char	cmd_BINGO_cmd[32] = "sh";   /* Command for which a match ==> "BINGO!" */
#endif	CMD_BINGO
u_short	vaGate		= SETS_32MB_MAXVA;/* Specify our virt. addr	      */
short	normalMmuIndx	=  MMU_32MB;	/* Usually < mmuIndxBigMap: h/vmmac.h */


#ifdef	MMU_BINGO		    /* C.f., s32/{context.c,map.c,startup.c}  */
short	mmu_BINGO	= 0;	    /* 0==>Disable; 1==>Enable pattern match'g*/
u_long	mmu_BINGO_vaddr	= 0x011321c;/* Virt addr @ which a match ==> "BINGO!" */
u_long	mmu_BINGO_paddr	= 0x015321c;/* Phys addr @ which a match ==> "BINGO!" */
#endif	MMU_BINGO

long debug = 0;

#if 0
long	debug	= 0;
long	debug	= D_CTXT|D_VMEM;
long	debug	= D_CTXT|D_VMEM|D_PMEM;
long	debug	= D_CTXT|D_VMEM  |  ~(D_PIB|D_MAIN|D_TRAP);
long	debug	= D_CTXT|D_VMEM  |  ~(D_PIB|D_MAIN|D_TRAP|D_PMEM);
long	debug	= D_CTXT|D_VMEM  |  ~(D_PIB|D_MAIN|D_TRAP|D_RUN); /* No 'rN' */
long	debug	= D_CTXT | ~(D_PIB|D_MAIN);
#endif 0

#ifdef	QUICKEN
short	okToQuicken	= 1;	/* 0==>Disable; 1==>Enable Quicken	      */
short	printSymVal	= 0;	/* 0==>Disable; 1==>Enable Quicken-blab	      */
short	quickenBlab	= 0;	/* 0==>No blab; !0==>Blab; C.f, s32/quicken.c */
short	quickenSummary	= 0;	/* 0==>No blab; !0==>Blab; C.f, s32/quicken.c */
#endif	QUICKEN


	/* Interrupt/exception dispatch table */

struct dispatch {
	short	disp_ins;	/* Contains a JSR instruction */
	long	disp_addr;	/* JSR address */
	short	disp_id;	/* Pad to 8 bytes */
} dispatch[NTRAP];		/* One for each possible exception vector */

label_t *nofault;	/* When nonzero, buserr will longjmp (see trap.c) */

	/* icode is the bootstrap program used to exec() /etc/init */

short	icode[] = {
/*hex offsets*/
/* 0*/ 0x4ffa,0x0800,	/*	lea pc@(0x802-.-2),sp	*/
/* 4*/ 0x41fa,0x001e,	/*	lea pc@(argp-.-2),a0	*/
/* 8*/ 0x43e8,0x000e,	/*	lea a0@(name-argp),a1	*/
/* c*/ 0x45e8,0x000c,	/*	lea a0@(boot-argp),a2	*/
/*10*/ 0x4868,0x0008,	/*	pea a0@(envp-argp)	*/
/*14*/ 0x2f08,		/*	movl a0,sp@-		*/
/*16*/ 0x2f09,		/*	movl a1,sp@-		*/
/*18*/ 0x20c9,		/*	movl a1,a0@+		*/
/*1a*/ 0x20ca,		/*	movl a2,a0@+		*/
/*1c*/ 0x42a7,		/*	clrl sp@-		*/
/*1e*/ 0x703b,		/*	moveq #59,d0		*/
/*20*/ 0x4e40,		/*	trap #0			*/
/*22*/ 0x60fe,		/*	jra .			*/
/*24*/ 0,0,		/*argp:	.long 0 	| &name	*/
/*28*/ 0,0,		/*	.long 0		| &boot	*/
/*2c*/ 0,0,		/*envp:	.long 0
/*30*/ 0,		/*boot:	.word 0		| .asciz "a" for autoboot */
/*32*/ 0x2f65,0x7463,	/*name:	.asciz "/etc/init"
/*36*/ 0x2f69,0x6e69,
#ifndef	s32	/* INIT_DOT_TEST */
/*3a*/ 0x7400
#else	s32	/* INIT_DOT_TEST */
			/* Poke a '.' in the 0x00 to get "/etc/init.test" */
#define	ETC_INIT		(0x32/sizeof(short))
#define	INIT_DOT_TEST		(0x3a/sizeof(short))
/*3a*/ 0x7400,
/*3c*/ 0x7465,
/*3e*/ 0x7374,
/*40*/ 0x0000
#endif	s32	/* INIT_DOT_TEST */
};

#define IC_BOOT (0x30/sizeof(short))	/* Index of boot: in icode[] */

#ifdef	s32	/* INIT_DOT_TEST */
short	useEtcInitTest	= 0;	/* 0==> /etc/init	1==> /etc/init.test */
#endif	s32	/* INIT_DOT_TEST */

int	szicode = sizeof (icode);

struct	pte *Bufmap;

int	nfreepages;		/* Number of free pages in bit map */

extern	char	*boottype;
int	manualboot = 0;

int	vax_mapen  = 0;		/* Message buffer map is enabled */

extern	char start[], etext[], edata[], end[];

/*
 *	mapdummyu()
 *
 * This subroutine runs on a stack at 0x1000, as setup
 * by start() in machine/locore.s
 * We must now set up another stack, an intermediate Upage,
 * to allow the busaddr() and fault() code to function.
 */
mapdummyu()	/* Called from 'startup1' herein -- stack @ TMPSTACK */
{
/*A5*/	A_V_CONTEXT;				/* Allocate register-var*/
	register int	i;
	int		s	= spl7();
	u_char		oldctxt	= R_V_CONTEXT;

	/*
	 * Map DUMMYU_PA into the U page area.
	 */
	for (i=0; i<UPAGES; ++i)
	{
		R_V_CONTEXT = (oldctxt & ~V_MAP_CONTROL)
			  | V_ACCPM
			  | ((btop(&u)+i < btoc(V_PAGEMAP))
				? V_ACCLOW
				: V_ACCHIGH
			    );
#ifdef	WHITE_V_PRESENT
	   *(u_short *)(((int)&u + (int)ptob(i)) | V_PAGEMAP) = btop(DUMMYU_PA)
							      + i | V_PRESENT;
#else	WHITE_V_PRESENT
	   *(u_short *)(((int)&u + (int)ptob(i)) | V_PAGEMAP) = btop(DUMMYU_PA)
							      + i;
#endif	WHITE_V_PRESENT
	   R_V_CONTEXT = oldctxt;
	}
	splx(s);
	/*
	 * Clear the U page so references to it will
	 * pick up known values and, specifically, so
	 * the debugger will work.
	 */
#ifdef	INITMAP
	clearpage(btop(DUMMYU_PA));
#else	INITMAP
	{
		register long  *addr	= (long *)&u;
		register int	count	= (UPAGES*NBPG)/sizeof(long);

		while (count--)
			*addr++ = 0;
	}
#endif	INITMAP
}

#ifdef WHITE
int	MaryGray = 0x100;		/* 1M, not 4! */
#else WHITE
int	MaryGray = PHYSMEMPAGES;	/* For cdebugger() */
#endif WHITE

#if	defined(DEBUG)
short	cdbAtVectors	= 0;	/* 1==>enable; 0==> disable		*/
short	goDebugger	= 0;	/* 1 ==> side trip to cdebugger()	*/	
short	verbosity	= 0;	/* Degree of debug blab; 0==> disable	*/

short	issigMsg	= 0;	/* 1==> enable "issig" msg to console	*/
short	goprintmap	= 0;	/* 1==> print memory layout to console	*/
extern	long	godebugger;	/* 1 ==> side trip to asm/c-debugger()	*/

short	boardMapDebug	= 0;	/* 1==>enable; 0==> disable		*/
u_long	firstNonPhysMem	= 0x280000;/* 1st page of non-existent phys mem	*/
#endif	defined(DEBUG)


#ifdef WHITE
/*
 * Weirdo memory sizing routine
 * returns the maximum possible size of physical memory,
 * either 1 megabyte or 4 (for 64K vs. 256K RAMs).
 * The return value is in page-sized chunks (assuming pagesize == 4096!)
 * in order to be useful to the MaryGray loop in startup1.
 */
maxszm() {
	register char *p = (char *)0xFFFFF;
	/*
	 * Check for reflections.  If the memory board is built
	 * out of 64K parts, then it will reflect addresses every
	 * megabyte.
	 */
	*p = 4;
	p[0x100000] = 5;
	return (*p == 5)? 0x100: 0x400;
}
#endif WHITE

#ifdef	M68020
#ifdef	s32	/* INIT_CACHE */
/*
 * cpuIsRevB() -- Returns -1 iff cpu can cope with vaddr's >16MB.
 *
 * NOTE:	1) We presume that the appropriate vaddr bits
 *		   have already been set in the STATUS REG;
 */
cpuIsRevB()
{
#ifndef	WHITE
/*d7*/	register u_short  sEntry	= (((MAPONLY_PAGE>>segshift) & SEG_PAGE)
					| V_SKERNEL);
/*d6*/	register u_short  prevSeg;

/*d5*/	register u_long	  va		= (u_long)V_MAXVA_16MB;
/*A5*/	register u_short *saddr		= (u_short *)((va & ~1) | V_SEGMAP);
/*A4*/	register u_short *pte		= (u_short *) (va       | V_PAGEMAP);
/*A3*/	A_V_CONTEXT;				/* Allocate register-var*/
/*d4*/	register u_short  pEntry	= btop(MAPONLY_PAGE) | mbmem;
/*d3*/	register u_short  prevPte;

/*+08*/	u_short		  oldctxt	= R_V_CONTEXT;
/*+0C*/	int		  s		= spl7();
/*+10*/	int		  i;
/*+14*/	label_t		  jb, *saved_jb;

	/*
	 * BUG:  Just say it's a RevB for now...
	 */
	if (1)	return -1;

	if (chipType==CHIPTYPE_68020) {

		/*
		 * Setup the SEGMENT map
		 * =====================
		 */
		R_V_CONTEXT = (oldctxt & ~V_MAP_CONTROL)
			  | V_ACCSM
			  | ((va & V_SEGMAP)
				? V_ACCHIGH
				: V_ACCLOW
			    );

		saved_jb = nofault; /* Just in case mmu h/w is wrong/broken */
		if (!setjmp(&jb)) {
			nofault = &jb;

			/*
			 * Try to access the SEGMENT map
			 */
			prevSeg	= *saddr;
			*saddr	= sEntry;
		} else {
			nofault = saved_jb;
			printf("cpuIsRevB/I-1: vaddr >= 16MB doesn't work\n");
			return 0;		/* Say NOT RevB */
		}
		nofault = saved_jb;

		/*
		 * Setup the PAGE map
		 * ==================
		 */
		R_V_CONTEXT = (oldctxt & ~V_MAP_CONTROL)
			  | V_ACCPM
			  | ((va & V_PAGEMAP)
				? V_ACCHIGH
				: V_ACCLOW
			    );

		saved_jb = nofault; /* Just in case mmu h/w is wrong/broken */
		if (!setjmp(&jb)) {
			nofault = &jb;

			/*
			 * Try to access the PAGE map
			 */
			prevPte	= *pte;
			*pte	= pEntry;

			/*
			 * Read from the vaddr to see if it is OK
			 */
			i = *(u_short *) va;
		} else {
			nofault = saved_jb;
			printf("cpuIsRevB/I-2: vaddr >= 16MB doesn't work\n");
			return 0;		/* Say NOT RevB */
		} 
		nofault = saved_jb;

		/*
		 * Restore the context
		 */
		R_V_CONTEXT = oldctxt;
		splx(s);

		/*
		 * BUG: Need to poke the h/w to see
		 * if cpu supports vaddr's > 16MB.
		 * Currently we lie about it and say that it does.
		 */
		printf("cpuIsRevB/I-3: vaddr >= 16MB does work\n");
		return -1;			/* Say its RevB */
	} else

#endif	WHITE
		printf("cpuIsRevB/I-4: vaddr >= 16MB not available\n");
		return 0;			/* Say NOT RevB */
}

/*
 * 68020 caches.
 *
 * BUG:  Cannot trace through initCache()
 * with the cdebugger().
 */
short		enableOnBoardCache = 1;		/* 1==>enable; 0==> disable   */
short		enableOnChipCache  = 1;		/* 1==>enable; 0==> disable   */
short		disMbCmds	   = 0;		/* !0 ==> Disable mltbus cmds */
#endif	s32	/* INIT_CACHE */

/*
 * Onboard 1MHz, 16-bit clock/counter
 */
extern	int	prontoTicker;
extern	int	ticksPerClkRupt;
#endif	M68020

#ifdef	M68881
u_long	coProcessorType;
short	okToDo68881FPU	= 1;	/* 0==>Disable; 1==>Enable M68881 save/restore*/
#endif	M68881

/*
 * BUG: This will break for inhomogeneous process
 * virtual address space sizes, since 'nSegs' ==> 'normalMmuIndx'
 */
int	nSegs	= ptos(BIGMAP_PAGES);	/* Early value: to satisfy getSegMap()*/

/*
 * Do the next level of initialization:
 * The entire sequence is:
 *
 *	start()			-- machine/locore.s
 *		startup1()	-- machine/startup.c
 *		main()		-- sys/init_main.c
 *		startup()	-- machine/startup.c
 *		  ...
 */
startup1()	/* Called from 'start' in machine/locore.s -- stack @ TMPSTACK*/
{
/*A5*/	A_V_CONTEXT;				/* Allocate register-var*/
	register unsigned i, j;				/* Work-variables */
	extern	int buserr(), addrerr(), scall();
#ifdef	M68000
	extern	int	busErr68000(), addrErr68000();
#endif	M68000
#ifdef	M68010
	extern	int	busErr68010(), addrErr68010();
#endif	M68010
#ifdef	M68020
	extern	int	busErr68020(), addrErr68020();
#endif	M68020
	/*
	 * Historical note:
	 *	Sun architecture has both
	 *	localmem and mbusmem.
	 *
	 *	WHITE has only localmem.
	 *	s32   has only mbusmem.
	 */
	int	localmem = 0;		/* Pages of local memory	      */
	int	mbusmem	 = 0;		/* Pages of multibus memory	      */

	register struct	dispatch *d;
	label_t		jb, *saved_jb;
	unsigned short	pgslot;		/* Bucket for page # to pagefree()    */
	unsigned long	mbmbeg,		/* First page of memory beyond kernel */
			mbmend,		/* Last page of memory		      */
			sysmem;		/* Unused: mbmbeg - one segment	      */
	unsigned short	sysmbpage;	/* Page # of  MBMEM_VA page	      */

	extern	 struct	dispatch proto;	/* Prototype dispatch vector	      */
	extern	 long	godebugger;	/* 1 ==> side trip to cdebugger()     */
#ifdef KERN_RESTART
	extern	 int	symbytes;	/* # bytes of kernel symbol table     */
#endif KERN_RESTART
#ifdef	DEBUG
	extern	caddr_t vtop();
#endif	DEBUG
	extern	char	version[];	/* Version-# when kernel built	      */
	extern	char	options[];	/* -D... options from 'cc' of kernel  */

#define V ((int (**)())0)
#define D ((struct dispatch **)0)



#ifndef	WHITE
	/*
	 * PIT<0>:
	 * This timer drives the HZ timer
	 * for the kernel's scheduler.
	 * We turn the clock OFF for now.
	 */
	CLKADDR->c_mode = C_MODE0	/* Interrupt on terminal count     */
			| C_SEL0	/* Counter #0			   */
			| C_WORD;	/* Read/write both bytes (0 first) */
#endif	WHITE

	/*
	 * Unmap everything in kernel virtual space which
	 * is not needed.  We assume that everything after
	 * end can go away until it is explicitly mapped
	 * in; also map the user structure to a dummy place
	 * so that busaddr() and fault() have a valid place to
	 * store things.
	 *
	 * NOTE:  printf() doesn't work any earlier than after this.
	 */
	mapdummyu();

	/*
	 * Firewall used by machine/locore.s to check for stack overflow.
	 * Leave 64 bytes of safety margin to handle any ensuing panic().
	 */
	kstkbot = (int)&u + sizeof(struct user) + 64;

	V_STATUS |= V_GREENLED;		/* Indicate useful work has begun  */

	/*
	 *  Catch all interrupts and exceptions.
	 *
	 *  Each 68000 exception vector points to a cooresponding
	 *  entry in the dispatch structure.  The structure contains
	 *  a "jsr fault" instruction (located in mch.s) followed by
	 *  the exception id number which fault() uses to figure out
	 *  what happened.  Certain vectors must be left intact.
	 */

	for (i=0; i<NTRAP; ++i)
		switch (i)
		{
			case T_RSSP:
			case T_RPC:
			/* case T_ILL:		/* macsbug */
			/* case T_TRACE:	/* ddt */
			case T_TRAP14:		/* ddt */
			case T_TRAP15:		/* monitor emt */
				break;
			default:
				proto.disp_id	= i;
				dispatch[i]	= proto;
				D[i]		= &dispatch[i];
				break;
		}

	/*
	 * Bus and address exceptions
	 * are handled differently (see mch.s)
	 */
	V[T_BUSERR]  = buserr;
	V[T_ADDRERR] = addrerr;
	V[T_TRAP0]   = scall;

	/*
	 * Either trap 14 or level 7
	 * will end up in versabug
	 *
	 * ***** BUG: *****
	 * ***** We don't have VERSABUG anymore - ELP *********
	 */
	V[T_TRAP14] = V[T_VEC7];


	/*
	 * Find out which cpu processor chip is installed
	 * and install the correct exception vectors.
	 * 
	 * NOTE:  printf's don't work this early in a WHITE.
	 */
	if (getChipType() != CHIPTYPE_68020) {
		/*
		 * We MUST clear the h/w errors from the Address Error fault
		 * because the addrErr fault is indeed a bus error.
		 *
		 * NOTE:  setErrorReg() requires chipType
		 * to be properly set, which of course it (now) is.
		 */
		setErrorReg(0);
	}

	switch (chipType) {
#ifdef	M68000
	case	CHIPTYPE_68000:
		V[T_BUSERR]  =  busErr68000;
		V[T_ADDRERR] = addrErr68000;
		break;
#endif	M68000

#ifdef	M68010
	case	CHIPTYPE_68010:
		V[T_BUSERR]  =  busErr68010;
		V[T_ADDRERR] = addrErr68010;
		break;
#endif	M68010

#ifdef	M68020
	case	CHIPTYPE_68020:
		V[T_BUSERR]  =  busErr68020;
		V[T_ADDRERR] = addrErr68020;
		/*
		 * NOTE:  Since getChipType() experienced no address error,
		 * we need NOT strobe the CLR.TIMEOUT.PND status bit
		 * to allow "pending" of timeouts.
		 * Any pending timeout would cause a busErr as soon
		 * as the errReg is cleared.
		 *
		 * Neither should we now arm for the NEXT
		 * (possibly extant) timeout bus error.
		 */
		break;
#endif	M68020

	case	CHIPTYPE_ERROR:
#ifndef	WHITE
		printf("chipType ERROR!\n");
		cdebugger("startup1/E-9: Botched chipType!");
#endif	WHITE
		break;

	default:
#ifndef	WHITE
		printf("chipType UNKNOWN!\n");
		cdebugger("startup1/E-10: Unknown chipType");
#endif	WHITE
		break;
	}
#if 1
#ifndef	WHITE
	/*
	 * NOTE:  For reasons unknown, this message
	 *	  is printed TWICE!
	 */
	printf("CPU chipType=%X\n", chipType);
#endif	WHITE
#endif 1


#if 0
	/*
	 * We retain this hook into the cdebugger()
	 * to facilitate Engineering fixes
	 * for brain damage during road-shows, etc.
	 *
	 * NOTE: Can't look at symbols or perform setpagemap()
	 * with the cdebugger because virtual memory is not yet setup.
	 */
	if (cdbAtVectors) {
		printf("startup1/I-12: virtual memory is NOT yet SETUP.\n");
		cdebugger("After new vectors installed.");
	}
#endif 1


	if (chipType == CHIPTYPE_68020 && V_SWITCHES & V_SWITCH_LARGEVM) {
		vaGate		= SETS_128MB_MAXVA;
		normalMmuIndx	=  MMU_128MB;
	}
	/*
	 * Reset the cpu and mmu h/w to a known state.
	 * We are not compelled to do this.
	 * Validate 'vaGate', which specifies the
	 * particular sizing of the larger virtual
	 * address space option.
	 */
#ifndef	M68020
	V_STATUS   = V_STATUS0_DEFAULT;
#else	M68020
	switch (MAXVA_BITS(vaGate)) {
#if 0					/* Duplicate CASE-SWITCH w/16MB_MAXVA */
	case SETS_4MB_MAXVA:
		mmuIndx	   = MMU_8MB;
		break;

	case SETS_8MB_MAXVA:
		mmuIndx	   = MMU_8MB;
		break;
#endif 0				/* Duplicate CASE-SWITCH w/16MB_MAXVA */

	case SETS_16MB_MAXVA:
		mmuIndx	   = MMU_16MB;
		break;

	case SETS_32MB_MAXVA:
		mmuIndx	   = MMU_32MB;
		break;

	case SETS_64MB_MAXVA:
		mmuIndx	   = MMU_64MB;
		break;

	case SETS_128MB_MAXVA:
		mmuIndx	   = MMU_128MB;
		break;

	default:
		mmuIndx	   = MMU_16MB;
	}

	/*
	 * NOTE:  setStatusReg() requires chipType to be properly set.
	 */
	if	(chipType==CHIPTYPE_68000)
		mmuIndx	   = MMU_4MB;

	else if	(chipType!=CHIPTYPE_68020)
		mmuIndx	   = MMU_16MB;

	/*
	 * Setup fundamental constants
	 * Size the h/w memory map, etc.
	 */
	pagesize  = NBPG;
	pagemask  = pagesize - 1;
	pageshift = PGSHIFT;
	mmuIndxBigMap	= mmuIndx;		/* Indicate our bigest map */
	normalMmuIndx	= mmuIndx;		/* Set the default */
	smallmap_pages	= SMALLMAP_PAGES;	/* Can only ever be this   */
	  bigmap_pages	= (u_long)mmu_sizing[mmuIndxBigMap].mmu_ctxtMaxVaddr
			>> pageshift;

	msegsize  = SEGSIZE;
	segmask   = SEGSIZE - 1;
	segshift  = SEGSHIFT;
	/*
	 * Determine if we even need to deal with large address space(s).
	 * The RevB+ 68020 requires special handling.
	 * BUG: I need to probe @ 32MB to determine if RevB 68020.
	 */
	if (cpuIsRevB() && (mmuIndxBigMap > MMU_16MB)) {
		largeContexts = 1;	/* Activate processing for MMU_32MB++ */
#if	0
		cdebugger("startup1: Before ORing vaGate into STATUS reg");
#endif	0
		orStatusReg(vaGate);	/* Activate the LARGE VADDR h/w */
	} else {
		largeContexts = 0;	/* Saves labor later...		      */
	}


	{ register bigmap_vaddr = bigmap_pages<<pageshift;

	printf("MMU sized for %d %dKb pages ==> %sMbyte virtual addr space\n",
		  bigmap_pages, pagesize>>10,
		  bigmap_vaddr==V_MAXVA_4MB	? "4"
		: bigmap_vaddr==V_MAXVA_8MB	? "8"
		: bigmap_vaddr==V_MAXVA_16MB	? "16"
		: bigmap_vaddr==V_MAXVA_32MB	? "32"
		: bigmap_vaddr==V_MAXVA_64MB	? "64"
		: bigmap_vaddr==V_MAXVA_128MB	? "128"
		: bigmap_vaddr==V_MAXVA_256MB	? "256"
		: bigmap_vaddr==V_MAXVA_512MB	? "512"
		: bigmap_vaddr==V_MAXVA_1024MB	? "1024"
		: bigmap_vaddr==V_MAXVA_2048MB	? "2048"
		:			"UNKNOWN-"
		);
	}

#ifdef	WHITE
	maxpage = BIGPAGES - 1;
#else	WHITE

#if	defined(M68010) || defined(M68020)
	if (chipType==CHIPTYPE_68010 || chipType==CHIPTYPE_68020)
	   if (!(V_SWITCHES & V_SWITCH_BIGMAP))
		panic("bigmap switch (switch 5) must be set on CPU board");
#endif	defined(M68010) || defined(M68020)

	/*
	 * If the BIGMAP switch is set and the
	 * big map really does appear to exist then
	 * set sizes and limits appropriately.
	 */
	maxpage = bigmap_pages - 1;
	nSegs	= ptos(bigmap_pages);	/* To satisfy getSegMap() */

	if (verbosity>=8)
	   printf("startup1/I-13:  maxpage=0x%X nSegs=0x%x largeContexts=%d\n",
			maxpage, nSegs, largeContexts);

	if (V_SWITCHES & V_SWITCH_BIGMAP)
	{
		extern	u_short	getSegMap(), setSegMap();
		u_short	oldsmap, newsmap;
		u_short	oldpmap, newpmap;
		u_short	pageX	= bigmap_pages-2;
		u_short	pageY	= bigmap_pages-5;

		/*
		 * We can not presume that the segment maps
		 * for the large virtual address spaces
		 * are initialized yet.
		 *
		 * ASSUMPTION: pageX and pageY are both
		 * within the same segment.
		 */
		if (PTOS(pageX) == PTOS(pageY)) {

		   /*
		    * Get the old segment map
		    */
		   if (verbosity>=8)
		      printf("startup1/I-14: getSegMap(SYSCTXT=0x%x, PTOS(pageY=0x%x)=0x%x)",
				SYSCTXT,
				pageY,
				PTOS(pageY));
		   oldsmap = getSegMap(SYSCTXT,PTOS(pageY),nSegs);
		   if (verbosity>=8)
		      printf("=0x%x\n", oldsmap);

		   /*
		    * Set a new value for the map
		    */
		   if (verbosity>=8)
		      printf("startup1/I-16: setSegMap(SYSCTXT=0x%x, ((pageY=0x%x) << (pageshift=%d))=0x%X, btos(MAPONLY_PAGE)=0x%x|V_SKERNEL)",
				SYSCTXT,
				pageY,
				pageshift,
				pageY<<pageshift,
				btos(MAPONLY_PAGE));
		   oldsmap = setSegMap(SYSCTXT,
					pageY<<pageshift,
					btos(MAPONLY_PAGE)|V_SKERNEL,
					nSegs);
		   if (verbosity>=8)
		      printf("=0x%x\n", oldsmap);

	if (verbosity>=12)
	   printf("startup1/I-17:  maxpage=0x%X nSegs=0x%x largeContexts=%d\n",
			maxpage, nSegs, largeContexts);

		} else {
		   printf("\nstartup1/I-18: PTOS(pageX=0x%x)=0x%x != PTOS(pageY=0x%x)=0x%x\n",
			pageX, PTOS(pageX),
			pageY, PTOS(pageY));
		   cdebugger("startup1/E-6c: Botched segment assumption");
		   panic("startup1/E-6c: botched segment assumption");
		}

		/*
		 * Get the map for an arbitrary location
		 * within the exclusive domain of the big map
		 * and alter it.  Then check if the alteration
		 * actually happened, or went to "Bit Heaven."
		 *
		 * NOTE:  getpagemap() and setpagemap() do not
		 * make any mmu_sizing, u-page, or process references.
		 * getpagemap() can return -1.
		 */
		oldpmap = getpagemap(pageY);	/* Arbitrary page   */
		newpmap = oldpmap ^ V_PAGEMASK;		/* Flip pageno bits */

		/*
		 * See if the bits we bash into the
		 * bigmap portion are really there...
		 */
		(void)setpagemap(pageX, newpmap); /* Stuff elsewhere  */

		if   (setpagemap(pageX, oldpmap) != newpmap) {
			maxpage = smallmap_pages - 1;	/* "Broken" bigmap! */
			printf("startup1/A-20: Bigmap is not functional\n");
		}
	} else {
			maxpage = smallmap_pages - 1;
			printf("startup1/A-22: Switch #5 on CPU board not ON -- no bigmap\n");
	}
#if	defined(M68010) || defined(M68020)
	if (chipType==CHIPTYPE_68010 || chipType==CHIPTYPE_68020)
	   /*
	    * Complain about the MMU, if necessary
	    */
	   if (maxpage != bigmap_pages-1)
		panic("CPU must have a big map:  Insure CPU SW5 is ON.");
#endif	defined(M68010) || defined(M68020)

#endif	WHITE

	/*
	 * Set some of the fundamental constants
	 * for the system.
	 */
	kvarea	 = maxpage + 1 - SEGSIZE/NBPG;
	p1Pages	 = maxpage + 1			/* All of the PHYSICAL pages */
		 - SEGSIZE/NBPG;		/* ...minus the topmost seg  */
	usrbase	 = USRTEXT >> pageshift;

	/*
	 * Set the GLOBAL buckets with the LARGEST values
	 * that a process could have.
	 * NOTE that the information for individual processes
	 * is gotten from the 'mmu_sizing' table entry
	 * that is appropriate for the particular virtual address space.
	 */
	usrTop	 = maxpage + 1 - SEGSIZE/NBPG - HIGHPAGES;

	nSegs	 = ctos(maxpage + 1);
	usrtext	 = ptob(usrbase);
	usrStack = ptob(usrTop);

	for (i=0; i <= MMU_MAX_INDX; i++) {
	   register struct mmu_sizing_t	* mmup;

	   mmup			= &mmu_sizing[i];
	   mmup->mmu_usrtext	= usrtext;
	   mmup->mmu_usrbase	= usrbase;			/* Pages */
	   mmup->mmu_nsegs	= ctos((u_long)
					mmup->mmu_ctxtMaxVaddr >> pageshift);
	   mmup->mmu_usrtop	= btop((u_long)mmup->mmu_ctxtMaxVaddr)
				- SEGSIZE/NBPG - HIGHPAGES;	/* Pages */
	   mmup->mmu_usrstack	= ptob(mmup->mmu_usrtop);
	   mmup->mmu_kvarea	= btop((u_long)mmup->mmu_ctxtMaxVaddr)
				- SEGSIZE/NBPG;			/* Pages */
	   mmup->mmu_p1pages	= mmup->mmu_kvarea;		/* Pages */
	   mmup->mmu_maxVSmaps	= ptos(   mmup->mmu_usrtop
					- mmup->mmu_usrbase
					+ 1 /* Top segment */);	/* Segs */
	}

	/*
	 * PHYSICAL limit on the # of segment maps available.
	 * NOTE: ptos() rounds up; PTOS() does not.
	 */
	maxPSmapsAvail	= PTOS(   mmu_sizing[MMU_16MB].mmu_kvarea
				- mmu_sizing[MMU_16MB].mmu_usrbase
				- 1
			      );

	/*
	 * VIRTUAL limit on the # of segment maps available.
	 * BUG:  'maxVSmapsAvail' might be off-by-1
	 * BUG:  Really should use the values in 'mmu_maxVSmaps'!
	 */
	maxVSmapsAvail	= ptos(   mmu_sizing[normalMmuIndx].mmu_kvarea
				- mmu_sizing[normalMmuIndx].mmu_usrbase
				- 1
			      );

	if (verbosity>=12)
	   printf("startup1/I-93: maxpage=0x%X nSegs=0x%x largeContexts=%d\n",
			maxpage, nSegs, largeContexts);

	/*
	 *  segsize is the largest segment size found in any implementation.
	 *  It is used to determine the separation between text and data/bss
	 *  segments for mode 410 binary files (read-only text segment).
	 *  It must agree with a similar value used by the loader.
	 *
	 *  THIS WILL CHANGE IF THE PROTECTION BITS GET MOVED TO THE PAGE MAP
	 */

	segsize  = SEGSIZE;

	/*
	 * Construct the code image that is to invoke '/etc/init'.
	 * The code image is subsequently copied into a process image
	 * and scheduled for running.
	 */
	saved_jb = nofault; /* Just in case 'boottype' points into boonies */

	/*
	 * Tell /etc/init if it's an autoboot
	 */
	if (!setjmp(&jb)) {
		nofault = &jb;
		/*
		 * "Oh, ye of little faith..."
		 */
		if (!boottype)				   /* NULL pointer... */
			icode[IC_BOOT] = 'e\0';		   /* 'e' for "error" */

		else if (strlen(boottype) > sizeof(short)) /* Runaway length  */
			icode[IC_BOOT] = 'E\0';		   /* 'E' for "Error" */

		else strncpy(&icode[IC_BOOT],boottype,sizeof(short));
	} 
	nofault = saved_jb;

#ifdef	KERN_RESTART
	/*
	 * Save kernel data where it won't get stomped
	 * on (immediately following the BSS loader section).
	 */
	savekernel();
	k_lastpage = btoc(end + (edata - etext));	/* btoc() rounds up */

	printf("0x%x=%d bytes of kernel data saved at 0x%x\n",
		edata - etext,
		edata - etext, end);
	printf("0x%x=%d bytes of symbol table saved at 0x%x\n",
		symbytes, symbytes, (int)SYM_PA);
#else	KERN_RESTART
	k_lastpage = btoc(end);				/* btoc() rounds up */
#endif	KERN_RESTART

	/*
	 * Start by setting physmem to be k_lastpage since
	 * we know that there is at least that much physical
	 * address space (with holes in it, of course).
	 * physmem will be changed whenever a page of core
	 * is found which is above physmem.  physmem is needed
	 * in order to initialize the core map.
	 */
	physmem = k_lastpage;

	/*
	 * Provide a primitive gateway
	 * to debugging facilities.
	 */
	if (*(u_long *)0x800 == 0xABCABC) *(u_long *)0x800 = 0, manualboot = 1;
	if (*(u_long *)0x800 == 0x123123) *(u_long *)0x800 = 0, godebugger = 1;
	if (*(u_long *)0x900 == 0x789789) *(u_long *)0x900 = 0, goprintmap = 1;

#ifdef	WHITE
	dsopen();		/* Initialize the display */
	/*
	 * BUG: the keyboard uses timeout and sleep
	 */
	kbopen();		/* Initialize the keyboard */
	printf("SCALD IV with a M%x\n", chipType);
#if 0
	cdebugger("Hi, I'm a white kernel");
#endif 0
#endif	WHITE

	/*
	 * This is the nominal entry
	 * to the cdebugger() during 'bringup'
	 * of new kernel features.
	 */
	if (godebugger||goDebugger) {
		printf("startup1/I-24: virtual memory IS SETUP NOW.\n");
		cdebugger("From startup1() Just after godebugger test");
	}

#ifdef	M68881
	if (chipType==CHIPTYPE_68020) {
		/*
		 * NOTE:  This does NOT require a pre-existing u-page,
		 * since getCoProcessorType() does:
		 *
		 *	...
		 *	lea	fpuCtlRegs+12,a2
		 *	FMOVE FPCR/FPSR/FPIAR,a2@-
		 *	...
		 *
		 * to push all of the FPU's Control Regs into 'fpuCtlRegs'.
		 */
		if (coProcessorType = getCoProcessorType()) {
			printf("CPU boardset has an MC%X coprocessor.\n",
				coProcessorType);
		} else {
			/*
			 * We MUST clear the h/w errors from the FPU fault
			 * because the FPU fault is indeed a bus error.
			 *
			 * NOTE:  setStatusReg() requires chipType
			 * to be properly set.
			 */
			setErrorReg(0);
		}
	}
#endif	M68881

#ifdef	QUICKEN
	if (chipType==CHIPTYPE_68020) {
		/*
		 * Bash the function calls for the likes
		 * of the *, /, % 'c' operators
		 * into inline 68020 machine code.
		 * Thanks to Roger Scott, who did the initial
		 * version which worked on a.out files.
		 *
		 * BUG:  The disassembler does NOT yet understand
		 * the 68020 machine code which quicken() installs.
		 */
		if (okToQuicken) {
			int	rc;

		        if (!quickenSummary)
				printf("Optimizing kernel for 68020 ...");
			rc = quicken();
			if (!rc) {
			   if (!quickenSummary)
				printf(" completed.\n");
			} else {
			   if (rc<0)
				cdebugger("startup/E-25: problem w/quickening");
			}
		} else
			printf("Kernel quickening bypassed.\n");
	}
#endif	QUICKEN

#ifdef	s32	/* INIT_DOT_TEST */
	/*
	 * Provide for less dangerous testing
	 * for /etc/init.test, (rather than /etc/init)
	 */
	if (useEtcInitTest) {
		printf("startup1/I-26: Instead of '%s', will use '%s'\n",
			 &icode[ETC_INIT],
			((icode[INIT_DOT_TEST] |= (unsigned char)'.'),
			 &icode[ETC_INIT]
			)
		);
	}
#endif	s32	/* INIT_DOT_TEST */

#ifdef	M68020
	/*
	 * Setup the 68020's and onchip cache and
	 * Valid's onboard cache.
	 */
	if (chipType==CHIPTYPE_68020) {
		if (enableOnChipCache) {
			/*
			 * Inform the board that we will
			 * entertain caching at this point.
			 */
			orStatusReg(S1_INT_CACHE_EN); 	/* OnChip cache */

			/*
			 * Proceed with the litany for the chip.
			 * It would probably suffice
			 * to merely clear the OnChipCache,
			 * but for completeness we will
			 * invoke the entire ceremony.
			 */
			asm("	movb	#0,d0		| Disable cache	");
			asm("	.word	0x4e7a,0x0002	| movec	d0,cacr	");

			asm("	movl	#8,d0		| Clear cache	");
			asm("	.word	0x4e7a,0x0002	| movec	d0,cacr	");

			asm("	movb	#1,d0		| Enable cache	");
			asm("	.word	0x4e7a,0x0002	| movec	d0,cacr	");
		}

		if (enableOnBoardCache) {
			/*
			 * initCache() turns on the onboard cache
			 * and leaves it enabled.
			 */
			register retval = initCache();

			if (verbosity>=8)
			   printf("Onboard cache initialization %s\n",
				  retval == -1	? "FAILED!"
				: retval ==  1	? "bypassed."
				: retval ==  0	? "succeded."
						: "UNKNOWN!"
				 );
		} else {
			/*
			 * The 68020, sans the onboard (external) cache,
			 * runs SO SLOW that we are always
			 * trying the catch up on clock ticks,
			 * so forget it...
			 */
			prontoTicker	= ticksPerClkRupt - 10;
		}
	}
#endif	M68020

	/*
	 * Setup per processor constants
	 */
	page_free	= V_PAGE_INVALID;
	page_reserved	= page_free + 1;
#ifdef	WHITE
	localmem	= sysmem = k_lastpage;
#else	WHITE

	mbmem	  = V_MBMEM;
	mbio	  = V_MBIO;
	sysmbpage = k_lastpage++;	/* Count MBMEM_VA page */

	if (sysmbpage >= physmem) physmem = sysmbpage+1;

	mbmbeg	= k_lastpage | mbmem;
	mbmend	= PHYSMEMPAGES | mbmem;		/* C.f., machine/cpu.h */
	mbusmem = sysmem =  k_lastpage;

	/*
	 * Map multibus i/o space into MBIO_VA
	 */
	for (i=MBIO_VA; i< (MBIO_VA + MBIO_SIZE); i += pagesize)
		setpagemap (i >> pageshift, mbio + ((i-MBIO_VA) >> pageshift));

	/*
	 * Map one page of multibus memory space into MBMEM_VA
	 */
	setpagemap (MBMEM_VA >> pageshift, sysmbpage | mbmem );
#endif	WHITE

	/*
	 * Put the kernel text, data, and bss areas
	 * into Sysmap so that the map is complete.
	 */
	for (i=btop(K_A); i < btop((int)etext); ++i)
		*(int *)&Sysmap[i] = PG_V | PG_KR | i;	/* Readonly TEXT */

	for (; i <= btop((int)end - 1); ++i)
		*(int *)&Sysmap[i] = PG_V | PG_KW | i;	/* Writable DATA+BSS */

#ifdef WHITE
	/*
	 * Probe the extent of physical memory before invalidating the
	 * map (lazy!)
	 */
	MaryGray = maxszm();
#endif WHITE

	/*
	 * Allocate kernel virtual memory for all the
	 * needed areas by using kvalloc().
	 */
	allocvmem();

	/*
	 * Initialize the segment map giving
	 * appropriate access permissions.
	 */
	kvinit(ALLCTXT, 0/*segBias*/, nSegs);

	/*
	 * Say who we are and how we got
	 * to be what we are...
	 */
	printf("\nSCALDsystem Unix, version %s\n", &version[14]);

	if (goprintmap) printf("Compile-time options were %s\n",  options);

	printf("pagesize=%d pagemask=0x%x pageshift=%d ",
		pagesize,   pagemask,     pageshift);
	printf("usrbase 0x%x usrtop 0x%x\n", usrbase, usrTop);


	/*
	 * Clear and free the pysical memory which is
	 * overlaid by the CPU resources in the second
	 * segment.  Do not adjust mbusmem or physmem
	 * since we have already taken these memory
	 * pages into account.
	 */
	for( i = SEGSIZE / NBPG; i < 2 * SEGSIZE / NBPG; i++ )
	{
		setpagemap( i, V_PAGE_INVALID );
#ifdef WHITE
		j = i;
#else WHITE
		j = i | V_MBMEM;
#endif WHITE
		clearpage( j );
		pgslot=i; pagfree(&pgslot,1);
	}
	sysmem -= SEGSIZE / NBPG;

#ifdef WHITE
	/*
	 * Find, clear, and free all of memory which
	 * is not already used by the kernel.
	 * Memory map is real simple:
	 *
	 *	000000:3FFFFF	real memory
	 *	400000:7FFFFF	map thereto
	 *	800000:FFFFFF	I/O devices
	 */
	saved_jb = nofault;
	nofault  = &jb;
	for (i = k_lastpage; i < MaryGray; ++i) {
		if (!setjmp(&jb)) {
			if (clearpage(i))
				continue;
			pgslot = i; pagfree(&pgslot,1);
			localmem++;
			/*
			 * Make sure that physmem contains the address
			 * just above the last page of physical memory.
			 */
			if (i >= physmem) physmem = i + 1;
		}
	}
	nofault = saved_jb;

#else	WHITE
	/* Probe for multibus memory
	 *
	 * Current memory map for s32 looks like this:
	 *
	 *	+-----------------------+ 0x000000
	 *	|			|		   ^
	 *	|    Real Memory        |		0x380,000
	 *	|			|		   v
	 *	+-----------------------+ 0x37FFFF
	 *	+-----------------------+ 0x380000
	 *	|			|		   ^
	 *	|  Ethernet, VG's, PIB  |		0x80,000
	 *	|			|		   v
	 *	+-----------------------+ 0x3FFFFF
	 *	+-----------------------+ 0x400000
	 *	|			|		   ^
	 *	|    Real Memory	|		0x400,000
	 *	|			|		   v
	 *	+-----------------------+ 0x7FFFFF
	 *	+-----------------------+ 0x800000
	 *	|			|		   ^
	 *	|    Color Ram  (CRB)   |		0x100,000
	 *	|			|		   v
	 *	+-----------------------+ 0x8FFFFF
	 *	+-----------------------+ 0x900000
	 *	|			|		   ^
	 *	|    Real Memory        |		0x580,000
	 *	|			|		   v
	 *	+-----------------------+ 0xD7FFFF
	 *	+-----------------------+ 0xDC0000
	 *	|			|		   ^
	 *	|    RealChip 2         |		0x20,000
	 *	|			|		   v
	 *	+-----------------------+ 0xDDFFFF
	 *	+-----------------------+ 0xDE0000
	 *	|			|		   ^
	 *	|    RealChip 3         |		0x20,000
	 *	|			|		   v
	 *	+-----------------------+ 0xDFFFFF
	 *	+-----------------------+ 0xE00000
	 *	|			|		   ^
	 *	| Color Graphics Board  |		0x40,000
	 *	|	(CGB0)		|		   v
	 *	+-----------------------+ 0xE3FFFF
	 *	+-----------------------+ 0xE40000
	 *	|			|		   ^
	 *	| Color Graphics Board  |		0x40,000
	 *	|	(CGB1 | ZOID)	|		   v
	 *	+-----------------------+ 0xE7FFFF
	 *	+-----------------------+ 0xE80000
	 *	|			|		   ^
	 *	| Color Graphics Board  |		0x40,000
	 *	|	(CGB2)		|		   v
	 *	+-----------------------+ 0xEBFFFF
	 *	+-----------------------+ 0xEC0000
	 *	|			|		   ^
	 *	| Color Graphics Board  |		0x40,000
	 *	|	(CGB3)		|		   v
	 *	+-----------------------+ 0xEFFFFF
	 *	+-----------------------+ 0xF00000
	 *	|			|		   ^
	 *	|    RealChip 0         |		0x20,000
	 *	|			|		   v
	 *	+-----------------------+ 0xF1FFFF
	 *	+-----------------------+ 0xF20000
	 *	|			|		   ^
	 *	|    RealChip 1         |		0x20,000
	 *	|			|		   v
	 *	+-----------------------+ 0xF3FFFF
	 *	+-----------------------+ 0xF40000
	 *	|			|		   ^
	 *	|       UNUSED          |		0x90,000
	 *	|			|		   v
	 *	+-----------------------+ 0xFCFFFF
	 *	+-----------------------+ 0xFD0000
	 *	|			|		   ^
	 *	|      RealFast         |		0x30,000
	 *	|			|		   v
	 *	+-----------------------+ 0xFFFFFF
	 *
	 */
#if 1
	/*
	 * Only for 'boardmap[]' testing/debugging.
	 */
	if (boardMapDebug)
		cdebugger("About to initialize memory via 'boardmap'");
#endif


	/*
	 * Reset the cpu and mmu h/w to a known state
	 * so that we are assured of bus errors
	 * for absent physical memory.
	 */
#ifndef	M68020
	V_CLR_ERRS = 0;
#else	M68020

	/*
	 * NOTE:  setErrorReg() requires chipType to be properly set.
	 */
	setErrorReg(0);
#endif	M68020


	saved_jb = nofault;
	nofault  = &jb;

	/*
	 * Find, clear, and free all of memory which
	 * is not already used by the kernel.
	 */
	for (i = mbmbeg; i < mbmend; i++) {	/* For each page... */

		/*
		 * Do not look at addresses reserved
		 * for Valid's memory mapped devices.
		 */
		for (j=0; j < BOARD_COUNT; j++) {
			register struct	boardmap_t *bmp = &boardmap[j];

			if ((((bmp->paddr	     )	>> pageshift) <= i)
			 && (((bmp->paddr + bmp->size)	>> pageshift) >  i)) {

				if (bmp->flags & (BMF_DONTMAP_ATSTARTUP|BMF_IGNORE)) {
					/*
					 * Don't touch this page.
					 */
					goto skip;
				} else {
#ifdef	M68020
				    if (chipType==CHIPTYPE_68020) {
					if (bmp->flags  &   BMF_NONCACHED) {
						setpagemap(i, V_NONCACHED);
						bmp->nonCached = 1;
						goto skip;
					}
#ifdef	DEBUG
					if (goprintmap)
					   printf("page=0x%x  bmp=0x%X  paddr=0x%X  size=0x%X  offset=0x%X  mask=0x%X  value=0x%X  name='%s'  #=%d  flags=%d  nonCached=%d  isopen=%d\n",
						i, bmp,
						bmp->paddr, bmp->size,
						bmp->offset,
						bmp->mask, bmp->value,
						bmp->name,
						bmp->number, bmp->flags,
						bmp->nonCached, bmp->isopen);
#endif	DEBUG
				    }
#endif	M68020
				    goto skip;
				}
			}
		}

		if (!setjmp(&jb)) {
			if (clearpage(i))
				continue;
			pgslot = i;

asm(" .globl	memCheck");			/* Debugger handle */
asm("memCheck:		");
			if (boardMapDebug && (i == (firstNonPhysMem>>PGSHIFT)))
				cdebugger("Non-existent memory not generating bus error!");
			pagfree(&pgslot,1);
			mbusmem++;
			/*
			 * Make sure that physmem contains the address
			 * just above the last page of physical memory.
			 */
			if (i >= physmem) physmem = i + 1;
		}
skip:	;
	}
	nofault = saved_jb;
#endif WHITE

	/*
	 *  Allocate memory for process #0 page tables
	 *  and u page.
	 *  This must be done here since the kernel stack
	 *  pointer is moved into the u page in locore.s before
	 *  main() is called.  We have been using a dummy U
	 *  page so that bus error information can be saved
	 *  there.
	 */

	*(int *)&Cmap2 = 0;  /* Invalidate so that resume() does not do a
				setpagemap() on it every time */
	/*
	 * Setup the pagetable for proc #0
	 */
	if (pagalloc(&Usrptmap[SWAPPER_SLOTNUM], 1) == 0)
		panic("startup1: proc 0 page table alloc");
	setsysmap(btop(&usrpt[SWAPPER_SLOTNUM]), &Usrptmap[SWAPPER_SLOTNUM], 1);


	/*
	 * Setup the upage for proc #0
	 */
	if (pagalloc(&usrpt[NPTEPG-UPAGES], UPAGES) == 0)
		panic("startup1: proc 0 upage alloc");
	setsysmap(UPAGENUM, &usrpt[NPTEPG-UPAGES], UPAGES);

	if (verbosity>=8)
	   printf("startup1/I-34:setsysmap(UPAGENUM=0x%x, &usrpt[NPTEPG-UPAGES]=0x%x, UPAGES=0x%x)",
		UPAGENUM,
		&usrpt[NPTEPG-UPAGES],
		UPAGES);
	if (verbosity>=8) {
	   printf("=0x%x\n",
		setsysmap(UPAGENUM, &usrpt[NPTEPG-UPAGES], UPAGES));
	} else
		setsysmap(UPAGENUM, &usrpt[NPTEPG-UPAGES], UPAGES);



	printf("%d Kbytes real memory ", (ctob(localmem+mbusmem)) >> 10);

#ifndef	WHITE
	printf("(%d Kbytes local, %d Kbytes multibus)\n",
		 ctob(localmem) >> 10,
		 ctob(mbusmem)  >> 10);
#endif	WHITE
}

/*
 * This is the second half of the startup code.
 * It allocates tables and frees memory.
 * It is called from main() and is running
 * on a stack in a real U page.
 */
startup()   /* Called from 'start()' (machine/locore.s) -- stack @ DUMMYU_PA */
{
/*A5*/	A_V_CONTEXT;				/* Allocate register-var*/
	register int		unixsize;
	register unsigned	i;
	register struct pte	*pte;
	int			mapaddr;
#ifndef WHITE
	struct	pte		wastepage;
#endif WHITE
	register caddr_t	v;
	int			maxbufs, base, residual;
	register int		dev = 0;
	char			s[64];
	register struct	cdevsw	*cp;
#ifdef	STARTUP_SIZING
	extern	usrptsize;
	extern	maxusers;
	extern	maxuprc;	/* Max users per process group	*/
	extern	nmount;
	extern	nport;
#endif	STARTUP_SIZING

	/*
	 * Initialize error message buffer (at end of core).
	 */
#ifdef	s32
	/*
	 * We don't have to allocate an exact
	 * clicks worth of memory to the message
	 * buffer since our new meminit (vm_mem.c)
	 * will not allocate the click if any
	 * page of it is used.
	 */
	/* BUG not at end of memory */
	pagalloc(&msgbufmap[0], btop(sizeof(struct msgbuf)+NBPG-1));
	setsysmap(btop(&msgbuf), &msgbufmap[0],
					btop(sizeof(struct msgbuf)+NBPG-1));
	vax_mapen = 1;    /* Enable buffering of console messages */
#else	s32
	maxmem -= btoc(sizeof (struct msgbuf));
	pte = msgbufmap;
	for (i = 0; i < btoc(sizeof (struct msgbuf)); i++)
		*(int *)pte++ = PG_V | PG_KW | (maxmem + i);
	mtpr(TBIA, 1);
#endif	s32

	/*
	 * Good {morning,afternoon,evening,night}.
	 */
	printf("real mem  = %d\n", ptob(nfreepages));
	
	/*
	 * Determine how many buffers to allocate.
	 * Use 10% of memory, with min of 16.
	 * We allocate 1/2 as many swap buffer headers as file i/o buffers.
	 */
#ifdef	s32
	maxbufs = ((SYSPTSIZE * NBPG) - (int)((etext - start) * 3/2 + start)) /
	    MAXBSIZE;
#else	s32
	maxbufs = ((SYSPTSIZE * NBPG) - (5 * (int)(etext - 0x80000000))) /
	    MAXBSIZE;
#endif	s32
	if (bufpages == 0)
		bufpages = (physmem * NBPG) / 10 / CLBYTES;
	if (nbuf == 0) {
#ifdef	s32
		/*
		 * sbs 850903.  Parameterized 2 in the following computation,
		 * based on differences between s32 and VAX definitions of
		 * MAXBSIZE and CLBYTES.
		 */
		nbuf = bufpages / (MAXBSIZE / CLBYTES);
#else	s32
		nbuf = bufpages / 2;
#endif	s32
		if (nbuf < 16)
			nbuf = 16;
		if (nbuf > maxbufs)
			nbuf = maxbufs;
	}
	if (bufpages > nbuf * (MAXBSIZE / CLBYTES))
		bufpages = nbuf * (MAXBSIZE / CLBYTES);
	if (nswbuf == 0) {
		nswbuf = (nbuf / 2) &~ 1;	/* force even */
		if (nswbuf > 256)
			nswbuf = 256;		/* sanity */
	}

	/*
	 * Allocate space for system data structures.
	 * The first available real memory address is in "firstaddr".
	 * As pages of memory are allocated, "firstaddr" is incremented.
	 * The first available kernel virtual address is in "v".
	 * As pages of kernel virtual memory are allocated, "v" is incremented.
	 * An index into the kernel page table corresponding to the
	 * virtual memory address maintained in "v" is kept in "mapaddr".
	 */
#ifdef	s32
	/*
	 * The first usable address is after the
	 * kernel text/data/bss, the proc0 page table,
	 * and the proc0 Upage.
	 */
	mapaddr = k_lastpage;
	v = (caddr_t)(mapaddr * NBPG);
#else	s32
	mapaddr = firstaddr;
	v = (caddr_t)(0x80000000 | (firstaddr * NBPG));
#endif	s32

/*
 * Helpfull macros for allocating system data structures.
 */
#define	valloc(name, type, num) \
	    if (!(num)) cdebugger("startup/valloc/E-?: num==0"); \
	    (name) = (type *)(v); (v) = (caddr_t)((name)+(num))
#define	valloclim(name, type, num, lim) \
	    if (!(num)) cdebugger("startup/valloclim/E-?: num==0"); \
	    (name) = (type *)(v); (v) = (caddr_t)((lim) = ((name)+(num)))

#ifdef	s32
	valloc(Bufmap, struct pte, bufpages);
	buffers = (char *)ptob(kvalloc(bufpages));
#else	s32
	valloc(buffers, char, MAXBSIZE * nbuf);
	base = bufpages / nbuf;
	residual = bufpages % nbuf;
	for (i = 0; i < residual; i++) {
		for (j = 0; j < (base + 1) * CLSIZE; j++) {
			*(int *)(&Sysmap[mapaddr+j]) = PG_V | PG_KW | firstaddr;
			clearpage((unsigned)firstaddr);
			firstaddr++;
		}
		mapaddr += MAXBSIZE / NBPG;
	}
	for (i = residual; i < nbuf; i++) {
		for (j = 0; j < base * CLSIZE; j++) {
			*(int *)(&Sysmap[mapaddr+j]) = PG_V | PG_KW | firstaddr;
			clearpage((unsigned)firstaddr);
			firstaddr++;
		}
		mapaddr += MAXBSIZE / NBPG;
	}
#endif	s32
#ifndef	STARTUP_SIZING
	valloc(buf,	struct	buf,	nbuf);
	valloc(swbuf,	struct	buf,	nswbuf);
	valloclim(inode,struct	inode,	ninode,	inodeNINODE);
	valloclim(file,	struct	file,	nfile,	fileNFILE);
	valloclim(proc,	struct	proc,	nproc,	procNPROC);
	valloclim(text,	struct	text,	ntext,	textNTEXT);
	valloc(cfree,	struct	cblock,	nclist);
	valloc(callout,	struct	callout,ncallout);
	valloc(swapmap,	struct	map,	nswapmap = nproc * 2);
	valloc(argmap,	struct	map,	ARGMAPSIZE);
	valloc(kernelmap,struct map,	nproc);
	valloc(mbmap,	struct	map,	nmbclusters/4);
#ifdef	QUOTA
	valloclim(quota, struct	quota,	nquota, quotaNQUOTA);
	valloclim(dquot, struct	dquot,	ndquot, dquotNDQUOT);
#endif	QUOTA

#else	STARTUP_SIZING
	/*
	 * We size the system in terms of
	 * an alterable # of users.
	 * These effectively override
	 * the compile-time values in conf/param.c
	 *
	 * NOTE:  It has been observed that if one of the n-buckets
	 *	  is set to zero, then the data structures can overlap!
	 *	  This will become apparent near the initializaton time
	 *	  for the data structure:  it or a neighbor will walk
	 *	  upon something that it should not...
	 */
	nproc	 =		 20 + procsPerUser * maxusers;	
	ntext	 =		 96 + maxusers;
	ninode	 =	(nproc + 48 + maxusers);
	nfile	 =     ((nproc + 16 + maxusers) << 4) / 10 + 32;
	ncallout = 16 +  nproc;
	nclist	 = 100	       +     (maxusers  << 4);
	nport	 = nproc >> 1;
	usrptsize= nproc;	
#ifdef	QUOTA
	nquota	 =  (maxusers * 9)/procsPerUser	+ 3;
	ndquot	 = ((maxusers * nmount) >> 2)	+ nproc;
#endif	QUOTA
	maxuprc	 = maxuprc>nproc ? nproc : maxuprc;	/* Stay within uprbnd */

	/*
	 * We have allocated Usrptmap to be modestly
	 * larger than we will ever need:  c.f., machine/{vmparam.h,locore.s}
	 * However, check it!
	 */
	if (usrptsize>USRPTSIZE) {
		printf("(usrptsize=%d) > (USRPTSIZE=%d)\n", usrptsize, USRPTSIZE);
		panic("startup/I-36:startup: usrptsize(==nproc) too large: Usrptmap too small.");
	}

	valloc(buf,	 struct	buf,	nbuf);
	valloc(swbuf,	 struct	buf,	nswbuf);
	valloclim(proc,	 struct	proc,	nproc,	procNPROC);
	valloclim(inode, struct	inode,	ninode,	inodeNINODE);
	valloclim(file,	 struct	file,	nfile,	fileNFILE);
	valloclim(text,	 struct	text,	ntext,	textNTEXT);
	valloc(cfree,	 struct	cblock,	nclist);
	valloc(callout,	 struct	callout,ncallout);
	valloc(swapmap,	 struct	map,	nswapmap = nproc * 2);
	valloc(argmap,	 struct	map,	ARGMAPSIZE);
	valloc(kernelmap, struct map,	nproc);
	valloc(mbmap,	 struct	map,	nmbclusters/4);
#ifdef	QUOTA
	valloclim(quota, struct	quota, nquota,	quotaNQUOTA);
	valloclim(dquot, struct	dquot, ndquot,	dquotNDQUOT);
#endif	QUOTA
#endif	STARTUP_SIZING

#ifdef	s32
	/*
	 * Now allocate space for core map
	 * We cannot subtract the space used by the kernel
	 * since there may be some free pages below the
	 * beginning of it.  This only accounts for an extra
	 * 0x20000 in the numerator below or approximately
	 * 32/CLSIZE extra cmaps if there is NO memory below the
	 * kernel.
	 */
	/* ncmap = physmem*NBPG / (NBPG*CLSIZE + sizeof(struct cmap)); */

	ncmap = physmem / CLSIZE + 1;
#else	s32
	/*
	 * Now allocate space for core map
	 * Allow space for all of phsical memory minus the amount 
	 * dedicated to the system. The amount of physical memory
	 * dedicated to the system is the total virtual memory of
	 * the system minus the space in the buffers which is not
	 * allocated real memory.
	 */
	ncmap = (physmem*NBPG - ((int)v &~ 0x80000000) +
		(nbuf * (MAXBSIZE - 2 * CLBYTES))) /
		    (NBPG*CLSIZE + sizeof (struct cmap));
#endif	s32
	valloclim(cmap, struct cmap, ncmap, ecmap);

	printf("sysptsize = 0x%x, 0x%x used\n", SYSPTSIZE, btop(ecmap)+1);
	printf("kvsize    = 0x%x, 0x%x used\n", KVSIZE, KVBASE+Syssize);

	/*
	 * Document what the upperbounds and allocations are
	 * for this configuration of memory and users.
	 */
	printf("nproc=%d ntext=%d ninode=%d nfile=%d ncallout=%d nclist=%d\n",
		nproc,   ntext,   ninode,   nfile,   ncallout,   nclist);
	printf("ncmap=%d nbuf=%d nswbuf=%d nquota=%d ndquot=%d maxuprc=%d usrptsize=%d\n",
		ncmap,   nbuf,   nswbuf,   nquota,   ndquot,   maxuprc,   usrptsize);

	if ((int)(ecmap+1) > SYSPTSIZE*NBPG)
		panic("startup/E-37: sys pt too small");
#ifdef	s32
	if (KVBASE+Syssize > KVSIZE)
		panic("startup/E-38: kernel virtual space too big");

	/*
	 * systop is the top of the non-user virtual space
	 * which is available to the kernel.  It is
	 * decremented by any driver which needs virtual
	 * address space.
	 */
	systop = KVSIZE - UPAGES;	/* in pages */

	/*
	 * Clear allocated space, and make r/w entries
	 * for the space in the kernel map.
	 */
	unixsize = btoc((int)(ecmap))+1;
	physpagalloc(&Sysmap[mapaddr], unixsize - mapaddr, mapaddr);
	setsysmap(btop(&Sysbase) + mapaddr, &Sysmap[mapaddr], unixsize-mapaddr);

	/*
	 * Allocate and map physical memory for
	 * the buffers.  We do this after the other
	 * allocation since we don't care whether or
	 * not the pages map virtual to physical memory
	 * one-to-one.
	 */
	pagalloc(Bufmap, bufpages);
	setsysmap(btop(buffers), Bufmap, bufpages);

	/*
	 * Set up the initial mapping registers and
	 * their shadows in the proc 0 upage.
	 */
	setp0br(&usrpt[SWAPPER_SLOTNUM]);
	setp0lr(0);
	/*
	 * Uses 'normalMmuIndx'
	 */
	setp1br(initP1br(&usrpt[NPTEPG]));
	setp1lr(mmu_sizing[normalMmuIndx].mmu_p1pages - HIGHPAGES);
	u.u_pcb.pcb_szpt = CLSIZE;

	if (nfreepages <= 8*UPAGES)
		panic("no memory");
#else	s32
	unixsize = btoc((int)(ecmap+1) &~ 0x80000000);
	for (i = mapaddr; i < unixsize; i++) {
		*(int *)(&Sysmap[i]) = PG_V | PG_KW | firstaddr;
		clearpage((unsigned)firstaddr);
		firstaddr++;
	}
	if (firstaddr >= physmem - 8*UPAGES)
		panic("no memory");
	mtpr(TBIA, 1);
#endif	s32

	/*
	 * Uses 'normalMmuIndx'
	 */
	setp1br(initP1br(&usrpt[NPTEPG]));

	/*
	 * Initialize callouts
	 */
	callfree = callout;
	for (i = 1; i < ncallout; i++)
		callout[i-1].c_next = &callout[i];

	/*
	 * Initialize memory allocator and swap
	 * and user page table maps.
	 *
	 * THE USER PAGE TABLE MAP IS CALLED ``kernelmap''
	 * WHICH IS A VERY UNDESCRIPTIVE AND INCONSISTENT NAME.
	 */
#ifdef	s32
	/*
	 * The arguments are the lowest possible free
	 * page and the one greater than the highest
	 * possible free page.  Note that not all
	 * pages between the two (including the two)
	 * are free.
	 */
#ifndef WHITE
	if (pagalloc(&wastepage, 1) == 0)
		panic("startup/E-39: wastepage");
#endif WHITE
	meminit(0, physmem);
#else	s32
	meminit(firstaddr, maxmem);
#endif	s32
	maxmem = freemem;
	printf("avail mem = %d\n", ctob(maxmem));
	printf("using %d buffers containing %d bytes of memory\n",
		nbuf, bufpages * CLBYTES);
#ifdef BSDBUGFIX
#ifndef	STARTUP_SIZING
	rminit(kernelmap, (long)USRPTSIZE-1, (long)1,
#else	STARTUP_SIZING
	rminit(kernelmap, (long)usrptsize-1, (long)1,
#endif	STARTUP_SIZING
#else BSDBUGFIX
#ifndef	STARTUP_SIZING
	rminit(kernelmap, (long)USRPTSIZE, (long)1,
#else	STARTUP_SIZING
	rminit(kernelmap, (long)usrptsize, (long)1,
#endif	STARTUP_SIZING
#endif BSDBUGFIX
	    "usrpt", nproc);
	rminit(mbmap, (long)((nmbclusters - 1) * CLSIZE), (long)CLSIZE,
	    "mbclusters", nmbclusters/4);

	/*
	 * Configure the system.
	 */
#ifdef	s32
	/*
	 * Enable interrupts.
	 */
#ifndef	M68020
	V_STATUS   |= V_ENINT;
#else	M68020
	orStatusReg(V_ENINT);
#endif	M68020

	configure();

#ifndef WHITE
	/*
	 * Print out a picture of memory and
	 * do some device dependent allocation
	 * for VALID's "invented-here" hardware.
	 *
	 * BUG: The allocation belongs in the respective drivers.
	 *
	 * This must be called after meminit since it calls palloc
	 * to get pages of memory.
	 */
	s32meminit(wastepage.pg_pfnum);
	memfree(&wastepage, 1, 1/*Detach*/);	/* Release the wasepage */
#endif	WHITE

#ifdef	USE_CTXT
	/*
	 * Initialize the context resources.
	 */
	ctxt_init();

#endif	USE_CTXT

	/*
	 *  Autoconfigure devices.
	 *
 	 *  Each device driver includes an autoconfiguration routine
	 *  that determines if the device is present and does any
	 *  one-time initilization.
	 */

#ifdef	DEBUG
#ifdef	BAB
	/*
	 * BAB no longer defined.
	 * Must map address before accessing
	 */
	if (debug & D_BAB)	/* start bus analyzer board recording */
		BABstatus |= (BABGOMSK|BABGREENLEDBIT);  /* all references */
#endif	BAB
#endif	DEBUG

	/* Initialize devices */

	cp = cdevsw;

	for (i=0; i<nchrdev; ++i) {
		if (*cp->d_init) {
#ifdef DEBUG
			if (debug & D_MAIN) 
				printf("\ninitdev %x", cp);
#endif DEBUG
			(*cp->d_init)(makedev(i, 0));
		}
		cp++;
	}

	printf("%d pages used for kernel virtual area; %d pages wasted\n",
		maxpage+1-kvarea, kvarea-((kvarea >> PTOSSHIFT) << PTOSSHIFT));
	printf("top of user stack is 0x%x\n", usrStack);

#ifdef	DEBUG
	if (manualboot)
	{
		char inbuf[32];

		printf("\nDebug [0x%x]? ", debug);
		gets(inbuf);
		if (*inbuf)
		{
			register char *cp = &inbuf[0];

			debug = 0;
			while (*cp)
				debug = debug*16 | ctox(*cp), ++cp;
		}
		rootdev = getdev("Root", rootdev);
	}
#endif	DEBUG

#ifdef	WHITE
	sysinit();
#ifdef	REALNIRQL
	appleinit();
#else	REALNIRQL
	lvl1init();
#endif	REALNIRQL
#endif	WHITE

#else	s32
	configure();
	/*
	 * Clear restart inhibit flags.
	 */
	tocons(TXDB_CWSI);
	tocons(TXDB_CCSI);
#endif	s32
}	

#ifdef WHITE
/*
 * Kernel initialization functions. Called from machdep.c
 * before going to spl0 in the kernel.
 */
sysinit()
{
	extern int dsbase;
	extern char kb_ctlcode, kb_venctl;

	/*
	 * Initialize the via
	 */
	VIAADDR->v_acr = ACR_SR0|ACR_T1FR;
	VIAADDR->v_ier = I_CLR|I_CA2|I_CA1|I_SR|I_CB2|I_CB1|I_T2;
	VIAADDR->v_ier = I_SET|I_T1;
	VIAADDR->v_ddra = A_XOR;
	VIAADDR->v_ddrb = B_CH1|B_CH0|B_VADDR1|B_VADDR0|B_VOFF;
	VIAADDR->v_rb = (dsbase>>16) & (B_VADDR1|B_VADDR0);
					/* select video page */
	/* kb_ctlcode = kb_venctl; */
#if 0
	/*
	 * The clock is now initialized in
	 * startrtclock()
	 */
	VIAADDR->v_t1ll = CLKCOUNT;
	VIAADDR->v_t1lh = CLKCOUNT >> 8;
	VIAADDR->v_t1ch = CLKCOUNT >> 8;

	/* ominit() is to be called from cinit -- sbs */
	/* BUG need omxinit next */
	/* omxinit(); */
#endif 0
}
#endif	WHITE

#ifdef	DEBUG
/*
 * Allow the device being used for some
 * function to be changed at boot time.
 */
getdev(name, dev)
	char	*name;
	dev_t	dev;
{
	for (;;)
	{
#ifdef	WHITE
		cdebugger("getdev");
#else	WHITE
		char inbuf[32];

		printf("%s on which device [rim%d%x]? ",
			name, minor(dev) >> 4, minor(dev) & 0xF);
		gets(inbuf);
		if (inbuf[0] == 'r' && inbuf[1] == 'i' && inbuf[2] == 'm' &&
		    '0' <= inbuf[3] && inbuf[3] <= '7' &&
		    ctox(inbuf[4]) != -1 && inbuf[5] == '\0')
			return(makedev(major(dev),
				       (((inbuf[3]-'0')<<4) + ctox(inbuf[4]))));
		else if (*inbuf == '\0')
			return(dev);
		printf("Device must be rim[0-7][0-f].\n");
#endif	WHITE
	}
}

ctox(c)
   register char c;
{
	if ('0' <= c && c <= '9')
		return(c - '0');
	else if ('a' <= c && c <= 'f')
		return(c - 'a' + 10);
	return(-1);
}

gets(cp)
   char *cp;
{
	register char *lp = cp;
	register c;

	for (;;)
	{
		switch (c = getchar())
		{
		case '\n':
		case '\r':
			*lp++ = '\0';
			return;
		case '\b':
		case '#':
			if (lp > cp)
				--lp;
			break;
		case '@':
		case 'u' & 037:
		case 'x' & 037:
			lp = cp;
			cnputc('\n');
			break;
		default:
			*lp++ = c;
			break;
		}
	}
}
#endif	DEBUG

/*
 * This procedure inits the segment map giving
 * appropriate access permissions.
 *
 * kvinit() has been generalized
 * to be callable from ctxt_deMux()
 * whereby "shadowed" contexts get
 * their segment and page tables properly reset.
 *
 * ASSUMPTION: The proper MMU bits in the STATUS
 * register have been (or are still) set by/at this time.
 */

kvinit(context, segBias, nSegs)
	int	context;		/* Context to be mapped		*/
	int	segBias;		/* Segment # bias: 0==> No bias	*/
	int	nSegs;			/* Size of the segment map	*/
{
	register unsigned int	j;
	extern   unsigned short	getsegmap(), setsegmap();
	extern   u_short	getSegMap(), setSegMap();
	extern	 char		end[];


#ifdef WHITE
#if 0
	whitemapinit();
#endif 0
	/*
	 * For now we set the segment maps to a
	 * 1 to 1 mapping.
	 */
	for (j=0; j<nsegs; ++j)
		setsegmap(ALLCTXT, j<<segshift, j | V_SKERNEL);
#endif WHITE

	/*
	 * Seg KERNEL access to segments BELOW kernel
	 * TEXT/DATA/BSS.  Maintain the current mapping,
	 * but insure the desired protections.
	 * This does NOT work: kernel needs R/W/E and user only READ access:
	 *	Kernel 'faults' somewhat further along before making it
	 *	to the "n Kbytes real memory" console msg.
	 */
#ifdef	LATER
	j = 0;
	setsegmap(ALLCTXT, j << segshift,
		(getsegmap(SYSCTXT,j << segshift) & SEG_PAGE) | V_SKERNEL);
#endif	LATER
	/*
	 * Allow read/write/execute access
	 * for the remainder, only to the kernel.
	 * Bypass the process dependent mmu_sizing information
	 * and simply use the global touchstones instead.
	 * Ditto for subsequent invocations of getSegMap()
	 * and setSegMap() herein.
	 */
	for (j=1; j < btos(K_A); j++)
	    setSegMap(	context,
			j << segshift,
			(getSegMap(SYSCTXT, j << segshift, nSegs) & SEG_PAGE)
			+ segBias | V_SKERNEL,

			nSegs
		     );

	/*
	 * Write protect segments entirely in kernel
	 * text space.
	 */
	for (; j < ((int)etext >> segshift); j++)
	    setSegMap(	context,
			j << segshift, 

			(getSegMap(SYSCTXT, j << segshift, nSegs) & SEG_PAGE)
			/*+ segBias*/ | V_SREAD|V_SEXEC,

			nSegs
		     );
	/*
	 * Kernel access to all of remaining (upper) memory,
	 * including user space.
	 */
	if (!segBias) {		/* Onetime, only! */
		/*
		 * Once only we set the nether portions
		 * of the segment map to a 1:1 mapping.
		 *
		 * NOTE:  Neither the u-page or proc[0] have
		 * been initialized yet.
		 * However the mmu_sizing info needed
		 * by getsegmap() and setsegmap() is kept
		 * in the process entry,
		 * the current-proc being selected via u.u_procp
		 *
		 * BUG:	aka KLUDGE: Use getSegMap() and setSegMap() variants,
		 * together with 'nSegs', all of which make no use
		 * of the mmu_sizing table.
		 *
		 * NOTE:  The lexical override of 'nSegs'
		 */
		for (j = (k_lastpage >> PTOSSHIFT); j < nSegs; j++)
		    setSegMap(	context,
				j<<segshift,
				/*segBias +*/ j | V_SKERNEL,
				nSegs);
	}


#ifndef USE_CTXT
#ifdef	s32
	/*
	 * Allow the user to access the top segment
	 * of memory so he can use the 16 bit addressing
	 * mode on the 68000.
	 * (C.f., h/map.h for SEG_AURW definition, which requires s32/cpu.h)
	 * BUG: nsegs is different for nonhomogeneous virt. address spaces.
	 */
	setSegMap(	context,
			(nSegs-1) << segshift,

			(getSegMap(	SYSCTXT,
					(nSegs-1) << segshift,
					nSegs)
			& SEG_PAGE)

			+ segBias | SEG_AURW, nSegs);
#endif s32
#endif USE_CTXT

#ifdef	COMPILERBUG
	/*
	 * Map the pages in the GAP between the end of kernel TEXT
	 * and the start of the USER TEXT, to a benign page.
	 */
	for (j=btop((int)end - 1) + 1; j < usrbase; ++j) {
		/*
		 * Ostensively we never write to this page.
		 * Recalling Murphy's Law, that may not be true.
		 */
		setpagemap(j, btop(MAPONLY_PAGE) | mbmem);
	}

	/*
	 * Map all the the potential user TEXT+DATA+STACK pages.
	 * Also take care not to "runaway on the topend."
	 */
	for (j = usrbase; j < usrTop && j < MAXPHYSMEM_PAGES; ++j)
		setpagemap(j + (segBias<<PTOSSHIFT), V_PAGE_INVALID);

#ifdef s32	/*MAPUPPER64K*/
	for (j=(maxpage + 1) - SEGSIZE/NBPG; j <= maxpage; ++j)
		setpagemap(j + (segBias<<PTOSSHIFT), V_PAGE_INVALID);
#endif s32	/*MAPUPPER64K*/
#else COMPILERBUG
	/*
	 * Unmap all pages that are above end.
	 */
	for (j=btop((int)end - 1)+1; j <= maxpage && j < MAXPHYSMEM_PAGES; ++j)
		setpagemap(j, V_PAGE_INVALID);
#endif	COMPILERBUG
}

#define MAXFREE		PHYSMEMPAGES		/* Up to 16Mb of phys memory */
#define FREETSIZE	(MAXFREE/FREETBITS)	/* Entries in free table */
#define FREETBITS	(sizeof(u_long)*NBBY)	/* Bits in each entry */
#define FREETMASK	(FREETBITS-1)
#define FREETSHFT	5			/* log2(FREETBITS) */

u_long	freepages[FREETSIZE];	/* Bit map of free pages */


/*
 * pagalloc -- Page allocation of physical memory.
 *
 * Allocate count pages from physical memory into
 * the pte(s) pointed to by pte.  Make them
 * kernel writeable.
 */
pagalloc(pte, count)
   register struct pte *pte;
   register int		count;
{
	register u_long	mask  = 1;
	register int	index = 0;
	register int	page;

	if (count > nfreepages)
		return(0);
	/*
	 * We allocate pages "in the large",
	 * from left-to-right:
	 * 'page' monotonically ascends.
	 */
	for (page=0; page<MAXFREE; ++page, mask<<=1) {
		if (mask == 0)
			++index, mask = 1;
		if (freepages[index] == 0)
			mask <<= FREETBITS - 1, page += FREETBITS - 1;
		else if (freepages[index] & mask) {
			/*
			 * However we allocate pages "in the small",
			 * from right-to-left within a 32-bit group,
			 * merely for computational convienience, ie,
			 * the mask-bit moves right-to-left.
			 */
			freepages[index] &= ~mask;
			*(int *)pte++ = page | PG_V | PG_KW;
			--nfreepages;
			if (--count == 0)
				return(1);
		}
	}
	panic("pagalloc");
}

/*
 * Allocate pages like pagalloc but make sure
 * that each virtual page is mapped to the
 * physical page with the same number.
 */
physpagalloc(pte, count, page)
   register struct pte *pte;
   register int		count;
   register int		page;
{
	register u_long mask  = 1 << (page & FREETMASK);
	register int	index = page >> FREETSHFT;

	if (count > nfreepages)
		return(0);
	for (; count--; ++page, mask<<=1) {
		if (mask == 0)
			++index, mask = 1;
		if ((freepages[index] & mask) == 0)
			panic("physpagalloc");
		freepages[index] &= ~mask;
		*(int *)pte++ = page | PG_V | PG_KW;
		--nfreepages;
	}
	return(1);
}

/*
 * ispagfree  --  Return 1 if the specified page is free or 0 if not.
 *
 * Always return 0 for invalid
 * page numbers.
 */
ispagfree(page)	/* Return 1 if the specified page is free or 0 if not. */
/*D7*/	register int	page;
{
/*D6*/	register int	freetShft	= FREETSHFT;
/*D5*/	register int	freetMask	= FREETMASK;

	if (page < 0 || MAXFREE <= page)
		return(0);
	if (freepages[page >> freetShft] & (1 << (page & freetMask)))
		return(1);
	return(0);
}

/*
 * pagfree  --  Free n pages into the physical page map.
 *
 * pte points to the page table
 * entries for the freed pages.
 */
pagfree(entryp, count)	/* Free n pages into the physical page map */
/*A5*/	register u_short	*entryp;
/*D7*/	register int		 count;
{
/*D6*/	register int		 freetShft	= FREETSHFT;
/*D5*/	register int		 freetMask	= FREETMASK;

	while (count--)
	{
/*A4*/		register int	pf	= *entryp;
/*D4*/		register u_long	mask	= 1 << (pf & freetMask);
/*D3*/		register int	index	= pf >> freetShft;

		if (pf >= MAXFREE)
			panic("pagfree: pf >= MAXFREE");
		if (freepages[index] & mask)
			panic("pagfree: dup free");
		freepages[index] |= mask;
		++nfreepages;
		++entryp;
	}
}

/*
 * Allocate more virtual memory for the kernel
 * from the top of memory.  The space is allocated
 * by the page, but user space is decreased by
 * the segment.  Return the page number of the
 * base of the virtual space.  Recompute the
 * new top of the user area.
 */
kvalloc(count)
   int count;
{
	register int	i;
	int	page;

	kvarea	-= count;
	page	 = kvarea;
	/*
	 * Must synchronize 'suregp1lr' with 'p1pages'.
	 * Thought that we could trust the device drivers,
	 * but we can't...
	 * Since we have mucked with p1pages we need to reset the values
	 * of p1br and p1lr since they are inheirited from proc 0 by
	 * proc 2.  If this is not done, then when proc 2 is created
	 * vgetu will recalculate p1br based on this new "lower" value of
	 * p1pages and not change the value of p1lr.  The only time p1lr
	 * is recalculated is if a process has a stack.  Since the only
	 * process which will never grow a stack is proc 2, it will retain
	 * the improperly calculated value for p1lr.  This can lead to
	 * Kernel Mode Bus Error(s) [One per boot] near the end of sureg.
	 *
	 * ELP - 3/14/86
	 */
	p1Pages	 = ((kvarea >> PTOSSHIFT) << PTOSSHIFT);

	/*
	 * Must synchronize 'suregp1lr' with 'p1pages'.
	 * Thought that we could trust the device drivers,
	 * but we can't...
	 */
	setp1br(initP1br(&usrpt[NPTEPG]));
	setp1lr(p1Pages - HIGHPAGES);
	usrTop	 = p1Pages - HIGHPAGES;
	usrStack = ptob(usrTop);

	/*
	 * Now the stuff that does depend
	 * upon virtual address space size.
	 */
	for (i=0; i <= MMU_MAX_INDX; i++)
	{	register struct mmu_sizing_t	* mmup = &mmu_sizing[i];

	   mmup->mmu_kvarea    -= count;

	   /*
	    * 'p1pages' is truncated to whole segments.
	    */
	   mmup->mmu_p1pages	= (mmup->mmu_kvarea >> PTOSSHIFT)
						    << PTOSSHIFT;
	   mmup->mmu_usrtop	= mmup->mmu_p1pages - HIGHPAGES;
	   mmup->mmu_usrstack	= ptob(mmup->mmu_usrtop);
	}

	/*
	 * PHYSICAL limit on the # of segment maps available.
	 * NOTE: ptos() rounds up; PTOS() does not.
	 */
	maxPSmapsAvail	= PTOS(   mmu_sizing[MMU_16MB].mmu_kvarea
				- mmu_sizing[MMU_16MB].mmu_usrbase
				- 1
			      );
	return(page);
}

/*
 * Allocate kernel virtual memory for all the
 * needed areas using kvalloc.
 */
allocvmem()
{
	register int	i;
#ifndef	STARTUP_SIZING
	usrpt = (struct pte *)ptob(kvalloc(USRPTSIZE));
	mbutl = (struct mbuf *)ptob(kvalloc(NMBCLUSTERS*CLSIZE));
#else	STARTUP_SIZING
	usrpt = (struct pte  *)ptob(kvalloc(usrptsize));
	mbUtl = (struct mbuf *)ptob(kvalloc(nmbclusters*CLSIZE));

	/*
	 * Relativize the 'mbutl' and 'usrpt' references
	 * for all of the virtual address spaces.
	 *
	 * NOTE:  The allocations were made from the kernel area
	 * near the TOP of the particular virtual address space.
	 * Hence, those accesses DO depend upon the virtual address space size
	 * from which the reference is made.
	 *
	 * We compute the respective deltas for 'mbutl' and 'usrpt'
	 * from the 'normalMmuIndx'-ith virtual address space.
	 * Then we meld those deltas with the upperbound
	 * for each of every address space.
	 */
	i = normalMmuIndx;
	{	register struct mmu_sizing_t	* mmup = &mmu_sizing[i];
		register u_long	deltaM	= (u_long)mmup->mmu_ctxtMaxVaddr  
					- (u_long)mbUtl;
		register u_long	deltaU	= (u_long)mmup->mmu_ctxtMaxVaddr 
					- (u_long)usrpt;

	   for (i=0; i <= MMU_MAX_INDX; i++) {
		register u_long	maxVaddr;

	   	mmup		= &mmu_sizing[i];
		maxVaddr	= (u_long)mmup->mmu_ctxtMaxVaddr;
		mmup->mmu_usrpt	= (struct pte *)(maxVaddr - deltaU);/*...Meld */
		mmup->mmu_mbutl	= (struct mbuf*)(maxVaddr - deltaM);
	   }
	}
#endif	STARTUP_SIZING
}

#ifdef WHITE
/*
 * The following function initializes the map
 * under the WHITE kernel to identity in all
 * sixteen contexts and in both user and
 * supervisor modes.  It does this by copying
 * some code into the static RAM (which resides
 * in ALL contexts) to do the work.
 */
whitemapinit()
{
	extern mapcode(), endmapcode();

	bcopy((caddr_t)mapcode, 0x800000, (int)endmapcode - (int)mapcode);
	(*(int (*)())0x800000)();
}

/*
 * The map code is called as a function, but
 * it is location independent so we don't have
 * to worry about its load address versus its
 * execution address.
 */
asm("	.data			");
asm("	.globl	mapspsave	");

asm("mapspsave: .long 0		");

asm("	.text			");
asm("	.globl	mapcode		");
asm("	.globl	endmapcode	");

asm("mapcode:			");
asm("	movl	sp,mapspsave	");	/* Save the stack pointer */
asm("	movl	#0x801000,sp	");	/* Put stack at top of static RAM */

asm("	movb	#0x80,d0	");	/* V_MAPACC */
asm(".ctxtloop:			");
asm("	bsr	.doctxt		");	/* Set kernel map for this context */
asm("	eorb	#0x10,d0	");	/* Set V_ACCUSER */
asm("	bsr	.doctxt		");	/* Set user map for this context */
asm("	eorb	#0x10,d0	");	/* Clear V_ACCUSER */
asm("	addqb	#1,d0		");	/* Go to next context */
asm("	cmpb	#0x90,d0	");	/* Last? */
asm("	jne	.ctxtloop	");	/* No, go do next context */

asm("	movb	#0,0x840003	");	/* Guarantee kernel context 0 */
asm("	movl	mapspsave,sp	");	/* Restore the stack pointer */
asm("	rts			");	/* And leave the static RAM */
asm("endmapcode:		");

/*
 * This function is called twice for each
 * context (once for user and once for kernel).
 *	D0 contains context register value
 */

asm(".doctxt:			");
asm("	movb	d0,0x840003	");	/* Go to the correct context */
asm("	orb	#0xE0,0x840003	");	/* Set V_ACCSM, V_ACCLOW */
asm("	movw	#0x0700,d1	");	/* Set V_EXEC, V_READ, V_WRITE */
asm("	movl	#400000,a0	");
asm(".lowsloop:			");
asm("	movw	d1,a0@		");	/* Map one segment */
asm("	addl	#0x10000,a0	");
asm("	addqw	#1,d1		");	/* Go to next segment */
asm("	cmpw	#0x740,d1	");	/* Last one? */
asm("	jne	.lowsloop	");	/* No, do another */

asm("	eorb	#0x40,0x840003	");	/* Clear V_ACCLOW */
asm("	movl	#0x400000,a0	");
asm(".highsloop:		");
asm("	movw	d1,a0@		");	/* Map one segment */
asm("	addl	#0x10000,a0	");
asm("	addqw	#1,d1		");	/* Go to next segment */
asm("	cmpw	#0x780,d1	");	/* Last one? */
asm("	jne	.highsloop	");	/* No, do another */

asm("	movb	d0,0x840003	");	/* Go back to V_ACCPM */
asm("	orb	#0x40,0x840003	");	/* Set V_ACCLOW */
asm("	movw	#0x0000,d1	");	/* Initial page map entry */
asm("	movl	#400000,a0	");
asm(".lowploop:			");
asm("	movw	d1,a0@		");	/* Map one page */
asm("	addl	#0x1000,a0	");
asm("	addqw	#1,d1		");	/* Go to next page */
asm("	cmpw	#0x400,d1	");	/* Last one? */
asm("	jne	.lowploop	");	/* No, do another */

asm("	eorb	#0x40,0x840003	");	/* Clear V_ACCLOW */
asm("	movl	#400000,a0	");
asm(".highploop:		");
asm("	movw	d1,a0@		");	/* Map one page */
asm("	addl	#0x1000,a0	");
asm("	addqw	#1,d1		");	/* Go to next page */
asm("	cmpw	#0x800,d1	");	/* Last one? */
asm("	jne	.highploop	");	/* No, do another */

asm("	rts			");

#endif WHITE
