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