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 */
* 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;
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,
};
* 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;
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 (
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 );
+}
#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>
/** 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.
*
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;
}
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; "