diff options
author | Michael Brown <mcb30@ipxe.org> | 2014-06-25 14:47:35 +0100 |
---|---|---|
committer | Michael Brown <mcb30@ipxe.org> | 2014-06-25 14:47:35 +0100 |
commit | 0e3ab6064e9f9eec28712c3b2c1e082672e73461 (patch) | |
tree | 244639d414c47633e9f761c568ff5b4559a4b7a4 /src/interface/efi/efi_bofm.c | |
parent | f2c116ff7d8fb9e52c9344c285012f41ee6636f1 (diff) | |
download | ipxe-0e3ab6064e9f9eec28712c3b2c1e082672e73461.tar.gz |
[efi] Restructure EFI driver model
Provide a single instance of EFI_DRIVER_BINDING_PROTOCOL (attached to
our image handle); this matches the expectations scattered throughout
the EFI specification.
Open the underlying hardware device using EFI_OPEN_PROTOCOL_BY_DRIVER
and EFI_OPEN_PROTOCOL_EXCLUSIVE, to prevent other drivers from
attaching to the same device.
Do not automatically connect to devices when being loaded as a driver;
leave this task to the platform firmware (or to the user, if loading
directly from the EFI shell).
When running as an application, forcibly disconnect any existing
drivers from devices that we want to control, and reconnect them on
exit.
Provide a meaningful driver version number (based on the build
timestamp), to allow platform firmware to automatically load newer
versions of iPXE drivers if multiple drivers are present.
Include device paths within debug messages where possible, to aid in
debugging.
Signed-off-by: Michael Brown <mcb30@ipxe.org>
Diffstat (limited to 'src/interface/efi/efi_bofm.c')
-rw-r--r-- | src/interface/efi/efi_bofm.c | 202 |
1 files changed, 79 insertions, 123 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, }; |