Pull request for efi-2022-04-rc3

Documentation:
 
 * add man-page for fatload
 * add SMBIOS table page
 
 UEFI:
 
 * partial fix for UEFI secure boot with intermediate certs
 * disable watchdog when returning to command line
 * reset system after capsule update
 -----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCAAdFiEEbcT5xx8ppvoGt20zxIHbvCwFGsQFAmIZ0JQACgkQxIHbvCwF
 GsS3fA/9GAvda+4uvrWKw7H4bI49m0mDEMyUWd9k8f4Tzk20130/dPONtXFrdgqM
 uStlcK0NapUPq7i4iNvur3mbwkTrbgF3ynmXvUak+Yj27jngQlXtFJtmdPCQqmBA
 OvhUL35AEsIef2ZTCTBZOOVhMO9EcG9TzAU/o4sLo5VOUmi4DcLPD8uLa+B8qd+N
 LYb1gUfbG9Y/ban/kw22b2ug1EUpx2PFpag4PB4ITK8KGoTu8LNco7PqEQU/muCc
 FUa2wHHFgNnO4aW5JoyAI8+Rmxw/ZSII0QU4AFTf3p+T5LGsHojHj/XMTUPk2oeS
 W36MMDeqNgfyH7PmkGDm03HPthPHLridAd9/5hyKynpzRhA/kmp2e3g5UUzfCG8H
 XMp4JM3Ki06beQPh+h3dj4b8UQeyyqhetuvZfZhW76apJqBC3/asbkooH9p4cSV9
 rr2wi4OdFb0f/nVrrVfnEZnqIQOgC4iuTo3FC5ruoElRgWCoLsf9zvvzFr+OS+d1
 qeD2nWNmY4MTC3PEtd7JV6c56KqkabmsD2bhOGLcxDjs/pwaKUm7p5wZx/AtNjN1
 haFa+3pSYl7oxCu1sWLWPdiuiRRpA+VEYj8JstR/KDcdCMHouFW7jdbarpHVQdZo
 kQ7FCchuTjL28scrZDXNMz6ODoKaLLVAmf3Nqq0upT3paVLI6uI=
 =XSzP
 -----END PGP SIGNATURE-----

Merge tag 'efi-2022-04-rc3' of https://source.denx.de/u-boot/custodians/u-boot-efi

Pull request for efi-2022-04-rc3

Documentation:

* add man-page for fatload
* add SMBIOS table page

UEFI:

* partial fix for UEFI secure boot with intermediate certs
* disable watchdog when returning to command line
* reset system after capsule update
This commit is contained in:
Tom Rini 2022-02-26 10:21:39 -05:00
commit a900c7f816
13 changed files with 243 additions and 85 deletions

View file

@ -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;
}

View file

@ -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
---------

View file

@ -22,6 +22,7 @@ Implementation
makefiles
menus
printf
smbios
uefi/index
version

22
doc/develop/smbios.rst Normal file
View file

@ -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>`_

80
doc/usage/fatload.rst Normal file
View file

@ -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).

View file

@ -34,6 +34,7 @@ Shell commands
exit
false
fatinfo
fatload
for
load
loady

View file

@ -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 */

View file

@ -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,

View file

@ -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;
}

View file

@ -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)

View file

@ -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

View file

@ -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 = []

View file

@ -210,8 +210,6 @@ static int create_auth_data(struct auth_context *ctx)
cert.size = file_size;
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)