Message ID | 20190121074923.29959-2-takahiro.akashi@linaro.org |
---|---|
State | Superseded |
Delegated to: | Alexander Graf |
Headers | show |
Series | cmd: add efidebug for efi environment | expand |
On 01/21/2019 08:49 AM, AKASHI Takahiro wrote: > Currently, there is no easy way to add or modify UEFI variables. > In particular, bootmgr supports BootOrder/BootXXXX variables, it is > quite hard to define them as u-boot variables because they are represented > in a complicated and encoded format. > > The new command, efidebug, helps address these issues and give us > more friendly interfaces: > * efidebug boot add: add BootXXXX variable > * efidebug boot rm: remove BootXXXX variable > * efidebug boot dump: display all BootXXXX variables > * efidebug boot next: set BootNext variable > * efidebug boot order: set/display a boot order (BootOrder) > * efidebug setvar: set an UEFI variable (with limited functionality) > * efidebug dumpvar: display all UEFI variables > > Please note that the file, efidebug.c, will be compiled under > CONFIG_EFI_LOADER because some helper functions will be used > to enable "env -e" command in a later patch whether or not > the command is compiled in. > > Signed-off-by: AKASHI Takahiro <takahiro.akashi@linaro.org> > --- > MAINTAINERS | 1 + > cmd/Kconfig | 10 + > cmd/Makefile | 1 + > cmd/efidebug.c | 755 ++++++++++++++++++++++++++++++++++++++++++++++ > include/command.h | 6 + > 5 files changed, 773 insertions(+) > create mode 100644 cmd/efidebug.c > > diff --git a/MAINTAINERS b/MAINTAINERS > index ae825014bda9..301c5c69ea25 100644 > --- a/MAINTAINERS > +++ b/MAINTAINERS > @@ -438,6 +438,7 @@ F: lib/efi*/ > F: test/py/tests/test_efi* > F: test/unicode_ut.c > F: cmd/bootefi.c > +F: cmd/efidebug.c > F: tools/file2include.c > > FPGA > diff --git a/cmd/Kconfig b/cmd/Kconfig > index ea1a325eb301..d9cab3cc0c49 100644 > --- a/cmd/Kconfig > +++ b/cmd/Kconfig > @@ -1397,6 +1397,16 @@ config CMD_DISPLAY > displayed on a simple board-specific display. Implement > display_putc() to use it. > > +config CMD_EFIDEBUG > + bool "efidebug - display/customize UEFI environment" > + depends on EFI_LOADER > + default n > + help > + Enable the 'efidebug' command which provides a subset of UEFI > + shell utility with simplified functionality. It will be useful > + particularly for managing boot parameters as well as examining > + various EFI status for debugging. > + > config CMD_LED > bool "led" > default y if LED > diff --git a/cmd/Makefile b/cmd/Makefile > index 15ae4d250f50..e48d34c394ee 100644 > --- a/cmd/Makefile > +++ b/cmd/Makefile > @@ -51,6 +51,7 @@ obj-$(CONFIG_CMD_ECHO) += echo.o > obj-$(CONFIG_ENV_IS_IN_EEPROM) += eeprom.o > obj-$(CONFIG_CMD_EEPROM) += eeprom.o > obj-$(CONFIG_EFI_STUB) += efi.o > +obj-$(CONFIG_EFI_LOADER) += efidebug.o > obj-$(CONFIG_CMD_ELF) += elf.o > obj-$(CONFIG_HUSH_PARSER) += exit.o > obj-$(CONFIG_CMD_EXT4) += ext4.o > diff --git a/cmd/efidebug.c b/cmd/efidebug.c > new file mode 100644 > index 000000000000..c54fb6cfa101 > --- /dev/null > +++ b/cmd/efidebug.c > @@ -0,0 +1,755 @@ > +// SPDX-License-Identifier: GPL-2.0+ > +/* > + * UEFI Shell-like command > + * > + * Copyright (c) 2018 AKASHI Takahiro, Linaro Limited > + */ > + > +#include <charset.h> > +#include <common.h> > +#include <command.h> > +#include <efi_loader.h> > +#include <environment.h> > +#include <errno.h> > +#include <exports.h> > +#include <hexdump.h> > +#include <malloc.h> > +#include <search.h> > +#include <linux/ctype.h> > +#include <asm/global_data.h> > + > +static void dump_var_data(char *data, unsigned long len) > +{ > + char *start, *end, *p; > + unsigned long pos, count; > + char hex[3], line[9]; > + int i; > + > + end = data + len; > + for (start = data, pos = 0; start < end; start += count, pos += count) { > + count = end - start; > + if (count > 16) > + count = 16; > + > + /* count should be multiple of two */ > + printf("%08lx: ", pos); > + > + /* in hex format */ > + p = start; > + for (i = 0; i < count / 2; p += 2, i++) > + printf(" %c%c", *p, *(p + 1)); > + for (; i < 8; i++) > + printf(" "); > + > + /* in character format */ > + p = start; > + hex[2] = '\0'; > + for (i = 0; i < count / 2; i++) { > + hex[0] = *p++; > + hex[1] = *p++; > + line[i] = (char)simple_strtoul(hex, 0, 16); > + if (line[i] < 0x20 || line[i] > 0x7f) > + line[i] = '.'; > + } > + line[i] = '\0'; > + printf(" %s\n", line); > + } > +} Is this print_hex_dump() reimplemented? Alex
Alex, On Mon, Jan 21, 2019 at 02:07:31PM +0100, Alexander Graf wrote: > On 01/21/2019 08:49 AM, AKASHI Takahiro wrote: > >Currently, there is no easy way to add or modify UEFI variables. > >In particular, bootmgr supports BootOrder/BootXXXX variables, it is > >quite hard to define them as u-boot variables because they are represented > >in a complicated and encoded format. > > > >The new command, efidebug, helps address these issues and give us > >more friendly interfaces: > > * efidebug boot add: add BootXXXX variable > > * efidebug boot rm: remove BootXXXX variable > > * efidebug boot dump: display all BootXXXX variables > > * efidebug boot next: set BootNext variable > > * efidebug boot order: set/display a boot order (BootOrder) > > * efidebug setvar: set an UEFI variable (with limited functionality) > > * efidebug dumpvar: display all UEFI variables > > > >Please note that the file, efidebug.c, will be compiled under > >CONFIG_EFI_LOADER because some helper functions will be used > >to enable "env -e" command in a later patch whether or not > >the command is compiled in. > > > >Signed-off-by: AKASHI Takahiro <takahiro.akashi@linaro.org> > >--- > > MAINTAINERS | 1 + > > cmd/Kconfig | 10 + > > cmd/Makefile | 1 + > > cmd/efidebug.c | 755 ++++++++++++++++++++++++++++++++++++++++++++++ > > include/command.h | 6 + > > 5 files changed, 773 insertions(+) > > create mode 100644 cmd/efidebug.c > > > >diff --git a/MAINTAINERS b/MAINTAINERS > >index ae825014bda9..301c5c69ea25 100644 > >--- a/MAINTAINERS > >+++ b/MAINTAINERS > >@@ -438,6 +438,7 @@ F: lib/efi*/ > > F: test/py/tests/test_efi* > > F: test/unicode_ut.c > > F: cmd/bootefi.c > >+F: cmd/efidebug.c > > F: tools/file2include.c > > FPGA > >diff --git a/cmd/Kconfig b/cmd/Kconfig > >index ea1a325eb301..d9cab3cc0c49 100644 > >--- a/cmd/Kconfig > >+++ b/cmd/Kconfig > >@@ -1397,6 +1397,16 @@ config CMD_DISPLAY > > displayed on a simple board-specific display. Implement > > display_putc() to use it. > >+config CMD_EFIDEBUG > >+ bool "efidebug - display/customize UEFI environment" > >+ depends on EFI_LOADER > >+ default n > >+ help > >+ Enable the 'efidebug' command which provides a subset of UEFI > >+ shell utility with simplified functionality. It will be useful > >+ particularly for managing boot parameters as well as examining > >+ various EFI status for debugging. > >+ > > config CMD_LED > > bool "led" > > default y if LED > >diff --git a/cmd/Makefile b/cmd/Makefile > >index 15ae4d250f50..e48d34c394ee 100644 > >--- a/cmd/Makefile > >+++ b/cmd/Makefile > >@@ -51,6 +51,7 @@ obj-$(CONFIG_CMD_ECHO) += echo.o > > obj-$(CONFIG_ENV_IS_IN_EEPROM) += eeprom.o > > obj-$(CONFIG_CMD_EEPROM) += eeprom.o > > obj-$(CONFIG_EFI_STUB) += efi.o > >+obj-$(CONFIG_EFI_LOADER) += efidebug.o > > obj-$(CONFIG_CMD_ELF) += elf.o > > obj-$(CONFIG_HUSH_PARSER) += exit.o > > obj-$(CONFIG_CMD_EXT4) += ext4.o > >diff --git a/cmd/efidebug.c b/cmd/efidebug.c > >new file mode 100644 > >index 000000000000..c54fb6cfa101 > >--- /dev/null > >+++ b/cmd/efidebug.c > >@@ -0,0 +1,755 @@ > >+// SPDX-License-Identifier: GPL-2.0+ > >+/* > >+ * UEFI Shell-like command > >+ * > >+ * Copyright (c) 2018 AKASHI Takahiro, Linaro Limited > >+ */ > >+ > >+#include <charset.h> > >+#include <common.h> > >+#include <command.h> > >+#include <efi_loader.h> > >+#include <environment.h> > >+#include <errno.h> > >+#include <exports.h> > >+#include <hexdump.h> > >+#include <malloc.h> > >+#include <search.h> > >+#include <linux/ctype.h> > >+#include <asm/global_data.h> > >+ > >+static void dump_var_data(char *data, unsigned long len) > >+{ > >+ char *start, *end, *p; > >+ unsigned long pos, count; > >+ char hex[3], line[9]; > >+ int i; > >+ > >+ end = data + len; > >+ for (start = data, pos = 0; start < end; start += count, pos += count) { > >+ count = end - start; > >+ if (count > 16) > >+ count = 16; > >+ > >+ /* count should be multiple of two */ > >+ printf("%08lx: ", pos); > >+ > >+ /* in hex format */ > >+ p = start; > >+ for (i = 0; i < count / 2; p += 2, i++) > >+ printf(" %c%c", *p, *(p + 1)); > >+ for (; i < 8; i++) > >+ printf(" "); > >+ > >+ /* in character format */ > >+ p = start; > >+ hex[2] = '\0'; > >+ for (i = 0; i < count / 2; i++) { > >+ hex[0] = *p++; > >+ hex[1] = *p++; > >+ line[i] = (char)simple_strtoul(hex, 0, 16); > >+ if (line[i] < 0x20 || line[i] > 0x7f) > >+ line[i] = '.'; > >+ } > >+ line[i] = '\0'; > >+ printf(" %s\n", line); > >+ } > >+} > > Is this print_hex_dump() reimplemented? Actually, no. A UEFI variable on u-boot is encoded as ascii representation of binary data. That means, for example, => env set -e PlatformLang en => env print -e PlatformLang: {boot,run}(blob) 00000000: 65 6e en => env print ... efi_8be4df61-93ca-11d2-aa0d-00e098032b8c_PlatformLang={boot,run}(blob)656e ... the value of "PlatformLang" as a u-boot variable here is "656e", not "en." So if we want to use print_hex_dump(), we first have to convert that string to a binary. But then print_hex_dump() converts the binary to a string. It's just rediculuous, isn't it? You might think that the value in this case should be {boot, run}(utf8)en ^^^^ It's possible, but it depends on a variable and currently my do_set_efi_var() doesn't support it anyway. Thanks, -Takahiro Akashi > > Alex >
On 22.01.19 02:02, AKASHI Takahiro wrote: > Alex, > > On Mon, Jan 21, 2019 at 02:07:31PM +0100, Alexander Graf wrote: >> On 01/21/2019 08:49 AM, AKASHI Takahiro wrote: >>> Currently, there is no easy way to add or modify UEFI variables. >>> In particular, bootmgr supports BootOrder/BootXXXX variables, it is >>> quite hard to define them as u-boot variables because they are represented >>> in a complicated and encoded format. >>> >>> The new command, efidebug, helps address these issues and give us >>> more friendly interfaces: >>> * efidebug boot add: add BootXXXX variable >>> * efidebug boot rm: remove BootXXXX variable >>> * efidebug boot dump: display all BootXXXX variables >>> * efidebug boot next: set BootNext variable >>> * efidebug boot order: set/display a boot order (BootOrder) >>> * efidebug setvar: set an UEFI variable (with limited functionality) >>> * efidebug dumpvar: display all UEFI variables >>> >>> Please note that the file, efidebug.c, will be compiled under >>> CONFIG_EFI_LOADER because some helper functions will be used >>> to enable "env -e" command in a later patch whether or not >>> the command is compiled in. >>> >>> Signed-off-by: AKASHI Takahiro <takahiro.akashi@linaro.org> >>> --- >>> MAINTAINERS | 1 + >>> cmd/Kconfig | 10 + >>> cmd/Makefile | 1 + >>> cmd/efidebug.c | 755 ++++++++++++++++++++++++++++++++++++++++++++++ >>> include/command.h | 6 + >>> 5 files changed, 773 insertions(+) >>> create mode 100644 cmd/efidebug.c >>> >>> diff --git a/MAINTAINERS b/MAINTAINERS >>> index ae825014bda9..301c5c69ea25 100644 >>> --- a/MAINTAINERS >>> +++ b/MAINTAINERS >>> @@ -438,6 +438,7 @@ F: lib/efi*/ >>> F: test/py/tests/test_efi* >>> F: test/unicode_ut.c >>> F: cmd/bootefi.c >>> +F: cmd/efidebug.c >>> F: tools/file2include.c >>> FPGA >>> diff --git a/cmd/Kconfig b/cmd/Kconfig >>> index ea1a325eb301..d9cab3cc0c49 100644 >>> --- a/cmd/Kconfig >>> +++ b/cmd/Kconfig >>> @@ -1397,6 +1397,16 @@ config CMD_DISPLAY >>> displayed on a simple board-specific display. Implement >>> display_putc() to use it. >>> +config CMD_EFIDEBUG >>> + bool "efidebug - display/customize UEFI environment" >>> + depends on EFI_LOADER >>> + default n >>> + help >>> + Enable the 'efidebug' command which provides a subset of UEFI >>> + shell utility with simplified functionality. It will be useful >>> + particularly for managing boot parameters as well as examining >>> + various EFI status for debugging. >>> + >>> config CMD_LED >>> bool "led" >>> default y if LED >>> diff --git a/cmd/Makefile b/cmd/Makefile >>> index 15ae4d250f50..e48d34c394ee 100644 >>> --- a/cmd/Makefile >>> +++ b/cmd/Makefile >>> @@ -51,6 +51,7 @@ obj-$(CONFIG_CMD_ECHO) += echo.o >>> obj-$(CONFIG_ENV_IS_IN_EEPROM) += eeprom.o >>> obj-$(CONFIG_CMD_EEPROM) += eeprom.o >>> obj-$(CONFIG_EFI_STUB) += efi.o >>> +obj-$(CONFIG_EFI_LOADER) += efidebug.o >>> obj-$(CONFIG_CMD_ELF) += elf.o >>> obj-$(CONFIG_HUSH_PARSER) += exit.o >>> obj-$(CONFIG_CMD_EXT4) += ext4.o >>> diff --git a/cmd/efidebug.c b/cmd/efidebug.c >>> new file mode 100644 >>> index 000000000000..c54fb6cfa101 >>> --- /dev/null >>> +++ b/cmd/efidebug.c >>> @@ -0,0 +1,755 @@ >>> +// SPDX-License-Identifier: GPL-2.0+ >>> +/* >>> + * UEFI Shell-like command >>> + * >>> + * Copyright (c) 2018 AKASHI Takahiro, Linaro Limited >>> + */ >>> + >>> +#include <charset.h> >>> +#include <common.h> >>> +#include <command.h> >>> +#include <efi_loader.h> >>> +#include <environment.h> >>> +#include <errno.h> >>> +#include <exports.h> >>> +#include <hexdump.h> >>> +#include <malloc.h> >>> +#include <search.h> >>> +#include <linux/ctype.h> >>> +#include <asm/global_data.h> >>> + >>> +static void dump_var_data(char *data, unsigned long len) >>> +{ >>> + char *start, *end, *p; >>> + unsigned long pos, count; >>> + char hex[3], line[9]; >>> + int i; >>> + >>> + end = data + len; >>> + for (start = data, pos = 0; start < end; start += count, pos += count) { >>> + count = end - start; >>> + if (count > 16) >>> + count = 16; >>> + >>> + /* count should be multiple of two */ >>> + printf("%08lx: ", pos); >>> + >>> + /* in hex format */ >>> + p = start; >>> + for (i = 0; i < count / 2; p += 2, i++) >>> + printf(" %c%c", *p, *(p + 1)); >>> + for (; i < 8; i++) >>> + printf(" "); >>> + >>> + /* in character format */ >>> + p = start; >>> + hex[2] = '\0'; >>> + for (i = 0; i < count / 2; i++) { >>> + hex[0] = *p++; >>> + hex[1] = *p++; >>> + line[i] = (char)simple_strtoul(hex, 0, 16); >>> + if (line[i] < 0x20 || line[i] > 0x7f) >>> + line[i] = '.'; >>> + } >>> + line[i] = '\0'; >>> + printf(" %s\n", line); >>> + } >>> +} >> >> Is this print_hex_dump() reimplemented? > > Actually, no. > A UEFI variable on u-boot is encoded as ascii representation of binary data. > That means, for example, > > => env set -e PlatformLang en > => env print -e > PlatformLang: {boot,run}(blob) > 00000000: 65 6e en > => env print > ... > efi_8be4df61-93ca-11d2-aa0d-00e098032b8c_PlatformLang={boot,run}(blob)656e > ... > > the value of "PlatformLang" as a u-boot variable here is "656e", not "en." > So if we want to use print_hex_dump(), we first have to convert that > string to a binary. But then print_hex_dump() converts the binary to > a string. It's just rediculuous, isn't it? I actually think I would prefer that. This way we consolidate everything through a single API which means we then know that the results are always the same. If we implement parsing multiple times, there's a good chance we'll have a bug in one of them which gives us different results which then again makes debugging harder rather than easier. > You might think that the value in this case should be > {boot, run}(utf8)en > ^^^^ > It's possible, but it depends on a variable and > currently my do_set_efi_var() doesn't support it anyway. One more reason to use only a single path to funnel things through :). So yes, can you maybe reuse RTS->get_variable() here? Same question on writing variables I suppose. Alex
On Tue, Jan 22, 2019 at 10:18:58AM +0100, Alexander Graf wrote: > > > On 22.01.19 02:02, AKASHI Takahiro wrote: > > Alex, > > > > On Mon, Jan 21, 2019 at 02:07:31PM +0100, Alexander Graf wrote: > >> On 01/21/2019 08:49 AM, AKASHI Takahiro wrote: > >>> Currently, there is no easy way to add or modify UEFI variables. > >>> In particular, bootmgr supports BootOrder/BootXXXX variables, it is > >>> quite hard to define them as u-boot variables because they are represented > >>> in a complicated and encoded format. > >>> > >>> The new command, efidebug, helps address these issues and give us > >>> more friendly interfaces: > >>> * efidebug boot add: add BootXXXX variable > >>> * efidebug boot rm: remove BootXXXX variable > >>> * efidebug boot dump: display all BootXXXX variables > >>> * efidebug boot next: set BootNext variable > >>> * efidebug boot order: set/display a boot order (BootOrder) > >>> * efidebug setvar: set an UEFI variable (with limited functionality) > >>> * efidebug dumpvar: display all UEFI variables > >>> > >>> Please note that the file, efidebug.c, will be compiled under > >>> CONFIG_EFI_LOADER because some helper functions will be used > >>> to enable "env -e" command in a later patch whether or not > >>> the command is compiled in. > >>> > >>> Signed-off-by: AKASHI Takahiro <takahiro.akashi@linaro.org> > >>> --- > >>> MAINTAINERS | 1 + > >>> cmd/Kconfig | 10 + > >>> cmd/Makefile | 1 + > >>> cmd/efidebug.c | 755 ++++++++++++++++++++++++++++++++++++++++++++++ > >>> include/command.h | 6 + > >>> 5 files changed, 773 insertions(+) > >>> create mode 100644 cmd/efidebug.c > >>> > >>> diff --git a/MAINTAINERS b/MAINTAINERS > >>> index ae825014bda9..301c5c69ea25 100644 > >>> --- a/MAINTAINERS > >>> +++ b/MAINTAINERS > >>> @@ -438,6 +438,7 @@ F: lib/efi*/ > >>> F: test/py/tests/test_efi* > >>> F: test/unicode_ut.c > >>> F: cmd/bootefi.c > >>> +F: cmd/efidebug.c > >>> F: tools/file2include.c > >>> FPGA > >>> diff --git a/cmd/Kconfig b/cmd/Kconfig > >>> index ea1a325eb301..d9cab3cc0c49 100644 > >>> --- a/cmd/Kconfig > >>> +++ b/cmd/Kconfig > >>> @@ -1397,6 +1397,16 @@ config CMD_DISPLAY > >>> displayed on a simple board-specific display. Implement > >>> display_putc() to use it. > >>> +config CMD_EFIDEBUG > >>> + bool "efidebug - display/customize UEFI environment" > >>> + depends on EFI_LOADER > >>> + default n > >>> + help > >>> + Enable the 'efidebug' command which provides a subset of UEFI > >>> + shell utility with simplified functionality. It will be useful > >>> + particularly for managing boot parameters as well as examining > >>> + various EFI status for debugging. > >>> + > >>> config CMD_LED > >>> bool "led" > >>> default y if LED > >>> diff --git a/cmd/Makefile b/cmd/Makefile > >>> index 15ae4d250f50..e48d34c394ee 100644 > >>> --- a/cmd/Makefile > >>> +++ b/cmd/Makefile > >>> @@ -51,6 +51,7 @@ obj-$(CONFIG_CMD_ECHO) += echo.o > >>> obj-$(CONFIG_ENV_IS_IN_EEPROM) += eeprom.o > >>> obj-$(CONFIG_CMD_EEPROM) += eeprom.o > >>> obj-$(CONFIG_EFI_STUB) += efi.o > >>> +obj-$(CONFIG_EFI_LOADER) += efidebug.o > >>> obj-$(CONFIG_CMD_ELF) += elf.o > >>> obj-$(CONFIG_HUSH_PARSER) += exit.o > >>> obj-$(CONFIG_CMD_EXT4) += ext4.o > >>> diff --git a/cmd/efidebug.c b/cmd/efidebug.c > >>> new file mode 100644 > >>> index 000000000000..c54fb6cfa101 > >>> --- /dev/null > >>> +++ b/cmd/efidebug.c > >>> @@ -0,0 +1,755 @@ > >>> +// SPDX-License-Identifier: GPL-2.0+ > >>> +/* > >>> + * UEFI Shell-like command > >>> + * > >>> + * Copyright (c) 2018 AKASHI Takahiro, Linaro Limited > >>> + */ > >>> + > >>> +#include <charset.h> > >>> +#include <common.h> > >>> +#include <command.h> > >>> +#include <efi_loader.h> > >>> +#include <environment.h> > >>> +#include <errno.h> > >>> +#include <exports.h> > >>> +#include <hexdump.h> > >>> +#include <malloc.h> > >>> +#include <search.h> > >>> +#include <linux/ctype.h> > >>> +#include <asm/global_data.h> > >>> + > >>> +static void dump_var_data(char *data, unsigned long len) > >>> +{ > >>> + char *start, *end, *p; > >>> + unsigned long pos, count; > >>> + char hex[3], line[9]; > >>> + int i; > >>> + > >>> + end = data + len; > >>> + for (start = data, pos = 0; start < end; start += count, pos += count) { > >>> + count = end - start; > >>> + if (count > 16) > >>> + count = 16; > >>> + > >>> + /* count should be multiple of two */ > >>> + printf("%08lx: ", pos); > >>> + > >>> + /* in hex format */ > >>> + p = start; > >>> + for (i = 0; i < count / 2; p += 2, i++) > >>> + printf(" %c%c", *p, *(p + 1)); > >>> + for (; i < 8; i++) > >>> + printf(" "); > >>> + > >>> + /* in character format */ > >>> + p = start; > >>> + hex[2] = '\0'; > >>> + for (i = 0; i < count / 2; i++) { > >>> + hex[0] = *p++; > >>> + hex[1] = *p++; > >>> + line[i] = (char)simple_strtoul(hex, 0, 16); > >>> + if (line[i] < 0x20 || line[i] > 0x7f) > >>> + line[i] = '.'; > >>> + } > >>> + line[i] = '\0'; > >>> + printf(" %s\n", line); > >>> + } > >>> +} > >> > >> Is this print_hex_dump() reimplemented? > > > > Actually, no. > > A UEFI variable on u-boot is encoded as ascii representation of binary data. > > That means, for example, > > > > => env set -e PlatformLang en > > => env print -e > > PlatformLang: {boot,run}(blob) > > 00000000: 65 6e en > > => env print > > ... > > efi_8be4df61-93ca-11d2-aa0d-00e098032b8c_PlatformLang={boot,run}(blob)656e > > ... > > > > the value of "PlatformLang" as a u-boot variable here is "656e", not "en." > > So if we want to use print_hex_dump(), we first have to convert that > > string to a binary. But then print_hex_dump() converts the binary to > > a string. It's just rediculuous, isn't it? > > I actually think I would prefer that. This way we consolidate everything > through a single API which means we then know that the results are > always the same. If we implement parsing multiple times, there's a good > chance we'll have a bug in one of them which gives us different results > which then again makes debugging harder rather than easier. Agree, but please note we have to add an apparently weird dependency of CONFIG_HEXDUMP to EFI_LOADER as do_efi_dump_var_ext() needs to be compiled in whether CMD_EFIDEBUG is enabled or not. > > You might think that the value in this case should be > > {boot, run}(utf8)en > > ^^^^ > > It's possible, but it depends on a variable and > > currently my do_set_efi_var() doesn't support it anyway. > > One more reason to use only a single path to funnel things through :). > > So yes, can you maybe reuse RTS->get_variable() here? Same question on > writing variables I suppose. Well, we need GetNextVariableName API if we want to use GetVariable (for listing). I have held off merging my another patch for this. Is it time to do it? -Takahiro Akashi > > Alex
On 01/23/2019 05:47 AM, AKASHI Takahiro wrote: > On Tue, Jan 22, 2019 at 10:18:58AM +0100, Alexander Graf wrote: >> >> On 22.01.19 02:02, AKASHI Takahiro wrote: >>> Alex, >>> >>> On Mon, Jan 21, 2019 at 02:07:31PM +0100, Alexander Graf wrote: >>>> On 01/21/2019 08:49 AM, AKASHI Takahiro wrote: >>>>> Currently, there is no easy way to add or modify UEFI variables. >>>>> In particular, bootmgr supports BootOrder/BootXXXX variables, it is >>>>> quite hard to define them as u-boot variables because they are represented >>>>> in a complicated and encoded format. >>>>> >>>>> The new command, efidebug, helps address these issues and give us >>>>> more friendly interfaces: >>>>> * efidebug boot add: add BootXXXX variable >>>>> * efidebug boot rm: remove BootXXXX variable >>>>> * efidebug boot dump: display all BootXXXX variables >>>>> * efidebug boot next: set BootNext variable >>>>> * efidebug boot order: set/display a boot order (BootOrder) >>>>> * efidebug setvar: set an UEFI variable (with limited functionality) >>>>> * efidebug dumpvar: display all UEFI variables >>>>> >>>>> Please note that the file, efidebug.c, will be compiled under >>>>> CONFIG_EFI_LOADER because some helper functions will be used >>>>> to enable "env -e" command in a later patch whether or not >>>>> the command is compiled in. >>>>> >>>>> Signed-off-by: AKASHI Takahiro <takahiro.akashi@linaro.org> >>>>> --- >>>>> MAINTAINERS | 1 + >>>>> cmd/Kconfig | 10 + >>>>> cmd/Makefile | 1 + >>>>> cmd/efidebug.c | 755 ++++++++++++++++++++++++++++++++++++++++++++++ >>>>> include/command.h | 6 + >>>>> 5 files changed, 773 insertions(+) >>>>> create mode 100644 cmd/efidebug.c >>>>> >>>>> diff --git a/MAINTAINERS b/MAINTAINERS >>>>> index ae825014bda9..301c5c69ea25 100644 >>>>> --- a/MAINTAINERS >>>>> +++ b/MAINTAINERS >>>>> @@ -438,6 +438,7 @@ F: lib/efi*/ >>>>> F: test/py/tests/test_efi* >>>>> F: test/unicode_ut.c >>>>> F: cmd/bootefi.c >>>>> +F: cmd/efidebug.c >>>>> F: tools/file2include.c >>>>> FPGA >>>>> diff --git a/cmd/Kconfig b/cmd/Kconfig >>>>> index ea1a325eb301..d9cab3cc0c49 100644 >>>>> --- a/cmd/Kconfig >>>>> +++ b/cmd/Kconfig >>>>> @@ -1397,6 +1397,16 @@ config CMD_DISPLAY >>>>> displayed on a simple board-specific display. Implement >>>>> display_putc() to use it. >>>>> +config CMD_EFIDEBUG >>>>> + bool "efidebug - display/customize UEFI environment" >>>>> + depends on EFI_LOADER >>>>> + default n >>>>> + help >>>>> + Enable the 'efidebug' command which provides a subset of UEFI >>>>> + shell utility with simplified functionality. It will be useful >>>>> + particularly for managing boot parameters as well as examining >>>>> + various EFI status for debugging. >>>>> + >>>>> config CMD_LED >>>>> bool "led" >>>>> default y if LED >>>>> diff --git a/cmd/Makefile b/cmd/Makefile >>>>> index 15ae4d250f50..e48d34c394ee 100644 >>>>> --- a/cmd/Makefile >>>>> +++ b/cmd/Makefile >>>>> @@ -51,6 +51,7 @@ obj-$(CONFIG_CMD_ECHO) += echo.o >>>>> obj-$(CONFIG_ENV_IS_IN_EEPROM) += eeprom.o >>>>> obj-$(CONFIG_CMD_EEPROM) += eeprom.o >>>>> obj-$(CONFIG_EFI_STUB) += efi.o >>>>> +obj-$(CONFIG_EFI_LOADER) += efidebug.o >>>>> obj-$(CONFIG_CMD_ELF) += elf.o >>>>> obj-$(CONFIG_HUSH_PARSER) += exit.o >>>>> obj-$(CONFIG_CMD_EXT4) += ext4.o >>>>> diff --git a/cmd/efidebug.c b/cmd/efidebug.c >>>>> new file mode 100644 >>>>> index 000000000000..c54fb6cfa101 >>>>> --- /dev/null >>>>> +++ b/cmd/efidebug.c >>>>> @@ -0,0 +1,755 @@ >>>>> +// SPDX-License-Identifier: GPL-2.0+ >>>>> +/* >>>>> + * UEFI Shell-like command >>>>> + * >>>>> + * Copyright (c) 2018 AKASHI Takahiro, Linaro Limited >>>>> + */ >>>>> + >>>>> +#include <charset.h> >>>>> +#include <common.h> >>>>> +#include <command.h> >>>>> +#include <efi_loader.h> >>>>> +#include <environment.h> >>>>> +#include <errno.h> >>>>> +#include <exports.h> >>>>> +#include <hexdump.h> >>>>> +#include <malloc.h> >>>>> +#include <search.h> >>>>> +#include <linux/ctype.h> >>>>> +#include <asm/global_data.h> >>>>> + >>>>> +static void dump_var_data(char *data, unsigned long len) >>>>> +{ >>>>> + char *start, *end, *p; >>>>> + unsigned long pos, count; >>>>> + char hex[3], line[9]; >>>>> + int i; >>>>> + >>>>> + end = data + len; >>>>> + for (start = data, pos = 0; start < end; start += count, pos += count) { >>>>> + count = end - start; >>>>> + if (count > 16) >>>>> + count = 16; >>>>> + >>>>> + /* count should be multiple of two */ >>>>> + printf("%08lx: ", pos); >>>>> + >>>>> + /* in hex format */ >>>>> + p = start; >>>>> + for (i = 0; i < count / 2; p += 2, i++) >>>>> + printf(" %c%c", *p, *(p + 1)); >>>>> + for (; i < 8; i++) >>>>> + printf(" "); >>>>> + >>>>> + /* in character format */ >>>>> + p = start; >>>>> + hex[2] = '\0'; >>>>> + for (i = 0; i < count / 2; i++) { >>>>> + hex[0] = *p++; >>>>> + hex[1] = *p++; >>>>> + line[i] = (char)simple_strtoul(hex, 0, 16); >>>>> + if (line[i] < 0x20 || line[i] > 0x7f) >>>>> + line[i] = '.'; >>>>> + } >>>>> + line[i] = '\0'; >>>>> + printf(" %s\n", line); >>>>> + } >>>>> +} >>>> Is this print_hex_dump() reimplemented? >>> Actually, no. >>> A UEFI variable on u-boot is encoded as ascii representation of binary data. >>> That means, for example, >>> >>> => env set -e PlatformLang en >>> => env print -e >>> PlatformLang: {boot,run}(blob) >>> 00000000: 65 6e en >>> => env print >>> ... >>> efi_8be4df61-93ca-11d2-aa0d-00e098032b8c_PlatformLang={boot,run}(blob)656e >>> ... >>> >>> the value of "PlatformLang" as a u-boot variable here is "656e", not "en." >>> So if we want to use print_hex_dump(), we first have to convert that >>> string to a binary. But then print_hex_dump() converts the binary to >>> a string. It's just rediculuous, isn't it? >> I actually think I would prefer that. This way we consolidate everything >> through a single API which means we then know that the results are >> always the same. If we implement parsing multiple times, there's a good >> chance we'll have a bug in one of them which gives us different results >> which then again makes debugging harder rather than easier. > Agree, but please note we have to add an apparently weird dependency of > CONFIG_HEXDUMP to EFI_LOADER as do_efi_dump_var_ext() needs to be compiled in > whether CMD_EFIDEBUG is enabled or not. You can just not print hex dumps of variables if CONFIG_HEXDUMP is not set? > >>> You might think that the value in this case should be >>> {boot, run}(utf8)en >>> ^^^^ >>> It's possible, but it depends on a variable and >>> currently my do_set_efi_var() doesn't support it anyway. >> One more reason to use only a single path to funnel things through :). >> >> So yes, can you maybe reuse RTS->get_variable() here? Same question on >> writing variables I suppose. > Well, we need GetNextVariableName API if we want to use GetVariable > (for listing). I have held off merging my another patch for this. > Is it time to do it? I thought that was in the tree now? Alex
On Wed, Jan 23, 2019 at 10:52:38AM +0100, Alexander Graf wrote: > On 01/23/2019 05:47 AM, AKASHI Takahiro wrote: > >On Tue, Jan 22, 2019 at 10:18:58AM +0100, Alexander Graf wrote: > >> > >>On 22.01.19 02:02, AKASHI Takahiro wrote: > >>>Alex, > >>> > >>>On Mon, Jan 21, 2019 at 02:07:31PM +0100, Alexander Graf wrote: > >>>>On 01/21/2019 08:49 AM, AKASHI Takahiro wrote: > >>>>>Currently, there is no easy way to add or modify UEFI variables. > >>>>>In particular, bootmgr supports BootOrder/BootXXXX variables, it is > >>>>>quite hard to define them as u-boot variables because they are represented > >>>>>in a complicated and encoded format. > >>>>> > >>>>>The new command, efidebug, helps address these issues and give us > >>>>>more friendly interfaces: > >>>>> * efidebug boot add: add BootXXXX variable > >>>>> * efidebug boot rm: remove BootXXXX variable > >>>>> * efidebug boot dump: display all BootXXXX variables > >>>>> * efidebug boot next: set BootNext variable > >>>>> * efidebug boot order: set/display a boot order (BootOrder) > >>>>> * efidebug setvar: set an UEFI variable (with limited functionality) > >>>>> * efidebug dumpvar: display all UEFI variables > >>>>> > >>>>>Please note that the file, efidebug.c, will be compiled under > >>>>>CONFIG_EFI_LOADER because some helper functions will be used > >>>>>to enable "env -e" command in a later patch whether or not > >>>>>the command is compiled in. > >>>>> > >>>>>Signed-off-by: AKASHI Takahiro <takahiro.akashi@linaro.org> > >>>>>--- > >>>>> MAINTAINERS | 1 + > >>>>> cmd/Kconfig | 10 + > >>>>> cmd/Makefile | 1 + > >>>>> cmd/efidebug.c | 755 ++++++++++++++++++++++++++++++++++++++++++++++ > >>>>> include/command.h | 6 + > >>>>> 5 files changed, 773 insertions(+) > >>>>> create mode 100644 cmd/efidebug.c > >>>>> > >>>>>diff --git a/MAINTAINERS b/MAINTAINERS > >>>>>index ae825014bda9..301c5c69ea25 100644 > >>>>>--- a/MAINTAINERS > >>>>>+++ b/MAINTAINERS > >>>>>@@ -438,6 +438,7 @@ F: lib/efi*/ > >>>>> F: test/py/tests/test_efi* > >>>>> F: test/unicode_ut.c > >>>>> F: cmd/bootefi.c > >>>>>+F: cmd/efidebug.c > >>>>> F: tools/file2include.c > >>>>> FPGA > >>>>>diff --git a/cmd/Kconfig b/cmd/Kconfig > >>>>>index ea1a325eb301..d9cab3cc0c49 100644 > >>>>>--- a/cmd/Kconfig > >>>>>+++ b/cmd/Kconfig > >>>>>@@ -1397,6 +1397,16 @@ config CMD_DISPLAY > >>>>> displayed on a simple board-specific display. Implement > >>>>> display_putc() to use it. > >>>>>+config CMD_EFIDEBUG > >>>>>+ bool "efidebug - display/customize UEFI environment" > >>>>>+ depends on EFI_LOADER > >>>>>+ default n > >>>>>+ help > >>>>>+ Enable the 'efidebug' command which provides a subset of UEFI > >>>>>+ shell utility with simplified functionality. It will be useful > >>>>>+ particularly for managing boot parameters as well as examining > >>>>>+ various EFI status for debugging. > >>>>>+ > >>>>> config CMD_LED > >>>>> bool "led" > >>>>> default y if LED > >>>>>diff --git a/cmd/Makefile b/cmd/Makefile > >>>>>index 15ae4d250f50..e48d34c394ee 100644 > >>>>>--- a/cmd/Makefile > >>>>>+++ b/cmd/Makefile > >>>>>@@ -51,6 +51,7 @@ obj-$(CONFIG_CMD_ECHO) += echo.o > >>>>> obj-$(CONFIG_ENV_IS_IN_EEPROM) += eeprom.o > >>>>> obj-$(CONFIG_CMD_EEPROM) += eeprom.o > >>>>> obj-$(CONFIG_EFI_STUB) += efi.o > >>>>>+obj-$(CONFIG_EFI_LOADER) += efidebug.o > >>>>> obj-$(CONFIG_CMD_ELF) += elf.o > >>>>> obj-$(CONFIG_HUSH_PARSER) += exit.o > >>>>> obj-$(CONFIG_CMD_EXT4) += ext4.o > >>>>>diff --git a/cmd/efidebug.c b/cmd/efidebug.c > >>>>>new file mode 100644 > >>>>>index 000000000000..c54fb6cfa101 > >>>>>--- /dev/null > >>>>>+++ b/cmd/efidebug.c > >>>>>@@ -0,0 +1,755 @@ > >>>>>+// SPDX-License-Identifier: GPL-2.0+ > >>>>>+/* > >>>>>+ * UEFI Shell-like command > >>>>>+ * > >>>>>+ * Copyright (c) 2018 AKASHI Takahiro, Linaro Limited > >>>>>+ */ > >>>>>+ > >>>>>+#include <charset.h> > >>>>>+#include <common.h> > >>>>>+#include <command.h> > >>>>>+#include <efi_loader.h> > >>>>>+#include <environment.h> > >>>>>+#include <errno.h> > >>>>>+#include <exports.h> > >>>>>+#include <hexdump.h> > >>>>>+#include <malloc.h> > >>>>>+#include <search.h> > >>>>>+#include <linux/ctype.h> > >>>>>+#include <asm/global_data.h> > >>>>>+ > >>>>>+static void dump_var_data(char *data, unsigned long len) > >>>>>+{ > >>>>>+ char *start, *end, *p; > >>>>>+ unsigned long pos, count; > >>>>>+ char hex[3], line[9]; > >>>>>+ int i; > >>>>>+ > >>>>>+ end = data + len; > >>>>>+ for (start = data, pos = 0; start < end; start += count, pos += count) { > >>>>>+ count = end - start; > >>>>>+ if (count > 16) > >>>>>+ count = 16; > >>>>>+ > >>>>>+ /* count should be multiple of two */ > >>>>>+ printf("%08lx: ", pos); > >>>>>+ > >>>>>+ /* in hex format */ > >>>>>+ p = start; > >>>>>+ for (i = 0; i < count / 2; p += 2, i++) > >>>>>+ printf(" %c%c", *p, *(p + 1)); > >>>>>+ for (; i < 8; i++) > >>>>>+ printf(" "); > >>>>>+ > >>>>>+ /* in character format */ > >>>>>+ p = start; > >>>>>+ hex[2] = '\0'; > >>>>>+ for (i = 0; i < count / 2; i++) { > >>>>>+ hex[0] = *p++; > >>>>>+ hex[1] = *p++; > >>>>>+ line[i] = (char)simple_strtoul(hex, 0, 16); > >>>>>+ if (line[i] < 0x20 || line[i] > 0x7f) > >>>>>+ line[i] = '.'; > >>>>>+ } > >>>>>+ line[i] = '\0'; > >>>>>+ printf(" %s\n", line); > >>>>>+ } > >>>>>+} > >>>>Is this print_hex_dump() reimplemented? > >>>Actually, no. > >>>A UEFI variable on u-boot is encoded as ascii representation of binary data. > >>>That means, for example, > >>> > >>> => env set -e PlatformLang en > >>> => env print -e > >>> PlatformLang: {boot,run}(blob) > >>> 00000000: 65 6e en > >>> => env print > >>> ... > >>> efi_8be4df61-93ca-11d2-aa0d-00e098032b8c_PlatformLang={boot,run}(blob)656e > >>> ... > >>> > >>>the value of "PlatformLang" as a u-boot variable here is "656e", not "en." > >>>So if we want to use print_hex_dump(), we first have to convert that > >>>string to a binary. But then print_hex_dump() converts the binary to > >>>a string. It's just rediculuous, isn't it? > >>I actually think I would prefer that. This way we consolidate everything > >>through a single API which means we then know that the results are > >>always the same. If we implement parsing multiple times, there's a good > >>chance we'll have a bug in one of them which gives us different results > >>which then again makes debugging harder rather than easier. > >Agree, but please note we have to add an apparently weird dependency of > >CONFIG_HEXDUMP to EFI_LOADER as do_efi_dump_var_ext() needs to be compiled in > >whether CMD_EFIDEBUG is enabled or not. > > You can just not print hex dumps of variables if CONFIG_HEXDUMP is not set? Yes, print_hex_dump() just prints nothing if !CONFIG_HEXDUMP. Adding "imply HEXDUMP" would be enough. > > > >>>You might think that the value in this case should be > >>> {boot, run}(utf8)en > >>> ^^^^ > >>>It's possible, but it depends on a variable and > >>>currently my do_set_efi_var() doesn't support it anyway. > >>One more reason to use only a single path to funnel things through :). > >> > >>So yes, can you maybe reuse RTS->get_variable() here? Same question on > >>writing variables I suppose. > >Well, we need GetNextVariableName API if we want to use GetVariable > >(for listing). I have held off merging my another patch for this. > >Is it time to do it? > > I thought that was in the tree now? Not GetNextVariableName patch itself, but a patch of modifying do_efi_dump_var() using GetNextVariableName. -Takahiro Akashi > > Alex >
diff --git a/MAINTAINERS b/MAINTAINERS index ae825014bda9..301c5c69ea25 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -438,6 +438,7 @@ F: lib/efi*/ F: test/py/tests/test_efi* F: test/unicode_ut.c F: cmd/bootefi.c +F: cmd/efidebug.c F: tools/file2include.c FPGA diff --git a/cmd/Kconfig b/cmd/Kconfig index ea1a325eb301..d9cab3cc0c49 100644 --- a/cmd/Kconfig +++ b/cmd/Kconfig @@ -1397,6 +1397,16 @@ config CMD_DISPLAY displayed on a simple board-specific display. Implement display_putc() to use it. +config CMD_EFIDEBUG + bool "efidebug - display/customize UEFI environment" + depends on EFI_LOADER + default n + help + Enable the 'efidebug' command which provides a subset of UEFI + shell utility with simplified functionality. It will be useful + particularly for managing boot parameters as well as examining + various EFI status for debugging. + config CMD_LED bool "led" default y if LED diff --git a/cmd/Makefile b/cmd/Makefile index 15ae4d250f50..e48d34c394ee 100644 --- a/cmd/Makefile +++ b/cmd/Makefile @@ -51,6 +51,7 @@ obj-$(CONFIG_CMD_ECHO) += echo.o obj-$(CONFIG_ENV_IS_IN_EEPROM) += eeprom.o obj-$(CONFIG_CMD_EEPROM) += eeprom.o obj-$(CONFIG_EFI_STUB) += efi.o +obj-$(CONFIG_EFI_LOADER) += efidebug.o obj-$(CONFIG_CMD_ELF) += elf.o obj-$(CONFIG_HUSH_PARSER) += exit.o obj-$(CONFIG_CMD_EXT4) += ext4.o diff --git a/cmd/efidebug.c b/cmd/efidebug.c new file mode 100644 index 000000000000..c54fb6cfa101 --- /dev/null +++ b/cmd/efidebug.c @@ -0,0 +1,755 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * UEFI Shell-like command + * + * Copyright (c) 2018 AKASHI Takahiro, Linaro Limited + */ + +#include <charset.h> +#include <common.h> +#include <command.h> +#include <efi_loader.h> +#include <environment.h> +#include <errno.h> +#include <exports.h> +#include <hexdump.h> +#include <malloc.h> +#include <search.h> +#include <linux/ctype.h> +#include <asm/global_data.h> + +static void dump_var_data(char *data, unsigned long len) +{ + char *start, *end, *p; + unsigned long pos, count; + char hex[3], line[9]; + int i; + + end = data + len; + for (start = data, pos = 0; start < end; start += count, pos += count) { + count = end - start; + if (count > 16) + count = 16; + + /* count should be multiple of two */ + printf("%08lx: ", pos); + + /* in hex format */ + p = start; + for (i = 0; i < count / 2; p += 2, i++) + printf(" %c%c", *p, *(p + 1)); + for (; i < 8; i++) + printf(" "); + + /* in character format */ + p = start; + hex[2] = '\0'; + for (i = 0; i < count / 2; i++) { + hex[0] = *p++; + hex[1] = *p++; + line[i] = (char)simple_strtoul(hex, 0, 16); + if (line[i] < 0x20 || line[i] > 0x7f) + line[i] = '.'; + } + line[i] = '\0'; + printf(" %s\n", line); + } +} + +/* + * From efi_variable.c, + * + * Mapping between UEFI variables and u-boot variables: + * + * efi_$guid_$varname = {attributes}(type)value + */ +static int do_efi_dump_var(cmd_tbl_t *cmdtp, int flag, + int argc, char * const argv[]) +{ + char regex[256]; + char * const regexlist[] = {regex}; + char *res = NULL, *start, *end; + int len; + + if (argc > 2) + return CMD_RET_USAGE; + + if (argc == 2) + snprintf(regex, 256, "efi_.*-.*-.*-.*-.*_%s", argv[1]); + else + snprintf(regex, 256, "efi_.*-.*-.*-.*-.*_.*"); + debug("%s:%d grep uefi var %s\n", __func__, __LINE__, regex); + + len = hexport_r(&env_htab, '\n', H_MATCH_REGEX | H_MATCH_KEY, + &res, 0, 1, regexlist); + + if (len < 0) + return CMD_RET_FAILURE; + + if (len > 0) { + end = res; + while (true) { + /* variable name */ + start = strchr(end, '_'); + if (!start) + break; + start = strchr(++start, '_'); + if (!start) + break; + end = strchr(++start, '='); + if (!end) + break; + printf("%.*s:", (int)(end - start), start); + end++; + + /* value */ + start = end; + end = strstr(start, "(blob)"); + if (!end) { + putc('\n'); + break; + } + end += 6; + printf(" %.*s\n", (int)(end - start), start); + + start = end; + end = strchr(start, '\n'); + if (!end) + break; + dump_var_data(start, end - start); + } + free(res); + + if (len < 2 && argc == 2) + printf("%s: not found\n", argv[1]); + } + + return CMD_RET_SUCCESS; +} + +int do_efi_dump_var_ext(cmd_tbl_t *cmdtp, int flag, + int argc, char * const argv[]) +{ + efi_status_t r; + + /* Initialize EFI drivers */ + r = efi_init_obj_list(); + if (r != EFI_SUCCESS) { + printf("Error: Cannot initialize UEFI sub-system, r = %lu\n", + r & ~EFI_ERROR_MASK); + return CMD_RET_FAILURE; + } + + return do_efi_dump_var(cmdtp, flag, argc, argv); +} + +static int append_value(char **bufp, unsigned long *sizep, char *data) +{ + char *tmp_buf = NULL, *new_buf = NULL, *value; + unsigned long len = 0; + + if (!strncmp(data, "=0x", 2)) { /* hexadecimal number */ + union { + u8 u8; + u16 u16; + u32 u32; + u64 u64; + } tmp_data; + unsigned long hex_value; + void *hex_ptr; + + data += 3; + len = strlen(data); + if ((len & 0x1)) /* not multiple of two */ + return -1; + + len /= 2; + if (len > 8) + return -1; + else if (len > 4) + len = 8; + else if (len > 2) + len = 4; + + /* convert hex hexadecimal number */ + if (strict_strtoul(data, 16, &hex_value) < 0) + return -1; + + tmp_buf = malloc(len); + if (!tmp_buf) + return -1; + + if (len == 1) { + tmp_data.u8 = hex_value; + hex_ptr = &tmp_data.u8; + } else if (len == 2) { + tmp_data.u16 = hex_value; + hex_ptr = &tmp_data.u16; + } else if (len == 4) { + tmp_data.u32 = hex_value; + hex_ptr = &tmp_data.u32; + } else { + tmp_data.u64 = hex_value; + hex_ptr = &tmp_data.u64; + } + memcpy(tmp_buf, hex_ptr, len); + value = tmp_buf; + + } else if (!strncmp(data, "=H", 2)) { /* hexadecimal-byte array */ + data += 2; + len = strlen(data); + if (len & 0x1) /* not multiple of two */ + return -1; + + len /= 2; + tmp_buf = malloc(len); + if (!tmp_buf) + return -1; + + if (hex2bin((u8 *)tmp_buf, data, len) < 0) + return -1; + + value = tmp_buf; + } else { /* string */ + if (!strncmp(data, "=\"", 2) || !strncmp(data, "=S\"", 3)) { + if (data[1] == '"') + data += 2; + else + data += 3; + value = data; + len = strlen(data) - 1; + if (data[len] != '"') + return -1; + } else { + value = data; + len = strlen(data); + } + } + + new_buf = realloc(*bufp, *sizep + len); + if (!new_buf) + goto out; + + memcpy(new_buf + *sizep, value, len); + *bufp = new_buf; + *sizep += len; + +out: + free(tmp_buf); + + return 0; +} + +static int do_efi_set_var(cmd_tbl_t *cmdtp, int flag, + int argc, char * const argv[]) +{ + char *var_name, *value = NULL; + efi_uintn_t size = 0; + u16 *var_name16 = NULL, *p; + efi_guid_t guid; + efi_status_t ret; + + if (argc == 1) + return CMD_RET_SUCCESS; + + var_name = argv[1]; + if (argc == 2) { + /* remove */ + value = NULL; + size = 0; + } else { /* set */ + argc -= 2; + argv += 2; + + for ( ; argc > 0; argc--, argv++) + if (append_value(&value, &size, argv[0]) < 0) { + ret = CMD_RET_FAILURE; + goto out; + } + } + + var_name16 = malloc((strlen(var_name) + 1) * 2); + p = var_name16; + utf8_utf16_strncpy(&p, var_name, strlen(var_name) + 1); + + guid = efi_global_variable_guid; + ret = efi_set_variable(var_name16, &guid, + EFI_VARIABLE_BOOTSERVICE_ACCESS | + EFI_VARIABLE_RUNTIME_ACCESS, size, value); + ret = (ret == EFI_SUCCESS ? CMD_RET_SUCCESS : CMD_RET_FAILURE); +out: + free(value); + free(var_name16); + + return ret; +} + +int do_efi_set_var_ext(cmd_tbl_t *cmdtp, int flag, + int argc, char * const argv[]) +{ + efi_status_t r; + + /* Initialize EFI drivers */ + r = efi_init_obj_list(); + if (r != EFI_SUCCESS) { + printf("Error: Cannot initialize UEFI sub-system, r = %lu\n", + r & ~EFI_ERROR_MASK); + return CMD_RET_FAILURE; + } + + return do_efi_set_var(cmdtp, flag, argc, argv); +} + +#ifdef CONFIG_CMD_EFIDEBUG +static int do_efi_boot_add(cmd_tbl_t *cmdtp, int flag, + int argc, char * const argv[]) +{ + int id; + char *endp; + char var_name[9]; + u16 var_name16[9], *p; + efi_guid_t guid; + size_t label_len, label_len16; + u16 *label; + struct efi_device_path *device_path = NULL, *file_path = NULL; + struct efi_load_option lo; + void *data = NULL; + efi_uintn_t size; + int ret; + + if (argc < 6 || argc > 7) + return CMD_RET_USAGE; + + id = (int)simple_strtoul(argv[1], &endp, 16); + if (*endp != '\0' || id > 0xffff) + return CMD_RET_FAILURE; + + sprintf(var_name, "Boot%04X", id); + p = var_name16; + utf8_utf16_strncpy(&p, var_name, 9); + + guid = efi_global_variable_guid; + + /* attributes */ + lo.attributes = 0x1; /* always ACTIVE */ + + /* label */ + label_len = strlen(argv[2]); + label_len16 = utf8_utf16_strnlen(argv[2], label_len); + label = malloc((label_len16 + 1) * sizeof(u16)); + if (!label) + return CMD_RET_FAILURE; + lo.label = label; /* label will be changed below */ + utf8_utf16_strncpy(&label, argv[2], label_len); + + /* file path */ + ret = efi_dp_from_name(argv[3], argv[4], argv[5], &device_path, + &file_path); + if (ret != EFI_SUCCESS) { + ret = CMD_RET_FAILURE; + goto out; + } + lo.file_path = file_path; + lo.file_path_length = efi_dp_size(file_path) + + sizeof(struct efi_device_path); /* for END */ + + /* optional data */ + lo.optional_data = (u8 *)(argc == 6 ? "" : argv[6]); + + size = efi_serialize_load_option(&lo, (u8 **)&data); + if (!size) { + ret = CMD_RET_FAILURE; + goto out; + } + + ret = efi_set_variable(var_name16, &guid, + EFI_VARIABLE_BOOTSERVICE_ACCESS | + EFI_VARIABLE_RUNTIME_ACCESS, size, data); + ret = (ret == EFI_SUCCESS ? CMD_RET_SUCCESS : CMD_RET_FAILURE); +out: + free(data); + efi_free_pool(device_path); + efi_free_pool(file_path); + free(lo.label); + + return ret; +} + +static int do_efi_boot_rm(cmd_tbl_t *cmdtp, int flag, + int argc, char * const argv[]) +{ + efi_guid_t guid; + int id, i; + char *endp; + char var_name[9]; + u16 var_name16[9]; + efi_status_t ret; + + if (argc == 1) + return CMD_RET_USAGE; + + guid = efi_global_variable_guid; + for (i = 1; i < argc; i++, argv++) { + id = (int)simple_strtoul(argv[1], &endp, 16); + if (*endp != '\0' || id > 0xffff) + return CMD_RET_FAILURE; + + sprintf(var_name, "Boot%04X", id); + utf8_utf16_strncpy((u16 **)&var_name16, var_name, 9); + + ret = efi_set_variable(var_name16, &guid, 0, 0, NULL); + if (ret) { + printf("cannot remove Boot%04X", id); + return CMD_RET_FAILURE; + } + } + + return CMD_RET_SUCCESS; +} + +static void show_efi_boot_opt_data(int id, void *data) +{ + struct efi_load_option lo; + char *label, *p; + size_t label_len16, label_len; + u16 *dp_str; + + efi_deserialize_load_option(&lo, data); + + label_len16 = u16_strlen(lo.label); + label_len = utf16_utf8_strnlen(lo.label, label_len16); + label = malloc(label_len + 1); + if (!label) + return; + p = label; + utf16_utf8_strncpy(&p, lo.label, label_len16); + + printf("Boot%04X:\n", id); + printf("\tattributes: %c%c%c (0x%08x)\n", + /* ACTIVE */ + lo.attributes & 0x1 ? 'A' : '-', + /* FORCE RECONNECT */ + lo.attributes & 0x2 ? 'R' : '-', + /* HIDDEN */ + lo.attributes & 0x8 ? 'H' : '-', + lo.attributes); + printf("\tlabel: %s\n", label); + + dp_str = efi_dp_str(lo.file_path); + printf("\tfile_path: %ls\n", dp_str); + efi_free_pool(dp_str); + + printf("\tdata: %s\n", lo.optional_data); + + free(label); +} + +static void show_efi_boot_opt(int id) +{ + char var_name[9]; + u16 var_name16[9], *p; + efi_guid_t guid; + void *data = NULL; + efi_uintn_t size; + int ret; + + sprintf(var_name, "Boot%04X", id); + p = var_name16; + utf8_utf16_strncpy(&p, var_name, 9); + guid = efi_global_variable_guid; + + size = 0; + ret = efi_get_variable(var_name16, &guid, NULL, &size, NULL); + if (ret == (int)EFI_BUFFER_TOO_SMALL) { + data = malloc(size); + ret = efi_get_variable(var_name16, &guid, NULL, &size, data); + } + if (ret == EFI_SUCCESS) + show_efi_boot_opt_data(id, data); + else if (ret == EFI_NOT_FOUND) + printf("Boot%04X: not found\n", id); + + free(data); +} + +static int do_efi_boot_dump(cmd_tbl_t *cmdtp, int flag, + int argc, char * const argv[]) +{ + char regex[256]; + char * const regexlist[] = {regex}; + char *variables = NULL, *boot, *value; + int len; + int id; + + if (argc > 1) + return CMD_RET_USAGE; + + snprintf(regex, 256, "efi_.*-.*-.*-.*-.*_Boot[0-9A-F]+"); + + len = hexport_r(&env_htab, '\n', H_MATCH_REGEX | H_MATCH_KEY, + &variables, 0, 1, regexlist); + + if (!len) + return CMD_RET_SUCCESS; + + if (len < 0) + return CMD_RET_FAILURE; + + boot = variables; + while (*boot) { + value = strstr(boot, "Boot") + 4; + id = (int)simple_strtoul(value, NULL, 16); + show_efi_boot_opt(id); + boot = strchr(boot, '\n'); + if (!*boot) + break; + boot++; + } + free(variables); + + return CMD_RET_SUCCESS; +} + +static int show_efi_boot_order(void) +{ + efi_guid_t guid; + u16 *bootorder = NULL; + efi_uintn_t size; + int num, i; + char var_name[9]; + u16 var_name16[9], *p16; + void *data; + struct efi_load_option lo; + char *label, *p; + size_t label_len16, label_len; + efi_status_t ret; + + guid = efi_global_variable_guid; + size = 0; + ret = efi_get_variable(L"BootOrder", &guid, NULL, &size, NULL); + if (ret == EFI_BUFFER_TOO_SMALL) { + bootorder = malloc(size); + ret = efi_get_variable(L"BootOrder", &guid, NULL, &size, + bootorder); + } + if (ret == EFI_NOT_FOUND) { + printf("BootOrder not defined\n"); + ret = CMD_RET_SUCCESS; + goto out; + } else if (ret != EFI_SUCCESS) { + ret = CMD_RET_FAILURE; + goto out; + } + + num = size / sizeof(u16); + for (i = 0; i < num; i++) { + sprintf(var_name, "Boot%04X", bootorder[i]); + p16 = var_name16; + utf8_utf16_strncpy(&p16, var_name, 9); + + size = 0; + ret = efi_get_variable(var_name16, &guid, NULL, &size, NULL); + if (ret != EFI_BUFFER_TOO_SMALL) { + printf("%2d: Boot%04X: (not defined)\n", + i + 1, bootorder[i]); + continue; + } + + data = malloc(size); + if (!data) { + ret = CMD_RET_FAILURE; + goto out; + } + ret = efi_get_variable(var_name16, &guid, NULL, &size, data); + if (ret != EFI_SUCCESS) { + free(data); + ret = CMD_RET_FAILURE; + goto out; + } + + efi_deserialize_load_option(&lo, data); + + label_len16 = u16_strlen(lo.label); + label_len = utf16_utf8_strnlen(lo.label, label_len16); + label = malloc(label_len + 1); + if (!label) { + free(data); + ret = CMD_RET_FAILURE; + goto out; + } + p = label; + utf16_utf8_strncpy(&p, lo.label, label_len16); + printf("%2d: Boot%04X: %s\n", i + 1, bootorder[i], label); + free(label); + + free(data); + } +out: + free(bootorder); + + return ret; +} + +static int do_efi_boot_next(cmd_tbl_t *cmdtp, int flag, + int argc, char * const argv[]) +{ + u16 bootnext; + efi_uintn_t size; + char *endp; + efi_guid_t guid; + efi_status_t ret; + + if (argc != 2) + return CMD_RET_USAGE; + + bootnext = (u16)simple_strtoul(argv[1], &endp, 16); + if (*endp != '\0' || bootnext > 0xffff) { + printf("invalid value: %s\n", argv[1]); + ret = CMD_RET_FAILURE; + goto out; + } + + guid = efi_global_variable_guid; + size = sizeof(u16); + ret = efi_set_variable(L"BootNext", &guid, + EFI_VARIABLE_BOOTSERVICE_ACCESS | + EFI_VARIABLE_RUNTIME_ACCESS, size, &bootnext); + ret = (ret == EFI_SUCCESS ? CMD_RET_SUCCESS : CMD_RET_FAILURE); +out: + return ret; +} + +static int do_efi_boot_order(cmd_tbl_t *cmdtp, int flag, + int argc, char * const argv[]) +{ + u16 *bootorder = NULL; + efi_uintn_t size; + int id, i; + char *endp; + efi_guid_t guid; + efi_status_t ret; + + if (argc == 1) + return show_efi_boot_order(); + + argc--; + argv++; + + size = argc * sizeof(u16); + bootorder = malloc(size); + if (!bootorder) + return CMD_RET_FAILURE; + + for (i = 0; i < argc; i++) { + id = (int)simple_strtoul(argv[i], &endp, 16); + if (*endp != '\0' || id > 0xffff) { + printf("invalid value: %s\n", argv[i]); + ret = CMD_RET_FAILURE; + goto out; + } + + bootorder[i] = (u16)id; + } + + guid = efi_global_variable_guid; + ret = efi_set_variable(L"BootOrder", &guid, + EFI_VARIABLE_BOOTSERVICE_ACCESS | + EFI_VARIABLE_RUNTIME_ACCESS, size, bootorder); + ret = (ret == EFI_SUCCESS ? CMD_RET_SUCCESS : CMD_RET_FAILURE); +out: + free(bootorder); + + return ret; +} + +static cmd_tbl_t cmd_efidebug_boot_sub[] = { + U_BOOT_CMD_MKENT(add, CONFIG_SYS_MAXARGS, 1, do_efi_boot_add, "", ""), + U_BOOT_CMD_MKENT(rm, CONFIG_SYS_MAXARGS, 1, do_efi_boot_rm, "", ""), + U_BOOT_CMD_MKENT(dump, CONFIG_SYS_MAXARGS, 1, do_efi_boot_dump, "", ""), + U_BOOT_CMD_MKENT(next, CONFIG_SYS_MAXARGS, 1, do_efi_boot_next, "", ""), + U_BOOT_CMD_MKENT(order, CONFIG_SYS_MAXARGS, 1, do_efi_boot_order, + "", ""), +}; + +static int do_efi_boot_opt(cmd_tbl_t *cmdtp, int flag, + int argc, char * const argv[]) +{ + cmd_tbl_t *cp; + + if (argc < 2) + return CMD_RET_USAGE; + + argc--; argv++; + + cp = find_cmd_tbl(argv[0], cmd_efidebug_boot_sub, + ARRAY_SIZE(cmd_efidebug_boot_sub)); + if (!cp) + return CMD_RET_USAGE; + + return cp->cmd(cmdtp, flag, argc, argv); +} + +static cmd_tbl_t cmd_efidebug_sub[] = { + U_BOOT_CMD_MKENT(boot, CONFIG_SYS_MAXARGS, 1, do_efi_boot_opt, "", ""), + U_BOOT_CMD_MKENT(dumpvar, CONFIG_SYS_MAXARGS, 1, do_efi_dump_var, + "", ""), + U_BOOT_CMD_MKENT(setvar, CONFIG_SYS_MAXARGS, 1, do_efi_set_var, "", ""), +}; + +/* Interpreter command to configure UEFI environment */ +static int do_efidebug(cmd_tbl_t *cmdtp, int flag, + int argc, char * const argv[]) +{ + cmd_tbl_t *cp; + efi_status_t r; + + if (argc < 2) + return CMD_RET_USAGE; + + argc--; argv++; + + /* Initialize UEFI drivers */ + r = efi_init_obj_list(); + if (r != EFI_SUCCESS) { + printf("Error: Cannot initialize UEFI sub-system, r = %lu\n", + r & ~EFI_ERROR_MASK); + return CMD_RET_FAILURE; + } + + cp = find_cmd_tbl(argv[0], cmd_efidebug_sub, + ARRAY_SIZE(cmd_efidebug_sub)); + if (!cp) + return CMD_RET_USAGE; + + return cp->cmd(cmdtp, flag, argc, argv); +} + +#ifdef CONFIG_SYS_LONGHELP +static char efidebug_help_text[] = + " - UEFI Shell-like interface to configure UEFI environment\n" + "\n" + "efidebug boot add <bootid> <label> <interface> <device>[:<part>] <file path> [<load options>]\n" + " - set UEFI BootXXXX variable\n" + " <load options> will be passed to UEFI application\n" + "efidebug boot rm <bootid#1> [<bootid#2> [<bootid#3> [...]]]\n" + " - delete UEFI BootXXXX variables\n" + "efidebug boot dump\n" + " - show all UEFI BootXXXX variables\n" + "efidebug boot next <bootid>\n" + " - set UEFI BootNext variable\n" + "efidebug boot order [<bootid#1> [<bootid#2> [<bootid#3> [...]]]]\n" + " - set/show UEFI boot order\n" + "\n" + "efidebug dumpvar [<name>]\n" + " - show UEFI variable's value\n" + "efidebug setvar <name> [<value>]\n" + " - set/delete uefi variable's value\n" + " <value> may be \"=\"...\"\", \"=0x...\", \"=H...\", (set) or \"=\" (delete)\n"; +#endif + +U_BOOT_CMD( + efidebug, 10, 0, do_efidebug, + "Configure UEFI environment", + efidebug_help_text +); +#endif /* CONFIG_CMD_EFIDEBUG */ diff --git a/include/command.h b/include/command.h index feddef300ccc..7210d1769a63 100644 --- a/include/command.h +++ b/include/command.h @@ -51,6 +51,12 @@ extern int do_run(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]); #if defined(CONFIG_CMD_BOOTEFI) extern int do_bootefi_run(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]); #endif +#if defined(CONFIG_EFI_LOADER) +int do_efi_dump_var_ext(cmd_tbl_t *cmdtp, int flag, + int argc, char * const argv[]); +int do_efi_set_var_ext(cmd_tbl_t *cmdtp, int flag, + int argc, char * const argv[]); +#endif /* common/command.c */ int _do_help (cmd_tbl_t *cmd_start, int cmd_items, cmd_tbl_t * cmdtp, int
Currently, there is no easy way to add or modify UEFI variables. In particular, bootmgr supports BootOrder/BootXXXX variables, it is quite hard to define them as u-boot variables because they are represented in a complicated and encoded format. The new command, efidebug, helps address these issues and give us more friendly interfaces: * efidebug boot add: add BootXXXX variable * efidebug boot rm: remove BootXXXX variable * efidebug boot dump: display all BootXXXX variables * efidebug boot next: set BootNext variable * efidebug boot order: set/display a boot order (BootOrder) * efidebug setvar: set an UEFI variable (with limited functionality) * efidebug dumpvar: display all UEFI variables Please note that the file, efidebug.c, will be compiled under CONFIG_EFI_LOADER because some helper functions will be used to enable "env -e" command in a later patch whether or not the command is compiled in. Signed-off-by: AKASHI Takahiro <takahiro.akashi@linaro.org> --- MAINTAINERS | 1 + cmd/Kconfig | 10 + cmd/Makefile | 1 + cmd/efidebug.c | 755 ++++++++++++++++++++++++++++++++++++++++++++++ include/command.h | 6 + 5 files changed, 773 insertions(+) create mode 100644 cmd/efidebug.c