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;
|
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 struct efi_device * efidev_parent ( struct device *dev );
|
||||||
extern int efi_driver_install ( void );
|
extern int efi_driver_install ( void );
|
||||||
extern void efi_driver_uninstall ( void );
|
extern void efi_driver_uninstall ( void );
|
||||||
|
|
|
@ -61,6 +61,67 @@ static LIST_HEAD ( efi_devices );
|
||||||
/** We are currently disconnecting drivers */
|
/** We are currently disconnecting drivers */
|
||||||
static int efi_driver_disconnecting;
|
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
|
* Find EFI device
|
||||||
*
|
*
|
||||||
|
@ -159,16 +220,9 @@ efi_driver_supported ( EFI_DRIVER_BINDING_PROTOCOL *driver __unused,
|
||||||
static EFI_STATUS EFIAPI
|
static EFI_STATUS EFIAPI
|
||||||
efi_driver_start ( EFI_DRIVER_BINDING_PROTOCOL *driver __unused,
|
efi_driver_start ( EFI_DRIVER_BINDING_PROTOCOL *driver __unused,
|
||||||
EFI_HANDLE device, EFI_DEVICE_PATH_PROTOCOL *child ) {
|
EFI_HANDLE device, EFI_DEVICE_PATH_PROTOCOL *child ) {
|
||||||
EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
|
|
||||||
struct efi_driver *efidrv;
|
struct efi_driver *efidrv;
|
||||||
struct efi_device *efidev;
|
struct efi_device *efidev;
|
||||||
struct efi_saved_tpl tpl;
|
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;
|
EFI_STATUS efirc;
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
|
@ -197,36 +251,12 @@ efi_driver_start ( EFI_DRIVER_BINDING_PROTOCOL *driver __unused,
|
||||||
goto err_disconnecting;
|
goto err_disconnecting;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Open device path */
|
/* Add new device */
|
||||||
if ( ( efirc = bs->OpenProtocol ( device,
|
efidev = efidev_alloc ( 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 ) {
|
if ( ! efidev ) {
|
||||||
efirc = EFI_OUT_OF_RESOURCES;
|
efirc = EFI_OUT_OF_RESOURCES;
|
||||||
goto err_alloc;
|
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 */
|
/* Try to start this device */
|
||||||
for_each_table_entry ( efidrv, EFI_DRIVERS ) {
|
for_each_table_entry ( efidrv, EFI_DRIVERS ) {
|
||||||
|
@ -251,14 +281,8 @@ efi_driver_start ( EFI_DRIVER_BINDING_PROTOCOL *driver __unused,
|
||||||
}
|
}
|
||||||
efirc = EFI_UNSUPPORTED;
|
efirc = EFI_UNSUPPORTED;
|
||||||
|
|
||||||
list_del ( &efidev->dev.siblings );
|
efidev_free ( efidev );
|
||||||
free ( efidev );
|
|
||||||
err_alloc:
|
err_alloc:
|
||||||
if ( path.path ) {
|
|
||||||
bs->CloseProtocol ( device, &efi_device_path_protocol_guid,
|
|
||||||
efi_image_handle, device );
|
|
||||||
}
|
|
||||||
err_open_path:
|
|
||||||
err_disconnecting:
|
err_disconnecting:
|
||||||
efi_restore_tpl ( &tpl );
|
efi_restore_tpl ( &tpl );
|
||||||
err_already_started:
|
err_already_started:
|
||||||
|
@ -306,8 +330,7 @@ efi_driver_stop ( EFI_DRIVER_BINDING_PROTOCOL *driver __unused,
|
||||||
efidrv = efidev->driver;
|
efidrv = efidev->driver;
|
||||||
assert ( efidrv != NULL );
|
assert ( efidrv != NULL );
|
||||||
efidrv->stop ( efidev );
|
efidrv->stop ( efidev );
|
||||||
list_del ( &efidev->dev.siblings );
|
efidev_free ( efidev );
|
||||||
free ( efidev );
|
|
||||||
|
|
||||||
efi_restore_tpl ( &tpl );
|
efi_restore_tpl ( &tpl );
|
||||||
return 0;
|
return 0;
|
||||||
|
|
Loading…
Reference in New Issue