aboutsummaryrefslogtreecommitdiff
path: root/src/interface/efi/efi_init.c
diff options
context:
space:
mode:
authorMichael Brown <mcb30@ipxe.org>2014-06-25 14:47:35 +0100
committerMichael Brown <mcb30@ipxe.org>2014-06-25 14:47:35 +0100
commit0e3ab6064e9f9eec28712c3b2c1e082672e73461 (patch)
tree244639d414c47633e9f761c568ff5b4559a4b7a4 /src/interface/efi/efi_init.c
parentf2c116ff7d8fb9e52c9344c285012f41ee6636f1 (diff)
downloadipxe-0e3ab6064e9f9eec28712c3b2c1e082672e73461.zip
ipxe-0e3ab6064e9f9eec28712c3b2c1e082672e73461.tar.gz
ipxe-0e3ab6064e9f9eec28712c3b2c1e082672e73461.tar.bz2
[efi] Restructure EFI driver model
Provide a single instance of EFI_DRIVER_BINDING_PROTOCOL (attached to our image handle); this matches the expectations scattered throughout the EFI specification. Open the underlying hardware device using EFI_OPEN_PROTOCOL_BY_DRIVER and EFI_OPEN_PROTOCOL_EXCLUSIVE, to prevent other drivers from attaching to the same device. Do not automatically connect to devices when being loaded as a driver; leave this task to the platform firmware (or to the user, if loading directly from the EFI shell). When running as an application, forcibly disconnect any existing drivers from devices that we want to control, and reconnect them on exit. Provide a meaningful driver version number (based on the build timestamp), to allow platform firmware to automatically load newer versions of iPXE drivers if multiple drivers are present. Include device paths within debug messages where possible, to aid in debugging. Signed-off-by: Michael Brown <mcb30@ipxe.org>
Diffstat (limited to 'src/interface/efi/efi_init.c')
-rw-r--r--src/interface/efi/efi_init.c122
1 files changed, 42 insertions, 80 deletions
diff --git a/src/interface/efi/efi_init.c b/src/interface/efi/efi_init.c
index 5eb1013..4204b79 100644
--- a/src/interface/efi/efi_init.c
+++ b/src/interface/efi/efi_init.c
@@ -21,12 +21,10 @@ FILE_LICENCE ( GPL2_OR_LATER );
#include <string.h>
#include <errno.h>
+#include <ipxe/init.h>
#include <ipxe/efi/efi.h>
#include <ipxe/efi/efi_driver.h>
#include <ipxe/efi/Protocol/LoadedImage.h>
-#include <ipxe/efi/Protocol/DevicePath.h>
-#include <ipxe/uuid.h>
-#include <ipxe/init.h>
/** Image handle passed to entry point */
EFI_HANDLE efi_image_handle;
@@ -48,61 +46,6 @@ static EFI_EVENT efi_shutdown_event;
static EFI_STATUS EFIAPI efi_unload ( EFI_HANDLE image_handle );
/**
- * Check to see if driver supports a device
- *
- * @v driver EFI driver
- * @v device EFI device
- * @v child Path to child device, if any
- * @ret efirc EFI status code
- */
-static EFI_STATUS EFIAPI
-efi_image_supported ( EFI_DRIVER_BINDING_PROTOCOL *driver __unused,
- EFI_HANDLE device __unused,
- EFI_DEVICE_PATH_PROTOCOL *child __unused ) {
-
- return EFI_UNSUPPORTED;
-}
-
-/**
- * Attach driver to device
- *
- * @v driver EFI driver
- * @v device EFI device
- * @v child Path to child device, if any
- * @ret efirc EFI status code
- */
-static EFI_STATUS EFIAPI
-efi_image_start ( EFI_DRIVER_BINDING_PROTOCOL *driver __unused,
- EFI_HANDLE device __unused,
- EFI_DEVICE_PATH_PROTOCOL *child __unused ) {
-
- return EFI_UNSUPPORTED;
-}
-
-/**
- * Detach driver from device
- *
- * @v driver EFI driver
- * @v device EFI device
- * @v pci PCI device
- * @v num_children Number of child devices
- * @v children List of child devices
- * @ret efirc EFI status code
- */
-static EFI_STATUS EFIAPI
-efi_image_stop ( EFI_DRIVER_BINDING_PROTOCOL *driver __unused,
- EFI_HANDLE device __unused, UINTN num_children __unused,
- EFI_HANDLE *children __unused ) {
-
- return EFI_UNSUPPORTED;
-}
-
-/** EFI loaded image driver */
-static struct efi_driver efi_image_driver =
- EFI_DRIVER_INIT ( NULL, efi_image_supported, efi_image_start,
- efi_image_stop );
-
-/**
* Shut down in preparation for booting an OS.
*
* This hook gets called at ExitBootServices time in order to make
@@ -153,18 +96,24 @@ EFI_STATUS efi_init ( EFI_HANDLE image_handle,
efi_systab = systab;
/* Sanity checks */
- if ( ! systab )
- return EFI_NOT_AVAILABLE_YET;
- if ( ! systab->ConOut )
- return EFI_NOT_AVAILABLE_YET;
+ if ( ! systab ) {
+ efirc = EFI_NOT_AVAILABLE_YET;
+ goto err_sanity;
+ }
+ if ( ! systab->ConOut ) {
+ efirc = EFI_NOT_AVAILABLE_YET;
+ goto err_sanity;
+ }
if ( ! systab->BootServices ) {
DBGC ( systab, "EFI provided no BootServices entry point\n" );
- return EFI_NOT_AVAILABLE_YET;
+ efirc = EFI_NOT_AVAILABLE_YET;
+ goto err_sanity;
}
if ( ! systab->RuntimeServices ) {
DBGC ( systab, "EFI provided no RuntimeServices entry "
"point\n" );
- return EFI_NOT_AVAILABLE_YET;
+ efirc = EFI_NOT_AVAILABLE_YET;
+ goto err_sanity;
}
DBGC ( systab, "EFI handle %p systab %p\n", image_handle, systab );
bs = systab->BootServices;
@@ -181,7 +130,7 @@ EFI_STATUS efi_init ( EFI_HANDLE image_handle,
efi_guid_ntoa ( &prot->guid ) );
/* Fail if protocol is required */
if ( prot->required )
- return efirc;
+ goto err_missing_protocol;
}
}
@@ -193,8 +142,10 @@ EFI_STATUS efi_init ( EFI_HANDLE image_handle,
} else {
DBGC ( systab, "EFI does not provide configuration "
"table %s\n", efi_guid_ntoa ( &tab->guid ) );
- if ( tab->required )
- return EFI_NOT_AVAILABLE_YET;
+ if ( tab->required ) {
+ efirc = EFI_NOT_AVAILABLE_YET;
+ goto err_missing_table;
+ }
}
}
@@ -206,7 +157,7 @@ EFI_STATUS efi_init ( EFI_HANDLE image_handle,
rc = -EEFI ( efirc );
DBGC ( systab, "EFI could not get loaded image protocol: %s",
strerror ( rc ) );
- return efirc;
+ goto err_no_loaded_image;
}
efi_loaded_image = loaded_image;
DBGC ( systab, "EFI image base address %p\n",
@@ -223,23 +174,31 @@ EFI_STATUS efi_init ( EFI_HANDLE image_handle,
rc = -EEFI ( efirc );
DBGC ( systab, "EFI could not create ExitBootServices event: "
"%s\n", strerror ( rc ) );
- return efirc;
+ goto err_create_event;
}
- /* Install an EFI driver on the image handle, to allow the
- * driver to be subsequently unloaded.
- */
- efi_image_driver.driver.DriverBindingHandle = image_handle;
- if ( ( rc = efi_driver_install ( &efi_image_driver ) ) != 0 ) {
- DBGC ( systab, "EFI could not install loaded image driver: "
- "%s\n", strerror ( rc ) );
- return EFIRC ( rc );
+ /* Install driver binding protocol */
+ if ( ( rc = efi_driver_install() ) != 0 ) {
+ DBGC ( systab, "EFI could not install driver: %s\n",
+ strerror ( rc ) );
+ efirc = EFIRC ( rc );
+ goto err_driver_install;
}
/* Install image unload method */
efi_loaded_image->Unload = efi_unload;
return 0;
+
+ efi_driver_uninstall();
+ err_driver_install:
+ bs->CloseEvent ( efi_shutdown_event );
+ err_create_event:
+ err_no_loaded_image:
+ err_missing_table:
+ err_missing_protocol:
+ err_sanity:
+ return efirc;
}
/**
@@ -256,12 +215,15 @@ static EFI_STATUS EFIAPI efi_unload ( EFI_HANDLE image_handle __unused ) {
/* Shut down */
shutdown_exit();
+ /* Disconnect any remaining devices */
+ efi_driver_disconnect_all();
+
+ /* Uninstall driver binding protocol */
+ efi_driver_uninstall();
+
/* Uninstall exit boot services event */
bs->CloseEvent ( efi_shutdown_event );
- /* Uninstall loaded image driver */
- efi_driver_uninstall ( &efi_image_driver );
-
DBGC ( systab, "EFI image unloaded\n" );
return 0;