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