Pull request for efi-2022-01-rc3-2

Test:
 * fix pylint warnings
 
 UEFI:
 * disable interrupts before removing devices in ExitBootServices()
 * implement poweroff in efi_system_reset() on sandbox
 * allow booting via EFI even if some block device fails
 -----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCAAdFiEEbcT5xx8ppvoGt20zxIHbvCwFGsQFAmGhUDgACgkQxIHbvCwF
 GsTQRQ//TM2VwpjMWYBB6K91hVEHVJ4wYpNb5/ZqP0+NwYJbNo/3zF4qwFeSTN6O
 tbarpoiM6GNlSIC4Eo/+17JdUJd7NkfsGnhaV+SxG5Q+etaU0OabC8hbyPqw+nmg
 fbaL43xGygSj5t2RWqyBQYsnsYimgwkAz7pbCBnvrpIsGKImVqp36ft5KWo1ICTE
 JD8yRb9IMpPKfY5aK0q3c8X/Qbf6oPI1u6xGVcwyc+vQb4RjRMX46sGMJswcLnF0
 jGcxIB66/MeKeKN8bTtUoRZ9F4itF3k+FA0rnnwzQl+xre2Tu0fTnaEYHzKayu5J
 ilaPIcqXPvjfcN00V34kKzXWeMWm8saQA8Ecqowlrw2qQbahYrxX96n0RXzuNyy/
 LxpQtEyrGu/lQfPg9YOABKCRhZZPT3C8EE+0lUqGg1+5Ap0QPTXiNKJ7vx76cCny
 E7zYBQRmbhvmlrfFVACYS7zbUaxTbSMGmDKhhBU4tGFAzkb+bGkErRzjUbvt3TaR
 eQZoOAU6+kuEl9haSlKxo8IwnljfjpIqbgLgBdJ+BLQH/W67rFh631CNfM8x10qG
 7qbzLHLjIXwL2z86tfgmUvMGoLisOPDr53QbhLFv02ywFn4UgjGxcyoRFqlxIi0g
 9+A9nvbpQ4ZnI3HRHjYJ+uFbt9A8am3HwK7CBMR7EN666at7hz8=
 =X5Tv
 -----END PGP SIGNATURE-----

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

Pull request for efi-2022-01-rc3-2

Test:
* fix pylint warnings

UEFI:
* disable interrupts before removing devices in ExitBootServices()
* implement poweroff in efi_system_reset() on sandbox
* allow booting via EFI even if some block device fails
This commit is contained in:
Tom Rini 2021-11-26 17:10:53 -05:00
commit 693650b15d
13 changed files with 94 additions and 105 deletions

View file

@ -434,8 +434,10 @@ void __efi_runtime EFIAPI efi_reset_system(
efi_status_t reset_status, efi_status_t reset_status,
unsigned long data_size, void *reset_data) unsigned long data_size, void *reset_data)
{ {
os_fd_restore(); if (reset_type == EFI_RESET_SHUTDOWN)
os_relaunch(os_argv); sandbox_exit();
else
sandbox_reset();
} }
void sandbox_reset(void) void sandbox_reset(void)

View file

@ -2167,6 +2167,7 @@ static efi_status_t EFIAPI efi_exit_boot_services(efi_handle_t image_handle,
} }
if (!efi_st_keep_devices) { if (!efi_st_keep_devices) {
bootm_disable_interrupts();
if (IS_ENABLED(CONFIG_USB_DEVICE)) if (IS_ENABLED(CONFIG_USB_DEVICE))
udc_disconnect(); udc_disconnect();
board_quiesce_devices(); board_quiesce_devices();
@ -2179,9 +2180,6 @@ static efi_status_t EFIAPI efi_exit_boot_services(efi_handle_t image_handle,
/* Fix up caches for EFI payloads if necessary */ /* Fix up caches for EFI payloads if necessary */
efi_exit_caches(); efi_exit_caches();
/* This stops all lingering devices */
bootm_disable_interrupts();
/* Disable boot time services */ /* Disable boot time services */
systab.con_in_handle = NULL; systab.con_in_handle = NULL;
systab.con_in = NULL; systab.con_in = NULL;

View file

@ -1037,30 +1037,45 @@ efi_status_t __weak efi_load_capsule_drivers(void)
} }
/** /**
* check_run_capsules - Check whether capsule update should run * check_run_capsules() - check whether capsule update should run
* *
* The spec says OsIndications must be set in order to run the capsule update * The spec says OsIndications must be set in order to run the capsule update
* on-disk. Since U-Boot doesn't support runtime SetVariable, allow capsules to * on-disk. Since U-Boot doesn't support runtime SetVariable, allow capsules to
* run explicitly if CONFIG_EFI_IGNORE_OSINDICATIONS is selected * run explicitly if CONFIG_EFI_IGNORE_OSINDICATIONS is selected
*
* Return: EFI_SUCCESS if update to run, EFI_NOT_FOUND otherwise
*/ */
static bool check_run_capsules(void) static efi_status_t check_run_capsules(void)
{ {
u64 os_indications; u64 os_indications;
efi_uintn_t size; efi_uintn_t size;
efi_status_t ret; efi_status_t r;
if (IS_ENABLED(CONFIG_EFI_IGNORE_OSINDICATIONS))
return true;
size = sizeof(os_indications); size = sizeof(os_indications);
ret = efi_get_variable_int(L"OsIndications", &efi_global_variable_guid, r = efi_get_variable_int(L"OsIndications", &efi_global_variable_guid,
NULL, &size, &os_indications, NULL); NULL, &size, &os_indications, NULL);
if (ret == EFI_SUCCESS && if (r != EFI_SUCCESS || size != sizeof(os_indications))
(os_indications return EFI_NOT_FOUND;
& EFI_OS_INDICATIONS_FILE_CAPSULE_DELIVERY_SUPPORTED))
return true;
return false; if (os_indications &
EFI_OS_INDICATIONS_FILE_CAPSULE_DELIVERY_SUPPORTED) {
os_indications &=
~EFI_OS_INDICATIONS_FILE_CAPSULE_DELIVERY_SUPPORTED;
r = efi_set_variable_int(L"OsIndications",
&efi_global_variable_guid,
EFI_VARIABLE_NON_VOLATILE |
EFI_VARIABLE_BOOTSERVICE_ACCESS |
EFI_VARIABLE_RUNTIME_ACCESS,
sizeof(os_indications),
&os_indications, false);
if (r != EFI_SUCCESS)
log_err("Setting %ls failed\n", L"OsIndications");
return EFI_SUCCESS;
} else if (IS_ENABLED(CONFIG_EFI_IGNORE_OSINDICATIONS)) {
return EFI_SUCCESS;
} else {
return EFI_NOT_FOUND;
}
} }
/** /**
@ -1078,7 +1093,7 @@ efi_status_t efi_launch_capsules(void)
unsigned int nfiles, index, i; unsigned int nfiles, index, i;
efi_status_t ret; efi_status_t ret;
if (!check_run_capsules()) if (check_run_capsules() != EFI_SUCCESS)
return EFI_SUCCESS; return EFI_SUCCESS;
index = get_last_capsule(); index = get_last_capsule();

View file

@ -424,7 +424,7 @@ static efi_status_t efi_disk_add_dev(
&efi_block_io_guid, &diskobj->ops, &efi_block_io_guid, &diskobj->ops,
guid, NULL, NULL)); guid, NULL, NULL));
if (ret != EFI_SUCCESS) if (ret != EFI_SUCCESS)
return ret; goto error;
/* /*
* On partitions or whole disks without partitions install the * On partitions or whole disks without partitions install the
@ -573,7 +573,7 @@ efi_status_t efi_disk_register(void)
if (ret) { if (ret) {
log_err("ERROR: failure to add disk device %s, r = %lu\n", log_err("ERROR: failure to add disk device %s, r = %lu\n",
dev->name, ret & ~EFI_ERROR_MASK); dev->name, ret & ~EFI_ERROR_MASK);
return ret; continue;
} }
disks++; disks++;

View file

@ -175,36 +175,6 @@ static efi_status_t efi_init_os_indications(void)
} }
/**
* efi_clear_os_indications() - clear OsIndications
*
* Clear EFI_OS_INDICATIONS_FILE_CAPSULE_DELIVERY_SUPPORTED
*/
static efi_status_t efi_clear_os_indications(void)
{
efi_uintn_t size;
u64 os_indications;
efi_status_t ret;
size = sizeof(os_indications);
ret = efi_get_variable_int(L"OsIndications", &efi_global_variable_guid,
NULL, &size, &os_indications, NULL);
if (ret != EFI_SUCCESS)
os_indications = 0;
else
os_indications &=
~EFI_OS_INDICATIONS_FILE_CAPSULE_DELIVERY_SUPPORTED;
ret = efi_set_variable_int(L"OsIndications", &efi_global_variable_guid,
EFI_VARIABLE_NON_VOLATILE |
EFI_VARIABLE_BOOTSERVICE_ACCESS |
EFI_VARIABLE_RUNTIME_ACCESS,
sizeof(os_indications), &os_indications,
false);
if (ret != EFI_SUCCESS)
log_err("Setting %ls failed\n", L"OsIndications");
return ret;
}
/** /**
* efi_init_obj_list() - Initialize and populate EFI object list * efi_init_obj_list() - Initialize and populate EFI object list
* *
@ -212,7 +182,7 @@ static efi_status_t efi_clear_os_indications(void)
*/ */
efi_status_t efi_init_obj_list(void) efi_status_t efi_init_obj_list(void)
{ {
efi_status_t r, ret = EFI_SUCCESS; efi_status_t ret = EFI_SUCCESS;
/* Initialize once only */ /* Initialize once only */
if (efi_obj_list_initialized != OBJ_LIST_NOT_INITIALIZED) if (efi_obj_list_initialized != OBJ_LIST_NOT_INITIALIZED)
@ -331,11 +301,7 @@ efi_status_t efi_init_obj_list(void)
if (IS_ENABLED(CONFIG_EFI_CAPSULE_ON_DISK) && if (IS_ENABLED(CONFIG_EFI_CAPSULE_ON_DISK) &&
!IS_ENABLED(CONFIG_EFI_CAPSULE_ON_DISK_EARLY)) !IS_ENABLED(CONFIG_EFI_CAPSULE_ON_DISK_EARLY))
ret = efi_launch_capsules(); ret = efi_launch_capsules();
out: out:
r = efi_clear_os_indications();
if (ret == EFI_SUCCESS)
ret = r;
efi_obj_list_initialized = ret; efi_obj_list_initialized = ret;
return ret; return ret;
} }

View file

@ -23,23 +23,24 @@ static const char *fdt;
static const efi_guid_t fdt_guid = EFI_FDT_GUID; static const efi_guid_t fdt_guid = EFI_FDT_GUID;
static const efi_guid_t acpi_guid = EFI_ACPI_TABLE_GUID; static const efi_guid_t acpi_guid = EFI_ACPI_TABLE_GUID;
/* /**
* Convert FDT value to host endianness. * f2h() - convert FDT value to host endianness.
* *
* @val FDT value * UEFI code is always low endian. The FDT is big endian.
* @return converted value *
* @val: FDT value
* Return: converted value
*/ */
static uint32_t f2h(fdt32_t val) static uint32_t f2h(fdt32_t val)
{ {
char *buf = (char *)&val; char *buf = (char *)&val;
char i; char i;
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
/* Swap the bytes */ /* Swap the bytes */
i = buf[0]; buf[0] = buf[3]; buf[3] = i; i = buf[0]; buf[0] = buf[3]; buf[3] = i;
i = buf[1]; buf[1] = buf[2]; buf[2] = i; i = buf[1]; buf[1] = buf[2]; buf[2] = i;
#endif
return *(uint32_t *)buf; return val;
} }
/** /**

View file

@ -2,8 +2,10 @@
# Copyright (c) 2015 Stephen Warren # Copyright (c) 2015 Stephen Warren
# Copyright (c) 2015-2016, NVIDIA CORPORATION. All rights reserved. # Copyright (c) 2015-2016, NVIDIA CORPORATION. All rights reserved.
# Generate an HTML-formatted log file containing multiple streams of data, """
# each represented in a well-delineated/-structured fashion. Generate an HTML-formatted log file containing multiple streams of data,
each represented in a well-delineated/-structured fashion.
"""
import datetime import datetime
import html import html
@ -178,7 +180,7 @@ class RunAndLog(object):
raise exception raise exception
return output return output
class SectionCtxMgr(object): class SectionCtxMgr:
"""A context manager for Python's "with" statement, which allows a certain """A context manager for Python's "with" statement, which allows a certain
portion of test code to be logged to a separate section of the log file. portion of test code to be logged to a separate section of the log file.
Objects of this type should be created by factory functions in the Logfile Objects of this type should be created by factory functions in the Logfile
@ -206,7 +208,7 @@ class SectionCtxMgr(object):
def __exit__(self, extype, value, traceback): def __exit__(self, extype, value, traceback):
self.log.end_section(self.marker) self.log.end_section(self.marker)
class Logfile(object): class Logfile:
"""Generates an HTML-formatted log file containing multiple streams of """Generates an HTML-formatted log file containing multiple streams of
data, each represented in a well-delineated/-structured fashion.""" data, each represented in a well-delineated/-structured fashion."""
@ -320,8 +322,8 @@ $(document).ready(function () {
# The set of characters that should be represented as hexadecimal codes in # The set of characters that should be represented as hexadecimal codes in
# the log file. # the log file.
_nonprint = {ord('%')} _nonprint = {ord('%')}
_nonprint.update({c for c in range(0, 32) if c not in (9, 10)}) _nonprint.update(c for c in range(0, 32) if c not in (9, 10))
_nonprint.update({c for c in range(127, 256)}) _nonprint.update(range(127, 256))
def _escape(self, data): def _escape(self, data):
"""Render data format suitable for inclusion in an HTML document. """Render data format suitable for inclusion in an HTML document.

View file

@ -6,9 +6,6 @@
# Test efi loader implementation # Test efi loader implementation
import pytest
import u_boot_utils
""" """
Note: This test relies on boardenv_* containing configuration values to define Note: This test relies on boardenv_* containing configuration values to define
which network environment is available for testing. Without this, the parts which network environment is available for testing. Without this, the parts
@ -50,6 +47,9 @@ env__efi_loader_helloworld_file = {
} }
""" """
import pytest
import u_boot_utils
net_set_up = False net_set_up = False
def test_efi_pre_commands(u_boot_console): def test_efi_pre_commands(u_boot_console):
@ -80,7 +80,7 @@ def test_efi_setup_dhcp(u_boot_console):
env_vars = u_boot_console.config.env.get('env__net_static_env_vars', None) env_vars = u_boot_console.config.env.get('env__net_static_env_vars', None)
if not env_vars: if not env_vars:
pytest.skip('No DHCP server available') pytest.skip('No DHCP server available')
return None return
u_boot_console.run_command('setenv autoload no') u_boot_console.run_command('setenv autoload no')
output = u_boot_console.run_command('dhcp') output = u_boot_console.run_command('dhcp')
@ -193,7 +193,7 @@ def test_efi_grub_net(u_boot_console):
check_smbios = u_boot_console.config.env.get('env__efi_loader_check_smbios', False) check_smbios = u_boot_console.config.env.get('env__efi_loader_check_smbios', False)
if check_smbios: if check_smbios:
u_boot_console.wait_for('grub>') u_boot_console.wait_for('grub>')
output = u_boot_console.run_command('lsefisystab', wait_for_prompt=False, wait_for_echo=False) u_boot_console.run_command('lsefisystab', wait_for_prompt=False, wait_for_echo=False)
u_boot_console.wait_for('SMBIOS') u_boot_console.wait_for('SMBIOS')
# Then exit cleanly # Then exit cleanly

View file

@ -73,8 +73,7 @@ def test_efi_selftest_text_input(u_boot_console):
This function calls the text input EFI selftest. This function calls the text input EFI selftest.
""" """
u_boot_console.run_command(cmd='setenv efi_selftest text input') u_boot_console.run_command(cmd='setenv efi_selftest text input')
output = u_boot_console.run_command(cmd='bootefi selftest', u_boot_console.run_command(cmd='bootefi selftest', wait_for_prompt=False)
wait_for_prompt=False)
m = u_boot_console.p.expect([r'To terminate type \'x\'']) m = u_boot_console.p.expect([r'To terminate type \'x\''])
if m != 0: if m != 0:
raise Exception('No prompt for \'text input\' test') raise Exception('No prompt for \'text input\' test')
@ -143,8 +142,7 @@ def test_efi_selftest_text_input_ex(u_boot_console):
This function calls the extended text input EFI selftest. This function calls the extended text input EFI selftest.
""" """
u_boot_console.run_command(cmd='setenv efi_selftest extended text input') u_boot_console.run_command(cmd='setenv efi_selftest extended text input')
output = u_boot_console.run_command(cmd='bootefi selftest', u_boot_console.run_command(cmd='bootefi selftest', wait_for_prompt=False)
wait_for_prompt=False)
m = u_boot_console.p.expect([r'To terminate type \'CTRL\+x\'']) m = u_boot_console.p.expect([r'To terminate type \'CTRL\+x\''])
if m != 0: if m != 0:
raise Exception('No prompt for \'text input\' test') raise Exception('No prompt for \'text input\' test')

View file

@ -2,8 +2,10 @@
# Copyright (c) 2015 Stephen Warren # Copyright (c) 2015 Stephen Warren
# Copyright (c) 2015-2016, NVIDIA CORPORATION. All rights reserved. # Copyright (c) 2015-2016, NVIDIA CORPORATION. All rights reserved.
# Logic to interact with U-Boot running on real hardware, typically via a """
# physical serial port. Logic to interact with U-Boot running on real hardware, typically via a
physical serial port.
"""
import sys import sys
from u_boot_spawn import Spawn from u_boot_spawn import Spawn

View file

@ -2,7 +2,9 @@
# Copyright (c) 2015 Stephen Warren # Copyright (c) 2015 Stephen Warren
# Copyright (c) 2015-2016, NVIDIA CORPORATION. All rights reserved. # Copyright (c) 2015-2016, NVIDIA CORPORATION. All rights reserved.
# Logic to interact with the sandbox port of U-Boot, running as a sub-process. """
Logic to interact with the sandbox port of U-Boot, running as a sub-process.
"""
import time import time
from u_boot_spawn import Spawn from u_boot_spawn import Spawn

View file

@ -1,7 +1,9 @@
# SPDX-License-Identifier: GPL-2.0 # SPDX-License-Identifier: GPL-2.0
# Copyright (c) 2015-2016, NVIDIA CORPORATION. All rights reserved. # Copyright (c) 2015-2016, NVIDIA CORPORATION. All rights reserved.
# Logic to spawn a sub-process and interact with its stdio. """
Logic to spawn a sub-process and interact with its stdio.
"""
import os import os
import re import re
@ -9,12 +11,12 @@ import pty
import signal import signal
import select import select
import time import time
import traceback
class Timeout(Exception): class Timeout(Exception):
"""An exception sub-class that indicates that a timeout occurred.""" """An exception sub-class that indicates that a timeout occurred."""
pass
class Spawn(object): class Spawn:
"""Represents the stdio of a freshly created sub-process. Commands may be """Represents the stdio of a freshly created sub-process. Commands may be
sent to the process, and responses waited for. sent to the process, and responses waited for.
@ -58,14 +60,14 @@ class Spawn(object):
os.execvp(args[0], args) os.execvp(args[0], args)
except: except:
print('CHILD EXECEPTION:') print('CHILD EXECEPTION:')
import traceback
traceback.print_exc() traceback.print_exc()
finally: finally:
os._exit(255) os._exit(255)
try: try:
self.poll = select.poll() self.poll = select.poll()
self.poll.register(self.fd, select.POLLIN | select.POLLPRI | select.POLLERR | select.POLLHUP | select.POLLNVAL) self.poll.register(self.fd, select.POLLIN | select.POLLPRI | select.POLLERR |
select.POLLHUP | select.POLLNVAL)
except: except:
self.close() self.close()
raise raise
@ -106,7 +108,7 @@ class Spawn(object):
elif os.WIFSIGNALED(status): elif os.WIFSIGNALED(status):
signum = os.WTERMSIG(status) signum = os.WTERMSIG(status)
self.exit_code = -signum self.exit_code = -signum
self.exit_info = 'signal %d (%s)' % (signum, signal.Signals(signum)) self.exit_info = 'signal %d (%s)' % (signum, signal.Signals(signum).name)
self.waited = True self.waited = True
return False, self.exit_code, self.exit_info return False, self.exit_code, self.exit_info
@ -196,13 +198,11 @@ class Spawn(object):
# shouldn't and explain why. This is much more friendly than # shouldn't and explain why. This is much more friendly than
# just dying with an I/O error # just dying with an I/O error
if err.errno == 5: # Input/output error if err.errno == 5: # Input/output error
alive, exit_code, info = self.checkalive() alive, _, info = self.checkalive()
if alive: if alive:
raise raise err
else: raise ValueError('U-Boot exited with %s' % info)
raise ValueError('U-Boot exited with %s' % info) raise err
else:
raise
if self.logfile_read: if self.logfile_read:
self.logfile_read.write(c) self.logfile_read.write(c)
self.buf += c self.buf += c
@ -227,7 +227,7 @@ class Spawn(object):
""" """
os.close(self.fd) os.close(self.fd)
for i in range(100): for _ in range(100):
if not self.isalive(): if not self.isalive():
break break
time.sleep(0.1) time.sleep(0.1)

View file

@ -1,17 +1,20 @@
# SPDX-License-Identifier: GPL-2.0 # SPDX-License-Identifier: GPL-2.0
# Copyright (c) 2016, NVIDIA CORPORATION. All rights reserved. # Copyright (c) 2016, NVIDIA CORPORATION. All rights reserved.
# Utility code shared across multiple tests. """
Utility code shared across multiple tests.
"""
import hashlib import hashlib
import inspect import inspect
import os import os
import os.path import os.path
import pytest import pathlib
import signal import signal
import sys import sys
import time import time
import re import re
import pytest
def md5sum_data(data): def md5sum_data(data):
"""Calculate the MD5 hash of some data. """Calculate the MD5 hash of some data.
@ -48,7 +51,7 @@ def md5sum_file(fn, max_length=None):
data = fh.read(*params) data = fh.read(*params)
return md5sum_data(data) return md5sum_data(data)
class PersistentRandomFile(object): class PersistentRandomFile:
"""Generate and store information about a persistent file containing """Generate and store information about a persistent file containing
random data.""" random data."""
@ -144,7 +147,7 @@ def wait_until_file_open_fails(fn, ignore_errors):
Nothing. Nothing.
""" """
for i in range(100): for _ in range(100):
fh = attempt_to_open_file(fn) fh = attempt_to_open_file(fn)
if not fh: if not fh:
return return
@ -192,9 +195,9 @@ def run_and_log_expect_exception(u_boot_console, cmd, retcode, msg):
try: try:
runner = u_boot_console.log.get_runner(cmd[0], sys.stdout) runner = u_boot_console.log.get_runner(cmd[0], sys.stdout)
runner.run(cmd) runner.run(cmd)
except Exception as e: except Exception:
assert(retcode == runner.exit_status) assert retcode == runner.exit_status
assert(msg in runner.output) assert msg in runner.output
else: else:
raise Exception("Expected an exception with retcode %d message '%s'," raise Exception("Expected an exception with retcode %d message '%s',"
"but it was not raised" % (retcode, msg)) "but it was not raised" % (retcode, msg))
@ -279,17 +282,17 @@ class PersistentFileHelperCtxMgr(object):
if filename_timestamp < self.module_timestamp: if filename_timestamp < self.module_timestamp:
self.log.action('Removing stale generated file ' + self.log.action('Removing stale generated file ' +
self.filename) self.filename)
os.unlink(self.filename) pathlib.Path(self.filename).unlink()
def __exit__(self, extype, value, traceback): def __exit__(self, extype, value, traceback):
if extype: if extype:
try: try:
os.path.unlink(self.filename) pathlib.Path(self.filename).unlink()
except: except Exception:
pass pass
return return
logged = False logged = False
for i in range(20): for _ in range(20):
filename_timestamp = os.path.getmtime(self.filename) filename_timestamp = os.path.getmtime(self.filename)
if filename_timestamp > self.module_timestamp: if filename_timestamp > self.module_timestamp:
break break