autoconf.c revision 22564
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 *	$FreeBSD: head/sys/i386/i386/autoconf.c 22564 1997-02-11 15:03:31Z bde $
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 <sys/param.h>
49#include <sys/systm.h>
50#include <sys/buf.h>
51#include <sys/conf.h>
52#include <sys/dmap.h>
53#include <sys/reboot.h>
54#include <sys/kernel.h>
55#include <sys/mount.h>
56#include <sys/vnode.h>
57#include <sys/sysctl.h>
58
59#include <machine/bootinfo.h>
60#include <machine/cons.h>
61#include <machine/md_var.h>
62#include <i386/isa/icu.h> /* For interrupts */
63
64#include "isa.h"
65#if NISA > 0
66#include <i386/isa/isa_device.h>
67#endif
68
69#include "eisa.h"
70#if NEISA > 0
71#include <i386/eisa/eisaconf.h>
72#endif
73
74#include "pci.h"
75#if NPCI > 0
76#include <pci/pcivar.h>
77#endif
78
79#include "crd.h"
80#if NCRD > 0
81#include <pccard/driver.h>
82#endif
83
84#include "scbus.h"
85#if NSCBUS > 0
86#include <scsi/scsiconf.h>
87#endif
88
89static void	configure __P((void *));
90SYSINIT(configure, SI_SUB_CONFIGURE, SI_ORDER_FIRST, configure, NULL)
91
92static void	configure_finish __P((void));
93static void	configure_start __P((void));
94static int	setdumpdev __P((dev_t dev));
95static void	setroot __P((void));
96
97#ifdef CD9660
98
99#include <isofs/cd9660/iso.h>
100
101/* We need to try out all our potential CDROM drives, so we need a table. */
102static struct {
103	char *name;
104	int major;
105} try_cdrom[] = {
106	{ "cd", 6 },
107	{ "mcd", 7 },
108	{ "scd", 16 },
109	{ "matcd", 17 },
110	{ 0, 0}
111};
112
113static int	find_cdrom_root __P((void *));
114
115static int
116find_cdrom_root(dummy)
117	void *dummy;
118{
119	int i,j,k;
120
121	for (j = 0 ; j < 2; j++)
122		for (k = 0 ; try_cdrom[k].name ; k++) {
123			rootdev = makedev(try_cdrom[k].major,j*8);
124			printf("trying rootdev=0x%lx (%s%d)\n",
125				rootdev, try_cdrom[k].name,j);
126			i = (*cd9660_mountroot)();
127			if (!i) return i;
128		}
129	return EINVAL;
130}
131#endif /* CD9660 */
132
133static void
134configure_start()
135{
136#if NSCBUS > 0
137	scsi_configure_start();
138#endif
139}
140
141static void
142configure_finish()
143{
144#if NSCBUS > 0
145	scsi_configure_finish();
146#endif
147}
148
149/*
150 * Determine i/o configuration for a machine.
151 */
152static void
153configure(dummy)
154	void *dummy;
155{
156	int i;
157
158	configure_start();
159
160	/* Allow all routines to decide for themselves if they want intrs */
161        enable_intr();
162        INTREN(IRQ_SLAVE);
163
164#if NEISA > 0
165	eisa_configure();
166#endif
167
168#if NPCI > 0
169	pci_configure();
170#endif
171
172#if NISA > 0
173	isa_configure();
174#endif
175
176#if NCRD > 0
177	/* After everyone else has a chance at grabbing resources */
178	pccard_configure();
179#endif
180
181	if (setdumpdev(dumpdev) != 0)
182		dumpdev = NODEV;
183
184	configure_finish();
185
186	cninit_finish();
187
188	if (bootverbose) {
189		/*
190		 * Print out the BIOS's idea of the disk geometries.
191		 */
192		printf("BIOS Geometries:\n");
193		for (i = 0; i < N_BIOS_GEOM; i++) {
194			unsigned long bios_geom;
195			int max_cylinder, max_head, max_sector;
196
197			bios_geom = bootinfo.bi_bios_geom[i];
198
199			/*
200			 * XXX the bootstrap punts a 1200K floppy geometry
201			 * when the get-disk-geometry interrupt fails.  Skip
202			 * drives that have this geometry.
203			 */
204			if (bios_geom == 0x4f010f)
205				continue;
206
207			printf(" %x:%08lx ", i, bios_geom);
208			max_cylinder = bios_geom >> 16;
209			max_head = (bios_geom >> 8) & 0xff;
210			max_sector = bios_geom & 0xff;
211			printf(
212		"0..%d=%d cylinders, 0..%d=%d heads, 1..%d=%d sectors\n",
213			       max_cylinder, max_cylinder + 1,
214			       max_head, max_head + 1,
215			       max_sector, max_sector);
216		}
217		printf(" %d accounted for\n", bootinfo.bi_n_bios_used);
218
219		printf("Device configuration finished.\n");
220	}
221
222#ifdef CD9660
223	if ((boothowto & RB_CDROM)) {
224		if (bootverbose)
225			printf("Considering CD-ROM root f/s.\n");
226		mountrootfsname = "cd9660";
227	}
228#endif
229
230#ifdef MFS_ROOT
231	if (!mountrootfsname) {
232		if (bootverbose)
233			printf("Considering MFS root f/s.\n");
234		mountrootfsname = "mfs";
235		/*
236		 * Ignore the -a flag if this kernel isn't compiled
237		 * with a generic root/swap configuration: if we skip
238		 * setroot() and we aren't a generic kernel, chaos
239		 * will ensue because setconf() will be a no-op.
240		 * (rootdev is always initialized to NODEV in a
241		 * generic configuration, so we test for that.)
242		 */
243		if ((boothowto & RB_ASKNAME) == 0 || rootdev != NODEV)
244			setroot();
245	}
246#endif
247
248#ifdef NFS
249	if (!mountrootfsname && nfs_diskless_valid) {
250		if (bootverbose)
251			printf("Considering NFS root f/s.\n");
252		mountrootfsname = "nfs";
253	}
254#endif /* NFS */
255
256#ifdef FFS
257	if (!mountrootfsname) {
258		mountrootfsname = "ufs";
259		if (bootverbose)
260			printf("Considering FFS root f/s.\n");
261		/*
262		 * Ignore the -a flag if this kernel isn't compiled
263		 * with a generic root/swap configuration: if we skip
264		 * setroot() and we aren't a generic kernel, chaos
265		 * will ensue because setconf() will be a no-op.
266		 * (rootdev is always initialized to NODEV in a
267		 * generic configuration, so we test for that.)
268		 */
269		if ((boothowto & RB_ASKNAME) == 0 || rootdev != NODEV)
270			setroot();
271	}
272#endif
273
274#ifdef LFS
275	if (!mountrootfsname) {
276		if (bootverbose)
277			printf("Considering LFS root f/s.\n");
278		mountrootfsname = "lfs";
279		/*
280		 * Ignore the -a flag if this kernel isn't compiled
281		 * with a generic root/swap configuration: if we skip
282		 * setroot() and we aren't a generic kernel, chaos
283		 * will ensue because setconf() will be a no-op.
284		 * (rootdev is always initialized to NODEV in a
285		 * generic configuration, so we test for that.)
286		 */
287		if ((boothowto & RB_ASKNAME) == 0 || rootdev != NODEV)
288			setroot();
289	}
290#endif
291
292	if (!mountrootfsname) {
293		panic("Nobody wants to mount my root for me");
294	}
295
296	setconf();
297	cold = 0;
298	if (bootverbose)
299		printf("configure() finished.\n");
300}
301
302static int
303setdumpdev(dev)
304	dev_t dev;
305{
306	int maj, psize;
307	long newdumplo;
308
309	if (dev == NODEV) {
310		dumpdev = dev;
311		return (0);
312	}
313	maj = major(dev);
314	if (maj >= nblkdev)
315		return (ENXIO);
316	if (bdevsw[maj] == NULL)
317		return (ENXIO);		/* XXX is this right? */
318	if (bdevsw[maj]->d_psize == NULL)
319		return (ENXIO);		/* XXX should be ENODEV ? */
320	psize = bdevsw[maj]->d_psize(dev);
321	if (psize == -1)
322		return (ENXIO);		/* XXX should be ENODEV ? */
323	newdumplo = psize - Maxmem * PAGE_SIZE / DEV_BSIZE;
324	if (newdumplo < 0)
325		return (ENOSPC);
326	dumpdev = dev;
327	dumplo = newdumplo;
328	return (0);
329}
330
331u_long	bootdev = 0;		/* not a dev_t - encoding is different */
332
333static	char devname[][2] = {
334      {'w','d'},      /* 0 = wd */
335      {'s','w'},      /* 1 = sw */
336#define FDMAJOR 2
337      {'f','d'},      /* 2 = fd */
338      {'w','t'},      /* 3 = wt */
339      {'s','d'},      /* 4 = sd -- new SCSI system */
340};
341
342#define	PARTITIONMASK	0x7
343#define	PARTITIONSHIFT	3
344#define FDUNITSHIFT     6
345#define RAW_PART        2
346
347/*
348 * Attempt to find the device from which we were booted.
349 * If we can do so, and not instructed not to do so,
350 * change rootdev to correspond to the load device.
351 */
352static void
353setroot()
354{
355	int  majdev, mindev, unit, part, adaptor;
356	dev_t orootdev;
357
358/*printf("howto %x bootdev %x ", boothowto, bootdev);*/
359	if (boothowto & RB_DFLTROOT ||
360	    (bootdev & B_MAGICMASK) != (u_long)B_DEVMAGIC)
361		return;
362	majdev = (bootdev >> B_TYPESHIFT) & B_TYPEMASK;
363	if (majdev > sizeof(devname) / sizeof(devname[0]))
364		return;
365	adaptor = (bootdev >> B_ADAPTORSHIFT) & B_ADAPTORMASK;
366	unit = (bootdev >> B_UNITSHIFT) & B_UNITMASK;
367	if (majdev == FDMAJOR) {
368		part = RAW_PART;
369		mindev = unit << FDUNITSHIFT;
370	}
371	else {
372		part = (bootdev >> B_PARTITIONSHIFT) & B_PARTITIONMASK;
373		mindev = (unit << PARTITIONSHIFT) + part;
374	}
375	orootdev = rootdev;
376	rootdev = makedev(majdev, mindev);
377	/*
378	 * If the original rootdev is the same as the one
379	 * just calculated, don't need to adjust the swap configuration.
380	 */
381	if (rootdev == orootdev)
382		return;
383	printf("changing root device to %c%c%d%c\n",
384		devname[majdev][0], devname[majdev][1],
385		mindev >> (majdev == FDMAJOR ? FDUNITSHIFT : PARTITIONSHIFT),
386		part + 'a');
387}
388
389static int
390sysctl_kern_dumpdev SYSCTL_HANDLER_ARGS
391{
392	int error;
393	dev_t ndumpdev;
394
395	ndumpdev = dumpdev;
396	error = sysctl_handle_opaque(oidp, &ndumpdev, sizeof ndumpdev, req);
397	if (error == 0 && req->newptr != NULL)
398		error = setdumpdev(ndumpdev);
399	return (error);
400}
401
402SYSCTL_PROC(_kern, KERN_DUMPDEV, dumpdev, CTLTYPE_OPAQUE|CTLFLAG_RW,
403	0, sizeof dumpdev, sysctl_kern_dumpdev, "T,dev_t", "");
404