[PATCH v2 3/3] blsuki: Add uki command to load Unified Kernel Image entries

2025-03-25 Thread Alec Brown via Grub-devel
A Unified Kernel Image is a single UEFI PE file that combines a UEFI boot stub,
a Linux kernel image, an initrd, and further resources. The uki command will
locate where the uki file is and create a GRUB menu entry to load it.

Signed-off-by: Alec Brown 
---
 docs/grub.texi  |  26 +++
 grub-core/commands/blsuki.c | 415 ++--
 include/grub/menu.h |   2 +
 3 files changed, 428 insertions(+), 15 deletions(-)

diff --git a/docs/grub.texi b/docs/grub.texi
index 19b0cc024..9317b4130 100644
--- a/docs/grub.texi
+++ b/docs/grub.texi
@@ -6491,6 +6491,7 @@ you forget a command, you can run the command 
@command{help}
 * tpm2_key_protector_clear::Clear the TPM2 key protector
 * true::Do nothing, successfully
 * trust::   Add public key to list of trusted keys
+* uki:: Load Unified Kernel Image menu entries
 * unset::   Unset an environment variable
 @comment * vbeinfo:: List available video modes
 * verify_detached:: Verify detached digital signature
@@ -8164,6 +8165,31 @@ Unset the environment variable @var{envvar}.
 @end deffn
 
 
+@node uki
+@subsection uki
+
+@deffn Command uki [@option{--path} dir] [@option{--show-default}] 
[@option{--show-non-default}] [@option{--entry} file]
+Load Unified Kernel Image entries into the GRUB menu.
+
+The @option{--path} option overrides the default path to the directory 
containing
+the UKI entries. If this option isn't used, the default location is
+/EFI/Linux in the EFI system partition.
+
+The @option{--show-default} option allows the default boot entry to be added 
to the
+GRUB menu from the UKI entries.
+
+The @option{--show-non-default} option allows non-default boot entries to be 
added to
+the GRUB menu from the UKI entries.
+
+The @option{--entry} option allows specific boot entries to be added to the 
GRUB menu
+from the UKI entries.
+
+The @option{--entry}, @option{--show-default}, and @option{--show-non-default} 
options
+are used to filter which UKI entries are added to the GRUB menu. If none are
+used, all entries in the default location or the location specified by 
@option{--path}
+will be added to the GRUB menu.
+@end deffn
+
 @ignore
 @node vbeinfo
 @subsection vbeinfo
diff --git a/grub-core/commands/blsuki.c b/grub-core/commands/blsuki.c
index 12a9a1ed1..bf284e002 100644
--- a/grub-core/commands/blsuki.c
+++ b/grub-core/commands/blsuki.c
@@ -39,9 +39,21 @@
 #define GRUB_BOOT_DEVICE ""
 #endif
 
+#ifdef GRUB_MACHINE_EFI
+#include 
+#include 
+#include 
+#endif
+
 GRUB_MOD_LICENSE ("GPLv3+");
 
 #define GRUB_BLS_CONFIG_PATH "/loader/entries/"
+#define GRUB_UKI_CONFIG_PATH "/EFI/Linux"
+
+#define GRUB_BLS_CMD 1
+#define GRUB_UKI_CMD 2
+
+static int cmd_type = 0;
 
 static const struct grub_arg_option bls_opt[] =
   {
@@ -52,6 +64,17 @@ static const struct grub_arg_option bls_opt[] =
 {0, 0, 0, 0, 0, 0}
   };
 
+#ifdef GRUB_MACHINE_EFI
+static const struct grub_arg_option uki_opt[] =
+  {
+{"path", 'p', 0, N_("Specify path to find UKI entries."), N_("DIR"), 
ARG_TYPE_PATHNAME},
+{"show-default", 'd', 0, N_("Allow the default UKI entry to be added to 
the GRUB menu."), 0, ARG_TYPE_NONE},
+{"show-non-default", 'n', 0, N_("Allow the non-default UKI entries to be 
added to the GRUB menu."), 0, ARG_TYPE_NONE},
+{"entry", 'e', 0, N_("Allow specificUKII entries to be added to the GRUB 
menu."), N_("FILE"), ARG_TYPE_FILE},
+{0, 0, 0, 0, 0, 0}
+  };
+#endif
+
 struct keyval
 {
   const char *key;
@@ -288,6 +311,206 @@ bls_read_entry (grub_file_t f, grub_blsuki_entry_t *entry)
   return err;
 }
 
+#ifdef GRUB_MACHINE_EFI
+static grub_err_t
+uki_read_entry (grub_file_t f, grub_blsuki_entry_t *entry)
+{
+  struct grub_msdos_image_header *dos = NULL;
+  struct grub_pe_image_header *pe = NULL;
+  grub_off_t section_offset = 0;
+  struct grub_pe32_section_table *section = NULL;
+  struct grub_pe32_coff_header *coff_header = NULL;
+  char *val = NULL;
+  char *key = NULL;
+  const char *target[] = {".cmdline", ".osrel", ".linux", NULL};
+  bool has_linux = false;
+  grub_err_t err = GRUB_ERR_NONE;
+
+  dos = grub_zalloc (sizeof (*dos));
+  if (dos == NULL)
+return grub_errno;
+  if (grub_file_read (f, dos, sizeof (*dos)) < (grub_ssize_t) sizeof (*dos))
+{
+  err = grub_error (GRUB_ERR_FILE_READ_ERROR, "failed to read UKI image 
header");
+  goto fail;
+}
+  if (dos->msdos_magic != GRUB_PE32_MAGIC)
+{
+  err = grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, N_("plain image kernel 
not supported"));
+  goto fail;
+}
+
+  grub_dprintf ("blsuki", "PE/COFF header @ %08x\n", 
dos->pe_image_header_offset);
+  pe = grub_zalloc (sizeof (*pe));
+  if (pe == NULL)
+{
+  err = grub_errno;
+  goto fail;
+}
+  if (grub_file_seek (f, dos->pe_image_header_offset) == (grub_off_t) -1
+  || grub_file_read (f, pe, sizeof (*pe)) != sizeof (*pe))
+{
+ 

Re: [PATCH v3 05/10] tss2: Add TPM 2.0 NV index commands

2025-03-25 Thread Daniel Kiper via Grub-devel
On Mon, Jan 13, 2025 at 11:07:08AM +0800, Gary Lin wrote:
> The following TPM 2.0 commands are introduced to tss2 to access the
> TPM non-volatile memory associated with the NV index handles.
>
> - TPM2_NV_DefineSpace
> - TPM2_NV_UndefineSpace
> - TPM2_NV_ReadPublic
> - TPM2_NV_Read
> - TPM2_NV_Write
>
> The related marshal/unmarshal functions are also introduced.
>
> Signed-off-by: Gary Lin 
> Reviewed-by: Stefan Berger 

Reviewed-by: Daniel Kiper  except one nit below...

> diff --git a/grub-core/lib/tss2/tss2_mu.c b/grub-core/lib/tss2/tss2_mu.c
> index 86134cc0a..816e5b37f 100644
> --- a/grub-core/lib/tss2/tss2_mu.c
> +++ b/grub-core/lib/tss2/tss2_mu.c
> @@ -17,6 +17,7 @@
>   *  along with GRUB.  If not, see .
>   */
>
> +#include 

I am not sure why you include grub/mm.h...

>  #include 
>
>  #include 

Daniel

___
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel


Re: [PATCH v4 05/12] tpm2_key_protector: Unseal key from a buffer

2025-03-25 Thread Daniel Kiper via Grub-devel
On Fri, Mar 21, 2025 at 03:59:01PM +0800, Gary Lin wrote:
> Extract the logic to handle the file buffer from the SRK recover
> function to prepare to load the sealed key from the NV index handle,
> so the NV index mode can share the same code path in the later patch.
> The SRK recover function now only reads the file and sends the file
> buffer to the new function.
>
> Besides this, to avoid introducing more options for the NV index mode,
> the file format is detected automatically before unmarshalling the data,
> so there is no need to use the command option to specify the file format
> anymore. In other words, '--tpm2key' and '--keyfile' are the same now.

You are referring to long options in the commit message but documentation
updates doing some stuff around short ones. I can understand they are
equivalent but I think you should be consistent and use short form
everywhere or both in the commit message.

Additionally, it seems to me the docs mention short or long options but
do not show there are some equivalents. Am I right? If yes I think this
should be fixed in separate patch.

Daniel

___
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel


[PATCH v2 1/3] blsuki: Add blscfg command to parse Boot Loader Specification snippets

2025-03-25 Thread Alec Brown via Grub-devel
The BootLoaderSpec (BLS) defines a scheme where different bootloaders can
share a format for boot items and a configuration directory that accepts
these common configurations as drop-in files.

Signed-off-by: Peter Jones 
Signed-off-by: Javier Martinez Canillas 
Signed-off-by: Will Thompson 
Signed-off-by: Alec Brown 
---
 Makefile.util.def  |   16 +
 docs/grub.texi |   27 +
 grub-core/Makefile.core.def|   10 +
 grub-core/commands/blsuki.c| 1028 
 grub-core/commands/legacycfg.c |4 +-
 grub-core/commands/menuentry.c |8 +-
 grub-core/lib/vercmp.c |  317 ++
 grub-core/normal/main.c|6 +
 include/grub/lib/vercmp.h  |   35 ++
 include/grub/menu.h|   15 +
 include/grub/normal.h  |2 +-
 tests/vercmp_unit_test.c   |   65 ++
 12 files changed, 1527 insertions(+), 6 deletions(-)
 create mode 100644 grub-core/commands/blsuki.c
 create mode 100644 grub-core/lib/vercmp.c
 create mode 100644 include/grub/lib/vercmp.h
 create mode 100644 tests/vercmp_unit_test.c

diff --git a/Makefile.util.def b/Makefile.util.def
index 038253b37..a911f2e0a 100644
--- a/Makefile.util.def
+++ b/Makefile.util.def
@@ -1373,6 +1373,22 @@ program = {
   ldadd = '$(LIBDEVMAPPER) $(LIBZFS) $(LIBNVPAIR) $(LIBGEOM)';
 };
 
+program = {
+  testcase = native;
+  name = vercmp_unit_test;
+  common = tests/vercmp_unit_test.c;
+  common = tests/lib/unit_test.c;
+  common = grub-core/kern/list.c;
+  common = grub-core/kern/misc.c;
+  common = grub-core/tests/lib/test.c;
+  common = grub-core/lib/vercmp.c;
+  ldadd = libgrubmods.a;
+  ldadd = libgrubgcry.a;
+  ldadd = libgrubkern.a;
+  ldadd = grub-core/lib/gnulib/libgnu.a;
+  ldadd = '$(LIBDEVMAPPER) $(LIBZFS) $(LIBNVPAIR) $(LIBGEOM)';
+};
+
 program = {
   name = grub-menulst2cfg;
   mansection = 1;
diff --git a/docs/grub.texi b/docs/grub.texi
index d9b26fa36..19b0cc024 100644
--- a/docs/grub.texi
+++ b/docs/grub.texi
@@ -6417,6 +6417,7 @@ you forget a command, you can run the command 
@command{help}
 * background_image::Load background image for active terminal
 * badram::  Filter out bad regions of RAM
 * blocklist::   Print a block list
+* blscfg::  Load Boot Loader Specification menu entries
 * boot::Start up your operating system
 * cat:: Show the contents of a file
 * clear::   Clear the screen
@@ -6603,6 +6604,32 @@ Print a block list (@pxref{Block list syntax}) for 
@var{file}.
 @end deffn
 
 
+@node blscfg
+@subsection blscfg
+
+@deffn Command blscfg [@option{--path} dir] [@option{--show-default}] 
[@option{--show-non-default}] [@option{--entry} file]
+Load Boot Loader Specification entries into the GRUB menu.
+
+The @option{--path} option overrides the default path to the directory 
containing
+the BLS entries. If this option isn't used, the default location is
+/loader/entries in @code{$BOOT}.
+
+The @option{--show-default} option allows the default boot entry to be added 
to the
+GRUB menu from the BLS entries.
+
+The @option{--show-non-default} option allows non-default boot entries to be 
added to
+the GRUB menu from the BLS entries.
+
+The @option{--entry} option allows specific boot entries to be added to the 
GRUB menu
+from the BLS entries.
+
+The @option{--entry}, @option{--show-default}, and @option{--show-non-default} 
options
+are used to filter which BLS entries are added to the GRUB menu. If none are
+used, all entries in the default location or the location specified by 
@option{--path}
+will be added to the GRUB menu.
+@end deffn
+
+
 @node boot
 @subsection boot
 
diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def
index f70e02e69..f3b776c0a 100644
--- a/grub-core/Makefile.core.def
+++ b/grub-core/Makefile.core.def
@@ -845,6 +845,16 @@ module = {
   common = commands/blocklist.c;
 };
 
+module = {
+  name = blsuki;
+  common = commands/blsuki.c;
+  common = lib/vercmp.c;
+  enable = powerpc_ieee1275;
+  enable = efi;
+  enable = i386_pc;
+  enable = emu;
+};
+
 module = {
   name = boot;
   common = commands/boot.c;
diff --git a/grub-core/commands/blsuki.c b/grub-core/commands/blsuki.c
new file mode 100644
index 0..0f77fb568
--- /dev/null
+++ b/grub-core/commands/blsuki.c
@@ -0,0 +1,1028 @@
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2025  Free Software Foundation, Inc.
+ *
+ *  GRUB is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  GRUB is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details

[PATCH v2 2/3] blsuki: Check for mounted /boot in emu

2025-03-25 Thread Alec Brown via Grub-devel
Irritatingly, BLS defines paths relatives to the mountpoint of the
filesystem which contains its snippets, not / or any other fixed
location. So grub2-emu needs to know whether /boot is a separate
filesystem from / and conditionally prepend a path.

Signed-off-by: Robbie Harwood 
Signed-off-by: Alec Brown 
---
 grub-core/Makefile.core.def |  4 +++
 grub-core/commands/blsuki.c | 54 -
 grub-core/osdep/linux/getroot.c |  8 +
 grub-core/osdep/unix/getroot.c  | 10 ++
 include/grub/emu/misc.h |  2 +-
 5 files changed, 70 insertions(+), 8 deletions(-)

diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def
index f3b776c0a..9a0e7bc55 100644
--- a/grub-core/Makefile.core.def
+++ b/grub-core/Makefile.core.def
@@ -367,6 +367,10 @@ kernel = {
   emu = kern/emu/cache_s.S;
   emu = kern/emu/hostdisk.c;
   emu = osdep/unix/hostdisk.c;
+  emu = osdep/relpath.c;
+  emu = osdep/getroot.c;
+  emu = osdep/unix/getroot.c;
+  emu = osdep/devmapper/getroot.c;
   emu = osdep/exec.c;
   extra_dist = osdep/unix/exec.c;
   emu = osdep/devmapper/hostdisk.c;
diff --git a/grub-core/commands/blsuki.c b/grub-core/commands/blsuki.c
index 0f77fb568..12a9a1ed1 100644
--- a/grub-core/commands/blsuki.c
+++ b/grub-core/commands/blsuki.c
@@ -32,6 +32,13 @@
 #include 
 #include 
 
+#ifdef GRUB_MACHINE_EMU
+#include 
+#define GRUB_BOOT_DEVICE "/boot"
+#else
+#define GRUB_BOOT_DEVICE ""
+#endif
+
 GRUB_MOD_LICENSE ("GPLv3+");
 
 #define GRUB_BLS_CONFIG_PATH "/loader/entries/"
@@ -53,8 +60,40 @@ struct keyval
 
 static grub_blsuki_entry_t *entries = NULL;
 
+/*
+ * Cache probing in blsuki_update_boot_device(). Used for linux entry also.
+ */
+static int separate_boot = -1;
+
 #define FOR_BLSUKI_ENTRIES(var) FOR_LIST_ELEMENTS (var, entries)
 
+/*
+ * BLS appears to make paths relative to the filesystem that snippets are
+ * on, not /.  Attempt to cope.
+ */
+static char *blsuki_update_boot_device (char *tmp)
+{
+#ifdef GRUB_MACHINE_EMU
+  char *ret;
+
+  if (separate_boot != -1)
+goto probed;
+
+  separate_boot = 0;
+
+  ret = grub_make_system_path_relative_to_its_root (GRUB_BOOT_DEVICE);
+
+  if (ret != NULL)
+separate_boot = 1;
+
+ probed:
+  if (!separate_boot)
+return grub_stpcpy (tmp, " ");
+#endif
+
+  return grub_stpcpy (tmp, " " GRUB_BOOT_DEVICE);
+}
+
 static grub_err_t
 blsuki_add_keyval (grub_blsuki_entry_t *entry, char *key, char *val)
 {
@@ -645,7 +684,7 @@ bls_create_entry (grub_blsuki_entry_t *entry)
 
   for (i = 0; early_initrds != NULL && early_initrds[i] != NULL; i++)
{
- if (grub_add (initrd_size, sizeof (" "), &initrd_size) ||
+ if (grub_add (initrd_size, sizeof (" " GRUB_BOOT_DEVICE), 
&initrd_size) ||
  grub_add (initrd_size, grub_strlen (initrd_prefix), &initrd_size) 
||
  grub_add (initrd_size, grub_strlen (early_initrds[i]), 
&initrd_size) ||
  grub_add (initrd_size, 1, &initrd_size))
@@ -657,7 +696,7 @@ bls_create_entry (grub_blsuki_entry_t *entry)
 
   for (i = 0; initrds != NULL && initrds[i] != NULL; i++)
{
- if (grub_add (initrd_size, sizeof (" "), &initrd_size) ||
+ if (grub_add (initrd_size, sizeof (" " GRUB_BOOT_DEVICE), 
&initrd_size) ||
  grub_add (initrd_size, grub_strlen (initrds[i]), &initrd_size) ||
  grub_add (initrd_size, 1, &initrd_size))
{
@@ -683,7 +722,7 @@ bls_create_entry (grub_blsuki_entry_t *entry)
   for (i = 0; early_initrds != NULL && early_initrds[i] != NULL; i++)
{
  grub_dprintf ("blsuki", "adding early initrd %s\n", early_initrds[i]);
- tmp = grub_stpcpy (tmp, " ");
+ tmp = blsuki_update_boot_device (tmp);
  tmp = grub_stpcpy (tmp, initrd_prefix);
  tmp = grub_stpcpy (tmp, early_initrds[i]);
  grub_free (early_initrds[i]);
@@ -692,7 +731,7 @@ bls_create_entry (grub_blsuki_entry_t *entry)
   for (i = 0; initrds != NULL && initrds[i] != NULL; i++)
{
  grub_dprintf ("blsuki", "adding initrd %s\n", initrds[i]);
- tmp = grub_stpcpy (tmp, " ");
+ tmp = blsuki_update_boot_device (tmp);
  tmp = grub_stpcpy (tmp, initrds[i]);
}
   tmp = grub_stpcpy (tmp, "\n");
@@ -711,7 +750,7 @@ bls_create_entry (grub_blsuki_entry_t *entry)
}
}
 
-  if (grub_add (sizeof ("devicetree "), grub_strlen (devicetree), 
&dt_size) ||
+  if (grub_add (sizeof ("devicetree " GRUB_BOOT_DEVICE), grub_strlen 
(devicetree), &dt_size) ||
  grub_add (dt_size, 1, &dt_size))
{
  grub_error (GRUB_ERR_OUT_OF_RANGE, "overflow detected calculating 
device tree buffer size");
@@ -735,7 +774,7 @@ bls_create_entry (grub_blsuki_entry_t *entry)
}
   tmp = dt;
   tmp = grub_stpcpy (dt, "devicetree");
-  tmp = grub_stpcpy (tmp, " ");
+  tmp = blsuki_update_boot_device (tmp);
   if (add_dt_prefix == true)
tmp = grub_stpcpy (tmp, prefix);
 

[PATCH v2 0/3] Add commands to load BLS and UKI files

2025-03-25 Thread Alec Brown via Grub-devel
v2: 
 - Improved function prefixes to indicate internal blsuki functions.
 - Added enums to indicate output from vercmp functions.
 - Separated bls and uki create_entry functions to improve readability.
 - Updated uki code to only store keyvals of necessary PE sections.
 - Fixed a bug where an extra '/' was added to the start of kernel and initrd
   paths.
 - Removed extra commands added to grub menu output for bls and uki.

This patch set is introducing BootLoaderSpec support to upstream GRUB from
Fedora GRUB. I've also added a uki command to load Unified Kernel Images since
it shares similar code to loading BLS config files.

Alec Brown

Alec Brown (1):
  blsuki: Add uki command to load Unified Kernel Image entries

Peter Jones (1):
  blsuki: Add blscfg command to parse Boot Loader Specification snippets

Robbie Harwood (1):
  blsuki: Check for mounted /boot in emu

 Makefile.util.def   |   16 +++
 docs/grub.texi  |   53 
 grub-core/Makefile.core.def |   14 ++
 grub-core/commands/blsuki.c | 1453 
+
 grub-core/commands/legacycfg.c  |4 +-
 grub-core/commands/menuentry.c  |8 +-
 grub-core/lib/vercmp.c  |  317 
+++
 grub-core/normal/main.c |6 +
 grub-core/osdep/linux/getroot.c |8 ++
 grub-core/osdep/unix/getroot.c  |   10 ++
 include/grub/emu/misc.h |2 +-
 include/grub/lib/vercmp.h   |   35 +
 include/grub/menu.h |   17 +++
 include/grub/normal.h   |2 +-
 tests/vercmp_unit_test.c|   65 +
 15 files changed, 2003 insertions(+), 7 deletions(-)



___
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel


[PATCH v4 12/12] INSTALL: Document the packages needed for TPM2 key protector tests

2025-03-25 Thread Gary Lin via Grub-devel
The TPM2 key protector tests require two external packages: swtpm-tools
and tpm2-tools. Add those two packages to the INSTALL file to inform
the user to install those packages before starting the TPM2 key protector
tests.

Signed-off-by: Gary Lin 
---
 INSTALL | 1 +
 1 file changed, 1 insertion(+)

diff --git a/INSTALL b/INSTALL
index 6b04e3016..724584c57 100644
--- a/INSTALL
+++ b/INSTALL
@@ -74,6 +74,7 @@ Prerequisites for make-check:
 * wamerican, for grub-fs-tester
 * mtools, FAT tools for EFI platforms
 * xfonts-unifont, for the functional tests
+* swtpm-tools and tpm2-tools, for TPM2 key protector tests
 
 * If running a Linux kernel the following modules must be loaded:
   - fuse, loop
-- 
2.43.0


___
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel


Re: [PATCH v2 2/3] blsuki: Check for mounted /boot in emu

2025-03-25 Thread Vladimir 'phcoder' Serbinenko
Le mar. 25 mars 2025, 10:15, Alec Brown  a écrit :

> Irritatingly, BLS defines paths relatives to the mountpoint of the
> filesystem which contains its snippets, not / or any other fixed
> location. So grub2-emu needs to know whether /boot is a separate
> filesystem from / and conditionally prepend a path.
>
> Signed-off-by: Robbie Harwood 
> Signed-off-by: Alec Brown 
> ---
>  grub-core/Makefile.core.def |  4 +++
>  grub-core/commands/blsuki.c | 54 -
>  grub-core/osdep/linux/getroot.c |  8 +
>  grub-core/osdep/unix/getroot.c  | 10 ++
>  include/grub/emu/misc.h |  2 +-
>  5 files changed, 70 insertions(+), 8 deletions(-)
>
> diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def
> index f3b776c0a..9a0e7bc55 100644
> --- a/grub-core/Makefile.core.def
> +++ b/grub-core/Makefile.core.def
> @@ -367,6 +367,10 @@ kernel = {
>emu = kern/emu/cache_s.S;
>emu = kern/emu/hostdisk.c;
>emu = osdep/unix/hostdisk.c;
> +  emu = osdep/relpath.c;
> +  emu = osdep/getroot.c;
> +  emu = osdep/unix/getroot.c;
> +  emu = osdep/devmapper/getroot.c;
>emu = osdep/exec.c;
>extra_dist = osdep/unix/exec.c;
>emu = osdep/devmapper/hostdisk.c;
> diff --git a/grub-core/commands/blsuki.c b/grub-core/commands/blsuki.c
> index 0f77fb568..12a9a1ed1 100644
> --- a/grub-core/commands/blsuki.c
> +++ b/grub-core/commands/blsuki.c
> @@ -32,6 +32,13 @@
>  #include 
>  #include 
>
> +#ifdef GRUB_MACHINE_EMU
> +#include 
> +#define GRUB_BOOT_DEVICE "/boot"
> +#else
> +#define GRUB_BOOT_DEVICE ""
> +#endif
> +
>  GRUB_MOD_LICENSE ("GPLv3+");
>
>  #define GRUB_BLS_CONFIG_PATH "/loader/entries/"
> @@ -53,8 +60,40 @@ struct keyval
>
>  static grub_blsuki_entry_t *entries = NULL;
>
> +/*
> + * Cache probing in blsuki_update_boot_device(). Used for linux entry
> also.
> + */
> +static int separate_boot = -1;
>

On non-emu it's an unused static. It might trigger a warning. I'd prefer
this to be inside ifdef.

+
>  #define FOR_BLSUKI_ENTRIES(var) FOR_LIST_ELEMENTS (var, entries)
>
> +/*
> + * BLS appears to make paths relative to the filesystem that snippets are
> + * on, not /.  Attempt to cope.
> + */
> +static char *blsuki_update_boot_device (char *tmp)
> +{
> +#ifdef GRUB_MACHINE_EMU
> +  char *ret;
> +
> +  if (separate_boot != -1)
> +goto probed;
> +
> +  separate_boot = 0;
> +
> +  ret = grub_make_system_path_relative_to_its_root (GRUB_BOOT_DEVICE);
> +
> +  if (ret != NULL)
> +separate_boot = 1;
>
Are you sure that != NULL is the right check? It looks like it should be
strcmp with "/". How do you get a NULL here? Shouldn't happen if the path
exists.

> +
> + probed:
> +  if (!separate_boot)
> +return grub_stpcpy (tmp, " ");
> +#endif
> +
> +  return grub_stpcpy (tmp, " " GRUB_BOOT_DEVICE);
> +}
> +
>  static grub_err_t
>  blsuki_add_keyval (grub_blsuki_entry_t *entry, char *key, char *val)
>  {
> @@ -645,7 +684,7 @@ bls_create_entry (grub_blsuki_entry_t *entry)
>
>for (i = 0; early_initrds != NULL && early_initrds[i] != NULL; i++)
> {
> - if (grub_add (initrd_size, sizeof (" "), &initrd_size) ||
> + if (grub_add (initrd_size, sizeof (" " GRUB_BOOT_DEVICE),
> &initrd_size) ||
>   grub_add (initrd_size, grub_strlen (initrd_prefix),
> &initrd_size) ||
>   grub_add (initrd_size, grub_strlen (early_initrds[i]),
> &initrd_size) ||
>   grub_add (initrd_size, 1, &initrd_size))
> @@ -657,7 +696,7 @@ bls_create_entry (grub_blsuki_entry_t *entry)
>
>for (i = 0; initrds != NULL && initrds[i] != NULL; i++)
> {
> - if (grub_add (initrd_size, sizeof (" "), &initrd_size) ||
> + if (grub_add (initrd_size, sizeof (" " GRUB_BOOT_DEVICE),
> &initrd_size) ||
>   grub_add (initrd_size, grub_strlen (initrds[i]),
> &initrd_size) ||
>   grub_add (initrd_size, 1, &initrd_size))
> {
> @@ -683,7 +722,7 @@ bls_create_entry (grub_blsuki_entry_t *entry)
>for (i = 0; early_initrds != NULL && early_initrds[i] != NULL; i++)
> {
>   grub_dprintf ("blsuki", "adding early initrd %s\n",
> early_initrds[i]);
> - tmp = grub_stpcpy (tmp, " ");
> + tmp = blsuki_update_boot_device (tmp);
>   tmp = grub_stpcpy (tmp, initrd_prefix);
>   tmp = grub_stpcpy (tmp, early_initrds[i]);
>   grub_free (early_initrds[i]);
> @@ -692,7 +731,7 @@ bls_create_entry (grub_blsuki_entry_t *entry)
>for (i = 0; initrds != NULL && initrds[i] != NULL; i++)
> {
>   grub_dprintf ("blsuki", "adding initrd %s\n", initrds[i]);
> - tmp = grub_stpcpy (tmp, " ");
> + tmp = blsuki_update_boot_device (tmp);
>   tmp = grub_stpcpy (tmp, initrds[i]);
> }
>tmp = grub_stpcpy (tmp, "\n");
> @@ -711,7 +750,7 @@ bls_create_entry (grub_blsuki_entry_t *entry)
> }
> }
>
> -  if (grub_add (sizeof ("devicetree "), grub_strlen (devicetree),
> &dt_si