]> git.ipfire.org Git - thirdparty/grub.git/commitdiff
kern/ieee1275/init: Use net config for boot location instead of firmware bootpath
authorMichael Chang <mchang@suse.com>
Mon, 13 Oct 2025 06:52:24 +0000 (14:52 +0800)
committerDaniel Kiper <daniel.kiper@oracle.com>
Fri, 24 Oct 2025 18:05:07 +0000 (20:05 +0200)
On network boots grub_ieee1275_net_config() is used to determine the
boot device but the path continues to be taken from the Open Firmware
/chosen/bootpath property. This assumes the device node follows the
generic IEEE 1275 syntax which is not always the case. Different drivers
may extend or redefine the format and GRUB may then misinterpret the
argument as a filename and set $prefix incorrectly.

The generic Open Firmware device path format is:

  device-name[:device-argument]
  device-argument := [partition][,[filename]]

For example, a bootpath such as:

  /vdevice/l-lan@30000002:speed=auto,duplex=auto,1.2.243.345,,9.8.76.543,1.2.34.5,5,5,255.255.255.0,512

does not follow this form. The section after the colon (the device-argument)
contains driver-specific options and network parameters, not a valid filename.
The GRUB interprets this string as a filename which results in $prefix being
set to "/", effectively losing the intended boot directory.

The firmware is not at fault here since interpretation of device nodes
is driver-specific. Instead, GRUB should use the filename provided in
the cached DHCP packet which is consistent and reliable. This is also
the same mechanism already used on UEFI and legacy BIOS platforms.

This patch updates grub_machine_get_bootlocation() to prefer the result
from grub_ieee1275_net_config() when complete and only fall back to the
firmware bootpath otherwise.

Signed-off-by: Michael Chang <mchang@suse.com>
Reviewed-by: Avnish Chouhan <avnish@linux.ibm.com>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
grub-core/kern/ieee1275/init.c

index 0ef888058c1ff7d99a60d77669c21ad7c7c59e05..7cdcd750f0373832c38357b17cb7b1eeb34aeaf7 100644 (file)
@@ -162,6 +162,8 @@ grub_machine_get_bootlocation (char **device, char **path)
   char *bootpath;
   char *filename;
   char *type;
+  char *ret_device = NULL;
+  char *ret_path = NULL;
 
   bootpath = grub_ieee1275_get_boot_dev ();
   if (! bootpath)
@@ -177,7 +179,7 @@ grub_machine_get_bootlocation (char **device, char **path)
       dev = grub_ieee1275_get_aliasdevname (bootpath);
       canon = grub_ieee1275_canonicalise_devname (dev);
       if (! canon)
-        return;
+       goto done;
       ptr = canon + grub_strlen (canon) - 1;
       while (ptr > canon && (*ptr == ',' || *ptr == ':'))
        ptr--;
@@ -185,13 +187,17 @@ grub_machine_get_bootlocation (char **device, char **path)
       *ptr = 0;
 
       if (grub_ieee1275_net_config)
-       grub_ieee1275_net_config (canon, device, path, bootpath);
+       grub_ieee1275_net_config (canon, &ret_device, &ret_path, bootpath);
       grub_free (dev);
       grub_free (canon);
+
+      /* Use path from net config if it is provided by cached DHCP info */
+      if (ret_path != NULL)
+       goto done;
+      /* Fall through to use firmware bootpath */
     }
   else
-    *device = grub_ieee1275_encode_devname (bootpath);
-  grub_free (type);
+    ret_device = grub_ieee1275_encode_devname (bootpath);
 
   filename = grub_ieee1275_get_filename (bootpath);
   if (filename)
@@ -204,10 +210,18 @@ grub_machine_get_bootlocation (char **device, char **path)
          *lastslash = '\0';
          grub_translate_ieee1275_path (filename);
 
-         *path = filename;
+         ret_path = filename;
        }
     }
+
+ done:
+  grub_free (type);
   grub_free (bootpath);
+
+  if (device != NULL)
+    *device = ret_device;
+  if (path != NULL)
+    *path = ret_path;
 }
 
 /* Claim some available memory in the first /memory node. */