autoconf.c revision 27288
1/*-
2 * Copyright (c) 1990 The Regents of the University of California.
3 * All rights reserved.
4 *
5 * This code is derived from software contributed to Berkeley by
6 * William Jolitz.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 *    notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 *    notice, this list of conditions and the following disclaimer in the
15 *    documentation and/or other materials provided with the distribution.
16 * 3. All advertising materials mentioning features or use of this software
17 *    must display the following acknowledgement:
18 *	This product includes software developed by the University of
19 *	California, Berkeley and its contributors.
20 * 4. Neither the name of the University nor the names of its contributors
21 *    may be used to endorse or promote products derived from this software
22 *    without specific prior written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 * SUCH DAMAGE.
35 *
36 *	from: @(#)autoconf.c	7.1 (Berkeley) 5/9/91
37 *	$Id: autoconf.c,v 1.2 1997/07/08 23:40:04 smp Exp smp $
38 */
39
40/*
41 * Setup the system to run on the current machine.
42 *
43 * Configure() is called at boot time and initializes the vba
44 * device tables and the memory controller monitoring.  Available
45 * devices are determined (from possibilities mentioned in ioconf.c),
46 * and the drivers are initialized.
47 */
48#include "opt_cd9660.h"
49
50#include <sys/param.h>
51#include <sys/systm.h>
52#include <sys/buf.h>
53#include <sys/conf.h>
54#include <sys/dmap.h>
55#include <sys/reboot.h>
56#include <sys/kernel.h>
57#include <sys/mount.h>
58#include <sys/vnode.h>
59#include <sys/sysctl.h>
60
61#include <machine/bootinfo.h>
62#include <machine/cons.h>
63#include <machine/md_var.h>
64#ifdef APIC_IO
65#include <machine/smp.h>
66#endif /* APIC_IO */
67
68#include <i386/isa/icu.h> /* For interrupts */
69
70#include "isa.h"
71#if NISA > 0
72#include <i386/isa/isa_device.h>
73#endif
74
75#include "eisa.h"
76#if NEISA > 0
77#include <i386/eisa/eisaconf.h>
78#endif
79
80#include "pci.h"
81#if NPCI > 0
82#include <pci/pcivar.h>
83#endif
84
85#include "crd.h"
86#if NCRD > 0
87#include <pccard/driver.h>
88#endif
89
90#include "scbus.h"
91#if NSCBUS > 0
92#include <scsi/scsiconf.h>
93#endif
94
95static void	configure __P((void *));
96SYSINIT(configure, SI_SUB_CONFIGURE, SI_ORDER_FIRST, configure, NULL)
97
98static void	configure_finish __P((void));
99static void	configure_start __P((void));
100static int	setdumpdev __P((dev_t dev));
101static void	setroot __P((void));
102
103#ifdef CD9660
104
105#include <sys/fcntl.h>
106#include <sys/proc.h>
107#include <sys/stat.h>
108#include <machine/clock.h>
109#include <isofs/cd9660/iso.h>
110
111/*
112 * XXX All this CD-ROM root stuff is fairly messy.  Ick.
113 *
114 * We need to try out all our potential CDROM drives, so we need a table.
115 */
116static struct {
117	char *name;
118	int major;
119} try_cdrom[] = {
120	{ "cd", 6 },
121	{ "mcd", 7 },
122	{ "scd", 16 },
123	{ "matcd", 17 },
124	{ "wcd", 19 },
125	{ 0, 0}
126};
127
128static int	find_cdrom_root __P((void));
129
130static int
131find_cdrom_root()
132{
133	int i, j, error;
134	struct bdevsw *bd;
135	dev_t orootdev;
136
137#if CD9660_ROOTDELAY > 0
138	DELAY(CD9660_ROOTDELAY * 1000000);
139#endif
140	orootdev = rootdev;
141	for (i = 0 ; i < 2; i++)
142		for (j = 0 ; try_cdrom[j].name ; j++) {
143			if (try_cdrom[j].major >= nblkdev)
144				continue;
145			rootdev = makedev(try_cdrom[j].major, i * 8);
146			bd = bdevsw[major(rootdev)];
147			if (bd == NULL || bd->d_open == NULL)
148				continue;
149			if (bootverbose)
150				printf("trying %s%d as rootdev (0x%x)\n",
151				       try_cdrom[j].name, i, rootdev);
152			error = (bd->d_open)(rootdev, FREAD, S_IFBLK, curproc);
153			if (error == 0) {
154				if (bd->d_close != NULL)
155					(bd->d_close)(rootdev, FREAD, S_IFBLK,
156						      curproc);
157				return 0;
158			}
159		}
160
161	rootdev = orootdev;
162	return EINVAL;
163}
164#endif /* CD9660 */
165
166static void
167configure_start()
168{
169#if NSCBUS > 0
170	scsi_configure_start();
171#endif
172}
173
174static void
175configure_finish()
176{
177#if NSCBUS > 0
178	scsi_configure_finish();
179#endif
180}
181
182/*
183 * Determine i/o configuration for a machine.
184 */
185static void
186configure(dummy)
187	void *dummy;
188{
189	int i;
190
191	configure_start();
192
193	/* Allow all routines to decide for themselves if they want intrs */
194#ifdef APIC_IO
195	bsp_apic_configure();
196	enable_intr();
197#else
198	enable_intr();
199	INTREN(IRQ_SLAVE);
200#endif /* APIC_IO */
201
202#if NEISA > 0
203	eisa_configure();
204#endif
205
206#if NPCI > 0
207	pci_configure();
208#endif
209
210#if NISA > 0
211	isa_configure();
212#endif
213
214#if NCRD > 0
215	/* After everyone else has a chance at grabbing resources */
216	pccard_configure();
217#endif
218
219	if (setdumpdev(dumpdev) != 0)
220		dumpdev = NODEV;
221
222	configure_finish();
223
224	cninit_finish();
225
226	if (bootverbose) {
227		/*
228		 * Print out the BIOS's idea of the disk geometries.
229		 */
230		printf("BIOS Geometries:\n");
231		for (i = 0; i < N_BIOS_GEOM; i++) {
232			unsigned long bios_geom;
233			int max_cylinder, max_head, max_sector;
234
235			bios_geom = bootinfo.bi_bios_geom[i];
236
237			/*
238			 * XXX the bootstrap punts a 1200K floppy geometry
239			 * when the get-disk-geometry interrupt fails.  Skip
240			 * drives that have this geometry.
241			 */
242			if (bios_geom == 0x4f010f)
243				continue;
244
245			printf(" %x:%08lx ", i, bios_geom);
246			max_cylinder = bios_geom >> 16;
247			max_head = (bios_geom >> 8) & 0xff;
248			max_sector = bios_geom & 0xff;
249			printf(
250		"0..%d=%d cylinders, 0..%d=%d heads, 1..%d=%d sectors\n",
251			       max_cylinder, max_cylinder + 1,
252			       max_head, max_head + 1,
253			       max_sector, max_sector);
254		}
255		printf(" %d accounted for\n", bootinfo.bi_n_bios_used);
256
257		printf("Device configuration finished.\n");
258	}
259
260#ifdef CD9660
261	if ((boothowto & RB_CDROM)) {
262		if (bootverbose)
263			printf("Considering CD-ROM root f/s.\n");
264		/* NB: find_cdrom_root() sets rootdev if successful. */
265		if (find_cdrom_root() == 0)
266			mountrootfsname = "cd9660";
267		else if (bootverbose)
268			printf("No CD-ROM available as root f/s.\n");
269	}
270#endif
271
272#ifdef MFS_ROOT
273	if (!mountrootfsname) {
274		if (bootverbose)
275			printf("Considering MFS root f/s.\n");
276		mountrootfsname = "mfs";
277		/*
278		 * Ignore the -a flag if this kernel isn't compiled
279		 * with a generic root/swap configuration: if we skip
280		 * setroot() and we aren't a generic kernel, chaos
281		 * will ensue because setconf() will be a no-op.
282		 * (rootdev is always initialized to NODEV in a
283		 * generic configuration, so we test for that.)
284		 */
285		if ((boothowto & RB_ASKNAME) == 0 || rootdev != NODEV)
286			setroot();
287	}
288#endif
289
290#ifdef BOOTP_NFSROOT
291	if (!mountrootfsname && !nfs_diskless_valid) {
292		if (bootverbose)
293			printf("Considering BOOTP NFS root f/s.\n");
294		mountrootfsname = "nfs";
295	}
296#endif /* BOOTP_NFSROOT */
297#ifdef NFS
298	if (!mountrootfsname && nfs_diskless_valid) {
299		if (bootverbose)
300			printf("Considering NFS root f/s.\n");
301		mountrootfsname = "nfs";
302	}
303#endif /* NFS */
304
305#ifdef FFS
306	if (!mountrootfsname) {
307		mountrootfsname = "ufs";
308		if (bootverbose)
309			printf("Considering FFS root f/s.\n");
310		/*
311		 * Ignore the -a flag if this kernel isn't compiled
312		 * with a generic root/swap configuration: if we skip
313		 * setroot() and we aren't a generic kernel, chaos
314		 * will ensue because setconf() will be a no-op.
315		 * (rootdev is always initialized to NODEV in a
316		 * generic configuration, so we test for that.)
317		 */
318		if ((boothowto & RB_ASKNAME) == 0 || rootdev != NODEV)
319			setroot();
320	}
321#endif
322
323#ifdef LFS
324	if (!mountrootfsname) {
325		if (bootverbose)
326			printf("Considering LFS root f/s.\n");
327		mountrootfsname = "lfs";
328		/*
329		 * Ignore the -a flag if this kernel isn't compiled
330		 * with a generic root/swap configuration: if we skip
331		 * setroot() and we aren't a generic kernel, chaos
332		 * will ensue because setconf() will be a no-op.
333		 * (rootdev is always initialized to NODEV in a
334		 * generic configuration, so we test for that.)
335		 */
336		if ((boothowto & RB_ASKNAME) == 0 || rootdev != NODEV)
337			setroot();
338	}
339#endif
340
341	if (!mountrootfsname) {
342		panic("Nobody wants to mount my root for me");
343	}
344
345	setconf();
346	cold = 0;
347	if (bootverbose)
348		printf("configure() finished.\n");
349}
350
351static int
352setdumpdev(dev)
353	dev_t dev;
354{
355	int maj, psize;
356	long newdumplo;
357
358	if (dev == NODEV) {
359		dumpdev = dev;
360		return (0);
361	}
362	maj = major(dev);
363	if (maj >= nblkdev)
364		return (ENXIO);
365	if (bdevsw[maj] == NULL)
366		return (ENXIO);		/* XXX is this right? */
367	if (bdevsw[maj]->d_psize == NULL)
368		return (ENXIO);		/* XXX should be ENODEV ? */
369	psize = bdevsw[maj]->d_psize(dev);
370	if (psize == -1)
371		return (ENXIO);		/* XXX should be ENODEV ? */
372	newdumplo = psize - Maxmem * PAGE_SIZE / DEV_BSIZE;
373	if (newdumplo < 0)
374		return (ENOSPC);
375	dumpdev = dev;
376	dumplo = newdumplo;
377	return (0);
378}
379
380u_long	bootdev = 0;		/* not a dev_t - encoding is different */
381
382static	char devname[][2] = {
383      {'w','d'},      /* 0 = wd */
384      {'s','w'},      /* 1 = sw */
385#define FDMAJOR 2
386      {'f','d'},      /* 2 = fd */
387      {'w','t'},      /* 3 = wt */
388      {'s','d'},      /* 4 = sd -- new SCSI system */
389};
390
391#define	PARTITIONMASK	0x7
392#define	PARTITIONSHIFT	3
393#define FDUNITSHIFT     6
394#define RAW_PART        2
395
396/*
397 * Attempt to find the device from which we were booted.
398 * If we can do so, and not instructed not to do so,
399 * change rootdev to correspond to the load device.
400 */
401static void
402setroot()
403{
404	int  majdev, mindev, unit, part, adaptor;
405	dev_t orootdev;
406
407/*printf("howto %x bootdev %x ", boothowto, bootdev);*/
408	if (boothowto & RB_DFLTROOT ||
409	    (bootdev & B_MAGICMASK) != (u_long)B_DEVMAGIC)
410		return;
411	majdev = (bootdev >> B_TYPESHIFT) & B_TYPEMASK;
412	if (majdev > sizeof(devname) / sizeof(devname[0]))
413		return;
414	adaptor = (bootdev >> B_ADAPTORSHIFT) & B_ADAPTORMASK;
415	unit = (bootdev >> B_UNITSHIFT) & B_UNITMASK;
416	if (majdev == FDMAJOR) {
417		part = RAW_PART;
418		mindev = unit << FDUNITSHIFT;
419	}
420	else {
421		part = (bootdev >> B_PARTITIONSHIFT) & B_PARTITIONMASK;
422		mindev = (unit << PARTITIONSHIFT) + part;
423	}
424	orootdev = rootdev;
425	rootdev = makedev(majdev, mindev);
426	/*
427	 * If the original rootdev is the same as the one
428	 * just calculated, don't need to adjust the swap configuration.
429	 */
430	if (rootdev == orootdev)
431		return;
432	printf("changing root device to %c%c%d%c\n",
433		devname[majdev][0], devname[majdev][1],
434		mindev >> (majdev == FDMAJOR ? FDUNITSHIFT : PARTITIONSHIFT),
435		part + 'a');
436}
437
438static int
439sysctl_kern_dumpdev SYSCTL_HANDLER_ARGS
440{
441	int error;
442	dev_t ndumpdev;
443
444	ndumpdev = dumpdev;
445	error = sysctl_handle_opaque(oidp, &ndumpdev, sizeof ndumpdev, req);
446	if (error == 0 && req->newptr != NULL)
447		error = setdumpdev(ndumpdev);
448	return (error);
449}
450
451SYSCTL_PROC(_kern, KERN_DUMPDEV, dumpdev, CTLTYPE_OPAQUE|CTLFLAG_RW,
452	0, sizeof dumpdev, sysctl_kern_dumpdev, "T,dev_t", "");
453