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