svn commit: r353543 - in releng/12.1/stand: efi/boot1 efi/include efi/libefi efi/loader efi/loader/arch/i386 libsa

Toomas Soome tsoome at FreeBSD.org
Tue Oct 15 06:19:34 UTC 2019


Author: tsoome
Date: Tue Oct 15 06:19:33 2019
New Revision: 353543
URL: https://svnweb.freebsd.org/changeset/base/353543

Log:
  loader.efi: efipart needs to use ioalign
  
  UEFI specification 2.7A, EFI_BLOCK_IO_PROTOCOL, page 566.
  
  The ioalign property does define the alignment of data buffer.
  
  If the alignment is required and our buffer is not aligned, or if
  the data buffer is not multiple of Blocksize, we need to use bounce buffer
  to perform the block IO. This is much like with BIOS version, except
  there the INT13 needs buffer to be located in low memory.
  
  MFS: r353501
  MFC: r347195,350654-350656,351274,351630,351637,352421,352439,352443-352446,352451
  
  Approved by:	re (gjb)

Modified:
  releng/12.1/stand/efi/boot1/boot1.c
  releng/12.1/stand/efi/include/efilib.h
  releng/12.1/stand/efi/libefi/devpath.c
  releng/12.1/stand/efi/libefi/efinet.c
  releng/12.1/stand/efi/libefi/efipart.c
  releng/12.1/stand/efi/libefi/libefi.c
  releng/12.1/stand/efi/loader/arch/i386/efimd.c
  releng/12.1/stand/efi/loader/efi_main.c
  releng/12.1/stand/efi/loader/framebuffer.c
  releng/12.1/stand/efi/loader/main.c
  releng/12.1/stand/libsa/stand.h
  releng/12.1/stand/libsa/zalloc.c
  releng/12.1/stand/libsa/zalloc_defs.h
  releng/12.1/stand/libsa/zalloc_malloc.c
  releng/12.1/stand/libsa/zalloc_mem.h
  releng/12.1/stand/libsa/zalloc_protos.h
Directory Properties:
  releng/12.1/   (props changed)

Modified: releng/12.1/stand/efi/boot1/boot1.c
==============================================================================
--- releng/12.1/stand/efi/boot1/boot1.c	Tue Oct 15 04:50:08 2019	(r353542)
+++ releng/12.1/stand/efi/boot1/boot1.c	Tue Oct 15 06:19:33 2019	(r353543)
@@ -246,8 +246,9 @@ try_boot(void)
 		goto errout;
 	}
 
-	if ((status = BS->HandleProtocol(loaderhandle, &LoadedImageGUID,
-	    (VOID**)&loaded_image)) != EFI_SUCCESS) {
+	status = OpenProtocolByHandle(loaderhandle, &LoadedImageGUID,
+	    (void **)&loaded_image);
+	if (status != EFI_SUCCESS) {
 		printf("Failed to query LoadedImage provided by %s (%lu)\n",
 		    mod->name, EFI_ERROR_CODE(status));
 		goto errout;
@@ -306,7 +307,7 @@ probe_handle(EFI_HANDLE h, EFI_DEVICE_PATH *imgpath, B
 	UINTN i;
 
 	/* Figure out if we're dealing with an actual partition. */
-	status = BS->HandleProtocol(h, &DevicePathGUID, (void **)&devpath);
+	status = OpenProtocolByHandle(h, &DevicePathGUID, (void **)&devpath);
 	if (status == EFI_UNSUPPORTED)
 		return (status);
 
@@ -322,7 +323,7 @@ probe_handle(EFI_HANDLE h, EFI_DEVICE_PATH *imgpath, B
 		efi_free_devpath_name(text);
 	}
 #endif
-	status = BS->HandleProtocol(h, &BlockIoProtocolGUID, (void **)&blkio);
+	status = OpenProtocolByHandle(h, &BlockIoProtocolGUID, (void **)&blkio);
 	if (status == EFI_UNSUPPORTED)
 		return (status);
 
@@ -445,7 +446,7 @@ efi_main(EFI_HANDLE Ximage, EFI_SYSTEM_TABLE *Xsystab)
 	putchar('\n');
 
 	/* Determine the devpath of our image so we can prefer it. */
-	status = BS->HandleProtocol(IH, &LoadedImageGUID, (VOID**)&img);
+	status = OpenProtocolByHandle(IH, &LoadedImageGUID, (void **)&img);
 	imgpath = NULL;
 	if (status == EFI_SUCCESS) {
 		text = efi_devpath_name(img->FilePath);
@@ -455,8 +456,8 @@ efi_main(EFI_HANDLE Ximage, EFI_SYSTEM_TABLE *Xsystab)
 			efi_free_devpath_name(text);
 		}
 
-		status = BS->HandleProtocol(img->DeviceHandle, &DevicePathGUID,
-		    (void **)&imgpath);
+		status = OpenProtocolByHandle(img->DeviceHandle,
+		    &DevicePathGUID, (void **)&imgpath);
 		if (status != EFI_SUCCESS) {
 			DPRINTF("Failed to get image DevicePath (%lu)\n",
 			    EFI_ERROR_CODE(status));

Modified: releng/12.1/stand/efi/include/efilib.h
==============================================================================
--- releng/12.1/stand/efi/include/efilib.h	Tue Oct 15 04:50:08 2019	(r353542)
+++ releng/12.1/stand/efi/include/efilib.h	Tue Oct 15 06:19:33 2019	(r353543)
@@ -69,6 +69,7 @@ pdinfo_t *efiblk_get_pdinfo_by_handle(EFI_HANDLE h);
 pdinfo_t *efiblk_get_pdinfo_by_device_path(EFI_DEVICE_PATH *path);
 
 void *efi_get_table(EFI_GUID *tbl);
+EFI_STATUS OpenProtocolByHandle(EFI_HANDLE, EFI_GUID *, void **);
 
 int efi_getdev(void **vdev, const char *devspec, const char **path);
 char *efi_fmtdev(void *vdev);
@@ -92,6 +93,7 @@ CHAR16 *efi_devpath_name(EFI_DEVICE_PATH *);
 void efi_free_devpath_name(CHAR16 *);
 EFI_DEVICE_PATH *efi_devpath_to_media_path(EFI_DEVICE_PATH *);
 UINTN efi_devpath_length(EFI_DEVICE_PATH *);
+EFI_HANDLE efi_devpath_to_handle(EFI_DEVICE_PATH *path, EFI_HANDLE *handles, unsigned nhandles);
 
 int efi_status_to_errno(EFI_STATUS);
 EFI_STATUS errno_to_efi_status(int errno);

Modified: releng/12.1/stand/efi/libefi/devpath.c
==============================================================================
--- releng/12.1/stand/efi/libefi/devpath.c	Tue Oct 15 04:50:08 2019	(r353542)
+++ releng/12.1/stand/efi/libefi/devpath.c	Tue Oct 15 06:19:33 2019	(r353543)
@@ -42,8 +42,8 @@ efi_lookup_image_devpath(EFI_HANDLE handle)
 	EFI_DEVICE_PATH *devpath;
 	EFI_STATUS status;
 
-	status = BS->HandleProtocol(handle, &ImageDevicePathGUID,
-	    (VOID **)&devpath);
+	status = OpenProtocolByHandle(handle, &ImageDevicePathGUID,
+	    (void **)&devpath);
 	if (EFI_ERROR(status))
 		devpath = NULL;
 	return (devpath);
@@ -55,7 +55,8 @@ efi_lookup_devpath(EFI_HANDLE handle)
 	EFI_DEVICE_PATH *devpath;
 	EFI_STATUS status;
 
-	status = BS->HandleProtocol(handle, &DevicePathGUID, (VOID **)&devpath);
+	status = OpenProtocolByHandle(handle, &DevicePathGUID,
+	    (void **)&devpath);
 	if (EFI_ERROR(status))
 		devpath = NULL;
 	return (devpath);
@@ -228,4 +229,26 @@ efi_devpath_length(EFI_DEVICE_PATH  *path)
 	while (!IsDevicePathEnd(path))
 		path = NextDevicePathNode(path);
 	return ((UINTN)path - (UINTN)start) + DevicePathNodeLength(path);
+}
+
+EFI_HANDLE
+efi_devpath_to_handle(EFI_DEVICE_PATH *path, EFI_HANDLE *handles, unsigned nhandles)
+{
+	unsigned i;
+	EFI_DEVICE_PATH *media, *devpath;
+	EFI_HANDLE h;
+
+	media = efi_devpath_to_media_path(path);
+	if (media == NULL)
+		return (NULL);
+	for (i = 0; i < nhandles; i++) {
+		h = handles[i];
+		devpath = efi_lookup_devpath(h);
+		if (devpath == NULL)
+			continue;
+		if (!efi_devpath_match_node(media, efi_devpath_to_media_path(devpath)))
+			continue;
+		return (h);
+	}
+	return (NULL);
 }

Modified: releng/12.1/stand/efi/libefi/efinet.c
==============================================================================
--- releng/12.1/stand/efi/libefi/efinet.c	Tue Oct 15 04:50:08 2019	(r353542)
+++ releng/12.1/stand/efi/libefi/efinet.c	Tue Oct 15 06:19:33 2019	(r353543)
@@ -195,7 +195,7 @@ efinet_init(struct iodesc *desc, void *machdep_hint)
 	}
 
 	h = nif->nif_driver->netif_ifs[nif->nif_unit].dif_private;
-	status = BS->HandleProtocol(h, &sn_guid, (VOID **)&nif->nif_devdata);
+	status = OpenProtocolByHandle(h, &sn_guid, (void **)&nif->nif_devdata);
 	if (status != EFI_SUCCESS) {
 		printf("net%d: cannot fetch interface data (status=%lu)\n",
 		    nif->nif_unit, EFI_ERROR_CODE(status));

Modified: releng/12.1/stand/efi/libefi/efipart.c
==============================================================================
--- releng/12.1/stand/efi/libefi/efipart.c	Tue Oct 15 04:50:08 2019	(r353542)
+++ releng/12.1/stand/efi/libefi/efipart.c	Tue Oct 15 06:19:33 2019	(r353543)
@@ -64,6 +64,9 @@ static int efipart_printhd(int);
 #define	PNP0700	0x700
 #define	PNP0701	0x701
 
+/* Bounce buffer max size */
+#define	BIO_BUFFER_SIZE	0x4000
+
 struct devsw efipart_fddev = {
 	.dv_name = "fd",
 	.dv_type = DEVT_FD,
@@ -100,12 +103,18 @@ struct devsw efipart_hddev = {
 	.dv_cleanup = NULL
 };
 
-static pdinfo_list_t fdinfo;
-static pdinfo_list_t cdinfo;
-static pdinfo_list_t hdinfo;
+static pdinfo_list_t fdinfo = STAILQ_HEAD_INITIALIZER(fdinfo);
+static pdinfo_list_t cdinfo = STAILQ_HEAD_INITIALIZER(cdinfo);
+static pdinfo_list_t hdinfo = STAILQ_HEAD_INITIALIZER(hdinfo);
 
-static EFI_HANDLE *efipart_handles = NULL;
-static UINTN efipart_nhandles = 0;
+/*
+ * efipart_inithandles() is used to build up the pdinfo list from
+ * block device handles. Then each devsw init callback is used to
+ * pick items from pdinfo and move to proper device list.
+ * In ideal world, we should end up with empty pdinfo once all
+ * devsw initializers are called.
+ */
+static pdinfo_list_t pdinfo = STAILQ_HEAD_INITIALIZER(pdinfo);
 
 pdinfo_list_t *
 efiblk_get_pdinfo_list(struct devsw *dev)
@@ -140,23 +149,14 @@ efiblk_get_pdinfo(struct devdesc *dev)
 pdinfo_t *
 efiblk_get_pdinfo_by_device_path(EFI_DEVICE_PATH *path)
 {
-	unsigned i;
-	EFI_DEVICE_PATH *media, *devpath;
 	EFI_HANDLE h;
+	EFI_STATUS status;
+	EFI_DEVICE_PATH *devp = path;
 
-	media = efi_devpath_to_media_path(path);
-	if (media == NULL)
+	status = BS->LocateDevicePath(&blkio_guid, &devp, &h);
+	if (EFI_ERROR(status))
 		return (NULL);
-	for (i = 0; i < efipart_nhandles; i++) {
-		h = efipart_handles[i];
-		devpath = efi_lookup_devpath(h);
-		if (devpath == NULL)
-			continue;
-		if (!efi_devpath_match_node(media, efi_devpath_to_media_path(devpath)))
-			continue;
-		return (efiblk_get_pdinfo_by_handle(h));
-	}
-	return (NULL);
+	return (efiblk_get_pdinfo_by_handle(h));
 }
 
 static bool
@@ -185,6 +185,10 @@ efiblk_get_pdinfo_by_handle(EFI_HANDLE h)
 	STAILQ_FOREACH(dp, &cdinfo, pd_link) {
 		if (same_handle(dp, h))
 			return (dp);
+		STAILQ_FOREACH(pp, &dp->pd_part, pd_link) {
+			if (same_handle(pp, h))
+				return (pp);
+		}
 	}
 	STAILQ_FOREACH(dp, &fdinfo, pd_link) {
 		if (same_handle(dp, h))
@@ -208,15 +212,16 @@ efiblk_pdinfo_count(pdinfo_list_t *pdi)
 int
 efipart_inithandles(void)
 {
+	unsigned i, nin;
 	UINTN sz;
 	EFI_HANDLE *hin;
+	EFI_DEVICE_PATH *devpath;
+	EFI_BLOCK_IO *blkio;
 	EFI_STATUS status;
+	pdinfo_t *pd;
 
-	if (efipart_nhandles != 0) {
-		free(efipart_handles);
-		efipart_handles = NULL;
-		efipart_nhandles = 0;
-	}
+	if (!STAILQ_EMPTY(&pdinfo))
+		return (0);
 
 	sz = 0;
 	hin = NULL;
@@ -231,12 +236,60 @@ efipart_inithandles(void)
 	if (EFI_ERROR(status))
 		return (efi_status_to_errno(status));
 
-	efipart_handles = hin;
-	efipart_nhandles = sz / sizeof(*hin);
+	nin = sz / sizeof(*hin);
 #ifdef EFIPART_DEBUG
-	printf("%s: Got %d BLOCK IO MEDIA handle(s)\n", __func__,
-	    efipart_nhandles);
+	printf("%s: Got %d BLOCK IO MEDIA handle(s)\n", __func__, nin);
 #endif
+
+	for (i = 0; i < nin; i++) {
+		/*
+		 * Get devpath and open protocol.
+		 * We should not get errors here
+		 */
+		if ((devpath = efi_lookup_devpath(hin[i])) == NULL)
+			continue;
+
+		status = OpenProtocolByHandle(hin[i], &blkio_guid,
+		    (void **)&blkio);
+		if (EFI_ERROR(status)) {
+			printf("error %lu\n", EFI_ERROR_CODE(status));
+			continue;
+		}
+
+		/*
+		 * We assume the block size 512 or greater power of 2.
+		 * Also skip devices with block size > 64k (16 is max
+		 * ashift supported by zfs).
+		 * iPXE is known to insert stub BLOCK IO device with
+		 * BlockSize 1.
+		 */
+		if (blkio->Media->BlockSize < 512 ||
+		    blkio->Media->BlockSize > (1 << 16) ||
+		    !powerof2(blkio->Media->BlockSize)) {
+			continue;
+		}
+
+		/* Allowed values are 0, 1 and power of 2. */
+		if (blkio->Media->IoAlign > 1 &&
+		    !powerof2(blkio->Media->IoAlign)) {
+			continue;
+		}
+
+		/* This is bad. */
+		if ((pd = calloc(1, sizeof(*pd))) == NULL) {
+			printf("efipart_inithandles: Out of memory.\n");
+			free(hin);
+			return (ENOMEM);
+		}
+		STAILQ_INIT(&pd->pd_part);
+
+		pd->pd_handle = hin[i];
+		pd->pd_devpath = devpath;
+		pd->pd_blkio = blkio;
+		STAILQ_INSERT_TAIL(&pdinfo, pd, pd_link);
+	}
+
+	free(hin);
 	return (0);
 }
 
@@ -257,134 +310,49 @@ efipart_floppy(EFI_DEVICE_PATH *node)
 	return (NULL);
 }
 
-/*
- * Determine if the provided device path is hdd.
- *
- * There really is no simple fool proof way to classify the devices.
- * Since we do build three lists of devices - floppy, cd and hdd, we
- * will try to see  if the device is floppy or cd, and list anything else
- * as hdd.
- */
-static bool
-efipart_hdd(EFI_DEVICE_PATH *dp)
+static pdinfo_t *
+efipart_find_parent(pdinfo_list_t *pdi, EFI_DEVICE_PATH *devpath)
 {
-	unsigned i;
-	EFI_DEVICE_PATH *devpath, *node;
-	EFI_BLOCK_IO *blkio;
-	EFI_STATUS status;
+	pdinfo_t *pd;
 
-	if (dp == NULL)
-		return (false);
-
-	if ((node = efi_devpath_last_node(dp)) == NULL)
-		return (false);
-
-	if (efipart_floppy(node) != NULL)
-		return (false);
-
-	/*
-	 * Test every EFI BLOCK IO handle to make sure dp is not device path
-	 * for CD/DVD.
-	 */
-	for (i = 0; i < efipart_nhandles; i++) {
-		devpath = efi_lookup_devpath(efipart_handles[i]);
-		if (devpath == NULL)
-			return (false);
-
-		/* Only continue testing when dp is prefix in devpath. */
-		if (!efi_devpath_is_prefix(dp, devpath))
-			continue;
-
-		/*
-		 * The device path has to have last node describing the
-		 *  device, or we can not test the type.
-		 */
-		if ((node = efi_devpath_last_node(devpath)) == NULL)
-			return (false);
-
-		if (DevicePathType(node) == MEDIA_DEVICE_PATH &&
-		    DevicePathSubType(node) == MEDIA_CDROM_DP) {
-			return (false);
-		}
-
-		/* Make sure we do have the media. */
-		status = BS->HandleProtocol(efipart_handles[i],
-		    &blkio_guid, (void **)&blkio);
-		if (EFI_ERROR(status))
-			return (false);
-
-		/* USB or SATA cd without the media. */
-		if (blkio->Media->RemovableMedia &&
-		    !blkio->Media->MediaPresent) {
-			return (false);
-		}
-
-		/*
-		 * We assume the block size 512 or greater power of 2. 
-		 * iPXE is known to insert stub BLOCK IO device with
-		 * BlockSize 1.
-		 */
-		if (blkio->Media->BlockSize < 512 ||
-		    !powerof2(blkio->Media->BlockSize)) {
-			return (false);
-		}
+	STAILQ_FOREACH(pd, pdi, pd_link) {
+		if (efi_devpath_is_prefix(pd->pd_devpath, devpath))
+			return (pd);
 	}
-	return (true);
+	return (NULL);
 }
 
-/*
- * Add or update entries with new handle data.
- */
 static int
-efipart_fdinfo_add(EFI_HANDLE handle, uint32_t uid, EFI_DEVICE_PATH *devpath)
+efipart_initfd(void)
 {
-	pdinfo_t *fd;
-
-	fd = calloc(1, sizeof(pdinfo_t));
-	if (fd == NULL) {
-		printf("Failed to register floppy %d, out of memory\n", uid);
-		return (ENOMEM);
-	}
-	STAILQ_INIT(&fd->pd_part);
-
-	fd->pd_unit = uid;
-	fd->pd_handle = handle;
-	fd->pd_devpath = devpath;
-	fd->pd_parent = NULL;
-	fd->pd_devsw = &efipart_fddev;
-	STAILQ_INSERT_TAIL(&fdinfo, fd, pd_link);
-	return (0);
-}
-
-static void
-efipart_updatefd(void)
-{
-	EFI_DEVICE_PATH *devpath, *node;
+	EFI_DEVICE_PATH *node;
 	ACPI_HID_DEVICE_PATH *acpi;
-	int i;
+	pdinfo_t *parent, *fd;
 
-	for (i = 0; i < efipart_nhandles; i++) {
-		devpath = efi_lookup_devpath(efipart_handles[i]);
-		if (devpath == NULL)
+restart:
+	STAILQ_FOREACH(fd, &pdinfo, pd_link) {
+		if ((node = efi_devpath_last_node(fd->pd_devpath)) == NULL)
 			continue;
 
-		if ((node = efi_devpath_last_node(devpath)) == NULL)
+		if ((acpi = efipart_floppy(node)) == NULL)
 			continue;
-		if ((acpi = efipart_floppy(node)) != NULL) {
-			efipart_fdinfo_add(efipart_handles[i], acpi->UID,
-			    devpath);
+
+		STAILQ_REMOVE(&pdinfo, fd, pdinfo, pd_link);
+		parent = efipart_find_parent(&pdinfo, fd->pd_devpath);
+		if (parent != NULL) {
+			STAILQ_REMOVE(&pdinfo, parent, pdinfo, pd_link);
+			parent->pd_alias = fd->pd_handle;
+			parent->pd_unit = acpi->UID;
+			free(fd);
+			fd = parent;
+		} else {
+			fd->pd_unit = acpi->UID;
 		}
+		fd->pd_devsw = &efipart_fddev;
+		STAILQ_INSERT_TAIL(&fdinfo, fd, pd_link);
+		goto restart;
 	}
-}
 
-static int
-efipart_initfd(void)
-{
-
-	STAILQ_INIT(&fdinfo);
-
-	efipart_updatefd();
-
 	bcache_add_dev(efiblk_pdinfo_count(&fdinfo));
 	return (0);
 }
@@ -392,68 +360,90 @@ efipart_initfd(void)
 /*
  * Add or update entries with new handle data.
  */
-static int
-efipart_cdinfo_add(EFI_HANDLE handle, EFI_HANDLE alias,
-    EFI_DEVICE_PATH *devpath)
+static void
+efipart_cdinfo_add(pdinfo_t *cd)
 {
-	int unit;
-	pdinfo_t *cd;
-	pdinfo_t *pd;
+	pdinfo_t *pd, *last;
 
-	unit = 0;
 	STAILQ_FOREACH(pd, &cdinfo, pd_link) {
-		if (efi_devpath_match(pd->pd_devpath, devpath) == true) {
-			pd->pd_handle = handle;
-			pd->pd_alias = alias;
-			return (0);
+		if (efi_devpath_is_prefix(pd->pd_devpath, cd->pd_devpath)) {
+			last = STAILQ_LAST(&pd->pd_part, pdinfo, pd_link);
+			if (last != NULL)
+				cd->pd_unit = last->pd_unit + 1;
+			else
+				cd->pd_unit = 0;
+			cd->pd_parent = pd;
+			cd->pd_devsw = &efipart_cddev;
+			STAILQ_INSERT_TAIL(&pd->pd_part, cd, pd_link);
+			return;
 		}
-		unit++;
 	}
 
-	cd = calloc(1, sizeof(pdinfo_t));
-	if (cd == NULL) {
-		printf("Failed to add cd %d, out of memory\n", unit);
-		return (ENOMEM);
-	}
-	STAILQ_INIT(&cd->pd_part);
+	last = STAILQ_LAST(&cdinfo, pdinfo, pd_link);
+	if (last != NULL)
+		cd->pd_unit = last->pd_unit + 1;
+	else
+		cd->pd_unit = 0;
 
-	cd->pd_handle = handle;
-	cd->pd_unit = unit;
-	cd->pd_alias = alias;
-	cd->pd_devpath = devpath;
 	cd->pd_parent = NULL;
 	cd->pd_devsw = &efipart_cddev;
 	STAILQ_INSERT_TAIL(&cdinfo, cd, pd_link);
-	return (0);
 }
 
+static bool
+efipart_testcd(EFI_DEVICE_PATH *node, EFI_BLOCK_IO *blkio)
+{
+	if (DevicePathType(node) == MEDIA_DEVICE_PATH &&
+	    DevicePathSubType(node) == MEDIA_CDROM_DP) {
+		return (true);
+	}
+
+	/* cd drive without the media. */
+	if (blkio->Media->RemovableMedia &&
+	    !blkio->Media->MediaPresent) {
+		return (true);
+	}
+
+	return (false);
+}
+
 static void
 efipart_updatecd(void)
 {
-	int i;
-	EFI_DEVICE_PATH *devpath, *devpathcpy, *tmpdevpath, *node;
-	EFI_HANDLE handle;
-	EFI_BLOCK_IO *blkio;
+	EFI_DEVICE_PATH *devpath, *node;
 	EFI_STATUS status;
+	pdinfo_t *parent, *cd;
 
-	for (i = 0; i < efipart_nhandles; i++) {
-		devpath = efi_lookup_devpath(efipart_handles[i]);
-		if (devpath == NULL)
+restart:
+	STAILQ_FOREACH(cd, &pdinfo, pd_link) {
+		if ((node = efi_devpath_last_node(cd->pd_devpath)) == NULL)
 			continue;
 
-		if ((node = efi_devpath_last_node(devpath)) == NULL)
-			continue;
-
 		if (efipart_floppy(node) != NULL)
 			continue;
 
-		if (efipart_hdd(devpath))
-			continue;
+		/* Is parent of this device already registered? */
+		parent = efipart_find_parent(&cdinfo, cd->pd_devpath);
+		if (parent != NULL) {
+			STAILQ_REMOVE(&pdinfo, cd, pdinfo, pd_link);
+			efipart_cdinfo_add(cd);
+			goto restart;
+		}
 
-		status = BS->HandleProtocol(efipart_handles[i],
-		    &blkio_guid, (void **)&blkio);
-		if (EFI_ERROR(status))
+		if (!efipart_testcd(node, cd->pd_blkio))
 			continue;
+
+		/* Find parent and unlink both parent and cd from pdinfo */
+		STAILQ_REMOVE(&pdinfo, cd, pdinfo, pd_link);
+		parent = efipart_find_parent(&pdinfo, cd->pd_devpath);
+		if (parent != NULL) {
+			STAILQ_REMOVE(&pdinfo, parent, pdinfo, pd_link);
+			efipart_cdinfo_add(parent);
+		}
+
+		if (parent == NULL)
+			parent = efipart_find_parent(&cdinfo, cd->pd_devpath);
+
 		/*
 		 * If we come across a logical partition of subtype CDROM
 		 * it doesn't refer to the CD filesystem itself, but rather
@@ -462,132 +452,79 @@ efipart_updatecd(void)
 		 * that will be the CD filesystem.
 		 */
 		if (DevicePathType(node) == MEDIA_DEVICE_PATH &&
-		    DevicePathSubType(node) == MEDIA_CDROM_DP) {
-			devpathcpy = efi_devpath_trim(devpath);
-			if (devpathcpy == NULL)
-				continue;
-			tmpdevpath = devpathcpy;
-			status = BS->LocateDevicePath(&blkio_guid, &tmpdevpath,
-			    &handle);
-			free(devpathcpy);
-			if (EFI_ERROR(status))
-				continue;
-			devpath = efi_lookup_devpath(handle);
-			efipart_cdinfo_add(handle, efipart_handles[i],
-			    devpath);
-			continue;
-		}
+		    DevicePathSubType(node) == MEDIA_CDROM_DP &&
+		    parent == NULL) {
+			parent = calloc(1, sizeof(*parent));
+			if (parent == NULL) {
+				printf("efipart_updatecd: out of memory\n");
+				/* this device is lost but try again. */
+				free(cd);
+				goto restart;
+			}
 
-		if (DevicePathType(node) == MESSAGING_DEVICE_PATH &&
-		    DevicePathSubType(node) == MSG_ATAPI_DP) {
-			efipart_cdinfo_add(efipart_handles[i], NULL,
-			    devpath);
-			continue;
+			devpath = efi_devpath_trim(cd->pd_devpath);
+			if (devpath == NULL) {
+				printf("efipart_updatecd: out of memory\n");
+				/* this device is lost but try again. */
+				free(parent);
+				free(cd);
+				goto restart;
+			}
+			parent->pd_devpath = devpath;
+			status = BS->LocateDevicePath(&blkio_guid,
+			    &parent->pd_devpath, &parent->pd_handle);
+			free(devpath);
+			if (EFI_ERROR(status)) {
+				printf("efipart_updatecd: error %lu\n",
+				    EFI_ERROR_CODE(status));
+				free(parent);
+				free(cd);
+				goto restart;
+			}
+			parent->pd_devpath =
+			    efi_lookup_devpath(parent->pd_handle);
+			efipart_cdinfo_add(parent);
 		}
 
-		/* USB or SATA cd without the media. */
-		if (blkio->Media->RemovableMedia &&
-		    !blkio->Media->MediaPresent) {
-			efipart_cdinfo_add(efipart_handles[i], NULL,
-			    devpath);
-		}
+		efipart_cdinfo_add(cd);
+		goto restart;
 	}
 }
 
 static int
 efipart_initcd(void)
 {
-
-	STAILQ_INIT(&cdinfo);
-
 	efipart_updatecd();
 
 	bcache_add_dev(efiblk_pdinfo_count(&cdinfo));
 	return (0);
 }
 
-static int
-efipart_hdinfo_add(EFI_HANDLE disk_handle, EFI_HANDLE part_handle)
+static void
+efipart_hdinfo_add(pdinfo_t *hd, HARDDRIVE_DEVICE_PATH *node)
 {
-	EFI_DEVICE_PATH *disk_devpath, *part_devpath;
-	HARDDRIVE_DEVICE_PATH *node;
-	int unit;
-	pdinfo_t *hd, *pd, *last;
+	pdinfo_t *pd, *last;
 
-	disk_devpath = efi_lookup_devpath(disk_handle);
-	if (disk_devpath == NULL)
-		return (ENOENT);
-
-	if (part_handle != NULL) {
-		part_devpath = efi_lookup_devpath(part_handle);
-		if (part_devpath == NULL)
-			return (ENOENT);
-		node = (HARDDRIVE_DEVICE_PATH *)
-		    efi_devpath_last_node(part_devpath);
-		if (node == NULL)
-			return (ENOENT);	/* This should not happen. */
-	} else {
-		part_devpath = NULL;
-		node = NULL;
-	}
-
-	pd = calloc(1, sizeof(pdinfo_t));
-	if (pd == NULL) {
-		printf("Failed to add disk, out of memory\n");
-		return (ENOMEM);
-	}
-	STAILQ_INIT(&pd->pd_part);
-
-	STAILQ_FOREACH(hd, &hdinfo, pd_link) {
-		if (efi_devpath_match(hd->pd_devpath, disk_devpath) == true) {
-			if (part_devpath == NULL)
-				return (0);
-
+	STAILQ_FOREACH(pd, &hdinfo, pd_link) {
+		if (efi_devpath_is_prefix(pd->pd_devpath, hd->pd_devpath)) {
 			/* Add the partition. */
-			pd->pd_handle = part_handle;
-			pd->pd_unit = node->PartitionNumber;
-			pd->pd_devpath = part_devpath;
-			pd->pd_parent = hd;
-			pd->pd_devsw = &efipart_hddev;
-			STAILQ_INSERT_TAIL(&hd->pd_part, pd, pd_link);
-			return (0);
+			hd->pd_unit = node->PartitionNumber;
+			hd->pd_parent = pd;
+			hd->pd_devsw = &efipart_hddev;
+			STAILQ_INSERT_TAIL(&pd->pd_part, hd, pd_link);
+			return;
 		}
 	}
 
 	last = STAILQ_LAST(&hdinfo, pdinfo, pd_link);
 	if (last != NULL)
-		unit = last->pd_unit + 1;
+		hd->pd_unit = last->pd_unit + 1;
 	else
-		unit = 0;
+		hd->pd_unit = 0;
 
 	/* Add the disk. */
-	hd = pd;
-	hd->pd_handle = disk_handle;
-	hd->pd_unit = unit;
-	hd->pd_devpath = disk_devpath;
-	hd->pd_parent = NULL;
 	hd->pd_devsw = &efipart_hddev;
 	STAILQ_INSERT_TAIL(&hdinfo, hd, pd_link);
-
-	if (part_devpath == NULL)
-		return (0);
-
-	pd = calloc(1, sizeof(pdinfo_t));
-	if (pd == NULL) {
-		printf("Failed to add partition, out of memory\n");
-		return (ENOMEM);
-	}
-	STAILQ_INIT(&pd->pd_part);
-
-	/* Add the partition. */
-	pd->pd_handle = part_handle;
-	pd->pd_unit = node->PartitionNumber;
-	pd->pd_devpath = part_devpath;
-	pd->pd_parent = hd;
-	pd->pd_devsw = &efipart_hddev;
-	STAILQ_INSERT_TAIL(&hd->pd_part, pd, pd_link);
-
-	return (0);
 }
 
 /*
@@ -596,40 +533,25 @@ efipart_hdinfo_add(EFI_HANDLE disk_handle, EFI_HANDLE 
  * of typeN:M, where type is interface type, N is disk id
  * and M is partition id.
  */
-static int
-efipart_hdinfo_add_filepath(EFI_HANDLE disk_handle)
+static void
+efipart_hdinfo_add_filepath(pdinfo_t *hd, FILEPATH_DEVICE_PATH *node)
 {
-	EFI_DEVICE_PATH *devpath;
-	FILEPATH_DEVICE_PATH *node;
 	char *pathname, *p;
-	int unit, len;
-	pdinfo_t *pd, *last;
+	int len;
+	pdinfo_t *last;
 
-	/* First collect and verify all the data */
-	if ((devpath = efi_lookup_devpath(disk_handle)) == NULL)
-		return (ENOENT);
-	node = (FILEPATH_DEVICE_PATH *)efi_devpath_last_node(devpath);
-	if (node == NULL)
-		return (ENOENT);	/* This should not happen. */
-
-	pd = calloc(1, sizeof(pdinfo_t));
-	if (pd == NULL) {
-		printf("Failed to add disk, out of memory\n");
-		return (ENOMEM);
-	}
-	STAILQ_INIT(&pd->pd_part);
 	last = STAILQ_LAST(&hdinfo, pdinfo, pd_link);
 	if (last != NULL)
-		unit = last->pd_unit + 1;
+		hd->pd_unit = last->pd_unit + 1;
 	else
-		unit = 0;
+		hd->pd_unit = 0;
 
 	/* FILEPATH_DEVICE_PATH has 0 terminated string */
 	len = ucs2len(node->PathName);
 	if ((pathname = malloc(len + 1)) == NULL) {
 		printf("Failed to add disk, out of memory\n");
-		free(pd);
-		return (ENOMEM);
+		free(hd);
+		return;
 	}
 	cpy16to8(node->PathName, pathname, len + 1);
 	p = strchr(pathname, ':');
@@ -640,23 +562,19 @@ efipart_hdinfo_add_filepath(EFI_HANDLE disk_handle)
 	 * false, this code would need update.
 	 */
 	if (p == NULL) {	/* no colon, add the disk */
-		pd->pd_handle = disk_handle;
-		pd->pd_unit = unit;
-		pd->pd_devpath = devpath;
-		pd->pd_parent = NULL;
-		pd->pd_devsw = &efipart_hddev;
-		STAILQ_INSERT_TAIL(&hdinfo, pd, pd_link);
+		hd->pd_devsw = &efipart_hddev;
+		STAILQ_INSERT_TAIL(&hdinfo, hd, pd_link);
 		free(pathname);
-		return (0);
+		return;
 	}
 	p++;	/* skip the colon */
 	errno = 0;
-	unit = (int)strtol(p, NULL, 0);
+	hd->pd_unit = (int)strtol(p, NULL, 0);
 	if (errno != 0) {
 		printf("Bad unit number for partition \"%s\"\n", pathname);
 		free(pathname);
-		free(pd);
-		return (EUNIT);
+		free(hd);
+		return;
 	}
 
 	/*
@@ -668,80 +586,99 @@ efipart_hdinfo_add_filepath(EFI_HANDLE disk_handle)
 	if (last == NULL) {
 		printf("BUG: No disk for partition \"%s\"\n", pathname);
 		free(pathname);
-		free(pd);
-		return (EINVAL);
+		free(hd);
+		return;
 	}
 	/* Add the partition. */
-	pd->pd_handle = disk_handle;
-	pd->pd_unit = unit;
-	pd->pd_devpath = devpath;
-	pd->pd_parent = last;
-	pd->pd_devsw = &efipart_hddev;
-	STAILQ_INSERT_TAIL(&last->pd_part, pd, pd_link);
+	hd->pd_parent = last;
+	hd->pd_devsw = &efipart_hddev;
+	STAILQ_INSERT_TAIL(&last->pd_part, hd, pd_link);
 	free(pathname);
-	return (0);
 }
 
 static void
 efipart_updatehd(void)
 {
-	int i;
-	EFI_DEVICE_PATH *devpath, *devpathcpy, *tmpdevpath, *node;
-	EFI_HANDLE handle;
-	EFI_BLOCK_IO *blkio;
+	EFI_DEVICE_PATH *devpath, *node;
 	EFI_STATUS status;
+	pdinfo_t *parent, *hd;
 
-	for (i = 0; i < efipart_nhandles; i++) {
-		devpath = efi_lookup_devpath(efipart_handles[i]);
-		if (devpath == NULL)
+restart:
+	STAILQ_FOREACH(hd, &pdinfo, pd_link) {
+		if ((node = efi_devpath_last_node(hd->pd_devpath)) == NULL)
 			continue;
 
-		if ((node = efi_devpath_last_node(devpath)) == NULL)
+		if (efipart_floppy(node) != NULL)
 			continue;
 
-		if (!efipart_hdd(devpath))
+		if (efipart_testcd(node, hd->pd_blkio))
 			continue;
 
-		status = BS->HandleProtocol(efipart_handles[i],
-		    &blkio_guid, (void **)&blkio);
-		if (EFI_ERROR(status))
-			continue;
+		if (DevicePathType(node) == HARDWARE_DEVICE_PATH &&
+		    (DevicePathSubType(node) == HW_PCI_DP ||
+		     DevicePathSubType(node) == HW_VENDOR_DP)) {
+			STAILQ_REMOVE(&pdinfo, hd, pdinfo, pd_link);
+			efipart_hdinfo_add(hd, NULL);
+			goto restart;
+		}
 
 		if (DevicePathType(node) == MEDIA_DEVICE_PATH &&
 		    DevicePathSubType(node) == MEDIA_FILEPATH_DP) {
-			efipart_hdinfo_add_filepath(efipart_handles[i]);
-			continue;
+			STAILQ_REMOVE(&pdinfo, hd, pdinfo, pd_link);
+			efipart_hdinfo_add_filepath(hd,
+			    (FILEPATH_DEVICE_PATH *)node);
+			goto restart;
 		}
 
+		STAILQ_REMOVE(&pdinfo, hd, pdinfo, pd_link);
+		parent = efipart_find_parent(&pdinfo, hd->pd_devpath);
+		if (parent != NULL) {
+			STAILQ_REMOVE(&pdinfo, parent, pdinfo, pd_link);
+			efipart_hdinfo_add(parent, NULL);
+		} else {
+			parent = efipart_find_parent(&hdinfo, hd->pd_devpath);
+		}
+
 		if (DevicePathType(node) == MEDIA_DEVICE_PATH &&
-		    DevicePathSubType(node) == MEDIA_HARDDRIVE_DP) {
-			devpathcpy = efi_devpath_trim(devpath);
-			if (devpathcpy == NULL)
-				continue;
-			tmpdevpath = devpathcpy;
-			status = BS->LocateDevicePath(&blkio_guid, &tmpdevpath,
-			    &handle);
-			free(devpathcpy);
-			if (EFI_ERROR(status))
-				continue;
-			/*
-			 * We do not support nested partitions.
-			 */
-			devpathcpy = efi_lookup_devpath(handle);
-			if (devpathcpy == NULL)
-				continue;
-			if ((node = efi_devpath_last_node(devpathcpy)) == NULL)
-				continue;
+		    DevicePathSubType(node) == MEDIA_HARDDRIVE_DP &&
+		    parent == NULL) {
+			parent = calloc(1, sizeof(*parent));
+			if (parent == NULL) {
+				printf("efipart_updatehd: out of memory\n");
+				/* this device is lost but try again. */
+				free(hd);
+				goto restart;
+			}
 
-			if (DevicePathType(node) == MEDIA_DEVICE_PATH &&
-			    DevicePathSubType(node) == MEDIA_HARDDRIVE_DP)
-				continue;
+			devpath = efi_devpath_trim(hd->pd_devpath);
+			if (devpath == NULL) {
+				printf("efipart_updatehd: out of memory\n");
+				/* this device is lost but try again. */
+				free(parent);
+				free(hd);
+				goto restart;
+			}
 
-			efipart_hdinfo_add(handle, efipart_handles[i]);
-			continue;
+			parent->pd_devpath = devpath;
+			status = BS->LocateDevicePath(&blkio_guid,
+			    &parent->pd_devpath, &parent->pd_handle);
+			free(devpath);
+			if (EFI_ERROR(status)) {
+				printf("efipart_updatehd: error %lu\n",
+				    EFI_ERROR_CODE(status));
+				free(parent);
+				free(hd);
+				goto restart;
+			}
+
+			parent->pd_devpath =
+			    efi_lookup_devpath(&parent->pd_handle);
+
+			efipart_hdinfo_add(parent, NULL);
 		}
 
-		efipart_hdinfo_add(efipart_handles[i], NULL);
+		efipart_hdinfo_add(hd, (HARDDRIVE_DEVICE_PATH *)node);
+		goto restart;
 	}
 }
 
@@ -749,8 +686,6 @@ static int
 efipart_inithd(void)
 {
 
-	STAILQ_INIT(&hdinfo);
-
 	efipart_updatehd();
 
 	bcache_add_dev(efiblk_pdinfo_count(&hdinfo));

*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***


More information about the svn-src-releng mailing list