autoconf.c revision 22521
176575Smarkm/*-
276575Smarkm * Copyright (c) 1990 The Regents of the University of California.
376575Smarkm * All rights reserved.
476575Smarkm *
576575Smarkm * This code is derived from software contributed to Berkeley by
676575Smarkm * William Jolitz.
776575Smarkm *
876575Smarkm * Redistribution and use in source and binary forms, with or without
976575Smarkm * modification, are permitted provided that the following conditions
1076575Smarkm * are met:
1176575Smarkm * 1. Redistributions of source code must retain the above copyright
1276575Smarkm *    notice, this list of conditions and the following disclaimer.
1376575Smarkm * 2. Redistributions in binary form must reproduce the above copyright
1476575Smarkm *    notice, this list of conditions and the following disclaimer in the
1576575Smarkm *    documentation and/or other materials provided with the distribution.
1676575Smarkm * 3. All advertising materials mentioning features or use of this software
1776575Smarkm *    must display the following acknowledgement:
1876575Smarkm *	This product includes software developed by the University of
1976575Smarkm *	California, Berkeley and its contributors.
2076575Smarkm * 4. Neither the name of the University nor the names of its contributors
2176575Smarkm *    may be used to endorse or promote products derived from this software
2276575Smarkm *    without specific prior written permission.
2376575Smarkm *
2476575Smarkm * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2576575Smarkm * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2676575Smarkm * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27112044Sobrien * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28112044Sobrien * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29112044Sobrien * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
3076575Smarkm * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
3176575Smarkm * 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 22521 1997-02-10 02:22:35Z dyson $
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 NCRD > 0
165	/* Before isa_configure to avoid ISA drivers finding our cards */
166	pccard_configure();
167#endif
168
169#if NEISA > 0
170	eisa_configure();
171#endif
172
173#if NPCI > 0
174	pci_configure();
175#endif
176
177#if NISA > 0
178	isa_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 NFS
231	if (!mountrootfsname && nfs_diskless_valid) {
232		if (bootverbose)
233			printf("Considering NFS root f/s.\n");
234		mountrootfsname = "nfs";
235	}
236#endif /* NFS */
237
238#ifdef MFS_ROOT
239	if (!mountrootfsname) {
240		if (bootverbose)
241			printf("Considering MFS root f/s.\n");
242		mountrootfsname = "mfs";
243		/*
244		 * Ignore the -a flag if this kernel isn't compiled
245		 * with a generic root/swap configuration: if we skip
246		 * setroot() and we aren't a generic kernel, chaos
247		 * will ensue because setconf() will be a no-op.
248		 * (rootdev is always initialized to NODEV in a
249		 * generic configuration, so we test for that.)
250		 */
251		if ((boothowto & RB_ASKNAME) == 0 || rootdev != NODEV)
252			setroot();
253	}
254#endif
255#ifdef FFS
256	if (!mountrootfsname) {
257		mountrootfsname = "ufs";
258		if (bootverbose)
259			printf("Considering FFS root f/s.\n");
260		/*
261		 * Ignore the -a flag if this kernel isn't compiled
262		 * with a generic root/swap configuration: if we skip
263		 * setroot() and we aren't a generic kernel, chaos
264		 * will ensue because setconf() will be a no-op.
265		 * (rootdev is always initialized to NODEV in a
266		 * generic configuration, so we test for that.)
267		 */
268		if ((boothowto & RB_ASKNAME) == 0 || rootdev != NODEV)
269			setroot();
270	}
271#endif
272#ifdef LFS
273	if (!mountrootfsname) {
274		if (bootverbose)
275			printf("Considering LFS root f/s.\n");
276		mountrootfsname = "lfs";
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	if (!mountrootfsname) {
290		panic("Nobody wants to mount my root for me");
291	}
292
293	setconf();
294	cold = 0;
295	if (bootverbose)
296		printf("configure() finished.\n");
297}
298
299static int
300setdumpdev(dev)
301	dev_t dev;
302{
303	int maj, psize;
304	long newdumplo;
305
306	if (dev == NODEV) {
307		dumpdev = dev;
308		return (0);
309	}
310	maj = major(dev);
311	if (maj >= nblkdev)
312		return (ENXIO);
313	if (bdevsw[maj] == NULL)
314		return (ENXIO);		/* XXX is this right? */
315	if (bdevsw[maj]->d_psize == NULL)
316		return (ENXIO);		/* XXX should be ENODEV ? */
317	psize = bdevsw[maj]->d_psize(dev);
318	if (psize == -1)
319		return (ENXIO);		/* XXX should be ENODEV ? */
320	newdumplo = psize - Maxmem * PAGE_SIZE / DEV_BSIZE;
321	if (newdumplo < 0)
322		return (ENOSPC);
323	dumpdev = dev;
324	dumplo = newdumplo;
325	return (0);
326}
327
328u_long	bootdev = 0;		/* not a dev_t - encoding is different */
329
330static	char devname[][2] = {
331      {'w','d'},      /* 0 = wd */
332      {'s','w'},      /* 1 = sw */
333#define FDMAJOR 2
334      {'f','d'},      /* 2 = fd */
335      {'w','t'},      /* 3 = wt */
336      {'s','d'},      /* 4 = sd -- new SCSI system */
337};
338
339#define	PARTITIONMASK	0x7
340#define	PARTITIONSHIFT	3
341#define FDUNITSHIFT     6
342#define RAW_PART        2
343
344/*
345 * Attempt to find the device from which we were booted.
346 * If we can do so, and not instructed not to do so,
347 * change rootdev to correspond to the load device.
348 */
349static void
350setroot()
351{
352	int  majdev, mindev, unit, part, adaptor;
353	dev_t orootdev;
354
355/*printf("howto %x bootdev %x ", boothowto, bootdev);*/
356	if (boothowto & RB_DFLTROOT ||
357	    (bootdev & B_MAGICMASK) != (u_long)B_DEVMAGIC)
358		return;
359	majdev = (bootdev >> B_TYPESHIFT) & B_TYPEMASK;
360	if (majdev > sizeof(devname) / sizeof(devname[0]))
361		return;
362	adaptor = (bootdev >> B_ADAPTORSHIFT) & B_ADAPTORMASK;
363	unit = (bootdev >> B_UNITSHIFT) & B_UNITMASK;
364	if (majdev == FDMAJOR) {
365		part = RAW_PART;
366		mindev = unit << FDUNITSHIFT;
367	}
368	else {
369		part = (bootdev >> B_PARTITIONSHIFT) & B_PARTITIONMASK;
370		mindev = (unit << PARTITIONSHIFT) + part;
371	}
372	orootdev = rootdev;
373	rootdev = makedev(majdev, mindev);
374	/*
375	 * If the original rootdev is the same as the one
376	 * just calculated, don't need to adjust the swap configuration.
377	 */
378	if (rootdev == orootdev)
379		return;
380	printf("changing root device to %c%c%d%c\n",
381		devname[majdev][0], devname[majdev][1],
382		mindev >> (majdev == FDMAJOR ? FDUNITSHIFT : PARTITIONSHIFT),
383		part + 'a');
384}
385
386static int
387sysctl_kern_dumpdev SYSCTL_HANDLER_ARGS
388{
389	int error;
390	dev_t ndumpdev;
391
392	ndumpdev = dumpdev;
393	error = sysctl_handle_opaque(oidp, &ndumpdev, sizeof ndumpdev, req);
394	if (error == 0 && req->newptr != NULL)
395		error = setdumpdev(ndumpdev);
396	return (error);
397}
398
399SYSCTL_PROC(_kern, KERN_DUMPDEV, dumpdev, CTLTYPE_OPAQUE|CTLFLAG_RW,
400	0, sizeof dumpdev, sysctl_kern_dumpdev, "I", "");
401