diff options
author | Michael Brown <mcb30@ipxe.org> | 2023-03-01 15:35:14 +0000 |
---|---|---|
committer | Michael Brown <mcb30@ipxe.org> | 2023-03-01 15:35:14 +0000 |
commit | 587ef78ad003f8e57fae352f6405ba58b60b3a99 (patch) | |
tree | 7adf3c6bdc7ba11bd1d4e8917fdedb23bf72a51f | |
parent | 96bb6ba441653a30729ade38dc6c23bc9e2d2339 (diff) | |
download | ipxe-efivars.tar.gz |
WIP - EFI settingsefivars
-rw-r--r-- | src/config/config.c | 3 | ||||
-rw-r--r-- | src/config/defaults/efi.h | 2 | ||||
-rw-r--r-- | src/config/settings.h | 2 | ||||
-rw-r--r-- | src/include/ipxe/efi/Guid/GlobalVariable.h | 188 | ||||
-rw-r--r-- | src/include/ipxe/errfile.h | 1 | ||||
-rw-r--r-- | src/interface/efi/efi_settings.c | 189 |
6 files changed, 385 insertions, 0 deletions
diff --git a/src/config/config.c b/src/config/config.c index a81866132..329a41320 100644 --- a/src/config/config.c +++ b/src/config/config.c @@ -352,6 +352,9 @@ REQUIRE_OBJECT ( vram_settings ); #ifdef ACPI_SETTINGS REQUIRE_OBJECT ( acpi_settings ); #endif +#ifdef EFI_SETTINGS +REQUIRE_OBJECT ( efi_settings ); +#endif /* * Drag in selected keyboard map diff --git a/src/config/defaults/efi.h b/src/config/defaults/efi.h index 8e53b9ab6..cb9e2348a 100644 --- a/src/config/defaults/efi.h +++ b/src/config/defaults/efi.h @@ -48,6 +48,8 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #define REBOOT_CMD /* Reboot command */ +#define EFI_SETTINGS /* EFI variable settings */ + #if defined ( __i386__ ) || defined ( __x86_64__ ) #define IOAPI_X86 #define NAP_EFIX86 diff --git a/src/config/settings.h b/src/config/settings.h index d9c86a384..d7f787d38 100644 --- a/src/config/settings.h +++ b/src/config/settings.h @@ -9,6 +9,8 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); +#include <config/defaults.h> + #define PCI_SETTINGS /* PCI device settings */ //#define CPUID_SETTINGS /* CPUID settings */ //#define MEMMAP_SETTINGS /* Memory map settings */ diff --git a/src/include/ipxe/efi/Guid/GlobalVariable.h b/src/include/ipxe/efi/Guid/GlobalVariable.h new file mode 100644 index 000000000..5a9806cac --- /dev/null +++ b/src/include/ipxe/efi/Guid/GlobalVariable.h @@ -0,0 +1,188 @@ +/** @file + GUID for EFI (NVRAM) Variables. + + Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent + + @par Revision Reference: + GUID defined in UEFI 2.1 +**/ + +#ifndef __GLOBAL_VARIABLE_GUID_H__ +#define __GLOBAL_VARIABLE_GUID_H__ + +FILE_LICENCE ( BSD2_PATENT ); + +#define EFI_GLOBAL_VARIABLE \ + { \ + 0x8BE4DF61, 0x93CA, 0x11d2, {0xAA, 0x0D, 0x00, 0xE0, 0x98, 0x03, 0x2B, 0x8C } \ + } + +extern EFI_GUID gEfiGlobalVariableGuid; + +// +// Follow UEFI 2.4 spec: +// To prevent name collisions with possible future globally defined variables, +// other internal firmware data variables that are not defined here must be +// saved with a unique VendorGuid other than EFI_GLOBAL_VARIABLE or +// any other GUID defined by the UEFI Specification. Implementations must +// only permit the creation of variables with a UEFI Specification-defined +// VendorGuid when these variables are documented in the UEFI Specification. +// +// Note: except the globally defined variables defined below, the spec also defines +// L"Boot####" - A boot load option. +// L"Driver####" - A driver load option. +// L"SysPrep####" - A System Prep application load option. +// L"Key####" - Describes hot key relationship with a Boot#### load option. +// The attribute for them is NV+BS+RT, #### is a printed hex value, and no 0x or h +// is included in the hex value. They can not be expressed as a #define like other globally +// defined variables, it is because we can not list the Boot0000, Boot0001, etc one by one. +// + +/// +/// The language codes that the firmware supports. This value is deprecated. +/// Its attribute is BS+RT. +/// +#define EFI_LANG_CODES_VARIABLE_NAME L"LangCodes" +/// +/// The language code that the system is configured for. This value is deprecated. +/// Its attribute is NV+BS+RT. +/// +#define EFI_LANG_VARIABLE_NAME L"Lang" +/// +/// The firmware's boot managers timeout, in seconds, before initiating the default boot selection. +/// Its attribute is NV+BS+RT. +/// +#define EFI_TIME_OUT_VARIABLE_NAME L"Timeout" +/// +/// The language codes that the firmware supports. +/// Its attribute is BS+RT. +/// +#define EFI_PLATFORM_LANG_CODES_VARIABLE_NAME L"PlatformLangCodes" +/// +/// The language code that the system is configured for. +/// Its attribute is NV+BS+RT. +/// +#define EFI_PLATFORM_LANG_VARIABLE_NAME L"PlatformLang" +/// +/// The device path of the default input/output/error output console. +/// Its attribute is NV+BS+RT. +/// +#define EFI_CON_IN_VARIABLE_NAME L"ConIn" +#define EFI_CON_OUT_VARIABLE_NAME L"ConOut" +#define EFI_ERR_OUT_VARIABLE_NAME L"ErrOut" +/// +/// The device path of all possible input/output/error output devices. +/// Its attribute is BS+RT. +/// +#define EFI_CON_IN_DEV_VARIABLE_NAME L"ConInDev" +#define EFI_CON_OUT_DEV_VARIABLE_NAME L"ConOutDev" +#define EFI_ERR_OUT_DEV_VARIABLE_NAME L"ErrOutDev" +/// +/// The ordered boot option load list. +/// Its attribute is NV+BS+RT. +/// +#define EFI_BOOT_ORDER_VARIABLE_NAME L"BootOrder" +/// +/// The boot option for the next boot only. +/// Its attribute is NV+BS+RT. +/// +#define EFI_BOOT_NEXT_VARIABLE_NAME L"BootNext" +/// +/// The boot option that was selected for the current boot. +/// Its attribute is BS+RT. +/// +#define EFI_BOOT_CURRENT_VARIABLE_NAME L"BootCurrent" +/// +/// The types of boot options supported by the boot manager. Should be treated as read-only. +/// Its attribute is BS+RT. +/// +#define EFI_BOOT_OPTION_SUPPORT_VARIABLE_NAME L"BootOptionSupport" +/// +/// The ordered driver load option list. +/// Its attribute is NV+BS+RT. +/// +#define EFI_DRIVER_ORDER_VARIABLE_NAME L"DriverOrder" +/// +/// The ordered System Prep Application load option list. +/// Its attribute is NV+BS+RT. +/// +#define EFI_SYS_PREP_ORDER_VARIABLE_NAME L"SysPrepOrder" +/// +/// Identifies the level of hardware error record persistence +/// support implemented by the platform. This variable is +/// only modified by firmware and is read-only to the OS. +/// Its attribute is NV+BS+RT. +/// +#define EFI_HW_ERR_REC_SUPPORT_VARIABLE_NAME L"HwErrRecSupport" +/// +/// Whether the system is operating in setup mode (1) or not (0). +/// All other values are reserved. Should be treated as read-only. +/// Its attribute is BS+RT. +/// +#define EFI_SETUP_MODE_NAME L"SetupMode" +/// +/// The Key Exchange Key Signature Database. +/// Its attribute is NV+BS+RT+AT. +/// +#define EFI_KEY_EXCHANGE_KEY_NAME L"KEK" +/// +/// The public Platform Key. +/// Its attribute is NV+BS+RT+AT. +/// +#define EFI_PLATFORM_KEY_NAME L"PK" +/// +/// Array of GUIDs representing the type of signatures supported +/// by the platform firmware. Should be treated as read-only. +/// Its attribute is BS+RT. +/// +#define EFI_SIGNATURE_SUPPORT_NAME L"SignatureSupport" +/// +/// Whether the platform firmware is operating in Secure boot mode (1) or not (0). +/// All other values are reserved. Should be treated as read-only. +/// Its attribute is BS+RT. +/// +#define EFI_SECURE_BOOT_MODE_NAME L"SecureBoot" +/// +/// The OEM's default Key Exchange Key Signature Database. Should be treated as read-only. +/// Its attribute is BS+RT. +/// +#define EFI_KEK_DEFAULT_VARIABLE_NAME L"KEKDefault" +/// +/// The OEM's default public Platform Key. Should be treated as read-only. +/// Its attribute is BS+RT. +/// +#define EFI_PK_DEFAULT_VARIABLE_NAME L"PKDefault" +/// +/// The OEM's default secure boot signature store. Should be treated as read-only. +/// Its attribute is BS+RT. +/// +#define EFI_DB_DEFAULT_VARIABLE_NAME L"dbDefault" +/// +/// The OEM's default secure boot blacklist signature store. Should be treated as read-only. +/// Its attribute is BS+RT. +/// +#define EFI_DBX_DEFAULT_VARIABLE_NAME L"dbxDefault" +/// +/// The OEM's default secure boot timestamp signature store. Should be treated as read-only. +/// Its attribute is BS+RT. +/// +#define EFI_DBT_DEFAULT_VARIABLE_NAME L"dbtDefault" +/// +/// Allows the firmware to indicate supported features and actions to the OS. +/// Its attribute is BS+RT. +/// +#define EFI_OS_INDICATIONS_SUPPORT_VARIABLE_NAME L"OsIndicationsSupported" +/// +/// Allows the OS to request the firmware to enable certain features and to take certain actions. +/// Its attribute is NV+BS+RT. +/// +#define EFI_OS_INDICATIONS_VARIABLE_NAME L"OsIndications" +/// +/// Whether the system is configured to use only vendor provided +/// keys or not. Should be treated as read-only. +/// Its attribute is BS+RT. +/// +#define EFI_VENDOR_KEYS_VARIABLE_NAME L"VendorKeys" + +#endif diff --git a/src/include/ipxe/errfile.h b/src/include/ipxe/errfile.h index e6fd8524e..a540ab287 100644 --- a/src/include/ipxe/errfile.h +++ b/src/include/ipxe/errfile.h @@ -404,6 +404,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #define ERRFILE_dhe ( ERRFILE_OTHER | 0x005a0000 ) #define ERRFILE_efi_cmdline ( ERRFILE_OTHER | 0x005b0000 ) #define ERRFILE_efi_rng ( ERRFILE_OTHER | 0x005c0000 ) +#define ERRFILE_efi_settings ( ERRFILE_OTHER | 0x005d0000 ) /** @} */ diff --git a/src/interface/efi/efi_settings.c b/src/interface/efi/efi_settings.c new file mode 100644 index 000000000..652396b17 --- /dev/null +++ b/src/interface/efi/efi_settings.c @@ -0,0 +1,189 @@ +/* + * Copyright (C) 2023 Michael Brown <mbrown@fensystems.co.uk>. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + * + * You can also choose to distribute this program under the terms of + * the Unmodified Binary Distribution Licence (as given in the file + * COPYING.UBDL), provided that you have satisfied its requirements. + */ + +FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); + +/** + * @file + * + * EFI variable settings + * + */ + +#include <stdlib.h> +#include <string.h> +#include <errno.h> +#include <ipxe/settings.h> +#include <ipxe/init.h> +#include <ipxe/efi/efi.h> +#include <ipxe/efi/Guid/GlobalVariable.h> + +/** An EFI variable settings block */ +struct efivar_settings { + /** Settings block */ + struct settings settings; + /** Vendor GUID */ + EFI_GUID guid; +}; + +/** EFI settings scope */ +static const struct settings_scope efivar_scope; + +/** + * Check applicability of EFI variable setting + * + * @v settings Settings block + * @v setting Setting + * @ret applies Setting applies within this settings block + */ +static int efivar_applies ( struct settings *settings __unused, + const struct setting *setting ) { + + return ( setting->scope == &efivar_scope ); +} + +/** + * Fetch value of EFI variable setting + * + * @v settings Settings block + * @v setting Setting to fetch + * @v data Buffer to fill with setting data + * @v len Length of buffer + * @ret len Length of setting data, or negative error + */ +static int efivar_fetch ( struct settings *settings, struct setting *setting, + void *data, size_t len ) { + EFI_RUNTIME_SERVICES *rs = efi_systab->RuntimeServices; + struct efivar_settings *efivars = + container_of ( settings, struct efivar_settings, settings ); + size_t name_len = strlen ( setting->name ); + CHAR16 wname[ name_len + 1 /* wNUL */ ]; + UINT32 attrs; + UINTN size; + void *buf; + unsigned int i; + EFI_STATUS efirc; + int rc; + + /* Convert name to UCS-2 */ + for ( i = 0 ; i <= name_len ; i++ ) + wname[i] = setting->name[i]; + + /* Get variable length */ + size = 0; + efirc = rs->GetVariable ( wname, &efivars->guid, &attrs, &size, NULL ); + if ( ( efirc != 0 ) && ( efirc != EFI_BUFFER_TOO_SMALL ) ) { + rc = -EEFI ( efirc ); + DBGC ( efivars, "EFIVAR %s:%s not present: %s\n", + efi_guid_ntoa ( &efivars->guid ), setting->name, + strerror ( rc ) ); + goto err_len; + } + + /* Allocate temporary buffer, since GetVariable() is not + * guaranteed to return partial data for an underlength + * buffer. + */ + buf = malloc ( size ); + if ( ! buf ) { + rc = -ENOMEM; + goto err_alloc; + } + + /* Get variable value */ + if ( ( efirc = rs->GetVariable ( wname, &efivars->guid, &attrs, &size, + buf ) ) != 0 ) { + rc = -EEFI ( efirc ); + DBGC ( efivars, "EFIVAR %s:%s could not get %zd bytes: %s\n", + efi_guid_ntoa ( &efivars->guid ), setting->name, + ( ( size_t ) size ), strerror ( rc ) ); + goto err_get; + } + DBGC ( efivars, "EFIVAR %s:%s:\n", efi_guid_ntoa ( &efivars->guid ), + setting->name ); + DBGC_HDA ( efivars, 0, buf, size ); + + /* Return setting value */ + if ( len > size ) + len = size; + memcpy ( data, buf, len ); + if ( ! setting->type ) + setting->type = &setting_type_hex; + + /* Free temporary buffer */ + free ( buf ); + + return size; + + err_get: + free ( buf ); + err_alloc: + err_len: + return rc; +} + +/** EFI variable settings operations */ +static struct settings_operations efivar_operations = { + .applies = efivar_applies, + .fetch = efivar_fetch, +}; + +/** Well-known EFI variable settings blocks */ +static struct efivar_settings efivar_settings[] = { + { .settings = { .name = "efi" }, .guid = EFI_GLOBAL_VARIABLE }, +}; + +/** + * Initialise EFI variable settings + * + */ +static void efivar_init ( void ) { + struct efivar_settings *efivars; + const char *name; + unsigned int i; + int rc; + + /* Register all settings blocks */ + for ( i = 0 ; i < ( sizeof ( efivar_settings ) / + sizeof ( efivar_settings[0] ) ) ; i++ ) { + + /* Initialise settings block */ + efivars = &efivar_settings[i]; + settings_init ( &efivars->settings, &efivar_operations, NULL, + &efivar_scope ); + + /* Register settings block */ + name = efivars->settings.name; + if ( ( rc = register_settings ( &efivars->settings, NULL, + name ) ) != 0 ) { + DBGC ( &efivar_settings, "EFIVAR could not register " + "%s: %s\n", name, strerror ( rc ) ); + /* Continue trying to register remaining blocks */ + } + } +} + +/** EFI variable settings initialiser */ +struct init_fn efivar_init_fn __init_fn ( INIT_NORMAL ) = { + .initialise = efivar_init, +}; |