summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMichael Brown2024-03-29 13:43:24 +0100
committerMichael Brown2024-03-29 15:46:13 +0100
commitb52b4a46d9ee854130db7a8927f33391fc6ba1fe (patch)
treec368cac28dc284799b8405d2a867e3b179d879bc
parent[http] Add error table entry for HTTP 404 Not Found error (diff)
downloadipxe-b52b4a46d9ee854130db7a8927f33391fc6ba1fe.tar.gz
ipxe-b52b4a46d9ee854130db7a8927f33391fc6ba1fe.tar.xz
ipxe-b52b4a46d9ee854130db7a8927f33391fc6ba1fe.zip
[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>
-rw-r--r--src/include/ipxe/efi/efi_driver.h2
-rw-r--r--src/interface/efi/efi_driver.c107
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
@@ -62,6 +62,67 @@ static LIST_HEAD ( efi_devices );
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
*
* @v device EFI device handle (or child handle)
@@ -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;