rework setroot() and friends, largely by cloning from the sparc code

and whacking a bit here and there where appropriate.  Does not yet do
automatic root device detection, but that's much easier to add now.
RB_ASKNAME now supports specification of network devices, for diskless
booting.  Also, RB_ASKNAME is now supported on _all_ kernels.
This commit is contained in:
cgd 1996-06-12 01:57:17 +00:00
parent ba53a90965
commit 811bbb5c72
1 changed files with 353 additions and 72 deletions

View File

@ -1,30 +1,47 @@
/* $NetBSD: autoconf.c,v 1.3 1996/04/12 06:07:05 cgd Exp $ */
/* $NetBSD: autoconf.c,v 1.4 1996/06/12 01:57:17 cgd Exp $ */
/*
* Copyright (c) 1994, 1995, 1996 Carnegie-Mellon University.
* All rights reserved.
* Copyright (c) 1992, 1993
* The Regents of the University of California. All rights reserved.
*
* Authors: Keith Bostic, Chris G. Demetriou
*
* Permission to use, copy, modify and distribute this software and
* its documentation is hereby granted, provided that both the copyright
* notice and this permission notice appear in all copies of the
* software, derivative works or modified versions, and any portions
* thereof, and that both notices appear in supporting documentation.
*
* CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
* CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND
* FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
*
* Carnegie Mellon requests users of this software to return to
* This software was developed by the Computer Systems Engineering group
* at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
* contributed to Berkeley.
*
* Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
* School of Computer Science
* Carnegie Mellon University
* Pittsburgh PA 15213-3890
* All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Lawrence Berkeley Laboratory.
*
* any improvements or extensions that they make and grant Carnegie the
* rights to redistribute these changes.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* @(#)autoconf.c 8.4 (Berkeley) 10/1/93
*/
#include <sys/param.h>
@ -37,6 +54,12 @@
#include <machine/autoconf.h>
struct device *parsedisk __P((char *str, int len, int defpart, dev_t *devp));
static struct device *getdisk __P((char *str, int len, int defpart,
dev_t *devp));
static int findblkmajor __P((struct device *dv));
static int getstr __P((char *cp, int size));
/*
* configure:
* called at boot time, configure all devices on system
@ -51,13 +74,7 @@ configure()
panic("no mainbus found");
(void)spl0();
#ifdef GENERIC
if ((boothowto & RB_ASKNAME) == 0)
setroot();
setconf();
#else
setroot();
#endif
swapconf();
cold = 0;
}
@ -67,12 +84,11 @@ configure()
*/
swapconf()
{
register struct swdevt *swp;
register int nblks;
struct swdevt *swp;
int nblks, maj;
for (swp = swdevt; swp->sw_dev != NODEV; swp++) {
int maj = major(swp->sw_dev);
maj = major(swp->sw_dev);
if (maj > nblkdev)
break;
if (bdevsw[maj].d_psize) {
@ -83,62 +99,282 @@ swapconf()
swp->sw_nblks = ctod(dtoc(swp->sw_nblks));
}
}
dumpconf();
}
#define DOSWAP /* change swdevt and dumpdev */
dev_t bootdev = 0; /* should be dev_t, but not until 32 bits */
static char devname[][2] = {
'x','x', /* 0 = XX */
'x','x', /* 1 = XX */
'x','x', /* 2 = XX */
'x','x', /* 3 = XX */
'x','x', /* 4 = XX */
'x','x', /* 5 = XX */
'x','x', /* 6 = XX */
'x','x', /* 7 = XX */
's','d', /* 8 = sd */
struct nam2blk {
char *name;
int maj;
} nam2blk[] = {
{ "st", 2 },
{ "cd", 3 },
{ "sd", 8 },
#if 0
{ "fd", XXX },
#endif
};
static int
findblkmajor(dv)
struct device *dv;
{
char *name = dv->dv_xname;
register int i;
for (i = 0; i < sizeof(nam2blk)/sizeof(nam2blk[0]); ++i)
if (strncmp(name, nam2blk[i].name, strlen(nam2blk[0].name))
== 0)
return (nam2blk[i].maj);
return (-1);
}
static struct device *
getdisk(str, len, defpart, devp)
char *str;
int len, defpart;
dev_t *devp;
{
register struct device *dv;
if ((dv = parsedisk(str, len, defpart, devp)) == NULL) {
printf("use one of:");
for (dv = alldevs.tqh_first; dv != NULL;
dv = dv->dv_list.tqe_next) {
if (dv->dv_class == DV_DISK)
printf(" %s[a-h]", dv->dv_xname);
#ifdef NFSCLIENT
if (dv->dv_class == DV_IFNET)
printf(" %s", dv->dv_xname);
#endif
}
printf("\n");
}
return (dv);
}
struct device *
parsedisk(str, len, defpart, devp)
char *str;
int len, defpart;
dev_t *devp;
{
register struct device *dv;
register char *cp, c;
int majdev, part;
if (len == 0)
return (NULL);
cp = str + len - 1;
c = *cp;
if (c >= 'a' && c <= ('a' + MAXPARTITIONS - 1)) {
part = c - 'a';
*cp = '\0';
} else
part = defpart;
for (dv = alldevs.tqh_first; dv != NULL; dv = dv->dv_list.tqe_next) {
if (dv->dv_class == DV_DISK &&
strcmp(str, dv->dv_xname) == 0) {
majdev = findblkmajor(dv);
if (majdev < 0)
panic("parsedisk");
*devp = MAKEDISKDEV(majdev, dv->dv_unit, part);
break;
}
#ifdef NFSCLIENT
if (dv->dv_class == DV_IFNET &&
strcmp(str, dv->dv_xname) == 0) {
*devp = NODEV;
break;
}
#endif
}
*cp = c;
return (dv);
}
/*
* Attempt to find the device from which we were booted.
* If we can do so, and not instructed not to do so,
* change rootdev to correspond to the load device.
*
* XXX Actually, swap and root must be on the same type of device,
* (ie. DV_DISK or DV_IFNET) because of how (*mountroot) is written.
* That should be fixed.
*/
setroot()
{
int majdev, mindev, unit, part, adaptor;
dev_t temp, orootdev;
struct swdevt *swp;
struct device *dv;
register int len;
dev_t nrootdev, nswapdev = NODEV;
char buf[128];
extern int (*mountroot) __P((void *));
dev_t temp;
struct device *bootdv, *rootdv, *swapdv;
int bootpartition; /* XXX */
#if defined(NFSCLIENT)
extern char *nfsbootdevname;
extern int nfs_mountroot __P((void *));
#endif
#if defined(FFS)
extern int ffs_mountroot __P((void *));
#endif
bootdv = NULL; /* XXX */
bootpartition = 0; /* XXX */
/*printf("howto %x bootdev %x ", boothowto, bootdev);*/
if (boothowto & RB_DFLTROOT ||
(bootdev & B_MAGICMASK) != (u_long)B_DEVMAGIC)
return;
majdev = (bootdev >> B_TYPESHIFT) & B_TYPEMASK;
if (majdev > sizeof(devname) / sizeof(devname[0]))
return;
adaptor = (bootdev >> B_ADAPTORSHIFT) & B_ADAPTORMASK;
part = (bootdev >> B_PARTITIONSHIFT) & B_PARTITIONMASK;
unit = (bootdev >> B_UNITSHIFT) & B_UNITMASK;
mindev = (unit * MAXPARTITIONS) + part;
orootdev = rootdev;
rootdev = makedev(majdev, mindev);
/*
* If the original rootdev is the same as the one
* just calculated, don't need to adjust the swap configuration.
* If 'swap generic' and we couldn't determine root device,
* ask the user.
*/
if (rootdev == orootdev)
return;
printf("changing root device to %c%c%d%c\n",
devname[majdev][0], devname[majdev][1],
unit, part + 'a');
if (mountroot == NULL && bootdv == NULL)
boothowto |= RB_ASKNAME;
#ifdef DOSWAP
if (boothowto & RB_ASKNAME) {
for (;;) {
printf("root device");
if (bootdv != NULL)
printf(" (default %s%c)",
bootdv->dv_xname,
bootdv->dv_class == DV_DISK
? bootpartition + 'a' : ' ');
printf(": ");
len = getstr(buf, sizeof(buf));
if (len == 0 && bootdv != NULL) {
strcpy(buf, bootdv->dv_xname);
len = strlen(buf);
}
if (len == 4 && !strcmp(buf, "halt"))
boot(RB_HALT);
if (len > 0 && buf[len - 1] == '*') {
buf[--len] = '\0';
dv = getdisk(buf, len, 1, &nrootdev);
if (dv != NULL) {
rootdv = dv;
nswapdev = nrootdev;
goto gotswap;
}
}
dv = getdisk(buf, len, bootpartition, &nrootdev);
if (dv != NULL) {
rootdv = dv;
break;
}
}
/*
* because swap must be on same device type as root, for
* network devices this is easy.
*/
if (rootdv->dv_class == DV_IFNET) {
swapdv = NULL;
goto gotswap;
}
for (;;) {
printf("swap device");
printf(" (default %s%c)", rootdv->dv_xname,
rootdv->dv_class == DV_DISK?'b':' ');
printf(": ");
len = getstr(buf, sizeof(buf));
if (len == 0) {
switch (rootdv->dv_class) {
case DV_IFNET:
nswapdev = NODEV;
break;
case DV_DISK:
nswapdev = MAKEDISKDEV(major(nrootdev),
DISKUNIT(nrootdev), 1);
break;
case DV_TAPE:
case DV_TTY:
case DV_DULL:
case DV_CPU:
break;
}
swapdv = rootdv;
break;
}
if (len == 4 && !strcmp(buf, "halt"))
boot(RB_HALT);
dv = getdisk(buf, len, 1, &nswapdev);
if (dv) {
if (dv->dv_class == DV_IFNET)
nswapdev = NODEV;
swapdv = dv;
break;
}
}
gotswap:
rootdev = nrootdev;
dumpdev = nswapdev;
swdevt[0].sw_dev = nswapdev;
swdevt[1].sw_dev = NODEV;
} else if (mountroot == NULL) {
int majdev;
/*
* "swap generic"
*/
majdev = findblkmajor(bootdv);
if (majdev >= 0) {
/*
* Root and swap are on a disk.
*/
rootdv = swapdv = bootdv;
rootdev = MAKEDISKDEV(majdev, bootdv->dv_unit,
bootpartition);
nswapdev = dumpdev =
MAKEDISKDEV(majdev, bootdv->dv_unit, 1);
} else {
/*
* Root and swap are on a net.
*/
rootdv = swapdv = NULL;
nswapdev = dumpdev = NODEV;
}
swdevt[0].sw_dev = nswapdev;
swdevt[1].sw_dev = NODEV;
} else {
/*
* `root DEV swap DEV': honour rootdev/swdevt.
* rootdev/swdevt/mountroot already properly set.
*/
return;
}
switch (rootdv->dv_class) {
#if defined(NFSCLIENT)
case DV_IFNET:
mountroot = nfs_mountroot;
nfsbootdevname = rootdv->dv_xname;
return;
#endif
#if defined(FFS)
case DV_DISK:
mountroot = ffs_mountroot;
printf("root on %s%c", rootdv->dv_xname,
DISKPART(rootdev) + 'a');
if (nswapdev != NODEV)
printf(" swap on %s%c", swapdv->dv_xname,
DISKPART(nswapdev) + 'a');
printf("\n");
break;
#endif
default:
printf("can't figure root, hope your kernel is right\n");
return;
}
/*
* Make the swap partition on the root drive the primary swap.
*/
temp = NODEV;
for (swp = swdevt; swp->sw_dev != NODEV; swp++) {
if (majdev == major(swp->sw_dev) &&
(mindev / MAXPARTITIONS)
== (minor(swp->sw_dev) / MAXPARTITIONS)) {
if (major(rootdev) == major(swp->sw_dev) &&
DISKUNIT(rootdev) == DISKUNIT(swp->sw_dev)) {
temp = swdevt[0].sw_dev;
swdevt[0].sw_dev = swp->sw_dev;
swp->sw_dev = temp;
@ -154,5 +390,50 @@ setroot()
*/
if (temp == dumpdev)
dumpdev = swdevt[0].sw_dev;
#endif
}
static int
getstr(cp, size)
register char *cp;
register int size;
{
register char *lp;
register int c;
register int len;
lp = cp;
len = 0;
for (;;) {
c = cngetc();
switch (c) {
case '\n':
case '\r':
printf("\n");
*lp++ = '\0';
return (len);
case '\b':
case '\177':
case '#':
if (len) {
--len;
--lp;
printf("\b \b");
}
continue;
case '@':
case 'u'&037:
len = 0;
lp = cp;
printf("\n");
continue;
default:
if (len + 1 >= size || c < ' ') {
printf("\007");
continue;
}
printf("%c", c);
++len;
*lp++ = c;
}
}
}