Device tree properties are not explicitly typed but values can take multiple forms from strings to arrays and byte-strings. grub_fdt_prop_to_string() adds a heuristic to determine the type and convert it to a string for printing.
Signed-off-by: Tobias Heider <tobias.hei...@canonical.com> --- grub-core/lib/fdt.c | 87 ++++++++++++++++++++++++++++++++++++++ grub-core/loader/efi/fdt.c | 15 +++++-- include/grub/fdt.h | 3 ++ 3 files changed, 101 insertions(+), 4 deletions(-) diff --git a/grub-core/lib/fdt.c b/grub-core/lib/fdt.c index 73cfa94a2..5ec32ac56 100644 --- a/grub-core/lib/fdt.c +++ b/grub-core/lib/fdt.c @@ -1,6 +1,7 @@ /* * GRUB -- GRand Unified Bootloader * Copyright (C) 2013 Free Software Foundation, Inc. + * Copyright (C) 2024 Canonical, Ltd. * * GRUB is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -501,6 +502,92 @@ int grub_fdt_set_prop (void *fdt, unsigned int nodeoffset, const char *name, return 0; } +static int +prop_isstring (const unsigned char *str, grub_uint32_t len) +{ + grub_uint32_t i; + int is_nonzero = 0; + + if (!len || str[len - 1]) + return 0; + + for (i = 0; i < len; i++) + { + if (!str[i]) + { + if (!is_nonzero) + return 0; + + is_nonzero = 0; + continue; + } + if (!grub_isprint (str[i])) + return 0; + + is_nonzero = 1; + } + return 1; +} + +char * +grub_fdt_prop_to_string (const unsigned char *val, grub_uint32_t len) +{ + char *str; + int pos, slen; + grub_uint32_t i; + + if (prop_isstring (val, len)) + { + /* string */ + return grub_strdup ((const char *)val); + } + else if (len & 0x3) + { + /* byte string */ + grub_printf ("["); + + slen = (len * 3) + 2; + str = grub_malloc (slen); + if (str == NULL) + return NULL; + + pos = 0; + str[pos++] = '['; + for (i = 0; i < len; i++) + { + pos += grub_snprintf (&str[pos], slen - pos, "%02x", val[i]); + if (i != len - 1) + str[pos++] = ' '; + } + str[pos++] = ']'; + str[pos] = '\0'; + } + else + { + /* cell list */ + const grub_uint32_t *cell = (const grub_uint32_t *)val; + + slen = (len * 11) + 2; + str = grub_malloc (slen); + if (str == NULL) + return NULL; + + pos = 0; + str[pos++] = '<'; + for (i = 0, len /= 4; i < len; i++) + { + pos += grub_snprintf (&str[pos], slen - pos, "0x%08x", + grub_be_to_cpu32 (cell[i])); + if (i != len - 1) + str[pos++] = ' '; + } + str[pos++] = '>'; + str[pos] = '\0'; + } + + return str; +} + int grub_fdt_create_empty_tree (void *fdt, unsigned int size) { diff --git a/grub-core/loader/efi/fdt.c b/grub-core/loader/efi/fdt.c index e510b3491..b43ff730d 100644 --- a/grub-core/loader/efi/fdt.c +++ b/grub-core/loader/efi/fdt.c @@ -183,8 +183,10 @@ grub_cmd_fdtdump (grub_extcmd_context_t ctxt, char **argv __attribute__ ((unused))) { struct grub_arg_list *state = ctxt->state; - const char *value = NULL; + const unsigned char *value = NULL; + char *str; void *fw_fdt; + grub_uint32_t len; fw_fdt = grub_efi_get_firmware_fdt (); if (fw_fdt == NULL) @@ -192,17 +194,22 @@ grub_cmd_fdtdump (grub_extcmd_context_t ctxt, N_("No device tree found")); if (state[0].set) - value = grub_fdt_get_prop (fw_fdt, 0, state[0].arg, NULL); + value = grub_fdt_get_prop (fw_fdt, 0, state[0].arg, &len); if (value == NULL) return grub_error (GRUB_ERR_OUT_OF_RANGE, N_("failed to retrieve the prop field")); + str = grub_fdt_prop_to_string (value, len); + if (str == NULL) + return grub_error (GRUB_ERR_IO, N_("Failed to print string")); + if (state[1].set) - grub_env_set (state[1].arg, value); + grub_env_set (state[1].arg, str); else - grub_printf ("%s\n", value); + grub_printf ("%s", str); + grub_free (str); return GRUB_ERR_NONE; } diff --git a/include/grub/fdt.h b/include/grub/fdt.h index e609c7e41..4db644544 100644 --- a/include/grub/fdt.h +++ b/include/grub/fdt.h @@ -118,6 +118,9 @@ EXPORT_FUNC(grub_fdt_get_nodename) (const void *fdt, unsigned int nodeoffset); const void *EXPORT_FUNC(grub_fdt_get_prop) (const void *fdt, unsigned int nodeoffset, const char *name, grub_uint32_t *len); +char *EXPORT_FUNC(grub_fdt_prop_to_string) (const unsigned char *val, + grub_uint32_t len); + int EXPORT_FUNC(grub_fdt_set_prop) (void *fdt, unsigned int nodeoffset, const char *name, const void *val, grub_uint32_t len); #define grub_fdt_set_prop32(fdt, nodeoffset, name, val) \ -- 2.43.0 _______________________________________________ Grub-devel mailing list Grub-devel@gnu.org https://lists.gnu.org/mailman/listinfo/grub-devel