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

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

/*
 * Perform high level startup and initializations.
 *
 */

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

#include "../h/param.h"
#include "../h/systm.h"
#include "../h/dir.h"
#include "../h/quota.h"
#include "../h/user.h"
#include "../h/kernel.h"
#include "../h/fs.h"
#include "../h/mount.h"
#include "../h/map.h"
#include "../h/proc.h"
#include "../h/inode.h"
#include "../h/seg.h"
#include "../h/conf.h"
#include "../h/buf.h"
#include "../h/vm.h"
#include "../h/vmmac.h"		/* usrtop(p) */
#include "../h/cmap.h"
#include "../h/text.h"
#include "../h/clist.h"
#ifdef INET
#include "../h/protosw.h"
#endif
#ifdef s32
#include "../h/nami.h"
#endif s32
#include "../machine/reg.h"
#include "../machine/cpu.h"

#ifdef s32
short		canSyncNow;	/* 0 ==> May NOT update() yet. C.f., panic() */
extern	int	manualboot;
#endif s32

extern	short	proc0Initd;	/* 0 ==> proc[0], upage NOT initialized; */
extern	struct user u;		/* have to declare it somewhere! */
/*
 * Initialization code.
 * Called from cold start routine as
 * soon as a stack and segmentation
 * have been established.
 * Functions:
 *	Clear and free user core
 *	Turn on clock
 *	Hand craft 0th process
 *	Call all initialization routines
 *	fork - process 0 to schedule	(A.K.A. "swapper")
 *	     - process 2 to page out	(A.K.A. "pagedaemon")
 *	     - process 1 execute bootstrap
 *
 * Exception handling:
 *	Loop at loc 0x100022 (USERTEXT+0x22) in user mode -- /etc/init
 *	cannot be executed. C.f., machine/startup.c -- IC_BOOT.
 */
#ifdef s32
main()
#else s32
main(firstaddr)
	int	firstaddr;
#endif s32
{
	register int		 i;
	register struct proc	*p;
	struct	 fs		*fs;
	int			 s;

	rqinit();
#include "loop.h"

#ifdef s32
	startup();
#else s32
	startup(firstaddr);
#endif s32

	/*
	 * set up system process 0 (swapper)
	 */
	p	  = &proc[SWAPPER_SLOTNUM];
	p->p_mmuIndx	    = normalMmuIndx;	/* Initialized in startup1() */
	p->p_mmuStatRegBits = 0;  /* Status reg bits for A<26..24> -> ctxtReg */
	p->p_p0br = u.u_pcb.pcb_p0br;
	p->p_szpt = 1;
	p->p_addr = uaddr(p);
	p->p_stat = SRUN;
	p->p_flag |= SLOAD|SSYS;
	p->p_nice = NZERO;
	setredzone(p->p_addr, (caddr_t)&u);
	u.u_procp = p;
#ifdef s32
	u.u_usrtop = usrtop(p);
	proc0Initd = 1;		/* proc[0], upage are now initialized */
#ifdef UPAGECWD
	*(char *)u.u_stack = '\0';	/* Cwd is root */
#endif UPAGECWD
#endif s32
#ifdef USE_CTXT
	ctxt_invalidate(p);
#endif USE_CTXT
	u.u_cmask = CMASK;
	for (i = 1; i < NGROUPS; i++)
		u.u_groups[i] = NOGROUP;
	for (i = 0; i < sizeof(u.u_rlimit)/sizeof(u.u_rlimit[0]); i++)
		u.u_rlimit[i].rlim_cur = u.u_rlimit[i].rlim_max = 
		    RLIM_INFINITY;
	u.u_rlimit[RLIMIT_STACK].rlim_cur = 512*1024;
	u.u_rlimit[RLIMIT_STACK].rlim_max = ctob(MAXDSIZ);
	u.u_rlimit[RLIMIT_DATA].rlim_max =
	    u.u_rlimit[RLIMIT_DATA].rlim_cur = ctob(MAXDSIZ);
	p->p_maxrss = RLIM_INFINITY/NBPG;
#ifdef QUOTA
	qtinit();
	p->p_quota = u.u_quota = getquota(0, 0, Q_NDQ);
#endif
	startrtclock();
#include "kg.h"
#if NKG > 0
	startkgclock();
#endif

	/*
	 * Initialize tables, protocols, and set up well-known inodes.
	 */
	mbinit();
	cinit();			/* needed by dmc-11 driver */
#ifdef INET
#if NLOOP > 0
	loattach();			/* XXX */
#endif
	/*
	 * Block reception of incoming packets
	 * until protocols have been initialized.
	 */
	s = splimp();
	ifinit();
#endif
	domaininit();
#ifdef INET
	splx(s);
#endif
	ihinit(); /* Init hash links for inodes and build inode free list.  */
	bhinit(); /* Init hash links for buffers.			    */
	binit();  /* Init the buffer I/O system.			    */
	bswinit();/* Init linked list of free swap headers.		    */
#ifdef s32
	canSyncNow = -1;		/* ~0 ==> Safe to update() now */
#endif s32
#ifdef GPROF
	kmstartup();
#endif

	fs = mountfs(rootdev, 0, (struct inode *)0);
	if (fs == 0)
		panic("iinit");
	bcopy("/", fs->fs_fsmnt, 2);

	inittodr(fs->fs_time);
	boottime = time;

	/*
	 * Kick off timeout driven events
	 * by calling first time
	 */
	roundrobin();
	schedcpu();
	schedpaging();
#ifdef s32
	scanpcmem();
#endif s32

	/*
	 * Set up the root file system
	 */
#ifndef	VALID_DFS
	rootdir = iget(rootdev, fs, (ino_t)ROOTINO);
#else	VALID_DFS
	rootdir = iget(rootdev, fs, (ino_t)ROOTINO, 0/*optional_host*/);
#endif	VALID_DFS
	iunlock(rootdir);
#ifndef	VALID_DFS
	u.u_cdir = iget(rootdev, fs, (ino_t)ROOTINO);
#else	VALID_DFS
	u.u_cdir = iget(rootdev, fs, (ino_t)ROOTINO, 0/*optional_host*/);
#endif	VALID_DFS
	iunlock(u.u_cdir);
	u.u_rdir = NULL;

#ifdef s32
	if (manualboot) {
		swdevt[0].sw_dev = getdev("Swap", swdevt[0].sw_dev);
		swdevt[0].sw_nblks = 0;
		argdev = dumpdev = swdevt[0].sw_dev;
		printf("\nSwapping on ");
	} else {
		/*
		 * Use "/dev/swap" as the first swap device
		 * if it exists, else just use the one compiled
		 * into the kernel in swdevt[0].
		 */
		register struct inode *ip;

		u.u_dirp = "/dev/swap";
		ip = namei(schar, LOOKUP, 1/*follow*/);
		if (ip != NULL) {
			if ((ip->i_mode & IFMT) == IFBLK) {
				swdevt[0].sw_dev = ip->i_rdev;
				swdevt[0].sw_nblks = 0;
				printf("\nSwapping on /dev/swap: ");
			} else
				printf("\n/dev/swap is not a bdev; using ");
			iput(ip);
		} else
			printf("\nNo /dev/swap; using ");
	}
	printf("%s%d%x", bdevsw[major(swdevt[0].sw_dev)].d_name,
		minor(swdevt[0].sw_dev) >> 4,
		minor(swdevt[0].sw_dev) & 0xF);
	/*
	 * Note that for the Valid kernels we must
	 * do swapconf() here (it was already done
	 * by configure()) since the swdevt[0] may
	 * have changed above.
	 */
	swapconf();
	swapinit();
	printf(" (%dK bytes on %d dev%s)\n",
		nswap*DEV_BSIZE/1024, nswdev, (nswdev==1 ? "" : "s"));
#endif s32

	u.u_dmap = zdmap;
	u.u_smap = zdmap;

	/*
	 * Set the scan rate and other parameters of the paging subsystem.
	 */
	setupclock();

	/*
	 * make page-out daemon (process 2)
	 * the daemon has ctopt(nswbuf*CLSIZE*KLMAX) pages of page
	 * table so that it can map dirty pages into
	 * its address space during asychronous pushes.
	 */
	mpid = 1;
#ifdef s32
	proc[SWAPPER_SLOTNUM].p_szpt = clrnd(ctopt(nswbuf*CLSIZE*KLMAX
						+ UPAGES + UWASTE));
#else s32

	proc[SWAPPER_SLOTNUM].p_szpt = clrnd(ctopt(nswbuf*CLSIZE*KLMAX
						+ UPAGES));
#endif s32
	proc[ETC_INIT_SLOTNUM].p_stat = SZOMB;	/* Force it in 2nd proc slot */
	if (newproc(0/*isvfork*/)) {
		proc[PAGE_DAEMON_SLOTNUM].p_flag	|= SLOAD|SSYS;
		proc[PAGE_DAEMON_SLOTNUM].p_dsize	 = u.u_dsize
							 = nswbuf*CLSIZE*KLMAX; 
		pageout();
		/*NOTREACHED*/
	}
#ifdef VALID_RPC
	conn_init();
	rpc_init();
	rpc_serverInit();
	rpc_clientInit();
	rpcsignal_init();
#ifdef VALID_EFS
	efs_init();
#endif VALID_EFS
#ifdef	VALID_BULK
	bulk_init();
#endif	VALID_BULK
#endif VALID_RPC

	/*
	 * make init process and
	 * enter scheduling loop
	 */

	mpid = 0;
	proc[ETC_INIT_SLOTNUM].p_stat = 0;
	proc[SWAPPER_SLOTNUM].p_szpt = CLSIZE;
	if (newproc(0)) {
		expand(clrnd((int)btoc(szicode)), 0);
		(void) swpexpand(u.u_dsize, 0, &u.u_dmap, &u.u_smap);
#ifdef s32
		(void) copyout((caddr_t)icode, (caddr_t)USRTEXT,
			       (unsigned)szicode);
		/*
		 * Return goes to loc. USRTEXT of user init
		 * code just copied out.
		 */
#else s32
		(void) copyout((caddr_t)icode, (caddr_t)0, (unsigned)szicode);
		/*
		 * Return goes to loc. 0 of user init
		 * code just copied out.
		 */
#endif s32
		return;
	}
	proc[SWAPPER_SLOTNUM].p_szpt = 1;
	sched();
}

/*
 * Initialize hash links for buffers.
 */
bhinit()
{
	register int i;
	register struct bufhd *bp;

	for (bp = bufhash, i = 0; i < BUFHSZ; i++, bp++)
		bp->b_forw = bp->b_back = (struct buf *)bp;
}

/*
 * Initialize the buffer I/O system by freeing
 * all buffers and setting all device buffer lists to empty.
 */
binit()
{
	register struct buf *bp, *dp;
	register int i;
#ifndef s32
	struct swdevt *swp;
#endif s32
	int base, residual;

	for (dp = bfreelist; dp < &bfreelist[BQUEUES]; dp++) {
		dp->b_forw = dp->b_back = dp->av_forw = dp->av_back = dp;
		dp->b_flags = B_HEAD;
	}
	base = bufpages / nbuf;
	residual = bufpages % nbuf;
	for (i = 0; i < nbuf; i++) {
		bp = &buf[i];
		bp->b_dev = NODEV;
		bp->b_bcount = 0;
		bp->b_un.b_addr = buffers + i * MAXBSIZE;
		if (i < residual)
			bp->b_bufsize = (base + 1) * CLBYTES;
		else
			bp->b_bufsize = base * CLBYTES;
		binshash(bp, &bfreelist[BQ_AGE]);
		bp->b_flags = B_BUSY|B_INVAL;
		brelse(bp);
	}
#ifdef s32
}
swapinit()
{
	register struct swdevt *swp;

#endif s32
	/*
	 * Count swap devices, and adjust total swap space available.
	 * Some of this space will not be available until a vswapon()
	 * system is issued, usually when the system goes multi-user.
	 */
	nswdev = 0;
	nswap = 0;
	for (swp = swdevt; swp->sw_dev; swp++) {
		nswdev++;
		if (swp->sw_nblks > nswap)
			nswap = swp->sw_nblks;
	}
	if (nswdev == 0)
		panic("binit");
	if (nswdev > 1)
		nswap = ((nswap + dmmax - 1) / dmmax) * dmmax;
	nswap *= nswdev;
	maxpgio *= nswdev;
	swfree(0);
}

/*
 * Initialize linked list of free swap
 * headers. These do not actually point
 * to buffers, but rather to pages that
 * are being swapped in and out.
 */
bswinit()
{
	register int i;
	register struct buf *sp = swbuf;

	bswlist.av_forw = sp;
	for (i=0; i<nswbuf-1; i++, sp++)
		sp->av_forw = sp+1;
	sp->av_forw = NULL;
}

/*
 * Initialize clist by freeing all character blocks, then count
 * number of character devices. (Once-only routine)
 */
cinit()
{
	register int ccp;
	register struct cblock *cp;

	ccp = (int)cfree;
	ccp = (ccp+CROUND) & ~CROUND;
	for(cp=(struct cblock *)ccp; cp < &cfree[nclist-1]; cp++) {
		cp->c_next = cfreelist;
		cfreelist = cp;
		cfreecount += CBSIZE;
	}
}
