autoconf.c revision 42817
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.110 1998/10/26 07:05:34 bde Exp $
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_bootp.h"
49#include "opt_ffs.h"
50#include "opt_cd9660.h"
51#include "opt_mfs.h"
52#include "opt_nfsroot.h"
53
54#include <sys/param.h>
55#include <sys/systm.h>
56#include <sys/conf.h>
57#include <sys/disklabel.h>
58#include <sys/diskslice.h>
59#include <sys/reboot.h>
60#include <sys/kernel.h>
61#include <sys/malloc.h>
62#include <sys/mount.h>
63#include <sys/sysctl.h>
64
65#include <machine/bootinfo.h>
66#include <machine/cons.h>
67#include <machine/ipl.h>
68#include <machine/md_var.h>
69#ifdef APIC_IO
70#include <machine/smp.h>
71#endif /* APIC_IO */
72
73#include <i386/isa/icu.h>
74
75#include "isa.h"
76#if NISA > 0
77#include <i386/isa/isa_device.h>
78#endif
79
80#include "pnp.h"
81#if NPNP > 0
82#include <i386/isa/pnp.h>
83#endif
84
85#include "eisa.h"
86#if NEISA > 0
87#include <i386/eisa/eisaconf.h>
88#endif
89
90#include "pci.h"
91#if NPCI > 0
92#include <pci/pcivar.h>
93#endif
94
95#include <sys/bus.h>
96
97static void	configure_first __P((void *));
98static void	configure __P((void *));
99static void	configure_final __P((void *));
100
101static void	configure_finish __P((void));
102static void	configure_start __P((void));
103static int	setdumpdev __P((dev_t dev));
104static void	setroot __P((void));
105
106SYSINIT(configure1, SI_SUB_CONFIGURE, SI_ORDER_FIRST, configure_first, NULL);
107/* SI_ORDER_SECOND is hookable */
108SYSINIT(configure2, SI_SUB_CONFIGURE, SI_ORDER_THIRD, configure, NULL);
109/* SI_ORDER_MIDDLE is hookable */
110SYSINIT(configure3, SI_SUB_CONFIGURE, SI_ORDER_ANY, configure_final, NULL);
111
112
113#if defined(CD9660) || defined(CD9660_ROOT)
114
115#include <sys/fcntl.h>
116#include <sys/proc.h>
117#include <sys/stat.h>
118#include <machine/clock.h>
119
120/*
121 * XXX All this CD-ROM root stuff is fairly messy.  Ick.
122 *
123 * We need to try out all our potential CDROM drives, so we need a table.
124 */
125static struct {
126	char *name;
127	int major;
128} try_cdrom[] = {
129	{ "cd", 6 },
130	{ "mcd", 7 },
131	{ "scd", 16 },
132	{ "matcd", 17 },
133	{ "wcd", 19 },
134	{ 0, 0}
135};
136
137static int	find_cdrom_root __P((void));
138
139static int
140find_cdrom_root()
141{
142	int i, j, error;
143	struct cdevsw *bd;
144	dev_t orootdev;
145
146#if CD9660_ROOTDELAY > 0
147	DELAY(CD9660_ROOTDELAY * 1000000);
148#endif
149	orootdev = rootdev;
150	for (i = 0 ; i < 2; i++)
151		for (j = 0 ; try_cdrom[j].name ; j++) {
152			if (try_cdrom[j].major >= nblkdev)
153				continue;
154			rootdev = makedev(try_cdrom[j].major, i * 8);
155			bd = bdevsw[major(rootdev)];
156			if (bd == NULL || bd->d_open == NULL)
157				continue;
158			if (bootverbose)
159				printf("trying %s%d as rootdev (0x%x)\n",
160				       try_cdrom[j].name, i, rootdev);
161			error = (bd->d_open)(rootdev, FREAD, S_IFBLK, curproc);
162			if (error == 0) {
163				if (bd->d_close != NULL)
164					(bd->d_close)(rootdev, FREAD, S_IFBLK,
165						      curproc);
166				return 0;
167			}
168		}
169
170	rootdev = orootdev;
171	return EINVAL;
172}
173#endif /* CD9660 || CD9660_ROOT */
174
175#ifdef MFS_ROOT
176extern u_char *mfs_getimage __P((void));
177#endif
178
179static void
180configure_start()
181{
182}
183
184static void
185configure_finish()
186{
187}
188
189/*
190 * Determine i/o configuration for a machine.
191 */
192static void
193configure_first(dummy)
194	void *dummy;
195{
196
197	configure_start();		/* DDB hook? */
198}
199
200static void
201configure(dummy)
202	void *dummy;
203{
204
205	/* Allow all routines to decide for themselves if they want intrs */
206	/*
207	 * XXX Since this cannot be achieved on all architectures, we should
208	 * XXX go back to disabling all interrupts until configuration is
209	 * XXX completed and switch any devices that rely on the current
210	 * XXX behavior to no longer rely on interrupts or to register an
211	 * XXX interrupt_driven_config_hook for the task.
212	 */
213	/*
214	 * XXX The above is wrong, because we're implicitly at splhigh(),
215	 * XXX and should stay there, so enabling interrupts in the CPU
216	 * XXX and the ICU at most gives pending interrupts which just get
217	 * XXX in the way.
218	 */
219#ifdef APIC_IO
220	bsp_apic_configure();
221	enable_intr();
222#else
223	enable_intr();
224	INTREN(IRQ_SLAVE);
225#endif /* APIC_IO */
226
227#if NEISA > 0
228	eisa_configure();
229#endif
230
231#if NPCI > 0
232	pci_configure();
233#endif
234
235#if NPNP > 0
236	pnp_configure();
237#endif
238
239#if NISA > 0
240	isa_configure();
241#endif
242
243	/* initialize new bus architecture */
244	root_bus_configure();
245
246	/*
247	 * Now we're ready to handle (pending) interrupts.
248	 * XXX this is slightly misplaced.
249	 */
250	spl0();
251
252	/*
253	 * Allow lowering of the ipl to the lowest kernel level if we
254	 * panic (or call tsleep() before clearing `cold').  No level is
255	 * completely safe (since a panic may occur in a critical region
256	 * at splhigh()), but we want at least bio interrupts to work.
257	 */
258	safepri = cpl;
259}
260
261static void
262configure_final(dummy)
263	void *dummy;
264{
265	int i;
266
267	configure_finish();			/* DDB hook? */
268
269	cninit_finish();
270
271	if (bootverbose) {
272
273#ifdef APIC_IO
274		imen_dump();
275#endif /* APIC_IO */
276
277		/*
278		 * Print out the BIOS's idea of the disk geometries.
279		 */
280		printf("BIOS Geometries:\n");
281		for (i = 0; i < N_BIOS_GEOM; i++) {
282			unsigned long bios_geom;
283			int max_cylinder, max_head, max_sector;
284
285			bios_geom = bootinfo.bi_bios_geom[i];
286
287			/*
288			 * XXX the bootstrap punts a 1200K floppy geometry
289			 * when the get-disk-geometry interrupt fails.  Skip
290			 * drives that have this geometry.
291			 */
292			if (bios_geom == 0x4f010f)
293				continue;
294
295			printf(" %x:%08lx ", i, bios_geom);
296			max_cylinder = bios_geom >> 16;
297			max_head = (bios_geom >> 8) & 0xff;
298			max_sector = bios_geom & 0xff;
299			printf(
300		"0..%d=%d cylinders, 0..%d=%d heads, 1..%d=%d sectors\n",
301			       max_cylinder, max_cylinder + 1,
302			       max_head, max_head + 1,
303			       max_sector, max_sector);
304		}
305		printf(" %d accounted for\n", bootinfo.bi_n_bios_used);
306
307		printf("Device configuration finished.\n");
308	}
309	cold = 0;
310}
311
312
313void
314cpu_rootconf()
315{
316	/*
317	 * XXX NetBSD has a much cleaner approach to finding root.
318	 * XXX We should adopt their code.
319	 */
320#if defined(CD9660) || defined(CD9660_ROOT)
321	if ((boothowto & RB_CDROM)) {
322		if (bootverbose)
323			printf("Considering CD-ROM root f/s.\n");
324		/* NB: find_cdrom_root() sets rootdev if successful. */
325		if (find_cdrom_root() == 0)
326			mountrootfsname = "cd9660";
327		else if (bootverbose)
328			printf("No CD-ROM available as root f/s.\n");
329	}
330#endif
331
332#ifdef MFS_ROOT
333	if (!mountrootfsname) {
334		if (bootverbose)
335			printf("Considering MFS root f/s.\n");
336		if (mfs_getimage()) {
337			mountrootfsname = "mfs";
338			/*
339			 * Ignore the -a flag if this kernel isn't compiled
340			 * with a generic root/swap configuration: if we skip
341			 * setroot() and we aren't a generic kernel, chaos
342			 * will ensue because setconf() will be a no-op.
343			 * (rootdev is always initialized to NODEV in a
344			 * generic configuration, so we test for that.)
345			 */
346			if ((boothowto & RB_ASKNAME) == 0 || rootdev != NODEV)
347				setroot();
348		} else if (bootverbose)
349			printf("No MFS image available as root f/s.\n");
350	}
351#endif
352
353#ifdef BOOTP_NFSROOT
354	if (!mountrootfsname && !nfs_diskless_valid) {
355		if (bootverbose)
356			printf("Considering BOOTP NFS root f/s.\n");
357		mountrootfsname = "nfs";
358	}
359#endif /* BOOTP_NFSROOT */
360#if defined(NFS) || defined(NFS_ROOT)
361	if (!mountrootfsname && nfs_diskless_valid) {
362		if (bootverbose)
363			printf("Considering NFS root f/s.\n");
364		mountrootfsname = "nfs";
365	}
366#endif /* NFS */
367
368#if defined(FFS) || defined(FFS_ROOT)
369	if (!mountrootfsname) {
370		mountrootfsname = "ufs";
371		if (bootverbose)
372			printf("Considering FFS root f/s.\n");
373		/*
374		 * Ignore the -a flag if this kernel isn't compiled
375		 * with a generic root/swap configuration: if we skip
376		 * setroot() and we aren't a generic kernel, chaos
377		 * will ensue because setconf() will be a no-op.
378		 * (rootdev is always initialized to NODEV in a
379		 * generic configuration, so we test for that.)
380		 */
381		if ((boothowto & RB_ASKNAME) == 0 || rootdev != NODEV)
382			setroot();
383	}
384#endif
385
386	if (!mountrootfsname) {
387		panic("Nobody wants to mount my root for me");
388	}
389
390	setconf();
391}
392
393
394void
395cpu_dumpconf()
396{
397	if (setdumpdev(dumpdev) != 0)
398		dumpdev = NODEV;
399}
400
401static int
402setdumpdev(dev)
403	dev_t dev;
404{
405	int maj, psize;
406	long newdumplo;
407
408	if (dev == NODEV) {
409		dumpdev = dev;
410		return (0);
411	}
412	maj = major(dev);
413	if (maj >= nblkdev || bdevsw[maj] == NULL)
414		return (ENXIO);		/* XXX is this right? */
415	if (bdevsw[maj]->d_psize == NULL)
416		return (ENXIO);		/* XXX should be ENODEV ? */
417	psize = bdevsw[maj]->d_psize(dev);
418	if (psize == -1)
419		return (ENXIO);		/* XXX should be ENODEV ? */
420	/*
421	 * XXX should clean up checking in dumpsys() to be more like this,
422	 * and nuke dodump sysctl (too many knobs), and move this to
423	 * kern_shutdown.c...
424	 */
425	newdumplo = psize - Maxmem * PAGE_SIZE / DEV_BSIZE;
426	if (newdumplo < 0)
427		return (ENOSPC);
428	dumpdev = dev;
429	dumplo = newdumplo;
430	return (0);
431}
432
433
434u_long	bootdev = 0;		/* not a dev_t - encoding is different */
435
436#define FDMAJOR 2
437#define FDUNITSHIFT     6
438
439/*
440 * Attempt to find the device from which we were booted.
441 * If we can do so, and not instructed not to do so,
442 * set rootdevs[] and rootdevnames[] to correspond to the
443 * boot device(s).
444 */
445static void
446setroot()
447{
448	int majdev, mindev, unit, slice, part;
449	dev_t newrootdev;
450	char partname[2];
451	char *sname;
452
453	if (boothowto & RB_DFLTROOT || (bootdev & B_MAGICMASK) != B_DEVMAGIC)
454		return;
455	majdev = B_TYPE(bootdev);
456	if (majdev >= nblkdev || bdevsw[majdev] == NULL)
457		return;
458	unit = B_UNIT(bootdev);
459	slice = B_SLICE(bootdev);
460	if (slice == WHOLE_DISK_SLICE)
461		slice = COMPATIBILITY_SLICE;
462	if (slice < 0 || slice >= MAX_SLICES)
463		return;
464
465	/*
466	 * XXX kludge for inconsistent unit numbering and lack of slice
467	 * support for floppies.
468	 */
469	if (majdev == FDMAJOR) {
470		slice = COMPATIBILITY_SLICE;
471		part = RAW_PART;
472		mindev = unit << FDUNITSHIFT;
473	} else {
474		part = B_PARTITION(bootdev);
475		mindev = dkmakeminor(unit, slice, part);
476	}
477
478	newrootdev = makedev(majdev, mindev);
479	rootdevs[0] = newrootdev;
480	sname = dsname(bdevsw[majdev]->d_name, unit, slice, part, partname);
481	rootdevnames[0] = malloc(strlen(sname) + 2, M_DEVBUF, M_NOWAIT);
482	sprintf(rootdevnames[0], "%s%s", sname, partname);
483
484	/*
485	 * For properly dangerously dedicated disks (ones with a historical
486	 * bogus partition table), the boot blocks will give slice = 4, but
487	 * the kernel will only provide the compatibility slice since it
488	 * knows that slice 4 is not a real slice.  Arrange to try mounting
489	 * the compatibility slice as root if mounting the slice passed by
490	 * the boot blocks fails.  This handles the dangerously dedicated
491	 * case and perhaps others.
492	 */
493	if (slice == COMPATIBILITY_SLICE)
494		return;
495	slice = COMPATIBILITY_SLICE;
496	rootdevs[1] = dkmodslice(newrootdev, slice);
497	sname = dsname(bdevsw[majdev]->d_name, unit, slice, part, partname);
498	rootdevnames[1] = malloc(strlen(sname) + 2, M_DEVBUF, M_NOWAIT);
499	sprintf(rootdevnames[1], "%s%s", sname, partname);
500}
501
502
503static int
504sysctl_kern_dumpdev SYSCTL_HANDLER_ARGS
505{
506	int error;
507	dev_t ndumpdev;
508
509	ndumpdev = dumpdev;
510	error = sysctl_handle_opaque(oidp, &ndumpdev, sizeof ndumpdev, req);
511	if (error == 0 && req->newptr != NULL)
512		error = setdumpdev(ndumpdev);
513	return (error);
514}
515
516SYSCTL_PROC(_kern, KERN_DUMPDEV, dumpdev, CTLTYPE_OPAQUE|CTLFLAG_RW,
517	0, sizeof dumpdev, sysctl_kern_dumpdev, "T,dev_t", "");
518