/* $Copyright:	$
 * Copyright (c) 1984, 1985, 1986, 1987, 1988, 1989, 1990 
 * Sequent Computer Systems, Inc.   All rights reserved.
 *  
 * This software is furnished under a license and may be used
 * only in accordance with the terms of that license and with the
 * inclusion of the above copyright notice.   This software may not
 * be provided or otherwise made available to, or used by, any
 * other person.  No title to or ownership of the software is
 * hereby transferred.
 */

#ident	"$Header: init_main.c 1.53 90/08/31 $"

/*
 * init_main.c
 *	Final initializations, init/start system processes.
 */

/* $Log:	init_main.c,v $
 */

#include "sys/types.h"
#include "sys/devsw.h"
#include "sys/param.h"
#include "sys/debug.h"
#include "sys/signal.h"
#include "sys/systm.h"
#include "sys/mutex.h"
#include "sys/vfs.h"
#include "sys/user.h"
#include "sys/map.h"
#include "sys/timer.h"
#include "sys/session.h"
#include "sys/proc.h"
#include "sys/conf.h"
#include "sys/buf.h"
#include "sys/vm.h"
#include "sys/cmap.h"
#include "sys/vnode.h"
#include "sys/var.h"
#ifdef QUOTA
#include "sys/ufsquota.h"
#endif
#include "sys/snode.h"
#include "sys/file.h"
#include "sys/cmn_err.h"

#include "sys/engine.h"

#include "sys/pte.h"
#include "sys/plocal.h"
#include "sys/intctl.h"
#include "sys/gate.h"

/*
 * main()
 *	Initialization code.  Unix "main" procedure.
 *
 * Called from cold start routine after basic initializations
 * done (eg, sysinit()).  Running with stack on mapped U-area
 * of proc[0].
 *
 * Functions:
 *	hand craft 0th process
 *	call all initialization routines
 *	fork - process 0 to schedule
 *	     - process 2 to page out
 *	     - process 1 execute bootstrap
 */

main(puarea)
	unsigned puarea;	/* phys (==virt) addr of proc[0] U-block */
{
	register void	(**initptr)();
	extern	void	(*io_init[])();
	extern	void	(*init_tab[])();
	register int 	i;
	register struct proc *p;
	int error;

	rqinit();
	mutexinit();				/* misc locks and semas */

	/*
	 * Set up system process 0 (swapper).  All fields are init'd to
	 * zero in sysinit().
	 */

	p = &proc[0];
	v.ve_proc = &proc[1];		/* init high-water */
	p->p_uarea = UBTOUSER(puarea);
	p->p_stat = SRUN;
	p->p_affinity = ANYENG;
	p->p_flag |= SLOAD|SSYS|SORPH;
	p->p_nice = NZERO;
	/*
	 * Group and session must be zero for newproc.
	 */
	p->p_pgrp = 0;
	p->p_sid = 0;
	/*
	 * This session is inherited by all
	 */
	p->p_session = &sess[0];
	sess[0].s_sid = p->p_sid;
	sess[0].s_pgrp = p;
	sess[0].s_vp = NULL;
	sess[0].s_ctty_count = 0;
	sess[0].s_ctty = NULL;
	init_lock(&sess[0].s_lock);
	init_sema(&sess[0].s_sema, 0);
	p->p_sessf = NULL;
	p->p_sessb = p;
	p->p_pgrpf = p;
	p->p_pgrpb = p;
#ifdef	ns32000
	p->p_upte = &Sysmap[btop(p->p_uarea)];
	setredzone(p->p_upte, (caddr_t)&u);
#endif	/* ns32000  */

	u.u_procp = p;
	u.u_cmask = CMASK;

	l.multprog = -1;			/* don't count proc[2] */

	nullvattr_init();			/* init the "null" vattr */

	/*
	 * Initialize kernel heap memory allocator
	 */
	kmem_init();
	
	/*
	 * Initialize partitioning on the root and primary swap devices,
	 * then configure the primary swap device.
	 */

	rootinit();
	swapconf();

	/*
	 * Setup credentials.
	 */

	ucred_init();
	u.u_cred = crget();
	bzero((caddr_t)u.u_cred, sizeof(*u.u_cred));
	u.u_cred->cr_ref = 1;
	init_lock(&u.u_cred->cr_lock);

	for (i = 1; i < NGROUPS; i++)
		u.u_groups[i] = INVAL_GID;

	u.u_limit = v.v_ulimit; 
	p->p_maxrss = RLIM_INFINITY/CLBYTES;
#ifdef QUOTA
	qtinit();			/* init quota structures */
#endif

	/*
	 * Open a vnode for the swap device.
	 */

	swapdevinit();
	swapdev_vp = bdevvp(swapdev);
	error = VOP_OPEN(&swapdev_vp, FREAD | FWRITE, u.u_cred);
	if (error) {
		cmn_err(CE_PANIC, "main: can't open swapdev, error = %d\n",
					error);
		/*
		 *+ The swap device configured for the kernel cannot 
		 *+ be opened for read/write access.  The error number
		 *+ is reported.  (Refer to <sys/errno.h>.)  Corrective action: 
		 *+ correct the
		 *+ error and/or reconfigure the kernel to use a different
		 *+ swap device.
		 */
	}

	/*
	 * Initialize tables
	 */

	procinit();				/* init proc-list locks/semas */
	ihinit();				/* inode hash/etc inits */
	bhinit();				/* init buffer hash queues */
	binit();				/* init buffer cache headers */
	finit();				/* file-table inits */
	mfinit();				/* mapped file table inits */
	xinit();				/* text inits */
	ptrcinit();				/* init ptrace semas */
	bswinit();				/* init swap buffers */
	dnlc_init();				/* init dir lookup cache */
	flckinit();				/* initialize record locks */
	abufinit();				/* init async I/O buffers */

	/*	Call all system initialization functions.
	*/

	for (initptr= &init_tab[0]; *initptr; initptr++) (**initptr)();
	for (initptr= &io_init[0]; *initptr; initptr++) (**initptr)();

	/*
	 * mount the root, gets rootdir
	 * No need to obtain vfs_mutex since we're the only
	 * processor at this point and no other processes exist.
	 */

	vfs_mountroot();

	boottime = time;
	FW_WDTINIT();			/* initialize the watchdog timer */

	/*
	 * Kick off timeout driven events by calling first time.
	 */

	memerr();			/* polling for memory errors */
	schedcpu();
	timeslice();

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

	u.u_start = time;

	/*
	 * Make init process.
	 */

	mpid = 0;
	proc[1].p_stat = 0;
	proc[1].p_sig = 0;
	proc[1].p_cursig = 0;
	proc[0].p_szpt = SZPT(&proc[0]);	/* so proc[1] gets PT's */
	proc[0].p_rscurr = vmtune.vt_minRS;	/* and a minimal Rset array */
	if (newproc(0)) {

		/*
		 * We are proc[1] at this point, and have U-area and
		 * page-tables.  Now expand and copy out the "init-code"
		 * which will exec /etc/init.
		 */

		(void) vsalloc(&u.u_dmap, 0, u.u_dsize);
		(void) vsalloc(&u.u_smap, 0, u.u_ssize);
		(void) expand((int)clrnd(btoc(szicode)),
				(int)clrnd(btoc(1)), 0, PG_ZFOD);
		(void) copyout(icode, (caddr_t)0, (unsigned)szicode);

		/*
		 * Setup to verify running correct version of system.
		 */

		check_sys(1);

		/*
		 * Return goes to location 0 of user init code
		 * just copied out.
		 */

		return (0);				/* value for lint */
	}

	/*
	 * Make page-out daemon (process 2).
	 *
	 * Ok to create this after creating proc[1] since shouldn't
	 * dispatch (eg, allow [1] to execute) until after pageout()
	 * blocks.  Would be ok anyhow, since would only postpone
	 * start of pageout IO.
	 *
	 * p_dsize of proc[2] is to allow mapping of pages during
	 * pageouts (avoiding races with other concurrent uses of
	 * page-tables).
	 */

	proc[0].p_rscurr = 0;
	proc[0].p_szpt = clrnd(SZL2PT(v.v_pbuf*CLSIZE*KLMAX, 0) + UL1PT_PAGES);
	if (newproc(0)) {
		proc[2].p_flag |= SLOAD|SSYS|SORPH;
		proc[2].p_noswap++;			/* insure no swapping */
		proc[2].p_dsize = u.u_dsize = v.v_pbuf*CLSIZE*KLMAX; 
		bcopy("vhand", u.u_comm, 5);
		bcopy("vhand", u.u_psargs, 6);
		pageout();
		/*NOTREACHED*/
	}

	/*
	 * Enter swap-scheduling loop.
	 */

	proc[0].p_szpt = SZPT(&proc[0]);	/* reflect reality */
	bcopy("sched", u.u_comm, 5);
	bcopy("sched", u.u_psargs, 6);
	sched();
	/*NOTREACHED*/
}

/*
 * procinit()
 *	Init semaphores and locks in each proc table entry.
 */

procinit()
{
	register struct proc *p;
	register int	lkgate;
	extern lock_t zombie_todo;

	/*
	 * Init proc-list locker.  TMP only sema.
	 * and sess-list
	 */

	init_lock(&proc_list);
	init_lock(&sess_list);
	init_lock(&zombie_todo);

	/*
	 * Init the lock's/sema's for each proc entry.
	 */

	for(p = proc, lkgate = 0; p < procNPROC; p++, lkgate++) {
		init_sema(&p->p_pagewait, 0);
		init_sema(&p->p_zombie, 0);
		init_sema(&p->p_vfork, 0);
		init_lock(&p->p_state);
	}
#ifdef	lint
	lint_ref_int(lkgate);
#endif	/* lint  */
}

/*
 * mutexinit()
 *	Init semaphores not yet initialized.
 */

mutexinit()
{
	extern sema_t paused;
	extern sema_t acct_sema;
	extern sema_t tmp_onoff;
	extern sema_t dir_rename_mutex;
	extern sema_t sync_sema;
	extern sema_t uadmin_sema;


	init_sema(&acct_sema, 1);	/* sema for accounting */
 	init_sema(&dir_rename_mutex, 1); /* see direnter() */
	init_sema(&lbolt, 0);		/* sema for lighning bolt */
	init_sema(&paused, 0);		/* sema for sigpause sleep */
 	init_sema(&tmp_onoff, 1);	/* sema for on/off-line */
	init_sema(&vfs_mutex, 1);	/* For mount,umount */
	init_sema(&unmount_mutex, 1);	/* Serialize umounts */
	init_sema(&sync_sema, 1);	/* sync mutex */
	init_sema(&uadmin_sema, 1);	/* uadmin mutex */
}
