summaryrefslogtreecommitdiffstats
path: root/src/interface/efi
diff options
context:
space:
mode:
authorSimon Rettberg2026-01-28 12:53:53 +0100
committerSimon Rettberg2026-01-28 12:53:53 +0100
commit8e82785c584dc13e20f9229decb95bd17bbe9cd1 (patch)
treea8b359e59196be5b2e3862bed189107f4bc9975f /src/interface/efi
parentMerge branch 'master' into openslx (diff)
parent[prefix] Make unlzma.S compatible with 386 class CPUs (diff)
downloadipxe-openslx.tar.gz
ipxe-openslx.tar.xz
ipxe-openslx.zip
Merge branch 'master' into openslxopenslx
Diffstat (limited to 'src/interface/efi')
-rw-r--r--src/interface/efi/efi_acpi.c10
-rw-r--r--src/interface/efi/efi_autoboot.c22
-rw-r--r--src/interface/efi/efi_autoexec.c18
-rw-r--r--src/interface/efi/efi_block.c124
-rw-r--r--src/interface/efi/efi_bofm.c23
-rw-r--r--src/interface/efi/efi_cacert.c202
-rw-r--r--src/interface/efi/efi_cachedhcp.c51
-rw-r--r--src/interface/efi/efi_cmdline.c7
-rw-r--r--src/interface/efi/efi_connect.c111
-rw-r--r--src/interface/efi/efi_console.c23
-rw-r--r--src/interface/efi/efi_debug.c336
-rw-r--r--src/interface/efi/efi_download.c1
-rw-r--r--src/interface/efi/efi_driver.c181
-rw-r--r--src/interface/efi/efi_entropy.c1
-rw-r--r--src/interface/efi/efi_fbcon.c29
-rw-r--r--src/interface/efi/efi_fdt.c111
-rw-r--r--src/interface/efi/efi_file.c71
-rw-r--r--src/interface/efi/efi_guid.c357
-rw-r--r--src/interface/efi/efi_hii.c13
-rw-r--r--src/interface/efi/efi_init.c48
-rw-r--r--src/interface/efi/efi_local.c30
-rw-r--r--src/interface/efi/efi_nap.c (renamed from src/interface/efi/efi_uaccess.c)38
-rw-r--r--src/interface/efi/efi_null.c1
-rw-r--r--src/interface/efi/efi_open.c360
-rw-r--r--src/interface/efi/efi_path.c282
-rw-r--r--src/interface/efi/efi_pci.c423
-rw-r--r--src/interface/efi/efi_pxe.c50
-rw-r--r--src/interface/efi/efi_reboot.c32
-rw-r--r--src/interface/efi/efi_rng.c46
-rw-r--r--src/interface/efi/efi_service.c51
-rw-r--r--src/interface/efi/efi_settings.c2
-rw-r--r--src/interface/efi/efi_shim.c30
-rw-r--r--src/interface/efi/efi_smbios.c10
-rw-r--r--src/interface/efi/efi_snp.c64
-rw-r--r--src/interface/efi/efi_snp_hii.c1
-rw-r--r--src/interface/efi/efi_strings.c1
-rw-r--r--src/interface/efi/efi_table.c179
-rw-r--r--src/interface/efi/efi_time.c1
-rw-r--r--src/interface/efi/efi_timer.c1
-rw-r--r--src/interface/efi/efi_umalloc.c34
-rw-r--r--src/interface/efi/efi_usb.c6
-rw-r--r--src/interface/efi/efi_utils.c46
-rw-r--r--src/interface/efi/efi_veto.c151
-rw-r--r--src/interface/efi/efi_watchdog.c1
-rw-r--r--src/interface/efi/efi_wrap.c539
-rw-r--r--src/interface/efi/efiprefix.c11
46 files changed, 2864 insertions, 1265 deletions
diff --git a/src/interface/efi/efi_acpi.c b/src/interface/efi/efi_acpi.c
index 07a225632..cb8b4a5d0 100644
--- a/src/interface/efi/efi_acpi.c
+++ b/src/interface/efi/efi_acpi.c
@@ -22,6 +22,7 @@
*/
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+FILE_SECBOOT ( PERMITTED );
/**
* @file
@@ -31,6 +32,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
*/
#include <ipxe/acpi.h>
+#include <ipxe/uaccess.h>
#include <ipxe/efi/efi.h>
#include <ipxe/efi/Guid/Acpi.h>
#include <ipxe/efi/efi_acpi.h>
@@ -42,15 +44,15 @@ EFI_USE_TABLE ( ACPI_10_TABLE, &rsdp, 0 );
/**
* Locate ACPI root system description table
*
- * @ret rsdt ACPI root system description table, or UNULL
+ * @ret rsdt ACPI root system description table, or NULL
*/
-static userptr_t efi_find_rsdt ( void ) {
+static const struct acpi_rsdt * efi_find_rsdt ( void ) {
/* Locate RSDT via ACPI configuration table, if available */
if ( rsdp )
- return phys_to_user ( rsdp->RsdtAddress );
+ return phys_to_virt ( rsdp->RsdtAddress );
- return UNULL;
+ return NULL;
}
PROVIDE_ACPI ( efi, acpi_find_rsdt, efi_find_rsdt );
diff --git a/src/interface/efi/efi_autoboot.c b/src/interface/efi/efi_autoboot.c
index a103c2f19..9e0c3e42e 100644
--- a/src/interface/efi/efi_autoboot.c
+++ b/src/interface/efi/efi_autoboot.c
@@ -22,6 +22,7 @@
*/
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+FILE_SECBOOT ( PERMITTED );
#include <string.h>
#include <errno.h>
@@ -48,30 +49,21 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
*/
int efi_set_autoboot_ll_addr ( EFI_HANDLE device,
EFI_DEVICE_PATH_PROTOCOL *path ) {
- EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
- union {
- EFI_SIMPLE_NETWORK_PROTOCOL *snp;
- void *interface;
- } snp;
+ EFI_SIMPLE_NETWORK_PROTOCOL *snp;
EFI_SIMPLE_NETWORK_MODE *mode;
- EFI_STATUS efirc;
unsigned int vlan;
int rc;
/* Look for an SNP instance on the image's device handle */
- if ( ( efirc = bs->OpenProtocol ( device,
- &efi_simple_network_protocol_guid,
- &snp.interface, efi_image_handle,
- NULL,
- EFI_OPEN_PROTOCOL_GET_PROTOCOL ))!=0){
- rc = -EEFI ( efirc );
+ if ( ( rc = efi_open ( device, &efi_simple_network_protocol_guid,
+ &snp ) ) != 0 ) {
DBGC ( device, "EFI %s has no SNP instance: %s\n",
efi_handle_name ( device ), strerror ( rc ) );
return rc;
}
/* Record autoboot device */
- mode = snp.snp->Mode;
+ mode = snp->Mode;
vlan = efi_path_vlan ( path );
set_autoboot_ll_addr ( &mode->CurrentAddress, mode->HwAddressSize,
vlan );
@@ -90,9 +82,5 @@ int efi_set_autoboot_ll_addr ( EFI_HANDLE device,
efi_handle_name ( device ), vlan );
}
- /* Close protocol */
- bs->CloseProtocol ( device, &efi_simple_network_protocol_guid,
- efi_image_handle, NULL );
-
return 0;
}
diff --git a/src/interface/efi/efi_autoexec.c b/src/interface/efi/efi_autoexec.c
index d9ad3b990..b63ac1602 100644
--- a/src/interface/efi/efi_autoexec.c
+++ b/src/interface/efi/efi_autoexec.c
@@ -22,12 +22,14 @@
*/
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+FILE_SECBOOT ( PERMITTED );
#include <string.h>
#include <errno.h>
#include <ipxe/timer.h>
#include <ipxe/image.h>
#include <ipxe/netdevice.h>
+#include <ipxe/uri.h>
#include <ipxe/efi/efi.h>
#include <ipxe/efi/efi_utils.h>
#include <ipxe/efi/efi_autoexec.h>
@@ -42,7 +44,10 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
*/
/** Timeout for autoexec script downloads */
-#define EFI_AUTOEXEC_TIMEOUT ( 2 * TICKS_PER_SEC )
+#define EFI_AUTOEXEC_TIMEOUT ( 30 * TICKS_PER_SEC )
+
+/** Timeout for autoexec pending operation completion */
+#define EFI_AUTOEXEC_SYNC_TIMEOUT ( 1 * TICKS_PER_SEC )
/** Autoexec script image name */
#define EFI_AUTOEXEC_NAME "autoexec.ipxe"
@@ -111,6 +116,14 @@ static int efi_autoexec_network ( EFI_HANDLE handle, struct image **image ) {
goto err_create;
}
+ /* Do nothing unless we have a usable current working URI */
+ if ( ! cwuri ) {
+ DBGC ( device, "EFI %s has no current working URI\n",
+ efi_handle_name ( device ) );
+ rc = -ENOTTY;
+ goto err_cwuri;
+ }
+
/* Open network device */
if ( ( rc = netdev_open ( netdev ) ) != 0 ) {
DBGC ( device, "EFI %s could not open net device: %s\n",
@@ -127,9 +140,10 @@ static int efi_autoexec_network ( EFI_HANDLE handle, struct image **image ) {
}
/* Ensure network exchanges have completed */
- sync ( EFI_AUTOEXEC_TIMEOUT );
+ sync ( EFI_AUTOEXEC_SYNC_TIMEOUT );
err_open:
+ err_cwuri:
mnptemp_destroy ( netdev );
err_create:
return rc;
diff --git a/src/interface/efi/efi_block.c b/src/interface/efi/efi_block.c
index a9c3d656d..0da92307b 100644
--- a/src/interface/efi/efi_block.c
+++ b/src/interface/efi/efi_block.c
@@ -22,6 +22,7 @@
*/
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+FILE_SECBOOT ( PERMITTED );
/**
* @file
@@ -59,8 +60,8 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <ipxe/efi/efi_snp.h>
#include <ipxe/efi/efi_path.h>
#include <ipxe/efi/efi_null.h>
+#include <ipxe/efi/efi_wrap.h>
#include <ipxe/efi/efi_block.h>
-#include <usr/efiboot.h>
/** ACPI table protocol protocol */
static EFI_ACPI_TABLE_PROTOCOL *acpi;
@@ -96,8 +97,9 @@ struct efi_block_data {
static int efi_block_rw ( struct san_device *sandev, uint64_t lba,
void *data, size_t len,
int ( * sandev_rw ) ( struct san_device *sandev,
- uint64_t lba, unsigned int count,
- userptr_t buffer ) ) {
+ uint64_t lba,
+ unsigned int count,
+ void *buffer ) ) {
struct efi_block_data *block = sandev->priv;
unsigned int count;
int rc;
@@ -111,8 +113,7 @@ static int efi_block_rw ( struct san_device *sandev, uint64_t lba,
}
/* Read from / write to block device */
- if ( ( rc = sandev_rw ( sandev, lba, count,
- virt_to_user ( data ) ) ) != 0 ) {
+ if ( ( rc = sandev_rw ( sandev, lba, count, data ) ) != 0 ) {
DBGC ( sandev->drive, "EFIBLK %#02x I/O failed: %s\n",
sandev->drive, strerror ( rc ) );
return rc;
@@ -219,14 +220,10 @@ efi_block_io_flush ( EFI_BLOCK_IO_PROTOCOL *block_io ) {
* @v handle Block device handle
*/
static void efi_block_connect ( unsigned int drive, EFI_HANDLE handle ) {
- EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
- EFI_STATUS efirc;
int rc;
/* Try to connect all possible drivers to this block device */
- if ( ( efirc = bs->ConnectController ( handle, NULL, NULL,
- TRUE ) ) != 0 ) {
- rc = -EEFI ( efirc );
+ if ( ( rc = efi_connect ( handle, NULL ) ) != 0 ) {
DBGC ( drive, "EFIBLK %#02x could not connect drivers: %s\n",
drive, strerror ( rc ) );
/* May not be an error; may already be connected */
@@ -519,40 +516,27 @@ static int efi_block_describe ( void ) {
*/
static int efi_block_root ( unsigned int drive, EFI_HANDLE handle,
EFI_FILE_PROTOCOL **root ) {
- EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
- EFI_GUID *protocol = &efi_simple_file_system_protocol_guid;
- union {
- EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *fs;
- void *interface;
- } u;
+ EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *fs;
EFI_STATUS efirc;
int rc;
/* Open filesystem protocol */
- if ( ( efirc = bs->OpenProtocol ( handle, protocol, &u.interface,
- efi_image_handle, handle,
- EFI_OPEN_PROTOCOL_GET_PROTOCOL ))!=0){
- rc = -EEFI ( efirc );
+ if ( ( rc = efi_open ( handle, &efi_simple_file_system_protocol_guid,
+ &fs ) ) != 0 ) {
DBGC ( drive, "EFIBLK %#02x could not open %s filesystem: %s\n",
drive, efi_handle_name ( handle ), strerror ( rc ) );
- goto err_open;
+ return rc;
}
/* Open root volume */
- if ( ( efirc = u.fs->OpenVolume ( u.fs, root ) ) != 0 ) {
+ if ( ( efirc = fs->OpenVolume ( fs, root ) ) != 0 ) {
rc = -EEFI ( efirc );
DBGC ( drive, "EFIBLK %#02x could not open %s root: %s\n",
drive, efi_handle_name ( handle ), strerror ( rc ) );
- goto err_volume;
+ return rc;
}
- /* Success */
- rc = 0;
-
- err_volume:
- bs->CloseProtocol ( handle, protocol, efi_image_handle, handle );
- err_open:
- return rc;
+ return 0;
}
/**
@@ -675,31 +659,21 @@ static int efi_block_match ( unsigned int drive, EFI_HANDLE handle,
EFI_DEVICE_PATH_PROTOCOL *path,
struct san_boot_config *config,
EFI_DEVICE_PATH_PROTOCOL **fspath ) {
- EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
- EFI_GUID *protocol = &efi_device_path_protocol_guid;
- union {
- EFI_DEVICE_PATH_PROTOCOL *path;
- void *interface;
- } u;
EFI_FILE *root;
union uuid guid;
- EFI_STATUS efirc;
int rc;
/* Identify device path */
- if ( ( efirc = bs->OpenProtocol ( handle, protocol, &u.interface,
- efi_image_handle, handle,
- EFI_OPEN_PROTOCOL_GET_PROTOCOL ))!=0){
- rc = -EEFI ( efirc );
+ if ( ( rc = efi_open ( handle, &efi_device_path_protocol_guid,
+ fspath ) ) != 0 ) {
DBGC ( drive, "EFIBLK %#02x could not open %s device path: "
"%s\n", drive, efi_handle_name ( handle ),
strerror ( rc ) );
goto err_open;
}
- *fspath = u.path;
/* Check if filesystem is a child of this block device */
- if ( memcmp ( u.path, path, efi_path_len ( path ) ) != 0 ) {
+ if ( memcmp ( *fspath, path, efi_path_len ( path ) ) != 0 ) {
/* Not a child device */
rc = -ENOTTY;
DBGC2 ( drive, "EFIBLK %#02x is not parent of %s\n",
@@ -707,11 +681,11 @@ static int efi_block_match ( unsigned int drive, EFI_HANDLE handle,
goto err_not_child;
}
DBGC ( drive, "EFIBLK %#02x contains filesystem %s\n",
- drive, efi_devpath_text ( u.path ) );
+ drive, efi_devpath_text ( *fspath ) );
/* Check if filesystem matches GUID, if applicable */
if ( config->uuid ) {
- if ( ( rc = efi_path_guid ( u.path, &guid ) ) != 0 ) {
+ if ( ( rc = efi_path_guid ( *fspath, &guid ) ) != 0 ) {
DBGC ( drive, "EFIBLK %#02x could not determine GUID: "
"%s\n", drive, strerror ( rc ) );
goto err_no_guid;
@@ -759,7 +733,6 @@ static int efi_block_match ( unsigned int drive, EFI_HANDLE handle,
err_wrong_guid:
err_no_guid:
err_not_child:
- bs->CloseProtocol ( handle, protocol, efi_image_handle, handle );
err_open:
return rc;
}
@@ -777,11 +750,7 @@ static int efi_block_scan ( unsigned int drive, EFI_HANDLE handle,
struct san_boot_config *config,
EFI_DEVICE_PATH_PROTOCOL **fspath ) {
EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
- EFI_GUID *protocol = &efi_device_path_protocol_guid;
- union {
- EFI_DEVICE_PATH_PROTOCOL *path;
- void *interface;
- } u;
+ EFI_DEVICE_PATH_PROTOCOL *path;
EFI_HANDLE *handles;
UINTN count;
unsigned int i;
@@ -792,10 +761,8 @@ static int efi_block_scan ( unsigned int drive, EFI_HANDLE handle,
efi_block_connect ( drive, handle );
/* Identify device path */
- if ( ( efirc = bs->OpenProtocol ( handle, protocol, &u.interface,
- efi_image_handle, handle,
- EFI_OPEN_PROTOCOL_GET_PROTOCOL ))!=0){
- rc = -EEFI ( efirc );
+ if ( ( rc = efi_open ( handle, &efi_device_path_protocol_guid,
+ &path ) ) != 0 ) {
DBGC ( drive, "EFIBLK %#02x could not open device path: %s\n",
drive, strerror ( rc ) );
goto err_open;
@@ -816,7 +783,7 @@ static int efi_block_scan ( unsigned int drive, EFI_HANDLE handle,
for ( i = 0 ; i < count ; i++ ) {
/* Check for a matching filesystem */
- if ( ( rc = efi_block_match ( drive, handles[i], u.path,
+ if ( ( rc = efi_block_match ( drive, handles[i], path,
config, fspath ) ) != 0 )
continue;
@@ -825,7 +792,6 @@ static int efi_block_scan ( unsigned int drive, EFI_HANDLE handle,
bs->FreePool ( handles );
err_locate:
- bs->CloseProtocol ( handle, protocol, efi_image_handle, handle );
err_open:
return rc;
}
@@ -897,12 +863,18 @@ static int efi_block_exec ( unsigned int drive,
}
}
+ /* Wrap calls made by the loaded image (for debugging) */
+ efi_wrap_image ( image );
+
/* Start image */
efirc = bs->StartImage ( image, NULL, NULL );
rc = ( efirc ? -EEFI ( efirc ) : 0 );
DBGC ( drive, "EFIBLK %#02x boot image returned: %s\n",
drive, strerror ( rc ) );
+ /* Remove wrapper */
+ efi_unwrap();
+
err_load_security_violation:
bs->UnloadImage ( image );
err_load:
@@ -922,52 +894,34 @@ static int efi_block_exec ( unsigned int drive,
* equivalent functionality to BIOS drive numbers.
*/
static int efi_block_local ( EFI_HANDLE handle ) {
- EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
- EFI_GUID *protocol = &efi_block_io_protocol_guid;
struct san_device *sandev;
struct efi_block_data *block;
- union {
- EFI_BLOCK_IO_PROTOCOL *blockio;
- void *interface;
- } u;
- EFI_STATUS efirc;
+ EFI_BLOCK_IO_PROTOCOL *blockio;
int rc;
/* Check if handle belongs to a SAN device */
for_each_sandev ( sandev ) {
block = sandev->priv;
- if ( handle == block->handle ) {
- rc = -ENOTTY;
- goto err_sandev;
- }
+ if ( handle == block->handle )
+ return -ENOTTY;
}
/* Open block I/O protocol */
- if ( ( efirc = bs->OpenProtocol ( handle, protocol, &u.interface,
- efi_image_handle, handle,
- EFI_OPEN_PROTOCOL_GET_PROTOCOL ))!=0){
- rc = -EEFI ( efirc );
+ if ( ( rc = efi_open ( handle, &efi_block_io_protocol_guid,
+ &blockio ) ) != 0 ) {
DBGC ( handle, "EFIBLK %s could not open block I/O: %s\n",
efi_handle_name ( handle ), strerror ( rc ) );
- goto err_open;
+ return rc;
}
/* Do not assign drive numbers for partitions */
- if ( u.blockio->Media->LogicalPartition ) {
- rc = -ENOTTY;
+ if ( blockio->Media->LogicalPartition ) {
DBGC2 ( handle, "EFLBLK %s is a partition\n",
efi_handle_name ( handle ) );
- goto err_partition;
+ return -ENOTTY;
}
- /* Success */
- rc = 0;
-
- err_partition:
- bs->CloseProtocol ( handle, protocol, efi_image_handle, handle );
- err_open:
- err_sandev:
- return rc;
+ return 0;
}
/**
@@ -991,6 +945,8 @@ static int efi_block_boot ( unsigned int drive,
EFI_STATUS efirc;
int rc;
+ /* Ensure that any local drives are connected */
+ efi_driver_reconnect_all();
/* Release SNP devices */
efi_snp_release();
diff --git a/src/interface/efi/efi_bofm.c b/src/interface/efi/efi_bofm.c
index 15f3837cc..3d956800e 100644
--- a/src/interface/efi/efi_bofm.c
+++ b/src/interface/efi/efi_bofm.c
@@ -23,6 +23,7 @@
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+#include <string.h>
#include <errno.h>
#include <ipxe/bofm.h>
#include <ipxe/efi/efi.h>
@@ -232,10 +233,20 @@ static int efi_bofm_start ( struct efi_device *efidev ) {
EFI_STATUS efirc;
int rc;
- /* Open PCI device, if possible */
- if ( ( rc = efipci_open ( device, EFI_OPEN_PROTOCOL_GET_PROTOCOL,
- &efipci ) ) != 0 )
+ /* Get PCI device information */
+ if ( ( rc = efipci_info ( device, &efipci ) ) != 0 ) {
+ DBGC ( device, "EFIBOFM %s cannot get PCI information: %s\n",
+ efi_handle_name ( device ), strerror ( rc ) );
+ goto err_info;
+ }
+
+ /* Open PCI I/O protocol */
+ if ( ( rc = efi_open_unsafe ( device, &efi_pci_io_protocol_guid,
+ &efipci.io ) ) != 0 ) {
+ DBGC ( device, "EFIBOFM %s cannot open PCI device: %s\n",
+ efi_handle_name ( device ), strerror ( rc ) );
goto err_open;
+ }
/* Locate BOFM protocol */
if ( ( efirc = bs->LocateProtocol ( &bofm1_protocol_guid, NULL,
@@ -274,8 +285,7 @@ static int efi_bofm_start ( struct efi_device *efidev ) {
efi_handle_name ( device ) );
DBGC2_HD ( device, bofmtab2, bofmtab2->Parameters.Length );
}
- bofmrc = bofm ( virt_to_user ( bofmtab2 ? bofmtab2 : bofmtab ),
- &efipci.pci );
+ bofmrc = bofm ( ( bofmtab2 ? bofmtab2 : bofmtab ), &efipci.pci );
DBGC ( device, "EFIBOFM %s status %08x\n",
efi_handle_name ( device ), bofmrc );
DBGC2 ( device, "EFIBOFM %s version 1 after processing:\n",
@@ -313,8 +323,9 @@ static int efi_bofm_start ( struct efi_device *efidev ) {
err_set_status:
err_locate_bofm:
- efipci_close ( device );
+ efi_close_unsafe ( device, &efi_pci_io_protocol_guid );
err_open:
+ err_info:
return rc;
}
diff --git a/src/interface/efi/efi_cacert.c b/src/interface/efi/efi_cacert.c
new file mode 100644
index 000000000..3e941ddc5
--- /dev/null
+++ b/src/interface/efi/efi_cacert.c
@@ -0,0 +1,202 @@
+/*
+ * Copyright (C) 2025 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_SECBOOT ( PERMITTED );
+
+/** @file
+ *
+ * EFI CA certificates
+ *
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <errno.h>
+#include <ipxe/init.h>
+#include <ipxe/x509.h>
+#include <ipxe/rootcert.h>
+#include <ipxe/efi/efi.h>
+#include <ipxe/efi/efi_siglist.h>
+#include <ipxe/efi/Guid/TlsAuthentication.h>
+
+/** List of EFI CA certificates */
+static struct x509_chain efi_cacerts = {
+ .refcnt = REF_INIT ( ref_no_free ),
+ .links = LIST_HEAD_INIT ( efi_cacerts.links ),
+};
+
+/**
+ * Retrieve EFI CA certificate
+ *
+ * @v data TlsCaCertificate variable data
+ * @v len Length of TlsCaCertificate
+ * @v offset Offset within data
+ * @v next Next offset, or negative error
+ */
+static int efi_cacert ( const void *data, size_t len, size_t offset ) {
+ struct asn1_cursor *cursor;
+ struct x509_certificate *cert;
+ int next;
+ int rc;
+
+ /* Extract ASN.1 object */
+ next = efisig_asn1 ( data, len, offset, &cursor );
+ if ( next < 0 ) {
+ rc = next;
+ DBGC ( &efi_cacerts, "EFICA could not parse at +%#zx: %s\n",
+ offset, strerror ( rc ) );
+ goto err_asn1;
+ }
+
+ /* Append to list of EFI CA certificates */
+ if ( ( rc = x509_append_raw ( &efi_cacerts, cursor->data,
+ cursor->len ) ) != 0 ) {
+ DBGC ( &efi_cacerts, "EFICA could not append at +%#zx: %s\n",
+ offset, strerror ( rc ) );
+ goto err_append;
+ }
+ cert = x509_last ( &efi_cacerts );
+ DBGC ( &efi_cacerts, "EFICA found certificate %s\n",
+ x509_name ( cert ) );
+
+ /* Mark certificate as valid (i.e. trusted) if permitted */
+ if ( allow_trust_override ) {
+ DBGC ( &efi_cacerts, "EFICA trusting certificate %s\n",
+ x509_name ( cert ) );
+ x509_set_valid ( cert, NULL, &root_certificates );
+ }
+
+ /* Free ASN.1 object */
+ free ( cursor );
+
+ return next;
+
+ err_append:
+ free ( cursor );
+ err_asn1:
+ return rc;
+}
+
+/**
+ * Retrieve all EFI CA certificates
+ *
+ * @ret rc Return status code
+ */
+static int efi_cacert_all ( void ) {
+ EFI_RUNTIME_SERVICES *rs = efi_systab->RuntimeServices;
+ EFI_GUID *guid = &efi_tls_ca_certificate_guid;
+ static CHAR16 *wname = EFI_TLS_CA_CERTIFICATE_VARIABLE;
+ int offset = 0;
+ UINT32 attrs;
+ UINTN size;
+ void *data;
+ EFI_STATUS efirc;
+ int rc;
+
+ /* Get variable length */
+ size = 0;
+ if ( ( efirc = rs->GetVariable ( wname, guid, &attrs, &size,
+ NULL ) ) != EFI_BUFFER_TOO_SMALL ) {
+ rc = -EEFI ( efirc );
+ DBGC ( &efi_cacerts, "EFICA could not get %ls size: %s\n",
+ wname, strerror ( rc ) );
+ goto err_len;
+ }
+
+ /* Allocate temporary buffer */
+ data = malloc ( size );
+ if ( ! data ) {
+ rc = -ENOMEM;
+ goto err_alloc;
+ }
+
+ /* Read variable */
+ if ( ( efirc = rs->GetVariable ( wname, guid, &attrs, &size,
+ data ) ) != 0 ) {
+ rc = -EEFI ( efirc );
+ DBGC ( &efi_cacerts, "EFICA could not read %ls: %s\n",
+ wname, strerror ( rc ) );
+ goto err_get;
+ }
+
+ /* Parse certificates */
+ while ( ( ( size_t ) offset ) < size ) {
+ offset = efi_cacert ( data, size, offset );
+ if ( offset < 0 ) {
+ rc = offset;
+ goto err_cacert;
+ }
+ }
+
+ /* Success */
+ rc = 0;
+
+ err_cacert:
+ err_get:
+ free ( data );
+ err_alloc:
+ err_len:
+ return rc;
+}
+
+/**
+ * Initialise EFI CA certificates
+ *
+ */
+static void efi_cacert_init ( void ) {
+ int rc;
+
+ /* Initialise all certificates */
+ if ( ( rc = efi_cacert_all() ) != 0 ) {
+ DBGC ( &efi_cacert, "EFICA could not initialise: %s\n",
+ strerror ( rc ) );
+ /* Nothing we can do at this point */
+ return;
+ }
+}
+
+/** EFI CA certificates initialisation function */
+struct init_fn efi_cacert_init_fn __init_fn ( INIT_LATE ) = {
+ .name = "eficacert",
+ .initialise = efi_cacert_init,
+};
+
+/**
+ * Discard any EFI CA certificates
+ *
+ */
+static void efi_cacert_shutdown ( int booting __unused ) {
+
+ /* Drop our references to the certificates */
+ DBGC ( &efi_cacert, "EFICA discarding certificates\n" );
+ x509_truncate ( &efi_cacerts, NULL );
+ assert ( list_empty ( &efi_cacerts.links ) );
+}
+
+/** EFI CA certificates shutdown function */
+struct startup_fn efi_cacert_shutdown_fn __startup_fn ( STARTUP_NORMAL ) = {
+ .name = "efi_cacert",
+ .shutdown = efi_cacert_shutdown,
+};
diff --git a/src/interface/efi/efi_cachedhcp.c b/src/interface/efi/efi_cachedhcp.c
index b9e49cf48..2f33fcefb 100644
--- a/src/interface/efi/efi_cachedhcp.c
+++ b/src/interface/efi/efi_cachedhcp.c
@@ -22,6 +22,7 @@
*/
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+FILE_SECBOOT ( PERMITTED );
#include <string.h>
#include <errno.h>
@@ -46,79 +47,57 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
*/
int efi_cachedhcp_record ( EFI_HANDLE device,
EFI_DEVICE_PATH_PROTOCOL *path ) {
- EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
unsigned int vlan;
- union {
- EFI_PXE_BASE_CODE_PROTOCOL *pxe;
- void *interface;
- } pxe;
+ EFI_PXE_BASE_CODE_PROTOCOL *pxe;
EFI_PXE_BASE_CODE_MODE *mode;
- EFI_STATUS efirc;
int rc;
/* Get VLAN tag, if any */
vlan = efi_path_vlan ( path );
/* Look for a PXE base code instance on the image's device handle */
- if ( ( efirc = bs->OpenProtocol ( device,
- &efi_pxe_base_code_protocol_guid,
- &pxe.interface, efi_image_handle,
- NULL,
- EFI_OPEN_PROTOCOL_GET_PROTOCOL ))!=0){
- rc = -EEFI ( efirc );
+ if ( ( rc = efi_open ( device, &efi_pxe_base_code_protocol_guid,
+ &pxe ) ) != 0 ) {
DBGC ( device, "EFI %s has no PXE base code instance: %s\n",
efi_handle_name ( device ), strerror ( rc ) );
- goto err_open;
+ return rc;
}
/* Do not attempt to cache IPv6 packets */
- mode = pxe.pxe->Mode;
+ mode = pxe->Mode;
if ( mode->UsingIpv6 ) {
- rc = -ENOTSUP;
DBGC ( device, "EFI %s has IPv6 PXE base code\n",
efi_handle_name ( device ) );
- goto err_ipv6;
+ return -ENOTSUP;
}
/* Record DHCPACK, if present */
if ( mode->DhcpAckReceived &&
- ( ( rc = cachedhcp_record ( &cached_dhcpack, vlan,
- virt_to_user ( &mode->DhcpAck ),
+ ( ( rc = cachedhcp_record ( &cached_dhcpack, vlan, &mode->DhcpAck,
sizeof ( mode->DhcpAck ) ) ) != 0 ) ) {
DBGC ( device, "EFI %s could not record DHCPACK: %s\n",
efi_handle_name ( device ), strerror ( rc ) );
- goto err_dhcpack;
+ return rc;
}
/* Record ProxyDHCPOFFER, if present */
if ( mode->ProxyOfferReceived &&
( ( rc = cachedhcp_record ( &cached_proxydhcp, vlan,
- virt_to_user ( &mode->ProxyOffer ),
+ &mode->ProxyOffer,
sizeof ( mode->ProxyOffer ) ) ) != 0)){
DBGC ( device, "EFI %s could not record ProxyDHCPOFFER: %s\n",
efi_handle_name ( device ), strerror ( rc ) );
- goto err_proxydhcp;
+ return rc;
}
/* Record PxeBSACK, if present */
if ( mode->PxeReplyReceived &&
- ( ( rc = cachedhcp_record ( &cached_pxebs, vlan,
- virt_to_user ( &mode->PxeReply ),
- sizeof ( mode->PxeReply ) ) ) != 0)){
+ ( ( rc = cachedhcp_record ( &cached_pxebs, vlan, &mode->PxeReply,
+ sizeof ( mode->PxeReply ) ) ) != 0 )){
DBGC ( device, "EFI %s could not record PXEBSACK: %s\n",
efi_handle_name ( device ), strerror ( rc ) );
- goto err_pxebs;
+ return rc;
}
- /* Success */
- rc = 0;
-
- err_pxebs:
- err_proxydhcp:
- err_dhcpack:
- err_ipv6:
- bs->CloseProtocol ( device, &efi_pxe_base_code_protocol_guid,
- efi_image_handle, NULL );
- err_open:
- return rc;
+ return 0;
}
diff --git a/src/interface/efi/efi_cmdline.c b/src/interface/efi/efi_cmdline.c
index b33bebd8c..f5844f2ad 100644
--- a/src/interface/efi/efi_cmdline.c
+++ b/src/interface/efi/efi_cmdline.c
@@ -22,6 +22,7 @@
*/
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+FILE_SECBOOT ( PERMITTED );
/** @file
*
@@ -31,11 +32,13 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stdio.h>
#include <stdlib.h>
+#include <string.h>
#include <ctype.h>
#include <errno.h>
#include <ipxe/init.h>
#include <ipxe/image.h>
#include <ipxe/script.h>
+#include <ipxe/uaccess.h>
#include <ipxe/efi/efi.h>
#include <ipxe/efi/efi_cmdline.h>
@@ -57,6 +60,7 @@ static void efi_cmdline_free ( struct refcnt *refcnt ) {
struct image *image = container_of ( refcnt, struct image, refcnt );
DBGC ( image, "CMDLINE freeing command line\n" );
+ free_image ( refcnt );
free ( efi_cmdline_copy );
}
@@ -64,6 +68,7 @@ static void efi_cmdline_free ( struct refcnt *refcnt ) {
static struct image efi_cmdline_image = {
.refcnt = REF_INIT ( efi_cmdline_free ),
.name = "<CMDLINE>",
+ .flags = ( IMAGE_STATIC | IMAGE_STATIC_NAME ),
.type = &script_image_type,
};
@@ -110,7 +115,7 @@ static int efi_cmdline_init ( void ) {
DBGC ( colour, "CMDLINE using command line \"%s\"\n", cmdline );
/* Prepare and register image */
- efi_cmdline_image.data = virt_to_user ( cmdline );
+ efi_cmdline_image.data = cmdline;
efi_cmdline_image.len = strlen ( cmdline );
if ( efi_cmdline_image.len &&
( ( rc = register_image ( &efi_cmdline_image ) ) != 0 ) ) {
diff --git a/src/interface/efi/efi_connect.c b/src/interface/efi/efi_connect.c
new file mode 100644
index 000000000..f4747cf6b
--- /dev/null
+++ b/src/interface/efi/efi_connect.c
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2025 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_SECBOOT ( PERMITTED );
+
+/** @file
+ *
+ * EFI driver connection and disconnection
+ *
+ */
+
+#include <errno.h>
+#include <string.h>
+#include <ipxe/efi/efi.h>
+
+/* Disambiguate the various error causes */
+#define EINFO_EEFI_CONNECT \
+ __einfo_uniqify ( EINFO_EPLATFORM, 0x01, \
+ "Could not connect controllers" )
+#define EINFO_EEFI_CONNECT_PROHIBITED \
+ __einfo_platformify ( EINFO_EEFI_CONNECT, \
+ EFI_SECURITY_VIOLATION, \
+ "Connecting controllers prohibited by " \
+ "security policy" )
+#define EEFI_CONNECT_PROHIBITED \
+ __einfo_error ( EINFO_EEFI_CONNECT_PROHIBITED )
+#define EEFI_CONNECT( efirc ) EPLATFORM ( EINFO_EEFI_CONNECT, efirc, \
+ EEFI_CONNECT_PROHIBITED )
+
+/**
+ * Connect UEFI driver(s)
+ *
+ * @v device EFI device handle
+ * @v driver EFI driver handle, or NULL
+ * @ret rc Return status code
+ */
+int efi_connect ( EFI_HANDLE device, EFI_HANDLE driver ) {
+ EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
+ EFI_HANDLE driverlist[2] = { driver, NULL };
+ EFI_HANDLE *drivers = ( driver ? driverlist : NULL );
+ EFI_STATUS efirc;
+ int rc;
+
+ /* Attempt connection at external TPL */
+ DBGC ( device, "EFI %s connecting ", efi_handle_name ( device ) );
+ DBGC ( device, "%s driver at %s TPL\n",
+ ( driver ? efi_handle_name ( driver ) : "any" ),
+ efi_tpl_name ( efi_external_tpl ) );
+ bs->RestoreTPL ( efi_external_tpl );
+ efirc = bs->ConnectController ( device, drivers, NULL, TRUE );
+ bs->RaiseTPL ( efi_internal_tpl );
+ if ( efirc != 0 ) {
+ rc = -EEFI_CONNECT ( efirc );
+ DBGC ( device, "EFI %s could not connect: %s\n",
+ efi_handle_name ( device ), strerror ( rc ) );
+ return rc;
+ }
+
+ return 0;
+}
+
+/**
+ * Disconnect UEFI driver(s)
+ *
+ * @v device EFI device handle
+ * @v driver EFI driver handle, or NULL
+ * @ret rc Return status code
+ */
+int efi_disconnect ( EFI_HANDLE device, EFI_HANDLE driver ) {
+ EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
+ EFI_STATUS efirc;
+ int rc;
+
+ /* Attempt disconnection at external TPL */
+ DBGC ( device, "EFI %s disconnecting ", efi_handle_name ( device ) );
+ DBGC ( device, "%s driver at %s TPL\n",
+ ( driver ? efi_handle_name ( driver ) : "any" ),
+ efi_tpl_name ( efi_external_tpl ) );
+ bs->RestoreTPL ( efi_external_tpl );
+ efirc = bs->DisconnectController ( device, driver, NULL );
+ bs->RaiseTPL ( efi_internal_tpl );
+ if ( ( efirc != 0 ) && ( efirc != EFI_NOT_FOUND ) ) {
+ rc = -EEFI ( efirc );
+ DBGC ( device, "EFI %s could not disconnect: %s\n",
+ efi_handle_name ( device ), strerror ( rc ) );
+ return rc;
+ }
+
+ return 0;
+}
diff --git a/src/interface/efi/efi_console.c b/src/interface/efi/efi_console.c
index 04bbd9e0c..afbd722ab 100644
--- a/src/interface/efi/efi_console.c
+++ b/src/interface/efi/efi_console.c
@@ -18,6 +18,7 @@
*/
FILE_LICENCE ( GPL2_OR_LATER );
+FILE_SECBOOT ( PERMITTED );
#include <stddef.h>
#include <string.h>
@@ -386,8 +387,6 @@ static int efi_getchar ( void ) {
static int efi_iskey ( void ) {
EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
EFI_SIMPLE_TEXT_INPUT_PROTOCOL *conin = efi_systab->ConIn;
- EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *conin_ex = efi_conin_ex;
- EFI_EVENT *event;
EFI_STATUS efirc;
/* If we are mid-sequence, we are always ready */
@@ -395,8 +394,7 @@ static int efi_iskey ( void ) {
return 1;
/* Check to see if the WaitForKey event has fired */
- event = ( conin_ex ? conin_ex->WaitForKeyEx : conin->WaitForKey );
- if ( ( efirc = bs->CheckEvent ( event ) ) == 0 )
+ if ( ( efirc = bs->CheckEvent ( conin->WaitForKey ) ) == 0 )
return 1;
return 0;
@@ -415,13 +413,7 @@ struct console_driver efi_console __console_driver = {
*
*/
static void efi_console_init ( void ) {
- EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
EFI_CONSOLE_CONTROL_SCREEN_MODE mode;
- union {
- void *interface;
- EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *wtf;
- } u;
- EFI_STATUS efirc;
int rc;
/* On some older EFI 1.10 implementations, we must use the
@@ -441,15 +433,11 @@ static void efi_console_init ( void ) {
* apparently the expected behaviour for all UEFI
* applications. Don't ask.
*/
- if ( ( efirc = bs->OpenProtocol ( efi_systab->ConsoleInHandle,
- &efi_simple_text_input_ex_protocol_guid,
- &u.interface, efi_image_handle,
- efi_systab->ConsoleInHandle,
- EFI_OPEN_PROTOCOL_GET_PROTOCOL ) ) == 0 ) {
- efi_conin_ex = u.wtf;
+ if ( ( rc = efi_open_unsafe ( efi_systab->ConsoleInHandle,
+ &efi_simple_text_input_ex_protocol_guid,
+ &efi_conin_ex ) ) == 0 ) {
DBG ( "EFI using SimpleTextInputEx\n" );
} else {
- rc = -EEFI ( efirc );
DBG ( "EFI has no SimpleTextInputEx: %s\n", strerror ( rc ) );
}
}
@@ -458,5 +446,6 @@ static void efi_console_init ( void ) {
* EFI console initialisation function
*/
struct init_fn efi_console_init_fn __init_fn ( INIT_EARLY ) = {
+ .name = "eficonsole",
.initialise = efi_console_init,
};
diff --git a/src/interface/efi/efi_debug.c b/src/interface/efi/efi_debug.c
index 52efebe5f..067899a72 100644
--- a/src/interface/efi/efi_debug.c
+++ b/src/interface/efi/efi_debug.c
@@ -31,15 +31,14 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
*/
#include <stdio.h>
-#include <string.h>
#include <errno.h>
-#include <ipxe/uuid.h>
#include <ipxe/base16.h>
#include <ipxe/vsprintf.h>
#include <ipxe/efi/efi.h>
#include <ipxe/efi/efi_path.h>
#include <ipxe/efi/Protocol/ComponentName.h>
#include <ipxe/efi/Protocol/ComponentName2.h>
+#include <ipxe/efi/Protocol/DriverBinding.h>
#include <ipxe/efi/Protocol/DevicePathToText.h>
#include <ipxe/efi/IndustryStandard/PeImage.h>
@@ -47,234 +46,25 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
static EFI_DEVICE_PATH_TO_TEXT_PROTOCOL *efidpt;
EFI_REQUEST_PROTOCOL ( EFI_DEVICE_PATH_TO_TEXT_PROTOCOL, &efidpt );
-/** HttpBootDxe module GUID */
-static EFI_GUID efi_http_boot_dxe_guid = {
- 0xecebcb00, 0xd9c8, 0x11e4,
- { 0xaf, 0x3d, 0x8c, 0xdc, 0xd4, 0x26, 0xc9, 0x73 }
-};
-
-/** IScsiDxe module GUID */
-static EFI_GUID efi_iscsi_dxe_guid = {
- 0x86cddf93, 0x4872, 0x4597,
- { 0x8a, 0xf9, 0xa3, 0x5a, 0xe4, 0xd3, 0x72, 0x5f }
-};
-
-/** Old IScsi4Dxe module GUID */
-static EFI_GUID efi_iscsi4_dxe_guid = {
- 0x4579b72d, 0x7ec4, 0x4dd4,
- { 0x84, 0x86, 0x08, 0x3c, 0x86, 0xb1, 0x82, 0xa7 }
-};
-
-/** UefiPxeBcDxe module GUID */
-static EFI_GUID efi_uefi_pxe_bc_dxe_guid = {
- 0xb95e9fda, 0x26de, 0x48d2,
- { 0x88, 0x07, 0x1f, 0x91, 0x07, 0xac, 0x5e, 0x3a }
-};
-
-/** VlanConfigDxe module GUID */
-static EFI_GUID efi_vlan_config_dxe_guid = {
- 0xe4f61863, 0xfe2c, 0x4b56,
- { 0xa8, 0xf4, 0x08, 0x51, 0x9b, 0xc4, 0x39, 0xdf }
-};
-
-/** A well-known GUID */
-struct efi_well_known_guid {
- /** GUID */
- EFI_GUID *guid;
- /** Name */
- const char *name;
-};
-
-/** Well-known GUIDs */
-static struct efi_well_known_guid efi_well_known_guids[] = {
- { &efi_absolute_pointer_protocol_guid,
- "AbsolutePointer" },
- { &efi_acpi_table_protocol_guid,
- "AcpiTable" },
- { &efi_apple_net_boot_protocol_guid,
- "AppleNetBoot" },
- { &efi_arp_protocol_guid,
- "Arp" },
- { &efi_arp_service_binding_protocol_guid,
- "ArpSb" },
- { &efi_block_io_protocol_guid,
- "BlockIo" },
- { &efi_block_io2_protocol_guid,
- "BlockIo2" },
- { &efi_bus_specific_driver_override_protocol_guid,
- "BusSpecificDriverOverride" },
- { &efi_component_name_protocol_guid,
- "ComponentName" },
- { &efi_component_name2_protocol_guid,
- "ComponentName2" },
- { &efi_console_control_protocol_guid,
- "ConsoleControl" },
- { &efi_device_path_protocol_guid,
- "DevicePath" },
- { &efi_driver_binding_protocol_guid,
- "DriverBinding" },
- { &efi_dhcp4_protocol_guid,
- "Dhcp4" },
- { &efi_dhcp4_service_binding_protocol_guid,
- "Dhcp4Sb" },
- { &efi_dhcp6_protocol_guid,
- "Dhcp6" },
- { &efi_dhcp6_service_binding_protocol_guid,
- "Dhcp6Sb" },
- { &efi_disk_io_protocol_guid,
- "DiskIo" },
- { &efi_dns4_protocol_guid,
- "Dns4" },
- { &efi_dns4_service_binding_protocol_guid,
- "Dns4Sb" },
- { &efi_dns6_protocol_guid,
- "Dns6" },
- { &efi_dns6_service_binding_protocol_guid,
- "Dns6Sb" },
- { &efi_graphics_output_protocol_guid,
- "GraphicsOutput" },
- { &efi_hii_config_access_protocol_guid,
- "HiiConfigAccess" },
- { &efi_hii_font_protocol_guid,
- "HiiFont" },
- { &efi_http_boot_dxe_guid,
- "HttpBootDxe" },
- { &efi_http_protocol_guid,
- "Http" },
- { &efi_http_service_binding_protocol_guid,
- "HttpSb" },
- { &efi_ip4_protocol_guid,
- "Ip4" },
- { &efi_ip4_config_protocol_guid,
- "Ip4Config" },
- { &efi_ip4_config2_protocol_guid,
- "Ip4Config2" },
- { &efi_ip4_service_binding_protocol_guid,
- "Ip4Sb" },
- { &efi_ip6_protocol_guid,
- "Ip6" },
- { &efi_ip6_config_protocol_guid,
- "Ip6Config" },
- { &efi_ip6_service_binding_protocol_guid,
- "Ip6Sb" },
- { &efi_iscsi_dxe_guid,
- "IScsiDxe" },
- { &efi_iscsi4_dxe_guid,
- "IScsi4Dxe" },
- { &efi_load_file_protocol_guid,
- "LoadFile" },
- { &efi_load_file2_protocol_guid,
- "LoadFile2" },
- { &efi_loaded_image_protocol_guid,
- "LoadedImage" },
- { &efi_loaded_image_device_path_protocol_guid,
- "LoadedImageDevicePath"},
- { &efi_managed_network_protocol_guid,
- "ManagedNetwork" },
- { &efi_managed_network_service_binding_protocol_guid,
- "ManagedNetworkSb" },
- { &efi_mtftp4_protocol_guid,
- "Mtftp4" },
- { &efi_mtftp4_service_binding_protocol_guid,
- "Mtftp4Sb" },
- { &efi_mtftp6_protocol_guid,
- "Mtftp6" },
- { &efi_mtftp6_service_binding_protocol_guid,
- "Mtftp6Sb" },
- { &efi_nii_protocol_guid,
- "Nii" },
- { &efi_nii31_protocol_guid,
- "Nii31" },
- { &efi_pci_io_protocol_guid,
- "PciIo" },
- { &efi_pci_root_bridge_io_protocol_guid,
- "PciRootBridgeIo" },
- { &efi_pxe_base_code_protocol_guid,
- "PxeBaseCode" },
- { &efi_serial_io_protocol_guid,
- "SerialIo" },
- { &efi_shim_lock_protocol_guid,
- "ShimLock" },
- { &efi_simple_file_system_protocol_guid,
- "SimpleFileSystem" },
- { &efi_simple_network_protocol_guid,
- "SimpleNetwork" },
- { &efi_simple_pointer_protocol_guid,
- "SimplePointer" },
- { &efi_simple_text_input_protocol_guid,
- "SimpleTextInput" },
- { &efi_simple_text_input_ex_protocol_guid,
- "SimpleTextInputEx" },
- { &efi_simple_text_output_protocol_guid,
- "SimpleTextOutput" },
- { &efi_tcg_protocol_guid,
- "Tcg" },
- { &efi_tcp4_protocol_guid,
- "Tcp4" },
- { &efi_tcp4_service_binding_protocol_guid,
- "Tcp4Sb" },
- { &efi_tcp6_protocol_guid,
- "Tcp6" },
- { &efi_tcp6_service_binding_protocol_guid,
- "Tcp6Sb" },
- { &efi_tree_protocol_guid,
- "TrEE" },
- { &efi_udp4_protocol_guid,
- "Udp4" },
- { &efi_udp4_service_binding_protocol_guid,
- "Udp4Sb" },
- { &efi_udp6_protocol_guid,
- "Udp6" },
- { &efi_udp6_service_binding_protocol_guid,
- "Udp6Sb" },
- { &efi_uefi_pxe_bc_dxe_guid,
- "UefiPxeBcDxe" },
- { &efi_uga_draw_protocol_guid,
- "UgaDraw" },
- { &efi_unicode_collation_protocol_guid,
- "UnicodeCollation" },
- { &efi_usb_hc_protocol_guid,
- "UsbHc" },
- { &efi_usb2_hc_protocol_guid,
- "Usb2Hc" },
- { &efi_usb_io_protocol_guid,
- "UsbIo" },
- { &efi_vlan_config_protocol_guid,
- "VlanConfig" },
- { &efi_vlan_config_dxe_guid,
- "VlanConfigDxe" },
-};
-
/**
- * Convert GUID to a printable string
+ * Name EFI TPL
*
- * @v guid GUID
- * @ret string Printable string
+ * @v tpl Task priority level
+ * @ret text Task priority level as text
*/
-const __attribute__ (( pure )) char * efi_guid_ntoa ( CONST EFI_GUID *guid ) {
- union {
- union uuid uuid;
- EFI_GUID guid;
- } u;
- unsigned int i;
-
- /* Sanity check */
- if ( ! guid )
- return NULL;
-
- /* Check for a match against well-known GUIDs */
- for ( i = 0 ; i < ( sizeof ( efi_well_known_guids ) /
- sizeof ( efi_well_known_guids[0] ) ) ; i++ ) {
- if ( memcmp ( guid, efi_well_known_guids[i].guid,
- sizeof ( *guid ) ) == 0 ) {
- return efi_well_known_guids[i].name;
- }
+const __attribute__ (( pure )) char * efi_tpl_name ( EFI_TPL tpl ) {
+ static char buf[ 19 /* "0xXXXXXXXXXXXXXXXX" + NUL */ ];
+
+ switch ( tpl ) {
+ case TPL_APPLICATION: return "Application";
+ case TPL_CALLBACK: return "Callback";
+ case TPL_NOTIFY: return "Notify";
+ case TPL_HIGH_LEVEL: return "HighLevel";
+ default:
+ snprintf ( buf, sizeof ( buf ), "%#lx",
+ ( unsigned long ) tpl );
+ return buf;
}
-
- /* Convert GUID to standard endianness */
- memcpy ( &u.guid, guid, sizeof ( u.guid ) );
- uuid_mangle ( &u.uuid );
- return uuid_ntoa ( &u.uuid );
}
/**
@@ -393,15 +183,11 @@ void dbg_efi_openers ( EFI_HANDLE handle, EFI_GUID *protocol ) {
* @v protocol Protocol GUID
*/
void dbg_efi_protocol ( EFI_HANDLE handle, EFI_GUID *protocol ) {
- EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
VOID *interface;
- EFI_STATUS efirc;
int rc;
/* Get protocol instance */
- if ( ( efirc = bs->HandleProtocol ( handle, protocol,
- &interface ) ) != 0 ) {
- rc = -EEFI ( efirc );
+ if ( ( rc = efi_open ( handle, protocol, &interface ) ) != 0 ) {
printf ( "HANDLE %s could not identify %s: %s\n",
efi_handle_name ( handle ),
efi_guid_ntoa ( protocol ), strerror ( rc ) );
@@ -553,6 +339,64 @@ static const char * efi_driver_name2 ( EFI_COMPONENT_NAME2_PROTOCOL *wtf ) {
}
/**
+ * Get driver binding name
+ *
+ * @v binding Driver binding protocol
+ * @ret name Driver name, or NULL
+ */
+static const char * efi_binding_name ( EFI_DRIVER_BINDING_PROTOCOL *binding ) {
+ EFI_COMPONENT_NAME_PROTOCOL *name;
+ EFI_HANDLE image;
+ int rc;
+
+ /* Sanity check */
+ if ( ! binding ) {
+ DBG ( "[NULL DriverBinding]" );
+ return NULL;
+ }
+
+ /* Try to open component name protocol on image handle */
+ image = binding->ImageHandle;
+ if ( ( rc = efi_open ( image, &efi_component_name_protocol_guid,
+ &name ) ) != 0 ) {
+ DBG ( "[DriverBinding no ComponentName]" );
+ return NULL;
+ }
+
+ /* Try to get name from component name protocol */
+ return efi_driver_name ( name );
+}
+
+/**
+ * Get driver binding name
+ *
+ * @v binding Driver binding protocol
+ * @ret name Driver name, or NULL
+ */
+static const char * efi_binding_name2 ( EFI_DRIVER_BINDING_PROTOCOL *binding ){
+ EFI_HANDLE image;
+ EFI_COMPONENT_NAME2_PROTOCOL *name2;
+ int rc;
+
+ /* Sanity check */
+ if ( ! binding ) {
+ DBG ( "[NULL DriverBinding]" );
+ return NULL;
+ }
+
+ /* Try to open component name protocol on image handle */
+ image = binding->ImageHandle;
+ if ( ( rc = efi_open ( image, &efi_component_name2_protocol_guid,
+ &name2 ) ) != 0 ) {
+ DBG ( "[DriverBinding no ComponentName2]" );
+ return NULL;
+ }
+
+ /* Try to get name from component name protocol */
+ return efi_driver_name2 ( name2 );
+}
+
+/**
* Get PE/COFF debug filename
*
* @v loaded Loaded image
@@ -770,15 +614,12 @@ struct efi_handle_name_type {
/** EFI handle name types */
static struct efi_handle_name_type efi_handle_name_types[] = {
- /* Device path */
- EFI_HANDLE_NAME_TYPE ( &efi_device_path_protocol_guid,
- efi_devpath_text ),
- /* Driver name (for driver image handles) */
- EFI_HANDLE_NAME_TYPE ( &efi_component_name2_protocol_guid,
- efi_driver_name2 ),
+ /* Driver name (for driver binding handles) */
+ EFI_HANDLE_NAME_TYPE ( &efi_driver_binding_protocol_guid,
+ efi_binding_name2 ),
/* Driver name (via obsolete original ComponentName protocol) */
- EFI_HANDLE_NAME_TYPE ( &efi_component_name_protocol_guid,
- efi_driver_name ),
+ EFI_HANDLE_NAME_TYPE ( &efi_driver_binding_protocol_guid,
+ efi_binding_name ),
/* PE/COFF debug filename (for image handles) */
EFI_HANDLE_NAME_TYPE ( &efi_loaded_image_protocol_guid,
efi_pecoff_debug_name ),
@@ -791,6 +632,9 @@ static struct efi_handle_name_type efi_handle_name_types[] = {
/* Handle's loaded image file path (for image handles) */
EFI_HANDLE_NAME_TYPE ( &efi_loaded_image_protocol_guid,
efi_loaded_image_filepath_name ),
+ /* Device path */
+ EFI_HANDLE_NAME_TYPE ( &efi_device_path_protocol_guid,
+ efi_devpath_text ),
/* Our standard input file handle */
EFI_HANDLE_NAME_TYPE ( &efi_simple_text_input_protocol_guid,
efi_conin_name ),
@@ -816,6 +660,7 @@ const __attribute__ (( pure )) char * efi_handle_name ( EFI_HANDLE handle ) {
void *interface;
const char *name;
EFI_STATUS efirc;
+ int rc;
/* Fail immediately for NULL handles */
if ( ! handle )
@@ -828,10 +673,8 @@ const __attribute__ (( pure )) char * efi_handle_name ( EFI_HANDLE handle ) {
DBG2 ( "<%d", i );
/* Try to open the applicable protocol */
- efirc = bs->OpenProtocol ( handle, type->protocol, &interface,
- efi_image_handle, handle,
- EFI_OPEN_PROTOCOL_GET_PROTOCOL );
- if ( efirc != 0 ) {
+ if ( ( rc = efi_open ( handle, type->protocol,
+ &interface ) ) != 0 ) {
DBG2 ( ">" );
continue;
}
@@ -839,12 +682,7 @@ const __attribute__ (( pure )) char * efi_handle_name ( EFI_HANDLE handle ) {
/* Try to get name from this protocol */
DBG2 ( "-" );
name = type->name ( interface );
- DBG2 ( "%c", ( name ? ( name[0] ? 'Y' : 'E' ) : 'N' ) );
-
- /* Close protocol */
- bs->CloseProtocol ( handle, type->protocol,
- efi_image_handle, handle );
- DBG2 ( ">" );
+ DBG2 ( "%c>", ( name ? ( name[0] ? 'Y' : 'E' ) : 'N' ) );
/* Use this name, if possible */
if ( name && name[0] )
diff --git a/src/interface/efi/efi_download.c b/src/interface/efi/efi_download.c
index 8d12bd57c..1c2f13573 100644
--- a/src/interface/efi/efi_download.c
+++ b/src/interface/efi/efi_download.c
@@ -17,6 +17,7 @@
*/
FILE_LICENCE ( GPL2_OR_LATER );
+FILE_SECBOOT ( PERMITTED );
#include <stdlib.h>
#include <string.h>
diff --git a/src/interface/efi/efi_driver.c b/src/interface/efi/efi_driver.c
index fd9be5f51..cb07af401 100644
--- a/src/interface/efi/efi_driver.c
+++ b/src/interface/efi/efi_driver.c
@@ -18,6 +18,7 @@
*/
FILE_LICENCE ( GPL2_OR_LATER );
+FILE_SECBOOT ( PERMITTED );
#include <stddef.h>
#include <stdlib.h>
@@ -39,20 +40,6 @@ FILE_LICENCE ( GPL2_OR_LATER );
*
*/
-/* Disambiguate the various error causes */
-#define EINFO_EEFI_CONNECT \
- __einfo_uniqify ( EINFO_EPLATFORM, 0x01, \
- "Could not connect controllers" )
-#define EINFO_EEFI_CONNECT_PROHIBITED \
- __einfo_platformify ( EINFO_EEFI_CONNECT, \
- EFI_SECURITY_VIOLATION, \
- "Connecting controllers prohibited by " \
- "security policy" )
-#define EEFI_CONNECT_PROHIBITED \
- __einfo_error ( EINFO_EEFI_CONNECT_PROHIBITED )
-#define EEFI_CONNECT( efirc ) EPLATFORM ( EINFO_EEFI_CONNECT, efirc, \
- EEFI_CONNECT_PROHIBITED )
-
static EFI_DRIVER_BINDING_PROTOCOL efi_driver_binding;
/** List of controlled EFI devices */
@@ -68,45 +55,32 @@ static int efi_driver_disconnecting;
* @ret efidev EFI device, or NULL on error
*/
struct efi_device * efidev_alloc ( EFI_HANDLE device ) {
- EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
struct efi_device *efidev = NULL;
- union {
- EFI_DEVICE_PATH_PROTOCOL *path;
- void *interface;
- } path;
+ EFI_DEVICE_PATH_PROTOCOL *path;
EFI_DEVICE_PATH_PROTOCOL *path_end;
size_t path_len;
- EFI_STATUS efirc;
int rc;
/* Open device path */
- if ( ( efirc = bs->OpenProtocol ( device,
- &efi_device_path_protocol_guid,
- &path.interface, efi_image_handle,
- device,
- EFI_OPEN_PROTOCOL_GET_PROTOCOL ))!=0){
- rc = -EEFI ( efirc );
+ if ( ( rc = efi_open ( device, &efi_device_path_protocol_guid,
+ &path ) ) != 0 ) {
DBGC ( device, "EFIDRV %s could not open device path: %s\n",
efi_handle_name ( device ), strerror ( rc ) );
- goto err_open_path;
+ return NULL;
}
- path_len = ( efi_path_len ( path.path ) + sizeof ( *path_end ) );
+ path_len = ( efi_path_len ( path ) + sizeof ( *path_end ) );
/* Allocate and initialise structure */
efidev = zalloc ( sizeof ( *efidev ) + path_len );
if ( ! efidev )
- goto err_alloc;
+ return NULL;
efidev->device = device;
efidev->dev.desc.bus_type = BUS_TYPE_EFI;
efidev->path = ( ( ( void * ) efidev ) + sizeof ( *efidev ) );
- memcpy ( efidev->path, path.path, path_len );
+ memcpy ( efidev->path, path, path_len );
INIT_LIST_HEAD ( &efidev->dev.children );
list_add ( &efidev->dev.siblings, &efi_devices );
- err_alloc:
- bs->CloseProtocol ( device, &efi_device_path_protocol_guid,
- efi_image_handle, device );
- err_open_path:
return efidev;
}
@@ -180,6 +154,7 @@ static EFI_STATUS EFIAPI
efi_driver_supported ( EFI_DRIVER_BINDING_PROTOCOL *driver __unused,
EFI_HANDLE device, EFI_DEVICE_PATH_PROTOCOL *child ) {
struct efi_driver *efidrv;
+ unsigned int count;
int rc;
DBGCP ( device, "EFIDRV %s DRIVER_SUPPORTED",
@@ -195,18 +170,24 @@ efi_driver_supported ( EFI_DRIVER_BINDING_PROTOCOL *driver __unused,
return EFI_ALREADY_STARTED;
}
- /* Look for a driver claiming to support this device */
+ /* Count drivers claiming to support this device */
+ count = 0;
for_each_table_entry ( efidrv, EFI_DRIVERS ) {
if ( ( rc = efidrv->supported ( device ) ) == 0 ) {
DBGC ( device, "EFIDRV %s has driver \"%s\"\n",
efi_handle_name ( device ), efidrv->name );
- return 0;
+ count++;
}
}
- DBGCP ( device, "EFIDRV %s has no driver\n",
- efi_handle_name ( device ) );
- return EFI_UNSUPPORTED;
+ /* Check that we have at least one driver */
+ if ( ! count ) {
+ DBGCP ( device, "EFIDRV %s has no driver\n",
+ efi_handle_name ( device ) );
+ return EFI_UNSUPPORTED;
+ }
+
+ return 0;
}
/**
@@ -320,7 +301,7 @@ efi_driver_stop ( EFI_DRIVER_BINDING_PROTOCOL *driver __unused,
if ( ! efidev ) {
DBGCP ( device, "EFIDRV %s is not started\n",
efi_handle_name ( device ) );
- return EFI_DEVICE_ERROR;
+ return 0;
}
/* Raise TPL */
@@ -375,24 +356,17 @@ static EFI_STATUS EFIAPI
efi_driver_controller_name ( EFI_COMPONENT_NAME2_PROTOCOL *wtf __unused,
EFI_HANDLE device, EFI_HANDLE child,
CHAR8 *language, CHAR16 **controller_name ) {
- EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
- union {
- EFI_COMPONENT_NAME2_PROTOCOL *name2;
- void *interface;
- } name2;
- EFI_STATUS efirc;
+ EFI_COMPONENT_NAME2_PROTOCOL *name2;
+ int rc;
/* Delegate to the EFI_COMPONENT_NAME2_PROTOCOL instance
* installed on child handle, if present.
*/
if ( ( child != NULL ) &&
- ( ( efirc = bs->OpenProtocol (
- child, &efi_component_name2_protocol_guid,
- &name2.interface, NULL, NULL,
- EFI_OPEN_PROTOCOL_GET_PROTOCOL ) ) == 0 ) ) {
- return name2.name2->GetControllerName ( name2.name2, device,
- child, language,
- controller_name );
+ ( ( rc = efi_open ( child, &efi_component_name2_protocol_guid,
+ &name2 ) ) == 0 ) ) {
+ return name2->GetControllerName ( name2, device, child,
+ language, controller_name );
}
/* Otherwise, let EFI use the default Device Path Name */
@@ -455,15 +429,76 @@ void efi_driver_uninstall ( void ) {
}
/**
+ * Try to disconnect an existing EFI driver
+ *
+ * @v device EFI device
+ * @v protocol Protocol GUID
+ * @ret rc Return status code
+ */
+int efi_driver_exclude ( EFI_HANDLE device, EFI_GUID *protocol ) {
+ EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
+ EFI_OPEN_PROTOCOL_INFORMATION_ENTRY *openers;
+ EFI_OPEN_PROTOCOL_INFORMATION_ENTRY *opener;
+ EFI_HANDLE driver;
+ UINTN count;
+ unsigned int i;
+ EFI_STATUS efirc;
+ int rc;
+
+ /* Retrieve list of openers */
+ if ( ( efirc = bs->OpenProtocolInformation ( device, protocol, &openers,
+ &count ) ) != 0 ) {
+ rc = -EEFI ( efirc );
+ DBGC ( device, "EFIDRV %s could not list %s openers: %s\n",
+ efi_handle_name ( device ), efi_guid_ntoa ( protocol ),
+ strerror ( rc ) );
+ goto err_list;
+ }
+
+ /* Identify BY_DRIVER opener */
+ driver = NULL;
+ for ( i = 0 ; i < count ; i++ ) {
+ opener = &openers[i];
+ if ( opener->Attributes & EFI_OPEN_PROTOCOL_BY_DRIVER ) {
+ driver = opener->AgentHandle;
+ break;
+ }
+ }
+
+ /* Try to disconnect driver */
+ DBGC ( device, "EFIDRV %s disconnecting %s drivers\n",
+ efi_handle_name ( device ), efi_guid_ntoa ( protocol ) );
+ if ( driver ) {
+ DBGC ( device, "EFIDRV %s disconnecting %s driver ",
+ efi_handle_name ( device ), efi_guid_ntoa ( protocol ) );
+ DBGC ( device, "%s\n", efi_handle_name ( driver ) );
+ if ( ( rc = efi_disconnect ( device, driver ) ) != 0 ) {
+ DBGC ( device, "EFIDRV %s could not disconnect ",
+ efi_handle_name ( device ) );
+ DBGC ( device, "%s: %s\n",
+ efi_handle_name ( driver ), strerror ( rc ) );
+ goto err_disconnect;
+ }
+ }
+
+ /* Success */
+ rc = 0;
+
+ err_disconnect:
+ bs->FreePool ( openers );
+ err_list:
+ return rc;
+}
+
+/**
* Try to connect EFI driver
*
* @v device EFI device
* @ret rc Return status code
*/
static int efi_driver_connect ( EFI_HANDLE device ) {
- EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
- EFI_HANDLE drivers[2] =
- { efi_driver_binding.DriverBindingHandle, NULL };
+ EFI_HANDLE driver = efi_driver_binding.DriverBindingHandle;
+ struct efi_driver *efidrv;
EFI_STATUS efirc;
int rc;
@@ -481,13 +516,17 @@ static int efi_driver_connect ( EFI_HANDLE device ) {
DBGC ( device, "EFIDRV %s disconnecting existing drivers\n",
efi_handle_name ( device ) );
efi_driver_disconnecting = 1;
- if ( ( efirc = bs->DisconnectController ( device, NULL,
- NULL ) ) != 0 ) {
- rc = -EEFI ( efirc );
- DBGC ( device, "EFIDRV %s could not disconnect existing "
- "drivers: %s\n", efi_handle_name ( device ),
- strerror ( rc ) );
- /* Ignore the error and attempt to connect our drivers */
+ for_each_table_entry_reverse ( efidrv, EFI_DRIVERS ) {
+ if ( ! efidrv->exclude )
+ continue;
+ if ( ( rc = efidrv->supported ( device ) ) != 0 )
+ continue;
+ if ( ( rc = efidrv->exclude ( device ) ) != 0 ) {
+ DBGC ( device, "EFIDRV %s could not disconnect "
+ "drivers: %s\n", efi_handle_name ( device ),
+ strerror ( rc ) );
+ /* Ignore the error and attempt to connect anyway */
+ }
}
efi_driver_disconnecting = 0;
DBGC2 ( device, "EFIDRV %s after disconnecting:\n",
@@ -497,16 +536,14 @@ static int efi_driver_connect ( EFI_HANDLE device ) {
/* Connect our driver */
DBGC ( device, "EFIDRV %s connecting new drivers\n",
efi_handle_name ( device ) );
- if ( ( efirc = bs->ConnectController ( device, drivers, NULL,
- TRUE ) ) != 0 ) {
- rc = -EEFI_CONNECT ( efirc );
+ if ( ( rc = efi_connect ( device, driver ) ) != 0 ) {
DBGC ( device, "EFIDRV %s could not connect new drivers: "
"%s\n", efi_handle_name ( device ), strerror ( rc ) );
DBGC ( device, "EFIDRV %s connecting driver directly\n",
efi_handle_name ( device ) );
if ( ( efirc = efi_driver_start ( &efi_driver_binding, device,
NULL ) ) != 0 ) {
- rc = -EEFI_CONNECT ( efirc );
+ rc = -EEFI ( efirc );
DBGC ( device, "EFIDRV %s could not connect driver "
"directly: %s\n", efi_handle_name ( device ),
strerror ( rc ) );
@@ -527,14 +564,13 @@ static int efi_driver_connect ( EFI_HANDLE device ) {
* @ret rc Return status code
*/
static int efi_driver_disconnect ( EFI_HANDLE device ) {
- EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
+ EFI_HANDLE driver = efi_driver_binding.DriverBindingHandle;
/* Disconnect our driver */
efi_driver_disconnecting = 1;
- bs->DisconnectController ( device,
- efi_driver_binding.DriverBindingHandle,
- NULL );
+ efi_disconnect ( device, driver );
efi_driver_disconnecting = 0;
+
return 0;
}
@@ -545,10 +581,9 @@ static int efi_driver_disconnect ( EFI_HANDLE device ) {
* @ret rc Return status code
*/
static int efi_driver_reconnect ( EFI_HANDLE device ) {
- EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
/* Reconnect any available driver */
- bs->ConnectController ( device, NULL, NULL, TRUE );
+ efi_connect ( device, NULL );
return 0;
}
diff --git a/src/interface/efi/efi_entropy.c b/src/interface/efi/efi_entropy.c
index cda1c3640..b6bd12ccc 100644
--- a/src/interface/efi/efi_entropy.c
+++ b/src/interface/efi/efi_entropy.c
@@ -22,6 +22,7 @@
*/
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+FILE_SECBOOT ( PERMITTED );
#include <errno.h>
#include <ipxe/entropy.h>
diff --git a/src/interface/efi/efi_fbcon.c b/src/interface/efi/efi_fbcon.c
index e3c4d001d..afa3da5e2 100644
--- a/src/interface/efi/efi_fbcon.c
+++ b/src/interface/efi/efi_fbcon.c
@@ -22,6 +22,7 @@
*/
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+FILE_SECBOOT ( PERMITTED );
/**
* @file
@@ -42,6 +43,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <ipxe/ansicol.h>
#include <ipxe/fbcon.h>
#include <ipxe/console.h>
+#include <ipxe/uaccess.h>
#include <ipxe/umalloc.h>
#include <ipxe/rotate.h>
#include <config/console.h>
@@ -91,7 +93,7 @@ struct efifb {
/** Font definition */
struct fbcon_font font;
/** Character glyph cache */
- userptr_t glyphs;
+ uint8_t *glyphs;
/** Dynamic characters in cache */
unsigned int dynamic[EFIFB_DYNAMIC];
/** Next dynamic character cache entry to evict */
@@ -117,14 +119,14 @@ static int efifb_draw ( unsigned int character, unsigned int index,
unsigned int height;
unsigned int x;
unsigned int y;
+ uint8_t *glyph;
uint8_t bitmask;
- size_t offset;
EFI_STATUS efirc;
int rc;
/* Clear existing glyph */
- offset = ( index * efifb.font.height );
- memset_user ( efifb.glyphs, offset, 0, efifb.font.height );
+ glyph = &efifb.glyphs[ index * efifb.font.height ];
+ memset ( glyph, 0, efifb.font.height );
/* Get glyph */
blt = NULL;
@@ -157,8 +159,7 @@ static int efifb_draw ( unsigned int character, unsigned int index,
pixel++;
}
bitmask ^= toggle;
- copy_to_user ( efifb.glyphs, offset++, &bitmask,
- sizeof ( bitmask ) );
+ *(glyph++) = bitmask;
}
/* Free glyph */
@@ -223,11 +224,10 @@ static unsigned int efifb_dynamic ( unsigned int character ) {
* Get character glyph
*
* @v character Unicode character
- * @v glyph Character glyph to fill in
+ * @ret glyph Character glyph to fill in
*/
-static void efifb_glyph ( unsigned int character, uint8_t *glyph ) {
+static const uint8_t * efifb_glyph ( unsigned int character ) {
unsigned int index;
- size_t offset;
/* Identify glyph */
if ( character < EFIFB_ASCII ) {
@@ -241,9 +241,8 @@ static void efifb_glyph ( unsigned int character, uint8_t *glyph ) {
index = efifb_dynamic ( character );
}
- /* Copy cached glyph */
- offset = ( index * efifb.font.height );
- copy_from_user ( glyph, efifb.glyphs, offset, efifb.font.height );
+ /* Return cached glyph */
+ return &efifb.glyphs[ index * efifb.font.height ];
}
/**
@@ -296,7 +295,7 @@ static int efifb_glyphs ( void ) {
rc = -ENOMEM;
goto err_alloc;
}
- memset_user ( efifb.glyphs, 0, 0, len );
+ memset ( efifb.glyphs, 0, len );
/* Get font data */
for ( character = 0 ; character < EFIFB_ASCII ; character++ ) {
@@ -582,10 +581,10 @@ static int efifb_init ( struct console_configuration *config ) {
efifb.start = efifb.gop->Mode->FrameBufferBase;
DBGC ( &efifb, "EFIFB using mode %d (%dx%d %dbpp at %#08lx)\n",
mode, efifb.pixel.width, efifb.pixel.height, bpp, efifb.start );
-}
+ }
/* Initialise frame buffer console */
- if ( ( rc = fbcon_init ( &efifb.fbcon, phys_to_user ( efifb.start ),
+ if ( ( rc = fbcon_init ( &efifb.fbcon, phys_to_virt ( efifb.start ),
&efifb.pixel, &efifb.map, &efifb.font,
config ) ) != 0 )
goto err_fbcon_init;
diff --git a/src/interface/efi/efi_fdt.c b/src/interface/efi/efi_fdt.c
index cd3f109df..cd8580fcb 100644
--- a/src/interface/efi/efi_fdt.c
+++ b/src/interface/efi/efi_fdt.c
@@ -22,11 +22,16 @@
*/
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+FILE_SECBOOT ( PERMITTED );
#include <string.h>
+#include <byteswap.h>
#include <ipxe/fdt.h>
-#include <ipxe/efi/efi.h>
#include <ipxe/init.h>
+#include <ipxe/efi/efi.h>
+#include <ipxe/efi/efi_table.h>
+#include <ipxe/efi/efi_fdt.h>
+#include <ipxe/efi/Guid/Fdt.h>
/** @file
*
@@ -34,19 +39,17 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
*
*/
-#define DEVICE_TREE_TABLE_GUID \
- { 0xb1b621d5, 0xf19c, 0x41a5, \
- { 0x83, 0x0b, 0xd9, 0x15, 0x2c, 0x69, 0xaa, 0xe0 } }
-
/** EFI Flattened Device Tree configuration table */
static struct fdt_header *efi_fdt;
-EFI_USE_TABLE ( DEVICE_TREE_TABLE, &efi_fdt, 0 );
+EFI_USE_TABLE ( FDT_TABLE, &efi_fdt, 0 );
/**
* Initialise EFI Flattened Device Tree
*
*/
static void efi_fdt_init ( void ) {
+ EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
+ EFI_STATUS efirc;
int rc;
/* Do nothing if no configuration table is present */
@@ -56,15 +59,105 @@ static void efi_fdt_init ( void ) {
}
DBGC ( &efi_fdt, "EFIFDT configuration table at %p\n", efi_fdt );
- /* Register device tree */
- if ( ( rc = register_fdt ( efi_fdt ) ) != 0 ) {
- DBGC ( &efi_fdt, "EFIFDT could not register: %s\n",
+ /* Parse as system device tree */
+ if ( ( rc = fdt_parse ( &sysfdt, efi_fdt, -1UL ) ) != 0 ) {
+ DBGC ( &efi_fdt, "EFIFDT could not parse: %s\n",
strerror ( rc ) );
return;
}
+
+ /* Create copy, since table may be removed at any time */
+ if ( ( efirc = bs->AllocatePool ( EfiBootServicesData, sysfdt.len,
+ &sysfdt.raw ) ) != 0 ) {
+ DBGC ( &efi_fdt, "EFIFDT could not create copy\n" );
+ sysfdt.len = 0;
+ return;
+ }
+ memcpy ( sysfdt.raw, efi_fdt, sysfdt.len );
}
/** EFI Flattened Device Tree initialisation function */
struct init_fn efi_fdt_init_fn __init_fn ( INIT_EARLY ) = {
+ .name = "efifdt",
.initialise = efi_fdt_init,
};
+
+/**
+ * Determine length of EFI Flattened Device Tree
+ *
+ * @v data Configuration table data (presumed valid)
+ * @ret len Length of table
+ */
+static size_t efi_fdt_len ( const void *data ) {
+ const struct fdt_header *hdr = data;
+
+ return be32_to_cpu ( hdr->totalsize );
+}
+
+/** EFI Flattened Device Tree table type */
+static struct efi_table efi_fdt_table = {
+ .guid = &efi_fdt_table_guid,
+ .len = efi_fdt_len,
+};
+
+/** EFI Flattened Device Tree table backup */
+static void *efi_fdt_backup;
+
+/** EFI Flattened Device Tree installed table */
+static struct fdt_header *efi_fdt_installed;
+
+/**
+ * Install EFI Flattened Device Tree table
+ *
+ * @v cmdline Command line, or NULL
+ * @ret rc Return status code
+ */
+int efi_fdt_install ( const char *cmdline ) {
+ int rc;
+
+ /* Create device tree */
+ if ( ( rc = fdt_create ( &efi_fdt_installed, cmdline, 0, 0 ) ) != 0 ) {
+ DBGC ( &efi_fdt, "EFI_FDT could not install: %s\n",
+ strerror ( rc ) );
+ goto err_create;
+ }
+
+ /* Install table */
+ if ( ( rc = efi_install_table ( &efi_fdt_table, efi_fdt_installed,
+ &efi_fdt_backup ) ) != 0 ) {
+ DBGC ( &efi_fdt, "EFIFDT could not install: %s\n",
+ strerror ( rc ) );
+ goto err_install;
+ }
+
+ return 0;
+
+ efi_uninstall_table ( &efi_fdt_table, &efi_fdt_backup );
+ err_install:
+ fdt_remove ( efi_fdt_installed );
+ err_create:
+ return rc;
+}
+
+/**
+ * Uninstall EFI Flattened Device Tree table
+ *
+ * @ret rc Return status code
+ */
+int efi_fdt_uninstall ( void ) {
+ int rc;
+
+ /* Uninstall table */
+ if ( ( rc = efi_uninstall_table ( &efi_fdt_table,
+ &efi_fdt_backup ) ) != 0 ) {
+ DBGC ( &efi_fdt, "EFIFDT could not %sinstall: %s\n",
+ ( efi_fdt_backup ? "re" : "un" ), strerror ( rc ) );
+ /* Leak memory: there is nothing else we can do */
+ return rc;
+ }
+
+ /* Remove table */
+ fdt_remove ( efi_fdt_installed );
+
+ return 0;
+}
diff --git a/src/interface/efi/efi_file.c b/src/interface/efi/efi_file.c
index 2ae3a0cb4..2f49b1a99 100644
--- a/src/interface/efi/efi_file.c
+++ b/src/interface/efi/efi_file.c
@@ -22,6 +22,7 @@
*/
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+FILE_SECBOOT ( PERMITTED );
/**
* @file
@@ -39,6 +40,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <wchar.h>
#include <ipxe/image.h>
#include <ipxe/cpio.h>
+#include <ipxe/initrd.h>
#include <ipxe/efi/efi.h>
#include <ipxe/efi/Protocol/SimpleFileSystem.h>
#include <ipxe/efi/Protocol/BlockIo.h>
@@ -177,12 +179,12 @@ static size_t efi_file_len ( struct efi_file *file ) {
* Read chunk of EFI file
*
* @v reader EFI file reader
- * @v data Input data, or UNULL to zero-fill
+ * @v data Input data, or NULL to zero-fill
* @v len Length of input data
* @ret len Length of output data
*/
static size_t efi_file_read_chunk ( struct efi_file_reader *reader,
- userptr_t data, size_t len ) {
+ const void *data, size_t len ) {
struct efi_file *file = reader->file;
size_t offset;
@@ -203,7 +205,7 @@ static size_t efi_file_read_chunk ( struct efi_file_reader *reader,
/* Copy or zero output data */
if ( data ) {
- copy_from_user ( reader->data, data, offset, len );
+ memcpy ( reader->data, ( data + offset ), len );
} else {
memset ( reader->data, 0, len );
}
@@ -245,6 +247,7 @@ static size_t efi_file_read_initrd ( struct efi_file_reader *reader ) {
size_t cpio_len;
size_t name_len;
size_t len;
+ unsigned int i;
/* Read from file */
len = 0;
@@ -261,24 +264,22 @@ static size_t efi_file_read_initrd ( struct efi_file_reader *reader ) {
efi_file_name ( file ), reader->pos,
( reader->pos + pad_len ) );
}
- len += efi_file_read_chunk ( reader, UNULL, pad_len );
-
- /* Read CPIO header, if applicable */
- cpio_len = cpio_header ( image, &cpio );
- if ( cpio_len ) {
- name = cpio_name ( image );
- name_len = cpio_name_len ( image );
- pad_len = ( cpio_len - sizeof ( cpio ) - name_len );
+ len += efi_file_read_chunk ( reader, NULL, pad_len );
+
+ /* Read CPIO header(s), if applicable */
+ name = cpio_name ( image );
+ for ( i = 0 ; ( cpio_len = cpio_header ( image, i, &cpio ) );
+ i++ ) {
+ name_len = ( cpio_len - sizeof ( cpio ) );
+ pad_len = cpio_pad_len ( cpio_len );
DBGC ( file, "EFIFILE %s [%#08zx,%#08zx) %s header\n",
efi_file_name ( file ), reader->pos,
- ( reader->pos + cpio_len ), image->name );
- len += efi_file_read_chunk ( reader,
- virt_to_user ( &cpio ),
+ ( reader->pos + cpio_len + pad_len ),
+ image->name );
+ len += efi_file_read_chunk ( reader, &cpio,
sizeof ( cpio ) );
- len += efi_file_read_chunk ( reader,
- virt_to_user ( name ),
- name_len );
- len += efi_file_read_chunk ( reader, UNULL, pad_len );
+ len += efi_file_read_chunk ( reader, name, name_len );
+ len += efi_file_read_chunk ( reader, NULL, pad_len );
}
/* Read file data */
@@ -386,8 +387,12 @@ efi_file_open ( EFI_FILE_PROTOCOL *this, EFI_FILE_PROTOCOL **new,
name++;
}
+ /* Strip redundant path separator characters */
+ while ( ( *name == '\\' ) || ( *name == '.' ) )
+ name++;
+
/* Allow root directory itself to be opened */
- if ( ( name[0] == '\0' ) || ( name[0] == '.' ) )
+ if ( ! *name )
return efi_file_open_fixed ( &efi_file_root, wname, new );
/* Fail unless opening from the root */
@@ -976,9 +981,9 @@ static EFI_DISK_IO_PROTOCOL efi_disk_io_protocol = {
*/
static int efi_file_path_claim ( struct efi_file_path *file ) {
EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
+ EFI_DEVICE_PATH_PROTOCOL *old;
EFI_DEVICE_PATH_PROTOCOL *end;
EFI_HANDLE handle;
- VOID *old;
EFI_STATUS efirc;
int rc;
@@ -994,10 +999,8 @@ static int efi_file_path_claim ( struct efi_file_path *file ) {
}
/* Locate device path protocol on this handle */
- if ( ( ( efirc = bs->HandleProtocol ( handle,
- &efi_device_path_protocol_guid,
- &old ) ) != 0 ) ) {
- rc = -EEFI ( efirc );
+ if ( ( rc = efi_open ( handle, &efi_device_path_protocol_guid,
+ &old ) != 0 ) ) {
DBGC ( file, "EFIFILE %s could not locate %s: %s\n",
efi_file_name ( &file->file ),
efi_devpath_text ( file->path ), strerror ( rc ) );
@@ -1112,10 +1115,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;
- union {
- EFI_DISK_IO_PROTOCOL *diskio;
- void *interface;
- } diskio;
+ EFI_DISK_IO_PROTOCOL *diskio;
struct image *image;
EFI_STATUS efirc;
int rc;
@@ -1163,17 +1163,14 @@ int efi_file_install ( EFI_HANDLE handle ) {
* of calls to our DRIVER_STOP method when starting the EFI
* shell. I have no idea why this is.
*/
- if ( ( efirc = bs->OpenProtocol ( handle, &efi_disk_io_protocol_guid,
- &diskio.interface, efi_image_handle,
- handle,
- EFI_OPEN_PROTOCOL_BY_DRIVER ) ) != 0){
- rc = -EEFI ( efirc );
+ if ( ( rc = efi_open_by_driver ( handle, &efi_disk_io_protocol_guid,
+ &diskio ) ) != 0 ) {
DBGC ( handle, "Could not open disk I/O protocol: %s\n",
strerror ( rc ) );
DBGC_EFI_OPENERS ( handle, handle, &efi_disk_io_protocol_guid );
goto err_open;
}
- assert ( diskio.diskio == &efi_disk_io_protocol );
+ assert ( diskio == &efi_disk_io_protocol );
/* Claim Linux initrd fixed device path */
if ( ( rc = efi_file_path_claim ( &efi_file_initrd ) ) != 0 )
@@ -1193,8 +1190,7 @@ int efi_file_install ( EFI_HANDLE handle ) {
efi_file_path_uninstall ( &efi_file_initrd );
err_initrd_install:
err_initrd_claim:
- bs->CloseProtocol ( handle, &efi_disk_io_protocol_guid,
- efi_image_handle, handle );
+ efi_close_by_driver ( handle, &efi_disk_io_protocol_guid );
err_open:
bs->UninstallMultipleProtocolInterfaces (
handle,
@@ -1222,8 +1218,7 @@ void efi_file_uninstall ( EFI_HANDLE handle ) {
efi_file_path_uninstall ( &efi_file_initrd );
/* Close our own disk I/O protocol */
- bs->CloseProtocol ( handle, &efi_disk_io_protocol_guid,
- efi_image_handle, handle );
+ efi_close_by_driver ( handle, &efi_disk_io_protocol_guid );
/* We must install the file system protocol first, since
* otherwise the EDK2 code will attempt to helpfully uninstall
diff --git a/src/interface/efi/efi_guid.c b/src/interface/efi/efi_guid.c
index f841448f1..c989aebfe 100644
--- a/src/interface/efi/efi_guid.c
+++ b/src/interface/efi/efi_guid.c
@@ -22,10 +22,14 @@
*/
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+FILE_SECBOOT ( PERMITTED );
+#include <string.h>
+#include <ipxe/uuid.h>
#include <ipxe/efi/efi.h>
#include <ipxe/efi/Protocol/AbsolutePointer.h>
#include <ipxe/efi/Protocol/AcpiTable.h>
+#include <ipxe/efi/Protocol/AdapterInformation.h>
#include <ipxe/efi/Protocol/AppleNetBoot.h>
#include <ipxe/efi/Protocol/Arp.h>
#include <ipxe/efi/Protocol/BlockIo.h>
@@ -42,6 +46,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <ipxe/efi/Protocol/Dns4.h>
#include <ipxe/efi/Protocol/Dns6.h>
#include <ipxe/efi/Protocol/DriverBinding.h>
+#include <ipxe/efi/Protocol/EapConfiguration.h>
#include <ipxe/efi/Protocol/GraphicsOutput.h>
#include <ipxe/efi/Protocol/HiiConfigAccess.h>
#include <ipxe/efi/Protocol/HiiFont.h>
@@ -61,6 +66,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <ipxe/efi/Protocol/PciIo.h>
#include <ipxe/efi/Protocol/PciRootBridgeIo.h>
#include <ipxe/efi/Protocol/PxeBaseCode.h>
+#include <ipxe/efi/Protocol/Rng.h>
#include <ipxe/efi/Protocol/SerialIo.h>
#include <ipxe/efi/Protocol/ShimLock.h>
#include <ipxe/efi/Protocol/SimpleFileSystem.h>
@@ -69,7 +75,10 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <ipxe/efi/Protocol/SimpleTextIn.h>
#include <ipxe/efi/Protocol/SimpleTextInEx.h>
#include <ipxe/efi/Protocol/SimpleTextOut.h>
+#include <ipxe/efi/Protocol/StorageSecurityCommand.h>
+#include <ipxe/efi/Protocol/Supplicant.h>
#include <ipxe/efi/Protocol/TcgService.h>
+#include <ipxe/efi/Protocol/Tcg2Protocol.h>
#include <ipxe/efi/Protocol/Tcp4.h>
#include <ipxe/efi/Protocol/Tcp6.h>
#include <ipxe/efi/Protocol/Udp4.h>
@@ -80,8 +89,16 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <ipxe/efi/Protocol/Usb2HostController.h>
#include <ipxe/efi/Protocol/UsbIo.h>
#include <ipxe/efi/Protocol/VlanConfig.h>
+#include <ipxe/efi/Protocol/WiFi2.h>
+#include <ipxe/efi/Guid/Acpi.h>
+#include <ipxe/efi/Guid/Fdt.h>
#include <ipxe/efi/Guid/FileInfo.h>
#include <ipxe/efi/Guid/FileSystemInfo.h>
+#include <ipxe/efi/Guid/GlobalVariable.h>
+#include <ipxe/efi/Guid/ImageAuthentication.h>
+#include <ipxe/efi/Guid/MicrosoftVendor.h>
+#include <ipxe/efi/Guid/SmBios.h>
+#include <ipxe/efi/Guid/TlsAuthentication.h>
/** @file
*
@@ -94,6 +111,11 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
{ 0x607f766c, 0x7455, 0x42be, \
{ 0x93, 0x0b, 0xe4, 0xd7, 0x6d, 0xb2, 0x72, 0x0f } }
+/* Unicode collation protocol GUID was deleted from EDK2 headers */
+#define EFI_UNICODE_COLLATION_PROTOCOL_GUID \
+ { 0x1d85cd7f, 0xf43d, 0x11d2, \
+ { 0x9a, 0xc, 0x0, 0x90, 0x27, 0x3f, 0xc1, 0x4d } }
+
/** Absolute pointer protocol GUID */
EFI_GUID efi_absolute_pointer_protocol_guid
= EFI_ABSOLUTE_POINTER_PROTOCOL_GUID;
@@ -102,6 +124,10 @@ EFI_GUID efi_absolute_pointer_protocol_guid
EFI_GUID efi_acpi_table_protocol_guid
= EFI_ACPI_TABLE_PROTOCOL_GUID;
+/** Adapter information protocol GUID */
+EFI_GUID efi_adapter_information_protocol_guid
+ = EFI_ADAPTER_INFORMATION_PROTOCOL_GUID;
+
/** Apple NetBoot protocol GUID */
EFI_GUID efi_apple_net_boot_protocol_guid
= EFI_APPLE_NET_BOOT_PROTOCOL_GUID;
@@ -182,6 +208,10 @@ EFI_GUID efi_dns6_service_binding_protocol_guid
EFI_GUID efi_driver_binding_protocol_guid
= EFI_DRIVER_BINDING_PROTOCOL_GUID;
+/** EAP configuration protocol GUID */
+EFI_GUID efi_eap_configuration_protocol_guid
+ = EFI_EAP_CONFIGURATION_PROTOCOL_GUID;
+
/** Graphics output protocol GUID */
EFI_GUID efi_graphics_output_protocol_guid
= EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID;
@@ -290,6 +320,10 @@ EFI_GUID efi_pci_root_bridge_io_protocol_guid
EFI_GUID efi_pxe_base_code_protocol_guid
= EFI_PXE_BASE_CODE_PROTOCOL_GUID;
+/** Random number generator protocol GUID */
+EFI_GUID efi_rng_protocol_guid
+ = EFI_RNG_PROTOCOL_GUID;
+
/** Serial I/O protocol GUID */
EFI_GUID efi_serial_io_protocol_guid
= EFI_SERIAL_IO_PROTOCOL_GUID;
@@ -322,10 +356,22 @@ EFI_GUID efi_simple_text_input_ex_protocol_guid
EFI_GUID efi_simple_text_output_protocol_guid
= EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL_GUID;
+/** Storage security protocol GUID */
+EFI_GUID efi_storage_security_command_protocol_guid
+ = EFI_STORAGE_SECURITY_COMMAND_PROTOCOL_GUID;
+
+/** Supplicant protocol GUID */
+EFI_GUID efi_supplicant_protocol_guid
+ = EFI_SUPPLICANT_PROTOCOL_GUID;
+
/** TCG protocol GUID */
EFI_GUID efi_tcg_protocol_guid
= EFI_TCG_PROTOCOL_GUID;
+/** TCG2 protocol GUID */
+EFI_GUID efi_tcg2_protocol_guid
+ = EFI_TCG2_PROTOCOL_GUID;
+
/** TCPv4 protocol GUID */
EFI_GUID efi_tcp4_protocol_guid
= EFI_TCP4_PROTOCOL_GUID;
@@ -386,8 +432,319 @@ EFI_GUID efi_usb_io_protocol_guid
EFI_GUID efi_vlan_config_protocol_guid
= EFI_VLAN_CONFIG_PROTOCOL_GUID;
+/** WiFi 2 protocol GUID */
+EFI_GUID efi_wifi2_protocol_guid
+ = EFI_WIRELESS_MAC_CONNECTION_II_PROTOCOL_GUID;
+
+/** ACPI 1.0 table GUID */
+EFI_GUID efi_acpi_10_table_guid
+ = ACPI_10_TABLE_GUID;
+
+/** ACPI 2.0 table GUID */
+EFI_GUID efi_acpi_20_table_guid
+ = EFI_ACPI_20_TABLE_GUID;
+
+/** FDT table GUID */
+EFI_GUID efi_fdt_table_guid
+ = FDT_TABLE_GUID;
+
+/** SMBIOS table GUID */
+EFI_GUID efi_smbios_table_guid
+ = SMBIOS_TABLE_GUID;
+
+/** SMBIOS3 table GUID */
+EFI_GUID efi_smbios3_table_guid
+ = SMBIOS3_TABLE_GUID;
+
+/** X.509 certificate GUID */
+EFI_GUID efi_cert_x509_guid = EFI_CERT_X509_GUID;
+
/** File information GUID */
EFI_GUID efi_file_info_id = EFI_FILE_INFO_ID;
/** File system information GUID */
EFI_GUID efi_file_system_info_id = EFI_FILE_SYSTEM_INFO_ID;
+
+/** Global variable GUID */
+EFI_GUID efi_global_variable = EFI_GLOBAL_VARIABLE;
+
+/** Image security database GUID */
+EFI_GUID efi_image_security_database_guid = EFI_IMAGE_SECURITY_DATABASE_GUID;
+
+/** Microsoft vendor GUID */
+EFI_GUID efi_microsoft_vendor_guid = MICROSOFT_VENDOR_GUID;
+
+/** TLS CA certificate variable GUID */
+EFI_GUID efi_tls_ca_certificate_guid = EFI_TLS_CA_CERTIFICATE_GUID;
+
+/** HttpBootDxe module GUID */
+static EFI_GUID efi_http_boot_dxe_guid = {
+ 0xecebcb00, 0xd9c8, 0x11e4,
+ { 0xaf, 0x3d, 0x8c, 0xdc, 0xd4, 0x26, 0xc9, 0x73 }
+};
+
+/** IScsiDxe module GUID */
+static EFI_GUID efi_iscsi_dxe_guid = {
+ 0x86cddf93, 0x4872, 0x4597,
+ { 0x8a, 0xf9, 0xa3, 0x5a, 0xe4, 0xd3, 0x72, 0x5f }
+};
+
+/** Old IScsi4Dxe module GUID */
+static EFI_GUID efi_iscsi4_dxe_guid = {
+ 0x4579b72d, 0x7ec4, 0x4dd4,
+ { 0x84, 0x86, 0x08, 0x3c, 0x86, 0xb1, 0x82, 0xa7 }
+};
+
+/** UefiPxeBcDxe module GUID */
+static EFI_GUID efi_uefi_pxe_bc_dxe_guid = {
+ 0xb95e9fda, 0x26de, 0x48d2,
+ { 0x88, 0x07, 0x1f, 0x91, 0x07, 0xac, 0x5e, 0x3a }
+};
+
+/** VlanConfigDxe module GUID */
+static EFI_GUID efi_vlan_config_dxe_guid = {
+ 0xe4f61863, 0xfe2c, 0x4b56,
+ { 0xa8, 0xf4, 0x08, 0x51, 0x9b, 0xc4, 0x39, 0xdf }
+};
+
+/** WiFiConnectionMgrDxe module GUID */
+static EFI_GUID efi_wifi_connection_mgr_dxe_guid = {
+ 0x99b7c019, 0x4789, 0x4829,
+ { 0xa7, 0xbd, 0x0d, 0x4b, 0xaa, 0x62, 0x28, 0x72 }
+};
+
+/** A well-known GUID */
+struct efi_well_known_guid {
+ /** GUID */
+ EFI_GUID *guid;
+ /** Name */
+ const char *name;
+};
+
+/** Well-known GUIDs */
+static struct efi_well_known_guid efi_well_known_guids[] = {
+ { &efi_absolute_pointer_protocol_guid,
+ "AbsolutePointer" },
+ { &efi_acpi_10_table_guid,
+ "Acpi10" },
+ { &efi_acpi_20_table_guid,
+ "Acpi20" },
+ { &efi_acpi_table_protocol_guid,
+ "AcpiTable" },
+ { &efi_adapter_information_protocol_guid,
+ "AdapterInfo" },
+ { &efi_apple_net_boot_protocol_guid,
+ "AppleNetBoot" },
+ { &efi_arp_protocol_guid,
+ "Arp" },
+ { &efi_arp_service_binding_protocol_guid,
+ "ArpSb" },
+ { &efi_block_io_protocol_guid,
+ "BlockIo" },
+ { &efi_block_io2_protocol_guid,
+ "BlockIo2" },
+ { &efi_bus_specific_driver_override_protocol_guid,
+ "BusSpecificDriverOverride" },
+ { &efi_cert_x509_guid,
+ "CertX509" },
+ { &efi_component_name_protocol_guid,
+ "ComponentName" },
+ { &efi_component_name2_protocol_guid,
+ "ComponentName2" },
+ { &efi_console_control_protocol_guid,
+ "ConsoleControl" },
+ { &efi_device_path_protocol_guid,
+ "DevicePath" },
+ { &efi_driver_binding_protocol_guid,
+ "DriverBinding" },
+ { &efi_dhcp4_protocol_guid,
+ "Dhcp4" },
+ { &efi_dhcp4_service_binding_protocol_guid,
+ "Dhcp4Sb" },
+ { &efi_dhcp6_protocol_guid,
+ "Dhcp6" },
+ { &efi_dhcp6_service_binding_protocol_guid,
+ "Dhcp6Sb" },
+ { &efi_disk_io_protocol_guid,
+ "DiskIo" },
+ { &efi_dns4_protocol_guid,
+ "Dns4" },
+ { &efi_dns4_service_binding_protocol_guid,
+ "Dns4Sb" },
+ { &efi_dns6_protocol_guid,
+ "Dns6" },
+ { &efi_dns6_service_binding_protocol_guid,
+ "Dns6Sb" },
+ { &efi_eap_configuration_protocol_guid,
+ "EapConfig" },
+ { &efi_fdt_table_guid,
+ "Fdt" },
+ { &efi_global_variable,
+ "GlobalVar" },
+ { &efi_graphics_output_protocol_guid,
+ "GraphicsOutput" },
+ { &efi_hii_config_access_protocol_guid,
+ "HiiConfigAccess" },
+ { &efi_hii_font_protocol_guid,
+ "HiiFont" },
+ { &efi_http_boot_dxe_guid,
+ "HttpBootDxe" },
+ { &efi_http_protocol_guid,
+ "Http" },
+ { &efi_http_service_binding_protocol_guid,
+ "HttpSb" },
+ { &efi_image_security_database_guid,
+ "ImageSecDb" },
+ { &efi_ip4_protocol_guid,
+ "Ip4" },
+ { &efi_ip4_config_protocol_guid,
+ "Ip4Config" },
+ { &efi_ip4_config2_protocol_guid,
+ "Ip4Config2" },
+ { &efi_ip4_service_binding_protocol_guid,
+ "Ip4Sb" },
+ { &efi_ip6_protocol_guid,
+ "Ip6" },
+ { &efi_ip6_config_protocol_guid,
+ "Ip6Config" },
+ { &efi_ip6_service_binding_protocol_guid,
+ "Ip6Sb" },
+ { &efi_iscsi_dxe_guid,
+ "IScsiDxe" },
+ { &efi_iscsi4_dxe_guid,
+ "IScsi4Dxe" },
+ { &efi_load_file_protocol_guid,
+ "LoadFile" },
+ { &efi_load_file2_protocol_guid,
+ "LoadFile2" },
+ { &efi_loaded_image_protocol_guid,
+ "LoadedImage" },
+ { &efi_loaded_image_device_path_protocol_guid,
+ "LoadedImageDevicePath"},
+ { &efi_managed_network_protocol_guid,
+ "ManagedNetwork" },
+ { &efi_managed_network_service_binding_protocol_guid,
+ "ManagedNetworkSb" },
+ { &efi_microsoft_vendor_guid,
+ "Microsoft" },
+ { &efi_mtftp4_protocol_guid,
+ "Mtftp4" },
+ { &efi_mtftp4_service_binding_protocol_guid,
+ "Mtftp4Sb" },
+ { &efi_mtftp6_protocol_guid,
+ "Mtftp6" },
+ { &efi_mtftp6_service_binding_protocol_guid,
+ "Mtftp6Sb" },
+ { &efi_nii_protocol_guid,
+ "Nii" },
+ { &efi_nii31_protocol_guid,
+ "Nii31" },
+ { &efi_pci_io_protocol_guid,
+ "PciIo" },
+ { &efi_pci_root_bridge_io_protocol_guid,
+ "PciRootBridgeIo" },
+ { &efi_pxe_base_code_protocol_guid,
+ "PxeBaseCode" },
+ { &efi_rng_protocol_guid,
+ "Rng" },
+ { &efi_serial_io_protocol_guid,
+ "SerialIo" },
+ { &efi_shim_lock_protocol_guid,
+ "ShimLock" },
+ { &efi_simple_file_system_protocol_guid,
+ "SimpleFileSystem" },
+ { &efi_simple_network_protocol_guid,
+ "SimpleNetwork" },
+ { &efi_simple_pointer_protocol_guid,
+ "SimplePointer" },
+ { &efi_simple_text_input_protocol_guid,
+ "SimpleTextInput" },
+ { &efi_simple_text_input_ex_protocol_guid,
+ "SimpleTextInputEx" },
+ { &efi_simple_text_output_protocol_guid,
+ "SimpleTextOutput" },
+ { &efi_smbios_table_guid,
+ "Smbios" },
+ { &efi_smbios3_table_guid,
+ "Smbios3" },
+ { &efi_storage_security_command_protocol_guid,
+ "StorageSecurityCommand" },
+ { &efi_supplicant_protocol_guid,
+ "Supplicant" },
+ { &efi_tcg_protocol_guid,
+ "Tcg" },
+ { &efi_tcg2_protocol_guid,
+ "Tcg2" },
+ { &efi_tcp4_protocol_guid,
+ "Tcp4" },
+ { &efi_tcp4_service_binding_protocol_guid,
+ "Tcp4Sb" },
+ { &efi_tcp6_protocol_guid,
+ "Tcp6" },
+ { &efi_tcp6_service_binding_protocol_guid,
+ "Tcp6Sb" },
+ { &efi_tls_ca_certificate_guid,
+ "TlsCaCert" },
+ { &efi_tree_protocol_guid,
+ "TrEE" },
+ { &efi_udp4_protocol_guid,
+ "Udp4" },
+ { &efi_udp4_service_binding_protocol_guid,
+ "Udp4Sb" },
+ { &efi_udp6_protocol_guid,
+ "Udp6" },
+ { &efi_udp6_service_binding_protocol_guid,
+ "Udp6Sb" },
+ { &efi_uefi_pxe_bc_dxe_guid,
+ "UefiPxeBcDxe" },
+ { &efi_uga_draw_protocol_guid,
+ "UgaDraw" },
+ { &efi_unicode_collation_protocol_guid,
+ "UnicodeCollation" },
+ { &efi_usb_hc_protocol_guid,
+ "UsbHc" },
+ { &efi_usb2_hc_protocol_guid,
+ "Usb2Hc" },
+ { &efi_usb_io_protocol_guid,
+ "UsbIo" },
+ { &efi_vlan_config_protocol_guid,
+ "VlanConfig" },
+ { &efi_vlan_config_dxe_guid,
+ "VlanConfigDxe" },
+ { &efi_wifi2_protocol_guid,
+ "Wifi2" },
+ { &efi_wifi_connection_mgr_dxe_guid,
+ "WiFiConnectionMgrDxe" },
+};
+
+/**
+ * Convert GUID to a printable string
+ *
+ * @v guid GUID
+ * @ret string Printable string
+ */
+const __attribute__ (( pure )) char * efi_guid_ntoa ( CONST EFI_GUID *guid ) {
+ union {
+ union uuid uuid;
+ EFI_GUID guid;
+ } u;
+ unsigned int i;
+
+ /* Sanity check */
+ if ( ! guid )
+ return NULL;
+
+ /* Check for a match against well-known GUIDs */
+ for ( i = 0 ; i < ( sizeof ( efi_well_known_guids ) /
+ sizeof ( efi_well_known_guids[0] ) ) ; i++ ) {
+ if ( memcmp ( guid, efi_well_known_guids[i].guid,
+ sizeof ( *guid ) ) == 0 ) {
+ return efi_well_known_guids[i].name;
+ }
+ }
+
+ /* Convert GUID to standard endianness */
+ memcpy ( &u.guid, guid, sizeof ( u.guid ) );
+ uuid_mangle ( &u.uuid );
+ return uuid_ntoa ( &u.uuid );
+}
diff --git a/src/interface/efi/efi_hii.c b/src/interface/efi/efi_hii.c
index 506fc8869..fd65ae122 100644
--- a/src/interface/efi/efi_hii.c
+++ b/src/interface/efi/efi_hii.c
@@ -22,6 +22,7 @@
*/
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+FILE_SECBOOT ( PERMITTED );
#include <stdlib.h>
#include <stddef.h>
@@ -147,13 +148,13 @@ void efi_ifr_end_op ( struct efi_ifr_builder *ifr ) {
*/
void efi_ifr_false_op ( struct efi_ifr_builder *ifr ) {
size_t dispaddr = ifr->ops_len;
- EFI_IFR_FALSE *false;
+ EFI_IFR_FALSE *op;
/* Add opcode */
- false = efi_ifr_op ( ifr, EFI_IFR_FALSE_OP, sizeof ( *false ) );
+ op = efi_ifr_op ( ifr, EFI_IFR_FALSE_OP, sizeof ( *op ) );
DBGC ( ifr, "IFR %p false\n", ifr );
- DBGC2_HDA ( ifr, dispaddr, false, sizeof ( *false ) );
+ DBGC2_HDA ( ifr, dispaddr, op, sizeof ( *op ) );
}
/**
@@ -462,13 +463,13 @@ void efi_ifr_text_op ( struct efi_ifr_builder *ifr, unsigned int prompt_id,
*/
void efi_ifr_true_op ( struct efi_ifr_builder *ifr ) {
size_t dispaddr = ifr->ops_len;
- EFI_IFR_TRUE *true;
+ EFI_IFR_TRUE *op;
/* Add opcode */
- true = efi_ifr_op ( ifr, EFI_IFR_TRUE_OP, sizeof ( *true ) );
+ op = efi_ifr_op ( ifr, EFI_IFR_TRUE_OP, sizeof ( *op ) );
DBGC ( ifr, "IFR %p true\n", ifr );
- DBGC2_HDA ( ifr, dispaddr, true, sizeof ( *true ) );
+ DBGC2_HDA ( ifr, dispaddr, op, sizeof ( *op ) );
}
/**
diff --git a/src/interface/efi/efi_init.c b/src/interface/efi/efi_init.c
index d3c5042d7..ac62ea747 100644
--- a/src/interface/efi/efi_init.c
+++ b/src/interface/efi/efi_init.c
@@ -18,6 +18,7 @@
*/
FILE_LICENCE ( GPL2_OR_LATER );
+FILE_SECBOOT ( PERMITTED );
#include <string.h>
#include <errno.h>
@@ -25,6 +26,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
#include <ipxe/init.h>
#include <ipxe/rotate.h>
#include <ipxe/efi/efi.h>
+#include <ipxe/efi/efi_table.h>
#include <ipxe/efi/efi_driver.h>
#include <ipxe/efi/efi_path.h>
#include <ipxe/efi/efi_cmdline.h>
@@ -104,24 +106,6 @@ static EFIAPI void efi_shutdown_hook ( EFI_EVENT event __unused,
}
/**
- * Look up EFI configuration table
- *
- * @v guid Configuration table GUID
- * @ret table Configuration table, or NULL
- */
-static void * efi_find_table ( EFI_GUID *guid ) {
- unsigned int i;
-
- for ( i = 0 ; i < efi_systab->NumberOfTableEntries ; i++ ) {
- if ( memcmp ( &efi_systab->ConfigurationTable[i].VendorGuid,
- guid, sizeof ( *guid ) ) == 0 )
- return efi_systab->ConfigurationTable[i].VendorTable;
- }
-
- return NULL;
-}
-
-/**
* Construct a stack cookie value
*
* @v handle Image handle
@@ -173,8 +157,7 @@ EFI_STATUS efi_init ( EFI_HANDLE image_handle,
EFI_BOOT_SERVICES *bs;
struct efi_protocol *prot;
struct efi_config_table *tab;
- void *loaded_image;
- void *device_path;
+ EFI_DEVICE_PATH_PROTOCOL *device_path;
void *device_path_copy;
size_t device_path_len;
EFI_STATUS efirc;
@@ -241,17 +224,19 @@ EFI_STATUS efi_init ( EFI_HANDLE image_handle,
}
}
- /* Get loaded image protocol */
- if ( ( efirc = bs->OpenProtocol ( image_handle,
- &efi_loaded_image_protocol_guid,
- &loaded_image, image_handle, NULL,
- EFI_OPEN_PROTOCOL_GET_PROTOCOL ) ) != 0 ) {
- rc = -EEFI ( efirc );
+ /* Get loaded image protocol
+ *
+ * We assume that our loaded image protocol will not be
+ * uninstalled while our image code is still running.
+ */
+ if ( ( rc = efi_open_unsafe ( image_handle,
+ &efi_loaded_image_protocol_guid,
+ &efi_loaded_image ) ) != 0 ) {
DBGC ( systab, "EFI could not get loaded image protocol: %s",
strerror ( rc ) );
+ efirc = EFIRC ( rc );
goto err_no_loaded_image;
}
- efi_loaded_image = loaded_image;
DBGC ( systab, "EFI image base address %p\n",
efi_loaded_image->ImageBase );
@@ -260,13 +245,12 @@ EFI_STATUS efi_init ( EFI_HANDLE image_handle,
efi_cmdline_len = efi_loaded_image->LoadOptionsSize;
/* Get loaded image's device handle's device path */
- if ( ( efirc = bs->OpenProtocol ( efi_loaded_image->DeviceHandle,
- &efi_device_path_protocol_guid,
- &device_path, image_handle, NULL,
- EFI_OPEN_PROTOCOL_GET_PROTOCOL ) ) != 0 ) {
- rc = -EEFI ( efirc );
+ if ( ( rc = efi_open ( efi_loaded_image->DeviceHandle,
+ &efi_device_path_protocol_guid,
+ &device_path ) ) != 0 ) {
DBGC ( systab, "EFI could not get loaded image's device path: "
"%s", strerror ( rc ) );
+ efirc = EFIRC ( rc );
goto err_no_device_path;
}
diff --git a/src/interface/efi/efi_local.c b/src/interface/efi/efi_local.c
index b28814241..27c9e3eaf 100644
--- a/src/interface/efi/efi_local.c
+++ b/src/interface/efi/efi_local.c
@@ -22,6 +22,7 @@
*/
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+FILE_SECBOOT ( PERMITTED );
#include <string.h>
#include <strings.h>
@@ -208,42 +209,27 @@ static int efi_local_check_volume_name ( struct efi_local *local,
*/
static int efi_local_open_root ( struct efi_local *local, EFI_HANDLE device,
EFI_FILE_PROTOCOL **root ) {
- EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
- union {
- void *interface;
- EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *fs;
- } u;
+ EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *fs;
EFI_STATUS efirc;
int rc;
/* Open file system protocol */
- if ( ( efirc = bs->OpenProtocol ( device,
- &efi_simple_file_system_protocol_guid,
- &u.interface, efi_image_handle,
- device,
- EFI_OPEN_PROTOCOL_GET_PROTOCOL ))!=0){
- rc = -EEFI ( efirc );
+ if ( ( rc = efi_open ( device, &efi_simple_file_system_protocol_guid,
+ &fs ) ) != 0 ) {
DBGC ( local, "LOCAL %p could not open filesystem on %s: %s\n",
local, efi_handle_name ( device ), strerror ( rc ) );
- goto err_filesystem;
+ return rc;
}
/* Open root directory */
- if ( ( efirc = u.fs->OpenVolume ( u.fs, root ) ) != 0 ) {
+ if ( ( efirc = fs->OpenVolume ( fs, root ) ) != 0 ) {
rc = -EEFI ( efirc );
DBGC ( local, "LOCAL %p could not open volume on %s: %s\n",
local, efi_handle_name ( device ), strerror ( rc ) );
- goto err_volume;
+ return rc;
}
- /* Success */
- rc = 0;
-
- err_volume:
- bs->CloseProtocol ( device, &efi_simple_file_system_protocol_guid,
- efi_image_handle, device );
- err_filesystem:
- return rc;
+ return 0;
}
/**
diff --git a/src/interface/efi/efi_uaccess.c b/src/interface/efi/efi_nap.c
index e058be66b..9d97dae6e 100644
--- a/src/interface/efi/efi_uaccess.c
+++ b/src/interface/efi/efi_nap.c
@@ -22,23 +22,37 @@
*/
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+FILE_SECBOOT ( PERMITTED );
-#include <ipxe/uaccess.h>
+#include <ipxe/nap.h>
#include <ipxe/efi/efi.h>
/** @file
*
- * iPXE user access API for EFI
+ * iPXE CPU sleeping API for EFI
*
*/
-PROVIDE_UACCESS_INLINE ( efi, phys_to_user );
-PROVIDE_UACCESS_INLINE ( efi, user_to_phys );
-PROVIDE_UACCESS_INLINE ( efi, virt_to_user );
-PROVIDE_UACCESS_INLINE ( efi, user_to_virt );
-PROVIDE_UACCESS_INLINE ( efi, userptr_add );
-PROVIDE_UACCESS_INLINE ( efi, memcpy_user );
-PROVIDE_UACCESS_INLINE ( efi, memmove_user );
-PROVIDE_UACCESS_INLINE ( efi, memset_user );
-PROVIDE_UACCESS_INLINE ( efi, strlen_user );
-PROVIDE_UACCESS_INLINE ( efi, memchr_user );
+/**
+ * Sleep until next interrupt
+ *
+ */
+static void efi_cpu_nap ( void ) {
+ /*
+ * I can't find any EFI API that allows us to put the CPU to
+ * sleep. The CpuSleep() function is defined in CpuLib.h, but
+ * isn't part of any exposed protocol so we have no way to
+ * call it.
+ *
+ * The EFI shell doesn't seem to bother sleeping the CPU; it
+ * just sits there idly burning power.
+ *
+ * If a shutdown is in progess, there may be nothing to
+ * generate an interrupt since the timer is disabled in the
+ * first step of ExitBootServices().
+ */
+ if ( ! efi_shutdown_in_progress )
+ cpu_halt();
+}
+
+PROVIDE_NAP ( efi, cpu_nap, efi_cpu_nap );
diff --git a/src/interface/efi/efi_null.c b/src/interface/efi/efi_null.c
index d0f0428cc..fb9ee1780 100644
--- a/src/interface/efi/efi_null.c
+++ b/src/interface/efi/efi_null.c
@@ -22,6 +22,7 @@
*/
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+FILE_SECBOOT ( PERMITTED );
#include <string.h>
#include <ipxe/efi/efi.h>
diff --git a/src/interface/efi/efi_open.c b/src/interface/efi/efi_open.c
new file mode 100644
index 000000000..679d1946e
--- /dev/null
+++ b/src/interface/efi/efi_open.c
@@ -0,0 +1,360 @@
+/*
+ * Copyright (C) 2025 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_SECBOOT ( PERMITTED );
+
+/** @file
+ *
+ * EFI protocol opening and closing
+ *
+ * The UEFI model for opening and closing protocols is broken by
+ * design and cannot be repaired.
+ *
+ * Calling OpenProtocol() to obtain a protocol interface pointer does
+ * not, in general, provide any guarantees about the lifetime of that
+ * pointer. It is theoretically possible that the pointer has already
+ * become invalid by the time that OpenProtocol() returns the pointer
+ * to its caller. (This can happen when a USB device is physically
+ * removed, for example.)
+ *
+ * Various UEFI design flaws make it occasionally necessary to hold on
+ * to a protocol interface pointer despite the total lack of
+ * guarantees that the pointer will remain valid.
+ *
+ * The UEFI driver model overloads the semantics of OpenProtocol() to
+ * accommodate the use cases of recording a driver attachment (which
+ * is modelled as opening a protocol with EFI_OPEN_PROTOCOL_BY_DRIVER
+ * attributes) and recording the existence of a related child
+ * controller (which is modelled as opening a protocol with
+ * EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER attributes).
+ *
+ * The parameters defined for CloseProtocol() are not sufficient to
+ * allow the implementation to precisely identify the matching call to
+ * OpenProtocol(). While the UEFI model appears to allow for matched
+ * open and close pairs, this is merely an illusion. Calling
+ * CloseProtocol() will delete *all* matching records in the protocol
+ * open information tables.
+ *
+ * Since the parameters defined for CloseProtocol() do not include the
+ * attributes passed to OpenProtocol(), this means that a matched
+ * open/close pair using EFI_OPEN_PROTOCOL_GET_PROTOCOL can
+ * inadvertently end up deleting the record that defines a driver
+ * attachment or the existence of a child controller. This in turn
+ * can cause some very unexpected side effects, such as allowing other
+ * UEFI drivers to start controlling hardware to which iPXE believes
+ * it has exclusive access. This rarely ends well.
+ *
+ * To prevent this kind of inadvertent deletion, we establish a
+ * convention for four different types of protocol opening:
+ *
+ * - ephemeral opens: always opened with ControllerHandle = NULL
+ *
+ * - unsafe opens: always opened with ControllerHandle = AgentHandle
+ *
+ * - by-driver opens: always opened with ControllerHandle = Handle
+ *
+ * - by-child opens: always opened with ControllerHandle != Handle
+ *
+ * This convention ensures that the four types of open never overlap
+ * within the set of parameters defined for CloseProtocol(), and so a
+ * close of one type cannot inadvertently delete the record
+ * corresponding to a different type.
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <ipxe/efi/efi.h>
+
+/**
+ * Open (or test) protocol for ephemeral use
+ *
+ * @v handle EFI handle
+ * @v protocol Protocol GUID
+ * @v interface Protocol interface pointer to fill in (or NULL to test)
+ * @ret rc Return status code
+ */
+int efi_open_untyped ( EFI_HANDLE handle, EFI_GUID *protocol,
+ void **interface ) {
+ EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
+ EFI_HANDLE agent = efi_image_handle;
+ EFI_HANDLE controller;
+ unsigned int attributes;
+ EFI_STATUS efirc;
+ int rc;
+
+ /* Sanity checks */
+ assert ( handle != NULL );
+ assert ( protocol != NULL );
+
+ /* Open protocol
+ *
+ * We set ControllerHandle to NULL to avoid collisions with
+ * other open types.
+ */
+ controller = NULL;
+ attributes = ( interface ? EFI_OPEN_PROTOCOL_GET_PROTOCOL :
+ EFI_OPEN_PROTOCOL_TEST_PROTOCOL );
+ if ( ( efirc = bs->OpenProtocol ( handle, protocol, interface, agent,
+ controller, attributes ) ) != 0 ) {
+ rc = -EEFI ( efirc );
+ if ( interface )
+ *interface = NULL;
+ return rc;
+ }
+
+ /* Close protocol immediately
+ *
+ * While it may seem prima facie unsafe to use a protocol
+ * after closing it, UEFI doesn't actually give us any safety
+ * even while the protocol is nominally open. Opening a
+ * protocol with EFI_OPEN_PROTOCOL_GET_PROTOCOL attributes
+ * does not in any way ensure that the interface pointer
+ * remains valid: there are no locks or notifications
+ * associated with these "opens".
+ *
+ * The only way to obtain a (partially) guaranteed persistent
+ * interface pointer is to open the protocol with the
+ * EFI_OPEN_PROTOCOL_BY_DRIVER attributes. This is not
+ * possible in the general case, since UEFI permits only a
+ * single image at a time to have the protocol opened with
+ * these attributes.
+ *
+ * We can therefore obtain at best an ephemeral interface
+ * pointer: one that is guaranteed to remain valid only for as
+ * long as we do not relinquish the thread of control.
+ *
+ * (Since UEFI permits calls to UninstallProtocolInterface()
+ * at levels up to and including TPL_NOTIFY, this means that
+ * we technically cannot rely on the pointer remaining valid
+ * unless the caller is itself running at TPL_NOTIFY. This is
+ * clearly impractical, and large portions of the EDK2
+ * codebase presume that using EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ * is safe at lower TPLs.)
+ *
+ * Closing is not strictly necessary for protocols opened
+ * ephemerally (i.e. using EFI_OPEN_PROTOCOL_GET_PROTOCOL or
+ * EFI_OPEN_PROTOCOL_TEST_PROTOCOL), but avoids polluting the
+ * protocol open information tables with stale data.
+ *
+ * Closing immediately also simplifies the callers' code
+ * paths, since they do not need to worry about closing the
+ * protocol.
+ *
+ * The overall effect is equivalent to using HandleProtocol(),
+ * but without the associated pollution of the protocol open
+ * information tables, and with improved traceability.
+ */
+ bs->CloseProtocol ( handle, protocol, agent, controller );
+
+ return 0;
+}
+
+/**
+ * Open protocol for unsafe persistent use
+ *
+ * @v handle EFI handle
+ * @v protocol Protocol GUID
+ * @v interface Protocol interface pointer to fill in
+ * @ret rc Return status code
+ */
+int efi_open_unsafe_untyped ( EFI_HANDLE handle, EFI_GUID *protocol,
+ void **interface ) {
+ EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
+ EFI_HANDLE agent = efi_image_handle;
+ EFI_HANDLE controller;
+ unsigned int attributes;
+ EFI_STATUS efirc;
+ int rc;
+
+ /* Sanity checks */
+ assert ( handle != NULL );
+ assert ( protocol != NULL );
+ assert ( interface != NULL );
+
+ /* Open protocol
+ *
+ * We set ControllerHandle equal to AgentHandle to avoid
+ * collisions with other open types.
+ */
+ controller = agent;
+ attributes = EFI_OPEN_PROTOCOL_GET_PROTOCOL;
+ if ( ( efirc = bs->OpenProtocol ( handle, protocol, interface, agent,
+ controller, attributes ) ) != 0 ) {
+ rc = -EEFI ( efirc );
+ *interface = NULL;
+ return rc;
+ }
+
+ return 0;
+}
+
+/**
+ * Close protocol opened for unsafe persistent use
+ *
+ * @v handle EFI handle
+ * @v protocol Protocol GUID
+ * @v child Child controller handle
+ */
+void efi_close_unsafe ( EFI_HANDLE handle, EFI_GUID *protocol ) {
+ EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
+ EFI_HANDLE agent = efi_image_handle;
+ EFI_HANDLE controller;
+
+ /* Sanity checks */
+ assert ( handle != NULL );
+ assert ( protocol != NULL );
+
+ /* Close protocol */
+ controller = agent;
+ bs->CloseProtocol ( handle, protocol, agent, controller );
+}
+
+/**
+ * Open protocol for persistent use by a driver
+ *
+ * @v handle EFI handle
+ * @v protocol Protocol GUID
+ * @v interface Protocol interface pointer to fill in
+ * @ret rc Return status code
+ */
+int efi_open_by_driver_untyped ( EFI_HANDLE handle, EFI_GUID *protocol,
+ void **interface ) {
+ EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
+ EFI_HANDLE agent = efi_image_handle;
+ EFI_HANDLE controller;
+ unsigned int attributes;
+ EFI_STATUS efirc;
+ int rc;
+
+ /* Sanity checks */
+ assert ( handle != NULL );
+ assert ( protocol != NULL );
+ assert ( interface != NULL );
+
+ /* Open protocol
+ *
+ * We set ControllerHandle equal to Handle to avoid collisions
+ * with other open types.
+ */
+ controller = handle;
+ attributes = ( EFI_OPEN_PROTOCOL_BY_DRIVER |
+ EFI_OPEN_PROTOCOL_EXCLUSIVE );
+ if ( ( efirc = bs->OpenProtocol ( handle, protocol, interface, agent,
+ controller, attributes ) ) != 0 ) {
+ rc = -EEFI ( efirc );
+ *interface = NULL;
+ return rc;
+ }
+
+ return 0;
+}
+
+/**
+ * Close protocol opened for persistent use by a driver
+ *
+ * @v handle EFI handle
+ * @v protocol Protocol GUID
+ */
+void efi_close_by_driver ( EFI_HANDLE handle, EFI_GUID *protocol ) {
+ EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
+ EFI_HANDLE agent = efi_image_handle;
+ EFI_HANDLE controller;
+
+ /* Sanity checks */
+ assert ( handle != NULL );
+ assert ( protocol != NULL );
+
+ /* Close protocol */
+ controller = handle;
+ bs->CloseProtocol ( handle, protocol, agent, controller );
+}
+
+/**
+ * Open protocol for persistent use by a child controller
+ *
+ * @v handle EFI handle
+ * @v protocol Protocol GUID
+ * @v child Child controller handle
+ * @v interface Protocol interface pointer to fill in
+ * @ret rc Return status code
+ */
+int efi_open_by_child_untyped ( EFI_HANDLE handle, EFI_GUID *protocol,
+ EFI_HANDLE child, void **interface ) {
+ EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
+ EFI_HANDLE agent = efi_image_handle;
+ EFI_HANDLE controller;
+ unsigned int attributes;
+ EFI_STATUS efirc;
+ int rc;
+
+ /* Sanity checks */
+ assert ( handle != NULL );
+ assert ( protocol != NULL );
+ assert ( child != NULL );
+ assert ( interface != NULL );
+
+ /* Open protocol
+ *
+ * We set ControllerHandle to a non-NULL value distinct from
+ * both Handle and AgentHandle to avoid collisions with other
+ * open types.
+ */
+ controller = child;
+ assert ( controller != handle );
+ assert ( controller != agent );
+ attributes = EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER;
+ if ( ( efirc = bs->OpenProtocol ( handle, protocol, interface, agent,
+ controller, attributes ) ) != 0 ) {
+ rc = -EEFI ( efirc );
+ *interface = NULL;
+ return rc;
+ }
+
+ return 0;
+}
+
+/**
+ * Close protocol opened for persistent use by a child controller
+ *
+ * @v handle EFI handle
+ * @v protocol Protocol GUID
+ * @v child Child controller handle
+ */
+void efi_close_by_child ( EFI_HANDLE handle, EFI_GUID *protocol,
+ EFI_HANDLE child ) {
+ EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
+ EFI_HANDLE agent = efi_image_handle;
+ EFI_HANDLE controller;
+
+ /* Sanity checks */
+ assert ( handle != NULL );
+ assert ( protocol != NULL );
+ assert ( child != NULL );
+
+ /* Close protocol */
+ controller = child;
+ assert ( controller != handle );
+ assert ( controller != agent );
+ bs->CloseProtocol ( handle, protocol, agent, controller );
+}
diff --git a/src/interface/efi/efi_path.c b/src/interface/efi/efi_path.c
index ac3c04987..37558c36e 100644
--- a/src/interface/efi/efi_path.c
+++ b/src/interface/efi/efi_path.c
@@ -18,6 +18,7 @@
*/
FILE_LICENCE ( GPL2_OR_LATER );
+FILE_SECBOOT ( PERMITTED );
#include <stdlib.h>
#include <stdarg.h>
@@ -38,6 +39,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
#include <ipxe/dhcp.h>
#include <ipxe/efi/efi.h>
#include <ipxe/efi/efi_driver.h>
+#include <ipxe/efi/efi_strings.h>
#include <ipxe/efi/efi_path.h>
/** @file
@@ -46,6 +48,34 @@ FILE_LICENCE ( GPL2_OR_LATER );
*
*/
+/** Dummy parent device path
+ *
+ * This is used as the parent device path when we need to construct a
+ * path for a device that has no EFI parent device.
+ */
+static struct {
+ BBS_BBS_DEVICE_PATH bbs;
+ CHAR8 tring[4];
+ EFI_DEVICE_PATH_PROTOCOL end;
+} __attribute__ (( packed )) efi_dummy_parent_path = {
+ .bbs = {
+ .Header = {
+ .Type = BBS_DEVICE_PATH,
+ .SubType = BBS_BBS_DP,
+ .Length[0] = ( sizeof ( efi_dummy_parent_path.bbs ) +
+ sizeof ( efi_dummy_parent_path.tring )),
+ },
+ .DeviceType = BBS_TYPE_UNKNOWN,
+ .String[0] = 'i',
+ },
+ .tring = "PXE",
+ .end = {
+ .Type = END_DEVICE_PATH_TYPE,
+ .SubType = END_ENTIRE_DEVICE_PATH_SUBTYPE,
+ .Length[0] = sizeof ( efi_dummy_parent_path.end ),
+ },
+};
+
/** An EFI device path settings block */
struct efi_path_settings {
/** Settings interface */
@@ -148,6 +178,33 @@ size_t efi_path_len ( EFI_DEVICE_PATH_PROTOCOL *path ) {
}
/**
+ * Check that device path is well-formed
+ *
+ * @v path Device path, or NULL
+ * @v max Maximum device path length
+ * @ret rc Return status code
+ */
+int efi_path_check ( EFI_DEVICE_PATH_PROTOCOL *path, size_t max ) {
+ EFI_DEVICE_PATH_PROTOCOL *next;
+ size_t remaining = max;
+ size_t len;
+
+ /* Check that path terminates within maximum length */
+ for ( ; ; path = next ) {
+ if ( remaining < sizeof ( *path ) )
+ return -EINVAL;
+ next = efi_path_next ( path );
+ if ( ! next )
+ break;
+ len = ( ( ( void * ) next ) - ( ( void * ) path ) );
+ if ( remaining < len )
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+/**
* Get MAC address from device path
*
* @v path Device path
@@ -325,6 +382,24 @@ EFI_DEVICE_PATH_PROTOCOL * efi_paths ( EFI_DEVICE_PATH_PROTOCOL *first, ... ) {
}
/**
+ * Construct EFI parent device path
+ *
+ * @v dev Generic device
+ * @ret path Parent (or dummy) device path
+ */
+static EFI_DEVICE_PATH_PROTOCOL * efi_parent_path ( struct device *dev ) {
+ struct efi_device *efidev;
+
+ /* Use EFI parent device's path, if possible */
+ efidev = efidev_parent ( dev );
+ if ( efidev )
+ return efidev->path;
+
+ /* Otherwise, use a dummy parent device path */
+ return &efi_dummy_parent_path.bbs.Header;
+}
+
+/**
* Construct EFI device path for network device
*
* @v netdev Network device
@@ -334,7 +409,7 @@ EFI_DEVICE_PATH_PROTOCOL * efi_paths ( EFI_DEVICE_PATH_PROTOCOL *first, ... ) {
* allocated device path.
*/
EFI_DEVICE_PATH_PROTOCOL * efi_netdev_path ( struct net_device *netdev ) {
- struct efi_device *efidev;
+ EFI_DEVICE_PATH_PROTOCOL *parent;
EFI_DEVICE_PATH_PROTOCOL *path;
MAC_ADDR_DEVICE_PATH *macpath;
VLAN_DEVICE_PATH *vlanpath;
@@ -343,13 +418,11 @@ EFI_DEVICE_PATH_PROTOCOL * efi_netdev_path ( struct net_device *netdev ) {
size_t prefix_len;
size_t len;
- /* Find parent EFI device */
- efidev = efidev_parent ( netdev->dev );
- if ( ! efidev )
- return NULL;
+ /* Get parent EFI device path */
+ parent = efi_parent_path ( netdev->dev );
/* Calculate device path length */
- prefix_len = efi_path_len ( efidev->path );
+ prefix_len = efi_path_len ( parent );
len = ( prefix_len + sizeof ( *macpath ) + sizeof ( *vlanpath ) +
sizeof ( *end ) );
@@ -359,7 +432,7 @@ EFI_DEVICE_PATH_PROTOCOL * efi_netdev_path ( struct net_device *netdev ) {
return NULL;
/* Construct device path */
- memcpy ( path, efidev->path, prefix_len );
+ memcpy ( path, parent, prefix_len );
macpath = ( ( ( void * ) path ) + prefix_len );
macpath->Header.Type = MESSAGING_DEVICE_PATH;
macpath->Header.SubType = MSG_MAC_ADDR_DP;
@@ -573,20 +646,18 @@ EFI_DEVICE_PATH_PROTOCOL * efi_ib_srp_path ( struct ib_srp_device *ib_srp ) {
union ib_srp_target_port_id *id =
container_of ( &sbft->srp.target, union ib_srp_target_port_id,
srp );
- struct efi_device *efidev;
+ EFI_DEVICE_PATH_PROTOCOL *parent;
EFI_DEVICE_PATH_PROTOCOL *path;
INFINIBAND_DEVICE_PATH *ibpath;
EFI_DEVICE_PATH_PROTOCOL *end;
size_t prefix_len;
size_t len;
- /* Find parent EFI device */
- efidev = efidev_parent ( ib_srp->ibdev->dev );
- if ( ! efidev )
- return NULL;
+ /* Get parent EFI device path */
+ parent = efi_parent_path ( ib_srp->ibdev->dev );
/* Calculate device path length */
- prefix_len = efi_path_len ( efidev->path );
+ prefix_len = efi_path_len ( parent );
len = ( prefix_len + sizeof ( *ibpath ) + sizeof ( *end ) );
/* Allocate device path */
@@ -595,7 +666,7 @@ EFI_DEVICE_PATH_PROTOCOL * efi_ib_srp_path ( struct ib_srp_device *ib_srp ) {
return NULL;
/* Construct device path */
- memcpy ( path, efidev->path, prefix_len );
+ memcpy ( path, parent, prefix_len );
ibpath = ( ( ( void * ) path ) + prefix_len );
ibpath->Header.Type = MESSAGING_DEVICE_PATH;
ibpath->Header.SubType = MSG_INFINIBAND_DP;
@@ -625,7 +696,7 @@ EFI_DEVICE_PATH_PROTOCOL * efi_ib_srp_path ( struct ib_srp_device *ib_srp ) {
*/
EFI_DEVICE_PATH_PROTOCOL * efi_usb_path ( struct usb_function *func ) {
struct usb_device *usb = func->usb;
- struct efi_device *efidev;
+ EFI_DEVICE_PATH_PROTOCOL *parent;
EFI_DEVICE_PATH_PROTOCOL *path;
EFI_DEVICE_PATH_PROTOCOL *end;
USB_DEVICE_PATH *usbpath;
@@ -636,14 +707,12 @@ EFI_DEVICE_PATH_PROTOCOL * efi_usb_path ( struct usb_function *func ) {
/* Sanity check */
assert ( func->desc.count >= 1 );
- /* Find parent EFI device */
- efidev = efidev_parent ( &func->dev );
- if ( ! efidev )
- return NULL;
+ /* Get parent EFI device path */
+ parent = efi_parent_path ( &func->dev );
/* Calculate device path length */
count = ( usb_depth ( usb ) + 1 );
- prefix_len = efi_path_len ( efidev->path );
+ prefix_len = efi_path_len ( parent );
len = ( prefix_len + ( count * sizeof ( *usbpath ) ) +
sizeof ( *end ) );
@@ -653,7 +722,7 @@ EFI_DEVICE_PATH_PROTOCOL * efi_usb_path ( struct usb_function *func ) {
return NULL;
/* Construct device path */
- memcpy ( path, efidev->path, prefix_len );
+ memcpy ( path, parent, prefix_len );
end = ( ( ( void * ) path ) + len - sizeof ( *end ) );
efi_path_terminate ( end );
usbpath = ( ( ( void * ) end ) - sizeof ( *usbpath ) );
@@ -669,6 +738,177 @@ EFI_DEVICE_PATH_PROTOCOL * efi_usb_path ( struct usb_function *func ) {
}
/**
+ * Get EFI device path from load option
+ *
+ * @v load EFI load option
+ * @v len Length of EFI load option
+ * @ret path EFI device path, or NULL on error
+ *
+ * The caller is responsible for eventually calling free() on the
+ * allocated device path.
+ */
+EFI_DEVICE_PATH_PROTOCOL * efi_load_path ( EFI_LOAD_OPTION *load,
+ size_t len ) {
+ EFI_DEVICE_PATH_PROTOCOL *path;
+ EFI_DEVICE_PATH_PROTOCOL *copy;
+ CHAR16 *wdesc;
+ size_t path_max;
+ size_t wmax;
+ size_t wlen;
+
+ /* Check basic structure size */
+ if ( len < sizeof ( *load ) ) {
+ DBGC ( load, "EFI load option too short for header:\n" );
+ DBGC_HDA ( load, 0, load, len );
+ return NULL;
+ }
+
+ /* Get length of description */
+ wdesc = ( ( ( void * ) load ) + sizeof ( *load ) );
+ wmax = ( ( len - sizeof ( *load ) ) / sizeof ( wdesc[0] ) );
+ wlen = wcsnlen ( wdesc, wmax );
+ if ( wlen == wmax ) {
+ DBGC ( load, "EFI load option has unterminated "
+ "description:\n" );
+ DBGC_HDA ( load, 0, load, len );
+ return NULL;
+ }
+
+ /* Get inline device path */
+ path = ( ( ( void * ) load ) + sizeof ( *load ) +
+ ( wlen * sizeof ( wdesc[0] ) ) + 2 /* wNUL */ );
+ path_max = ( len - sizeof ( *load ) - ( wlen * sizeof ( wdesc[0] ) )
+ - 2 /* wNUL */ );
+ if ( load->FilePathListLength > path_max ) {
+ DBGC ( load, "EFI load option too short for path(s):\n" );
+ DBGC_HDA ( load, 0, load, len );
+ return NULL;
+ }
+
+ /* Check path length */
+ if ( efi_path_check ( path, path_max ) != 0 ) {
+ DBGC ( load, "EFI load option has unterminated device "
+ "path:\n" );
+ DBGC_HDA ( load, 0, load, len );
+ return NULL;
+ }
+
+ /* Allocate copy of path */
+ copy = malloc ( path_max );
+ if ( ! copy )
+ return NULL;
+ memcpy ( copy, path, path_max );
+
+ return copy;
+}
+
+/**
+ * Get EFI device path for numbered boot option
+ *
+ * @v number Boot option number
+ * @ret path EFI device path, or NULL on error
+ *
+ * The caller is responsible for eventually calling free() on the
+ * allocated device path.
+ */
+EFI_DEVICE_PATH_PROTOCOL * efi_boot_path ( unsigned int number ) {
+ EFI_RUNTIME_SERVICES *rs = efi_systab->RuntimeServices;
+ EFI_GUID *guid = &efi_global_variable;
+ CHAR16 wname[ 9 /* "BootXXXX" + wNUL */ ];
+ EFI_LOAD_OPTION *load;
+ EFI_DEVICE_PATH *path;
+ UINT32 attrs;
+ UINTN size;
+ EFI_STATUS efirc;
+ int rc;
+
+ /* Construct variable name */
+ efi_snprintf ( wname, ( sizeof ( wname ) / sizeof ( wname[0] ) ),
+ "Boot%04X", number );
+
+ /* Get variable length */
+ size = 0;
+ if ( ( efirc = rs->GetVariable ( wname, guid, &attrs, &size,
+ NULL ) != EFI_BUFFER_TOO_SMALL ) ) {
+ rc = -EEFI ( efirc );
+ DBGC ( rs, "EFI could not get size of %ls: %s\n",
+ wname, strerror ( rc ) );
+ goto err_size;
+ }
+
+ /* Allocate temporary buffer for EFI_LOAD_OPTION */
+ load = malloc ( size );
+ if ( ! load ) {
+ rc = -ENOMEM;
+ goto err_alloc;
+ }
+
+ /* Read variable */
+ if ( ( efirc = rs->GetVariable ( wname, guid, &attrs, &size,
+ load ) != 0 ) ) {
+ rc = -EEFI ( efirc );
+ DBGC ( rs, "EFI could not read %ls: %s\n",
+ wname, strerror ( rc ) );
+ goto err_read;
+ }
+ DBGC2 ( rs, "EFI boot option %ls is:\n", wname );
+ DBGC2_HDA ( rs, 0, load, size );
+
+ /* Get device path from load option */
+ path = efi_load_path ( load, size );
+ if ( ! path ) {
+ rc = -EINVAL;
+ DBGC ( rs, "EFI could not parse %ls: %s\n",
+ wname, strerror ( rc ) );
+ goto err_path;
+ }
+
+ /* Free temporary buffer */
+ free ( load );
+
+ return path;
+
+ err_path:
+ err_read:
+ free ( load );
+ err_alloc:
+ err_size:
+ return NULL;
+}
+
+/**
+ * Get EFI device path for current boot option
+ *
+ * @ret path EFI device path, or NULL on error
+ *
+ * The caller is responsible for eventually calling free() on the
+ * allocated device path.
+ */
+EFI_DEVICE_PATH_PROTOCOL * efi_current_boot_path ( void ) {
+ EFI_RUNTIME_SERVICES *rs = efi_systab->RuntimeServices;
+ EFI_GUID *guid = &efi_global_variable;
+ CHAR16 wname[] = L"BootCurrent";
+ UINT16 current;
+ UINT32 attrs;
+ UINTN size;
+ EFI_STATUS efirc;
+ int rc;
+
+ /* Read current boot option index */
+ size = sizeof ( current );
+ if ( ( efirc = rs->GetVariable ( wname, guid, &attrs, &size,
+ &current ) != 0 ) ) {
+ rc = -EEFI ( efirc );
+ DBGC ( rs, "EFI could not read %ls: %s\n",
+ wname, strerror ( rc ) );
+ return NULL;
+ }
+
+ /* Get device path from this boot option */
+ return efi_boot_path ( current );
+}
+
+/**
* Describe object as an EFI device path
*
* @v intf Interface
diff --git a/src/interface/efi/efi_pci.c b/src/interface/efi/efi_pci.c
index e2eeeb344..4bf3977c5 100644
--- a/src/interface/efi/efi_pci.c
+++ b/src/interface/efi/efi_pci.c
@@ -22,8 +22,10 @@
*/
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+FILE_SECBOOT ( PERMITTED );
#include <stdlib.h>
+#include <string.h>
#include <errno.h>
#include <ipxe/pci.h>
#include <ipxe/acpi.h>
@@ -63,33 +65,43 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
*/
/**
- * Check for a matching PCI root bridge I/O protocol
+ * Find closest bus:dev.fn address range within a root bridge
*
- * @v pci PCI device
+ * @v pci Starting PCI device
* @v handle EFI PCI root bridge handle
- * @v root EFI PCI root bridge I/O protocol
+ * @v range PCI bus:dev.fn address range to fill in
* @ret rc Return status code
*/
-static int efipci_root_match ( struct pci_device *pci, EFI_HANDLE handle,
- EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *root ) {
+static int efipci_discover_one ( struct pci_device *pci, EFI_HANDLE handle,
+ struct pci_range *range ) {
+ EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *root;
union {
union acpi_resource *res;
void *raw;
- } u;
- unsigned int segment = PCI_SEG ( pci->busdevfn );
- unsigned int bus = PCI_BUS ( pci->busdevfn );
- unsigned int start;
- unsigned int end;
+ } acpi;
+ uint32_t best = 0;
+ uint32_t start;
+ uint32_t count;
+ uint32_t index;
unsigned int tag;
EFI_STATUS efirc;
int rc;
- /* Check segment number */
- if ( root->SegmentNumber != segment )
- return -ENOENT;
+ /* Return empty range on error */
+ range->start = 0;
+ range->count = 0;
+
+ /* Open root bridge I/O protocol */
+ if ( ( rc = efi_open ( handle, &efi_pci_root_bridge_io_protocol_guid,
+ &root ) ) != 0 ) {
+ DBGC ( pci, "EFIPCI " PCI_FMT " cannot open %s: %s\n",
+ PCI_ARGS ( pci ), efi_handle_name ( handle ),
+ strerror ( rc ) );
+ return rc;
+ }
/* Get ACPI resource descriptors */
- if ( ( efirc = root->Configuration ( root, &u.raw ) ) != 0 ) {
+ if ( ( efirc = root->Configuration ( root, &acpi.raw ) ) != 0 ) {
rc = -EEFI ( efirc );
DBGC ( pci, "EFIPCI " PCI_FMT " cannot get configuration for "
"%s: %s\n", PCI_ARGS ( pci ),
@@ -97,57 +109,79 @@ static int efipci_root_match ( struct pci_device *pci, EFI_HANDLE handle,
return rc;
}
- /* Assume success if no bus number range descriptors are found */
- rc = 0;
-
/* Parse resource descriptors */
- for ( ; ( ( tag = acpi_resource_tag ( u.res ) ) != ACPI_END_RESOURCE ) ;
- u.res = acpi_resource_next ( u.res ) ) {
+ for ( ; ( ( tag = acpi_resource_tag ( acpi.res ) ) !=
+ ACPI_END_RESOURCE ) ;
+ acpi.res = acpi_resource_next ( acpi.res ) ) {
/* Ignore anything other than a bus number range descriptor */
if ( tag != ACPI_QWORD_ADDRESS_SPACE_RESOURCE )
continue;
- if ( u.res->qword.type != ACPI_ADDRESS_TYPE_BUS )
+ if ( acpi.res->qword.type != ACPI_ADDRESS_TYPE_BUS )
continue;
- /* Check for a matching bus number */
- start = le64_to_cpu ( u.res->qword.min );
- end = ( start + le64_to_cpu ( u.res->qword.len ) );
- if ( ( bus >= start ) && ( bus < end ) )
- return 0;
+ /* Get range for this descriptor */
+ start = PCI_BUSDEVFN ( root->SegmentNumber,
+ le64_to_cpu ( acpi.res->qword.min ),
+ 0, 0 );
+ count = PCI_BUSDEVFN ( 0, le64_to_cpu ( acpi.res->qword.len ),
+ 0, 0 );
+ DBGC2 ( pci, "EFIPCI " PCI_FMT " found %04x:[%02x-%02x] via "
+ "%s\n", PCI_ARGS ( pci ), root->SegmentNumber,
+ PCI_BUS ( start ), PCI_BUS ( start + count - 1 ),
+ efi_handle_name ( handle ) );
+
+ /* Check for a matching or new closest range */
+ index = ( pci->busdevfn - start );
+ if ( ( index < count ) || ( index > best ) ) {
+ range->start = start;
+ range->count = count;
+ best = index;
+ }
- /* We have seen at least one non-matching range
- * descriptor, so assume failure unless we find a
- * subsequent match.
- */
- rc = -ENOENT;
+ /* Stop if this range contains the target bus:dev.fn address */
+ if ( index < count )
+ break;
}
- return rc;
+ /* If no range descriptors were seen, assume that the root
+ * bridge has a single bus.
+ */
+ if ( ! range->count ) {
+ range->start = PCI_BUSDEVFN ( root->SegmentNumber, 0, 0, 0 );
+ range->count = PCI_BUSDEVFN ( 0, 1, 0, 0 );
+ }
+
+ return 0;
}
/**
- * Open EFI PCI root bridge I/O protocol
+ * Find closest bus:dev.fn address range within any root bridge
*
- * @v pci PCI device
- * @ret handle EFI PCI root bridge handle
- * @ret root EFI PCI root bridge I/O protocol, or NULL if not found
+ * @v pci Starting PCI device
+ * @v range PCI bus:dev.fn address range to fill in
+ * @v handle PCI root bridge I/O handle to fill in
* @ret rc Return status code
*/
-static int efipci_root_open ( struct pci_device *pci, EFI_HANDLE *handle,
- EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL **root ) {
+static int efipci_discover_any ( struct pci_device *pci,
+ struct pci_range *range,
+ EFI_HANDLE *handle ) {
EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
+ uint32_t best = 0;
+ uint32_t index;
+ struct pci_range tmp;
EFI_HANDLE *handles;
UINTN num_handles;
- union {
- void *interface;
- EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *root;
- } u;
- EFI_STATUS efirc;
UINTN i;
+ EFI_STATUS efirc;
int rc;
- /* Enumerate all handles */
+ /* Return an empty range and no handle on error */
+ range->start = 0;
+ range->count = 0;
+ *handle = NULL;
+
+ /* Enumerate all root bridge I/O protocol handles */
if ( ( efirc = bs->LocateHandleBuffer ( ByProtocol,
&efi_pci_root_bridge_io_protocol_guid,
NULL, &num_handles, &handles ) ) != 0 ) {
@@ -157,48 +191,87 @@ static int efipci_root_open ( struct pci_device *pci, EFI_HANDLE *handle,
goto err_locate;
}
- /* Look for matching root bridge I/O protocol */
+ /* Iterate over all root bridge I/O protocols */
for ( i = 0 ; i < num_handles ; i++ ) {
- *handle = handles[i];
- if ( ( efirc = bs->OpenProtocol ( *handle,
- &efi_pci_root_bridge_io_protocol_guid,
- &u.interface, efi_image_handle, *handle,
- EFI_OPEN_PROTOCOL_GET_PROTOCOL ) ) != 0 ) {
- rc = -EEFI ( efirc );
- DBGC ( pci, "EFIPCI " PCI_FMT " cannot open %s: %s\n",
- PCI_ARGS ( pci ), efi_handle_name ( *handle ),
- strerror ( rc ) );
+
+ /* Get matching or closest range for this root bridge */
+ if ( ( rc = efipci_discover_one ( pci, handles[i],
+ &tmp ) ) != 0 )
continue;
+
+ /* Check for a matching or new closest range */
+ index = ( pci->busdevfn - tmp.start );
+ if ( ( index < tmp.count ) || ( index > best ) ) {
+ range->start = tmp.start;
+ range->count = tmp.count;
+ best = index;
}
- if ( efipci_root_match ( pci, *handle, u.root ) == 0 ) {
- *root = u.root;
- bs->FreePool ( handles );
- return 0;
+
+ /* Stop if this range contains the target bus:dev.fn address */
+ if ( index < tmp.count ) {
+ *handle = handles[i];
+ break;
}
- bs->CloseProtocol ( *handle,
- &efi_pci_root_bridge_io_protocol_guid,
- efi_image_handle, *handle );
}
- DBGC ( pci, "EFIPCI " PCI_FMT " found no root bridge\n",
- PCI_ARGS ( pci ) );
- rc = -ENOENT;
+ /* Check for a range containing the target bus:dev.fn address */
+ if ( ! *handle ) {
+ rc = -ENOENT;
+ goto err_range;
+ }
+
+ /* Success */
+ rc = 0;
+
+ err_range:
bs->FreePool ( handles );
err_locate:
return rc;
}
/**
- * Close EFI PCI root bridge I/O protocol
+ * Find next PCI bus:dev.fn address range in system
*
- * @v handle EFI PCI root bridge handle
+ * @v busdevfn Starting PCI bus:dev.fn address
+ * @v range PCI bus:dev.fn address range to fill in
*/
-static void efipci_root_close ( EFI_HANDLE handle ) {
- EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
+static void efipci_discover ( uint32_t busdevfn, struct pci_range *range ) {
+ struct pci_device pci;
+ EFI_HANDLE handle;
+
+ /* Find range */
+ memset ( &pci, 0, sizeof ( pci ) );
+ pci_init ( &pci, busdevfn );
+ efipci_discover_any ( &pci, range, &handle );
+}
+
+/**
+ * Open EFI PCI root bridge I/O protocol for ephemeral use
+ *
+ * @v pci PCI device
+ * @ret handle EFI PCI root bridge handle
+ * @ret root EFI PCI root bridge I/O protocol, or NULL if not found
+ * @ret rc Return status code
+ */
+static int efipci_root_open ( struct pci_device *pci, EFI_HANDLE *handle,
+ EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL **root ) {
+ struct pci_range tmp;
+ int rc;
+
+ /* Find matching root bridge I/O protocol handle */
+ if ( ( rc = efipci_discover_any ( pci, &tmp, handle ) ) != 0 )
+ return rc;
- /* Close protocol */
- bs->CloseProtocol ( handle, &efi_pci_root_bridge_io_protocol_guid,
- efi_image_handle, handle );
+ /* Open PCI root bridge I/O protocol */
+ if ( ( rc = efi_open ( *handle, &efi_pci_root_bridge_io_protocol_guid,
+ root ) ) != 0 ) {
+ DBGC ( pci, "EFIPCI " PCI_FMT " cannot open %s: %s\n",
+ PCI_ARGS ( pci ), efi_handle_name ( *handle ),
+ strerror ( rc ) );
+ return rc;
+ }
+
+ return 0;
}
/**
@@ -234,7 +307,7 @@ int efipci_read ( struct pci_device *pci, unsigned long location,
/* Open root bridge */
if ( ( rc = efipci_root_open ( pci, &handle, &root ) ) != 0 )
- goto err_root;
+ return rc;
/* Read from configuration space */
if ( ( efirc = root->Pci.Read ( root, EFIPCI_WIDTH ( location ),
@@ -244,13 +317,10 @@ int efipci_read ( struct pci_device *pci, unsigned long location,
DBGC ( pci, "EFIPCI " PCI_FMT " config read from offset %02lx "
"failed: %s\n", PCI_ARGS ( pci ),
EFIPCI_OFFSET ( location ), strerror ( rc ) );
- goto err_read;
+ return rc;
}
- err_read:
- efipci_root_close ( handle );
- err_root:
- return rc;
+ return 0;
}
/**
@@ -270,7 +340,7 @@ int efipci_write ( struct pci_device *pci, unsigned long location,
/* Open root bridge */
if ( ( rc = efipci_root_open ( pci, &handle, &root ) ) != 0 )
- goto err_root;
+ return rc;
/* Read from configuration space */
if ( ( efirc = root->Pci.Write ( root, EFIPCI_WIDTH ( location ),
@@ -280,13 +350,10 @@ int efipci_write ( struct pci_device *pci, unsigned long location,
DBGC ( pci, "EFIPCI " PCI_FMT " config write to offset %02lx "
"failed: %s\n", PCI_ARGS ( pci ),
EFIPCI_OFFSET ( location ), strerror ( rc ) );
- goto err_write;
+ return rc;
}
- err_write:
- efipci_root_close ( handle );
- err_root:
- return rc;
+ return 0;
}
/**
@@ -357,12 +424,12 @@ void * efipci_ioremap ( struct pci_device *pci, unsigned long bus_addr,
}
err_config:
- efipci_root_close ( handle );
err_root:
return ioremap ( bus_addr, len );
}
-PROVIDE_PCIAPI_INLINE ( efi, pci_discover );
+PROVIDE_PCIAPI_INLINE ( efi, pci_can_probe );
+PROVIDE_PCIAPI ( efi, pci_discover, efipci_discover );
PROVIDE_PCIAPI_INLINE ( efi, pci_read_config_byte );
PROVIDE_PCIAPI_INLINE ( efi, pci_read_config_word );
PROVIDE_PCIAPI_INLINE ( efi, pci_read_config_dword );
@@ -370,6 +437,7 @@ PROVIDE_PCIAPI_INLINE ( efi, pci_write_config_byte );
PROVIDE_PCIAPI_INLINE ( efi, pci_write_config_word );
PROVIDE_PCIAPI_INLINE ( efi, pci_write_config_dword );
PROVIDE_PCIAPI ( efi, pci_ioremap, efipci_ioremap );
+PROVIDE_PCIAPI_RUNTIME ( efi, PCIAPI_PRIORITY_EFI );
/******************************************************************************
*
@@ -389,7 +457,7 @@ PROVIDE_PCIAPI ( efi, pci_ioremap, efipci_ioremap );
* @ret rc Return status code
*/
static int efipci_dma_map ( struct dma_device *dma, struct dma_mapping *map,
- physaddr_t addr, size_t len, int flags ) {
+ void *addr, size_t len, int flags ) {
struct efi_pci_device *efipci =
container_of ( dma, struct efi_pci_device, pci.dma );
struct pci_device *pci = &efipci->pci;
@@ -398,6 +466,7 @@ static int efipci_dma_map ( struct dma_device *dma, struct dma_mapping *map,
EFI_PHYSICAL_ADDRESS bus;
UINTN count;
VOID *mapping;
+ physaddr_t phys;
EFI_STATUS efirc;
int rc;
@@ -420,18 +489,19 @@ static int efipci_dma_map ( struct dma_device *dma, struct dma_mapping *map,
}
/* Map buffer (if non-zero length) */
+ phys = virt_to_phys ( addr );
count = len;
if ( len ) {
- if ( ( efirc = pci_io->Map ( pci_io, op, phys_to_virt ( addr ),
- &count, &bus, &mapping ) ) != 0 ) {
+ if ( ( efirc = pci_io->Map ( pci_io, op, addr, &count, &bus,
+ &mapping ) ) != 0 ) {
rc = -EEFI ( efirc );
- DBGC ( pci, "EFIPCI " PCI_FMT " cannot map %08lx+%zx: "
+ DBGC ( pci, "EFIPCI " PCI_FMT " cannot map %p+%zx: "
"%s\n", PCI_ARGS ( pci ), addr, len,
strerror ( rc ) );
goto err_map;
}
} else {
- bus = addr;
+ bus = phys;
mapping = NULL;
}
@@ -442,14 +512,14 @@ static int efipci_dma_map ( struct dma_device *dma, struct dma_mapping *map,
*/
if ( count != len ) {
DBGC ( pci, "EFIPCI " PCI_FMT " attempted split mapping for "
- "%08lx+%zx\n", PCI_ARGS ( pci ), addr, len );
+ "%p+%zx\n", PCI_ARGS ( pci ), addr, len );
rc = -ENOTSUP;
goto err_len;
}
/* Populate mapping */
map->dma = dma;
- map->offset = ( bus - addr );
+ map->offset = ( bus - phys );
map->token = mapping;
/* Increment mapping count (for debugging) */
@@ -469,9 +539,10 @@ static int efipci_dma_map ( struct dma_device *dma, struct dma_mapping *map,
*
* @v dma DMA device
* @v map DMA mapping
+ * @v len Used length
*/
static void efipci_dma_unmap ( struct dma_device *dma,
- struct dma_mapping *map ) {
+ struct dma_mapping *map, size_t len __unused ) {
struct efi_pci_device *efipci =
container_of ( dma, struct efi_pci_device, pci.dma );
EFI_PCI_IO_PROTOCOL *pci_io = efipci->io;
@@ -528,8 +599,7 @@ static void * efipci_dma_alloc ( struct dma_device *dma,
memset ( addr, 0, ( pages * EFI_PAGE_SIZE ) );
/* Map buffer */
- if ( ( rc = efipci_dma_map ( dma, map, virt_to_phys ( addr ),
- ( pages * EFI_PAGE_SIZE ),
+ if ( ( rc = efipci_dma_map ( dma, map, addr, ( pages * EFI_PAGE_SIZE ),
DMA_BI ) ) != 0 )
goto err_map;
@@ -539,7 +609,7 @@ static void * efipci_dma_alloc ( struct dma_device *dma,
return addr;
- efipci_dma_unmap ( dma, map );
+ efipci_dma_unmap ( dma, map, len );
err_map:
pci_io->FreeBuffer ( pci_io, pages, addr );
err_alloc:
@@ -565,7 +635,7 @@ static void efipci_dma_free ( struct dma_device *dma, struct dma_mapping *map,
pages = ( ( len + EFI_PAGE_SIZE - 1 ) / EFI_PAGE_SIZE );
/* Unmap buffer */
- efipci_dma_unmap ( dma, map );
+ efipci_dma_unmap ( dma, map, len );
/* Free buffer */
pci_io->FreeBuffer ( pci_io, pages, addr );
@@ -576,38 +646,6 @@ static void efipci_dma_free ( struct dma_device *dma, struct dma_mapping *map,
}
/**
- * Allocate and map DMA-coherent buffer from external (user) memory
- *
- * @v dma DMA device
- * @v map DMA mapping to fill in
- * @v len Length of buffer
- * @v align Physical alignment
- * @ret addr Buffer address, or NULL on error
- */
-static userptr_t efipci_dma_umalloc ( struct dma_device *dma,
- struct dma_mapping *map,
- size_t len, size_t align ) {
- void *addr;
-
- addr = efipci_dma_alloc ( dma, map, len, align );
- return virt_to_user ( addr );
-}
-
-/**
- * Unmap and free DMA-coherent buffer from external (user) memory
- *
- * @v dma DMA device
- * @v map DMA mapping
- * @v addr Buffer address
- * @v len Length of buffer
- */
-static void efipci_dma_ufree ( struct dma_device *dma, struct dma_mapping *map,
- userptr_t addr, size_t len ) {
-
- efipci_dma_free ( dma, map, user_to_virt ( addr, 0 ), len );
-}
-
-/**
* Set addressable space mask
*
* @v dma DMA device
@@ -645,8 +683,8 @@ static struct dma_operations efipci_dma_operations = {
.unmap = efipci_dma_unmap,
.alloc = efipci_dma_alloc,
.free = efipci_dma_free,
- .umalloc = efipci_dma_umalloc,
- .ufree = efipci_dma_ufree,
+ .umalloc = efipci_dma_alloc,
+ .ufree = efipci_dma_free,
.set_mask = efipci_dma_set_mask,
};
@@ -658,44 +696,35 @@ static struct dma_operations efipci_dma_operations = {
*/
/**
- * Open EFI PCI device
+ * Get EFI PCI device information
*
* @v device EFI device handle
- * @v attributes Protocol opening attributes
* @v efipci EFI PCI device to fill in
* @ret rc Return status code
*/
-int efipci_open ( EFI_HANDLE device, UINT32 attributes,
- struct efi_pci_device *efipci ) {
- EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
- union {
- EFI_PCI_IO_PROTOCOL *pci_io;
- void *interface;
- } pci_io;
+int efipci_info ( EFI_HANDLE device, struct efi_pci_device *efipci ) {
+ EFI_PCI_IO_PROTOCOL *pci_io;
UINTN pci_segment, pci_bus, pci_dev, pci_fn;
unsigned int busdevfn;
EFI_STATUS efirc;
int rc;
/* See if device is a PCI device */
- if ( ( efirc = bs->OpenProtocol ( device, &efi_pci_io_protocol_guid,
- &pci_io.interface, efi_image_handle,
- device, attributes ) ) != 0 ) {
- rc = -EEFI_PCI ( efirc );
+ if ( ( rc = efi_open ( device, &efi_pci_io_protocol_guid,
+ &pci_io ) ) != 0 ) {
DBGCP ( device, "EFIPCI %s cannot open PCI protocols: %s\n",
efi_handle_name ( device ), strerror ( rc ) );
- goto err_open_protocol;
+ return rc;
}
- efipci->io = pci_io.pci_io;
+ efipci->io = pci_io;
/* Get PCI bus:dev.fn address */
- if ( ( efirc = pci_io.pci_io->GetLocation ( pci_io.pci_io, &pci_segment,
- &pci_bus, &pci_dev,
- &pci_fn ) ) != 0 ) {
+ if ( ( efirc = pci_io->GetLocation ( pci_io, &pci_segment, &pci_bus,
+ &pci_dev, &pci_fn ) ) != 0 ) {
rc = -EEFI ( efirc );
DBGC ( device, "EFIPCI %s could not get PCI location: %s\n",
efi_handle_name ( device ), strerror ( rc ) );
- goto err_get_location;
+ return rc;
}
busdevfn = PCI_BUSDEVFN ( pci_segment, pci_bus, pci_dev, pci_fn );
pci_init ( &efipci->pci, busdevfn );
@@ -709,63 +738,20 @@ int efipci_open ( EFI_HANDLE device, UINT32 attributes,
* support I/O cycles). Work around any such platforms by
* enabling bits individually and simply ignoring any errors.
*/
- pci_io.pci_io->Attributes ( pci_io.pci_io,
- EfiPciIoAttributeOperationEnable,
- EFI_PCI_IO_ATTRIBUTE_IO, NULL );
- pci_io.pci_io->Attributes ( pci_io.pci_io,
- EfiPciIoAttributeOperationEnable,
- EFI_PCI_IO_ATTRIBUTE_MEMORY, NULL );
- pci_io.pci_io->Attributes ( pci_io.pci_io,
- EfiPciIoAttributeOperationEnable,
- EFI_PCI_IO_ATTRIBUTE_BUS_MASTER, NULL );
+ pci_io->Attributes ( pci_io, EfiPciIoAttributeOperationEnable,
+ EFI_PCI_IO_ATTRIBUTE_IO, NULL );
+ pci_io->Attributes ( pci_io, EfiPciIoAttributeOperationEnable,
+ EFI_PCI_IO_ATTRIBUTE_MEMORY, NULL );
+ pci_io->Attributes ( pci_io, EfiPciIoAttributeOperationEnable,
+ EFI_PCI_IO_ATTRIBUTE_BUS_MASTER, NULL );
/* Populate PCI device */
if ( ( rc = pci_read_config ( &efipci->pci ) ) != 0 ) {
DBGC ( device, "EFIPCI " PCI_FMT " cannot read PCI "
"configuration: %s\n",
PCI_ARGS ( &efipci->pci ), strerror ( rc ) );
- goto err_pci_read_config;
- }
-
- return 0;
-
- err_pci_read_config:
- err_get_location:
- bs->CloseProtocol ( device, &efi_pci_io_protocol_guid,
- efi_image_handle, device );
- err_open_protocol:
- return rc;
-}
-
-/**
- * Close EFI PCI device
- *
- * @v device EFI device handle
- */
-void efipci_close ( EFI_HANDLE device ) {
- EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
-
- bs->CloseProtocol ( device, &efi_pci_io_protocol_guid,
- efi_image_handle, device );
-}
-
-/**
- * Get EFI PCI device information
- *
- * @v device EFI device handle
- * @v efipci EFI PCI device to fill in
- * @ret rc Return status code
- */
-int efipci_info ( EFI_HANDLE device, struct efi_pci_device *efipci ) {
- int rc;
-
- /* Open PCI device, if possible */
- if ( ( rc = efipci_open ( device, EFI_OPEN_PROTOCOL_GET_PROTOCOL,
- efipci ) ) != 0 )
return rc;
-
- /* Close PCI device */
- efipci_close ( device );
+ }
return 0;
}
@@ -817,6 +803,26 @@ static int efipci_supported ( EFI_HANDLE device ) {
}
/**
+ * Exclude existing drivers
+ *
+ * @v device EFI device handle
+ * @ret rc Return status code
+ */
+static int efipci_exclude ( EFI_HANDLE device ) {
+ EFI_GUID *protocol = &efi_pci_io_protocol_guid;
+ int rc;
+
+ /* Exclude existing PCI I/O protocol drivers */
+ if ( ( rc = efi_driver_exclude ( device, protocol ) ) != 0 ) {
+ DBGC ( device, "EFIPCI %s could not exclude drivers: %s\n",
+ efi_handle_name ( device ), strerror ( rc ) );
+ return rc;
+ }
+
+ return 0;
+}
+
+/**
* Attach driver to device
*
* @v efidev EFI device
@@ -834,10 +840,13 @@ static int efipci_start ( struct efi_device *efidev ) {
goto err_alloc;
}
- /* Open PCI device */
- if ( ( rc = efipci_open ( device, ( EFI_OPEN_PROTOCOL_BY_DRIVER |
- EFI_OPEN_PROTOCOL_EXCLUSIVE ),
- efipci ) ) != 0 ) {
+ /* Get PCI device information */
+ if ( ( rc = efipci_info ( device, efipci ) ) != 0 )
+ goto err_info;
+
+ /* Open PCI I/O protocol */
+ if ( ( rc = efi_open_by_driver ( device, &efi_pci_io_protocol_guid,
+ &efipci->io ) ) != 0 ) {
DBGC ( device, "EFIPCI %s could not open PCI device: %s\n",
efi_handle_name ( device ), strerror ( rc ) );
DBGC_EFI_OPENERS ( device, device, &efi_pci_io_protocol_guid );
@@ -872,8 +881,9 @@ static int efipci_start ( struct efi_device *efidev ) {
err_probe:
list_del ( &efipci->pci.dev.siblings );
err_find_driver:
- efipci_close ( device );
+ efi_close_by_driver ( device, &efi_pci_io_protocol_guid );
err_open:
+ err_info:
free ( efipci );
err_alloc:
return rc;
@@ -892,14 +902,15 @@ static void efipci_stop ( struct efi_device *efidev ) {
list_del ( &efipci->pci.dev.siblings );
assert ( efipci->pci.dma.mapped == 0 );
assert ( efipci->pci.dma.allocated == 0 );
- efipci_close ( device );
+ efi_close_by_driver ( device, &efi_pci_io_protocol_guid );
free ( efipci );
}
/** EFI PCI driver */
-struct efi_driver efipci_driver __efi_driver ( EFI_DRIVER_NORMAL ) = {
+struct efi_driver efipci_driver __efi_driver ( EFI_DRIVER_HARDWARE ) = {
.name = "PCI",
.supported = efipci_supported,
+ .exclude = efipci_exclude,
.start = efipci_start,
.stop = efipci_stop,
};
diff --git a/src/interface/efi/efi_pxe.c b/src/interface/efi/efi_pxe.c
index 843ebb5e7..2d1a6fd73 100644
--- a/src/interface/efi/efi_pxe.c
+++ b/src/interface/efi/efi_pxe.c
@@ -22,6 +22,7 @@
*/
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+FILE_SECBOOT ( PERMITTED );
#include <string.h>
#include <errno.h>
@@ -305,48 +306,6 @@ static int efi_pxe_ip_filter ( struct efi_pxe *pxe, EFI_IP_ADDRESS *ip ) {
/******************************************************************************
*
- * Data transfer buffer
- *
- ******************************************************************************
- */
-
-/**
- * Reallocate PXE data transfer buffer
- *
- * @v xferbuf Data transfer buffer
- * @v len New length (or zero to free buffer)
- * @ret rc Return status code
- */
-static int efi_pxe_buf_realloc ( struct xfer_buffer *xferbuf __unused,
- size_t len __unused ) {
-
- /* Can never reallocate: return EFI_BUFFER_TOO_SMALL */
- return -ERANGE;
-}
-
-/**
- * Write data to PXE data transfer buffer
- *
- * @v xferbuf Data transfer buffer
- * @v offset Starting offset
- * @v data Data to copy
- * @v len Length of data
- */
-static void efi_pxe_buf_write ( struct xfer_buffer *xferbuf, size_t offset,
- const void *data, size_t len ) {
-
- /* Copy data to buffer */
- memcpy ( ( xferbuf->data + offset ), data, len );
-}
-
-/** PXE data transfer buffer operations */
-static struct xfer_buffer_operations efi_pxe_buf_operations = {
- .realloc = efi_pxe_buf_realloc,
- .write = efi_pxe_buf_write,
-};
-
-/******************************************************************************
- *
* (M)TFTP download interface
*
******************************************************************************
@@ -966,8 +925,7 @@ efi_pxe_mtftp ( EFI_PXE_BASE_CODE_PROTOCOL *base,
pxe->blksize = ( ( callback && blksize ) ? *blksize : -1UL );
/* Initialise data transfer buffer */
- pxe->buf.data = data;
- pxe->buf.len = *len;
+ xferbuf_fixed_init ( &pxe->buf, data, *len );
/* Open download */
if ( ( rc = efi_pxe_tftp_open ( pxe, ip,
@@ -987,6 +945,7 @@ efi_pxe_mtftp ( EFI_PXE_BASE_CODE_PROTOCOL *base,
err_download:
efi_pxe_tftp_close ( pxe, rc );
err_open:
+ xferbuf_fixed_init ( &pxe->buf, NULL, 0 );
efi_snp_release();
err_opcode:
return EFIRC ( rc );
@@ -1611,7 +1570,6 @@ int efi_pxe_install ( EFI_HANDLE handle, struct net_device *netdev ) {
pxe->base.Mode = &pxe->mode;
memcpy ( &pxe->apple, &efi_apple_net_boot_protocol,
sizeof ( pxe->apple ) );
- pxe->buf.op = &efi_pxe_buf_operations;
intf_init ( &pxe->tftp, &efi_pxe_tftp_desc, &pxe->refcnt );
intf_init ( &pxe->udp, &efi_pxe_udp_desc, &pxe->refcnt );
INIT_LIST_HEAD ( &pxe->queue );
@@ -1679,7 +1637,7 @@ void efi_pxe_uninstall ( EFI_HANDLE handle ) {
/* Locate PXE base code */
pxe = efi_pxe_find ( handle );
- if ( ! handle ) {
+ if ( ! pxe ) {
DBG ( "PXE could not find base code for %s\n",
efi_handle_name ( handle ) );
return;
diff --git a/src/interface/efi/efi_reboot.c b/src/interface/efi/efi_reboot.c
index 35919221e..cc35ef7ad 100644
--- a/src/interface/efi/efi_reboot.c
+++ b/src/interface/efi/efi_reboot.c
@@ -22,6 +22,7 @@
*/
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+FILE_SECBOOT ( PERMITTED );
/**
* @file
@@ -31,19 +32,44 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
*/
#include <errno.h>
+#include <string.h>
#include <ipxe/efi/efi.h>
+#include <ipxe/efi/Guid/GlobalVariable.h>
#include <ipxe/reboot.h>
/**
* Reboot system
*
- * @v warm Perform a warm reboot
+ * @v flags Reboot flags
*/
-static void efi_reboot ( int warm ) {
+static void efi_reboot ( int flags ) {
EFI_RUNTIME_SERVICES *rs = efi_systab->RuntimeServices;
+ static CHAR16 wname[] = EFI_OS_INDICATIONS_VARIABLE_NAME;
+ UINT64 osind;
+ UINT32 attrs;
+ EFI_RESET_TYPE type;
+ EFI_STATUS efirc;
+ int rc;
+
+ /* Request boot to firmware setup, if applicable */
+ if ( flags & REBOOT_SETUP ) {
+ osind = EFI_OS_INDICATIONS_BOOT_TO_FW_UI;
+ attrs = ( EFI_VARIABLE_BOOTSERVICE_ACCESS |
+ EFI_VARIABLE_RUNTIME_ACCESS |
+ EFI_VARIABLE_NON_VOLATILE );
+ if ( ( efirc = rs->SetVariable ( wname, &efi_global_variable,
+ attrs, sizeof ( osind ),
+ &osind ) ) != 0 ) {
+ rc = -EEFI ( efirc );
+ DBGC ( efi_systab, "EFI could not set %ls: %s\n",
+ wname, strerror ( rc ) );
+ /* Continue to reboot anyway */
+ }
+ }
/* Use runtime services to reset system */
- rs->ResetSystem ( ( warm ? EfiResetWarm : EfiResetCold ), 0, 0, NULL );
+ type = ( ( flags & REBOOT_WARM ) ? EfiResetWarm : EfiResetCold );
+ rs->ResetSystem ( type, 0, 0, NULL );
}
/**
diff --git a/src/interface/efi/efi_rng.c b/src/interface/efi/efi_rng.c
index b76a6fc0d..66b37fe89 100644
--- a/src/interface/efi/efi_rng.c
+++ b/src/interface/efi/efi_rng.c
@@ -22,6 +22,7 @@
*/
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+FILE_SECBOOT ( PERMITTED );
#include <errno.h>
#include <ipxe/entropy.h>
@@ -54,6 +55,15 @@ EFI_REQUEST_PROTOCOL ( EFI_RNG_PROTOCOL, &efirng );
*/
#define EFIRNG_LEN 32
+/** Maximum number of times to attempting requesting data from RNG
+ *
+ * The UEFI spec allows GetRNG() to return EFI_NOT_READY, which is not
+ * a particularly helpful error status since there is nothing that can
+ * sensibly be done except to retry immediately. We retry failed
+ * calls to GetRNG() (for any reason) up to this number of times.
+ */
+#define EFIRNG_MAX_RETRY 16
+
/**
* Enable entropy gathering
*
@@ -85,29 +95,35 @@ static int efirng_enable ( void ) {
*/
static int efirng_get_noise ( noise_sample_t *noise ) {
uint8_t buf[EFIRNG_LEN];
+ unsigned int i;
EFI_STATUS efirc;
int rc;
/* Sanity check */
assert ( efirng != NULL );
- /* Get the minimum allowed number of random bytes */
- if ( ( efirc = efirng->GetRNG ( efirng, NULL, sizeof ( buf ),
- buf ) ) != 0 ) {
- rc = -EEFI ( efirc );
- DBGC ( &efirng, "ENTROPY could not read from RNG: %s\n",
- strerror ( rc ) );
- return rc;
+ /* Get random bytes, retrying if needed */
+ for ( i = 0 ; i < EFIRNG_MAX_RETRY ; i++ ) {
+
+ /* Get the minimum allowed number of random bytes */
+ if ( ( efirc = efirng->GetRNG ( efirng, NULL, sizeof ( buf ),
+ buf ) ) != 0 ) {
+ rc = -EEFI ( efirc );
+ continue;
+ }
+
+ /* Reduce random bytes to a single noise sample. This
+ * seems like overkill, but we have no way of knowing
+ * how much entropy is actually present in the bytes
+ * returned by the RNG protocol.
+ */
+ *noise = crc32_le ( 0, buf, sizeof ( buf ) );
+ return 0;
}
- /* Reduce random bytes to a single noise sample. This seems
- * like overkill, but we have no way of knowing how much
- * entropy is actually present in the bytes returned by the
- * RNG protocol.
- */
- *noise = crc32_le ( 0, buf, sizeof ( buf ) );
-
- return 0;
+ DBGC ( &efirng, "ENTROPY could not read from RNG: %s\n",
+ strerror ( rc ) );
+ return rc;
}
/** EFI random number generator protocol entropy source */
diff --git a/src/interface/efi/efi_service.c b/src/interface/efi/efi_service.c
index d4129c0d9..4e2f2e951 100644
--- a/src/interface/efi/efi_service.c
+++ b/src/interface/efi/efi_service.c
@@ -22,6 +22,7 @@
*/
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+FILE_SECBOOT ( PERMITTED );
/** @file
*
@@ -45,44 +46,31 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
*/
int efi_service_add ( EFI_HANDLE service, EFI_GUID *binding,
EFI_HANDLE *handle ) {
- EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
- union {
- EFI_SERVICE_BINDING_PROTOCOL *sb;
- void *interface;
- } u;
+ EFI_SERVICE_BINDING_PROTOCOL *sb;
EFI_STATUS efirc;
int rc;
/* Open service binding protocol */
- if ( ( efirc = bs->OpenProtocol ( service, binding, &u.interface,
- efi_image_handle, service,
- EFI_OPEN_PROTOCOL_GET_PROTOCOL ))!=0){
- rc = -EEFI ( efirc );
+ if ( ( rc = efi_open ( service, binding, &sb ) ) != 0 ) {
DBGC ( service, "EFISVC %s cannot open %s binding: %s\n",
efi_handle_name ( service ), efi_guid_ntoa ( binding ),
strerror ( rc ) );
- goto err_open;
+ return rc;
}
/* Create child handle */
- if ( ( efirc = u.sb->CreateChild ( u.sb, handle ) ) != 0 ) {
+ if ( ( efirc = sb->CreateChild ( sb, handle ) ) != 0 ) {
rc = -EEFI ( efirc );
DBGC ( service, "EFISVC %s could not create %s child: %s\n",
efi_handle_name ( service ), efi_guid_ntoa ( binding ),
strerror ( rc ) );
- goto err_create;
+ return rc;
}
- /* Success */
- rc = 0;
DBGC ( service, "EFISVC %s created %s child ",
efi_handle_name ( service ), efi_guid_ntoa ( binding ) );
DBGC ( service, "%s\n", efi_handle_name ( *handle ) );
-
- err_create:
- bs->CloseProtocol ( service, binding, efi_image_handle, service );
- err_open:
- return rc;
+ return 0;
}
/**
@@ -95,11 +83,7 @@ int efi_service_add ( EFI_HANDLE service, EFI_GUID *binding,
*/
int efi_service_del ( EFI_HANDLE service, EFI_GUID *binding,
EFI_HANDLE handle ) {
- EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
- union {
- EFI_SERVICE_BINDING_PROTOCOL *sb;
- void *interface;
- } u;
+ EFI_SERVICE_BINDING_PROTOCOL *sb;
EFI_STATUS efirc;
int rc;
@@ -108,31 +92,22 @@ int efi_service_del ( EFI_HANDLE service, EFI_GUID *binding,
DBGC ( service, "%s\n", efi_handle_name ( handle ) );
/* Open service binding protocol */
- if ( ( efirc = bs->OpenProtocol ( service, binding, &u.interface,
- efi_image_handle, service,
- EFI_OPEN_PROTOCOL_GET_PROTOCOL ))!=0){
- rc = -EEFI ( efirc );
+ if ( ( rc = efi_open ( service, binding, &sb ) ) != 0 ) {
DBGC ( service, "EFISVC %s cannot open %s binding: %s\n",
efi_handle_name ( service ), efi_guid_ntoa ( binding ),
strerror ( rc ) );
- goto err_open;
+ return rc;
}
/* Destroy child handle */
- if ( ( efirc = u.sb->DestroyChild ( u.sb, handle ) ) != 0 ) {
+ if ( ( efirc = sb->DestroyChild ( sb, handle ) ) != 0 ) {
rc = -EEFI ( efirc );
DBGC ( service, "EFISVC %s could not destroy %s child ",
efi_handle_name ( service ), efi_guid_ntoa ( binding ) );
DBGC ( service, "%s: %s\n",
efi_handle_name ( handle ), strerror ( rc ) );
- goto err_destroy;
+ return rc;
}
- /* Success */
- rc = 0;
-
- err_destroy:
- bs->CloseProtocol ( service, binding, efi_image_handle, service );
- err_open:
- return rc;
+ return 0;
}
diff --git a/src/interface/efi/efi_settings.c b/src/interface/efi/efi_settings.c
index cde0ff8d1..95fe2c03c 100644
--- a/src/interface/efi/efi_settings.c
+++ b/src/interface/efi/efi_settings.c
@@ -22,6 +22,7 @@
*/
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+FILE_SECBOOT ( PERMITTED );
/**
* @file
@@ -232,5 +233,6 @@ static void efivars_init ( void ) {
/** EFI variable settings initialiser */
struct init_fn efivars_init_fn __init_fn ( INIT_NORMAL ) = {
+ .name = "efivars",
.initialise = efivars_init,
};
diff --git a/src/interface/efi/efi_shim.c b/src/interface/efi/efi_shim.c
index d5419512d..553cb2721 100644
--- a/src/interface/efi/efi_shim.c
+++ b/src/interface/efi/efi_shim.c
@@ -22,6 +22,7 @@
*/
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+FILE_SECBOOT ( PERMITTED );
#include <string.h>
#include <stdlib.h>
@@ -40,6 +41,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
*/
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+FILE_SECBOOT ( PERMITTED );
/**
* Require use of a third party loader binary
@@ -272,42 +274,28 @@ static EFIAPI EFI_STATUS efi_shim_get_memory_map ( UINTN *len,
* @ret rc Return status code
*/
static int efi_shim_inhibit_pxe ( EFI_HANDLE handle ) {
- EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
- union {
- EFI_PXE_BASE_CODE_PROTOCOL *pxe;
- void *interface;
- } u;
+ EFI_PXE_BASE_CODE_PROTOCOL *pxe;
EFI_STATUS efirc;
int rc;
/* Locate PXE base code */
- if ( ( efirc = bs->OpenProtocol ( handle,
- &efi_pxe_base_code_protocol_guid,
- &u.interface, efi_image_handle, NULL,
- EFI_OPEN_PROTOCOL_GET_PROTOCOL ))!=0){
- rc = -EEFI ( efirc );
+ if ( ( rc = efi_open ( handle, &efi_pxe_base_code_protocol_guid,
+ &pxe ) ) != 0 ) {
DBGC ( &efi_shim, "SHIM could not open PXE base code: %s\n",
strerror ( rc ) );
- goto err_no_base;
+ return rc;
}
/* Stop PXE base code */
- if ( ( efirc = u.pxe->Stop ( u.pxe ) ) != 0 ) {
+ if ( ( efirc = pxe->Stop ( pxe ) ) != 0 ) {
rc = -EEFI ( efirc );
DBGC ( &efi_shim, "SHIM could not stop PXE base code: %s\n",
strerror ( rc ) );
- goto err_stop;
+ return rc;
}
- /* Success */
- rc = 0;
DBGC ( &efi_shim, "SHIM stopped PXE base code\n" );
-
- err_stop:
- bs->CloseProtocol ( handle, &efi_pxe_base_code_protocol_guid,
- efi_image_handle, NULL );
- err_no_base:
- return rc;
+ return 0;
}
/**
diff --git a/src/interface/efi/efi_smbios.c b/src/interface/efi/efi_smbios.c
index d7877b0aa..c10ba1440 100644
--- a/src/interface/efi/efi_smbios.c
+++ b/src/interface/efi/efi_smbios.c
@@ -18,8 +18,10 @@
*/
FILE_LICENCE ( GPL2_OR_LATER );
+FILE_SECBOOT ( PERMITTED );
#include <errno.h>
+#include <ipxe/uaccess.h>
#include <ipxe/smbios.h>
#include <ipxe/efi/efi.h>
#include <ipxe/efi/Guid/SmBios.h>
@@ -48,27 +50,27 @@ static int efi_find_smbios ( struct smbios *smbios ) {
/* Use 64-bit table if present */
if ( smbios3_entry && ( smbios3_entry->signature == SMBIOS3_SIGNATURE ) ) {
- smbios->address = phys_to_user ( smbios3_entry->smbios_address );
+ smbios->address = phys_to_virt ( smbios3_entry->smbios_address );
smbios->len = smbios3_entry->smbios_len;
smbios->count = 0;
smbios->version =
SMBIOS_VERSION ( smbios3_entry->major, smbios3_entry->minor );
DBG ( "Found 64-bit SMBIOS v%d.%d entry point at %p (%lx+%zx)\n",
smbios3_entry->major, smbios3_entry->minor, smbios3_entry,
- user_to_phys ( smbios->address, 0 ), smbios->len );
+ virt_to_phys ( smbios->address ), smbios->len );
return 0;
}
/* Otherwise, use 32-bit table if present */
if ( smbios_entry && ( smbios_entry->signature == SMBIOS_SIGNATURE ) ) {
- smbios->address = phys_to_user ( smbios_entry->smbios_address );
+ smbios->address = phys_to_virt ( smbios_entry->smbios_address );
smbios->len = smbios_entry->smbios_len;
smbios->count = smbios_entry->smbios_count;
smbios->version =
SMBIOS_VERSION ( smbios_entry->major, smbios_entry->minor );
DBG ( "Found 32-bit SMBIOS v%d.%d entry point at %p (%lx+%zx)\n",
smbios_entry->major, smbios_entry->minor, smbios_entry,
- user_to_phys ( smbios->address, 0 ), smbios->len );
+ virt_to_phys ( smbios->address ), smbios->len );
return 0;
}
diff --git a/src/interface/efi/efi_snp.c b/src/interface/efi/efi_snp.c
index 8443be997..dad8b33df 100644
--- a/src/interface/efi/efi_snp.c
+++ b/src/interface/efi/efi_snp.c
@@ -18,6 +18,7 @@
*/
FILE_LICENCE ( GPL2_OR_LATER );
+FILE_SECBOOT ( PERMITTED );
#include <stdlib.h>
#include <string.h>
@@ -175,7 +176,7 @@ static void efi_snp_poll ( struct efi_snp_device *snpdev ) {
while ( ( iobuf = netdev_rx_dequeue ( snpdev->netdev ) ) ) {
list_add_tail ( &iobuf->list, &snpdev->rx );
snpdev->interrupts |= EFI_SIMPLE_NETWORK_RECEIVE_INTERRUPT;
- bs->SignalEvent ( &snpdev->snp.WaitForPacket );
+ bs->SignalEvent ( snpdev->snp.WaitForPacket );
}
}
@@ -1792,14 +1793,6 @@ static int efi_snp_probe ( struct net_device *netdev, void *priv __unused ) {
EFI_STATUS efirc;
int rc;
- /* Find parent EFI device */
- efidev = efidev_parent ( netdev->dev );
- if ( ! efidev ) {
- DBG ( "SNP skipping non-EFI device %s\n", netdev->name );
- rc = 0;
- goto err_no_efidev;
- }
-
/* Allocate the SNP device */
snpdev = zalloc ( sizeof ( *snpdev ) );
if ( ! snpdev ) {
@@ -1807,9 +1800,13 @@ static int efi_snp_probe ( struct net_device *netdev, void *priv __unused ) {
goto err_alloc_snp;
}
snpdev->netdev = netdev_get ( netdev );
- snpdev->efidev = efidev;
INIT_LIST_HEAD ( &snpdev->rx );
+ /* Find parent EFI device, if any */
+ efidev = efidev_parent ( netdev->dev );
+ if ( efidev )
+ snpdev->parent = efidev->device;
+
/* Sanity check */
if ( netdev->ll_protocol->ll_addr_len > sizeof ( EFI_MAC_ADDRESS ) ) {
DBGC ( snpdev, "SNPDEV %p cannot support link-layer address "
@@ -1916,29 +1913,25 @@ static int efi_snp_probe ( struct net_device *netdev, void *priv __unused ) {
* instances to prevent SnpDxe from attempting to bind to
* them.
*/
- if ( ( efirc = bs->OpenProtocol ( snpdev->handle,
- &efi_nii_protocol_guid, &interface,
- efi_image_handle, snpdev->handle,
- ( EFI_OPEN_PROTOCOL_BY_DRIVER |
- EFI_OPEN_PROTOCOL_EXCLUSIVE )))!=0){
- rc = -EEFI ( efirc );
+ if ( ( rc = efi_open_by_driver ( snpdev->handle,
+ &efi_nii_protocol_guid,
+ &interface ) ) != 0 ) {
DBGC ( snpdev, "SNPDEV %p could not open NII protocol: %s\n",
snpdev, strerror ( rc ) );
goto err_open_nii;
}
- if ( ( efirc = bs->OpenProtocol ( snpdev->handle,
- &efi_nii31_protocol_guid, &interface,
- efi_image_handle, snpdev->handle,
- ( EFI_OPEN_PROTOCOL_BY_DRIVER |
- EFI_OPEN_PROTOCOL_EXCLUSIVE )))!=0){
- rc = -EEFI ( efirc );
+ if ( ( rc = efi_open_by_driver ( snpdev->handle,
+ &efi_nii31_protocol_guid,
+ &interface ) ) != 0 ) {
DBGC ( snpdev, "SNPDEV %p could not open NII31 protocol: %s\n",
snpdev, strerror ( rc ) );
goto err_open_nii31;
}
- /* Add as child of EFI parent device */
- if ( ( rc = efi_child_add ( efidev->device, snpdev->handle ) ) != 0 ) {
+ /* Add as child of EFI parent device, if applicable */
+ if ( snpdev->parent &&
+ ( ( rc = efi_child_add ( snpdev->parent,
+ snpdev->handle ) ) != 0 ) ) {
DBGC ( snpdev, "SNPDEV %p could not become child of %s: %s\n",
snpdev, efi_handle_name ( efidev->device ),
strerror ( rc ) );
@@ -1958,10 +1951,6 @@ static int efi_snp_probe ( struct net_device *netdev, void *priv __unused ) {
/* Add to list of SNP devices */
list_add ( &snpdev->list, &efi_snp_devices );
- /* Close device path */
- bs->CloseProtocol ( efidev->device, &efi_device_path_protocol_guid,
- efi_image_handle, efidev->device );
-
DBGC ( snpdev, "SNPDEV %p installed for %s as device %s\n",
snpdev, netdev->name, efi_handle_name ( snpdev->handle ) );
return 0;
@@ -1969,13 +1958,12 @@ static int efi_snp_probe ( struct net_device *netdev, void *priv __unused ) {
list_del ( &snpdev->list );
if ( snpdev->package_list )
leak |= efi_snp_hii_uninstall ( snpdev );
- efi_child_del ( efidev->device, snpdev->handle );
+ if ( snpdev->parent )
+ efi_child_del ( snpdev->parent, snpdev->handle );
err_efi_child_add:
- bs->CloseProtocol ( snpdev->handle, &efi_nii31_protocol_guid,
- efi_image_handle, snpdev->handle );
+ efi_close_by_driver ( snpdev->handle, &efi_nii31_protocol_guid );
err_open_nii31:
- bs->CloseProtocol ( snpdev->handle, &efi_nii_protocol_guid,
- efi_image_handle, snpdev->handle );
+ efi_close_by_driver ( snpdev->handle, &efi_nii_protocol_guid );
err_open_nii:
if ( ( efirc = bs->UninstallMultipleProtocolInterfaces (
snpdev->handle,
@@ -2008,7 +1996,6 @@ static int efi_snp_probe ( struct net_device *netdev, void *priv __unused ) {
free ( snpdev );
}
err_alloc_snp:
- err_no_efidev:
if ( leak )
DBGC ( snpdev, "SNPDEV %p nullified and leaked\n", snpdev );
return rc;
@@ -2063,11 +2050,10 @@ static void efi_snp_remove ( struct net_device *netdev, void *priv __unused ) {
list_del ( &snpdev->list );
if ( snpdev->package_list )
leak |= efi_snp_hii_uninstall ( snpdev );
- efi_child_del ( snpdev->efidev->device, snpdev->handle );
- bs->CloseProtocol ( snpdev->handle, &efi_nii_protocol_guid,
- efi_image_handle, snpdev->handle );
- bs->CloseProtocol ( snpdev->handle, &efi_nii31_protocol_guid,
- efi_image_handle, snpdev->handle );
+ if ( snpdev->parent )
+ efi_child_del ( snpdev->parent, snpdev->handle );
+ efi_close_by_driver ( snpdev->handle, &efi_nii_protocol_guid );
+ efi_close_by_driver ( snpdev->handle, &efi_nii31_protocol_guid );
if ( ( ! efi_shutdown_in_progress ) &&
( ( efirc = bs->UninstallMultipleProtocolInterfaces (
snpdev->handle,
diff --git a/src/interface/efi/efi_snp_hii.c b/src/interface/efi/efi_snp_hii.c
index 8b65c8a78..25287673a 100644
--- a/src/interface/efi/efi_snp_hii.c
+++ b/src/interface/efi/efi_snp_hii.c
@@ -22,6 +22,7 @@
*/
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+FILE_SECBOOT ( PERMITTED );
/**
* @file
diff --git a/src/interface/efi/efi_strings.c b/src/interface/efi/efi_strings.c
index 765b23ca6..3dae22e41 100644
--- a/src/interface/efi/efi_strings.c
+++ b/src/interface/efi/efi_strings.c
@@ -22,6 +22,7 @@
*/
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+FILE_SECBOOT ( PERMITTED );
#include <stddef.h>
#include <stdarg.h>
diff --git a/src/interface/efi/efi_table.c b/src/interface/efi/efi_table.c
new file mode 100644
index 000000000..da5966a13
--- /dev/null
+++ b/src/interface/efi/efi_table.c
@@ -0,0 +1,179 @@
+/*
+ * Copyright (C) 2025 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_SECBOOT ( PERMITTED );
+
+#include <assert.h>
+#include <errno.h>
+#include <string.h>
+#include <ipxe/efi/efi.h>
+#include <ipxe/efi/efi_table.h>
+
+/** @file
+ *
+ * EFI configuration tables
+ *
+ */
+
+/**
+ * Look up EFI configuration table
+ *
+ * @v guid Configuration table GUID
+ * @ret table Configuration table, or NULL
+ */
+void * efi_find_table ( EFI_GUID *guid ) {
+ void *table;
+ unsigned int i;
+
+ /* Scan for installed table */
+ for ( i = 0 ; i < efi_systab->NumberOfTableEntries ; i++ ) {
+ if ( memcmp ( &efi_systab->ConfigurationTable[i].VendorGuid,
+ guid, sizeof ( *guid ) ) == 0 ) {
+ table = efi_systab->ConfigurationTable[i].VendorTable;
+ DBGC ( guid, "EFITAB %s is at %p\n",
+ efi_guid_ntoa ( guid ), table );
+ return table;
+ }
+ }
+
+ return NULL;
+}
+
+/**
+ * Install EFI configuration table
+ *
+ * @v table Configuration table type
+ * @v data Configuration table data, or NULL to uninstall
+ * @v backup Table backup, or NULL to not back up old table
+ * @ret rc Return status code
+ */
+int efi_install_table ( struct efi_table *table, const void *data,
+ void **backup ) {
+ EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
+ EFI_GUID *guid = table->guid;
+ void *copy;
+ void *new;
+ void *old;
+ size_t old_len;
+ size_t new_len;
+ EFI_STATUS efirc;
+ int rc;
+
+ /* Get currently installed table, if any */
+ old = efi_find_table ( guid );
+ old_len = ( old ? table->len ( old ) : 0 );
+
+ /* Create backup copy, if applicable */
+ if ( old_len && backup ) {
+ if ( ( efirc = bs->AllocatePool ( EfiBootServicesData, old_len,
+ &copy ) ) != 0 ) {
+ rc = -EEFI ( efirc );
+ goto err_backup;
+ }
+ memcpy ( copy, old, old_len );
+ DBGC ( table, "EFITAB %s %p+%#zx backed up\n",
+ efi_guid_ntoa ( guid ), old, old_len );
+ } else {
+ copy = NULL;
+ }
+
+ /* Create installable runtime services data copy, if applicable */
+ new_len = ( data ? table->len ( data ) : 0 );
+ if ( new_len ) {
+ if ( ( efirc = bs->AllocatePool ( EfiRuntimeServicesData,
+ new_len, &new ) ) != 0 ) {
+ rc = -EEFI ( efirc );
+ goto err_allocate;
+ }
+ memcpy ( new, data, new_len );
+ } else {
+ new = NULL;
+ }
+
+ /* (Un)install configuration table, if applicable */
+ if ( new || old ) {
+ if ( ( efirc = bs->InstallConfigurationTable ( guid,
+ new ) ) != 0 ) {
+ rc = -EEFI ( efirc );
+ DBGC ( table, "EFITAB %s could not install: %s\n",
+ efi_guid_ntoa ( guid ), strerror ( rc ) );
+ goto err_install;
+ }
+ if ( old ) {
+ DBGC ( table, "EFITAB %s %p+%#zx uninstalled\n",
+ efi_guid_ntoa ( guid ), old, old_len );
+ }
+ if ( new ) {
+ DBGC ( table, "EFITAB %s %p+%#zx installed\n",
+ efi_guid_ntoa ( guid ), new, new_len );
+ }
+ }
+
+ /* Record backup copy, if applicable */
+ if ( backup ) {
+ if ( *backup )
+ bs->FreePool ( *backup );
+ *backup = copy;
+ }
+
+ /* Sanity check */
+ assert ( efi_find_table ( guid ) == new );
+
+ return 0;
+
+ err_install:
+ if ( new )
+ bs->FreePool ( new );
+ err_allocate:
+ if ( copy )
+ bs->FreePool ( copy );
+ err_backup:
+ return rc;
+}
+
+/**
+ * Uninstall EFI configuration table
+ *
+ * @v table Configuration table type
+ * @v backup Table backup (or NULL to not restore old table)
+ * @ret rc Return status code
+ */
+int efi_uninstall_table ( struct efi_table *table, void **backup ) {
+ EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
+ void *old;
+ int rc;
+
+ /* Uninstall or reinstall as applicable */
+ old = ( backup ? *backup : NULL );
+ if ( ( rc = efi_install_table ( table, old, NULL ) ) != 0 )
+ return rc;
+
+ /* Free backup copy, if applicable */
+ if ( backup && *backup ) {
+ bs->FreePool ( *backup );
+ *backup = NULL;
+ }
+
+ return 0;
+}
diff --git a/src/interface/efi/efi_time.c b/src/interface/efi/efi_time.c
index 983a0ef5c..a4c77da20 100644
--- a/src/interface/efi/efi_time.c
+++ b/src/interface/efi/efi_time.c
@@ -22,6 +22,7 @@
*/
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+FILE_SECBOOT ( PERMITTED );
#include <string.h>
#include <errno.h>
diff --git a/src/interface/efi/efi_timer.c b/src/interface/efi/efi_timer.c
index 6427eb1d8..ffb899c86 100644
--- a/src/interface/efi/efi_timer.c
+++ b/src/interface/efi/efi_timer.c
@@ -22,6 +22,7 @@
*/
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+FILE_SECBOOT ( PERMITTED );
#include <string.h>
#include <errno.h>
diff --git a/src/interface/efi/efi_umalloc.c b/src/interface/efi/efi_umalloc.c
index e3f1dacc2..257b27bec 100644
--- a/src/interface/efi/efi_umalloc.c
+++ b/src/interface/efi/efi_umalloc.c
@@ -22,10 +22,12 @@
*/
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+FILE_SECBOOT ( PERMITTED );
#include <string.h>
#include <errno.h>
#include <assert.h>
+#include <ipxe/uaccess.h>
#include <ipxe/umalloc.h>
#include <ipxe/efi/efi.h>
@@ -35,25 +37,23 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
*
*/
-/** Equivalent of NOWHERE for user pointers */
-#define UNOWHERE ( ~UNULL )
-
/**
* Reallocate external memory
*
- * @v old_ptr Memory previously allocated by umalloc(), or UNULL
+ * @v old_ptr Memory previously allocated by umalloc(), or NULL
* @v new_size Requested size
- * @ret new_ptr Allocated memory, or UNULL
+ * @ret new_ptr Allocated memory, or NULL
*
* Calling realloc() with a new size of zero is a valid way to free a
* memory block.
*/
-static userptr_t efi_urealloc ( userptr_t old_ptr, size_t new_size ) {
+static void * efi_urealloc ( void *old_ptr, size_t new_size ) {
EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
EFI_PHYSICAL_ADDRESS phys_addr;
unsigned int new_pages, old_pages;
- userptr_t new_ptr = UNOWHERE;
+ void *new_ptr = NOWHERE;
size_t old_size;
+ size_t *info;
EFI_STATUS efirc;
int rc;
@@ -69,12 +69,12 @@ static userptr_t efi_urealloc ( userptr_t old_ptr, size_t new_size ) {
rc = -EEFI ( efirc );
DBG ( "EFI could not allocate %d pages: %s\n",
new_pages, strerror ( rc ) );
- return UNULL;
+ return NULL;
}
assert ( phys_addr != 0 );
- new_ptr = phys_to_user ( phys_addr + EFI_PAGE_SIZE );
- copy_to_user ( new_ptr, -EFI_PAGE_SIZE,
- &new_size, sizeof ( new_size ) );
+ new_ptr = phys_to_virt ( phys_addr + EFI_PAGE_SIZE );
+ info = ( new_ptr - EFI_PAGE_SIZE );
+ *info = new_size;
DBG ( "EFI allocated %d pages at %llx\n",
new_pages, phys_addr );
}
@@ -84,13 +84,13 @@ static userptr_t efi_urealloc ( userptr_t old_ptr, size_t new_size ) {
* is valid, or (b) new_size is 0; either way, the memcpy() is
* valid.
*/
- if ( old_ptr && ( old_ptr != UNOWHERE ) ) {
- copy_from_user ( &old_size, old_ptr, -EFI_PAGE_SIZE,
- sizeof ( old_size ) );
- memcpy_user ( new_ptr, 0, old_ptr, 0,
- ( (old_size < new_size) ? old_size : new_size ));
+ if ( old_ptr && ( old_ptr != NOWHERE ) ) {
+ info = ( old_ptr - EFI_PAGE_SIZE );
+ old_size = *info;
+ memcpy ( new_ptr, old_ptr,
+ ( (old_size < new_size) ? old_size : new_size ) );
old_pages = ( EFI_SIZE_TO_PAGES ( old_size ) + 1 );
- phys_addr = user_to_phys ( old_ptr, -EFI_PAGE_SIZE );
+ phys_addr = virt_to_phys ( old_ptr - EFI_PAGE_SIZE );
if ( ( efirc = bs->FreePages ( phys_addr, old_pages ) ) != 0 ){
rc = -EEFI ( efirc );
DBG ( "EFI could not free %d pages at %llx: %s\n",
diff --git a/src/interface/efi/efi_usb.c b/src/interface/efi/efi_usb.c
index 28dfc8680..a3b153c88 100644
--- a/src/interface/efi/efi_usb.c
+++ b/src/interface/efi/efi_usb.c
@@ -22,6 +22,7 @@
*/
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+FILE_SECBOOT ( PERMITTED );
#include <stdlib.h>
#include <stdio.h>
@@ -1198,7 +1199,7 @@ static void efi_usb_uninstall ( struct efi_usb_interface *usbintf ) {
* when uninstalling protocols.
*/
if ( ! efi_shutdown_in_progress )
- bs->DisconnectController ( usbintf->handle, NULL, NULL );
+ efi_disconnect ( usbintf->handle, NULL );
/* Uninstall protocols */
if ( ( ! efi_shutdown_in_progress ) &&
@@ -1260,7 +1261,6 @@ static void efi_usb_uninstall_all ( struct efi_usb_device *efiusb ) {
*/
static int efi_usb_probe ( struct usb_function *func,
struct usb_configuration_descriptor *config ) {
- EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
struct usb_device *usb = func->usb;
struct efi_usb_device *usbdev;
struct efi_usb_interface *usbintf;
@@ -1318,7 +1318,7 @@ static int efi_usb_probe ( struct usb_function *func,
/* Connect any external drivers */
list_for_each_entry ( usbintf, &usbdev->interfaces, list )
- bs->ConnectController ( usbintf->handle, NULL, NULL, TRUE );
+ efi_connect ( usbintf->handle, NULL );
return 0;
diff --git a/src/interface/efi/efi_utils.c b/src/interface/efi/efi_utils.c
index 53f82bfe4..a7008afd4 100644
--- a/src/interface/efi/efi_utils.c
+++ b/src/interface/efi/efi_utils.c
@@ -18,6 +18,7 @@
*/
FILE_LICENCE ( GPL2_OR_LATER );
+FILE_SECBOOT ( PERMITTED );
#include <stdio.h>
#include <string.h>
@@ -45,10 +46,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
int efi_locate_device ( EFI_HANDLE device, EFI_GUID *protocol,
EFI_HANDLE *parent, unsigned int skip ) {
EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
- union {
- EFI_DEVICE_PATH_PROTOCOL *path;
- void *interface;
- } u;
+ EFI_DEVICE_PATH_PROTOCOL *devpath;
EFI_DEVICE_PATH_PROTOCOL *path;
EFI_DEVICE_PATH_PROTOCOL *end;
size_t len;
@@ -56,25 +54,21 @@ int efi_locate_device ( EFI_HANDLE device, EFI_GUID *protocol,
int rc;
/* Get device path */
- if ( ( efirc = bs->OpenProtocol ( device,
- &efi_device_path_protocol_guid,
- &u.interface,
- efi_image_handle, device,
- EFI_OPEN_PROTOCOL_GET_PROTOCOL ))!=0){
- rc = -EEFI ( efirc );
+ if ( ( rc = efi_open ( device, &efi_device_path_protocol_guid,
+ &devpath ) ) != 0 ) {
DBGC ( device, "EFIDEV %s cannot open device path: %s\n",
efi_handle_name ( device ), strerror ( rc ) );
goto err_open_device_path;
}
/* Create modifiable copy of device path */
- len = ( efi_path_len ( u.path ) + sizeof ( EFI_DEVICE_PATH_PROTOCOL ));
+ len = ( efi_path_len ( devpath ) + sizeof ( *end ) );
path = malloc ( len );
if ( ! path ) {
rc = -ENOMEM;
goto err_alloc_path;
}
- memcpy ( path, u.path, len );
+ memcpy ( path, devpath, len );
/* Locate parent device(s) */
while ( 1 ) {
@@ -100,14 +94,9 @@ int efi_locate_device ( EFI_HANDLE device, EFI_GUID *protocol,
efi_path_terminate ( end );
}
- /* Success */
- rc = 0;
-
err_locate_protocol:
free ( path );
err_alloc_path:
- bs->CloseProtocol ( device, &efi_device_path_protocol_guid,
- efi_image_handle, device );
err_open_device_path:
return rc;
}
@@ -120,19 +109,12 @@ int efi_locate_device ( EFI_HANDLE device, EFI_GUID *protocol,
* @ret rc Return status code
*/
int efi_child_add ( EFI_HANDLE parent, EFI_HANDLE child ) {
- EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
- void *devpath;
- EFI_STATUS efirc;
+ EFI_DEVICE_PATH_PROTOCOL *devpath;
int rc;
/* Re-open the device path protocol */
- if ( ( efirc = bs->OpenProtocol ( parent,
- &efi_device_path_protocol_guid,
- &devpath,
- efi_image_handle, child,
- EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
- ) ) != 0 ) {
- rc = -EEFI ( efirc );
+ if ( ( rc = efi_open_by_child ( parent, &efi_device_path_protocol_guid,
+ child, &devpath ) ) != 0 ) {
DBGC ( parent, "EFIDEV %s could not add child",
efi_handle_name ( parent ) );
DBGC ( parent, " %s: %s\n",
@@ -154,10 +136,8 @@ int efi_child_add ( EFI_HANDLE parent, EFI_HANDLE child ) {
* @v child EFI child device handle
*/
void efi_child_del ( EFI_HANDLE parent, EFI_HANDLE child ) {
- EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
- bs->CloseProtocol ( parent, &efi_device_path_protocol_guid,
- efi_image_handle, child );
+ efi_close_by_child ( parent, &efi_device_path_protocol_guid, child );
DBGC2 ( parent, "EFIDEV %s removed child", efi_handle_name ( parent ) );
DBGC2 ( parent, " %s\n", efi_handle_name ( child ) );
}
@@ -170,8 +150,8 @@ void efi_child_del ( EFI_HANDLE parent, EFI_HANDLE child ) {
* @v dev Generic device to fill in
* @ret rc Return status code
*/
-static int efi_pci_info ( EFI_HANDLE device, const char *prefix,
- struct device *dev ) {
+static int efi_device_info_pci ( EFI_HANDLE device, const char *prefix,
+ struct device *dev ) {
EFI_HANDLE pci_device;
struct efi_pci_device efipci;
int rc;
@@ -211,7 +191,7 @@ void efi_device_info ( EFI_HANDLE device, const char *prefix,
int rc;
/* Try getting underlying PCI device information */
- if ( ( rc = efi_pci_info ( device, prefix, dev ) ) == 0 )
+ if ( ( rc = efi_device_info_pci ( device, prefix, dev ) ) == 0 )
return;
/* If we cannot get any underlying device information, fall
diff --git a/src/interface/efi/efi_veto.c b/src/interface/efi/efi_veto.c
index a3b60d65f..788515dd1 100644
--- a/src/interface/efi/efi_veto.c
+++ b/src/interface/efi/efi_veto.c
@@ -18,6 +18,7 @@
*/
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+FILE_SECBOOT ( PERMITTED );
#include <stddef.h>
#include <stdlib.h>
@@ -29,6 +30,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <ipxe/efi/Protocol/DriverBinding.h>
#include <ipxe/efi/Protocol/LoadedImage.h>
#include <ipxe/efi/Protocol/ComponentName.h>
+#include <ipxe/efi/Protocol/ComponentName2.h>
#include <ipxe/efi/efi_veto.h>
/** @file
@@ -46,14 +48,12 @@ struct efi_veto_candidate {
*
* @v binding Driver binding protocol
* @v loaded Loaded image protocol
- * @v wtf Component name protocol, if present
* @v manufacturer Manufacturer name, if present
- * @v name Driver name (in "eng" language), if present
+ * @v name Driver name, if present
* @ret vetoed Driver is to be vetoed
*/
int ( * veto ) ( EFI_DRIVER_BINDING_PROTOCOL *binding,
EFI_LOADED_IMAGE_PROTOCOL *loaded,
- EFI_COMPONENT_NAME_PROTOCOL *wtf,
const char *manufacturer, const CHAR16 *name );
};
@@ -123,9 +123,7 @@ static int efi_veto_disconnect ( struct efi_veto *veto ) {
/* Disconnect driver from all handles, in reverse order */
for ( i = 0 ; i < count ; i++ ) {
handle = handles[ count - i - 1 ];
- efirc = bs->DisconnectController ( handle, driver, NULL );
- if ( ( efirc != 0 ) && ( efirc != EFI_NOT_FOUND ) ) {
- rc = -EEFI ( efirc );
+ if ( ( rc = efi_disconnect ( handle, driver ) ) != 0 ) {
DBGC ( driver, "EFIVETO %s could not disconnect",
efi_handle_name ( driver ) );
DBGC ( driver, " %s: %s\n",
@@ -154,33 +152,23 @@ static int efi_veto_disconnect ( struct efi_veto *veto ) {
static int efi_veto_uninstall ( struct efi_veto *veto ) {
EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
EFI_HANDLE driver = veto->driver;
- union {
- EFI_DRIVER_BINDING_PROTOCOL *binding;
- void *interface;
- } binding;
+ EFI_DRIVER_BINDING_PROTOCOL *binding;
EFI_STATUS efirc;
int rc;
/* Open driver binding protocol */
- if ( ( efirc = bs->OpenProtocol (
- driver, &efi_driver_binding_protocol_guid,
- &binding.interface, efi_image_handle, driver,
- EFI_OPEN_PROTOCOL_GET_PROTOCOL ) ) != 0 ) {
- rc = -EEFI ( efirc );
+ if ( ( rc = efi_open ( driver, &efi_driver_binding_protocol_guid,
+ &binding ) ) != 0 ) {
DBGC ( driver, "EFIVETO %s could not open driver binding "
"protocol: %s\n", efi_handle_name ( driver ),
strerror ( rc ) );
return rc;
}
- /* Close driver binding protocol */
- bs->CloseProtocol ( driver, &efi_driver_binding_protocol_guid,
- efi_image_handle, driver );
-
/* Uninstall driver binding protocol */
if ( ( efirc = bs->UninstallMultipleProtocolInterfaces (
driver, &efi_driver_binding_protocol_guid,
- binding.binding, NULL ) ) != 0 ) {
+ binding, NULL ) ) != 0 ) {
rc = -EEFI ( efirc );
DBGC ( driver, "EFIVETO %s could not uninstall driver "
"binding protocol: %s\n",
@@ -394,7 +382,6 @@ static int efi_veto_driver ( struct efi_veto *veto ) {
*
* @v binding Driver binding protocol
* @v loaded Loaded image protocol
- * @v wtf Component name protocol, if present
* @v manufacturer Manufacturer name, if present
* @v name Driver name, if present
* @ret vetoed Driver is to be vetoed
@@ -402,7 +389,6 @@ static int efi_veto_driver ( struct efi_veto *veto ) {
static int
efi_veto_ip4config ( EFI_DRIVER_BINDING_PROTOCOL *binding __unused,
EFI_LOADED_IMAGE_PROTOCOL *loaded __unused,
- EFI_COMPONENT_NAME_PROTOCOL *wtf __unused,
const char *manufacturer, const CHAR16 *name ) {
static const CHAR16 ip4cfg[] = L"IP4 CONFIG Network Service Driver";
static const char *dell = "Dell Inc.";
@@ -427,7 +413,6 @@ efi_veto_ip4config ( EFI_DRIVER_BINDING_PROTOCOL *binding __unused,
*
* @v binding Driver binding protocol
* @v loaded Loaded image protocol
- * @v wtf Component name protocol, if present
* @v manufacturer Manufacturer name, if present
* @v name Driver name, if present
* @ret vetoed Driver is to be vetoed
@@ -435,7 +420,6 @@ efi_veto_ip4config ( EFI_DRIVER_BINDING_PROTOCOL *binding __unused,
static int
efi_veto_hp_xhci ( EFI_DRIVER_BINDING_PROTOCOL *binding __unused,
EFI_LOADED_IMAGE_PROTOCOL *loaded __unused,
- EFI_COMPONENT_NAME_PROTOCOL *wtf __unused,
const char *manufacturer, const CHAR16 *name ) {
static const CHAR16 xhci[] = L"Usb Xhci Driver";
static const char *hp = "HP";
@@ -468,7 +452,6 @@ efi_veto_hp_xhci ( EFI_DRIVER_BINDING_PROTOCOL *binding __unused,
*
* @v binding Driver binding protocol
* @v loaded Loaded image protocol
- * @v wtf Component name protocol, if present
* @v manufacturer Manufacturer name, if present
* @v name Driver name, if present
* @ret vetoed Driver is to be vetoed
@@ -476,7 +459,6 @@ efi_veto_hp_xhci ( EFI_DRIVER_BINDING_PROTOCOL *binding __unused,
static int
efi_veto_vmware_uefipxebc ( EFI_DRIVER_BINDING_PROTOCOL *binding __unused,
EFI_LOADED_IMAGE_PROTOCOL *loaded __unused,
- EFI_COMPONENT_NAME_PROTOCOL *wtf __unused,
const char *manufacturer, const CHAR16 *name ) {
static const CHAR16 uefipxebc[] = L"UEFI PXE Base Code Driver";
static const char *vmware = "VMware, Inc.";
@@ -494,6 +476,30 @@ efi_veto_vmware_uefipxebc ( EFI_DRIVER_BINDING_PROTOCOL *binding __unused,
return 1;
}
+/**
+ * Veto Dhcp6Dxe driver
+ *
+ * @v binding Driver binding protocol
+ * @v loaded Loaded image protocol
+ * @v manufacturer Manufacturer name, if present
+ * @v name Driver name, if present
+ * @ret vetoed Driver is to be vetoed
+ */
+static int efi_veto_dhcp6 ( EFI_DRIVER_BINDING_PROTOCOL *binding __unused,
+ EFI_LOADED_IMAGE_PROTOCOL *loaded __unused,
+ const char *manufacturer __unused,
+ const CHAR16 *name ) {
+ static const CHAR16 dhcp6[] = L"DHCP6 Protocol Driver";
+
+ /* Check driver name */
+ if ( ! name )
+ return 0;
+ if ( memcmp ( name, dhcp6, sizeof ( dhcp6 ) ) != 0 )
+ return 0;
+
+ return 1;
+}
+
/** Driver vetoes */
static struct efi_veto_candidate efi_vetoes[] = {
{
@@ -508,6 +514,10 @@ static struct efi_veto_candidate efi_vetoes[] = {
.name = "VMware UefiPxeBc",
.veto = efi_veto_vmware_uefipxebc,
},
+ {
+ .name = "Dhcp6",
+ .veto = efi_veto_dhcp6,
+ },
};
/**
@@ -520,70 +530,56 @@ static struct efi_veto_candidate efi_vetoes[] = {
*/
static int efi_veto_find ( EFI_HANDLE driver, const char *manufacturer,
struct efi_veto *veto ) {
- EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
- union {
- EFI_DRIVER_BINDING_PROTOCOL *binding;
- void *interface;
- } binding;
- union {
- EFI_LOADED_IMAGE_PROTOCOL *loaded;
- void *interface;
- } loaded;
- union {
- EFI_COMPONENT_NAME_PROTOCOL *wtf;
- void *interface;
- } wtf;
+ EFI_DRIVER_BINDING_PROTOCOL *binding;
+ EFI_LOADED_IMAGE_PROTOCOL *loaded;
+ EFI_COMPONENT_NAME2_PROTOCOL *wtf2;
+ EFI_COMPONENT_NAME_PROTOCOL *wtf;
CHAR16 *name;
unsigned int i;
EFI_HANDLE image;
EFI_STATUS efirc;
int rc;
- DBGC2 ( &efi_vetoes, "EFIVETO checking %s\n",
- efi_handle_name ( driver ) );
-
/* Mark as not vetoed */
memset ( veto, 0, sizeof ( *veto ) );
/* Open driver binding protocol */
- if ( ( efirc = bs->OpenProtocol (
- driver, &efi_driver_binding_protocol_guid,
- &binding.interface, efi_image_handle, driver,
- EFI_OPEN_PROTOCOL_GET_PROTOCOL ) ) != 0 ) {
- rc = -EEFI ( efirc );
+ if ( ( rc = efi_open ( driver, &efi_driver_binding_protocol_guid,
+ &binding ) ) != 0 ) {
DBGC ( driver, "EFIVETO %s could not open driver binding "
"protocol: %s\n", efi_handle_name ( driver ),
strerror ( rc ) );
- goto err_binding;
+ return rc;
}
- image = binding.binding->ImageHandle;
+ image = binding->ImageHandle;
/* Open loaded image protocol */
- if ( ( efirc = bs->OpenProtocol (
- image, &efi_loaded_image_protocol_guid,
- &loaded.interface, efi_image_handle, image,
- EFI_OPEN_PROTOCOL_GET_PROTOCOL ) ) != 0 ) {
- rc = -EEFI ( efirc );
+ if ( ( rc = efi_open ( image, &efi_loaded_image_protocol_guid,
+ &loaded ) ) != 0 ) {
DBGC ( driver, "EFIVETO %s could not open",
efi_handle_name ( driver ) );
DBGC ( driver, " %s loaded image protocol: %s\n",
efi_handle_name ( image ), strerror ( rc ) );
- goto err_loaded;
+ return rc;
}
- /* Open component name protocol, if present*/
- if ( ( efirc = bs->OpenProtocol (
- driver, &efi_component_name_protocol_guid,
- &wtf.interface, efi_image_handle, driver,
- EFI_OPEN_PROTOCOL_GET_PROTOCOL ) ) != 0 ) {
+ /* Open component name protocol, if present */
+ if ( ( rc = efi_open ( image, &efi_component_name2_protocol_guid,
+ &wtf2 ) ) != 0 ) {
+ /* Ignore failure; is not required to be present */
+ }
+
+ /* Open obsolete component name protocol, if present */
+ if ( ( rc = efi_open ( image, &efi_component_name_protocol_guid,
+ &wtf ) ) != 0 ) {
/* Ignore failure; is not required to be present */
- wtf.interface = NULL;
}
/* Get driver name, if available */
- if ( wtf.wtf &&
- ( ( efirc = wtf.wtf->GetDriverName ( wtf.wtf, "eng",
- &name ) == 0 ) ) ) {
+ if ( ( wtf2 && ( ( efirc = wtf2->GetDriverName ( wtf2, "en",
+ &name ) == 0 ) ) ) ||
+ ( wtf && ( ( efirc = wtf->GetDriverName ( wtf, "eng",
+ &name ) == 0 ) ) ) ) {
/* Driver has a name */
} else {
/* Ignore failure; name is not required to be present */
@@ -591,36 +587,25 @@ static int efi_veto_find ( EFI_HANDLE driver, const char *manufacturer,
}
/* Check vetoes */
+ DBGC2 ( &efi_vetoes, "EFIVETO checking %s [%p,%p)\n",
+ efi_handle_name ( driver ), loaded->ImageBase,
+ ( loaded->ImageBase + loaded->ImageSize ) );
for ( i = 0 ; i < ( sizeof ( efi_vetoes ) /
sizeof ( efi_vetoes[0] ) ) ; i++ ) {
- if ( efi_vetoes[i].veto ( binding.binding, loaded.loaded,
- wtf.wtf, manufacturer, name ) ) {
+ if ( efi_vetoes[i].veto ( binding, loaded, manufacturer,
+ name ) ) {
DBGC ( driver, "EFIVETO %s is vetoed (%s)\n",
efi_handle_name ( driver ),
efi_vetoes[i].name );
veto->driver = driver;
- veto->binding = binding.binding;
+ veto->binding = binding;
veto->image = image;
- veto->loaded = loaded.loaded;
+ veto->loaded = loaded;
break;
}
}
- /* Success */
- rc = 0;
-
- /* Close protocols */
- if ( wtf.wtf ) {
- bs->CloseProtocol ( driver, &efi_component_name_protocol_guid,
- efi_image_handle, driver );
- }
- bs->CloseProtocol ( image, &efi_loaded_image_protocol_guid,
- efi_image_handle, image );
- err_loaded:
- bs->CloseProtocol ( driver, &efi_driver_binding_protocol_guid,
- efi_image_handle, driver );
- err_binding:
- return rc;
+ return 0;
}
/**
diff --git a/src/interface/efi/efi_watchdog.c b/src/interface/efi/efi_watchdog.c
index dcc9a5668..5e4eb626c 100644
--- a/src/interface/efi/efi_watchdog.c
+++ b/src/interface/efi/efi_watchdog.c
@@ -22,6 +22,7 @@
*/
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+FILE_SECBOOT ( PERMITTED );
/**
* @file
diff --git a/src/interface/efi/efi_wrap.c b/src/interface/efi/efi_wrap.c
index 5d5d2caee..572d05aac 100644
--- a/src/interface/efi/efi_wrap.c
+++ b/src/interface/efi/efi_wrap.c
@@ -22,6 +22,7 @@
*/
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+FILE_SECBOOT ( PERMITTED );
/**
* @file
@@ -40,6 +41,30 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
/** Colour for debug messages */
#define colour &efi_systab
+/** Maximum size for hex dumps */
+#define EFI_WRAP_DUMP_MAX 128
+
+/** Number of lines to prescroll when needed */
+#define EFI_WRAP_PRESCROLL 16
+
+/** Public EFI system table pointer */
+static EFI_SYSTEM_TABLE *efi_systab_pub;
+
+/** Private EFI system table used while wrapping is active */
+static EFI_SYSTEM_TABLE efi_systab_priv;
+
+/** Original EFI boot services table pointer */
+static EFI_BOOT_SERVICES *efi_bs_orig;
+
+/** Backup of original EFI boot services table */
+static EFI_BOOT_SERVICES efi_bs_copy;
+
+/** Original EFI runtime services table pointer */
+static EFI_RUNTIME_SERVICES *efi_rs_orig;
+
+/** Backup of original EFI runtime services table */
+static EFI_RUNTIME_SERVICES efi_rs_copy;
+
/**
* Convert EFI status code to text
*
@@ -106,27 +131,6 @@ static const char * efi_boolean ( BOOLEAN boolean ) {
}
/**
- * Convert EFI TPL to text
- *
- * @v tpl Task priority level
- * @ret text Task priority level as text
- */
-static const char * efi_tpl ( EFI_TPL tpl ) {
- static char buf[ 19 /* "0xXXXXXXXXXXXXXXXX" + NUL */ ];
-
- switch ( tpl ) {
- case TPL_APPLICATION: return "Application";
- case TPL_CALLBACK: return "Callback";
- case TPL_NOTIFY: return "Notify";
- case TPL_HIGH_LEVEL: return "HighLevel";
- default:
- snprintf ( buf, sizeof ( buf ), "%#lx",
- ( unsigned long ) tpl );
- return buf;
- }
-}
-
-/**
* Convert EFI allocation type to text
*
* @v type Allocation type
@@ -196,25 +200,86 @@ static const char * efi_timer_delay ( EFI_TIMER_DELAY type ) {
}
/**
+ * Convert EFI time to text
+ *
+ * @v time Time, or NULL
+ * @ret text Time as text
+ */
+static const char * efi_time ( EFI_TIME *time ) {
+ static char buf[ 20 /* "xxxx-xx-xx xx:xx:xx" + NUL */ ];
+
+ if ( ! time )
+ return "<NULL>";
+ snprintf ( buf, sizeof ( buf ), "%04d-%02d-%02d %02d:%02d:%02d",
+ time->Year, time->Month, time->Day, time->Hour,
+ time->Minute, time->Second );
+ return buf;
+}
+
+/**
+ * Convert EFI reset type to text
+ *
+ * @v type Reset type
+ * @ret text Reset type as text
+ */
+static const char * efi_reset_type ( EFI_RESET_TYPE type ) {
+ static char buf[ 11 /* "0xXXXXXXXX" + NUL */ ];
+
+ switch ( type ) {
+ case EfiResetCold: return "Cold";
+ case EfiResetWarm: return "Warm";
+ case EfiResetShutdown: return "Shutdown";
+ case EfiResetPlatformSpecific: return "PlatformSpecific";
+ default:
+ snprintf ( buf, sizeof ( buf ), "%#x", type );
+ return buf;
+ }
+}
+
+/**
+ * Pre-scroll display to create space for output lines
+ *
+ * @v lines Number of lines required
+ * @ret efirc EFI status code
+ */
+static int efi_prescroll ( unsigned int lines ) {
+ EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *conout = efi_systab->ConOut;
+ UINTN columns;
+ UINTN rows;
+ UINTN space;
+ EFI_STATUS efirc;
+
+ /* Get number of rows and columns */
+ if ( ( efirc = conout->QueryMode ( conout, conout->Mode->Mode,
+ &columns, &rows ) ) != 0 )
+ return efirc;
+
+ /* Calculate available space */
+ space = ( rows - conout->Mode->CursorRow - 1 );
+
+ /* Scroll to create space */
+ while ( space++ < lines )
+ conout->OutputString ( conout, L"\n" );
+
+ /* Move cursor to start of space */
+ conout->SetCursorPosition ( conout, 0,
+ ( conout->Mode->CursorRow - lines ) );
+
+ return 0;
+}
+
+/**
* Dump information about a loaded image
*
* @v handle Image handle
*/
static void efi_dump_image ( EFI_HANDLE handle ) {
- EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
- union {
- EFI_LOADED_IMAGE_PROTOCOL *image;
- void *intf;
- } loaded;
- EFI_STATUS efirc;
+ EFI_LOADED_IMAGE_PROTOCOL *loaded;
int rc;
/* Open loaded image protocol */
- if ( ( efirc = bs->OpenProtocol ( handle,
- &efi_loaded_image_protocol_guid,
- &loaded.intf, efi_image_handle, NULL,
- EFI_OPEN_PROTOCOL_GET_PROTOCOL ))!=0){
- rc = -EEFI ( efirc );
+ if ( ( rc = efi_open ( handle, &efi_loaded_image_protocol_guid,
+ &loaded ) ) != 0 ) {
DBGC ( colour, "WRAP %s could not get loaded image protocol: "
"%s\n", efi_handle_name ( handle ), strerror ( rc ) );
return;
@@ -222,18 +287,14 @@ static void efi_dump_image ( EFI_HANDLE handle ) {
/* Dump image information */
DBGC ( colour, "WRAP %s at base %p has protocols:\n",
- efi_handle_name ( handle ), loaded.image->ImageBase );
+ efi_handle_name ( handle ), loaded->ImageBase );
DBGC_EFI_PROTOCOLS ( colour, handle );
DBGC ( colour, "WRAP %s parent", efi_handle_name ( handle ) );
- DBGC ( colour, " %s\n", efi_handle_name ( loaded.image->ParentHandle ));
+ DBGC ( colour, " %s\n", efi_handle_name ( loaded->ParentHandle ) );
DBGC ( colour, "WRAP %s device", efi_handle_name ( handle ) );
- DBGC ( colour, " %s\n", efi_handle_name ( loaded.image->DeviceHandle ));
+ DBGC ( colour, " %s\n", efi_handle_name ( loaded->DeviceHandle ) );
DBGC ( colour, "WRAP %s file", efi_handle_name ( handle ) );
- DBGC ( colour, " %s\n", efi_devpath_text ( loaded.image->FilePath ) );
-
- /* Close loaded image protocol */
- bs->CloseProtocol ( handle, &efi_loaded_image_protocol_guid,
- efi_image_handle, NULL );
+ DBGC ( colour, " %s\n", efi_devpath_text ( loaded->FilePath ) );
}
/**
@@ -246,9 +307,9 @@ efi_raise_tpl_wrapper ( EFI_TPL new_tpl ) {
void *retaddr = __builtin_return_address ( 0 );
EFI_TPL old_tpl;
- DBGCP ( colour, "RaiseTPL ( %s ) ", efi_tpl ( new_tpl ) );
+ DBGCP ( colour, "RaiseTPL ( %s ) ", efi_tpl_name ( new_tpl ) );
old_tpl = bs->RaiseTPL ( new_tpl );
- DBGCP ( colour, "= %s -> %p\n", efi_tpl ( old_tpl ), retaddr );
+ DBGCP ( colour, "= %s -> %p\n", efi_tpl_name ( old_tpl ), retaddr );
return old_tpl;
}
@@ -261,7 +322,7 @@ efi_restore_tpl_wrapper ( EFI_TPL old_tpl ) {
EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
void *retaddr = __builtin_return_address ( 0 );
- DBGCP ( colour, "RestoreTPL ( %s ) ", efi_tpl ( old_tpl ) );
+ DBGCP ( colour, "RestoreTPL ( %s ) ", efi_tpl_name ( old_tpl ) );
bs->RestoreTPL ( old_tpl );
DBGCP ( colour, "-> %p\n", retaddr );
}
@@ -398,8 +459,8 @@ efi_create_event_wrapper ( UINT32 type, EFI_TPL notify_tpl,
void *retaddr = __builtin_return_address ( 0 );
EFI_STATUS efirc;
- DBGC ( colour, "CreateEvent ( %#x, %s, %p, %p ) ",
- type, efi_tpl ( notify_tpl ), notify_function, notify_context );
+ DBGC ( colour, "CreateEvent ( %#x, %s, %p, %p ) ", type,
+ efi_tpl_name ( notify_tpl ), notify_function, notify_context );
efirc = bs->CreateEvent ( type, notify_tpl, notify_function,
notify_context, event );
DBGC ( colour, "= %s ( %p ) -> %p\n",
@@ -478,7 +539,7 @@ efi_close_event_wrapper ( EFI_EVENT event ) {
EFI_STATUS efirc;
DBGC ( colour, "CloseEvent ( %p ) ", event );
- efirc = bs->SignalEvent ( event );
+ efirc = bs->CloseEvent ( event );
DBGC ( colour, "= %s -> %p\n", efi_status ( efirc ), retaddr );
return efirc;
}
@@ -493,7 +554,7 @@ efi_check_event_wrapper ( EFI_EVENT event ) {
EFI_STATUS efirc;
DBGCP ( colour, "CheckEvent ( %p ) ", event );
- efirc = bs->SignalEvent ( event );
+ efirc = bs->CheckEvent ( event );
DBGCP ( colour, "= %s -> %p\n", efi_status ( efirc ), retaddr );
return efirc;
}
@@ -783,6 +844,15 @@ efi_exit_boot_services_wrapper ( EFI_HANDLE image_handle, UINTN map_key ) {
if ( efirc != 0 ) {
DBGC ( colour, "ExitBootServices ( ... ) = %s -> %p\n",
efi_status ( efirc ), retaddr );
+ /* On some systems, scrolling the output will cause
+ * the system memory map to change (and so cause
+ * ExitBootServices() to fail).
+ *
+ * After the first failed attempt, prescroll the
+ * screen to maximise the chance of the subsequent
+ * attempt succeeding.
+ */
+ efi_prescroll ( EFI_WRAP_PRESCROLL );
}
return efirc;
}
@@ -814,11 +884,11 @@ efi_stall_wrapper ( UINTN microseconds ) {
void *retaddr = __builtin_return_address ( 0 );
EFI_STATUS efirc;
- DBGC2 ( colour, "Stall ( %ld.%06lds ) ",
+ DBGCP ( colour, "Stall ( %ld.%06lds ) ",
( ( unsigned long ) ( microseconds / 1000000 ) ),
( ( unsigned long ) ( microseconds % 1000000 ) ) );
efirc = bs->Stall ( microseconds );
- DBGC2 ( colour, "= %s -> %p\n", efi_status ( efirc ), retaddr );
+ DBGCP ( colour, "= %s -> %p\n", efi_status ( efirc ), retaddr );
return efirc;
}
@@ -1163,8 +1233,8 @@ efi_create_event_ex_wrapper ( UINT32 type, EFI_TPL notify_tpl,
EFI_STATUS efirc;
DBGC ( colour, "CreateEventEx ( %#x, %s, %p, %p, %s ) ",
- type, efi_tpl ( notify_tpl ), notify_function, notify_context,
- efi_guid_ntoa ( event_group ) );
+ type, efi_tpl_name ( notify_tpl ), notify_function,
+ notify_context, efi_guid_ntoa ( event_group ) );
efirc = bs->CreateEventEx ( type, notify_tpl, notify_function,
notify_context, event_group, event );
DBGC ( colour, "= %s ( %p ) -> %p\n",
@@ -1173,93 +1243,336 @@ efi_create_event_ex_wrapper ( UINT32 type, EFI_TPL notify_tpl,
}
/**
- * Build boot services table wrapper
+ * Wrap GetTime()
+ *
+ */
+static EFI_STATUS EFIAPI
+efi_get_time_wrapper ( EFI_TIME *time, EFI_TIME_CAPABILITIES *cap ) {
+ EFI_RUNTIME_SERVICES *rs = efi_systab->RuntimeServices;
+ void *retaddr = __builtin_return_address ( 0 );
+ EFI_STATUS efirc;
+
+ DBGCP ( colour, "GetTime() " );
+ efirc = rs->GetTime ( time, cap );
+ DBGCP ( colour, "= %s ( %s ) -> %p\n",
+ efi_status ( efirc ), efi_time ( time ), retaddr );
+ return efirc;
+}
+
+/**
+ * Wrap SetTime()
+ *
+ */
+static EFI_STATUS EFIAPI
+efi_set_time_wrapper ( EFI_TIME *time ) {
+ EFI_RUNTIME_SERVICES *rs = efi_systab->RuntimeServices;
+ void *retaddr = __builtin_return_address ( 0 );
+ EFI_STATUS efirc;
+
+ DBGC ( colour, "SetTime ( %s ) ", efi_time ( time ) );
+ efirc = rs->SetTime ( time );
+ DBGC ( colour, "= %s -> %p\n", efi_status ( efirc ), retaddr );
+ return efirc;
+}
+
+/**
+ * Wrap GetWakeupTime()
*
- * @ret bs Wrapped boot services table
*/
-EFI_BOOT_SERVICES * efi_wrap_bs ( void ) {
- static EFI_BOOT_SERVICES efi_bs_wrapper;
+static EFI_STATUS EFIAPI
+efi_get_wakeup_time_wrapper ( BOOLEAN *enabled, BOOLEAN *pending,
+ EFI_TIME *time ) {
+ EFI_RUNTIME_SERVICES *rs = efi_systab->RuntimeServices;
+ void *retaddr = __builtin_return_address ( 0 );
+ EFI_STATUS efirc;
+
+ DBGC ( colour, "GetWakeupTime() " );
+ efirc = rs->GetWakeupTime ( enabled, pending, time );
+ DBGC ( colour, "= %s ( %s, %s, %s ) -> %p\n", efi_status ( efirc ),
+ efi_boolean ( *enabled ), efi_boolean ( *pending ),
+ efi_time ( time ), retaddr );
+ return efirc;
+}
+
+/**
+ * Wrap SetWakeupTime()
+ *
+ */
+static EFI_STATUS EFIAPI
+efi_set_wakeup_time_wrapper ( BOOLEAN enable, EFI_TIME *time ) {
+ EFI_RUNTIME_SERVICES *rs = efi_systab->RuntimeServices;
+ void *retaddr = __builtin_return_address ( 0 );
+ EFI_STATUS efirc;
+
+ DBGC ( colour, "SetWakeupTime ( %s, %s ) ",
+ efi_boolean ( enable ), efi_time ( time ) );
+ efirc = rs->SetWakeupTime ( enable, time );
+ DBGC ( colour, "= %s -> %p\n", efi_status ( efirc ), retaddr );
+ return efirc;
+}
+
+/**
+ * Wrap GetVariable()
+ *
+ */
+static EFI_STATUS EFIAPI
+efi_get_variable_wrapper ( CHAR16 *name, EFI_GUID *guid, UINT32 *attrs,
+ UINTN *len, VOID *data ) {
+ EFI_RUNTIME_SERVICES *rs = efi_systab->RuntimeServices;
+ void *retaddr = __builtin_return_address ( 0 );
+ size_t dumplen;
+ EFI_STATUS efirc;
+
+ DBGC ( colour, "GetVariable ( %s:%ls, %#llx ) ",
+ efi_guid_ntoa ( guid ), name, ( ( unsigned long long ) *len ) );
+ efirc = rs->GetVariable ( name, guid, attrs, len, data );
+ DBGC ( colour, "= %s ( %#llx",
+ efi_status ( efirc ), ( ( unsigned long long ) *len ) );
+ if ( DBG_EXTRA && ( efirc == 0 ) ) {
+ dumplen = *len;
+ if ( dumplen > EFI_WRAP_DUMP_MAX )
+ dumplen = EFI_WRAP_DUMP_MAX;
+ DBGC2 ( colour, ",\n" );
+ DBGC2_HD ( colour, data, dumplen );
+ if ( dumplen != *len )
+ DBGC2 ( colour, "... " );
+ } else {
+ DBGC ( colour, " " );
+ }
+ DBGC ( colour, ") -> %p\n", retaddr );
+ return efirc;
+}
+
+/**
+ * Wrap GetNextVariableName()
+ *
+ */
+static EFI_STATUS EFIAPI
+efi_get_next_variable_name_wrapper ( UINTN *len, CHAR16 *name,
+ EFI_GUID *guid ) {
+ EFI_RUNTIME_SERVICES *rs = efi_systab->RuntimeServices;
+ void *retaddr = __builtin_return_address ( 0 );
+ EFI_STATUS efirc;
+
+ DBGC ( colour, "GetNextVariableName ( %#llx, %s:%ls ) ",
+ ( ( unsigned long long ) *len ), efi_guid_ntoa ( guid ), name );
+ efirc = rs->GetNextVariableName ( len, name, guid );
+ DBGC ( colour, "= %s ( %#llx, %s:%ls ) -> %p\n", efi_status ( efirc ),
+ ( ( unsigned long long ) *len ), efi_guid_ntoa ( guid ), name,
+ retaddr );
+ return efirc;
+}
+
+/**
+ * Wrap SetVariable()
+ *
+ */
+static EFI_STATUS EFIAPI
+efi_set_variable_wrapper ( CHAR16 *name, EFI_GUID *guid, UINT32 attrs,
+ UINTN len, VOID *data ) {
+ EFI_RUNTIME_SERVICES *rs = efi_systab->RuntimeServices;
+ void *retaddr = __builtin_return_address ( 0 );
+ EFI_STATUS efirc;
+
+ DBGC ( colour, "SetVariable ( %s:%ls, %#02x",
+ efi_guid_ntoa ( guid ), name, attrs );
+ if ( len ) {
+ DBGC ( colour, ",\n" );
+ DBGC_HD ( colour, data, len );
+ DBGC ( colour, ") " );
+ } else {
+ DBGC ( colour, ", %#llx, %p ) ",
+ ( ( unsigned long long ) len ), data );
+ }
+ efirc = rs->SetVariable ( name, guid, attrs, len, data );
+ DBGC ( colour, "= %s -> %p\n", efi_status ( efirc ), retaddr );
+ return efirc;
+}
+
+/**
+ * Wrap ResetSystem()
+ *
+ */
+static VOID EFIAPI
+efi_reset_system_wrapper ( EFI_RESET_TYPE type, EFI_STATUS status,
+ UINTN len, VOID *data ) {
+ EFI_RUNTIME_SERVICES *rs = efi_systab->RuntimeServices;
+ void *retaddr = __builtin_return_address ( 0 );
+
+ DBGC ( colour, "ResetSystem ( %s, %s, %#llx, %p ) -> %p\n",
+ efi_reset_type ( type ), efi_status ( status ),
+ ( ( unsigned long long ) len ), data, retaddr );
+ rs->ResetSystem ( type, status, len, data );
+}
+
+/**
+ * Wrap a boot services table
+ *
+ * @v wrapper Boot services table to wrap
+ */
+void efi_wrap_bs ( EFI_BOOT_SERVICES *wrapper ) {
EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
+ /* Do nothing unless debugging is enabled */
+ if ( ! DBG_LOG )
+ return;
+
/* Build boot services table wrapper */
- memcpy ( &efi_bs_wrapper, bs, sizeof ( efi_bs_wrapper ) );
- efi_bs_wrapper.RaiseTPL = efi_raise_tpl_wrapper;
- efi_bs_wrapper.RestoreTPL = efi_restore_tpl_wrapper;
- efi_bs_wrapper.AllocatePages = efi_allocate_pages_wrapper;
- efi_bs_wrapper.FreePages = efi_free_pages_wrapper;
- efi_bs_wrapper.GetMemoryMap = efi_get_memory_map_wrapper;
- efi_bs_wrapper.AllocatePool = efi_allocate_pool_wrapper;
- efi_bs_wrapper.FreePool = efi_free_pool_wrapper;
- efi_bs_wrapper.CreateEvent = efi_create_event_wrapper;
- efi_bs_wrapper.SetTimer = efi_set_timer_wrapper;
- efi_bs_wrapper.WaitForEvent = efi_wait_for_event_wrapper;
- efi_bs_wrapper.SignalEvent = efi_signal_event_wrapper;
- efi_bs_wrapper.CloseEvent = efi_close_event_wrapper;
- efi_bs_wrapper.CheckEvent = efi_check_event_wrapper;
- efi_bs_wrapper.InstallProtocolInterface
+ memcpy ( wrapper, bs, sizeof ( *wrapper ) );
+ wrapper->RaiseTPL = efi_raise_tpl_wrapper;
+ wrapper->RestoreTPL = efi_restore_tpl_wrapper;
+ wrapper->AllocatePages = efi_allocate_pages_wrapper;
+ wrapper->FreePages = efi_free_pages_wrapper;
+ wrapper->GetMemoryMap = efi_get_memory_map_wrapper;
+ wrapper->AllocatePool = efi_allocate_pool_wrapper;
+ wrapper->FreePool = efi_free_pool_wrapper;
+ wrapper->CreateEvent = efi_create_event_wrapper;
+ wrapper->SetTimer = efi_set_timer_wrapper;
+ wrapper->WaitForEvent = efi_wait_for_event_wrapper;
+ wrapper->SignalEvent = efi_signal_event_wrapper;
+ wrapper->CloseEvent = efi_close_event_wrapper;
+ wrapper->CheckEvent = efi_check_event_wrapper;
+ wrapper->InstallProtocolInterface
= efi_install_protocol_interface_wrapper;
- efi_bs_wrapper.ReinstallProtocolInterface
+ wrapper->ReinstallProtocolInterface
= efi_reinstall_protocol_interface_wrapper;
- efi_bs_wrapper.UninstallProtocolInterface
+ wrapper->UninstallProtocolInterface
= efi_uninstall_protocol_interface_wrapper;
- efi_bs_wrapper.HandleProtocol = efi_handle_protocol_wrapper;
- efi_bs_wrapper.RegisterProtocolNotify
- = efi_register_protocol_notify_wrapper;
- efi_bs_wrapper.LocateHandle = efi_locate_handle_wrapper;
- efi_bs_wrapper.LocateDevicePath = efi_locate_device_path_wrapper;
- efi_bs_wrapper.InstallConfigurationTable
+ wrapper->HandleProtocol = efi_handle_protocol_wrapper;
+ wrapper->RegisterProtocolNotify = efi_register_protocol_notify_wrapper;
+ wrapper->LocateHandle = efi_locate_handle_wrapper;
+ wrapper->LocateDevicePath = efi_locate_device_path_wrapper;
+ wrapper->InstallConfigurationTable
= efi_install_configuration_table_wrapper;
- efi_bs_wrapper.LoadImage = efi_load_image_wrapper;
- efi_bs_wrapper.StartImage = efi_start_image_wrapper;
- efi_bs_wrapper.Exit = efi_exit_wrapper;
- efi_bs_wrapper.UnloadImage = efi_unload_image_wrapper;
- efi_bs_wrapper.ExitBootServices = efi_exit_boot_services_wrapper;
- efi_bs_wrapper.GetNextMonotonicCount
- = efi_get_next_monotonic_count_wrapper;
- efi_bs_wrapper.Stall = efi_stall_wrapper;
- efi_bs_wrapper.SetWatchdogTimer = efi_set_watchdog_timer_wrapper;
- efi_bs_wrapper.ConnectController
- = efi_connect_controller_wrapper;
- efi_bs_wrapper.DisconnectController
- = efi_disconnect_controller_wrapper;
- efi_bs_wrapper.OpenProtocol = efi_open_protocol_wrapper;
- efi_bs_wrapper.CloseProtocol = efi_close_protocol_wrapper;
- efi_bs_wrapper.OpenProtocolInformation
+ wrapper->LoadImage = efi_load_image_wrapper;
+ wrapper->StartImage = efi_start_image_wrapper;
+ wrapper->Exit = efi_exit_wrapper;
+ wrapper->UnloadImage = efi_unload_image_wrapper;
+ wrapper->ExitBootServices = efi_exit_boot_services_wrapper;
+ wrapper->GetNextMonotonicCount = efi_get_next_monotonic_count_wrapper;
+ wrapper->Stall = efi_stall_wrapper;
+ wrapper->SetWatchdogTimer = efi_set_watchdog_timer_wrapper;
+ wrapper->ConnectController = efi_connect_controller_wrapper;
+ wrapper->DisconnectController = efi_disconnect_controller_wrapper;
+ wrapper->OpenProtocol = efi_open_protocol_wrapper;
+ wrapper->CloseProtocol = efi_close_protocol_wrapper;
+ wrapper->OpenProtocolInformation
= efi_open_protocol_information_wrapper;
- efi_bs_wrapper.ProtocolsPerHandle
- = efi_protocols_per_handle_wrapper;
- efi_bs_wrapper.LocateHandleBuffer
- = efi_locate_handle_buffer_wrapper;
- efi_bs_wrapper.LocateProtocol = efi_locate_protocol_wrapper;
- efi_bs_wrapper.InstallMultipleProtocolInterfaces
+ wrapper->ProtocolsPerHandle = efi_protocols_per_handle_wrapper;
+ wrapper->LocateHandleBuffer = efi_locate_handle_buffer_wrapper;
+ wrapper->LocateProtocol = efi_locate_protocol_wrapper;
+ wrapper->InstallMultipleProtocolInterfaces
= efi_install_multiple_protocol_interfaces_wrapper;
- efi_bs_wrapper.UninstallMultipleProtocolInterfaces
+ wrapper->UninstallMultipleProtocolInterfaces
= efi_uninstall_multiple_protocol_interfaces_wrapper;
- efi_bs_wrapper.CreateEventEx = efi_create_event_ex_wrapper;
+ wrapper->CreateEventEx = efi_create_event_ex_wrapper;
+}
- return &efi_bs_wrapper;
+/**
+ * Wrap a runtime services table
+ *
+ * @v wrapper Runtime services table to wrap
+ */
+void efi_wrap_rs ( EFI_RUNTIME_SERVICES *wrapper ) {
+ EFI_RUNTIME_SERVICES *rs = efi_systab->RuntimeServices;
+
+ /* Do nothing unless debugging is enabled */
+ if ( ! DBG_LOG )
+ return;
+
+ /* Build boot services table wrapper */
+ memcpy ( wrapper, rs, sizeof ( *wrapper ) );
+ wrapper->GetTime = efi_get_time_wrapper;
+ wrapper->SetTime = efi_set_time_wrapper;
+ wrapper->GetWakeupTime = efi_get_wakeup_time_wrapper;
+ wrapper->SetWakeupTime = efi_set_wakeup_time_wrapper;
+ wrapper->GetVariable = efi_get_variable_wrapper;
+ wrapper->GetNextVariableName = efi_get_next_variable_name_wrapper;
+ wrapper->SetVariable = efi_set_variable_wrapper;
+ wrapper->ResetSystem = efi_reset_system_wrapper;
}
/**
- * Wrap the calls made by a loaded image
+ * Wrap the public EFI system table
*
- * @v handle Image handle
+ * @v global Patch global boot services table in-place
*/
-void efi_wrap ( EFI_HANDLE handle ) {
- static EFI_SYSTEM_TABLE efi_systab_copy;
+void efi_wrap_systab ( int global ) {
+ static EFI_BOOT_SERVICES local_bs;
+ static EFI_RUNTIME_SERVICES local_rs;
+ EFI_BOOT_SERVICES *bs;
+ EFI_RUNTIME_SERVICES *rs;
/* Do nothing unless debugging is enabled */
if ( ! DBG_LOG )
return;
- /* Construct modified system table */
- if ( efi_systab != &efi_systab_copy ) {
- memcpy ( &efi_systab_copy, efi_systab,
- sizeof ( efi_systab_copy ) );
- efi_systab->BootServices = efi_wrap_bs();
- efi_systab = &efi_systab_copy;
+ /* Preserve original system and boot services tables */
+ if ( ! efi_systab_pub ) {
+ efi_systab_pub = efi_systab;
+ efi_bs_orig = efi_systab_pub->BootServices;
+ efi_rs_orig = efi_systab_pub->RuntimeServices;
+ memcpy ( &efi_bs_copy, efi_bs_orig, sizeof ( efi_bs_copy ) );
+ memcpy ( &efi_rs_copy, efi_rs_orig, sizeof ( efi_rs_copy ) );
+ }
+
+ /* Construct and use private system table */
+ if ( efi_systab != &efi_systab_priv ) {
+ memcpy ( &efi_systab_priv, efi_systab_pub,
+ sizeof ( efi_systab_priv ) );
+ efi_systab_priv.BootServices = &efi_bs_copy;
+ efi_systab_priv.RuntimeServices = &efi_rs_copy;
+ efi_systab = &efi_systab_priv;
}
+ /* Wrap global or local boot services table as applicable */
+ bs = ( global ? efi_bs_orig : &local_bs );
+ rs = ( global ? efi_rs_orig : &local_rs );
+ efi_wrap_bs ( bs );
+ efi_wrap_rs ( rs );
+ efi_systab_pub->BootServices = bs;
+ efi_systab_pub->RuntimeServices = rs;
+ DBGC ( colour, "WRAP installed %s wrappers\n",
+ ( global ? "global" : "local" ) );
+}
+
+/**
+ * Remove boot services table wrapper
+ *
+ */
+void efi_unwrap ( void ) {
+
+ /* Do nothing unless debugging is enabled */
+ if ( ! DBG_LOG )
+ return;
+
+ /* Do nothing if wrapping was never enabled */
+ if ( ! efi_systab_pub )
+ return;
+
+ /* Restore original system and boot services tables */
+ memcpy ( efi_bs_orig, &efi_bs_copy, sizeof ( *efi_bs_orig ) );
+ efi_systab_pub->BootServices = efi_bs_orig;
+
+ /* Switch back to using public system table */
+ efi_systab = efi_systab_pub;
+ DBGC ( colour, "WRAP uninstalled wrappers\n" );
+}
+
+/**
+ * Wrap calls made by a newly loaded image
+ *
+ * @v handle Image handle
+ */
+void efi_wrap_image ( EFI_HANDLE handle ) {
+
+ /* Do nothing unless debugging is enabled */
+ if ( ! DBG_LOG )
+ return;
+
/* Dump image information */
efi_dump_image ( handle );
+
+ /* Patch public system table */
+ efi_wrap_systab ( 0 );
}
diff --git a/src/interface/efi/efiprefix.c b/src/interface/efi/efiprefix.c
index 10d8f0bf6..3c095afdc 100644
--- a/src/interface/efi/efiprefix.c
+++ b/src/interface/efi/efiprefix.c
@@ -18,6 +18,7 @@
*/
FILE_LICENCE ( GPL2_OR_LATER );
+FILE_SECBOOT ( PERMITTED );
#include <stdlib.h>
#include <errno.h>
@@ -81,13 +82,22 @@ EFI_STATUS EFIAPI _efi_start ( EFI_HANDLE image_handle,
static void efi_init_application ( void ) {
EFI_HANDLE device = efi_loaded_image->DeviceHandle;
EFI_DEVICE_PATH_PROTOCOL *devpath = efi_loaded_image_path;
+ EFI_DEVICE_PATH_PROTOCOL *bootpath;
struct uri *uri;
/* Set current working URI from device path, if present */
+ bootpath = efi_current_boot_path();
+ DBGC ( device, "EFI has loaded image device path %s\n",
+ efi_devpath_text ( devpath ) );
+ DBGC ( device, "EFI has boot option device path %s\n",
+ efi_devpath_text ( bootpath ) );
uri = efi_path_uri ( devpath );
+ if ( bootpath && ( ! uri ) )
+ uri = efi_path_uri ( bootpath );
if ( uri )
churi ( uri );
uri_put ( uri );
+ free ( bootpath );
/* Identify autoboot device, if any */
efi_set_autoboot_ll_addr ( device, devpath );
@@ -98,6 +108,7 @@ static void efi_init_application ( void ) {
/** EFI application initialisation function */
struct init_fn efi_init_application_fn __init_fn ( INIT_NORMAL ) = {
+ .name = "efi",
.initialise = efi_init_application,
};