Annotation of sys/arch/sparc/sparc/autoconf.c, Revision 1.1.1.1
1.1 nbrk 1: /* $OpenBSD: autoconf.c,v 1.80 2007/06/01 19:25:10 deraadt Exp $ */
2: /* $NetBSD: autoconf.c,v 1.73 1997/07/29 09:41:53 fair Exp $ */
3:
4: /*
5: * Copyright (c) 1996
6: * The President and Fellows of Harvard College. All rights reserved.
7: * Copyright (c) 1992, 1993
8: * The Regents of the University of California. All rights reserved.
9: *
10: * This software was developed by the Computer Systems Engineering group
11: * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
12: * contributed to Berkeley.
13: *
14: * All advertising materials mentioning features or use of this software
15: * must display the following acknowledgement:
16: * This product includes software developed by Harvard University.
17: * This product includes software developed by the University of
18: * California, Lawrence Berkeley Laboratory.
19: *
20: * Redistribution and use in source and binary forms, with or without
21: * modification, are permitted provided that the following conditions
22: * are met:
23: * 1. Redistributions of source code must retain the above copyright
24: * notice, this list of conditions and the following disclaimer.
25: * 2. Redistributions in binary form must reproduce the above copyright
26: * notice, this list of conditions and the following disclaimer in the
27: * documentation and/or other materials provided with the distribution.
28: * 3. 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/device.h>
52: #include <sys/disk.h>
53: #include <sys/dkstat.h>
54: #include <sys/conf.h>
55: #include <sys/reboot.h>
56: #include <sys/socket.h>
57: #include <sys/malloc.h>
58: #include <sys/queue.h>
59: #include <sys/user.h>
60:
61: #include <net/if.h>
62:
63: #include <scsi/scsi_all.h>
64: #include <scsi/scsiconf.h>
65:
66: #include <dev/cons.h>
67:
68: #include <uvm/uvm_extern.h>
69:
70: #include <machine/autoconf.h>
71: #include <machine/bsd_openprom.h>
72: #ifdef SUN4
73: #include <machine/oldmon.h>
74: #include <machine/idprom.h>
75: #include <sparc/sparc/memreg.h>
76: #endif
77: #include <machine/cpu.h>
78: #include <machine/ctlreg.h>
79: #include <machine/pmap.h>
80: #include <sparc/sparc/asm.h>
81: #include <sparc/sparc/cpuvar.h>
82: #include <sparc/sparc/timerreg.h>
83:
84: #ifdef DDB
85: #include <machine/db_machdep.h>
86: #include <ddb/db_sym.h>
87: #include <ddb/db_extern.h>
88: #endif
89:
90:
91: /*
92: * The following several variables are related to
93: * the configuration process, and are used in initializing
94: * the machine.
95: */
96: int fbnode; /* node ID of ROM's console frame buffer */
97: int optionsnode; /* node ID of ROM's options */
98: int mmu_3l; /* SUN4_400 models have a 3-level MMU */
99:
100: #ifdef KGDB
101: extern int kgdb_debug_panic;
102: #endif
103:
104: static int rootnode;
105: static char *str2hex(char *, int *);
106: static int mbprint(void *, const char *);
107: static void crazymap(char *, int *);
108: void sync_crash(void);
109: int mainbus_match(struct device *, void *, void *);
110: static void mainbus_attach(struct device *, struct device *, void *);
111:
112: struct bootpath bootpath[8];
113: int nbootpath;
114: static void bootpath_build(void);
115: static void bootpath_fake(struct bootpath *, char *);
116: static void bootpath_print(struct bootpath *);
117: int search_prom(int, char *);
118: char mainbus_model[30];
119:
120: /* Translate SBus interrupt level to processor IPL */
121: int intr_sbus2ipl_4c[] = {
122: 0, 1, 2, 3, 5, 7, 8, 9
123: };
124: int intr_sbus2ipl_4m[] = {
125: 0, 2, 3, 5, 7, 9, 11, 13
126: };
127:
128: /*
129: * Convert hex ASCII string to a value. Returns updated pointer.
130: * Depends on ASCII order (this *is* machine-dependent code, you know).
131: */
132: static char *
133: str2hex(str, vp)
134: register char *str;
135: register int *vp;
136: {
137: register int v, c;
138:
139: for (v = 0;; v = v * 16 + c, str++) {
140: c = *(u_char *)str;
141: if (c <= '9') {
142: if ((c -= '0') < 0)
143: break;
144: } else if (c <= 'F') {
145: if ((c -= 'A' - 10) < 10)
146: break;
147: } else if (c <= 'f') {
148: if ((c -= 'a' - 10) < 10)
149: break;
150: } else
151: break;
152: }
153: *vp = v;
154: return (str);
155: }
156:
157: #ifdef SUN4
158: struct promvec promvecdat;
159: struct om_vector *oldpvec = (struct om_vector *)PROM_BASE;
160: #endif
161:
162: /*
163: * locore.s code calls bootstrap() just before calling main(), after double
164: * mapping the kernel to high memory and setting up the trap base register.
165: * We must finish mapping the kernel properly and glean any bootstrap info.
166: */
167: void
168: bootstrap()
169: {
170: #if defined(SUN4)
171: if (CPU_ISSUN4) {
172: extern void oldmon_w_cmd(u_long, char *);
173:
174: /*
175: * XXX:
176: * The promvec is bogus. We need to build a
177: * fake one from scratch as soon as possible.
178: */
179: bzero(&promvecdat, sizeof promvecdat);
180: promvec = &promvecdat;
181:
182: promvec->pv_stdin = oldpvec->inSource;
183: promvec->pv_stdout = oldpvec->outSink;
184: promvec->pv_putchar = oldpvec->putChar;
185: promvec->pv_putstr = oldpvec->fbWriteStr;
186: promvec->pv_nbgetchar = oldpvec->mayGet;
187: promvec->pv_getchar = oldpvec->getChar;
188: promvec->pv_romvec_vers = 0; /* eek! */
189: promvec->pv_reboot = oldpvec->reBoot;
190: promvec->pv_abort = oldpvec->abortEntry;
191: promvec->pv_setctxt = oldpvec->setcxsegmap;
192: promvec->pv_v0bootargs = (struct v0bootargs **)(oldpvec->bootParam);
193: promvec->pv_halt = oldpvec->exitToMon;
194:
195: /*
196: * Discover parts of the machine memory organization
197: * that we need this early.
198: */
199: if (oldpvec->romvecVersion >= 2)
200: *oldpvec->vector_cmd = oldmon_w_cmd;
201: }
202: #endif /* SUN4 */
203:
204: bzero(&cpuinfo, sizeof(struct cpu_softc));
205: cpuinfo.master = 1;
206: getcpuinfo(&cpuinfo, 0);
207:
208: pmap_bootstrap(cpuinfo.mmu_ncontext,
209: cpuinfo.mmu_nregion,
210: cpuinfo.mmu_nsegment);
211: /* Moved zs_kgdb_init() to zs.c:consinit() */
212: #ifdef DDB
213: db_machine_init();
214: ddb_init();
215: #endif
216:
217: /*
218: * On sun4ms we have to do some nasty stuff here. We need to map
219: * in the interrupt registers (since we need to find out where
220: * they are from the PROM, since they aren't in a fixed place), and
221: * disable all interrupts. We can't do this easily from locore
222: * since the PROM is ugly to use from assembly. We also need to map
223: * in the counter registers because we can't disable the level 14
224: * (statclock) interrupt, so we need a handler early on (ugh).
225: *
226: * NOTE: We *demand* the psl to stay at splhigh() at least until
227: * we get here. The system _cannot_ take interrupts until we map
228: * the interrupt registers.
229: */
230:
231: #if defined(SUN4M)
232: #define getpte4m(va) lda(((va) & 0xFFFFF000) | ASI_SRMMUFP_L3, ASI_SRMMUFP)
233:
234: /* First we'll do the interrupt registers */
235: if (CPU_ISSUN4M) {
236: register int node;
237: struct romaux ra;
238: register u_int pte;
239: register int i;
240: extern void setpte4m(u_int, u_int);
241: extern struct timer_4m *timerreg_4m;
242: extern struct counter_4m *counterreg_4m;
243:
244: if ((node = opennode("/obio/interrupt")) == 0)
245: if ((node=search_prom(findroot(),"interrupt"))==0)
246: panic("bootstrap: could not get interrupt "
247: "node from prom");
248:
249: if (!romprop(&ra, "interrupt", node))
250: panic("bootstrap: could not get interrupt properties");
251: if (ra.ra_nvaddrs < 2)
252: panic("bootstrap: less than 2 interrupt regs. available");
253: if (ra.ra_nvaddrs > 5)
254: panic("bootstrap: cannot support capability of > 4 CPUs");
255:
256: for (i = 0; i < ra.ra_nvaddrs - 1; i++) {
257:
258: pte = getpte4m((u_int)ra.ra_vaddrs[i]);
259: if ((pte & SRMMU_TETYPE) != SRMMU_TEPTE)
260: panic("bootstrap: PROM has invalid mapping for "
261: "processor interrupt register %d",i);
262: pte |= PPROT_S;
263:
264: /* Duplicate existing mapping */
265:
266: setpte4m(PI_INTR_VA + (_MAXNBPG * i), pte);
267: }
268:
269: /*
270: * That was the processor register...now get system register;
271: * it is the last returned by the PROM
272: */
273: pte = getpte4m((u_int)ra.ra_vaddrs[i]);
274: if ((pte & SRMMU_TETYPE) != SRMMU_TEPTE)
275: panic("bootstrap: PROM has invalid mapping for system "
276: "interrupt register");
277: pte |= PPROT_S;
278:
279: setpte4m(SI_INTR_VA, pte);
280:
281: /* Now disable interrupts */
282: ienab_bis(SINTR_MA);
283:
284: /* Send all interrupts to primary processor */
285: *((u_int *)ICR_ITR) = 0;
286:
287: #ifdef DEBUG
288: /* printf("SINTR: mask: 0x%x, pend: 0x%x\n", *(int *)ICR_SI_MASK,
289: *(int *)ICR_SI_PEND);
290: */
291: #endif
292:
293: /*
294: * Now map in the counters
295: * (XXX: fix for multiple CPUs! We assume 1)
296: * The processor register is the first; the system is the last.
297: * See also timerattach() in clock.c.
298: * This shouldn't be necessary; we ought to keep interrupts off
299: * and/or disable the (level 14) counter...
300: */
301:
302: if ((node = opennode("/obio/counter")) == 0)
303: if ((node=search_prom(findroot(),"counter"))==0)
304: panic("bootstrap: could not find counter in OPENPROM");
305:
306: if (!romprop(&ra, "counter", node))
307: panic("bootstrap: could not find counter properties");
308:
309: counterreg_4m = (struct counter_4m *)ra.ra_vaddrs[0];
310: timerreg_4m = (struct timer_4m *)ra.ra_vaddrs[ra.ra_nvaddrs-1];
311: }
312: #endif /* SUN4M */
313:
314: if (CPU_ISSUN4OR4C) {
315: /* Map Interrupt Enable Register */
316: pmap_kenter_pa(INTRREG_VA,
317: INT_ENABLE_REG_PHYSADR | PMAP_NC | PMAP_OBIO,
318: VM_PROT_READ | VM_PROT_WRITE);
319: pmap_update(pmap_kernel());
320: /* Disable all interrupts */
321: *((unsigned char *)INTRREG_VA) = 0;
322: }
323: }
324:
325: /*
326: * bootpath_build: build a bootpath. Used when booting a generic
327: * kernel to find our root device. Newer proms give us a bootpath,
328: * for older proms we have to create one. An element in a bootpath
329: * has 4 fields: name (device name), val[0], val[1], and val[2]. Note that:
330: * Interpretation of val[] is device-dependent. Some examples:
331: *
332: * if (val[0] == -1) {
333: * val[1] is a unit number (happens most often with old proms)
334: * } else {
335: * [sbus device] val[0] is a sbus slot, and val[1] is an sbus offset
336: * [scsi disk] val[0] is target, val[1] is lun, val[2] is partition
337: * [scsi tape] val[0] is target, val[1] is lun, val[2] is file #
338: * }
339: *
340: */
341:
342: static void
343: bootpath_build()
344: {
345: register char *cp, *pp;
346: register struct bootpath *bp;
347:
348: /*
349: * On SS1s, promvec->pv_v0bootargs->ba_argv[1] contains the flags
350: * that were given after the boot command. On SS2s, pv_v0bootargs
351: * is NULL but *promvec->pv_v2bootargs.v2_bootargs points to
352: * "vmunix -s" or whatever.
353: * XXX DO THIS BEFORE pmap_bootstrap?
354: */
355: bzero(bootpath, sizeof(bootpath));
356: bp = bootpath;
357: if (promvec->pv_romvec_vers < 2) {
358: /*
359: * Grab boot device name and values. build fake bootpath.
360: */
361: cp = (*promvec->pv_v0bootargs)->ba_argv[0];
362:
363: if (cp != NULL)
364: bootpath_fake(bp, cp);
365:
366: /* Setup pointer to boot flags */
367: cp = (*promvec->pv_v0bootargs)->ba_argv[1];
368: if (cp == NULL || *cp != '-')
369: return;
370: } else {
371: /*
372: * Grab boot path from PROM
373: */
374: cp = *promvec->pv_v2bootargs.v2_bootpath;
375: while (cp != NULL && *cp == '/') {
376: /* Step over '/' */
377: ++cp;
378: /* Extract name */
379: pp = bp->name;
380: while (*cp != '@' && *cp != '/' && *cp != '\0')
381: *pp++ = *cp++;
382: *pp = '\0';
383: if (*cp == '@') {
384: cp = str2hex(++cp, &bp->val[0]);
385: if (*cp == ',')
386: cp = str2hex(++cp, &bp->val[1]);
387: if (*cp == ':') {
388: /*
389: * We only store one character here,
390: * as we will only use this field
391: * to compute a partition index
392: * for block devices. However, it
393: * might be an ethernet media
394: * specification, so be sure to
395: * skip all letters.
396: */
397: bp->val[2] = *++cp - 'a';
398: while (*cp != '\0' && *cp != '/')
399: cp++;
400: }
401: } else {
402: bp->val[0] = -1; /* no #'s: assume unit 0, no
403: sbus offset/address */
404: }
405: ++bp;
406: ++nbootpath;
407: }
408: bp->name[0] = 0;
409:
410: /* Setup pointer to boot flags */
411: cp = *promvec->pv_v2bootargs.v2_bootargs;
412: if (cp == NULL)
413: return;
414: while (*cp != '-')
415: if (*cp++ == '\0')
416: return;
417: }
418: for (;;) {
419: switch (*++cp) {
420:
421: case '\0':
422: return;
423:
424: case 'a':
425: boothowto |= RB_ASKNAME;
426: break;
427:
428: case 'b':
429: boothowto |= RB_DFLTROOT;
430: break;
431:
432: case 'c':
433: boothowto |= RB_CONFIG;
434: break;
435:
436: case 'd': /* kgdb - always on zs XXX */
437: #ifdef KGDB
438: boothowto |= RB_KDB; /* XXX unused */
439: kgdb_debug_panic = 1;
440: kgdb_connect(1);
441: #elif DDB
442: Debugger();
443: #else
444: printf("kernel has no debugger\n");
445: #endif
446: break;
447:
448: case 's':
449: boothowto |= RB_SINGLE;
450: break;
451: }
452: }
453: }
454:
455: /*
456: * Fake a ROM generated bootpath.
457: * The argument `cp' points to a string such as "xd(0,0,0)bsd"
458: */
459:
460: static void
461: bootpath_fake(bp, cp)
462: struct bootpath *bp;
463: char *cp;
464: {
465: register char *pp;
466: int v0val[3];
467:
468: #define BP_APPEND(BP,N,V0,V1,V2) { \
469: strlcpy((BP)->name, N, sizeof (BP)->name); \
470: (BP)->val[0] = (V0); \
471: (BP)->val[1] = (V1); \
472: (BP)->val[2] = (V2); \
473: (BP)++; \
474: nbootpath++; \
475: }
476:
477: #if defined(SUN4)
478: if (CPU_ISSUN4M) {
479: printf("twas brillig..\n");
480: return;
481: }
482: #endif
483:
484: pp = cp + 2;
485: v0val[0] = v0val[1] = v0val[2] = 0;
486: if (*pp == '(' /* for vi: ) */
487: && *(pp = str2hex(++pp, &v0val[0])) == ','
488: && *(pp = str2hex(++pp, &v0val[1])) == ',')
489: (void)str2hex(++pp, &v0val[2]);
490:
491: #if defined(SUN4)
492: if (CPU_ISSUN4) {
493: char tmpname[8];
494:
495: /*
496: * xylogics VME dev: xd, xy, xt
497: * fake looks like: /vmel0/xdc0/xd@1,0
498: */
499: if (cp[0] == 'x') {
500: if (cp[1] == 'd') {/* xd? */
501: BP_APPEND(bp, "vmel", -1, 0, 0);
502: } else {
503: BP_APPEND(bp, "vmes", -1, 0, 0);
504: }
505: snprintf(tmpname,sizeof tmpname,"x%cc", cp[1]); /* e.g. xdc */
506: BP_APPEND(bp, tmpname,-1, v0val[0], 0);
507: snprintf(tmpname,sizeof tmpname,"%c%c", cp[0], cp[1]);
508: BP_APPEND(bp, tmpname,v0val[1], v0val[2], 0); /* e.g. xd */
509: return;
510: }
511:
512: /*
513: * ethernet: ie, le (rom supports only obio?)
514: * fake looks like: /obio0/le0
515: */
516: if ((cp[0] == 'i' || cp[0] == 'l') && cp[1] == 'e') {
517: BP_APPEND(bp, "obio", -1, 0, 0);
518: snprintf(tmpname,sizeof tmpname,"%c%c", cp[0], cp[1]);
519: BP_APPEND(bp, tmpname, -1, 0, 0);
520: return;
521: }
522:
523: /*
524: * scsi: sd, st, sr
525: * assume: 4/100 = sw: /obio0/sw0/sd@0,0:a
526: * 4/200 & 4/400 = si/sc: /vmes0/si0/sd@0,0:a
527: * 4/300 = esp: /obio0/esp0/sd@0,0:a
528: * (note we expect sc to mimic an si...)
529: */
530: if (cp[0] == 's' &&
531: (cp[1] == 'd' || cp[1] == 't' || cp[1] == 'r')) {
532:
533: int target, lun;
534:
535: switch (cpuinfo.cpu_type) {
536: case CPUTYP_4_200:
537: case CPUTYP_4_400:
538: BP_APPEND(bp, "vmes", -1, 0, 0);
539: BP_APPEND(bp, "si", -1, v0val[0], 0);
540: break;
541: case CPUTYP_4_100:
542: BP_APPEND(bp, "obio", -1, 0, 0);
543: BP_APPEND(bp, "sw", -1, v0val[0], 0);
544: break;
545: case CPUTYP_4_300:
546: BP_APPEND(bp, "obio", -1, 0, 0);
547: BP_APPEND(bp, "esp", -1, v0val[0], 0);
548: break;
549: default:
550: panic("bootpath_fake: unknown system type %d",
551: cpuinfo.cpu_type);
552: }
553: /*
554: * Deal with target/lun encodings.
555: * Note: more special casing in device_register().
556: */
557: if (oldpvec->monId[0] > '1') {
558: target = v0val[1] >> 3; /* new format */
559: lun = v0val[1] & 0x7;
560: } else {
561: target = v0val[1] >> 2; /* old format */
562: lun = v0val[1] & 0x3;
563: }
564: snprintf(tmpname, sizeof tmpname, "%c%c", cp[0], cp[1]);
565: BP_APPEND(bp, tmpname, target, lun, v0val[2]);
566: return;
567: }
568:
569: return; /* didn't grok bootpath, no change */
570: }
571: #endif /* SUN4 */
572:
573: #if defined(SUN4C)
574: /*
575: * sun4c stuff
576: */
577:
578: /*
579: * floppy: fd
580: * fake looks like: /fd@0,0:a
581: */
582: if (cp[0] == 'f' && cp[1] == 'd') {
583: /*
584: * Assume `fd(c,u,p)' means:
585: * partition `p' on floppy drive `u' on controller `c'
586: */
587: BP_APPEND(bp, "fd", v0val[0], v0val[1], v0val[2]);
588: return;
589: }
590:
591: /*
592: * ethernet: le
593: * fake looks like: /sbus0/le0
594: */
595: if (cp[0] == 'l' && cp[1] == 'e') {
596: BP_APPEND(bp, "sbus", -1, 0, 0);
597: BP_APPEND(bp, "le", -1, v0val[0], 0);
598: return;
599: }
600:
601: /*
602: * scsi: sd, st, sr
603: * fake looks like: /sbus0/esp0/sd@3,0:a
604: */
605: if (cp[0] == 's' && (cp[1] == 'd' || cp[1] == 't' || cp[1] == 'r')) {
606: char tmpname[8];
607: int target, lun;
608:
609: BP_APPEND(bp, "sbus", -1, 0, 0);
610: BP_APPEND(bp, "esp", -1, v0val[0], 0);
611: if (cp[1] == 'r')
612: snprintf(tmpname, sizeof tmpname, "cd"); /* OpenBSD uses 'cd', not 'sr'*/
613: else
614: snprintf(tmpname, sizeof tmpname, "%c%c", cp[0], cp[1]);
615: /* XXX - is TARGET/LUN encoded in v0val[1]? */
616: target = v0val[1];
617: lun = 0;
618: BP_APPEND(bp, tmpname, target, lun, v0val[2]);
619: return;
620: }
621: #endif /* SUN4C */
622:
623:
624: /*
625: * unknown; return
626: */
627:
628: #undef BP_APPEND
629: }
630:
631: /*
632: * print out the bootpath
633: * the %x isn't 0x%x because the Sun EPROMs do it this way, and
634: * consistency with the EPROMs is probably better here.
635: */
636:
637: static void
638: bootpath_print(bp)
639: struct bootpath *bp;
640: {
641: printf("bootpath: ");
642: while (bp->name[0]) {
643: if (bp->val[0] == -1)
644: printf("/%s%x", bp->name, bp->val[1]);
645: else
646: printf("/%s@%x,%x", bp->name, bp->val[0], bp->val[1]);
647: if (bp->val[2] != 0)
648: printf(":%c", bp->val[2] + 'a');
649: bp++;
650: }
651: printf("\n");
652: }
653:
654:
655: /*
656: * save or read a bootpath pointer from the boothpath store.
657: *
658: * XXX. required because of SCSI... we don't have control over the "sd"
659: * device, so we can't set boot device there. we patch in with
660: * device_register(), and use this to recover the bootpath.
661: */
662:
663: struct bootpath *
664: bootpath_store(storep, bp)
665: int storep;
666: struct bootpath *bp;
667: {
668: static struct bootpath *save;
669: struct bootpath *retval;
670:
671: retval = save;
672: if (storep)
673: save = bp;
674:
675: return (retval);
676: }
677:
678: /*
679: * Set up the sd target mappings for non SUN4 PROMs.
680: * Find out about the real SCSI target, given the PROM's idea of the
681: * target of the (boot) device (i.e., the value in bp->v0val[0]).
682: */
683: static void
684: crazymap(prop, map)
685: char *prop;
686: int *map;
687: {
688: int i;
689: char *propval;
690:
691: if (!CPU_ISSUN4 && promvec->pv_romvec_vers < 2) {
692: /*
693: * Machines with real v0 proms have an `s[dt]-targets' property
694: * which contains the mapping for us to use. v2 proms donot
695: * require remapping.
696: */
697: propval = getpropstring(optionsnode, prop);
698: if (propval == NULL || strlen(propval) != 8) {
699: build_default_map:
700: printf("WARNING: %s map is bogus, using default\n",
701: prop);
702: for (i = 0; i < 8; ++i)
703: map[i] = i;
704: i = map[0];
705: map[0] = map[3];
706: map[3] = i;
707: return;
708: }
709: for (i = 0; i < 8; ++i) {
710: map[i] = propval[i] - '0';
711: if (map[i] < 0 ||
712: map[i] >= 8)
713: goto build_default_map;
714: }
715: } else {
716: /*
717: * Set up the identity mapping for old sun4 monitors
718: * and v[2-] OpenPROMs. Note: device_register() does the
719: * SCSI-target juggling for sun4 monitors.
720: */
721: for (i = 0; i < 8; ++i)
722: map[i] = i;
723: }
724: }
725:
726: int
727: sd_crazymap(n)
728: int n;
729: {
730: static int prom_sd_crazymap[8]; /* static: compute only once! */
731: static int init = 0;
732:
733: if (init == 0) {
734: crazymap("sd-targets", prom_sd_crazymap);
735: init = 1;
736: }
737: return prom_sd_crazymap[n];
738: }
739:
740: /*
741: * Determine mass storage and memory configuration for a machine.
742: * We get the PROM's root device and make sure we understand it, then
743: * attach it as `mainbus0'. We also set up to handle the PROM `sync'
744: * command.
745: */
746: void
747: cpu_configure()
748: {
749: struct confargs oca;
750: register int node = 0;
751: register char *cp;
752: int s;
753: extern struct user *proc0paddr;
754:
755: /* build the bootpath */
756: bootpath_build();
757:
758: if (boothowto & RB_CONFIG) {
759: #ifdef BOOT_CONFIG
760: user_config();
761: #else
762: printf("kernel does not support -c; continuing..\n");
763: #endif
764: }
765:
766: #if defined(SUN4)
767: if (CPU_ISSUN4) {
768: extern struct cfdata cfdata[];
769: extern struct cfdriver memreg_cd, obio_cd;
770: struct cfdata *cf, *memregcf = NULL;
771: register short *p;
772: struct rom_reg rr;
773:
774: for (cf = cfdata; memregcf==NULL && cf->cf_driver; cf++) {
775: if (cf->cf_driver != &memreg_cd ||
776: cf->cf_loc[0] == -1) /* avoid sun4m memreg0 */
777: continue;
778: /*
779: * On the 4/100 obio addresses must be mapped at
780: * 0x0YYYYYYY, but alias higher up (we avoid the
781: * alias condition because it causes pmap difficulties)
782: * XXX: We also assume that 4/[23]00 obio addresses
783: * must be 0xZYYYYYYY, where (Z != 0)
784: * make sure we get the correct memreg cfdriver!
785: */
786: if (cpuinfo.cpu_type == CPUTYP_4_100 &&
787: (cf->cf_loc[0] & 0xf0000000))
788: continue;
789: if (cpuinfo.cpu_type != CPUTYP_4_100 &&
790: !(cf->cf_loc[0] & 0xf0000000))
791: continue;
792: for (p = cf->cf_parents; memregcf==NULL && *p >= 0; p++)
793: if (cfdata[*p].cf_driver == &obio_cd)
794: memregcf = cf;
795: }
796: if (memregcf == NULL)
797: panic("cpu_configure: no memreg found!");
798:
799: rr.rr_iospace = PMAP_OBIO;
800: rr.rr_paddr = (void *)memregcf->cf_loc[0];
801: rr.rr_len = NBPG;
802: par_err_reg = (u_int *)bus_map(&rr, NBPG);
803: if (par_err_reg == NULL)
804: panic("cpu_configure: ROM hasn't mapped memreg!");
805: }
806: #endif
807: #if defined(SUN4C)
808: if (CPU_ISSUN4C) {
809: node = findroot();
810: cp = getpropstring(node, "device_type");
811: if (strcmp(cp, "cpu") != 0)
812: panic("PROM root device type = %s (need CPU)", cp);
813: }
814: #endif
815: #if defined(SUN4M)
816: if (CPU_ISSUN4M)
817: node = findroot();
818: #endif
819:
820: *promvec->pv_synchook = sync_crash;
821:
822: oca.ca_ra.ra_node = node;
823: oca.ca_ra.ra_name = cp = "mainbus";
824: if (config_rootfound(cp, (void *)&oca) == NULL)
825: panic("mainbus not configured");
826:
827: /* Enable device interrupts */
828: #if defined(SUN4M)
829: if (CPU_ISSUN4M)
830: ienab_bic(SINTR_MA);
831: #endif
832: #if defined(SUN4) || defined(SUN4C)
833: if (CPU_ISSUN4OR4C)
834: ienab_bis(IE_ALLIE);
835: #endif
836: (void)spl0();
837:
838: /*
839: * Re-zero proc0's user area, to nullify the effect of the
840: * stack running into it during auto-configuration.
841: * XXX - should fix stack usage.
842: */
843: s = splhigh();
844: bzero(proc0paddr, sizeof(struct user));
845:
846: pmap_redzone();
847: splx(s);
848: cold = 0;
849: }
850:
851: void
852: diskconf(void)
853: {
854: struct bootpath *bp;
855: struct device *bootdv;
856:
857: /*
858: * Configure swap area and related system
859: * parameter based on device(s) used.
860: */
861: bootpath_print(bootpath);
862:
863: bp = nbootpath == 0 ? NULL : &bootpath[nbootpath-1];
864: bootdv = (bp == NULL) ? NULL : bp->dev;
865:
866: setroot(bootdv, bp->val[2], RB_USERREQ | RB_HALT);
867: dumpconf();
868: }
869:
870: /*
871: * Console `sync' command. SunOS just does a `panic: zero' so I guess
872: * no one really wants anything fancy...
873: */
874: void
875: sync_crash()
876: {
877:
878: panic("PROM sync command");
879: }
880:
881: char *
882: clockfreq(freq)
883: register int freq;
884: {
885: register char *p;
886: static char buf[10];
887:
888: freq /= 1000;
889: snprintf(buf, sizeof buf, "%d", freq / 1000);
890: freq %= 1000;
891: if (freq) {
892: freq += 1000; /* now in 1000..1999 */
893: p = buf + strlen(buf);
894: snprintf(p, buf + sizeof buf - p, "%d", freq);
895: *p = '.'; /* now buf = %d.%3d */
896: }
897: return (buf);
898: }
899:
900: /* ARGSUSED */
901: static int
902: mbprint(aux, name)
903: void *aux;
904: const char *name;
905: {
906: register struct confargs *ca = aux;
907:
908: if (name)
909: printf("%s at %s", ca->ca_ra.ra_name, name);
910: if (ca->ca_ra.ra_paddr)
911: printf(" %saddr 0x%x", ca->ca_ra.ra_iospace ? "io" : "",
912: (int)ca->ca_ra.ra_paddr);
913: return (UNCONF);
914: }
915:
916: int
917: findroot()
918: {
919: register int node;
920:
921: if ((node = rootnode) == 0 && (node = nextsibling(0)) == 0)
922: panic("no PROM root device");
923: rootnode = node;
924: return (node);
925: }
926:
927: /*
928: * Given a `first child' node number, locate the node with the given name.
929: * Return the node number, or 0 if not found.
930: */
931: int
932: findnode(first, name)
933: int first;
934: register const char *name;
935: {
936: register int node;
937:
938: for (node = first; node; node = nextsibling(node))
939: if (strcmp(getpropstring(node, "name"), name) == 0)
940: return (node);
941: return (0);
942: }
943:
944: /*
945: * Fill in a romaux. Returns 1 on success, 0 if the register property
946: * was not the right size.
947: */
948: int
949: romprop(rp, cp, node)
950: register struct romaux *rp;
951: const char *cp;
952: register int node;
953: {
954: int len, n, intr;
955: union { char regbuf[256]; struct rom_reg rr[RA_MAXREG]; } u;
956: static const char pl[] = "property length";
957:
958: bzero(u.regbuf, sizeof u);
959: len = getprop(node, "reg", (void *)u.regbuf, sizeof(u.regbuf));
960: if (len == -1 &&
961: node_has_property(node, "device_type") &&
962: strcmp(getpropstring(node, "device_type"), "hierarchical") == 0)
963: len = 0;
964: if (len % sizeof(struct rom_reg)) {
965: printf("%s \"reg\" %s = %d (need multiple of %d)\n",
966: cp, pl, len, sizeof(struct rom_reg));
967: return (0);
968: }
969: if (len > RA_MAXREG * sizeof(struct rom_reg))
970: printf("warning: %s \"reg\" %s %d > %d, excess ignored\n",
971: cp, pl, len, RA_MAXREG * sizeof(struct rom_reg));
972: rp->ra_node = node;
973: rp->ra_name = cp;
974: rp->ra_nreg = len / sizeof(struct rom_reg);
975: bcopy(u.rr, rp->ra_reg, len);
976:
977: len = getprop(node, "address", (void *)rp->ra_vaddrs,
978: sizeof(rp->ra_vaddrs));
979: if (len == -1) {
980: rp->ra_vaddr = 0; /* XXX - driver compat */
981: len = 0;
982: }
983: if (len & 3) {
984: printf("%s \"address\" %s = %d (need multiple of 4)\n",
985: cp, pl, len);
986: len = 0;
987: }
988: rp->ra_nvaddrs = len >> 2;
989:
990: len = getprop(node, "intr", (void *)&rp->ra_intr, sizeof rp->ra_intr);
991: if (len == -1)
992: len = 0;
993:
994: /*
995: * Some SBus cards only provide an "interrupts" properly, listing
996: * SBus levels. But since obio devices will usually also provide
997: * both properties, only check for "interrupts" last.
998: */
999: if (len == 0) {
1000: u_int32_t *interrupts;
1001: len = getproplen(node, "interrupts");
1002: if (len > 0 &&
1003: (interrupts = malloc(len, M_TEMP, M_NOWAIT)) != NULL) {
1004: /* Build rom_intr structures from the list */
1005: getprop(node, "interrupts", interrupts, len);
1006: len /= sizeof(u_int32_t);
1007: for (n = 0; n < len; n++) {
1008: intr = interrupts[n];
1009: /*
1010: * Non-SBus devices (such as the cgfourteen,
1011: * which attaches on obio) do not need their
1012: * interrupt level translated.
1013: */
1014: if (intr < 8) {
1015: intr = CPU_ISSUN4M ?
1016: intr_sbus2ipl_4m[intr] :
1017: intr_sbus2ipl_4c[intr];
1018: }
1019: rp->ra_intr[n].int_pri = intr;
1020: rp->ra_intr[n].int_vec = 0;
1021: };
1022: len *= sizeof(struct rom_intr);
1023: free(interrupts, M_TEMP);
1024: } else
1025: len = 0;
1026: }
1027:
1028: if (len & 7) {
1029: printf("%s \"intr\" %s = %d (need multiple of 8)\n",
1030: cp, pl, len);
1031: len = 0;
1032: }
1033: rp->ra_nintr = len >>= 3;
1034: /* SPARCstation interrupts are not hardware-vectored */
1035: while (--len >= 0) {
1036: if (rp->ra_intr[len].int_vec) {
1037: printf("WARNING: %s interrupt %d has nonzero vector\n",
1038: cp, len);
1039: break;
1040: }
1041: #if defined(SUN4M)
1042: if (CPU_ISSUN4M) {
1043: /* What's in these high bits anyway? */
1044: rp->ra_intr[len].int_pri &= 0xf;
1045: }
1046: #endif
1047:
1048: }
1049: return (1);
1050: }
1051:
1052: int
1053: mainbus_match(parent, self, aux)
1054: struct device *parent;
1055: void *self;
1056: void *aux;
1057: {
1058: struct cfdata *cf = self;
1059: register struct confargs *ca = aux;
1060: register struct romaux *ra = &ca->ca_ra;
1061:
1062: return (strcmp(cf->cf_driver->cd_name, ra->ra_name) == 0);
1063: }
1064:
1065: int autoconf_nzs = 0; /* must be global so obio.c can see it */
1066:
1067: /*
1068: * Attach the mainbus.
1069: *
1070: * Our main job is to attach the CPU (the root node we got in cpu_configure())
1071: * and iterate down the list of `mainbus devices' (children of that node).
1072: * We also record the `node id' of the default frame buffer, if any.
1073: */
1074: static void
1075: mainbus_attach(parent, dev, aux)
1076: struct device *parent, *dev;
1077: void *aux;
1078: {
1079: struct confargs oca;
1080: register const char *const *ssp, *sp = NULL;
1081: struct confargs *ca = aux;
1082: #if defined(SUN4C) || defined(SUN4M)
1083: register int node0, node;
1084: const char *const *openboot_special;
1085: #define L1A_HACK /* XXX hack to allow L1-A during autoconf */
1086: #ifdef L1A_HACK
1087: int audio = 0;
1088: #endif
1089: #endif
1090: #if defined(SUN4)
1091: static const char *const oldmon_special[] = {
1092: "vmel",
1093: "vmes",
1094: "led",
1095: NULL
1096: };
1097: #endif /* SUN4 */
1098:
1099: #if defined(SUN4C)
1100: static const char *const openboot_special4c[] = {
1101: /* find these first (end with empty string) */
1102: "memory-error", /* as early as convenient, in case of error */
1103: "eeprom",
1104: "counter-timer",
1105: "auxiliary-io",
1106: "",
1107:
1108: /* ignore these (end with NULL) */
1109: "aliases",
1110: "interrupt-enable",
1111: "memory",
1112: "openprom",
1113: "options",
1114: "packages",
1115: "virtual-memory",
1116: NULL
1117: };
1118: #else
1119: #define openboot_special4c ((void *)0)
1120: #endif
1121: #if defined(SUN4M)
1122: static const char *const openboot_special4m[] = {
1123: /* find these first */
1124: "obio", /* smart enough to get eeprom/etc mapped */
1125: "",
1126:
1127: /* ignore these (end with NULL) */
1128: /*
1129: * These are _root_ devices to ignore. Others must be handled
1130: * elsewhere.
1131: */
1132: "SUNW,sx", /* XXX: no driver for SX yet */
1133: "eccmemctl",
1134: "virtual-memory",
1135: "aliases",
1136: "memory",
1137: "openprom",
1138: "options",
1139: "packages",
1140: /* we also skip any nodes with device_type == "cpu" */
1141: NULL
1142: };
1143: #else
1144: #define openboot_special4m ((void *)0)
1145: #endif
1146:
1147: if (CPU_ISSUN4)
1148: snprintf(mainbus_model, sizeof mainbus_model,
1149: "SUN-4/%d series", cpuinfo.classlvl);
1150: else
1151: strlcat(mainbus_model, getpropstring(ca->ca_ra.ra_node,"name"),
1152: sizeof mainbus_model);
1153: printf(": %s\n", mainbus_model);
1154:
1155: /*
1156: * Locate and configure the ``early'' devices. These must be
1157: * configured before we can do the rest. For instance, the
1158: * EEPROM contains the Ethernet address for the LANCE chip.
1159: * If the device cannot be located or configured, panic.
1160: */
1161:
1162: #if defined(SUN4)
1163: if (CPU_ISSUN4) {
1164: /* Configure the CPU. */
1165: bzero(&oca, sizeof(oca));
1166: oca.ca_ra.ra_name = "cpu";
1167: (void)config_found(dev, (void *)&oca, mbprint);
1168:
1169: /* Start at the beginning of the bootpath */
1170: bzero(&oca, sizeof(oca));
1171: oca.ca_ra.ra_bp = bootpath;
1172:
1173: oca.ca_bustype = BUS_MAIN;
1174: oca.ca_ra.ra_name = "obio";
1175: if (config_found(dev, (void *)&oca, mbprint) == NULL)
1176: panic("obio missing");
1177:
1178: for (ssp = oldmon_special; (sp = *ssp) != NULL; ssp++) {
1179: oca.ca_bustype = BUS_MAIN;
1180: oca.ca_ra.ra_name = sp;
1181: (void)config_found(dev, (void *)&oca, mbprint);
1182: }
1183: return;
1184: }
1185: #endif
1186:
1187: /*
1188: * The rest of this routine is for OBP machines exclusively.
1189: */
1190: #if defined(SUN4C) || defined(SUN4M)
1191:
1192: openboot_special = CPU_ISSUN4M
1193: ? openboot_special4m
1194: : openboot_special4c;
1195:
1196: node = ca->ca_ra.ra_node; /* i.e., the root node */
1197:
1198: /* the first early device to be configured is the cpu */
1199: if (CPU_ISSUN4M) {
1200: /* XXX - what to do on multiprocessor machines? */
1201: register const char *cp;
1202:
1203: for (node = firstchild(node); node; node = nextsibling(node)) {
1204: cp = getpropstring(node, "device_type");
1205: if (strcmp(cp, "cpu") == 0) {
1206: bzero(&oca, sizeof(oca));
1207: oca.ca_ra.ra_node = node;
1208: oca.ca_ra.ra_name = "cpu";
1209: oca.ca_ra.ra_paddr = 0;
1210: oca.ca_ra.ra_nreg = 0;
1211: config_found(dev, (void *)&oca, mbprint);
1212: }
1213: }
1214: } else if (CPU_ISSUN4C) {
1215: bzero(&oca, sizeof(oca));
1216: oca.ca_ra.ra_node = node;
1217: oca.ca_ra.ra_name = "cpu";
1218: oca.ca_ra.ra_paddr = 0;
1219: oca.ca_ra.ra_nreg = 0;
1220: config_found(dev, (void *)&oca, mbprint);
1221: }
1222:
1223: node = ca->ca_ra.ra_node; /* re-init root node */
1224:
1225: if (promvec->pv_romvec_vers <= 2) {
1226: /*
1227: * Revision 1 prom will always return a framebuffer device
1228: * node if a framebuffer is installed, even if console is
1229: * set to serial.
1230: */
1231: if (*promvec->pv_stdout != PROMDEV_SCREEN)
1232: fbnode = 0;
1233: else {
1234: /* remember which frame buffer is the console */
1235: fbnode = getpropint(node, "fb", 0);
1236: }
1237: }
1238:
1239: /* Find the "options" node */
1240: node0 = firstchild(node);
1241: optionsnode = findnode(node0, "options");
1242: if (optionsnode == 0)
1243: panic("no options in OPENPROM");
1244:
1245: /* Start at the beginning of the bootpath */
1246: oca.ca_ra.ra_bp = bootpath;
1247:
1248: for (ssp = openboot_special; *(sp = *ssp) != 0; ssp++) {
1249: if ((node = findnode(node0, sp)) == 0) {
1250: printf("could not find %s in OPENPROM\n", sp);
1251: panic(sp);
1252: }
1253: oca.ca_bustype = BUS_MAIN;
1254: if (!romprop(&oca.ca_ra, sp, node) ||
1255: (config_found(dev, (void *)&oca, mbprint) == NULL))
1256: panic(sp);
1257: }
1258:
1259: /*
1260: * Configure the rest of the devices, in PROM order. Skip
1261: * PROM entries that are not for devices, or which must be
1262: * done before we get here.
1263: */
1264: for (node = node0; node; node = nextsibling(node)) {
1265: register const char *cp;
1266:
1267: #if defined(SUN4M)
1268: if (CPU_ISSUN4M) /* skip the CPUs */
1269: if (node_has_property(node, "device_type") &&
1270: !strcmp(getpropstring(node, "device_type"), "cpu"))
1271: continue;
1272: #endif
1273: cp = getpropstring(node, "name");
1274: for (ssp = openboot_special; (sp = *ssp) != NULL; ssp++)
1275: if (strcmp(cp, sp) == 0)
1276: break;
1277: if (sp == NULL && romprop(&oca.ca_ra, cp, node)) {
1278: #ifdef L1A_HACK
1279: if (strcmp(cp, "audio") == 0)
1280: audio = 1;
1281: if (strcmp(cp, "zs") == 0)
1282: autoconf_nzs++;
1283: if (/*audio &&*/ autoconf_nzs >= 2) /*XXX*/
1284: splx(11 << 8); /*XXX*/
1285: #endif
1286: oca.ca_bustype = BUS_MAIN;
1287: (void) config_found(dev, (void *)&oca, mbprint);
1288: }
1289: }
1290: #endif /* SUN4C || SUN4M */
1291: }
1292:
1293: struct cfattach mainbus_ca = {
1294: sizeof(struct device), mainbus_match, mainbus_attach
1295: };
1296:
1297: struct cfdriver mainbus_cd = {
1298: NULL, "mainbus", DV_DULL
1299: };
1300:
1301: /*
1302: * findzs() is called from the zs driver (which is, at least in theory,
1303: * generic to any machine with a Zilog ZSCC chip). It should return the
1304: * address of the corresponding zs channel. It may not fail, and it
1305: * may be called before the VM code can be used. Here we count on the
1306: * FORTH PROM to map in the required zs chips.
1307: */
1308: void *
1309: findzs(zs)
1310: int zs;
1311: {
1312:
1313: #if defined(SUN4)
1314: #define ZS0_PHYS 0xf1000000
1315: #define ZS1_PHYS 0xf0000000
1316: #define ZS2_PHYS 0xe0000000
1317:
1318: if (CPU_ISSUN4) {
1319: struct rom_reg rr;
1320: register void *vaddr;
1321:
1322: switch (zs) {
1323: case 0:
1324: rr.rr_paddr = (void *)ZS0_PHYS;
1325: break;
1326: case 1:
1327: rr.rr_paddr = (void *)ZS1_PHYS;
1328: break;
1329: case 2:
1330: rr.rr_paddr = (void *)ZS2_PHYS;
1331: break;
1332: default:
1333: panic("findzs: unknown zs device %d", zs);
1334: }
1335:
1336: rr.rr_iospace = PMAP_OBIO;
1337: rr.rr_len = NBPG;
1338: vaddr = bus_map(&rr, NBPG);
1339: if (vaddr)
1340: return (vaddr);
1341: }
1342: #endif
1343:
1344: #if defined(SUN4C) || defined(SUN4M)
1345: if (CPU_ISSUN4COR4M) {
1346: int node;
1347:
1348: node = firstchild(findroot());
1349: if (CPU_ISSUN4M) { /* zs is in "obio" tree on Sun4M */
1350: node = findnode(node, "obio");
1351: if (!node)
1352: panic("findzs: no obio node");
1353: node = firstchild(node);
1354: }
1355: while ((node = findnode(node, "zs")) != 0) {
1356: int vaddrs[10];
1357:
1358: if (getpropint(node, "slave", -1) != zs) {
1359: node = nextsibling(node);
1360: continue;
1361: }
1362:
1363: /*
1364: * On some machines (e.g. the Voyager), the zs
1365: * device has multi-valued register properties.
1366: */
1367: if (getprop(node, "address",
1368: (void *)vaddrs, sizeof(vaddrs)) != 0)
1369: return ((void *)vaddrs[0]);
1370: }
1371: return (NULL);
1372: }
1373: #endif
1374: panic("findzs: cannot find zs%d", zs);
1375: /* NOTREACHED */
1376: }
1377:
1378: #if defined(SUN4C) || defined(SUN4M)
1379: struct v2rmi {
1380: int zero;
1381: int addr;
1382: int len;
1383: } v2rmi[200]; /* version 2 rom meminfo layout */
1384: #endif
1385:
1386: int
1387: makememarr(ap, max, which)
1388: register struct memarr *ap;
1389: int max, which;
1390: {
1391: #if defined(SUN4C) || defined(SUN4M)
1392: #define MAXMEMINFO (sizeof(v2rmi) / sizeof(*v2rmi))
1393: register struct v0mlist *mp;
1394: register int i, node, len;
1395: char *prop;
1396: #endif
1397:
1398: #if defined(SUN4)
1399: if (CPU_ISSUN4) {
1400: switch (which) {
1401: case MEMARR_AVAILPHYS:
1402: ap[0].addr = 0;
1403: ap[0].len = *oldpvec->memoryAvail;
1404: break;
1405: case MEMARR_TOTALPHYS:
1406: ap[0].addr = 0;
1407: ap[0].len = *oldpvec->memorySize;
1408: break;
1409: default:
1410: printf("pre_panic: makememarr");
1411: break;
1412: }
1413: return (1);
1414: }
1415: #endif
1416: #if defined(SUN4C) || defined(SUN4M)
1417: switch (i = promvec->pv_romvec_vers) {
1418:
1419: case 0:
1420: /*
1421: * Version 0 PROMs use a linked list to describe these
1422: * guys.
1423: */
1424: switch (which) {
1425:
1426: case MEMARR_AVAILPHYS:
1427: mp = *promvec->pv_v0mem.v0_physavail;
1428: break;
1429:
1430: case MEMARR_TOTALPHYS:
1431: mp = *promvec->pv_v0mem.v0_phystot;
1432: break;
1433:
1434: default:
1435: panic("makememarr");
1436: }
1437: for (i = 0; mp != NULL; mp = mp->next, i++) {
1438: if (i >= max)
1439: goto overflow;
1440: ap->addr = (u_int)mp->addr;
1441: ap->len = mp->nbytes;
1442: ap++;
1443: }
1444: break;
1445:
1446: default:
1447: printf("makememarr: hope version %d PROM is like version 2\n",
1448: i);
1449: /* FALLTHROUGH */
1450:
1451: case 3:
1452: case 2:
1453: /*
1454: * Version 2 PROMs use a property array to describe them.
1455: */
1456: if (max > MAXMEMINFO) {
1457: printf("makememarr: limited to %d\n", MAXMEMINFO);
1458: max = MAXMEMINFO;
1459: }
1460: if ((node = findnode(firstchild(findroot()), "memory")) == 0)
1461: panic("makememarr: cannot find \"memory\" node");
1462: switch (which) {
1463:
1464: case MEMARR_AVAILPHYS:
1465: prop = "available";
1466: break;
1467:
1468: case MEMARR_TOTALPHYS:
1469: prop = "reg";
1470: break;
1471:
1472: default:
1473: panic("makememarr");
1474: }
1475: len = getprop(node, prop, (void *)v2rmi, sizeof v2rmi) /
1476: sizeof(struct v2rmi);
1477: for (i = 0; i < len; i++) {
1478: if (i >= max)
1479: goto overflow;
1480: ap->addr = v2rmi[i].addr;
1481: ap->len = v2rmi[i].len;
1482: ap++;
1483: }
1484: break;
1485: }
1486:
1487: /*
1488: * Success! (Hooray)
1489: */
1490: if (i == 0)
1491: panic("makememarr: no memory found");
1492: return (i);
1493:
1494: overflow:
1495: /*
1496: * Oops, there are more things in the PROM than our caller
1497: * provided space for. Truncate any extras.
1498: */
1499: printf("makememarr: WARNING: lost some memory\n");
1500: return (i);
1501: #endif
1502: }
1503:
1504: /*
1505: * Internal form of getprop(). Returns the actual length.
1506: */
1507: int
1508: getprop(node, name, buf, bufsiz)
1509: int node;
1510: char *name;
1511: void *buf;
1512: register int bufsiz;
1513: {
1514: #if defined(SUN4C) || defined(SUN4M)
1515: register struct nodeops *no;
1516: register int len;
1517: #endif
1518:
1519: #if defined(SUN4)
1520: if (CPU_ISSUN4) {
1521: printf("WARNING: getprop not valid on sun4! %s\n", name);
1522: return (0);
1523: }
1524: #endif
1525:
1526: #if defined(SUN4C) || defined(SUN4M)
1527: no = promvec->pv_nodeops;
1528: len = no->no_proplen(node, name);
1529: if (len > bufsiz) {
1530: printf("node 0x%x property %s length %d > %d\n",
1531: node, name, len, bufsiz);
1532: #ifdef DEBUG
1533: panic("getprop");
1534: #else
1535: return (0);
1536: #endif
1537: }
1538: no->no_getprop(node, name, buf);
1539: return (len);
1540: #endif
1541: }
1542:
1543: /*
1544: * Internal form of proplen(). Returns the property length.
1545: */
1546: int
1547: getproplen(node, name)
1548: int node;
1549: char *name;
1550: {
1551: register struct nodeops *no = promvec->pv_nodeops;
1552:
1553: return (no->no_proplen(node, name));
1554: }
1555:
1556: /*
1557: * Return a string property. There is a (small) limit on the length;
1558: * the string is fetched into a static buffer which is overwritten on
1559: * subsequent calls.
1560: */
1561: char *
1562: getpropstring(node, name)
1563: int node;
1564: char *name;
1565: {
1566: register int len;
1567: static char stringbuf[32];
1568:
1569: len = getprop(node, name, (void *)stringbuf, sizeof stringbuf - 1);
1570: if (len == -1)
1571: len = 0;
1572: stringbuf[len] = '\0'; /* usually unnecessary */
1573: return (stringbuf);
1574: }
1575:
1576: /*
1577: * Fetch an integer (or pointer) property.
1578: * The return value is the property, or the default if there was none.
1579: */
1580: int
1581: getpropint(node, name, deflt)
1582: int node;
1583: char *name;
1584: int deflt;
1585: {
1586: register int len;
1587: char intbuf[16];
1588:
1589: len = getprop(node, name, (void *)intbuf, sizeof intbuf);
1590: if (len != 4)
1591: return (deflt);
1592: return (*(int *)intbuf);
1593: }
1594:
1595: /*
1596: * OPENPROM functions. These are here mainly to hide the OPENPROM interface
1597: * from the rest of the kernel.
1598: */
1599: int
1600: firstchild(node)
1601: int node;
1602: {
1603:
1604: return (promvec->pv_nodeops->no_child(node));
1605: }
1606:
1607: int
1608: nextsibling(node)
1609: int node;
1610: {
1611:
1612: return (promvec->pv_nodeops->no_nextnode(node));
1613: }
1614:
1615: /* The following recursively searches a PROM tree for a given node */
1616: int
1617: search_prom(rootnode, name)
1618: register int rootnode;
1619: register char *name;
1620: {
1621: register int rtnnode;
1622: register int node = rootnode;
1623:
1624: if (node == findroot() || !strcmp("hierarchical",
1625: getpropstring(node, "device_type")))
1626: node = firstchild(node);
1627:
1628: if (!node)
1629: panic("search_prom: null node");
1630:
1631: do {
1632: if (strcmp(getpropstring(node, "name"),name) == 0)
1633: return node;
1634:
1635: if (node_has_property(node,"device_type") &&
1636: (!strcmp(getpropstring(node, "device_type"),"hierarchical")
1637: || !strcmp(getpropstring(node, "name"),"iommu"))
1638: && (rtnnode = search_prom(node, name)) != 0)
1639: return rtnnode;
1640:
1641: } while ((node = nextsibling(node)));
1642:
1643: return 0;
1644: }
1645:
1646: /* The following are used primarily in consinit() */
1647:
1648: int
1649: opennode(path) /* translate phys. device path to node */
1650: register char *path;
1651: {
1652: register int fd;
1653:
1654: if (promvec->pv_romvec_vers < 2) {
1655: printf("WARNING: opennode not valid on sun4! %s\n", path);
1656: return (0);
1657: }
1658: fd = promvec->pv_v2devops.v2_open(path);
1659: if (fd == 0)
1660: return 0;
1661: return promvec->pv_v2devops.v2_fd_phandle(fd);
1662: }
1663:
1664: int
1665: node_has_property(node, prop) /* returns 1 if node has given property */
1666: register int node;
1667: register const char *prop;
1668: {
1669:
1670: return ((*promvec->pv_nodeops->no_proplen)(node, (caddr_t)prop) != -1);
1671: }
1672:
1673: /* Pass a string to the FORTH PROM to be interpreted */
1674: void
1675: rominterpret(s)
1676: register char *s;
1677: {
1678:
1679: if (promvec->pv_romvec_vers < 2)
1680: promvec->pv_fortheval.v0_eval(strlen(s), s);
1681: else
1682: promvec->pv_fortheval.v2_eval(s);
1683: }
1684:
1685: /*
1686: * Try to figure out where the PROM stores the cursor row & column
1687: * variables. Returns nonzero on error.
1688: */
1689: int
1690: romgetcursoraddr(rowp, colp)
1691: register int **rowp, **colp;
1692: {
1693: char buf[100];
1694:
1695: /*
1696: * line# and column# are global in older proms (rom vector < 2)
1697: * and in some newer proms. They are local in version 2.9. The
1698: * correct cutoff point is unknown, as yet; we use 2.9 here.
1699: */
1700: if (promvec->pv_romvec_vers < 2 || promvec->pv_printrev < 0x00020009)
1701: snprintf(buf, sizeof buf,
1702: "' line# >body >user %lx ! ' column# >body >user %lx !",
1703: (u_long)rowp, (u_long)colp);
1704: else
1705: snprintf(buf, sizeof buf,
1706: "stdout @ is my-self addr line# %lx ! addr column# %lx !",
1707: (u_long)rowp, (u_long)colp);
1708: *rowp = *colp = NULL;
1709: rominterpret(buf);
1710: return (*rowp == NULL || *colp == NULL);
1711: }
1712:
1713: void
1714: romhalt()
1715: {
1716: if (CPU_ISSUN4COR4M)
1717: *promvec->pv_synchook = NULL;
1718:
1719: promvec->pv_halt();
1720: panic("PROM exit failed");
1721: }
1722:
1723: void
1724: romboot(str)
1725: char *str;
1726: {
1727: if (CPU_ISSUN4COR4M)
1728: *promvec->pv_synchook = NULL;
1729:
1730: promvec->pv_reboot(str);
1731: panic("PROM boot failed");
1732: }
1733:
1734: void
1735: callrom()
1736: {
1737:
1738: #if 0 /* sun4c FORTH PROMs do this for us */
1739: if (CPU_ISSUN4)
1740: fb_unblank();
1741: #endif
1742: promvec->pv_abort();
1743: }
1744:
1745: /*
1746: * find the boot device (if it was a disk). we must check to see if
1747: * unit info in saved bootpath structure matches unit info in our softc.
1748: * note that knowing the device name (e.g. "xd0") is not useful... we
1749: * must check the drive number (or target/lun, in the case of SCSI).
1750: * (XXX is it worth ifdef'ing this?)
1751: */
1752:
1753: void
1754: device_register(struct device *dev, void *aux)
1755: {
1756: struct bootpath *bp = bootpath_store(0, NULL); /* restore bootpath! */
1757:
1758: if (bp == NULL)
1759: return;
1760:
1761: /*
1762: * scsi: sd,cd
1763: */
1764: if (strncmp("sd", dev->dv_xname, 2) == 0 ||
1765: strncmp("cd", dev->dv_xname, 2) == 0) {
1766: struct scsi_attach_args *sa = aux;
1767: struct scsibus_softc *sbsc;
1768: int target, lun;
1769:
1770: sbsc = (struct scsibus_softc *)dev->dv_parent;
1771:
1772: target = bp->val[0];
1773: lun = bp->val[1];
1774:
1775: #if defined(SUN4)
1776: if (CPU_ISSUN4 && dev->dv_xname[0] == 's' &&
1777: target == 0 && sbsc->sc_link[0][0] == NULL) {
1778: /*
1779: * disk unit 0 is magic: if there is actually no
1780: * target 0 scsi device, the PROM will call
1781: * target 3 `sd0'.
1782: * XXX - what if someone puts a tape at target 0?
1783: */
1784: /* Note that sc_link[0][0] will be NULL when we are
1785: * invoked to match the device for target 0, if it
1786: * exists. But then the attachment args will have
1787: * its own target set to zero. It this case, skip
1788: * the remapping.
1789: */
1790: if (sa->sa_sc_link->target != 0) {
1791: target = 3; /* remap to 3 */
1792: lun = 0;
1793: }
1794: }
1795: #endif
1796:
1797: #if defined(SUN4C)
1798: if (CPU_ISSUN4C && dev->dv_xname[0] == 's')
1799: target = sd_crazymap(target);
1800: #endif
1801:
1802: if (sa->sa_sc_link->target == target &&
1803: sa->sa_sc_link->lun == lun) {
1804: bp->dev = dev; /* got it! */
1805: return;
1806: }
1807: }
1808: }
1809:
1810: /*
1811: * find a device matching "name" and unit number
1812: */
1813: struct device *
1814: getdevunit(name, unit)
1815: char *name;
1816: int unit;
1817: {
1818: struct device *dev = TAILQ_FIRST(&alldevs);
1819: char num[10], fullname[16];
1820: int lunit;
1821:
1822: /* compute length of name and decimal expansion of unit number */
1823: snprintf(num, sizeof num, "%d", unit);
1824: lunit = strlen(num);
1825: if (strlen(name) + lunit >= sizeof(fullname) - 1)
1826: panic("config_attach: device name too long");
1827:
1828: strlcpy(fullname, name, sizeof fullname);
1829: strlcat(fullname, num, sizeof fullname);
1830:
1831: while (strcmp(dev->dv_xname, fullname) != 0) {
1832: if ((dev = TAILQ_NEXT(dev, dv_list)) == NULL)
1833: return NULL;
1834: }
1835: return dev;
1836: }
1837:
1838: struct nam2blk nam2blk[] = {
1839: { "xy", 3 },
1840: { "sd", 7 },
1841: { "xd", 10 },
1842: { "st", 11 },
1843: { "fd", 16 },
1844: { "rd", 17 },
1845: { "cd", 18 },
1846: { "raid", 25 },
1847: { NULL, -1 }
1848: };
CVSweb