it's ours
[unix-history] / usr / src / sys / kern / init_main.c
/*
* Copyright (c) 1982, 1986, 1989, 1991 Regents of the University of California.
* All rights reserved.
*
* %sccs.include.redist.c%
*
* @(#)init_main.c 7.37 (Berkeley) %G%
*/
#include "param.h"
#include "filedesc.h"
#include "kernel.h"
#include "mount.h"
#include "map.h"
#include "proc.h"
#include "resourcevar.h"
#include "signalvar.h"
#include "systm.h"
#include "vnode.h"
#include "seg.h"
#include "conf.h"
#include "buf.h"
#include "clist.h"
#include "malloc.h"
#include "protosw.h"
#include "reboot.h"
#include "user.h"
#include "machine/cpu.h"
#include "vm/vm.h"
/*
* Components of process 0;
* never freed.
*/
struct session session0;
struct pgrp pgrp0;
struct proc proc0;
struct pcred cred0;
struct filedesc0 filedesc0;
struct plimit limit0;
struct vmspace vmspace0;
struct proc *curproc = &proc0;
struct proc *initproc, *pageproc;
int cmask = CMASK;
extern caddr_t proc0paddr;
extern int (*mountroot)();
/*
* System startup; initialize the world, create process 0,
* mount root filesystem, and fork to create init and pagedaemon.
* Most of the hard work is done in the lower-level initialization
* routines including startup(), which does memory initialization
* and autoconfiguration.
*/
main(firstaddr)
int firstaddr;
{
register int i;
register struct proc *p;
register struct filedesc0 *fdp;
int s, rval[2];
/*
* Initialize curproc before any possible traps/probes
* to simplify trap processing.
*/
p = &proc0;
curproc = p;
/*
* Attempt to find console and initialize
* in case of early panic or other messages.
*/
consinit();
vm_mem_init();
kmeminit();
startup(firstaddr);
/*
* set up system process 0 (swapper)
*/
p = &proc0;
curproc = p;
allproc = p;
p->p_prev = &allproc;
p->p_pgrp = &pgrp0;
pgrphash[0] = &pgrp0;
pgrp0.pg_mem = p;
pgrp0.pg_session = &session0;
session0.s_count = 1;
session0.s_leader = p;
p->p_flag = SLOAD|SSYS;
p->p_stat = SRUN;
p->p_nice = NZERO;
bcopy("swapper", p->p_comm, sizeof ("swapper"));
/*
* Setup credentials
*/
p->p_cred = &cred0;
p->p_ucred = crget();
p->p_ucred->cr_ngroups = 1; /* group 0 */
/*
* Create the file descriptor table for process 0.
*/
fdp = &filedesc0;
p->p_fd = &fdp->fd_fd;
fdp->fd_fd.fd_refcnt = 1;
fdp->fd_fd.fd_cmask = cmask;
fdp->fd_fd.fd_ofiles = fdp->fd_dfiles;
fdp->fd_fd.fd_ofileflags = fdp->fd_dfileflags;
fdp->fd_fd.fd_nfiles = NDFILE;
/*
* Set initial limits
*/
p->p_limit = &limit0;
for (i = 0; i < sizeof(p->p_rlimit)/sizeof(p->p_rlimit[0]); i++)
limit0.pl_rlimit[i].rlim_cur =
limit0.pl_rlimit[i].rlim_max = RLIM_INFINITY;
limit0.pl_rlimit[RLIMIT_OFILE].rlim_cur = NOFILE;
limit0.pl_rlimit[RLIMIT_NPROC].rlim_cur = MAXUPRC;
limit0.p_refcnt = 1;
/*
* Allocate a prototype map so we have something to fork
*/
p->p_vmspace = &vmspace0;
vmspace0.vm_refcnt = 1;
pmap_pinit(&vmspace0.vm_pmap);
vm_map_init(&p->p_vmspace->vm_map, round_page(VM_MIN_ADDRESS),
trunc_page(VM_MAX_ADDRESS), TRUE);
vmspace0.vm_map.pmap = &vmspace0.vm_pmap;
p->p_addr = proc0paddr; /* XXX */
/*
* We continue to place resource usage info
* and signal actions in the user struct so they're pageable.
*/
p->p_stats = &((struct user *)p->p_addr)->u_stats;
p->p_sigacts = &((struct user *)p->p_addr)->u_sigacts;
rqinit();
/*
* configure virtual memory system,
* set vm rlimits
*/
vm_init_limits(p);
/*
* Initialize the file systems.
*
* Get vnodes for swapdev, argdev, and rootdev.
*/
vfsinit();
if (bdevvp(swapdev, &swapdev_vp) ||
bdevvp(argdev, &argdev_vp) ||
bdevvp(rootdev, &rootvp))
panic("can't setup bdevvp's");
startrtclock();
#if defined(vax)
#include "kg.h"
#if NKG > 0
startkgclock();
#endif
#endif
/*
* Initialize tables, protocols, and set up well-known inodes.
*/
mbinit();
cinit();
#ifdef SYSVSHM
shminit();
#endif
#include "sl.h"
#if NSL > 0
slattach(); /* XXX */
#endif
#include "loop.h"
#if NLOOP > 0
loattach(); /* XXX */
#endif
/*
* Block reception of incoming packets
* until protocols have been initialized.
*/
s = splimp();
ifinit();
domaininit();
splx(s);
#ifdef GPROF
kmstartup();
#endif
/* kick off timeout driven events by calling first time */
roundrobin();
schedcpu();
enablertclock(); /* enable realtime clock interrupts */
/*
* Set up the root file system and vnode.
*/
if ((*mountroot)())
panic("cannot mount root");
/*
* Get vnode for '/'.
* Setup rootdir and fdp->fd_fd.fd_cdir to point to it.
*/
if (VFS_ROOT(rootfs, &rootdir))
panic("cannot find root vnode");
fdp->fd_fd.fd_cdir = rootdir;
VREF(fdp->fd_fd.fd_cdir);
VOP_UNLOCK(rootdir);
fdp->fd_fd.fd_rdir = NULL;
swapinit();
/*
* Now can look at time, having had a chance
* to verify the time from the file system.
*/
boottime = p->p_stats->p_start = time;
/*
* make init process
*/
siginit(p);
if (fork(p, (void *) NULL, rval))
panic("fork init");
if (rval[1]) {
static char initflags[] = "-sf";
char *ip = initflags + 1;
vm_offset_t addr = 0;
/*
* Now in process 1. Set init flags into icode,
* get a minimal address space, copy out "icode",
* and return to it to do an exec of init.
*/
p = curproc;
initproc = p;
if (boothowto&RB_SINGLE)
*ip++ = 's';
#ifdef notyet
if (boothowto&RB_FASTBOOT)
*ip++ = 'f';
#endif
*ip++ = '\0';
if (vm_allocate(&p->p_vmspace->vm_map, &addr,
round_page(szicode + sizeof(initflags)), FALSE) != 0 ||
addr != 0)
panic("init: couldn't allocate at zero");
/* need just enough stack to exec from */
addr = trunc_page(VM_MAX_ADDRESS - PAGE_SIZE);
if (vm_allocate(&p->p_vmspace->vm_map, &addr,
PAGE_SIZE, FALSE) != KERN_SUCCESS)
panic("vm_allocate init stack");
p->p_vmspace->vm_maxsaddr = (caddr_t)addr;
(void) copyout((caddr_t)icode, (caddr_t)0, (unsigned)szicode);
(void) copyout(initflags, (caddr_t)szicode, sizeof(initflags));
return; /* returns to icode */
}
/*
* Start up pageout daemon (process 2).
*/
if (fork(p, (void *) NULL, rval))
panic("fork pager");
if (rval[1]) {
/*
* Now in process 2.
*/
p = curproc;
pageproc = p;
p->p_flag |= SLOAD|SSYS; /* XXX */
bcopy("pagedaemon", curproc->p_comm, sizeof ("pagedaemon"));
vm_pageout();
/*NOTREACHED*/
}
/*
* enter scheduling loop
*/
sched();
}
/* MOVE TO vfs_bio.c (bufinit) XXX */
/*
* Initialize buffers and hash links for buffers.
*/
bufinit()
{
register int i;
register struct buf *bp, *dp;
register struct bufhd *hp;
int base, residual;
for (hp = bufhash, i = 0; i < BUFHSZ; i++, hp++)
hp->b_forw = hp->b_back = (struct buf *)hp;
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_rcred = NOCRED;
bp->b_wcred = NOCRED;
bp->b_dirtyoff = 0;
bp->b_dirtyend = 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);
}
}