summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMichael Brown2024-03-22 17:50:13 +0100
committerMichael Brown2024-03-25 18:58:33 +0100
commitda5188f3ea73900f1c6a4e44a8345b48320d396f (patch)
treed9adcce6a6b91145a2b34f91132d7bfe9d521d1b
parent[efi] Add helper functions for service binding protocols (diff)
downloadipxe-da5188f3ea73900f1c6a4e44a8345b48320d396f.tar.gz
ipxe-da5188f3ea73900f1c6a4e44a8345b48320d396f.tar.xz
ipxe-da5188f3ea73900f1c6a4e44a8345b48320d396f.zip
[efi] Allow for drivers to be located via child handles
When using a service binding protocol, CreateChild() will create a new protocol instance (and optionally a new handle). The caller will then typically open this new protocol instance with BY_DRIVER attributes, since the service binding mechanism has no equivalent of the driver binding protocol's Stop() method, and there is therefore no other way for the caller to be informed if the protocol instance is about to become invalid (e.g. because the service driver wants to remove the child). The caller cannot ask CreateChild() to install the new protocol instance on the original handle (i.e. the service binding handle), since the whole point of the service binding protocol is to allow for the existence of multiple children, and UEFI does not permit multiple instances of the same protocol to be installed on a handle. Our current drivers all open the original handle (as passed to our driver binding's Start() method) with BY_DRIVER attributes, and so the same handle will be passed to our Stop() method. This changes when our driver must use a separate handle, as described above. Add an optional "child handle" field to struct efi_device (on the assumption that we will not have any drivers that need to create multiple children), and generalise efidev_find() to match on either the original handle or the child handle. 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.c10
2 files changed, 10 insertions, 2 deletions
diff --git a/src/include/ipxe/efi/efi_driver.h b/src/include/ipxe/efi/efi_driver.h
index 74ece90d..411e9364 100644
--- a/src/include/ipxe/efi/efi_driver.h
+++ b/src/include/ipxe/efi/efi_driver.h
@@ -19,6 +19,8 @@ struct efi_device {
struct device dev;
/** EFI device handle */
EFI_HANDLE device;
+ /** EFI child device handle (if present) */
+ EFI_HANDLE child;
/** EFI device path copy */
EFI_DEVICE_PATH_PROTOCOL *path;
/** Driver for this device */
diff --git a/src/interface/efi/efi_driver.c b/src/interface/efi/efi_driver.c
index 8e537d53..8f8c9f3d 100644
--- a/src/interface/efi/efi_driver.c
+++ b/src/interface/efi/efi_driver.c
@@ -64,16 +64,22 @@ static int efi_driver_disconnecting;
/**
* Find EFI device
*
- * @v device EFI device handle
+ * @v device EFI device handle (or child handle)
* @ret efidev EFI device, or NULL if not found
*/
static struct efi_device * efidev_find ( EFI_HANDLE device ) {
struct efi_device *efidev;
+ /* Avoid false positive matches against NULL children */
+ if ( ! device )
+ return NULL;
+
/* Look for an existing EFI device */
list_for_each_entry ( efidev, &efi_devices, dev.siblings ) {
- if ( efidev->device == device )
+ if ( ( device == efidev->device ) ||
+ ( device == efidev->child ) ) {
return efidev;
+ }
}
return NULL;