From 814a7eea80f6183cede88a7568f8e382c1523a74 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Fri, 25 Mar 2022 07:01:59 +0100 Subject: [PATCH 1/6] doc: man-page for the wdt command Describe the wdt command. Signed-off-by: Heinrich Schuchardt --- doc/usage/index.rst | 1 + doc/usage/wdt.rst | 77 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 78 insertions(+) create mode 100644 doc/usage/wdt.rst diff --git a/doc/usage/index.rst b/doc/usage/index.rst index 0aacf531b22..630a6cb28ab 100644 --- a/doc/usage/index.rst +++ b/doc/usage/index.rst @@ -52,3 +52,4 @@ Shell commands size true ums + wdt diff --git a/doc/usage/wdt.rst b/doc/usage/wdt.rst new file mode 100644 index 00000000000..8d80433c1fa --- /dev/null +++ b/doc/usage/wdt.rst @@ -0,0 +1,77 @@ +.. SPDX-License-Identifier: GPL-2.0+: + +wdt command +============ + +Synopsis +-------- + +:: + + wdt list + wdt dev [] + wdt start [flags] + wdt stop + wdt reset + wdt expirer [flags] + +Description +----------- + +The wdt command is used to control watchdog timers. + +The 'wdt list' command shows a list of all watchdog devices. + +The 'wdt dev' command called without argument shows the current watchdog device. +The current device is set when passing the name of the device as argument. + +The 'wdt start' command starts the current watchdog timer. + +The 'wdt stop' command stops the current watchdog timer. + +The 'wdt reset' command resets the current watchdog timer without stopping it. + +The 'wdt expire' command let's the current watchdog timer expire immediately. +This will lead to a reset. + +name + name of the watchdog device + +timeout_ms + timeout interval in milliseconds + +flags + unsigned long value passed to the driver. The usage is driver specific. + The value is ignored by most drivers. + +Example +------- + +:: + + => wdt dev + No watchdog timer device set! + => wdt list + watchdog@1c20ca0 (sunxi_wdt) + => wdt dev watchdog@1c20ca0 + => wdt dev + dev: watchdog@1c20ca0 + => wdt start 3000 + => wdt reset + => wdt stop + => wdt expire + + U-Boot SPL 2022.04-rc3 (Mar 25 2022 - 13:48:33 +0000) + + In the example above '(sunxi_wdt)' refers to the driver for the watchdog + device. + +Configuration +------------- + +The command is only available if CONFIG_CMD_WDT=y. + +Return value +------------ + +The return value $? is 0 if the command succeeds, 1 upon failure. From df96deeed6a9b34e76544ebe9b0fdd2e44ceb6cd Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Mon, 21 Mar 2022 08:26:48 +0100 Subject: [PATCH 2/6] efi_loader: typo devie-path %s/devie-path/device-path/ Reported-by: Ilias Apalodimas Signed-off-by: Heinrich Schuchardt --- lib/efi_loader/efi_device_path.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/efi_loader/efi_device_path.c b/lib/efi_loader/efi_device_path.c index 0a8802903d7..0542aaae16c 100644 --- a/lib/efi_loader/efi_device_path.c +++ b/lib/efi_loader/efi_device_path.c @@ -137,7 +137,7 @@ int efi_dp_match(const struct efi_device_path *a, * * See UEFI spec (section 3.1.2, about short-form device-paths) * - * @dp: original devie-path + * @dp: original device-path * @Return: shortened device-path or NULL */ struct efi_device_path *efi_dp_shorten(struct efi_device_path *dp) From ae794fae091759aa53fd2f88b09a8e5f31688167 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Sun, 20 Mar 2022 09:21:57 +0100 Subject: [PATCH 3/6] efi_loader: nocolor command line attr for initrddump.efi initrddump.efi uses colored output and clear the screen. This is not helpful for integration into Python tests. Allow specifying 'nocolor' in the load option data to suppress color output and clearing the screen. Signed-off-by: Heinrich Schuchardt --- lib/efi_loader/initrddump.c | 77 ++++++++++++++++++++++++++++++++----- 1 file changed, 68 insertions(+), 9 deletions(-) diff --git a/lib/efi_loader/initrddump.c b/lib/efi_loader/initrddump.c index 7de43bcfff4..6f8dd09a79c 100644 --- a/lib/efi_loader/initrddump.c +++ b/lib/efi_loader/initrddump.c @@ -4,6 +4,9 @@ * * initrddump.efi saves the initial RAM disk provided via the * EFI_LOAD_FILE2_PROTOCOL. + * + * Specifying 'nocolor' as load option data suppresses colored output and + * clearing of the screen. */ #include @@ -25,6 +28,7 @@ static const efi_guid_t guid_simple_file_system_protocol = EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_GUID; static const efi_guid_t load_file2_guid = EFI_LOAD_FILE2_PROTOCOL_GUID; static efi_handle_t handle; +static bool nocolor; /* * Device path defined by Linux to identify the handle providing the @@ -46,6 +50,17 @@ static const struct efi_initrd_dp initrd_dp = { } }; +/** + * color() - set foreground color + * + * @color: foreground color + */ +static void color(u8 color) +{ + if (!nocolor) + cout->set_attribute(cout, color | EFI_BACKGROUND_BLACK); +} + /** * print() - print string * @@ -56,6 +71,17 @@ static void print(u16 *string) cout->output_string(cout, string); } +/** + * cls() - clear screen + */ +static void cls(void) +{ + if (nocolor) + print(u"\r\n"); + else + cout->clear_screen(cout); +} + /** * error() - print error string * @@ -63,9 +89,9 @@ static void print(u16 *string) */ static void error(u16 *string) { - cout->set_attribute(cout, EFI_LIGHTRED | EFI_BACKGROUND_BLACK); + color(EFI_LIGHTRED); print(string); - cout->set_attribute(cout, EFI_LIGHTBLUE | EFI_BACKGROUND_BLACK); + color(EFI_LIGHTBLUE); } /* @@ -215,10 +241,13 @@ static u16 *skip_whitespace(u16 *pos) * * @string: string to search for keyword * @keyword: keyword to be searched - * Return: true fi @string starts with the keyword + * Return: true if @string starts with the keyword */ static bool starts_with(u16 *string, u16 *keyword) { + if (!string || !keyword) + return false; + for (; *keyword; ++string, ++keyword) { if (*string != *keyword) return false; @@ -400,6 +429,30 @@ out: return ret; } +/** + * get_load_options() - get load options + * + * Return: load options or NULL + */ +u16 *get_load_options(void) +{ + efi_status_t ret; + struct efi_loaded_image *loaded_image; + + ret = bs->open_protocol(handle, &loaded_image_guid, + (void **)&loaded_image, NULL, NULL, + EFI_OPEN_PROTOCOL_GET_PROTOCOL); + if (ret != EFI_SUCCESS) { + error(u"Loaded image protocol not found\r\n"); + return NULL; + } + + if (!loaded_image->load_options_size || !loaded_image->load_options) + return NULL; + + return loaded_image->load_options; +} + /** * efi_main() - entry point of the EFI application. * @@ -410,18 +463,23 @@ out: efi_status_t EFIAPI efi_main(efi_handle_t image_handle, struct efi_system_table *systab) { + u16 *load_options; + handle = image_handle; systable = systab; cerr = systable->std_err; cout = systable->con_out; cin = systable->con_in; bs = systable->boottime; + load_options = get_load_options(); - cout->set_attribute(cout, EFI_LIGHTBLUE | EFI_BACKGROUND_BLACK); - cout->clear_screen(cout); - cout->set_attribute(cout, EFI_WHITE | EFI_BACKGROUND_BLACK); + if (starts_with(load_options, u"nocolor")) + nocolor = true; + + color(EFI_WHITE); + cls(); print(u"INITRD Dump\r\n===========\r\n\r\n"); - cout->set_attribute(cout, EFI_LIGHTBLUE | EFI_BACKGROUND_BLACK); + color(EFI_LIGHTBLUE); for (;;) { u16 command[BUFFER_SIZE]; @@ -443,7 +501,8 @@ efi_status_t EFIAPI efi_main(efi_handle_t image_handle, do_help(); } - cout->set_attribute(cout, EFI_LIGHTGRAY | EFI_BACKGROUND_BLACK); - cout->clear_screen(cout); + color(EFI_LIGHTGRAY); + cls(); + return EFI_SUCCESS; } From 24cf707ed71534f6c4dc9a4a04f9a7b4c93d286b Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Tue, 22 Mar 2022 18:20:07 +0100 Subject: [PATCH 4/6] efi_loader: initrddump: drain input before prompt Up to now the initrddump.efi application has drained the input after showing the prompt. This works for humans but leads to problems when automating testing. If the input is drained, this should be done before showing the prompt. Signed-off-by: Heinrich Schuchardt Acked-by: Ilias Apalodimas --- lib/efi_loader/initrddump.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/lib/efi_loader/initrddump.c b/lib/efi_loader/initrddump.c index 6f8dd09a79c..98721069816 100644 --- a/lib/efi_loader/initrddump.c +++ b/lib/efi_loader/initrddump.c @@ -120,6 +120,14 @@ static void printx(u64 val, u32 prec) print(buf); } +/** + * efi_drain_input() - drain console input + */ +static void efi_drain_input(void) +{ + cin->reset(cin, true); +} + /** * efi_input_yn() - get answer to yes/no question * @@ -137,8 +145,6 @@ static efi_status_t efi_input_yn(void) efi_uintn_t index; efi_status_t ret; - /* Drain the console input */ - ret = cin->reset(cin, true); for (;;) { ret = bs->wait_for_event(1, &cin->wait_for_key, &index); if (ret != EFI_SUCCESS) @@ -179,8 +185,6 @@ static efi_status_t efi_input(u16 *buffer, efi_uintn_t buffer_size) u16 outbuf[2] = u" "; efi_status_t ret; - /* Drain the console input */ - ret = cin->reset(cin, true); *buffer = 0; for (;;) { ret = bs->wait_for_event(1, &cin->wait_for_key, &index); @@ -393,6 +397,7 @@ static efi_status_t do_save(u16 *filename) ret = root->open(root, &file, filename, EFI_FILE_MODE_READ, 0); if (ret == EFI_SUCCESS) { file->close(file); + efi_drain_input(); print(u"Overwrite existing file (y/n)? "); ret = efi_input_yn(); print(u"\r\n"); @@ -486,6 +491,7 @@ efi_status_t EFIAPI efi_main(efi_handle_t image_handle, u16 *pos; efi_uintn_t ret; + efi_drain_input(); print(u"=> "); ret = efi_input(command, sizeof(command)); if (ret == EFI_ABORTED) From 46490abbbcbda9bbb1bb26e9eac92308ba83d090 Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Thu, 3 Mar 2022 12:31:18 +0100 Subject: [PATCH 5/6] test: test UEFI boot manager Provide a unit test for * efidebug boot add * efidebug boot order * bootefi bootmgr * initrd via EFI_LOAD_FILE2_PROTOCOL Signed-off-by: Heinrich Schuchardt --- test/py/tests/test_efi_bootmgr/conftest.py | 42 +++++++++++++++++++ .../test_efi_bootmgr/test_efi_bootmgr.py | 32 ++++++++++++++ 2 files changed, 74 insertions(+) create mode 100644 test/py/tests/test_efi_bootmgr/conftest.py create mode 100644 test/py/tests/test_efi_bootmgr/test_efi_bootmgr.py diff --git a/test/py/tests/test_efi_bootmgr/conftest.py b/test/py/tests/test_efi_bootmgr/conftest.py new file mode 100644 index 00000000000..69008fddce7 --- /dev/null +++ b/test/py/tests/test_efi_bootmgr/conftest.py @@ -0,0 +1,42 @@ +# SPDX-License-Identifier: GPL-2.0+ + +"""Fixture for UEFI bootmanager test +""" + +import os +import pytest +import shutil +from subprocess import call, check_call + +@pytest.fixture(scope='session') +def efi_bootmgr_data(u_boot_config): + """Set up a file system to be used in UEFI bootmanager + tests + + Args: + u_boot_config: U-boot configuration. + + Return: + A path to disk image to be used for testing + """ + mnt_point = u_boot_config.persistent_data_dir + '/test_efi_bootmgr' + image_path = u_boot_config.persistent_data_dir + '/efi_bootmgr.img' + + shutil.rmtree(mnt_point, ignore_errors=True) + os.mkdir(mnt_point, mode = 0o755) + + with open(mnt_point + '/initrd-1.img', 'w', encoding = 'ascii') as file: + file.write("initrd 1") + + with open(mnt_point + '/initrd-2.img', 'w', encoding = 'ascii') as file: + file.write("initrd 2") + + shutil.copyfile(u_boot_config.build_dir + '/lib/efi_loader/initrddump.efi', + mnt_point + '/initrddump.efi') + + check_call('virt-make-fs --partition=gpt --size=+1M --type=vfat {} {}' + .format(mnt_point, image_path), shell=True) + + print(image_path) + + yield image_path diff --git a/test/py/tests/test_efi_bootmgr/test_efi_bootmgr.py b/test/py/tests/test_efi_bootmgr/test_efi_bootmgr.py new file mode 100644 index 00000000000..f87e0a20b80 --- /dev/null +++ b/test/py/tests/test_efi_bootmgr/test_efi_bootmgr.py @@ -0,0 +1,32 @@ +# SPDX-License-Identifier: GPL-2.0+ + +import pytest + +@pytest.mark.boardspec('sandbox') +@pytest.mark.buildconfigspec('cmd_efidebug') +@pytest.mark.buildconfigspec('cmd_bootefi_bootmgr') +def test_efi_bootmgr(u_boot_console, efi_bootmgr_data): + u_boot_console.run_command(cmd = 'host bind 0 {}'.format(efi_bootmgr_data)) + + u_boot_console.run_command(cmd = 'efidebug boot add ' \ + '-b 0001 label-1 host 0:1 initrddump.efi ' \ + '-i host 0:1 initrd-1.img -s nocolor') + u_boot_console.run_command(cmd = 'efidebug boot dump') + u_boot_console.run_command(cmd = 'efidebug boot order 0001') + u_boot_console.run_command(cmd = 'bootefi bootmgr') + response = u_boot_console.run_command(cmd = 'load', wait_for_echo=False) + assert 'crc32: 0x181464af' in response + u_boot_console.run_command(cmd = 'exit', wait_for_echo=False) + + u_boot_console.run_command(cmd = 'efidebug boot add ' \ + '-B 0002 label-2 host 0:1 initrddump.efi ' \ + '-I host 0:1 initrd-2.img -s nocolor') + u_boot_console.run_command(cmd = 'efidebug boot dump') + u_boot_console.run_command(cmd = 'efidebug boot order 0002') + u_boot_console.run_command(cmd = 'bootefi bootmgr') + response = u_boot_console.run_command(cmd = 'load', wait_for_echo=False) + assert 'crc32: 0x811d3515' in response + u_boot_console.run_command(cmd = 'exit', wait_for_echo=False) + + u_boot_console.run_command(cmd = 'efidebug boot rm 0001') + u_boot_console.run_command(cmd = 'efidebug boot rm 0002') From ccc41fcfaf33356f7789c8bd50551a9e37507f2d Mon Sep 17 00:00:00 2001 From: Heinrich Schuchardt Date: Wed, 23 Mar 2022 20:26:25 +0100 Subject: [PATCH 6/6] cmd: efidebug: simplify do_efi_boot_add() When calling efi_dp_from_name() we are not interested in the device part. Just pass NULL as an argument. Suggested-by: AKASHI Takahiro Signed-off-by: Heinrich Schuchardt --- cmd/efidebug.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/cmd/efidebug.c b/cmd/efidebug.c index 51e2850d218..3cc6f2bfcca 100644 --- a/cmd/efidebug.c +++ b/cmd/efidebug.c @@ -810,7 +810,7 @@ static int do_efi_boot_add(struct cmd_tbl *cmdtp, int flag, efi_guid_t guid; size_t label_len, label_len16; u16 *label; - struct efi_device_path *device_path = NULL, *file_path = NULL; + struct efi_device_path *file_path = NULL; struct efi_device_path *fp_free = NULL; struct efi_device_path *final_fp = NULL; struct efi_device_path *initrd_dp = NULL; @@ -865,7 +865,7 @@ static int do_efi_boot_add(struct cmd_tbl *cmdtp, int flag, /* file path */ ret = efi_dp_from_name(argv[3], argv[4], argv[5], - &device_path, &fp_free); + NULL, &fp_free); if (ret != EFI_SUCCESS) { printf("Cannot create device path for \"%s %s\"\n", argv[3], argv[4]); @@ -953,7 +953,6 @@ out: free(data); efi_free_pool(final_fp); efi_free_pool(initrd_dp); - efi_free_pool(device_path); efi_free_pool(fp_free); free(lo.label);