Skip to content

Commit

Permalink
[efi] Restructure EFI driver model
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
mcb30 committed Jun 25, 2014
1 parent f2c116f commit 0e3ab60
Show file tree
Hide file tree
Showing 7 changed files with 582 additions and 486 deletions.
35 changes: 35 additions & 0 deletions src/arch/x86/prefix/efiprefix.c
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,9 @@ FILE_LICENCE ( GPL2_OR_LATER );

#include <stdlib.h>
#include <errno.h>
#include <ipxe/device.h>
#include <ipxe/efi/efi.h>
#include <ipxe/efi/efi_driver.h>

/**
* EFI entry point
Expand All @@ -47,6 +49,39 @@ EFI_STATUS EFIAPI _efi_start ( EFI_HANDLE image_handle,

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,
};
61 changes: 35 additions & 26 deletions src/include/ipxe/efi/efi_driver.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,43 +8,52 @@

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 */
10 changes: 3 additions & 7 deletions src/include/ipxe/efi/efi_pci.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ static inline EFIAPI uint64_t LShiftU64 ( UINT64 value, UINTN shift ) {
return ( value << shift );
}

struct efi_driver;
struct device;

/** An EFI PCI device */
Expand All @@ -32,20 +31,17 @@ struct 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 );
extern int efipci_child_add ( struct efi_pci_device *efipci,
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 */
Loading

0 comments on commit 0e3ab60

Please sign in to comment.