Index: sys/boot/efi/boot1/boot1.c =================================================================== --- sys/boot/efi/boot1/boot1.c +++ sys/boot/efi/boot1/boot1.c @@ -51,7 +51,10 @@ EFI_STATUS efi_main(EFI_HANDLE Ximage, EFI_SYSTEM_TABLE* Xsystab); static void try_load(const boot_module_t* mod); -static EFI_STATUS probe_handle(EFI_HANDLE h); +static void probe_handle_status(EFI_HANDLE h, EFI_DEVICE_PATH *imgpath, + BOOLEAN match); +static EFI_STATUS probe_handle(EFI_HANDLE h, EFI_DEVICE_PATH *imgpath, + BOOLEAN match); EFI_SYSTEM_TABLE *systab; EFI_BOOT_SERVICES *bs; @@ -168,10 +171,42 @@ } } +static BOOLEAN +paths_match(EFI_DEVICE_PATH *imgpath, EFI_DEVICE_PATH *devpath) +{ + int len; + + if (imgpath == NULL || imgpath->Type != devpath->Type || + imgpath->SubType != devpath->SubType) + return (FALSE); + + len = DevicePathNodeLength(imgpath); + + if (len != DevicePathNodeLength(devpath)) + return (FALSE); + + return (memcmp(imgpath, devpath, (size_t)len) == 0); +} + +static EFI_DEVICE_PATH * +messaging_path(EFI_DEVICE_PATH *devpath) +{ + while (!IsDevicePathMessaging(devpath) && + !IsDevicePathEnd(NextDevicePathNode(devpath))) + devpath = NextDevicePathNode(devpath); + + if (!IsDevicePathMessaging(devpath)) + return (NULL); + + return (devpath); +} + EFI_STATUS efi_main(EFI_HANDLE Ximage, EFI_SYSTEM_TABLE *Xsystab) { EFI_HANDLE *handles; + EFI_LOADED_IMAGE *img; + EFI_DEVICE_PATH *imgpath; EFI_STATUS status; EFI_CONSOLE_CONTROL_PROTOCOL *ConsoleControl = NULL; SIMPLE_TEXT_OUTPUT_INTERFACE *conout = NULL; @@ -254,20 +289,29 @@ /* Scan all partitions, probing with all modules. */ nhandles = hsize / sizeof(*handles); printf(" Probing %zu block devices...", nhandles); - for (i = 0; i < nhandles; i++) { - status = probe_handle(handles[i]); - switch (status) { - case EFI_UNSUPPORTED: - printf("."); - break; - case EFI_SUCCESS: - printf("+"); - break; - default: - printf("x"); - break; + + /* + * We start by probing handles which match our images media path, so if + * possible we boot from a partition on our device. + */ + status = bs->HandleProtocol(image, &LoadedImageGUID, (VOID**)&img); + imgpath = NULL; + if (status == EFI_SUCCESS) { + status = bs->HandleProtocol(img->DeviceHandle, &DevicePathGUID, + (void **)&imgpath); + if (status == EFI_SUCCESS) { + imgpath = messaging_path(imgpath); + if (imgpath != NULL) { + for (i = 0; i < nhandles; i++) + probe_handle_status(handles[i], imgpath, + TRUE); + } } } + + /* Now check for other bootable partitions. */ + for (i = 0; i < nhandles; i++) + probe_handle_status(handles[i], imgpath, FALSE); printf(" done\n"); /* Status summary. */ @@ -287,13 +331,34 @@ panic("No bootable partitions found!"); } +static void +probe_handle_status(EFI_HANDLE h, EFI_DEVICE_PATH *imgpath, BOOLEAN match) +{ + + switch (probe_handle(h, imgpath, match)) { + case EFI_UNSUPPORTED: + printf("."); + break; + case EFI_SUCCESS: + printf("%c", match ? '*' : '+'); + break; + case EFI_NOT_FOUND: + /* Didn't match or already tested. */ + break; + default: + printf("x"); + break; + } +} + static EFI_STATUS -probe_handle(EFI_HANDLE h) +probe_handle(EFI_HANDLE h, EFI_DEVICE_PATH *imgpath, BOOLEAN match) { dev_info_t *devinfo; EFI_BLOCK_IO *blkio; EFI_DEVICE_PATH *devpath; EFI_STATUS status; + BOOLEAN matched; UINTN i; /* Figure out if we're dealing with an actual partition. */ @@ -307,8 +372,34 @@ return (status); } - while (!IsDevicePathEnd(NextDevicePathNode(devpath))) + matched = FALSE; + while (!IsDevicePathEnd(NextDevicePathNode(devpath))) { + if (IsDevicePathMessaging(devpath) && !matched) { + if (match) { + if (!paths_match(imgpath, devpath)) + return (EFI_NOT_FOUND); + matched = TRUE; + } else if (paths_match(imgpath, devpath)) { + /* Already tested. */ + return (EFI_NOT_FOUND); + } + } devpath = NextDevicePathNode(devpath); + } + + if (IsDevicePathMessaging(devpath)) { + if (match) { + if (!paths_match(imgpath, devpath)) + return (EFI_NOT_FOUND); + matched = TRUE; + } else if (paths_match(imgpath, devpath)) { + /* Already tested. */ + return (EFI_NOT_FOUND); + } + } + + if (match && !matched) + return (EFI_NOT_FOUND); status = bs->HandleProtocol(h, &BlockIoProtocolGUID, (void **)&blkio); if (status == EFI_UNSUPPORTED) Index: sys/boot/efi/boot1/ufs_module.c =================================================================== --- sys/boot/efi/boot1/ufs_module.c +++ sys/boot/efi/boot1/ufs_module.c @@ -93,7 +93,7 @@ } static EFI_STATUS -try_load(dev_info_t *dev, const char *loader_path, void **bufp, size_t *bufsize) +try_load(dev_info_t *dev, const char *filepath, void **bufp, size_t *bufsize) { ufs_ino_t ino; EFI_STATUS status; @@ -101,28 +101,36 @@ ssize_t read; void *buf; - if (init_dev(dev) < 0) + DPRINTF("try_load: '%s' MediaId: %d, devpath: %d.%d\n", filepath, + dev->dev->Media->MediaId, dev->devpath->Type, + dev->devpath->SubType); + + if (init_dev(dev) < 0) { + DPRINTF("Failed to device %p\n", dev); return (EFI_UNSUPPORTED); + } - if ((ino = lookup(loader_path)) == 0) + if ((ino = lookup(filepath)) == 0) { + DPRINTF("Failed to lookup '%s' on %p\n", filepath, dev); return (EFI_NOT_FOUND); + } if (fsread_size(ino, NULL, 0, &size) < 0 || size <= 0) { - printf("Failed to read size of '%s' ino: %d\n", loader_path, + printf("Failed to read size of '%s' ino: %d\n", filepath, ino); return (EFI_INVALID_PARAMETER); } if ((status = bs->AllocatePool(EfiLoaderData, size, &buf)) != EFI_SUCCESS) { - printf("Failed to allocate read buffer (%lu)\n", - EFI_ERROR_CODE(status)); + printf("Failed to allocate read buffer %zu for '%s' (%lu)\n", + size, filepath, EFI_ERROR_CODE(status)); return (status); } read = fsread(ino, buf, size); if ((size_t)read != size) { - printf("Failed to read '%s' (%zd != %zu)\n", loader_path, read, + printf("Failed to read '%s' (%zd != %zu)\n", filepath, read, size); (void)bs->FreePool(buf); return (EFI_INVALID_PARAMETER); @@ -135,19 +143,16 @@ } static EFI_STATUS -load(const char *loader_path, dev_info_t **devinfop, void **buf, +load(const char *filepath, dev_info_t **devinfop, void **buf, size_t *bufsize) { dev_info_t *dev; - EFI_STATUS status; for (dev = devices; dev != NULL; dev = dev->next) { - status = try_load(dev, loader_path, buf, bufsize); - if (status == EFI_SUCCESS) { + if (try_load(dev, filepath, buf, bufsize) == + EFI_SUCCESS) { *devinfop = dev; return (EFI_SUCCESS); - } else if (status != EFI_NOT_FOUND) { - return (status); } } Index: sys/boot/efi/boot1/zfs_module.c =================================================================== --- sys/boot/efi/boot1/zfs_module.c +++ sys/boot/efi/boot1/zfs_module.c @@ -91,7 +91,8 @@ } static EFI_STATUS -try_load(dev_info_t *devinfo, const char *loader_path, void **bufp, size_t *bufsize) +try_load(dev_info_t *devinfo, const char *filepath, void **bufp, + size_t *bufsize) { spa_t *spa; struct zfsmount zfsmount; @@ -102,32 +103,42 @@ EFI_STATUS status; spa = devinfo->devdata; - if (zfs_spa_init(spa) != 0) { - /* Init failed, don't report this loudly. */ + + DPRINTF("try_load: '%s' spa: '%s', MediaId: %d, devpath: %d.%d\n", + filepath, spa->spa_name, devinfo->dev->Media->MediaId, + devinfo->devpath->Type, devinfo->devpath->SubType); + + if ((err = zfs_spa_init(spa)) != 0) { + DPRINTF("Failed to load pool '%s' (%d)\n", spa->spa_name, err); return (EFI_NOT_FOUND); } - if (zfs_mount(spa, 0, &zfsmount) != 0) { - /* Mount failed, don't report this loudly. */ + if ((err = zfs_mount(spa, 0, &zfsmount)) != 0) { + DPRINTF("Failed to mount pool '%s' (%d)\n", spa->spa_name, err); return (EFI_NOT_FOUND); } - if ((err = zfs_lookup(&zfsmount, loader_path, &dn)) != 0) { - printf("Failed to lookup %s on pool %s (%d)\n", loader_path, + if ((err = zfs_lookup(&zfsmount, filepath, &dn)) != 0) { + if (err == ENOENT) { + DPRINTF("Failed to find '%s' on pool '%s' (%d)\n", + filepath, spa->spa_name, err); + return (EFI_NOT_FOUND); + } + printf("Failed to lookup '%s' on pool '%s' (%d)\n", filepath, spa->spa_name, err); return (EFI_INVALID_PARAMETER); } if ((err = zfs_dnode_stat(spa, &dn, &st)) != 0) { - printf("Failed to lookup %s on pool %s (%d)\n", loader_path, + printf("Failed to stat '%s' on pool '%s' (%d)\n", filepath, spa->spa_name, err); return (EFI_INVALID_PARAMETER); } if ((status = bs->AllocatePool(EfiLoaderData, (UINTN)st.st_size, &buf)) != EFI_SUCCESS) { - printf("Failed to allocate load buffer for pool %s (%lu)\n", - spa->spa_name, EFI_ERROR_CODE(status)); + printf("Failed to allocate load buffer %zu for pool '%s' for '%s' " + "(%lu)\n", st.st_size, spa->spa_name, filepath, EFI_ERROR_CODE(status)); return (EFI_INVALID_PARAMETER); } @@ -145,19 +156,16 @@ } static EFI_STATUS -load(const char *loader_path, dev_info_t **devinfop, void **bufp, +load(const char *filepath, dev_info_t **devinfop, void **bufp, size_t *bufsize) { dev_info_t *devinfo; - EFI_STATUS status; for (devinfo = devices; devinfo != NULL; devinfo = devinfo->next) { - status = try_load(devinfo, loader_path, bufp, bufsize); - if (status == EFI_SUCCESS) { + if (try_load(devinfo, filepath, bufp, bufsize) == + EFI_SUCCESS) { *devinfop = devinfo; return (EFI_SUCCESS); - } else if (status != EFI_NOT_FOUND) { - return (status); } } Index: sys/boot/efi/include/efidevp.h =================================================================== --- sys/boot/efi/include/efidevp.h +++ sys/boot/efi/include/efidevp.h @@ -40,9 +40,7 @@ #define EFI_DP_TYPE_MASK 0x7F #define EFI_DP_TYPE_UNPACKED 0x80 -//#define END_DEVICE_PATH_TYPE 0xff #define END_DEVICE_PATH_TYPE 0x7f -//#define END_DEVICE_PATH_TYPE_UNPACKED 0x7f #define END_ENTIRE_DEVICE_PATH_SUBTYPE 0xff #define END_INSTANCE_DEVICE_PATH_SUBTYPE 0x01 @@ -56,8 +54,9 @@ #define DevicePathSubType(a) ( (a)->SubType ) #define DevicePathNodeLength(a) ( ((a)->Length[0]) | ((a)->Length[1] << 8) ) #define NextDevicePathNode(a) ( (EFI_DEVICE_PATH *) ( ((UINT8 *) (a)) + DevicePathNodeLength(a))) -//#define IsDevicePathEndType(a) ( DevicePathType(a) == END_DEVICE_PATH_TYPE_UNPACKED ) -#define IsDevicePathEndType(a) ( DevicePathType(a) == END_DEVICE_PATH_TYPE ) +#define IsDevicePathType(a, t) ( DevicePathType(a) == t ) +#define IsDevicePathEndType(a) IsDevicePathType(a, END_DEVICE_PATH_TYPE) +#define IsDevicePathMessaging(a) IsDevicePathType(a, MESSAGING_DEVICE_PATH) #define IsDevicePathEndSubType(a) ( (a)->SubType == END_ENTIRE_DEVICE_PATH_SUBTYPE ) #define IsDevicePathEnd(a) ( IsDevicePathEndType(a) && IsDevicePathEndSubType(a) ) #define IsDevicePathUnpacked(a) ( (a)->Type & EFI_DP_TYPE_UNPACKED )