[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
Michael Brown 2024-03-29 12:43:24 +00:00
parent 764e34f15a
commit b52b4a46d9
2 changed files with 67 additions and 42 deletions

View File

@ -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 );

View File

@ -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;