#include <stdlib.h>
#include <errno.h>
+#include <ipxe/device.h>
#include <ipxe/efi/efi.h>
+#include <ipxe/efi/efi_driver.h>
/**
* EFI entry point
err_main:
efi_loaded_image->Unload ( image_handle );
+ efi_driver_reconnect_all();
err_init:
return efirc;
}
+
+/**
+ * Probe EFI root bus
+ *
+ * @v rootdev EFI root device
+ */
+static int efi_probe ( struct root_device *rootdev __unused ) {
+
+ return efi_driver_connect_all();
+}
+
+/**
+ * Remove EFI root bus
+ *
+ * @v rootdev EFI root device
+ */
+static void efi_remove ( struct root_device *rootdev __unused ) {
+
+ efi_driver_disconnect_all();
+}
+
+/** EFI root device driver */
+static struct root_driver efi_root_driver = {
+ .probe = efi_probe,
+ .remove = efi_remove,
+};
+
+/** EFI root device */
+struct root_device efi_root_device __root_device = {
+ .dev = { .name = "EFI" },
+ .driver = &efi_root_driver,
+};
FILE_LICENCE ( GPL2_OR_LATER );
+#include <ipxe/tables.h>
#include <ipxe/efi/efi.h>
-#include <ipxe/efi/Protocol/DriverBinding.h>
-#include <ipxe/efi/Protocol/ComponentName2.h>
#include <ipxe/efi/Protocol/DevicePath.h>
/** An EFI driver */
struct efi_driver {
/** Name */
const char *name;
- /** EFI name */
- CHAR16 wname[32];
- /** EFI driver binding protocol */
- EFI_DRIVER_BINDING_PROTOCOL driver;
- /** EFI component name protocol */
- EFI_COMPONENT_NAME2_PROTOCOL wtf;
+ /**
+ * Check if driver supports device
+ *
+ * @v device Device
+ * @ret rc Return status code
+ */
+ int ( * supported ) ( EFI_HANDLE device );
+ /**
+ * Attach driver to device
+ *
+ * @v device Device
+ * @ret rc Return status code
+ */
+ int ( * start ) ( EFI_HANDLE device );
+ /**
+ * Detach driver from device
+ *
+ * @v device Device
+ */
+ void ( * stop ) ( EFI_HANDLE device );
};
-/** Initialise an EFI driver
- *
- * @v name Driver name
- * @v supported Device supported method
- * @v start Device start method
- * @v stop Device stop method
- */
-#define EFI_DRIVER_INIT( _name, _supported, _start, _stop ) { \
- .name = _name, \
- .driver = { \
- .Supported = _supported, \
- .Start = _start, \
- .Stop = _stop, \
- .Version = 0x10, \
- } }
+/** EFI driver table */
+#define EFI_DRIVERS __table ( struct efi_driver, "efi_drivers" )
+
+/** Declare an EFI driver */
+#define __efi_driver( order ) __table_entry ( EFI_DRIVERS, order )
+
+#define EFI_DRIVER_EARLY 01 /**< Early drivers */
+#define EFI_DRIVER_NORMAL 02 /**< Normal drivers */
+#define EFI_DRIVER_LATE 03 /**< Late drivers */
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 );
+extern int efi_driver_install ( void );
+extern void efi_driver_uninstall ( void );
+extern int efi_driver_connect_all ( void );
+extern void efi_driver_disconnect_all ( void );
+extern void efi_driver_reconnect_all ( void );
#endif /* _IPXE_EFI_DRIVER_H */
return ( value << shift );
}
-struct efi_driver;
struct device;
/** An EFI PCI device */
EFI_PCI_IO_PROTOCOL *pci_io;
/** Device path */
EFI_DEVICE_PATH_PROTOCOL *path;
- /** EFI driver */
- struct efi_driver *efidrv;
};
-extern struct efi_pci_device * efipci_create ( struct efi_driver *efidrv,
- EFI_HANDLE device );
+extern int efipci_create ( EFI_HANDLE device, UINT32 attributes,
+ struct efi_pci_device **efipci );
extern int efipci_enable ( struct efi_pci_device *efipci );
extern struct efi_pci_device * efipci_find_efi ( EFI_HANDLE device );
extern struct efi_pci_device * efipci_find ( struct device *dev );
EFI_HANDLE device );
extern void efipci_child_del ( struct efi_pci_device *efipci,
EFI_HANDLE device );
-extern void efipci_destroy ( struct efi_driver *efidrv,
- struct efi_pci_device *efipci );
+extern void efipci_destroy ( struct efi_pci_device *efipci );
#endif /* _IPXE_EFI_PCI_H */
#include <errno.h>
#include <ipxe/bofm.h>
-#include <ipxe/init.h>
#include <ipxe/efi/efi.h>
#include <ipxe/efi/efi_pci.h>
#include <ipxe/efi/efi_driver.h>
/**
* Check if device is supported
*
- * @v driver EFI driver
* @v device EFI device
- * @v child Path to child device, if any
- * @ret efirc EFI status code
+ * @ret rc Return status code
*/
-static EFI_STATUS EFIAPI
-efi_bofm_supported ( EFI_DRIVER_BINDING_PROTOCOL *driver,
- EFI_HANDLE device,
- EFI_DEVICE_PATH_PROTOCOL *child ) {
- struct efi_driver *efidrv =
- container_of ( driver, struct efi_driver, driver );
+static int efi_bofm_supported ( EFI_HANDLE device ) {
EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
union {
IBM_BOFM_DRIVER_CONFIGURATION_PROTOCOL *bofm1;
EFI_STATUS efirc;
int rc;
- DBGCP ( efidrv, "EFIBOFM DRIVER_SUPPORTED %p (%p)\n", device, child );
+ /* Do nothing if we are already driving this device */
+ efipci = efipci_find_efi ( device );
+ if ( efipci ) {
+ DBGCP ( device, "EFIBOFM %p %s already started\n",
+ device, efi_devpath_text ( efipci->path ) );
+ rc = -EALREADY;
+ goto err_already_started;
+ }
/* Create corresponding PCI device, if any */
- efipci = efipci_create ( efidrv, device );
- if ( ! efipci ) {
- rc = -ENOTSUP;
- goto err_not_pci;
- }
+ if ( ( rc = efipci_create ( device, EFI_OPEN_PROTOCOL_GET_PROTOCOL,
+ &efipci ) ) != 0 )
+ goto err_create;
/* Look for a BOFM driver */
if ( ( rc = bofm_find_driver ( &efipci->pci ) ) != 0 ) {
- DBGCP ( efidrv, "EFIBOFM " PCI_FMT " has no driver\n",
- PCI_ARGS ( &efipci->pci ) );
+ DBGCP ( device, "EFIBOFM %p %s has no driver\n",
+ device, efi_devpath_text ( efipci->path ) );
goto err_no_driver;
}
if ( ( efirc = bs->LocateProtocol ( &bofm1_protocol_guid, NULL,
&bofm1.interface ) ) != 0 ) {
rc = -EEFI ( efirc );
- DBGC ( efidrv, "EFIBOFM " PCI_FMT " cannot find BOFM "
- "protocol\n", PCI_ARGS ( &efipci->pci ) );
+ DBGC ( device, "EFIBOFM %p %s cannot find BOFM protocol\n",
+ device, efi_devpath_text ( efipci->path ) );
goto err_not_bofm;
}
0x00 /* No iSCSI */,
0x02 /* Version */ ))!=0){
rc = -EEFI ( efirc );
- DBGC ( efidrv, "EFIBOFM " PCI_FMT " could not register "
- "support: %s\n", PCI_ARGS ( &efipci->pci ),
+ DBGC ( device, "EFIBOFM %p %s could not register support: %s\n",
+ device, efi_devpath_text ( efipci->path ),
strerror ( rc ) );
goto err_cannot_register;
}
- DBGC ( efidrv, "EFIBOFM " PCI_FMT " is supported by driver \"%s\"\n",
- PCI_ARGS ( &efipci->pci ), efipci->pci.id->name );
+ DBGC ( device, "EFIBOFM %p %s has driver \"%s\"\n", device,
+ efi_devpath_text ( efipci->path ), efipci->pci.id->name );
/* Destroy temporary PCI device */
- efipci_destroy ( efidrv, efipci );
+ efipci_destroy ( efipci );
return 0;
err_cannot_register:
err_not_bofm:
err_no_driver:
- efipci_destroy ( efidrv, efipci );
- err_not_pci:
- return EFIRC ( rc );
+ efipci_destroy ( efipci );
+ err_create:
+ err_already_started:
+ return rc;
}
/**
* 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
+ * @ret rc Return status code
*/
-static EFI_STATUS EFIAPI efi_bofm_start ( EFI_DRIVER_BINDING_PROTOCOL *driver,
- EFI_HANDLE device,
- EFI_DEVICE_PATH_PROTOCOL *child ) {
- struct efi_driver *efidrv =
- container_of ( driver, struct efi_driver, driver );
+static int efi_bofm_start ( EFI_HANDLE device ) {
EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
union {
IBM_BOFM_DRIVER_CONFIGURATION_PROTOCOL *bofm1;
EFI_STATUS efirc;
int rc;
- DBGCP ( efidrv, "EFIBOFM DRIVER_START %p (%p)\n", device, child );
+ /* Do nothing if we are already driving this device */
+ efipci = efipci_find_efi ( device );
+ if ( efipci ) {
+ DBGCP ( device, "EFIPCI %p %s already started\n",
+ device, efi_devpath_text ( efipci->path ) );
+ rc = -EALREADY;
+ goto err_already_started;
+ }
/* Create corresponding PCI device */
- efipci = efipci_create ( efidrv, device );
- if ( ! efipci ) {
- rc = -ENOMEM;
+ if ( ( rc = efipci_create ( device, EFI_OPEN_PROTOCOL_GET_PROTOCOL,
+ &efipci ) ) != 0 )
goto err_create;
- }
/* Enable PCI device */
if ( ( rc = efipci_enable ( efipci ) ) != 0 )
if ( ( efirc = bs->LocateProtocol ( &bofm1_protocol_guid, NULL,
&bofm1.interface ) ) != 0 ) {
rc = -EEFI ( efirc );
- DBGC ( efidrv, "EFIBOFM " PCI_FMT " cannot find BOFM "
- "protocol\n", PCI_ARGS ( &efipci->pci ) );
+ DBGC ( device, "EFIBOFM %p %s cannot find BOFM protocol\n",
+ device, efi_devpath_text ( efipci->path ) );
goto err_locate_bofm;
}
bofmtab = &bofm1.bofm1->BofmTable;
- DBGC ( efidrv, "EFIBOFM " PCI_FMT " found version 1 BOFM table at "
- "%p+%04x\n", PCI_ARGS ( &efipci->pci ), bofmtab,
+ DBGC ( device, "EFIBOFM %p %s found version 1 BOFM table at %p+%04x\n",
+ device, efi_devpath_text ( efipci->path ), bofmtab,
bofmtab->Parameters.Length );
/* Locate BOFM2 protocol, if available */
if ( ( efirc = bs->LocateProtocol ( &bofm2_protocol_guid, NULL,
&bofm2.interface ) ) == 0 ) {
bofmtab2 = &bofm2.bofm2->BofmTable;
- DBGC ( efidrv, "EFIBOFM " PCI_FMT " found version 2 BOFM table "
- "at %p+%04x\n", PCI_ARGS ( &efipci->pci ), bofmtab2,
- bofmtab2->Parameters.Length );
+ DBGC ( device, "EFIBOFM %p %s found version 2 BOFM table at "
+ "%p+%04x\n", device, efi_devpath_text ( efipci->path ),
+ bofmtab2, bofmtab2->Parameters.Length );
assert ( bofm2.bofm2->RegisterSupport ==
bofm1.bofm1->RegisterSupport );
} else {
- DBGC ( efidrv, "EFIBOFM " PCI_FMT " cannot find BOFM2 "
- "protocol\n", PCI_ARGS ( &efipci->pci ) );
+ DBGC ( device, "EFIBOFM %p %s cannot find BOFM2 protocol\n",
+ device, efi_devpath_text ( efipci->path ) );
/* Not a fatal error; may be a BOFM1-only system */
bofmtab2 = NULL;
}
/* Process BOFM table */
- DBGC2 ( efidrv, "EFIBOFM " PCI_FMT " version 1 before processing:\n",
- PCI_ARGS ( &efipci->pci ) );
- DBGC2_HD ( efidrv, bofmtab, bofmtab->Parameters.Length );
+ DBGC2 ( device, "EFIBOFM %p %s version 1 before processing:\n",
+ device, efi_devpath_text ( efipci->path ) );
+ DBGC2_HD ( device, bofmtab, bofmtab->Parameters.Length );
if ( bofmtab2 ) {
- DBGC2 ( efidrv, "EFIBOFM " PCI_FMT " version 2 before "
- "processing:\n", PCI_ARGS ( &efipci->pci ) );
- DBGC2_HD ( efidrv, bofmtab2, bofmtab2->Parameters.Length );
+ DBGC2 ( device, "EFIBOFM %p %s version 2 before processing:\n",
+ device, efi_devpath_text ( efipci->path ) );
+ DBGC2_HD ( device, bofmtab2, bofmtab2->Parameters.Length );
}
bofmrc = bofm ( virt_to_user ( bofmtab2 ? bofmtab2 : bofmtab ),
&efipci->pci );
- DBGC ( efidrv, "EFIBOFM " PCI_FMT " status %08x\n",
- PCI_ARGS ( &efipci->pci ), bofmrc );
- DBGC2 ( efidrv, "EFIBOFM " PCI_FMT " version 1 after processing:\n",
- PCI_ARGS ( &efipci->pci ) );
- DBGC2_HD ( efidrv, bofmtab, bofmtab->Parameters.Length );
+ DBGC ( device, "EFIBOFM %p %s status %08x\n",
+ device, efi_devpath_text ( efipci->path ), bofmrc );
+ DBGC2 ( device, "EFIBOFM %p %s version 1 after processing:\n",
+ device, efi_devpath_text ( efipci->path ) );
+ DBGC2_HD ( device, bofmtab, bofmtab->Parameters.Length );
if ( bofmtab2 ) {
- DBGC2 ( efidrv, "EFIBOFM " PCI_FMT " version 2 after "
- "processing:\n", PCI_ARGS ( &efipci->pci ) );
- DBGC2_HD ( efidrv, bofmtab2, bofmtab2->Parameters.Length );
+ DBGC2 ( device, "EFIBOFM %p %s version 2 after processing:\n",
+ device, efi_devpath_text ( efipci->path ) );
+ DBGC2_HD ( device, bofmtab2, bofmtab2->Parameters.Length );
}
/* Return BOFM status */
if ( ( efirc = bofm2.bofm2->SetStatus ( bofm2.bofm2, device,
FALSE, bofmrc ) ) != 0){
rc = -EEFI ( efirc );
- DBGC ( efidrv, "EFIBOFM " PCI_FMT " could not set "
- "BOFM2 status: %s\n", PCI_ARGS ( &efipci->pci ),
+ DBGC ( device, "EFIBOFM %p %s could not set BOFM2 "
+ "status: %s\n",
+ device, efi_devpath_text ( efipci->path ),
strerror ( rc ) );
goto err_set_status;
}
if ( ( efirc = bofm1.bofm1->SetStatus ( bofm1.bofm1, device,
FALSE, bofmrc ) ) != 0){
rc = -EEFI ( efirc );
- DBGC ( efidrv, "EFIBOFM " PCI_FMT " could not set "
- "BOFM status: %s\n", PCI_ARGS ( &efipci->pci ),
+ DBGC ( device, "EFIBOFM %p %s could not set BOFM "
+ "status: %s\n",
+ device, efi_devpath_text ( efipci->path ),
strerror ( rc ) );
goto err_set_status;
}
}
/* Destroy the PCI device anyway; we have no further use for it */
- efipci_destroy ( efidrv, efipci );
+ efipci_destroy ( efipci );
/* BOFM (ab)uses the "start" method to mean "process and exit" */
- return EFI_NOT_READY;
+ return -EAGAIN;
err_set_status:
err_locate_bofm:
err_enable:
- efipci_destroy ( efidrv, efipci );
+ efipci_destroy ( efipci );
err_create:
- return EFIRC ( rc );
+ err_already_started:
+ return rc;
}
/**
* Detach driver from device
*
- * @v driver EFI driver
* @v device EFI device
- * @v num_children Number of child devices
- * @v children List of child devices
- * @ret efirc EFI status code
*/
-static EFI_STATUS EFIAPI efi_bofm_stop ( EFI_DRIVER_BINDING_PROTOCOL *driver,
- EFI_HANDLE device, UINTN num_children,
- EFI_HANDLE *children ) {
- struct efi_driver *efidrv =
- container_of ( driver, struct efi_driver, driver );
-
- DBGCP ( efidrv, "EFIBOFM DRIVER_STOP %p (%ld %p)\n",
- device, ( ( unsigned long ) num_children ), children );
-
- return 0;
+static void efi_bofm_stop ( EFI_HANDLE device __unused ) {
+ /* Nothing to do */
}
/** EFI BOFM driver */
-static struct efi_driver efi_bofm_driver =
- EFI_DRIVER_INIT ( "BOFM",
- efi_bofm_supported, efi_bofm_start, efi_bofm_stop );
-
-/**
- * Install EFI BOFM driver
- *
- */
-static void efi_bofm_driver_startup ( void ) {
- struct efi_driver *efidrv = &efi_bofm_driver;
- int rc;
-
- /* Install driver */
- if ( ( rc = efi_driver_install ( efidrv ) ) != 0 ) {
- DBGC ( efidrv, "EFIBOFM could not install driver: %s\n",
- strerror ( rc ) );
- return;
- }
-
- 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_startup,
- .shutdown = efi_bofm_driver_shutdown,
+struct efi_driver efi_bofm_driver __efi_driver ( EFI_DRIVER_EARLY ) = {
+ .name = "BOFM",
+ .supported = efi_bofm_supported,
+ .start = efi_bofm_start,
+ .stop = efi_bofm_stop,
};
*
*/
+static EFI_DRIVER_BINDING_PROTOCOL efi_driver_binding;
+
/** EFI driver binding protocol GUID */
static EFI_GUID efi_driver_binding_protocol_guid
= EFI_DRIVER_BINDING_PROTOCOL_GUID;
return path;
}
+/**
+ * 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_driver_supported ( EFI_DRIVER_BINDING_PROTOCOL *driver __unused,
+ EFI_HANDLE device, EFI_DEVICE_PATH_PROTOCOL *child ) {
+ struct efi_driver *efidrv;
+ int rc;
+
+ DBGCP ( device, "EFIDRV %p %s DRIVER_SUPPORTED",
+ device, efi_handle_devpath_text ( device ) );
+ if ( child )
+ DBGCP ( device, " (child %s)", efi_devpath_text ( child ) );
+ DBGCP ( device, "\n" );
+
+ /* Look for a driver claiming to support this device */
+ for_each_table_entry ( efidrv, EFI_DRIVERS ) {
+ if ( ( rc = efidrv->supported ( device ) ) == 0 ) {
+ DBGC ( device, "EFIDRV %p %s has driver \"%s\"\n",
+ device, efi_handle_devpath_text ( device ),
+ efidrv->name );
+ return 0;
+ }
+ }
+ DBGCP ( device, "EFIDRV %p %s has no driver\n",
+ device, efi_handle_devpath_text ( device ) );
+
+ 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_driver_start ( EFI_DRIVER_BINDING_PROTOCOL *driver __unused,
+ EFI_HANDLE device, EFI_DEVICE_PATH_PROTOCOL *child ) {
+ struct efi_driver *efidrv;
+ int rc;
+
+ DBGC ( device, "EFIDRV %p %s DRIVER_START",
+ device, efi_handle_devpath_text ( device ) );
+ if ( child )
+ DBGC ( device, " (child %s)", efi_devpath_text ( child ) );
+ DBGC ( device, "\n" );
+
+ /* Try to start this device */
+ for_each_table_entry ( efidrv, EFI_DRIVERS ) {
+ if ( ( rc = efidrv->start ( device ) ) == 0 ) {
+ DBGC ( device, "EFIDRV %p %s using driver \"%s\"\n",
+ device, efi_handle_devpath_text ( device ),
+ efidrv->name );
+ return 0;
+ }
+ DBGC ( device, "EFIDRV %p %s could not start driver \"%s\": "
+ "%s\n", device, efi_handle_devpath_text ( device ),
+ efidrv->name, strerror ( rc ) );
+ }
+
+ 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_driver_stop ( EFI_DRIVER_BINDING_PROTOCOL *driver __unused,
+ EFI_HANDLE device, UINTN num_children,
+ EFI_HANDLE *children ) {
+ struct efi_driver *efidrv;
+ UINTN i;
+
+ DBGC ( device, "EFIDRV %p %s DRIVER_STOP",
+ device, efi_handle_devpath_text ( device ) );
+ for ( i = 0 ; i < num_children ; i++ ) {
+ DBGC ( device, "%s%p %s", ( i ? ", " : " child " ),
+ children[i], efi_handle_devpath_text ( children[i] ) );
+ }
+ DBGC ( device, "\n" );
+
+ /* Try to stop this device */
+ for_each_table_entry ( efidrv, EFI_DRIVERS )
+ efidrv->stop ( device );
+
+ return 0;
+}
+
+/** EFI driver binding protocol */
+static EFI_DRIVER_BINDING_PROTOCOL efi_driver_binding = {
+ .Supported = efi_driver_supported,
+ .Start = efi_driver_start,
+ .Stop = efi_driver_stop,
+};
+
/**
* Look up driver name
*
* @ret efirc EFI status code
*/
static EFI_STATUS EFIAPI
-efi_driver_get_driver_name ( EFI_COMPONENT_NAME2_PROTOCOL *wtf,
- CHAR8 *language __unused, CHAR16 **driver_name ) {
- struct efi_driver *efidrv =
- container_of ( wtf, struct efi_driver, wtf );
+efi_driver_name ( EFI_COMPONENT_NAME2_PROTOCOL *wtf __unused,
+ CHAR8 *language __unused, CHAR16 **driver_name ) {
+ const wchar_t *name;
- *driver_name = efidrv->wname;
+ name = ( product_wname[0] ? product_wname : build_wname );
+ *driver_name = ( ( wchar_t * ) name );
return 0;
}
* @ret efirc EFI status code
*/
static EFI_STATUS EFIAPI
-efi_driver_get_controller_name ( EFI_COMPONENT_NAME2_PROTOCOL *wtf __unused,
- EFI_HANDLE device, EFI_HANDLE child,
- CHAR8 *language, CHAR16 **controller_name ) {
+efi_driver_controller_name ( EFI_COMPONENT_NAME2_PROTOCOL *wtf __unused,
+ EFI_HANDLE device, EFI_HANDLE child,
+ CHAR8 *language, CHAR16 **controller_name ) {
EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
union {
EFI_COMPONENT_NAME2_PROTOCOL *name2;
return EFI_UNSUPPORTED;
}
+/** EFI component name protocol */
+static EFI_COMPONENT_NAME2_PROTOCOL efi_wtf = {
+ .GetDriverName = efi_driver_name,
+ .GetControllerName = efi_driver_controller_name,
+ .SupportedLanguages = "en",
+};
+
+/**
+ * Install EFI driver
+ *
+ * @ret rc Return status code
+ */
+int efi_driver_install ( void ) {
+ EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
+ EFI_STATUS efirc;
+ int rc;
+
+ /* Calculate driver version number. We use the build
+ * timestamp (in seconds since the Epoch) shifted right by six
+ * bits: this gives us an approximately one-minute resolution
+ * and a scheme which will last until the year 10680.
+ */
+ efi_driver_binding.Version = ( build_timestamp >> 6 );
+
+ /* Install protocols on image handle */
+ efi_driver_binding.ImageHandle = efi_image_handle;
+ efi_driver_binding.DriverBindingHandle = efi_image_handle;
+ if ( ( efirc = bs->InstallMultipleProtocolInterfaces (
+ &efi_image_handle,
+ &efi_driver_binding_protocol_guid, &efi_driver_binding,
+ &efi_component_name2_protocol_guid, &efi_wtf,
+ NULL ) ) != 0 ) {
+ rc = -EEFI ( efirc );
+ DBGC ( &efi_driver_binding, "EFIDRV could not install "
+ "protocols: %s\n", strerror ( rc ) );
+ return rc;
+ }
+
+ return 0;
+}
+
+/**
+ * Uninstall EFI driver
+ *
+ */
+void efi_driver_uninstall ( void ) {
+ EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
+
+ /* Uninstall protocols */
+ bs->UninstallMultipleProtocolInterfaces (
+ efi_image_handle,
+ &efi_driver_binding_protocol_guid, &efi_driver_binding,
+ &efi_component_name2_protocol_guid, &efi_wtf, NULL );
+}
+
/**
* Try to connect EFI driver
*
- * @v efidrv EFI driver
- * @v handle Controller handle
+ * @v device EFI device
+ * @ret rc Return status code
*/
-static void efi_driver_connect ( struct efi_driver *efidrv, EFI_HANDLE handle ){
+static int efi_driver_connect ( EFI_HANDLE device ) {
EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
- EFI_HANDLE drivers[2] = { efidrv->driver.DriverBindingHandle, NULL };
+ EFI_HANDLE drivers[2] =
+ { efi_driver_binding.DriverBindingHandle, NULL };
+ EFI_STATUS efirc;
+ int rc;
+
+ /* Check if we want to drive this device */
+ if ( ( efirc = efi_driver_supported ( &efi_driver_binding, device,
+ NULL ) ) != 0 ) {
+ /* Not supported; not an error */
+ return 0;
+ }
+
+ /* Disconnect any existing drivers */
+ DBGC ( device, "EFIDRV %p %s disconnecting existing drivers\n",
+ device, efi_handle_devpath_text ( device ) );
+ bs->DisconnectController ( device, NULL, NULL );
- bs->ConnectController ( handle, drivers, NULL, FALSE );
+ /* Connect our driver */
+ DBGC ( device, "EFIDRV %p %s connecting new drivers\n",
+ device, efi_handle_devpath_text ( device ) );
+ if ( ( efirc = bs->ConnectController ( device, drivers, NULL,
+ FALSE ) ) != 0 ) {
+ rc = -EEFI ( efirc );
+ DBGC ( device, "EFIDRV %p %s could not connect new drivers: "
+ "%s\n", device, efi_handle_devpath_text ( device ),
+ strerror ( rc ) );
+ return rc;
+ }
+
+ return 0;
}
/**
* Try to disconnect EFI driver
*
- * @v efidrv EFI driver
- * @v handle Controller handle
+ * @v device EFI device
+ * @ret rc Return status code
*/
-static void efi_driver_disconnect ( struct efi_driver *efidrv,
- EFI_HANDLE handle ) {
+static int efi_driver_disconnect ( EFI_HANDLE device ) {
EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
- bs->DisconnectController ( handle, efidrv->driver.DriverBindingHandle,
+ /* Disconnect our driver */
+ bs->DisconnectController ( device,
+ efi_driver_binding.DriverBindingHandle,
NULL );
+ return 0;
+}
+
+/**
+ * Reconnect original EFI driver
+ *
+ * @v device EFI device
+ * @ret rc Return status code
+ */
+static int efi_driver_reconnect ( EFI_HANDLE device ) {
+ EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
+
+ /* Reconnect any available driver */
+ bs->ConnectController ( device, NULL, NULL, FALSE );
+
+ return 0;
}
/**
* Connect/disconnect EFI driver from all handles
*
- * @v efidrv EFI driver
* @v method Connect/disconnect method
* @ret rc Return status code
*/
-static int efi_driver_handles ( struct efi_driver *efidrv,
- void ( * method ) ( struct efi_driver *efidrv,
- EFI_HANDLE handle ) ) {
+static int efi_driver_handles ( int ( * method ) ( EFI_HANDLE handle ) ) {
EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
EFI_HANDLE *handles;
UINTN num_handles;
&num_handles,
&handles ) ) != 0 ) {
rc = -EEFI ( efirc );
- DBGC ( efidrv, "EFIDRV %s could not list handles: %s\n",
- efidrv->name, strerror ( rc ) );
- return rc;
+ DBGC ( &efi_driver_binding, "EFIDRV could not list handles: "
+ "%s\n", strerror ( rc ) );
+ goto err_locate;
}
/* Connect/disconnect driver from all handles */
- for ( i = 0 ; i < num_handles ; i++ )
- method ( efidrv, handles[i] );
+ for ( i = 0 ; i < num_handles ; i++ ) {
+ if ( ( rc = method ( handles[i] ) ) != 0 )
+ goto err_method;
+ }
- /* Free list of handles */
- bs->FreePool ( handles );
+ /* Success */
+ rc = 0;
- return 0;
+ err_method:
+ bs->FreePool ( handles );
+ err_locate:
+ return rc;
}
/**
- * Install EFI driver
+ * Connect EFI driver to all possible devices
*
- * @v efidrv EFI driver
* @ret rc Return status code
*/
-int efi_driver_install ( struct efi_driver *efidrv ) {
- EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
- EFI_DRIVER_BINDING_PROTOCOL *driver = &efidrv->driver;
- EFI_COMPONENT_NAME2_PROTOCOL *wtf = &efidrv->wtf;
- EFI_STATUS efirc;
- int rc;
-
- /* Configure driver binding protocol */
- driver->ImageHandle = efi_image_handle;
-
- /* Configure component name protocol */
- wtf->GetDriverName = efi_driver_get_driver_name;
- wtf->GetControllerName = efi_driver_get_controller_name;
- wtf->SupportedLanguages = "en";
+int efi_driver_connect_all ( void ) {
- /* Fill in driver name */
- efi_snprintf ( efidrv->wname,
- ( sizeof ( efidrv->wname ) /
- sizeof ( efidrv->wname[0] ) ),
- "%s%s%s", product_short_name,
- ( efidrv->name ? " - " : "" ),
- ( efidrv->name ? efidrv->name : "" ) );
-
- /* Install driver */
- if ( ( efirc = bs->InstallMultipleProtocolInterfaces (
- &driver->DriverBindingHandle,
- &efi_driver_binding_protocol_guid, driver,
- &efi_component_name2_protocol_guid, wtf,
- NULL ) ) != 0 ) {
- rc = -EEFI ( efirc );
- DBGC ( efidrv, "EFIDRV %s could not install protocol: %s\n",
- efidrv->name, strerror ( rc ) );
- return rc;
- }
+ DBGC ( &efi_driver_binding, "EFIDRV connecting our drivers\n" );
+ return efi_driver_handles ( efi_driver_connect );
+}
- /* Connect devices */
- DBGC ( efidrv, "EFIDRV %s connecting devices\n", efidrv->name );
- efi_driver_handles ( efidrv, efi_driver_connect );
+/**
+ * Disconnect EFI driver from all possible devices
+ *
+ * @ret rc Return status code
+ */
+void efi_driver_disconnect_all ( void ) {
- DBGC ( efidrv, "EFIDRV %s installed\n", efidrv->name );
- return 0;
+ DBGC ( &efi_driver_binding, "EFIDRV disconnecting our drivers\n" );
+ efi_driver_handles ( efi_driver_disconnect );
}
/**
- * Uninstall EFI driver
+ * Reconnect original EFI drivers to all possible devices
*
- * @v efidrv EFI driver
+ * @ret rc Return status code
*/
-void efi_driver_uninstall ( struct efi_driver *efidrv ) {
- EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
-
- /* Disconnect the driver from its devices */
- DBGC ( efidrv, "EFIDRV %s disconnecting devices\n", efidrv->name );
- efi_driver_handles ( efidrv, efi_driver_disconnect );
+void efi_driver_reconnect_all ( void ) {
- /* 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 );
+ DBGC ( &efi_driver_binding, "EFIDRV reconnecting old drivers\n" );
+ efi_driver_handles ( efi_driver_reconnect );
}
#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;
/* 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.
*
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;
efi_guid_ntoa ( &prot->guid ) );
/* Fail if protocol is required */
if ( prot->required )
- return efirc;
+ goto err_missing_protocol;
}
}
} 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;
+ }
}
}
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",
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;
}
/**
/* 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;
#include <stdlib.h>
#include <errno.h>
#include <ipxe/pci.h>
-#include <ipxe/init.h>
#include <ipxe/efi/efi.h>
#include <ipxe/efi/efi_pci.h>
#include <ipxe/efi/efi_driver.h>
*
*/
+/* Disambiguate the various error causes */
+#define EINFO_EEFI_PCI \
+ __einfo_uniqify ( EINFO_EPLATFORM, 0x01, \
+ "Could not open PCI I/O protocols" )
+#define EINFO_EEFI_PCI_NOT_PCI \
+ __einfo_platformify ( EINFO_EEFI_PCI, EFI_UNSUPPORTED, \
+ "Not a PCI device" )
+#define EEFI_PCI_NOT_PCI __einfo_error ( EINFO_EEFI_PCI_NOT_PCI )
+#define EINFO_EEFI_PCI_IN_USE \
+ __einfo_platformify ( EINFO_EEFI_PCI, EFI_ACCESS_DENIED, \
+ "PCI device already has a driver" )
+#define EEFI_PCI_IN_USE __einfo_error ( EINFO_EEFI_PCI_IN_USE )
+#define EEFI_PCI( efirc ) \
+ EPLATFORM ( EINFO_EEFI_PCI, efirc, \
+ EEFI_PCI_NOT_PCI, EEFI_PCI_IN_USE )
+
/******************************************************************************
*
* iPXE PCI API
/**
* Create EFI PCI device
*
- * @v efidrv EFI driver
* @v device EFI device
- * @ret efipci EFI PCI device, or NULL
+ * @v attributes Protocol opening attributes
+ * @v efipci EFI PCI device to fill in
+ * @ret rc Return status code
*/
-struct efi_pci_device * efipci_create ( struct efi_driver *efidrv,
- EFI_HANDLE device ) {
+int efipci_create ( EFI_HANDLE device, UINT32 attributes,
+ struct efi_pci_device **efipci ) {
EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
- struct efi_pci_device *efipci;
union {
EFI_PCI_IO_PROTOCOL *pci_io;
void *interface;
int rc;
/* Allocate PCI device */
- efipci = zalloc ( sizeof ( *efipci ) );
- if ( ! efipci )
+ *efipci = zalloc ( sizeof ( **efipci ) );
+ if ( ! *efipci ) {
+ rc = -ENOMEM;
goto err_zalloc;
- efipci->device = device;
- efipci->efidrv = efidrv;
+ }
+ (*efipci)->device = device;
/* See if device is a PCI device */
if ( ( efirc = bs->OpenProtocol ( device,
&efi_pci_io_protocol_guid,
&pci_io.interface,
- efidrv->driver.DriverBindingHandle,
- device,
- EFI_OPEN_PROTOCOL_BY_DRIVER )) !=0 ){
- rc = -EEFI ( efirc );
- DBGCP ( efipci, "EFIPCI device %p is not a PCI device\n",
- device );
+ efi_image_handle,
+ device, attributes ) ) != 0 ) {
+ rc = -EEFI_PCI ( efirc );
+ DBGCP ( device, "EFIPCI %p %s cannot open PCI protocols: %s\n",
+ device, efi_handle_devpath_text ( device ),
+ strerror ( rc ) );
goto err_open_protocol;
}
- efipci->pci_io = pci_io.pci_io;
+ (*efipci)->pci_io = pci_io.pci_io;
/* Get PCI bus:dev.fn address */
if ( ( efirc = pci_io.pci_io->GetLocation ( pci_io.pci_io,
&pci_bus, &pci_dev,
&pci_fn ) ) != 0 ) {
rc = -EEFI ( efirc );
- DBGC ( efipci, "EFIPCI device %p could not get PCI "
- "location: %s\n", device, strerror ( rc ) );
+ DBGC ( device, "EFIPCI %p %s could not get PCI location: "
+ "%s\n", device, efi_handle_devpath_text ( device ),
+ strerror ( rc ) );
goto err_get_location;
}
- DBGC2 ( efipci, "EFIPCI device %p is PCI %04lx:%02lx:%02lx.%lx\n",
- device, ( ( unsigned long ) pci_segment ),
- ( ( unsigned long ) pci_bus ), ( ( unsigned long ) pci_dev ),
- ( ( unsigned long ) pci_fn ) );
+ DBGC2 ( device, "EFIPCI %p %s is PCI %04lx:%02lx:%02lx.%lx\n",
+ device, efi_handle_devpath_text ( device ),
+ ( ( unsigned long ) pci_segment ), ( ( unsigned long ) pci_bus),
+ ( ( unsigned long ) pci_dev ), ( ( unsigned long ) pci_fn ) );
/* Populate PCI device */
- pci_init ( &efipci->pci, PCI_BUSDEVFN ( pci_bus, pci_dev, pci_fn ) );
- if ( ( rc = pci_read_config ( &efipci->pci ) ) != 0 ) {
- DBGC ( efipci, "EFIPCI " PCI_FMT " cannot read PCI "
- "configuration: %s\n",
- PCI_ARGS ( &efipci->pci ), strerror ( rc ) );
+ pci_init ( &(*efipci)->pci, PCI_BUSDEVFN ( pci_bus, pci_dev, pci_fn ) );
+ if ( ( rc = pci_read_config ( &(*efipci)->pci ) ) != 0 ) {
+ DBGC ( device, "EFIPCI %p %s cannot read PCI configuration: "
+ "%s\n", device, efi_handle_devpath_text ( device ),
+ strerror ( rc ) );
goto err_pci_read_config;
}
/* Retrieve device path */
if ( ( efirc = bs->OpenProtocol ( device,
&efi_device_path_protocol_guid,
- &path.interface,
- efidrv->driver.DriverBindingHandle,
- device,
- EFI_OPEN_PROTOCOL_BY_DRIVER )) !=0 ){
+ &path.interface, efi_image_handle,
+ device, attributes ) ) != 0 ) {
rc = -EEFI ( efirc );
- DBGC ( efipci, "EFIPCI " PCI_FMT " has no device path\n",
- PCI_ARGS ( &efipci->pci ) );
+ DBGC ( device, "EFIPCI %p %s has no device path\n",
+ device, efi_handle_devpath_text ( device ) );
goto err_no_device_path;
}
- efipci->path = path.path;
+ (*efipci)->path = path.path;
/* Add to list of PCI devices */
- list_add ( &efipci->list, &efi_pci_devices );
+ list_add ( &(*efipci)->list, &efi_pci_devices );
- return efipci;
+ return 0;
bs->CloseProtocol ( device, &efi_device_path_protocol_guid,
- efidrv->driver.DriverBindingHandle, device );
+ efi_image_handle, device );
err_no_device_path:
err_pci_read_config:
err_get_location:
bs->CloseProtocol ( device, &efi_pci_io_protocol_guid,
- efidrv->driver.DriverBindingHandle, device );
+ efi_image_handle, device );
err_open_protocol:
- free ( efipci );
+ free ( *efipci );
err_zalloc:
- return NULL;
+ return rc;
}
/**
*/
int efipci_child_add ( struct efi_pci_device *efipci, EFI_HANDLE device ) {
EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
- struct efi_driver *efidrv = efipci->efidrv;
union {
EFI_PCI_IO_PROTOCOL *pci_io;
void *interface;
if ( ( efirc = bs->OpenProtocol ( efipci->device,
&efi_pci_io_protocol_guid,
&pci_io.interface,
- efidrv->driver.DriverBindingHandle,
- device,
+ efi_image_handle, device,
EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
) ) != 0 ) {
rc = -EEFI ( efirc );
- DBGC ( efipci, "EFIPCI " PCI_FMT " could not add child: %s\n",
- PCI_ARGS ( &efipci->pci ), strerror ( rc ) );
+ DBGC ( efipci->device, "EFIPCI %p %s could not add child",
+ efipci->device, efi_devpath_text ( efipci->path ) );
+ DBGC ( efipci->device, " %p %s: %s\n", device,
+ efi_handle_devpath_text ( device ), strerror ( rc ) );
return rc;
}
+ DBGC2 ( efipci->device, "EFIPCI %p %s added child",
+ efipci->device, efi_devpath_text ( efipci->path ) );
+ DBGC2 ( efipci->device, " %p %s\n",
+ device, efi_handle_devpath_text ( device ) );
return 0;
}
*/
void efipci_child_del ( struct efi_pci_device *efipci, EFI_HANDLE device ) {
EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
- struct efi_driver *efidrv = efipci->efidrv;
bs->CloseProtocol ( efipci->device, &efi_pci_io_protocol_guid,
- efidrv->driver.DriverBindingHandle, device );
+ efi_image_handle, device );
+ DBGC2 ( efipci->device, "EFIPCI %p %s removed child",
+ efipci->device, efi_devpath_text ( efipci->path ) );
+ DBGC2 ( efipci->device, " %p %s\n",
+ device, efi_handle_devpath_text ( device ) );
}
/**
* Destroy EFI PCI device
*
- * @v efidrv EFI driver
* @v efipci EFI PCI device
*/
-void efipci_destroy ( struct efi_driver *efidrv,
- struct efi_pci_device *efipci ) {
+void efipci_destroy ( struct efi_pci_device *efipci ) {
EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
list_del ( &efipci->list );
bs->CloseProtocol ( efipci->device, &efi_device_path_protocol_guid,
- efidrv->driver.DriverBindingHandle,
- efipci->device );
+ efi_image_handle, efipci->device );
bs->CloseProtocol ( efipci->device, &efi_pci_io_protocol_guid,
- efidrv->driver.DriverBindingHandle,
- efipci->device );
+ efi_image_handle, efipci->device );
free ( efipci );
}
/**
* 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
+ * @ret rc Return status code
*/
-static EFI_STATUS EFIAPI
-efipci_supported ( EFI_DRIVER_BINDING_PROTOCOL *driver, EFI_HANDLE device,
- EFI_DEVICE_PATH_PROTOCOL *child ) {
- struct efi_driver *efidrv =
- container_of ( driver, struct efi_driver, driver );
+static int efipci_supported ( EFI_HANDLE device ) {
struct efi_pci_device *efipci;
int rc;
- DBGCP ( efidrv, "EFIPCI DRIVER_SUPPORTED %p (%p)\n", device, child );
+ /* Do nothing if we are already driving this device */
+ efipci = efipci_find_efi ( device );
+ if ( efipci ) {
+ DBGCP ( device, "EFIPCI %p %s already started\n",
+ device, efi_devpath_text ( efipci->path ) );
+ rc = -EALREADY;
+ goto err_already_started;
+ }
/* Create temporary corresponding PCI device, if any */
- efipci = efipci_create ( efidrv, device );
- if ( ! efipci ) {
- /* Non-PCI devices are simply unsupported */
- rc = -ENOTSUP;
- goto err_not_pci;
- }
+ if ( ( rc = efipci_create ( device, EFI_OPEN_PROTOCOL_GET_PROTOCOL,
+ &efipci ) ) != 0 )
+ goto err_create;
/* Look for a driver */
if ( ( rc = pci_find_driver ( &efipci->pci ) ) != 0 ) {
- DBGCP ( efipci, "EFIPCI " PCI_FMT " has no driver\n",
- PCI_ARGS ( &efipci->pci ) );
+ DBGCP ( device, "EFIPCI %p %s has no driver\n",
+ device, efi_devpath_text ( efipci->path ) );
goto err_no_driver;
}
- DBGC ( efipci, "EFIPCI " PCI_FMT " is supported by driver \"%s\"\n",
- PCI_ARGS ( &efipci->pci ), efipci->pci.id->name );
+ DBGC ( device, "EFIPCI %p %s has driver \"%s\"\n", device,
+ efi_devpath_text ( efipci->path ), efipci->pci.id->name );
/* Destroy temporary PCI device */
- efipci_destroy ( efidrv, efipci );
+ efipci_destroy ( efipci );
return 0;
err_no_driver:
- efipci_destroy ( efidrv, efipci );
- err_not_pci:
- return EFIRC ( rc );
+ efipci_destroy ( efipci );
+ err_create:
+ err_already_started:
+ return rc;
}
/**
* 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
+ * @ret rc Return status code
*/
-static EFI_STATUS EFIAPI
-efipci_start ( EFI_DRIVER_BINDING_PROTOCOL *driver, EFI_HANDLE device,
- EFI_DEVICE_PATH_PROTOCOL *child ) {
- struct efi_driver *efidrv =
- container_of ( driver, struct efi_driver, driver );
+static int efipci_start ( EFI_HANDLE device ) {
struct efi_pci_device *efipci;
int rc;
- DBGC ( efidrv, "EFIPCI DRIVER_START %p (%p)\n", device, child );
+ /* Do nothing if we are already driving this device */
+ efipci = efipci_find_efi ( device );
+ if ( efipci ) {
+ DBGCP ( device, "EFIPCI %p %s already started\n",
+ device, efi_devpath_text ( efipci->path ) );
+ rc = -EALREADY;
+ goto err_already_started;
+ }
/* Create corresponding PCI device */
- efipci = efipci_create ( efidrv, device );
- if ( ! efipci ) {
- rc = -ENOMEM;
+ if ( ( rc = efipci_create ( device, ( EFI_OPEN_PROTOCOL_BY_DRIVER |
+ EFI_OPEN_PROTOCOL_EXCLUSIVE ),
+ &efipci ) ) != 0 )
goto err_create;
- }
/* Find driver */
if ( ( rc = pci_find_driver ( &efipci->pci ) ) != 0 ) {
- DBGC ( efipci, "EFIPCI " PCI_FMT " has no driver\n",
- PCI_ARGS ( &efipci->pci ) );
+ DBGC ( device, "EFIPCI %p %s has no driver\n",
+ device, efi_devpath_text ( efipci->path ) );
goto err_find_driver;
}
/* Probe driver */
if ( ( rc = pci_probe ( &efipci->pci ) ) != 0 ) {
- DBGC ( efipci, "EFIPCI " PCI_FMT " could not probe driver "
- "\"%s\": %s\n", PCI_ARGS ( &efipci->pci ),
+ DBGC ( device, "EFIPCI %p %s could not probe driver \"%s\": "
+ "%s\n", device, efi_devpath_text ( efipci->path ),
efipci->pci.id->name, strerror ( rc ) );
goto err_probe;
}
+ DBGC ( device, "EFIPCI %p %s using driver \"%s\"\n", device,
+ efi_devpath_text ( efipci->path ), efipci->pci.id->name );
return 0;
err_probe:
err_enable:
err_find_driver:
- efipci_destroy ( efidrv, efipci );
+ efipci_destroy ( efipci );
err_create:
- return EFIRC ( rc );
+ err_already_started:
+ return rc;
}
/**
* 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
-efipci_stop ( EFI_DRIVER_BINDING_PROTOCOL *driver, EFI_HANDLE device,
- UINTN num_children, EFI_HANDLE *children ) {
- struct efi_driver *efidrv =
- container_of ( driver, struct efi_driver, driver );
+ */
+static void efipci_stop ( EFI_HANDLE device ) {
struct efi_pci_device *efipci;
- DBGC ( efidrv, "EFIPCI DRIVER_STOP %p (%ld %p)\n",
- device, ( ( unsigned long ) num_children ), children );
-
/* Find PCI device */
efipci = efipci_find_efi ( device );
- if ( ! efipci ) {
- DBGC ( efidrv, "EFIPCI device %p not started!\n", device );
- return EFI_INVALID_PARAMETER;
- }
+ if ( ! efipci )
+ return;
/* Remove device */
pci_remove ( &efipci->pci );
/* Delete EFI PCI device */
- efipci_destroy ( efidrv, efipci );
-
- return 0;
+ efipci_destroy ( efipci );
}
/** EFI PCI driver */
-static struct efi_driver efipci_driver =
- EFI_DRIVER_INIT ( "PCI", efipci_supported, efipci_start, efipci_stop );
-
-/**
- * Install EFI PCI driver
- *
- */
-static void efipci_driver_startup ( void ) {
- struct efi_driver *efidrv = &efipci_driver;
- int rc;
-
- /* Install driver */
- if ( ( rc = efi_driver_install ( efidrv ) ) != 0 ) {
- DBGC ( efidrv, "EFIPCI could not install driver: %s\n",
- strerror ( rc ) );
- return;
- }
-
- DBGC ( efidrv, "EFIPCI driver installed\n" );
-}
-
-/**
- * Shut down EFI PCI driver
- *
- * @v booting System is shutting down for OS boot
- */
-static void efipci_driver_shutdown ( int booting __unused ) {
- struct efi_driver *efidrv = &efipci_driver;
- 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; "
- "forcing close\n", PCI_ARGS ( &efipci->pci ) );
- pci_remove ( &efipci->pci );
- efipci_destroy ( efidrv, efipci );
- }
-}
-
-/** EFI PCI startup function */
-struct startup_fn startup_pci __startup_fn ( STARTUP_NORMAL ) = {
- .startup = efipci_driver_startup,
- .shutdown = efipci_driver_shutdown,
+struct efi_driver efipci_driver __efi_driver ( EFI_DRIVER_NORMAL ) = {
+ .name = "PCI",
+ .supported = efipci_supported,
+ .start = efipci_start,
+ .stop = efipci_stop,
};