Home | History | Annotate | Line # | Download | only in x86
      1 /*	$NetBSD: x86_autoconf.c,v 1.92 2025/10/13 14:12:13 thorpej Exp $	*/
      2 
      3 /*-
      4  * Copyright (c) 1990 The Regents of the University of California.
      5  * All rights reserved.
      6  *
      7  * This code is derived from software contributed to Berkeley by
      8  * William Jolitz.
      9  *
     10  * Redistribution and use in source and binary forms, with or without
     11  * modification, are permitted provided that the following conditions
     12  * are met:
     13  * 1. Redistributions of source code must retain the above copyright
     14  *    notice, this list of conditions and the following disclaimer.
     15  * 2. Redistributions in binary form must reproduce the above copyright
     16  *    notice, this list of conditions and the following disclaimer in the
     17  *    documentation and/or other materials provided with the distribution.
     18  * 3. Neither the name of the University nor the names of its contributors
     19  *    may be used to endorse or promote products derived from this software
     20  *    without specific prior written permission.
     21  *
     22  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     23  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     24  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     25  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     26  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     27  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     28  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     29  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     31  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     32  * SUCH DAMAGE.
     33  *
     34  *	@(#)autoconf.c	7.1 (Berkeley) 5/9/91
     35  */
     36 
     37 #include <sys/cdefs.h>
     38 __KERNEL_RCSID(0, "$NetBSD: x86_autoconf.c,v 1.92 2025/10/13 14:12:13 thorpej Exp $");
     39 
     40 #include <sys/param.h>
     41 #include <sys/systm.h>
     42 #include <sys/device.h>
     43 #include <sys/disklabel.h>
     44 #include <sys/conf.h>
     45 #include <sys/malloc.h>
     46 #include <sys/vnode.h>
     47 #include <sys/fcntl.h>
     48 #include <sys/disk.h>
     49 #include <sys/proc.h>
     50 #include <sys/md5.h>
     51 #include <sys/kauth.h>
     52 
     53 #include <machine/autoconf.h>
     54 #include <machine/bootinfo.h>
     55 #include <machine/pio.h>
     56 
     57 #include <xen/xen.h>
     58 
     59 #include <dev/i2c/i2cvar.h>
     60 
     61 #include "acpica.h"
     62 #include "wsdisplay.h"
     63 #ifndef XENPV
     64 #include "hyperv.h"
     65 #endif
     66 
     67 #if NACPICA > 0
     68 #include <dev/acpi/acpivar.h>
     69 #endif
     70 #if NHYPERV > 0
     71 #include <x86/x86/hypervvar.h>
     72 #endif
     73 
     74 struct disklist *x86_alldisks;
     75 int x86_ndisks;
     76 int x86_found_console;
     77 
     78 #ifdef DEBUG_GEOM
     79 #define DPRINTF(a) printf a
     80 #else
     81 #define DPRINTF(a)
     82 #endif
     83 
     84 static void
     85 dmatch(const char *func, device_t dv, const char *method)
     86 {
     87 
     88 	printf("WARNING: %s: double match for boot device (%s:%s %s:%s)\n",
     89 	    func, booted_method, device_xname(booted_device),
     90 	    method, device_xname(dv));
     91 }
     92 
     93 static int
     94 is_valid_disk(device_t dv)
     95 {
     96 
     97 	if (device_class(dv) != DV_DISK)
     98 		return 0;
     99 
    100 	return (device_is_a(dv, "dk") ||
    101 		device_is_a(dv, "sd") ||
    102 		device_is_a(dv, "wd") ||
    103 		device_is_a(dv, "ld") ||
    104 		device_is_a(dv, "xbd") ||
    105 		device_is_a(dv, "ed"));
    106 }
    107 
    108 /*
    109  * XXX Ugly bit of code.  But, this is the only safe time that the
    110  * match between BIOS disks and native disks can be done.
    111  */
    112 static void
    113 matchbiosdisks(void)
    114 {
    115 	struct btinfo_biosgeom *big;
    116 	struct bi_biosgeom_entry *be;
    117 	device_t dv;
    118 	deviter_t di;
    119 	int i, ck, error, m, n;
    120 	struct vnode *tv;
    121 	char mbr[DEV_BSIZE];
    122 	int dklist_size;
    123 	int numbig;
    124 
    125 	if (x86_ndisks)
    126 		return;
    127 	big = lookup_bootinfo(BTINFO_BIOSGEOM);
    128 
    129 	numbig = big ? big->num : 0;
    130 
    131 	/* First, count all native disks. */
    132 	for (dv = deviter_first(&di, DEVITER_F_ROOT_FIRST); dv != NULL;
    133 	     dv = deviter_next(&di)) {
    134 		if (is_valid_disk(dv))
    135 			x86_ndisks++;
    136 	}
    137 	deviter_release(&di);
    138 
    139 	dklist_size = sizeof(struct disklist) + (x86_ndisks - 1) *
    140 	    sizeof(struct nativedisk_info);
    141 
    142 	/* XXX M_TEMP is wrong */
    143 	x86_alldisks = malloc(dklist_size, M_TEMP, M_WAITOK | M_ZERO);
    144 	x86_alldisks->dl_nnativedisks = x86_ndisks;
    145 	x86_alldisks->dl_nbiosdisks = numbig;
    146 	for (i = 0; i < numbig; i++) {
    147 		x86_alldisks->dl_biosdisks[i].bi_dev = big->disk[i].dev;
    148 		x86_alldisks->dl_biosdisks[i].bi_sec = big->disk[i].sec;
    149 		x86_alldisks->dl_biosdisks[i].bi_head = big->disk[i].head;
    150 		x86_alldisks->dl_biosdisks[i].bi_cyl = big->disk[i].cyl;
    151 		x86_alldisks->dl_biosdisks[i].bi_lbasecs = big->disk[i].totsec;
    152 		x86_alldisks->dl_biosdisks[i].bi_flags = big->disk[i].flags;
    153 		DPRINTF(("%s: disk %x: flags %x",
    154 		    __func__, big->disk[i].dev, big->disk[i].flags));
    155 #ifdef BIOSDISK_EXTINFO_V3
    156 		DPRINTF((", interface %x, device %llx",
    157 		    big->disk[i].interface_path, big->disk[i].device_path));
    158 #endif
    159 		DPRINTF(("\n"));
    160 	}
    161 
    162 	/* XXX Code duplication from findroot(). */
    163 	n = -1;
    164 	for (dv = deviter_first(&di, DEVITER_F_ROOT_FIRST); dv != NULL;
    165 	     dv = deviter_next(&di)) {
    166 		if (!is_valid_disk(dv))
    167 			continue;
    168 		DPRINTF(("%s: trying to match (%s) %s: ", __func__,
    169 		    device_xname(dv), device_cfdata(dv)->cf_name));
    170 		n++;
    171 		snprintf(x86_alldisks->dl_nativedisks[n].ni_devname,
    172 		    sizeof(x86_alldisks->dl_nativedisks[n].ni_devname),
    173 		    "%s", device_xname(dv));
    174 
    175 		if ((tv = opendisk(dv)) == NULL) {
    176 			DPRINTF(("cannot open\n"));
    177 			continue;
    178 		}
    179 
    180 		error = vn_rdwr(UIO_READ, tv, mbr, DEV_BSIZE, 0, UIO_SYSSPACE,
    181 		    IO_NODELOCKED, NOCRED, NULL, NULL);
    182 		VOP_CLOSE(tv, FREAD, NOCRED);
    183 		vput(tv);
    184 		if (error) {
    185 			DPRINTF(("MBR read failure %d\n", error));
    186 			continue;
    187 		}
    188 
    189 		for (ck = i = 0; i < DEV_BSIZE; i++)
    190 			ck += mbr[i];
    191 		for (m = i = 0; i < numbig; i++) {
    192 			be = &big->disk[i];
    193 			if (be->flags & BI_GEOM_INVALID)
    194 				continue;
    195 			DPRINTF(("matched with %d dev ck %x bios ck %x\n",
    196 			    i, ck, be->cksum));
    197 			if (be->cksum == ck && memcmp(&mbr[MBR_PART_OFFSET],
    198 			    be->mbrparts, MBR_PART_COUNT
    199 			    * sizeof(struct mbr_partition)) == 0) {
    200 				DPRINTF(("%s: matched BIOS disk %x with %s\n",
    201 				    __func__, be->dev, device_xname(dv)));
    202 				x86_alldisks->dl_nativedisks[n].
    203 				    ni_biosmatches[m++] = i;
    204 			}
    205 		}
    206 		x86_alldisks->dl_nativedisks[n].ni_nmatches = m;
    207 	}
    208 	deviter_release(&di);
    209 }
    210 
    211 /*
    212  * Helper function for findroot():
    213  * Return non-zero if wedge device matches bootinfo.
    214  */
    215 static int
    216 match_bootwedge(device_t dv, struct btinfo_bootwedge *biw)
    217 {
    218 	MD5_CTX ctx;
    219 	struct vnode *tmpvn;
    220 	int error;
    221 	uint8_t bf[DEV_BSIZE];
    222 	uint8_t hash[16];
    223 	int found = 0;
    224 	daddr_t blk;
    225 	uint64_t nblks;
    226 
    227 	/*
    228 	 * If the boot loader didn't specify the sector, abort.
    229 	 */
    230 	if (biw->matchblk == -1) {
    231 		DPRINTF(("%s: no sector specified for %s\n", __func__,
    232 			device_xname(dv)));
    233 		return 0;
    234 	}
    235 
    236 	if ((tmpvn = opendisk(dv)) == NULL) {
    237 		DPRINTF(("%s: can't open %s\n", __func__, device_xname(dv)));
    238 		return 0;
    239 	}
    240 
    241 	MD5Init(&ctx);
    242 	for (blk = biw->matchblk, nblks = biw->matchnblks;
    243 	     nblks != 0; nblks--, blk++) {
    244 		error = vn_rdwr(UIO_READ, tmpvn, (void *) bf,
    245 		    sizeof(bf), blk * DEV_BSIZE, UIO_SYSSPACE,
    246 		    IO_NODELOCKED, NOCRED, NULL, NULL);
    247 		if (error) {
    248 			if (error != EINVAL) {
    249 				aprint_error("%s: unable to read block %"
    250 				    PRId64 " " "of dev %s (%d)\n", __func__,
    251 				    blk, device_xname(dv), error);
    252 			}
    253 			goto closeout;
    254 		}
    255 		MD5Update(&ctx, bf, sizeof(bf));
    256 	}
    257 	MD5Final(hash, &ctx);
    258 
    259 	/* Compare with the provided hash. */
    260 	found = memcmp(biw->matchhash, hash, sizeof(hash)) == 0;
    261 	DPRINTF(("%s: %s found=%d\n", __func__, device_xname(dv), found));
    262 
    263  closeout:
    264 	VOP_CLOSE(tmpvn, FREAD, NOCRED);
    265 	vput(tmpvn);
    266 	return found;
    267 }
    268 
    269 /*
    270  * Helper function for findroot():
    271  * Return non-zero if disk device matches bootinfo.
    272  */
    273 static int
    274 match_bootdisk(device_t dv, struct btinfo_bootdisk *bid)
    275 {
    276 	struct vnode *tmpvn;
    277 	int error;
    278 	struct disklabel label;
    279 	int found = 0;
    280 
    281 	if (device_is_a(dv, "dk")) {
    282 		DPRINTF(("%s: dk %s\n", __func__, device_xname(dv)));
    283 		return 0;
    284 	}
    285 
    286 	/*
    287 	 * A disklabel is required here.  The boot loader doesn't refuse
    288 	 * to boot from a disk without a label, but this is normally not
    289 	 * wanted.
    290 	 */
    291 	if (bid->labelsector == -1) {
    292 		DPRINTF(("%s: no label %s\n", __func__, device_xname(dv)));
    293 		return 0;
    294 	}
    295 
    296 	if ((tmpvn = opendisk(dv)) == NULL) {
    297 		DPRINTF(("%s: can't open %s\n", __func__, device_xname(dv)));
    298 		return 0;
    299 	}
    300 
    301 	VOP_UNLOCK(tmpvn);
    302 	error = VOP_IOCTL(tmpvn, DIOCGDINFO, &label, FREAD, NOCRED);
    303 	vn_lock(tmpvn, LK_EXCLUSIVE | LK_RETRY);
    304 	if (error) {
    305 		/*
    306 		 * XXX Can't happen -- open() would have errored out
    307 		 * or faked one up.
    308 		 */
    309 		printf("%s: can't get label for dev %s (%d)\n", __func__,
    310 		    device_xname(dv), error);
    311 		goto closeout;
    312 	}
    313 
    314 	/* Compare with our data. */
    315 	if (label.d_type == bid->label.type &&
    316 	    label.d_checksum == bid->label.checksum &&
    317 	    strncmp(label.d_packname, bid->label.packname, 16) == 0)
    318 		found = 1;
    319 
    320 	DPRINTF(("%s: %s found=%d\n", __func__, device_xname(dv), found));
    321  closeout:
    322 	VOP_CLOSE(tmpvn, FREAD, NOCRED);
    323 	vput(tmpvn);
    324 	return found;
    325 }
    326 
    327 /*
    328  * Attempt to find the device from which we were booted.  If we can do so,
    329  * and not instructed not to do so, change rootdev to correspond to the
    330  * load device.
    331  */
    332 static void
    333 findroot(void)
    334 {
    335 	struct btinfo_rootdevice *biv;
    336 	struct btinfo_bootdisk *bid;
    337 	struct btinfo_bootwedge *biw;
    338 	struct btinfo_biosgeom *big;
    339 	device_t dv;
    340 	deviter_t di;
    341 	static char bootspecbuf[sizeof(biv->devname)+1];
    342 
    343 	if (booted_device)
    344 		return;
    345 
    346 	if (lookup_bootinfo(BTINFO_NETIF) != NULL) {
    347 		/*
    348 		 * We got netboot interface information, but device_register()
    349 		 * failed to match it to a configured device.  Boot disk
    350 		 * information cannot be present at the same time, so give
    351 		 * up.
    352 		 */
    353 		printf("%s: netboot interface not found.\n", __func__);
    354 		return;
    355 	}
    356 
    357 	if ((biv = lookup_bootinfo(BTINFO_ROOTDEVICE)) != NULL) {
    358 		for (dv = deviter_first(&di, DEVITER_F_ROOT_FIRST);
    359 		     dv != NULL;
    360 		     dv = deviter_next(&di)) {
    361 			cfdata_t cd;
    362 			size_t len;
    363 
    364 			if (device_class(dv) != DV_DISK)
    365 				continue;
    366 
    367 			cd = device_cfdata(dv);
    368 			len = strlen(cd->cf_name);
    369 
    370 			if (strncmp(cd->cf_name, biv->devname, len) == 0 &&
    371 			    biv->devname[len] - '0' == device_unit(dv)) {
    372 				booted_device = dv;
    373 				booted_method = "bootinfo/rootdevice";
    374 				booted_partition = biv->devname[len + 1] - 'a';
    375 				booted_nblks = 0;
    376 				break;
    377 			}
    378 		}
    379 		DPRINTF(("%s: BTINFO_ROOTDEVICE %s\n", __func__,
    380 		    booted_device ? device_xname(booted_device) : "not found"));
    381 		deviter_release(&di);
    382 		if (dv != NULL)
    383 			return;
    384 
    385 		if (biv->devname[0] != '\0') {
    386 			strlcpy(bootspecbuf, biv->devname, sizeof(bootspecbuf));
    387 			bootspec = bootspecbuf;
    388 			return;
    389 		}
    390 	}
    391 
    392 	bid = lookup_bootinfo(BTINFO_BOOTDISK);
    393 	biw = lookup_bootinfo(BTINFO_BOOTWEDGE);
    394 
    395 	if (biw != NULL) {
    396 		/*
    397 		 * Scan all disk devices for ones that match the passed data.
    398 		 * Don't break if one is found, to get possible multiple
    399 		 * matches - for problem tracking.  Use the first match anyway
    400 		 * because lower devices numbers are more likely to be the
    401 		 * boot device.
    402 		 */
    403 		for (dv = deviter_first(&di, DEVITER_F_ROOT_FIRST);
    404 		     dv != NULL;
    405 		     dv = deviter_next(&di)) {
    406 			if (is_valid_disk(dv)) {
    407 				/*
    408 				 * Don't trust BIOS device numbers, try
    409 				 * to match the information passed by the
    410 				 * boot loader instead.
    411 				 */
    412 				if ((biw->biosdev & 0x80) == 0 ||
    413 				    match_bootwedge(dv, biw) == 0)
    414 					continue;
    415 				goto bootwedge_found;
    416 			}
    417 
    418 			continue;
    419  bootwedge_found:
    420 			if (booted_device) {
    421 				dmatch(__func__, dv, "bootinfo/bootwedge");
    422 				continue;
    423 			}
    424 			booted_device = dv;
    425 			booted_method = "bootinfo/bootwedge";
    426 			booted_partition = bid != NULL ? bid->partition : 0;
    427 			booted_nblks = biw->nblks;
    428 			booted_startblk = biw->startblk;
    429 		}
    430 		deviter_release(&di);
    431 
    432 		DPRINTF(("%s: BTINFO_BOOTWEDGE %s\n", __func__,
    433 		    booted_device ? device_xname(booted_device) : "not found"));
    434 		if (booted_nblks)
    435 			return;
    436 	}
    437 
    438 	if (bid != NULL) {
    439 		/*
    440 		 * Scan all disk devices for ones that match the passed data.
    441 		 * Don't break if one is found, to get possible multiple
    442 		 * matches - for problem tracking.  Use the first match anyway
    443 		 * because lower device numbers are more likely to be the
    444 		 * boot device.
    445 		 */
    446 		for (dv = deviter_first(&di, DEVITER_F_ROOT_FIRST);
    447 		     dv != NULL;
    448 		     dv = deviter_next(&di)) {
    449 
    450 			if (device_is_a(dv, "fd") &&
    451 			    device_class(dv) == DV_DISK) {
    452 				/*
    453 				 * Assume the configured unit number matches
    454 				 * the BIOS device number.  (This is the old
    455 				 * behavior.)  Needs some ideas how to handle
    456 				 * the BIOS's "swap floppy drive" options.
    457 				 */
    458 				/* XXX device_unit() abuse */
    459 				if ((bid->biosdev & 0x80) != 0 ||
    460 				    device_unit(dv) != bid->biosdev)
    461 					continue;
    462 				goto bootdisk_found;
    463 			}
    464 
    465 			if (is_valid_disk(dv)) {
    466 				/*
    467 				 * Don't trust BIOS device numbers, try
    468 				 * to match the information passed by the
    469 				 * boot loader instead.
    470 				 */
    471 				if ((bid->biosdev & 0x80) == 0 ||
    472 				    match_bootdisk(dv, bid) == 0)
    473 					continue;
    474 				goto bootdisk_found;
    475 			}
    476 
    477 			continue;
    478  bootdisk_found:
    479 			if (booted_device) {
    480 				dmatch(__func__, dv, "bootinfo/bootdisk");
    481 				continue;
    482 			}
    483 			booted_device = dv;
    484 			booted_method = "bootinfo/bootdisk";
    485 			booted_partition = bid->partition;
    486 			booted_nblks = 0;
    487 		}
    488 		deviter_release(&di);
    489 
    490 		DPRINTF(("%s: BTINFO_BOOTDISK %s\n", __func__,
    491 		    booted_device ? device_xname(booted_device) : "not found"));
    492 		if (booted_device)
    493 			return;
    494 
    495 		/*
    496 		 * No booted device found; check CD-ROM boot at last.
    497 		 *
    498 		 * Our bootloader assumes CD-ROM boot if biosdev is larger
    499 		 * or equal than the number of hard drives recognized by the
    500 		 * BIOS. The number of drives can be found in BTINFO_BIOSGEOM
    501 		 * here. For example, if we have wd0, wd1, and cd0:
    502 		 *
    503 		 *	big->num = 2 (for wd0 and wd1)
    504 		 *	bid->biosdev = 0x80 (wd0)
    505 		 *	bid->biosdev = 0x81 (wd1)
    506 		 *	bid->biosdev = 0x82 (cd0)
    507 		 *
    508 		 * See src/sys/arch/i386/stand/boot/devopen.c and
    509 		 * src/sys/arch/i386/stand/lib/bootinfo_biosgeom.c .
    510 		 */
    511 		if ((big = lookup_bootinfo(BTINFO_BIOSGEOM)) != NULL &&
    512 		    bid->biosdev >= 0x80 + big->num) {
    513 			/*
    514 			 * XXX
    515 			 * There is no proper way to detect which unit is
    516 			 * recognized as a bootable CD-ROM drive by the BIOS.
    517 			 * Assume the first unit is the one.
    518 			 */
    519 			for (dv = deviter_first(&di, DEVITER_F_ROOT_FIRST);
    520 			     dv != NULL;
    521 			     dv = deviter_next(&di)) {
    522 				if (device_class(dv) == DV_DISK &&
    523 				    device_is_a(dv, "cd")) {
    524 					booted_device = dv;
    525 					booted_method = "bootinfo/biosgeom";
    526 					booted_partition = 0;
    527 					booted_nblks = 0;
    528 					break;
    529 				}
    530 			}
    531 			deviter_release(&di);
    532 			DPRINTF(("%s: BTINFO_BIOSGEOM %s\n", __func__,
    533 			    booted_device ? device_xname(booted_device) :
    534 			    "not found"));
    535 		}
    536 	}
    537 }
    538 
    539 void
    540 cpu_bootconf(void)
    541 {
    542 #ifdef XEN
    543 	if (pvh_boot) {
    544 		xen_bootconf();
    545 		return;
    546 	}
    547 #endif
    548 	findroot();
    549 	matchbiosdisks();
    550 }
    551 
    552 void
    553 cpu_rootconf(void)
    554 {
    555 	cpu_bootconf();
    556 
    557 	aprint_normal("boot device: %s\n",
    558 	    booted_device ? device_xname(booted_device) : "<unknown>");
    559 	rootconf();
    560 }
    561 
    562 void
    563 device_register(device_t dev, void *aux)
    564 {
    565 	device_t isaboot, pciboot;
    566 
    567 	/*
    568 	 * The Intel Integrated Memory Controller has a built-in i2c
    569 	 * controller that's rather limited in capability; it is intended
    570 	 * only for reading memory module EERPOMs and sensors.
    571 	 */
    572 	if (device_is_a(dev, "iic") &&
    573 	    device_is_a(device_parent(dev), "imcsmb")) {
    574 		static const char *imcsmb_device_permitlist[] = {
    575 			"spdmem",
    576 			"sdtemp",
    577 			NULL,
    578 		};
    579 		prop_array_t permitlist = prop_array_create();
    580 		prop_dictionary_t props = device_properties(dev);
    581 		int i;
    582 
    583 		for (i = 0; imcsmb_device_permitlist[i] != NULL; i++) {
    584 			prop_string_t pstr = prop_string_create_nocopy(
    585 			    imcsmb_device_permitlist[i]);
    586 			(void) prop_array_add(permitlist, pstr);
    587 			prop_object_release(pstr);
    588 		}
    589 		(void) prop_dictionary_set(props,
    590 					   I2C_PROP_INDIRECT_DEVICE_PERMITLIST,
    591 					   permitlist);
    592 		(void) prop_dictionary_set_string_nocopy(props,
    593 					   I2C_PROP_INDIRECT_PROBE_STRATEGY,
    594 					   I2C_PROBE_STRATEGY_NONE);
    595 	}
    596 
    597 	device_acpi_register(dev, aux);
    598 
    599 	isaboot = device_isa_register(dev, aux);
    600 	pciboot = device_pci_register(dev, aux);
    601 #if NHYPERV > 0
    602 	(void)device_hyperv_register(dev, aux);
    603 #endif
    604 
    605 	if (device_is_a(dev, "com") && vm_guest > VM_GUEST_NO) {
    606 		device_setprop_bool(dev, "skip_attach_delay", true);
    607 	}
    608 
    609 	if (isaboot == NULL && pciboot == NULL)
    610 		return;
    611 
    612 	if (booted_device != NULL) {
    613 		/* XXX should be a panic() */
    614 		dmatch(__func__, dev, "device/register");
    615 	} else {
    616 		booted_device = (isaboot != NULL) ? isaboot : pciboot;
    617 		booted_method = "device/register";
    618 	}
    619 }
    620