Let me update the diff,

On Tue, 28 Feb 2017 22:41:21 +0900 (JST)
YASUOKA Masahiko <[email protected]> wrote:
> On Mon, 27 Feb 2017 11:10:31 +0100
> Patrick Wildt <[email protected]> wrote:
>> I'm surprised this didn't come up earlier, but I think the for-loop is a
>> bit wrong.  What the code is supposed to be doing is going over each
>> device path node for the loaded image, which is supposed to be the path
>> to the device that efiboot was loaded from, and check for a node that
>> is a medium (as in hard drive, cdrom) and look for a hard drive.
> 
> Yes, you are right it's wrong.
> 
>> As it turns out, the code would actually skip all device paths that
>> are mediums and instead match on all non-media types.  It's surprising
>> to me that this seems to work for people.
>> 
>> On Qemu and VMware the first node in the device path is ACPI (2) with
>> subtype (1).  Interestingly, the hard drive subtype in the media type
>> has the subtype (1) as well.  So that might be a reason it did work.
> 
> As far as my test on QEMU and VAIO, the first node is ACPI and subtype
> is 1.
> 
> But we had another bug,
> 
>      87         if (status == EFI_SUCCESS) {
>      88                 for (dp = dp0; !IsDevicePathEnd(dp);
>      89                     dp = NextDevicePathNode(dp)) {
>      90                         if (DevicePathType(dp) == MEDIA_DEVICE_PATH)
>      91                                 continue;
>      92                         if (DevicePathSubType(dp) == 
> MEDIA_HARDDRIVE_DP) {
>      93                                 bios_bootdev = 0x80;
>      94                                 efi_bootdp = dp;
>      95                                 break;
>      96                         }
>      97                         break;
>      98                 }
>      99         }
> 
> if we fix the bug at #90, at #94 efi_bootdp will not become the first
> dp node(dp0).  Then efi_diskprobe() will fail to reorder hd? properly
> since the function assumes efi_bootdp is the first dp node.
> 
> So I'd like to commit the diff below.
> 
> diff --git a/sys/arch/amd64/stand/efiboot/efiboot.c 
> b/sys/arch/amd64/stand/efiboot/efiboot.c

(snip)

> +                     if (efi_device_path_cmp(efi_bootdp, dp, 
> MESSAGING_DEVICE_PATH)
> +                         == 0)
>                               bootdev = 1;

Not only the messaging device path but hardware device path and acpi
device path also must be compared.

diff --git a/sys/arch/amd64/stand/efiboot/efiboot.c 
b/sys/arch/amd64/stand/efiboot/efiboot.c
index 1903862d271..2087a4112e3 100644
--- a/sys/arch/amd64/stand/efiboot/efiboot.c
+++ b/sys/arch/amd64/stand/efiboot/efiboot.c
@@ -41,7 +41,8 @@
 EFI_SYSTEM_TABLE       *ST;
 EFI_BOOT_SERVICES      *BS;
 EFI_RUNTIME_SERVICES   *RS;
-EFI_HANDLE              IH, efi_bootdp = NULL;
+EFI_HANDLE              IH;
+EFI_DEVICE_PATH                *efi_bootdp = NULL;
 EFI_PHYSICAL_ADDRESS    heap;
 EFI_LOADED_IMAGE       *loadedImage;
 UINTN                   heapsiz = 1 * 1024 * 1024;
@@ -51,6 +52,7 @@ static EFI_GUID                blkio_guid = BLOCK_IO_PROTOCOL;
 static EFI_GUID                 devp_guid = DEVICE_PATH_PROTOCOL;
 u_long                  efi_loadaddr;
 
+static int      efi_device_path_cmp(EFI_DEVICE_PATH *, EFI_DEVICE_PATH *, int);
 static void     efi_heap_init(void);
 static void     efi_memprobe_internal(void);
 static void     efi_video_init(void);
@@ -87,14 +89,12 @@ efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *systab)
        if (status == EFI_SUCCESS) {
                for (dp = dp0; !IsDevicePathEnd(dp);
                    dp = NextDevicePathNode(dp)) {
-                       if (DevicePathType(dp) == MEDIA_DEVICE_PATH)
-                               continue;
-                       if (DevicePathSubType(dp) == MEDIA_HARDDRIVE_DP) {
+                       if (DevicePathType(dp) == MEDIA_DEVICE_PATH &&
+                           DevicePathSubType(dp) == MEDIA_HARDDRIVE_DP) {
                                bios_bootdev = 0x80;
-                               efi_bootdp = dp;
+                               efi_bootdp = dp0;
                                break;
                        }
-                       break;
                }
        }
 
@@ -166,7 +166,7 @@ efi_diskprobe(void)
        EFI_BLOCK_IO            *blkio;
        EFI_BLOCK_IO_MEDIA      *media;
        struct diskinfo         *di;
-       EFI_DEVICE_PATH         *dp, *bp;
+       EFI_DEVICE_PATH         *dp;
 
        TAILQ_INIT(&efi_disklist);
 
@@ -193,23 +193,18 @@ efi_diskprobe(void)
                di = alloc(sizeof(struct diskinfo));
                efid_init(di, blkio);
 
-               if (efi_bootdp == NULL)
-                       goto next;
-               status = EFI_CALL(BS->HandleProtocol, handles[i], &devp_guid,
-                   (void **)&dp);
-               if (EFI_ERROR(status))
-                       goto next;
-               bp = efi_bootdp;
-               while (1) {
-                       if (IsDevicePathEnd(dp)) {
+               if (efi_bootdp != NULL) {
+                       status = EFI_CALL(BS->HandleProtocol, handles[i], 
&devp_guid,
+                           (void **)&dp);
+                       if (EFI_ERROR(status))
+                               goto next;
+                       if (efi_device_path_cmp(efi_bootdp, dp, 
HARDWARE_DEVICE_PATH)
+                           == 0 &&
+                           efi_device_path_cmp(efi_bootdp, dp, 
ACPI_DEVICE_PATH)
+                           == 0 &&
+                           efi_device_path_cmp(efi_bootdp, dp, 
MESSAGING_DEVICE_PATH)
+                           == 0)
                                bootdev = 1;
-                               break;
-                       }
-                       if (memcmp(dp, bp, sizeof(EFI_DEVICE_PATH)) != 0 ||
-                           memcmp(dp, bp, DevicePathNodeLength(dp)) != 0)
-                               break;
-                       dp = NextDevicePathNode(dp);
-                       bp = NextDevicePathNode(bp);
                }
 next:
                if (bootdev)
@@ -221,6 +216,35 @@ next:
        free(handles, sz);
 }
 
+static int
+efi_device_path_cmp(EFI_DEVICE_PATH *dpa, EFI_DEVICE_PATH *dpb, int dptype)
+{
+       int              cmp;
+       EFI_DEVICE_PATH *dp, *dpt_a = NULL, *dpt_b = NULL;
+
+       for (dp = dpa; !IsDevicePathEnd(dp); dp = NextDevicePathNode(dp)) {
+               if (DevicePathType(dp) == dptype) {
+                       dpt_a = dp;
+                       break;
+               }
+       }
+       for (dp = dpb; !IsDevicePathEnd(dp); dp = NextDevicePathNode(dp)) {
+               if (DevicePathType(dp) == dptype) {
+                       dpt_b = dp;
+                       break;
+               }
+       }
+
+       if (dpt_a && dpt_b) {
+               cmp = DevicePathNodeLength(dpt_a) - DevicePathNodeLength(dpt_b);
+               if (cmp)
+                       return (cmp);
+               return (memcmp(dpt_a, dpt_b, DevicePathNodeLength(dpt_a)));
+       }
+
+       return ((uintptr_t)dpt_a - (uintptr_t)dpt_b);
+}
+
 /***********************************************************************
  * Memory
  ***********************************************************************/

Reply via email to