From owner-svn-src-releng@freebsd.org Tue Oct 15 06:19:34 2019 Return-Path: Delivered-To: svn-src-releng@mailman.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mailman.nyi.freebsd.org (Postfix) with ESMTP id 97C9D1549CC; Tue, 15 Oct 2019 06:19:34 +0000 (UTC) (envelope-from tsoome@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) server-signature RSA-PSS (4096 bits) client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "Let's Encrypt Authority X3" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id 46sldL4Bs2z3Fr8; Tue, 15 Oct 2019 06:19:34 +0000 (UTC) (envelope-from tsoome@FreeBSD.org) Received: from repo.freebsd.org (repo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mxrelay.nyi.freebsd.org (Postfix) with ESMTPS id 746061A646; Tue, 15 Oct 2019 06:19:34 +0000 (UTC) (envelope-from tsoome@FreeBSD.org) Received: from repo.freebsd.org ([127.0.1.37]) by repo.freebsd.org (8.15.2/8.15.2) with ESMTP id x9F6JYwG016025; Tue, 15 Oct 2019 06:19:34 GMT (envelope-from tsoome@FreeBSD.org) Received: (from tsoome@localhost) by repo.freebsd.org (8.15.2/8.15.2/Submit) id x9F6JXLi016019; Tue, 15 Oct 2019 06:19:33 GMT (envelope-from tsoome@FreeBSD.org) Message-Id: <201910150619.x9F6JXLi016019@repo.freebsd.org> X-Authentication-Warning: repo.freebsd.org: tsoome set sender to tsoome@FreeBSD.org using -f From: Toomas Soome Date: Tue, 15 Oct 2019 06:19:33 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-releng@freebsd.org Subject: svn commit: r353543 - in releng/12.1/stand: efi/boot1 efi/include efi/libefi efi/loader efi/loader/arch/i386 libsa X-SVN-Group: releng X-SVN-Commit-Author: tsoome X-SVN-Commit-Paths: in releng/12.1/stand: efi/boot1 efi/include efi/libefi efi/loader efi/loader/arch/i386 libsa X-SVN-Commit-Revision: 353543 X-SVN-Commit-Repository: base MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-releng@freebsd.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: SVN commit messages for the release engineering / security commits to the src tree List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 15 Oct 2019 06:19:34 -0000 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 ***