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 <alec.r.br...@oracle.com>
---
docs/grub.texi | 26 ++
grub-core/commands/blsuki.c | 712 +++++++++++++++++++++++++++---------
include/grub/menu.h | 2 +
3 files changed, 562 insertions(+), 178 deletions(-)
diff --git a/docs/grub.texi b/docs/grub.texi
index a8465fc0b..ecf261717 100644
--- a/docs/grub.texi
+++ b/docs/grub.texi
@@ -4403,6 +4403,7 @@ you forget a command, you can run the command
@command{help}
* test:: Check file types and compare values
* 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
@@ -5904,6 +5905,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 8a3c5818f..3c26f2a56 100644
--- a/grub-core/commands/blsuki.c
+++ b/grub-core/commands/blsuki.c
@@ -39,11 +39,23 @@
#define GRUB_BOOT_DEVICE "/"
#endif
+#ifdef GRUB_MACHINE_EFI
+#include <grub/efi/efi.h>
+#include <grub/efi/disk.h>
+#include <grub/efi/pe32.h>
+#endif
+
GRUB_MOD_LICENSE ("GPLv3+");
#define GRUB_BLS_CONFIG_PATH "/loader/entries/"
+#define GRUB_UKI_CONFIG_PATH "/EFI/Linux"
-static const struct grub_arg_option opt[] =
+#define GRUB_BLS_CMD 1
+#define GRUB_UKI_CMD 2
+
+static int cmd_type = 0;
+
+static const struct grub_arg_option bls_opt[] =
{
{"path", 'p', 0, N_("Specify path to find BLS entries."), N_("DIR"),
ARG_TYPE_PATHNAME},
{"show-default", 'd', 0, N_("Allow the default BLS entry to be added to the
GRUB menu."), 0, ARG_TYPE_NONE},
@@ -52,6 +64,17 @@ static const struct grub_arg_option 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;
@@ -270,7 +293,7 @@ bls_read_entry (grub_file_t f, grub_blsuki_entry_t *entry)
break;
}
- separator[0] = '\0';
+ separator[0] = '\0';
do
{
@@ -287,6 +310,183 @@ bls_read_entry (grub_file_t f, grub_blsuki_entry_t *entry)
return rc;
}
+#ifdef GRUB_MACHINE_EFI
+static int
+uki_read_entry (grub_file_t f, grub_blsuki_entry_t *entry)
+{
+ struct grub_msdos_image_header *dos;
+ struct grub_pe_image_header *pe;
+ grub_off_t section_offset = 0;
+ struct grub_pe32_section_table *section;
+ struct grub_pe32_coff_header *coff_header;
+
+ dos = grub_zalloc (sizeof (*dos));
+ if (dos == NULL)
+ return 1;
+ if (grub_file_read (f, dos, sizeof (*dos)) < (grub_ssize_t) sizeof (*dos))
+ {
+ grub_dprintf ("blsuki", "failed to read UKI image header\n");
+ grub_free (dos);
+ return 1;
+ }
+ if (dos->msdos_magic != GRUB_PE32_MAGIC)
+ {
+ grub_dprintf ("blsuki", "plain image kernel not supported\n");
+ grub_free (dos);
+ return 1;
+ }
+ grub_dprintf ("blsuki", "PE/COFF header @ %08x\n",
dos->pe_image_header_offset);
+ pe = grub_zalloc (sizeof (*pe));
+ if (pe == NULL)
+ {
+ grub_free (dos);
+ return 1;
+ }
+ if (grub_file_seek (f, dos->pe_image_header_offset) == (grub_off_t) -1
+ || grub_file_read (f, pe, sizeof (*pe)) != sizeof (*pe))
+ {
+ grub_dprintf ("blsuki", "failed to read COFF image header\n");
+ grub_free (dos);
+ grub_free (pe);
+ return 1;
+ }
+ if (pe->optional_header.magic != GRUB_PE32_NATIVE_MAGIC)
+ {
+ grub_dprintf ("blsuki", "non-native image not supported\n");
+ grub_free (dos);
+ grub_free (pe);
+ return 1;
+ }
+
+ coff_header = &(pe->coff_header);
+ section_offset = dos->pe_image_header_offset + sizeof (*pe);
+
+ for (int i = 0; i < coff_header->num_sections; i++)
+ {
+ char *val;
+ char *key;
+ return 1;
+ }
+ grub_dprintf ("blsuki", "section name: %s\n", key);
+ blsuki_add_keyval (entry, key, val);
+ section_offset += sizeof (*section);
+ grub_free (section);
+ grub_free (val);
+ grub_free (key);
+ }
+ return 0;
+}
+#endif
+
+static char *
+uki_read_osrel (char *content, grub_off_t *pos, char **key_ret, char **val_ret)
+{
+ char *line;
+ char *value;
+ grub_size_t linelen;
+
+ skip:
+ line = content + *pos;
+ if (*line == '\0')
+ return NULL;
+
+ linelen = 0;
+ while (line[linelen] != '\0' && !grub_strchr ("\n\r", line[linelen]))
+ linelen++;
+
+ /* Move pos to the next line */
+ *pos += linelen;
+ if (content[*pos] != '\0')
+ (*pos)++;
+
+ /* Skip empty line */
+ if (linelen == 0)
+ goto skip;
+
+ line[linelen] = '\0';
+
+ /* Remove leading white space */
+ while (grub_strchr (" \t", *line))
+ {
+ line++;
+ linelen--;
+ }
+
+ /* Remove trailing whitespace */
+ while (linelen > 0 && grub_strchr ("=", line[linelen - 1]))
+ linelen--;
+ line[linelen] = '\0';
+
+ if (*line == '#')
+ goto skip;
+
+ /* Split key/value */
+ value = line;
+ while (*value != '\0' && !grub_strchr ("=", *value))
+ value++;
+ if (*value == '\0')
+ goto skip;
+ *value = '\0';
+ value++;
+ while (*value != '\0' && grub_strchr ("=", *value))
+ value++;
+
+ /* Remove quotes from value */
+ if (value[0] == '\"' && line[linelen - 1] == '\"')
+ {
+ value++;
+ line[linelen - 1] = '\0';
+ }
+
+ *key_ret = line;
+ *val_ret = value;
+ return line;
+}
+
struct read_entry_info
{
const char *devid;
@@ -299,10 +499,12 @@ read_entry (const char *filename,
const struct grub_dirhook_info *dirhook_info __attribute__
((__unused__)),
void *data)
{
- grub_size_t m = 0, n, ext_len = 5;
+ grub_size_t m = 0, n, ext_len;
int rc = 0;
char *p = NULL;
+ const char *ext = NULL;
grub_file_t f = NULL;
+ enum grub_file_type file_type = 0;
grub_blsuki_entry_t *entry;
struct read_entry_info *info = (struct read_entry_info *) data;
@@ -310,6 +512,18 @@ read_entry (const char *filename,
n = grub_strlen (filename);
+ if (cmd_type == GRUB_BLS_CMD)
+ {
+ ext = ".conf";
+ file_type = GRUB_FILE_TYPE_CONFIG;
+ }
+ else if (cmd_type == GRUB_UKI_CMD)
+ {
+ ext = ".efi";
+ file_type = GRUB_FILE_TYPE_EFI_CHAINLOADED_IMAGE;
+ }
+ ext_len = grub_strlen (ext);
+
if (info->file != NULL)
{
f = info->file;
@@ -319,15 +533,15 @@ read_entry (const char *filename,
if (filename[0] == '.')
return 0;
- if (n <= 5)
+ if (n <= ext_len)
return 0;
- if (grub_strcmp (filename + n - ext_len, ".conf") != 0)
+ if (grub_strcmp (filename + n - ext_len, ext) != 0)
return 0;
p = grub_xasprintf ("(%s)%s/%s", info->devid, info->dirname, filename);
-
- f = grub_file_open (p, GRUB_FILE_TYPE_CONFIG);
+ //GRUB_FILE_TYPE_EFI_CHAINLOADER_IMAGE for uki
+ f = grub_file_open (p, file_type);
grub_free (p);
if (f == NULL)
goto finish;
@@ -364,7 +578,28 @@ read_entry (const char *filename,
goto finish;
}
- rc = bls_read_entry (f, entry);
+ entry->dirname = grub_strdup (info->dirname);
+ if (entry->dirname == NULL)
+ {
+ grub_free (entry);
+ goto finish;
+ }
+
+ entry->devid = grub_strdup (info->devid);
+ if (entry->devid == NULL)
+ {
+ grub_free (entry);
+ goto finish;
+ }
+
+ if (cmd_type == GRUB_BLS_CMD)
+ rc = bls_read_entry (f, entry);
+ else if (cmd_type == GRUB_UKI_CMD)
+ {
+#ifdef GRUB_MACHINE_EFI
+ rc = uki_read_entry (f, entry);
+#endif
+ }
if (rc == 0)
blsuki_add_entry (entry);
@@ -565,7 +800,7 @@ create_entry (grub_blsuki_entry_t *entry)
{
int argc = 0;
const char **argv = NULL;
- char *title = NULL;
+ char *title = entry->filename;
char *clinux = NULL;
char *options = NULL;
char **initrds = NULL;
@@ -592,224 +827,286 @@ create_entry (grub_blsuki_entry_t *entry)
bool add_dt_prefix = false;
bool savedefault;
- clinux = blsuki_get_val (entry, "linux", NULL);
+ if (cmd_type == GRUB_BLS_CMD)
+ clinux = blsuki_get_val (entry, "linux", NULL);
+ else if (cmd_type == GRUB_UKI_CMD)
+ clinux = blsuki_get_val (entry, ".linux", NULL);
if (clinux == NULL)
{
grub_dprintf ("blsuki", "Skipping file %s with no 'linux' key.\n",
entry->filename);
goto finish;
}
- /* Strip the ".conf" off the end before we make it our "id" field. */
- do
+ if (cmd_type == GRUB_BLS_CMD)
{
- dotconf = grub_strstr (dotconf, ".conf");
- }
- while (dotconf != NULL && dotconf[5] != '\0');
- if (dotconf != NULL)
- dotconf[0] = '\0';
-
- title = blsuki_get_val (entry, "title", NULL);
- options = expand_val (blsuki_get_val (entry, "options", NULL));
+ /* Strip the ".conf" off the end before we make it our "id" field. */
+ do
+ {
+ dotconf = grub_strstr (dotconf, ".conf");
+ }
+ while (dotconf != NULL && dotconf[5] != '\0');
+ if (dotconf != NULL)
+ dotconf[0] = '\0';
- if (options == NULL)
- options = expand_val (grub_env_get ("default_kernelopts"));
+ title = blsuki_get_val (entry, "title", NULL);
+ options = expand_val (blsuki_get_val (entry, "options", NULL));
- initrds = blsuki_make_list (entry, "initrd", NULL);
+ if (options == NULL)
+ options = expand_val (grub_env_get ("default_kernelopts"));
- devicetree = expand_val (blsuki_get_val (entry, "devicetree", NULL));
+ initrds = blsuki_make_list (entry, "initrd", NULL);
- if (devicetree == NULL)
- {
- devicetree = expand_val (grub_env_get ("devicetree"));
- add_dt_prefix = true;
- }
+ devicetree = expand_val (blsuki_get_val (entry, "devicetree", NULL));
- hotkey = blsuki_get_val (entry, "grub_hotkey", NULL);
- users = expand_val (blsuki_get_val (entry, "grub_users", NULL));
- classes = blsuki_make_list (entry, "grub_class", NULL);
- args = blsuki_make_list (entry, "grub_arg", &argc);
-
- argc += 1;
- if (grub_mul (argc + 1, sizeof (char *), &size))
- {
- grub_error (GRUB_ERR_OUT_OF_RANGE, N_("overflow detected creating argv
list"));
- goto finish;
- }
- argv = grub_malloc (size);
- if (argv == NULL)
- {
- grub_error (GRUB_ERR_OUT_OF_MEMORY, "failed to allocate argv list");
- goto finish;
- }
- argv[0] = title ? title : clinux;
- for (i = 1; i < argc; i++)
- argv[i] = args[i-1];
- argv[argc] = NULL;
-
- early_initrd = grub_env_get ("early_initrd");
-
- grub_dprintf ("blsuki", "adding menu entry for \"%s\" with id \"%s\"\n",
- title, id);
- if (early_initrd != NULL)
- {
- early_initrds = early_initrd_list (early_initrd);
- if (early_initrds == NULL)
+ if (devicetree == NULL)
{
- grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("failed to create early initrd
list"));
- goto finish;
+ devicetree = expand_val (grub_env_get ("devicetree"));
+ add_dt_prefix = true;
}
- if (initrds != NULL && initrds[0] != NULL)
- {
- initrd_prefix = grub_strrchr (initrds[0], '/');
- initrd_prefix = grub_strndup (initrds[0], initrd_prefix - initrds[0]
+ 1);
- }
- else
+ hotkey = blsuki_get_val (entry, "grub_hotkey", NULL);
+ users = expand_val (blsuki_get_val (entry, "grub_users", NULL));
+ classes = blsuki_make_list (entry, "grub_class", NULL);
+ args = blsuki_make_list (entry, "grub_arg", &argc);
+
+ argc += 1;
+ if (grub_mul (argc + 1, sizeof (char *), &size))
{
- initrd_prefix = grub_strrchr (clinux, '/');
- initrd_prefix = grub_strndup (clinux, initrd_prefix - clinux + 1);
+ grub_error (GRUB_ERR_OUT_OF_RANGE, N_("overflow detected creating argv
list"));
+ goto finish;
}
-
- if (initrd_prefix == NULL)
+ argv = grub_malloc (size);
+ if (argv == NULL)
{
- grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("failed to allocate initrd prefix
buffer"));
+ grub_error (GRUB_ERR_OUT_OF_MEMORY, "failed to allocate argv list");
goto finish;
}
- }
+ argv[0] = title ? title : clinux;
+ for (i = 1; i < argc; i++)
+ argv[i] = args[i-1];
+ argv[argc] = NULL;
- if (early_initrds != NULL || initrds != NULL)
- {
- initrd_size = sizeof ("initrd");
+ early_initrd = grub_env_get ("early_initrd");
- for (i = 0; early_initrds != NULL && early_initrds[i] != NULL; i++)
+ grub_dprintf ("blsuki", "adding menu entry for \"%s\" with id \"%s\"\n",
+ title, id);
+ if (early_initrd != NULL)
{
- 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))
+ early_initrds = early_initrd_list (early_initrd);
+ if (early_initrds == NULL)
{
- grub_error (GRUB_ERR_OUT_OF_RANGE, "overflow detected calculating
initrd buffer size");
+ grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("failed to create early initrd
list"));
goto finish;
}
- }
- for (i = 0; initrds != NULL && initrds[i] != NULL; i++)
- {
- 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))
+ if (initrds != NULL && initrds[0] != NULL)
{
- grub_error (GRUB_ERR_OUT_OF_RANGE, "overflow detected calculating
initrd buffer size");
+ initrd_prefix = grub_strrchr (initrds[0], '/');
+ initrd_prefix = grub_strndup (initrds[0], initrd_prefix -
initrds[0] + 1);
+ }
+ else
+ {
+ initrd_prefix = grub_strrchr (clinux, '/');
+ initrd_prefix = grub_strndup (clinux, initrd_prefix - clinux + 1);
+ }
+
+ if (initrd_prefix == NULL)
+ {
+ grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("failed to allocate initrd
prefix buffer"));
goto finish;
}
}
- if (grub_add (initrd_size, 1, &initrd_size))
+ if (early_initrds != NULL || initrds != NULL)
{
- grub_error (GRUB_ERR_OUT_OF_RANGE, "overflow detected calculating initrd
buffer size");
- goto finish;
- }
+ initrd_size = sizeof ("initrd");
- initrd = grub_malloc (initrd_size);
- if (initrd == NULL)
- {
- grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("failed to allocate initrd
buffer"));
- goto finish;
- }
+ for (i = 0; early_initrds != NULL && early_initrds[i] != NULL; i++)
+ {
+ 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))
+ {
+ grub_error (GRUB_ERR_OUT_OF_RANGE, "overflow detected calculating
initrd buffer size");
+ goto finish;
+ }
+ }
- tmp = grub_stpcpy (initrd, "initrd");
- for (i = 0; early_initrds != NULL && early_initrds[i] != NULL; i++)
- {
- grub_dprintf ("blsuki", "adding early initrd %s\n", early_initrds[i]);
- tmp = frob_boot_device (tmp);
- tmp = grub_stpcpy (tmp, initrd_prefix);
- tmp = grub_stpcpy (tmp, early_initrds[i]);
- grub_free (early_initrds[i]);
- }
+ for (i = 0; initrds != NULL && initrds[i] != NULL; i++)
+ {
+ 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))
+ {
+ grub_error (GRUB_ERR_OUT_OF_RANGE, "overflow detected calculating
initrd buffer size");
+ goto finish;
+ }
+ }
- for (i = 0; initrds != NULL && initrds[i] != NULL; i++)
- {
- grub_dprintf ("blsuki", "adding initrd %s\n", initrds[i]);
- tmp = frob_boot_device (tmp);
- tmp = grub_stpcpy (tmp, initrds[i]);
- }
- tmp = grub_stpcpy (tmp, "\n");
- }
+ if (grub_add (initrd_size, 1, &initrd_size))
+ {
+ grub_error (GRUB_ERR_OUT_OF_RANGE, "overflow detected calculating
initrd buffer size");
+ goto finish;
+ }
- if (devicetree != NULL)
- {
- if (add_dt_prefix == true)
- {
- prefix = grub_strrchr (clinux, '/');
- prefix = grub_strndup (clinux, prefix - clinux + 1);
- if (prefix == NULL)
+ initrd = grub_malloc (initrd_size);
+ if (initrd == NULL)
{
- grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("failed to allocate prefix
buffer"));
+ grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("failed to allocate initrd
buffer"));
goto finish;
}
- }
- 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");
- goto finish;
+ tmp = grub_stpcpy (initrd, "initrd");
+ for (i = 0; early_initrds != NULL && early_initrds[i] != NULL; i++)
+ {
+ grub_dprintf ("blsuki", "adding early initrd %s\n",
early_initrds[i]);
+ tmp = frob_boot_device (tmp);
+ tmp = grub_stpcpy (tmp, initrd_prefix);
+ tmp = grub_stpcpy (tmp, early_initrds[i]);
+ grub_free (early_initrds[i]);
+ }
+
+ for (i = 0; initrds != NULL && initrds[i] != NULL; i++)
+ {
+ grub_dprintf ("blsuki", "adding initrd %s\n", initrds[i]);
+ tmp = frob_boot_device (tmp);
+ tmp = grub_stpcpy (tmp, initrds[i]);
+ }
+ tmp = grub_stpcpy (tmp, "\n");
}
- if (add_dt_prefix == true)
+ if (devicetree != NULL)
{
- if (grub_add (dt_size, grub_strlen (prefix), &dt_size))
+ if (add_dt_prefix == true)
+ {
+ prefix = grub_strrchr (clinux, '/');
+ prefix = grub_strndup (clinux, prefix - clinux + 1);
+ if (prefix == NULL)
+ {
+ grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("failed to allocate prefix
buffer"));
+ goto finish;
+ }
+ }
+
+ 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");
goto finish;
}
+
+ if (add_dt_prefix == true)
+ {
+ if (grub_add (dt_size, grub_strlen (prefix), &dt_size))
+ {
+ grub_error (GRUB_ERR_OUT_OF_RANGE, "overflow detected calculating
device tree buffer size");
+ goto finish;
+ }
+ }
+
+ dt = grub_malloc (dt_size);
+ if (dt == NULL)
+ {
+ grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("failed to allocate device tree
buffer"));
+ goto finish;
+ }
+ tmp = dt;
+ tmp = grub_stpcpy (dt, "devicetree");
+ tmp = frob_boot_device (tmp);
+ if (add_dt_prefix == true)
+ tmp = grub_stpcpy (tmp, prefix);
+ tmp = grub_stpcpy (tmp, devicetree);
+ tmp = grub_stpcpy (tmp, "\n");
+
+ grub_free (prefix);
}
- dt = grub_malloc (dt_size);
- if (dt == NULL)
- {
- grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("failed to allocate device tree
buffer"));
- goto finish;
- }
- tmp = dt;
- tmp = grub_stpcpy (dt, "devicetree");
- tmp = frob_boot_device (tmp);
- if (add_dt_prefix == true)
- tmp = grub_stpcpy (tmp, prefix);
- tmp = grub_stpcpy (tmp, devicetree);
- tmp = grub_stpcpy (tmp, "\n");
-
- grub_free (prefix);
+ grub_dprintf ("blsuki", "devicetree %s for id:\"%s\"\n", dt, id);
+
+ sdval = grub_env_get ("save_default");
+ savedefault = ((NULL != sdval) && (grub_strcmp (sdval, "true") == 0));
+ src = grub_xasprintf ("%sload_video\n"
+ "set gfxpayload=keep\n"
+ "insmod gzio\n"
+ "linux %s%s%s%s\n"
+ "%s%s",
+ savedefault ? "savedefault\n" : "",
+ separate_boot ? GRUB_BOOT_DEVICE : "",
+ clinux, options ? " " : "", options ? options : "",
+ initrd ? initrd : "", dt ? dt : "");
}
+ else if (cmd_type == GRUB_UKI_CMD)
+ {
+ char *osrel = NULL;
+ char *line;
+ char *key = NULL;
+ char *value = NULL;
+ grub_off_t pos = 0;
+
+ options = blsuki_get_val (entry, ".cmdline", NULL);
+ if (options == NULL)
+ {
+ grub_dprintf ("blsuki", "Skipping file %s with no '.cmdline' key.\n",
entry->filename);
+ goto finish;
+ }
+ osrel = blsuki_get_val (entry, ".osrel", NULL);
+ if (osrel == NULL)
+ {
+ grub_dprintf ("blsuki", "Skipping file %s with no '.osrel' key.\n",
entry->filename);
+ goto finish;
+ }
+
+ line = osrel;
+ while ((line = uki_read_osrel (osrel, &pos, &key, &value)))
+ {
+ if (grub_strcmp ("PRETTY_NAME", key) == 0)
+ {
+ title = value;
+ break;
+ }
+ }
- grub_dprintf ("blsuki", "devicetree %s for id:\"%s\"\n", dt, id);
-
- sdval = grub_env_get ("save_default");
- savedefault = ((NULL != sdval) && (grub_strcmp (sdval, "true") == 0));
- src = grub_xasprintf ("%sload_video\n"
- "set gfxpayload=keep\n"
- "insmod gzio\n"
- "linux %s%s%s%s\n"
- "%s%s",
- savedefault ? "savedefault\n" : "",
- separate_boot ? GRUB_BOOT_DEVICE : "",
- clinux, options ? " " : "", options ? options : "",
- initrd ? initrd : "", dt ? dt : "");
+ argc += 1;
+ if (grub_mul (argc + 1, sizeof (char *), &size))
+ {
+ grub_error (GRUB_ERR_OUT_OF_RANGE, N_("overflow detected creating argv
list"));
+ goto finish;
+ }
+ argv = grub_malloc (size);
+ if (argv == NULL)
+ {
+ grub_error (GRUB_ERR_OUT_OF_MEMORY, "failed to allocate argv list");
+ goto finish;
+ }
+ argv[0] = title;
+ argv[argc] = NULL;
+
+ src = grub_xasprintf ("set root=(%s)\n"
+ "insmod gzio\n"
+ "insmod chain\n"
+ "chainloader %s/%s%s%s\n",
+ entry->devid, entry->dirname,
+ entry->filename, options ? " " : "", options ? options :
"");
+ }
grub_normal_add_menu_entry (argc, argv, classes, id, users, hotkey, NULL, src, 0, entry);
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);
- grub_free (args);
+ if (cmd_type == GRUB_BLS_CMD)
+ {
+ grub_free (dt);
+ grub_free (initrd);
+ grub_free (initrd_prefix);
+ grub_free (early_initrds);
+ grub_free (devicetree);
+ grub_free (initrds);
+ grub_free (classes);
+ grub_free (args);
+ }
grub_free (argv);
grub_free (src);
+ grub_free (options);
}
struct find_entry_info
@@ -832,7 +1129,12 @@ find_entry (struct find_entry_info *info)
int r = 0;
if (dir == NULL)
- dir = GRUB_BLS_CONFIG_PATH;
+ {
+ if (cmd_type == GRUB_BLS_CMD)
+ dir = GRUB_BLS_CONFIG_PATH;
+ else if (cmd_type == GRUB_UKI_CMD)
+ dir = GRUB_UKI_CONFIG_PATH;
+ }
read_entry_info.file = NULL;
read_entry_info.dirname = dir;
@@ -855,11 +1157,17 @@ find_entry (struct find_entry_info *info)
/*
* If we aren't able to find BLS entries in the directory given by
info->dirname,
* we can fallback to the default location "/boot/loader/entries/" and see
if we
- * can find the files there.
+ * can find the files there. If we can't find UKI entries, fallback to
+ * "/boot/efi/EFI/Linux".
*/
if (r != 0 && info->dirname == NULL && fallback == 0)
{
- read_entry_info.dirname = "/boot" GRUB_BLS_CONFIG_PATH;
+ if (cmd_type == GRUB_BLS_CMD)
+ read_entry_info.dirname = "/boot" GRUB_BLS_CONFIG_PATH;
+ else if (cmd_type == GRUB_UKI_CMD)
+ {
+ read_entry_info.dirname = GRUB_UKI_CONFIG_PATH;
+ }
grub_dprintf ("blsuki", "Entries weren't found in %s, fallback to %s\n",
dir, read_entry_info.dirname);
fallback = 1;
@@ -871,11 +1179,13 @@ static grub_err_t
blsuki_load_entries (char *path)
{
grub_size_t len;
+ grub_size_t ext_len;
grub_fs_t fs;
grub_device_t dev;
static grub_err_t r;
const char *devid = NULL;
char *dir = NULL;
+ const char *ext = NULL;
struct find_entry_info info = {
.dev = NULL,
.fs = NULL,
@@ -888,8 +1198,14 @@ blsuki_load_entries (char *path)
if (path != NULL)
{
+ if (cmd_type == GRUB_BLS_CMD)
+ ext = ".conf";
+ else if (cmd_type == GRUB_UKI_CMD)
+ ext = ".efi";
+
len = grub_strlen (path);
- if (grub_strcmp (path + len - 5, ".conf") == 0)
+ ext_len = grub_strlen (ext);
+ if (grub_strcmp (path + len - ext_len, ext) == 0)
{
rei.file = grub_file_open (path, GRUB_FILE_TYPE_CONFIG);
if (rei.file == NULL)
@@ -918,11 +1234,22 @@ blsuki_load_entries (char *path)
if (devid == NULL)
{
+ if (cmd_type == GRUB_BLS_CMD)
+ {
#ifdef GRUB_MACHINE_EMU
- devid = "host";
+ devid = "host";
#else
- devid = grub_env_get ("root");
+ devid = grub_env_get ("root");
#endif
+ }
+ else if (cmd_type == GRUB_UKI_CMD)
+ {
+#ifdef GRUB_MACHINE_EFI
+ grub_efi_loaded_image_t *image;
+ image = grub_efi_get_loaded_image (grub_efi_image_handle);
+ devid = grub_efidisk_get_device_name (image->device_handle);
+#endif
+ }
if (devid == NULL)
return grub_error (GRUB_ERR_FILE_NOT_FOUND, N_("variable `%s' isn't set"),
"root");
}
@@ -1013,8 +1340,7 @@ blsuki_create_entries (bool show_default, bool
show_non_default, char *entry_id)
}
static grub_err_t
-grub_cmd_blscfg (grub_extcmd_context_t ctxt, int argc __attribute__ ((unused)),
- char **args __attribute__ ((unused)))
+blsuki_cmd (grub_extcmd_context_t ctxt)
{
grub_err_t err;
struct grub_arg_list *state = ctxt->state;
@@ -1023,6 +1349,7 @@ grub_cmd_blscfg (grub_extcmd_context_t ctxt, int argc
__attribute__ ((unused)),
bool show_default = false;
bool show_non_default = false;
bool all = true;
+ entries = NULL;
if (state[0].set)
path = state[0].arg;
@@ -1048,23 +1375,52 @@ grub_cmd_blscfg (grub_extcmd_context_t ctxt, int argc
__attribute__ ((unused)),
}
err = blsuki_load_entries (path);
+
if (err != GRUB_ERR_NONE)
return err;
return blsuki_create_entries (show_default, show_non_default, entry_id);
}
+static grub_err_t
+grub_cmd_blscfg (grub_extcmd_context_t ctxt, int argc __attribute__ ((unused)),
+ char **args __attribute__ ((unused)))
+{
+ cmd_type = GRUB_BLS_CMD;
+ return blsuki_cmd (ctxt);
+}
+
static grub_extcmd_t bls_cmd;
+#ifdef GRUB_MACHINE_EFI
+static grub_err_t
+grub_cmd_uki (grub_extcmd_context_t ctxt, int argc __attribute__ ((unused)),
+ char **args __attribute__ ((unused)))
+{
+ cmd_type = GRUB_UKI_CMD;
+ return blsuki_cmd (ctxt);
+}
+
+static grub_extcmd_t uki_cmd;
+#endif
+
GRUB_MOD_INIT(blsuki)
{
bls_cmd = grub_register_extcmd ("blscfg", grub_cmd_blscfg, 0,
N_("[-p|--path] DIR [-d|--show-default]
[-n|--show-non-default] [-e|--entry] FILE"),
N_("Import Boot Loader Specification
snippets."),
- opt);
+ bls_opt);
+#ifdef GRUB_MACHINE_EFI
+ uki_cmd = grub_register_extcmd ("uki", grub_cmd_uki, 0,
+ N_("[-p|--path] DIR [-d|--show-default]
[-n|--show-non-default] [-e|--entry] FILE"),
+ N_("Import Unified Kernel Images"), uki_opt);
+#endif
}
GRUB_MOD_FINI(blsuki)
{
grub_unregister_extcmd (bls_cmd);
+#ifdef GRUB_MACHINE_EFI
+ grub_unregister_extcmd (uki_cmd);
+#endif
}
diff --git a/include/grub/menu.h b/include/grub/menu.h
index c25a0d16d..907373625 100644
--- a/include/grub/menu.h
+++ b/include/grub/menu.h
@@ -28,6 +28,8 @@ struct grub_blsuki_entry
grub_size_t keyvals_size;
int nkeyvals;
char *filename;
+ char *dirname;
+ char *devid;
int visible;
};
typedef struct grub_blsuki_entry grub_blsuki_entry_t;