diff options
-rw-r--r-- | cmd/bootefi.c | 17 | ||||
-rw-r--r-- | doc/arch/x86.rst | 2 | ||||
-rw-r--r-- | doc/develop/index.rst | 1 | ||||
-rw-r--r-- | doc/develop/smbios.rst | 22 | ||||
-rw-r--r-- | doc/usage/fatload.rst | 80 | ||||
-rw-r--r-- | doc/usage/index.rst | 1 | ||||
-rw-r--r-- | lib/efi_loader/efi_capsule.c | 20 | ||||
-rw-r--r-- | lib/efi_loader/efi_signature.c | 11 | ||||
-rw-r--r-- | lib/efi_loader/efi_watchdog.c | 13 | ||||
-rw-r--r-- | test/py/tests/test_efi_capsule/test_capsule_firmware.py | 37 | ||||
-rw-r--r-- | test/py/u_boot_console_base.py | 115 | ||||
-rw-r--r-- | test/py/u_boot_console_sandbox.py | 7 | ||||
-rw-r--r-- | tools/mkeficapsule.c | 2 |
13 files changed, 243 insertions, 85 deletions
diff --git a/cmd/bootefi.c b/cmd/bootefi.c index 94d18ca..46eebd5 100644 --- a/cmd/bootefi.c +++ b/cmd/bootefi.c @@ -353,6 +353,19 @@ static efi_status_t do_bootefi_exec(efi_handle_t handle, void *load_options) /* On ARM switch from EL3 or secure mode to EL2 or non-secure mode */ switch_to_non_secure_mode(); + /* + * The UEFI standard requires that the watchdog timer is set to five + * minutes when invoking an EFI boot option. + * + * Unified Extensible Firmware Interface (UEFI), version 2.7 Errata A + * 7.5. Miscellaneous Boot Services - EFI_BOOT_SERVICES.SetWatchdogTimer + */ + ret = efi_set_watchdog(300); + if (ret != EFI_SUCCESS) { + log_err("ERROR: Failed to set watchdog timer\n"); + goto out; + } + /* Call our payload! */ ret = EFI_CALL(efi_start_image(handle, &exit_data_size, &exit_data)); if (ret != EFI_SUCCESS) { @@ -366,11 +379,15 @@ static efi_status_t do_bootefi_exec(efi_handle_t handle, void *load_options) efi_restore_gd(); +out: free(load_options); if (IS_ENABLED(CONFIG_EFI_LOAD_FILE2_INITRD)) efi_initrd_deregister(); + /* Control is returned to U-Boot, disable EFI watchdog */ + efi_set_watchdog(0); + return ret; } diff --git a/doc/arch/x86.rst b/doc/arch/x86.rst index 5494155..634387a 100644 --- a/doc/arch/x86.rst +++ b/doc/arch/x86.rst @@ -732,7 +732,7 @@ SMBIOS tables To generate SMBIOS tables in U-Boot, for use by the OS, enable the CONFIG_GENERATE_SMBIOS_TABLE option. The easiest way to provide the values to use is via the device tree. For details see -device-tree-bindings/sysinfo/smbios.txt +:download:`smbios.txt <../device-tree-bindings/sysinfo/smbios.txt>`. TODO List --------- diff --git a/doc/develop/index.rst b/doc/develop/index.rst index 9714887..93ebfa4 100644 --- a/doc/develop/index.rst +++ b/doc/develop/index.rst @@ -22,6 +22,7 @@ Implementation makefiles menus printf + smbios uefi/index version diff --git a/doc/develop/smbios.rst b/doc/develop/smbios.rst new file mode 100644 index 0000000..a4efb0a --- /dev/null +++ b/doc/develop/smbios.rst @@ -0,0 +1,22 @@ +.. SPDX-License-Identifier: GPL-2.0+ + +SMBIOS tables +============= + +The System Management BIOS (SMBIOS) table is used to deliver management +information from the firmware to the operating system. The content is +standardized in [1]_. + +In Linux you can use the dmidecode command to view the contents of the SMBIOS +table. + +When booting via UEFI the SMBIOS table is transferred as an UEFI configuration +table to the operating system. + +To generate SMBIOS tables in U-Boot, the CONFIG_GENERATE_SMBIOS_TABLE option +must be enabled. The easiest way to provide the values to use is via the device +tree. For details see +:download:`smbios.txt <../device-tree-bindings/sysinfo/smbios.txt>`. + +.. [1] `System Management BIOS (SMBIOS) Reference, version 3.5 + <https://www.dmtf.org/content/dmtf-releases-smbios-35>`_ diff --git a/doc/usage/fatload.rst b/doc/usage/fatload.rst new file mode 100644 index 0000000..93acb27 --- /dev/null +++ b/doc/usage/fatload.rst @@ -0,0 +1,80 @@ +.. SPDX-License-Identifier: GPL-2.0+: + +fatload command +=============== + +Synopsis +-------- + +:: + + fatload <interface> [<dev[:part]> [<addr> [<filename> [bytes [pos]]]]] + +Description +----------- + +The fatload command is used to read a file from a FAT filesystem into memory. +You can always use the :doc:`load command <load>` instead. + +The number of transferred bytes is saved in the environment variable filesize. +The load address is saved in the environment variable fileaddr. + +interface + interface for accessing the block device (mmc, sata, scsi, usb, ....) + +dev + device number + +part + partition number, defaults to 0 (whole device) + +addr + load address, defaults to environment variable loadaddr or if loadaddr is + not set to configuration variable CONFIG_SYS_LOAD_ADDR + +filename + path to file, defaults to environment variable bootfile + +bytes + maximum number of bytes to load + +pos + number of bytes to skip + +addr, bytes, pos are hexadecimal numbers. + +If either 'pos' or 'bytes' are not aligned according to the minimum alignment +requirement for DMA transfer (ARCH_DMA_MINALIGN) additional buffering will be +used, a misaligned buffer warning will be printed, and performance will suffer +for the load. + +Example +------- + +:: + + => fatload mmc 0:1 ${kernel_addr_r} snp.efi + 149280 bytes read in 11 ms (12.9 MiB/s) + => + => fatload mmc 0:1 ${kernel_addr_r} snp.efi 1000000 + 149280 bytes read in 9 ms (15.8 MiB/s) + => + => fatload mmc 0:1 ${kernel_addr_r} snp.efi 1000000 100 + 149024 bytes read in 10 ms (14.2 MiB/s) + => + => fatload mmc 0:1 ${kernel_addr_r} snp.efi 10 + 16 bytes read in 1 ms (15.6 KiB/s) + => + +Configuration +------------- + +The fatload command is only available if CONFIG_CMD_FAT=y. + +Return value +------------ + +The return value $? is set to 0 (true) if the file was successfully loaded +even if the number of bytes is less then the specified length. + +If an error occurs, the return value $? is set to 1 (false). diff --git a/doc/usage/index.rst b/doc/usage/index.rst index 964d761..0aacf53 100644 --- a/doc/usage/index.rst +++ b/doc/usage/index.rst @@ -34,6 +34,7 @@ Shell commands exit false fatinfo + fatload for load loady diff --git a/lib/efi_loader/efi_capsule.c b/lib/efi_loader/efi_capsule.c index f4519c7..613b531 100644 --- a/lib/efi_loader/efi_capsule.c +++ b/lib/efi_loader/efi_capsule.c @@ -14,6 +14,7 @@ #include <env.h> #include <fdtdec.h> #include <fs.h> +#include <hang.h> #include <malloc.h> #include <mapmem.h> #include <sort.h> @@ -1118,10 +1119,13 @@ efi_status_t efi_launch_capsules(void) index = 0; ret = efi_capsule_read_file(files[i], &capsule); if (ret == EFI_SUCCESS) { - ret = EFI_CALL(efi_update_capsule(&capsule, 1, 0)); + ret = efi_capsule_update_firmware(capsule); if (ret != EFI_SUCCESS) - log_err("Applying capsule %ls failed\n", + log_err("Applying capsule %ls failed.\n", files[i]); + else + log_info("Applying capsule %ls succeeded.\n", + files[i]); /* create CapsuleXXXX */ set_capsule_result(index, capsule, ret); @@ -1142,6 +1146,16 @@ efi_status_t efi_launch_capsules(void) free(files[i]); free(files); - return ret; + /* + * UEFI spec requires to reset system after complete processing capsule + * update on the storage. + */ + log_info("Reboot after firmware update"); + /* Cold reset is required for loading the new firmware. */ + do_reset(NULL, 0, 0, NULL); + hang(); + /* not reach here */ + + return 0; } #endif /* CONFIG_EFI_CAPSULE_ON_DISK */ diff --git a/lib/efi_loader/efi_signature.c b/lib/efi_loader/efi_signature.c index 1bd1fdc..79ed077 100644 --- a/lib/efi_loader/efi_signature.c +++ b/lib/efi_loader/efi_signature.c @@ -518,12 +518,11 @@ bool efi_signature_verify(struct efi_image_regions *regs, goto out; EFI_PRINT("Verifying last certificate in chain\n"); - if (signer->self_signed) { - if (efi_lookup_certificate(signer, db)) - if (efi_signature_check_revocation(sinfo, - signer, dbx)) - break; - } else if (efi_verify_certificate(signer, db, &root)) { + if (efi_lookup_certificate(signer, db)) + if (efi_signature_check_revocation(sinfo, signer, dbx)) + break; + if (!signer->self_signed && + efi_verify_certificate(signer, db, &root)) { bool check; check = efi_signature_check_revocation(sinfo, root, diff --git a/lib/efi_loader/efi_watchdog.c b/lib/efi_loader/efi_watchdog.c index 87ca6c5..d741076 100644 --- a/lib/efi_loader/efi_watchdog.c +++ b/lib/efi_loader/efi_watchdog.c @@ -75,17 +75,6 @@ efi_status_t efi_watchdog_register(void) printf("ERROR: Failed to register watchdog event\n"); return r; } - /* - * The UEFI standard requires that the watchdog timer is set to five - * minutes when invoking an EFI boot option. - * - * Unified Extensible Firmware Interface (UEFI), version 2.7 Errata A - * 7.5. Miscellaneous Boot Services - EFI_BOOT_SERVICES.SetWatchdogTimer - */ - r = efi_set_watchdog(300); - if (r != EFI_SUCCESS) { - printf("ERROR: Failed to set watchdog timer\n"); - return r; - } + return EFI_SUCCESS; } diff --git a/test/py/tests/test_efi_capsule/test_capsule_firmware.py b/test/py/tests/test_efi_capsule/test_capsule_firmware.py index 6e803f6..1dcf1c7 100644 --- a/test/py/tests/test_efi_capsule/test_capsule_firmware.py +++ b/test/py/tests/test_efi_capsule/test_capsule_firmware.py @@ -143,13 +143,14 @@ class TestEfiCapsuleFirmwareFit(object): 'fatls host 0:1 %s' % CAPSULE_INSTALL_DIR]) assert 'Test01' in ''.join(output) - # reboot - u_boot_console.restart_uboot() - capsule_early = u_boot_config.buildconfig.get( 'config_efi_capsule_on_disk_early') capsule_auth = u_boot_config.buildconfig.get( 'config_efi_capsule_authenticate') + + # reboot + u_boot_console.restart_uboot(expect_reset = capsule_early) + with u_boot_console.log.section('Test Case 2-b, after reboot'): if not capsule_early: # make sure that dfu_alt_info exists even persistent variables @@ -162,7 +163,7 @@ class TestEfiCapsuleFirmwareFit(object): # need to run uefi command to initiate capsule handling output = u_boot_console.run_command( - 'env print -e Capsule0000') + 'env print -e Capsule0000', wait_for_reboot = True) output = u_boot_console.run_command_list([ 'host bind 0 %s' % disk_img, @@ -218,13 +219,14 @@ class TestEfiCapsuleFirmwareFit(object): 'fatls host 0:1 %s' % CAPSULE_INSTALL_DIR]) assert 'Test02' in ''.join(output) - # reboot - u_boot_console.restart_uboot() - capsule_early = u_boot_config.buildconfig.get( 'config_efi_capsule_on_disk_early') capsule_auth = u_boot_config.buildconfig.get( 'config_efi_capsule_authenticate') + + # reboot + u_boot_console.restart_uboot(expect_reset = capsule_early) + with u_boot_console.log.section('Test Case 3-b, after reboot'): if not capsule_early: # make sure that dfu_alt_info exists even persistent variables @@ -237,9 +239,12 @@ class TestEfiCapsuleFirmwareFit(object): # need to run uefi command to initiate capsule handling output = u_boot_console.run_command( - 'env print -e Capsule0000') + 'env print -e Capsule0000', wait_for_reboot = True) - output = u_boot_console.run_command_list(['efidebug capsule esrt']) + # make sure the dfu_alt_info exists because it is required for making ESRT. + output = u_boot_console.run_command_list([ + 'env set dfu_alt_info "sf 0:0=u-boot-bin raw 0x100000 0x50000;u-boot-env raw 0x150000 0x200000"', + 'efidebug capsule esrt']) # ensure that EFI_FIRMWARE_IMAGE_TYPE_UBOOT_FIT_GUID is in the ESRT. assert 'AE13FF2D-9AD4-4E25-9AC8-6D80B3B22147' in ''.join(output) @@ -293,13 +298,14 @@ class TestEfiCapsuleFirmwareFit(object): 'fatls host 0:1 %s' % CAPSULE_INSTALL_DIR]) assert 'Test03' in ''.join(output) - # reboot - u_boot_console.restart_uboot() - capsule_early = u_boot_config.buildconfig.get( 'config_efi_capsule_on_disk_early') capsule_auth = u_boot_config.buildconfig.get( 'config_efi_capsule_authenticate') + + # reboot + u_boot_console.restart_uboot(expect_reset = capsule_early) + with u_boot_console.log.section('Test Case 4-b, after reboot'): if not capsule_early: # make sure that dfu_alt_info exists even persistent variables @@ -312,9 +318,12 @@ class TestEfiCapsuleFirmwareFit(object): # need to run uefi command to initiate capsule handling output = u_boot_console.run_command( - 'env print -e Capsule0000') + 'env print -e Capsule0000', wait_for_reboot = True) - output = u_boot_console.run_command_list(['efidebug capsule esrt']) + # make sure the dfu_alt_info exists because it is required for making ESRT. + output = u_boot_console.run_command_list([ + 'env set dfu_alt_info "sf 0:0=u-boot-bin raw 0x100000 0x50000;u-boot-env raw 0x150000 0x200000"', + 'efidebug capsule esrt']) # ensure that EFI_FIRMWARE_IMAGE_TYPE_UBOOT_RAW_GUID is in the ESRT. assert 'E2BB9C06-70E9-4B14-97A3-5A7913176E3F' in ''.join(output) diff --git a/test/py/u_boot_console_base.py b/test/py/u_boot_console_base.py index 384fd53..3938ec1 100644 --- a/test/py/u_boot_console_base.py +++ b/test/py/u_boot_console_base.py @@ -139,8 +139,55 @@ class ConsoleBase(object): self.p.close() self.logstream.close() + def wait_for_boot_prompt(self, loop_num = 1): + """Wait for the boot up until command prompt. This is for internal use only. + """ + try: + bcfg = self.config.buildconfig + config_spl = bcfg.get('config_spl', 'n') == 'y' + config_spl_serial = bcfg.get('config_spl_serial', 'n') == 'y' + env_spl_skipped = self.config.env.get('env__spl_skipped', False) + env_spl2_skipped = self.config.env.get('env__spl2_skipped', True) + + while loop_num > 0: + loop_num -= 1 + if config_spl and config_spl_serial and not env_spl_skipped: + m = self.p.expect([pattern_u_boot_spl_signon] + + self.bad_patterns) + if m != 0: + raise Exception('Bad pattern found on SPL console: ' + + self.bad_pattern_ids[m - 1]) + if not env_spl2_skipped: + m = self.p.expect([pattern_u_boot_spl2_signon] + + self.bad_patterns) + if m != 0: + raise Exception('Bad pattern found on SPL2 console: ' + + self.bad_pattern_ids[m - 1]) + m = self.p.expect([pattern_u_boot_main_signon] + self.bad_patterns) + if m != 0: + raise Exception('Bad pattern found on console: ' + + self.bad_pattern_ids[m - 1]) + self.u_boot_version_string = self.p.after + while True: + m = self.p.expect([self.prompt_compiled, + pattern_stop_autoboot_prompt] + self.bad_patterns) + if m == 0: + break + if m == 1: + self.p.send(' ') + continue + raise Exception('Bad pattern found on console: ' + + self.bad_pattern_ids[m - 2]) + + except Exception as ex: + self.log.error(str(ex)) + self.cleanup_spawn() + raise + finally: + self.log.timestamp() + def run_command(self, cmd, wait_for_echo=True, send_nl=True, - wait_for_prompt=True): + wait_for_prompt=True, wait_for_reboot=False): """Execute a command via the U-Boot console. The command is always sent to U-Boot. @@ -168,6 +215,9 @@ class ConsoleBase(object): wait_for_prompt: Boolean indicating whether to wait for the command prompt to be sent by U-Boot. This typically occurs immediately after the command has been executed. + wait_for_reboot: Boolean indication whether to wait for the + reboot U-Boot. If this sets True, wait_for_prompt must also + be True. Returns: If wait_for_prompt == False: @@ -202,11 +252,14 @@ class ConsoleBase(object): self.bad_pattern_ids[m - 1]) if not wait_for_prompt: return - m = self.p.expect([self.prompt_compiled] + self.bad_patterns) - if m != 0: - self.at_prompt = False - raise Exception('Bad pattern found on console: ' + - self.bad_pattern_ids[m - 1]) + if wait_for_reboot: + self.wait_for_boot_prompt() + else: + m = self.p.expect([self.prompt_compiled] + self.bad_patterns) + if m != 0: + self.at_prompt = False + raise Exception('Bad pattern found on console: ' + + self.bad_pattern_ids[m - 1]) self.at_prompt = True self.at_prompt_logevt = self.logstream.logfile.cur_evt # Only strip \r\n; space/TAB might be significant if testing @@ -321,7 +374,7 @@ class ConsoleBase(object): finally: self.p.timeout = orig_timeout - def ensure_spawned(self): + def ensure_spawned(self, expect_reset=False): """Ensure a connection to a correctly running U-Boot instance. This may require spawning a new Sandbox process or resetting target @@ -330,7 +383,9 @@ class ConsoleBase(object): This is an internal function and should not be called directly. Args: - None. + expect_reset: Boolean indication whether this boot is expected + to be reset while the 1st boot process after main boot before + prompt. False by default. Returns: Nothing. @@ -349,41 +404,11 @@ class ConsoleBase(object): if not self.config.gdbserver: self.p.timeout = 30000 self.p.logfile_read = self.logstream - bcfg = self.config.buildconfig - config_spl = bcfg.get('config_spl', 'n') == 'y' - config_spl_serial = bcfg.get('config_spl_serial', - 'n') == 'y' - env_spl_skipped = self.config.env.get('env__spl_skipped', - False) - env_spl2_skipped = self.config.env.get('env__spl2_skipped', - True) - if config_spl and config_spl_serial and not env_spl_skipped: - m = self.p.expect([pattern_u_boot_spl_signon] + - self.bad_patterns) - if m != 0: - raise Exception('Bad pattern found on SPL console: ' + - self.bad_pattern_ids[m - 1]) - if not env_spl2_skipped: - m = self.p.expect([pattern_u_boot_spl2_signon] + - self.bad_patterns) - if m != 0: - raise Exception('Bad pattern found on SPL2 console: ' + - self.bad_pattern_ids[m - 1]) - m = self.p.expect([pattern_u_boot_main_signon] + self.bad_patterns) - if m != 0: - raise Exception('Bad pattern found on console: ' + - self.bad_pattern_ids[m - 1]) - self.u_boot_version_string = self.p.after - while True: - m = self.p.expect([self.prompt_compiled, - pattern_stop_autoboot_prompt] + self.bad_patterns) - if m == 0: - break - if m == 1: - self.p.send(' ') - continue - raise Exception('Bad pattern found on console: ' + - self.bad_pattern_ids[m - 2]) + if expect_reset: + loop_num = 2 + else: + loop_num = 1 + self.wait_for_boot_prompt(loop_num = loop_num) self.at_prompt = True self.at_prompt_logevt = self.logstream.logfile.cur_evt except Exception as ex: @@ -416,10 +441,10 @@ class ConsoleBase(object): pass self.p = None - def restart_uboot(self): + def restart_uboot(self, expect_reset=False): """Shut down and restart U-Boot.""" self.cleanup_spawn() - self.ensure_spawned() + self.ensure_spawned(expect_reset) def get_spawn_output(self): """Return the start-up output from U-Boot diff --git a/test/py/u_boot_console_sandbox.py b/test/py/u_boot_console_sandbox.py index 7e1eb0e..ce4ca7e 100644 --- a/test/py/u_boot_console_sandbox.py +++ b/test/py/u_boot_console_sandbox.py @@ -57,11 +57,14 @@ class ConsoleSandbox(ConsoleBase): cmd += self.sandbox_flags return Spawn(cmd, cwd=self.config.source_dir) - def restart_uboot_with_flags(self, flags): + def restart_uboot_with_flags(self, flags, expect_reset=False): """Run U-Boot with the given command-line flags Args: flags: List of flags to pass, each a string + expect_reset: Boolean indication whether this boot is expected + to be reset while the 1st boot process after main boot before + prompt. False by default. Returns: A u_boot_spawn.Spawn object that is attached to U-Boot. @@ -69,7 +72,7 @@ class ConsoleSandbox(ConsoleBase): try: self.sandbox_flags = flags - return self.restart_uboot() + return self.restart_uboot(expect_reset) finally: self.sandbox_flags = [] diff --git a/tools/mkeficapsule.c b/tools/mkeficapsule.c index f7590e4..c118335 100644 --- a/tools/mkeficapsule.c +++ b/tools/mkeficapsule.c @@ -212,8 +212,6 @@ static int create_auth_data(struct auth_context *ctx) ret = read_bin_file(ctx->key_file, &key.data, &file_size); if (ret < 0) return -1; - if (ret < 0) - return -1; if (file_size > UINT_MAX) return -1; key.size = file_size; |