From b52b4a46d9ee854130db7a8927f33391fc6ba1fe Mon Sep 17 00:00:00 2001 From: Michael Brown Date: Fri, 29 Mar 2024 12:43:24 +0000 Subject: [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 --- src/include/ipxe/efi/efi_driver.h | 2 + src/interface/efi/efi_driver.c | 107 +++++++++++++++++++++++--------------- 2 files changed, 67 insertions(+), 42 deletions(-) diff --git a/src/include/ipxe/efi/efi_driver.h b/src/include/ipxe/efi/efi_driver.h index 411e9364..7b64e1e0 100644 --- a/src/include/ipxe/efi/efi_driver.h +++ b/src/include/ipxe/efi/efi_driver.h @@ -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 ); diff --git a/src/interface/efi/efi_driver.c b/src/interface/efi/efi_driver.c index 8f8c9f3d..fd9be5f5 100644 --- a/src/interface/efi/efi_driver.c +++ b/src/interface/efi/efi_driver.c @@ -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; -- cgit v1.2.3-55-g7522