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