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