summaryrefslogtreecommitdiffstats
path: root/src/interface
diff options
context:
space:
mode:
Diffstat (limited to 'src/interface')
-rw-r--r--src/interface/efi/efi_bofm.c202
-rw-r--r--src/interface/efi/efi_driver.c346
-rw-r--r--src/interface/efi/efi_init.c122
-rw-r--r--src/interface/efi/efi_pci.c292
4 files changed, 509 insertions, 453 deletions
diff --git a/src/interface/efi/efi_bofm.c b/src/interface/efi/efi_bofm.c
index 4982b22cc..2a258a9b5 100644
--- a/src/interface/efi/efi_bofm.c
+++ b/src/interface/efi/efi_bofm.c
@@ -21,7 +21,6 @@ FILE_LICENCE ( GPL2_OR_LATER );
#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>
@@ -156,17 +155,10 @@ static EFI_GUID bofm2_protocol_guid =
/**
* 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;
@@ -176,19 +168,24 @@ efi_bofm_supported ( EFI_DRIVER_BINDING_PROTOCOL *driver,
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;
}
@@ -196,8 +193,8 @@ efi_bofm_supported ( EFI_DRIVER_BINDING_PROTOCOL *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;
}
@@ -207,41 +204,36 @@ efi_bofm_supported ( EFI_DRIVER_BINDING_PROTOCOL *driver,
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;
@@ -258,14 +250,19 @@ static EFI_STATUS EFIAPI efi_bofm_start ( EFI_DRIVER_BINDING_PROTOCOL *driver,
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 )
@@ -275,51 +272,51 @@ static EFI_STATUS EFIAPI efi_bofm_start ( EFI_DRIVER_BINDING_PROTOCOL *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_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 */
@@ -327,8 +324,9 @@ static EFI_STATUS EFIAPI efi_bofm_start ( EFI_DRIVER_BINDING_PROTOCOL *driver,
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;
}
@@ -336,84 +334,42 @@ static EFI_STATUS EFIAPI efi_bofm_start ( EFI_DRIVER_BINDING_PROTOCOL *driver,
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,
};
diff --git a/src/interface/efi/efi_driver.c b/src/interface/efi/efi_driver.c
index 6d49eca52..8ef471337 100644
--- a/src/interface/efi/efi_driver.c
+++ b/src/interface/efi/efi_driver.c
@@ -36,6 +36,8 @@ FILE_LICENCE ( GPL2_OR_LATER );
*
*/
+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;
@@ -63,6 +65,116 @@ EFI_DEVICE_PATH_PROTOCOL * efi_devpath_end ( EFI_DEVICE_PATH_PROTOCOL *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
*
* @v wtf Component name protocol
@@ -71,12 +183,12 @@ EFI_DEVICE_PATH_PROTOCOL * efi_devpath_end ( EFI_DEVICE_PATH_PROTOCOL *path ) {
* @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;
}
@@ -91,9 +203,9 @@ efi_driver_get_driver_name ( EFI_COMPONENT_NAME2_PROTOCOL *wtf,
* @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;
@@ -118,43 +230,139 @@ efi_driver_get_controller_name ( EFI_COMPONENT_NAME2_PROTOCOL *wtf __unused,
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;
@@ -167,87 +375,55 @@ static int efi_driver_handles ( struct efi_driver *efidrv,
&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 );
}
diff --git a/src/interface/efi/efi_init.c b/src/interface/efi/efi_init.c
index 5eb101350..4204b79b3 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;
diff --git a/src/interface/efi/efi_pci.c b/src/interface/efi/efi_pci.c
index dc7304a35..dd65b20f1 100644
--- a/src/interface/efi/efi_pci.c
+++ b/src/interface/efi/efi_pci.c
@@ -22,7 +22,6 @@ FILE_LICENCE ( GPL2_OR_LATER );
#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>
@@ -35,6 +34,22 @@ FILE_LICENCE ( GPL2_OR_LATER );
*
*/
+/* 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
@@ -119,14 +134,14 @@ static LIST_HEAD ( efi_pci_devices );
/**
* 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;
@@ -140,25 +155,26 @@ struct efi_pci_device * efipci_create ( struct efi_driver *efidrv,
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,
@@ -166,54 +182,53 @@ struct efi_pci_device * efipci_create ( struct efi_driver *efidrv,
&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;
}
/**
@@ -282,7 +297,6 @@ struct efi_pci_device * efipci_find ( struct device *dev ) {
*/
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;
@@ -294,16 +308,21 @@ int efipci_child_add ( struct efi_pci_device *efipci, EFI_HANDLE device ) {
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;
}
@@ -316,29 +335,28 @@ int efipci_child_add ( struct efi_pci_device *efipci, EFI_HANDLE device ) {
*/
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 );
}
@@ -352,79 +370,78 @@ void efipci_destroy ( struct efi_driver *efidrv,
/**
* 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;
}
@@ -434,11 +451,13 @@ efipci_start ( EFI_DRIVER_BINDING_PROTOCOL *driver, EFI_HANDLE device,
/* 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;
@@ -446,93 +465,36 @@ efipci_start ( EFI_DRIVER_BINDING_PROTOCOL *driver, EFI_HANDLE device,
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,
};