summaryrefslogtreecommitdiffstats
path: root/src/interface/efi
diff options
context:
space:
mode:
Diffstat (limited to 'src/interface/efi')
-rw-r--r--src/interface/efi/efi_debug.c98
-rw-r--r--src/interface/efi/efi_file.c116
-rw-r--r--src/interface/efi/efi_guid.c87
-rw-r--r--src/interface/efi/efi_settings.c236
-rw-r--r--src/interface/efi/efi_shim.c402
-rw-r--r--src/interface/efi/efi_snp.c9
-rw-r--r--src/interface/efi/efi_strings.c44
-rw-r--r--src/interface/efi/efi_veto.c160
8 files changed, 1062 insertions, 90 deletions
diff --git a/src/interface/efi/efi_debug.c b/src/interface/efi/efi_debug.c
index 967bb618..1372776f 100644
--- a/src/interface/efi/efi_debug.c
+++ b/src/interface/efi/efi_debug.c
@@ -47,12 +47,30 @@ 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 );
-/** Iscsi4Dxe module 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,
@@ -99,20 +117,48 @@ static struct efi_well_known_guid efi_well_known_guids[] = {
"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,
@@ -131,6 +177,10 @@ static struct efi_well_known_guid efi_well_known_guids[] = {
"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,
@@ -143,6 +193,8 @@ static struct efi_well_known_guid efi_well_known_guids[] = {
"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,
@@ -161,12 +213,22 @@ static struct efi_well_known_guid efi_well_known_guids[] = {
"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,
@@ -325,6 +387,34 @@ void dbg_efi_openers ( EFI_HANDLE handle, EFI_GUID *protocol ) {
}
/**
+ * Print protocol information on a given handle
+ *
+ * @v handle EFI handle
+ * @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 );
+ printf ( "HANDLE %s could not identify %s: %s\n",
+ efi_handle_name ( handle ),
+ efi_guid_ntoa ( protocol ), strerror ( rc ) );
+ return;
+ }
+ printf ( "HANDLE %s %s at %p\n", efi_handle_name ( handle ),
+ efi_guid_ntoa ( protocol ), interface );
+
+ /* Dump list of openers */
+ dbg_efi_openers ( handle, protocol );
+}
+
+/**
* Print list of protocol handlers attached to a handle
*
* @v handle EFI handle
@@ -332,7 +422,6 @@ void dbg_efi_openers ( EFI_HANDLE handle, EFI_GUID *protocol ) {
void dbg_efi_protocols ( EFI_HANDLE handle ) {
EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
EFI_GUID **protocols;
- EFI_GUID *protocol;
UINTN count;
unsigned int i;
EFI_STATUS efirc;
@@ -355,10 +444,7 @@ void dbg_efi_protocols ( EFI_HANDLE handle ) {
/* Dump list of protocols */
for ( i = 0 ; i < count ; i++ ) {
- protocol = protocols[i];
- printf ( "HANDLE %s %s supported\n", efi_handle_name ( handle ),
- efi_guid_ntoa ( protocol ) );
- dbg_efi_openers ( handle, protocol );
+ dbg_efi_protocol ( handle, protocols[i] );
}
/* Free list */
diff --git a/src/interface/efi/efi_file.c b/src/interface/efi/efi_file.c
index b232591d..2ae3a0cb 100644
--- a/src/interface/efi/efi_file.c
+++ b/src/interface/efi/efi_file.c
@@ -250,6 +250,10 @@ static size_t efi_file_read_initrd ( struct efi_file_reader *reader ) {
len = 0;
for_each_image ( image ) {
+ /* Skip hidden images */
+ if ( image->flags & IMAGE_HIDDEN )
+ continue;
+
/* Pad to alignment boundary */
pad_len = ( ( -reader->pos ) & ( INITRD_ALIGN - 1 ) );
if ( pad_len ) {
@@ -291,10 +295,12 @@ static size_t efi_file_read_initrd ( struct efi_file_reader *reader ) {
* Open fixed file
*
* @v file EFI file
+ * @v wname Filename
* @v new New EFI file
* @ret efirc EFI status code
*/
static EFI_STATUS efi_file_open_fixed ( struct efi_file *file,
+ const wchar_t *wname,
EFI_FILE_PROTOCOL **new ) {
/* Increment reference count */
@@ -303,7 +309,8 @@ static EFI_STATUS efi_file_open_fixed ( struct efi_file *file,
/* Return opened file */
*new = &file->file;
- DBGC ( file, "EFIFILE %s opened\n", efi_file_name ( file ) );
+ DBGC ( file, "EFIFILE %s opened via %ls\n",
+ efi_file_name ( file ), wname );
return 0;
}
@@ -321,6 +328,36 @@ static void efi_file_image ( struct efi_file *file, struct image *image ) {
}
/**
+ * Open image-backed file
+ *
+ * @v image Image
+ * @v wname Filename
+ * @v new New EFI file
+ * @ret efirc EFI status code
+ */
+static EFI_STATUS efi_file_open_image ( struct image *image,
+ const wchar_t *wname,
+ EFI_FILE_PROTOCOL **new ) {
+ struct efi_file *file;
+
+ /* Allocate and initialise file */
+ file = zalloc ( sizeof ( *file ) );
+ if ( ! file )
+ return EFI_OUT_OF_RESOURCES;
+ ref_init ( &file->refcnt, efi_file_free );
+ memcpy ( &file->file, &efi_file_root.file, sizeof ( file->file ) );
+ memcpy ( &file->load, &efi_file_root.load, sizeof ( file->load ) );
+ efi_file_image ( file, image_get ( image ) );
+
+ /* Return opened file */
+ *new = &file->file;
+
+ DBGC ( file, "EFIFILE %s opened via %ls\n",
+ efi_file_name ( file ), wname );
+ return 0;
+}
+
+/**
* Open file
*
* @v this EFI file
@@ -335,9 +372,9 @@ efi_file_open ( EFI_FILE_PROTOCOL *this, EFI_FILE_PROTOCOL **new,
CHAR16 *wname, UINT64 mode, UINT64 attributes __unused ) {
struct efi_file *file = container_of ( this, struct efi_file, file );
char buf[ wcslen ( wname ) + 1 /* NUL */ ];
- struct efi_file *new_file;
struct image *image;
char *name;
+ char *sep;
/* Convert name to ASCII */
snprintf ( buf, sizeof ( buf ), "%ls", wname );
@@ -351,7 +388,7 @@ efi_file_open ( EFI_FILE_PROTOCOL *this, EFI_FILE_PROTOCOL **new,
/* Allow root directory itself to be opened */
if ( ( name[0] == '\0' ) || ( name[0] == '.' ) )
- return efi_file_open_fixed ( &efi_file_root, new );
+ return efi_file_open_fixed ( &efi_file_root, wname, new );
/* Fail unless opening from the root */
if ( file != &efi_file_root ) {
@@ -367,31 +404,28 @@ efi_file_open ( EFI_FILE_PROTOCOL *this, EFI_FILE_PROTOCOL **new,
return EFI_WRITE_PROTECTED;
}
- /* Allow magic initrd to be opened */
- if ( strcasecmp ( name, efi_file_initrd.file.name ) == 0 )
- return efi_file_open_fixed ( &efi_file_initrd.file, new );
+ /* Allow registered images to be opened */
+ if ( ( image = efi_file_find ( name ) ) != NULL )
+ return efi_file_open_image ( image, wname, new );
- /* Identify image */
- image = efi_file_find ( name );
- if ( ! image ) {
- DBGC ( file, "EFIFILE %s does not exist\n", name );
- return EFI_NOT_FOUND;
+ /* Allow magic initrd to be opened */
+ if ( strcasecmp ( name, efi_file_initrd.file.name ) == 0 ) {
+ return efi_file_open_fixed ( &efi_file_initrd.file, wname,
+ new );
}
- /* Allocate and initialise file */
- new_file = zalloc ( sizeof ( *new_file ) );
- if ( ! new_file )
- return EFI_OUT_OF_RESOURCES;
- ref_init ( &file->refcnt, efi_file_free );
- memcpy ( &new_file->file, &efi_file_root.file,
- sizeof ( new_file->file ) );
- memcpy ( &new_file->load, &efi_file_root.load,
- sizeof ( new_file->load ) );
- efi_file_image ( new_file, image_get ( image ) );
- *new = &new_file->file;
- DBGC ( new_file, "EFIFILE %s opened\n", efi_file_name ( new_file ) );
+ /* Allow currently selected image to be opened as "grub*.efi",
+ * to work around buggy versions of the UEFI shim.
+ */
+ if ( ( strncasecmp ( name, "grub", 4 ) == 0 ) &&
+ ( ( sep = strrchr ( name, '.' ) ) != NULL ) &&
+ ( strcasecmp ( sep, ".efi" ) == 0 ) &&
+ ( ( image = find_image_tag ( &selected_image ) ) != NULL ) ) {
+ return efi_file_open_image ( image, wname, new );
+ }
- return 0;
+ DBGC ( file, "EFIFILE %ls does not exist\n", wname );
+ return EFI_NOT_FOUND;
}
/**
@@ -505,13 +539,21 @@ static EFI_STATUS efi_file_read_dir ( struct efi_file *file, UINTN *len,
/* Construct directory entries for image-backed files */
index = file->pos;
for_each_image ( image ) {
- if ( index-- == 0 ) {
- efi_file_image ( &entry, image );
- efirc = efi_file_info ( &entry, len, data );
- if ( efirc == 0 )
- file->pos++;
- return efirc;
- }
+
+ /* Skip hidden images */
+ if ( image->flags & IMAGE_HIDDEN )
+ continue;
+
+ /* Skip preceding images */
+ if ( index-- )
+ continue;
+
+ /* Construct directory entry */
+ efi_file_image ( &entry, image );
+ efirc = efi_file_info ( &entry, len, data );
+ if ( efirc == 0 )
+ file->pos++;
+ return efirc;
}
/* No more entries */
@@ -821,7 +863,7 @@ efi_file_open_volume ( EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *filesystem __unused,
EFI_FILE_PROTOCOL **file ) {
DBGC ( &efi_file_root, "EFIFILE open volume\n" );
- return efi_file_open_fixed ( &efi_file_root, file );
+ return efi_file_open_fixed ( &efi_file_root, L"<volume>", file );
}
/** EFI simple file system protocol */
@@ -1074,6 +1116,7 @@ int efi_file_install ( EFI_HANDLE handle ) {
EFI_DISK_IO_PROTOCOL *diskio;
void *interface;
} diskio;
+ struct image *image;
EFI_STATUS efirc;
int rc;
@@ -1137,9 +1180,12 @@ int efi_file_install ( EFI_HANDLE handle ) {
goto err_initrd_claim;
/* Install Linux initrd fixed device path file if non-empty */
- if ( have_images() &&
- ( ( rc = efi_file_path_install ( &efi_file_initrd ) ) != 0 ) ) {
- goto err_initrd_install;
+ for_each_image ( image ) {
+ if ( image->flags & IMAGE_HIDDEN )
+ continue;
+ if ( ( rc = efi_file_path_install ( &efi_file_initrd ) ) != 0 )
+ goto err_initrd_install;
+ break;
}
return 0;
diff --git a/src/interface/efi/efi_guid.c b/src/interface/efi/efi_guid.c
index 663585dc..f841448f 100644
--- a/src/interface/efi/efi_guid.c
+++ b/src/interface/efi/efi_guid.c
@@ -37,23 +37,32 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <ipxe/efi/Protocol/DevicePath.h>
#include <ipxe/efi/Protocol/DevicePathToText.h>
#include <ipxe/efi/Protocol/Dhcp4.h>
+#include <ipxe/efi/Protocol/Dhcp6.h>
#include <ipxe/efi/Protocol/DiskIo.h>
+#include <ipxe/efi/Protocol/Dns4.h>
+#include <ipxe/efi/Protocol/Dns6.h>
#include <ipxe/efi/Protocol/DriverBinding.h>
#include <ipxe/efi/Protocol/GraphicsOutput.h>
#include <ipxe/efi/Protocol/HiiConfigAccess.h>
#include <ipxe/efi/Protocol/HiiFont.h>
+#include <ipxe/efi/Protocol/Http.h>
#include <ipxe/efi/Protocol/Ip4.h>
#include <ipxe/efi/Protocol/Ip4Config.h>
+#include <ipxe/efi/Protocol/Ip4Config2.h>
+#include <ipxe/efi/Protocol/Ip6.h>
+#include <ipxe/efi/Protocol/Ip6Config.h>
#include <ipxe/efi/Protocol/LoadFile.h>
#include <ipxe/efi/Protocol/LoadFile2.h>
#include <ipxe/efi/Protocol/LoadedImage.h>
#include <ipxe/efi/Protocol/ManagedNetwork.h>
#include <ipxe/efi/Protocol/Mtftp4.h>
+#include <ipxe/efi/Protocol/Mtftp6.h>
#include <ipxe/efi/Protocol/NetworkInterfaceIdentifier.h>
#include <ipxe/efi/Protocol/PciIo.h>
#include <ipxe/efi/Protocol/PciRootBridgeIo.h>
#include <ipxe/efi/Protocol/PxeBaseCode.h>
#include <ipxe/efi/Protocol/SerialIo.h>
+#include <ipxe/efi/Protocol/ShimLock.h>
#include <ipxe/efi/Protocol/SimpleFileSystem.h>
#include <ipxe/efi/Protocol/SimpleNetwork.h>
#include <ipxe/efi/Protocol/SimplePointer.h>
@@ -62,7 +71,9 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <ipxe/efi/Protocol/SimpleTextOut.h>
#include <ipxe/efi/Protocol/TcgService.h>
#include <ipxe/efi/Protocol/Tcp4.h>
+#include <ipxe/efi/Protocol/Tcp6.h>
#include <ipxe/efi/Protocol/Udp4.h>
+#include <ipxe/efi/Protocol/Udp6.h>
#include <ipxe/efi/Protocol/UgaDraw.h>
#include <ipxe/efi/Protocol/UnicodeCollation.h>
#include <ipxe/efi/Protocol/UsbHostController.h>
@@ -139,10 +150,34 @@ EFI_GUID efi_dhcp4_protocol_guid
EFI_GUID efi_dhcp4_service_binding_protocol_guid
= EFI_DHCP4_SERVICE_BINDING_PROTOCOL_GUID;
+/** DHCPv6 protocol GUID */
+EFI_GUID efi_dhcp6_protocol_guid
+ = EFI_DHCP6_PROTOCOL_GUID;
+
+/** DHCPv6 service binding protocol GUID */
+EFI_GUID efi_dhcp6_service_binding_protocol_guid
+ = EFI_DHCP6_SERVICE_BINDING_PROTOCOL_GUID;
+
/** Disk I/O protocol GUID */
EFI_GUID efi_disk_io_protocol_guid
= EFI_DISK_IO_PROTOCOL_GUID;
+/** DNSv4 protocol GUID */
+EFI_GUID efi_dns4_protocol_guid
+ = EFI_DNS4_PROTOCOL_GUID;
+
+/** DNSv4 service binding protocol GUID */
+EFI_GUID efi_dns4_service_binding_protocol_guid
+ = EFI_DNS4_SERVICE_BINDING_PROTOCOL_GUID;
+
+/** DNSv6 protocol GUID */
+EFI_GUID efi_dns6_protocol_guid
+ = EFI_DNS6_PROTOCOL_GUID;
+
+/** DNSv6 service binding protocol GUID */
+EFI_GUID efi_dns6_service_binding_protocol_guid
+ = EFI_DNS6_SERVICE_BINDING_PROTOCOL_GUID;
+
/** Driver binding protocol GUID */
EFI_GUID efi_driver_binding_protocol_guid
= EFI_DRIVER_BINDING_PROTOCOL_GUID;
@@ -159,6 +194,14 @@ EFI_GUID efi_hii_config_access_protocol_guid
EFI_GUID efi_hii_font_protocol_guid
= EFI_HII_FONT_PROTOCOL_GUID;
+/** HTTP protocol GUID */
+EFI_GUID efi_http_protocol_guid
+ = EFI_HTTP_PROTOCOL_GUID;
+
+/** HTTP service binding protocol GUID */
+EFI_GUID efi_http_service_binding_protocol_guid
+ = EFI_HTTP_SERVICE_BINDING_PROTOCOL_GUID;
+
/** IPv4 protocol GUID */
EFI_GUID efi_ip4_protocol_guid
= EFI_IP4_PROTOCOL_GUID;
@@ -167,10 +210,26 @@ EFI_GUID efi_ip4_protocol_guid
EFI_GUID efi_ip4_config_protocol_guid
= EFI_IP4_CONFIG_PROTOCOL_GUID;
+/** IPv4 configuration 2 protocol GUID */
+EFI_GUID efi_ip4_config2_protocol_guid
+ = EFI_IP4_CONFIG2_PROTOCOL_GUID;
+
/** IPv4 service binding protocol GUID */
EFI_GUID efi_ip4_service_binding_protocol_guid
= EFI_IP4_SERVICE_BINDING_PROTOCOL_GUID;
+/** IPv6 protocol GUID */
+EFI_GUID efi_ip6_protocol_guid
+ = EFI_IP6_PROTOCOL_GUID;
+
+/** IPv6 configuration protocol GUID */
+EFI_GUID efi_ip6_config_protocol_guid
+ = EFI_IP6_CONFIG_PROTOCOL_GUID;
+
+/** IPv6 service binding protocol GUID */
+EFI_GUID efi_ip6_service_binding_protocol_guid
+ = EFI_IP6_SERVICE_BINDING_PROTOCOL_GUID;
+
/** Load file protocol GUID */
EFI_GUID efi_load_file_protocol_guid
= EFI_LOAD_FILE_PROTOCOL_GUID;
@@ -203,6 +262,14 @@ EFI_GUID efi_mtftp4_protocol_guid
EFI_GUID efi_mtftp4_service_binding_protocol_guid
= EFI_MTFTP4_SERVICE_BINDING_PROTOCOL_GUID;
+/** MTFTPv6 protocol GUID */
+EFI_GUID efi_mtftp6_protocol_guid
+ = EFI_MTFTP6_PROTOCOL_GUID;
+
+/** MTFTPv6 service binding protocol GUID */
+EFI_GUID efi_mtftp6_service_binding_protocol_guid
+ = EFI_MTFTP6_SERVICE_BINDING_PROTOCOL_GUID;
+
/** Network interface identifier protocol GUID (old version) */
EFI_GUID efi_nii_protocol_guid
= EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL_GUID;
@@ -227,6 +294,10 @@ EFI_GUID efi_pxe_base_code_protocol_guid
EFI_GUID efi_serial_io_protocol_guid
= EFI_SERIAL_IO_PROTOCOL_GUID;
+/** Shim lock protocol GUID */
+EFI_GUID efi_shim_lock_protocol_guid
+ = EFI_SHIM_LOCK_PROTOCOL_GUID;
+
/** Simple file system protocol GUID */
EFI_GUID efi_simple_file_system_protocol_guid
= EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_GUID;
@@ -263,6 +334,14 @@ EFI_GUID efi_tcp4_protocol_guid
EFI_GUID efi_tcp4_service_binding_protocol_guid
= EFI_TCP4_SERVICE_BINDING_PROTOCOL_GUID;
+/** TCPv6 protocol GUID */
+EFI_GUID efi_tcp6_protocol_guid
+ = EFI_TCP6_PROTOCOL_GUID;
+
+/** TCPv6 service binding protocol GUID */
+EFI_GUID efi_tcp6_service_binding_protocol_guid
+ = EFI_TCP6_SERVICE_BINDING_PROTOCOL_GUID;
+
/** TrEE protocol GUID */
EFI_GUID efi_tree_protocol_guid
= EFI_TREE_PROTOCOL_GUID;
@@ -275,6 +354,14 @@ EFI_GUID efi_udp4_protocol_guid
EFI_GUID efi_udp4_service_binding_protocol_guid
= EFI_UDP4_SERVICE_BINDING_PROTOCOL_GUID;
+/** UDPv6 protocol GUID */
+EFI_GUID efi_udp6_protocol_guid
+ = EFI_UDP6_PROTOCOL_GUID;
+
+/** UDPv6 service binding protocol GUID */
+EFI_GUID efi_udp6_service_binding_protocol_guid
+ = EFI_UDP6_SERVICE_BINDING_PROTOCOL_GUID;
+
/** UGA draw protocol GUID */
EFI_GUID efi_uga_draw_protocol_guid
= EFI_UGA_DRAW_PROTOCOL_GUID;
diff --git a/src/interface/efi/efi_settings.c b/src/interface/efi/efi_settings.c
new file mode 100644
index 00000000..cde0ff8d
--- /dev/null
+++ b/src/interface/efi/efi_settings.c
@@ -0,0 +1,236 @@
+/*
+ * Copyright (C) 2023 Michael Brown <mbrown@fensystems.co.uk>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ * You can also choose to distribute this program under the terms of
+ * the Unmodified Binary Distribution Licence (as given in the file
+ * COPYING.UBDL), provided that you have satisfied its requirements.
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+
+/**
+ * @file
+ *
+ * EFI variable settings
+ *
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <ipxe/settings.h>
+#include <ipxe/init.h>
+#include <ipxe/efi/efi.h>
+#include <ipxe/efi/efi_strings.h>
+
+/** EFI variable settings scope */
+static const struct settings_scope efivars_scope;
+
+/** EFI variable settings */
+static struct settings efivars;
+
+/**
+ * Check applicability of EFI variable setting
+ *
+ * @v settings Settings block
+ * @v setting Setting
+ * @ret applies Setting applies within this settings block
+ */
+static int efivars_applies ( struct settings *settings __unused,
+ const struct setting *setting ) {
+
+ return ( setting->scope == &efivars_scope );
+}
+
+/**
+ * Find first matching EFI variable name
+ *
+ * @v wname Name
+ * @v guid GUID to fill in
+ * @ret rc Return status code
+ */
+static int efivars_find ( const CHAR16 *wname, EFI_GUID *guid ) {
+ EFI_RUNTIME_SERVICES *rs = efi_systab->RuntimeServices;
+ size_t wname_len = ( ( wcslen ( wname ) + 1 ) * sizeof ( wname[0] ) );
+ CHAR16 *buf;
+ CHAR16 *tmp;
+ UINTN size;
+ EFI_STATUS efirc;
+ int rc;
+
+ /* Allocate single wNUL for first call to GetNextVariableName() */
+ size = sizeof ( buf[0] );
+ buf = zalloc ( size );
+ if ( ! buf )
+ return -ENOMEM;
+
+ /* Iterate over all veriables */
+ while ( 1 ) {
+
+ /* Get next variable name */
+ efirc = rs->GetNextVariableName ( &size, buf, guid );
+ if ( efirc == EFI_BUFFER_TOO_SMALL ) {
+ tmp = realloc ( buf, size );
+ if ( ! tmp ) {
+ rc = -ENOMEM;
+ break;
+ }
+ buf = tmp;
+ efirc = rs->GetNextVariableName ( &size, buf, guid );
+ }
+ if ( efirc == EFI_NOT_FOUND ) {
+ rc = -ENOENT;
+ break;
+ }
+ if ( efirc != 0 ) {
+ rc = -EEFI ( efirc );
+ DBGC ( &efivars, "EFIVARS %s:%ls could not fetch next "
+ "variable name: %s\n",
+ efi_guid_ntoa ( guid ), buf, strerror ( rc ) );
+ break;
+ }
+ DBGC2 ( &efivars, "EFIVARS %s:%ls exists\n",
+ efi_guid_ntoa ( guid ), buf );
+
+ /* Check for matching variable name */
+ if ( memcmp ( wname, buf, wname_len ) == 0 ) {
+ rc = 0;
+ break;
+ }
+ }
+
+ /* Free temporary buffer */
+ free ( buf );
+
+ return rc;
+}
+
+/**
+ * Fetch value of EFI variable setting
+ *
+ * @v settings Settings block
+ * @v setting Setting to fetch
+ * @v data Buffer to fill with setting data
+ * @v len Length of buffer
+ * @ret len Length of setting data, or negative error
+ */
+static int efivars_fetch ( struct settings *settings __unused,
+ struct setting *setting, void *data, size_t len ) {
+ EFI_RUNTIME_SERVICES *rs = efi_systab->RuntimeServices;
+ size_t name_len = strlen ( setting->name );
+ CHAR16 wname[ name_len + 1 /* wNUL */ ];
+ EFI_GUID guid;
+ UINT32 attrs;
+ UINTN size;
+ void *buf;
+ EFI_STATUS efirc;
+ int rc;
+
+ /* Convert name to UCS-2 */
+ efi_snprintf ( wname, sizeof ( wname ), "%s", setting->name );
+
+ /* Find variable GUID */
+ if ( ( rc = efivars_find ( wname, &guid ) ) != 0 )
+ goto err_find;
+
+ /* Get variable length */
+ size = 0;
+ if ( ( efirc = rs->GetVariable ( wname, &guid, &attrs, &size,
+ NULL ) != EFI_BUFFER_TOO_SMALL ) ) {
+ rc = -EEFI ( efirc );
+ DBGC ( &efivars, "EFIVARS %s:%ls could not get size: %s\n",
+ efi_guid_ntoa ( &guid ), wname, strerror ( rc ) );
+ goto err_len;
+ }
+
+ /* Allocate temporary buffer, since GetVariable() is not
+ * guaranteed to return partial data for an underlength
+ * buffer.
+ */
+ buf = malloc ( size );
+ if ( ! buf ) {
+ rc = -ENOMEM;
+ goto err_alloc;
+ }
+
+ /* Get variable value */
+ if ( ( efirc = rs->GetVariable ( wname, &guid, &attrs, &size,
+ buf ) ) != 0 ) {
+ rc = -EEFI ( efirc );
+ DBGC ( &efivars, "EFIVARS %s:%ls could not get %zd bytes: "
+ "%s\n", efi_guid_ntoa ( &guid ), wname,
+ ( ( size_t ) size ), strerror ( rc ) );
+ goto err_get;
+ }
+ DBGC ( &efivars, "EFIVARS %s:%ls:\n", efi_guid_ntoa ( &guid ), wname );
+ DBGC_HDA ( &efivars, 0, buf, size );
+
+ /* Return setting value */
+ if ( len > size )
+ len = size;
+ memcpy ( data, buf, len );
+ if ( ! setting->type )
+ setting->type = &setting_type_hex;
+
+ /* Free temporary buffer */
+ free ( buf );
+
+ return size;
+
+ err_get:
+ free ( buf );
+ err_alloc:
+ err_len:
+ err_find:
+ return rc;
+}
+
+/** EFI variable settings operations */
+static struct settings_operations efivars_operations = {
+ .applies = efivars_applies,
+ .fetch = efivars_fetch,
+};
+
+/** EFI variable settings */
+static struct settings efivars = {
+ .refcnt = NULL,
+ .siblings = LIST_HEAD_INIT ( efivars.siblings ),
+ .children = LIST_HEAD_INIT ( efivars.children ),
+ .op = &efivars_operations,
+ .default_scope = &efivars_scope,
+};
+
+/**
+ * Initialise EFI variable settings
+ *
+ */
+static void efivars_init ( void ) {
+ int rc;
+
+ /* Register settings block */
+ if ( ( rc = register_settings ( &efivars, NULL, "efi" ) ) != 0 ) {
+ DBGC ( &efivars, "EFIVARS could not register: %s\n",
+ strerror ( rc ) );
+ return;
+ }
+}
+
+/** EFI variable settings initialiser */
+struct init_fn efivars_init_fn __init_fn ( INIT_NORMAL ) = {
+ .initialise = efivars_init,
+};
diff --git a/src/interface/efi/efi_shim.c b/src/interface/efi/efi_shim.c
new file mode 100644
index 00000000..a46d79d0
--- /dev/null
+++ b/src/interface/efi/efi_shim.c
@@ -0,0 +1,402 @@
+/*
+ * Copyright (C) 2022 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 (at your option) 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 );
+
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <ipxe/image.h>
+#include <ipxe/efi/efi.h>
+#include <ipxe/efi/efi_strings.h>
+#include <ipxe/efi/efi_shim.h>
+#include <ipxe/efi/Protocol/PxeBaseCode.h>
+#include <ipxe/efi/Protocol/ShimLock.h>
+
+/** @file
+ *
+ * UEFI shim special handling
+ *
+ */
+
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
+
+/**
+ * Require use of a third party loader binary
+ *
+ * The UEFI shim is gradually becoming less capable of directly
+ * executing a Linux kernel image, due to an ever increasing list of
+ * assumptions that it will only ever be used in conjunction with a
+ * second stage loader binary such as GRUB.
+ *
+ * For example: shim will erroneously complain if the image that it
+ * loads and executes does not in turn call in to the "shim lock
+ * protocol" to verify a separate newly loaded binary before calling
+ * ExitBootServices(), even if no such separate binary is used or
+ * required.
+ *
+ * Experience shows that there is unfortunately no point in trying to
+ * get a fix for this upstreamed into shim. We therefore default to
+ * reducing the Secure Boot attack surface by removing, where
+ * possible, this spurious requirement for the use of an additional
+ * second stage loader.
+ *
+ * This option may be used to require the use of an additional second
+ * stage loader binary, in case this behaviour is ever desirable.
+ */
+int efi_shim_require_loader = 0;
+
+/**
+ * Allow use of PXE base code protocol
+ *
+ * We provide shim with access to all of the relevant downloaded files
+ * via our EFI_SIMPLE_FILE_SYSTEM_PROTOCOL interface. However, shim
+ * will instead try to redownload the files via TFTP since it prefers
+ * to use the EFI_PXE_BASE_CODE_PROTOCOL installed on the same handle.
+ *
+ * Experience shows that there is unfortunately no point in trying to
+ * get a fix for this upstreamed into shim. We therefore default to
+ * working around this undesirable behaviour by stopping the PXE base
+ * code protocol before invoking shim.
+ *
+ * This option may be used to allow shim to use the PXE base code
+ * protocol, in case this behaviour is ever desirable.
+ */
+int efi_shim_allow_pxe = 0;
+
+/**
+ * Allow SBAT variable access
+ *
+ * The UEFI shim implements a fairly nicely designed revocation
+ * mechanism designed around the concept of security generations.
+ * Unfortunately nobody in the shim community has thus far added the
+ * relevant metadata to the Linux kernel, with the result that current
+ * versions of shim are incapable of booting current versions of the
+ * Linux kernel.
+ *
+ * Experience shows that there is unfortunately no point in trying to
+ * get a fix for this upstreamed into shim. We therefore default to
+ * working around this undesirable behaviour by patching data read
+ * from the "SbatLevel" variable used to hold SBAT configuration.
+ *
+ * This option may be used to allow shim unpatched access to the
+ * "SbatLevel" variable, in case this behaviour is ever desirable.
+ */
+int efi_shim_allow_sbat = 0;
+
+/** UEFI shim image */
+struct image_tag efi_shim __image_tag = {
+ .name = "SHIM",
+};
+
+/** Original GetMemoryMap() function */
+static EFI_GET_MEMORY_MAP efi_shim_orig_get_memory_map;
+
+/** Original ExitBootServices() function */
+static EFI_EXIT_BOOT_SERVICES efi_shim_orig_exit_boot_services;
+
+/** Original SetVariable() function */
+static EFI_SET_VARIABLE efi_shim_orig_set_variable;
+
+/** Original GetVariable() function */
+static EFI_GET_VARIABLE efi_shim_orig_get_variable;
+
+/** Verify read from SbatLevel variable */
+static int efi_shim_sbatlevel_verify;
+
+/**
+ * Check if variable is SbatLevel
+ *
+ * @v name Variable name
+ * @v guid Variable namespace GUID
+ * @ret is_sbatlevel Variable is SbatLevel
+ */
+static int efi_shim_is_sbatlevel ( const CHAR16 *name, const EFI_GUID *guid ) {
+ static CHAR16 sbatlevel[] = L"SbatLevel";
+ EFI_GUID *shimlock = &efi_shim_lock_protocol_guid;
+
+ return ( ( memcmp ( name, sbatlevel, sizeof ( sbatlevel ) ) == 0 ) &&
+ ( memcmp ( guid, shimlock, sizeof ( *shimlock ) ) == 0 ) );
+}
+
+/**
+ * Unlock UEFI shim
+ *
+ */
+static void efi_shim_unlock ( void ) {
+ EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
+ uint8_t empty[0];
+ union {
+ EFI_SHIM_LOCK_PROTOCOL *lock;
+ void *interface;
+ } u;
+ EFI_STATUS efirc;
+
+ /* Locate shim lock protocol */
+ if ( ( efirc = bs->LocateProtocol ( &efi_shim_lock_protocol_guid,
+ NULL, &u.interface ) ) == 0 ) {
+ u.lock->Verify ( empty, sizeof ( empty ) );
+ DBGC ( &efi_shim, "SHIM unlocked via %p\n", u.lock );
+ }
+}
+
+/**
+ * Wrap GetMemoryMap()
+ *
+ * @v len Memory map size
+ * @v map Memory map
+ * @v key Memory map key
+ * @v desclen Descriptor size
+ * @v descver Descriptor version
+ * @ret efirc EFI status code
+ */
+static EFIAPI EFI_STATUS efi_shim_get_memory_map ( UINTN *len,
+ EFI_MEMORY_DESCRIPTOR *map,
+ UINTN *key, UINTN *desclen,
+ UINT32 *descver ) {
+
+ /* Unlock shim */
+ if ( ! efi_shim_require_loader )
+ efi_shim_unlock();
+
+ /* Hand off to original GetMemoryMap() */
+ return efi_shim_orig_get_memory_map ( len, map, key, desclen,
+ descver );
+}
+
+/**
+ * Wrap ExitBootServices()
+ *
+ * @v handle Image handle
+ * @v key Memory map key
+ * @ret efirc EFI status code
+ */
+static EFIAPI EFI_STATUS efi_shim_exit_boot_services ( EFI_HANDLE handle,
+ UINTN key ) {
+ EFI_RUNTIME_SERVICES *rs = efi_systab->RuntimeServices;
+
+ /* Restore original runtime services functions */
+ rs->SetVariable = efi_shim_orig_set_variable;
+ rs->GetVariable = efi_shim_orig_get_variable;
+
+ /* Hand off to original ExitBootServices() */
+ return efi_shim_orig_exit_boot_services ( handle, key );
+}
+
+/**
+ * Wrap SetVariable()
+ *
+ * @v name Variable name
+ * @v guid Variable namespace GUID
+ * @v attrs Attributes
+ * @v len Buffer size
+ * @v data Data buffer
+ * @ret efirc EFI status code
+ */
+static EFI_STATUS EFIAPI
+efi_shim_set_variable ( CHAR16 *name, EFI_GUID *guid, UINT32 attrs,
+ UINTN len, VOID *data ) {
+ EFI_STATUS efirc;
+
+ /* Call original SetVariable() */
+ efirc = efi_shim_orig_set_variable ( name, guid, attrs, len, data );
+
+ /* Allow verification of SbatLevel variable content */
+ if ( efi_shim_is_sbatlevel ( name, guid ) && ( efirc == 0 ) ) {
+ DBGC ( &efi_shim, "SHIM detected write to %ls:\n", name );
+ DBGC_HDA ( &efi_shim, 0, data, len );
+ efi_shim_sbatlevel_verify = 1;
+ }
+
+ return efirc;
+}
+
+/**
+ * Wrap GetVariable()
+ *
+ * @v name Variable name
+ * @v guid Variable namespace GUID
+ * @v attrs Attributes to fill in
+ * @v len Buffer size
+ * @v data Data buffer
+ * @ret efirc EFI status code
+ */
+static EFI_STATUS EFIAPI
+efi_shim_get_variable ( CHAR16 *name, EFI_GUID *guid, UINT32 *attrs,
+ UINTN *len, VOID *data ) {
+ char *value = data;
+ EFI_STATUS efirc;
+
+ /* Call original GetVariable() */
+ efirc = efi_shim_orig_get_variable ( name, guid, attrs, len, data );
+
+ /* Patch SbatLevel variable if applicable */
+ if ( efi_shim_is_sbatlevel ( name, guid ) && data && ( efirc == 0 ) ) {
+ if ( efi_shim_allow_sbat ) {
+ DBGC ( &efi_shim, "SHIM allowing read from %ls:\n",
+ name );
+ } else if ( efi_shim_sbatlevel_verify ) {
+ DBGC ( &efi_shim, "SHIM allowing one read from %ls:\n",
+ name );
+ efi_shim_sbatlevel_verify = 0;
+ } else {
+ DBGC ( &efi_shim, "SHIM patching read from %ls:\n",
+ name );
+ value[0] = '\0';
+ }
+ DBGC_HDA ( &efi_shim, 0, data, *len );
+ }
+
+ return efirc;
+}
+
+/**
+ * Inhibit use of PXE base code
+ *
+ * @v handle EFI handle
+ * @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_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 );
+ DBGC ( &efi_shim, "SHIM could not open PXE base code: %s\n",
+ strerror ( rc ) );
+ goto err_no_base;
+ }
+
+ /* Stop PXE base code */
+ if ( ( efirc = u.pxe->Stop ( u.pxe ) ) != 0 ) {
+ rc = -EEFI ( efirc );
+ DBGC ( &efi_shim, "SHIM could not stop PXE base code: %s\n",
+ strerror ( rc ) );
+ goto err_stop;
+ }
+
+ /* 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;
+}
+
+/**
+ * Update command line
+ *
+ * @v shim Shim image
+ * @v cmdline Command line to update
+ * @ret rc Return status code
+ */
+static int efi_shim_cmdline ( struct image *shim, wchar_t **cmdline ) {
+ wchar_t *shimcmdline;
+ int len;
+ int rc;
+
+ /* Construct new command line */
+ len = ( shim->cmdline ?
+ efi_asprintf ( &shimcmdline, "%s %s", shim->name,
+ shim->cmdline ) :
+ efi_asprintf ( &shimcmdline, "%s %ls", shim->name,
+ *cmdline ) );
+ if ( len < 0 ) {
+ rc = len;
+ DBGC ( &efi_shim, "SHIM could not construct command line: "
+ "%s\n", strerror ( rc ) );
+ return rc;
+ }
+
+ /* Replace command line */
+ free ( *cmdline );
+ *cmdline = shimcmdline;
+
+ return 0;
+}
+
+/**
+ * Install UEFI shim special handling
+ *
+ * @v shim Shim image
+ * @v handle EFI device handle
+ * @v cmdline Command line to update
+ * @ret rc Return status code
+ */
+int efi_shim_install ( struct image *shim, EFI_HANDLE handle,
+ wchar_t **cmdline ) {
+ EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
+ EFI_RUNTIME_SERVICES *rs = efi_systab->RuntimeServices;
+ int rc;
+
+ /* Stop PXE base code */
+ if ( ( ! efi_shim_allow_pxe ) &&
+ ( ( rc = efi_shim_inhibit_pxe ( handle ) ) != 0 ) ) {
+ return rc;
+ }
+
+ /* Update command line */
+ if ( ( rc = efi_shim_cmdline ( shim, cmdline ) ) != 0 )
+ return rc;
+
+ /* Record original boot and runtime services functions */
+ efi_shim_orig_get_memory_map = bs->GetMemoryMap;
+ efi_shim_orig_exit_boot_services = bs->ExitBootServices;
+ efi_shim_orig_set_variable = rs->SetVariable;
+ efi_shim_orig_get_variable = rs->GetVariable;
+
+ /* Wrap relevant boot and runtime services functions */
+ bs->GetMemoryMap = efi_shim_get_memory_map;
+ bs->ExitBootServices = efi_shim_exit_boot_services;
+ rs->SetVariable = efi_shim_set_variable;
+ rs->GetVariable = efi_shim_get_variable;
+
+ return 0;
+}
+
+/**
+ * Uninstall UEFI shim special handling
+ *
+ */
+void efi_shim_uninstall ( void ) {
+ EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
+ EFI_RUNTIME_SERVICES *rs = efi_systab->RuntimeServices;
+
+ /* Restore original boot and runtime services functions */
+ bs->GetMemoryMap = efi_shim_orig_get_memory_map;
+ bs->ExitBootServices = efi_shim_orig_exit_boot_services;
+ rs->SetVariable = efi_shim_orig_set_variable;
+ rs->GetVariable = efi_shim_orig_get_variable;
+}
diff --git a/src/interface/efi/efi_snp.c b/src/interface/efi/efi_snp.c
index c4f7d4ea..8443be99 100644
--- a/src/interface/efi/efi_snp.c
+++ b/src/interface/efi/efi_snp.c
@@ -1777,9 +1777,10 @@ static struct efi_snp_device * efi_snp_demux ( struct net_device *netdev ) {
* Create SNP device
*
* @v netdev Network device
+ * @v priv Private data
* @ret rc Return status code
*/
-static int efi_snp_probe ( struct net_device *netdev ) {
+static int efi_snp_probe ( struct net_device *netdev, void *priv __unused ) {
EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
struct efi_device *efidev;
struct efi_snp_device *snpdev;
@@ -2017,8 +2018,9 @@ static int efi_snp_probe ( struct net_device *netdev ) {
* Handle SNP device or link state change
*
* @v netdev Network device
+ * @v priv Private data
*/
-static void efi_snp_notify ( struct net_device *netdev ) {
+static void efi_snp_notify ( struct net_device *netdev, void *priv __unused ) {
struct efi_snp_device *snpdev;
/* Locate SNP device */
@@ -2042,8 +2044,9 @@ static void efi_snp_notify ( struct net_device *netdev ) {
* Destroy SNP device
*
* @v netdev Network device
+ * @v priv Private data
*/
-static void efi_snp_remove ( struct net_device *netdev ) {
+static void efi_snp_remove ( struct net_device *netdev, void *priv __unused ) {
EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
struct efi_snp_device *snpdev;
int leak = efi_shutdown_in_progress;
diff --git a/src/interface/efi/efi_strings.c b/src/interface/efi/efi_strings.c
index aa3afc64..765b23ca 100644
--- a/src/interface/efi/efi_strings.c
+++ b/src/interface/efi/efi_strings.c
@@ -25,6 +25,8 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <stddef.h>
#include <stdarg.h>
+#include <stdlib.h>
+#include <errno.h>
#include <ipxe/vsprintf.h>
#include <ipxe/efi/efi_strings.h>
@@ -150,3 +152,45 @@ int efi_ssnprintf ( wchar_t *wbuf, ssize_t swsize, const char *fmt, ... ) {
va_end ( args );
return len;
}
+
+/**
+ * Write a formatted string to newly allocated memory
+ *
+ * @v wstrp Pointer to hold allocated string
+ * @v fmt Format string
+ * @v args Arguments corresponding to the format string
+ * @ret len Length of formatted string (in wide characters)
+ */
+int efi_vasprintf ( wchar_t **wstrp, const char *fmt, va_list args ) {
+ size_t len;
+ va_list args_tmp;
+
+ /* Calculate length needed for string */
+ va_copy ( args_tmp, args );
+ len = ( efi_vsnprintf ( NULL, 0, fmt, args_tmp ) + 1 );
+ va_end ( args_tmp );
+
+ /* Allocate and fill string */
+ *wstrp = malloc ( len * sizeof ( **wstrp ) );
+ if ( ! *wstrp )
+ return -ENOMEM;
+ return efi_vsnprintf ( *wstrp, len, fmt, args );
+}
+
+/**
+ * Write a formatted string to newly allocated memory
+ *
+ * @v wstrp Pointer to hold allocated string
+ * @v fmt Format string
+ * @v ... Arguments corresponding to the format string
+ * @ret len Length of formatted string (in wide characters)
+ */
+int efi_asprintf ( wchar_t **wstrp, const char *fmt, ... ) {
+ va_list args;
+ int len;
+
+ va_start ( args, fmt );
+ len = efi_vasprintf ( wstrp, fmt, args );
+ va_end ( args );
+ return len;
+}
diff --git a/src/interface/efi/efi_veto.c b/src/interface/efi/efi_veto.c
index b616539d..a3b60d65 100644
--- a/src/interface/efi/efi_veto.c
+++ b/src/interface/efi/efi_veto.c
@@ -37,8 +37,8 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
*
*/
-/** A driver veto */
-struct efi_veto {
+/** A driver veto candidate */
+struct efi_veto_candidate {
/** Veto name (for debugging) */
const char *name;
/**
@@ -57,22 +57,38 @@ struct efi_veto {
const char *manufacturer, const CHAR16 *name );
};
+/** A driver veto */
+struct efi_veto {
+ /** Driver binding handle */
+ EFI_HANDLE driver;
+ /** Driving binding protocol */
+ EFI_DRIVER_BINDING_PROTOCOL *binding;
+ /** Image handle */
+ EFI_HANDLE image;
+ /** Loaded image protocol */
+ EFI_LOADED_IMAGE_PROTOCOL *loaded;
+};
+
/**
* Unload an EFI driver
*
- * @v driver Driver binding handle
+ * @v veto Driver veto
* @ret rc Return status code
*/
-static int efi_veto_unload ( EFI_HANDLE driver ) {
+static int efi_veto_unload ( struct efi_veto *veto ) {
EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
+ EFI_HANDLE driver = veto->driver;
+ EFI_HANDLE image = veto->image;
EFI_STATUS efirc;
int rc;
/* Unload the driver */
- if ( ( efirc = bs->UnloadImage ( driver ) ) != 0 ) {
+ if ( ( efirc = bs->UnloadImage ( image ) ) != 0 ) {
rc = -EEFI ( efirc );
- DBGC ( driver, "EFIVETO %s could not unload: %s\n",
- efi_handle_name ( driver ), strerror ( rc ) );
+ DBGC ( driver, "EFIVETO %s could not unload",
+ efi_handle_name ( driver ) );
+ DBGC ( driver, " %s: %s\n", efi_handle_name ( image ),
+ strerror ( rc ) );
return rc;
}
@@ -82,11 +98,12 @@ static int efi_veto_unload ( EFI_HANDLE driver ) {
/**
* Disconnect an EFI driver from all handles
*
- * @v driver Driver binding handle
+ * @v veto Driver veto
* @ret rc Return status code
*/
-static int efi_veto_disconnect ( EFI_HANDLE driver ) {
+static int efi_veto_disconnect ( struct efi_veto *veto ) {
EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
+ EFI_HANDLE driver = veto->driver;
EFI_HANDLE *handles;
EFI_HANDLE handle;
UINTN count;
@@ -131,11 +148,12 @@ static int efi_veto_disconnect ( EFI_HANDLE driver ) {
/**
* Uninstall an EFI driver binding protocol
*
- * @v driver Driver binding handle
+ * @v veto Driver veto
* @ret rc Return status code
*/
-static int efi_veto_uninstall ( EFI_HANDLE driver ) {
+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;
@@ -178,14 +196,16 @@ static int efi_veto_uninstall ( EFI_HANDLE driver ) {
/**
* Close protocol on handle potentially opened by an EFI driver
*
- * @v driver Driver binding handle
+ * @v veto Driver veto
* @v handle Potentially opened handle
* @v protocol Opened protocol
* @ret rc Return status code
*/
-static int efi_veto_close_protocol ( EFI_HANDLE driver, EFI_HANDLE handle,
+static int efi_veto_close_protocol ( struct efi_veto *veto, EFI_HANDLE handle,
EFI_GUID *protocol ) {
EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
+ EFI_HANDLE driver = veto->driver;
+ EFI_HANDLE image = veto->image;
EFI_OPEN_PROTOCOL_INFORMATION_ENTRY *openers;
EFI_OPEN_PROTOCOL_INFORMATION_ENTRY *opener;
EFI_HANDLE controller;
@@ -207,9 +227,11 @@ static int efi_veto_close_protocol ( EFI_HANDLE driver, EFI_HANDLE handle,
/* Close anything opened by this driver */
for ( i = 0 ; i < count ; i++ ) {
- opener = &openers[i];
- if ( opener->AgentHandle != driver )
+ opener = &openers[ count - i - 1 ];
+ if ( ( opener->AgentHandle != driver ) &&
+ ( opener->AgentHandle != image ) ) {
continue;
+ }
controller = opener->ControllerHandle;
DBGC_EFI_OPENER ( driver, handle, protocol, opener );
if ( ( efirc = bs->CloseProtocol ( handle, protocol, driver,
@@ -235,13 +257,15 @@ static int efi_veto_close_protocol ( EFI_HANDLE driver, EFI_HANDLE handle,
/**
* Close handle potentially opened by an EFI driver
*
- * @v driver Driver binding handle
+ * @v veto Driver veto
* @v handle Potentially opened handle
* @ret rc Return status code
*/
-static int efi_veto_close_handle ( EFI_HANDLE driver, EFI_HANDLE handle ) {
+static int efi_veto_close_handle ( struct efi_veto *veto, EFI_HANDLE handle ) {
EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
+ EFI_HANDLE driver = veto->driver;
EFI_GUID **protocols;
+ EFI_GUID *protocol;
UINTN count;
unsigned int i;
EFI_STATUS efirc;
@@ -260,8 +284,9 @@ static int efi_veto_close_handle ( EFI_HANDLE driver, EFI_HANDLE handle ) {
/* Close each protocol */
for ( i = 0 ; i < count ; i++ ) {
- if ( ( rc = efi_veto_close_protocol ( driver, handle,
- protocols[i] ) ) != 0 )
+ protocol = protocols[ count - i - 1];
+ if ( ( rc = efi_veto_close_protocol ( veto, handle,
+ protocol ) ) != 0 )
goto err_close;
}
@@ -277,12 +302,14 @@ static int efi_veto_close_handle ( EFI_HANDLE driver, EFI_HANDLE handle ) {
/**
* Close all remaining handles opened by an EFI driver
*
- * @v driver Driver binding handle
+ * @v veto Driver veto
* @ret rc Return status code
*/
-static int efi_veto_close ( EFI_HANDLE driver ) {
+static int efi_veto_close ( struct efi_veto *veto ) {
EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
+ EFI_HANDLE driver = veto->driver;
EFI_HANDLE *handles;
+ EFI_HANDLE handle;
UINTN count;
unsigned int i;
EFI_STATUS efirc;
@@ -299,8 +326,8 @@ static int efi_veto_close ( EFI_HANDLE driver ) {
/* Close each handle */
for ( i = 0 ; i < count ; i++ ) {
- if ( ( rc = efi_veto_close_handle ( driver,
- handles[i] ) ) != 0 )
+ handle = handles[ count - i - 1 ];
+ if ( ( rc = efi_veto_close_handle ( veto, handle ) ) != 0 )
goto err_close;
}
@@ -318,22 +345,23 @@ static int efi_veto_close ( EFI_HANDLE driver ) {
/**
* Terminate an EFI driver with extreme prejudice
*
- * @v driver Driver binding handle
+ * @v veto Driver veto
* @ret rc Return status code
*/
-static int efi_veto_destroy ( EFI_HANDLE driver ) {
+static int efi_veto_destroy ( struct efi_veto *veto ) {
+ EFI_HANDLE driver = veto->driver;
int rc;
/* Disconnect driver from all handles */
- if ( ( rc = efi_veto_disconnect ( driver ) ) != 0 )
+ if ( ( rc = efi_veto_disconnect ( veto ) ) != 0 )
return rc;
/* Uninstall driver binding protocol */
- if ( ( rc = efi_veto_uninstall ( driver ) ) != 0 )
+ if ( ( rc = efi_veto_uninstall ( veto ) ) != 0 )
return rc;
/* Close any remaining opened handles */
- if ( ( rc = efi_veto_close ( driver ) ) != 0 )
+ if ( ( rc = efi_veto_close ( veto ) ) != 0 )
return rc;
DBGC ( driver, "EFIVETO %s forcibly removed\n",
@@ -344,18 +372,18 @@ static int efi_veto_destroy ( EFI_HANDLE driver ) {
/**
* Veto an EFI driver
*
- * @v driver Driver binding handle
+ * @v veto Driver veto
* @ret rc Return status code
*/
-static int efi_veto_driver ( EFI_HANDLE driver ) {
+static int efi_veto_driver ( struct efi_veto *veto ) {
int rc;
/* Try gracefully unloading the driver */
- if ( ( rc = efi_veto_unload ( driver ) ) == 0 )
+ if ( ( rc = efi_veto_unload ( veto ) ) == 0 )
return 0;
/* If that fails, use a hammer */
- if ( ( rc = efi_veto_destroy ( driver ) ) == 0 )
+ if ( ( rc = efi_veto_destroy ( veto ) ) == 0 )
return 0;
return rc;
@@ -435,8 +463,39 @@ efi_veto_hp_xhci ( EFI_DRIVER_BINDING_PROTOCOL *binding __unused,
return 0;
}
+/**
+ * Veto VMware UefiPxeBcDxe driver
+ *
+ * @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
+ */
+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.";
+
+ /* Check manufacturer and driver name */
+ if ( ! manufacturer )
+ return 0;
+ if ( ! name )
+ return 0;
+ if ( strcmp ( manufacturer, vmware ) != 0 )
+ return 0;
+ if ( memcmp ( name, uefipxebc, sizeof ( uefipxebc ) ) != 0 )
+ return 0;
+
+ return 1;
+}
+
/** Driver vetoes */
-static struct efi_veto efi_vetoes[] = {
+static struct efi_veto_candidate efi_vetoes[] = {
{
.name = "Ip4Config",
.veto = efi_veto_ip4config,
@@ -445,6 +504,10 @@ static struct efi_veto efi_vetoes[] = {
.name = "HP Xhci",
.veto = efi_veto_hp_xhci,
},
+ {
+ .name = "VMware UefiPxeBc",
+ .veto = efi_veto_vmware_uefipxebc,
+ },
};
/**
@@ -452,11 +515,11 @@ static struct efi_veto efi_vetoes[] = {
*
* @v driver Driver binding handle
* @v manufacturer Manufacturer name, if present
- * @ret veto Driver veto, or NULL
+ * @ret veto Driver veto to fill in
* @ret rc Return status code
*/
static int efi_veto_find ( EFI_HANDLE driver, const char *manufacturer,
- struct efi_veto **veto ) {
+ struct efi_veto *veto ) {
EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
union {
EFI_DRIVER_BINDING_PROTOCOL *binding;
@@ -480,7 +543,7 @@ static int efi_veto_find ( EFI_HANDLE driver, const char *manufacturer,
efi_handle_name ( driver ) );
/* Mark as not vetoed */
- *veto = NULL;
+ memset ( veto, 0, sizeof ( *veto ) );
/* Open driver binding protocol */
if ( ( efirc = bs->OpenProtocol (
@@ -532,7 +595,13 @@ static int efi_veto_find ( EFI_HANDLE driver, const char *manufacturer,
sizeof ( efi_vetoes[0] ) ) ; i++ ) {
if ( efi_vetoes[i].veto ( binding.binding, loaded.loaded,
wtf.wtf, manufacturer, name ) ) {
- *veto = &efi_vetoes[i];
+ DBGC ( driver, "EFIVETO %s is vetoed (%s)\n",
+ efi_handle_name ( driver ),
+ efi_vetoes[i].name );
+ veto->driver = driver;
+ veto->binding = binding.binding;
+ veto->image = image;
+ veto->loaded = loaded.loaded;
break;
}
}
@@ -560,10 +629,10 @@ static int efi_veto_find ( EFI_HANDLE driver, const char *manufacturer,
*/
void efi_veto ( void ) {
EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
- struct efi_veto *veto;
+ struct efi_veto veto;
EFI_HANDLE *drivers;
EFI_HANDLE driver;
- UINTN num_drivers;
+ UINTN count;
unsigned int i;
char *manufacturer;
EFI_STATUS efirc;
@@ -572,7 +641,7 @@ void efi_veto ( void ) {
/* Locate all driver binding protocol handles */
if ( ( efirc = bs->LocateHandleBuffer (
ByProtocol, &efi_driver_binding_protocol_guid,
- NULL, &num_drivers, &drivers ) ) != 0 ) {
+ NULL, &count, &drivers ) ) != 0 ) {
rc = -EEFI ( efirc );
DBGC ( &efi_vetoes, "EFIVETO could not list all drivers: "
"%s\n", strerror ( rc ) );
@@ -582,10 +651,11 @@ void efi_veto ( void ) {
/* Get manufacturer name */
fetch_string_setting_copy ( NULL, &manufacturer_setting,
&manufacturer );
+ DBGC ( &efi_vetoes, "EFIVETO manufacturer is \"%s\"\n", manufacturer );
/* Unload any vetoed drivers */
- for ( i = 0 ; i < num_drivers ; i++ ) {
- driver = drivers[i];
+ for ( i = 0 ; i < count ; i++ ) {
+ driver = drivers[ count - i - 1 ];
if ( ( rc = efi_veto_find ( driver, manufacturer,
&veto ) ) != 0 ) {
DBGC ( driver, "EFIVETO %s could not determine "
@@ -593,11 +663,9 @@ void efi_veto ( void ) {
efi_handle_name ( driver ), strerror ( rc ) );
continue;
}
- if ( ! veto )
+ if ( ! veto.driver )
continue;
- DBGC ( driver, "EFIVETO %s is vetoed (%s)\n",
- efi_handle_name ( driver ), veto->name );
- if ( ( rc = efi_veto_driver ( driver ) ) != 0 ) {
+ if ( ( rc = efi_veto_driver ( &veto ) ) != 0 ) {
DBGC ( driver, "EFIVETO %s could not veto: %s\n",
efi_handle_name ( driver ), strerror ( rc ) );
}