autoconf.c revision 1.14 1 /* $NetBSD: autoconf.c,v 1.14 1996/10/13 02:59:23 christos Exp $ */
2
3 /*
4 * Copyright (c) 1992, 1993
5 * The Regents of the University of California. All rights reserved.
6 *
7 * This software was developed by the Computer Systems Engineering group
8 * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
9 * contributed to Berkeley.
10 *
11 * All advertising materials mentioning features or use of this software
12 * must display the following acknowledgement:
13 * This product includes software developed by the University of
14 * California, Lawrence Berkeley Laboratory.
15 *
16 * Redistribution and use in source and binary forms, with or without
17 * modification, are permitted provided that the following conditions
18 * are met:
19 * 1. Redistributions of source code must retain the above copyright
20 * notice, this list of conditions and the following disclaimer.
21 * 2. Redistributions in binary form must reproduce the above copyright
22 * notice, this list of conditions and the following disclaimer in the
23 * documentation and/or other materials provided with the distribution.
24 * 3. All advertising materials mentioning features or use of this software
25 * must display the following acknowledgement:
26 * This product includes software developed by the University of
27 * California, Berkeley and its contributors.
28 * 4. Neither the name of the University nor the names of its contributors
29 * may be used to endorse or promote products derived from this software
30 * without specific prior written permission.
31 *
32 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
33 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
34 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
35 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
36 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
37 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
38 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
39 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
40 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
41 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
42 * SUCH DAMAGE.
43 *
44 * @(#)autoconf.c 8.4 (Berkeley) 10/1/93
45 */
46
47 #include <sys/param.h>
48 #include <sys/systm.h>
49 #include <sys/buf.h>
50 #include <sys/disklabel.h>
51 #include <sys/conf.h>
52 #include <sys/reboot.h>
53 #include <sys/device.h>
54
55 #include <machine/autoconf.h>
56 #include <machine/prom.h>
57
58 extern char root_device[17]; /* XXX */
59
60 struct device *booted_device;
61 int booted_partition;
62 struct bootdev_data *bootdev_data;
63 char boot_dev[128];
64
65 void parse_prom_bootdev __P((void));
66 int atoi __P((char *));
67
68 static struct device *parsedisk __P((char *str, int len, int defpart,
69 dev_t *devp));
70 static struct device *getdisk __P((char *str, int len, int defpart,
71 dev_t *devp));
72 static int findblkmajor __P((struct device *dv));
73 static char *findblkname __P((int));
74 static int getstr __P((char *cp, int size));
75
76 /*
77 * configure:
78 * called at boot time, configure all devices on system
79 */
80 void
81 configure()
82 {
83 extern int cold;
84
85 parse_prom_bootdev();
86
87 (void)splhigh();
88 if (config_rootfound("mainbus", "mainbus") == NULL)
89 panic("no mainbus found");
90 (void)spl0();
91
92 if (booted_device == NULL)
93 printf("WARNING: can't figure what device matches \"%s\"\n",
94 boot_dev);
95 setroot();
96 swapconf();
97 cold = 0;
98 }
99
100 /*
101 * Configure swap space and related parameters.
102 */
103 swapconf()
104 {
105 struct swdevt *swp;
106 int nblks, maj;
107
108 for (swp = swdevt; swp->sw_dev != NODEV; swp++) {
109 maj = major(swp->sw_dev);
110 if (maj > nblkdev)
111 break;
112 if (bdevsw[maj].d_psize) {
113 nblks = (*bdevsw[maj].d_psize)(swp->sw_dev);
114 if (nblks != -1 &&
115 (swp->sw_nblks == 0 || swp->sw_nblks > nblks))
116 swp->sw_nblks = nblks;
117 swp->sw_nblks = ctod(dtoc(swp->sw_nblks));
118 }
119 }
120 dumpconf();
121 }
122
123 struct nam2blk {
124 char *name;
125 int maj;
126 } nam2blk[] = {
127 { "st", 2 },
128 { "cd", 3 },
129 { "rd", 6 },
130 { "sd", 8 },
131 #if 0
132 { "fd", XXX },
133 #endif
134 };
135
136 #ifdef RAMDISK_HOOKS
137 static struct device fakerdrootdev = { DV_DISK, {}, NULL, 0, "rd0", NULL };
138 #endif
139
140 static int
141 findblkmajor(dv)
142 struct device *dv;
143 {
144 char *name = dv->dv_xname;
145 register int i;
146
147 for (i = 0; i < sizeof(nam2blk)/sizeof(nam2blk[0]); ++i)
148 if (strncmp(name, nam2blk[i].name, strlen(nam2blk[0].name))
149 == 0)
150 return (nam2blk[i].maj);
151 return (-1);
152 }
153
154 static char *
155 findblkname(maj)
156 int maj;
157 {
158 register int i;
159
160 for (i = 0; i < sizeof(nam2blk)/sizeof(nam2blk[0]); ++i)
161 if (maj == nam2blk[i].maj)
162 return (nam2blk[i].name);
163 return (NULL);
164 }
165
166 static struct device *
167 getdisk(str, len, defpart, devp)
168 char *str;
169 int len, defpart;
170 dev_t *devp;
171 {
172 register struct device *dv;
173
174 if ((dv = parsedisk(str, len, defpart, devp)) == NULL) {
175 printf("use one of:");
176 #ifdef RAMDISK_HOOKS
177 printf(" %s[a-h]", fakerdrootdev.dv_xname);
178 #endif
179 for (dv = alldevs.tqh_first; dv != NULL;
180 dv = dv->dv_list.tqe_next) {
181 if (dv->dv_class == DV_DISK)
182 printf(" %s[a-h]", dv->dv_xname);
183 #ifdef NFSCLIENT
184 if (dv->dv_class == DV_IFNET)
185 printf(" %s", dv->dv_xname);
186 #endif
187 }
188 printf(" halt\n");
189 }
190 return (dv);
191 }
192
193 static struct device *
194 parsedisk(str, len, defpart, devp)
195 char *str;
196 int len, defpart;
197 dev_t *devp;
198 {
199 register struct device *dv;
200 register char *cp, c;
201 int majdev, part;
202
203 if (len == 0)
204 return (NULL);
205
206 if (len == 4 && !strcmp(str, "halt"))
207 boot(RB_HALT, NULL);
208
209 cp = str + len - 1;
210 c = *cp;
211 if (c >= 'a' && c <= ('a' + MAXPARTITIONS - 1)) {
212 part = c - 'a';
213 *cp = '\0';
214 } else
215 part = defpart;
216
217 #ifdef RAMDISK_HOOKS
218 if (strcmp(str, fakerdrootdev.dv_xname) == 0) {
219 dv = &fakerdrootdev;
220 goto gotdisk;
221 }
222 #endif
223 for (dv = alldevs.tqh_first; dv != NULL; dv = dv->dv_list.tqe_next) {
224 if (dv->dv_class == DV_DISK &&
225 strcmp(str, dv->dv_xname) == 0) {
226 #ifdef RAMDISK_HOOKS
227 gotdisk:
228 #endif
229 majdev = findblkmajor(dv);
230 if (majdev < 0)
231 panic("parsedisk");
232 *devp = MAKEDISKDEV(majdev, dv->dv_unit, part);
233 break;
234 }
235 #ifdef NFSCLIENT
236 if (dv->dv_class == DV_IFNET &&
237 strcmp(str, dv->dv_xname) == 0) {
238 *devp = NODEV;
239 break;
240 }
241 #endif
242 }
243
244 *cp = c;
245 return (dv);
246 }
247
248 /*
249 * Attempt to find the device from which we were booted.
250 * If we can do so, and not instructed not to do so,
251 * change rootdev to correspond to the load device.
252 *
253 * XXX Actually, swap and root must be on the same type of device,
254 * (ie. DV_DISK or DV_IFNET) because of how (*mountroot) is written.
255 * That should be fixed.
256 */
257 setroot()
258 {
259 struct swdevt *swp;
260 struct device *dv;
261 register int len;
262 dev_t nrootdev, nswapdev = NODEV;
263 char buf[128], *rootdevname;
264 extern int (*mountroot) __P((void *));
265 dev_t temp;
266 struct device *bootdv, *rootdv, *swapdv;
267 int bootpartition;
268 #if defined(NFSCLIENT)
269 extern char *nfsbootdevname;
270 extern int nfs_mountroot __P((void *));
271 #endif
272 #if defined(FFS)
273 extern int ffs_mountroot __P((void *));
274 #endif
275
276 #ifdef RAMDISK_HOOKS
277 bootdv = &fakerdrootdev;
278 bootpartition = 0;
279 #else
280 bootdv = booted_device;
281 bootpartition = booted_partition;
282 #endif
283
284 /*
285 * If 'swap generic' and we couldn't determine root device,
286 * ask the user.
287 */
288 if (mountroot == NULL && bootdv == NULL)
289 boothowto |= RB_ASKNAME;
290
291 if (boothowto & RB_ASKNAME) {
292 for (;;) {
293 printf("root device");
294 if (bootdv != NULL) {
295 printf(" (default %s", bootdv->dv_xname);
296 if (bootdv->dv_class == DV_DISK)
297 printf("%c", bootpartition + 'a');
298 printf(")");
299 }
300 printf(": ");
301 len = getstr(buf, sizeof(buf));
302 if (len == 0 && bootdv != NULL) {
303 strcpy(buf, bootdv->dv_xname);
304 len = strlen(buf);
305 }
306 if (len > 0 && buf[len - 1] == '*') {
307 buf[--len] = '\0';
308 dv = getdisk(buf, len, 1, &nrootdev);
309 if (dv != NULL) {
310 rootdv = dv;
311 nswapdev = nrootdev;
312 goto gotswap;
313 }
314 }
315 dv = getdisk(buf, len, bootpartition, &nrootdev);
316 if (dv != NULL) {
317 rootdv = dv;
318 break;
319 }
320 }
321
322 /*
323 * because swap must be on same device type as root, for
324 * network devices this is easy.
325 */
326 if (rootdv->dv_class == DV_IFNET) {
327 swapdv = NULL;
328 goto gotswap;
329 }
330 for (;;) {
331 printf("swap device");
332 printf(" (default %s", rootdv->dv_xname);
333 if (rootdv->dv_class == DV_DISK)
334 printf("b");
335 printf(")");
336 printf(": ");
337 len = getstr(buf, sizeof(buf));
338 if (len == 0) {
339 switch (rootdv->dv_class) {
340 case DV_IFNET:
341 nswapdev = NODEV;
342 break;
343 case DV_DISK:
344 nswapdev = MAKEDISKDEV(major(nrootdev),
345 DISKUNIT(nrootdev), 1);
346 break;
347 case DV_TAPE:
348 case DV_TTY:
349 case DV_DULL:
350 case DV_CPU:
351 break;
352 }
353 swapdv = rootdv;
354 break;
355 }
356 dv = getdisk(buf, len, 1, &nswapdev);
357 if (dv) {
358 if (dv->dv_class == DV_IFNET)
359 nswapdev = NODEV;
360 swapdv = dv;
361 break;
362 }
363 }
364 gotswap:
365 rootdev = nrootdev;
366 dumpdev = nswapdev;
367 swdevt[0].sw_dev = nswapdev;
368 swdevt[1].sw_dev = NODEV;
369 } else if (mountroot == NULL) {
370 int majdev;
371
372 /*
373 * "swap generic"
374 */
375 majdev = findblkmajor(bootdv);
376 if (majdev >= 0) {
377 /*
378 * Root and swap are on a disk.
379 */
380 rootdv = swapdv = bootdv;
381 rootdev = MAKEDISKDEV(majdev, bootdv->dv_unit,
382 bootpartition);
383 nswapdev = dumpdev =
384 MAKEDISKDEV(majdev, bootdv->dv_unit, 1);
385 } else {
386 /*
387 * Root and swap are on a net.
388 */
389 rootdv = swapdv = bootdv;
390 nswapdev = dumpdev = NODEV;
391 }
392 swdevt[0].sw_dev = nswapdev;
393 swdevt[1].sw_dev = NODEV;
394 } else {
395 /*
396 * `root DEV swap DEV': honor rootdev/swdevt.
397 * rootdev/swdevt/mountroot already properly set.
398 */
399
400 rootdevname = findblkname(major(rootdev));
401 if (rootdevname == NULL) {
402 /* Root on NFS or unknown device. */
403 strcpy(root_device, "??");
404 } else {
405 /* Root on known block device. */
406 sprintf(root_device, "%s%d%c", rootdevname,
407 DISKUNIT(rootdev), DISKPART(rootdev) + 'a');
408 }
409
410 return;
411 }
412
413 switch (rootdv->dv_class) {
414 #if defined(NFSCLIENT)
415 case DV_IFNET:
416 strcpy(root_device, "??");
417 mountroot = nfs_mountroot;
418 nfsbootdevname = rootdv->dv_xname;
419 return;
420 #endif
421 #if defined(FFS)
422 case DV_DISK:
423 mountroot = ffs_mountroot;
424 sprintf(root_device, "%s%c", rootdv->dv_xname,
425 DISKPART(rootdev) + 'a');
426 printf("root on %s", root_device);
427 if (nswapdev != NODEV)
428 printf(" swap on %s%c", swapdv->dv_xname,
429 DISKPART(nswapdev) + 'a');
430 printf("\n");
431 break;
432 #endif
433 default:
434 printf("can't figure root, hope your kernel is right\n");
435 return;
436 }
437
438 /*
439 * Make the swap partition on the root drive the primary swap.
440 */
441 temp = NODEV;
442 for (swp = swdevt; swp->sw_dev != NODEV; swp++) {
443 if (major(rootdev) == major(swp->sw_dev) &&
444 DISKUNIT(rootdev) == DISKUNIT(swp->sw_dev)) {
445 temp = swdevt[0].sw_dev;
446 swdevt[0].sw_dev = swp->sw_dev;
447 swp->sw_dev = temp;
448 break;
449 }
450 }
451 if (swp->sw_dev == NODEV)
452 return;
453
454 /*
455 * If dumpdev was the same as the old primary swap device, move
456 * it to the new primary swap device.
457 */
458 if (temp == dumpdev)
459 dumpdev = swdevt[0].sw_dev;
460 }
461
462 static int
463 getstr(cp, size)
464 register char *cp;
465 register int size;
466 {
467 register char *lp;
468 register int c;
469 register int len;
470
471 lp = cp;
472 len = 0;
473 for (;;) {
474 c = cngetc();
475 switch (c) {
476 case '\n':
477 case '\r':
478 printf("\n");
479 *lp++ = '\0';
480 return (len);
481 case '\b':
482 case '\177':
483 case '#':
484 if (len) {
485 --len;
486 --lp;
487 printf("\b \b");
488 }
489 continue;
490 case '@':
491 case 'u'&037:
492 len = 0;
493 lp = cp;
494 printf("\n");
495 continue;
496 default:
497 if (len + 1 >= size || c < ' ') {
498 printf("\007");
499 continue;
500 }
501 printf("%c", c);
502 ++len;
503 *lp++ = c;
504 }
505 }
506 }
507
508 void
509 parse_prom_bootdev()
510 {
511 static char hacked_boot_dev[128];
512 static struct bootdev_data bd;
513 char *cp, *scp, *boot_fields[8];
514 int i, done;
515
516 booted_device = NULL;
517 booted_partition = 0;
518 bootdev_data = NULL;
519
520 prom_getenv(PROM_E_BOOTED_DEV, boot_dev, sizeof(boot_dev));
521 bcopy(boot_dev, hacked_boot_dev, sizeof hacked_boot_dev);
522 #if 0
523 printf("parse_prom_bootdev: boot dev = \"%s\"\n", boot_dev);
524 #endif
525
526 i = 0;
527 scp = cp = hacked_boot_dev;
528 for (done = 0; !done; cp++) {
529 if (*cp != ' ' && *cp != '\0')
530 continue;
531 if (*cp == '\0')
532 done = 1;
533
534 *cp = '\0';
535 boot_fields[i++] = scp;
536 scp = cp + 1;
537 if (i == 8)
538 done = 1;
539 }
540 if (i != 8)
541 return; /* doesn't look like anything we know! */
542
543 #if 0
544 printf("i = %d, done = %d\n", i, done);
545 for (i--; i >= 0; i--)
546 printf("%d = %s\n", i, boot_fields[i]);
547 #endif
548
549 bd.protocol = boot_fields[0];
550 bd.bus = atoi(boot_fields[1]);
551 bd.slot = atoi(boot_fields[2]);
552 bd.channel = atoi(boot_fields[3]);
553 bd.remote_address = boot_fields[4];
554 bd.unit = atoi(boot_fields[5]);
555 bd.boot_dev_type = atoi(boot_fields[6]);
556 bd.ctrl_dev_type = boot_fields[7];
557
558 #if 0
559 printf("parsed: proto = %s, bus = %d, slot = %d, channel = %d,\n",
560 bd.protocol, bd.bus, bd.slot, bd.channel);
561 printf("\tremote = %s, unit = %d, dev_type = %d, ctrl_type = %s\n",
562 bd.remote_address, bd.unit, bd.boot_dev_type, bd.ctrl_dev_type);
563 #endif
564
565 bootdev_data = &bd;
566 }
567
568 int
569 atoi(s)
570 char *s;
571 {
572 int n, neg;
573 char c;
574
575 n = 0;
576 neg = 0;
577
578 while (*s == '-') {
579 s++;
580 neg = !neg;
581 }
582
583 while (*s != '\0') {
584 if (*s < '0' && *s > '9')
585 break;
586
587 n = (10 * n) + (*s - '0');
588 s++;
589 }
590
591 return (neg ? -n : n);
592 }
593
594 void
595 device_register(dev, aux)
596 struct device *dev;
597 void *aux;
598 {
599 extern void (*cpu_device_register) __P((struct device *dev, void *aux));
600
601 if (bootdev_data == NULL) {
602 /*
603 * There is no hope.
604 */
605
606 return;
607 }
608
609 (*cpu_device_register)(dev, aux);
610 }
611