mirror of https://github.com/ipxe/ipxe.git
[efi] Allow driver to be unloaded
Signed-off-by: Michael Brown <mcb30@ipxe.org>pull/17/head
parent
9681170fbe
commit
8de6b973c4
|
@ -45,5 +45,6 @@ extern EFI_DEVICE_PATH_PROTOCOL *
|
|||
efi_devpath_end ( EFI_DEVICE_PATH_PROTOCOL *path );
|
||||
|
||||
extern int efi_driver_install ( struct efi_driver *efidrv );
|
||||
extern void efi_driver_uninstall ( struct efi_driver *efidrv );
|
||||
|
||||
#endif /* _IPXE_EFI_DRIVER_H */
|
||||
|
|
|
@ -387,7 +387,7 @@ static struct efi_driver efi_bofm_driver =
|
|||
* Install EFI BOFM driver
|
||||
*
|
||||
*/
|
||||
static void efi_bofm_driver_init ( void ) {
|
||||
static void efi_bofm_driver_startup ( void ) {
|
||||
struct efi_driver *efidrv = &efi_bofm_driver;
|
||||
int rc;
|
||||
|
||||
|
@ -401,7 +401,19 @@ static void efi_bofm_driver_init ( void ) {
|
|||
DBGC ( efidrv, "EFIBOFM driver installed\n" );
|
||||
}
|
||||
|
||||
/**
|
||||
* Shut down EFI BOFM driver
|
||||
*
|
||||
* @v booting System is shutting down for OS boot
|
||||
*/
|
||||
static void efi_bofm_driver_shutdown ( int booting __unused ) {
|
||||
struct efi_driver *efidrv = &efi_bofm_driver;
|
||||
|
||||
efi_driver_uninstall ( efidrv );
|
||||
}
|
||||
|
||||
/** EFI BOFM startup function */
|
||||
struct startup_fn startup_bofm __startup_fn ( STARTUP_EARLY ) = {
|
||||
.startup = efi_bofm_driver_init,
|
||||
.startup = efi_bofm_driver_startup,
|
||||
.shutdown = efi_bofm_driver_shutdown,
|
||||
};
|
||||
|
|
|
@ -122,7 +122,7 @@ efi_driver_get_controller_name ( EFI_COMPONENT_NAME2_PROTOCOL *wtf __unused,
|
|||
* Install EFI driver
|
||||
*
|
||||
* @v efidrv EFI driver
|
||||
* @ret efirc EFI status code
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
int efi_driver_install ( struct efi_driver *efidrv ) {
|
||||
EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
|
||||
|
@ -143,7 +143,9 @@ int efi_driver_install ( struct efi_driver *efidrv ) {
|
|||
efi_snprintf ( efidrv->wname,
|
||||
( sizeof ( efidrv->wname ) /
|
||||
sizeof ( efidrv->wname[0] ) ),
|
||||
PRODUCT_SHORT_NAME " - %s", efidrv->name );
|
||||
PRODUCT_SHORT_NAME "%s%s",
|
||||
( efidrv->name ? " - " : "" ),
|
||||
( efidrv->name ? efidrv->name : "" ) );
|
||||
|
||||
/* Install driver */
|
||||
if ( ( efirc = bs->InstallMultipleProtocolInterfaces (
|
||||
|
@ -160,3 +162,43 @@ int efi_driver_install ( struct efi_driver *efidrv ) {
|
|||
DBGC ( efidrv, "EFIDRV %s installed\n", efidrv->name );
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Uninstall EFI driver
|
||||
*
|
||||
* @v efidrv EFI driver
|
||||
*/
|
||||
void efi_driver_uninstall ( struct efi_driver *efidrv ) {
|
||||
EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
|
||||
EFI_HANDLE *handles;
|
||||
UINTN num_handles;
|
||||
EFI_STATUS efirc;
|
||||
UINTN i;
|
||||
int rc;
|
||||
|
||||
/* Disconnect the driver from its devices */
|
||||
if ( ( efirc = bs->LocateHandleBuffer ( AllHandles, NULL, NULL,
|
||||
&num_handles,
|
||||
&handles ) ) != 0 ) {
|
||||
rc = -EEFI ( efirc );
|
||||
DBGC ( efidrv, "EFIDRV %s could not list handles: %s\n",
|
||||
efidrv->name, strerror ( rc ) );
|
||||
/* No way to disconnect driver; leave it loaded */
|
||||
return;
|
||||
}
|
||||
DBGC ( efidrv, "EFIDRV %s disconnecting devices\n", efidrv->name );
|
||||
for ( i = 0 ; i < num_handles ; i++ ) {
|
||||
bs->DisconnectController ( handles[i],
|
||||
efidrv->driver.DriverBindingHandle,
|
||||
NULL );
|
||||
}
|
||||
bs->FreePool ( handles );
|
||||
|
||||
/* Uninstall the driver */
|
||||
bs->UninstallMultipleProtocolInterfaces (
|
||||
efidrv->driver.DriverBindingHandle,
|
||||
&efi_driver_binding_protocol_guid, &efidrv->driver,
|
||||
&efi_component_name2_protocol_guid, &efidrv->wtf,
|
||||
NULL );
|
||||
DBGC ( efidrv, "EFIDRV %s uninstalled\n", efidrv->name );
|
||||
}
|
||||
|
|
|
@ -22,6 +22,7 @@ FILE_LICENCE ( GPL2_OR_LATER );
|
|||
#include <string.h>
|
||||
#include <errno.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>
|
||||
|
@ -50,6 +51,64 @@ static EFI_GUID efi_loaded_image_device_path_protocol_guid
|
|||
/** Event used to signal shutdown */
|
||||
static EFI_EVENT efi_shutdown_event;
|
||||
|
||||
/* Forward declarations */
|
||||
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.
|
||||
*
|
||||
|
@ -189,5 +248,43 @@ EFI_STATUS efi_init ( EFI_HANDLE image_handle,
|
|||
return efirc;
|
||||
}
|
||||
|
||||
/* 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 image unload method */
|
||||
efi_loaded_image->Unload = efi_unload;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Shut down EFI environment
|
||||
*
|
||||
* @v image_handle Image handle
|
||||
*/
|
||||
static EFI_STATUS EFIAPI efi_unload ( EFI_HANDLE image_handle __unused ) {
|
||||
EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
|
||||
EFI_SYSTEM_TABLE *systab = efi_systab;
|
||||
|
||||
DBGC ( systab, "EFI image unloading\n" );
|
||||
|
||||
/* Shut down */
|
||||
shutdown_exit();
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
|
|
@ -519,6 +519,9 @@ static void efipci_driver_shutdown ( int booting __unused ) {
|
|||
struct efi_pci_device *efipci;
|
||||
struct efi_pci_device *tmp;
|
||||
|
||||
/* Uninstall driver */
|
||||
efi_driver_uninstall ( efidrv );
|
||||
|
||||
/* Shut down any remaining devices */
|
||||
list_for_each_entry_safe ( efipci, tmp, &efi_pci_devices, list ) {
|
||||
DBGC ( efipci, "EFIPCI " PCI_FMT " still active at shutdown; "
|
||||
|
|
Loading…
Reference in New Issue