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