diff --git a/cmd/efidebug.c b/cmd/efidebug.c index 51e2850d218b7afa4415016cc777b9b92baee5ec..3cc6f2bfcca803ae710a8dc35e6bf36b2c701c84 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); diff --git a/doc/usage/index.rst b/doc/usage/index.rst index 0aacf531b22f479daf5e841d21542a248a8d47bf..630a6cb28ab2ac37d87b6265c99c5c2a4008ff68 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 0000000000000000000000000000000000000000..8d80433c1fa5953f4bd0cdaa8ee1ff1084f503ad --- /dev/null +++ b/doc/usage/wdt.rst @@ -0,0 +1,77 @@ +.. SPDX-License-Identifier: GPL-2.0+: + +wdt command +============ + +Synopsis +-------- + +:: + + wdt list + wdt dev [<name>] + wdt start <timeout_ms> [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. diff --git a/lib/efi_loader/efi_device_path.c b/lib/efi_loader/efi_device_path.c index 0a8802903d7c3bc08bba8fb890c95f8c677ddd1c..0542aaae16c719d5293f33475931effd48d0a9f6 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) diff --git a/lib/efi_loader/initrddump.c b/lib/efi_loader/initrddump.c index 7de43bcfff49bd1723367394f4c18634721c8b35..98721069816dee86f64efa24d0a52fbdfa40843f 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 <common.h> @@ -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); } /* @@ -94,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 * @@ -111,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) @@ -153,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); @@ -215,10 +245,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; @@ -364,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"); @@ -400,6 +434,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,24 +468,30 @@ 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]; u16 *pos; efi_uintn_t ret; + efi_drain_input(); print(u"=> "); ret = efi_input(command, sizeof(command)); if (ret == EFI_ABORTED) @@ -443,7 +507,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; } 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 0000000000000000000000000000000000000000..69008fddce7f56c61db647b99c6c96be57042b3b --- /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 0000000000000000000000000000000000000000..f87e0a20b800db04523f95ae24bb6bfe46729c36 --- /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')