mirror of https://github.com/ipxe/ipxe.git
[efi] Allow for allocating EFI devices from arbitrary handles
Split out the code that allocates our internal struct efi_device representations, to allow for the creation of temporary MNP devices in order to download the autoexec.ipxe script. Signed-off-by: Michael Brown <mcb30@ipxe.org>pull/1180/head
parent
764e34f15a
commit
b52b4a46d9
|
@ -86,6 +86,8 @@ static inline void * efidev_get_drvdata ( struct efi_device *efidev ) {
|
|||
return efidev->priv;
|
||||
}
|
||||
|
||||
extern struct efi_device * efidev_alloc ( EFI_HANDLE device );
|
||||
extern void efidev_free ( struct efi_device *efidev );
|
||||
extern struct efi_device * efidev_parent ( struct device *dev );
|
||||
extern int efi_driver_install ( void );
|
||||
extern void efi_driver_uninstall ( void );
|
||||
|
|
|
@ -61,6 +61,67 @@ static LIST_HEAD ( efi_devices );
|
|||
/** We are currently disconnecting drivers */
|
||||
static int efi_driver_disconnecting;
|
||||
|
||||
/**
|
||||
* Allocate new EFI device
|
||||
*
|
||||
* @v device EFI device handle
|
||||
* @ret efidev EFI device, or NULL on error
|
||||
*/
|
||||
struct efi_device * efidev_alloc ( EFI_HANDLE device ) {
|
||||
EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
|
||||
struct efi_device *efidev = NULL;
|
||||
union {
|
||||
EFI_DEVICE_PATH_PROTOCOL *path;
|
||||
void *interface;
|
||||
} path;
|
||||
EFI_DEVICE_PATH_PROTOCOL *path_end;
|
||||
size_t path_len;
|
||||
EFI_STATUS efirc;
|
||||
int rc;
|
||||
|
||||
/* Open device path */
|
||||
if ( ( efirc = bs->OpenProtocol ( device,
|
||||
&efi_device_path_protocol_guid,
|
||||
&path.interface, efi_image_handle,
|
||||
device,
|
||||
EFI_OPEN_PROTOCOL_GET_PROTOCOL ))!=0){
|
||||
rc = -EEFI ( efirc );
|
||||
DBGC ( device, "EFIDRV %s could not open device path: %s\n",
|
||||
efi_handle_name ( device ), strerror ( rc ) );
|
||||
goto err_open_path;
|
||||
}
|
||||
path_len = ( efi_path_len ( path.path ) + sizeof ( *path_end ) );
|
||||
|
||||
/* Allocate and initialise structure */
|
||||
efidev = zalloc ( sizeof ( *efidev ) + path_len );
|
||||
if ( ! efidev )
|
||||
goto err_alloc;
|
||||
efidev->device = device;
|
||||
efidev->dev.desc.bus_type = BUS_TYPE_EFI;
|
||||
efidev->path = ( ( ( void * ) efidev ) + sizeof ( *efidev ) );
|
||||
memcpy ( efidev->path, path.path, path_len );
|
||||
INIT_LIST_HEAD ( &efidev->dev.children );
|
||||
list_add ( &efidev->dev.siblings, &efi_devices );
|
||||
|
||||
err_alloc:
|
||||
bs->CloseProtocol ( device, &efi_device_path_protocol_guid,
|
||||
efi_image_handle, device );
|
||||
err_open_path:
|
||||
return efidev;
|
||||
}
|
||||
|
||||
/**
|
||||
* Free EFI device
|
||||
*
|
||||
* @v efidev EFI device
|
||||
*/
|
||||
void efidev_free ( struct efi_device *efidev ) {
|
||||
|
||||
assert ( list_empty ( &efidev->dev.children ) );
|
||||
list_del ( &efidev->dev.siblings );
|
||||
free ( efidev );
|
||||
}
|
||||
|
||||
/**
|
||||
* Find EFI device
|
||||
*
|
||||
|
@ -159,16 +220,9 @@ efi_driver_supported ( EFI_DRIVER_BINDING_PROTOCOL *driver __unused,
|
|||
static EFI_STATUS EFIAPI
|
||||
efi_driver_start ( EFI_DRIVER_BINDING_PROTOCOL *driver __unused,
|
||||
EFI_HANDLE device, EFI_DEVICE_PATH_PROTOCOL *child ) {
|
||||
EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
|
||||
struct efi_driver *efidrv;
|
||||
struct efi_device *efidev;
|
||||
struct efi_saved_tpl tpl;
|
||||
union {
|
||||
EFI_DEVICE_PATH_PROTOCOL *path;
|
||||
void *interface;
|
||||
} path;
|
||||
EFI_DEVICE_PATH_PROTOCOL *path_end;
|
||||
size_t path_len;
|
||||
EFI_STATUS efirc;
|
||||
int rc;
|
||||
|
||||
|
@ -197,36 +251,12 @@ efi_driver_start ( EFI_DRIVER_BINDING_PROTOCOL *driver __unused,
|
|||
goto err_disconnecting;
|
||||
}
|
||||
|
||||
/* Open device path */
|
||||
if ( ( efirc = bs->OpenProtocol ( device,
|
||||
&efi_device_path_protocol_guid,
|
||||
&path.interface, efi_image_handle,
|
||||
device,
|
||||
EFI_OPEN_PROTOCOL_GET_PROTOCOL ))!=0){
|
||||
rc = -EEFI ( efirc );
|
||||
DBGC ( device, "EFIDRV %s could not open device path: %s\n",
|
||||
efi_handle_name ( device ), strerror ( rc ) );
|
||||
goto err_open_path;
|
||||
}
|
||||
path_len = ( efi_path_len ( path.path ) + sizeof ( *path_end ) );
|
||||
|
||||
/* Allocate and initialise structure */
|
||||
efidev = zalloc ( sizeof ( *efidev ) + path_len );
|
||||
/* Add new device */
|
||||
efidev = efidev_alloc ( device );
|
||||
if ( ! efidev ) {
|
||||
efirc = EFI_OUT_OF_RESOURCES;
|
||||
goto err_alloc;
|
||||
}
|
||||
efidev->device = device;
|
||||
efidev->dev.desc.bus_type = BUS_TYPE_EFI;
|
||||
efidev->path = ( ( ( void * ) efidev ) + sizeof ( *efidev ) );
|
||||
memcpy ( efidev->path, path.path, path_len );
|
||||
INIT_LIST_HEAD ( &efidev->dev.children );
|
||||
list_add ( &efidev->dev.siblings, &efi_devices );
|
||||
|
||||
/* Close device path */
|
||||
bs->CloseProtocol ( device, &efi_device_path_protocol_guid,
|
||||
efi_image_handle, device );
|
||||
path.path = NULL;
|
||||
|
||||
/* Try to start this device */
|
||||
for_each_table_entry ( efidrv, EFI_DRIVERS ) {
|
||||
|
@ -251,14 +281,8 @@ efi_driver_start ( EFI_DRIVER_BINDING_PROTOCOL *driver __unused,
|
|||
}
|
||||
efirc = EFI_UNSUPPORTED;
|
||||
|
||||
list_del ( &efidev->dev.siblings );
|
||||
free ( efidev );
|
||||
efidev_free ( efidev );
|
||||
err_alloc:
|
||||
if ( path.path ) {
|
||||
bs->CloseProtocol ( device, &efi_device_path_protocol_guid,
|
||||
efi_image_handle, device );
|
||||
}
|
||||
err_open_path:
|
||||
err_disconnecting:
|
||||
efi_restore_tpl ( &tpl );
|
||||
err_already_started:
|
||||
|
@ -306,8 +330,7 @@ efi_driver_stop ( EFI_DRIVER_BINDING_PROTOCOL *driver __unused,
|
|||
efidrv = efidev->driver;
|
||||
assert ( efidrv != NULL );
|
||||
efidrv->stop ( efidev );
|
||||
list_del ( &efidev->dev.siblings );
|
||||
free ( efidev );
|
||||
efidev_free ( efidev );
|
||||
|
||||
efi_restore_tpl ( &tpl );
|
||||
return 0;
|
||||
|
|
Loading…
Reference in New Issue