autoconf.c revision 1.7 1 /* $NetBSD: autoconf.c,v 1.7 1996/06/14 20:40:46 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%c)",
269 bootdv->dv_xname,
270 bootdv->dv_class == DV_DISK
271 ? bootpartition + 'a' : ' ');
272 printf(": ");
273 len = getstr(buf, sizeof(buf));
274 if (len == 0 && bootdv != NULL) {
275 strcpy(buf, bootdv->dv_xname);
276 len = strlen(buf);
277 }
278 if (len == 4 && !strcmp(buf, "halt"))
279 boot(RB_HALT);
280 if (len > 0 && buf[len - 1] == '*') {
281 buf[--len] = '\0';
282 dv = getdisk(buf, len, 1, &nrootdev);
283 if (dv != NULL) {
284 rootdv = dv;
285 nswapdev = nrootdev;
286 goto gotswap;
287 }
288 }
289 dv = getdisk(buf, len, bootpartition, &nrootdev);
290 if (dv != NULL) {
291 rootdv = dv;
292 break;
293 }
294 }
295
296 /*
297 * because swap must be on same device type as root, for
298 * network devices this is easy.
299 */
300 if (rootdv->dv_class == DV_IFNET) {
301 swapdv = NULL;
302 goto gotswap;
303 }
304 for (;;) {
305 printf("swap device");
306 printf(" (default %s%c)", rootdv->dv_xname,
307 rootdv->dv_class == DV_DISK?'b':' ');
308 printf(": ");
309 len = getstr(buf, sizeof(buf));
310 if (len == 0) {
311 switch (rootdv->dv_class) {
312 case DV_IFNET:
313 nswapdev = NODEV;
314 break;
315 case DV_DISK:
316 nswapdev = MAKEDISKDEV(major(nrootdev),
317 DISKUNIT(nrootdev), 1);
318 break;
319 case DV_TAPE:
320 case DV_TTY:
321 case DV_DULL:
322 case DV_CPU:
323 break;
324 }
325 swapdv = rootdv;
326 break;
327 }
328 if (len == 4 && !strcmp(buf, "halt"))
329 boot(RB_HALT);
330 dv = getdisk(buf, len, 1, &nswapdev);
331 if (dv) {
332 if (dv->dv_class == DV_IFNET)
333 nswapdev = NODEV;
334 swapdv = dv;
335 break;
336 }
337 }
338 gotswap:
339 rootdev = nrootdev;
340 dumpdev = nswapdev;
341 swdevt[0].sw_dev = nswapdev;
342 swdevt[1].sw_dev = NODEV;
343 } else if (mountroot == NULL) {
344 int majdev;
345
346 /*
347 * "swap generic"
348 */
349 majdev = findblkmajor(bootdv);
350 if (majdev >= 0) {
351 /*
352 * Root and swap are on a disk.
353 */
354 rootdv = swapdv = bootdv;
355 rootdev = MAKEDISKDEV(majdev, bootdv->dv_unit,
356 bootpartition);
357 nswapdev = dumpdev =
358 MAKEDISKDEV(majdev, bootdv->dv_unit, 1);
359 } else {
360 /*
361 * Root and swap are on a net.
362 */
363 rootdv = swapdv = bootdv;
364 nswapdev = dumpdev = NODEV;
365 }
366 swdevt[0].sw_dev = nswapdev;
367 swdevt[1].sw_dev = NODEV;
368 } else {
369 /*
370 * `root DEV swap DEV': honour rootdev/swdevt.
371 * rootdev/swdevt/mountroot already properly set.
372 */
373
374 rootdevname = findblkname(major(rootdev));
375 if (rootdevname == NULL) {
376 /* Root on NFS or unknown device. */
377 strcpy(root_device, "??");
378 } else {
379 /* Root on known block device. */
380 sprintf(root_device, "%s%d%c", rootdevname,
381 DISKUNIT(rootdev), DISKPART(rootdev) + 'a');
382 }
383
384 return;
385 }
386
387 switch (rootdv->dv_class) {
388 #if defined(NFSCLIENT)
389 case DV_IFNET:
390 strcpy(root_device, "??");
391 mountroot = nfs_mountroot;
392 nfsbootdevname = rootdv->dv_xname;
393 return;
394 #endif
395 #if defined(FFS)
396 case DV_DISK:
397 mountroot = ffs_mountroot;
398 sprintf(root_device, "%s%c", rootdv->dv_xname,
399 DISKPART(rootdev) + 'a');
400 printf("root on %s", root_device);
401 if (nswapdev != NODEV)
402 printf(" swap on %s%c", swapdv->dv_xname,
403 DISKPART(nswapdev) + 'a');
404 printf("\n");
405 break;
406 #endif
407 default:
408 printf("can't figure root, hope your kernel is right\n");
409 return;
410 }
411
412 /*
413 * Make the swap partition on the root drive the primary swap.
414 */
415 temp = NODEV;
416 for (swp = swdevt; swp->sw_dev != NODEV; swp++) {
417 if (major(rootdev) == major(swp->sw_dev) &&
418 DISKUNIT(rootdev) == DISKUNIT(swp->sw_dev)) {
419 temp = swdevt[0].sw_dev;
420 swdevt[0].sw_dev = swp->sw_dev;
421 swp->sw_dev = temp;
422 break;
423 }
424 }
425 if (swp->sw_dev == NODEV)
426 return;
427
428 /*
429 * If dumpdev was the same as the old primary swap device, move
430 * it to the new primary swap device.
431 */
432 if (temp == dumpdev)
433 dumpdev = swdevt[0].sw_dev;
434 }
435
436 static int
437 getstr(cp, size)
438 register char *cp;
439 register int size;
440 {
441 register char *lp;
442 register int c;
443 register int len;
444
445 lp = cp;
446 len = 0;
447 for (;;) {
448 c = cngetc();
449 switch (c) {
450 case '\n':
451 case '\r':
452 printf("\n");
453 *lp++ = '\0';
454 return (len);
455 case '\b':
456 case '\177':
457 case '#':
458 if (len) {
459 --len;
460 --lp;
461 printf("\b \b");
462 }
463 continue;
464 case '@':
465 case 'u'&037:
466 len = 0;
467 lp = cp;
468 printf("\n");
469 continue;
470 default:
471 if (len + 1 >= size || c < ' ') {
472 printf("\007");
473 continue;
474 }
475 printf("%c", c);
476 ++len;
477 *lp++ = c;
478 }
479 }
480 }
481
482 void
483 parse_prom_bootdev()
484 {
485 static char hacked_boot_dev[128];
486 static struct bootdev_data bd;
487 char *cp, *scp, *boot_fields[8];
488 int i, done;
489
490 booted_device = NULL;
491 booted_partition = 0;
492 bootdev_data = NULL;
493
494 prom_getenv(PROM_E_BOOTED_DEV, boot_dev, sizeof(boot_dev));
495 bcopy(boot_dev, hacked_boot_dev, sizeof hacked_boot_dev);
496 #if 0
497 printf("parse_prom_bootdev: boot dev = \"%s\"\n", boot_dev);
498 #endif
499
500 i = 0;
501 scp = cp = hacked_boot_dev;
502 for (done = 0; !done; cp++) {
503 if (*cp != ' ' && *cp != '\0')
504 continue;
505 if (*cp == '\0')
506 done = 1;
507
508 *cp = '\0';
509 boot_fields[i++] = scp;
510 scp = cp + 1;
511 if (i == 8)
512 done = 1;
513 }
514 if (i != 8)
515 return; /* doesn't look like anything we know! */
516
517 #if 0
518 printf("i = %d, done = %d\n", i, done);
519 for (i--; i >= 0; i--)
520 printf("%d = %s\n", i, boot_fields[i]);
521 #endif
522
523 bd.protocol = boot_fields[0];
524 bd.bus = atoi(boot_fields[1]);
525 bd.slot = atoi(boot_fields[2]);
526 bd.channel = atoi(boot_fields[3]);
527 bd.remote_address = boot_fields[4];
528 bd.unit = atoi(boot_fields[5]);
529 bd.boot_dev_type = atoi(boot_fields[6]);
530 bd.ctrl_dev_type = boot_fields[7];
531
532 #if 0
533 printf("parsed: proto = %s, bus = %d, slot = %d, channel = %d,\n",
534 bd.protocol, bd.bus, bd.slot, bd.channel);
535 printf("\tremote = %s, unit = %d, dev_type = %d, ctrl_type = %s\n",
536 bd.remote_address, bd.unit, bd.boot_dev_type, bd.ctrl_dev_type);
537 #endif
538
539 bootdev_data = &bd;
540 }
541
542 int
543 atoi(s)
544 char *s;
545 {
546 int n, neg;
547 char c;
548
549 n = 0;
550 neg = 0;
551
552 while (*s == '-') {
553 s++;
554 neg = !neg;
555 }
556
557 while (*s != '\0') {
558 if (*s < '0' && *s > '9')
559 break;
560
561 n = (10 * n) + (*s - '0');
562 s++;
563 }
564
565 return (neg ? -n : n);
566 }
567
568 void
569 device_register(dev, aux)
570 struct device *dev;
571 void *aux;
572 {
573 extern void (*cpu_device_register) __P((struct device *dev, void *aux));
574
575 if (bootdev_data == NULL) {
576 /*
577 * There is no hope.
578 */
579
580 return;
581 }
582
583 (*cpu_device_register)(dev, aux);
584 }
585