/* * Copyright (c) 1986 Regents of the University of California. * All rights reserved. The Berkeley software License Agreement * specifies the terms and conditions for redistribution. * * @(#)init_main.c 2.5 (2.11BSD GTE) 1997/9/26 */ #include "param.h" #include "../machine/seg.h" #include "user.h" #include "fs.h" #include "mount.h" #include "map.h" #include "proc.h" #include "ioctl.h" #include "inode.h" #include "conf.h" #include "buf.h" #include "fcntl.h" #include "vm.h" #include "clist.h" #include "uba.h" #include "reboot.h" #include "systm.h" #include "kernel.h" #include "namei.h" #include "disklabel.h" #include "stat.h" #ifdef QUOTA #include "quota.h" #endif int netoff = 1; int cmask = CMASK; int securelevel; extern size_t physmem; extern struct mapent _coremap[]; /* * 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 * - process 1 execute bootstrap */ main() { extern dev_t bootdev; extern caddr_t bootcsr; register struct proc *p; register int i; register struct fs *fs; time_t toytime, toyclk(); daddr_t swsize; int (*ioctl)(); struct partinfo dpart; startup(); /* * set up system process 0 (swapper) */ p = &proc[0]; p->p_addr = *ka6; p->p_stat = SRUN; p->p_flag |= SLOAD|SSYS; p->p_nice = NZERO; u.u_procp = p; /* init user structure */ u.u_ap = u.u_arg; u.u_cmask = cmask; u.u_lastfile = -1; 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; bcopy("root", u.u_login, sizeof ("root")); /* Initialize signal state for process 0 */ siginit(p); /* * Initialize tables, protocols, and set up well-known inodes. */ cinit(); pqinit(); xinit(); ihinit(); bhinit(); binit(); ubinit(); #ifdef QUOTA QUOTAMAP(); qtinit(); u.u_quota = getquota(0, 0, Q_NDQ); QUOTAUNMAP(); #endif nchinit(); clkstart(); /* * If the kernel is configured for the boot/load device AND the use of the * compiled in 'bootdev' has not been overridden (by turning on RB_DFLTROOT, * see conf/boot.c for details) THEN switch 'rootdev', 'swapdev' and 'pipedev' * over to the boot/load device. Set 'pipedev' to be 'rootdev'. * * The &077 removes the controller number (bits 6 and 7) - those bits are * passed thru from /boot but would only greatly confuse the rest of the kernel. */ i = major(bootdev); if ((bdevsw[i].d_strategy != nodev) && !(boothowto & RB_DFLTROOT)) { rootdev = makedev(i, minor(bootdev) & 077); swapdev = rootdev | 1; /* partition 'b' */ pipedev = rootdev; /* * We check that the dump device is the same as the boot device. If it is * different then it is likely that crashdumps go to a tape device rather than * the swap area. In that case do not switch the dump device. */ if ((dumpdev != NODEV) && major(dumpdev) == i) dumpdev = swapdev; } /* * Need to attach the root device. The CSR is passed thru because this * may be a 2nd or 3rd controller rather than the 1st. NOTE: This poses * a big problem if 'swapdev' is not on the same controller as 'rootdev' * _or_ if 'swapdev' itself is on a 2nd or 3rd controller. Short of moving * autconfigure back in to the kernel it is not known what can be done about * this. * * One solution (for now) is to call swapdev's attach routine with a zero * address. The MSCP driver treats the 0 as a signal to perform the * old (fixed address) attach. Drivers (all the rest at this point) which * do not support alternate controller booting always attach the first * (primary) CSR and do not expect an argument to be passed. */ (void)(*bdevsw[major(bootdev)].d_root)(bootcsr); (void)(*bdevsw[major(swapdev)].d_root)((caddr_t) 0); /* XXX */ /* * Now we find out how much swap space is available. Since 'nswap' is * a "u_int" we have to restrict the amount of swap to 65535 sectors (~32mb). * Considering that 4mb is the maximum physical memory capacity of a pdp-11 * 32mb swap should be enough ;-) * * The initialization of the swap map was moved here from machdep2.c because * 'nswap' was no longer statically defined and this is where the swap dev * is opened/initialized. * * Also, we toss away/ignore .5kb (1 sector) of swap space (because a 0 value * can not be placed in a resource map). * * 'swplo' was a hack which has _finally_ gone away! It was never anything * but 0 and caused a number of double word adds in the kernel. */ (*bdevsw[major(swapdev)].d_open)(swapdev, FREAD|FWRITE, S_IFBLK); swsize = (*bdevsw[major(swapdev)].d_psize)(swapdev); if (swsize <= 0) panic("swsiz"); /* don't want to panic, but what ? */ /* * Next we make sure that we do not swap on a partition unless it is of * type FS_SWAP. If the driver does not have an ioctl entry point or if * retrieving the partition information fails then the driver does not * support labels and we proceed normally, otherwise the partition must be * a swap partition (so that we do not swap on top of a filesystem by mistake). */ ioctl = cdevsw[blktochr(swapdev)].d_ioctl; if (ioctl && !(*ioctl)(swapdev, DIOCGPART, (caddr_t)&dpart, FREAD)) { if (dpart.part->p_fstype != FS_SWAP) panic("swtyp"); } if (swsize > (daddr_t)65535) swsize = 65535; nswap = swsize; mfree(swapmap, --nswap, 1); fs = mountfs(rootdev, boothowto & RB_RDONLY ? MNT_RDONLY : 0, (struct inode *)0); if (!fs) panic("iinit"); mount[0].m_inodp = (struct inode *)1; /* XXX */ mount_updname(fs, "/", "root", 1, 4); time.tv_sec = fs->fs_time; if (toytime = toyclk()) time.tv_sec = toytime; boottime = time; /* kick off timeout driven events by calling first time */ schedcpu(); /* set up the root file system */ rootdir = iget(rootdev, &mount[0].m_filsys, (ino_t)ROOTINO); iunlock(rootdir); u.u_cdir = iget(rootdev, &mount[0].m_filsys, (ino_t)ROOTINO); iunlock(u.u_cdir); u.u_rdir = NULL; #ifdef INET if (netoff = netinit()) printf("netinit failed\n"); else { NETSETHZ(); NETSTART(); } #endif /* * This came from pdp/machdep2.c because the memory available statements * were being made _before_ memory for the networking code was allocated. * A side effect of moving this code is that network "attach" and MSCP * "online" messages can appear before the memory sizes. The (currently * safe) assumption is made that no 'free' calls are made so that the * size in the first entry of the core map is correct. */ printf("\nphys mem = %D\n", ctob((long)physmem)); printf("avail mem = %D\n", ctob((long)_coremap[0].m_size)); maxmem = MAXMEM; printf("user mem = %D\n", ctob((long)MAXMEM)); #if NRAM > 0 printf("ram disk = %D\n", ctob((long)ramsize)); #endif printf("\n"); /* * make init process */ if (newproc(0)) { expand((int)btoc(szicode), S_DATA); expand((int)1, S_STACK); /* one click of stack */ estabur((u_int)0, (u_int)btoc(szicode), (u_int)1, 0, RO); copyout((caddr_t)icode, (caddr_t)0, szicode); /* * return goes to location 0 of user init code * just copied out. */ return; } else sched(); } /* * Initialize hash links for buffers. */ static 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; } memaddr bpaddr; /* physical click-address of buffers */ /* * Initialize the buffer I/O system by freeing * all buffers and setting all device buffer lists to empty. */ static binit() { register struct buf *bp; register int i; long paddr; for (bp = bfreelist; bp < &bfreelist[BQUEUES]; bp++) bp->b_forw = bp->b_back = bp->av_forw = bp->av_back = bp; paddr = ((long)bpaddr) << 6; for (i = 0; i < nbuf; i++, paddr += MAXBSIZE) { bp = &buf[i]; bp->b_dev = NODEV; bp->b_bcount = 0; bp->b_un.b_addr = (caddr_t)loint(paddr); bp->b_xmem = hiint(paddr); binshash(bp, &bfreelist[BQ_AGE]); bp->b_flags = B_BUSY|B_INVAL; brelse(bp); } } /* * Initialize clist by freeing all character blocks, then count * number of character devices. (Once-only routine) */ static cinit() { register int ccp; register struct cblock *cp; ccp = (int)cfree; #ifdef UCB_CLIST mapseg5(clststrt, clstdesc); /* don't save, we know it's normal */ #else ccp = (ccp + CROUND) & ~CROUND; #endif for (cp = (struct cblock *)ccp; cp <= &cfree[nclist - 1]; cp++) { cp->c_next = cfreelist; cfreelist = cp; cfreecount += CBSIZE; } #ifdef UCB_CLIST normalseg5(); #endif } #ifdef INET memaddr netdata; /* click address of start of net data */ /* * We are called here after all the other init routines (clist, inode, * unibusmap, etc...) have been called. Open the * file NETNIX and read the a.out header, based on that go allocate * memory and read the text+data into the memory. Set up supervisor page * registers, SDSA6 and SDSA7 have already been set up in mch_start.s. */ static char NETNIX[] = "/netnix"; static netinit() { register u_short *ap, *dp; register int i; struct exec ex; struct inode *ip; memaddr nettext; long lsize; off_t off; int initdata, netdsize, nettsize, ret, err, resid; char oneclick[ctob(1)]; struct nameidata nd; register struct nameidata *ndp = &nd; ret = 1; NDINIT(ndp, LOOKUP, FOLLOW, UIO_SYSSPACE, NETNIX); if (!(ip = namei(ndp))) { printf("%s not found\n", NETNIX); goto leave; } if ((ip->i_mode & IFMT) != IFREG || !ip->i_size) { printf("%s bad inode\n", NETNIX); goto leave; } err = rdwri(UIO_READ, ip, &ex, sizeof (ex), (off_t)0, UIO_SYSSPACE, IO_UNIT, &resid); if (err || resid) { printf("%s header %d\n", NETNIX, ret); goto leave; } if (ex.a_magic != A_MAGIC3) { printf("%s bad magic %o\n", NETNIX, ex.a_magic); goto leave; } lsize = (long)ex.a_data + (long)ex.a_bss; if (lsize > 48L * 1024L) { printf("%s 2big %ld\n", NETNIX, lsize); goto leave; } nettsize = btoc(ex.a_text); nettext = (memaddr)malloc(coremap, nettsize); netdsize = btoc(ex.a_data + ex.a_bss); netdata = (memaddr)malloc(coremap, netdsize); initdata = ex.a_data >> 6; off = sizeof (ex); for (i = 0; i < nettsize; i++) { err = rdwri(UIO_READ, ip, oneclick, ctob(1), off, UIO_SYSSPACE, IO_UNIT, &resid); if (err || resid) goto release; mapseg5(nettext + i, 077406); bcopy(oneclick, SEG5, ctob(1)); off += ctob(1); normalseg5(); } for (i = 0; i < initdata; i++) { err = rdwri(UIO_READ, ip, oneclick, ctob(1), off, UIO_SYSSPACE, IO_UNIT, &resid); if (err || resid) goto release; mapseg5(netdata + i, 077406); bcopy(oneclick, SEG5, ctob(1)); normalseg5(); off += ctob(1); } if (ex.a_data & 077) { err = rdwri(UIO_READ, ip, oneclick, ex.a_data & 077, off, UIO_SYSSPACE, IO_UNIT, &resid); if (err || resid) { release: printf("%s err %d\n", NETNIX, err); mfree(coremap, nettsize, nettext); mfree(coremap, netdsize, netdata); nettsize = netdsize = 0; netdata = nettext = 0; goto leave; } mapseg5(netdata + i, 077406); /* i is set from above loop */ bcopy(oneclick, SEG5, ex.a_data & 077); normalseg5(); } for (i = 0, ap = SISA0, dp = SISD0; i < nettsize; i += stoc(1)) { *ap++ = nettext + i; *dp++ = ((stoc(1) - 1) << 8) | RO; } /* might have over run the length on the last one, patch it now */ if (i > nettsize) *--dp -= ((i - nettsize) << 8); for (i = 0, ap = SDSA0, dp = SDSD0; i < netdsize; i += stoc(1)) { *ap++ = netdata + i; *dp++ = ((stoc(1) - 1) << 8) | RW; } if (i > netdsize) *--dp -= ((i - netdsize) << 8); ret = 0; leave: if (ip) iput(ip); u.u_error = 0; return(ret); } #endif