autoconf.c revision 1.60 1 /* $NetBSD: autoconf.c,v 1.60 2025/03/09 01:06:41 thorpej 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. Neither the name of the University nor the names of its contributors
25 * may be used to endorse or promote products derived from this software
26 * without specific prior written permission.
27 *
28 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
29 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
30 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
31 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
32 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
33 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
34 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
35 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
36 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
37 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
38 * SUCH DAMAGE.
39 *
40 * @(#)autoconf.c 8.4 (Berkeley) 10/1/93
41 */
42
43 #include <sys/cdefs.h> /* RCS ID & Copyright macro defns */
44
45 __KERNEL_RCSID(0, "$NetBSD: autoconf.c,v 1.60 2025/03/09 01:06:41 thorpej Exp $");
46
47 #include "pci.h"
48
49 #include <sys/param.h>
50 #include <sys/systm.h>
51 #include <sys/buf.h>
52 #include <sys/disklabel.h>
53 #include <sys/reboot.h>
54 #include <sys/device.h>
55 #include <sys/conf.h>
56 #include <dev/cons.h>
57
58 #include <dev/pci/pcivar.h>
59
60 #include <net/if.h>
61 #include <net/if_ether.h>
62
63 #include <machine/autoconf.h>
64 #include <machine/alpha.h>
65 #include <machine/cpu.h>
66 #include <machine/prom.h>
67 #include <machine/cpuconf.h>
68 #include <machine/intr.h>
69
70 struct bootdev_data *bootdev_data;
71 bool bootdev_is_disk;
72 bool bootdev_is_net;
73
74 static void parse_prom_bootdev(void);
75
76 /*
77 * cpu_configure:
78 * called at boot time, configure all devices on system
79 */
80 void
81 cpu_configure(void)
82 {
83
84 parse_prom_bootdev();
85
86 /*
87 * Disable interrupts during autoconfiguration. splhigh() won't
88 * work, because it simply _raises_ the IPL, so if machine checks
89 * are disabled, they'll stay disabled. Machine checks are needed
90 * during autoconfig.
91 */
92 (void)alpha_pal_swpipl(ALPHA_PSL_IPL_HIGH);
93 if (config_rootfound("mainbus", NULL) == NULL)
94 panic("no mainbus found");
95 (void)spl0();
96
97 /*
98 * Note that bootstrapping is finished, and set the HWRPB up
99 * to do restarts.
100 */
101 hwrpb_restart_setup();
102 }
103
104 static void
105 qemu_find_rootdev(void)
106 {
107 char buf[32] = { 0 };
108
109 /*
110 * Check for "rootdev=wd0".
111 */
112 if (! prom_qemu_getenv("rootdev", buf, sizeof(buf))) {
113 /*
114 * Check "root=/dev/wd0a", "root=/dev/hda1", etc.
115 */
116 if (! prom_qemu_getenv("root", buf, sizeof(buf))) {
117 printf("WARNING: no rootdev= or root= arguments "
118 "provided by Qemu\n");
119 return;
120 }
121 }
122
123 const size_t devlen = strlen("/dev/");
124 const char *cp = buf;
125 char *ecp = &buf[sizeof(buf) - 1];
126
127 /* Find the start of the device xname. */
128 if (strlen(cp) > devlen && strncmp(cp, "/dev/", devlen) == 0) {
129 cp += devlen;
130 }
131
132 /* Now strip any partition letter off the end. */
133 while (ecp != cp) {
134 if (*ecp >= '0' && *ecp <= '9') {
135 break;
136 }
137 *ecp-- = '\0';
138 }
139
140 snprintf(bootinfo.booted_dev, sizeof(bootinfo.booted_dev),
141 "root=%s", cp);
142 booted_device = device_find_by_xname(cp);
143 }
144
145 static bool
146 parse_dec_macaddr(const char *str, uint8_t enaddr[ETHER_ADDR_LEN])
147 {
148 char *cp;
149 long long l;
150 int i;
151
152 /*
153 * DEC Ethernet address strings are formatted like so:
154 *
155 * XX-XX-XX-XX-XX-XX
156 */
157
158 for (i = 0; i < ETHER_ADDR_LEN; i++) {
159 l = strtoll(str, &cp, 16);
160 if (l < 0 || l > 0xff) {
161 /* Not a valid MAC address. */
162 return false;
163 }
164 if (*cp == '-') {
165 /* Octet separator. */
166 enaddr[i] = (uint8_t)l;
167 str = cp + 1;
168 continue;
169 }
170 if (*cp == ' ' || *cp == '\0') {
171 /* End of the string. */
172 enaddr[i] = (uint8_t)l;
173 return i == ETHER_ADDR_LEN - 1;
174 }
175 /* Bogus character. */
176 break;
177 }
178
179 /* Encountered bogus character or didn't reach end of string. */
180 return false;
181 }
182
183 static void
184 netboot_find_rootdev_planb(void)
185 {
186 struct psref psref;
187 uint8_t enaddr[ETHER_ADDR_LEN];
188 char ifname[IFNAMSIZ];
189 int i;
190
191 if (!bootdev_is_net) {
192 /* We weren't netbooted. */
193 return;
194 }
195
196 for (i = 2; bootinfo.booted_dev[i] != '\0'; i++) {
197 if (bootinfo.booted_dev[i] == '-') {
198 if (parse_dec_macaddr(&bootinfo.booted_dev[i - 2],
199 enaddr)) {
200 /* Found it! */
201 break;
202 }
203 }
204 }
205 if (bootinfo.booted_dev[i] == '\0') {
206 /* No MAC address in string. */
207 return;
208 }
209
210 /* Now try to look up the interface by the link address. */
211 struct ifnet *ifp = if_get_bylla(enaddr, ETHER_ADDR_LEN, &psref);
212 if (ifp == NULL) {
213 /* No interface attached with that MAC address. */
214 return;
215 }
216
217 strlcpy(ifname, if_name(ifp), sizeof(ifname));
218 if_put(ifp, &psref);
219
220 /* Ok! Now look up the device_t by name! */
221 booted_device = device_find_by_xname(ifname);
222 }
223
224 void
225 cpu_rootconf(void)
226 {
227
228 if (booted_device == NULL && alpha_is_qemu) {
229 qemu_find_rootdev();
230 }
231
232 if (booted_device == NULL) {
233 /*
234 * It's possible that we netbooted from an Ethernet
235 * interface that can't be matched via the usual
236 * logic in device_register() (a DE204 in an ISA slot,
237 * for example). In these cases, the console may have
238 * provided us with a MAC address that we can use to
239 * try and find the interface, * e.g.:
240 *
241 * BOOTP 1 1 0 0 0 5 0 08-00-2B-xx-xx-xx 1
242 */
243 netboot_find_rootdev_planb();
244 }
245
246 if (booted_device == NULL) {
247 printf("WARNING: can't figure what device matches \"%s\"\n",
248 bootinfo.booted_dev);
249 }
250 rootconf();
251 }
252
253 static inline int
254 atoi(const char *s)
255 {
256 return (int)strtoll(s, NULL, 10);
257 }
258
259 static void
260 parse_prom_bootdev(void)
261 {
262 static char hacked_boot_dev[128];
263 static struct bootdev_data bd;
264 char *cp, *scp, *boot_fields[8];
265 int i, done;
266
267 booted_device = NULL;
268 booted_partition = 0;
269 bootdev_data = NULL;
270
271 memcpy(hacked_boot_dev, bootinfo.booted_dev,
272 uimin(sizeof bootinfo.booted_dev, sizeof hacked_boot_dev));
273 #if 0
274 printf("parse_prom_bootdev: boot dev = \"%s\"\n", hacked_boot_dev);
275 #endif
276
277 i = 0;
278 scp = cp = hacked_boot_dev;
279 for (done = 0; !done; cp++) {
280 if (*cp != ' ' && *cp != '\0')
281 continue;
282 if (*cp == '\0')
283 done = 1;
284
285 *cp = '\0';
286 boot_fields[i++] = scp;
287 scp = cp + 1;
288 if (i == 8)
289 done = 1;
290 }
291 if (i != 8)
292 return; /* doesn't look like anything we know! */
293
294 #if 0
295 printf("i = %d, done = %d\n", i, done);
296 for (i--; i >= 0; i--)
297 printf("%d = %s\n", i, boot_fields[i]);
298 #endif
299
300 bd.protocol = boot_fields[0];
301 bd.bus = atoi(boot_fields[1]);
302 bd.slot = atoi(boot_fields[2]);
303 bd.channel = atoi(boot_fields[3]);
304 bd.remote_address = boot_fields[4];
305 bd.unit = atoi(boot_fields[5]);
306 bd.boot_dev_type = atoi(boot_fields[6]);
307 bd.ctrl_dev_type = boot_fields[7];
308
309 #if 0
310 printf("parsed: proto = %s, bus = %d, slot = %d, channel = %d,\n",
311 bd.protocol, bd.bus, bd.slot, bd.channel);
312 printf("\tremote = %s, unit = %d, dev_type = %d, ctrl_type = %s\n",
313 bd.remote_address, bd.unit, bd.boot_dev_type, bd.ctrl_dev_type);
314 #endif
315
316 bootdev_data = &bd;
317
318 bootdev_is_disk = (strcasecmp(bd.protocol, "SCSI") == 0) ||
319 (strcasecmp(bd.protocol, "RAID") == 0) ||
320 (strcasecmp(bd.protocol, "I2O") == 0) ||
321 (strcasecmp(bd.protocol, "IDE") == 0);
322
323 bootdev_is_net = (strcasecmp(bd.protocol, "BOOTP") == 0) ||
324 (strcasecmp(bd.protocol, "MOP") == 0);
325 #if 0
326 printf("bootdev_is_disk = %d, bootdev_is_net = %d\n",
327 bootdev_is_disk, bootdev_is_net);
328 #endif
329 }
330
331 void
332 device_register(device_t dev, void *aux)
333 {
334 #if NPCI > 0
335 device_t parent = device_parent(dev);
336
337 if (parent != NULL && device_is_a(parent, "pci"))
338 device_pci_register(dev, aux);
339 #endif
340 if (platform.device_register)
341 (*platform.device_register)(dev, aux);
342 }
343