From c7c3d839fc9120aee28de9aabe452dc85ad91502 Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Wed, 13 Mar 2013 22:42:26 +0000 Subject: [PATCH] [efi] Add our own EFI_LOAD_FILE_PROTOCOL implementation When iPXE is used as a UEFI driver, the UEFI PXE base code currently provides the TCP/IP stack, network protocols, and user interface. This represents a substantial downgrade from the standard BIOS iPXE user experience. Fix by installing our own EFI_LOAD_FILE_PROTOCOL implementation which initiates the standard iPXE boot procedure. This upgrades the UEFI iPXE user experience to match the standard BIOS iPXE user experience. Signed-off-by: Michael Brown --- src/include/ipxe/efi/efi_snp.h | 3 ++ src/interface/efi/efi_snp.c | 57 +++++++++++++++++++++++++++++++++- 2 files changed, 59 insertions(+), 1 deletion(-) diff --git a/src/include/ipxe/efi/efi_snp.h b/src/include/ipxe/efi/efi_snp.h index 074d1b27d..379164597 100644 --- a/src/include/ipxe/efi/efi_snp.h +++ b/src/include/ipxe/efi/efi_snp.h @@ -16,6 +16,7 @@ #include #include #include +#include /** An SNP device */ struct efi_snp_device { @@ -49,6 +50,8 @@ struct efi_snp_device { EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL nii; /** Component name protocol */ EFI_COMPONENT_NAME2_PROTOCOL name2; + /** Load file protocol handle */ + EFI_LOAD_FILE_PROTOCOL load_file; /** HII configuration access protocol */ EFI_HII_CONFIG_ACCESS_PROTOCOL hii; /** HII package list */ diff --git a/src/interface/efi/efi_snp.c b/src/interface/efi/efi_snp.c index 48a6f397e..95e39b7d9 100644 --- a/src/interface/efi/efi_snp.c +++ b/src/interface/efi/efi_snp.c @@ -34,6 +34,7 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include #include #include +#include /** EFI simple network protocol GUID */ static EFI_GUID efi_simple_network_protocol_guid @@ -57,10 +58,14 @@ static EFI_GUID efi_nii31_protocol_guid = { { 0xBC, 0x81, 0x76, 0x7F, 0x1F, 0x97, 0x7A, 0x89 } }; -/** EFI component name protocol */ +/** EFI component name protocol GUID */ static EFI_GUID efi_component_name2_protocol_guid = EFI_COMPONENT_NAME2_PROTOCOL_GUID; +/** EFI load file protocol GUID */ +static EFI_GUID efi_load_file_protocol_guid + = EFI_LOAD_FILE_PROTOCOL_GUID; + /** List of SNP devices */ static LIST_HEAD ( efi_snp_devices ); @@ -754,6 +759,49 @@ efi_snp_get_controller_name ( EFI_COMPONENT_NAME2_PROTOCOL *name2, return 0; } +/****************************************************************************** + * + * Load file protocol + * + ****************************************************************************** + */ + +/** + * Load file + * + * @v loadfile Load file protocol + * @v path File path + * @v booting Loading as part of a boot attempt + * @ret efirc EFI status code + */ +static EFI_STATUS EFIAPI +efi_snp_load_file ( EFI_LOAD_FILE_PROTOCOL *load_file, + EFI_DEVICE_PATH_PROTOCOL *path __unused, + BOOLEAN booting, UINTN *len __unused, + VOID *data __unused ) { + struct efi_snp_device *snpdev = + container_of ( load_file, struct efi_snp_device, load_file ); + struct net_device *netdev = snpdev->netdev; + + /* Fail unless this is a boot attempt */ + if ( ! booting ) { + DBGC ( snpdev, "SNPDEV %p cannot load non-boot file\n", + snpdev ); + return EFI_UNSUPPORTED; + } + + /* Boot from network device */ + ipxe ( netdev ); + + /* Assume boot process was aborted */ + return EFI_ABORTED; +} + +/** Load file protocol */ +static EFI_LOAD_FILE_PROTOCOL efi_snp_load_file_protocol = { + .LoadFile = efi_snp_load_file, +}; + /****************************************************************************** * * iPXE network driver @@ -861,6 +909,10 @@ static int efi_snp_probe ( struct net_device *netdev ) { snpdev->name2.GetControllerName = efi_snp_get_controller_name; snpdev->name2.SupportedLanguages = "en"; + /* Populate the load file protocol structure */ + memcpy ( &snpdev->load_file, &efi_snp_load_file_protocol, + sizeof ( snpdev->load_file ) ); + /* Populate the device name */ efi_snprintf ( snpdev->name, ( sizeof ( snpdev->name ) / sizeof ( snpdev->name[0] ) ), @@ -890,6 +942,7 @@ static int efi_snp_probe ( struct net_device *netdev ) { &efi_nii_protocol_guid, &snpdev->nii, &efi_nii31_protocol_guid, &snpdev->nii, &efi_component_name2_protocol_guid, &snpdev->name2, + &efi_load_file_protocol_guid, &snpdev->load_file, NULL ) ) != 0 ) { DBGC ( snpdev, "SNPDEV %p could not install protocols: " "%s\n", snpdev, efi_strerror ( efirc ) ); @@ -931,6 +984,7 @@ static int efi_snp_probe ( struct net_device *netdev ) { &efi_nii_protocol_guid, &snpdev->nii, &efi_nii31_protocol_guid, &snpdev->nii, &efi_component_name2_protocol_guid, &snpdev->name2, + &efi_load_file_protocol_guid, &snpdev->load_file, NULL ); err_install_protocol_interface: bs->CloseEvent ( snpdev->snp.WaitForPacket ); @@ -992,6 +1046,7 @@ static void efi_snp_remove ( struct net_device *netdev ) { &efi_nii_protocol_guid, &snpdev->nii, &efi_nii31_protocol_guid, &snpdev->nii, &efi_component_name2_protocol_guid, &snpdev->name2, + &efi_load_file_protocol_guid, &snpdev->load_file, NULL ); bs->CloseEvent ( snpdev->snp.WaitForPacket ); netdev_put ( snpdev->netdev );