[U-Boot] [RFC v2 01/15] efi_loader: efi objects and protocols as DM devices

AKASHI Takahiro takahiro.akashi at linaro.org
Fri Feb 8 08:15:28 UTC 2019


All efi objects are presented as DM devices, either existing device types
or efi-specific, and efi_handle_t is an opaque pointer to "struct udevice."

We still maintain efi_obj_list as it is quite inefficient to traverse
the DM hierarchy to find any efi objects, which are just part of it.

All efi protocols are also presented as DM devices, replacing
"struct efi_handler" with "struct udevice." So searching for an efi
protocol is nothing but traversing child nodes under a device.

Signed-off-by: AKASHI Takahiro <takahiro.akashi at linaro.org>
---
 include/dm/device.h           |   3 +
 include/dm/uclass-id.h        |   2 +
 include/efi.h                 |   4 +-
 include/efi_loader.h          |  37 +--
 lib/efi_loader/efi_boottime.c | 544 ++++++++++++++++++++++++----------
 5 files changed, 400 insertions(+), 190 deletions(-)

diff --git a/include/dm/device.h b/include/dm/device.h
index 27a6d7b9fdb0..0d82402c8e70 100644
--- a/include/dm/device.h
+++ b/include/dm/device.h
@@ -146,6 +146,9 @@ struct udevice {
 #ifdef CONFIG_DEVRES
 	struct list_head devres_head;
 #endif
+#ifdef CONFIG_EFI_LOADER
+	void *efi_obj;
+#endif
 };
 
 /* Maximum sequence number supported */
diff --git a/include/dm/uclass-id.h b/include/dm/uclass-id.h
index f3bafb3c6353..fb0ab40891c8 100644
--- a/include/dm/uclass-id.h
+++ b/include/dm/uclass-id.h
@@ -40,6 +40,8 @@ enum uclass_id {
 	UCLASS_DISPLAY,		/* Display (e.g. DisplayPort, HDMI) */
 	UCLASS_DMA,		/* Direct Memory Access */
 	UCLASS_EFI,		/* EFI managed devices */
+	UCLASS_EFI_OBJECT,	/* EFI managed objects */
+	UCLASS_EFI_PROTOCOL,	/* EFI managed protocols */
 	UCLASS_ETH,		/* Ethernet device */
 	UCLASS_FIRMWARE,	/* Firmware */
 	UCLASS_FS_FIRMWARE_LOADER,		/* Generic loader */
diff --git a/include/efi.h b/include/efi.h
index b5e2c64f38b5..58902299a9a0 100644
--- a/include/efi.h
+++ b/include/efi.h
@@ -96,7 +96,9 @@ typedef struct {
 typedef unsigned long efi_status_t;
 typedef u64 efi_physical_addr_t;
 typedef u64 efi_virtual_addr_t;
-typedef struct efi_object *efi_handle_t;
+/* Eventually this should be 'void *' */
+struct udevice;
+typedef struct udevice *efi_handle_t;
 
 #define EFI_GUID(a, b, c, d0, d1, d2, d3, d4, d5, d6, d7) \
 	{{ (a) & 0xff, ((a) >> 8) & 0xff, ((a) >> 16) & 0xff, \
diff --git a/include/efi_loader.h b/include/efi_loader.h
index 3077a1e9d58b..4d5e22564a72 100644
--- a/include/efi_loader.h
+++ b/include/efi_loader.h
@@ -167,38 +167,12 @@ struct efi_open_protocol_info_item {
  * protocol GUID to the respective protocol interface
  */
 struct efi_handler {
-	/* Link to the list of protocols of a handle */
-	struct list_head link;
 	const efi_guid_t *guid;
 	void *protocol_interface;
 	/* Link to the list of open protocol info items */
 	struct list_head open_infos;
 };
 
-/**
- * struct efi_object - dereferenced EFI handle
- *
- * @link:	pointers to put the handle into a linked list
- * @protocols:	linked list with the protocol interfaces installed on this
- *		handle
- *
- * UEFI offers a flexible and expandable object model. The objects in the UEFI
- * API are devices, drivers, and loaded images. struct efi_object is our storage
- * structure for these objects.
- *
- * When including this structure into a larger structure always put it first so
- * that when deleting a handle the whole encompassing structure can be freed.
- *
- * A pointer to this structure is referred to as a handle. Typedef efi_handle_t
- * has been created for such pointers.
- */
-struct efi_object {
-	/* Every UEFI object is part of a global object list */
-	struct list_head link;
-	/* The list of protocols */
-	struct list_head protocols;
-};
-
 /**
  * struct efi_loaded_image_obj - handle of a loaded image
  *
@@ -209,7 +183,6 @@ struct efi_object {
  * @entry:		entry address of the relocated image
  */
 struct efi_loaded_image_obj {
-	struct efi_object header;
 	void *reloc_base;
 	aligned_u64 reloc_size;
 	efi_status_t exit_status;
@@ -312,18 +285,18 @@ void efi_restore_gd(void);
 void efi_runtime_relocate(ulong offset, struct efi_mem_desc *map);
 /* Call this to set the current device name */
 void efi_set_bootdev(const char *dev, const char *devnr, const char *path);
+/* Go through all the efi objects and call func() for each */
+efi_status_t efi_foreach_dev(int (*func)(struct udevice *, void *), void *arg);
 /* Add a new object to the object list. */
-void efi_add_handle(efi_handle_t obj);
+efi_status_t efi_add_handle(struct udevice *dev);
 /* Create handle */
-efi_status_t efi_create_handle(efi_handle_t *handle);
+efi_status_t efi_create_handle(efi_handle_t *handle, char *name);
 /* Delete handle */
 void efi_delete_handle(efi_handle_t obj);
-/* Call this to validate a handle and find the EFI object for it */
-struct efi_object *efi_search_obj(const efi_handle_t handle);
 /* Find a protocol on a handle */
 efi_status_t efi_search_protocol(const efi_handle_t handle,
 				 const efi_guid_t *protocol_guid,
-				 struct efi_handler **handler);
+				 struct udevice **protocol);
 /* Install new protocol on a handle */
 efi_status_t efi_add_protocol(const efi_handle_t handle,
 			      const efi_guid_t *protocol,
diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c
index 291bc1bd35f9..d23e4fbbdf23 100644
--- a/lib/efi_loader/efi_boottime.c
+++ b/lib/efi_loader/efi_boottime.c
@@ -7,6 +7,10 @@
 
 #include <common.h>
 #include <div64.h>
+#include <dm.h>
+#include <dm/device-internal.h>
+#include <dm/lists.h>
+#include <dm/root.h>
 #include <efi_loader.h>
 #include <environment.h>
 #include <malloc.h>
@@ -17,6 +21,13 @@
 
 DECLARE_GLOBAL_DATA_PTR;
 
+struct efi_object {
+	/* Every UEFI object is part of a global object list */
+	struct list_head link;
+	/* The backing uclass device */
+	struct udevice *dev;
+};
+
 /* Task priority level */
 static efi_uintn_t efi_tpl = TPL_APPLICATION;
 
@@ -418,70 +429,125 @@ static efi_status_t EFIAPI efi_free_pool_ext(void *buffer)
 	return EFI_EXIT(r);
 }
 
+static bool efi_is_valid(efi_handle_t handle)
+{
+	struct efi_object *efiobj;
+
+	list_for_each_entry(efiobj, &efi_obj_list, link) {
+		if (efiobj->dev == handle)
+			return true;
+	}
+
+	return false;
+}
+
+/**
+ * efi_foreach_dev()
+ */
+efi_status_t efi_foreach_dev(int (*func)(struct udevice *, void *), void *arg)
+{
+	int ret;
+	struct efi_object *efiobj;
+
+	list_for_each_entry(efiobj, &efi_obj_list, link) {
+		ret = (*func)(efiobj->dev, arg);
+		if (ret == 1)
+			return EFI_SUCCESS;
+	}
+
+	return EFI_NOT_FOUND;
+}
+
 /**
  * efi_add_handle() - add a new object to the object list
- * @obj: object to be added
+ * @handle: udevice to be added as object
  *
  * The protocols list is initialized. The object handle is set.
  */
-void efi_add_handle(efi_handle_t handle)
+efi_status_t efi_add_handle(struct udevice *dev)
 {
-	if (!handle)
-		return;
-	INIT_LIST_HEAD(&handle->protocols);
-	list_add_tail(&handle->link, &efi_obj_list);
+	struct efi_object *efi_obj;
+
+	if (!dev)
+		return EFI_INVALID_PARAMETER;
+
+	efi_obj = calloc(1, sizeof(struct efi_object));
+	if (!efi_obj)
+		return EFI_OUT_OF_RESOURCES;
+
+	efi_obj->dev = dev;
+	dev->efi_obj = efi_obj;
+	list_add_tail(&efi_obj->link, &efi_obj_list);
+
+	return EFI_SUCCESS;
 }
 
 /**
  * efi_create_handle() - create handle
  * @handle: new handle
+ * @name: name
  *
  * Return: status code
  */
-efi_status_t efi_create_handle(efi_handle_t *handle)
+efi_status_t efi_create_handle(efi_handle_t *handle, char *name)
 {
-	struct efi_object *obj;
+	struct udevice *dev;
+	efi_status_t ret;
+
+	if (!handle)
+		return EFI_INVALID_PARAMETER;
 
-	obj = calloc(1, sizeof(struct efi_object));
-	if (!obj)
+	ret = device_bind_driver(dm_root(), "efi_dumb_object", name, &dev);
+	if (ret)
 		return EFI_OUT_OF_RESOURCES;
 
-	efi_add_handle(obj);
-	*handle = obj;
+	ret = efi_add_handle(dev);
+	if (ret)
+#ifdef CONFIG_DM_DEVICE_REMOVE
+		device_unbind(dev);
+#else
+		0;
+#endif
+	else
+		*handle = dev;
 
-	return EFI_SUCCESS;
+	return ret;
 }
 
 /**
  * efi_search_protocol() - find a protocol on a handle.
  * @handle:        handle
  * @protocol_guid: GUID of the protocol
- * @handler:       reference to the protocol
+ * @protocol:      reference to the protocol
  *
  * Return: status code
  */
 efi_status_t efi_search_protocol(const efi_handle_t handle,
 				 const efi_guid_t *protocol_guid,
-				 struct efi_handler **handler)
+				 struct udevice **protocol)
 {
-	struct efi_object *efiobj;
-	struct list_head *lhandle;
+	struct udevice *dev, *child;
+	struct efi_handler *handler;
 
 	if (!handle || !protocol_guid)
 		return EFI_INVALID_PARAMETER;
-	efiobj = efi_search_obj(handle);
-	if (!efiobj)
+
+	if (!efi_is_valid(handle))
 		return EFI_INVALID_PARAMETER;
-	list_for_each(lhandle, &efiobj->protocols) {
-		struct efi_handler *protocol;
+	dev = handle;
+
+	list_for_each_entry(child, &dev->child_head, sibling_node) {
+		if (child->driver->id != UCLASS_EFI_PROTOCOL)
+			continue;
 
-		protocol = list_entry(lhandle, struct efi_handler, link);
-		if (!guidcmp(protocol->guid, protocol_guid)) {
-			if (handler)
-				*handler = protocol;
+		handler = child->uclass_platdata;
+		if (!guidcmp(handler->guid, protocol_guid)) {
+			if (protocol)
+				*protocol = child;
 			return EFI_SUCCESS;
 		}
 	}
+
 	return EFI_NOT_FOUND;
 }
 
@@ -494,21 +560,33 @@ efi_status_t efi_search_protocol(const efi_handle_t handle,
  * Return: status code
  */
 efi_status_t efi_remove_protocol(const efi_handle_t handle,
-				 const efi_guid_t *protocol,
+				 const efi_guid_t *protocol_guid,
 				 void *protocol_interface)
 {
+	struct udevice *protocol;
 	struct efi_handler *handler;
 	efi_status_t ret;
 
-	ret = efi_search_protocol(handle, protocol, &handler);
+	ret = efi_search_protocol(handle, protocol_guid, &protocol);
 	if (ret != EFI_SUCCESS)
 		return ret;
-	if (guidcmp(handler->guid, protocol))
+
+	handler = protocol->uclass_platdata;
+	if (guidcmp(handler->guid, protocol_guid))
 		return EFI_INVALID_PARAMETER;
+
 	if (handler->protocol_interface != protocol_interface)
 		return EFI_INVALID_PARAMETER;
+
+#if 1 /* FIXME */
+	device_free(protocol);
+#ifdef CONFIG_DM_DEVICE_REMOVE
+	device_unbind(protocol);
+#endif
+#else
 	list_del(&handler->link);
 	free(handler);
+#endif
 	return EFI_SUCCESS;
 }
 
@@ -520,24 +598,46 @@ efi_status_t efi_remove_protocol(const efi_handle_t handle,
  */
 efi_status_t efi_remove_all_protocols(const efi_handle_t handle)
 {
-	struct efi_object *efiobj;
-	struct efi_handler *protocol;
-	struct efi_handler *pos;
+	struct udevice *dev, *child, *pos;
+	struct efi_handler *handler;
 
-	efiobj = efi_search_obj(handle);
-	if (!efiobj)
+	if (!efi_is_valid(handle))
 		return EFI_INVALID_PARAMETER;
-	list_for_each_entry_safe(protocol, pos, &efiobj->protocols, link) {
+	dev = handle;
+
+	list_for_each_entry_safe(child, pos, &dev->child_head, sibling_node) {
 		efi_status_t ret;
 
-		ret = efi_remove_protocol(handle, protocol->guid,
-					  protocol->protocol_interface);
+		if (child->driver->id != UCLASS_EFI_PROTOCOL)
+			continue;
+
+		handler = child->uclass_platdata;
+		ret = efi_remove_protocol(handle, handler->guid,
+					  handler->protocol_interface);
 		if (ret != EFI_SUCCESS)
 			return ret;
 	}
 	return EFI_SUCCESS;
 }
 
+static void efi_remove_handle(efi_handle_t handle)
+{
+	struct udevice *dev = handle;
+	struct efi_object *efi_obj = dev->efi_obj;
+
+	list_del(&efi_obj->link);
+	free(efi_obj);
+
+	/* free only if internal object */
+	if (dev->driver->id == UCLASS_EFI_OBJECT) {
+#ifdef CONFIG_DM_DEVICE_REMOVE
+		device_unbind(dev);
+#endif
+	}
+
+	/* native device handle should be taken care of by caller */
+}
+
 /**
  * efi_delete_handle() - delete handle
  *
@@ -547,9 +647,9 @@ void efi_delete_handle(efi_handle_t handle)
 {
 	if (!handle)
 		return;
+
 	efi_remove_all_protocols(handle);
-	list_del(&handle->link);
-	free(handle);
+	efi_remove_handle(handle);
 }
 
 /**
@@ -923,24 +1023,6 @@ static efi_status_t EFIAPI efi_check_event(struct efi_event *event)
 	return EFI_EXIT(EFI_NOT_READY);
 }
 
-/**
- * efi_search_obj() - find the internal EFI object for a handle
- * @handle: handle to find
- *
- * Return: EFI object
- */
-struct efi_object *efi_search_obj(const efi_handle_t handle)
-{
-	struct efi_object *efiobj;
-
-	list_for_each_entry(efiobj, &efi_obj_list, link) {
-		if (efiobj == handle)
-			return efiobj;
-	}
-
-	return NULL;
-}
-
 /**
  * efi_open_protocol_info_entry() - create open protocol info entry and add it
  *                                  to a protocol
@@ -976,6 +1058,88 @@ static efi_status_t efi_delete_open_info(
 	return EFI_SUCCESS;
 }
 
+/* FIXME */
+extern const efi_guid_t efi_guid_text_input_ex_protocol;
+extern const efi_guid_t efi_guid_text_input_protocol;
+extern const efi_guid_t efi_guid_text_output_protocol;
+extern const efi_guid_t efi_gop_guid;
+extern const efi_guid_t efi_net_guid;
+extern const efi_guid_t efi_pxe_guid;
+
+/* TODO: add entries one by one */
+static struct {
+	const efi_guid_t *guid;
+	const char *drv_name;
+} protocol_list[] = {
+	{
+		.guid = &efi_guid_text_input_ex_protocol,
+		.drv_name = "efi_simple_text_input_ex",
+	},
+	{
+		.guid = &efi_guid_text_input_protocol,
+		.drv_name = "efi_simple_text_input",
+	},
+	{
+		.guid = &efi_guid_text_output_protocol,
+		.drv_name = "efi_simple_text_output",
+	},
+	{
+		.guid = &efi_guid_device_path,
+		.drv_name = "efi_device_path",
+	},
+	{
+		.guid = &efi_guid_device_path_to_text_protocol,
+		.drv_name = "efi_device_path_to_text",
+	},
+	{
+		.guid = &efi_guid_device_path_utilities_protocol,
+		.drv_name = "efi_device_path_utils",
+	},
+#if defined(CONFIG_LCD) || defined(CONFIG_DM_VIDEO)
+	{
+		.guid = &efi_gop_guid,
+		.drv_name = "efi_gop",
+	},
+#endif
+#if defined(CONFIG_NET)
+	{
+		.guid = &efi_net_guid,
+		.drv_name = "efi_net",
+	},
+	{
+		.guid = &efi_net_guid,
+		.drv_name = "efi_pxe",
+	},
+#endif
+	{
+		.guid = &efi_guid_unicode_collation_protocol,
+		.drv_name = "efi_unicode_collation",
+	},
+	{
+		.guid = &efi_block_io_guid,
+		.drv_name = "efi_disk",
+	},
+	{
+		.guid = &efi_simple_file_system_protocol_guid,
+		.drv_name = "efi_simple_file_system",
+	},
+	{
+		.guid = &efi_guid_driver_binding_protocol,
+		.drv_name = "efi_driver_binding",
+	},
+};
+
+static const char *get_protocol_drv_name(const efi_guid_t *guid)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(protocol_list); i++)
+		if (!guidcmp(protocol_list[i].guid, guid))
+			return protocol_list[i].drv_name;
+
+	return "efi_protocol";
+}
+
 /**
  * efi_add_protocol() - install new protocol on a handle
  * @handle:             handle on which the protocol shall be installed
@@ -985,28 +1149,36 @@ static efi_status_t efi_delete_open_info(
  * Return: status code
  */
 efi_status_t efi_add_protocol(const efi_handle_t handle,
-			      const efi_guid_t *protocol,
+			      const efi_guid_t *protocol_guid,
 			      void *protocol_interface)
 {
-	struct efi_object *efiobj;
+	struct udevice *dev, *protocol;
 	struct efi_handler *handler;
 	efi_status_t ret;
 
-	efiobj = efi_search_obj(handle);
-	if (!efiobj)
+	if (!efi_is_valid(handle))
 		return EFI_INVALID_PARAMETER;
-	ret = efi_search_protocol(handle, protocol, NULL);
+	dev = handle;
+
+	ret = efi_search_protocol(handle, protocol_guid, NULL);
 	if (ret != EFI_NOT_FOUND)
 		return EFI_INVALID_PARAMETER;
-	handler = calloc(1, sizeof(struct efi_handler));
-	if (!handler)
+
+	ret = device_bind_driver(dev, get_protocol_drv_name(protocol_guid),
+				 "(PROTO)", &protocol);
+	if (ret)
 		return EFI_OUT_OF_RESOURCES;
-	handler->guid = protocol;
+
+	handler = protocol->uclass_platdata;
+	handler->guid = protocol_guid;
 	handler->protocol_interface = protocol_interface;
 	INIT_LIST_HEAD(&handler->open_infos);
-	list_add_tail(&handler->link, &efiobj->protocols);
-	if (!guidcmp(&efi_guid_device_path, protocol))
+
+	device_probe(protocol);
+
+	if (!guidcmp(&efi_guid_device_path, protocol_guid))
 		EFI_PRINT("installed device path '%pD'\n", protocol_interface);
+
 	return EFI_SUCCESS;
 }
 
@@ -1042,7 +1214,7 @@ static efi_status_t EFIAPI efi_install_protocol_interface(
 
 	/* Create new handle if requested. */
 	if (!*handle) {
-		r = efi_create_handle(handle);
+		r = efi_create_handle(handle, "(NO NAME)");
 		if (r != EFI_SUCCESS)
 			goto out;
 		debug("%sEFI: new handle %p\n", indent_string(nesting_level),
@@ -1073,13 +1245,20 @@ static efi_status_t efi_get_drivers(efi_handle_t handle,
 				    efi_uintn_t *number_of_drivers,
 				    efi_handle_t **driver_handle_buffer)
 {
+	struct udevice *dev, *child;
 	struct efi_handler *handler;
 	struct efi_open_protocol_info_item *item;
 	efi_uintn_t count = 0, i;
 	bool duplicate;
 
+	dev = handle;
+
 	/* Count all driver associations */
-	list_for_each_entry(handler, &handle->protocols, link) {
+	list_for_each_entry(child, &dev->child_head, sibling_node) {
+		if (child->driver->id != UCLASS_EFI_PROTOCOL)
+			continue;
+
+		handler = child->uclass_platdata;
 		if (protocol && guidcmp(handler->guid, protocol))
 			continue;
 		list_for_each_entry(item, &handler->open_infos, link) {
@@ -1097,7 +1276,11 @@ static efi_status_t efi_get_drivers(efi_handle_t handle,
 	if (!*driver_handle_buffer)
 		return EFI_OUT_OF_RESOURCES;
 	/* Collect unique driver handles */
-	list_for_each_entry(handler, &handle->protocols, link) {
+	list_for_each_entry(child, &dev->child_head, sibling_node) {
+		if (child->driver->id != UCLASS_EFI_PROTOCOL)
+			continue;
+
+		handler = child->uclass_platdata;
 		if (protocol && guidcmp(handler->guid, protocol))
 			continue;
 		list_for_each_entry(item, &handler->open_infos, link) {
@@ -1173,28 +1356,27 @@ static efi_status_t efi_disconnect_all_drivers
  *
  * Return: status code
  */
-static efi_status_t efi_uninstall_protocol
-			(efi_handle_t handle, const efi_guid_t *protocol,
-			 void *protocol_interface)
+static efi_status_t efi_uninstall_protocol(efi_handle_t handle,
+					   const efi_guid_t *protocol_guid,
+					   void *protocol_interface)
 {
-	struct efi_object *efiobj;
+	struct udevice *protocol;
 	struct efi_handler *handler;
 	struct efi_open_protocol_info_item *item;
 	struct efi_open_protocol_info_item *pos;
 	efi_status_t r;
 
-	/* Check handle */
-	efiobj = efi_search_obj(handle);
-	if (!efiobj) {
-		r = EFI_INVALID_PARAMETER;
-		goto out;
-	}
+	if (!efi_is_valid(handle))
+		return EFI_INVALID_PARAMETER;
+
 	/* Find the protocol on the handle */
-	r = efi_search_protocol(handle, protocol, &handler);
+	r = efi_search_protocol(handle, protocol_guid, &protocol);
 	if (r != EFI_SUCCESS)
 		goto out;
+	handler = protocol->uclass_platdata;
+
 	/* Disconnect controllers */
-	efi_disconnect_all_drivers(efiobj, protocol, NULL);
+	efi_disconnect_all_drivers(handle, protocol_guid, NULL);
 	if (!list_empty(&handler->open_infos)) {
 		r =  EFI_ACCESS_DENIED;
 		goto out;
@@ -1211,7 +1393,7 @@ static efi_status_t efi_uninstall_protocol
 		r =  EFI_ACCESS_DENIED;
 		goto out;
 	}
-	r = efi_remove_protocol(handle, protocol, protocol_interface);
+	r = efi_remove_protocol(handle, protocol_guid, protocol_interface);
 out:
 	return r;
 }
@@ -1242,10 +1424,9 @@ static efi_status_t EFIAPI efi_uninstall_protocol_interface
 		goto out;
 
 	/* If the last protocol has been removed, delete the handle. */
-	if (list_empty(&handle->protocols)) {
-		list_del(&handle->link);
-		free(handle);
-	}
+	if (device_find_first_child_by_uclass(handle, UCLASS_EFI_PROTOCOL,
+					      NULL))
+		efi_remove_handle(handle);
 out:
 	return EFI_EXIT(ret);
 }
@@ -1352,7 +1533,7 @@ static efi_status_t efi_locate_handle(
 
 	/* Count how much space we need */
 	list_for_each_entry(efiobj, &efi_obj_list, link) {
-		if (!efi_search(search_type, protocol, search_key, efiobj))
+		if (!efi_search(search_type, protocol, search_key, efiobj->dev))
 			size += sizeof(void *);
 	}
 
@@ -1367,8 +1548,8 @@ static efi_status_t efi_locate_handle(
 
 	/* Then fill the array */
 	list_for_each_entry(efiobj, &efi_obj_list, link) {
-		if (!efi_search(search_type, protocol, search_key, efiobj))
-			*buffer++ = efiobj;
+		if (!efi_search(search_type, protocol, search_key, efiobj->dev))
+			*buffer++ = efiobj->dev;
 	}
 
 	return EFI_SUCCESS;
@@ -2012,25 +2193,27 @@ static efi_status_t EFIAPI efi_set_watchdog_timer(unsigned long timeout,
  * Return: status code
  */
 static efi_status_t EFIAPI efi_close_protocol(efi_handle_t handle,
-					      const efi_guid_t *protocol,
+					      const efi_guid_t *protocol_guid,
 					      efi_handle_t agent_handle,
 					      efi_handle_t controller_handle)
 {
+	struct udevice *protocol;
 	struct efi_handler *handler;
 	struct efi_open_protocol_info_item *item;
 	struct efi_open_protocol_info_item *pos;
 	efi_status_t r;
 
-	EFI_ENTRY("%p, %pUl, %p, %p", handle, protocol, agent_handle,
+	EFI_ENTRY("%p, %pUl, %p, %p", handle, protocol_guid, agent_handle,
 		  controller_handle);
 
 	if (!agent_handle) {
 		r = EFI_INVALID_PARAMETER;
 		goto out;
 	}
-	r = efi_search_protocol(handle, protocol, &handler);
+	r = efi_search_protocol(handle, protocol_guid, &protocol);
 	if (r != EFI_SUCCESS)
 		goto out;
+	handler = protocol->uclass_platdata;
 
 	r = EFI_NOT_FOUND;
 	list_for_each_entry_safe(item, pos, &handler->open_infos, link) {
@@ -2061,17 +2244,18 @@ out:
  * Return: status code
  */
 static efi_status_t EFIAPI efi_open_protocol_information(
-			efi_handle_t handle, const efi_guid_t *protocol,
+			efi_handle_t handle, const efi_guid_t *protocol_guid,
 			struct efi_open_protocol_info_entry **entry_buffer,
 			efi_uintn_t *entry_count)
 {
 	unsigned long buffer_size;
 	unsigned long count;
+	struct udevice *protocol;
 	struct efi_handler *handler;
 	struct efi_open_protocol_info_item *item;
 	efi_status_t r;
 
-	EFI_ENTRY("%p, %pUl, %p, %p", handle, protocol, entry_buffer,
+	EFI_ENTRY("%p, %pUl, %p, %p", handle, protocol_guid, entry_buffer,
 		  entry_count);
 
 	/* Check parameters */
@@ -2079,9 +2263,10 @@ static efi_status_t EFIAPI efi_open_protocol_information(
 		r = EFI_INVALID_PARAMETER;
 		goto out;
 	}
-	r = efi_search_protocol(handle, protocol, &handler);
+	r = efi_search_protocol(handle, protocol_guid, &protocol);
 	if (r != EFI_SUCCESS)
 		goto out;
+	handler = protocol->uclass_platdata;
 
 	/* Count entries */
 	count = 0;
@@ -2127,9 +2312,8 @@ static efi_status_t EFIAPI efi_protocols_per_handle(
 			efi_handle_t handle, efi_guid_t ***protocol_buffer,
 			efi_uintn_t *protocol_buffer_count)
 {
+	struct udevice *dev, *child;
 	unsigned long buffer_size;
-	struct efi_object *efiobj;
-	struct list_head *protocol_handle;
 	efi_status_t r;
 
 	EFI_ENTRY("%p, %p, %p", handle, protocol_buffer,
@@ -2141,12 +2325,15 @@ static efi_status_t EFIAPI efi_protocols_per_handle(
 	*protocol_buffer = NULL;
 	*protocol_buffer_count = 0;
 
-	efiobj = efi_search_obj(handle);
-	if (!efiobj)
-		return EFI_EXIT(EFI_INVALID_PARAMETER);
+	if (!efi_is_valid(handle))
+		return EFI_INVALID_PARAMETER;
+	dev = handle;
 
 	/* Count protocols */
-	list_for_each(protocol_handle, &efiobj->protocols) {
+	list_for_each_entry(child, &dev->child_head, sibling_node) {
+		if (child->driver->id != UCLASS_EFI_PROTOCOL)
+			continue;
+
 		++*protocol_buffer_count;
 	}
 
@@ -2159,12 +2346,15 @@ static efi_status_t EFIAPI efi_protocols_per_handle(
 				      (void **)protocol_buffer);
 		if (r != EFI_SUCCESS)
 			return EFI_EXIT(r);
-		list_for_each(protocol_handle, &efiobj->protocols) {
-			struct efi_handler *protocol;
 
-			protocol = list_entry(protocol_handle,
-					      struct efi_handler, link);
-			(*protocol_buffer)[j] = (void *)protocol->guid;
+		list_for_each_entry(child, &dev->child_head, sibling_node) {
+			struct efi_handler *handler;
+
+			if (child->driver->id != UCLASS_EFI_PROTOCOL)
+				continue;
+
+			handler = child->uclass_platdata;
+			(*protocol_buffer)[j] = (void *)handler->guid;
 			++j;
 		}
 	}
@@ -2233,26 +2423,27 @@ out:
  *
  * Return: status code
  */
-static efi_status_t EFIAPI efi_locate_protocol(const efi_guid_t *protocol,
+static efi_status_t EFIAPI efi_locate_protocol(const efi_guid_t *protocol_guid,
 					       void *registration,
 					       void **protocol_interface)
 {
-	struct list_head *lhandle;
+	struct efi_object *efiobj;
 	efi_status_t ret;
 
-	EFI_ENTRY("%pUl, %p, %p", protocol, registration, protocol_interface);
+	EFI_ENTRY("%pUl, %p, %p", protocol_guid, registration,
+		  protocol_interface);
 
-	if (!protocol || !protocol_interface)
+	if (!protocol_guid || !protocol_interface)
 		return EFI_EXIT(EFI_INVALID_PARAMETER);
 
-	list_for_each(lhandle, &efi_obj_list) {
-		struct efi_object *efiobj;
+	list_for_each_entry(efiobj, &efi_obj_list, link) {
 		struct efi_handler *handler;
+		struct udevice *protocol;
 
-		efiobj = list_entry(lhandle, struct efi_object, link);
-
-		ret = efi_search_protocol(efiobj, protocol, &handler);
+		ret = efi_search_protocol(efiobj->dev, protocol_guid,
+					  &protocol);
 		if (ret == EFI_SUCCESS) {
+			handler = protocol->uclass_platdata;
 			*protocol_interface = handler->protocol_interface;
 			return EFI_EXIT(EFI_SUCCESS);
 		}
@@ -2277,12 +2468,13 @@ static efi_status_t EFIAPI efi_locate_protocol(const efi_guid_t *protocol,
  * Return: status code
  */
 static efi_status_t EFIAPI efi_locate_device_path(
-			const efi_guid_t *protocol,
+			const efi_guid_t *protocol_guid,
 			struct efi_device_path **device_path,
 			efi_handle_t *device)
 {
 	struct efi_device_path *dp;
 	size_t i;
+	struct udevice *protocol;
 	struct efi_handler *handler;
 	efi_handle_t *handles;
 	size_t len, len_dp;
@@ -2291,9 +2483,9 @@ static efi_status_t EFIAPI efi_locate_device_path(
 	u8 *remainder;
 	efi_status_t ret;
 
-	EFI_ENTRY("%pUl, %p, %p", protocol, device_path, device);
+	EFI_ENTRY("%pUl, %p, %p", protocol_guid, device_path, device);
 
-	if (!protocol || !device_path || !*device_path || !device) {
+	if (!protocol_guid || !device_path || !*device_path || !device) {
 		ret = EFI_INVALID_PARAMETER;
 		goto out;
 	}
@@ -2302,17 +2494,19 @@ static efi_status_t EFIAPI efi_locate_device_path(
 	len = efi_dp_instance_size(*device_path);
 
 	/* Get all handles implementing the protocol */
-	ret = EFI_CALL(efi_locate_handle_buffer(BY_PROTOCOL, protocol, NULL,
-						&no_handles, &handles));
+	ret = EFI_CALL(efi_locate_handle_buffer(BY_PROTOCOL, protocol_guid,
+						NULL, &no_handles, &handles));
 	if (ret != EFI_SUCCESS)
 		goto out;
 
 	for (i = 0; i < no_handles; ++i) {
 		/* Find the device path protocol */
 		ret = efi_search_protocol(handles[i], &efi_guid_device_path,
-					  &handler);
+					  &protocol);
 		if (ret != EFI_SUCCESS)
 			continue;
+
+		handler = protocol->uclass_platdata;
 		dp = (struct efi_device_path *)handler->protocol_interface;
 		len_dp = efi_dp_instance_size(dp);
 		/*
@@ -2442,10 +2636,11 @@ static efi_status_t EFIAPI efi_uninstall_multiple_protocol_interfaces(
 	efi_va_end(argptr);
 	if (r == EFI_SUCCESS) {
 		/* If the last protocol has been removed, delete the handle. */
-		if (list_empty(&handle->protocols)) {
-			list_del(&handle->link);
-			free(handle);
-		}
+		if (device_find_first_child_by_uclass(handle,
+						      UCLASS_EFI_PROTOCOL,
+						      NULL))
+			efi_remove_handle(handle);
+
 		return EFI_EXIT(r);
 	}
 
@@ -2635,18 +2830,19 @@ out:
  * Return: status code
  */
 static efi_status_t EFIAPI efi_open_protocol
-			(efi_handle_t handle, const efi_guid_t *protocol,
+			(efi_handle_t handle, const efi_guid_t *protocol_guid,
 			 void **protocol_interface, efi_handle_t agent_handle,
 			 efi_handle_t controller_handle, uint32_t attributes)
 {
+	struct udevice *protocol;
 	struct efi_handler *handler;
 	efi_status_t r = EFI_INVALID_PARAMETER;
 
-	EFI_ENTRY("%p, %pUl, %p, %p, %p, 0x%x", handle, protocol,
+	EFI_ENTRY("%p, %pUl, %p, %p, %p, 0x%x", handle, protocol_guid,
 		  protocol_interface, agent_handle, controller_handle,
 		  attributes);
 
-	if (!handle || !protocol ||
+	if (!handle || !protocol_guid ||
 	    (!protocol_interface && attributes !=
 	     EFI_OPEN_PROTOCOL_TEST_PROTOCOL)) {
 		goto out;
@@ -2663,23 +2859,26 @@ static efi_status_t EFIAPI efi_open_protocol
 		/* fall-through */
 	case EFI_OPEN_PROTOCOL_BY_DRIVER:
 	case EFI_OPEN_PROTOCOL_BY_DRIVER | EFI_OPEN_PROTOCOL_EXCLUSIVE:
-		/* Check that the controller handle is valid */
-		if (!efi_search_obj(controller_handle))
+		if (!efi_is_valid(controller_handle)) {
+			r = EFI_INVALID_PARAMETER;
 			goto out;
+		}
 		/* fall-through */
 	case EFI_OPEN_PROTOCOL_EXCLUSIVE:
-		/* Check that the agent handle is valid */
-		if (!efi_search_obj(agent_handle))
+		if (!efi_is_valid(agent_handle)) {
+			r = EFI_INVALID_PARAMETER;
 			goto out;
+		}
 		break;
 	default:
 		goto out;
 	}
 
-	r = efi_search_protocol(handle, protocol, &handler);
+	r = efi_search_protocol(handle, protocol_guid, &protocol);
 	if (r != EFI_SUCCESS)
 		goto out;
 
+	handler = protocol->uclass_platdata;
 	r = efi_protocol_open(handler, protocol_interface, agent_handle,
 			      controller_handle, attributes);
 out:
@@ -2839,18 +3038,16 @@ static efi_status_t EFIAPI efi_connect_controller(
 			struct efi_device_path *remain_device_path,
 			bool recursive)
 {
+	struct udevice *dev, *child;
 	efi_status_t r;
 	efi_status_t ret = EFI_NOT_FOUND;
-	struct efi_object *efiobj;
 
 	EFI_ENTRY("%p, %p, %p, %d", controller_handle, driver_image_handle,
 		  remain_device_path, recursive);
 
-	efiobj = efi_search_obj(controller_handle);
-	if (!efiobj) {
-		ret = EFI_INVALID_PARAMETER;
-		goto out;
-	}
+	if (!efi_is_valid(controller_handle))
+		return EFI_INVALID_PARAMETER;
+	dev = controller_handle;
 
 	r = efi_connect_single_controller(controller_handle,
 					  driver_image_handle,
@@ -2861,7 +3058,11 @@ static efi_status_t EFIAPI efi_connect_controller(
 		struct efi_handler *handler;
 		struct efi_open_protocol_info_item *item;
 
-		list_for_each_entry(handler, &efiobj->protocols, link) {
+		list_for_each_entry(child, &dev->child_head, sibling_node) {
+			if (child->driver->id != UCLASS_EFI_PROTOCOL)
+				continue;
+
+			handler = child->uclass_platdata;
 			list_for_each_entry(item, &handler->open_infos, link) {
 				if (item->info.attributes &
 				    EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER) {
@@ -2880,7 +3081,7 @@ static efi_status_t EFIAPI efi_connect_controller(
 	if (ret != EFI_SUCCESS && remain_device_path &&
 	    remain_device_path->type == DEVICE_PATH_TYPE_END)
 		ret = EFI_SUCCESS;
-out:
+
 	return EFI_EXIT(ret);
 }
 
@@ -2945,18 +3146,23 @@ out:
  * Return: status code
  */
 static efi_status_t efi_get_child_controllers(
-				struct efi_object *efiobj,
+				struct udevice *dev,
 				efi_handle_t driver_handle,
 				efi_uintn_t *number_of_children,
 				efi_handle_t **child_handle_buffer)
 {
+	struct udevice *child;
 	struct efi_handler *handler;
 	struct efi_open_protocol_info_item *item;
 	efi_uintn_t count = 0, i;
 	bool duplicate;
 
 	/* Count all child controller associations */
-	list_for_each_entry(handler, &efiobj->protocols, link) {
+	list_for_each_entry(child, &dev->child_head, sibling_node) {
+		if (child->driver->id != UCLASS_EFI_PROTOCOL)
+			continue;
+
+		handler = child->uclass_platdata;
 		list_for_each_entry(item, &handler->open_infos, link) {
 			if (item->info.agent_handle == driver_handle &&
 			    item->info.attributes &
@@ -2973,7 +3179,11 @@ static efi_status_t efi_get_child_controllers(
 	if (!*child_handle_buffer)
 		return EFI_OUT_OF_RESOURCES;
 	/* Copy unique child handles */
-	list_for_each_entry(handler, &efiobj->protocols, link) {
+	list_for_each_entry(child, &dev->child_head, sibling_node) {
+		if (child->driver->id != UCLASS_EFI_PROTOCOL)
+			continue;
+
+		handler = child->uclass_platdata;
 		list_for_each_entry(item, &handler->open_infos, link) {
 			if (item->info.agent_handle == driver_handle &&
 			    item->info.attributes &
@@ -3015,30 +3225,23 @@ static efi_status_t EFIAPI efi_disconnect_controller(
 				efi_handle_t driver_image_handle,
 				efi_handle_t child_handle)
 {
+	struct udevice *dev;
 	struct efi_driver_binding_protocol *binding_protocol;
 	efi_handle_t *child_handle_buffer = NULL;
 	size_t number_of_children = 0;
 	efi_status_t r;
 	size_t stop_count = 0;
-	struct efi_object *efiobj;
 
 	EFI_ENTRY("%p, %p, %p", controller_handle, driver_image_handle,
 		  child_handle);
 
-	efiobj = efi_search_obj(controller_handle);
-	if (!efiobj) {
-		r = EFI_INVALID_PARAMETER;
-		goto out;
-	}
-
-	if (child_handle && !efi_search_obj(child_handle)) {
-		r = EFI_INVALID_PARAMETER;
-		goto out;
-	}
+	if (!efi_is_valid(controller_handle))
+		return EFI_INVALID_PARAMETER;
+	dev = controller_handle;
 
 	/* If no driver handle is supplied, disconnect all drivers */
 	if (!driver_image_handle) {
-		r = efi_disconnect_all_drivers(efiobj, NULL, child_handle);
+		r = efi_disconnect_all_drivers(dev, NULL, child_handle);
 		goto out;
 	}
 
@@ -3047,7 +3250,7 @@ static efi_status_t EFIAPI efi_disconnect_controller(
 		number_of_children = 1;
 		child_handle_buffer = &child_handle;
 	} else {
-		efi_get_child_controllers(efiobj,
+		efi_get_child_controllers(dev,
 					  driver_image_handle,
 					  &number_of_children,
 					  &child_handle_buffer);
@@ -3186,3 +3389,30 @@ efi_status_t efi_initialize_system_table(void)
 
 	return ret;
 }
+
+/*
+ * UEFI object -- any device with no corresponding u-boot device
+ */
+U_BOOT_DRIVER(efi_dumb_obj) = {
+	.name = "efi_dumb_object",
+	.id = UCLASS_EFI_OBJECT,
+};
+
+UCLASS_DRIVER(efi_obj) = {
+	.name = "efi_object",
+	.id = UCLASS_EFI_OBJECT,
+};
+
+/*
+ * UEFI protocol
+ */
+U_BOOT_DRIVER(efi_protocol) = {
+	.name = "efi_protocol",
+	.id = UCLASS_EFI_PROTOCOL,
+};
+
+UCLASS_DRIVER(efi_protocol) = {
+	.name = "efi_protocol",
+	.id = UCLASS_EFI_PROTOCOL,
+	.per_device_platdata_auto_alloc_size = sizeof(struct efi_handler),
+};
-- 
2.19.1



More information about the U-Boot mailing list