diff --git a/src/image/efi_image.c b/src/image/efi_image.c index 0575496c..5bcc85f0 100644 --- a/src/image/efi_image.c +++ b/src/image/efi_image.c @@ -19,13 +19,19 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include +#include #include #include #include #include +#include FEATURE ( FEATURE_IMAGE, "EFI", DHCP_EB_FEATURE_EFI, 1 ); +/** EFI loaded image protocol GUID */ +static EFI_GUID efi_loaded_image_protocol_guid + = EFI_LOADED_IMAGE_PROTOCOL_GUID; + /** * Execute EFI image * @@ -34,7 +40,10 @@ FEATURE ( FEATURE_IMAGE, "EFI", DHCP_EB_FEATURE_EFI, 1 ); */ static int efi_image_exec ( struct image *image ) { EFI_BOOT_SERVICES *bs = efi_systab->BootServices; + EFI_LOADED_IMAGE_PROTOCOL *loaded_image = NULL; + void *loaded_image_void; EFI_HANDLE handle; + EFI_HANDLE device_handle = NULL; UINTN exit_data_size; CHAR16 *exit_data; EFI_STATUS efirc; @@ -50,6 +59,19 @@ static int efi_image_exec ( struct image *image ) { return -ENOEXEC; } + /* Get the loaded image protocol for the newly loaded image */ + efirc = bs->OpenProtocol ( handle, &efi_loaded_image_protocol_guid, + &loaded_image_void, efi_image_handle, NULL, + EFI_OPEN_PROTOCOL_GET_PROTOCOL ); + if ( efirc ) { + /* Should never happen */ + rc = EFIRC_TO_RC ( efirc ); + } + loaded_image = loaded_image_void; + + /* Pass a GPXE download protocol to the image */ + rc = efi_download_install ( &device_handle ); + /* Start the image */ if ( ( efirc = bs->StartImage ( handle, &exit_data_size, &exit_data ) ) != 0 ) { @@ -57,6 +79,9 @@ static int efi_image_exec ( struct image *image ) { image, efi_strerror ( efirc ) ); } rc = EFIRC_TO_RC ( efirc ); + if ( device_handle ) { + efi_download_uninstall ( device_handle ); + } /* Unload the image. We can't leave it loaded, because we * have no "unload" operation. diff --git a/src/include/ipxe/efi/efi.h b/src/include/ipxe/efi/efi.h index 8a216b53..034c0c4f 100644 --- a/src/include/ipxe/efi/efi.h +++ b/src/include/ipxe/efi/efi.h @@ -142,5 +142,8 @@ extern EFI_SYSTEM_TABLE *efi_systab; extern const char * efi_strerror ( EFI_STATUS efirc ); extern EFI_STATUS efi_init ( EFI_HANDLE image_handle, EFI_SYSTEM_TABLE *systab ); +extern int efi_download_install ( EFI_HANDLE *device_handle ); +extern void efi_download_uninstall ( EFI_HANDLE device_handle ); + #endif /* _IPXE_EFI_H */