From a2d218b17e33e56829b9a23f73dded07ae5839a8 Mon Sep 17 00:00:00 2001
From: Javier Martinez Canillas <javierm@redhat.com>
Date: Sun, 15 Sep 2019 09:37:45 +0200
Subject: [PATCH 177/220] blscfg: Add support for the devicetree field

The BootLoaderSpec mentions that a devicetree field can be used to pass a
Device Tree (DT) to the kernel, for the platforms that use it to describe
information about the hardware.

Allow the blscfg module to parse this field and call the grub2 devicetree
command in that case. If there is a devicetree grub2 environment variable
defined, this will be used if the field is not defined in the BLS snippet.

Resolves: rhbz#1751307

Signed-off-by: Javier Martinez Canillas <javierm@redhat.com>
---
 grub-core/commands/blscfg.c | 60 ++++++++++++++++++++++++++++++++++++++++++---
 1 file changed, 57 insertions(+), 3 deletions(-)

diff --git a/grub-core/commands/blscfg.c b/grub-core/commands/blscfg.c
index 54458b1..1ec8987 100644
--- a/grub-core/commands/blscfg.c
+++ b/grub-core/commands/blscfg.c
@@ -698,6 +698,8 @@ static void create_entry (struct bls_entry *entry)
   const char *early_initrd = NULL;
   char **early_initrds = NULL;
   char *initrd_prefix = NULL;
+  char *devicetree = NULL;
+  char *dt = NULL;
   char *id = entry->filename;
   char *dotconf = id;
   char *hotkey = NULL;
@@ -709,6 +711,7 @@ static void create_entry (struct bls_entry *entry)
 
   char *src = NULL;
   int i, index;
+  bool add_dt_prefix = false;
 
   grub_dprintf("blscfg", "%s got here\n", __func__);
   clinux = bls_get_val (entry, "linux", NULL);
@@ -736,6 +739,14 @@ static void create_entry (struct bls_entry *entry)
 
   initrds = bls_make_list (entry, "initrd", NULL);
 
+  devicetree = expand_val (bls_get_val (entry, "devicetree", NULL));
+
+  if (!devicetree)
+    {
+      devicetree = expand_val (grub_env_get("devicetree"));
+      add_dt_prefix = true;
+    }
+
   hotkey = bls_get_val (entry, "grub_hotkey", NULL);
   users = expand_val (bls_get_val (entry, "grub_users", NULL));
   classes = bls_make_list (entry, "grub_class", NULL);
@@ -801,7 +812,6 @@ static void create_entry (struct bls_entry *entry)
 	  goto finish;
 	}
 
-
       tmp = grub_stpcpy(initrd, "initrd");
       for (i = 0; early_initrds != NULL && early_initrds[i] != NULL; i++)
 	{
@@ -821,21 +831,65 @@ static void create_entry (struct bls_entry *entry)
       tmp = grub_stpcpy (tmp, "\n");
     }
 
+  if (devicetree)
+    {
+      char *prefix = NULL;
+      int dt_size;
+
+      if (add_dt_prefix)
+	{
+	  prefix = grub_strrchr (clinux, '/');
+	  prefix = grub_strndup(clinux, prefix - clinux + 1);
+	  if (!prefix)
+	    {
+	      grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("out of memory"));
+	      goto finish;
+	    }
+	}
+
+      dt_size = sizeof("devicetree " GRUB_BOOT_DEVICE) + grub_strlen(devicetree) + 1;
+
+      if (add_dt_prefix)
+	{
+	  dt_size += grub_strlen(prefix);
+	}
+
+      dt = grub_malloc (dt_size);
+      if (!dt)
+        {
+          grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("out of memory"));
+        goto finish;
+        }
+      char *tmp = dt;
+      tmp = grub_stpcpy (dt, "devicetree");
+      tmp = grub_stpcpy (tmp, " " GRUB_BOOT_DEVICE);
+      if (add_dt_prefix)
+        tmp = grub_stpcpy (tmp, prefix);
+      tmp = grub_stpcpy (tmp, devicetree);
+      tmp = grub_stpcpy (tmp, "\n");
+
+      grub_free(prefix);
+    }
+
+  grub_dprintf ("blscfg2", "devicetree %s for id:\"%s\"\n", dt, id);
+
   src = grub_xasprintf ("load_video\n"
 			"set gfxpayload=keep\n"
 			"insmod gzio\n"
 			"linux %s%s%s%s\n"
-			"%s",
+			"%s%s",
 			GRUB_BOOT_DEVICE, clinux, options ? " " : "", options ? options : "",
-			initrd ? initrd : "");
+			initrd ? initrd : "", dt ? dt : "");
 
   grub_normal_add_menu_entry (argc, argv, classes, id, users, hotkey, NULL, src, 0, &index, entry);
   grub_dprintf ("blscfg", "Added entry %d id:\"%s\"\n", index, id);
 
 finish:
+  grub_free (dt);
   grub_free (initrd);
   grub_free (initrd_prefix);
   grub_free (early_initrds);
+  grub_free (devicetree);
   grub_free (initrds);
   grub_free (options);
   grub_free (classes);
-- 
1.8.3.1

