]> git.ipfire.org Git - thirdparty/ipxe.git/commitdiff
[efi] Allow for allocating EFI devices from arbitrary handles
authorMichael Brown <mcb30@ipxe.org>
Fri, 29 Mar 2024 12:43:24 +0000 (12:43 +0000)
committerMichael Brown <mcb30@ipxe.org>
Fri, 29 Mar 2024 14:46:13 +0000 (14:46 +0000)
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>
src/include/ipxe/efi/efi_driver.h
src/interface/efi/efi_driver.c

index 411e9364232adac6cd19caf597c26895ad913126..7b64e1e0b9db407e0bdaf563e9dc243a9c77c463 100644 (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 );
index 8f8c9f3da36a69538486cdec82b6e7820abb0fa3..fd9be5f51954877c00b8dab9cd3f7427210fbbe4 100644 (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;