Home | History | Annotate | Line # | Download | only in alpha
autoconf.c revision 1.4
      1 /*	$NetBSD: autoconf.c,v 1.4 1996/06/12 01:57:17 cgd Exp $	*/
      2 
      3 /*
      4  * Copyright (c) 1992, 1993
      5  *	The Regents of the University of California.  All rights reserved.
      6  *
      7  * This software was developed by the Computer Systems Engineering group
      8  * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
      9  * contributed to Berkeley.
     10  *
     11  * All advertising materials mentioning features or use of this software
     12  * must display the following acknowledgement:
     13  *	This product includes software developed by the University of
     14  *	California, Lawrence Berkeley Laboratory.
     15  *
     16  * Redistribution and use in source and binary forms, with or without
     17  * modification, are permitted provided that the following conditions
     18  * are met:
     19  * 1. Redistributions of source code must retain the above copyright
     20  *    notice, this list of conditions and the following disclaimer.
     21  * 2. Redistributions in binary form must reproduce the above copyright
     22  *    notice, this list of conditions and the following disclaimer in the
     23  *    documentation and/or other materials provided with the distribution.
     24  * 3. All advertising materials mentioning features or use of this software
     25  *    must display the following acknowledgement:
     26  *	This product includes software developed by the University of
     27  *	California, Berkeley and its contributors.
     28  * 4. Neither the name of the University nor the names of its contributors
     29  *    may be used to endorse or promote products derived from this software
     30  *    without specific prior written permission.
     31  *
     32  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     33  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     34  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     35  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     36  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     37  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     38  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     39  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     40  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     41  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     42  * SUCH DAMAGE.
     43  *
     44  *	@(#)autoconf.c	8.4 (Berkeley) 10/1/93
     45  */
     46 
     47 #include <sys/param.h>
     48 #include <sys/systm.h>
     49 #include <sys/buf.h>
     50 #include <sys/disklabel.h>
     51 #include <sys/conf.h>
     52 #include <sys/reboot.h>
     53 #include <sys/device.h>
     54 
     55 #include <machine/autoconf.h>
     56 
     57 struct device *parsedisk __P((char *str, int len, int defpart, dev_t *devp));
     58 static struct device *getdisk __P((char *str, int len, int defpart,
     59 				   dev_t *devp));
     60 static int findblkmajor __P((struct device *dv));
     61 static int getstr __P((char *cp, int size));
     62 
     63 /*
     64  * configure:
     65  * called at boot time, configure all devices on system
     66  */
     67 void
     68 configure()
     69 {
     70 	extern int cold;
     71 
     72 	(void)splhigh();
     73 	if (config_rootfound("mainbus", "mainbus") == NULL)
     74 		panic("no mainbus found");
     75 	(void)spl0();
     76 
     77 	setroot();
     78 	swapconf();
     79 	cold = 0;
     80 }
     81 
     82 /*
     83  * Configure swap space and related parameters.
     84  */
     85 swapconf()
     86 {
     87 	struct swdevt *swp;
     88 	int nblks, maj;
     89 
     90 	for (swp = swdevt; swp->sw_dev != NODEV; swp++) {
     91 		maj = major(swp->sw_dev);
     92 		if (maj > nblkdev)
     93 			break;
     94 		if (bdevsw[maj].d_psize) {
     95 			nblks = (*bdevsw[maj].d_psize)(swp->sw_dev);
     96 			if (nblks != -1 &&
     97 			    (swp->sw_nblks == 0 || swp->sw_nblks > nblks))
     98 				swp->sw_nblks = nblks;
     99 			swp->sw_nblks = ctod(dtoc(swp->sw_nblks));
    100 		}
    101 	}
    102 	dumpconf();
    103 }
    104 
    105 struct nam2blk {
    106 	char *name;
    107 	int maj;
    108 } nam2blk[] = {
    109 	{ "st",		2 },
    110 	{ "cd",		3 },
    111 	{ "sd",		8 },
    112 #if 0
    113 	{ "fd",		XXX },
    114 #endif
    115 };
    116 
    117 static int
    118 findblkmajor(dv)
    119 	struct device *dv;
    120 {
    121 	char *name = dv->dv_xname;
    122 	register int i;
    123 
    124 	for (i = 0; i < sizeof(nam2blk)/sizeof(nam2blk[0]); ++i)
    125 		if (strncmp(name, nam2blk[i].name, strlen(nam2blk[0].name))
    126 		    == 0)
    127 			return (nam2blk[i].maj);
    128 	return (-1);
    129 }
    130 
    131 static struct device *
    132 getdisk(str, len, defpart, devp)
    133 	char *str;
    134 	int len, defpart;
    135 	dev_t *devp;
    136 {
    137 	register struct device *dv;
    138 
    139 	if ((dv = parsedisk(str, len, defpart, devp)) == NULL) {
    140 		printf("use one of:");
    141 		for (dv = alldevs.tqh_first; dv != NULL;
    142 		    dv = dv->dv_list.tqe_next) {
    143 			if (dv->dv_class == DV_DISK)
    144 				printf(" %s[a-h]", dv->dv_xname);
    145 #ifdef NFSCLIENT
    146 			if (dv->dv_class == DV_IFNET)
    147 				printf(" %s", dv->dv_xname);
    148 #endif
    149 		}
    150 		printf("\n");
    151 	}
    152 	return (dv);
    153 }
    154 
    155 struct device *
    156 parsedisk(str, len, defpart, devp)
    157 	char *str;
    158 	int len, defpart;
    159 	dev_t *devp;
    160 {
    161 	register struct device *dv;
    162 	register char *cp, c;
    163 	int majdev, part;
    164 
    165 	if (len == 0)
    166 		return (NULL);
    167 	cp = str + len - 1;
    168 	c = *cp;
    169 	if (c >= 'a' && c <= ('a' + MAXPARTITIONS - 1)) {
    170 		part = c - 'a';
    171 		*cp = '\0';
    172 	} else
    173 		part = defpart;
    174 
    175 	for (dv = alldevs.tqh_first; dv != NULL; dv = dv->dv_list.tqe_next) {
    176 		if (dv->dv_class == DV_DISK &&
    177 		    strcmp(str, dv->dv_xname) == 0) {
    178 			majdev = findblkmajor(dv);
    179 			if (majdev < 0)
    180 				panic("parsedisk");
    181 			*devp = MAKEDISKDEV(majdev, dv->dv_unit, part);
    182 			break;
    183 		}
    184 #ifdef NFSCLIENT
    185 		if (dv->dv_class == DV_IFNET &&
    186 		    strcmp(str, dv->dv_xname) == 0) {
    187 			*devp = NODEV;
    188 			break;
    189 		}
    190 #endif
    191 	}
    192 
    193 	*cp = c;
    194 	return (dv);
    195 }
    196 
    197 /*
    198  * Attempt to find the device from which we were booted.
    199  * If we can do so, and not instructed not to do so,
    200  * change rootdev to correspond to the load device.
    201  *
    202  * XXX Actually, swap and root must be on the same type of device,
    203  * (ie. DV_DISK or DV_IFNET) because of how (*mountroot) is written.
    204  * That should be fixed.
    205  */
    206 setroot()
    207 {
    208 	struct swdevt *swp;
    209 	struct device *dv;
    210         register int len;
    211 	dev_t nrootdev, nswapdev = NODEV;
    212 	char buf[128];
    213 	extern int (*mountroot) __P((void *));
    214 	dev_t temp;
    215 	struct device *bootdv, *rootdv, *swapdv;
    216 	int bootpartition;				/* XXX */
    217 #if defined(NFSCLIENT)
    218 	extern char *nfsbootdevname;
    219 	extern int nfs_mountroot __P((void *));
    220 #endif
    221 #if defined(FFS)
    222 	extern int ffs_mountroot __P((void *));
    223 #endif
    224 
    225 	bootdv = NULL;					/* XXX */
    226 	bootpartition = 0;				/* XXX */
    227 
    228 	/*
    229 	 * If 'swap generic' and we couldn't determine root device,
    230 	 * ask the user.
    231 	 */
    232 	if (mountroot == NULL && bootdv == NULL)
    233 		boothowto |= RB_ASKNAME;
    234 
    235 	if (boothowto & RB_ASKNAME) {
    236 		for (;;) {
    237 			printf("root device");
    238 			if (bootdv != NULL)
    239 				printf(" (default %s%c)",
    240 					bootdv->dv_xname,
    241 					bootdv->dv_class == DV_DISK
    242 						? bootpartition + 'a' : ' ');
    243 			printf(": ");
    244 			len = getstr(buf, sizeof(buf));
    245 			if (len == 0 && bootdv != NULL) {
    246 				strcpy(buf, bootdv->dv_xname);
    247 				len = strlen(buf);
    248 			}
    249 			if (len == 4 && !strcmp(buf, "halt"))
    250 				boot(RB_HALT);
    251 			if (len > 0 && buf[len - 1] == '*') {
    252 				buf[--len] = '\0';
    253 				dv = getdisk(buf, len, 1, &nrootdev);
    254 				if (dv != NULL) {
    255 					rootdv = dv;
    256 					nswapdev = nrootdev;
    257 					goto gotswap;
    258 				}
    259 			}
    260 			dv = getdisk(buf, len, bootpartition, &nrootdev);
    261 			if (dv != NULL) {
    262 				rootdv = dv;
    263 				break;
    264 			}
    265 		}
    266 
    267 		/*
    268 		 * because swap must be on same device type as root, for
    269 		 * network devices this is easy.
    270 		 */
    271 		if (rootdv->dv_class == DV_IFNET) {
    272 			swapdv = NULL;
    273 			goto gotswap;
    274 		}
    275 		for (;;) {
    276 			printf("swap device");
    277 			printf(" (default %s%c)", rootdv->dv_xname,
    278 			    rootdv->dv_class == DV_DISK?'b':' ');
    279 			printf(": ");
    280 			len = getstr(buf, sizeof(buf));
    281 			if (len == 0) {
    282 				switch (rootdv->dv_class) {
    283 				case DV_IFNET:
    284 					nswapdev = NODEV;
    285 					break;
    286 				case DV_DISK:
    287 					nswapdev = MAKEDISKDEV(major(nrootdev),
    288 					    DISKUNIT(nrootdev), 1);
    289 					break;
    290 				case DV_TAPE:
    291 				case DV_TTY:
    292 				case DV_DULL:
    293 				case DV_CPU:
    294 					break;
    295 				}
    296 				swapdv = rootdv;
    297 				break;
    298 			}
    299 			if (len == 4 && !strcmp(buf, "halt"))
    300 				boot(RB_HALT);
    301 			dv = getdisk(buf, len, 1, &nswapdev);
    302 			if (dv) {
    303 				if (dv->dv_class == DV_IFNET)
    304 					nswapdev = NODEV;
    305 				swapdv = dv;
    306 				break;
    307 			}
    308 		}
    309 gotswap:
    310 		rootdev = nrootdev;
    311 		dumpdev = nswapdev;
    312 		swdevt[0].sw_dev = nswapdev;
    313 		swdevt[1].sw_dev = NODEV;
    314 	} else if (mountroot == NULL) {
    315 		int majdev;
    316 
    317 		/*
    318 		 * "swap generic"
    319 		 */
    320 		majdev = findblkmajor(bootdv);
    321 		if (majdev >= 0) {
    322 			/*
    323 			 * Root and swap are on a disk.
    324 			 */
    325 			rootdv = swapdv = bootdv;
    326 			rootdev = MAKEDISKDEV(majdev, bootdv->dv_unit,
    327 			    bootpartition);
    328 			nswapdev = dumpdev =
    329 			    MAKEDISKDEV(majdev, bootdv->dv_unit, 1);
    330 		} else {
    331 			/*
    332 			 * Root and swap are on a net.
    333 			 */
    334 			rootdv = swapdv = NULL;
    335 			nswapdev = dumpdev = NODEV;
    336 		}
    337 		swdevt[0].sw_dev = nswapdev;
    338 		swdevt[1].sw_dev = NODEV;
    339         } else {
    340 
    341 		/*
    342 		 * `root DEV swap DEV': honour rootdev/swdevt.
    343 		 * rootdev/swdevt/mountroot already properly set.
    344 		 */
    345 		return;
    346 	}
    347 
    348 	switch (rootdv->dv_class) {
    349 #if defined(NFSCLIENT)
    350 	case DV_IFNET:
    351 		mountroot = nfs_mountroot;
    352 		nfsbootdevname = rootdv->dv_xname;
    353 		return;
    354 #endif
    355 #if defined(FFS)
    356 	case DV_DISK:
    357 		mountroot = ffs_mountroot;
    358 		printf("root on %s%c", rootdv->dv_xname,
    359 		    DISKPART(rootdev) + 'a');
    360 		if (nswapdev != NODEV)
    361 			printf(" swap on %s%c", swapdv->dv_xname,
    362 			    DISKPART(nswapdev) + 'a');
    363 		printf("\n");
    364 		break;
    365 #endif
    366 	default:
    367 		printf("can't figure root, hope your kernel is right\n");
    368 		return;
    369 	}
    370 
    371 	/*
    372 	 * Make the swap partition on the root drive the primary swap.
    373 	 */
    374 	temp = NODEV;
    375 	for (swp = swdevt; swp->sw_dev != NODEV; swp++) {
    376 		if (major(rootdev) == major(swp->sw_dev) &&
    377 		    DISKUNIT(rootdev) == DISKUNIT(swp->sw_dev)) {
    378 			temp = swdevt[0].sw_dev;
    379 			swdevt[0].sw_dev = swp->sw_dev;
    380 			swp->sw_dev = temp;
    381 			break;
    382 		}
    383 	}
    384 	if (swp->sw_dev == NODEV)
    385 		return;
    386 
    387 	/*
    388 	 * If dumpdev was the same as the old primary swap device, move
    389 	 * it to the new primary swap device.
    390 	 */
    391 	if (temp == dumpdev)
    392 		dumpdev = swdevt[0].sw_dev;
    393 }
    394 
    395 static int
    396 getstr(cp, size)
    397 	register char *cp;
    398 	register int size;
    399 {
    400 	register char *lp;
    401 	register int c;
    402 	register int len;
    403 
    404 	lp = cp;
    405 	len = 0;
    406 	for (;;) {
    407 		c = cngetc();
    408 		switch (c) {
    409 		case '\n':
    410 		case '\r':
    411 			printf("\n");
    412 			*lp++ = '\0';
    413 			return (len);
    414 		case '\b':
    415 		case '\177':
    416 		case '#':
    417 			if (len) {
    418 				--len;
    419 				--lp;
    420 				printf("\b \b");
    421 			}
    422 			continue;
    423 		case '@':
    424 		case 'u'&037:
    425 			len = 0;
    426 			lp = cp;
    427 			printf("\n");
    428 			continue;
    429 		default:
    430 			if (len + 1 >= size || c < ' ') {
    431 				printf("\007");
    432 				continue;
    433 			}
    434 			printf("%c", c);
    435 			++len;
    436 			*lp++ = c;
    437 		}
    438 	}
    439 }
    440