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