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