mirror of
https://gitlab.com/qemu-project/ipxe.git
synced 2025-11-03 07:59:06 +08:00
Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 587ef78ad0 |
@ -355,6 +355,10 @@ static size_t bzimage_load_initrd ( struct image *image,
|
||||
size_t offset;
|
||||
size_t pad_len;
|
||||
|
||||
/* Do not include kernel image itself as an initrd */
|
||||
if ( initrd == image )
|
||||
return 0;
|
||||
|
||||
/* Create cpio header for non-prebuilt images */
|
||||
offset = cpio_header ( initrd, &cpio );
|
||||
|
||||
@ -402,6 +406,10 @@ static int bzimage_check_initrds ( struct image *image,
|
||||
/* Calculate total loaded length of initrds */
|
||||
for_each_image ( initrd ) {
|
||||
|
||||
/* Skip kernel */
|
||||
if ( initrd == image )
|
||||
continue;
|
||||
|
||||
/* Calculate length */
|
||||
len += bzimage_load_initrd ( image, initrd, UNULL );
|
||||
len = bzimage_align ( len );
|
||||
|
||||
@ -204,6 +204,10 @@ static int multiboot_add_modules ( struct image *image, physaddr_t start,
|
||||
break;
|
||||
}
|
||||
|
||||
/* Do not include kernel image itself as a module */
|
||||
if ( module_image == image )
|
||||
continue;
|
||||
|
||||
/* Page-align the module */
|
||||
start = ( ( start + 0xfff ) & ~0xfff );
|
||||
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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 */
|
||||
|
||||
@ -312,7 +312,7 @@ void unregister_image ( struct image *image ) {
|
||||
struct image * find_image ( const char *name ) {
|
||||
struct image *image;
|
||||
|
||||
for_each_image ( image ) {
|
||||
list_for_each_entry ( image, &images, list ) {
|
||||
if ( strcmp ( image->name, name ) == 0 )
|
||||
return image;
|
||||
}
|
||||
@ -349,8 +349,9 @@ int image_exec ( struct image *image ) {
|
||||
/* Preserve record of any currently-running image */
|
||||
saved_current_image = current_image;
|
||||
|
||||
/* Take out a temporary reference to the image, so that it
|
||||
* does not get freed when temporarily unregistered.
|
||||
/* Take out a temporary reference to the image. This allows
|
||||
* the image to unregister itself if necessary, without
|
||||
* automatically freeing itself.
|
||||
*/
|
||||
current_image = image_get ( image );
|
||||
|
||||
@ -370,9 +371,6 @@ int image_exec ( struct image *image ) {
|
||||
/* Record boot attempt */
|
||||
syslog ( LOG_NOTICE, "Executing \"%s\"\n", image->name );
|
||||
|
||||
/* Temporarily unregister the image during its execution */
|
||||
unregister_image ( image );
|
||||
|
||||
/* Try executing the image */
|
||||
if ( ( rc = image->type->exec ( image ) ) != 0 ) {
|
||||
DBGC ( image, "IMAGE %s could not execute: %s\n",
|
||||
@ -389,10 +387,6 @@ int image_exec ( struct image *image ) {
|
||||
image->name, strerror ( rc ) );
|
||||
}
|
||||
|
||||
/* Re-register image (unless due to be replaced) */
|
||||
if ( ! image->replacement )
|
||||
register_image ( image );
|
||||
|
||||
/* Pick up replacement image before we drop the original
|
||||
* image's temporary reference. The replacement image must
|
||||
* already be registered, so we don't need to hold a temporary
|
||||
|
||||
@ -290,18 +290,6 @@ static int intel_reset ( struct intel_nic *intel ) {
|
||||
pba, readl ( intel->regs + INTEL_PBA ) );
|
||||
}
|
||||
|
||||
/* The Intel I210's packet buffer size registers reset only on
|
||||
* power up. If an operating system changes these but then
|
||||
* the computer recieves a reset signal without losing power,
|
||||
* the registers will stay the same (but be incompatible with
|
||||
* other register defaults), thus making the device unable to
|
||||
* pass traffic.
|
||||
*/
|
||||
if ( intel->flags & INTEL_PBSIZE_RST ) {
|
||||
writel ( INTEL_RXPBS_I210, intel->regs + INTEL_RXPBS );
|
||||
writel ( INTEL_TXPBS_I210, intel->regs + INTEL_TXPBS );
|
||||
}
|
||||
|
||||
/* Always reset MAC. Required to reset the TX and RX rings. */
|
||||
writel ( ( ctrl | INTEL_CTRL_RST ), intel->regs + INTEL_CTRL );
|
||||
mdelay ( INTEL_RESET_DELAY_MS );
|
||||
@ -1151,7 +1139,7 @@ static struct pci_device_id intel_nics[] = {
|
||||
PCI_ROM ( 0x8086, 0x1525, "82567v-4", "82567V-4", 0 ),
|
||||
PCI_ROM ( 0x8086, 0x1526, "82576-5", "82576", 0 ),
|
||||
PCI_ROM ( 0x8086, 0x1527, "82580-f2", "82580 Fiber", 0 ),
|
||||
PCI_ROM ( 0x8086, 0x1533, "i210", "I210", INTEL_PBSIZE_RST ),
|
||||
PCI_ROM ( 0x8086, 0x1533, "i210", "I210", 0 ),
|
||||
PCI_ROM ( 0x8086, 0x1539, "i211", "I211", 0 ),
|
||||
PCI_ROM ( 0x8086, 0x153a, "i217lm", "I217-LM", INTEL_NO_PHY_RST ),
|
||||
PCI_ROM ( 0x8086, 0x153b, "i217v", "I217-V", 0 ),
|
||||
@ -1159,7 +1147,7 @@ static struct pci_device_id intel_nics[] = {
|
||||
PCI_ROM ( 0x8086, 0x155a, "i218lm", "I218-LM", INTEL_NO_PHY_RST ),
|
||||
PCI_ROM ( 0x8086, 0x156f, "i219lm", "I219-LM", INTEL_I219 ),
|
||||
PCI_ROM ( 0x8086, 0x1570, "i219v", "I219-V", INTEL_I219 ),
|
||||
PCI_ROM ( 0x8086, 0x157b, "i210-2", "I210", INTEL_PBSIZE_RST ),
|
||||
PCI_ROM ( 0x8086, 0x157b, "i210-2", "I210", 0 ),
|
||||
PCI_ROM ( 0x8086, 0x15a0, "i218lm-2", "I218-LM", INTEL_NO_PHY_RST ),
|
||||
PCI_ROM ( 0x8086, 0x15a1, "i218v-2", "I218-V", 0 ),
|
||||
PCI_ROM ( 0x8086, 0x15a2, "i218lm-3", "I218-LM", INTEL_NO_PHY_RST ),
|
||||
|
||||
@ -138,10 +138,6 @@ struct intel_descriptor {
|
||||
/** Packet Buffer Size */
|
||||
#define INTEL_PBS 0x01008UL
|
||||
|
||||
/** Receive packet buffer size */
|
||||
#define INTEL_RXPBS 0x02404UL
|
||||
#define INTEL_RXPBS_I210 0x000000a2UL /**< I210 power-up default */
|
||||
|
||||
/** Receive Descriptor register block */
|
||||
#define INTEL_RD 0x02800UL
|
||||
|
||||
@ -158,10 +154,6 @@ struct intel_descriptor {
|
||||
/** Receive buffer length */
|
||||
#define INTEL_RX_MAX_LEN 2048
|
||||
|
||||
/** Transmit packet buffer size */
|
||||
#define INTEL_TXPBS 0x03404UL
|
||||
#define INTEL_TXPBS_I210 0x04000014UL /**< I210 power-up default */
|
||||
|
||||
/** Transmit Descriptor register block */
|
||||
#define INTEL_TD 0x03800UL
|
||||
|
||||
@ -327,8 +319,6 @@ enum intel_flags {
|
||||
INTEL_NO_ASDE = 0x0008,
|
||||
/** Reset may cause a complete device hang */
|
||||
INTEL_RST_HANG = 0x0010,
|
||||
/** PBSIZE registers must be explicitly reset */
|
||||
INTEL_PBSIZE_RST = 0x0020,
|
||||
};
|
||||
|
||||
/** The i219 has a seriously broken reset mechanism */
|
||||
|
||||
@ -473,7 +473,6 @@ static struct pci_device_id intelx_nics[] = {
|
||||
PCI_ROM ( 0x8086, 0x10f9, "82599-cx4", "82599 (CX4)", 0 ),
|
||||
PCI_ROM ( 0x8086, 0x10fb, "82599-sfp", "82599 (SFI/SFP+)", 0 ),
|
||||
PCI_ROM ( 0x8086, 0x10fc, "82599-xaui", "82599 (XAUI/BX4)", 0 ),
|
||||
PCI_ROM ( 0x8086, 0x151c, "82599-tn", "82599 (TN)", 0 ),
|
||||
PCI_ROM ( 0x8086, 0x1528, "x540t", "X540-AT2/X540-BT2", 0 ),
|
||||
PCI_ROM ( 0x8086, 0x154d, "82599-sfp-sf2", "82599 (SFI/SFP+)", 0 ),
|
||||
PCI_ROM ( 0x8086, 0x1557, "82599en-sfp", "82599 (Single Port SFI Only)", 0 ),
|
||||
|
||||
@ -147,38 +147,38 @@ static int efi_image_exec ( struct image *image ) {
|
||||
/* Find an appropriate device handle to use */
|
||||
snpdev = last_opened_snpdev();
|
||||
if ( ! snpdev ) {
|
||||
DBGC ( image, "EFIIMAGE %s could not identify SNP device\n",
|
||||
image->name );
|
||||
DBGC ( image, "EFIIMAGE %p could not identify SNP device\n",
|
||||
image );
|
||||
rc = -ENODEV;
|
||||
goto err_no_snpdev;
|
||||
}
|
||||
|
||||
/* Install file I/O protocols */
|
||||
if ( ( rc = efi_file_install ( snpdev->handle ) ) != 0 ) {
|
||||
DBGC ( image, "EFIIMAGE %s could not install file protocol: "
|
||||
"%s\n", image->name, strerror ( rc ) );
|
||||
DBGC ( image, "EFIIMAGE %p could not install file protocol: "
|
||||
"%s\n", image, strerror ( rc ) );
|
||||
goto err_file_install;
|
||||
}
|
||||
|
||||
/* Install PXE base code protocol */
|
||||
if ( ( rc = efi_pxe_install ( snpdev->handle, snpdev->netdev ) ) != 0 ){
|
||||
DBGC ( image, "EFIIMAGE %s could not install PXE protocol: "
|
||||
"%s\n", image->name, strerror ( rc ) );
|
||||
DBGC ( image, "EFIIMAGE %p could not install PXE protocol: "
|
||||
"%s\n", image, strerror ( rc ) );
|
||||
goto err_pxe_install;
|
||||
}
|
||||
|
||||
/* Install iPXE download protocol */
|
||||
if ( ( rc = efi_download_install ( snpdev->handle ) ) != 0 ) {
|
||||
DBGC ( image, "EFIIMAGE %s could not install iPXE download "
|
||||
"protocol: %s\n", image->name, strerror ( rc ) );
|
||||
DBGC ( image, "EFIIMAGE %p could not install iPXE download "
|
||||
"protocol: %s\n", image, strerror ( rc ) );
|
||||
goto err_download_install;
|
||||
}
|
||||
|
||||
/* Create device path for image */
|
||||
path = efi_image_path ( image, snpdev->path );
|
||||
if ( ! path ) {
|
||||
DBGC ( image, "EFIIMAGE %s could not create device path\n",
|
||||
image->name );
|
||||
DBGC ( image, "EFIIMAGE %p could not create device path\n",
|
||||
image );
|
||||
rc = -ENOMEM;
|
||||
goto err_image_path;
|
||||
}
|
||||
@ -186,8 +186,8 @@ static int efi_image_exec ( struct image *image ) {
|
||||
/* Create command line for image */
|
||||
cmdline = efi_image_cmdline ( image );
|
||||
if ( ! cmdline ) {
|
||||
DBGC ( image, "EFIIMAGE %s could not create command line\n",
|
||||
image->name );
|
||||
DBGC ( image, "EFIIMAGE %p could not create command line\n",
|
||||
image );
|
||||
rc = -ENOMEM;
|
||||
goto err_cmdline;
|
||||
}
|
||||
@ -199,8 +199,8 @@ static int efi_image_exec ( struct image *image ) {
|
||||
image->len, &handle ) ) != 0 ) {
|
||||
/* Not an EFI image */
|
||||
rc = -EEFI_LOAD ( efirc );
|
||||
DBGC ( image, "EFIIMAGE %s could not load: %s\n",
|
||||
image->name, strerror ( rc ) );
|
||||
DBGC ( image, "EFIIMAGE %p could not load: %s\n",
|
||||
image, strerror ( rc ) );
|
||||
if ( efirc == EFI_SECURITY_VIOLATION ) {
|
||||
goto err_load_image_security_violation;
|
||||
} else {
|
||||
@ -220,8 +220,8 @@ static int efi_image_exec ( struct image *image ) {
|
||||
|
||||
/* Some EFI 1.10 implementations seem not to fill in DeviceHandle */
|
||||
if ( loaded.image->DeviceHandle == NULL ) {
|
||||
DBGC ( image, "EFIIMAGE %s filling in missing DeviceHandle\n",
|
||||
image->name );
|
||||
DBGC ( image, "EFIIMAGE %p filling in missing DeviceHandle\n",
|
||||
image );
|
||||
loaded.image->DeviceHandle = snpdev->handle;
|
||||
}
|
||||
|
||||
@ -251,14 +251,14 @@ static int efi_image_exec ( struct image *image ) {
|
||||
/* Start the image */
|
||||
if ( ( efirc = bs->StartImage ( handle, NULL, NULL ) ) != 0 ) {
|
||||
rc = -EEFI_START ( efirc );
|
||||
DBGC ( image, "EFIIMAGE %s could not start (or returned with "
|
||||
"error): %s\n", image->name, strerror ( rc ) );
|
||||
DBGC ( image, "EFIIMAGE %p could not start (or returned with "
|
||||
"error): %s\n", image, strerror ( rc ) );
|
||||
goto err_start_image;
|
||||
}
|
||||
|
||||
/* If image was a driver, connect it up to anything available */
|
||||
if ( type == EfiBootServicesCode ) {
|
||||
DBGC ( image, "EFIIMAGE %s connecting drivers\n", image->name );
|
||||
DBGC ( image, "EFIIMAGE %p connecting drivers\n", image );
|
||||
efi_driver_reconnect_all();
|
||||
}
|
||||
|
||||
@ -324,8 +324,8 @@ static int efi_image_probe ( struct image *image ) {
|
||||
image->len, &handle ) ) != 0 ) {
|
||||
/* Not an EFI image */
|
||||
rc = -EEFI_LOAD ( efirc );
|
||||
DBGC ( image, "EFIIMAGE %s could not load: %s\n",
|
||||
image->name, strerror ( rc ) );
|
||||
DBGC ( image, "EFIIMAGE %p could not load: %s\n",
|
||||
image, strerror ( rc ) );
|
||||
if ( efirc == EFI_SECURITY_VIOLATION ) {
|
||||
goto err_load_image_security_violation;
|
||||
} else {
|
||||
|
||||
@ -197,6 +197,11 @@ static int script_exec ( struct image *image ) {
|
||||
size_t saved_offset;
|
||||
int rc;
|
||||
|
||||
/* Temporarily de-register image, so that a "boot" command
|
||||
* doesn't throw us into an execution loop.
|
||||
*/
|
||||
unregister_image ( image );
|
||||
|
||||
/* Preserve state of any currently-running script */
|
||||
saved_offset = script_offset;
|
||||
|
||||
@ -207,6 +212,10 @@ static int script_exec ( struct image *image ) {
|
||||
/* Restore saved state */
|
||||
script_offset = saved_offset;
|
||||
|
||||
/* Re-register image (unless we have been replaced) */
|
||||
if ( ! image->replacement )
|
||||
register_image ( image );
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
188
src/include/ipxe/efi/Guid/GlobalVariable.h
Normal file
188
src/include/ipxe/efi/Guid/GlobalVariable.h
Normal file
@ -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
|
||||
@ -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 )
|
||||
|
||||
/** @} */
|
||||
|
||||
|
||||
@ -52,9 +52,6 @@ struct tls_header {
|
||||
/** Change cipher content type */
|
||||
#define TLS_TYPE_CHANGE_CIPHER 20
|
||||
|
||||
/** Change cipher spec magic byte */
|
||||
#define TLS_CHANGE_CIPHER_SPEC 1
|
||||
|
||||
/** Alert content type */
|
||||
#define TLS_TYPE_ALERT 21
|
||||
|
||||
@ -398,8 +395,6 @@ struct tls_connection {
|
||||
struct io_buffer rx_header_iobuf;
|
||||
/** List of received data buffers */
|
||||
struct list_head rx_data;
|
||||
/** Received handshake fragment */
|
||||
struct io_buffer *rx_handshake;
|
||||
};
|
||||
|
||||
/** RX I/O buffer size
|
||||
|
||||
@ -93,18 +93,8 @@ struct efi_file {
|
||||
size_t ( * read ) ( struct efi_file_reader *reader );
|
||||
};
|
||||
|
||||
/** An EFI fixed device path file */
|
||||
struct efi_file_path {
|
||||
/** EFI file */
|
||||
struct efi_file file;
|
||||
/** Device path */
|
||||
EFI_DEVICE_PATH_PROTOCOL *path;
|
||||
/** EFI handle */
|
||||
EFI_HANDLE handle;
|
||||
};
|
||||
|
||||
static struct efi_file efi_file_root;
|
||||
static struct efi_file_path efi_file_initrd;
|
||||
static struct efi_file efi_file_initrd;
|
||||
|
||||
/**
|
||||
* Free EFI file
|
||||
@ -140,7 +130,7 @@ static struct image * efi_file_find ( const char *name ) {
|
||||
struct image *image;
|
||||
|
||||
/* Find image */
|
||||
for_each_image ( image ) {
|
||||
list_for_each_entry ( image, &images, list ) {
|
||||
if ( strcasecmp ( image->name, name ) == 0 )
|
||||
return image;
|
||||
}
|
||||
@ -250,6 +240,10 @@ static size_t efi_file_read_initrd ( struct efi_file_reader *reader ) {
|
||||
len = 0;
|
||||
for_each_image ( image ) {
|
||||
|
||||
/* Ignore currently executing image */
|
||||
if ( image == current_image )
|
||||
continue;
|
||||
|
||||
/* Pad to alignment boundary */
|
||||
pad_len = ( ( -reader->pos ) & ( INITRD_ALIGN - 1 ) );
|
||||
if ( pad_len ) {
|
||||
@ -368,8 +362,8 @@ efi_file_open ( EFI_FILE_PROTOCOL *this, EFI_FILE_PROTOCOL **new,
|
||||
}
|
||||
|
||||
/* Allow magic initrd to be opened */
|
||||
if ( strcasecmp ( name, efi_file_initrd.file.name ) == 0 )
|
||||
return efi_file_open_fixed ( &efi_file_initrd.file, new );
|
||||
if ( strcasecmp ( name, efi_file_initrd.name ) == 0 )
|
||||
return efi_file_open_fixed ( &efi_file_initrd, new );
|
||||
|
||||
/* Identify image */
|
||||
image = efi_file_find ( name );
|
||||
@ -711,10 +705,10 @@ static EFI_STATUS EFIAPI efi_file_flush ( EFI_FILE_PROTOCOL *this ) {
|
||||
* @v data Buffer, or NULL
|
||||
* @ret efirc EFI status code
|
||||
*/
|
||||
static EFI_STATUS EFIAPI
|
||||
efi_file_load ( EFI_LOAD_FILE2_PROTOCOL *this,
|
||||
EFI_DEVICE_PATH_PROTOCOL *path __unused,
|
||||
BOOLEAN boot __unused, UINTN *len, VOID *data ) {
|
||||
static EFI_STATUS EFIAPI efi_file_load ( EFI_LOAD_FILE2_PROTOCOL *this,
|
||||
EFI_DEVICE_PATH_PROTOCOL *path __unused,
|
||||
BOOLEAN boot __unused, UINTN *len,
|
||||
VOID *data ) {
|
||||
struct efi_file *file = container_of ( this, struct efi_file, load );
|
||||
size_t max_len;
|
||||
size_t file_len;
|
||||
@ -762,6 +756,30 @@ static struct efi_file efi_file_root = {
|
||||
.name = "",
|
||||
};
|
||||
|
||||
/** Magic initrd file */
|
||||
static struct efi_file efi_file_initrd = {
|
||||
.refcnt = REF_INIT ( ref_no_free ),
|
||||
.file = {
|
||||
.Revision = EFI_FILE_PROTOCOL_REVISION,
|
||||
.Open = efi_file_open,
|
||||
.Close = efi_file_close,
|
||||
.Delete = efi_file_delete,
|
||||
.Read = efi_file_read,
|
||||
.Write = efi_file_write,
|
||||
.GetPosition = efi_file_get_position,
|
||||
.SetPosition = efi_file_set_position,
|
||||
.GetInfo = efi_file_get_info,
|
||||
.SetInfo = efi_file_set_info,
|
||||
.Flush = efi_file_flush,
|
||||
},
|
||||
.load = {
|
||||
.LoadFile = efi_file_load,
|
||||
},
|
||||
.image = NULL,
|
||||
.name = "initrd.magic",
|
||||
.read = efi_file_read_initrd,
|
||||
};
|
||||
|
||||
/** Linux initrd fixed device path */
|
||||
static struct {
|
||||
VENDOR_DEVICE_PATH vendor;
|
||||
@ -782,33 +800,6 @@ static struct {
|
||||
},
|
||||
};
|
||||
|
||||
/** Magic initrd file */
|
||||
static struct efi_file_path efi_file_initrd = {
|
||||
.file = {
|
||||
.refcnt = REF_INIT ( ref_no_free ),
|
||||
.file = {
|
||||
.Revision = EFI_FILE_PROTOCOL_REVISION,
|
||||
.Open = efi_file_open,
|
||||
.Close = efi_file_close,
|
||||
.Delete = efi_file_delete,
|
||||
.Read = efi_file_read,
|
||||
.Write = efi_file_write,
|
||||
.GetPosition = efi_file_get_position,
|
||||
.SetPosition = efi_file_set_position,
|
||||
.GetInfo = efi_file_get_info,
|
||||
.SetInfo = efi_file_set_info,
|
||||
.Flush = efi_file_flush,
|
||||
},
|
||||
.load = {
|
||||
.LoadFile = efi_file_load,
|
||||
},
|
||||
.image = NULL,
|
||||
.name = "initrd.magic",
|
||||
.read = efi_file_read_initrd,
|
||||
},
|
||||
.path = &efi_file_initrd_path.vendor.Header,
|
||||
};
|
||||
|
||||
/**
|
||||
* Open root directory
|
||||
*
|
||||
@ -918,148 +909,107 @@ static EFI_DISK_IO_PROTOCOL efi_disk_io_protocol = {
|
||||
};
|
||||
|
||||
/**
|
||||
* Claim use of fixed device path
|
||||
* (Re)install fixed device path file
|
||||
*
|
||||
* @v file Fixed device path file
|
||||
* @ret rc Return status code
|
||||
*
|
||||
* The design choice in Linux of using a single fixed device path is
|
||||
* unfortunately messy to support, since device paths must be unique
|
||||
* within a system. When multiple bootloaders are used (e.g. GRUB
|
||||
* loading iPXE loading Linux) then only one bootloader can ever
|
||||
* install the device path onto a handle. Bootloaders must therefore
|
||||
* be prepared to locate an existing handle and uninstall its device
|
||||
* path protocol instance before installing a new handle with the
|
||||
* required device path.
|
||||
*/
|
||||
static int efi_file_path_claim ( struct efi_file_path *file ) {
|
||||
EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
|
||||
EFI_DEVICE_PATH_PROTOCOL *end;
|
||||
EFI_HANDLE handle;
|
||||
VOID *old;
|
||||
EFI_STATUS efirc;
|
||||
int rc;
|
||||
|
||||
/* Sanity check */
|
||||
assert ( file->handle == NULL );
|
||||
|
||||
/* Locate handle with this device path, if any */
|
||||
end = file->path;
|
||||
if ( ( ( efirc = bs->LocateDevicePath ( &efi_device_path_protocol_guid,
|
||||
&end, &handle ) ) != 0 ) ||
|
||||
( end->Type != END_DEVICE_PATH_TYPE ) ) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Locate device path protocol on this handle */
|
||||
if ( ( ( efirc = bs->HandleProtocol ( handle,
|
||||
&efi_device_path_protocol_guid,
|
||||
&old ) ) != 0 ) ) {
|
||||
rc = -EEFI ( efirc );
|
||||
DBGC ( file, "EFIFILE %s could not locate %s: %s\n",
|
||||
efi_file_name ( &file->file ),
|
||||
efi_devpath_text ( file->path ), strerror ( rc ) );
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Uninstall device path protocol, leaving other protocols untouched */
|
||||
if ( ( efirc = bs->UninstallMultipleProtocolInterfaces (
|
||||
handle,
|
||||
&efi_device_path_protocol_guid, old,
|
||||
NULL ) ) != 0 ) {
|
||||
rc = -EEFI ( efirc );
|
||||
DBGC ( file, "EFIFILE %s could not claim %s: %s\n",
|
||||
efi_file_name ( &file->file ),
|
||||
efi_devpath_text ( file->path ), strerror ( rc ) );
|
||||
return rc;
|
||||
}
|
||||
|
||||
DBGC ( file, "EFIFILE %s claimed %s",
|
||||
efi_file_name ( &file->file ), efi_devpath_text ( file->path ) );
|
||||
DBGC ( file, " from %s\n", efi_handle_name ( handle ) );
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Install fixed device path file
|
||||
*
|
||||
* @v file Fixed device path file
|
||||
* @v path Device path
|
||||
* @v load Load file protocol, or NULL to uninstall protocol
|
||||
* @ret rc Return status code
|
||||
*
|
||||
* Linux 5.7 added the ability to autodetect an initrd by searching
|
||||
* for a handle via a fixed vendor-specific "Linux initrd device path"
|
||||
* and then locating and using the EFI_LOAD_FILE2_PROTOCOL instance on
|
||||
* that handle.
|
||||
*
|
||||
* The design choice in Linux of using a single fixed device path
|
||||
* makes this unfortunately messy to support, since device paths must
|
||||
* be unique within a system. When multiple bootloaders are used
|
||||
* (e.g. GRUB loading iPXE loading Linux) then only one bootloader can
|
||||
* ever install the device path onto a handle. Subsequent bootloaders
|
||||
* must locate the existing handle and replace the load file protocol
|
||||
* instance with their own.
|
||||
*/
|
||||
static int efi_file_path_install ( struct efi_file_path *file ) {
|
||||
static int efi_file_path_install ( EFI_DEVICE_PATH_PROTOCOL *path,
|
||||
EFI_LOAD_FILE2_PROTOCOL *load ) {
|
||||
EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
|
||||
EFI_DEVICE_PATH_PROTOCOL *end;
|
||||
EFI_HANDLE handle;
|
||||
VOID *path_copy;
|
||||
VOID *old;
|
||||
size_t path_len;
|
||||
EFI_STATUS efirc;
|
||||
int rc;
|
||||
|
||||
/* Sanity check */
|
||||
assert ( file->handle == NULL );
|
||||
/* Locate or install the handle with this device path */
|
||||
end = path;
|
||||
if ( ( ( efirc = bs->LocateDevicePath ( &efi_device_path_protocol_guid,
|
||||
&end, &handle ) ) == 0 ) &&
|
||||
( end->Type == END_DEVICE_PATH_TYPE ) ) {
|
||||
|
||||
/* Create a new handle with this device path */
|
||||
if ( ( efirc = bs->InstallMultipleProtocolInterfaces (
|
||||
&file->handle,
|
||||
&efi_device_path_protocol_guid, file->path,
|
||||
&efi_load_file2_protocol_guid, &file->file.load,
|
||||
/* Exact match: reuse (or uninstall from) this handle */
|
||||
if ( load ) {
|
||||
DBGC ( path, "EFIFILE %s reusing existing handle\n",
|
||||
efi_devpath_text ( path ) );
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
/* Allocate a permanent copy of the device path, since
|
||||
* this handle will survive after this binary is
|
||||
* unloaded.
|
||||
*/
|
||||
path_len = ( efi_path_len ( path ) + sizeof ( *end ) );
|
||||
if ( ( efirc = bs->AllocatePool ( EfiBootServicesData, path_len,
|
||||
&path_copy ) ) != 0 ) {
|
||||
rc = -EEFI ( efirc );
|
||||
DBGC ( path, "EFIFILE %s could not allocate device path: "
|
||||
"%s\n", efi_devpath_text ( path ), strerror ( rc ) );
|
||||
return rc;
|
||||
}
|
||||
memcpy ( path_copy, path, path_len );
|
||||
|
||||
/* Create a new handle with this device path */
|
||||
handle = NULL;
|
||||
if ( ( efirc = bs->InstallMultipleProtocolInterfaces (
|
||||
&handle,
|
||||
&efi_device_path_protocol_guid, path_copy,
|
||||
NULL ) ) != 0 ) {
|
||||
rc = -EEFI ( efirc );
|
||||
DBGC ( path, "EFIFILE %s could not create handle: %s\n",
|
||||
efi_devpath_text ( path ), strerror ( rc ) );
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
|
||||
/* Uninstall existing load file protocol instance, if any */
|
||||
if ( ( ( efirc = bs->HandleProtocol ( handle, &efi_load_file2_protocol_guid,
|
||||
&old ) ) == 0 ) &&
|
||||
( ( efirc = bs->UninstallMultipleProtocolInterfaces (
|
||||
handle,
|
||||
&efi_load_file2_protocol_guid, old,
|
||||
NULL ) ) != 0 ) ) {
|
||||
rc = -EEFI ( efirc );
|
||||
DBGC ( file, "EFIFILE %s could not install %s: %s\n",
|
||||
efi_file_name ( &file->file ),
|
||||
efi_devpath_text ( file->path ), strerror ( rc ) );
|
||||
DBGC ( path, "EFIFILE %s could not uninstall %s: %s\n",
|
||||
efi_devpath_text ( path ),
|
||||
efi_guid_ntoa ( &efi_load_file2_protocol_guid ),
|
||||
strerror ( rc ) );
|
||||
return rc;
|
||||
}
|
||||
|
||||
DBGC ( file, "EFIFILE %s installed as %s\n",
|
||||
efi_file_name ( &file->file ), efi_devpath_text ( file->path ) );
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Uninstall fixed device path file
|
||||
*
|
||||
* @v file Fixed device path file
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
static void efi_file_path_uninstall ( struct efi_file_path *file ) {
|
||||
EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
|
||||
EFI_STATUS efirc;
|
||||
int rc;
|
||||
|
||||
/* Do nothing if file is already uninstalled */
|
||||
if ( ! file->handle )
|
||||
return;
|
||||
|
||||
/* Uninstall protocols. Do this via two separate calls, in
|
||||
* case another executable has already uninstalled the device
|
||||
* path protocol from our handle.
|
||||
*/
|
||||
if ( ( efirc = bs->UninstallMultipleProtocolInterfaces (
|
||||
file->handle,
|
||||
&efi_device_path_protocol_guid, file->path,
|
||||
NULL ) ) != 0 ) {
|
||||
/* Install new load file protocol instance, if applicable */
|
||||
if ( ( load != NULL ) &&
|
||||
( ( efirc = bs->InstallMultipleProtocolInterfaces (
|
||||
&handle,
|
||||
&efi_load_file2_protocol_guid, load,
|
||||
NULL ) ) != 0 ) ) {
|
||||
rc = -EEFI ( efirc );
|
||||
DBGC ( file, "EFIFILE %s could not uninstall %s: %s\n",
|
||||
efi_file_name ( &file->file ),
|
||||
efi_devpath_text ( file->path ), strerror ( rc ) );
|
||||
/* Continue uninstalling */
|
||||
}
|
||||
if ( ( efirc = bs->UninstallMultipleProtocolInterfaces (
|
||||
file->handle,
|
||||
&efi_load_file2_protocol_guid, &file->file.load,
|
||||
NULL ) ) != 0 ) {
|
||||
rc = -EEFI ( efirc );
|
||||
DBGC ( file, "EFIFILE %s could not uninstall %s: %s\n",
|
||||
efi_file_name ( &file->file ),
|
||||
DBGC ( path, "EFIFILE %s could not install %s: %s\n",
|
||||
efi_devpath_text ( path ),
|
||||
efi_guid_ntoa ( &efi_load_file2_protocol_guid ),
|
||||
strerror ( rc ) );
|
||||
/* Continue uninstalling */
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Mark handle as uninstalled */
|
||||
file->handle = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1070,6 +1020,7 @@ static void efi_file_path_uninstall ( struct efi_file_path *file ) {
|
||||
*/
|
||||
int efi_file_install ( EFI_HANDLE handle ) {
|
||||
EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
|
||||
EFI_LOAD_FILE2_PROTOCOL *load;
|
||||
union {
|
||||
EFI_DISK_IO_PROTOCOL *diskio;
|
||||
void *interface;
|
||||
@ -1132,21 +1083,24 @@ int efi_file_install ( EFI_HANDLE handle ) {
|
||||
}
|
||||
assert ( diskio.diskio == &efi_disk_io_protocol );
|
||||
|
||||
/* Claim Linux initrd fixed device path */
|
||||
if ( ( rc = efi_file_path_claim ( &efi_file_initrd ) ) != 0 )
|
||||
goto err_initrd_claim;
|
||||
|
||||
/* Install Linux initrd fixed device path file if non-empty */
|
||||
if ( have_images() &&
|
||||
( ( rc = efi_file_path_install ( &efi_file_initrd ) ) != 0 ) ) {
|
||||
goto err_initrd_install;
|
||||
/* Install Linux initrd fixed device path file
|
||||
*
|
||||
* Install the device path handle unconditionally, since we
|
||||
* are definitively the bootloader providing the initrd, if
|
||||
* any, to the booted image. Install the load file protocol
|
||||
* instance only if the initrd is non-empty, since Linux does
|
||||
* not gracefully handle a zero-length initrd.
|
||||
*/
|
||||
load = ( list_is_singular ( &images ) ? NULL : &efi_file_initrd.load );
|
||||
if ( ( rc = efi_file_path_install ( &efi_file_initrd_path.vendor.Header,
|
||||
load ) ) != 0 ) {
|
||||
goto err_initrd;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
efi_file_path_uninstall ( &efi_file_initrd );
|
||||
err_initrd_install:
|
||||
err_initrd_claim:
|
||||
efi_file_path_install ( &efi_file_initrd_path.vendor.Header, NULL );
|
||||
err_initrd:
|
||||
bs->CloseProtocol ( handle, &efi_disk_io_protocol_guid,
|
||||
efi_image_handle, handle );
|
||||
err_open:
|
||||
@ -1173,7 +1127,7 @@ void efi_file_uninstall ( EFI_HANDLE handle ) {
|
||||
int rc;
|
||||
|
||||
/* Uninstall Linux initrd fixed device path file */
|
||||
efi_file_path_uninstall ( &efi_file_initrd );
|
||||
efi_file_path_install ( &efi_file_initrd_path.vendor.Header, NULL );
|
||||
|
||||
/* Close our own disk I/O protocol */
|
||||
bs->CloseProtocol ( handle, &efi_disk_io_protocol_guid,
|
||||
|
||||
189
src/interface/efi/efi_settings.c
Normal file
189
src/interface/efi/efi_settings.c
Normal file
@ -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,
|
||||
};
|
||||
197
src/net/tls.c
197
src/net/tls.c
@ -388,7 +388,6 @@ static void free_tls ( struct refcnt *refcnt ) {
|
||||
list_del ( &iobuf->list );
|
||||
free_iob ( iobuf );
|
||||
}
|
||||
free_iob ( tls->rx_handshake );
|
||||
x509_chain_put ( tls->certs );
|
||||
x509_chain_put ( tls->chain );
|
||||
x509_root_put ( tls->root );
|
||||
@ -1683,14 +1682,9 @@ static int tls_send_certificate_verify ( struct tls_connection *tls ) {
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
static int tls_send_change_cipher ( struct tls_connection *tls ) {
|
||||
static const struct {
|
||||
uint8_t spec;
|
||||
} __attribute__ (( packed )) change_cipher = {
|
||||
.spec = TLS_CHANGE_CIPHER_SPEC,
|
||||
};
|
||||
|
||||
static const uint8_t change_cipher[1] = { 1 };
|
||||
return tls_send_plaintext ( tls, TLS_TYPE_CHANGE_CIPHER,
|
||||
&change_cipher, sizeof ( change_cipher ) );
|
||||
change_cipher, sizeof ( change_cipher ) );
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1737,27 +1731,20 @@ static int tls_send_finished ( struct tls_connection *tls ) {
|
||||
* Receive new Change Cipher record
|
||||
*
|
||||
* @v tls TLS connection
|
||||
* @v iobuf I/O buffer
|
||||
* @v data Plaintext record
|
||||
* @v len Length of plaintext record
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
static int tls_new_change_cipher ( struct tls_connection *tls,
|
||||
struct io_buffer *iobuf ) {
|
||||
const struct {
|
||||
uint8_t spec;
|
||||
} __attribute__ (( packed )) *change_cipher = iobuf->data;
|
||||
size_t len = iob_len ( iobuf );
|
||||
const void *data, size_t len ) {
|
||||
int rc;
|
||||
|
||||
/* Sanity check */
|
||||
if ( ( sizeof ( *change_cipher ) != len ) ||
|
||||
( change_cipher->spec != TLS_CHANGE_CIPHER_SPEC ) ) {
|
||||
if ( ( len != 1 ) || ( *( ( uint8_t * ) data ) != 1 ) ) {
|
||||
DBGC ( tls, "TLS %p received invalid Change Cipher\n", tls );
|
||||
DBGC_HD ( tls, change_cipher, len );
|
||||
DBGC_HD ( tls, data, len );
|
||||
return -EINVAL_CHANGE_CIPHER;
|
||||
}
|
||||
iob_pull ( iobuf, sizeof ( *change_cipher ) );
|
||||
|
||||
/* Change receive cipher spec */
|
||||
if ( ( rc = tls_change_cipher ( tls, &tls->rx_cipherspec_pending,
|
||||
&tls->rx_cipherspec ) ) != 0 ) {
|
||||
DBGC ( tls, "TLS %p could not activate RX cipher: %s\n",
|
||||
@ -1773,27 +1760,25 @@ static int tls_new_change_cipher ( struct tls_connection *tls,
|
||||
* Receive new Alert record
|
||||
*
|
||||
* @v tls TLS connection
|
||||
* @v iobuf I/O buffer
|
||||
* @v data Plaintext record
|
||||
* @v len Length of plaintext record
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
static int tls_new_alert ( struct tls_connection *tls,
|
||||
struct io_buffer *iobuf ) {
|
||||
static int tls_new_alert ( struct tls_connection *tls, const void *data,
|
||||
size_t len ) {
|
||||
const struct {
|
||||
uint8_t level;
|
||||
uint8_t description;
|
||||
char next[0];
|
||||
} __attribute__ (( packed )) *alert = iobuf->data;
|
||||
size_t len = iob_len ( iobuf );
|
||||
} __attribute__ (( packed )) *alert = data;
|
||||
|
||||
/* Sanity check */
|
||||
if ( sizeof ( *alert ) != len ) {
|
||||
DBGC ( tls, "TLS %p received overlength Alert\n", tls );
|
||||
DBGC_HD ( tls, alert, len );
|
||||
DBGC_HD ( tls, data, len );
|
||||
return -EINVAL_ALERT;
|
||||
}
|
||||
iob_pull ( iobuf, sizeof ( *alert ) );
|
||||
|
||||
/* Handle alert */
|
||||
switch ( alert->level ) {
|
||||
case TLS_ALERT_WARNING:
|
||||
DBGC ( tls, "TLS %p received warning alert %d\n",
|
||||
@ -2407,33 +2392,38 @@ static int tls_new_finished ( struct tls_connection *tls,
|
||||
* Receive new Handshake record
|
||||
*
|
||||
* @v tls TLS connection
|
||||
* @v iobuf I/O buffer
|
||||
* @v data Plaintext record
|
||||
* @v len Length of plaintext record
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
static int tls_new_handshake ( struct tls_connection *tls,
|
||||
struct io_buffer *iobuf ) {
|
||||
size_t remaining;
|
||||
const void *data, size_t len ) {
|
||||
size_t remaining = len;
|
||||
int rc;
|
||||
|
||||
while ( ( remaining = iob_len ( iobuf ) ) ) {
|
||||
while ( remaining ) {
|
||||
const struct {
|
||||
uint8_t type;
|
||||
tls24_t length;
|
||||
uint8_t payload[0];
|
||||
} __attribute__ (( packed )) *handshake = iobuf->data;
|
||||
} __attribute__ (( packed )) *handshake = data;
|
||||
const void *payload;
|
||||
size_t payload_len;
|
||||
size_t record_len;
|
||||
|
||||
/* Parse header */
|
||||
if ( sizeof ( *handshake ) > remaining ) {
|
||||
/* Leave remaining fragment unconsumed */
|
||||
break;
|
||||
DBGC ( tls, "TLS %p received underlength Handshake\n",
|
||||
tls );
|
||||
DBGC_HD ( tls, data, remaining );
|
||||
return -EINVAL_HANDSHAKE;
|
||||
}
|
||||
payload_len = tls_uint24 ( &handshake->length );
|
||||
if ( payload_len > ( remaining - sizeof ( *handshake ) ) ) {
|
||||
/* Leave remaining fragment unconsumed */
|
||||
break;
|
||||
DBGC ( tls, "TLS %p received overlength Handshake\n",
|
||||
tls );
|
||||
DBGC_HD ( tls, data, len );
|
||||
return -EINVAL_HANDSHAKE;
|
||||
}
|
||||
payload = &handshake->payload;
|
||||
record_len = ( sizeof ( *handshake ) + payload_len );
|
||||
@ -2480,60 +2470,15 @@ static int tls_new_handshake ( struct tls_connection *tls,
|
||||
* which are explicitly excluded).
|
||||
*/
|
||||
if ( handshake->type != TLS_HELLO_REQUEST )
|
||||
tls_add_handshake ( tls, handshake, record_len );
|
||||
tls_add_handshake ( tls, data, record_len );
|
||||
|
||||
/* Abort on failure */
|
||||
if ( rc != 0 )
|
||||
return rc;
|
||||
|
||||
/* Move to next handshake record */
|
||||
iob_pull ( iobuf, record_len );
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Receive new unknown record
|
||||
*
|
||||
* @v tls TLS connection
|
||||
* @v iobuf I/O buffer
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
static int tls_new_unknown ( struct tls_connection *tls __unused,
|
||||
struct io_buffer *iobuf ) {
|
||||
|
||||
/* RFC4346 says that we should just ignore unknown record types */
|
||||
iob_pull ( iobuf, iob_len ( iobuf ) );
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Receive new data record
|
||||
*
|
||||
* @v tls TLS connection
|
||||
* @v rx_data List of received data buffers
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
static int tls_new_data ( struct tls_connection *tls,
|
||||
struct list_head *rx_data ) {
|
||||
struct io_buffer *iobuf;
|
||||
int rc;
|
||||
|
||||
/* Fail unless we are ready to receive data */
|
||||
if ( ! tls_ready ( tls ) )
|
||||
return -ENOTCONN;
|
||||
|
||||
/* Deliver each I/O buffer in turn */
|
||||
while ( ( iobuf = list_first_entry ( rx_data, struct io_buffer,
|
||||
list ) ) ) {
|
||||
list_del ( &iobuf->list );
|
||||
if ( ( rc = xfer_deliver_iob ( &tls->plainstream,
|
||||
iobuf ) ) != 0 ) {
|
||||
DBGC ( tls, "TLS %p could not deliver data: "
|
||||
"%s\n", tls, strerror ( rc ) );
|
||||
return rc;
|
||||
}
|
||||
data += record_len;
|
||||
remaining -= record_len;
|
||||
}
|
||||
|
||||
return 0;
|
||||
@ -2549,18 +2494,41 @@ static int tls_new_data ( struct tls_connection *tls,
|
||||
*/
|
||||
static int tls_new_record ( struct tls_connection *tls, unsigned int type,
|
||||
struct list_head *rx_data ) {
|
||||
int ( * handler ) ( struct tls_connection *tls,
|
||||
struct io_buffer *iobuf );
|
||||
struct io_buffer *tmp = NULL;
|
||||
struct io_buffer **iobuf;
|
||||
struct io_buffer *iobuf;
|
||||
int ( * handler ) ( struct tls_connection *tls, const void *data,
|
||||
size_t len );
|
||||
int rc;
|
||||
|
||||
/* Deliver data records as-is to the plainstream interface */
|
||||
if ( type == TLS_TYPE_DATA )
|
||||
return tls_new_data ( tls, rx_data );
|
||||
/* Deliver data records to the plainstream interface */
|
||||
if ( type == TLS_TYPE_DATA ) {
|
||||
|
||||
/* Determine handler and fragment buffer */
|
||||
iobuf = &tmp;
|
||||
/* Fail unless we are ready to receive data */
|
||||
if ( ! tls_ready ( tls ) )
|
||||
return -ENOTCONN;
|
||||
|
||||
/* Deliver each I/O buffer in turn */
|
||||
while ( ( iobuf = list_first_entry ( rx_data, struct io_buffer,
|
||||
list ) ) ) {
|
||||
list_del ( &iobuf->list );
|
||||
if ( ( rc = xfer_deliver_iob ( &tls->plainstream,
|
||||
iobuf ) ) != 0 ) {
|
||||
DBGC ( tls, "TLS %p could not deliver data: "
|
||||
"%s\n", tls, strerror ( rc ) );
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* For all other records, merge into a single I/O buffer */
|
||||
iobuf = iob_concatenate ( rx_data );
|
||||
if ( ! iobuf ) {
|
||||
DBGC ( tls, "TLS %p could not concatenate non-data record "
|
||||
"type %d\n", tls, type );
|
||||
return -ENOMEM_RX_CONCAT;
|
||||
}
|
||||
|
||||
/* Determine handler */
|
||||
switch ( type ) {
|
||||
case TLS_TYPE_CHANGE_CIPHER:
|
||||
handler = tls_new_change_cipher;
|
||||
@ -2570,44 +2538,19 @@ static int tls_new_record ( struct tls_connection *tls, unsigned int type,
|
||||
break;
|
||||
case TLS_TYPE_HANDSHAKE:
|
||||
handler = tls_new_handshake;
|
||||
iobuf = &tls->rx_handshake;
|
||||
break;
|
||||
default:
|
||||
DBGC ( tls, "TLS %p unknown record type %d\n", tls, type );
|
||||
handler = tls_new_unknown;
|
||||
/* RFC4346 says that we should just ignore unknown
|
||||
* record types.
|
||||
*/
|
||||
handler = NULL;
|
||||
DBGC ( tls, "TLS %p ignoring record type %d\n", tls, type );
|
||||
break;
|
||||
}
|
||||
|
||||
/* Merge into a single I/O buffer */
|
||||
if ( *iobuf )
|
||||
list_add ( &(*iobuf)->list, rx_data );
|
||||
*iobuf = iob_concatenate ( rx_data );
|
||||
if ( ! *iobuf ) {
|
||||
DBGC ( tls, "TLS %p could not concatenate non-data record "
|
||||
"type %d\n", tls, type );
|
||||
rc = -ENOMEM_RX_CONCAT;
|
||||
goto err_concatenate;
|
||||
}
|
||||
|
||||
/* Handle record */
|
||||
if ( ( rc = handler ( tls, *iobuf ) ) != 0 )
|
||||
goto err_handle;
|
||||
|
||||
/* Discard I/O buffer if empty */
|
||||
if ( ! iob_len ( *iobuf ) ) {
|
||||
free_iob ( *iobuf );
|
||||
*iobuf = NULL;
|
||||
}
|
||||
|
||||
/* Sanity check */
|
||||
assert ( tmp == NULL );
|
||||
|
||||
return 0;
|
||||
|
||||
err_handle:
|
||||
free_iob ( *iobuf );
|
||||
*iobuf = NULL;
|
||||
err_concatenate:
|
||||
/* Handle record and free I/O buffer */
|
||||
rc = ( handler ? handler ( tls, iobuf->data, iob_len ( iobuf ) ) : 0 );
|
||||
free_iob ( iobuf );
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
@ -601,12 +601,6 @@ static void dhcp_request_rx ( struct dhcp_session *dhcp,
|
||||
return;
|
||||
}
|
||||
|
||||
/* Unregister any existing ProxyDHCP or PXEBS settings */
|
||||
if ( ( settings = find_settings ( PROXYDHCP_SETTINGS_NAME ) ) != NULL )
|
||||
unregister_settings ( settings );
|
||||
if ( ( settings = find_settings ( PXEBS_SETTINGS_NAME ) ) != NULL )
|
||||
unregister_settings ( settings );
|
||||
|
||||
/* Perform ProxyDHCP if applicable */
|
||||
if ( dhcp->proxy_offer /* Have ProxyDHCP offer */ &&
|
||||
( ! dhcp->no_pxedhcp ) /* ProxyDHCP not disabled */ ) {
|
||||
|
||||
Reference in New Issue
Block a user